Implemented World Loading

The character can now load entirely into a world instance. Next step is to implement all replica components so the world can have objects, and to figure out a way how to determine what to serialize/where to store object data.
This commit is contained in:
Wesley
2020-03-16 13:06:34 -04:00
parent c6dc9c023c
commit b757e40954
11 changed files with 792 additions and 36 deletions
+2
View File
@@ -21,6 +21,8 @@ class GameServer(pyraknet.server.Server):
self.add_handler(pyraknet.server.Event.UserPacket, self.handle_packet)
self.add_handler(pyraknet.server.Event.Disconnect, self.handle_disconnect)
self.additional_config = {}
self.address = address
self.name = name
self.zone = zone
self.config = configparser.ConfigParser()
+1
View File
@@ -6,6 +6,7 @@ CREATE TABLE `character_stats` (
`quick_builds_done` int(11) DEFAULT NULL,
`enemies_smashed` int(11) DEFAULT NULL,
`rockets_used` int(11) DEFAULT NULL,
`missions_completed` int(11) DEFAULT NULL,
`pets_tamed` int(11) DEFAULT NULL,
`imagination_collected` int(11) DEFAULT NULL,
`health_collected` int(11) DEFAULT NULL,
+4
View File
@@ -0,0 +1,4 @@
CREATE TABLE `completed_missions` (
`player_id` bigint(40) DEFAULT NULL,
`mission_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+5
View File
@@ -0,0 +1,5 @@
CREATE TABLE `current_missions` (
`mission_id` int(11) DEFAULT NULL,
`progress` int(11) DEFAULT NULL,
`player_id` bigint(40) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+6 -4
View File
@@ -3,6 +3,7 @@ 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:
@@ -43,19 +44,20 @@ class Plugin:
stream = ReadStream(data)
player_id = stream.read(client_to_world.JoinWorldPacket).object_id
c = server.db_connection.cursor()
c.execute("SELECT zone FROM wlus.character WHERE character_id = %s", (player_id,))
zone_id = c.fetchone()[0]
c.execute("SELECT zone, current_name FROM wlus.character WHERE character_id = %s", (player_id,))
char_data = c.fetchone()
session = server.lookup_session_by_ip(address[0])
zone_id = char_data[0]
if zone_id == 0:
zone_id = 1000
player = server.lookup_player_by_ip(address[0])
if player is None:
server.execute_master_query("""INSERT INTO online_players(id, session_id, current_zone, name)
VALUES (%s, %s, %s, "%s")""" % (player_id, session["id"], zone_id, session["username"]), do_return=False)
VALUES (%s, %s, %s, "%s")""" % (player_id, session["id"], zone_id, char_data[1]), do_return=False)
else:
server.execute_master_query("""UPDATE online_players SET id = %s, zone_id = %s, name = "%s"
WHERE session_id = %s""" % (player_id, zone_id, session["username"], player["session_id"]), do_return=False)
WHERE session_id = %s""" % (player_id, zone_id, char_data[1], player["session_id"]), do_return=False)
if zone_id != server.zone:
ip_address, port, instance_name = server.redirect_request("zone", str(zone_id))
+3
View File
@@ -0,0 +1,3 @@
from pyraknet.bitstream import *
from ..serializables import misc_serializables, packet_enum
+1 -1
View File
@@ -12,7 +12,7 @@ class HandshakePacket(bitstream.Serializable):
"""
def __init__(self):
self.game_version = 171022
self.unknown_0 = 0x93
self.unknown_0 = 0
self.remote_connection_type = 0 # For auth this is 1, otherwise it is 4
self.process_id = 1124
self.local_port = 0xff
+63
View File
@@ -32,6 +32,69 @@ class PacketHeader(Enum):
REDIRECT_TO_NEW_SERVER = b'S\x05\x00\x0e\x00\x00\x00\x00'
class ReplicaTypes(IntEnum):
CONSTRUCTION = 0
SERIALIZATION = 1
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
REQUEST_USE = 364
OFFER_MISSION = 248
class SerializedComponents(IntEnum):
POSSESSABLE = 108
MODULE_ASSEMBLY = 61
CONTROLLABLE_PHYSICS = 1
SIMPLE_PHYSICS = 3
RIGID_BODY_PHANTOM_PHYSICS = 20
VEHICLE_PHYSICS = 30
PHANTOM_PHYSICS = 40
DESTRUCTIBLE = 7
COLLECTIBLE = 23
PET = 26
CHARACTER = 4
INVENTORY = 17
SCRIPT = 5
SKILL = 9
BASE_COMBAT_AI = 60
REBUILD = 48
MOVING_PLATFORM = 25
SWITCH = 49
VENDOR = 16
BOUNCER = 6
SCRIPTED_ACTIVITY = 39
RACING_CONTROL = 71
EXHIBIT = 75
MODEL = 42
RENDER = 2
COMPONENT_107 = 107
TRIGGER = 69
class DisconnectionNotify(IntEnum):
"""
Contains various reasons for disconnect notify.
+421 -5
View File
@@ -1,10 +1,97 @@
"""
This file contains all of the replica components and the structs withing them
"""
from pyraknet import bitstream
from pyraknet.bitstream import *
from pyraknet.replicamanager import Replica
from plugins.serializables.packet_enum import ReplicaTypes, SerializedComponents
from plugins.serializables.misc_serializables import Vector3, Vector4
import sqlite3
class BaseDataComponent(bitstream.Serializable):
class ReplicaObject(Replica):
def __init__(self):
self.base_data = BaseDataComponent()
self.components = {}
def write_construction(self, stream: WriteStream) -> None:
self.write(stream, ReplicaTypes.CONSTRUCTION.value)
def serialize(self, stream: WriteStream) -> None:
self.write(stream, ReplicaTypes.SERIALIZATION.value)
def write(self, stream: WriteStream, replica_mode) -> None:
# Not Networked: 12, 31, 35, 36, 45, 55, 56, 64, 65, 68, 73, 104, 113, 114
self.base_data.replica_mode = replica_mode # TODO: There has to be a better way to do this
for comp in self.components:
self.components[comp].replica_mode = ReplicaTypes.CONSTRUCTION.value
conn = sqlite3.connect("./res/cdclient.sqlite")
c = conn.cursor()
c.execute("SELECT component_type FROM ComponentsRegistry WHERE id = ?", (self.base_data.lot,))
comp_table = c.fetchall()
components = []
for component in comp_table:
components.append(component[0])
stream.write(self.base_data)
if SerializedComponents.POSSESSABLE.value in components:
pass
if SerializedComponents.MODULE_ASSEMBLY.value in components:
pass
if SerializedComponents.CONTROLLABLE_PHYSICS.value in components:
stream.write(self.components[SerializedComponents.CONTROLLABLE_PHYSICS.value])
if SerializedComponents.SIMPLE_PHYSICS.value in components:
pass
if SerializedComponents.RIGID_BODY_PHANTOM_PHYSICS.value in components:
pass
if SerializedComponents.VEHICLE_PHYSICS.value in components:
pass
if SerializedComponents.PHANTOM_PHYSICS.value in components:
pass
if SerializedComponents.DESTRUCTIBLE.value in components:
stream.write(self.components[SerializedComponents.DESTRUCTIBLE.value].destructible_index)
stream.write(self.components[SerializedComponents.DESTRUCTIBLE.value].stats_index)
if SerializedComponents.COLLECTIBLE.value in components:
pass
if SerializedComponents.PET.value in components:
pass
if SerializedComponents.CHARACTER.value in components:
stream.write(self.components[SerializedComponents.CHARACTER.value])
if SerializedComponents.INVENTORY.value in components:
stream.write(self.components[SerializedComponents.INVENTORY.value])
if SerializedComponents.SCRIPT.value in components:
pass
if SerializedComponents.SKILL.value in components:
stream.write(self.components[SerializedComponents.SKILL.value])
if SerializedComponents.BASE_COMBAT_AI.value in components:
pass
if SerializedComponents.REBUILD.value in components:
pass
if SerializedComponents.MOVING_PLATFORM.value in components:
pass
if SerializedComponents.SWITCH.value in components:
pass
if SerializedComponents.VENDOR.value in components:
pass
if SerializedComponents.BOUNCER.value in components:
pass
if SerializedComponents.SCRIPTED_ACTIVITY.value in components:
pass
if SerializedComponents.RACING_CONTROL.value in components:
pass
if SerializedComponents.EXHIBIT.value in components:
pass
if SerializedComponents.MODEL.value in components:
pass
if SerializedComponents.RENDER.value in components:
stream.write(self.components[SerializedComponents.RENDER.value])
if SerializedComponents.COMPONENT_107.value in components:
stream.write(self.components[SerializedComponents.COMPONENT_107.value])
if SerializedComponents.MODEL.value in components:
pass
class BaseDataComponent(Serializable):
"""
Base Data should be supplied with every replica.
replica_mode refers to whether or not it is construction, serialization or destruction.
@@ -12,7 +99,7 @@ class BaseDataComponent(bitstream.Serializable):
Serialization - 1
Destruction - 2
"""
def __init__(self, replica_mode: int = 0):
def __init__(self, replica_mode=0):
self.replica_mode = replica_mode
self.object_id = 0
self.lot = 0
@@ -22,5 +109,334 @@ class BaseDataComponent(bitstream.Serializable):
self.spawner_id = 0
self.spawner_node_id = 0
self.scale = 1
self.object_world_state = 0
self.gm_level = 0
self.object_world_state = -1
self.gm_level = 0
def serialize(self, stream: WriteStream) -> None:
if self.replica_mode == ReplicaTypes.CONSTRUCTION.value:
stream.write(c_int64(self.object_id))
stream.write(c_int32(self.lot))
stream.write(self.name, length_type=c_uint8)
stream.write(c_uint32(self.time_since_created))
stream.write(c_bit(False)) # Unimplemented struct
stream.write(c_bit(self.has_trigger))
stream.write(c_bit(self.spawner_id != 0))
if self.spawner_id != 0:
stream.write(c_int64(self.spawner_id))
stream.write(c_bit(self.spawner_node_id != 0))
if self.spawner_node_id != 0:
stream.write(c_uint32(self.spawner_node_id))
stream.write(c_bit(self.scale != 1))
if self.scale != 1:
stream.write(c_float(self.scale))
stream.write(c_bit(self.object_world_state != -1))
if self.object_world_state != -1:
stream.write(c_uint8(self.object_world_state))
stream.write(c_bit(self.gm_level != 0))
if self.gm_level != 0:
stream.write(c_uint8(self.gm_level))
stream.write(c_bit(False)) # Unimplemented struct
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class ControllablePhysicsComponent(Serializable):
def __init__(self, replica_mode=0):
self.replica_mode = replica_mode
self.jetpack_equipped = False
self.jetpack_effect = 0
self.in_air = False
self.gravity_multiplier = 1
self.speed_multiplier = 1
self.position = Vector3()
self.rotation = Vector4()
self.on_ground = True
self.on_rail = False
self.velocity = Vector3()
self.angular_velocity = Vector3()
def serialize(self, stream: WriteStream) -> None:
if self.replica_mode == ReplicaTypes.CONSTRUCTION.value:
stream.write(c_bit(self.jetpack_equipped))
if self.jetpack_equipped:
stream.write(c_uint32(self.jetpack_effect))
stream.write(c_bit(self.in_air))
stream.write(c_bit(False))
stream.write(c_bit(False)) # Undiscovered struct?
stream.write(c_bit(self.gravity_multiplier != 1 or self.speed_multiplier != 1))
if self.gravity_multiplier != 1 or self.speed_multiplier != 1:
stream.write(c_float(self.gravity_multiplier))
stream.write(c_float(self.speed_multiplier))
stream.write(c_bit(False)) # Undiscovered struct?
stream.write(c_bit(False)) # Undiscovered struct?
stream.write(c_bit(True))
stream.write(self.position)
stream.write(self.rotation)
stream.write(c_bit(self.on_ground))
stream.write(c_bit(self.on_rail))
stream.write(c_bit(self.velocity != Vector3()))
if self.velocity != Vector3():
stream.write(self.velocity)
stream.write(c_bit(self.angular_velocity != Vector3()))
if self.angular_velocity != Vector3():
stream.write(self.angular_velocity)
stream.write(c_bit(False)) # Some struct relating to moving platforms
if self.replica_mode == ReplicaTypes.SERIALIZATION.value:
stream.write(c_bit(False))
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class DestructibleIndex(Serializable):
"""
This index is fairly unresearched.
"""
def __init__(self, replica_mode=0):
self.replica_mode = replica_mode
def serialize(self, stream: WriteStream) -> None:
if self.replica_mode == ReplicaTypes.CONSTRUCTION.value:
stream.write(c_bit(False))
stream.write(c_bit(False))
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class StatsIndex(Serializable):
def __init__(self, replica_mode=0):
self.replica_mode = replica_mode
self.health = 0
self.max_health = 0
self.armor = 0
self.max_armor = 0
self.imagination = 0
self.max_imagination = 0
self.absorbtion_points = 0
self.is_gm_immune = False
self.immune = False
self.shielded = False
self.factions = []
self.is_smashable = False
def serialize(self, stream: WriteStream) -> None:
if self.replica_mode == ReplicaTypes.CONSTRUCTION.value:
stream.write(c_bit(False))
stream.write(c_bit(True))
stream.write(c_uint32(self.health))
stream.write(c_float(self.max_health))
stream.write(c_uint32(self.armor))
stream.write(c_float(self.max_armor))
stream.write(c_uint32(self.imagination))
stream.write(c_float(self.max_imagination))
stream.write(c_uint32(self.absorbtion_points))
stream.write(c_bit(self.immune))
stream.write(c_bit(self.is_gm_immune))
stream.write(c_bit(self.shielded))
stream.write(c_float(self.max_health))
stream.write(c_float(self.max_armor))
stream.write(c_float(self.max_imagination))
stream.write(c_uint32(len(self.factions)))
for faction in self.factions:
stream.write(c_int32(faction))
stream.write(c_bit(self.is_smashable))
if self.replica_mode == ReplicaTypes.CONSTRUCTION.value:
stream.write(c_bit(False))
stream.write(c_bit(False))
if self.is_smashable:
stream.write(c_bit(False))
stream.write(c_bit(False))
stream.write(c_bit(False))
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class CharacterComponent(Serializable):
def __init__(self, replica_mode=0):
self.replica_mode = replica_mode
self.level = 0
self.hair_color = 0
self.hair_style = 0
self.shirt_color = 0
self.pants_color = 0
self.eyebrows = 0
self.eyes = 0
self.mouth = 0
self.account_id = 0
self.lego_score = 0
self.ftp = False
self.character_stats = []
for _ in range(27):
self.character_stats.append(0)
self.world_transition_state = 0
self.ldf_rocket_info = "1:9746;1:9747;1:9748;"
self.pvp = False
self.is_gm = False
self.gm_level = 0
self.activity = 0
# TODO: Add guild struct and vehicle struct
def serialize(self, stream: WriteStream) -> None:
stream.write(c_bit(False)) # Vehicle struct
stream.write(c_bit(False))
# stream.write(c_uint32(self.level))
stream.write(c_bit(False))
if self.replica_mode == ReplicaTypes.CONSTRUCTION.value:
stream.write(c_bit(False))
stream.write(c_bit(False))
stream.write(c_bit(False))
stream.write(c_bit(False))
stream.write(c_uint32(self.hair_color))
stream.write(c_uint32(self.hair_style))
stream.write(c_uint32(0))
stream.write(c_uint32(self.shirt_color))
stream.write(c_uint32(self.pants_color))
stream.write(c_uint32(0))
stream.write(c_uint32(0))
stream.write(c_uint32(self.eyebrows))
stream.write(c_uint32(self.eyes))
stream.write(c_uint32(self.mouth))
stream.write(c_uint64(self.account_id))
stream.write(c_uint64(0))
stream.write(c_uint64(0))
stream.write(c_uint64(self.lego_score))
stream.write(c_bit(self.ftp))
for stat in self.character_stats:
stream.write(c_uint64(stat))
if self.world_transition_state == 1:
stream.write(c_bit(True))
stream.write(c_bit(False))
stream.write(self.ldf_rocket_info, length_type=c_uint16)
elif self.world_transition_state == 2:
stream.write(c_bit(False))
stream.write(c_bit(True))
else:
stream.write(c_bit(False))
stream.write(c_bit(False))
stream.write(c_bit(True))
stream.write(c_bit(self.pvp))
stream.write(c_bit(self.is_gm))
stream.write(c_uint8(self.gm_level))
stream.write(c_bit(False))
stream.write(c_uint8(0))
stream.write(c_bit(self.activity != 0))
if self.activity != 0:
stream.write(c_uint32(self.activity))
stream.write(c_bit(False)) # Guild struct
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class InventoryItem(Serializable):
def __init__(self):
self.object_id = 0
self.lot = 0
self.count = 1
self.slot = 0
self.inventory_type = 4
def serialize(self, stream: WriteStream) -> None:
stream.write(c_int64(self.object_id))
stream.write(c_int32(self.lot))
stream.write(c_bit(False))
stream.write(c_bit(True))
stream.write(c_uint32(self.count))
stream.write(c_bit(True))
stream.write(c_uint16(self.slot))
stream.write(c_bit(True))
stream.write(c_uint32(self.inventory_type))
stream.write(c_bit(False))
stream.write(c_bit(True))
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class InventoryComponent(Serializable):
def __init__(self, replica_mode=0):
self.replica_mode = replica_mode
self.items = []
def serialize(self, stream: WriteStream) -> None:
stream.write(c_bit(True))
stream.write(c_uint32(len(self.items)))
for item in self.items:
stream.write(item)
stream.write(c_bit(False))
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class SkillComponent(Serializable):
"""
Not even really sure what this is for
"""
def __init__(self, replica_mode=0):
self.replica_mode = replica_mode
def serialize(self, stream: WriteStream) -> None:
if self.replica_mode == ReplicaTypes.CONSTRUCTION.value:
stream.write(c_bit(False))
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class RenderComponent(Serializable):
"""
Not even really sure what this is for
"""
def __init__(self, replica_mode=0):
self.replica_mode = replica_mode
# TODO: I should probably at least implement this struct
def serialize(self, stream: WriteStream) -> None:
if self.replica_mode == ReplicaTypes.CONSTRUCTION.value:
stream.write(c_int32(0))
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class Component107(Serializable):
def __init__(self, replica_mode = 0):
self.replica_mode = replica_mode
def serialize(self, stream: WriteStream) -> None:
stream.write(c_bit(False))
@classmethod
def deserialize(cls, stream: ReadStream) -> Serializable:
raise Exception("This struct cannot be deserialized")
class DestructibleComponent:
def __int__(self, replica_mode=0):
self.replica_mode = replica_mode
self.destructible_index = DestructibleIndex()
self.stats_index = StatsIndex()
+29 -3
View File
@@ -2,8 +2,9 @@
Contains all the packets that the world/char server would send to the client
"""
from pyraknet import bitstream
from plugins.serializables.misc_serializables import CString, Vector3, LUZ
from plugins.serializables.misc_serializables import CString, Vector3, LUZ, LDF
from plugins.easy_cdclient.cdclient_objects import Zone
import zlib
class MinfigureListPacket(bitstream.Serializable):
@@ -82,7 +83,7 @@ class WorldInfoPacket(bitstream.Serializable):
self.editor_enabled = False
self.editor_level = 0
self.player_position = Vector3()
self.is_in_battle = 0 # If in battle put 4??
self.activity = 0 # If in battle put 4??
@classmethod
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
@@ -96,7 +97,7 @@ class WorldInfoPacket(bitstream.Serializable):
stream.write(bitstream.c_bool(self.editor_enabled))
stream.write(bitstream.c_uint8(self.editor_level))
stream.write(self.player_position)
stream.write(bitstream.c_uint32(self.is_in_battle))
stream.write(bitstream.c_uint32(self.activity))
@classmethod
def from_cdclient(cls, zone_id, default_spawn=False) -> "WorldInfoPacket":
@@ -111,3 +112,28 @@ class WorldInfoPacket(bitstream.Serializable):
luz = stream.read(LUZ)
world_info.player_position = luz.spawnpoint_position
return world_info
class DetailedUserInfoPacket(bitstream.Serializable):
"""
[53-05-00-04]
Send after client load complete packet
"""
def __init__(self):
self.ldf = LDF()
@classmethod
def deserialize(cls, stream: bitstream.ReadStream) -> bitstream.Serializable:
raise Exception("This packet cannot be deserialized")
def serialize(self, stream: bitstream.WriteStream) -> None:
temp_stream = bitstream.WriteStream()
temp_stream.write(self.ldf)
temp_bytes = temp_stream.__bytes__()
compressed_bytes = zlib.compress(temp_bytes)
stream.write(bitstream.c_ulong(len(compressed_bytes) + 9))
stream.write(bitstream.c_bool(True))
stream.write(bitstream.c_ulong(len(temp_bytes)))
stream.write(bitstream.c_ulong(len(compressed_bytes)))
stream.write(compressed_bytes)
+257 -23
View File
@@ -1,16 +1,19 @@
"""
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 ..serializables import packet_enum, world_to_client, client_to_world, global_packets, misc_serializables, replica_components
from pyraknet.bitstream import *
from pyraknet.replicamanager import *
from pyraknet.messages import Message
from ..char_handler import char_handlers
from xml.etree import ElementTree
class Plugin:
def __init__(self, parent):
print("World Handler Initiated")
parent.register_handler(char_handlers.Plugin.handle_minifigure_list_request,
packet_enum.PacketHeader.CLIENT_USER_SESSION_INFO.value)
parent.register_handler(Plugin.handle_minifigure_list_request,
packet_enum.PacketHeader.CLIENT_MINIFIGURE_LIST_REQUEST.value)
parent.register_handler(char_handlers.Plugin.handle_minifigure_creation,
packet_enum.PacketHeader.CLIENT_MINIFIGURE_CREATE_REQUEST.value)
parent.register_handler(char_handlers.Plugin.handle_load_world,
@@ -21,34 +24,265 @@ class Plugin:
parent.register_handler(Plugin.handle_handshake, packet_enum.PacketHeader.HANDSHAKE.value)
parent.register_handler(Plugin.handle_detailed_user_info,
packet_enum.PacketHeader.CLIENT_LOAD_COMPLETE.value)
parent.register_handler(Plugin.handle_sesion_info, packet_enum.PacketHeader.CLIENT_USER_SESSION_INFO.value)
parent.additional_config["replica_manager"] = ReplicaManager(parent)
@classmethod
def handle_handshake(cls, data: bytes, address, server):
"""
Handles initial connection between server and client.
"""
player = server.lookup_player_by_ip(address[0])
c = server.db_connection.cursor()
c.execute("SELECT position FROM wlus.character_info WHERE player_id = %s", (int(player["id"]),))
player_pos = c.fetchone()[0]
if player_pos == "0,0,0":
world_info = world_to_client.WorldInfoPacket.from_cdclient(server.zone, default_spawn=True)
c.execute("UPDATE wlus.character_info SET position = %s WHERE player_id = %s",
(str(world_info.player_position), int(player["id"])))
server.db_connection.commit()
else:
world_info = world_to_client.WorldInfoPacket.from_cdclient(server.zone, default_spawn=False)
points = player_pos.split(",")
pos = misc_serializables.Vector3()
pos.x = float(points[0])
pos.y = float(points[1])
pos.z = float(points[2])
world_info.player_position = pos
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
packet = WriteStream()
packet.write(packet_enum.PacketHeader.WORLD_INFO.value)
packet.write(world_info)
packet.write(packet_enum.PacketHeader.HANDSHAKE.value)
packet.write(server_handshake)
server.send(packet, address)
@classmethod
def handle_sesion_info(cls, data: bytes, address, server):
stream = ReadStream(data)
session_info = stream.read(client_to_world.UserSessionInfoPacket)
c = server.db_connection.cursor()
session = server.lookup_session_by_username(session_info.username)
if session is not None:
if session["user_key"] == session_info.user_key:
# Add user to replica manager
server.additional_config["replica_manager"].add_participant(address)
# Send world info packet if the session key is correct
player = server.lookup_player_by_ip(address[0])
c.execute("SELECT position FROM wlus.character_info WHERE player_id = %s", (int(player["id"]),))
player_pos = c.fetchone()[0]
if player_pos == "0,0,0":
world_info = world_to_client.WorldInfoPacket.from_cdclient(server.zone, default_spawn=True)
c.execute("UPDATE wlus.character_info SET position = %s WHERE player_id = %s",
(str(world_info.player_position), int(player["id"])))
server.db_connection.commit()
else:
world_info = world_to_client.WorldInfoPacket.from_cdclient(server.zone, default_spawn=False)
points = player_pos.split(",")
pos = misc_serializables.Vector3()
pos.x = float(points[0])
pos.y = float(points[1])
pos.z = float(points[2])
world_info.player_position = pos
packet = WriteStream()
packet.write(packet_enum.PacketHeader.WORLD_INFO.value)
packet.write(world_info)
server.send(packet, address)
else:
disconnect = global_packets.DisconnectNotifyPacket()
disconnect.disconnect_id = packet_enum.DisconnectionNotify.INVALID_SESSION_KEY.value
disconnect.send(server, address)
else:
disconnect = global_packets.DisconnectNotifyPacket()
disconnect.disconnect_id = packet_enum.DisconnectionNotify.INVALID_SESSION_KEY.value
disconnect.send(server, address)
@classmethod
def handle_detailed_user_info(cls, data: bytes, address, server):
print("Client Load Complete")
# I'm honestly just going to ignore what the client sends here. I don't need to do anything with it
print(f"Sending detailed user info to {address}")
player_info = server.lookup_player_by_ip(address[0])
c = server.db_connection.cursor()
c.execute("SELECT backpack_space, currency, universe_score, level, position, rotation, health,"
" max_health, armor, max_armor, imagination, max_imagination FROM character_info WHERE player_id = %s"
, (player_info["id"],))
character_info = c.fetchone()
c.execute("SELECT * FROM wlus.inventory WHERE player_id = %s", (player_info["id"],))
inventory = c.fetchall()
c.execute("SELECT mission_id FROM wlus.completed_missions WHERE player_id = %s", (player_info["id"],))
complete_missions = c.fetchall()
c.execute("SELECT mission_id, progress FROM wlus.current_missions WHERE player_id = %s", (player_info["id"],))
current_missions = c.fetchall()
dui = world_to_client.DetailedUserInfoPacket()
dui.ldf.register_key("levelid", int(player_info["current_zone"]), 1)
dui.ldf.register_key("objid", int(player_info["id"]), 9)
dui.ldf.register_key("template", 1, 1)
dui.ldf.register_key("name", player_info["name"], 0)
root = ElementTree.Element("obj")
root.set("v", "1")
buff = ElementTree.SubElement(root, "buff")
skill = ElementTree.SubElement(root, "skill")
inv = ElementTree.SubElement(root, "inv")
bag = ElementTree.SubElement(inv, "bag")
bag_info = ElementTree.SubElement(bag, "b")
bag_info.set("t", "0")
bag_info.set("m", str(character_info[0]))
items = ElementTree.SubElement(inv, "items")
item_in = ElementTree.SubElement(items, "in")
for item in inventory:
i = ElementTree.SubElement(item_in, "i")
i.set("l", str(item[1]))
i.set("id", str(item[0]))
i.set("s", str(item[2]))
i.set("c", str(item[5]))
i.set("b", str(item[4]))
i.set("eq", str(item[3]))
mf = ElementTree.SubElement(root, "mf")
char = ElementTree.SubElement(root, "char")
char.set("cc", str(character_info[1]))
char.set("ls", str(character_info[2]))
lvl = ElementTree.SubElement(root, "lvl")
lvl.set("l", str(character_info[3]))
pets = ElementTree.SubElement(root, "pet")
mis = ElementTree.SubElement(root, "mis")
done = ElementTree.SubElement(mis, "done")
for mission in complete_missions:
m = ElementTree.SubElement(done, "m")
m.set("id", str(mission[0]))
m.set("cct", "1")
m.set("cts", "0")
cur = ElementTree.SubElement(mis, "cur")
for mission in current_missions:
m = ElementTree.SubElement(cur, "m")
m.set("id", str(mission[0]))
sv = ElementTree.SubElement(m, "sv")
sv.set("v", str(mission[1]))
dui.ldf.register_key("xmlData", root, 13)
packet = WriteStream()
packet.write(packet_enum.PacketHeader.DETAILED_USER_INFO.value)
packet.write(dui)
server.send(packet, address)
c.execute("SELECT * FROM character_stats WHERE player_id = %s", (player_info["id"],))
character_stats = c.fetchone()
c.execute("SELECT * FROM wlus.character WHERE character_id = %s", (player_info["id"],))
character_data = c.fetchone()
player = replica_components.ReplicaObject()
player.base_data.lot = 1
player.base_data.object_id = int(player_info["id"])
player.base_data.name = player_info["name"]
player.components[packet_enum.SerializedComponents.COMPONENT_107.value] = replica_components.Component107()
player.components[packet_enum.SerializedComponents.RENDER.value] = replica_components.RenderComponent()
player.components[packet_enum.SerializedComponents.SKILL.value] = replica_components.SkillComponent()
inventory_comp = replica_components.InventoryComponent()
for item in inventory:
inventory_item = replica_components.InventoryItem()
inventory_item.lot = item[1]
inventory_item.slot = item[2]
inventory_item.count = item[5]
inventory_item.object_id = item[0]
inventory_comp.items.append(inventory_item)
player.components[packet_enum.SerializedComponents.INVENTORY.value] = inventory_comp
controllable_physics = replica_components.ControllablePhysicsComponent()
pos = misc_serializables.Vector3()
p_points = character_info[4].split(",")
pos.x = float(p_points[0])
pos.y = float(p_points[1])
pos.z = float(p_points[2])
controllable_physics.position = pos
rot = misc_serializables.Vector4()
r_points = character_info[5].split(",")
rot.x = float(r_points[0])
rot.y = float(r_points[1])
rot.z = float(r_points[2])
rot.w = float(r_points[3])
controllable_physics.rotation = rot
player.components[packet_enum.SerializedComponents.CONTROLLABLE_PHYSICS.value] = controllable_physics
destructible_component = replica_components.DestructibleComponent()
stats_index = replica_components.StatsIndex()
stats_index.factions.append(1)
stats_index.health = character_info[6]
stats_index.max_health = character_info[7]
stats_index.armor = character_info[8]
stats_index.max_armor = character_info[9]
stats_index.imagination = character_info[10]
stats_index.max_imagination = character_info[11]
destructible_component.stats_index = stats_index
destructible_component.destructible_index = replica_components.DestructibleIndex()
player.components[packet_enum.SerializedComponents.DESTRUCTIBLE.value] = destructible_component
character_component = replica_components.CharacterComponent()
character_component.character_stats = character_stats[1:]
character_component.lego_score = character_info[2]
character_component.shirt_color = character_data[5]
character_component.pants_color = character_data[7]
character_component.hair_style = character_data[8]
character_component.hair_color = character_data[9]
character_component.eyebrows = character_data[12]
character_component.eyes = character_data[13]
character_component.mouth = character_data[14]
character_component.account_id = character_data[15]
character_component.activity = 1
player.components[packet_enum.SerializedComponents.CHARACTER.value] = character_component
server.additional_config["replica_manager"].construct(player)
server_done = WriteStream()
server_done.write(packet_enum.PacketHeader.SERVER_GAME_MESSAGE.value)
server_done.write(c_int64(int(player_info["id"])))
server_done.write(c_uint16(packet_enum.GameMessages.SERVER_DONE_LOADING_OBJECTS.value))
server.send(server_done, address)
player_ready = WriteStream()
player_ready.write(packet_enum.PacketHeader.SERVER_GAME_MESSAGE.value)
player_ready.write(c_int64(int(player_info["id"])))
player_ready.write(c_uint16(packet_enum.GameMessages.PLAYER_READY.value))
server.send(player_ready, address)
# This is just slightly different from the character instance handler
@classmethod
def handle_minifigure_list_request(cls, data: bytes, address, server):
c = server.db_connection.cursor()
packet = WriteStream()
session = server.lookup_session_by_ip(address[0])
c.execute("SELECT account_id FROM account WHERE username = %s", (session["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)
packet.write(packet_enum.PacketHeader.MINIFIGURE_LIST.value)
packet.write(char_list)
server.send(packet, address)