async def handle_permission_request(self, client: WvsLoginClient, packet: Packet): locale = packet.decode_byte() version = packet.decode_short() minor_version = packet.decode_string() if locale != server_constants.LOCALE or version != server_constants.SERVER_VERSION: client.close()
def create_new_char_result(success: LoginType, char: Character): send_packet = Packet(opcode=OutPacket.CREATE_NEW_CHARACTER_RESULT) send_packet.encode_byte(success.value) if success == LoginType.Success: char.cosmetic_info.encode_cosmetic(send_packet) return send_packet
def send_start_client(): """Returns the client start packet :return: Packet """ send_packet = Packet(opcode=OutPacket.CLIENT_START) send_packet.encode_byte(False) # encode byte return send_packet
def send_auth_server(use_auth_server: bool): """ :param use_auth_server: boolean :return: Packet """ send_packet = Packet(opcode=OutPacket.AUTH_SERVER) send_packet.encode_byte(use_auth_server) return send_packet
def send_connect(siv, riv): send_packet = Packet(opcode=15) send_packet.encode_short(server_constants.SERVER_VERSION) send_packet.encode_string(server_constants.MINOR_VERSION) send_packet.encode_int(riv) send_packet.encode_int(siv) send_packet.encode_byte(server_constants.LOCALE) return send_packet
async def handle_select_world(self, client: WvsLoginClient, packet: Packet): unk1 = packet.decode_byte() world_id = packet.decode_byte() channel = packet.decode_byte( ) + 1 # We add one cause channels start at index 0 client-side success_code = 0 user = client.user # Check if the instanced "user" object has accounts already instantiated if len(user.accounts) > 0: account = user.accounts[0] # We get the first one cause user should only have one account in this source else: account = user.get_account_from_db() world = global_states.worlds[ 0] # This way only allows us to have one world will change in the future if user is not None and world is not None and world.get_channel_by_id( channel) is not None: if account is None: account = Account(user=user, world_id=world_id) account.account_id = await database_manager.get_next_available_acc_id( ) account.init_characters() await database_manager.create_account( account ) # create a new row in SQL if account doesn't exist user.add_account(account) client.account = account client.world_id = world_id client.channel = channel await client.send_packet( Login.select_world_result(user=client.user, account=client.account, success_code=success_code, special_server="normal", burning_event_block=False)) else: await client.send_packet( Login.select_character_result( login_type=LoginType.UnauthorizedUser, error_code=0, port=0, character_id=0, ))
def encode(out_packet: Packet): out_packet.encode_byte(ENABLE_JOBS) out_packet.encode_byte(JOB_ORDER) for job_info in LOGIN_JOB.values(): job_type = job_info[0] job_flag = job_info[1] job_enum = job_info[2] out_packet.encode_byte(job_flag.value) out_packet.encode_short(job_flag.value)
def send_world_info_end(): send_packet = Packet(opcode=OutPacket.WORLD_INFORMATION) send_packet.encode_int(255) # Possible Ads encoding # ads = 0 # # advertisement = None if not ads else Advertisement() # send_packet.encode_byte(ads) # # for i in range(ads): # advertisement.encode(out_packet=send_packet) # # send_packet.encode_byte(0) # NotActiveAccountDlgFocus # send_packet.encode_int(49) # lockAccount Connection count return send_packet
async def handle_check_login_auth_info(self, client: WvsLoginClient, packet: Packet): """Where logging in is handled, passwords/username etc""" sid = packet.decode_byte() password = packet.decode_string() username = packet.decode_string() machine_id = packet.decode_buffer(16) success = False result = None # db_user is a database object, setting anything would set it in the database: SwordieDB() db_user = await database_manager.get_user_from_db(username) # this user is the User object in the source user = None if db_user is None and AUTO_REGISTER: # if there is no user in the database we register one await database_manager.register_user(username, password) await client.send_packet( WvsContext.broadcast_msg( BroadcastMsg.pop_up_message( "Your account has now been registered."))) if db_user is not None: if password.lower() == "fixme": # TODO, implement a loggedin check await client.send_packet( WvsContext.broadcast_msg( BroadcastMsg.pop_up_message( "Your account is now logged out."))) db_password = db_user.password success = db_password == password result = LoginType.Success if success else LoginType.IncorrectPassword if success: user = await User.get_user_from_name(username) client.user = user else: result = LoginType.NotRegistered await client.send_packet( Login.check_password_result(success, result, user))
def send_server_status(world_id: int): send_packet = Packet(opcode=OutPacket.SERVER_STATUS) world = None for world_created in worlds: if world_created.world_id == world_id: world = world_created if world is not None and not world.is_full(): send_packet.encode_byte(ServerStatus.NORMAL.value) else: send_packet.encode_byte(ServerStatus.BUSY.value) send_packet.encode_byte(0) # unknown return send_packet
async def handle_char_select_no_pic(self, client: WvsLoginClient, packet: Packet): """ Pic Creation, if the user does not already have a Pic Parameters ---------- client: WvsLoginClient packet: Packet ------- """ packet.decode_buffer(2) char_id = packet.decode_int() mac = packet.decode_string() unknown_string = packet.decode_string() pic = packet.decode_string() client.user.pic = pic # TODO: Hash Pic here if you choose to do so. await client.user.save() if client.user.get_first_account().get_char_by_id(char_id) is None: await client.send_packet( Login.select_character_result(LoginType.UnauthorizedUser, 0, 0, 0)) return world_id = client.world_id channel_id = client.channel # Note: We get the first world in worlds list in global_states.py (Not the best solution). channel = global_states.worlds[0].get_channel_by_id(channel_id) await client.send_packet( Login.select_character_result(LoginType.Success, 0, channel.port, char_id))
def check_duplicated_id_result(name: str, char_name_result: CharNameResult): send_packet = Packet(opcode=OutPacket.CHECK_DUPLICATED_ID_RESULT) send_packet.encode_string(name) send_packet.encode_byte(char_name_result.value) return send_packet
async def handle_check_duplicate_id(self, client: WvsLoginClient, packet: Packet): """ The Packet Handler for checking if a name is taken during character creation Parameters ---------- client: WvsLoginClient packet: Packet ------- """ name = packet.decode_string() code = None if name.lower() in BLOCKED_NAMES: code = CharNameResult.Unavailable_Invalid else: name_taken = await database_manager.check_name_taken(name) code = CharNameResult.Unavailable_InUse if name_taken else CharNameResult.Available await client.send_packet(Login.check_duplicated_id_result(name, code))
async def receive(self, client): self._is_online = True while self._is_online: if not self._overflow: recv_buffer = await self._loop.sock_recv( self._socket, self.receive_size) if not recv_buffer: client._parent.on_client_disconnect(client) return else: recv_buffer = self._overflow self._overflow = None if self.riv: async with self._lock: length = MapleAes.get_length(recv_buffer) if length != len(recv_buffer) - 4: self._overflow = recv_buffer[length + 4:] recv_buffer = recv_buffer[:length + 4] recv_buffer = self.manipulate_buffer(recv_buffer) client.dispatch(Packet(recv_buffer))
async def handle_client_error(self, client: WvsLoginClient, packet: Packet): client.close() if packet.get_length() < 8: debug.error(f"Error: {packet.to_string()}") return error_str_type = packet.decode_short() type_str = "" if error_str_type == 0x01: type_str = "SendBackupPacket" elif error_str_type == 0x02: type_str = "CrashReport" elif error_str_type == 0x03: type_str = "Exception" error_type = packet.decode_int() data_length = packet.decode_short() unk1 = packet.decode_int() opcode = packet.decode_short() debug.error(f"Error {error_type} at Opcode: {opcode}")
def encode(self, out_packet: Packet): out_packet.encode_string(self.striking_image) out_packet.encode_string(self.address_to_move) out_packet.encode_int(self.duration) out_packet.encode_int(self.width) out_packet.encode_int(self.height) out_packet.encode_int(self.x_pos) out_packet.encode_int(self.y_pos)
def send_auth_response(response: bool): send_packet = Packet(opcode=OutPacket.PRIVATE_SERVER_PACKET) send_packet.encode_int(response) return send_packet
def send_recommended_world_msg(world_id: int, msg: str): send_packet = Packet(opcode=OutPacket.RECOMMENDED_WORLD_MESSAGE) send_packet.encode_byte(1) send_packet.encode_int(world_id) send_packet.encode_string(msg) return send_packet
def send_world_information(world: World, string_infos: List[Tuple]): send_packet = Packet(opcode=OutPacket.WORLD_INFORMATION) send_packet.encode_byte(world.world_id) send_packet.encode_string(world.name) send_packet.encode_byte(world.world_state) send_packet.encode_string(world.world_event_description) send_packet.encode_short(world.world_event_exp_wse) send_packet.encode_short(world.world_event_drop_wse) send_packet.encode_byte(world.char_create_block) send_packet.encode_byte(world.get_channel_size()) for channel in world.channels: send_packet.encode_string(channel.name) send_packet.encode_int(channel.get_gauge_percent()) send_packet.encode_byte(channel.world_id) send_packet.encode_byte(channel.channel_id) send_packet.encode_byte(channel.adult_channel) if string_infos is None: send_packet.encode_short(0) else: send_packet.encode_short(len(string_infos)) for string_info in string_infos: send_packet.encode_position(string_info[0]) send_packet.encode_string(string_info[1]) send_packet.encode_int(0) # some Offset send_packet.encode_byte(world.star_planet) return send_packet
def select_world_result(user: User, account: Account, success_code: int, special_server: str, burning_event_block: bool) -> Packet: """ The packet that is sent to client when they Select a World (scania, etc) Parameters ---------- user: User account: Account success_code: int special_server: string burning_event_block: bool Returns: Packet ------- """ send_packet = Packet(opcode=OutPacket.SELECT_WORLD_RESULT) send_packet.encode_byte(success_code) send_packet.encode_string(special_server) send_packet.encode_int(14) # trunk/storage slot count send_packet.encode_byte(burning_event_block) reserved = 0 send_packet.encode_int(reserved) # Reserved size send_packet.encode_ft(FileTime(FileTimeType.ZERO_TIME)) for i in range(reserved): # FileTime send_packet.encode_int(0) # ft.encode() is_edited = False send_packet.encode_byte(is_edited) chars = account.characters chars.sort(key=lambda x: x.chr_id) # Sort by character ID char_size = len(chars) send_packet.encode_int(char_size) for char in chars: send_packet.encode_int(char.chr_id) send_packet.encode_byte(char_size) for char in chars: char.cosmetic_info.encode_cosmetic(send_packet) send_packet.encode_byte(False) # Family Stuff has_ranking = char.ranking is not None and not job_constants.is_gm_job( char.job_id) send_packet.encode_byte(False) if has_ranking: char.ranking.encode(send_packet) # TODO: Rankings encode send_packet.encode_byte(user.get_pic_status().value) # bLoginOpt send_packet.encode_byte(False) # bQuerySSNOnCreateNewCharacter send_packet.encode_int(user.character_slots) send_packet.encode_int(0) send_packet.encode_int(-1) # nEventNewCharJob send_packet.encode_ft(FileTime(FileTimeType.ZERO_TIME)) send_packet.encode_byte(0) # RenameCount send_packet.encode_byte(0) return send_packet
async def handle_create_new_char(self, client: WvsLoginClient, packet: Packet): """ This is where character creation entry begins. Parameters ---------- client: WvsLoginClient packet: Packet ------- """ account = client.account name = packet.decode_string() key_setting_type = packet.decode_int() event_new_char_sale_job = packet.decode_int() cur_selected_race = packet.decode_int() job = job_constants.get_login_job_by_id(cur_selected_race)[2] cur_selected_sub_job = packet.decode_short() gender = packet.decode_byte() skin = packet.decode_byte() item_length = packet.decode_byte() items = [packet.decode_int() for i in range(item_length)] face = items[0] hair = items[1] name_result_code = None # Add a check if starting items are valid if skin > 13 or skin < 0 or face < 20000 or face > 29999 or hair < 30000 or hair > 49999: print( f"{name} tried to add items unavailable on character creation") name_result_code = CharNameResult.Unavailable_CashItem name_taken = await database_manager.check_name_taken(name) if name in BLOCKED_NAMES: name_result_code = CharNameResult.Unavailable_Invalid elif name_taken: name_result_code = CharNameResult.Unavailable_InUse if name_result_code is not None: await client.send_packet( Login.check_duplicated_id_result(name, name_result_code)) return char_id = await database_manager.get_next_available_chr_id() char = Character( chr_id=char_id, acc_id=account.account_id, key_setting_type=key_setting_type, name=name, job_id=job.value[0], cur_selected_sub_job=cur_selected_sub_job, gender=gender, skin=skin, face=face, hair=hair, items=items, ) # TODO: Add Job Manager to Char char = await char.init_in_db() char_stat = char.cosmetic_info.character_stat if cur_selected_race == job_constants.LOGIN_JOB['DUAL_BLADE'][0]: char_stat.sub_job = 1 char_stat.world_id_for_log = account.world_id for hair_id in char.cosmetic_info.cosmetic_look.hair_equips: # TODO: Add item to inventory pass # TODO: Codex account.characters.append(char) await char.save() await account.save() await client.send_packet( Login.create_new_char_result(LoginType.Success, char))
async def handle_world_status_request(self, client: WvsLoginClient, packet: Packet): world_id = packet.decode_byte() await client.send_packet(Login.send_server_status(world_id))
def select_character_result(login_type: LoginType, error_code, port, character_id): send_packet = Packet(opcode=OutPacket.SELECT_CHARACTER_RESULT) send_packet.encode_byte(login_type.value) send_packet.encode_byte(error_code) if login_type == LoginType.Success: server = [8, 31, 99, 141] send_packet.encode_arr(server) send_packet.encode_short(port) chat_server = [8, 31, 99, 141] send_packet.encode_arr(chat_server) send_packet.encode_short(CHAT_PORT) send_packet.encode_int(character_id) send_packet.encode_byte(0) send_packet.encode_int(0) # ulArgument send_packet.encode_byte(0) send_packet.encode_int(0) send_packet.encode_int(0) send_packet.encode_byte(0) return send_packet
async def initialize(self): # Handshake packet send_packet = Packet(opcode=15) send_packet.encode_short(server_constants.SERVER_VERSION) send_packet.encode_string(server_constants.MINOR_VERSION) send_packet.encode_unsigned_int(self.socket.riv.value) send_packet.encode_unsigned_int(self.socket.siv.value) send_packet.encode_byte(server_constants.LOCALE) send_packet.encode_byte(False) await self.send_packet_raw(send_packet) await self.receive()
def encode(self, out_packet: Packet): out_packet.encode_short(self._charisma) out_packet.encode_short(self._insight) out_packet.encode_short(self._will) out_packet.encode_short(self._craft) out_packet.encode_short(self._sense) out_packet.encode_short(self._charm) out_packet.encode_byte(self._charm_by_cash_pr) out_packet.encode_ft(self._last_update_charm_by_cash_pr)
def encode(self, out_packet: Packet): for i in range(9): out_packet.encode_int(self.char_id) out_packet.encode_byte(self.level) out_packet.encode_int(self.job)
def encode(self, out_packet: Packet): out_packet.encode_byte(self.get_sp_set_size()) for sps in self.sp_set: out_packet.encode_byte(sps.job_level) out_packet.encode_int(sps.sp)
def encode(self, out_packet: Packet): out_packet.encode_int(self.chr_id) out_packet.encode_int(self.chr_id_for_log) out_packet.encode_int(self.world_id_for_log) out_packet.encode_fixed_string(self.name, 13) out_packet.encode_byte(self.gender) out_packet.encode_byte(self.skin) out_packet.encode_int(self.face) out_packet.encode_int(self.hair) out_packet.encode_byte(self.mix_base_hair_color) out_packet.encode_byte(self.mix_add_hair_color) out_packet.encode_byte(self.mix_hair_base_prob) out_packet.encode_byte(self.level) out_packet.encode_short(self.job) out_packet.encode_short(self.strength) out_packet.encode_short(self.dex) out_packet.encode_short(self.inte) out_packet.encode_short(self.luk) out_packet.encode_int(self.hp) out_packet.encode_int(self.max_hp) out_packet.encode_int(self.mp) out_packet.encode_int(self.max_hp) out_packet.encode_short(self.ap) if is_extend_sp_job(self.job): self.extend_sp.encode(out_packet) else: out_packet.encode_short(self.sp) out_packet.encode_long(int(self.exp)) out_packet.encode_int(self.pop) out_packet.encode_int(self.wp) out_packet.encode_int(int(self.pos_map)) out_packet.encode_int(self.gach_exp) out_packet.encode_byte(self.portal) out_packet.encode_int(0) # TODO: Figure out out_packet.encode_short(self.sub_job) job_id = self.job if is_demon(job_id) or is_xenon(job_id) or is_beast_tamer(job_id): out_packet.encode_int(self.def_face_acc) out_packet.encode_byte(self.fatigue) out_packet.encode_int(self.last_fatigue_update_time) out_packet.encode_int(self.charisma_exp) out_packet.encode_int(self.insight_exp) out_packet.encode_int(self.will_exp) out_packet.encode_int(self.craft_exp) out_packet.encode_int(self.sense_exp) out_packet.encode_int(self.charm_exp) self.non_combat_stat_day_limit.encode(out_packet) out_packet.encode_int(self.pvp_exp) out_packet.encode_byte(self.pvp_grade) out_packet.encode_int(self.pvp_point) out_packet.encode_byte(2) out_packet.encode_byte(self.pvp_mode_type) out_packet.encode_int(self.event_point) out_packet.encode_byte(self.alba_activity_id) out_packet.encode_ft(FileTime( FileTimeType.ZERO_TIME)) # self.alba_start_time out_packet.encode_int(self.alba_duration) out_packet.encode_byte(self.alba_special_reward) self.character_card.encode(out_packet) out_packet.encode_ft(FileTime( FileTimeType.ZERO_TIME)) # self.last_logout out_packet.encode_byte(self.burning)
def check_password_result(success: bool, login_type: LoginType, user: User) -> Packet: send_packet = Packet(opcode=OutPacket.CHECK_PASSWORD_RESULT) if success: send_packet.encode_byte(LoginType.Success.value) send_packet.encode_byte(0) send_packet.encode_int(0) send_packet.encode_string(user.name) send_packet.encode_int(user.user_id) send_packet.encode_byte(user.gender) send_packet.encode_byte(user.msg2) send_packet.encode_int(user.acc_type.value) send_packet.encode_int(user.age) has_censored = user.has_censored_nx_login_id send_packet.encode_byte(not has_censored) if has_censored: send_packet.encode_string(user.censored_nx_login_id) send_packet.encode_string(user.name) send_packet.encode_byte(user.p_block_reason) send_packet.encode_byte(0) # unknown send_packet.encode_long(user.chat_unblock_date) send_packet.encode_long(user.chat_unblock_date) send_packet.encode_int(user.character_slots + 3) job_constants.encode(send_packet) send_packet.encode_byte(user.grade_code) send_packet.encode_int(-1) # Enable Star Planet send_packet.encode_byte(0) # Unknown send_packet.encode_byte(0) # Unknown send_packet.encode_ft(user.creation_date) elif login_type == LoginType.Blocked: send_packet.encode_byte(login_type.value) send_packet.encode_byte(0) send_packet.encode_int(0) send_packet.encode_byte(0) send_packet.encode_ft(None) # FileTime is not handled atm else: send_packet.encode_byte(login_type.value) send_packet.encode_byte(0) send_packet.encode_int(0) return send_packet
def broadcast_msg(broadcast_msg): send_packet = Packet(opcode=OutPacket.BROADCAST_MSG) broadcast_msg.encode(send_packet) return send_packet