public static async void CharacterDelete(ClientPacketFragment fragment, Session session) { string account = fragment.Payload.ReadString16L(); uint characterSlot = fragment.Payload.ReadUInt32(); if (account != session.Account) { session.SendCharacterError(CharacterError.Delete); return; } var cachedCharacter = session.CachedCharacters.SingleOrDefault(c => c.SlotId == characterSlot); if (cachedCharacter == null) { session.SendCharacterError(CharacterError.Delete); return; } // TODO: check if character is already pending removal var characterDelete = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum); var characterDeleteFragment = new ServerPacketFragment(9, FragmentOpcode.CharacterDelete); characterDelete.Fragments.Add(characterDeleteFragment); NetworkManager.SendPacket(ConnectionType.Login, characterDelete, session); DatabaseManager.Character.DeleteOrRestore(WorldManager.GetUnixTime() + 3600ul, cachedCharacter.Guid.Low); var result = await DatabaseManager.Character.GetByAccount(session.Id); AuthenticationHandler.CharacterListSelectCallback(result, session); }
/// <summary> /// Processes a fragment, combining split fragments as needed, then handling them /// </summary> /// <param name="fragment">ClientPacketFragment to process</param> private void ProcessFragment(ClientPacketFragment fragment) { log.DebugFormat("[{0}] Processing fragment {1}", session.LoggingIdentifier, fragment.Header.Sequence); ClientMessage message = null; // Check if this fragment is split if (fragment.Header.Count != 1) { // Packet is split log.DebugFormat("[{0}] Fragment {1} is split, this index {2} of {3} fragments", session.LoggingIdentifier, fragment.Header.Sequence, fragment.Header.Index, fragment.Header.Count); MessageBuffer buffer = null; if (partialFragments.TryGetValue(fragment.Header.Sequence, out buffer)) { // Existing buffer, add this to it and check if we are finally complete. buffer.AddFragment(fragment); log.DebugFormat("[{0}] Added fragment {1} to existing buffer. Buffer at {2} of {3}", session.LoggingIdentifier, fragment.Header.Sequence, buffer.Count, buffer.TotalFragments); if (buffer.Complete) { // The buffer is complete, so we can go ahead and handle log.DebugFormat("[{0}] Buffer {1} is complete", session.LoggingIdentifier, buffer.Sequence); message = buffer.GetMessage(); MessageBuffer removed = null; partialFragments.TryRemove(fragment.Header.Sequence, out removed); } } else { // No existing buffer, so add a new one for this fragment sequence. log.DebugFormat("[{0}] Creating new buffer {1} for this split fragment", session.LoggingIdentifier, fragment.Header.Sequence); var newBuffer = new MessageBuffer(fragment.Header.Sequence, fragment.Header.Count); newBuffer.AddFragment(fragment); log.DebugFormat("[{0}] Added fragment {1} to the new buffer. Buffer at {2} of {3}", session.LoggingIdentifier, fragment.Header.Sequence, newBuffer.Count, newBuffer.TotalFragments); partialFragments.TryAdd(fragment.Header.Sequence, newBuffer); } } else { // Packet is not split, proceed with handling it. log.DebugFormat("[{0}] Fragment {1} is not split", session.LoggingIdentifier, fragment.Header.Sequence); message = new ClientMessage(fragment.Data); } // If message is not null, we have a complete message to handle if (message != null) { // First check if this message is the next sequence, if it is not, add it to our outOfOrderFragments if (fragment.Header.Sequence == lastReceivedFragmentSequence + 1) { log.DebugFormat("[{0}] Handling fragment {1}", session.LoggingIdentifier, fragment.Header.Sequence); HandleFragment(message); } else { log.DebugFormat("[{0}] Fragment {1} is early, lastReceivedFragmentSequence = {2}", session.LoggingIdentifier, fragment.Header.Sequence, lastReceivedFragmentSequence); outOfOrderFragments.TryAdd(fragment.Header.Sequence, message); } } }
public static void CharacterEnterWorldRequest(ClientPacketFragment fragment, Session session) { var characterEnterWorldServerReady = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum); characterEnterWorldServerReady.Fragments.Add(new ServerPacketFragment(9, FragmentOpcode.CharacterEnterWorldServerReady)); NetworkManager.SendPacket(ConnectionType.Login, characterEnterWorldServerReady, session); }
public void AddFragment(ClientPacketFragment fragment) { lock (fragments) { if (!Complete && !fragments.Any(x => x.Header.Index == fragment.Header.Index)) { fragments.Add(fragment); } } }
public static void HandleGameAction(GameActionOpcode opcode, ClientPacketFragment fragment, Session session) { if (!actionHandlers.ContainsKey(opcode)) { Console.WriteLine($"Received unhandled action opcode: 0x{((uint)opcode).ToString("X4")}"); } else { Type actionType; if (actionHandlers.TryGetValue(opcode, out actionType)) { var gameAction = (GameActionPacket)Activator.CreateInstance(actionType, session, fragment); gameAction.Read(); gameAction.Handle(); } } }
public static void CharacterEnterWorld(ClientPacketFragment fragment, Session session) { ObjectGuid guid = fragment.Payload.ReadGuid(); string account = fragment.Payload.ReadString16L(); if (account != session.Account) { session.SendCharacterError(CharacterError.EnterGameCharacterNotOwned); return; } var cachedCharacter = session.CachedCharacters.SingleOrDefault(c => c.Guid.Full == guid.Full); if (cachedCharacter == null) { session.SendCharacterError(CharacterError.EnterGameCharacterNotOwned); return; } session.CharacterRequested = cachedCharacter; // this isn't really that necessary since ACE doesn't split login/world to multiple daemons, handle it anyway byte[] connectionKey = new byte[sizeof(ulong)]; RandomNumberGenerator.Create().GetNonZeroBytes(connectionKey); session.WorldConnectionKey = BitConverter.ToUInt64(connectionKey, 0); var referralPacket = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum | PacketHeaderFlags.Referral); referralPacket.Payload.Write(session.WorldConnectionKey); referralPacket.Payload.Write((ushort)2); referralPacket.Payload.WriteUInt16BE((ushort)ConfigManager.Config.Server.Network.WorldPort); referralPacket.Payload.Write(ConfigManager.Host); referralPacket.Payload.Write(0ul); referralPacket.Payload.Write((ushort)0x18); referralPacket.Payload.Write((ushort)0); referralPacket.Payload.Write(0u); NetworkManager.SendPacket(ConnectionType.Login, referralPacket, session); session.State = SessionState.WorldLoginRequest; }
public static async void CharacterCreate(ClientPacketFragment fragment, Session session) { // known issues: // 1. getting the "next" character id is not thread-safe string account = fragment.Payload.ReadString16L(); if (account != session.Account) { return; } Character character = Character.CreateFromClientFragment(fragment, session.Id); // TODO: profanity filter // sendCharacterCreateResponse(session, 4); bool isAvailable = DatabaseManager.Character.IsNameAvailable(character.Name); if (!isAvailable) { SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.NameInUse); return; } uint lowGuid = DatabaseManager.Character.GetMaxId(); character.Id = lowGuid; character.AccountId = session.Id; if (!await DatabaseManager.Character.CreateCharacter(character)) { SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.DatabaseDown); return; } var guid = new ObjectGuid(lowGuid, GuidType.Player); session.CachedCharacters.Add(new CachedCharacter(guid, (byte)session.CachedCharacters.Count, character.Name, 0)); SendCharacterCreateResponse(session, CharacterGenerationVerificationResponse.Ok, guid, character.Name); }
public static void CharacterRestore(ClientPacketFragment fragment, Session session) { ObjectGuid guid = fragment.Payload.ReadGuid(); var cachedCharacter = session.CachedCharacters.SingleOrDefault(c => c.Guid.Full == guid.Full); if (cachedCharacter == null) { return; } DatabaseManager.Character.DeleteOrRestore(0, guid.Low); var characterRestore = new ServerPacket(0x0B, PacketHeaderFlags.EncryptedChecksum); var characterRestoreFragment = new ServerPacketFragment(9, FragmentOpcode.CharacterRestoreResponse); characterRestoreFragment.Payload.Write(1u /* Verification OK flag */); characterRestoreFragment.Payload.WriteGuid(guid); characterRestoreFragment.Payload.WriteString16L(cachedCharacter.Name); characterRestoreFragment.Payload.Write(0u /* secondsGreyedOut */); characterRestore.Fragments.Add(characterRestoreFragment); NetworkManager.SendPacket(ConnectionType.Login, characterRestore, session); }
public static async void CharacterCreate(ClientPacketFragment fragment, Session session) { // known issues: // 1. getting the "next" character id is not thread-safe string account = fragment.Payload.ReadString16L(); if (account != session.Account) { return; } Character character = Character.CreateFromClientFragment(fragment, session.Id); // TODO: profanity filter // sendCharacterCreateResponse(session, 4); bool isAvailable = DatabaseManager.Character.IsNameAvailable(character.Name); if (!isAvailable) { SendCharacterCreateResponse(session, 3); /* Name already in use. */ return; } uint guid = DatabaseManager.Character.GetMaxId() + 1; character.Id = guid; character.AccountId = session.Id; await DatabaseManager.Character.CreateCharacter(character); session.CachedCharacters.Add(new CachedCharacter(guid, (byte)session.CachedCharacters.Count, character.Name, 0)); SendCharacterCreateResponse(session, 1, guid, character.Name); }
public static void CharacterCreate(ClientPacketFragment fragment, Session session) { string account = fragment.Payload.ReadString16L(); if (account != session.Account) { return; } fragment.Payload.Skip(4); /* Unknown constant (1) */ uint race = fragment.Payload.ReadUInt32(); uint gender = fragment.Payload.ReadUInt32(); uint eyes = fragment.Payload.ReadUInt32(); uint nose = fragment.Payload.ReadUInt32(); uint mouth = fragment.Payload.ReadUInt32(); uint hairColor = fragment.Payload.ReadUInt32(); uint eyeColor = fragment.Payload.ReadUInt32(); uint hairStyle = fragment.Payload.ReadUInt32(); uint headgearStyle = fragment.Payload.ReadUInt32(); uint headgearColor = fragment.Payload.ReadUInt32(); uint shirtStyle = fragment.Payload.ReadUInt32(); uint shirtColor = fragment.Payload.ReadUInt32(); uint pantsStyle = fragment.Payload.ReadUInt32(); uint pantsColor = fragment.Payload.ReadUInt32(); uint footwearStyle = fragment.Payload.ReadUInt32(); uint footwearColor = fragment.Payload.ReadUInt32(); double skinHue = fragment.Payload.ReadDouble(); double hairHue = fragment.Payload.ReadDouble(); double headgearHue = fragment.Payload.ReadDouble(); double shirtHue = fragment.Payload.ReadDouble(); double pantsHue = fragment.Payload.ReadDouble(); double footwearHue = fragment.Payload.ReadDouble(); uint templateOption = fragment.Payload.ReadUInt32(); uint strength = fragment.Payload.ReadUInt32(); uint endurance = fragment.Payload.ReadUInt32(); uint coordination = fragment.Payload.ReadUInt32(); uint quickness = fragment.Payload.ReadUInt32(); uint focus = fragment.Payload.ReadUInt32(); uint self = fragment.Payload.ReadUInt32(); uint slot = fragment.Payload.ReadUInt32(); uint classId = fragment.Payload.ReadUInt32(); List <NewCharacterSkill> skills = new List <NewCharacterSkill>(); uint numOfSkills = fragment.Payload.ReadUInt32(); for (uint i = 0; i < numOfSkills; i++) { if (new[] { 0u, 1u, 2u, 3u, 4u, 5u, 8u, 9u, 10u, 11u, 12u, 13u, 17u, 25u, 26u, 42u, 53u }.Contains(i)) /* Inactive / retired skills */ { fragment.Payload.Skip(4); continue; } var newSkill = new NewCharacterSkill(); newSkill.Skill = (CharacterSkill)i; newSkill.Status = (SkillStatus)fragment.Payload.ReadUInt32(); skills.Add(newSkill); } string characterName = fragment.Payload.ReadString16L(); uint startArea = fragment.Payload.ReadUInt32(); bool isAdmin = Convert.ToBoolean(fragment.Payload.ReadUInt32()); bool isEnvoy = Convert.ToBoolean(fragment.Payload.ReadUInt32()); uint totalSkillPoints = fragment.Payload.ReadUInt32(); // TODO : profanity filter // sendCharacterCreateError(session, 4); var result = DatabaseManager.Character.SelectPreparedStatement(CharacterPreparedStatement.CharacterUniqueNameSelect, characterName); Debug.Assert(result != null); uint charsWithName = result.Read <uint>(0, "cnt"); if (charsWithName > 0) { sendCharacterCreateResponse(session, 3); /* Name already in use. */ return; } result = DatabaseManager.Character.SelectPreparedStatement(CharacterPreparedStatement.CharacterMaxIndex); Debug.Assert(result != null); uint guid = result.Read <uint>(0, "MAX(`guid`)") + 1; DatabaseManager.Character.ExecutePreparedStatement(CharacterPreparedStatement.CharacterInsert, guid, session.Id, characterName, templateOption, startArea, isAdmin, isEnvoy); // TODO : Persist appearance, stats and skills. session.CachedCharacters.Add(new CachedCharacter(guid, (byte)session.CachedCharacters.Count, characterName)); sendCharacterCreateResponse(session, 1, guid, characterName); }