using System; using System.Collections.Generic; using log4net; using WCell.Cryptography; using WCell.Network; using WCell.Network.Handler; using WCell.RealmServer.UpdateFields; //using WCell.DAL.TypedQueries; //using Sooda; namespace WCell.RealmServer { /// /// The world class /// public class World { #region Fields protected static ILog m_log = LogManager.GetLogger(typeof(World)); private static ObjectManager m_objectMgr; /// /// The Object Manager /// public static ObjectManager ObjectManager { get { return m_objectMgr; } } #endregion /// /// The resolver of World Class /// /// /// [Resolver] private static World Resolver(RealmClient session) { m_objectMgr = ObjectManager.Instance; return new World(); } #region Packet Handlers /// /// Handles an incomming ping request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_PING)] public void PingRequest(RealmClient session, RealmPacketIn packet) { SendPingReply(session, packet.ReadUInt32()); } /// /// Handles incomming Auth Session Request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_AUTH_SESSION)] public void AuthSessionRequest(RealmClient session, RealmPacketIn packet) { packet.SkipBytes(4); //GameBuild packet.SkipBytes(4); //Unknow field string accName = packet.ReadString(); uint clientSeed = packet.ReadUInt32(); BigInteger clientDigest = packet.ReadBigInteger(20); byte[] zeros = new byte[4]; //SecureRemotePassword srp = session.Client.Server.SessionKeyService.RequestSRP(accName); Currently not working if (session.Account == null) { //TODO: implement acct lookup when we get DB. maybe find a better place to put this. currently session.Account is never assigned to. session.Account = new Account(session, accName); //session.Account.Username = accName; } BigInteger salt = new BigInteger(session.Server.SessionKeyService.RequestSalt(accName), 32); BigInteger verifier = new BigInteger(session.Server.SessionKeyService.RequestVerifier(accName)); SecureRemotePassword srp = new SecureRemotePassword(accName, verifier, salt); session.Account.SessionKey = new BigInteger(session.Server.SessionKeyService.RequestSessionKey(accName)); BigInteger clientVerifier = srp.Hash(srp.Username, zeros, clientSeed, 0xDEADBABE, session.Account.SessionKey); session.IsEncrypted = true; // all packets from here on are encrypted, including the AuthSessionReplys if (clientVerifier == clientDigest) { SendAuthSessionSuccessReply(session); } else { SendAuthSessionErrorReply(session, RealmErrorCode.AuthFailed); } } /// /// Handles incomming Char Enum Request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_CHAR_ENUM)] public void CharEnumRequest(RealmClient session, RealmPacketIn packet) { SendCharEnum(session); } /// /// Handles incomming Char creation Request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_CHAR_CREATE)] public void CharCreateRequest(RealmClient session, RealmPacketIn packet) { try { String characterName = packet.ReadString(); //using (SoodaTransaction tran = new SoodaTransaction()) //{ // if (WCell.DAL.Character.LoadSingleObject(CharacterField.Name == characterName) != null) // { // SendCharCreateReply(session, RealmErrorCode.CharacterCreateNameInUse); // return; // } // Character ch = new Character(session.Account); // //ch.Name = packet.ReadString(); // ch.Name = characterName; // ch.Race = (RaceTypes)packet.ReadByte(); // ch.Class = (ClassTypes)packet.ReadByte(); // ch.Gender = (GenderTypes)packet.ReadByte(); // ch.Skin = packet.ReadByte(); // ch.Face = packet.ReadByte(); // ch.HairStyle = packet.ReadByte(); // ch.HairColour = packet.ReadByte(); // ch.FacialHair = packet.ReadByte(); // ch.OutFit = packet.ReadByte(); // TODO: This should be handled elsewhere //ch.Level = (byte)(40); //ch.PositionX = -8949.950195f; //ch.PositionY = -132.492996f; //ch.PositionZ = 83.531197f; //ch.Orientation = 0.0f; // ch.Save(); // session.Account.Characters.Add(ch.GUID, ch); // SendCharCreateReply(session, RealmErrorCode.CharacterCreateOk); //} } catch (Exception e) { m_log.Error(e); SendCharCreateReply(session, RealmErrorCode.CharacterCreateNameInUse); } } /// /// Handles incomming Char delete Request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_CHAR_DELETE)] public void CharDeleteRequest(RealmClient session, RealmPacketIn packet) { ulong charGUID = packet.ReadUInt64(); try { session.Account.Characters.Remove(charGUID); //session.Account.Characters[charGUID].Delete(); SendCharDeleteReply(session, RealmErrorCode.CharacterDeleteOk); } catch (Exception) { SendCharDeleteReply(session, RealmErrorCode.CharacterDeleteFailed); } } /// /// Handles incomming Player Login Request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_PLAYER_LOGIN)] public void CharPlayerLoginRequest(RealmClient session, RealmPacketIn packet) { try { ulong charGUID = packet.ReadUInt64(); if (charGUID != 0) { if (!m_objectMgr.CharacterListByGUID.ContainsKey(charGUID)) { /*foreach (Character ch in session.Account.Characters.Values) { if (ch.GUID == charGUID) { session.ActiveCharacter = ch; m_worldUnitList.Add(ch.GUID, ch); break; } }*/ if (session.Account.Characters.ContainsKey(charGUID)) { session.ActiveCharacter = session.Account.Characters[charGUID]; m_objectMgr.AddCharToLists(session.ActiveCharacter); } else throw new InvalidOperationException( string.Format("Character with guid {0} not found in this account!", charGUID)); session.Account.SendAccountDataMD5(session); //session.ActiveCharacter.SendSetRestStart(session); //session.ActiveCharacter.SendBindPointUpdate(session); session.ActiveCharacter.SendTutorialFlags(session); //session.ActiveCharacter.SendInitialSpells(session); //session.ActiveCharacter.SendActionButtons(session); SendUpdateObject(session, UpdateTypes.CreateSelf); session.ActiveCharacter.SendMoveUnlockMovementReply(session); } else { session.ActiveCharacter.SendCharacterLoginFail(session, AccountCharacterErrorCodes. ACCNT_MANIP_ALREADY_LOGGED_IN); session.Server.DisconnectClient(m_objectMgr.CharacterListByGUID[charGUID].Account.Client); } } } catch (Exception e) { m_log.Error(e); session.ActiveCharacter.SendCharacterLoginFail(session, AccountCharacterErrorCodes.ACCNT_MANIP_AUTH_FAILED); } } /// /// Handles incomming Query time Request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_QUERY_TIME)] public void QueryTimeRequest(RealmClient session, RealmPacketIn packet) { SendQueryTimeReply(session); } /// /// Handles incomming Name Query request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_NAME_QUERY)] public void NameQueryRequest(RealmClient session, RealmPacketIn packet) { SendNameQueryReply(session, session.ActiveCharacter); } /// /// Handles incomming Imediate Logout request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_PLAYER_LOGOUT)] public void PlayerImediateLogoutRequest(RealmClient session, RealmPacketIn packet) { SendPlayerImediateLogoutReply(session); } /// /// Handles incomming Logout request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_LOGOUT_REQUEST)] public void PlayerLogoutRequest(RealmClient session, RealmPacketIn packet) { SendLogoutReply(session, LogoutResponseCodes.LOGOUT_RESPONSE_ACCEPTED); } /// /// Handles incomming Logout Cancel Request /// /// the Session the incoming packet belongs to /// the full packet [PacketHandler(RealmServerOpCode.CMSG_LOGOUT_CANCEL)] public void PlayerLogoutCancel(RealmClient session, RealmPacketIn packet) { SendLogoutCancelReply(session); } #endregion #region Send/Reply methods /// /// Send the Ping Reply /// /// the Session the outdoing packet belongs to /// the sequencial number sent by client public void SendPingReply(RealmClient session, uint sequencial) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_PONG)) { packet.Write(sequencial); session.Send(packet); } } /// /// Send the Error of Auth Session to client /// /// the Session the outdoing packet belongs to /// error code public void SendAuthSessionErrorReply(RealmClient session, RealmErrorCode error) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_AUTH_RESPONSE)) { packet.Write((byte)error); session.Send(packet); } } /// /// Send a success auth session reply to the client /// /// the Session the outdoing packet belongs to public void SendAuthSessionSuccessReply(RealmClient session) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_AUTH_RESPONSE)) { packet.WriteByte((byte)RealmErrorCode.AuthOk); packet.WriteByte(0xB0); packet.WriteByte(0x09); packet.WriteByte(0x02); packet.WriteByte(0x00); packet.WriteByte(0x02); packet.WriteInt(0); if (session.Account.BurningCrusadeEnabled) { packet.WriteByte(1); } else { packet.WriteByte(0); } session.Send(packet); } } /// /// Sends the Char Enum to client /// /// the Session the outdoing packet belongs to public void SendCharEnum(RealmClient session) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_CHAR_ENUM)) { Dictionary characters = session.Account.Characters; packet.WriteByte((byte)characters.Count); foreach (Character c in characters.Values) //change to foreach so we dont get KeyNotFoundExceptions { packet.Write(c.GUID.Full); packet.WriteString(c.Name); packet.WriteByte((byte) c.Race); packet.WriteByte((byte) c.Class); packet.WriteByte((byte) c.Gender); packet.WriteByte(c.Skin); packet.WriteByte(c.Face); packet.WriteByte(c.HairStyle); packet.WriteByte(c.HairColour); packet.WriteByte(c.FacialHair); packet.WriteByte((byte)c.Level); packet.WriteByte(c.OutFit); // displayId? packet.Write(c.ZoneId); packet.Write(c.MapId); packet.Write(c.PositionX); packet.Write(c.PositionY); packet.Write(c.PositionZ); packet.WriteByte(0); //unk1 packet.WriteByte(0); //unk2 packet.WriteByte(0); //unk3 if (c.IsLocked) { packet.WriteByte(1); } else { packet.WriteByte(0); } packet.WriteInt(0); // rest packet.Write(c.PetInfoId); packet.Write(c.PetLevel); packet.Write(c.PetFamilyId); packet.WriteZeros(100); } session.Send(packet); } } /// /// Send Query Time Reply /// ///the Session the outdoing packet belongs to public void SendQueryTimeReply(RealmClient session) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_QUERY_TIME_RESPONSE)) { packet.WriteDateTime(DateTime.Now); session.Send(packet); } } /// /// Send a Name Query Reply /// ///the Session the outdoing packet belongs to /// the character that will be send public void SendNameQueryReply(RealmClient session, Character character) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_NAME_QUERY_RESPONSE)) { packet.Write(character.GUID); packet.Write(character.Name); packet.WriteZeros(1); packet.Write((byte)character.Race); packet.Write((byte)character.Gender); packet.Write((byte)character.Class); session.Send(packet); } } public void SendUpdateObject(RealmClient client, UpdateTypes updateType) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_UPDATE_OBJECT)) { packet.Write(1); // block count. packet.WriteByte(1); // unk constant // start repeat packet.WriteByte((byte)updateType); // update type packet.Write(client.ActiveCharacter.GUID.Packed); packet.WriteByte((byte)ObjectTypeIds.Player); // player object type WriteMovementUpdate(packet, client.ActiveCharacter, updateType); client.ActiveCharacter.Strength = 12; client.ActiveCharacter.Stamina = 3; client.ActiveCharacter.Health = 1000; client.ActiveCharacter.MaxHealth = 1500; client.ActiveCharacter.Power1 = 10; client.ActiveCharacter.MaxPower1 = 20; client.ActiveCharacter.NativeDisplayId = client.ActiveCharacter.DisplayId; client.ActiveCharacter.MountDisplayId = 15677; client.ActiveCharacter.Type = (uint)(ObjectTypes.Player | ObjectTypes.Unit | ObjectTypes.Object); client.ActiveCharacter.ScaleX = 1.0f; client.ActiveCharacter.WriteUpdateMask(packet); /*UpdateMask mask = new UpdateMask(PlayerFields._Count); mask.SetBit(ObjectFields.Guid, session.ActiveCharacter.GUID); mask.SetBit(UnitFields.UnitBytes0, session.ActiveCharacter.UnitBytes0); mask.SetBit(UnitFields.Health, 100); mask.SetBit(UnitFields.MaxHealth, 150); mask.SetBit(UnitFields.Level, (uint)session.ActiveCharacter.Level); mask.SetBit(UnitFields.DisplayId, session.ActiveCharacter.DisplayId); mask.SetBit(UnitFields.NativeDisplayId, session.ActiveCharacter.DisplayId); mask.SetBit(UnitFields.Power1, 10); mask.SetBit(UnitFields.MaxPower1, 20); mask.SetBit(UnitFields.MountDisplayId, 15677); mask.SetBit(ObjectFields.Type, (uint)(ObjectTypes.Player | ObjectTypes.Unit | ObjectTypes.Object)); mask.SetBit(ObjectFields.ScaleX, 1.0f); //mask.SetBit( mask.Write(packet);*/ client.Send(packet); } } private void WriteMovementUpdate(RealmPacketOut packet, Character c, UpdateTypes updateType) { byte flag1 = 0; uint flag2 = 0; switch (updateType) { case UpdateTypes.Create: { flag1 = 0x60; break; } case UpdateTypes.CreateSelf: { flag1 = 0x61; break; } } packet.WriteByte(flag1); packet.Write(flag2); packet.WriteDateTime(DateTime.Now); packet.Write(c.PositionX); packet.Write(c.PositionY); packet.Write(c.PositionZ); packet.Write(c.Orientation); // orientation packet.Write(0.0f); //unk packet.Write(20f); // Walk packet.Write(20f); // Run packet.Write(20f); // SwimBack packet.Write(20f); // Swim packet.Write(20f); // WalkBack packet.Write(20f); //FlightBack packet.Write(20f); // flight packet.Write((float)Math.PI); // turn } /// /// Send Char Create Reply /// ///the Session the outdoing packet belongs to /// Error code public void SendCharCreateReply(RealmClient session, RealmErrorCode error) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_CHAR_CREATE)) { packet.Write((byte)error); session.Send(packet); } } /// /// Send Char Delete Reply /// ///the Session the outdoing packet belongs to /// Error code public void SendCharDeleteReply(RealmClient session, RealmErrorCode error) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_CHAR_DELETE)) { packet.Write((byte)error); session.Send(packet); } } /// /// Sent by the server to notify the client about the environmental speed change. Usualy this speed equals to real life. /// ///the Session the outdoing packet belongs to public void SendLoginSetTimeSpeed(RealmClient session) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_LOGIN_SETTIMESPEED)) { packet.WriteDateTime(DateTime.Now); session.Send(packet); } } /// /// Sent by the server to mark the end of logout sequence. In reply to CMSG_PLAYER_LOGOUT. /// ///the Session the outdoing packet belongs to public void SendPlayerImediateLogoutReply(RealmClient session) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_LOGOUT_COMPLETE)) { m_objectMgr.RemoveCharFromLists(session.ActiveCharacter); session.Send(packet); } } /// /// Send Logout Response /// ///the Session the outdoing packet belongs to /// error code public void SendLogoutReply(RealmClient session, LogoutResponseCodes error) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_LOGOUT_RESPONSE)) { packet.Write((byte)error); packet.WriteZeros(4); session.Send(packet); } } /// /// Send Logout Cancel Reply /// ///the Session the outdoing packet belongs to public void SendLogoutCancelReply(RealmClient session) { using (RealmPacketOut packet = new RealmPacketOut(RealmServerOpCode.SMSG_LOGOUT_CANCEL_ACK)) { session.Send(packet); } } #endregion } }