public async Task SpawnPlayer(Character character, int build) { var updateForOtherActivePlayers = new Dictionary <int, SMSG_UPDATE_OBJECT> { { ClientBuild.Vanilla, SMSG_UPDATE_OBJECT.CreatePlayer(character, ClientBuild.Vanilla) }, { ClientBuild.TBC, SMSG_UPDATE_OBJECT.CreatePlayer(character, ClientBuild.TBC) }, }; var _this = this.Connections.Single(x => x.CharacterId == character.Id); foreach (var other in this.Connections) { if (!other.IsInWorld) { continue; } if (other.CharacterId == character.Id) { continue; } var otherCharacter = this.CharacterService.GetCharacter(other.CharacterId); if (!IsInRange(character, otherCharacter)) { continue; } await _this.SendPacket(SMSG_UPDATE_OBJECT.CreatePlayer(otherCharacter, build)); await other.SendPacket(updateForOtherActivePlayers[other.Build]); } }
public static async Task OnPlayerLogin(WorldClient client, byte[] data) { var request = new CMSG_PLAYER_LOGIN(data); var character = client.User.Characters.Single(x => x.ID == request.CharacterID); client.Log($"Player logged in with char {character.Name}"); await client.SendPacket(new SMSG_LOGIN_VERIFY_WORLD(character)); await client.SendPacket(new SMSG_ACCOUNT_DATA_TIMES()); await client.SendPacket(new SMSG_MESSAGECHAT(character.ID, "Hello World")); await client.SendPacket(new SMSG_MESSAGECHAT(character.ID, "World Hello")); await client.SendPacket(new SMSG_SET_REST_START()); await client.SendPacket(new SMSG_BINDPOINTUPDATE(character)); await client.SendPacket(new SMSG_TUTORIAL_FLAGS()); await client.SendPacket(new SMSG_LOGIN_SETTIMESPEED()); await client.SendPacket(new SMSG_INITIAL_SPELLS()); await client.SendPacket(new SMSG_ACTION_BUTTONS()); await client.SendPacket(new SMSG_INITIALIZE_FACTIONS()); // TODO: SMSG_TRIGGER_CINEMATIC (Human_ID = 81??) await client.SendPacket(new SMSG_CORPSE_RECLAIM_DELAY()); await client.SendPacket(new SMSG_INIT_WORLD_STATES()); await client.SendPacket(SMSG_UPDATE_OBJECT.CreateOwnPlayerObject(character, out var player)); client.Player = player; }
public static async Task OnPlayerLogin(PacketHandlerContext c) { var request = new CMSG_PLAYER_LOGIN(c.Packet); var character = c.GetCharacter(request.CharacterID); var account = c.AccountService.GetAccount(c.Client.Identifier); // Login with a deleted character or a character from another account. // TODO: Split for different log messages. if (character is null || !account.Characters.Contains(character.Id)) { c.Client.Log( $"{account.Identifier} tried to login with a deleted character or a character from another account.", LogLevel.Warning); return; } c.Client.Log($"Player logged in with char {character.Name}"); if (c.IsTBC()) { await c.SendPacket <MSG_SET_DUNGEON_DIFFICULTY>(); } await c.Client.SendPacket(new SMSG_LOGIN_VERIFY_WORLD(character)); await c.SendPacket <SMSG_ACCOUNT_DATA_TIMES>(); if (c.IsTBC()) { await c.SendPacket <SMSG_FEATURE_SYSTEM_STATUS>(); } await c.Client.SendPacket(new SMSG_EXPECTED_SPAM_RECORDS(Enumerable.Empty <string>())); if (c.IsVanilla()) { await c.Client.SendPacket(new SMSG_MESSAGECHAT(character.Id, MessageOfTheDay)); } else if (c.IsTBC()) { await c.Client.SendPacket(new SMSG_MOTD(MessageOfTheDay)); } // await args.Client.SendPacket(new SMSG_NAME_QUERY_RESPONSE(character, args.Client.Build)); // if (GUILD) -> SMSG_GUILD_EVENT if (character.Stats.Life == 0) { await c.SendPacket <SMSG_CORPSE_RECLAIM_DELAY>(); } await c.SendPacket <SMSG_SET_REST_START>(); await c.Client.SendPacket(new SMSG_BINDPOINTUPDATE(character)); await c.SendPacket <SMSG_TUTORIAL_FLAGS>(); if (c.IsTBC()) { await c.SendPacket <SMSG_INSTANCE_DIFFICULTY>(); } await c.Client.SendPacket(new SMSG_INITIAL_SPELLS(character.Spells)); // SMSG_SEND_UNLEARN_SPELLS await c.Client.SendPacket(new SMSG_ACTION_BUTTONS(character.ActionBar)); await c.Client.SendPacket(new SMSG_INITIALIZE_FACTIONS(ClientBuild.Vanilla)); // BUG?? await c.SendPacket <SMSG_LOGIN_SETTIMESPEED>(); // await args.Client.SendPacket(new SMSG_TRIGGER_CINEMATIC(CinematicID.NightElf)); c.Client.CharacterId = character.Id; await c.Client.SendPacket(SMSG_UPDATE_OBJECT.CreateOwnPlayerObject(character, c.Client.Build, out var player)); c.Client.Player = player; // TODO: Implement for TBC if (c.IsVanilla()) { // Initially spawn all creatures foreach (var unit in c.World.Creatures) { // TODO: Add range check await c.Client.SendPacket(SMSG_UPDATE_OBJECT_VANILLA.CreateUnit(unit)); } } await c.World.SpawnPlayer(character, c.Client.Build); // if (GROUP) -> SMSG_GROUP_LIST // if Vanilla // SMSG_FRIEND_LIST // SMSG_IGNORE_LIST // if TBC // SMSG_CONTACT_LIST if (c.IsTBC()) { await c.SendPacket <SMSG_TIME_SYNC_REQ>(); } // SMSG_ITEM_ENCHANT_TIME_UPDATE // SMSG_ITEM_TIME_UPDATE // SMSG_FRIEND_STATUS }
public static SMSG_UPDATE_OBJECT CreatePlayer(Character character, int build) { var update = new SMSG_UPDATE_OBJECT(); update.Writer .WriteUInt32(1) // blocks.Count .WriteUInt8(0) // hasTransport .WriteUInt8((byte)ObjectUpdateType.UPDATETYPE_CREATE_OBJECT_SELF) .WriteBytes(character.Id.ToPackedUInt64()) .WriteUInt8((byte)TypeId.TypeidPlayer); var updateFlags = build switch { ClientBuild.Vanilla => (byte)(ObjectUpdateFlag_VANILLA.All | ObjectUpdateFlag_VANILLA.HasPosition | ObjectUpdateFlag_VANILLA.Living), ClientBuild.TBC => (byte)(ObjectUpdateFlag_TBC.Highguid | ObjectUpdateFlag_TBC.HasPosition | ObjectUpdateFlag_TBC.Living), _ => throw new NotImplementedException($"GetUpdateFlags(build: {build})"), }; update.Writer .WriteUInt8(updateFlags) .WriteUInt32((uint)MovementFlags.None); if (build == ClientBuild.TBC) { update.Writer.WriteUInt8(0); // moveFlags2 } update.Writer .WriteUInt32((uint)Environment.TickCount) .WriteMap(character.Position) .WriteFloat(0) // ?? .WriteFloat(2.5f) // WalkSpeed .WriteFloat(7f) // RunSpeed .WriteFloat(2.5f) // Backwards WalkSpeed .WriteFloat(4.72f) // SwimSpeed .WriteFloat(2.5f); // Backwards SwimSpeed if (build == ClientBuild.TBC) { update.Writer .WriteFloat(14f) // MOVE_FLIGHT .WriteFloat(14f); // MOVE_FLIGHT_BACK } update.Writer .WriteFloat(3.14f) // TurnSpeed .WriteUInt32(0); // ?? // TODO: Can be done somewhere else? var player = new PlayerEntity(character, build); player.WriteUpdateFields(update.Writer); return(update); }