def handle(world_session, socket, reader: PacketReader) -> int: speed = 0.0 if world_session.player_mgr.is_gm: if len(reader.data ) >= 52: # Avoid handling empty speed cheat packet. speed = unpack('<f', reader.data[48:52])[0] else: # Disconnect if the player is not a GM. Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to use speed cheats.' ) return -1 if reader.opcode == OpCode.MSG_MOVE_SET_RUN_SPEED_CHEAT: world_session.player_mgr.change_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_SWIM_SPEED_CHEAT: world_session.player_mgr.change_swim_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_WALK_SPEED_CHEAT: world_session.player_mgr.change_walk_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_TURN_RATE_CHEAT: world_session.player_mgr.change_turn_speed(speed) else: return -1 return 0
def handle(world_session, socket, reader: PacketReader) -> int: speed = 0.0 if world_session.player_mgr.is_gm: if len(reader.data ) >= 52: # Avoid handling empty speed cheat packet. speed = unpack('<f', reader.data[48:52])[0] else: Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to use speed hacks.' ) # A speed of 0 will ensure that the speed is reset to the default values if the player is not a GM. if reader.opcode == OpCode.MSG_MOVE_SET_RUN_SPEED_CHEAT: world_session.player_mgr.change_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_SWIM_SPEED_CHEAT: world_session.player_mgr.change_swim_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_WALK_SPEED_CHEAT: world_session.player_mgr.change_walk_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_TURN_RATE_CHEAT: world_session.player_mgr.change_turn_speed(speed) # Disconnect if the player is not a GM as I haven't found a way to change turn speed back to normal. if not world_session.player_mgr.is_gm: return -1 else: return -1 return 0
def handle(world_session, socket, reader: PacketReader) -> int: if world_session.player_mgr.is_gm: # GM only. world_session.player_mgr.taxi_manager.disable_all_taxi_nodes() else: Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to clear all known taxi nodes.' ) return 0
def handle(world_session, socket, reader): if world_session.player_mgr.is_gm: pack_guid, map_, x, y, z, o = unpack('<IB4f', reader.data) world_session.player_mgr.teleport(map_, Vector(x, y, z, o)) else: Logger.anticheat('Player %s (%s) tried to teleport himself.' % (world_session.player_mgr.player.name, world_session.player_mgr.guid)) return 0
def handle(world_session, socket, reader: PacketReader) -> int: if len(reader.data) >= 4: # Avoid handling empty create item packet. item_entry = unpack('<I', reader.data[:4])[0] if not world_session.player_mgr.is_gm: Logger.anticheat(f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried create item {item_entry}.') return 0 CommandManager.additem(world_session, str(item_entry)) return 0
def handle(world_session, socket, reader: PacketReader) -> int: if not world_session.player_mgr.is_gm: Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to recharge powers.' ) return 0 world_session.player_mgr.recharge_power() return 0
def handle(world_session, socket, reader: PacketReader) -> int: if len(reader.data) >= 1: # Avoid handling empty god mode packet. if not world_session.player_mgr.is_gm: Logger.anticheat(f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to set godmode.') return 0 world_session.player_mgr.is_god = unpack('<B', reader.data[:1])[0] >= 1 world_session.enqueue_packet(PacketWriter.get_packet(OpCode.SMSG_GODMODE, reader.data[:1])) return 0
def handle(world_session, socket, reader: PacketReader) -> int: player_mgr = world_session.player_mgr if not player_mgr: return 0 if not player_mgr.is_gm: Logger.anticheat(f'Player {player_mgr.player.name} ({player_mgr.guid}) tried to clear all taxi nodes.') return 0 player_mgr.taxi_manager.disable_all_taxi_nodes() return 0
def handle(world_session, socket, reader: PacketReader) -> int: if len(reader.data) >= 4: # Avoid empty packet level cheat packet. new_level = unpack('<I', reader.data[:4])[0] if not world_session.player_mgr.is_gm: Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to level to {new_level}.' ) return 0 world_session.player_mgr.mod_level(new_level) return 0
def handle(world_session, socket, reader: PacketReader) -> int: if len(reader.data ) >= 4: # Avoid handling empty cheat set money packet. new_money = unpack('<I', reader.data[:4])[0] if not world_session.player_mgr.is_gm: Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to give himself {new_money} copper.' ) return 0 world_session.player_mgr.mod_money(new_money) return 0
def handle(world_session, socket, reader): if len(reader.data ) >= 4: # Avoid handling empty learn spell cheat packet. spell_id = unpack('<I', reader.data[:4])[0] if not world_session.player_mgr.is_gm: Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to learn the spell {spell_id}.' ) return 0 world_session.player_mgr.spell_manager.learn_spell(spell_id) return 0
def handle(world_session, socket, reader: PacketReader) -> int: player_mgr = world_session.player_mgr if not player_mgr: return 0 if not player_mgr.is_gm: Logger.anticheat( f'Player {player_mgr.player.name} ({player_mgr.guid}) tried to modify level.' ) return 0 player_mgr.mod_level(player_mgr.level + 1) return 0
def handle(world_session, socket, reader): if not world_session.player_mgr.is_gm: Logger.anticheat(f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to remove his cooldowns.') return 0 # Clear server-side cooldowns. for cooldown_entry in list(world_session.player_mgr.spell_manager.cooldowns): world_session.player_mgr.spell_manager.cooldowns.remove(cooldown_entry) # Clear client-side cooldowns. data = pack('<Q', world_session.player_mgr.guid) world_session.player_mgr.enqueue_packet(PacketWriter.get_packet(OpCode.SMSG_COOLDOWN_CHEAT, data)) return 0
def handle(world_session, socket, reader): # Don't teleport if player is in the middle of a flight. if world_session.player_mgr.movement_spline and world_session.player_mgr.movement_spline.flags == SplineFlags.SPLINEFLAG_FLYING: return 0 if world_session.player_mgr.is_gm: if len(reader.data ) >= 21: # Avoid handling empty world teleport packet. pack_guid, map_, x, y, z, o = unpack('<IB4f', reader.data[:21]) world_session.player_mgr.teleport(map_, Vector(x, y, z, o)) else: Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to teleport himself.' ) return 0
def handle(world_session, socket, reader): if len(reader.data) < 8: # Avoid handling wrong player login packet return -1 guid = unpack('<Q', reader.data[:8])[0] world_session.player_mgr = PlayerManager( RealmDatabaseManager.character_get_by_guid(guid), world_session) world_session.player_mgr.session = world_session if not world_session.player_mgr.player: Logger.anticheat('Character with wrong guid (%u) tried to login.' % guid) return -1 socket.sendall( PacketWriter.get_packet(OpCode.SMSG_LOGIN_SETTIMESPEED, PlayerLoginHandler._get_login_timespeed())) world_session.player_mgr.load_skills() world_session.player_mgr.load_spells() world_session.player_mgr.deathbind = RealmDatabaseManager.character_get_deathbind( world_session.player_mgr.guid) socket.sendall(world_session.player_mgr.get_deathbind_packet()) # Tutorials aren't implemented in 0.5.3 # socket.sendall(world_session.player_mgr.get_tutorial_packet()) socket.sendall(world_session.player_mgr.get_initial_spells()) socket.sendall(world_session.player_mgr.get_action_buttons()) # MotD ChatManager.send_system_message(world_session, config.Server.General.motd) world_session.player_mgr.inventory.load_items() world_session.player_mgr.stat_manager.init_stats() world_session.player_mgr.stat_manager.apply_bonuses() world_session.player_mgr.send_update_self(create=True) world_session.player_mgr.reset_fields() PlayerLoginHandler._send_cinematic(world_session, world_session.player_mgr.player, socket) world_session.player_mgr.complete_login() return 0
def handle(world_session, socket, reader: PacketReader) -> int: if len(reader.data ) >= 4: # Avoid handling empty trigger cinematic cheat packet. if not world_session.player_mgr.is_gm: Logger.anticheat( f'Player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}) tried to force trigger a cinematic.' ) return 0 cinematic_id = unpack('<I', reader.data[:4])[0] if DbcDatabaseManager.cinematic_sequences_get_by_id(cinematic_id): data = pack('<I', cinematic_id) world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_TRIGGER_CINEMATIC, data)) return 0
def handle(world_session, socket, reader): if not world_session.player_mgr.is_gm: Logger.anticheat('Player %s (%s) tried to use speed hacks.' % (world_session.player_mgr.player.name, world_session.player_mgr.guid)) if reader.opcode == OpCode.MSG_MOVE_SET_RUN_SPEED_CHEAT: world_session.player_mgr.change_speed() elif reader.opcode == OpCode.MSG_MOVE_SET_SWIM_SPEED_CHEAT: world_session.player_mgr.change_swim_speed() elif reader.opcode == OpCode.MSG_MOVE_SET_WALK_SPEED_CHEAT: world_session.player_mgr.change_walk_speed() elif reader.opcode == OpCode.MSG_MOVE_SET_TURN_RATE_CHEAT: # world_session.player_mgr.change_turn_speed() # Disconnect as I haven't found a way to change turn speed back to normal return -1 return 0
def handle(world_session, socket, reader: PacketReader) -> int: player_mgr = world_session.player_mgr if not player_mgr: return 0 if not player_mgr.is_gm: Logger.anticheat( f'Player {player_mgr.player.name} ({player_mgr.guid}) tried to give himself Beastmaster.' ) return 0 if len(reader.data) >= 1: # Avoid handling empty beast master packet. # Client sends `0` if you type `beastmaster off`, and `1` if you type `beastmaster`. player_mgr.beast_master = unpack('<B', reader.data[:1])[0] >= 1 ChatManager.send_system_message( world_session, f'Beastmaster ' f'{"enabled" if player_mgr.beast_master else "disabled"}') return 0
def handle(world_session, socket, reader: PacketReader) -> int: player_mgr = world_session.player_mgr if not player_mgr: return 0 if not player_mgr.is_gm: Logger.anticheat( f'Player {player_mgr.player.name} ({player_mgr.guid}) tried to set god mode.' ) return 0 if len(reader.data) >= 1: # Avoid handling empty god mode packet. # Client sends `0` if you type `godmode`, and `1` if you type `godmode 1` (or a number greater than 1). player_mgr.is_god = unpack('<B', reader.data[:1])[0] >= 1 world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_GODMODE, reader.data[:1])) ChatManager.send_system_message( world_session, f'Godmode ' f'{"enabled" if player_mgr.is_god else "disabled"}') return 0
def handle(world_session, socket, reader): if len(reader.data) < 8: # Avoid handling wrong player login packet return -1 guid = unpack('<Q', reader.data[:8])[0] world_session.player_mgr = PlayerManager( RealmDatabaseManager.character_get_by_guid(guid), world_session) world_session.player_mgr.session = world_session if not world_session.player_mgr.player: Logger.anticheat('Character with wrong guid (%u) tried to login.' % guid) return -1 socket.sendall(PacketWriter.get_packet(OpCode.SMSG_LOGIN_SETTIMESPEED, PlayerLoginHandler._get_login_timespeed())) world_session.player_mgr.load_skills() world_session.player_mgr.load_spells() socket.sendall(world_session.player_mgr.get_tutorial_packet()) socket.sendall(world_session.player_mgr.get_initial_spells()) socket.sendall(world_session.player_mgr.get_action_buttons()) # MotD ChatManager.send_system_message(world_session, config.Server.General.motd) # Clear Who list on login, otherwise the last search will appear PlayerLoginHandler._clear_who_list(socket) world_session.player_mgr.inventory.load_items() update_packet = UpdatePacketFactory.compress_if_needed(PacketWriter.get_packet( OpCode.SMSG_UPDATE_OBJECT, world_session.player_mgr.get_update_packet(update_type=UpdateTypes.UPDATE_FULL))) socket.sendall(update_packet) PlayerLoginHandler._send_cinematic(world_session, world_session.player_mgr.player, socket) world_session.player_mgr.complete_login() return 0
def handle(world_session, socket, reader: PacketReader) -> int: player_mgr = world_session.player_mgr if not player_mgr: return 0 if not player_mgr.is_gm: Logger.anticheat( f'Player {player_mgr.player.name} ({player_mgr.guid}) tried to modify speed.' ) return 0 if len(reader.data) >= 52: # Avoid handling empty speed cheat packet. speed = unpack('<f', reader.data[48:52])[0] if reader.opcode == OpCode.MSG_MOVE_SET_RUN_SPEED_CHEAT: player_mgr.change_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_SWIM_SPEED_CHEAT: player_mgr.change_swim_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_WALK_SPEED_CHEAT: player_mgr.change_walk_speed(speed) elif reader.opcode == OpCode.MSG_MOVE_SET_TURN_RATE_CHEAT: player_mgr.change_turn_speed(speed) return 0
def handle_movement_status(world_session, socket, reader): # Avoid handling malformed movement packets, or handling them while no player or player teleporting if world_session.player_mgr and len(reader.data) >= 48: try: transport_guid, transport_x, transport_y, transport_z, transport_o, x, y, z, o, pitch, flags = \ unpack('<Q9fI', reader.data[:48]) # Hacky way to prevent random teleports when colliding with elevators # Also acts as a rudimentary teleport cheat detection if not world_session.player_mgr.pending_taxi_destination and world_session.player_mgr.location.distance( x=x, y=y, z=z) > 64: Logger.anticheat( f'Preventing coordinate desync from player {world_session.player_mgr.player.name} ({world_session.player_mgr.guid}).' ) world_session.player_mgr.teleport( world_session.player_mgr.map_, world_session.player_mgr.location) return 0 # Send movement info to SpellManager until movement handling is merged to update system if flags & 0xF != 0: # MoveFlags.MOVEFLAG_MOVE_MASK | MoveFlags.MOVEFLAG_STRAFE_MASK world_session.player_mgr.spell_manager.flag_as_moved() world_session.player_mgr.transport_id = transport_guid world_session.player_mgr.transport.x = transport_x world_session.player_mgr.transport.y = transport_y world_session.player_mgr.transport.z = transport_z world_session.player_mgr.transport.o = transport_o world_session.player_mgr.location.x = x world_session.player_mgr.location.y = y world_session.player_mgr.location.z = z world_session.player_mgr.location.o = o world_session.player_mgr.pitch = pitch world_session.player_mgr.movement_flags = flags if flags & MoveFlags.MOVEFLAG_SPLINE_MOVER: world_session.player_mgr.movement_spline = MovementManager.MovementSpline.from_bytes( reader.data[48:]) movement_data = pack(f'<Q{len(reader.data)}s', world_session.player_mgr.guid, reader.data) GridManager.send_surrounding(PacketWriter.get_packet( OpCode(reader.opcode), movement_data), world_session.player_mgr, include_self=False) GridManager.update_object(world_session.player_mgr) world_session.player_mgr.sync_player() # Get up if you jump while not standing if reader.opcode == OpCode.MSG_MOVE_JUMP and \ world_session.player_mgr.stand_state != StandState.UNIT_DEAD and \ world_session.player_mgr.stand_state != StandState.UNIT_STANDING: world_session.player_mgr.stand_state = StandState.UNIT_STANDING world_session.player_mgr.set_dirty() except (AttributeError, error): Logger.error( f'Error while handling {OpCode(reader.opcode).name}, skipping. Data: {reader.data}' ) return 0
def handle_movement_status(world_session, socket, reader): movement_fmt = '<QfffffffffI' if not world_session.player_mgr.is_teleporting and len( reader.data ) >= 48: # Avoid handling malformed movement packets try: transport_guid, transport_x, transport_y, transport_z, transport_o, x, y, z, o, pitch, flags = \ unpack(movement_fmt, reader.data[:48]) # Hacky way to prevent random teleports when colliding with elevators # Also acts as a rudimentary teleport cheat detection if world_session.player_mgr.location.distance(x=x, y=y, z=z) > 64: Logger.anticheat( "Preventing coordinate desync from player %s (%s)." % (world_session.player_mgr.player.name, world_session.player_mgr.guid)) world_session.player_mgr.teleport( world_session.player_mgr.map_, world_session.player_mgr.location) return 0 world_session.player_mgr.transport_id = transport_guid world_session.player_mgr.transport.x = transport_x world_session.player_mgr.transport.y = transport_y world_session.player_mgr.transport.z = transport_z world_session.player_mgr.transport.o = transport_o world_session.player_mgr.location.x = x world_session.player_mgr.location.y = y world_session.player_mgr.location.z = z world_session.player_mgr.location.o = o world_session.player_mgr.pitch = pitch world_session.player_mgr.movement_flags = flags movement_data = pack('<Q%us' % len(reader.data), world_session.player_mgr.guid, reader.data) GridManager.send_surrounding(PacketWriter.get_packet( OpCode(reader.opcode), movement_data), world_session.player_mgr, include_self=False) GridManager.update_object(world_session.player_mgr) world_session.player_mgr.sync_player() if reader.opcode == OpCode.MSG_MOVE_JUMP and \ world_session.player_mgr.stand_state != StandState.UNIT_DEAD and \ world_session.player_mgr.stand_state != StandState.UNIT_STANDING: world_session.player_mgr.stand_state = StandState.UNIT_STANDING world_session.player_mgr.flagged_for_update = True except (AttributeError, error): Logger.error('Error while handling %s, skipping. Data: %s' % (OpCode(reader.opcode), reader.data)) return 0
def send_trainer_list(self, world_session): if not self.can_train(world_session.player_mgr): Logger.anticheat(f'send_trainer_list called from NPC {self.entry} by player with GUID {world_session.player_mgr.guid} but this unit does not train that player\'s class. Possible cheating') return train_spell_bytes: bytes = b'' train_spell_count: int = 0 trainer_ability_list: list[TrainerTemplate] = WorldDatabaseManager.TrainerSpellHolder.trainer_spells_get_by_trainer(self.entry) if not trainer_ability_list or trainer_ability_list.count == 0: Logger.warning(f'send_trainer_list called from NPC {self.entry} but no trainer spells found!') return for trainer_spell in trainer_ability_list: # trainer_spell: The spell the trainer uses to teach the player. player_spell_id = trainer_spell.playerspell ability_spell_chain: SpellChain = WorldDatabaseManager.SpellChainHolder.spell_chain_get_by_spell(player_spell_id) spell_level: int = trainer_spell.reqlevel # Use this and not spell data, as there are differences between data source (2003 Game Guide) and what is in spell table. spell_rank: int = ability_spell_chain.rank prev_spell: int = ability_spell_chain.prev_spell spell_is_too_high_level: bool = spell_level > world_session.player_mgr.level if player_spell_id in world_session.player_mgr.spell_manager.spells: status = TrainerServices.TRAINER_SERVICE_USED else: if prev_spell in world_session.player_mgr.spell_manager.spells and spell_rank > 1 and not spell_is_too_high_level: status = TrainerServices.TRAINER_SERVICE_AVAILABLE elif spell_rank == 1 and not spell_is_too_high_level: status = TrainerServices.TRAINER_SERVICE_AVAILABLE else: status = TrainerServices.TRAINER_SERVICE_UNAVAILABLE data: bytes = pack( '<IBI3B6I', player_spell_id, # Spell id status, # Status trainer_spell.spellcost, # Cost trainer_spell.talentpointcost, # Talent Point Cost trainer_spell.skillpointcost, # Skill Point Cost spell_level, # Required Level trainer_spell.reqskill, # Required Skill Line trainer_spell.reqskillvalue, # Required Skill Rank 0, # Required Skill Step prev_spell, # Required Ability (1) 0, # Required Ability (2) 0 # Required Ability (3) ) train_spell_bytes += data train_spell_count += 1 # TODO: Temp placeholder. greeting: str = f'Hello, {world_session.player_mgr.player.name}! Ready for some training?' greeting_bytes = PacketWriter.string_to_bytes(greeting) greeting_bytes = pack( f'<{len(greeting_bytes)}s', greeting_bytes ) data = pack('<Q2I', self.guid, TrainerTypes.TRAINER_TYPE_GENERAL, train_spell_count) + train_spell_bytes + greeting_bytes world_session.player_mgr.enqueue_packet(PacketWriter.get_packet(OpCode.SMSG_TRAINER_LIST, data))
def handle(world_session, socket, reader): if len(reader.data) < 8: # Avoid handling wrong player login packet. return -1 guid = unpack('<Q', reader.data[:8])[0] world_session.player_mgr = PlayerManager( RealmDatabaseManager.character_get_by_guid(guid), world_session) world_session.player_mgr.session = world_session if not world_session.player_mgr.player: Logger.anticheat( f'Character with wrong guid ({guid}) tried to login.') return -1 else: WorldSessionStateHandler.push_active_player_session(world_session) # Disabled race & class checks (only if not a GM) if not world_session.player_mgr.is_gm: disabled_race_mask = config.Server.General.disabled_race_mask disabled = disabled_race_mask & world_session.player_mgr.race_mask == world_session.player_mgr.race_mask if not disabled: disabled_class_mask = config.Server.General.disabled_class_mask disabled = disabled_class_mask & world_session.player_mgr.class_mask == world_session.player_mgr.class_mask if disabled: # Not 100% sure if CHAR_LOGIN_DISABLED matters here, but I don't know where else to send it data = pack('<B', CharLogin.CHAR_LOGIN_DISABLED) world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_CHARACTER_LOGIN_FAILED, data)) return 0 # Class & race allowed, continue with the login process world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_LOGIN_SETTIMESPEED, PlayerLoginHandler._get_login_timespeed())) world_session.player_mgr.skill_manager.load_proficiencies() world_session.player_mgr.spell_manager.load_spells() world_session.player_mgr.deathbind = RealmDatabaseManager.character_get_deathbind( world_session.player_mgr.guid) world_session.player_mgr.friends_manager.load_from_db( RealmDatabaseManager.character_get_social( world_session.player_mgr.guid)) world_session.enqueue_packet( world_session.player_mgr.get_deathbind_packet()) # Tutorials aren't implemented in 0.5.3 # world_session.enqueue_packet(world_session.player_mgr.get_tutorial_packet()) world_session.player_mgr.skill_manager.init_proficiencies() world_session.enqueue_packet( world_session.player_mgr.spell_manager.get_initial_spells()) world_session.enqueue_packet( world_session.player_mgr.get_action_buttons()) # MotD ChatManager.send_system_message(world_session, config.Server.General.motd) world_session.player_mgr.inventory.load_items() world_session.player_mgr.stat_manager.init_stats() world_session.player_mgr.stat_manager.apply_bonuses() world_session.player_mgr.skill_manager.load_skills() world_session.player_mgr.quest_manager.load_quests() world_session.player_mgr.reputation_manager.load_reputations() GuildManager.set_character_guild(world_session.player_mgr) GroupManager.set_character_group(world_session.player_mgr) PetitionManager.load_petition(world_session.player_mgr) # First login if world_session.player_mgr.player.totaltime == 0: # Replenish health, and mana if needed. world_session.player_mgr.set_health( world_session.player_mgr.max_health) if world_session.player_mgr.power_type == PowerTypes.TYPE_MANA: world_session.player_mgr.set_mana( world_session.player_mgr.max_power_1) # Load self before sending cinematic PlayerLoginHandler._load_self(world_session.player_mgr) # Send cinematic PlayerLoginHandler._send_cinematic(world_session, world_session.player_mgr.player, socket) else: PlayerLoginHandler._load_self(world_session.player_mgr) world_session.player_mgr.complete_login() return 0
def handle_movement_status(world_session, socket, reader): # Avoid handling malformed movement packets, or handling them while no player or player teleporting if world_session.player_mgr and not world_session.player_mgr.is_teleporting and len(reader.data) >= 48: try: transport_guid, transport_x, transport_y, transport_z, transport_o, x, y, z, o, pitch, flags = \ unpack('<Q9fI', reader.data[:48]) # Hacky way to prevent random teleports when colliding with elevators # Also acts as a rudimentary teleport cheat detection if not world_session.player_mgr.pending_taxi_destination and world_session.player_mgr.location.distance( x=x, y=y, z=z) > 64: Logger.anticheat("Preventing coordinate desync from player %s (%s)." % (world_session.player_mgr.player.name, world_session.player_mgr.guid)) world_session.player_mgr.teleport(world_session.player_mgr.map_, world_session.player_mgr.location) return 0 world_session.player_mgr.transport_id = transport_guid world_session.player_mgr.transport.x = transport_x world_session.player_mgr.transport.y = transport_y world_session.player_mgr.transport.z = transport_z world_session.player_mgr.transport.o = transport_o world_session.player_mgr.location.x = x world_session.player_mgr.location.y = y world_session.player_mgr.location.z = z world_session.player_mgr.location.o = o world_session.player_mgr.pitch = pitch world_session.player_mgr.movement_flags = flags if flags & MoveFlags.MOVEFLAG_SPLINE_MOVER: world_session.player_mgr.movement_spline = MovementManager.MovementSpline.from_bytes( reader.data[48:]) movement_data = pack('<Q%us' % len(reader.data), world_session.player_mgr.guid, reader.data) GridManager.send_surrounding(PacketWriter.get_packet(OpCode(reader.opcode), movement_data), world_session.player_mgr, include_self=False) GridManager.update_object(world_session.player_mgr) world_session.player_mgr.sync_player() # Hackfix for client not sending CMSG_ATTACKSWING. # m_combat.m_attackSent getting stuck in true: https://i.imgur.com/LLasM8i.png # if reader.opcode == OpCode.MSG_MOVE_STOP or \ # reader.opcode == OpCode.MSG_MOVE_STOP_PITCH or \ # reader.opcode == OpCode.MSG_MOVE_STOP_STRAFE or \ # reader.opcode == OpCode.MSG_MOVE_STOP_TURN: # data = pack('<2QI', world_session.player_mgr.guid, 0, 0) # socket.sendall(PacketWriter.get_packet(OpCode.SMSG_ATTACKSTOP, data)) # Get up if you jump while not standing if reader.opcode == OpCode.MSG_MOVE_JUMP and \ world_session.player_mgr.stand_state != StandState.UNIT_DEAD and \ world_session.player_mgr.stand_state != StandState.UNIT_STANDING: world_session.player_mgr.stand_state = StandState.UNIT_STANDING world_session.player_mgr.set_dirty() except (AttributeError, error): Logger.error('Error while handling %s, skipping. Data: %s' % (OpCode(reader.opcode), reader.data)) return 0
def handle_movement_status(world_session, socket, reader: PacketReader) -> int: # Avoid handling malformed movement packets, or handling them while no player or player teleporting. if world_session.player_mgr and len(reader.data) >= 48: try: transport_guid, transport_x, transport_y, transport_z, transport_o, x, y, z, o, pitch, flags = \ unpack('<Q9fI', reader.data[:48]) # Hacky way to prevent random teleports when colliding with elevators # Also acts as a rudimentary teleport cheat detection if not world_session.player_mgr.pending_taxi_destination and \ world_session.player_mgr.location.distance(x=x, y=y, z=z) > 64: Logger.anticheat( f'Preventing coordinate desync from player {world_session.player_mgr.player.name} ' f'({world_session.player_mgr.guid}).') world_session.player_mgr.teleport( world_session.player_mgr.map_, world_session.player_mgr.location, is_instant=True) return 0 jumped = reader.opcode == OpCode.MSG_MOVE_JUMP # Movement and jump actions. if flags & (MoveFlags.MOVEFLAG_MOVE_MASK | MoveFlags.MOVEFLAG_STRAFE_MASK) or jumped: # Don't mark player as moved if only jumping. if not jumped: world_session.player_mgr.set_has_moved(True) # Cancel looting if moved. if world_session.player_mgr.loot_selection: world_session.player_mgr.send_loot_release( world_session.player_mgr.loot_selection) world_session.player_mgr.spell_manager.check_spell_interrupts( moved=True) world_session.player_mgr.aura_manager.check_aura_interrupts( moved=True) # Turn actions. if flags & MoveFlags.MOVEFLAG_TURN_MASK: world_session.player_mgr.spell_manager.check_spell_interrupts( turned=True) world_session.player_mgr.transport_id = transport_guid world_session.player_mgr.transport.x = transport_x world_session.player_mgr.transport.y = transport_y world_session.player_mgr.transport.z = transport_z world_session.player_mgr.transport.o = transport_o world_session.player_mgr.location.x = x world_session.player_mgr.location.y = y world_session.player_mgr.location.z = z world_session.player_mgr.location.o = o world_session.player_mgr.pitch = pitch world_session.player_mgr.movement_flags = flags if flags & MoveFlags.MOVEFLAG_SPLINE_MOVER: world_session.player_mgr.movement_spline = MovementManager.MovementSpline.from_bytes( reader.data[48:]) # Broadcast player movement to surroundings. movement_data = pack(f'<Q{len(reader.data)}s', world_session.player_mgr.guid, reader.data) movement_packet = PacketWriter.get_packet( OpCode(reader.opcode), movement_data) MapManager.send_surrounding(movement_packet, world_session.player_mgr, include_self=False) # Get up if you jump while not standing. if jumped and world_session.player_mgr.stand_state != StandState.UNIT_DEAD and \ world_session.player_mgr.stand_state != StandState.UNIT_STANDING: world_session.player_mgr.set_stand_state( StandState.UNIT_STANDING) except (AttributeError, error): Logger.error( f'Error while handling {OpCode(reader.opcode).name}, skipping. Data: {reader.data}' ) return 0
def handle(world_session, socket, reader): if len(reader.data) < 8: # Avoid handling wrong player login packet return -1 guid = unpack('<Q', reader.data[:8])[0] world_session.player_mgr = PlayerManager( RealmDatabaseManager.character_get_by_guid(guid), world_session) world_session.player_mgr.session = world_session if not world_session.player_mgr.player: Logger.anticheat('Character with wrong guid (%u) tried to login.' % guid) return -1 # Disabled race & class checks (only if not a GM) if not world_session.player_mgr.is_gm: disabled_race_mask = config.Server.General.disabled_race_mask disabled = disabled_race_mask & world_session.player_mgr.race_mask == world_session.player_mgr.race_mask if not disabled: disabled_class_mask = config.Server.General.disabled_class_mask disabled = disabled_class_mask & world_session.player_mgr.class_mask == world_session.player_mgr.class_mask if disabled: # Not 100% sure if CHAR_LOGIN_DISABLED matters here, but I don't know where else to send it data = pack('<B', CharLogin.CHAR_LOGIN_DISABLED) socket.sendall( PacketWriter.get_packet(OpCode.SMSG_CHARACTER_LOGIN_FAILED, data)) return 0 # Class & race allowed, continue with the login process socket.sendall( PacketWriter.get_packet(OpCode.SMSG_LOGIN_SETTIMESPEED, PlayerLoginHandler._get_login_timespeed())) world_session.player_mgr.load_skills() world_session.player_mgr.load_spells() world_session.player_mgr.deathbind = RealmDatabaseManager.character_get_deathbind( world_session.player_mgr.guid) socket.sendall(world_session.player_mgr.get_deathbind_packet()) # Tutorials aren't implemented in 0.5.3 # socket.sendall(world_session.player_mgr.get_tutorial_packet()) socket.sendall(world_session.player_mgr.get_initial_spells()) socket.sendall(world_session.player_mgr.get_action_buttons()) # MotD ChatManager.send_system_message(world_session, config.Server.General.motd) world_session.player_mgr.inventory.load_items() world_session.player_mgr.stat_manager.init_stats() world_session.player_mgr.stat_manager.apply_bonuses() world_session.player_mgr.send_update_self(create=True) world_session.player_mgr.reset_fields() PlayerLoginHandler._send_cinematic(world_session, world_session.player_mgr.player, socket) world_session.player_mgr.complete_login() return 0
def handle(world_session, socket, reader: PacketReader) -> int: if len(reader.data ) >= 12: # Avoid handling empty trainer buy spell packet. trainer_guid: int = unpack('<Q', reader.data[:8])[0] spell_id: int = unpack('<I', reader.data[8:12])[0] # If the guid equals to player guid, training through a talent. if trainer_guid == world_session.player_mgr.guid: talent_mgr = world_session.player_mgr.talent_manager talent_cost = talent_mgr.get_talent_cost_by_id(spell_id) trainer_spell_id = WorldDatabaseManager.TrainerSpellHolder.trainer_spell_id_get_from_player_spell_id( WorldDatabaseManager.TrainerSpellHolder. TRAINER_TEMPLATE_TALENT_ID, spell_id) if talent_cost > world_session.player_mgr.talent_points: TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_NOT_ENOUGH_POINTS) return 0 elif spell_id in world_session.player_mgr.spell_manager.spells: TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_UNAVAILABLE) return 0 else: world_session.player_mgr.spell_manager.handle_cast_attempt( trainer_spell_id, world_session.player_mgr, SpellTargetMask.SELF, validate=False) world_session.player_mgr.remove_talent_points(talent_cost) TrainerBuySpellHandler.send_trainer_buy_succeeded( world_session, trainer_guid, spell_id) # Send talent list again to refresh it. world_session.player_mgr.talent_manager.send_talent_list() # Otherwise, using a trainer NPC. else: npc: CreatureManager = MapManager.get_surrounding_unit_by_guid( world_session.player_mgr, trainer_guid) trainer_creature_template: CreatureTemplate = WorldDatabaseManager.creature_get_by_entry( npc.entry) trainer_spell_id = WorldDatabaseManager.TrainerSpellHolder.trainer_spell_id_get_from_player_spell_id( trainer_creature_template.trainer_id, spell_id) trainer_spell = WorldDatabaseManager.TrainerSpellHolder.trainer_spell_entry_get_by_trainer_and_spell( trainer_creature_template.trainer_id, trainer_spell_id) spell_money_cost = trainer_spell.spellcost spell_skill_cost = trainer_spell.skillpointcost if not npc.is_trainer(): # Not a trainer. Logger.anticheat( f'Player with GUID {world_session.player_mgr.guid} tried to train spell {spell_id} from NPC {npc.entry} but that NPC is not a trainer. Possible cheating.' ) TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_UNAVAILABLE) return 0 elif not npc.can_train(world_session.player_mgr): Logger.anticheat( f'Player with GUID {world_session.player_mgr.guid} tried to train spell {spell_id} from NPC {npc.entry} but that NPC does not train that player. Possible cheating.' ) TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_UNAVAILABLE) return 0 elif not npc.trainer_has_spell( trainer_spell_id ): # Doesn't have that spell in its train list. Logger.anticheat( f'Player with GUID {world_session.player_mgr.guid} tried to train spell {spell_id} from NPC {npc.entry} but that NPC does not train that spell. Possible cheating.' ) TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_UNAVAILABLE) return 0 elif spell_money_cost > 0 and spell_money_cost > world_session.player_mgr.coinage: TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_NOT_ENOUGH_MONEY) return 0 elif spell_skill_cost > 0 and spell_skill_cost > world_session.player_mgr.skill_points: TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_NOT_ENOUGH_POINTS) return 0 elif spell_id in world_session.player_mgr.spell_manager.spells: TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_UNAVAILABLE) return 0 elif not world_session.player_mgr.is_gm and not npc.is_within_interactable_distance( world_session.player_mgr): # buyspell console command. TrainerBuySpellHandler.send_trainer_buy_fail( world_session, trainer_guid, spell_id, TrainingFailReasons.TRAIN_FAIL_UNAVAILABLE) return 0 else: npc.spell_manager.handle_cast_attempt( trainer_spell_id, world_session.player_mgr, SpellTargetMask.UNIT, validate=False) if spell_money_cost > 0: world_session.player_mgr.mod_money(-spell_money_cost) if spell_skill_cost > 0: # Some trainer spells cost skill points in alpha - class trainers trained weapon skills, which cost skill points. world_session.player_mgr.remove_skill_points( spell_skill_cost) TrainerBuySpellHandler.send_trainer_buy_succeeded( world_session, trainer_guid, spell_id) # TODO Revisit later - re-sending the list is (probably) not the way it should be done, # as it resets the selected spell & spell filters (avail, unavail etc.). npc.send_trainer_list(world_session) return 0
def handle(world_session, socket, reader: PacketReader) -> int: if len(reader.data) < 8: # Avoid handling wrong player login packet. return -1 guid = unpack('<Q', reader.data[:8])[0] world_session.player_mgr = PlayerManager( RealmDatabaseManager.character_get_by_guid(guid), world_session) if not world_session.player_mgr.player: Logger.anticheat( f'Character with wrong guid ({guid}) tried to login.') return -1 else: WorldSessionStateHandler.push_active_player_session(world_session) # Disabled race & class checks (only if not a GM). if not world_session.player_mgr.is_gm: disabled_race_mask = config.Server.General.disabled_race_mask disabled = disabled_race_mask & world_session.player_mgr.race_mask == world_session.player_mgr.race_mask if not disabled: disabled_class_mask = config.Server.General.disabled_class_mask disabled = disabled_class_mask & world_session.player_mgr.class_mask == world_session.player_mgr.class_mask if disabled: # Not 100% sure if CHAR_LOGIN_DISABLED matters here, but I don't know where else to send it. data = pack('<B', CharLogin.CHAR_LOGIN_DISABLED) world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_CHARACTER_LOGIN_FAILED, data)) return 0 # Class & race allowed, continue with the login process. world_session.enqueue_packet( PacketWriter.get_packet(OpCode.SMSG_LOGIN_SETTIMESPEED, PlayerLoginHandler._get_login_timespeed())) world_session.player_mgr.skill_manager.load_proficiencies() world_session.player_mgr.skill_manager.load_skills() world_session.player_mgr.spell_manager.load_spells() world_session.player_mgr.deathbind = RealmDatabaseManager.character_get_deathbind( world_session.player_mgr.guid) world_session.player_mgr.friends_manager.load_from_db( RealmDatabaseManager.character_get_social( world_session.player_mgr.guid)) # Only send the deathbind packet if it's a Binder NPC what bound the player. if world_session.player_mgr.deathbind.creature_binder_guid > 0: world_session.enqueue_packet( world_session.player_mgr.get_deathbind_packet()) # Tutorials aren't implemented in 0.5.3. # world_session.enqueue_packet(world_session.player_mgr.get_tutorial_packet()) world_session.enqueue_packet( world_session.player_mgr.spell_manager.get_initial_spells()) world_session.enqueue_packet( world_session.player_mgr.get_action_buttons()) # MotD. ChatManager.send_system_message(world_session, config.Server.General.motd) world_session.player_mgr.inventory.load_items() # Initialize stats first to have existing base stats for further calculations. world_session.player_mgr.stat_manager.init_stats() # Passive spells contain skill and proficiency learning. # Perform passive spell casts after loading skills to avoid duplicate database entries. world_session.player_mgr.spell_manager.cast_passive_spells() world_session.player_mgr.spell_manager.apply_cast_when_learned_spells() world_session.player_mgr.skill_manager.init_proficiencies() world_session.player_mgr.quest_manager.load_quests() world_session.player_mgr.reputation_manager.load_reputations() GuildManager.set_character_guild(world_session.player_mgr) GroupManager.set_character_group(world_session.player_mgr) PetitionManager.load_petition(world_session.player_mgr) first_login = world_session.player_mgr.player.totaltime == 0 # Send cinematic. if first_login: PlayerLoginHandler._send_cinematic(world_session, world_session.player_mgr.player, socket) world_session.player_mgr.complete_login(first_login=first_login) return 0