mirror of
https://github.com/Wesley-DeMontigny/WLUS.git
synced 2026-01-06 10:29:31 -06:00
Replacing projects
I didn't like what I was working with in the Old WLUS, so I'm working on a rewrite. This is the initial upload of the rewrite.
This commit is contained in:
69
.gitignore
vendored
69
.gitignore
vendored
@@ -1,69 +0,0 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Temporary databases
|
||||
*.tmp
|
||||
|
||||
# Custom config
|
||||
config.yml
|
||||
|
||||
# DB
|
||||
cms/db.sqlite3
|
||||
|
||||
# Pyaknet packet logs
|
||||
logs/
|
||||
21
LICENSE
21
LICENSE
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Wesley
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,8 +0,0 @@
|
||||
# WLUS
|
||||
This is a LEGO Universe Emulator written in Python 3.6</br>
|
||||
|
||||
# Installation
|
||||
This is the development version of WLUS and is currently not recommended to run if you are not familiar with how to do it in previous. A tutorial for an older version of WLUS can be found here https://lusprojects.github.io/
|
||||
|
||||
# Disclaimer
|
||||
The LEGO Group has not endorsed or authorized the operation of this game and is not liable for any safety issues in relation to its operation
|
||||
93
__main__.py
93
__main__.py
@@ -1,67 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import game
|
||||
import services
|
||||
import session_service
|
||||
import os
|
||||
import asyncio
|
||||
import configparser
|
||||
import player_service
|
||||
import threading
|
||||
"""
|
||||
This is the file that is used to start various servers.
|
||||
Command Line Arguments: <mode> <port> <zone> <name>
|
||||
mode - This determines what will run. There are technically infinite options.
|
||||
What actually determines what happens are the plugins that are of that same type.
|
||||
"Master" is a special type though -- it starts the master server. There are no plugins for the master server.
|
||||
To use a combination of server types like a Char and World server use a '-' between the types
|
||||
Example: char-world
|
||||
port - Port for the server
|
||||
zone - If there's no zone just put 'None' otherwise use the zone id of the world file you want to load
|
||||
name - The name of the instance (don't use spaces)
|
||||
"""
|
||||
import sys
|
||||
import replica_service
|
||||
import game_message_service
|
||||
import chat_command_service
|
||||
import chat_server_service
|
||||
import configparser
|
||||
from core import generic_game_server, master_server
|
||||
import asyncio
|
||||
sys.path.append("./plugins")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
game = game.Game()
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read("config.ini")
|
||||
game_config = config["GAME_CONFIG"]
|
||||
for config_option in game_config:
|
||||
game.set_config(config_option, eval(game_config[config_option]))
|
||||
|
||||
#Append all game scripts to Game
|
||||
for file in os.listdir("./game_scripts"):
|
||||
if file.endswith(".py"):
|
||||
mod = __import__(f'game_scripts.{file[:-3]}', fromlist=["Main"])
|
||||
if(hasattr(mod, 'Main')):
|
||||
game.add_script(getattr(mod, 'Main')(game))
|
||||
|
||||
database = services.DatabaseService(game)
|
||||
game.register_service(database)
|
||||
|
||||
player = player_service.PlayerService(game)
|
||||
game.register_service(player)
|
||||
|
||||
session = session_service.SessionService(game)
|
||||
game.register_service(session)
|
||||
|
||||
auth_server = services.AuthServerService(game)
|
||||
game.register_service(auth_server)
|
||||
|
||||
world_server = services.WorldServerService(game)
|
||||
game.register_service(world_server)
|
||||
|
||||
game_message = game_message_service.GameMessageService(game)
|
||||
game.register_service(game_message)
|
||||
|
||||
replica = replica_service.ReplicaService(game)
|
||||
game.register_service(replica)
|
||||
|
||||
world = services.WorldService(game)
|
||||
game.register_service(world)
|
||||
|
||||
chat_server = chat_server_service.ChatServerService(game)
|
||||
game.register_service(chat_server)
|
||||
|
||||
chat_command = chat_command_service.ChatCommandService(game)
|
||||
game.register_service(chat_command)
|
||||
|
||||
game.start()
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_forever()
|
||||
loop.close()
|
||||
if len(sys.argv) == 5 and str(sys.argv[1]).lower() != "master":
|
||||
config = configparser.ConfigParser()
|
||||
config.read("config.ini")
|
||||
generic_game_server.GameServer((config["GENERAL"]["bind_address"], int(sys.argv[2])), max_connections=5,
|
||||
incoming_password=b"3.25 ND1", server_type=str(sys.argv[1]).lower(),
|
||||
zone=eval(sys.argv[3]), name=sys.argv[4])
|
||||
print(f"Started WLUS Instance '{sys.argv[4]}'\n Type: [{sys.argv[1].lower()}]\n Port: [{sys.argv[2]}]\n"
|
||||
f" Zone: [{eval(sys.argv[3])}]")
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_forever()
|
||||
loop.close()
|
||||
elif len(sys.argv) == 3:
|
||||
server = master_server.MasterServer(('0.0.0.0', int(sys.argv[2])))
|
||||
else:
|
||||
print("Missing arguments")
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import pyraknet.server
|
||||
import pyraknet.messages
|
||||
import uuid
|
||||
import game_types
|
||||
from pyraknet.bitstream import *
|
||||
import game_enums
|
||||
import os
|
||||
|
||||
|
||||
class AuthServer(pyraknet.server.Server):
|
||||
def __init__(self, address: pyraknet.messages.Address, max_connections: int, incoming_password: bytes, auth_server_service):
|
||||
super().__init__(address, max_connections, incoming_password)
|
||||
self.auth_server_service = auth_server_service
|
||||
self.add_handler(pyraknet.server.Event.UserPacket, self.handle_packet)
|
||||
global game
|
||||
game = self.auth_server_service.get_parent()
|
||||
self.default_handlers = {"auth_handshake":["OnPacket_Auth_{}".format(game_enums.PacketHeaderEnum.HANDSHAKE.value), self.handle_handshake],
|
||||
"auth_login":["OnPacket_Auth_{}".format(game_enums.PacketHeaderEnum.CLIENT_LOGIN_INFO.value), self.handle_login]}
|
||||
|
||||
|
||||
def handle_handshake(self, data: bytes, address):
|
||||
stream = ReadStream(data)
|
||||
client_version = stream.read(c_ulong)
|
||||
|
||||
packet = WriteStream()
|
||||
packet.write(game_enums.PacketHeaderEnum.HANDSHAKE.value)
|
||||
packet.write(c_ulong(client_version))
|
||||
packet.write(c_ulong(0x93))
|
||||
packet.write(c_ulong(1)) # Connection Type (1 For Auth, 4 For Everything Else)
|
||||
packet.write(c_ulong(os.getpid()))
|
||||
packet.write(c_short(0xff)) # Local port
|
||||
packet.write(game.get_config("redirect_address"), allocated_length=33)
|
||||
|
||||
self.send(packet, address)
|
||||
|
||||
def handle_login(self, data: bytes, address):
|
||||
stream = ReadStream(data)
|
||||
username = stream.read(str, allocated_length=33)
|
||||
password = stream.read(str, allocated_length=41)
|
||||
|
||||
packet = WriteStream()
|
||||
print("Attempted Login With Username '{}' And Password '{}'".format(username, password))
|
||||
login, user_info = self.auth_server_service.validate_login(username, password)
|
||||
if (login):
|
||||
response = game_enums.LoginResponseEnum.SUCCESS.value
|
||||
print("Login Accepted!")
|
||||
else:
|
||||
response = game_enums.LoginResponseEnum.INVALID_LOGIN_INFO.value
|
||||
print("Login Rejected!")
|
||||
packet.write(game_enums.PacketHeaderEnum.LOGIN_RESPONSE.value)
|
||||
packet.write(c_uint8(response))
|
||||
packet.write(game_types.String("Talk_Like_A_Pirate", allocated_length=33))
|
||||
packet.write(game_types.String("", allocated_length=33 * 7))
|
||||
packet.write(c_ushort(1))
|
||||
packet.write(c_ushort(10)) # Version Major, Current and Minor
|
||||
packet.write(c_ushort(64))
|
||||
user_key = (str(uuid.uuid4()))[0:20]
|
||||
packet.write(user_key, allocated_length=33)
|
||||
packet.write(game_types.String(game.get_config("redirect_address"), allocated_length=33)) # World Instance IP
|
||||
packet.write(game_types.String(game.get_config("redirect_address"), allocated_length=33)) # Chat Instance IP
|
||||
packet.write(c_uint16(2002)) # World Port
|
||||
packet.write(c_ushort(3003)) # Chat Port
|
||||
packet.write(game_types.String('0', allocated_length=33)) # Some other IP
|
||||
packet.write(game_types.String('00000000-0000-0000-0000-000000000000', allocated_length=37))
|
||||
packet.write(c_ulong(0))
|
||||
packet.write(game_types.String('US', allocated_length=3)) # US Localization
|
||||
packet.write(c_bool(False))
|
||||
packet.write(c_bool(False))
|
||||
packet.write(c_ulonglong(0))
|
||||
packet.write("Hello there ;D", length_type=c_uint16) # Custom error message
|
||||
packet.write(c_uint16(0))
|
||||
packet.write(c_ulong(4))
|
||||
|
||||
self.send(packet, address)
|
||||
|
||||
if (login):
|
||||
session_service = game.get_service("Session")
|
||||
player_service = game.get_service("Player")
|
||||
player_service.add_account(account_id=user_info["account_id"])
|
||||
session_service.add_session(address=address, user_key=user_key, account_id=user_info["account_id"], username=username)
|
||||
|
||||
def handle_packet(self, data : bytes, address : pyraknet.messages.Address):
|
||||
game.trigger_event("OnPacket_Auth_{}".format(str(data[0:8])), args=[data[8:], address], debug=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import services
|
||||
from pyraknet.bitstream import *
|
||||
import copy
|
||||
import game_enums
|
||||
import components
|
||||
import json
|
||||
|
||||
class ChatCommandService(services.GameService):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Chat Command"
|
||||
self._commands = {}
|
||||
global game
|
||||
game = self.get_parent()
|
||||
|
||||
def initialize(self):
|
||||
self.register_command("/testmap", self.testmap)
|
||||
self.register_command("/fly", self.toggle_jetpack)
|
||||
self.register_command("/togglepvp", self.toggle_pvp)
|
||||
self.register_command("/gmadditem", self.get_item)
|
||||
self.register_command("/spawn", self.spawn_lot)
|
||||
self.register_command("/togglegm", self.toggle_gm, True)
|
||||
game.register_event_handler("GM_{}".format(game_enums.GameMessages.PARSE_CHAT_MSG.value))(self.handle_command)
|
||||
super().initialize()
|
||||
|
||||
def toggle_gm(self, object_id, address, args, client_state):
|
||||
player = game.get_service("Player").get_player_object_by_id(object_id)
|
||||
if(player.gm_level != 2):
|
||||
player.gm_level = 2
|
||||
else:
|
||||
player.gm_level = 2
|
||||
|
||||
def toggle_pvp(self, object_id, address, args, client_state):
|
||||
player = game.get_service("Player").get_player_object_by_id(object_id)
|
||||
player.zone.pvp_enabled = not player.zone.pvp_enabled
|
||||
|
||||
def spawn_lot(self, object_id, address, args, client_state):
|
||||
player = game.get_service("Player").get_player_object_by_id(object_id)
|
||||
try:
|
||||
lot = int(args[0])
|
||||
except:
|
||||
return
|
||||
object_config = {"lot":lot, "object_id":game.generate_object_id(), "position":player.get_component(components.Transform).position}
|
||||
player.zone.create_object(player.zone, object_config)
|
||||
|
||||
database_service = game.get_service("Database")
|
||||
server_db = database_service.server_db
|
||||
c = server_db.connection.cursor()
|
||||
adjusted_config = copy.deepcopy(object_config)
|
||||
adjusted_config["position"] = str(object_config["position"])
|
||||
c.execute("INSERT INTO ZoneObjects (zone_id, replica_config) VALUES (?, ?)", (player.zone.get_zone_id(), json.dumps(adjusted_config)))
|
||||
|
||||
|
||||
def handle_command(self, object_id, stream, address):
|
||||
client_state = stream.read(c_int)
|
||||
command = stream.read(str, length_type=c_ulong)
|
||||
args = command.split(" ")
|
||||
if(args[0] in self._commands):
|
||||
if (self._commands[args[0]][1] == False or game.get_config("allow_commands") == True or bool(game.get_service("Player").get_account_by_player_id(object_id)["is_admin"]) == True):
|
||||
copy_args = copy.deepcopy(args)
|
||||
del copy_args[0]
|
||||
self._commands[args[0]][0](object_id, address, copy_args, client_state)
|
||||
|
||||
def register_command(self, command_name, handler, requires_admin = True):
|
||||
self._commands[command_name] = [handler, requires_admin]
|
||||
|
||||
def get_item(self, object_id, address, args, client_state):
|
||||
lot = int(args[0])
|
||||
player_service = game.get_service("Player")
|
||||
item = player_service.add_item_to_inventory(object_id, lot, json_data={"from":"command"})
|
||||
if(item is not None):
|
||||
game.get_service("Game Message").add_item_to_inventory_client_sync(object_id, [address], item["lot"], item["item_id"], item["slot"])
|
||||
|
||||
def toggle_jetpack(self, object_id, address, args, client_state):
|
||||
player = game.get_service("Player").get_player_object_by_id(object_id)
|
||||
zone = player.zone
|
||||
if(player is not None):
|
||||
game.get_service("Game Message").set_jetpack_mode(object_id, zone.get_connections(), bypass_checks=True, use=not player.get_component(components.Character).jetpack_enabled, air_speed=20,
|
||||
max_air_speed=30, vert_vel=2, effect_id=36)
|
||||
player.get_component(components.Character).jetpack_enabled = not player.get_component(components.Character).jetpack_enabled
|
||||
|
||||
def testmap(self, object_id, address, args, client_state):
|
||||
if(game.get_service("World").get_zone_by_id(int(args[0])) is not None):
|
||||
world_server = game.get_service("World Server").server
|
||||
world_server.load_world(object_id, int(args[0]), address, True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import services
|
||||
import pyraknet.server
|
||||
import pyraknet.messages
|
||||
from pyraknet.bitstream import *
|
||||
import game_enums
|
||||
import copy
|
||||
import game_types
|
||||
|
||||
|
||||
class ChatServerService(services.GameService):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Chat Server"
|
||||
self.blacklist = []
|
||||
|
||||
if (parent.get_config("chat_port") is not None):
|
||||
self._port = parent.get_config("chat_port")
|
||||
else:
|
||||
self._port = 3003
|
||||
|
||||
if (parent.get_config("bind_address") is not None):
|
||||
self._address = parent.get_config("bind_address")
|
||||
else:
|
||||
self._address = "127.0.0.1"
|
||||
|
||||
if (parent.get_config("world_max_connections") is not None):#Since you would only be connected to the Chat Server if you were also connected to the World Server why not make them the same
|
||||
self._max_connections = parent.get_config("world_max_connections")
|
||||
else:
|
||||
self._max_connections = 10
|
||||
|
||||
self.server = ChatServer((self._address, self._port), max_connections=self._max_connections, incoming_password=b"3.25 ND1", chat_server_service=self)
|
||||
|
||||
global game
|
||||
game = self.get_parent()
|
||||
|
||||
def initialize(self):
|
||||
for handler in self.server.default_handlers:
|
||||
self.get_parent().register_event_handler(self.server.default_handlers[handler][0])(self.server.default_handlers[handler][1])
|
||||
super().initialize()
|
||||
|
||||
|
||||
class ChatServer(pyraknet.server.Server):
|
||||
def __init__(self, address: pyraknet.messages.Address, max_connections: int, incoming_password: bytes, chat_server_service):
|
||||
super().__init__(address, max_connections, incoming_password)
|
||||
self.chat_server_service = chat_server_service
|
||||
self.add_handler(pyraknet.server.Event.UserPacket, self.handle_packet)
|
||||
self.default_handlers = {"chat_whitelist_request":["OnPacket_World_{}".format(game_enums.PacketHeaderEnum.CLIENT_WHITELIST_REQUEST.value), self.handle_whitelist_request]}
|
||||
global game
|
||||
game = self.chat_server_service.get_parent()
|
||||
|
||||
|
||||
def handle_whitelist_request(self, data : bytes, address):#Just make the whole "accepted" and filter out any bad words when we send the actual message
|
||||
request_packet = ReadStream(data)
|
||||
super_chat_level = request_packet.read(c_uint8)
|
||||
request_id = request_packet.read(c_uint8)
|
||||
|
||||
stream = WriteStream()
|
||||
stream.write(game_enums.PacketHeaderEnum.CHAT_MODERATION_RESPONSE.value)
|
||||
stream.write(c_bit(True))
|
||||
stream.write(c_uint16(0))
|
||||
stream.write(c_uint8(request_id))
|
||||
stream.write(c_uint8(0))
|
||||
stream.write(game_types.String("", allocated_length=66))
|
||||
length = int(len(copy.deepcopy(stream).__bytes__()))
|
||||
stream.write(game_types.String("", allocated_length=99-length))
|
||||
stream.write(c_uint8(0))
|
||||
stream.write(c_uint8(0))
|
||||
|
||||
ws = game.get_service("World Server")
|
||||
ws.server.send(stream, address)#Doesn't work for some reason, i'll have to check it out
|
||||
|
||||
|
||||
|
||||
def handle_packet(self, data : bytes, address : pyraknet.messages.Address):
|
||||
game.trigger_event("OnPacket_Chat_{}".format(str(data[0:8])), args=[data[8:], address], debug=True)
|
||||
274
components.py
274
components.py
@@ -1,274 +0,0 @@
|
||||
import game_types
|
||||
import typing
|
||||
import time
|
||||
import copy
|
||||
|
||||
'''
|
||||
Components are used to attach specific values to game objects
|
||||
'''
|
||||
|
||||
class Component():
|
||||
def __init__(self, parent):
|
||||
self._parent = parent
|
||||
self._name = "Base Component"
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
|
||||
def get_parent(self):
|
||||
return self._parent
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
super().__setattr__(key, value)
|
||||
self.get_parent().update()
|
||||
|
||||
|
||||
class Transform(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Transform"
|
||||
self.scale : int = 1
|
||||
self.position : game_types.Vector3 = game_types.Vector3()
|
||||
self.rotation : game_types.Vector4 = game_types.Vector4()
|
||||
self.velocity : game_types.Vector3 = game_types.Vector3()
|
||||
self.on_ground : bool = True
|
||||
self.angular_velocity : game_types.Vector3 = game_types.Vector3()
|
||||
|
||||
if(self.get_parent().lot == 1):
|
||||
self.player_sync_thread = game_types.GameThread(target=self.player_sync)
|
||||
self.player_sync_thread.start()
|
||||
def player_sync(self):
|
||||
player_id = self.get_parent().get_object_id()
|
||||
game = self.get_parent().zone.get_parent().get_parent()
|
||||
player_service = game.get_service("Player")
|
||||
while self.get_parent().player_sync == True:
|
||||
player = player_service.get_player_by_id(player_id)
|
||||
player["Data"]["position"] = self.position
|
||||
player["Data"]["rotation"] = self.rotation
|
||||
time.sleep(.1)
|
||||
|
||||
|
||||
class Collectible(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Collectible"
|
||||
self.collectible_id : int = 0
|
||||
|
||||
class Bouncer(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Bouncer"
|
||||
self.pet_required : bool = False
|
||||
|
||||
#TODO: Implement This Component, It Doesn't Do Anything Now
|
||||
class Component107(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Component107"
|
||||
|
||||
class Character(Component):
|
||||
def __init__(self, parent, player_id : int = 0):
|
||||
super().__init__(parent)
|
||||
self._name = "Character"
|
||||
self.player_id : int = player_id
|
||||
self.vehicle_id : int = 0
|
||||
self.head_glow : int = 0
|
||||
self.gm_level : int = 0
|
||||
self.jetpack_enabled : bool = False
|
||||
|
||||
def get_player_info(self):
|
||||
game = self.get_parent().zone.get_parent().get_parent()
|
||||
player = game.get_service("Player").get_player_by_id(self.player_id)
|
||||
account = game.get_service("Player").get_account_by_player_id(self.player_id)
|
||||
return copy.deepcopy(player), copy.deepcopy(account)
|
||||
|
||||
class Minifig(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Minfig"
|
||||
self.head : int = 0
|
||||
self.chest : int = 0
|
||||
self.legs : int = 0
|
||||
self.hair_style : int = 0
|
||||
self.hair_color : int = 0
|
||||
self.chest_decal : int = 0
|
||||
self.head_color : int = 0
|
||||
self.left_hand : int = 0
|
||||
self.right_hand : int = 0
|
||||
self.eyebrows : int = 0
|
||||
self.eyes : int = 0
|
||||
self.mouth : int = 0
|
||||
|
||||
class Possessable(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Possessable"
|
||||
self.driver_object_id : int = 0
|
||||
|
||||
#TODO: Implement This Component, It Doesn't Do Anything Now
|
||||
class Vendor(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Vendor"
|
||||
|
||||
|
||||
class PhysicsEffect(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "PhysicsEffect"
|
||||
self.effect_type : int = 0
|
||||
self.effect_amount : float = 0.0
|
||||
self.effect_direction : game_types.Vector3 = game_types.Vector3()
|
||||
|
||||
class VehiclePhysics(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "VehiclePhysics"
|
||||
self.data_1 : int = 0
|
||||
self.flag_1 : bool = False
|
||||
self.flag_2 : bool = False
|
||||
self.flag_2_1 : bool = False
|
||||
|
||||
|
||||
#TODO: Implement This Component, It Doesn't Do Anything Now
|
||||
class RacingControl(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "RacingControl"
|
||||
|
||||
|
||||
# TODO: Implement This Component, It Doesn't Do Anything Now
|
||||
class ScriptedActivity(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "ScriptedActivity"
|
||||
|
||||
#TODO: Implement This Component, It Doesn't Do Anything Now
|
||||
class Skill(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Skill"
|
||||
|
||||
class Switch(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Switch"
|
||||
self.state : bool = False
|
||||
|
||||
class Trigger(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.tigger_id : int = 0
|
||||
|
||||
class ModelData(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "ModelData"
|
||||
self.ldf : game_types.LDF = game_types.LDF()
|
||||
|
||||
class Render(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Render"
|
||||
self.render_disabled : bool = False
|
||||
self.fx_effects : list = []
|
||||
|
||||
def add_fx_effect(self, name, effect_id, effect_type, scale, secondary):
|
||||
self.fx_effects.append(({"name":name, "effect_id":effect_id, "effect_type":effect_type, "scale":scale, "secondary":secondary}))
|
||||
|
||||
#TODO: Implement This Component, It Doesn't Do Anything Now
|
||||
class ModuleAssembly(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "ModuleAssembly"
|
||||
|
||||
class LUPExhibit(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "LUPExhibit"
|
||||
self.exhibited_lot : int = 10781
|
||||
|
||||
#TODO: Implement This Component, It Doesn't Do Anything Now
|
||||
class ScriptComponent(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "ScriptComponent"
|
||||
|
||||
class Pet(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Pet"
|
||||
self.owner_id : int= 0
|
||||
self.pet_name : str = "Petty The Pet"
|
||||
|
||||
class Stats(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Stats"
|
||||
self.health : int = 0
|
||||
self.max_health : int = 0
|
||||
self.armor : int = 0
|
||||
self.max_armor : int = 0
|
||||
self.imagination : int = 0
|
||||
self.max_imagination : int = 0
|
||||
self.faction : int = 0
|
||||
self.is_smashable : bool = False
|
||||
self.level : int = 1
|
||||
|
||||
if(self.get_parent().lot == 1):
|
||||
self.player_sync_thread = game_types.GameThread(target=self.player_sync)
|
||||
self.player_sync_thread.start()
|
||||
def player_sync(self):
|
||||
player_id = self.get_parent().get_object_id()
|
||||
game = self.get_parent().zone.get_parent().get_parent()
|
||||
player_service = game.get_service("Player")
|
||||
while self.get_parent().player_sync == True:
|
||||
player = player_service.get_player_by_id(player_id)
|
||||
player["Data"]["health"] = self.health
|
||||
player["Data"]["max_health"] = self.max_health
|
||||
player["Data"]["armor"] = self.armor
|
||||
player["Data"]["max_armor"] = self.max_armor
|
||||
player["Data"]["imagination"] = self.imagination
|
||||
player["Data"]["max_imagination"] = self.max_imagination
|
||||
time.sleep(.1)
|
||||
|
||||
#TODO: Implement This Component, It Doesn't Do Anything Now
|
||||
class Destructible(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Destructible"
|
||||
|
||||
#THIS COMPONENT DOES NOT APPLY TO PLAYERS
|
||||
class Inventory(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Inventory"
|
||||
self.items : list = []
|
||||
|
||||
|
||||
def add_item(self, item):
|
||||
self.items.append(item)
|
||||
|
||||
class BaseCombatAI(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "BaseCombatAI"
|
||||
self.action : int = 0
|
||||
self.target_id : int = 0
|
||||
|
||||
class Rebuild(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Rebuild"
|
||||
self.rebuild_state : int = 0
|
||||
self.success : bool = False
|
||||
self.enabled : bool = True
|
||||
self.time_since_start :float = 0.0
|
||||
self.reset_time : float = 0.0
|
||||
self.build_activator_pos : game_types.Vector3 = game_types.Vector3()
|
||||
|
||||
#TODO: Implement this component
|
||||
class MovingPlatform(Component):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "MovingPLatform"
|
||||
22
config.ini
22
config.ini
@@ -1,11 +1,11 @@
|
||||
[GAME_CONFIG]
|
||||
bind_address="0.0.0.0"
|
||||
redirect_address="127.0.0.1"
|
||||
auth_port=1001
|
||||
world_port=2002
|
||||
allow_commands=True
|
||||
auth_max_connections=10
|
||||
world_max_connections=10
|
||||
accept_custom_names=False
|
||||
jonnys_dumb_effect=False
|
||||
cache_structs=True
|
||||
[GENERAL]
|
||||
bind_address=0.0.0.0
|
||||
master_server_address=127.0.0.1
|
||||
master_server_port=4211
|
||||
master_server_password=1124 WLUS2.0
|
||||
|
||||
[MYSQL]
|
||||
user=root
|
||||
password=1088043
|
||||
host=127.0.0.1
|
||||
database=wlus
|
||||
BIN
core/__pycache__/generic_game_server.cpython-37.pyc
Normal file
BIN
core/__pycache__/generic_game_server.cpython-37.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/master_server.cpython-37.pyc
Normal file
BIN
core/__pycache__/master_server.cpython-37.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/plugin_manager.cpython-37.pyc
Normal file
BIN
core/__pycache__/plugin_manager.cpython-37.pyc
Normal file
Binary file not shown.
74
core/generic_game_server.py
Normal file
74
core/generic_game_server.py
Normal file
@@ -0,0 +1,74 @@
|
||||
"""
|
||||
This file contains the game server class.
|
||||
"""
|
||||
import pyraknet.server
|
||||
import pyraknet.messages
|
||||
import threading
|
||||
from core.plugin_manager import PluginManager
|
||||
import importlib
|
||||
from mysql.connector import connection
|
||||
import configparser
|
||||
import socket
|
||||
import sys
|
||||
|
||||
|
||||
class GameServer(pyraknet.server.Server):
|
||||
def __init__(self, address: pyraknet.messages.Address, max_connections: int, incoming_password: bytes,
|
||||
server_type: str, zone: int, name: str):
|
||||
|
||||
super().__init__(address, max_connections, incoming_password)
|
||||
self.add_handler(pyraknet.server.Event.UserPacket, self.handle_packet)
|
||||
|
||||
self.name = name
|
||||
self.zone = zone
|
||||
self.config = configparser.ConfigParser()
|
||||
self.config.read("config.ini")
|
||||
|
||||
self.master_server = socket.socket()
|
||||
self.master_server.connect((str(self.config["GENERAL"]["master_server_address"]),
|
||||
int(self.config["GENERAL"]["master_server_port"])))
|
||||
self.master_server.send(str(self.config["GENERAL"]["master_server_password"]).encode("UTF-8"))
|
||||
if self.master_server.recv(1024) == b"Accepted":
|
||||
print("Successfully Logged Into Master Server")
|
||||
self.master_server.send((str(server_type) + "$" + str(address[1]) + "$" + str(zone) + "$" + str(self.name))
|
||||
.encode("UTF-8"))
|
||||
if self.master_server.recv(1024) == b"Registered":
|
||||
print("Successfully Registered Server")
|
||||
else:
|
||||
print("Server Failed Registration")
|
||||
sys.exit()
|
||||
else:
|
||||
print("Server Failed To Login")
|
||||
sys.exit()
|
||||
|
||||
self.packet_handlers = {}
|
||||
self.db_connection = connection.MySQLConnection(user=self.config["MYSQL"]["user"],
|
||||
password=self.config["MYSQL"]["password"],
|
||||
host=self.config["MYSQL"]["host"],
|
||||
database=self.config["MYSQL"]["database"])
|
||||
|
||||
plugins_to_load = PluginManager.get_valid_plugins(server_type)
|
||||
for p in plugins_to_load:
|
||||
config = PluginManager.get_config(p)
|
||||
plugin_module = importlib.import_module(f"plugins.{p}.{config['main_file']}")
|
||||
plugin_module.Plugin(self)
|
||||
|
||||
def redirect_request(self, method: str, identifier: str):
|
||||
self.master_server.send(b"r")
|
||||
if self.master_server.recv(1024) == b"Redirect Acknowledged":
|
||||
self.master_server.send((method + "$" + identifier).encode("UTF-8"))
|
||||
data = self.master_server.recv(1024).decode("UTF-8")
|
||||
data = data.split("$")
|
||||
return str(data[0]), int(data[1])
|
||||
|
||||
def register_handler(self, function, packet_header):
|
||||
if packet_header in self.packet_handlers:
|
||||
self.packet_handlers[packet_header].append(function)
|
||||
else:
|
||||
self.packet_handlers[packet_header] = [function]
|
||||
|
||||
def handle_packet(self, data: bytes, address: pyraknet.messages.Address):
|
||||
if data[0:8] in self.packet_handlers:
|
||||
for f in self.packet_handlers[data[0:8]]:
|
||||
handler = threading.Thread(target=f, args=(data[8:], address, self))
|
||||
handler.start()
|
||||
73
core/master_server.py
Normal file
73
core/master_server.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import socket
|
||||
import threading
|
||||
|
||||
|
||||
class MasterServer:
|
||||
def __init__(self, address: tuple, max_connections: int = 10, password: bytes = b"1124 WLUS2.0"):
|
||||
self.address = address
|
||||
self.max_connections = max_connections
|
||||
self.password = password
|
||||
|
||||
self._s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._s.bind(address)
|
||||
self._s.listen(max_connections)
|
||||
self._connections = {}
|
||||
|
||||
main_thread = threading.Thread(target=self._run)
|
||||
main_thread.start()
|
||||
|
||||
def _run(self):
|
||||
print("Starting Master Server")
|
||||
while True:
|
||||
client_socket, address = self._s.accept()
|
||||
password = client_socket.recv(1024)
|
||||
print(f"Attempted Login From Address [{address}] With Password [{password.decode('UTF-8')}]")
|
||||
if password == self.password:
|
||||
client_socket.send(b"Accepted")
|
||||
server_info = client_socket.recv(1024)
|
||||
data = server_info.decode("UTF-8").split("$")
|
||||
if data[2].lower() == 'none':
|
||||
data[2] = None
|
||||
print(f"Registered Server With Data: {data}")
|
||||
self._connections[data[3]] = {"instance_type": data[0], "port": data[1], "zone": data[2],
|
||||
"address": address}
|
||||
client_socket.send(b"Registered")
|
||||
threading.Thread(target=self._client_thread, args=(client_socket, address)).start()
|
||||
else:
|
||||
client_socket.send(b"Bad Login")
|
||||
client_socket.close()
|
||||
|
||||
def _client_thread(self, client_socket: socket, address: tuple):
|
||||
while True:
|
||||
data = client_socket.recv(1024)
|
||||
if len(data.decode("UTF-8")) > 0:
|
||||
if data.decode("UTF-8")[0] == "r":
|
||||
client_socket.send(b"Redirect Acknowledged")
|
||||
# Format: <selector_type>$<selector>
|
||||
redirect_data = client_socket.recv(1024).decode("UTF-8").split("$")
|
||||
if len(redirect_data) == 2:
|
||||
print(f"Redirecting by type [{redirect_data[0]}] with selector [{redirect_data[1]}]")
|
||||
if redirect_data[0] == "instance":
|
||||
response = b"None"
|
||||
for conn in self._connections:
|
||||
if self._connections[conn]["instance_type"] == redirect_data[1]:
|
||||
response = (str(self._connections[conn]["address"][0]) + "$" +
|
||||
str(self._connections[conn]["port"])).encode("UTF-8")
|
||||
break
|
||||
client_socket.send(response)
|
||||
elif redirect_data[0] == "name":
|
||||
if redirect_data[1] in self._connections:
|
||||
client_socket.send((str(self._connections[redirect_data[1]]["address"][0]) + "$" +
|
||||
str(self._connections[redirect_data[1]]["port"])).encode("UTF-8"))
|
||||
else:
|
||||
client_socket.send(b"None")
|
||||
elif redirect_data[0] == "zone":
|
||||
response = b"None"
|
||||
for conn in self._connections:
|
||||
if self._connections[conn]["zone"] == redirect_data[1]:
|
||||
response = (str(self._connections[conn]["address"][0]) + "$" +
|
||||
str(self._connections[conn]["port"])).encode("UTF-8")
|
||||
break
|
||||
client_socket.send(response)
|
||||
else:
|
||||
client_socket.send(b"None")
|
||||
62
core/plugin_manager.py
Normal file
62
core/plugin_manager.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""
|
||||
This contains the PluginManager class.
|
||||
|
||||
THIS AINT WORKIN. What should be implemented is a recursive function that goes through each
|
||||
plugin and makes sure they all have their dependencies. STOP BEING LAZY AND FIX THIS WESLEY
|
||||
|
||||
NOTE: Plugin ids should be the same name as their folder.
|
||||
"""
|
||||
from typing import List, Dict
|
||||
import os
|
||||
import json
|
||||
|
||||
|
||||
class PluginManager:
|
||||
"""
|
||||
Makes sure that all dependencies are needed for the plugins that will be loaded.
|
||||
"""
|
||||
@classmethod
|
||||
def get_config(cls, plugin_id: str) -> Dict:
|
||||
with open(f"./plugins/{plugin_id}/plugin.json") as json_file:
|
||||
config = json.load(json_file)
|
||||
return config
|
||||
|
||||
@classmethod
|
||||
def get_valid_plugins(cls, plugin_type: str, debug: bool = True) -> List[str]:
|
||||
"""
|
||||
This gets all the plugins which have their dependencies fulfilled.
|
||||
:param plugin_type: The type of plugin the function will look for. (ie. an auth server will only want to load auth types)
|
||||
:param debug: Determines whether or not the function will output the plugins which aren't valid
|
||||
:return: Returns a list of all the plugin directories which should be loaded
|
||||
"""
|
||||
plugins = {} # Dict of lists of various plugin types
|
||||
for folder in next(os.walk('./plugins'))[1]:
|
||||
config = PluginManager.get_config(folder)
|
||||
if config["type"] in plugins:
|
||||
plugins[config["type"]].append((f"./plugins/{folder}/plugin.json", config))
|
||||
else:
|
||||
plugins[config["type"]] = [(f"./plugins/{folder}/plugin.json", config)]
|
||||
|
||||
valid_plugins = []
|
||||
for t in plugin_type.split("-"):
|
||||
if t in plugins:
|
||||
for plugin, config in plugins[t]:
|
||||
load = [True]
|
||||
for d in config["dependencies"]:
|
||||
has_plugin = False
|
||||
for p_type in plugins:
|
||||
for p in plugins[p_type]:
|
||||
if p[1]["id"] == d:
|
||||
has_plugin = True
|
||||
break
|
||||
if has_plugin:
|
||||
break
|
||||
if not has_plugin:
|
||||
load = False
|
||||
if debug:
|
||||
print(f"{config['name']} will not be loaded. Missing dependency: {d}")
|
||||
break
|
||||
if load[0]:
|
||||
valid_plugins.append(config["id"])
|
||||
|
||||
return valid_plugins
|
||||
9
core/terminal_insatnce.py
Normal file
9
core/terminal_insatnce.py
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
|
||||
class Terminal:
|
||||
"""
|
||||
This is what is created when the user starts a terminal instance.
|
||||
Not Implemented - Obviously
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
143
database.py
143
database.py
@@ -1,143 +0,0 @@
|
||||
'''
|
||||
from sqlalchemy import *
|
||||
from sqlalchemy.orm import *
|
||||
from sqlalchemy.ext.declarative import *
|
||||
'''
|
||||
import sqlite3
|
||||
|
||||
|
||||
#This is all for sqlalchemy orm implementation. I'm not 100% sure what Im doing so Im just gonna comment it out until I understand it better
|
||||
'''
|
||||
Base = declarative_base()
|
||||
|
||||
class Account(Base):
|
||||
__tablename__ = "Accounts"
|
||||
|
||||
account_id = Column('account_id', INTEGER, primary_key=True, autoincrement=True)
|
||||
username = Column('username', TEXT)
|
||||
password = Column('password', TEXT)
|
||||
banned = Column('banned', INTEGER)
|
||||
is_admin = Column('is_admin', INTEGER)
|
||||
|
||||
class CharacterData(Base):
|
||||
__tablename__ = "CharacterData"
|
||||
|
||||
universe_score = Column('universe_score', INTEGER)
|
||||
level = Column('level', INTEGER)
|
||||
health = Column('health', INTEGER)
|
||||
max_health = Column('max_health', INTEGER)
|
||||
armor = Column('armor', INTEGER)
|
||||
max_armor = Column('max_armor', INTEGER)
|
||||
imagination = Column('imagination', INTEGER)
|
||||
max_imagination = Column('max_imagination', INTEGER)
|
||||
currency = Column('currency', INTEGER)
|
||||
player_id = Column('player_id', INTEGER)
|
||||
backpack_space = Column('backpack_space', INTEGER)
|
||||
position = Column('position', TEXT)
|
||||
rotation = Column('rotation', TEXT)
|
||||
|
||||
class CharacterStats(Base):
|
||||
__tablename__ = "CharacterStats"
|
||||
|
||||
currency_collected = Column('currency_collected', INTEGER)
|
||||
bricks_collected = Column('bricks_collected', INTEGER)
|
||||
smashables_smashed = Column('smashables_smashed', INTEGER)
|
||||
level = Column('level', INTEGER)
|
||||
quick_builds_done = Column('quick_builds_done', INTEGER)
|
||||
enemies_smashed = Column('enemies_smashed', INTEGER)
|
||||
rockets_used = Column('rockets_used', INTEGER)
|
||||
pets_tamed = Column('pets_tamed', INTEGER)
|
||||
imagination_collected = Column('imagination_collected', INTEGER)
|
||||
health_collected = Column('health_collected', INTEGER)
|
||||
armor_collected = Column('armor_collected', INTEGER)
|
||||
distance_traveled = Column('distance_traveled', INTEGER)
|
||||
times_died = Column('times_died', INTEGER)
|
||||
damage_taken = Column('damage_taken', INTEGER)
|
||||
damage_healed = Column('damage_healed', INTEGER)
|
||||
armor_repaired = Column('armor_repaired', INTEGER)
|
||||
imagination_restored = Column('imagination_restored', INTEGER)
|
||||
imagination_used = Column('imagination_used', INTEGER)
|
||||
distance_driven = Column('distance_driven', INTEGER)
|
||||
time_airborne_in_car = Column('time_airborne_in_car', INTEGER)
|
||||
racing_imagination_collected = Column('racing_imagination_collected', INTEGER)
|
||||
racing_imagination_crates_smashed = Column('racing_imagination_crates_smashed', INTEGER)
|
||||
race_car_boosts = Column('race_car_boosts', INTEGER)
|
||||
car_wrecks = Column('car_wrecks', INTEGER)
|
||||
racing_smashables_smashed = Column('racing_smashables_smashed', INTEGER)
|
||||
races_finished = Column('races_finished', INTEGER)
|
||||
races_won = Column('races_won', INTEGER)
|
||||
player_id = Column('player_id', INTEGER)
|
||||
|
||||
class Character(Base):
|
||||
__tablename__ = "Characters"
|
||||
|
||||
player_id = Column('player_id', INTEGER)
|
||||
name = Column('name', TEXT)
|
||||
zone = Column('zone', INTEGER)
|
||||
shirt_color = Column('shirt_color', INTEGER)
|
||||
shirt_style = Column('shirt_style', INTEGER)
|
||||
pants_color = Column('pants_color', INTEGER)
|
||||
hair_color = Column('hair_color', INTEGER)
|
||||
hair_style = Column('hair_style', INTEGER)
|
||||
lh = Column('lh', INTEGER)
|
||||
rh = Column('rh', INTEGER)
|
||||
eyebrows = Column('eyebrows', INTEGER)
|
||||
eyes = Column('eyes', INTEGER)
|
||||
mouth = Column('mouth', INTEGER)
|
||||
account_id = Column('account_id', INTEGER)
|
||||
custom_name = Column('custom_name', TEXT)
|
||||
|
||||
class CompletedMission(Base):
|
||||
__tablename__ = "CompletedMissions"
|
||||
|
||||
player_id = Column('player_id', INTEGER)
|
||||
mission_id = Column('mission_id', INTEGER)
|
||||
|
||||
class CurrentMission(Base):
|
||||
__tablename__ = "CurrentMissions"
|
||||
|
||||
player_id = Column('player_id', INTEGER)
|
||||
mission_id = Column('mission_id', INTEGER)
|
||||
progress = Column('progress', INTEGER)
|
||||
|
||||
class Inventory(Base):
|
||||
__tablename__ = "Inventory"
|
||||
|
||||
lot = Column('lot', INTEGER)
|
||||
slot = Column('slot', INTEGER)
|
||||
equipped = Column('equipped', INTEGER)
|
||||
linked = Column('linked', INTEGER)
|
||||
quantity = Column('quantity', INTEGER)
|
||||
item_id = Column('item_id', INTEGER)
|
||||
player_id = Column('player_id', INTEGER)
|
||||
JSON = Column('JSON', TEXT)
|
||||
|
||||
class ZoneObject(Base):
|
||||
__tablename__ = "ZoneObjects"
|
||||
|
||||
zone_id = Column('zone_id', INTEGER)
|
||||
replica_config = Column('replica_config', TEXT)
|
||||
|
||||
|
||||
class ServerDB():
|
||||
def __init__(self, database_path : str):
|
||||
engine = create_engine(f"sqlite:///{database_path}")
|
||||
metadata = MetaData()
|
||||
Base.metadata.create_all(bind=engine)
|
||||
Session = sessionmaker(bind=engine)
|
||||
Session.configure(bind=engine)
|
||||
self.session = Session()
|
||||
self.conn = engine.connect()
|
||||
self.accounts = Table('accounts', metadata, )
|
||||
'''
|
||||
|
||||
class GameDB():
|
||||
def __init__(self, database_path : str):
|
||||
self.connection = sqlite3.connect(database_path, check_same_thread=False)
|
||||
self.connection.isolation_level = None
|
||||
def row_factory(cursor, row):
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
self.connection.row_factory = row_factory
|
||||
55
db/wlus_account.sql
Normal file
55
db/wlus_account.sql
Normal file
@@ -0,0 +1,55 @@
|
||||
-- MySQL dump 10.13 Distrib 8.0.16, for Win64 (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: wlus
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 8.0.16
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
SET NAMES utf8 ;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `account`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `account`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
SET character_set_client = utf8mb4 ;
|
||||
CREATE TABLE `account` (
|
||||
`account_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(45) DEFAULT NULL,
|
||||
`password` varchar(200) DEFAULT NULL,
|
||||
`banned` tinyint(4) DEFAULT NULL,
|
||||
`is_admin` tinyint(4) DEFAULT NULL,
|
||||
`last_login` bigint(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`account_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `account`
|
||||
--
|
||||
|
||||
LOCK TABLES `account` WRITE;
|
||||
/*!40000 ALTER TABLE `account` DISABLE KEYS */;
|
||||
INSERT INTO `account` VALUES (1,'wesley','$2b$12$dUzSrCFmGJt2WuR2zvDzj.9b3BTjdfIJWGt.hiQ1zskmG2Sjfks2i',0,1,NULL);
|
||||
/*!40000 ALTER TABLE `account` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2020-03-08 15:39:55
|
||||
65
db/wlus_character.sql
Normal file
65
db/wlus_character.sql
Normal file
@@ -0,0 +1,65 @@
|
||||
-- MySQL dump 10.13 Distrib 8.0.16, for Win64 (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: wlus
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 8.0.16
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
SET NAMES utf8 ;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `character`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `character`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
SET character_set_client = utf8mb4 ;
|
||||
CREATE TABLE `character` (
|
||||
`character_id` bigint(20) NOT NULL,
|
||||
`current_name` varchar(45) DEFAULT NULL,
|
||||
`requested_name` varchar(45) DEFAULT NULL,
|
||||
`head_color` int(11) DEFAULT NULL,
|
||||
`head` int(11) DEFAULT NULL,
|
||||
`chest_color` int(11) DEFAULT NULL,
|
||||
`chest` int(11) DEFAULT NULL,
|
||||
`legs` int(11) DEFAULT NULL,
|
||||
`hair_style` int(11) DEFAULT NULL,
|
||||
`hair_color` int(11) DEFAULT NULL,
|
||||
`left_hand` int(11) DEFAULT NULL,
|
||||
`right_hand` int(11) DEFAULT NULL,
|
||||
`eyebrow_style` int(11) DEFAULT NULL,
|
||||
`eye_style` int(11) DEFAULT NULL,
|
||||
`mouth_style` int(11) DEFAULT NULL,
|
||||
`account_id` int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (`character_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `character`
|
||||
--
|
||||
|
||||
LOCK TABLES `character` WRITE;
|
||||
/*!40000 ALTER TABLE `character` DISABLE KEYS */;
|
||||
INSERT INTO `character` VALUES (1152921512385983723,'CrustyRedTortilla','Wesley',0,0,0,9,1,0,96,28552208,28104900,33,1,5,1);
|
||||
/*!40000 ALTER TABLE `character` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2020-03-08 15:39:55
|
||||
57
db/wlus_inventory.sql
Normal file
57
db/wlus_inventory.sql
Normal file
@@ -0,0 +1,57 @@
|
||||
-- MySQL dump 10.13 Distrib 8.0.16, for Win64 (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: wlus
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 8.0.16
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
SET NAMES utf8 ;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `inventory`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `inventory`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
SET character_set_client = utf8mb4 ;
|
||||
CREATE TABLE `inventory` (
|
||||
`object_id` bigint(20) NOT NULL,
|
||||
`lot` int(11) DEFAULT NULL,
|
||||
`slot` int(11) DEFAULT NULL,
|
||||
`equipped` tinyint(4) DEFAULT NULL,
|
||||
`linked` tinyint(4) DEFAULT NULL,
|
||||
`quantity` int(11) DEFAULT NULL,
|
||||
`player_id` bigint(20) DEFAULT NULL,
|
||||
`proxy_items` varchar(500) DEFAULT NULL,
|
||||
PRIMARY KEY (`object_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `inventory`
|
||||
--
|
||||
|
||||
LOCK TABLES `inventory` WRITE;
|
||||
/*!40000 ALTER TABLE `inventory` DISABLE KEYS */;
|
||||
INSERT INTO `inventory` VALUES (537010342,2519,0,1,1,1,1152921512385983723,NULL),(625381859,4057,1,1,1,1,1152921512385983723,NULL);
|
||||
/*!40000 ALTER TABLE `inventory` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2020-03-08 15:39:55
|
||||
57
db/wlus_session.sql
Normal file
57
db/wlus_session.sql
Normal file
@@ -0,0 +1,57 @@
|
||||
-- MySQL dump 10.13 Distrib 8.0.16, for Win64 (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: wlus
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 8.0.16
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
SET NAMES utf8 ;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `session`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `session`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
SET character_set_client = utf8mb4 ;
|
||||
CREATE TABLE `session` (
|
||||
`session_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(45) DEFAULT NULL,
|
||||
`current_player` bigint(20) DEFAULT NULL,
|
||||
`current_zone` int(11) DEFAULT NULL,
|
||||
`current_instance` int(11) DEFAULT NULL,
|
||||
`user_key` varchar(45) DEFAULT NULL,
|
||||
`ip_address` varchar(45) DEFAULT NULL,
|
||||
`login_timestamp` bigint(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`session_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `session`
|
||||
--
|
||||
|
||||
LOCK TABLES `session` WRITE;
|
||||
/*!40000 ALTER TABLE `session` DISABLE KEYS */;
|
||||
INSERT INTO `session` VALUES (57,'wesley',NULL,NULL,NULL,'1cea7c36-fd8a-4792-a','(\'127.0.0.1\', 57170)',1581811925);
|
||||
/*!40000 ALTER TABLE `session` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2020-03-08 15:39:55
|
||||
99
game.py
99
game.py
@@ -1,99 +0,0 @@
|
||||
import typing
|
||||
import game_types
|
||||
import ctypes
|
||||
import threading
|
||||
import random
|
||||
import time
|
||||
|
||||
'''
|
||||
The Game class is the parent of all other objects in the game.
|
||||
Things should ALWAYS be implmented through either a service or a script
|
||||
'''
|
||||
|
||||
|
||||
class Game(game_types.BaseObject):
|
||||
def __init__(self):
|
||||
super().__init__(None)
|
||||
self._name = "Game"
|
||||
self._services = []
|
||||
self._config : dict = {}
|
||||
self._event_handlers = {}
|
||||
self._event_wait_list = {}
|
||||
self._console_command_handlers = {}
|
||||
|
||||
def wait_for_event(self, event_id : str, condition : str):
|
||||
if(event_id not in self._event_wait_list):
|
||||
self._event_wait_list[event_id] = {"condition":condition, "state":False}
|
||||
while self._event_wait_list[event_id]["state"] == False:
|
||||
time.sleep(.0001)
|
||||
|
||||
def start(self):
|
||||
for service in self._services:
|
||||
service.initialize()
|
||||
self.trigger_event("GameStarted")
|
||||
console_thread = threading.Thread(target =self._console_loop)
|
||||
console_thread.start()
|
||||
|
||||
def register_console_command(self, command, handler):
|
||||
self._console_command_handlers[command.upper()] = handler
|
||||
|
||||
def _console_loop(self):
|
||||
while True:
|
||||
input_str = input()
|
||||
args = input_str.rstrip().split(" ")
|
||||
if(args[0].upper() in self._console_command_handlers):
|
||||
self._console_command_handlers[args[0].upper()](args[1:])
|
||||
else:
|
||||
print("Unknown Console Command")
|
||||
|
||||
def generate_object_id(self):
|
||||
#TODO: You need to figure out the correct way to generate object ids you dumb dumb
|
||||
id = random.randint(100000000000000000, 999999999999999999)
|
||||
return id
|
||||
|
||||
def register_service(self, service):
|
||||
self._services.append(service)
|
||||
self.trigger_event("ServiceRegistered", args=(service,), debug=False)
|
||||
|
||||
def register_event_handler(self, event_id : str, threaded : bool = True):
|
||||
def register_handler(handler):
|
||||
self._event_handlers[handler] = [event_id, threaded]
|
||||
return register_handler
|
||||
|
||||
def trigger_event(self, event_id, args : typing.Tuple =(), debug : bool = False):
|
||||
if(event_id in self._event_wait_list):
|
||||
if(eval(self._event_wait_list[event_id]["condition"]) == True):
|
||||
self._event_wait_list[event_id]["state"] = True
|
||||
handler_activated = False
|
||||
for handler in self._event_handlers:
|
||||
if(self._event_handlers[handler][0] == event_id):
|
||||
if(self._event_handlers[handler][1] == True):
|
||||
handler_thread = threading.Thread(target=handler, args=args)
|
||||
handler_thread.start()
|
||||
else:
|
||||
handler(*args)
|
||||
handler_activated = True
|
||||
if(handler_activated != True and debug):
|
||||
print("{} Had No Handler!".format(event_id))
|
||||
|
||||
|
||||
def get_service(self, service_name : str):
|
||||
for service in self._services:
|
||||
if(service.get_name() == service_name):
|
||||
return service
|
||||
return None
|
||||
|
||||
def set_config(self, key : str, value : typing.Any):
|
||||
self._config[key.upper()] = value
|
||||
|
||||
def remove_config(self, key : str):
|
||||
del self._config[key.upper()]
|
||||
|
||||
def get_pyobject(self, id):
|
||||
return ctypes.cast(id, ctypes.py_object).value
|
||||
|
||||
def get_config(self, key : str):
|
||||
if(key.upper() in self._config):
|
||||
return self._config[key.upper()]
|
||||
else:
|
||||
return None
|
||||
154
game_enums.py
154
game_enums.py
@@ -1,154 +0,0 @@
|
||||
from enum import *
|
||||
import game_types
|
||||
|
||||
class PacketHeaderEnum(Enum):
|
||||
HANDSHAKE = b'S\x00\x00\x00\x00\x00\x00\x00'
|
||||
DISCONNECT_NOTIFY = b"S\x00\x00\x01\x00\x00\x00\x00"
|
||||
CLIENT_LOGIN_INFO = b'S\x01\x00\x00\x00\x00\x00\x00'
|
||||
LOGIN_RESPONSE = b'S\x05\x00\x00\x00\x00\x00\x00'
|
||||
CLIENT_USER_SESSION_INFO = b"S\x04\x00\x01\x00\x00\x00\x00"
|
||||
CLIENT_MINIFIGURE_LIST_REQUEST = b"S\x04\x00\x02\x00\x00\x00\x00"
|
||||
MINIFIGURE_LIST = b"S\x05\x00\x06\x00\x00\x00\x00"
|
||||
CLIENT_MINIFIGURE_CREATE_REQUEST = b"S\x04\x00\x03\x00\x00\x00\x00"
|
||||
MINIFIGURE_CREATION_RESPONSE = b"S\x05\x00\x08\x00\x00\x00\x00"
|
||||
CLIENT_DELETE_MINIFIGURE_REQUEST = b'S\x04\x00\x06\x00\x00\x00\x00'
|
||||
WORLD_INFO = b'S\x05\x00\x02\x00\x00\x00\x00'
|
||||
CLINET_ENTER_WORLD = b'S\x04\x00\x04\x00\x00\x00\x00'
|
||||
CLIENT_LOAD_COMPLETE = b'S\x04\x00\x13\x00\x00\x00\x00'
|
||||
DETAILED_USER_INFO = b'S\x05\x00\x04\x00\x00\x00\x00'
|
||||
ROUTED_PACKET = b'S\x04\x00\x15\x00\x00\x00\x00'
|
||||
CLIENT_GAME_MESSAGE = b'S\x04\x00\x05\x00\x00\x00\x00'
|
||||
SERVER_GAME_MESSAGE = b'S\x05\x00\x0c\x00\x00\x00\x00'
|
||||
CLIENT_POSITION_UPDATES = b'S\x04\x00\x16\x00\x00\x00\x00'
|
||||
CLIENT_CHAT_MESSAGE = b'S\x04\x00\x0e\x00\x00\x00\x00'
|
||||
CLIENT_WHITELIST_REQUEST = b'S\x04\x00\x19\x00\x00\x00\x00'
|
||||
CHAT_MODERATION_RESPONSE = b'S\x05\x00\x3b\x00\x00\x00\x00'
|
||||
|
||||
class ReplicaTypes(IntEnum):
|
||||
CONSTRUCTION = 0
|
||||
SERIALIZATION = 1
|
||||
|
||||
class LoginResponseEnum(IntEnum):
|
||||
SUCCESS = 0x01
|
||||
BANNED = 0x02
|
||||
INVALID_PERM = 0x03
|
||||
INVALID_LOGIN_INFO = 0x06
|
||||
ACCOUNT_LOCKED = 0x07
|
||||
|
||||
class DisconnectionReasonEnum(IntEnum):
|
||||
UNKNOWN_ERROR = 0x00
|
||||
DUPLICATE_LOGIN = 0x04
|
||||
SERVER_SHUTDOWN = 0x05
|
||||
SERVER_CANNOT_LOAD_MAP = 0x06
|
||||
INVALID_SESSION_KEY = 0x07
|
||||
CHARACTER_NOT_FOUND = 0x09
|
||||
CHARACTER_CORRUPTION = 0x0a
|
||||
KICKED = 0x0b
|
||||
|
||||
class ObjectTypes(IntEnum):
|
||||
UNDEFINED = 0
|
||||
SPAWNED = 1
|
||||
LOCAL = 2
|
||||
GLOBAL = 3
|
||||
STATIC = 4
|
||||
|
||||
class ItemLOTs(IntEnum):
|
||||
SHIRT_BRIGHT_RED = 4049
|
||||
SHIRT_BRIGHT_BLUE = 4083
|
||||
SHIRT_BRIGHT_YELLOW = 4117
|
||||
SHIRT_DARK_GREEN = 4151
|
||||
SHIRT_BRIGHT_ORANGE = 4185
|
||||
SHIRT_BLACK = 4219
|
||||
SHIRT_DARK_STONE_GRAY = 4253
|
||||
SHIRT_MEDIUM_STONE_GRAY = 4287
|
||||
SHIRT_REDDISH_BROWN = 4321
|
||||
SHIRT_WHITE = 4355
|
||||
SHIRT_MEDIUM_BLUE = 4389
|
||||
SHIRT_DARK_RED = 4423
|
||||
SHIRT_EARTH_BLUE = 4457
|
||||
SHIRT_EARTH_GREEN = 4491
|
||||
SHIRT_BRICK_YELLOW = 4525
|
||||
SHIRT_SAND_BLUE = 4559
|
||||
SHIRT_SAND_GREEN = 4593
|
||||
|
||||
PANTS_BRIGHT_RED = 2508
|
||||
PANTS_BRIGHT_ORANGE = 2509
|
||||
PANTS_BRICK_YELLOW = 2511
|
||||
PANTS_MEDIUM_BLUE = 2513
|
||||
PANTS_SAND_GREEN = 2514
|
||||
PANTS_DARK_GREEN = 2515
|
||||
PANTS_EARTH_GREEN = 2516
|
||||
PANTS_EARTH_BLUE = 2517
|
||||
PANTS_BRIGHT_BLUE = 2519
|
||||
PANTS_SAND_BLUE = 2520
|
||||
PANTS_DARK_STONE_GRAY = 2521
|
||||
PANTS_MEDIUM_STONE_GRAY = 2522
|
||||
PANTS_WHITE = 2523
|
||||
PANTS_BLACK = 2524
|
||||
PANTS_REDDISH_BROWN = 2526
|
||||
PANTS_DARK_RED = 2527
|
||||
|
||||
|
||||
class DeathType(Enum):
|
||||
DEATH_WATER = "death_water"
|
||||
SHARK = "shark-death"
|
||||
BIG_SHARK = "big-shark-death"
|
||||
ELECTRO_SHOCK = "electro-shock-death"
|
||||
|
||||
|
||||
class GameMessages(IntEnum):
|
||||
SERVER_DONE_LOADING_OBJECTS = 1642
|
||||
PLAYER_READY = 509
|
||||
READY_FOR_UPDATES = 888
|
||||
PLAY_FX_EFFECT = 154
|
||||
STOP_FX_EFFECT = 155
|
||||
PARSE_CHAT_MSG = 850
|
||||
SET_JETPACK_MODE = 561
|
||||
ADD_SKILL = 127
|
||||
REMOVE_SKILL = 128
|
||||
PLAYER_LOADED = 505
|
||||
ADD_ITEM_TO_INVENTORY_CLIENT_SYNC = 227
|
||||
EQUIP_INVENTORY = 231
|
||||
UNEQUIP_INVENTORY = 233
|
||||
RESYNC_EQUIPMENT = 1238
|
||||
START_SKILL = 119
|
||||
ECHO_START_SKILL = 118
|
||||
ECHO_SYNC_SKILL = 1144
|
||||
SYNC_SKILL = 1145
|
||||
DIE = 37
|
||||
REQUEST_DIE = 38
|
||||
PLAYER_REQUEST_SMASH = 1202
|
||||
RESSURECT_REQUEST = 159
|
||||
RESSURECT = 160
|
||||
|
||||
class ItemTypes(IntEnum):
|
||||
INVALID = 0
|
||||
BRICK = 1
|
||||
HAT = 2
|
||||
HAIR = 3
|
||||
NECK = 4
|
||||
LEFT_HAND = 5
|
||||
RIGHT_HAND = 6
|
||||
LEGS = 7
|
||||
LEFT_TRINKET = 8
|
||||
RIGHT_TRINKET = 9
|
||||
BEHAVIOR = 10
|
||||
PROPERTY = 11
|
||||
MODEL = 12
|
||||
COLLECTABLE = 13
|
||||
CONSUMABLE = 14
|
||||
CHEST = 15
|
||||
EGG = 16
|
||||
PET_FOOD = 17
|
||||
QUEST_OBJECT = 18
|
||||
PET_INVENTORY_ITEM = 19
|
||||
t20_PACKAGE = 20
|
||||
LOOT_MODEL = 21
|
||||
VEHICLE = 22
|
||||
|
||||
class MinifigureCreationResponseEnum(IntEnum):
|
||||
SUCCESS = 0x00
|
||||
ID_NOT_WORKING = 0x01
|
||||
NAME_NOT_ALLOWED = 0x02
|
||||
PREDEFINED_NAME_IN_USE = 0x03
|
||||
NAME_IN_USE = 0x04
|
||||
42
game_math.py
42
game_math.py
@@ -1,42 +0,0 @@
|
||||
import math
|
||||
import game_types
|
||||
'''import gem, supposedly this library is good for 3D math but I have no idea how to work it'''
|
||||
|
||||
|
||||
def quat_to_euler(quaternion : game_types.Vector4) -> game_types.Vector3:
|
||||
x = quaternion.X
|
||||
y = quaternion.Y
|
||||
z = quaternion.Z
|
||||
w = quaternion.W
|
||||
|
||||
y_sqr = y * y
|
||||
|
||||
t0 = +2.0 * (w * x + y * z)
|
||||
t1 = +1.0 - 2.0 * (x * x + y_sqr)
|
||||
X = math.degrees(math.atan2(t0, t1))
|
||||
|
||||
t2 = +2.0 * (w * y - z * x)
|
||||
t2 = +1.0 if t2 > +1.0 else t2
|
||||
t2 = -1.0 if t2 < -1.0 else t2
|
||||
Y = math.degrees(math.asin(t2))
|
||||
|
||||
t3 = +2.0 * (w * z + x * y)
|
||||
t4 = +1.0 - 2.0 * (y_sqr + z * z)
|
||||
Z = math.degrees(math.atan2(t3, t4))
|
||||
|
||||
return game_types.Vector3(float(X), float(Y), float(Z))
|
||||
|
||||
|
||||
#TODO: Fix
|
||||
def front_vector(rotation : game_types.Vector4, position : game_types.Vector3, magnitude : float = 1.0) -> game_types.Vector3:
|
||||
|
||||
direction = game_types.Vector3(2 * (rotation.X * rotation.Z - rotation.W * rotation.Y),
|
||||
2 * (rotation.Y * rotation.Z - rotation.W * rotation.X),
|
||||
1 - 2 * (rotation.X * rotation.X + rotation.Y * rotation.Y))
|
||||
return (position + direction * magnitude)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,268 +0,0 @@
|
||||
import services
|
||||
from pyraknet.bitstream import *
|
||||
import game_enums
|
||||
import game_types
|
||||
import copy
|
||||
|
||||
|
||||
class GameMessageService(services.GameService):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Game Message"
|
||||
global game
|
||||
game = self.get_parent()
|
||||
|
||||
def initialize(self):
|
||||
self.world_server = game.get_service("World Server").server
|
||||
super().initialize()
|
||||
|
||||
def init_game_msg(self, stream: WriteStream, object_id: int, message_id: int):
|
||||
stream.write(game_enums.PacketHeaderEnum.SERVER_GAME_MESSAGE.value)
|
||||
stream.write(c_longlong(object_id))
|
||||
stream.write(c_ushort(message_id))
|
||||
|
||||
def send_game_msg(self, object_id, msg_id, recipients: list):
|
||||
msg = WriteStream()
|
||||
msg.write(game_enums.PacketHeaderEnum.SERVER_GAME_MESSAGE.value)
|
||||
msg.write(c_longlong(object_id))
|
||||
msg.write(c_ushort(msg_id))
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
def play_fx_effect(self, object_id : int, recipients : list, effect_id : int, effect_type : str, scale : float, name : str, priority : float = 1.0, secondary : int = -1, serialize : bool = True):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.PLAY_FX_EFFECT.value)
|
||||
|
||||
msg.write(c_bit(effect_id != -1))
|
||||
if(effect_id != -1):
|
||||
msg.write(c_long(effect_id))
|
||||
|
||||
msg.write(effect_type, length_type=c_ulong)
|
||||
|
||||
msg.write(c_bit(scale != 1.0))
|
||||
if(scale != 1.0):
|
||||
msg.write(c_float(scale))
|
||||
|
||||
msg.write(game_types.String(name, length_type=c_ulong))
|
||||
|
||||
msg.write(c_bit(priority != 1.0))
|
||||
if(priority != 1.0):
|
||||
msg.write(c_float(priority))
|
||||
|
||||
msg.write(c_bit(secondary > -1))
|
||||
if(secondary > -1):
|
||||
msg.write(c_longlong(secondary))
|
||||
|
||||
msg.write(c_bit(serialize))
|
||||
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
def stop_fx_effect(self, object_id : int, recipients : list, kill_immediately : bool, name : str):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.STOP_FX_EFFECT.value)
|
||||
|
||||
msg.write(c_bit(kill_immediately))
|
||||
msg.write(game_types.String(name, length_type=c_ulong))
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
def add_item_to_inventory_client_sync(self, object_id : int, recipients : list, lot : int, item_id : int, slot_id : int, bound: bool = False, bound_on_equip : bool = False, bound_on_pickup : bool = False, loot_type_source : int = 0, extra_info : str = "", sub_key : int = 0, inventory_type : int = 0, item_count : int = 1, items_total : int = 0, flying_loot_pos : game_types.Vector3 = game_types.Vector3(), show_flying_loot : bool = True):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.ADD_ITEM_TO_INVENTORY_CLIENT_SYNC.value)
|
||||
|
||||
msg.write(c_bit(bound))
|
||||
msg.write(c_bit(bound_on_equip))
|
||||
msg.write(c_bit(bound_on_pickup))
|
||||
|
||||
msg.write(c_bit(loot_type_source != 0))
|
||||
if(loot_type_source != 0):
|
||||
msg.write(c_int(loot_type_source))
|
||||
|
||||
msg.write(extra_info, length_type=c_ulong)
|
||||
msg.write(c_ulong(lot))
|
||||
|
||||
msg.write(c_bit(sub_key != 0))
|
||||
if(sub_key != 0):
|
||||
msg.write(c_longlong(sub_key))
|
||||
|
||||
msg.write(c_bit(inventory_type != 0))
|
||||
if(inventory_type != 0):
|
||||
msg.write(c_int(inventory_type))
|
||||
|
||||
msg.write(c_bit(item_count != 1))
|
||||
if(item_count != 1):
|
||||
msg.write(c_ulong(item_count))
|
||||
|
||||
msg.write(c_bit(items_total != 0))
|
||||
if(items_total != 0):
|
||||
msg.write(c_ulong(items_total))
|
||||
|
||||
msg.write(c_longlong(item_id))
|
||||
|
||||
msg.write(c_float(flying_loot_pos.X))
|
||||
msg.write(c_float(flying_loot_pos.Y))
|
||||
msg.write(c_float(flying_loot_pos.Z))
|
||||
|
||||
msg.write(c_bit(show_flying_loot))
|
||||
|
||||
msg.write(c_int(slot_id))
|
||||
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
def remove_skill(self, object_id : int, recipients : list, skill_id : int, from_skill_set : bool = False):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.REMOVE_SKILL.value)
|
||||
|
||||
msg.write(c_bit(from_skill_set))
|
||||
|
||||
msg.write(c_int(skill_id))
|
||||
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
|
||||
def ressurect(self, object_id : int, recipients : list, rez_immediately : bool = False):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.RESSURECT.value)
|
||||
|
||||
msg.write(c_bit(rez_immediately))
|
||||
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
def die(self, object_id : int, recipients : list, killer_id : int = 0, client_death : bool = True, spawn_loot : bool = False, death_type : str = game_enums.DeathType.ELECTRO_SHOCK.value, dir_rel_xz : float = 0, dir_rel_y : float = 0, dir_rel_force = 0, loot_owner_id : int = 0):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.DIE.value)
|
||||
|
||||
msg.write(c_bit(client_death))
|
||||
|
||||
msg.write(c_bit(spawn_loot))
|
||||
|
||||
msg.write(death_type, length_type=c_ulong)
|
||||
|
||||
msg.write(c_float(dir_rel_xz))
|
||||
|
||||
msg.write(c_float(dir_rel_y))
|
||||
|
||||
msg.write(c_float(dir_rel_force))
|
||||
|
||||
msg.write(c_bit(False))
|
||||
|
||||
if(killer_id > 0):
|
||||
msg.write(c_longlong(killer_id))
|
||||
else:
|
||||
msg.write(c_longlong(object_id))
|
||||
|
||||
msg.write(c_bit(loot_owner_id != 0 and spawn_loot))
|
||||
if(loot_owner_id != 0 and spawn_loot):
|
||||
msg.write(c_longlong(loot_owner_id))
|
||||
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
def echo_start_skill(self, object_id : int, recipients : list, skill_id : int, bit_stream:str, optional_originator : int, used_mouse : bool = False, caster_latency : float = 0.0, cast_type : int = 0, last_clicked_pos : game_types.Vector3 = game_types.Vector3(), optional_target_id : int = 0, originator_rot : game_types.Vector4 = game_types.Vector4(), ui_skill_handle : int = 0):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.ECHO_START_SKILL.value)
|
||||
|
||||
msg.write(c_bit(used_mouse))
|
||||
|
||||
msg.write(c_bit(caster_latency != 0.0))
|
||||
if(caster_latency != 0.0):
|
||||
msg.write(c_float(caster_latency))
|
||||
|
||||
msg.write(c_bit(cast_type != 0))
|
||||
if(cast_type != 0):
|
||||
msg.write(c_int(cast_type))
|
||||
|
||||
msg.write(c_bit(last_clicked_pos != game_types.Vector3()))
|
||||
if(last_clicked_pos != game_types.Vector3()):
|
||||
msg.write(c_float(last_clicked_pos.X))
|
||||
msg.write(c_float(last_clicked_pos.Y))
|
||||
msg.write(c_float(last_clicked_pos.Z))
|
||||
|
||||
msg.write(c_longlong(optional_originator))
|
||||
|
||||
msg.write(c_bit(optional_target_id != 0))
|
||||
if(optional_target_id != 0):
|
||||
msg.write(c_longlong(optional_target_id))
|
||||
|
||||
msg.write(c_bit(originator_rot != game_types.Vector4()))
|
||||
if(originator_rot != game_types.Vector4()):
|
||||
msg.write(c_float(originator_rot.X))
|
||||
msg.write(c_float(originator_rot.Y))
|
||||
msg.write(c_float(originator_rot.Z))
|
||||
msg.write(c_float(originator_rot.W))
|
||||
|
||||
msg.write(game_types.String(bit_stream, length_type=c_ulong))
|
||||
|
||||
msg.write(c_ulong(skill_id))
|
||||
|
||||
msg.write(c_bit(ui_skill_handle != 0))
|
||||
if(ui_skill_handle != 0):
|
||||
msg.write(c_ulong(0))
|
||||
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
def add_skill(self, object_id : int, recipients : list, skill_id : int, ai_combat_weight : int = 0, from_skill_set : bool = False, cast_type : int = 0, time_secs : float = -1.0, times_can_cast : int = -1, slot_id : int = -1, temporary : bool = True):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.ADD_SKILL.value)
|
||||
|
||||
msg.write(c_bit(ai_combat_weight != 0 and ai_combat_weight is not None))
|
||||
if(ai_combat_weight != 0 and ai_combat_weight is not None):
|
||||
msg.write(c_int(ai_combat_weight))
|
||||
|
||||
msg.write(c_bit(from_skill_set))
|
||||
|
||||
msg.write(c_bit(cast_type != 0))
|
||||
if(cast_type != 0):
|
||||
msg.write(c_int(cast_type))
|
||||
|
||||
msg.write(c_bit(time_secs > -1.0))
|
||||
if(time_secs > -1.0):
|
||||
msg.write(c_float(time_secs))
|
||||
|
||||
msg.write(c_bit(times_can_cast > -1))
|
||||
if(times_can_cast > -1):
|
||||
msg.write(c_int(times_can_cast))
|
||||
|
||||
msg.write(c_ulong(skill_id))
|
||||
|
||||
msg.write(c_bit(slot_id > -1))
|
||||
if(slot_id > -1):
|
||||
msg.write(c_int(slot_id))
|
||||
|
||||
msg.write(c_bit(temporary))
|
||||
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
def set_jetpack_mode(self, object_id : int, recipients : list, bypass_checks : bool = True, hover : bool = False, use : bool = False, effect_id : int = -1, air_speed : int = 10, max_air_speed : int = 15, vert_vel : int = 1, warning_effect_id : int = -1):
|
||||
msg = WriteStream()
|
||||
self.init_game_msg(msg, object_id, game_enums.GameMessages.SET_JETPACK_MODE.value)
|
||||
|
||||
msg.write(c_bit(bypass_checks))
|
||||
msg.write(c_bit(hover))
|
||||
msg.write(c_bit(use))
|
||||
|
||||
msg.write(c_bit(effect_id != -1))
|
||||
if(effect_id != -1):
|
||||
msg.write(c_int(effect_id))
|
||||
|
||||
msg.write(c_bit(air_speed != 10))
|
||||
if(air_speed != 10):
|
||||
msg.write(c_float(air_speed))
|
||||
|
||||
msg.write(c_bit(max_air_speed != 15))
|
||||
if(max_air_speed != 15):
|
||||
msg.write(c_float(max_air_speed))
|
||||
|
||||
msg.write(c_bit(vert_vel != 1))
|
||||
if(vert_vel != 1):
|
||||
msg.write(c_float(vert_vel))
|
||||
|
||||
msg.write(c_bit(warning_effect_id != -1))
|
||||
if(warning_effect_id != -1):
|
||||
msg.write(c_int(0))
|
||||
|
||||
self.world_server.send(msg, recipients)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import game_types
|
||||
import components
|
||||
import game_enums
|
||||
|
||||
'''
|
||||
GameObjects are objects placed inside scenes
|
||||
'''
|
||||
|
||||
class GameObject(game_types.BaseObject):
|
||||
def __init__(self, parent, zone, object_id : int = None, name : str = "GameObject"):
|
||||
super().__init__(parent)
|
||||
self._name = name
|
||||
self._components = []
|
||||
self.zone = zone
|
||||
global game
|
||||
game = zone.get_parent().get_parent().get_parent()
|
||||
if(object_id is None):
|
||||
raise Exception("Need Object ID!")
|
||||
self._object_id = object_id
|
||||
|
||||
def add_component(self, component):
|
||||
self._components.append(component)
|
||||
|
||||
def get_component(self, component):
|
||||
for object_component in self._components:
|
||||
if(isinstance(object_component, component)):
|
||||
return object_component
|
||||
return None
|
||||
|
||||
def get_object_id(self):
|
||||
return self._object_id
|
||||
|
||||
def update(self):
|
||||
self.zone.update(self)
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
|
||||
def has_component(self, component):
|
||||
for object_component in self._components:
|
||||
if(isinstance(object_component, component)):
|
||||
return True
|
||||
return False
|
||||
|
||||
class ReplicaObject(GameObject):
|
||||
def __init__(self, parent, zone, config : dict):
|
||||
object_id = None
|
||||
name = ""
|
||||
if("object_id" in config):
|
||||
object_id = config["object_id"]
|
||||
else:
|
||||
object_id = zone.get_parent().get_parent().generate_object_id()
|
||||
if ("name" in config):
|
||||
name = config["name"]
|
||||
super().__init__(parent, zone, object_id, name)
|
||||
self.object_type = game_enums.ObjectTypes.UNDEFINED.value
|
||||
self.lot = 0
|
||||
self.spawner_id = None
|
||||
self.spawner_node_id = None
|
||||
self.world_state = None
|
||||
self.gm_level = None
|
||||
self.json = {}
|
||||
if("object_type" in config):
|
||||
self.object_type = int(config["object_type"])
|
||||
if("json" in config):
|
||||
self.json = config["json"]
|
||||
if("gm_level" in config):
|
||||
self.gm_level = config["gm_level"]
|
||||
if("world_state" in config):
|
||||
self.world_state = config["world_state"]
|
||||
if("lot" in config):
|
||||
self.lot = config["lot"]
|
||||
if(self.lot == 1):
|
||||
self.player_sync = True
|
||||
if("spawner_id" in config):
|
||||
self.spawner_id = config["spawner_id"]
|
||||
if("spawner_node_id" in config):
|
||||
self.spawner_node_id = config["spawner_node_id"]
|
||||
transform = components.Transform(self)
|
||||
self.add_component(transform)
|
||||
|
||||
def on_destruction(self):
|
||||
for component in self._components:
|
||||
if (hasattr(component, "player_sync_thread")):
|
||||
if(self.lot == 1):
|
||||
self.player_sync = False
|
||||
component.player_sync_thread.stop()
|
||||
@@ -1,61 +0,0 @@
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
import scripts
|
||||
import json
|
||||
import game_types
|
||||
import random
|
||||
|
||||
class Main(scripts.Script):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent, "Console Commands")
|
||||
global game
|
||||
game = self.get_parent()
|
||||
|
||||
def run(self):
|
||||
game.register_console_command("Register", self.register_handler)
|
||||
game.register_console_command("ImportLUZ", self.import_handler)
|
||||
|
||||
|
||||
def import_handler(self, args):
|
||||
if(len(args) == 1):
|
||||
zone = int(args[0])
|
||||
|
||||
file_path = input("JSON Directory: ")
|
||||
if(file_path == ''):
|
||||
return
|
||||
|
||||
lvl_files = []
|
||||
|
||||
luz = open(file_path, "r")
|
||||
luz_json = json.loads(luz.read())
|
||||
folder = '\\'.join(file_path.split('\\')[0:-1])
|
||||
for scene in luz_json["scenes"]:
|
||||
lvl_files.append({"scene_id":scene["id"], "path":folder+"/"+scene["filename"]+".json"})
|
||||
|
||||
for lvl in lvl_files:
|
||||
file = open(lvl["path"], "r")
|
||||
json_obj = json.loads(file.read())
|
||||
|
||||
database = game.get_service("Database")
|
||||
server_db = database.server_db
|
||||
c = server_db.connection.cursor()
|
||||
|
||||
for chunk in json_obj["chunks"]:
|
||||
if(chunk["_type"] == 2001):
|
||||
object_id = random.randint(100000000000000000, 999999999999900000)
|
||||
for game_object in chunk["objects"]:
|
||||
if("spawntemplate" in game_object["settings"]):
|
||||
object_id += 1
|
||||
config = {'lot':game_object["settings"]["spawntemplate"], 'spawner_id':game_object["id"],
|
||||
'position': str(game_types.Vector3(game_object['pos']['pos']['x'], game_object['pos']['pos']['y'], game_object['pos']['pos']['z'])),
|
||||
'rotation': str(game_types.Vector4(game_object['pos']['rot']['x'], game_object['pos']['rot']['y'], game_object['pos']['rot']['z'], game_object['pos']['rot']['w'])),
|
||||
'scale':game_object["scale"], 'spawner_node_id':0, 'object_id':object_id, 'scene':lvl["scene_id"], 'object_type':1}
|
||||
c.execute("INSERT INTO ZoneObjects (zone_id, replica_config) VALUES (?, ?)", (zone, json.dumps(config)))
|
||||
print("Imported Object {} To DB".format(config["object_id"]))
|
||||
|
||||
|
||||
def register_handler(self, args):
|
||||
username = args[0]
|
||||
password = args[1]
|
||||
auth_service = game.get_service("Auth Server")
|
||||
auth_service.register_account(username, password)
|
||||
@@ -1,29 +0,0 @@
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
import scripts
|
||||
import time
|
||||
|
||||
'''Big thanks to Tracer (the other Wesley), for providing me with the function from JALUS that does this thing'''
|
||||
|
||||
class Main(scripts.Script):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent, "Jonny's Dumb Effect")
|
||||
global game
|
||||
game = self.get_parent()
|
||||
|
||||
def run(self):
|
||||
game.wait_for_event("ServiceInitialized", '''args[0].get_name() == "World"''')
|
||||
game_message_service = game.get_service("Game Message")
|
||||
while True:
|
||||
if (game.get_config("jonnys_dumb_effect") is not None and game.get_config("jonnys_dumb_effect") == True):
|
||||
zones = game.get_service("World").get_zones()
|
||||
for zone in zones:
|
||||
players = zone.get_players()
|
||||
for player_id in players:
|
||||
game_message_service.stop_fx_effect(player_id, zone.get_connections(), False, "wisp_hands")
|
||||
game_message_service.play_fx_effect(player_id, zone.get_connections(), 1573, "on-anim", 1.0, "wisp_hands")
|
||||
|
||||
game_message_service.stop_fx_effect(player_id, zone.get_connections(), False, "wisp_hands_left")
|
||||
game_message_service.play_fx_effect(player_id, zone.get_connections(), 1579, "on-anim", 1.0, "wisp_hands_left")
|
||||
|
||||
time.sleep(.5)
|
||||
@@ -1,90 +0,0 @@
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
import scripts
|
||||
import game_types
|
||||
from pyraknet.bitstream import ReadStream
|
||||
import random
|
||||
|
||||
|
||||
#Zones should be in order of loading priority?
|
||||
zone_checksums = {1200: 0xda1e6b30,
|
||||
1000: 0x20b8087c,
|
||||
1001: 0x26680a3c,
|
||||
1100: 0x49525511,
|
||||
#1101: 0x538214e2,
|
||||
1102: 0x0fd403da,
|
||||
1150: 0x0fd403da,
|
||||
1151: 0x0a890303,
|
||||
1201: 0x476e1330,
|
||||
#1203: 0x10fc0502,
|
||||
1204: 0x07d40258,
|
||||
1250: 0x058d0191,
|
||||
1251: 0x094f045d,
|
||||
1300: 0x12eac290,
|
||||
1302: 0x0b7702ef,
|
||||
#9999: 0x13600646 #Frostburgh
|
||||
#1303: 0x152e078a,
|
||||
1350: 0x04b6015c,
|
||||
1400: 0x8519760d,
|
||||
1402: 0x02f50187,
|
||||
#1403: 0x81850f4e,
|
||||
1450: 0x03f00126,
|
||||
1600: 0x07c202ee,
|
||||
1601: 0x02320106,
|
||||
1602: 0x0793037f,
|
||||
1603: 0x043b01ad,
|
||||
1604: 0x181507dd,
|
||||
1700: 0x02040138,
|
||||
1800: 0x4b17a399,
|
||||
1900: 0x9e4af43c,
|
||||
2000: 0x4d692c74,
|
||||
2001: 0x09eb00ef}
|
||||
|
||||
class Main(scripts.Script):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent, "on_boot")
|
||||
global game
|
||||
game = self.get_parent()
|
||||
|
||||
def run(self):
|
||||
@game.register_event_handler("GameStarted", threaded=True)
|
||||
def register_zones():
|
||||
world_service = game.get_service("World")
|
||||
cdclient = game.get_service("Database").cdclient_db
|
||||
c = cdclient.connection.cursor()
|
||||
for zone in zone_checksums:
|
||||
json = {}
|
||||
c.execute("SELECT * FROM ZoneTable WHERE zoneID = ?", (zone,))
|
||||
zone_data = c.fetchone()
|
||||
luz_path = f"resources/{zone_data['zoneName']}"
|
||||
name = zone_data["DisplayDescription"]
|
||||
luz_file = open(luz_path, "rb")
|
||||
stream = ReadStream(luz_file.read())
|
||||
luz = game_types.LUZ().deserialize(stream)
|
||||
luz_file.close()
|
||||
spawn_loc = luz.config["spawnpoint_pos"]
|
||||
spawn_rot = luz.config["spawnpoint_rot"]
|
||||
folder = ""
|
||||
path_folders = luz_path.split("/")
|
||||
path_folders = path_folders[:-1]
|
||||
for path_folder in path_folders:
|
||||
folder += path_folder + "/"
|
||||
json["zone_path"] = folder
|
||||
json["scenes"] = luz.config["scenes"]
|
||||
world_service.register_zone(zone_id=zone, load_id=zone, checksum=zone_checksums[zone], spawn_loc=spawn_loc, spawn_rot=spawn_rot, name=name, json = json)
|
||||
zone = world_service.get_zone_by_id(zone)
|
||||
start_id = random.randint(100000000000000000, 999999999999900000)
|
||||
for scene in luz.config["scenes"]:
|
||||
folders = "/".join(zone_data['zoneName'].split('/')[:-1])
|
||||
scene_path = f"resources/{folders}/{scene['filename']}"
|
||||
lvl_file = open(scene_path, "rb")
|
||||
lvl_stream = ReadStream(lvl_file.read())
|
||||
lvl = game_types.LVL().deserialize(lvl_stream)
|
||||
for object_to_spawn in lvl.config["objects"]:
|
||||
object_to_spawn["object_id"] = start_id
|
||||
zone.create_object(zone, object_to_spawn)
|
||||
start_id+=1
|
||||
print(f"Registered {name}!")
|
||||
game.trigger_event("BootUp_WorldsRegistered")
|
||||
|
||||
|
||||
434
game_types.py
434
game_types.py
@@ -1,434 +0,0 @@
|
||||
import threading
|
||||
import typing
|
||||
from pyraknet.bitstream import *
|
||||
import pyraknet.replicamanager
|
||||
from pyraknet.messages import *
|
||||
from xml.etree import ElementTree
|
||||
import game_enums
|
||||
|
||||
class BaseObject():
|
||||
def __init__(self, parent):
|
||||
self._name = "Name"
|
||||
self._parent = parent
|
||||
self._children = []
|
||||
self._scripts = {}
|
||||
if(isinstance(self._parent, BaseObject)):
|
||||
self._parent._children.append(self)
|
||||
|
||||
def get_name(self):
|
||||
return self._name
|
||||
|
||||
def get_py_id(self):
|
||||
return id(self)
|
||||
|
||||
def set_name(self, name : str):
|
||||
self._name = name
|
||||
|
||||
def add_script(self, script):
|
||||
script_thread = GameThread(target=script.run)
|
||||
script_thread.start()
|
||||
self._scripts[script.get_name()] = script_thread
|
||||
|
||||
def remove_script(self, script_name : str):
|
||||
thread_list = threading.enumerate()
|
||||
for thread in thread_list:
|
||||
if(thread == self._scripts[script_name]):
|
||||
thread.stop()
|
||||
del self._scripts[script_name]
|
||||
return
|
||||
|
||||
def get_parent(self):
|
||||
return self._parent
|
||||
|
||||
def get_children(self):
|
||||
return self._children
|
||||
|
||||
|
||||
class GameThread(threading.Thread):
|
||||
def stop(self):
|
||||
self._tstate_lock = None
|
||||
self._stop()
|
||||
|
||||
class String(Serializable):
|
||||
def __init__(self, data='', allocated_length=None, length_type=None):
|
||||
self.data = data
|
||||
self.allocated_length = allocated_length
|
||||
self.length_type = length_type
|
||||
|
||||
def serialize(self, stream):
|
||||
stream.write(self.data if isinstance(self.data, bytes) else bytes(self.data, 'latin1'),
|
||||
allocated_length=self.allocated_length, length_type=self.length_type)
|
||||
|
||||
def deserialize(self, stream):
|
||||
return stream.read(bytes, allocated_length=self.allocated_length, length_type=self.length_type).decode('latin1')
|
||||
|
||||
|
||||
class LwoObjectID(Serializable):
|
||||
def __init__(self, value : int, type : int = 0):
|
||||
self._val = value
|
||||
self._type = type
|
||||
def serialize(self, stream: "WriteStream"):
|
||||
if(self._type == game_enums.ObjectTypes.SPAWNED.value):
|
||||
stream.write(c_longlong(self._val + (1>>57)))
|
||||
else:
|
||||
stream.write(c_longlong(self._val))
|
||||
def deserialize(cls, stream: "ReadStream"):
|
||||
return stream.read(c_longlong)
|
||||
|
||||
class Vector3(Serializable):
|
||||
def __init__(self, X : float = 0.0, Y : float = 0.0, Z : float = 0.0, str_val:str = None):
|
||||
self.X : float = X
|
||||
self.Y : float = Y
|
||||
self.Z : float = Z
|
||||
if(str_val is not None):
|
||||
vector_list = str_val.split(",")
|
||||
self.X = float(vector_list[0])
|
||||
self.Y = float(vector_list[1])
|
||||
self.Z = float(vector_list[2])
|
||||
|
||||
def __add__(self, other):
|
||||
return Vector3(self.X + other.X,self.Y + other.Y,self.Z + other.Z)
|
||||
|
||||
def __sub__(self, other):
|
||||
return Vector3(self.X - other.X, self.Y - other.Y, self.Z - other.Z)
|
||||
|
||||
def set(self, X : float, Y : float, Z : float):
|
||||
self.X = X
|
||||
self.Y = Y
|
||||
self.Z = Z
|
||||
|
||||
def __str__(self):
|
||||
return "{},{},{}".format(self.X, self.Y, self.Z)
|
||||
|
||||
def __eq__(self, other):
|
||||
if(self.X == other.X and self.Y == other.Y and self.Z == other.Z):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def serialize(self, stream):
|
||||
stream.write(c_float(self.X))
|
||||
stream.write(c_float(self.Y))
|
||||
stream.write(c_float(self.Z))
|
||||
|
||||
def deserialize(self, stream):
|
||||
return Vector3(stream.read(c_float), stream.read(c_float), stream.read(c_float))
|
||||
|
||||
def __mul__(self, other):
|
||||
if(isinstance(other, Vector3)):
|
||||
return Vector3(self.X * other.X, self.Y * other.Y, self.Z * other.Z)
|
||||
elif(isinstance(other, float)):
|
||||
return Vector3(self.X * other, self.Y * other, self.Z * other)
|
||||
elif(isinstance(other, int)):
|
||||
return Vector3(float(self.X * other), float(self.Y * other), float(self.Z * other))
|
||||
else:
|
||||
raise Exception(f"Vector3 cannot be multiplied with type {other.__class__}")
|
||||
|
||||
class LDF(Serializable):
|
||||
def __init__(self):
|
||||
self._keys : list = []
|
||||
def register_key(self, key_name : str, value : any, type : int):
|
||||
self._keys.append([key_name, value, type])
|
||||
def __str__(self):
|
||||
return str(self._keys)
|
||||
def serialize(self, stream):
|
||||
key_num = len(self._keys)
|
||||
stream.write(c_uint(key_num))
|
||||
for key in self._keys:
|
||||
name = key[0]
|
||||
value = key[1]
|
||||
type = key[2]
|
||||
stream.write(c_uint8(len(name) * 2))
|
||||
for char in name:
|
||||
stream.write(char.encode('latin1'))
|
||||
stream.write(b'\0')
|
||||
stream.write(c_ubyte(type))
|
||||
if(type == 0):
|
||||
stream.write(value, length_type=c_uint)
|
||||
elif(type == 1):
|
||||
stream.write(c_int(value))
|
||||
elif(type == 3):
|
||||
stream.write(c_float(value))
|
||||
elif(type == 5):
|
||||
stream.write(c_uint(value))
|
||||
elif(type == 7):
|
||||
stream.write(c_bool(value))
|
||||
elif(type == 8 or type == 9):
|
||||
stream.write(c_int64(value))
|
||||
elif(type == 13):
|
||||
xml_str = bytes(ElementTree.tostring(value))
|
||||
xml_str = b'<?xml version="1.0">' + xml_str
|
||||
stream.write(c_ulong(xml_str.__len__()))
|
||||
stream.write(xml_str)
|
||||
def deserialize(self, stream):
|
||||
return "Not Implemented"
|
||||
|
||||
class Vector4(Serializable):
|
||||
def __init__(self, X : float = 0.0, Y : float = 0.0, Z : float = 0.0, W : float = 0.0, str_val: str = None):
|
||||
self.X : float = X
|
||||
self.Y : float = Y
|
||||
self.Z : float = Z
|
||||
self.W : float = W
|
||||
if(str_val is not None):
|
||||
vector_list = str_val.split(",")
|
||||
self.X = float(vector_list[0])
|
||||
self.Y = float(vector_list[1])
|
||||
self.Z = float(vector_list[2])
|
||||
self.W = float(vector_list[3])
|
||||
|
||||
def __add__(self, other):
|
||||
return Vector4(self.X + other.X, self.Y + other.Y, self.Z + other.Z, self.W + other.W)
|
||||
|
||||
def __sub__(self, other):
|
||||
return Vector4(self.X - other.X, self.Y - other.Y, self.Z - other.Z, self.W - other.W)
|
||||
|
||||
def set(self, X : float, Y : float, Z : float, W : float):
|
||||
self.X = X
|
||||
self.Y = Y
|
||||
self.Z = Z
|
||||
self.W = W
|
||||
|
||||
def __str__(self):
|
||||
return "{},{},{},{}".format(self.X, self.Y, self.Z, self.W)
|
||||
|
||||
def __eq__(self, other):
|
||||
if(self.X == other.X and self.Y == other.Y and self.Z == other.Z, self.W == other.W):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __mul__(self, other):
|
||||
if(isinstance(other, Vector4)):
|
||||
return Vector4(self.X * other.X, self.Y * other.Y, self.Z * other.Z, self.W * other.W)
|
||||
elif(isinstance(other, float)):
|
||||
return Vector4(self.X * other, self.Y * other, self.Z * other, self.W * other)
|
||||
elif(isinstance(other, int)):
|
||||
return Vector4(float(self.X * other), float(self.Y * other), float(self.Z * other), float(self.W * other))
|
||||
else:
|
||||
raise Exception(f"Vector4 cannot be multiplied with type {other.__class__}")
|
||||
|
||||
def serialize(self, stream):
|
||||
stream.write(c_float(self.X))
|
||||
stream.write(c_float(self.Y))
|
||||
stream.write(c_float(self.Z))
|
||||
stream.write(c_float(self.W))
|
||||
|
||||
def deserialize(self, stream):
|
||||
return Vector4(stream.read(c_float), stream.read(c_float), stream.read(c_float), stream.read(c_float))
|
||||
|
||||
|
||||
class LVL(Serializable):
|
||||
def __init__(self, config : dict = None):
|
||||
self.config = config
|
||||
|
||||
def serialize(self, stream):
|
||||
raise NotImplementedError
|
||||
|
||||
def deserialize(self, stream):
|
||||
#Most of this is shamelessly ripped off from PyLUS because I'm very lazy (Sorry Knight d:)
|
||||
config = {}
|
||||
config["objects"] = []
|
||||
header = stream.read(bytes, length=4)
|
||||
stream._read_offset = 0
|
||||
|
||||
if header == b'CHNK':
|
||||
while not stream.all_read():
|
||||
assert stream._read_offset // 8 % 16 == 0
|
||||
start_pos = stream._read_offset // 8
|
||||
assert stream.read(bytes, length=4) == b'CHNK'
|
||||
|
||||
chunk_type = stream.read(c_uint)
|
||||
assert stream.read(c_ushort) == 1
|
||||
assert stream.read(c_ushort) in (1, 2)
|
||||
chunk_len = stream.read(c_uint)
|
||||
data_pos = stream.read(c_uint)
|
||||
stream._read_offset = data_pos * 8
|
||||
assert stream._read_offset // 8 % 16 == 0
|
||||
|
||||
if chunk_type == 1000:
|
||||
pass
|
||||
elif chunk_type == 2000:
|
||||
pass
|
||||
elif chunk_type == 2001:
|
||||
for _ in range(stream.read(c_uint)):
|
||||
objid = stream.read(c_int64)
|
||||
lot = stream.read(c_uint)
|
||||
unknown1 = stream.read(c_uint)
|
||||
unknown2 = stream.read(c_uint)
|
||||
position = Vector3().deserialize(stream)
|
||||
|
||||
rot_w = stream.read(c_float)
|
||||
rot_x = stream.read(c_float)
|
||||
rot_y = stream.read(c_float)
|
||||
rot_z = stream.read(c_float)
|
||||
|
||||
rotation = Vector4(rot_x, rot_y, rot_z, rot_w)
|
||||
scale = stream.read(c_float)
|
||||
object_config = self._read_ldf(stream.read(str, length_type=c_uint))
|
||||
|
||||
assert stream.read(c_uint) == 0
|
||||
|
||||
if('renderDisabled' in object_config):
|
||||
continue
|
||||
|
||||
if lot == 176:
|
||||
lot = int(object_config['spawntemplate'])
|
||||
|
||||
config["objects"].append({"lot":lot, "spawner_id":objid, "position":position, "rotation": rotation, "scale":scale, "object_type":game_enums.ObjectTypes.SPAWNED.value, "spawner_config":object_config})
|
||||
elif chunk_type == 2002:
|
||||
pass
|
||||
|
||||
stream._read_offset = (start_pos + chunk_len) * 8
|
||||
|
||||
return LVL(config)
|
||||
|
||||
def _read_ldf(self, ldf):
|
||||
ldf_dict = {}
|
||||
key_sets = ldf.split("\n")
|
||||
for x in key_sets:
|
||||
key = x.split("=")[0]
|
||||
value = x.split(":")[1]
|
||||
ldf_dict[key] = value
|
||||
return ldf_dict
|
||||
|
||||
class LUZ(Serializable):
|
||||
def __init__(self, config : dict = None):
|
||||
self.config = config
|
||||
|
||||
def serialize(self, stream):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def deserialize(self, stream):
|
||||
config = {}
|
||||
config["version"] = stream.read(c_ulong)
|
||||
if(config["version"] >= 0x24):
|
||||
config["ulong_01"] = stream.read(c_ulong)
|
||||
config["world_id"] = stream.read(c_ulong)
|
||||
if(config["version"] >= 0x26):
|
||||
config["spawnpoint_pos"] = Vector3().deserialize(stream)
|
||||
config["spawnpoint_rot"] = Vector4().deserialize(stream)
|
||||
if(config["version"] < 0x25):
|
||||
scene_count = stream.read(c_uint8)
|
||||
else:
|
||||
scene_count = stream.read(c_ulong)
|
||||
config["scenes"] = []
|
||||
for _ in range(scene_count):
|
||||
scene = {}
|
||||
scene["filename"] = String(length_type=c_uint8).deserialize(stream)
|
||||
scene["id"] = stream.read(c_uint8)
|
||||
scene["scene_3bytes_01"] = stream.read(bytes, length=3)
|
||||
scene["is_audio_scene"] = stream.read(c_uint8)
|
||||
scene["scene_3bytes_02"] = stream.read(bytes, length=3)
|
||||
scene["name"] = String(length_type=c_uint8).deserialize(stream)
|
||||
scene["scene_3bytes_03"] = stream.read(bytes, length=3)
|
||||
config["scenes"].append(scene)
|
||||
config["u8_01"] = stream.read(c_uint8)
|
||||
config["terrain_map_filename"] = String(length_type=c_uint8).deserialize(stream)
|
||||
config["terrain_map_name"] = String(length_type=c_uint8).deserialize(stream)
|
||||
config["terrain_map_desc"] = String(length_type=c_uint8).deserialize(stream)
|
||||
if(config["version"] >= 0x20):
|
||||
scene_transition_count = stream.read(c_ulong)
|
||||
config["scene_transitions"] = []
|
||||
for _ in range(scene_transition_count):
|
||||
scene_transition = {}
|
||||
if(config["version"] < 0x25):
|
||||
scene_transition["name"] = (String(length_type=c_uint8).deserialize(stream))
|
||||
if(config["version"] <= 0x21 or config["version"] >= 0x27):
|
||||
loop_times = 2
|
||||
else:
|
||||
loop_times = 5
|
||||
scene_transition["scene_transition_types"] = []
|
||||
for _ in range(loop_times):
|
||||
scene_transition_type = {}
|
||||
scene_transition_type["scene_id"] = stream.read(c_ulonglong)
|
||||
scene_transition_type["transition_point"] = Vector3().deserialize(stream)
|
||||
scene_transition["scene_transition_types"].append(scene_transition_type)
|
||||
config["scene_transitions"].append(scene_transition)
|
||||
config["length_of_rest_of_file"] = stream.read(c_ulong)
|
||||
config["ulong_02"] = stream.read(c_ulong)
|
||||
path_count = stream.read(c_ulong)
|
||||
#TODO: Fix Paths
|
||||
# config["paths"] = []
|
||||
# for _ in range(path_count):
|
||||
# path = {}
|
||||
# path["path_version"] = stream.read(c_ulong)
|
||||
# path["path_name"] = String(length_type=c_uint8).deserialize(stream)
|
||||
# path["path_type"] = stream.read(c_ulong)
|
||||
# path["ulong_01"] = stream.read(c_ulong)
|
||||
# path["path_behavior"] = stream.read(c_ulong)
|
||||
# if(path["path_type"] == 1):
|
||||
# if(path["path_version"] >= 18):
|
||||
# path["u8_01"] = stream.read(c_uint8)
|
||||
# elif(path["path_version"] >= 13):
|
||||
# path["moving_platform_sound"] = stream.read(str, length_type=c_uint8)
|
||||
# elif(path["path_type"] == 2):
|
||||
# path["long_01"] = stream.read(c_long)
|
||||
# path["price"] = stream.read(c_long)
|
||||
# path["rental_time"] = stream.read(c_long)
|
||||
# path["accociated_zone"] = stream.read(c_ulonglong)
|
||||
# path["display_name"] = String(length_type=c_uint8).deserialize(stream)
|
||||
# path["display_description"] = String(length_type=c_uint8).deserialize(stream)
|
||||
# path["long_02"] = stream.read(c_long)
|
||||
# path["clone_limit"] = stream.read(c_long)
|
||||
# path["reputation_multiplier"] = stream.read(c_float)
|
||||
# path["rental_time_unit"] = stream.read(c_long)
|
||||
# path["achievement_required"] = stream.read(c_long)
|
||||
# path["player_zone_pos"] = Vector3().deserialize(stream)
|
||||
# path["max_building_height"] = stream.read(c_float)
|
||||
# elif(path["path_type"] == 3):
|
||||
# path["next_path"] = String(length_type=c_uint8).deserialize(stream)
|
||||
# if(path["path_version"] >= 14):
|
||||
# path["u8_01"] = stream.read(c_uint8)
|
||||
# elif(path["path_type"] == 4):
|
||||
# path["spawned_lot"] = stream.read(c_ulong)
|
||||
# path["respawn_time"] = stream.read(c_ulong)
|
||||
# path["max_to_spawn"] = stream.read(c_long)
|
||||
# path["number_to_maintain"] = stream.read(c_ulong)
|
||||
# path["spawner_object_id"] = stream.read(c_longlong)
|
||||
# path["activate_spawner_network_on_load"] = stream.read(c_bit)
|
||||
# waypoint_count = stream.read(c_ulong)
|
||||
# path["waypoints"] = []
|
||||
# for _ in range(waypoint_count):
|
||||
# waypoint = {}
|
||||
# waypoint["position"] = Vector3().deserialize(stream)
|
||||
# if(path["path_type"] == 1):
|
||||
# waypoint["rotation"] = Vector4().deserialize(stream)
|
||||
# waypoint["lock_player_until_next_waypoint"] = stream.read(c_bit)
|
||||
# waypoint["speed"] = stream.read(c_float)
|
||||
# waypoint["wait"] = stream.read(c_float)
|
||||
# if(path["path_version"] >= 13):
|
||||
# waypoint["depart_sound"] = stream.read(str, length_type=c_uint8)
|
||||
# waypoint["arrive_sound"] = stream.read(str, length_type=c_uint8)
|
||||
# elif(path["path_type"] == 3):
|
||||
# waypoint["float_01"] = stream.read(c_float)
|
||||
# waypoint["float_02"] = stream.read(c_float)
|
||||
# waypoint["float_03"] = stream.read(c_float)
|
||||
# waypoint["float_04"] = stream.read(c_float)
|
||||
# waypoint["time"] = stream.read(c_float)
|
||||
# waypoint["float_05"] = stream.read(c_float)
|
||||
# waypoint["continuity"] = stream.read(c_float)
|
||||
# waypoint["bias"] = stream.read(c_float)
|
||||
# elif(path["path_type"] == 4):
|
||||
# waypoint["rotation"] = Vector4().deserialize(stream)
|
||||
# elif(path["path_type"] == 6):
|
||||
# waypoint["rotation"] = Vector4().deserialize(stream)
|
||||
# waypoint["u8_01"] = stream.read(c_uint8)
|
||||
# waypoint["u8_02"] = stream.read(c_uint8)
|
||||
# waypoint["float_01"] = stream.read(c_float)
|
||||
# waypoint["float_02"] = stream.read(c_float)
|
||||
# waypoint["float_03"] = stream.read(c_float)
|
||||
# elif(path["path_type"] == 7):
|
||||
# waypoint["float_01"] = stream.read(c_float)
|
||||
# waypoint["float_02"] = stream.read(c_float)
|
||||
# waypoint["float_03"] = stream.read(c_float)
|
||||
# waypoint["float_04"] = stream.read(c_float)
|
||||
# if(path["path_version"] >= 17):
|
||||
# waypoint["float_05"] = stream.read(c_float)
|
||||
# if(path["path_type"] in [0,4,7]):
|
||||
# waypoint["config"] = {}
|
||||
# for _ in range(stream.read(c_ulong)):
|
||||
# waypoint["config"][stream.read(str, length_type=c_uint8)] = stream.read(str, length_type=c_uint8)
|
||||
# path["waypoints"].append(waypoint)
|
||||
# config["paths"].append(path)
|
||||
return LUZ(config)
|
||||
1
master.bat
Normal file
1
master.bat
Normal file
@@ -0,0 +1 @@
|
||||
python __main__.py master 4211
|
||||
@@ -1,429 +0,0 @@
|
||||
import services
|
||||
import json
|
||||
import database
|
||||
import copy
|
||||
import game_enums
|
||||
import typing
|
||||
import time
|
||||
import threading
|
||||
import game_types
|
||||
|
||||
class PlayerService(services.GameService):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Player"
|
||||
|
||||
self._accounts = []
|
||||
|
||||
global game
|
||||
game = self.get_parent()
|
||||
|
||||
def initialize(self):
|
||||
super().initialize()
|
||||
def sync_thread():
|
||||
while True:
|
||||
self.sync_database()
|
||||
time.sleep(1)
|
||||
sync = threading.Thread(target=sync_thread)
|
||||
sync.start()
|
||||
|
||||
def add_account(self, account_id : int):
|
||||
server_db = self.get_parent().get_service("Database").server_db
|
||||
|
||||
c = server_db.connection.cursor()
|
||||
|
||||
c.execute("SELECT * FROM Accounts WHERE account_id = ?", (account_id,))
|
||||
account = c.fetchone()
|
||||
c.execute("SELECT * FROM Characters WHERE account_id = ?", (account_id,))
|
||||
characters = c.fetchall()
|
||||
for character in characters:
|
||||
c.execute("SELECT * FROM CharacterData WHERE player_id = ?", (character["player_id"],))
|
||||
data = c.fetchone()
|
||||
data["position"] = game_types.Vector3(str_val=data["position"])
|
||||
data["rotation"] = game_types.Vector4(str_val=data["rotation"])
|
||||
character["Data"] = data
|
||||
c.execute("SELECT * FROM CharacterStats WHERE player_id = ?", (character["player_id"],))
|
||||
character["Stats"] = c.fetchone()
|
||||
c.execute("SELECT * FROM CompletedMissions WHERE player_id = ?", (character["player_id"],))
|
||||
character["CompletedMissions"] = c.fetchall()
|
||||
c.execute("SELECT * FROM CurrentMissions WHERE player_id = ?", (character["player_id"],))
|
||||
character["CurrentMissions"] = c.fetchall()
|
||||
c.execute("SELECT * FROM Inventory WHERE player_id = ?", (character["player_id"],))
|
||||
inventory = c.fetchall()
|
||||
for item in inventory:
|
||||
if(item["json"] is not None):
|
||||
item["json"] = json.loads(item["json"])
|
||||
else:
|
||||
item["json"] = {}
|
||||
character["Inventory"] = inventory
|
||||
account["Characters"] = characters
|
||||
self._accounts.append(account)
|
||||
self.get_parent().trigger_event("AccountAdded", args=(account,))
|
||||
|
||||
def remove_account(self, account_id : int):
|
||||
for account in self._accounts:
|
||||
if(account["account_id"] == account_id):
|
||||
self._accounts.remove(account)
|
||||
|
||||
def sync_database(self, accounts : typing.Iterable = None):
|
||||
if(accounts is None):
|
||||
accounts = self._accounts
|
||||
server_db = self.get_parent().get_service("Database").server_db
|
||||
c = server_db.connection.cursor()
|
||||
|
||||
for account in accounts:
|
||||
account_copy = copy.deepcopy(account)
|
||||
for character in account_copy["Characters"]:
|
||||
inventory = copy.deepcopy(character["Inventory"])
|
||||
del character["Inventory"]
|
||||
stats = copy.deepcopy(character["Stats"])
|
||||
del character["Stats"]
|
||||
data = copy.deepcopy(character["Data"])
|
||||
data["position"] = str(data["position"])
|
||||
data["rotation"] = str(data["rotation"])
|
||||
del character["Data"]
|
||||
completed_missions = character["CompletedMissions"]
|
||||
del character["CompletedMissions"]
|
||||
current_missions = character["CurrentMissions"]
|
||||
del character["CurrentMissions"]
|
||||
|
||||
c.execute("UPDATE Characters SET name = ?, zone = ?, shirt_color = ?, shirt_style = ?, pants_color = ?, hair_color = ?, hair_style = ?, lh = ?, rh = ?, eyebrows = ?, eyes = ?, mouth = ? WHERE player_id = ?",
|
||||
(character["name"], character["zone"], character["shirt_color"], character["shirt_style"], character["pants_color"], character["hair_color"], character["hair_style"], character["lh"], character["rh"],
|
||||
character["eyebrows"], character["eyes"], character["mouth"], character["player_id"]))
|
||||
c.execute('''UPDATE CharacterStats SET currency_collected = ?, bricks_collected = ?, smashables_smashed = ?, quick_builds_done = ?, enemies_smashed = ?, rockets_used = ?, pets_tamed = ?, imagination_collected = ?, health_collected = ?, armor_collected = ?, distance_traveled = ?, times_died = ?,
|
||||
damage_taken = ?, damage_healed = ?, armor_repaired = ?, imagination_restored = ?, imagination_used = ?, distance_driven = ?, time_airborne_in_car = ?, racing_imagination_collected = ?, racing_imagination_crates_smashed = ?, race_car_boosts = ?, car_wrecks = ?, racing_smashables_smashed = ?,
|
||||
races_finished = ?, races_won = ? WHERE player_id = ?''', (stats["currency_collected"], stats["bricks_collected"], stats["smashables_smashed"], stats["quick_builds_done"], stats["enemies_smashed"], stats["rockets_used"], stats["pets_tamed"], stats["imagination_collected"], stats["health_collected"], stats["armor_collected"], stats["distance_traveled"], stats["times_died"],
|
||||
stats["damage_taken"], stats["damage_healed"], stats["armor_repaired"], stats["imagination_restored"], stats["imagination_used"], stats["distance_driven"], stats["time_airborne_in_car"], stats["racing_imagination_collected"], stats["racing_imagination_crates_smashed"], stats["race_car_boosts"], stats["car_wrecks"], stats["racing_smashables_smashed"],
|
||||
stats["races_finished"], stats["races_won"], character["player_id"]))
|
||||
c.execute('''UPDATE CharacterData SET universe_score = ?, level = ?, health = ?, max_health = ?, armor = ?, max_armor = ?, imagination = ?, max_imagination = ?, currency = ?, position = ?, rotation = ?, backpack_space = ? WHERE player_id = ?''',
|
||||
(data["universe_score"], data["level"], data["health"], data["max_health"], data["armor"], data["max_armor"], data["imagination"], data["max_imagination"], data["currency"], data["position"], data["rotation"], data["backpack_space"], character["player_id"]))
|
||||
|
||||
for mission in completed_missions:
|
||||
c.execute("SELECT * FROM CompletedMissions WHERE player_id = ? and mission_id = ?", (mission["player_id"], mission["mission_id"]))
|
||||
check = c.fetchall()
|
||||
if(check == []):
|
||||
c.execute("INSERT INTO CompletedMissions (player_id, mission_id) VALUES (?, ?)", (mission["player_id"], mission["mission_id"]))
|
||||
|
||||
for mission in current_missions:
|
||||
c.execute("SELECT * FROM CurrentMissions WHERE player_id = ? and mission_id = ?", (mission["player_id"], mission["mission_id"]))
|
||||
check = c.fetchall()
|
||||
if(check == []):
|
||||
c.execute("INSERT INTO CurrentMissions (player_id, mission_id, progress) VALUES (?, ?, ?)", (mission["player_id"], mission["mission_id"], mission["progress"]))
|
||||
else:
|
||||
c.execute("UPDATE CurrentMissions SET progress = ? WHERE player_id = ? AND mission_id = ?", (mission["progress"], mission["player_id"], mission["mission_id"]))
|
||||
|
||||
c.execute("SELECT * FROM CurrentMissions WHERE player_id = ?", (character["player_id"],))
|
||||
db_missions = c.fetchall()
|
||||
for mission in db_missions:
|
||||
keep = False
|
||||
for server_mission in current_missions:
|
||||
if(server_mission["mission_id"] == mission["mission_id"]):
|
||||
keep = True
|
||||
if(keep == False):
|
||||
c.execute("DELETE FROM CurrentMissions WHERE player_id = ? AND mission_id = ?", (mission["player_id"], mission["mission_id"]))
|
||||
|
||||
for item in inventory:
|
||||
item["json"] = json.dumps(item["json"])
|
||||
c.execute("SELECT * FROM Inventory WHERE item_id = ?", (item["item_id"],))
|
||||
check = c.fetchall()
|
||||
if(check == []):
|
||||
c.execute("INSERT INTO Inventory (lot, slot, equipped, linked, quantity, item_id, player_id, json) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(item["lot"], item["slot"], item["equipped"], item["linked"], item["quantity"], item["item_id"], item["player_id"], item["json"]))
|
||||
else:
|
||||
c.execute("UPDATE Inventory SET slot = ?, equipped = ?, linked = ?, quantity = ?, json = ? WHERE item_id = ?",
|
||||
(item["slot"], item["equipped"], item["linked"], item["quantity"], item["json"], item["item_id"]))
|
||||
|
||||
c.execute("SELECT * FROM Inventory WHERE player_id = ?", (character["player_id"],))
|
||||
db_inventory = c.fetchall()
|
||||
for item in db_inventory:
|
||||
keep = False
|
||||
for server_item in inventory:
|
||||
if(server_item["item_id"] == item["item_id"]):
|
||||
keep = True
|
||||
if(keep == False):
|
||||
c.execute("DELETE FROM Inventory WHERE item_id = ?", (item["item_id"],))
|
||||
|
||||
|
||||
def delete_player(self, player_id):
|
||||
account = self.get_account_by_player_id(player_id)
|
||||
self.sync_database(accounts=[account])
|
||||
player = copy.deepcopy(self.get_player_by_id(player_id))
|
||||
|
||||
for character in account["Characters"]:
|
||||
if(character["player_id"] == player_id):
|
||||
account["Characters"].remove(character)
|
||||
|
||||
db = self.get_parent().get_service("Database").server_db
|
||||
c = db.connection.cursor()
|
||||
|
||||
c.execute("DELETE FROM Characters WHERE player_id = ?", (player_id,))
|
||||
c.execute("DELETE FROM CharacterData WHERE player_id = ?", (player_id,))
|
||||
c.execute("DELETE FROM CharacterStats WHERE player_id = ?", (player_id,))
|
||||
c.execute("DELETE FROM CompletedMissions WHERE player_id = ?", (player_id,))
|
||||
c.execute("DELETE FROM CurrentMissions WHERE player_id = ?", (player_id,))
|
||||
c.execute("DELETE FROM Inventory WHERE player_id = ?", (player_id,))
|
||||
|
||||
self.get_parent().trigger_event("PlayerDeleted", args=(player,))
|
||||
|
||||
def create_player(self, account_id : int, name: str, shirt_color: int, shirt_style: int, pants_color: int, hair_color: int,
|
||||
hair_style: int, lh: int, rh: int, eyebrows: int, eyes: int, mouth: int, custom_name: str):
|
||||
db = self.get_parent().get_service("Database").server_db
|
||||
c = db.connection.cursor()
|
||||
|
||||
player_id = self.get_parent().generate_object_id()
|
||||
|
||||
c.execute('''INSERT INTO CharacterStats (currency_collected, bricks_collected, smashables_smashed, quick_builds_done, enemies_smashed, rockets_used, pets_tamed, imagination_collected, health_collected, armor_collected, distance_traveled, times_died,
|
||||
damage_taken, damage_healed, armor_repaired, imagination_restored , imagination_used, distance_driven, time_airborne_in_car, racing_imagination_collected, racing_imagination_crates_smashed, race_car_boosts, car_wrecks, racing_smashables_smashed,
|
||||
races_finished, races_won, player_id) VALUES (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,?)''', (player_id,))
|
||||
c.execute('''INSERT INTO Characters (account_id, name, shirt_color, shirt_style, pants_color, hair_color, hair_style, lh, rh, eyebrows, eyes, mouth, zone, player_id, custom_name) VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', (account_id, name, shirt_color, shirt_style, pants_color, hair_color, hair_style, lh, rh, eyebrows, eyes, mouth, 1000, player_id, custom_name))
|
||||
c.execute('''INSERT INTO CharacterData (universe_score, level, health, max_health, armor, max_armor, imagination, max_imagination, currency, position, rotation, player_id, backpack_space) VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''', (0, 0, 4, 4, 0, 0, 0, 0, 0, "0,0,0", "0,0,0", player_id, 20))
|
||||
|
||||
|
||||
|
||||
account = self.get_account_by_id(account_id)
|
||||
self.sync_database([account])
|
||||
player_copy = copy.deepcopy({"account_id":account_id, "name":name, "shirt_color":shirt_color, "shirt_style":shirt_style, "pants_color":pants_color, "hair_color":hair_color, "hair_style":hair_style,
|
||||
"lh":lh, "rh":rh, "eyebrows":eyebrows, "eyes":eyes, "mouth":mouth, "zone":1000, "player_id":player_id, "custom_name":custom_name})
|
||||
player_copy["Data"] = {"universe_score":0, "level":0, "health":4, "max_health":4, "armor":0, "max_armor":0, "imagination":0, "max_imagination":0, "currency":0, "position":"0,0,0",
|
||||
"rotation":"0,0,0,0", "player_id":player_id, "backpack_space":20}
|
||||
player_copy["Data"]["position"] = game_types.Vector3(str_val = player_copy["Data"]["position"])
|
||||
player_copy["Data"]["rotation"] = game_types.Vector4(str_val = player_copy["Data"]["rotation"])
|
||||
player_copy["Stats"] = {"currency_collected":0, "bricks_collected":0, "smashables_smashed":0, "quick_builds_done":0, "enemies_smashed":0, "rockets_used":0, "pets_tamed":0,
|
||||
"imagination_collected":0, "health_collected":0, "armor_collected":0, "distance_traveled":0, "times_died":0, "damage_taken":0, "damage_healed":0,
|
||||
"armor_repaired":0, "imagination_restored":0, "imagination_used":0, "distance_driven":0, "time_airborne_in_car":0, "racing_imagination_collected":0,
|
||||
"racing_imagination_crates_smashed":0, "race_car_boosts":0, "car_wrecks":0, "racing_smashables_smashed":0, "races_finished":0, "races_won":0, "player_id":player_id}
|
||||
player_copy["CompletedMissions"] = []
|
||||
player_copy["CurrentMissions"] = []
|
||||
player_copy["Inventory"] = []
|
||||
account["Characters"].append(player_copy)
|
||||
self.get_parent().trigger_event("PlayerCreated", args=[player_id,])
|
||||
|
||||
shirt_id = 0
|
||||
if (shirt_color == 0):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5730
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_BRIGHT_RED.value
|
||||
elif (shirt_color == 1):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5736
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_BRIGHT_BLUE.value
|
||||
elif (shirt_color == 3):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5808
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_DARK_GREEN.value
|
||||
elif (shirt_color == 5):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5754
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_BRIGHT_ORANGE.value
|
||||
elif (shirt_color == 6):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5760
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_BLACK.value
|
||||
elif (shirt_color == 7):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5766
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_DARK_STONE_GRAY.value
|
||||
elif (shirt_color == 8):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5772
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_MEDIUM_STONE_GRAY.value
|
||||
elif (shirt_color == 9):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5778
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_REDDISH_BROWN.value
|
||||
elif (shirt_color == 10):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5784
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_WHITE.value
|
||||
elif (shirt_color == 11):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5802
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_MEDIUM_BLUE.value
|
||||
elif (shirt_color == 13):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5796
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_DARK_RED.value
|
||||
elif (shirt_color == 14):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5802
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_EARTH_BLUE.value
|
||||
elif (shirt_color == 15):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5808
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_EARTH_GREEN.value
|
||||
elif (shirt_color == 16):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5814
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_BRICK_YELLOW.value
|
||||
elif (shirt_color == 84):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5820
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_SAND_BLUE.value
|
||||
elif (shirt_color == 96):
|
||||
if (shirt_style >= 35):
|
||||
shirt_id = 5826
|
||||
else:
|
||||
shirt_id = game_enums.ItemLOTs.SHIRT_SAND_GREEN.value
|
||||
|
||||
if (shirt_style >= 35):
|
||||
final_shirt_id = shirt_id + (shirt_style - 35)
|
||||
else:
|
||||
final_shirt_id = shirt_id + (shirt_style - 1)
|
||||
|
||||
if (pants_color == 0):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_BRIGHT_RED.value
|
||||
elif (pants_color == 1):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_BRIGHT_BLUE.value
|
||||
elif (pants_color == 3):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_DARK_GREEN.value
|
||||
elif (pants_color == 5):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_BRIGHT_ORANGE.value
|
||||
elif (pants_color == 6):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_BLACK.value
|
||||
elif (pants_color == 7):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_DARK_STONE_GRAY.value
|
||||
elif (pants_color == 8):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_MEDIUM_STONE_GRAY.value
|
||||
elif (pants_color == 9):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_REDDISH_BROWN.value
|
||||
elif (pants_color == 10):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_WHITE.value
|
||||
elif (pants_color == 11):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_MEDIUM_BLUE.value
|
||||
elif (pants_color == 13):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_DARK_RED.value
|
||||
elif (pants_color == 14):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_EARTH_BLUE.value
|
||||
elif (pants_color == 15):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_EARTH_GREEN.value
|
||||
elif (pants_color == 16):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_BRICK_YELLOW.value
|
||||
elif (pants_color == 84):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_SAND_BLUE.value
|
||||
elif (pants_color == 96):
|
||||
pants_id = game_enums.ItemLOTs.PANTS_SAND_GREEN.value
|
||||
else:
|
||||
pants_id = 2508
|
||||
|
||||
self.add_item_to_inventory(player_id, final_shirt_id, equipped=True, linked=True, json_data={"from":"character_creation"})
|
||||
self.add_item_to_inventory(player_id, pants_id, equipped=True, linked=True,json_data={"from":"character_creation"})
|
||||
|
||||
def get_account_by_id(self, account_id : int):
|
||||
for account in self._accounts:
|
||||
if(account["account_id"] == account_id):
|
||||
return account
|
||||
return None
|
||||
|
||||
def get_player_object_by_id(self, player_id : int):
|
||||
session = self.get_parent().get_service("Session").get_session_by_player_id(player_id)
|
||||
zone = self.get_parent().get_service("World").get_zone_by_id(session.zone_id)
|
||||
return zone.get_object_by_id(player_id)
|
||||
|
||||
|
||||
def get_account_by_player_id(self, player_id : int):
|
||||
for account in self._accounts:
|
||||
for character in account["Characters"]:
|
||||
if(character["player_id"] == player_id):
|
||||
return account
|
||||
return None
|
||||
|
||||
def get_player_by_id(self, player_id : int):
|
||||
for account in self._accounts:
|
||||
for character in account["Characters"]:
|
||||
if(character["player_id"] == player_id):
|
||||
return character
|
||||
return None
|
||||
|
||||
def add_item_to_inventory(self, player_id : int, lot : int, slot : int = None, equipped : bool = False, linked : bool = False, quantity : int = 1, json_data : dict = None):
|
||||
if(json_data is None):
|
||||
json_data = {}
|
||||
player = self.get_player_by_id(player_id)
|
||||
if(slot is None):
|
||||
availible_slots = []
|
||||
for i in range(player["Data"]["backpack_space"]):
|
||||
availible_slots.append(i)
|
||||
for item in player["Inventory"]:
|
||||
availible_slots.remove(item["slot"])
|
||||
if(availible_slots != []):
|
||||
slot = availible_slots[0]
|
||||
else:
|
||||
print("No Inventory Space Availible!")
|
||||
return None
|
||||
|
||||
database_service = game.get_service("Database")
|
||||
cdclient = database_service.cdclient_db
|
||||
c = cdclient.connection.cursor()
|
||||
|
||||
c.execute("SELECT component_id FROM ComponentsRegistry WHERE id = ? and component_type = 11", (lot,))
|
||||
item_component_id = c.fetchone()
|
||||
c.execute("SELECT * FROM ItemComponent WHERE id = ?", (item_component_id["component_id"],))
|
||||
item_data = c.fetchone()
|
||||
|
||||
new_item_id = game.generate_object_id()
|
||||
|
||||
json_data["proxy_items"] = []
|
||||
if(item_data["subItems"] is not None):
|
||||
json_data["proxy_items"].append({"player_id":player_id, "lot":int(item_data["subItems"]), "slot":-1, "equipped":1, "linked":1, "quantity":1, "item_id":game.generate_object_id(), "json":{"is_proxy":1, "parent_item":new_item_id}})
|
||||
|
||||
item = {"player_id":player_id, "lot":lot, "slot":slot, "equipped":int(equipped), "linked":int(linked), "quantity":quantity, "json":json_data, "item_id":new_item_id}
|
||||
|
||||
db = self.get_parent().get_service("Database").server_db
|
||||
c2 = db.connection.cursor()
|
||||
db_item = copy.deepcopy(item)
|
||||
db_item["json"] = json.dumps(db_item["json"])
|
||||
c2.execute("INSERT INTO Inventory (lot, slot, equipped, linked, quantity, item_id, player_id, json) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
(db_item["lot"], db_item["slot"], db_item["equipped"], db_item["linked"], db_item["quantity"], db_item["item_id"], db_item["player_id"], db_item["json"]))
|
||||
|
||||
player["Inventory"].append(item)
|
||||
self.get_parent().trigger_event("ItemAdded", args=[player_id, item])
|
||||
return item
|
||||
|
||||
def get_item_by_id(self, player_id : int, item_id : int):
|
||||
player = self.get_player_by_id(player_id)
|
||||
if(player is not None):
|
||||
for item in player["Inventory"]:
|
||||
if(item["item_id"] == item_id):
|
||||
return item
|
||||
return None
|
||||
|
||||
def get_equipped_items(self, player_id : int):
|
||||
player = self.get_player_by_id(player_id)
|
||||
items = []
|
||||
def parse_item(item):
|
||||
if (int(item["equipped"]) == 1):
|
||||
items.append(item)
|
||||
if ("proxy_items" in item["json"] and item["json"]["proxy_items"] != []):
|
||||
for proxy_item in item["json"]["proxy_items"]:
|
||||
parse_item(proxy_item)
|
||||
for item in player["Inventory"]:
|
||||
parse_item(item)
|
||||
self.get_parent().trigger_event("EquipListRequest", args=[player_id, items])
|
||||
return items
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
plugins/auth_handler/__pycache__/auth_handlers.cpython-37.pyc
Normal file
BIN
plugins/auth_handler/__pycache__/auth_handlers.cpython-37.pyc
Normal file
Binary file not shown.
75
plugins/auth_handler/auth_handlers.py
Normal file
75
plugins/auth_handler/auth_handlers.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
This plugin will handle all of the auth packet handlers
|
||||
"""
|
||||
from ..serializables import packet_enum, auth_to_client, client_to_auth, global_packets
|
||||
from pyraknet.bitstream import *
|
||||
import os
|
||||
import uuid
|
||||
import bcrypt
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Plugin:
|
||||
def __init__(self, parent):
|
||||
print("Auth Handler Initiated")
|
||||
parent.register_handler(Plugin.handle_handshake, packet_enum.PacketHeader.HANDSHAKE.value)
|
||||
parent.register_handler(Plugin.handle_login, packet_enum.PacketHeader.CLIENT_LOGIN_INFO.value)
|
||||
|
||||
@classmethod
|
||||
def handle_login(cls, data: bytes, address, server):
|
||||
stream = ReadStream(data)
|
||||
login_info = stream.read(client_to_auth.LoginInfoPacket)
|
||||
print(f"Player logging in with Username [{login_info.username}] and Password [{login_info.password}]")
|
||||
|
||||
packet = WriteStream()
|
||||
response = auth_to_client.LoginInfoPacket()
|
||||
|
||||
c = server.db_connection.cursor()
|
||||
c.execute("SELECT * FROM account WHERE username = %s", (login_info.username,))
|
||||
results = c.fetchone()
|
||||
if results is not None:
|
||||
user_info = dict(zip(c.column_names, results))
|
||||
if (not bool(user_info["banned"]) and
|
||||
bcrypt.checkpw(login_info.password.encode("utf-8"), user_info["password"].encode("utf-8"))):
|
||||
response.login_return_code = packet_enum.LoginReturnCode.SUCCESS.value
|
||||
|
||||
response.user_key = (str(uuid.uuid4()))[0:20]
|
||||
timestamp = datetime.timestamp(datetime.now())
|
||||
c.execute("DELETE FROM session WHERE username = %s", (login_info.username,))
|
||||
server.db_connection.commit()
|
||||
c.execute("INSERT INTO session (username, user_key, ip_address, login_timestamp)"
|
||||
"VALUES (%s, %s, %s, %s);",
|
||||
(login_info.username, response.user_key, str(address), timestamp))
|
||||
server.db_connection.commit()
|
||||
print(f"Login Succeeded - Created Session with User-key [{response.user_key}] "
|
||||
f"and Timestamp [{timestamp}]")
|
||||
else:
|
||||
response.login_return_code = packet_enum.LoginReturnCode.INVALID_LOGIN_INFO.value
|
||||
print("Login Failed")
|
||||
else:
|
||||
response.login_return_code = packet_enum.LoginReturnCode.INVALID_LOGIN_INFO.value
|
||||
print("Login Failed")
|
||||
|
||||
char_address, char_port = server.redirect_request("instance", "char")
|
||||
response.char_port = char_address
|
||||
response.char_ip = char_port
|
||||
packet.write(packet_enum.PacketHeader.LOGIN_RESPONSE.value)
|
||||
packet.write(response)
|
||||
server.send(packet, address)
|
||||
|
||||
@classmethod
|
||||
def handle_handshake(cls, data: bytes, address, server):
|
||||
"""
|
||||
Handles initial connection between server and client.
|
||||
"""
|
||||
stream = ReadStream(data)
|
||||
client_handshake = stream.read(global_packets.HandshakePacket)
|
||||
print(f"{address[0]} has initiated handshake - Client has version {client_handshake.game_version}")
|
||||
|
||||
server_handshake = global_packets.HandshakePacket()
|
||||
server_handshake.remote_connection_type = 1
|
||||
server_handshake.process_id = os.getpid()
|
||||
packet = WriteStream()
|
||||
packet.write(packet_enum.PacketHeader.HANDSHAKE.value)
|
||||
packet.write(server_handshake)
|
||||
server.send(packet, address)
|
||||
8
plugins/auth_handler/plugin.json
Normal file
8
plugins/auth_handler/plugin.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Auth Handler",
|
||||
"id": "auth_handler",
|
||||
"description": "This plugin handles auth packets.",
|
||||
"main_file": "auth_handlers",
|
||||
"type": "auth",
|
||||
"dependencies": ["serializables"]
|
||||
}
|
||||
BIN
plugins/char_handler/__pycache__/char_handlers.cpython-37.pyc
Normal file
BIN
plugins/char_handler/__pycache__/char_handlers.cpython-37.pyc
Normal file
Binary file not shown.
157
plugins/char_handler/char_handlers.py
Normal file
157
plugins/char_handler/char_handlers.py
Normal file
@@ -0,0 +1,157 @@
|
||||
"""
|
||||
This will handle all of the character related packets.
|
||||
"""
|
||||
from ..serializables import packet_enum, world_to_client, client_to_world, global_packets, misc_serializables
|
||||
from pyraknet.bitstream import *
|
||||
import os
|
||||
|
||||
|
||||
class Plugin:
|
||||
def __init__(self, parent):
|
||||
print("Character Handler Initiated")
|
||||
parent.register_handler(Plugin.handle_handshake, packet_enum.PacketHeader.HANDSHAKE.value)
|
||||
parent.register_handler(Plugin.handle_minifigure_list_request,
|
||||
packet_enum.PacketHeader.CLIENT_USER_SESSION_INFO.value)
|
||||
parent.register_handler(Plugin.handle_minifigure_creation,
|
||||
packet_enum.PacketHeader.CLIENT_MINIFIGURE_CREATE_REQUEST.value)
|
||||
|
||||
@classmethod
|
||||
def handle_handshake(cls, data: bytes, address, server):
|
||||
"""
|
||||
Handles initial connection between server and client.
|
||||
"""
|
||||
stream = ReadStream(data)
|
||||
client_handshake = stream.read(global_packets.HandshakePacket)
|
||||
print(f"{address[0]} has initiated handshake - Client has version {client_handshake.game_version}")
|
||||
|
||||
server_handshake = global_packets.HandshakePacket()
|
||||
server_handshake.remote_connection_type = 4
|
||||
server_handshake.process_id = os.getpid()
|
||||
packet = WriteStream()
|
||||
packet.write(packet_enum.PacketHeader.HANDSHAKE.value)
|
||||
packet.write(server_handshake)
|
||||
server.send(packet, address)
|
||||
|
||||
@classmethod
|
||||
def handle_minifigure_creation(cls, data: bytes, address, server):
|
||||
c = server.db_connection.cursor()
|
||||
c.execute("SELECT * FROM wlus.session WHERE ip_address = %s", (str(address),))
|
||||
session = c.fetchone()
|
||||
c.execute("SELECT account_id FROM wlus.account WHERE username = %s", (session[1],))
|
||||
account_id = c.fetchone()[0]
|
||||
|
||||
stream = ReadStream(data)
|
||||
minfig = stream.read(client_to_world.MinifigureCreateRequestPacket).to_login_character()
|
||||
minfig.save_to_db(account_id, server.db_connection)
|
||||
|
||||
response = world_to_client.MinifigureCreationResponsePacket()
|
||||
response.response = 0x00
|
||||
packet = WriteStream()
|
||||
packet.write(packet_enum.PacketHeader.MINIFIGURE_CREATION_RESPONSE.value)
|
||||
packet.write(response)
|
||||
server.send(packet, address)
|
||||
|
||||
characters = []
|
||||
c.execute("SELECT * FROM wlus.character WHERE account_id = %s", (account_id,))
|
||||
minifig_results = c.fetchall()
|
||||
for minifig in minifig_results:
|
||||
char = misc_serializables.LoginCharacter()
|
||||
char.object_id = minifig[0]
|
||||
char.current_name = minifig[1]
|
||||
char.unapproved_name = minifig[2]
|
||||
char.head_color = minifig[3]
|
||||
char.head = minifig[4]
|
||||
char.chest_color = minifig[5]
|
||||
char.chest = minifig[6]
|
||||
char.legs = minifig[7]
|
||||
char.hair_style = minifig[8]
|
||||
char.hair_color = minifig[9]
|
||||
char.left_hand = minifig[10]
|
||||
char.right_hand = minifig[11]
|
||||
char.eyebrows_style = minifig[12]
|
||||
char.eyes_style = minifig[13]
|
||||
char.mouth_style = minifig[14]
|
||||
c.execute("SELECT * FROM wlus.inventory WHERE player_id = %s AND equipped = 1", (char.object_id,))
|
||||
equipped_items = c.fetchall()
|
||||
for i in equipped_items:
|
||||
char.equipped_items.append(i[1])
|
||||
characters.append(char)
|
||||
|
||||
char_list = world_to_client.MinfigureListPacket()
|
||||
for c in characters:
|
||||
char_list.minifigs.append(c)
|
||||
packet = WriteStream()
|
||||
packet.write(packet_enum.PacketHeader.MINIFIGURE_LIST.value)
|
||||
packet.write(char_list)
|
||||
server.send(packet, address)
|
||||
|
||||
@classmethod
|
||||
def handle_minifigure_list_request(cls, data: bytes, address, server):
|
||||
stream = ReadStream(data)
|
||||
session_info = stream.read(client_to_world.UserSessionInfoPacket)
|
||||
c = server.db_connection.cursor()
|
||||
c.execute("SELECT * FROM wlus.session WHERE username = %s", (session_info.username,))
|
||||
results = c.fetchall()
|
||||
if results is not None:
|
||||
sessions = [dict(zip(c.column_names, result)) for result in results]
|
||||
if sessions[0]["user_key"] == session_info.user_key:
|
||||
packet = WriteStream()
|
||||
|
||||
c.execute("SELECT account_id FROM account WHERE username = %s", (session_info.username,))
|
||||
account_id = c.fetchone()[0]
|
||||
|
||||
characters = []
|
||||
c.execute("SELECT * FROM wlus.character WHERE account_id = %s", (account_id,))
|
||||
minifig_results = c.fetchall()
|
||||
for minifig in minifig_results:
|
||||
char = misc_serializables.LoginCharacter()
|
||||
char.object_id = minifig[0]
|
||||
char.current_name = minifig[1]
|
||||
char.unapproved_name = minifig[2]
|
||||
char.head_color = minifig[3]
|
||||
char.head = minifig[4]
|
||||
char.chest_color = minifig[5]
|
||||
char.chest = minifig[6]
|
||||
char.legs = minifig[7]
|
||||
char.hair_style = minifig[8]
|
||||
char.hair_color = minifig[9]
|
||||
char.left_hand = minifig[10]
|
||||
char.right_hand = minifig[11]
|
||||
char.eyebrows_style = minifig[12]
|
||||
char.eyes_style = minifig[13]
|
||||
char.mouth_style = minifig[14]
|
||||
c.execute("SELECT * FROM wlus.inventory WHERE player_id = %s AND equipped = 1", (char.object_id,))
|
||||
equipped_items = c.fetchall()
|
||||
for i in equipped_items:
|
||||
char.equipped_items.append(i[1])
|
||||
characters.append(char)
|
||||
|
||||
char_list = world_to_client.MinfigureListPacket()
|
||||
for c in characters:
|
||||
char_list.minifigs.append(c)
|
||||
|
||||
"""
|
||||
# Add Duke Exeter (For Testing)
|
||||
exeter = misc_serializables.LoginCharacter.from_cdclient(12261)
|
||||
exeter.equipped_items.append(7369)
|
||||
exeter.equipped_items.append(7381)
|
||||
char_list.minifigs.append(exeter)
|
||||
"""
|
||||
|
||||
packet.write(packet_enum.PacketHeader.MINIFIGURE_LIST.value)
|
||||
packet.write(char_list)
|
||||
server.send(packet, address)
|
||||
else:
|
||||
disconnect = global_packets.DisconnectNotifyPacket()
|
||||
disconnect.disconnect_id = packet_enum.DisconnectionNotify.INVALID_SESSION_KEY.value
|
||||
disconnect_packet = WriteStream()
|
||||
disconnect_packet.write(packet_enum.PacketHeader.DISCONNECT_NOTIFY.value)
|
||||
disconnect_packet.write(disconnect)
|
||||
server.send(disconnect_packet, address)
|
||||
else:
|
||||
disconnect = global_packets.DisconnectNotifyPacket()
|
||||
disconnect.disconnect_id = packet_enum.DisconnectionNotify.INVALID_SESSION_KEY.value
|
||||
disconnect_packet = WriteStream()
|
||||
disconnect_packet.write(packet_enum.PacketHeader.DISCONNECT_NOTIFY.value)
|
||||
disconnect_packet.write(disconnect)
|
||||
server.send(disconnect_packet, address)
|
||||
8
plugins/char_handler/plugin.json
Normal file
8
plugins/char_handler/plugin.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "Char Handler",
|
||||
"id": "char_handler",
|
||||
"description": "This plugin handles all the character packets.",
|
||||
"main_file": "char_handlers",
|
||||
"type": "char",
|
||||
"dependencies": ["serializables"]
|
||||
}
|
||||
BIN
plugins/easy_cdclient/__pycache__/cdclient_enum.cpython-37.pyc
Normal file
BIN
plugins/easy_cdclient/__pycache__/cdclient_enum.cpython-37.pyc
Normal file
Binary file not shown.
BIN
plugins/easy_cdclient/__pycache__/cdclient_tables.cpython-37.pyc
Normal file
BIN
plugins/easy_cdclient/__pycache__/cdclient_tables.cpython-37.pyc
Normal file
Binary file not shown.
84
plugins/easy_cdclient/cdclient_enum.py
Normal file
84
plugins/easy_cdclient/cdclient_enum.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""
|
||||
Contains various enum for the cdclient
|
||||
"""
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
class COMPONENTS(IntEnum):
|
||||
CONTROLLABLE_PHYSICS = 1
|
||||
RENDER = 2
|
||||
SIMPLE_PHYSICS = 3
|
||||
CHARACTER = 4
|
||||
SCRIPT = 5
|
||||
BOUNCER = 6
|
||||
DESTROYABLE = 7
|
||||
SKILL = 9
|
||||
SPAWNER = 10
|
||||
ITEM = 11
|
||||
REBUILD = 12
|
||||
REBUILD_START = 13
|
||||
VENDOR = 16
|
||||
INVENTORY = 17
|
||||
PROJECTILE_PHYSICS = 18
|
||||
SHOOTING_GALLERY = 19
|
||||
RIGID_BODY_PHANTOM_PHYSICS = 20
|
||||
CHEST = 22
|
||||
COLLECTIBLE = 23
|
||||
BLUEPRINT = 24
|
||||
MOVING_PLATFORM = 25
|
||||
PET = 26
|
||||
PLATFORM_BOUNDARY = 27
|
||||
MODULE = 28
|
||||
ARCADE = 29
|
||||
VEHICLE_PHYSICS_0 = 30
|
||||
MOVEMENT_AI = 31
|
||||
EXHIBIT = 32
|
||||
MINIFIG = 35
|
||||
PROPERTY = 36
|
||||
PET_CREATOR = 37
|
||||
MODEL_BUILDER = 38
|
||||
SCRIPTED_ACTIVITY = 39
|
||||
PHANTOM_PHYSICS = 40
|
||||
SPRINGPAD = 41
|
||||
B3_BEHAVIORS = 42
|
||||
PROPERTY_ENTRANCE = 43
|
||||
PROPERTY_MANAGEMENT = 45
|
||||
VEHICLE_PHYSICS_1 = 46
|
||||
PHYSICS_SYSTEM = 47
|
||||
QUICK_BUILD = 48
|
||||
SWITCH = 49
|
||||
MINIGAME = 50
|
||||
CHANGLING = 51
|
||||
CHOICE_BUILD = 52
|
||||
PACKAGE = 53
|
||||
SOUND_REPEATER = 54
|
||||
SOUND_AMBIENT_2D = 55
|
||||
SOUND_AMBIENT_3D = 56
|
||||
PRECONDITION = 57
|
||||
CUSTOM_BUILD_ASSEMBLY = 59
|
||||
BASE_COMBAT_AI = 60
|
||||
MODULE_ASSEMBLY = 61
|
||||
SHOWCASE_MODEL_HANDLER = 62
|
||||
RACING_MODULE = 63
|
||||
GENERIC_ACTIVATOR = 64
|
||||
PROPERTY_VENDOR = 65
|
||||
HF_LIGHT_DIRECTION_GADGET = 66
|
||||
ROCKET_LAUNCH = 67
|
||||
ROCKET_LANDING = 68
|
||||
RACING_CONTROL = 71
|
||||
FACTION_TRIGGER = 72
|
||||
MISSION_OFFER = 73
|
||||
RACING_STATS = 74
|
||||
LUP_EXHIBIT = 75
|
||||
SOUND_TRIGGER = 77
|
||||
PROXIMITY_MONITOR = 79
|
||||
USER_CONTROL = 95
|
||||
LUP_LAUNCHPAD = 97
|
||||
BRICK_DONATION = 100
|
||||
COMMENDATION_VENDOR = 102
|
||||
RAIL_ACTIVATOR = 104
|
||||
ROLLER = 105
|
||||
POSSESSABLE = 108
|
||||
PROPERTY_PLAQUE = 113
|
||||
BUILD_BORDER = 114
|
||||
CULLING_PLANE = 116
|
||||
6620
plugins/easy_cdclient/cdclient_tables.py
Normal file
6620
plugins/easy_cdclient/cdclient_tables.py
Normal file
File diff suppressed because it is too large
Load Diff
7
plugins/easy_cdclient/plugin.json
Normal file
7
plugins/easy_cdclient/plugin.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Easy CDClient Module",
|
||||
"id": "easy_cdclient",
|
||||
"description": "This module makes searching through the cdclient a lot easier. Something is currently wrong with it, sooo probably best not to use it for now.",
|
||||
"type": "module",
|
||||
"dependencies": []
|
||||
}
|
||||
BIN
plugins/serializables/__pycache__/auth_to_client.cpython-37.pyc
Normal file
BIN
plugins/serializables/__pycache__/auth_to_client.cpython-37.pyc
Normal file
Binary file not shown.
BIN
plugins/serializables/__pycache__/client_to_auth.cpython-37.pyc
Normal file
BIN
plugins/serializables/__pycache__/client_to_auth.cpython-37.pyc
Normal file
Binary file not shown.
BIN
plugins/serializables/__pycache__/client_to_world.cpython-37.pyc
Normal file
BIN
plugins/serializables/__pycache__/client_to_world.cpython-37.pyc
Normal file
Binary file not shown.
BIN
plugins/serializables/__pycache__/global_packets.cpython-37.pyc
Normal file
BIN
plugins/serializables/__pycache__/global_packets.cpython-37.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
plugins/serializables/__pycache__/packet_enum.cpython-37.pyc
Normal file
BIN
plugins/serializables/__pycache__/packet_enum.cpython-37.pyc
Normal file
Binary file not shown.
BIN
plugins/serializables/__pycache__/world_to_client.cpython-37.pyc
Normal file
BIN
plugins/serializables/__pycache__/world_to_client.cpython-37.pyc
Normal file
Binary file not shown.
53
plugins/serializables/auth_to_client.py
Normal file
53
plugins/serializables/auth_to_client.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""
|
||||
Contains all the packets that auth would send to the client
|
||||
"""
|
||||
from pyraknet import bitstream
|
||||
from .misc_serializables import CString
|
||||
|
||||
|
||||
class LoginInfoPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-05-00-00]
|
||||
This packet is sent in response to the character logging in.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.login_return_code = 0x06
|
||||
self.client_version_major = 1
|
||||
self.client_version_current = 10
|
||||
self.client_version_minor = 64
|
||||
self.user_key = ""
|
||||
self.char_ip = "127.0.0.1"
|
||||
self.chat_ip = "127.0.0.1"
|
||||
self.char_port = 2002
|
||||
self.chat_port = 3003
|
||||
self.localization = "US"
|
||||
self.custom_error = ""
|
||||
self.display_first_time = False
|
||||
self.is_ftp = False
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(bitstream.c_uint8(self.login_return_code))
|
||||
stream.write(CString("Talk_Like_A_Pirate", allocated_length=33))
|
||||
stream.write(CString("", allocated_length=33 * 7))
|
||||
stream.write(bitstream.c_uint16(self.client_version_major))
|
||||
stream.write(bitstream.c_uint16(self.client_version_current))
|
||||
stream.write(bitstream.c_uint16(self.client_version_minor))
|
||||
stream.write(self.user_key, allocated_length=33)
|
||||
stream.write(CString(self.char_ip, allocated_length=33))
|
||||
stream.write(CString(self.chat_ip, allocated_length=33))
|
||||
stream.write(bitstream.c_uint16(self.char_port))
|
||||
stream.write(bitstream.c_uint16(self.chat_port))
|
||||
stream.write(CString('0', allocated_length=33))
|
||||
stream.write(CString('00000000-0000-0000-0000-000000000000', allocated_length=37))
|
||||
stream.write(bitstream.c_uint32(0))
|
||||
stream.write(CString(self.localization, allocated_length=3)) # US Localization
|
||||
stream.write(bitstream.c_bool(self.display_first_time))
|
||||
stream.write(bitstream.c_bool(self.is_ftp))
|
||||
stream.write(bitstream.c_uint64(0))
|
||||
stream.write(self.custom_error, length_type=bitstream.c_uint16) # Custom error message
|
||||
stream.write(bitstream.c_uint16(0))
|
||||
stream.write(bitstream.c_uint32(4))
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
raise Exception("This packet cannot be deserialized.")
|
||||
30
plugins/serializables/client_to_auth.py
Normal file
30
plugins/serializables/client_to_auth.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
Contains all the packets that are sent from the client to the auth server.
|
||||
"""
|
||||
from pyraknet import bitstream
|
||||
|
||||
|
||||
class LoginInfoPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-01-00-00]
|
||||
This packet contains the username and password of a player logging in.
|
||||
Even though there is more information in the Login Info Packet,
|
||||
the only ones that this Serializable will read is the Username and Password
|
||||
"""
|
||||
def __init__(self):
|
||||
self.username = ""
|
||||
self.password = ""
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
raise Exception("This Serializable can only deserialize")
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = LoginInfoPacket()
|
||||
packet.username = stream.read(str, allocated_length=33)
|
||||
packet.password = stream.read(str, allocated_length=41)
|
||||
return packet
|
||||
|
||||
|
||||
|
||||
|
||||
326
plugins/serializables/client_to_world.py
Normal file
326
plugins/serializables/client_to_world.py
Normal file
@@ -0,0 +1,326 @@
|
||||
"""
|
||||
Contains all the packets sent from the client to the world/char server
|
||||
"""
|
||||
from pyraknet import bitstream
|
||||
from ..serializables import misc_serializables, packet_enum
|
||||
|
||||
|
||||
class UserSessionInfoPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-04-00-01]
|
||||
This packet contains the username and session key of a user who went through
|
||||
the auth server.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.username = ""
|
||||
self.user_key = ""
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
raise Exception("This Serializable can only deserialize")
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = UserSessionInfoPacket()
|
||||
packet.username = stream.read(str, allocated_length=33)
|
||||
packet.user_key = stream.read(str, allocated_length=33)
|
||||
return packet
|
||||
|
||||
|
||||
class MinifigureListRequestPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-04-00-02]
|
||||
This packet actually doesn't have any info. It's just here because it exists.
|
||||
This is sent to let the server know that it's ready for the minifgure list
|
||||
"""
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
raise Exception("This Serializable can only deserialize")
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = UserSessionInfoPacket()
|
||||
return packet
|
||||
|
||||
|
||||
class MinifigureCreateRequestPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-04-00-03]
|
||||
This packet is sent when a character clicks the create minfigure button.
|
||||
It contains all of the selection choices he/she made.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
self.predef_name_1 = 0
|
||||
self.predef_name_2 = 0
|
||||
self.predef_name_3 = 0
|
||||
self.unknown_0 = 0
|
||||
self.head_color = 0
|
||||
self.head = 0
|
||||
self.chest_color = 0
|
||||
self.chest = 0
|
||||
self.legs = 0
|
||||
self.hair_style = 0
|
||||
self.hair_color = 0
|
||||
self.left_hand = 0
|
||||
self.right_hand = 0
|
||||
self.eyebrow_style = 0
|
||||
self.eyes_style = 0
|
||||
self.mouth_style = 0
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
raise Exception("This Serializable can only deserialize")
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = MinifigureCreateRequestPacket()
|
||||
packet.name = stream.read(str, allocated_length=33)
|
||||
packet.predef_name_1 = stream.read(bitstream.c_uint32)
|
||||
packet.predef_name_2 = stream.read(bitstream.c_uint32)
|
||||
packet.predef_name_3 = stream.read(bitstream.c_uint32)
|
||||
packet.unknown_0 = stream.read(bitstream.c_uint8)
|
||||
packet.head_color = stream.read(bitstream.c_uint32)
|
||||
packet.head = stream.read(bitstream.c_uint32)
|
||||
packet.chest_color = stream.read(bitstream.c_uint32)
|
||||
packet.chest = stream.read(bitstream.c_uint32)
|
||||
packet.legs = stream.read(bitstream.c_uint32)
|
||||
packet.hair_style = stream.read(bitstream.c_uint32)
|
||||
packet.hair_color = stream.read(bitstream.c_uint32)
|
||||
packet.left_hand = stream.read(bitstream.c_uint32)
|
||||
packet.right_hand = stream.read(bitstream.c_uint32)
|
||||
packet.eyebrow_style = stream.read(bitstream.c_uint32)
|
||||
packet.eyes_style = stream.read(bitstream.c_uint32)
|
||||
packet.mouth_style = stream.read(bitstream.c_uint32)
|
||||
return packet
|
||||
|
||||
def to_login_character(self):
|
||||
char = misc_serializables.LoginCharacter()
|
||||
first = open('./res/minifigname_first.txt', 'r')
|
||||
safe_name = first.readlines()[self.predef_name_1].rstrip()
|
||||
first.close()
|
||||
middle = open('./res/minifigname_middle.txt', 'r')
|
||||
safe_name += middle.readlines()[self.predef_name_2].rstrip()
|
||||
middle.close()
|
||||
last = open('./res/minifigname_last.txt', 'r')
|
||||
safe_name += last.readlines()[self.predef_name_3].rstrip()
|
||||
last.close()
|
||||
char.object_id = misc_serializables.LwoObjID.gen_lwoobjid(persistent=True, character=True)
|
||||
char.current_name = safe_name
|
||||
char.unapproved_name = self.name
|
||||
char.head_color = self.head_color
|
||||
char.head = self.head
|
||||
char.chest_color = self.chest_color
|
||||
char.chest = self.chest
|
||||
char.legs = self.legs
|
||||
char.hair_style = self.hair_style
|
||||
char.hair_color = self.hair_color
|
||||
char.left_hand = self.left_hand
|
||||
char.right_hand = self.right_hand
|
||||
char.eyebrows_style = self.eyebrow_style
|
||||
char.eyes_style = self.eyes_style
|
||||
char.mouth_style = self.mouth_style
|
||||
|
||||
shirt_id = 0
|
||||
if self.chest_color == 0:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5730
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_BRIGHT_RED.value
|
||||
elif self.chest_color == 1:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5736
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_BRIGHT_BLUE.value
|
||||
elif self.chest_color == 3:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5808
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_DARK_GREEN.value
|
||||
elif self.chest_color == 5:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5754
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_BRIGHT_ORANGE.value
|
||||
elif self.chest_color == 6:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5760
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_BLACK.value
|
||||
elif self.chest_color == 7:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5766
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_DARK_STONE_GRAY.value
|
||||
elif self.chest_color == 8:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5772
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_MEDIUM_STONE_GRAY.value
|
||||
elif self.chest_color == 9:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5778
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_REDDISH_BROWN.value
|
||||
elif self.chest_color == 10:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5784
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_WHITE.value
|
||||
elif self.chest_color == 11:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5802
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_MEDIUM_BLUE.value
|
||||
elif self.chest_color == 13:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5796
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_DARK_RED.value
|
||||
elif self.chest_color == 14:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5802
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_EARTH_BLUE.value
|
||||
elif self.chest_color == 15:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5808
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_EARTH_GREEN.value
|
||||
elif self.chest_color == 16:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5814
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_BRICK_YELLOW.value
|
||||
elif self.chest_color == 84:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5820
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_SAND_BLUE.value
|
||||
elif self.chest_color == 96:
|
||||
if self.chest >= 35:
|
||||
shirt_id = 5826
|
||||
else:
|
||||
shirt_id = packet_enum.CreationLOT.SHIRT_SAND_GREEN.value
|
||||
|
||||
if self.chest >= 35:
|
||||
final_shirt_id = shirt_id + (self.chest - 35)
|
||||
else:
|
||||
final_shirt_id = shirt_id + (self.chest - 1)
|
||||
|
||||
if self.legs == 0:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_BRIGHT_RED.value
|
||||
elif self.legs == 1:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_BRIGHT_BLUE.value
|
||||
elif self.legs == 3:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_DARK_GREEN.value
|
||||
elif self.legs == 5:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_BRIGHT_ORANGE.value
|
||||
elif self.legs == 6:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_BLACK.value
|
||||
elif self.legs == 7:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_DARK_STONE_GRAY.value
|
||||
elif self.legs == 8:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_MEDIUM_STONE_GRAY.value
|
||||
elif self.legs == 9:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_REDDISH_BROWN.value
|
||||
elif self.legs == 10:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_WHITE.value
|
||||
elif self.legs == 11:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_MEDIUM_BLUE.value
|
||||
elif self.legs == 13:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_DARK_RED.value
|
||||
elif self.legs == 14:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_EARTH_BLUE.value
|
||||
elif self.legs == 15:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_EARTH_GREEN.value
|
||||
elif self.legs == 16:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_BRICK_YELLOW.value
|
||||
elif self.legs == 84:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_SAND_BLUE.value
|
||||
elif self.legs == 96:
|
||||
pants_id = packet_enum.CreationLOT.PANTS_SAND_GREEN.value
|
||||
else:
|
||||
pants_id = 2508
|
||||
|
||||
char.equipped_items.append(pants_id)
|
||||
char.equipped_items.append(final_shirt_id)
|
||||
|
||||
return char
|
||||
|
||||
|
||||
class JoinWorldPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-04-00-04]
|
||||
This packet is sent when a user clicks play.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.object_id = 0
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
raise Exception("This Serializable can only deserialize")
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = JoinWorldPacket()
|
||||
packet.object_id = stream.read(bitstream.c_int64)
|
||||
return packet
|
||||
|
||||
|
||||
class CharacterDeleteRequestPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-04-00-06]
|
||||
This packet is sent when a user deletes a character.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.object_id = 0
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
raise Exception("This Serializable can only deserialize")
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = CharacterDeleteRequestPacket()
|
||||
packet.object_id = stream.read(bitstream.c_int64)
|
||||
return packet
|
||||
|
||||
|
||||
class CharacterRenameRequestPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-04-00-07]
|
||||
This packet is sent when a user attempts to rename their character.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.object_id = 0
|
||||
self.new_name = ""
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
raise Exception("This Serializable can only deserialize")
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = CharacterRenameRequestPacket()
|
||||
packet.object_id = stream.read(bitstream.c_int64)
|
||||
packet.new_name = stream.read(str, allocated_length=33)
|
||||
return packet
|
||||
|
||||
|
||||
class ClientLoadCompletePacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-04-00-13]
|
||||
This packet is sent when the client is finished loading.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.zone_id = 0
|
||||
self.map_instance = 0
|
||||
self.map_clone = 0
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
raise Exception("This Serializable can only deserialize")
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = ClientLoadCompletePacket()
|
||||
packet.zone_id = stream.read(bitstream.c_uint16)
|
||||
packet.map_instance = stream.read(bitstream.c_uint16)
|
||||
packet.map_clone = stream.read(bitstream.c_uint32)
|
||||
return packet
|
||||
|
||||
|
||||
72
plugins/serializables/global_packets.py
Normal file
72
plugins/serializables/global_packets.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
Contains all the packets which are sent by either the client or server
|
||||
"""
|
||||
from pyraknet import bitstream
|
||||
|
||||
|
||||
class HandshakePacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-00-00-00]
|
||||
Global handshake packet serializable.
|
||||
This packet is sent to establish a connection.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.game_version = 171022
|
||||
self.unknown_0 = 0x93
|
||||
self.remote_connection_type = 0 # For auth this is 1, otherwise it is 4
|
||||
self.process_id = 1124
|
||||
self.local_port = 0xff
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(bitstream.c_uint32(self.game_version))
|
||||
stream.write(bitstream.c_uint32(self.unknown_0))
|
||||
stream.write(bitstream.c_uint32(self.remote_connection_type))
|
||||
stream.write(bitstream.c_uint32(self.process_id))
|
||||
stream.write(bitstream.c_uint16(self.local_port))
|
||||
stream.write("127.0.0.1", allocated_length=33)
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = HandshakePacket()
|
||||
packet.game_version = stream.read(bitstream.c_uint32)
|
||||
packet.unknown_0 = stream.read(bitstream.c_uint32)
|
||||
packet.remote_connection_type = stream.read(bitstream.c_uint32)
|
||||
packet.process_id = stream.read(bitstream.c_uint32)
|
||||
packet.local_port = stream.read(bitstream.c_uint16)
|
||||
return packet
|
||||
|
||||
|
||||
class DisconnectNotifyPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-00-00-01]
|
||||
This packet is sent when the server and client disconnect from each other
|
||||
"""
|
||||
def __init__(self):
|
||||
self.disconnect_id = 0
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(bitstream.c_uint32(self.disconnect_id))
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = DisconnectNotifyPacket()
|
||||
packet.disconnect_id = stream.read(bitstream.c_uint32)
|
||||
return packet
|
||||
|
||||
|
||||
class GeneralNotifyPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-00-00-02]
|
||||
This packet is sent to notify the player?
|
||||
"""
|
||||
def __init__(self):
|
||||
self.notify_id = 0
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(bitstream.c_uint32(self.notify_id))
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
packet = GeneralNotifyPacket()
|
||||
packet.notify_id = stream.read(bitstream.c_uint32)
|
||||
return packet
|
||||
192
plugins/serializables/misc_serializables.py
Normal file
192
plugins/serializables/misc_serializables.py
Normal file
@@ -0,0 +1,192 @@
|
||||
from pyraknet import bitstream
|
||||
import random
|
||||
import sqlite3
|
||||
from xml.etree import ElementTree
|
||||
|
||||
|
||||
class CString(bitstream.Serializable):
|
||||
def __init__(self, data='', allocated_length=None, length_type=None):
|
||||
self.data = data
|
||||
self.allocated_length = allocated_length
|
||||
self.length_type = length_type
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(self.data if isinstance(self.data, bytes) else bytes(self.data, 'latin1'),
|
||||
allocated_length=self.allocated_length, length_type=self.length_type)
|
||||
|
||||
def deserialize(self, stream: bitstream.ReadStream):
|
||||
return stream.read(bytes, allocated_length=self.allocated_length, length_type=self.length_type).decode('latin1')
|
||||
|
||||
|
||||
class LwoObjID:
|
||||
"""
|
||||
This is the data type that object ids are made out of.
|
||||
They are different from normal 64 bit ints because they have flags that must be set.
|
||||
"""
|
||||
@classmethod
|
||||
def gen_lwoobjid(cls, persistent: bool = False, client: bool = False, spawned: bool = False,
|
||||
character: bool = False):
|
||||
number = random.randrange(0, (2**32) - 1)
|
||||
number = number | (int(persistent) << 32)
|
||||
number = number | (int(client) << 46)
|
||||
number = number | (int(spawned) << 58)
|
||||
number = number | (int(character) << 60)
|
||||
return number
|
||||
|
||||
|
||||
class LDF(bitstream.Serializable):
|
||||
"""
|
||||
Lego Data Format
|
||||
"""
|
||||
def __init__(self):
|
||||
self._keys: list = []
|
||||
|
||||
def register_key(self, key_name: str, value: any, value_type: int):
|
||||
self._keys.append([key_name, value, value_type])
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
key_num = len(self._keys)
|
||||
stream.write(bitstream.c_uint(key_num))
|
||||
for key in self._keys:
|
||||
name = key[0]
|
||||
value = key[1]
|
||||
value_type = key[2]
|
||||
stream.write(bitstream.c_uint8(len(name) * 2))
|
||||
for char in name:
|
||||
stream.write(char.encode('latin1'))
|
||||
stream.write(b'\0')
|
||||
stream.write(bitstream.c_ubyte(value_type))
|
||||
if value_type == 0:
|
||||
stream.write(value, length_type=bitstream.c_uint)
|
||||
elif value_type == 1:
|
||||
stream.write(bitstream.c_int(value))
|
||||
elif value_type == 3:
|
||||
stream.write(bitstream.c_float(value))
|
||||
elif value_type == 5:
|
||||
stream.write(bitstream.c_uint(value))
|
||||
elif value_type == 7:
|
||||
stream.write(bitstream.c_bool(value))
|
||||
elif value_type == 8 or value_type == 9:
|
||||
stream.write(bitstream.c_int64(value))
|
||||
elif value_type == 13:
|
||||
xml_str = bytes(ElementTree.tostring(value))
|
||||
xml_str = b'<?xml version="1.0">' + xml_str
|
||||
stream.write(bitstream.c_ulong(xml_str.__len__()))
|
||||
stream.write(xml_str)
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
raise Exception("This struct cannot be deserialized")
|
||||
|
||||
|
||||
class LoginCharacter(bitstream.Serializable):
|
||||
"""
|
||||
This is a serializable that creates the struct which is repeated in the minfigure list packet
|
||||
"""
|
||||
def __init__(self):
|
||||
self.object_id = 1124
|
||||
self.current_name = ""
|
||||
self.unapproved_name = ""
|
||||
self.name_rejected = False
|
||||
self.is_ftp = False
|
||||
self.head_color = 0
|
||||
self.head = 0
|
||||
self.chest_color = 0
|
||||
self.chest = 0
|
||||
self.legs = 0
|
||||
self.hair_style = 0
|
||||
self.hair_color = 0
|
||||
self.left_hand = 0
|
||||
self.right_hand = 0
|
||||
self.eyebrows_style = 0
|
||||
self.eyes_style = 0
|
||||
self.mouth_style = 0
|
||||
self.last_zone = 0
|
||||
self.last_map_instance = 0
|
||||
self.last_map_clone = 0
|
||||
self.equipped_items = []
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
raise Exception("This struct cannot be deserialized")
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(bitstream.c_uint64(self.object_id))
|
||||
stream.write(bitstream.c_uint32(0))
|
||||
stream.write(self.current_name, allocated_length=33)
|
||||
stream.write(self.unapproved_name, allocated_length=33)
|
||||
stream.write(bitstream.c_bool(self.name_rejected))
|
||||
stream.write(bitstream.c_bool(self.is_ftp))
|
||||
stream.write(bitstream.c_uint32(self.head_color))
|
||||
stream.write(bitstream.c_uint16(0))
|
||||
stream.write(bitstream.c_uint32(self.head))
|
||||
stream.write(bitstream.c_uint32(self.chest_color))
|
||||
stream.write(bitstream.c_uint32(self.chest))
|
||||
stream.write(bitstream.c_uint32(self.legs))
|
||||
stream.write(bitstream.c_uint32(self.hair_style))
|
||||
stream.write(bitstream.c_uint32(self.hair_color))
|
||||
stream.write(bitstream.c_uint32(self.left_hand))
|
||||
stream.write(bitstream.c_uint32(self.right_hand))
|
||||
stream.write(bitstream.c_uint32(self.eyebrows_style))
|
||||
stream.write(bitstream.c_uint32(self.eyes_style))
|
||||
stream.write(bitstream.c_uint32(self.mouth_style))
|
||||
stream.write(bitstream.c_uint32(0))
|
||||
stream.write(bitstream.c_uint16(self.last_zone))
|
||||
stream.write(bitstream.c_uint16(self.last_map_instance))
|
||||
stream.write(bitstream.c_uint32(self.last_map_clone))
|
||||
stream.write(bitstream.c_uint64(0))
|
||||
stream.write(bitstream.c_uint16(len(self.equipped_items)))
|
||||
for item in self.equipped_items:
|
||||
stream.write(bitstream.c_uint32(item))
|
||||
|
||||
# For testing just use lot 6010
|
||||
@classmethod
|
||||
def from_cdclient(cls, lot: int):
|
||||
char = LoginCharacter()
|
||||
conn = sqlite3.connect("./res/cdclient.sqlite")
|
||||
c = conn.cursor()
|
||||
c.execute("SELECT displayName FROM Objects WHERE id = ?", (lot,))
|
||||
char.current_name = c.fetchone()[0].split("-")[0]
|
||||
c.execute("SELECT component_type, component_id FROM ComponentsRegistry WHERE id = ?", (lot,))
|
||||
components = c.fetchall()
|
||||
for comp in components:
|
||||
if comp[0] == 17:
|
||||
c.execute("SELECT itemid FROM InventoryComponent WHERE id = ?", (comp[1],))
|
||||
items = c.fetchall()
|
||||
equipped = []
|
||||
for i in items:
|
||||
equipped.append(i[0])
|
||||
char.equipped_items = equipped
|
||||
elif comp[0] == 35:
|
||||
c.execute("SELECT * FROM MinifigComponent WHERE id = ?", (comp[1],))
|
||||
minifig_comp = c.fetchone()
|
||||
char.head = minifig_comp[1]
|
||||
char.chest_color = minifig_comp[6]
|
||||
char.legs = minifig_comp[3]
|
||||
char.hair_style = minifig_comp[4]
|
||||
char.hair_color = minifig_comp[5]
|
||||
char.chest = minifig_comp[2]
|
||||
char.head_color = minifig_comp[7]
|
||||
char.left_hand = minifig_comp[8]
|
||||
char.right_hand = minifig_comp[9]
|
||||
char.eyebrows_style = minifig_comp[10]
|
||||
char.eyes_style = minifig_comp[11]
|
||||
char.mouth_style = minifig_comp[12]
|
||||
conn.close()
|
||||
return char
|
||||
|
||||
def save_to_db(self, account_id, connection):
|
||||
c = connection.cursor()
|
||||
c.execute("INSERT INTO wlus.character (character_id, current_name, requested_name, head_color,"
|
||||
" head, chest_color, chest, legs, hair_style, hair_color, left_hand, right_hand,"
|
||||
" eyebrow_style, eye_style, mouth_style, account_id) VALUES (%s, %s, %s, %s, %s, %s, %s, "
|
||||
"%s, %s, %s, %s, %s, %s, %s, %s, %s)", (self.object_id, self.current_name, self.unapproved_name,
|
||||
self.head_color, self.head, self.chest_color, self.chest,
|
||||
self.legs, self.hair_style, self.hair_color, self.left_hand,
|
||||
self.right_hand, self.eyebrows_style, self.eyes_style,
|
||||
self.mouth_style, account_id))
|
||||
for i in range(len(self.equipped_items)):
|
||||
item_id = LwoObjID.gen_lwoobjid()
|
||||
c.execute("INSERT INTO wlus.inventory (object_id, lot, slot, equipped, linked, quantity, player_id)"
|
||||
"VALUES (%s, %s, %s, 1, 1, 1, %s)", (item_id, self.equipped_items[i], i, self.object_id))
|
||||
connection.commit()
|
||||
97
plugins/serializables/packet_enum.py
Normal file
97
plugins/serializables/packet_enum.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
Contains all enums related to packets.
|
||||
"""
|
||||
from enum import Enum, IntEnum
|
||||
|
||||
|
||||
class PacketHeader(Enum):
|
||||
"""
|
||||
Contains the headers for packets.
|
||||
"""
|
||||
HANDSHAKE = b'S\x00\x00\x00\x00\x00\x00\x00'
|
||||
DISCONNECT_NOTIFY = b"S\x00\x00\x01\x00\x00\x00\x00"
|
||||
CLIENT_LOGIN_INFO = b'S\x01\x00\x00\x00\x00\x00\x00'
|
||||
LOGIN_RESPONSE = b'S\x05\x00\x00\x00\x00\x00\x00'
|
||||
CLIENT_USER_SESSION_INFO = b"S\x04\x00\x01\x00\x00\x00\x00"
|
||||
CLIENT_MINIFIGURE_LIST_REQUEST = b"S\x04\x00\x02\x00\x00\x00\x00"
|
||||
MINIFIGURE_LIST = b"S\x05\x00\x06\x00\x00\x00\x00"
|
||||
CLIENT_MINIFIGURE_CREATE_REQUEST = b"S\x04\x00\x03\x00\x00\x00\x00"
|
||||
MINIFIGURE_CREATION_RESPONSE = b"S\x05\x00\x08\x00\x00\x00\x00"
|
||||
CLIENT_DELETE_MINIFIGURE_REQUEST = b'S\x04\x00\x06\x00\x00\x00\x00'
|
||||
WORLD_INFO = b'S\x05\x00\x02\x00\x00\x00\x00'
|
||||
CLINET_ENTER_WORLD = b'S\x04\x00\x04\x00\x00\x00\x00'
|
||||
CLIENT_LOAD_COMPLETE = b'S\x04\x00\x13\x00\x00\x00\x00'
|
||||
DETAILED_USER_INFO = b'S\x05\x00\x04\x00\x00\x00\x00'
|
||||
ROUTED_PACKET = b'S\x04\x00\x15\x00\x00\x00\x00'
|
||||
CLIENT_GAME_MESSAGE = b'S\x04\x00\x05\x00\x00\x00\x00'
|
||||
SERVER_GAME_MESSAGE = b'S\x05\x00\x0c\x00\x00\x00\x00'
|
||||
CLIENT_POSITION_UPDATES = b'S\x04\x00\x16\x00\x00\x00\x00'
|
||||
CLIENT_CHAT_MESSAGE = b'S\x04\x00\x0e\x00\x00\x00\x00'
|
||||
CLIENT_WHITELIST_REQUEST = b'S\x04\x00\x19\x00\x00\x00\x00'
|
||||
CHAT_MODERATION_RESPONSE = b'S\x05\x00\x3b\x00\x00\x00\x00'
|
||||
|
||||
|
||||
class DisconnectionNotify(IntEnum):
|
||||
"""
|
||||
Contains various reasons for disconnect notify.
|
||||
"""
|
||||
UNKNOWN_ERROR = 0x00
|
||||
DUPLICATE_LOGIN = 0x04
|
||||
SERVER_SHUTDOWN = 0x05
|
||||
SERVER_CANNOT_LOAD_MAP = 0x06
|
||||
INVALID_SESSION_KEY = 0x07
|
||||
CHARACTER_NOT_FOUND = 0x09
|
||||
CHARACTER_CORRUPTION = 0x0a
|
||||
KICKED = 0x0b
|
||||
|
||||
|
||||
class LoginReturnCode(IntEnum):
|
||||
SUCCESS = 0x01
|
||||
BANNED = 0x02
|
||||
INVALID_PERM = 0x03
|
||||
INVALID_LOGIN_INFO = 0x06
|
||||
ACCOUNT_LOCKED = 0x07
|
||||
|
||||
|
||||
class ObjectFlag(IntEnum):
|
||||
OBJECT_BIT_PERSISTENT = 32
|
||||
OBJECT_BIT_CLIENT = 46
|
||||
OBJECT_BIT_SPAWNED = 58
|
||||
OBJECT_BIT_CHARACTER = 60
|
||||
|
||||
|
||||
class CreationLOT(IntEnum):
|
||||
SHIRT_BRIGHT_RED = 4049
|
||||
SHIRT_BRIGHT_BLUE = 4083
|
||||
SHIRT_BRIGHT_YELLOW = 4117
|
||||
SHIRT_DARK_GREEN = 4151
|
||||
SHIRT_BRIGHT_ORANGE = 4185
|
||||
SHIRT_BLACK = 4219
|
||||
SHIRT_DARK_STONE_GRAY = 4253
|
||||
SHIRT_MEDIUM_STONE_GRAY = 4287
|
||||
SHIRT_REDDISH_BROWN = 4321
|
||||
SHIRT_WHITE = 4355
|
||||
SHIRT_MEDIUM_BLUE = 4389
|
||||
SHIRT_DARK_RED = 4423
|
||||
SHIRT_EARTH_BLUE = 4457
|
||||
SHIRT_EARTH_GREEN = 4491
|
||||
SHIRT_BRICK_YELLOW = 4525
|
||||
SHIRT_SAND_BLUE = 4559
|
||||
SHIRT_SAND_GREEN = 4593
|
||||
|
||||
PANTS_BRIGHT_RED = 2508
|
||||
PANTS_BRIGHT_ORANGE = 2509
|
||||
PANTS_BRICK_YELLOW = 2511
|
||||
PANTS_MEDIUM_BLUE = 2513
|
||||
PANTS_SAND_GREEN = 2514
|
||||
PANTS_DARK_GREEN = 2515
|
||||
PANTS_EARTH_GREEN = 2516
|
||||
PANTS_EARTH_BLUE = 2517
|
||||
PANTS_BRIGHT_BLUE = 2519
|
||||
PANTS_SAND_BLUE = 2520
|
||||
PANTS_DARK_STONE_GRAY = 2521
|
||||
PANTS_MEDIUM_STONE_GRAY = 2522
|
||||
PANTS_WHITE = 2523
|
||||
PANTS_BLACK = 2524
|
||||
PANTS_REDDISH_BROWN = 2526
|
||||
PANTS_DARK_RED = 2527
|
||||
7
plugins/serializables/plugin.json
Normal file
7
plugins/serializables/plugin.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Serializables Module",
|
||||
"id": "serializables",
|
||||
"description": "Module for various serializable types.",
|
||||
"type": "module",
|
||||
"dependencies": []
|
||||
}
|
||||
26
plugins/serializables/replica_components.py
Normal file
26
plugins/serializables/replica_components.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""
|
||||
This file contains all of the replica components and the structs withing them
|
||||
"""
|
||||
from pyraknet import bitstream
|
||||
|
||||
|
||||
class BaseDataComponent(bitstream.Serializable):
|
||||
"""
|
||||
Base Data should be supplied with every replica.
|
||||
replica_mode refers to whether or not it is construction, serialization or destruction.
|
||||
Construction - 0
|
||||
Serialization - 1
|
||||
Destruction - 2
|
||||
"""
|
||||
def __init__(self, replica_mode: int = 0):
|
||||
self.replica_mode = replica_mode
|
||||
self.object_id = 0
|
||||
self.lot = 0
|
||||
self.name = ""
|
||||
self.time_since_created = 0
|
||||
self.has_trigger = False
|
||||
self.spawner_id = 0
|
||||
self.spawner_node_id = 0
|
||||
self.scale = 1
|
||||
self.object_world_state = 0
|
||||
self.gm_level = 0
|
||||
65
plugins/serializables/world_to_client.py
Normal file
65
plugins/serializables/world_to_client.py
Normal file
@@ -0,0 +1,65 @@
|
||||
"""
|
||||
Contains all the packets that the world/char server would send to the client
|
||||
"""
|
||||
from pyraknet import bitstream
|
||||
|
||||
|
||||
class MinfigureListPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-05-00-06]
|
||||
This sends all of the characters to the client.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.current_index = 0
|
||||
self.minifigs = []
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
raise Exception("This packet cannot be deserialized")
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(bitstream.c_uint8(len(self.minifigs)))
|
||||
stream.write(bitstream.c_uint8(self.current_index))
|
||||
for m in self.minifigs:
|
||||
stream.write(m)
|
||||
|
||||
|
||||
class MinifigureCreationResponsePacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-05-00-07]
|
||||
Lets the client know how the creation process was handled.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.response = 0x00
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
raise Exception("This packet cannot be deserialized")
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(bitstream.c_uint8(self.response))
|
||||
|
||||
|
||||
class RedirectiontoNewServerPacket(bitstream.Serializable):
|
||||
"""
|
||||
[53-05-00-0e]
|
||||
This packet redirects the client to connect to a new server.
|
||||
If worlds are hosted on separate servers, send this packet and
|
||||
let the other server handle the load world packet. It would
|
||||
probably be best if the other server sent the load world on
|
||||
handshake - because when would there be a connection which wasn't
|
||||
trying to load in the world.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.redirect_ip = "127.0.0.1"
|
||||
self.redirect_port = 1124
|
||||
self.is_mythran_dimension_shift = False
|
||||
|
||||
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
|
||||
raise Exception("This packet cannot be deserialized")
|
||||
|
||||
def serialize(self, stream: bitstream.WriteStream) -> None:
|
||||
stream.write(self.redirect_ip, allocated_length=33)
|
||||
stream.write(bitstream.c_uint16(self.redirect_port))
|
||||
stream.write(bitstream.c_bool(self.is_mythran_dimension_shift))
|
||||
@@ -1,6 +0,0 @@
|
||||
<60>
|
||||
[bit] - {replica.has_component(components.BaseCombatAI)}
|
||||
{%if previous == True%}
|
||||
[u32] - {replica.get_component(components.BaseCombatAI).action}
|
||||
[s64] - {replica.get_component(components.BaseCombatAI).target_id}
|
||||
{%end%}
|
||||
@@ -1,5 +0,0 @@
|
||||
<6>
|
||||
[bit] - {False}
|
||||
{%if previous == True%}
|
||||
[bit] - {True}#This is apparently "PetNotRequired" but I don't really care about pet bouncers right now
|
||||
{%end%}
|
||||
@@ -1,99 +0,0 @@
|
||||
<4>
|
||||
{character = replica.get_component(components.Character)}
|
||||
{player, account = character.get_player_info()}
|
||||
{minifig_comp = replica.get_component(components.Minifig)}
|
||||
{stats = player["Stats"]}
|
||||
[bit] - {character.vehicle_id != 0}
|
||||
{%if previous == True%}
|
||||
[bit] - {True}
|
||||
[s64] - {character.vehicle_id}
|
||||
[u8] - {0}
|
||||
{%end%}
|
||||
[bit] - {True}
|
||||
[u32] - {player["Data"]["level"]}
|
||||
[bit] - {False}
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
#[u64] - ???, could be "co" from xml data
|
||||
[bit] - {False}
|
||||
#[u64] - ???
|
||||
[bit] - {False}
|
||||
#[u64] - ???
|
||||
[bit] - {False}
|
||||
#[u64] - ???
|
||||
{%if minifig_comp is not None%}
|
||||
[u32] - {minifig_comp.hair_color}
|
||||
[u32] - {minifig_comp.hair_style}
|
||||
[u32] - {0}
|
||||
[u32] - {minifig_comp.chest}
|
||||
[u32] - {minifig_comp.legs}
|
||||
[u32] - {0}
|
||||
[u32] - {0}
|
||||
[u32] - {minifig_comp.eyebrows}
|
||||
[u32] - {minifig_comp.eyes}
|
||||
[u32] - {minifig_comp.mouth}
|
||||
{%end%}
|
||||
{%else%}
|
||||
[u32] - {player["hair_color"]}
|
||||
[u32] - {player["hair_style"]}
|
||||
[u32] - {0}
|
||||
[u32] - {player["shirt_color"]}
|
||||
[u32] - {player["pants_color"]}
|
||||
[u32] - {0}
|
||||
[u32] - {0}
|
||||
[u32] - {player["eyebrows"]}
|
||||
[u32] - {player["eyes"]}
|
||||
[u32] - {player["mouth"]}
|
||||
{%end%}
|
||||
[u64] - {player["account_id"]}
|
||||
[u64] - {0}
|
||||
[u64] - {0}
|
||||
[u64] - {player["Data"]["universe_score"]}
|
||||
[bit] - {False}
|
||||
[u64] - {stats["currency_collected"]}
|
||||
[u64] - {stats["bricks_collected"]}
|
||||
[u64] - {stats["smashables_smashed"]}
|
||||
[u64] - {stats["quick_builds_done"]}
|
||||
[u64] - {stats["enemies_smashed"]}
|
||||
[u64] - {stats["rockets_used"]}
|
||||
[u64] - {len(player["CompletedMissions"])}
|
||||
[u64] - {stats["pets_tamed"]}
|
||||
[u64] - {stats["imagination_collected"]}
|
||||
[u64] - {stats["health_collected"]}
|
||||
[u64] - {stats["armor_collected"]}
|
||||
[u64] - {stats["distance_traveled"]}
|
||||
[u64] - {stats["times_died"]}
|
||||
[u64] - {stats["damage_taken"]}
|
||||
[u64] - {stats["damage_healed"]}
|
||||
[u64] - {stats["armor_repaired"]}
|
||||
[u64] - {stats["imagination_restored"]}
|
||||
[u64] - {stats["imagination_used"]}
|
||||
[u64] - {stats["distance_driven"]}
|
||||
[u64] - {stats["time_airborne_in_car"]}
|
||||
[u64] - {stats["racing_imagination_collected"]}
|
||||
[u64] - {stats["racing_imagination_crates_smashed"]}
|
||||
[u64] - {stats["race_car_boosts"]}
|
||||
[u64] - {stats["car_wrecks"]}
|
||||
[u64] - {stats["racing_smashables_smashed"]}
|
||||
[u64] - {stats["races_finished"]}
|
||||
[u64] - {stats["races_won"]}
|
||||
[bit] - {False}
|
||||
[bit] - {False}#This needs to be implemented for rockets
|
||||
#[u16-wstring] - LDF info of rocket modules
|
||||
{%end%}
|
||||
[bit] - {True}
|
||||
[bit] - {replica.zone.pvp_enabled}
|
||||
[bit] - {False}
|
||||
[u8] - {character.gm_level}
|
||||
[bit] - {False}
|
||||
[u8] - {0}
|
||||
[bit] - {True}
|
||||
[u32] - {character.head_glow}
|
||||
[bit] - {False}
|
||||
#TODO: Implement Guilds
|
||||
#[s64] - guild (leader?) id, assert == 0
|
||||
#[u8-wstring] - guild name, assert == ""
|
||||
#[bit] - ???
|
||||
#[s32] - ???
|
||||
@@ -1 +0,0 @@
|
||||
[u16] - {replica.get_component(components.Collectible).collectible_id}
|
||||
@@ -1,3 +0,0 @@
|
||||
<107>
|
||||
[bit] - {False}
|
||||
#[s64] - ???
|
||||
@@ -1,8 +0,0 @@
|
||||
<108>
|
||||
[bit] - {False}
|
||||
#[bit] - flag
|
||||
#[s64] - driver object id
|
||||
#[bit] - flag
|
||||
#[u32] - possessable component id?
|
||||
#[bit] - ???
|
||||
#I should Implement this eventually
|
||||
@@ -1,60 +0,0 @@
|
||||
<1>
|
||||
{transform = replica.get_component(components.Transform)}
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
#[u32] - jetpack effect id
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
[bit] - {False}
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
{%end%}
|
||||
[bit] - {False}
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
[bit] - {False}
|
||||
#[float] - ???
|
||||
#[bit] - ???
|
||||
[bit] - {False}
|
||||
#[bit] - flag
|
||||
#[u32] - ???
|
||||
#[bit] - ???
|
||||
[bit] - {True}
|
||||
[float] - {transform.position.X}
|
||||
[float] - {transform.position.Y}
|
||||
[float] - {transform.position.Z}
|
||||
[float] - {transform.rotation.X}
|
||||
[float] - {transform.rotation.Y}
|
||||
[float] - {transform.rotation.Z}
|
||||
[float] - {transform.rotation.W}
|
||||
[bit] - {transform.on_ground}
|
||||
[bit] - {False}#On Rail
|
||||
[bit] - {transform.velocity != game_types.Vector3(0.0, 0.0, 0.0)}
|
||||
{%if previous == True%}
|
||||
[float] - {transform.velocity.X}
|
||||
[float] - {transform.velocity.Y}
|
||||
[float] - {transform.velocity.Z}
|
||||
{%end%}
|
||||
[bit] - {transform.angular_velocity != game_types.Vector3(0.0, 0.0, 0.0)}
|
||||
{%if previous == True%}
|
||||
[float] - {transform.angular_velocity.X}
|
||||
[float] - {transform.angular_velocity.Y}
|
||||
[float] - {transform.angular_velocity.Z}
|
||||
{%end%}
|
||||
[bit] - {False}
|
||||
#[s64] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[bit] - flag
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
{%if replica_type != game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
{%end%}
|
||||
@@ -1,39 +0,0 @@
|
||||
<7>
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
#[u32] - count for following structs
|
||||
#[u32] - ???
|
||||
#[bit] - flag
|
||||
#[u32] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#trigger=[bit] - ???, seems to trigger [s64] below?
|
||||
#[bit] - ???
|
||||
#if trigger:
|
||||
#[s64] - ???
|
||||
#[u32] - ???
|
||||
[bit] - {False}
|
||||
#[u32] - count for following structs
|
||||
#[u32] - ???
|
||||
#[bit] - flag
|
||||
#[u32] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#trigger=[bit] - ???, seems to trigger [s64] below?
|
||||
#[bit] - ???
|
||||
#if trigger:
|
||||
#[s64] - ???
|
||||
#[u32] - ???
|
||||
{%end%}
|
||||
@@ -1,4 +0,0 @@
|
||||
Exhibit ($+863790):
|
||||
[bit] - {False}
|
||||
#[s32] - exhibited LOT
|
||||
#Should be in replica.get_component(components.LUPExhibit) but I won't implement that right now
|
||||
@@ -1,47 +0,0 @@
|
||||
<17>
|
||||
{inventory = replica.get_component(components.Inventory)}
|
||||
{%if game.get_service("Player").get_player_by_id(int(replica.get_object_id())) is None%}
|
||||
[bit] - {True}
|
||||
[u32] - {len(inventory.items)}
|
||||
{%for item in inventory.items%}
|
||||
[s64] - {item["item_id"]}
|
||||
[lot] - {item["lot"]}
|
||||
[bit] - {False}
|
||||
#[s64] - ???
|
||||
[bit] - {True}
|
||||
[u32] - {item["quantity"]}
|
||||
[bit] - {True}
|
||||
[u16] - {item["slot"]}
|
||||
[bit] - {False}
|
||||
#[u32] - inventory type?, expect == 4
|
||||
[bit] - {False}
|
||||
#[compressed_ldf] - extra data
|
||||
#Should Probably Implement this
|
||||
[bit] - {True}
|
||||
{%end%}
|
||||
[bit] - {False}
|
||||
#[u32] - ???, assert == 0
|
||||
{%end%}
|
||||
{%else%}
|
||||
{player_items = game.get_service("Player").get_equipped_items(int(replica.get_object_id()))}
|
||||
[bit] - {True}
|
||||
[u32] - {len(player_items)}
|
||||
{%for item in player_items%}
|
||||
[s64] - {item["item_id"]}
|
||||
[lot] - {item["lot"]}
|
||||
[bit] - {False}
|
||||
#[s64] - ???
|
||||
[bit] - {True}
|
||||
[u32] - {item["quantity"]}
|
||||
[bit] - {True}
|
||||
[u16] - {item["slot"]}
|
||||
[bit] - {False}
|
||||
#[u32] - inventory type?, expect == 4
|
||||
[bit] - {False}
|
||||
#[compressed_ldf] - extra data
|
||||
#Should Probably Implement this
|
||||
[bit] - {True}
|
||||
{%end%}
|
||||
[bit] - {False}
|
||||
#[u32] - ???, assert == 0
|
||||
{%end%}
|
||||
@@ -1,9 +0,0 @@
|
||||
<61>
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
#[bit] - flag
|
||||
#[s64] - ???
|
||||
#[bit] - ???
|
||||
#[u16-wstring] - ???
|
||||
{%end%}
|
||||
#Need to implement
|
||||
@@ -1,41 +0,0 @@
|
||||
<25>
|
||||
[bit] - {False}
|
||||
[bit] - {False}
|
||||
#[bit] - ???
|
||||
#[u16-wstring] - path name
|
||||
#[u32] - ???
|
||||
#[bit] - ???
|
||||
#if flag:#(First Flag)
|
||||
#[bit] - ???
|
||||
#subcomponent_type=[u32] - subcomponent type, 4 - mover, 5 - simple mover?, expect in (4, 5)
|
||||
#if subcomponent_type == 4:
|
||||
#[bit] - ???
|
||||
#[u32] - state
|
||||
#[s32] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - based on this and some other criteria some other things are also included?
|
||||
#[float] - ???
|
||||
|
||||
#[float] - unexpected position x
|
||||
#[float] - unexpected position y
|
||||
#[float] - unexpected position z
|
||||
|
||||
#[u32] - current waypoint index
|
||||
#[u32] - next waypoint index
|
||||
|
||||
#[float] - idle time elapsed
|
||||
#[u32] - ???
|
||||
#if subcomponent_type == 5:
|
||||
#[bit] - flag
|
||||
#[bit] - flag
|
||||
#[float] - position x?
|
||||
#[float] - position y?
|
||||
#[float] - position z?
|
||||
#[float] - rotation x?
|
||||
#[float] - rotation y?
|
||||
#[float] - rotation z?
|
||||
#[float] - rotation w?
|
||||
#[bit] - flag
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[bit] - ???
|
||||
@@ -1,13 +0,0 @@
|
||||
<26>
|
||||
[bit] - {False}
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[bit] - flag, expect == False
|
||||
#[s64] - ???
|
||||
#[bit] - flag, expect == False
|
||||
#[s64] - ???
|
||||
#[bit] - flag, expect == False
|
||||
#[u32] - ???
|
||||
#[u8-wstring] - pet name
|
||||
#[u8-wstring] - pet owner name
|
||||
#Need to implement
|
||||
@@ -1,22 +0,0 @@
|
||||
<40>
|
||||
{transform = replica.get_component(components.Transform)}
|
||||
[bit] - {True}
|
||||
[float] - {transform.position.X}
|
||||
[float] - {transform.position.Y}
|
||||
[float] - {transform.position.Z}
|
||||
[float] - {transform.rotation.X}
|
||||
[float] - {transform.rotation.Y}
|
||||
[float] - {transform.rotation.Z}
|
||||
[float] - {transform.rotation.W}
|
||||
[bit] - {False}
|
||||
#[bit] - is physics effect active
|
||||
#[u32] - effect type, 0 = push, 1 = attract, 2 = repulse, 3 = gravity, 4 = friction
|
||||
#[float] - effect amount
|
||||
#[bit] - flag
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[bit] - flag
|
||||
#[float] - effect direction x
|
||||
#[float] - effect direction y
|
||||
#[float] - effect direction z
|
||||
#I do already have the physics effect component but this is just a quick implementation for now
|
||||
@@ -1,41 +0,0 @@
|
||||
<71>
|
||||
[bit] - {False}
|
||||
#[u32] - count
|
||||
#[u64] - player object id
|
||||
#constant size 10 loop
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
[bit] - {False}
|
||||
#[u16] - ???
|
||||
[bit] - {False}
|
||||
#while True:
|
||||
#not_break=[bit] - flag
|
||||
#if not not_break:
|
||||
#break
|
||||
#[s64] - player object id
|
||||
#[s64] - car object id
|
||||
#[u32] - ???
|
||||
#[bit] - ???
|
||||
[bit] - {False}
|
||||
#while True:
|
||||
#not_break=[bit] - flag
|
||||
#if not not_break:
|
||||
#break
|
||||
#[s64] - player object id
|
||||
#[u32] - ???
|
||||
[bit] - {False}
|
||||
#[u16] - remaining laps?
|
||||
#[u16-wstring] - path name
|
||||
[bit] - {False}
|
||||
#[bit] - flag
|
||||
#[s64] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
@@ -1,28 +0,0 @@
|
||||
[bit] - {False}
|
||||
#[u32] - count
|
||||
#[u64] - player object id
|
||||
#constant size 10 loop
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#end of ScriptedActivity
|
||||
[bit] - {False}
|
||||
#[u32] - rebuild state
|
||||
#[bit] - success
|
||||
#[bit] - enabled
|
||||
#[float] - rebuild time
|
||||
#[float] - a time related to paused rebuilds, expect == 0
|
||||
#if creation:
|
||||
#[bit] - ???
|
||||
#[u32] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[bit] - ???
|
||||
@@ -1,10 +0,0 @@
|
||||
<2>
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[s32] - {0}
|
||||
#[u8-string] - effect name
|
||||
#[s32] - effectID
|
||||
#[u8-wstring] - effectType
|
||||
#[float] - scale or priority?
|
||||
#[s64] - secondary?
|
||||
{%end%}
|
||||
#Should probably implement this soon
|
||||
@@ -1,10 +0,0 @@
|
||||
<20>
|
||||
{transform = replica.get_component(components.Transform)}
|
||||
[bit] - {True}
|
||||
[float] - {transform.position.X}
|
||||
[float] - {transform.position.Y}
|
||||
[float] - {transform.position.Z}
|
||||
[float] - {transform.rotation.X}
|
||||
[float] - {transform.rotation.Y}
|
||||
[float] - {transform.rotation.Z}
|
||||
[float] - {transform.rotation.W}
|
||||
@@ -1,5 +0,0 @@
|
||||
<5>
|
||||
{transform = replica.get_component(components.Transform)}
|
||||
[bit] - {False}
|
||||
#[compressed_ldf] - script variables
|
||||
{%end%}
|
||||
@@ -1,15 +0,0 @@
|
||||
<39>
|
||||
[bit] - {False}
|
||||
#[u32] - count
|
||||
#[s64] - player object id
|
||||
#constant size 10 loop
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
@@ -1,37 +0,0 @@
|
||||
<19>
|
||||
[bit] - {False}
|
||||
#[u32] - count
|
||||
#[s64] - player object id
|
||||
#constant size 10 loop
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[float] - {0}
|
||||
[float] - {0}
|
||||
[float] - {0}
|
||||
[float] - {0}
|
||||
[float] - {0}
|
||||
[float] - {0}
|
||||
{%end%}
|
||||
[bit] - {False}
|
||||
#[double] - Cannon Velocity
|
||||
#[double] - Cannon Refire Rate
|
||||
#[double] - Cannon Min Distance
|
||||
#[float] - Cannon Barrel Offset X
|
||||
#[float] - Cannon Barrel Offset Y
|
||||
#[float] - Cannon Barrel Offset Z
|
||||
#[float] - Cannon Angle
|
||||
#[float] - Facing X
|
||||
#[float] - Facing Y
|
||||
#[float] - Facing Z
|
||||
#[u64] - ???
|
||||
#[float] - ???, expect == -1
|
||||
#[float] - Cannon FOV
|
||||
@@ -1,23 +0,0 @@
|
||||
<3>
|
||||
{transform = replica.get_component(components.Transform)}
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
[float] - {0}
|
||||
{%end%}
|
||||
[bit] - {False}
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
[bit] - {False}
|
||||
#[u32] - ???, expect == 5
|
||||
[bit] - {True}
|
||||
[float] - {transform.position.X}
|
||||
[float] - {transform.position.Y}
|
||||
[float] - {transform.position.Z}
|
||||
[float] - {transform.rotation.X}
|
||||
[float] - {transform.rotation.Y}
|
||||
[float] - {transform.rotation.Z}
|
||||
[float] - {transform.rotation.W}
|
||||
@@ -1,21 +0,0 @@
|
||||
<9>
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
#[u32] - count for following structs
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - count for following structs
|
||||
#[u32] - ???
|
||||
#[u32] - ???, seems to be something in BehaviorTemplate?
|
||||
#[u32] - ???
|
||||
#[u32] - ???, expect == 18
|
||||
#[s64] - ???
|
||||
#[s64] - ???
|
||||
#[s64] - ???, expect == 0
|
||||
#[bit] - ???, assert == False
|
||||
#[float] - ???, expect == 0
|
||||
#[u32] - ???, expect == 0
|
||||
#[u32] - ???, expect == 0
|
||||
{%end%}
|
||||
@@ -1,42 +0,0 @@
|
||||
{stats = replica.get_component(components.Stats)}
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
#[u32] - ???
|
||||
#[u32] - is boss?, expect == 0
|
||||
#Should Implement the boss thing soon
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
#[u32] - ???, expect == 0
|
||||
#[u32] - ???, assert == 0
|
||||
#[u32] - ???, assert == 0
|
||||
#[u32] - ???
|
||||
#[u32] - ???
|
||||
{%end%}
|
||||
[bit] - {True}
|
||||
[u32] - {stats.health}
|
||||
[float] - {stats.max_health}
|
||||
[u32] - {stats.armor}
|
||||
[float] - {stats.max_armor}
|
||||
[u32] - {stats.imagination}
|
||||
[float] - {stats.max_imagination}
|
||||
[u32] - {0}
|
||||
[bit] - {False}
|
||||
[bit] - {False}
|
||||
[bit] - {False}
|
||||
[float] - {stats.max_health}
|
||||
[float] - {stats.max_armor}
|
||||
[float] - {stats.max_imagination}
|
||||
[u32] - {1}
|
||||
[s32] - {stats.faction}
|
||||
[bit] - {stats.is_smashable}
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[bit] - {False}
|
||||
[bit] - {False}
|
||||
{%if stats.is_smashable == True%}
|
||||
[bit] - {False}
|
||||
[bit] - {False}
|
||||
#[float] - ???
|
||||
{%end%}
|
||||
{%end%}
|
||||
[bit] - {False}
|
||||
#[bit] - ???
|
||||
@@ -1,2 +0,0 @@
|
||||
<49>
|
||||
[bit] - {replica.get_component(components.Switch).state}
|
||||
@@ -1,5 +0,0 @@
|
||||
#Trigger Component
|
||||
#Seems like this component is append when there is a trigger_id entry in the luz
|
||||
#See also .lutriggers files in the client
|
||||
[bit] - {False}
|
||||
#[s32] - ???, expect == -1
|
||||
@@ -1,42 +0,0 @@
|
||||
<30>
|
||||
[bit] - {False}
|
||||
#[float] - position x
|
||||
#[float] - position y
|
||||
#[float] - position z
|
||||
#[float] - rotation x
|
||||
#[float] - rotation y
|
||||
#[float] - rotation z
|
||||
#[float] - rotation w
|
||||
#[bit] - is on ground
|
||||
#[bit] - ???
|
||||
#[bit] - flag
|
||||
#[float] - velocity x
|
||||
#[float] - velocity y
|
||||
#[float] - velocity z
|
||||
#[bit] - flag
|
||||
#[float] - angular velocity x
|
||||
#[float] - angular velocity y
|
||||
#[float] - angular velocity z
|
||||
#[bit] - flag
|
||||
#[s64] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[bit] - flag
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
|
||||
#[bit] - flag
|
||||
#[float] - ???
|
||||
#[float] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
#[float] - ???
|
||||
#if not creation:
|
||||
#[bit] - flag?
|
||||
#if creation:
|
||||
#[u8] - ???
|
||||
#[bit] - ???
|
||||
#[bit] - flag
|
||||
#[bit] - ???
|
||||
@@ -1,4 +0,0 @@
|
||||
<16>
|
||||
[bit] - {False}
|
||||
#[bit] - ???
|
||||
#[bit] - ???
|
||||
@@ -1,31 +0,0 @@
|
||||
{%if replica_type == game_enums.ReplicaTypes.CONSTRUCTION%}
|
||||
[s64]-{replica.get_object_id()}
|
||||
[s32]-{replica.lot}
|
||||
[u8-wstring]-{replica.get_name()}
|
||||
[u32]-{0}
|
||||
[bit]-{replica.has_component(components.ModelData)}
|
||||
{%if previous == True%}
|
||||
[ldf]-{replica.get_component(components.ModelData).ldf}
|
||||
{%end%}
|
||||
[bit]-{replica.has_component(components.Trigger)}
|
||||
[bit]-{replica.spawner_id is not None}
|
||||
{%if previous == True%}
|
||||
[s64]-{replica.spawner_id}
|
||||
{%end%}
|
||||
[bit]-{replica.spawner_node_id is not None}
|
||||
{%if previous == True%}
|
||||
[u32]-{replica.spawner_node_id}
|
||||
{%end%}
|
||||
[bit]-{replica.get_component(components.Transform).scale != 1}
|
||||
{%if previous == True%}
|
||||
[float]-{replica.get_component(components.Transform).scale}
|
||||
{%end%}
|
||||
[bit]-{False}
|
||||
{%if previous == True%}
|
||||
[u8]-{0}#ObjectWorldState
|
||||
{%end%}
|
||||
[bit]-{False}
|
||||
{%if previous == True%}
|
||||
[u8]-{0}#GMLevel
|
||||
{%end%}
|
||||
{%end%}
|
||||
@@ -1,8 +0,0 @@
|
||||
[bit]-{False}
|
||||
#[bit]-flag
|
||||
#[object_id]-parent object id
|
||||
#[bit]-???
|
||||
#[bit]-flag
|
||||
#[u16]-count
|
||||
#[u64]-child object id
|
||||
#I need to implement this but I'm just gonna be lazy for now
|
||||
@@ -1,343 +0,0 @@
|
||||
import services
|
||||
import game_objects
|
||||
import game_types
|
||||
import components
|
||||
import game_enums
|
||||
import re
|
||||
from pyraknet.bitstream import *
|
||||
|
||||
class ReplicaService(services.GameService):
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self._name = "Replica"
|
||||
global game
|
||||
game = self.get_parent()
|
||||
#Cached structs should give a boost to performance, the only reason it should really be disabled is if you are working on a replica component
|
||||
self._cached_structs = {}
|
||||
|
||||
def initialize(self):
|
||||
if(game.get_config("cache_structs") is not None and game.get_config("cache_structs") == True):
|
||||
'''Theres probably a much better way to do this but I'm too lazy'''
|
||||
self._cached_structs["replica/creation_header.structs"] = compile(self.parse_struct("replica/creation_header.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/serialization_header.structs"] = compile(self.parse_struct("replica/serialization_header.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Component 108.structs"] = compile(self.parse_struct("replica/components/Component 108.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/ModuleAssembly.structs"] = compile(self.parse_struct("replica/components/ModuleAssembly.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/ControllablePhysics.structs"] = compile(self.parse_struct("replica/components/ControllablePhysics.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/SimplePhysics.structs"] = compile(self.parse_struct("replica/components/SimplePhysics.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/RigidBodyPhantomPhysics.structs"] = compile(self.parse_struct("replica/components/RigidBodyPhantomPhysics.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/VehiclePhysics.structs"] = compile(self.parse_struct("replica/components/VehiclePhysics.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/PhantomPhysics.structs"] = compile(self.parse_struct("replica/components/PhantomPhysics.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Destructible.structs"] = compile(self.parse_struct("replica/components/Destructible.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Stats.structs"] = compile(self.parse_struct("replica/components/Stats.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Collectible.structs"] = compile(self.parse_struct("replica/components/Collectible.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Pet.structs"] = compile(self.parse_struct("replica/components/Pet.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Character.structs"] = compile(self.parse_struct("replica/components/Character.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Shooting Gallery.structs"] = compile(self.parse_struct("replica/components/Shooting Gallery.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Inventory.structs"] = compile(self.parse_struct("replica/components/Inventory.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Script.structs"] = compile(self.parse_struct("replica/components/Script.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Skill.structs"] = compile(self.parse_struct("replica/components/Skill.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/BaseCombatAI.structs"] = compile(self.parse_struct("replica/components/BaseCombatAI.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Rebuild.structs"] = compile(self.parse_struct("replica/components/Rebuild.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/MovingPlatform.structs"] = compile(self.parse_struct("replica/components/MovingPlatform.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Switch.structs"] = compile(self.parse_struct("replica/components/Switch.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Vendor.structs"] = compile(self.parse_struct("replica/components/Vendor.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Bouncer.structs"] = compile(self.parse_struct("replica/components/Bouncer.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/ScriptedActivity.structs"] = compile(self.parse_struct("replica/components/ScriptedActivity.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/RacingControl.structs"] = compile(self.parse_struct("replica/components/RacingControl.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Exhibit.structs"] = compile(self.parse_struct("replica/components/Exhibit.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Render.structs"] = compile(self.parse_struct("replica/components/Render.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Component 107.structs"] = compile(self.parse_struct("replica/components/Component 107.structs"), '<string>', 'exec')
|
||||
self._cached_structs["replica/components/Trigger.structs"] = compile(self.parse_struct("replica/components/Trigger.structs"), '<string>', 'exec')
|
||||
super().initialize()
|
||||
|
||||
def create_replica_object(self, parent, zone, config : dict):
|
||||
if("lot" not in config):
|
||||
raise Exception("'create_replica_object' Requires A LOT In The Conifg!")
|
||||
replica = game_objects.ReplicaObject(parent, zone, config)
|
||||
|
||||
transform : components.Transform = replica.get_component(components.Transform)
|
||||
if("position" in config):
|
||||
if(not isinstance(config["position"], str)):
|
||||
transform.position = config["position"]
|
||||
else:
|
||||
transform.position = game_types.Vector3(str_val=config["position"])
|
||||
if("rotation" in config):
|
||||
if (not isinstance(config["rotation"], str)):
|
||||
transform.rotation = config["rotation"]
|
||||
else:
|
||||
transform.rotation = game_types.Vector4(str_val=config["rotation"])
|
||||
if("scale" in config):
|
||||
transform.scale = config["scale"]
|
||||
|
||||
cdclient_db = game.get_service("Database").cdclient_db
|
||||
c = cdclient_db.connection.cursor()
|
||||
c.execute("SELECT component_type, component_id FROM ComponentsRegistry WHERE id = ?", (config["lot"],))
|
||||
component_list = c.fetchall()
|
||||
object_components = {}
|
||||
for component in component_list:
|
||||
object_components[int(component["component_type"])] = int(component["component_id"])
|
||||
|
||||
if(108 in object_components):
|
||||
possesable = components.Possessable(replica)
|
||||
if("driver_object_id" in config):
|
||||
possesable.driver_object_id = config["driver_object_id"]
|
||||
replica.add_component(possesable)
|
||||
if(61 in object_components):
|
||||
module_assembly = components.ModuleAssembly(replica)
|
||||
replica.add_component(module_assembly)
|
||||
if(30 in object_components):
|
||||
vehicle_physics = components.VehiclePhysics(replica)
|
||||
replica.add_component(vehicle_physics)
|
||||
if(7 in object_components):
|
||||
destructible = components.Destructible(replica)
|
||||
replica.add_component(destructible)
|
||||
|
||||
c.execute("SELECT * FROM DestructibleComponent WHERE id = ?", (object_components[7],))
|
||||
destructible_data = c.fetchone()
|
||||
stats = components.Stats(replica)
|
||||
if(destructible_data["life"] is not None):
|
||||
stats.health = int(destructible_data["life"])
|
||||
stats.max_health = int(destructible_data["life"])
|
||||
if(destructible_data["armor"] is not None):
|
||||
stats.armor = int(destructible_data["armor"])
|
||||
stats.max_armor = int(destructible_data["armor"])
|
||||
if (destructible_data["imagination"] is not None):
|
||||
stats.imagination = int(destructible_data["imagination"])
|
||||
stats.max_imagination = int(destructible_data["imagination"])
|
||||
if (destructible_data["faction"] is not None):
|
||||
stats.faction = int(destructible_data["faction"])
|
||||
if (destructible_data["isSmashable"] is not None):
|
||||
stats.is_smashable = destructible_data["isSmashable"]
|
||||
|
||||
if("health" in config):
|
||||
stats.health = config["health"]
|
||||
if("max_health" in config):
|
||||
stats.max_health = config["max_health"]
|
||||
if("armor" in config):
|
||||
stats.armor = config["armor"]
|
||||
if("max_armor" in config):
|
||||
stats.max_armor = config["max_armor"]
|
||||
if("imagination" in config):
|
||||
stats.imagination = config["imagination"]
|
||||
if("max_imagination" in config):
|
||||
stats.max_imagination = config["max_imagination"]
|
||||
if("faction" in config):
|
||||
stats.faction = config["faction"]
|
||||
if("is_smashable" in config):
|
||||
stats.is_smashable = config["is_smashable"]
|
||||
replica.add_component(stats)
|
||||
if(23 in object_components):
|
||||
if(replica.get_component(components.Stats) is None):
|
||||
stats = components.Stats(replica)
|
||||
replica.add_component(stats)
|
||||
|
||||
collectible = components.Collectible(replica)
|
||||
if("collectible_id" in config):
|
||||
collectible.collectible_id = config["collectible_id"]
|
||||
replica.add_component(collectible)
|
||||
if(26 in object_components):
|
||||
#TODO: Actually Implement The Config
|
||||
pet = components.Pet(replica)
|
||||
replica.add_component(pet)
|
||||
if(4 in object_components):
|
||||
character = components.Character(replica, replica.get_object_id())
|
||||
replica.add_component(character)
|
||||
if(17 in object_components):
|
||||
if(game.get_service("Player").get_player_by_id(int(replica.get_object_id())) is None):
|
||||
inventory = components.Inventory(replica)
|
||||
c.execute("SELECT * FROM InventoryComponent WHERE id = ?", (object_components[17],))
|
||||
db_items = c.fetchall()
|
||||
for item in db_items:
|
||||
new_item = {}
|
||||
new_item["item_id"] = game.generate_object_id()
|
||||
new_item["lot"] = item["itemid"]
|
||||
new_item["quantity"] = item["count"]
|
||||
new_item["equipped"] = item["equip"]
|
||||
new_item["linked"] = 0
|
||||
new_item["slot"] = 0
|
||||
new_item["json"] = {"from_db":1}
|
||||
inventory.add_item(new_item)
|
||||
replica.add_component(inventory)
|
||||
if(5 in object_components):
|
||||
script_comp = components.ScriptComponent(replica)
|
||||
replica.add_component(script_comp)
|
||||
if(9 in object_components):
|
||||
skill = components.Skill(replica)
|
||||
replica.add_component(skill)
|
||||
if(60 in object_components):
|
||||
base_comabt_ai = components.BaseCombatAI(replica)
|
||||
replica.add_component(base_comabt_ai)
|
||||
if(48 in object_components):
|
||||
rebuild = components.Rebuild(replica)
|
||||
c.execute("SELECT * FROM RebuildComponent WHERE id = ?", (object_components[48],))
|
||||
db_rebuild = c.fetchone()
|
||||
rebuild.reset_time = float(db_rebuild["reset_time"])
|
||||
if("build_activator_pos" in config):
|
||||
rebuild.build_activator_pos = config["build_activator_pos"]
|
||||
if("build_enabled" in config):
|
||||
rebuild.enabled = config["build_enabled"]
|
||||
replica.add_component(rebuild)
|
||||
|
||||
if(replica.get_component(components.Stats) is None):
|
||||
stats = components.Stats(replica)
|
||||
stats.imagination = int(db_rebuild["take_imagination"])
|
||||
stats.max_imagination = int(db_rebuild["take_imagination"])
|
||||
replica.add_component(stats)
|
||||
if(25 in object_components):
|
||||
moving_platform = components.MovingPlatform(replica)
|
||||
replica.add_component(moving_platform)
|
||||
if(49 in object_components):
|
||||
switch = components.Switch(replica)
|
||||
replica.add_component(switch)
|
||||
if(16 in object_components):
|
||||
vendor = components.Vendor(replica)
|
||||
replica.add_component(vendor)
|
||||
if(6 in object_components):
|
||||
bouncer = components.Bouncer(replica)
|
||||
replica.add_component(bouncer)
|
||||
if(39 in object_components):
|
||||
scripted_activity = components.ScriptedActivity(replica)
|
||||
replica.add_component(scripted_activity)
|
||||
if(71 in object_components):
|
||||
racing_control = components.RacingControl(replica)
|
||||
replica.add_component(racing_control)
|
||||
if(75 in object_components):
|
||||
exhibit = components.LUPExhibit(replica)
|
||||
replica.add_component(exhibit)
|
||||
if(2 in object_components):
|
||||
render = components.Render(replica)
|
||||
replica.add_component(render)
|
||||
if(107 in object_components):
|
||||
comp107 = components.Component107(replica)
|
||||
replica.add_component(comp107)
|
||||
if(69 in object_components):
|
||||
trigger = components.Trigger(replica)
|
||||
replica.add_component(trigger)
|
||||
game.trigger_event("GeneratedReplica", args=[replica])
|
||||
return replica
|
||||
|
||||
|
||||
def parse_struct(self, file_path):
|
||||
write_methods = {"bit":"c_bit", "float":"c_float", "double":"c_double", "s8":"c_int8", "u8":"c_uint8", "s16":"c_int16", "u16":"c_uint16", "s32":"c_int32", "u32":"c_uint32", "s64":"c_int64", "u64":"c_uint64",
|
||||
"lot":"c_long"}
|
||||
execute_string = ""
|
||||
indent_level = 0
|
||||
def format_line(string, indentation_level):
|
||||
indent_string = ""
|
||||
for i in range(indentation_level):
|
||||
indent_string += " "
|
||||
return indent_string + string + "\n"
|
||||
with open(file_path, "r") as file:
|
||||
for line in file:
|
||||
line = line.split("#")[0]#Filter out comments
|
||||
line = line.strip()
|
||||
if(line[:1] == "["):#Line is trying to write something to the stream
|
||||
data_type = line[line.find("[")+1:line.find("]")]
|
||||
write_value = line[line.find("{")+1:line.find("}")]
|
||||
write_str = ""
|
||||
if(data_type in write_methods):
|
||||
write_str = "stream.write({}({}))".format(write_methods[data_type], write_value)
|
||||
else:
|
||||
if(len(data_type.split("-")) == 2 and data_type.split("-")[1] == "string"):#If it says string at the start then write it via the String data type in game_types
|
||||
write_str = "stream.write(game_types.String({}, length_type={}))".format(write_value, write_methods[data_type.split("-")[0]])
|
||||
elif(len(data_type.split("-")) == 2 and data_type.split("-")[1] == "wstring"):
|
||||
write_str = "stream.write({}, length_type={})".format(write_value, write_methods[data_type.split("-")[0]])
|
||||
elif(len(data_type.split("-")) == 2 and data_type.split("-")[0] == "lwoobjectid"):
|
||||
write_str = "stream.write(game_types.LwoObjectID({}, {}))".format(write_value, data_type.split("-")[1])
|
||||
elif(data_type == "ldf"):
|
||||
write_str = "stream.write({})".format(write_value)
|
||||
execute_string += format_line(write_str, indent_level)
|
||||
execute_string += format_line("previous = {}".format(write_value), indent_level)
|
||||
elif(line[:2] == "{%"):#Line is setting a condition or ending one
|
||||
conditional = line[line.find("{%")+2:line.find("%}")]
|
||||
if(conditional == "end"):
|
||||
indent_level -= 1
|
||||
else:
|
||||
execute_string += format_line(conditional+":", indent_level)
|
||||
indent_level += 1
|
||||
elif(line[:1] == "{"):
|
||||
write_value = line[line.find("{")+1:line.find("}")]
|
||||
execute_string += format_line(write_value, indent_level)
|
||||
return execute_string
|
||||
|
||||
def _get_real_time(self, file_name):
|
||||
return self.parse_struct(file_name)
|
||||
|
||||
def _get_from_cache(self, file_name):
|
||||
return self._cached_structs[file_name]
|
||||
|
||||
def write_to_stream(self, replica : game_objects.ReplicaObject, stream, replica_type):
|
||||
struct_method = self._get_real_time
|
||||
if(game.get_config("cache_structs") is not None and game.get_config("cache_structs") == True):
|
||||
struct_method = self._get_from_cache
|
||||
|
||||
|
||||
exec(struct_method("replica/creation_header.structs"))
|
||||
exec(struct_method("replica/serialization_header.structs"))
|
||||
|
||||
cdclient_db = game.get_service("Database").cdclient_db
|
||||
c = cdclient_db.connection.cursor()
|
||||
c.execute("SELECT component_type, component_id FROM ComponentsRegistry WHERE id = ?", (replica.lot,))
|
||||
component_list = c.fetchall()
|
||||
object_components = []
|
||||
for component in component_list:
|
||||
object_components.append(int(component["component_type"]))
|
||||
|
||||
|
||||
if(108 in object_components):
|
||||
exec(struct_method("replica/components/Component 108.structs"))
|
||||
if(61 in object_components):
|
||||
exec(struct_method("replica/components/ModuleAssembly.structs"))
|
||||
if(1 in object_components):
|
||||
exec(struct_method("replica/components/ControllablePhysics.structs"))
|
||||
if(3 in object_components):
|
||||
exec(struct_method("replica/components/SimplePhysics.structs"))
|
||||
if(20 in object_components):
|
||||
exec(struct_method("replica/components/RigidBodyPhantomPhysics.structs"))
|
||||
if(30 in object_components):
|
||||
exec(struct_method("replica/components/VehiclePhysics.structs"))
|
||||
if(40 in object_components):
|
||||
exec(struct_method("replica/components/PhantomPhysics.structs"))
|
||||
if(7 in object_components):
|
||||
exec(struct_method("replica/components/Destructible.structs"))
|
||||
exec(struct_method("replica/components/Stats.structs"))
|
||||
if(23 in object_components):
|
||||
exec(struct_method("replica/components/Stats.structs"))
|
||||
exec(struct_method("replica/components/Collectible.structs"))
|
||||
if(26 in object_components):
|
||||
exec(struct_method("replica/components/Pet.structs"))
|
||||
if(4 in object_components):
|
||||
exec(struct_method("replica/components/Character.structs"))
|
||||
if(19 in object_components):
|
||||
exec(struct_method("replica/components/Shooting Gallery.structs"))
|
||||
if(17 in object_components):
|
||||
exec(struct_method("replica/components/Inventory.structs"))
|
||||
if(5 in object_components):
|
||||
exec(struct_method("replica/components/Script.structs"))
|
||||
if(9 in object_components):
|
||||
exec(struct_method("replica/components/Skill.structs"))
|
||||
if(60 in object_components):
|
||||
exec(struct_method("replica/components/BaseCombatAI.structs"))
|
||||
if(48 in object_components):
|
||||
exec(struct_method("replica/components/Stats.structs"))
|
||||
exec(struct_method("replica/components/Rebuild.structs"))
|
||||
if(25 in object_components):
|
||||
exec(struct_method("replica/components/MovingPlatform.structs"))
|
||||
if(49 in object_components):
|
||||
exec(struct_method("replica/components/Switch.structs"))
|
||||
if(16 in object_components):
|
||||
exec(struct_method("replica/components/Vendor.structs"))
|
||||
if(6 in object_components):
|
||||
exec(struct_method("replica/components/Bouncer.structs"))
|
||||
if(39 in object_components):
|
||||
exec(struct_method("replica/components/ScriptedActivity.structs"))
|
||||
if(71 in object_components):
|
||||
exec(struct_method("replica/components/RacingControl.structs"))
|
||||
if(75 in object_components):
|
||||
exec(struct_method("replica/components/Exhibit.structs"))
|
||||
if(2 in object_components):
|
||||
exec(struct_method("replica/components/Render.structs"))
|
||||
if(107 in object_components):
|
||||
exec(struct_method("replica/components/Component 107.structs"))
|
||||
if(69 in object_components):
|
||||
exec(struct_method("replica/components/Trigger.structs"))
|
||||
@@ -1 +1,3 @@
|
||||
bcrypt
|
||||
bcrypt
|
||||
mysql-connector-python
|
||||
hg+https://bitbucket.org/lcdr/pyraknet@4251284791e1476f29e51bbda44986e38a448aed
|
||||
@@ -1,7 +0,0 @@
|
||||
|
||||
#asset list
|
||||
A:res\audio\NDAudio\Ambience\Ambience_Avant_Gardens\Ambience_Avant_Gardens_Streaming.fsb
|
||||
A:res\audio\NDAudio\Ambience\Ambience_Avant_Gardens\Ambience_Avant_Gardens_Non-Streaming.fsb
|
||||
A:res\audio\NDAudio\Ambience\Ambience_Avant_Gardens\Ambience_Avant_Gardens_2_Non-Streaming.fsb
|
||||
A:res\audio\NDAudio\Music\Music_Global\Music_Global_Avant_Gardens_Streaming.fsb
|
||||
A:res\audio\NDAudio\Music\Music_Global\Music_Global_Day1-Patch.fsb
|
||||
@@ -1,208 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!-- DO NOT EDIT THIS FILE -->
|
||||
<envData>
|
||||
<bindings>
|
||||
<binding sceneID="1" configuration="Launch" />
|
||||
<binding sceneID="2" configuration="Battlefield" />
|
||||
<binding sceneID="3" configuration="Monument" />
|
||||
<binding sceneID="4" configuration="Launch" />
|
||||
<binding sceneID="5" configuration="Cave_To_Mon" />
|
||||
<binding sceneID="6" configuration="Battlefield" />
|
||||
<binding sceneID="7" configuration="Battlefield" />
|
||||
<binding sceneID="8" configuration="Battlefield" />
|
||||
<binding sceneID="9" configuration="Battlefield" />
|
||||
<binding sceneID="10" configuration="Spider_Cave" />
|
||||
<binding sceneID="11" configuration="Spider_Cave_Rear" />
|
||||
<binding sceneID="12" configuration="SEN_Camp" />
|
||||
<binding sceneID="13" configuration="Spider_Cave" />
|
||||
<binding sceneID="14" configuration="Spider_Cave" />
|
||||
<binding sceneID="15" configuration="Spider_Cave_Rear" />
|
||||
<binding sceneID="16" configuration="Cave_To_Mon" />
|
||||
<binding sceneID="17" configuration="Cave_To_Mon" />
|
||||
<binding sceneID="18" configuration="Monument" />
|
||||
<binding sceneID="19" configuration="Monument" />
|
||||
<binding sceneID="20" configuration="Monument" />
|
||||
<binding sceneID="21" configuration="Monument" />
|
||||
<binding sceneID="22" configuration="Monument" />
|
||||
<binding sceneID="23" configuration="Monument" />
|
||||
<binding sceneID="24" configuration="Monument" />
|
||||
<binding sceneID="25" configuration="Monument" />
|
||||
<binding sceneID="26" configuration="Monument" />
|
||||
<binding sceneID="27" configuration="Launch" />
|
||||
<binding sceneID="28" configuration="Launch" />
|
||||
<binding sceneID="29" configuration="Launch" />
|
||||
<binding sceneID="30" configuration="Launch" />
|
||||
<binding sceneID="35" configuration="Monument" />
|
||||
<binding sceneID="37" configuration="Launch" />
|
||||
<binding sceneID="38" configuration="Monument" />
|
||||
<binding sceneID="40" configuration="Spider_Cave" />
|
||||
</bindings>
|
||||
<configuration name="Battlefield">
|
||||
<ambientLightColor>0.419608,0.619608,0.749020</ambientLightColor>
|
||||
<directionalLightColor>1.000000,1.000000,1.000000</directionalLightColor>
|
||||
<fogColor>0.788235,0.749020,0.698039</fogColor>
|
||||
<maxDrawDistance fogFar="700" fogNear="100" postFogFade="100" postFogSolid="100" />
|
||||
<minDrawDistance fogFar="300" fogNear="100" postFogFade="100" postFogSolid="80" />
|
||||
<position>-0.48,-0.86,-0.19</position>
|
||||
<skydomeFilename>mesh\env\env_sky_won_nim_landing.nif</skydomeFilename>
|
||||
<specularLightColor>1.000000,1.000000,1.000000</specularLightColor>
|
||||
<upperHemiColor>1.000000,1.000000,1.000000</upperHemiColor>
|
||||
<cullSettings>
|
||||
<cullData cullGroupID="0" cullMax="0" cullMin="0" />
|
||||
<cullData cullGroupID="1" cullMax="150" cullMin="100" />
|
||||
<cullData cullGroupID="2" cullMax="200" cullMin="150" />
|
||||
<cullData cullGroupID="3" cullMax="250" cullMin="200" />
|
||||
<cullData cullGroupID="4" cullMax="450" cullMin="350" />
|
||||
<cullData cullGroupID="5" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="6" cullMax="40" cullMin="40" />
|
||||
<cullData cullGroupID="7" cullMax="600" cullMin="400" />
|
||||
<cullData cullGroupID="8" cullMax="100" cullMin="60" />
|
||||
<cullData cullGroupID="9" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="10" cullMax="400" cullMin="300" />
|
||||
</cullSettings>
|
||||
</configuration>
|
||||
<configuration name="Cave_To_Mon">
|
||||
<ambientLightColor>0.419608,0.619608,0.749020</ambientLightColor>
|
||||
<directionalLightColor>1.000000,1.000000,1.000000</directionalLightColor>
|
||||
<fogColor>1.000000,1.000000,1.000000</fogColor>
|
||||
<maxDrawDistance fogFar="300" fogNear="200" postFogFade="100" postFogSolid="100" />
|
||||
<minDrawDistance fogFar="250" fogNear="100" postFogFade="50" postFogSolid="50" />
|
||||
<position>-0.48,-0.86,-0.19</position>
|
||||
<skydomeFilename>mesh\env\env_sky_won_nim_hills.nif</skydomeFilename>
|
||||
<specularLightColor>1.000000,1.000000,1.000000</specularLightColor>
|
||||
<upperHemiColor>1.000000,1.000000,1.000000</upperHemiColor>
|
||||
<cullSettings>
|
||||
<cullData cullGroupID="0" cullMax="0" cullMin="0" />
|
||||
<cullData cullGroupID="1" cullMax="150" cullMin="100" />
|
||||
<cullData cullGroupID="2" cullMax="200" cullMin="150" />
|
||||
<cullData cullGroupID="3" cullMax="250" cullMin="200" />
|
||||
<cullData cullGroupID="4" cullMax="450" cullMin="350" />
|
||||
<cullData cullGroupID="5" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="6" cullMax="40" cullMin="40" />
|
||||
<cullData cullGroupID="7" cullMax="600" cullMin="400" />
|
||||
<cullData cullGroupID="8" cullMax="100" cullMin="60" />
|
||||
<cullData cullGroupID="9" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="10" cullMax="400" cullMin="300" />
|
||||
</cullSettings>
|
||||
</configuration>
|
||||
<configuration name="Launch">
|
||||
<ambientLightColor>0.419608,0.619608,0.749020</ambientLightColor>
|
||||
<directionalLightColor>1.000000,1.000000,1.000000</directionalLightColor>
|
||||
<fogColor>0.564706,0.819608,0.901961</fogColor>
|
||||
<maxDrawDistance fogFar="800" fogNear="300" postFogFade="100" postFogSolid="160" />
|
||||
<minDrawDistance fogFar="750" fogNear="300" postFogFade="10" postFogSolid="10" />
|
||||
<position>-0.48,209.00,230.00</position>
|
||||
<skydomeFilename>mesh\env\env_sky_won_nim_landing.nif</skydomeFilename>
|
||||
<specularLightColor>1.000000,1.000000,1.000000</specularLightColor>
|
||||
<upperHemiColor>1.000000,1.000000,1.000000</upperHemiColor>
|
||||
<cullSettings>
|
||||
<cullData cullGroupID="0" cullMax="0" cullMin="0" />
|
||||
<cullData cullGroupID="1" cullMax="150" cullMin="100" />
|
||||
<cullData cullGroupID="2" cullMax="200" cullMin="150" />
|
||||
<cullData cullGroupID="3" cullMax="250" cullMin="200" />
|
||||
<cullData cullGroupID="4" cullMax="450" cullMin="350" />
|
||||
<cullData cullGroupID="5" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="6" cullMax="40" cullMin="40" />
|
||||
<cullData cullGroupID="7" cullMax="600" cullMin="400" />
|
||||
<cullData cullGroupID="8" cullMax="100" cullMin="60" />
|
||||
<cullData cullGroupID="9" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="10" cullMax="400" cullMin="300" />
|
||||
</cullSettings>
|
||||
</configuration>
|
||||
<configuration name="Monument">
|
||||
<ambientLightColor>0.419608,0.619608,0.749020</ambientLightColor>
|
||||
<directionalLightColor>1.000000,1.000000,1.000000</directionalLightColor>
|
||||
<fogColor>0.564706,0.819608,0.901961</fogColor>
|
||||
<maxDrawDistance fogFar="400" fogNear="150" postFogFade="800" postFogSolid="160" />
|
||||
<minDrawDistance fogFar="300" fogNear="150" postFogFade="700" postFogSolid="80" />
|
||||
<position>-0.48,-0.86,-0.19</position>
|
||||
<skydomeFilename>mesh\env\env_sky_won_nim_hills.nif</skydomeFilename>
|
||||
<specularLightColor>1.000000,1.000000,1.000000</specularLightColor>
|
||||
<upperHemiColor>1.000000,1.000000,1.000000</upperHemiColor>
|
||||
<cullSettings>
|
||||
<cullData cullGroupID="0" cullMax="0" cullMin="0" />
|
||||
<cullData cullGroupID="1" cullMax="150" cullMin="100" />
|
||||
<cullData cullGroupID="2" cullMax="200" cullMin="150" />
|
||||
<cullData cullGroupID="3" cullMax="250" cullMin="200" />
|
||||
<cullData cullGroupID="4" cullMax="450" cullMin="350" />
|
||||
<cullData cullGroupID="5" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="6" cullMax="40" cullMin="40" />
|
||||
<cullData cullGroupID="7" cullMax="600" cullMin="400" />
|
||||
<cullData cullGroupID="8" cullMax="100" cullMin="60" />
|
||||
<cullData cullGroupID="9" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="10" cullMax="400" cullMin="300" />
|
||||
</cullSettings>
|
||||
</configuration>
|
||||
<configuration name="SEN_Camp">
|
||||
<ambientLightColor>0.419608,0.619608,0.749020</ambientLightColor>
|
||||
<directionalLightColor>1.000000,1.000000,1.000000</directionalLightColor>
|
||||
<fogColor>0.784314,0.749020,0.694118</fogColor>
|
||||
<maxDrawDistance fogFar="700" fogNear="100" postFogFade="100" postFogSolid="100" />
|
||||
<minDrawDistance fogFar="250" fogNear="100" postFogFade="170" postFogSolid="70" />
|
||||
<position>-0.48,-0.86,-0.19</position>
|
||||
<skydomeFilename>mesh\env\env_sky_won_nim_landing.nif</skydomeFilename>
|
||||
<specularLightColor>1.000000,1.000000,1.000000</specularLightColor>
|
||||
<upperHemiColor>1.000000,1.000000,1.000000</upperHemiColor>
|
||||
<cullSettings>
|
||||
<cullData cullGroupID="0" cullMax="0" cullMin="0" />
|
||||
<cullData cullGroupID="1" cullMax="150" cullMin="100" />
|
||||
<cullData cullGroupID="2" cullMax="200" cullMin="150" />
|
||||
<cullData cullGroupID="3" cullMax="250" cullMin="200" />
|
||||
<cullData cullGroupID="4" cullMax="450" cullMin="350" />
|
||||
<cullData cullGroupID="5" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="6" cullMax="40" cullMin="40" />
|
||||
<cullData cullGroupID="7" cullMax="600" cullMin="400" />
|
||||
<cullData cullGroupID="8" cullMax="100" cullMin="60" />
|
||||
<cullData cullGroupID="9" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="10" cullMax="400" cullMin="300" />
|
||||
</cullSettings>
|
||||
</configuration>
|
||||
<configuration name="Spider_Cave">
|
||||
<ambientLightColor>0.419608,0.619608,0.749020</ambientLightColor>
|
||||
<directionalLightColor>1.000000,1.000000,1.000000</directionalLightColor>
|
||||
<fogColor>0.788235,0.749020,0.698039</fogColor>
|
||||
<maxDrawDistance fogFar="700" fogNear="100" postFogFade="100" postFogSolid="100" />
|
||||
<minDrawDistance fogFar="250" fogNear="100" postFogFade="50" postFogSolid="50" />
|
||||
<position>-0.48,-0.86,-0.19</position>
|
||||
<skydomeFilename>mesh\env\env_sky_won_nim_hills.nif</skydomeFilename>
|
||||
<specularLightColor>1.000000,1.000000,1.000000</specularLightColor>
|
||||
<upperHemiColor>1.000000,1.000000,1.000000</upperHemiColor>
|
||||
<cullSettings>
|
||||
<cullData cullGroupID="0" cullMax="0" cullMin="0" />
|
||||
<cullData cullGroupID="1" cullMax="150" cullMin="100" />
|
||||
<cullData cullGroupID="2" cullMax="200" cullMin="150" />
|
||||
<cullData cullGroupID="3" cullMax="250" cullMin="200" />
|
||||
<cullData cullGroupID="4" cullMax="450" cullMin="350" />
|
||||
<cullData cullGroupID="5" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="6" cullMax="40" cullMin="40" />
|
||||
<cullData cullGroupID="7" cullMax="600" cullMin="400" />
|
||||
<cullData cullGroupID="8" cullMax="100" cullMin="60" />
|
||||
<cullData cullGroupID="9" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="10" cullMax="400" cullMin="300" />
|
||||
</cullSettings>
|
||||
</configuration>
|
||||
<configuration name="Spider_Cave_Rear">
|
||||
<ambientLightColor>0.686275,0.686275,0.686275</ambientLightColor>
|
||||
<directionalLightColor>0.000000,0.000000,0.000000</directionalLightColor>
|
||||
<fogColor>0.000000,0.000000,0.000000</fogColor>
|
||||
<maxDrawDistance fogFar="10000" fogNear="10000" postFogFade="10000" postFogSolid="1000" />
|
||||
<minDrawDistance fogFar="10000" fogNear="100" postFogFade="50" postFogSolid="50" />
|
||||
<position>-0.48,-0.86,-0.19</position>
|
||||
<skydomeFilename>mesh\env\nexustower\env_sky_nx_towerblack.nif</skydomeFilename>
|
||||
<specularLightColor>0.247059,0.474510,0.619608</specularLightColor>
|
||||
<upperHemiColor>0.000000,0.000000,0.000000</upperHemiColor>
|
||||
<cullSettings>
|
||||
<cullData cullGroupID="0" cullMax="0" cullMin="0" />
|
||||
<cullData cullGroupID="1" cullMax="150" cullMin="100" />
|
||||
<cullData cullGroupID="2" cullMax="200" cullMin="150" />
|
||||
<cullData cullGroupID="3" cullMax="250" cullMin="200" />
|
||||
<cullData cullGroupID="4" cullMax="450" cullMin="350" />
|
||||
<cullData cullGroupID="5" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="6" cullMax="40" cullMin="40" />
|
||||
<cullData cullGroupID="7" cullMax="600" cullMin="400" />
|
||||
<cullData cullGroupID="8" cullMax="100" cullMin="60" />
|
||||
<cullData cullGroupID="9" cullMax="100" cullMin="50" />
|
||||
<cullData cullGroupID="10" cullMax="400" cullMin="300" />
|
||||
</cullSettings>
|
||||
</configuration>
|
||||
</envData>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!-- DO NOT EDIT THIS FILE -->
|
||||
<triggers nextID="157">
|
||||
<trigger id="1" enabled="1">
|
||||
<event id="OnEnter">
|
||||
<command id="zonePlayer" target="target" args="312" />
|
||||
</event>
|
||||
</trigger>
|
||||
<trigger id="44" enabled="1">
|
||||
<event id="OnCreate">
|
||||
<command id="SetPhysicsVolumeEffect" target="self" args="push,75,0.9,2,-0.41" />
|
||||
</event>
|
||||
</trigger>
|
||||
<trigger id="46" enabled="1">
|
||||
<event id="OnCreate">
|
||||
<command id="SetPhysicsVolumeEffect" target="self" args="push,75,0.9,3,-0.41" />
|
||||
</event>
|
||||
</trigger>
|
||||
</triggers>
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<!-- DO NOT EDIT THIS FILE -->
|
||||
<triggers nextID="5">
|
||||
<trigger id="4" enabled="1">
|
||||
<event id="OnEnter">
|
||||
<command id="updateMission" target="target" args="exploretask,1,1,1,AG_POI_RESEARCH" />
|
||||
</event>
|
||||
</trigger>
|
||||
</triggers>
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user