def __init__(self, xor_key, is_valid): self.unknown1 = Int8(1) self.id = Int8(is_valid) self.xor_key = Bytes(xor_key) self.unknown2 = Int32(1) self.unknown3 = Int32(1) self.unknown4 = Int8(1)
def __setitem__(self, key, value): try: if isinstance(key, slice): start = key.start stop = key.stop if start is None: start = 0 if stop is None: stop = len(self.data) - 1 if len(value) > stop - start: raise ValueError("Value is too long") elif start < len(self.data) and stop < len(self.data): for item_n, item in enumerate(value): self[start + item_n] = item else: raise ValueError() elif isinstance(value, Int8): self.data[key] = value else: self.data[key] = Int8(value) except IndexError: for _ in range(len(self.data), key): self.data.append(0) if isinstance(value, Int8): self.data.append(value) else: self.data.append(Int8(value))
class Reason: SYSTEM_ERROR = Int8(1) WRONG_PASSWORD = Int8(2) WRONG_LOGIN_OR_PASSWORD = Int8(2) ACCESS_DENIED = Int8(4) DATABASE_ERROR = Int8(5) ACCOUNT_ALREADY_IN_USE = Int8(7) ACCOUNT_BANNED = Int8(9) MAINTENANCE = Int8(16) EXPIRED = Int8(18) TIME_IS_UP = Int8(19)
class ServerList(LoginServerPacket): type = Int8(4) def __init__(self, servers_list: typing.List[GameServer] = None): self.servers = servers_list if servers_list is not None else [] @add_length @blowfish_encrypt() @add_checksum @add_padding() def encode(self, client): arr = ByteArray(self.type.encode()) arr.append(Int8(len(self.servers))) arr.append(Int8(client.account.latest_server)) for server in self.servers: arr.extend(Int8(server.id)) arr.append(Int8(server.ip[0])) arr.append(Int8(server.ip[1])) arr.append(Int8(server.ip[2])) arr.append(Int8(server.ip[3])) arr.append(Int32(server.port)) arr.append(Int8(server.age_limit)) arr.append(Int8(server.is_pvp)) arr.append(Int16(server.online)) arr.append(Int16(server.max_online)) arr.append(Int8(server.is_online)) arr.append(Int32(server.server_type)) arr.append(Int8(server.brackets)) arr.append(Int8(0)) return arr
class NewCharacter(GameClientPacket): type = Int8(168) arg_order = ["type"] @classmethod def parse(cls, data, client): return cls()
def __init__(self, iterable: bytes): self.data = [] if isinstance(iterable, ByteArray): self.data = iterable.data else: for value in iterable: self.data.append(Int8(value))
class UserInfo(GameServerPacket): type = Int8(4) arg_order = [ "type", "position_x", "position_y", "position_z", "head_tilt_angle", "character_id", "character_name", "race", "sex", "class_id", "level", "exp", "STR", "DEX", "CON", "INT", "WIT", "MEN", "max_hp", "current_hp", "max_mp", "current_mp", "sp", "inventory_weight", "max_inventory_weight", "unknown1", "underwear_id", "rear_id", "left_rear_id", "necklace_id", "right_ring_id", "left_ring_id", "helmet_id", "left_hand_id", "right_hand_id", "gloves_id", "main_armor_id", "leggings_id", "boots_id", "back_id", "left_right_hand_id", "hair_id", "face_id", "underwear_item_id", "rear_item_id", "left_rear_item_id", "necklace_item_id", "right_ring_item_id", "left_ring_item_id", "helmet_item_id", "left_hand_item_id", "right_hand_item_id", "gloves_item_id", "main_armor_item_id", "leggings_item_id", "boots_item_id", "back_item_id", "left_right_hand_item_id", "hair_item_id", "face_item_id", "unknown2", "patk", "patk_speed", "pdef", "evasion", "accuracy", "critical", "matk", "cast_speed", "attack_speed", "mdef", "is_in_pvp", "karma", "run_speed", "walk_speed", "run_swim_speed", "walk_swim_speed", "fl_run_speed", "fl_walk_speed", "run_fly_speed", "walk_fly_speed", "move_x", "atk_speed_x", "character_radius", "character_height", "haircut_type", "haircut_color", "face_type", "access_level", "title", "clan_id", "clan_icon_id", "alliance_id", "alliance_icon_id", "siege_flag", "is_riding", "private_store_type", "can_craft", "pvp_count", "pk_count", "cubes_summoned", "cubes", "find_party_members", "abnormal_effect", "unknown3", "clan_privileges", "recommends_left", "recommended", "unknown4", "max_inventory_items_count", "character_class_id", "effect_around_player", "max_cp", "current_cp", "enchant_state", "event_command_id", "big_clan_icon_id", "is_nobles", "is_hero", "is_fishing", "fish_x", "fish_y", "fish_z", "name_rgb", "walk_is_on", "clan_class", "unknown5", "title_rgb", "cursed_weapon_level" ]
class PlayFail(LoginServerPacket): type = Int8(6) arg_order = ["type", "reason_id"] REASON = Reason def __init__(self, reason_id): self.reason_id = Int8(reason_id)
class PlayOk(LoginServerPacket): type = Int8(7) arg_order = ["type", "play_ok1", "play_ok2", "unknown"] def __init__(self, play_ok1, play_ok2): self.play_ok1 = Int32(play_ok1) self.play_ok2 = Int32(play_ok2) self.unknown = Int8(1)
class ChangeMoveType(GameServerPacket): type = Int8(62) arg_order = ["character_id", "move_type", "constant"] def __init__(self, character_id, move_type): self.character_id = Int32(character_id) self.move_type = Int32(move_type) self.constant = Int32(0)
class AccountKicked(LoginServerPacket): type = Int8(2) arg_order = ["type", "kick_reason"] REASON = Reason def __init__(self, kick_reason_id): self.kick_reason = Int32(kick_reason_id)
class TeleportToLocation(GameServerPacket): type = Int8(56) arg_order = ["type", "character_id", "x", "y", "z"] def __init__(self, character_id, x, y, z): self.character_id = Int32(character_id) self.x = Int32(x) self.y = Int32(y) self.z = Int32(z)
def generate_game_key(cls): key = ByteArray(os.urandom(8)) key.append(Int8(0xc8)) key.append(Int8(0x27)) key.append(Int8(0x93)) key.append(Int8(0x01)) key.append(Int8(0xa1)) key.append(Int8(0x6c)) key.append(Int8(0x31)) key.append(Int8(0x97)) return key
def __init__(self, client): self.session_id = Int32(client.session_id) self.protocol_version = Int32(client.protocol_version) self.rsa_key = Bytes(client.rsa_key.scramble_mod()) self.unknown1 = Int32(0x29DD954E) self.unknown2 = Int32(0x77C39CFC) self.unknown3 = Int32(0x97ADB620) self.unknown4 = Int32(0x07BDE0F7) self.blowfish_key = Bytes(client.blowfish_key.key) self.null_termination = Int8(0)
class ChangeWaitType(GameServerPacket): type = Int8(47) arg_order = ["type", "character_id", "wait_type", "x", "y", "z"] def __init__(self, character_id, wait_type, x, y, z): self.character_id = Int32(character_id) self.wait_type = Int32(wait_type) self.x = Int32(x) self.y = Int32(y) self.z = Int32(z)
class LoginOk(LoginServerPacket): type = Int8(3) arg_order = ["type", "login_ok1", "login_ok2", "unknown"] def __init__(self, login_ok1, login_ok2): self.login_ok1 = Int32(login_ok1) self.login_ok2 = Int32(login_ok2) self.unknown = Bytes(b"\x00\x00\x00\x00" + b"\x00\x00\x00\x00" + b"\xEA\x03\x00\x00" + b"\x00\x00\x00\x00" + b"\x00\x00\x00\x00" + b"\x02\x00\x00\x00")
class ProtocolVersion(GameClientPacket): type = Int8(0) arg_order = ["type", "protocol_version"] skip_xor = True def __init__(self, protocol_version): self.protocol_version = Int32(protocol_version) @classmethod def parse(cls, data, client): version = Int32(data[1:5]) return cls(version)
class RequestAuthLogin(LoginClientPacket): type = Int8(0) arg_order = ["type", "login", "password"] def __init__(self, login, password): self.login = String(login) self.password = String(password) @classmethod @verify_checksum def parse(cls, data: ByteArray, client: "LoginClient"): data = ByteArray(data[1:]) encrypted = ByteArray(data[0:128]) key = client.rsa_key.m2crypto_key decrypt = key.private_decrypt(bytes(encrypted), RSA.no_padding) login = decrypt[94:107] password = decrypt[108:124] return cls(String.decode(login), String.decode(password)) @add_length @blowfish_encrypt() @add_checksum @add_padding() def encode(self, client): arr = ByteArray(self.type.encode()) encrypt_arr = ByteArray(b"") encrypt_arr.pad(128) encrypt_arr[0x5b] = 0x24 enc_login = self.login.encode() enc_password = self.password.encode() encrypt_arr[0x5e:0x5e + len(enc_login)] = enc_login encrypt_arr[0x6c:0x6c + len(enc_password)] = enc_password key = client.rsa_key.m2crypto_key encrypted_login_info = key.public_encrypt(bytes(encrypt_arr), RSA.no_padding) arr += ByteArray(encrypted_login_info) arr.append(client.session_id) arr += ByteArray([ 0x23, 0x01, 0x00, 0x00, 0x67, 0x45, 0x00, 0x00, 0xab, 0x89, 0x00, 0x00, 0xef, 0xcd, 0x00, 0x00 ]) arr += ByteArray( [0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) footer = ByteArray(b"") footer.pad(16) arr += footer return arr
class CharList(GameServerPacket): type = Int8(19) def __init__(self, characters_list: typing.List[Character]): self.characters = characters_list @add_length @xor_encrypt_game def encode(self, client): arr = ByteArray(self.type.encode()) arr.append(Int32(len(self.characters))) for character in self.characters: pass return arr
class RequestServerList(LoginClientPacket): type = Int8(5) arg_order = ["type", "session_id1"] def __init__(self, login_ok1, login_ok2): self.login_ok1 = Int32(login_ok1) self.login_ok2 = Int32(login_ok2) @classmethod @verify_checksum def parse(cls, data, client): data = data[1:] login_ok1 = data[0:4] login_ok2 = data[4:8] return cls(login_ok1, login_ok2)
def dexor(data, key): temp1 = Int32(0) for i in range(len(data)): temp2 = Int32(data[i]) & 0xff data[i] = Int8(temp2 ^ key[i & 15] ^ temp1) temp1 = temp2 old = (Int32(key[8]) & 0xff) old |= (Int32(key[9]) << 0x08) & 0xff00 old |= (Int32(key[10]) << 0x10) & 0xff0000 old |= (Int32(key[11]) << 0x18) & 0xff000000 old += Int32(len(data)) key[8:12] = old return data
class RequestServerLogin(LoginClientPacket): type = Int8(2) arg_order = ["type", "login_ok1", "login_ok2", "server_id"] def __init__(self, login_ok1, login_ok2, server_id): self.login_ok1 = Int32(login_ok1) self.login_ok2 = Int32(login_ok2) self.server_id = Int8(server_id) @classmethod @verify_checksum def parse(cls, data, client): data = ByteArray(data[1:]) login_ok1 = data[0:4] login_ok2 = data[4:8] server_id = data[8] return cls(login_ok1, login_ok2, server_id)
class CryptInit(GameServerPacket): type = Int8(0) arg_order = [ "type", "unknown1", "xor_key", "unknown2", "unknown3", "unknown4" ] def __init__(self, xor_key, is_valid): self.unknown1 = Int8(1) self.id = Int8(is_valid) self.xor_key = Bytes(xor_key) self.unknown2 = Int32(1) self.unknown3 = Int32(1) self.unknown4 = Int8(1) @classmethod def parse(cls, data, client): pass
class RequestAuthLogin(GameClientPacket): type = Int8(8) def __init__(self, login, play_ok1, play_ok2, login_ok1, login_ok2): self.login = String(login) self.play_ok1 = Int32(play_ok1) self.play_ok2 = Int32(play_ok2) self.login_ok1 = Int32(login_ok1) self.login_ok2 = Int32(login_ok2) @classmethod def parse(cls, data, client): login, pos = String.read(data, 1) play_ok2 = data[pos:pos + 4] play_ok1 = data[pos + 4:pos + 8] login_ok1 = data[pos + 8:pos + 12] login_ok2 = data[pos + 12:pos + 16] return cls(login, play_ok1, play_ok2, login_ok1, login_ok2)
class GGAuth(LoginServerPacket): type = Int8(11) arg_order = ["type", "reply", "zero1", "zero2", "zero3", "zero4"] def __init__(self, reply=1): self.reply = Int32(reply) self.zero1 = Int32(0) self.zero2 = Int32(0) self.zero3 = Int32(0) self.zero4 = Int32(0) async def answer(self, client): pass @classmethod @verify_checksum def parse(cls, data, client): return cls(data[1:5])
def xor(data, key): temp = Int32(0) for i in range(len(data)): temp2 = Int32(data[i] & 0xff) data[i] = Int8(temp2 ^ key[i & 15] ^ temp) temp = data[i] old = Int32(key[8] & 0xff) old |= Int32(key[9] << 0x08) & 0xff00 old |= Int32(key[10] << 0x10) & 0xff0000 old |= Int32(key[11] << 0x18) & 0xff000000 old += Int32(len(data)) key[8:12] = old return data
class MoveToLocation(GameServerPacket): type = Int8(1) arg_order = ["type", "object_id", "destination_x", "destination_y", "destination_z", "current_x", "current_y", "current_z"] def __init__(self, object_id, destination_x, destination_y, destination_z, current_x, current_y, current_z): self.object_id = Int32(object_id) self.destination_x = Int32(destination_x) self.destination_y = Int32(destination_y) self.destination_z = Int32(destination_z) self.current_x = Int32(current_x) self.current_y = Int32(current_y) self.current_z = Int32(current_z)
class Init(LoginServerPacket): type = Int8(0) arg_order = [ "type", "session_id", "protocol_version", "rsa_key", "unknown1", "unknown2", "unknown3", "unknown4", "blowfish_key", "null_termination" ] def __init__(self, client): self.session_id = Int32(client.session_id) self.protocol_version = Int32(client.protocol_version) self.rsa_key = Bytes(client.rsa_key.scramble_mod()) self.unknown1 = Int32(0x29DD954E) self.unknown2 = Int32(0x77C39CFC) self.unknown3 = Int32(0x97ADB620) self.unknown4 = Int32(0x07BDE0F7) self.blowfish_key = Bytes(client.blowfish_key.key) self.null_termination = Int8(0) @add_length @blowfish_encrypt(init=True) @xor_encrypt_login @add_padding(xor_key=True) def encode(self, client): return self.body @classmethod def parse(cls, data, client): client.xor_key = LoginXorKey(Int32.decode(data[-8:-4])) data = xor_decrypt_login(lambda packet_cls, data, client: data)(cls, data, client) data = data[1:] client.session_id = Int32.decode(data[0:4]) client.protocol_version = Int32.decode(data[4:8]) client.rsa_key = L2RsaKey.from_scrambled(bytes(ByteArray(data[8:136]))) client.blowfish_key = BlowfishKey(bytes(ByteArray(data[152:168]))) return cls(client)
def __init__(self): self.static = Int8(1)
class CharCreateOk(GameServerPacket): type = Int8(19) arg_order = ["type", "static"] def __init__(self): self.static = Int8(1)