def __init__(self, file, conn=None): self.conn = conn or sqlite3.connect('client_assets/cdclient.sqlite') self.scenes = [] with open(file, 'rb') as file: self.data = file.read() self.size = len(self.data) self.stream = ReadStream(self.data, unlocked=True) self.version = self.stream.read(c_uint) assert self.version == 41, self.version self.unknown1 = self.stream.read(c_uint) self.world_id = self.stream.read(c_uint) self.spawnpoint = Vector3(self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float)) self.spawnpoint_rot = Vector4(self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float)) self.num_scenes = self.stream.read(c_uint) for _ in range(self.num_scenes): filename = self.stream.read(bytes, length_type=c_ubyte).decode('latin1') scene_id = self.stream.read(c_uint64) scene_name = self.stream.read(bytes, length_type=c_ubyte).decode('latin1') assert self.stream.read(bytes, length=3) pth = os.path.join('client_assets', 'luz', filename) if os.path.exists(pth): with open(pth, 'rb') as file: objects = self.get_lvl_objects(ReadStream(file.read(), unlocked=True)) self.scenes.append(LUScene(scene_id, scene_name, objects)) else: self.scenes.append(LUScene(scene_id, scene_name))
def deserialize(cls, stream: ReadStream): """ Deserializes the packet """ return cls(username=stream.read(str, allocated_length=33), session_key=stream.read(str, allocated_length=33), unknown=stream.read(bytes, length=33))
def mission_accept(self, packet, conn: Connection, stream: ReadStream): """ Handles the mission dialogue ok game message """ complete = stream.read(c_bit) state = stream.read(c_int) mission_id = stream.read(c_int) responder_objid = stream.read(c_int64) print(f'Mission {mission_id} accepted') print(f'Complete: {complete}') print(f'State: {state}') print(f'Responder: {responder_objid}') session = self.server.handle_until_return('session:get_session', conn.get_address()) char = self.server.handle_until_return( 'char:characters', session.account.user.id)[session.account.front_character] if complete: self.server.handle('char:complete_mission', char.pk, mission_id) wstr = WriteStream() wstr.write(c_int(mission_id)) wstr.write(c_int(8)) wstr.write(c_bit(False)) msg = ServerGameMessage(responder_objid, GameMessageID.NOTIFY_MISSION, wstr) else: self.server.handle('char:activate_mission', char.pk, mission_id) # tasks = self.server.handle_until_return('world:get_mission_tasks', mission_id) # for task in tasks: # wstr = WriteStream() # wstr.write(c_int(mission_id)) # wstr.write(c_int(1 << (task[2] + 1))) # wstr.write(c_uint8(0)) # msg = ServerGameMessage(packet.objid, GameMessageID.NOTIFY_MISSION_TASK, wstr) # conn.send(msg) wstr = WriteStream() wstr.write(c_int(mission_id)) wstr.write(c_int(2)) wstr.write(c_bit(False)) msg = ServerGameMessage(responder_objid, GameMessageID.NOTIFY_MISSION, wstr) conn.send(msg)
def request_linked_mission(self, packet, conn: Connection, stream: ReadStream): """ Handles the request linked mission game message """ objid = stream.read(c_int64) mission = stream.read(c_int) offered = stream.read(c_bit) print(f'Request for linked mission {mission}') print(f'Object ID: {objid}') print(f'Offered: {offered}')
def allow_packet(self, data: ReadStream, conn: Connection): """ Allows a packet """ packet = Packet.deserialize(ReadStream(data), self.server.packets) if not getattr(packet, 'allow_without_session') and not self.get_session( conn.get_address()): self.destroy_session(conn)
def deserialize(cls, stream: ReadStream, packet_types): """ Deserialize the packet """ header = LUHeader.deserialize(stream) packet = packet_types.get(getattr(header, 'packet_name', None)) if packet: return packet.deserialize(stream) return cls(header=header, data=stream.read_remaining())
def __init__(self, file, server_zone): self.conn = sqlite3.connect('client_assets/cdclient.sqlite') self.scenes = [] with open(file, 'rb') as file: self.data = file.read() self.size = len(self.data) self.stream = ReadStream(self.data, unlocked=True) self.version = self.stream.read(c_uint) assert self.version in (36, 38, 39, 40, 41), 'Unknown LUZ version ' + self.version self.unknown1 = self.stream.read(c_uint) self.world_id = self.stream.read(c_uint) if self.version >= 38: self.spawnpoint = Vector3(self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float)) self.spawnpoint_rot = LVLVector4(self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float)) else: # TODO: Verify what should actually happen in versions < 38 self.spawnpoint = Vector3(0,0,0) self.spawnpoint_rot = Vector4(0,0,0,0) if self.version >= 37: self.num_scenes = self.stream.read(c_uint) else: self.num_scenes = self.stream.read(c_ubyte) for _ in range(self.num_scenes): filename = self.stream.read(bytes, length_type=c_ubyte).decode('latin1') scene_id = self.stream.read(c_uint64) scene_name = self.stream.read(bytes, length_type=c_ubyte).decode('latin1') assert self.stream.read(bytes, length=3) lvl_path = os.path.join('client_assets', 'lvl', server_zone, filename) if os.path.exists(lvl_path): with open(lvl_path, 'rb') as file: objects = self.get_lvl_objects(ReadStream(file.read(), unlocked=True)) self.scenes.append(LUScene(scene_id, scene_name, objects)) else: self.scenes.append(LUScene(scene_id, scene_name))
def on_packet(self, data: ReadStream, conn: Connection): """ Packet handler """ packet = Packet.deserialize(ReadStream(data), self.server.packets) if not getattr(packet.header, 'packet_name', None): self.server.handle('pkt:unknown_packet', packet) else: log.debug( f'[{self.server.type}] Recieved LU Packet {packet.header.packet_name}' ) self.server.handle(f'pkt:{packet.header.packet_name}', packet, conn)
def collected(self, packet, conn: Connection, stream: ReadStream): """ Handles the has been collected game message """ objid = stream.read(c_int64) print(f'Collected object') print(f'ID: {packet.objid}') print(f'Player: {objid}') session = self.server.handle_until_return('session:get_session', conn.get_address()) char = self.server.handle_until_return( 'char:characters', session.account.user.id)[session.account.front_character] clone = self.server.handle_until_return('world:get_clone', session.clone) char_missions = self.server.handle_until_return( 'char:get_missions', char.pk) objs = [x for x in clone.objects if x.objid == packet.objid] if objs: obj = objs[0] for char_mission in [x for x in char_missions if x.state == 2]: tasks = self.server.handle_until_return( 'world:get_mission_tasks', char_mission.mission) for task in tasks: if task[3] == obj.lot and task[2] == 3: char_mission.progress += 1 char_mission.save() wstr = WriteStream() wstr.write(c_int(char_mission.mission)) wstr.write(c_int(1 << (tasks.index(task) + 1))) wstr.write(c_uint8(1)) wstr.write( c_float(char_mission.progress + (clone.zone << 8))) msg = ServerGameMessage( objid, GameMessageID.NOTIFY_MISSION_TASK, wstr) conn.send(msg) return
def client_game_message(self, packet: ClientGameMessage, conn: Connection): """ Handles the game messages """ if packet.extra_data: stream = ReadStream(packet.extra_data) if packet.message_id == GameMessageID.REQUEST_USE: self.request_use(packet, conn, stream) elif packet.message_id == GameMessageID.MISSION_DIALOGUE_OK: self.mission_accept(packet, conn, stream) elif packet.message_id == GameMessageID.REQUEST_LINKED_MISSION: self.request_linked_mission(packet, conn, stream) elif packet.message_id == GameMessageID.HAS_BEEN_COLLECTED: self.collected(packet, conn, stream) elif packet.message_id == 888: pass else: print(f'Unhandled game message: {packet.message_id}')
def deserialize(cls, stream: ReadStream): """ Deserializes the packet """ return cls(username=stream.read(str, allocated_length=33), password=stream.read(str, allocated_length=41), language_id=stream.read(c_uint16), unknown=stream.read(c_uint8), process_memory_info=stream.read(str, allocated_length=256), graphics_driver_info=stream.read(str, allocated_length=128), processor_count=stream.read(c_uint32), processor_type=stream.read(c_uint32), processor_level=stream.read(c_uint16), processor_revision=stream.read(c_uint16), unknown1=stream.read(c_uint32), os_major_version=stream.read(c_uint32), os_minor_version=stream.read(c_uint32), os_build_number=stream.read(c_uint32), os_platform_id=stream.read(c_uint32))
def deserialize(cls, stream: ReadStream): """ Deserializes the game version """ return cls(stream.read(c_uint16), stream.read(c_uint16), stream.read(c_uint16))
def deserialize(cls, stream: ReadStream): """ Deserializes the packet """ char_id = stream.read(c_int64) return cls(char_id)
def request_use(self, packet, conn: Connection, stream: ReadStream): """ Handles the request use game message """ session = self.server.handle_until_return('session:get_session', conn.get_address()) clone = self.server.handle_until_return('world:get_clone', session.clone) char = self.server.handle_until_return( 'char:front_char', session.account.character_set.all()) char_missions = self.server.handle_until_return( 'char:get_missions', char.pk) multiinteract = stream.read(c_bit) multiinteract_id = stream.read(c_uint32) multiinteract_type = stream.read(c_int) objid = stream.read(c_int64) secondary = stream.read(c_bit) print(f'Multi interact: {multiinteract}') print(f'Multi interact ID: {multiinteract_id}') print(f'Multi interact type: {multiinteract_type}') print(f'Object ID: {objid}') print(f'Secondary: {secondary}') objs = [x for x in clone.objects if x.objid == objid] if objs: obj = objs[0] if char_missions: missions = self.server.handle_until_return( 'world:missions_for_lot_target', obj.lot) for char_mission in [x for x in char_missions if x.state == 2]: missions2 = [ x for x in missions if x[0] == char_mission.mission ] if missions2: mission = missions2[0] self.server.handle('char:complete_mission', char.pk, mission[0]) msg = ServerGameMessage( packet.objid, GameMessageID.OFFER_MISSION, c_int(mission[0]) + c_int64(objid)) conn.send(msg) return missions = self.server.handle_until_return( 'world:missions_for_lot', obj.lot) missions = [ x for x in missions if x[0] not in [y.mission for y in char_missions if y.state == 8] ] if missions: mission = missions[0] msg = ServerGameMessage(packet.objid, GameMessageID.OFFER_MISSION, c_int(mission[0]) + c_int64(objid)) conn.send(msg)
class LUZReader: """ LEGO Universe Zone file reader """ def __init__(self, file, conn=None): self.conn = conn or sqlite3.connect('client_assets/cdclient.sqlite') self.scenes = [] with open(file, 'rb') as file: self.data = file.read() self.size = len(self.data) self.stream = ReadStream(self.data, unlocked=True) self.version = self.stream.read(c_uint) assert self.version == 41, self.version self.unknown1 = self.stream.read(c_uint) self.world_id = self.stream.read(c_uint) self.spawnpoint = Vector3(self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float)) self.spawnpoint_rot = Vector4(self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float)) self.num_scenes = self.stream.read(c_uint) for _ in range(self.num_scenes): filename = self.stream.read(bytes, length_type=c_ubyte).decode('latin1') scene_id = self.stream.read(c_uint64) scene_name = self.stream.read(bytes, length_type=c_ubyte).decode('latin1') assert self.stream.read(bytes, length=3) pth = os.path.join('client_assets', 'luz', filename) if os.path.exists(pth): with open(pth, 'rb') as file: objects = self.get_lvl_objects(ReadStream(file.read(), unlocked=True)) self.scenes.append(LUScene(scene_id, scene_name, objects)) else: self.scenes.append(LUScene(scene_id, scene_name)) def get_lvl_objects(self, stream): """ Parses a level file and returns its objects """ header = stream.read(bytes, length=4) objects = [] 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: objects = self.parse_chunk_2001(stream) elif chunk_type == 2002: pass stream.read_offset = (start_pos + chunk_len) * 8 return objects def parse_chunk_2001(self, stream): """ Parses chunk 2001 """ objects = [] 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(stream.read(c_float), stream.read(c_float), stream.read(c_float)) rot_w = stream.read(c_float) rot_z = stream.read(c_float) rot_y = stream.read(c_float) rot_x = stream.read(c_float) rotation = Vector4(rot_x, rot_y, rot_z, rot_w) scale = stream.read(c_float) config_data = parse_ldf(stream.read(str, length_type=c_uint)) assert stream.read(c_uint) == 0 if config_data.get('renderDisabled'): continue if lot == 176: lot = config_data['spawntemplate'] # if lot == 4638: # continue obj = LUObject(objid, lot, position, rotation, scale, config_data, self.conn) objects.append(obj) return objects
class LUZReader: """ LEGO Universe Zone file reader """ def __init__(self, file, server_zone): self.conn = sqlite3.connect('client_assets/cdclient.sqlite') self.scenes = [] with open(file, 'rb') as file: self.data = file.read() self.size = len(self.data) self.stream = ReadStream(self.data, unlocked=True) self.version = self.stream.read(c_uint) assert self.version in (36, 38, 39, 40, 41), 'Unknown LUZ version ' + self.version self.unknown1 = self.stream.read(c_uint) self.world_id = self.stream.read(c_uint) if self.version >= 38: self.spawnpoint = Vector3(self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float)) self.spawnpoint_rot = LVLVector4(self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float), self.stream.read(c_float)) else: # TODO: Verify what should actually happen in versions < 38 self.spawnpoint = Vector3(0,0,0) self.spawnpoint_rot = Vector4(0,0,0,0) if self.version >= 37: self.num_scenes = self.stream.read(c_uint) else: self.num_scenes = self.stream.read(c_ubyte) for _ in range(self.num_scenes): filename = self.stream.read(bytes, length_type=c_ubyte).decode('latin1') scene_id = self.stream.read(c_uint64) scene_name = self.stream.read(bytes, length_type=c_ubyte).decode('latin1') assert self.stream.read(bytes, length=3) lvl_path = os.path.join('client_assets', 'lvl', server_zone, filename) if os.path.exists(lvl_path): with open(lvl_path, 'rb') as file: objects = self.get_lvl_objects(ReadStream(file.read(), unlocked=True)) self.scenes.append(LUScene(scene_id, scene_name, objects)) else: self.scenes.append(LUScene(scene_id, scene_name)) def get_lvl_objects(self, stream): """ Parses a level file and returns its objects """ header = stream.read(bytes, length=4) objects = [] stream.read_offset = 0 if header == b'CHNK': while not stream.all_read(): assert stream.read_offset // 8 % 16 == 0, 'Invalid LVL chunk read offset' 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: objects = self.parse_chunk_2001(stream) elif chunk_type == 2002: pass stream.read_offset = (start_pos + chunk_len) * 8 return objects def parse_chunk_2001(self, stream): """ Parses chunk 2001 """ objects = [] 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 = stream.read(Vector3) rotation = stream.read(LVLVector4) scale = stream.read(c_float) config_data = parse_ldf(stream.read(str, length_type=c_uint)) assert stream.read(c_uint) == 0 if config_data.get('renderDisabled'): continue spawner=None if lot == 176: spawner=objid lot = config_data['spawntemplate'] objid = random.randint(1000000000000000000, 1999999999999999999) obj = LUObject(objid, lot, position, rotation, scale, config_data, spawner, self.conn) objects.append(obj) return objects