#include "dCommonVars.h" #include "WorldPackets.h" #include "BitStream.h" #include "dMessageIdentifiers.h" #include "PacketUtils.h" #include "GeneralUtils.h" #include "User.h" #include "Character.h" #include "dLogger.h" #include #include "Game.h" #include "LDFFormat.h" #include "dServer.h" #include "dZoneManager.h" #include "CharacterComponent.h" #include "ZCompression.h" void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_LOAD_STATIC_ZONE); auto zone = dZoneManager::Instance()->GetZone()->GetZoneID(); bitStream.Write(static_cast(zone.GetMapID())); bitStream.Write(static_cast(zone.GetInstanceID())); //bitStream.Write(static_cast(zone.GetCloneID())); bitStream.Write(0); bitStream.Write(checksum); bitStream.Write(static_cast(0)); // ?? bitStream.Write(x); bitStream.Write(y); bitStream.Write(z); bitStream.Write(static_cast(0)); // Change this to eventually use 4 on activity worlds SEND_PACKET; } void WorldPackets::SendCharacterList(const SystemAddress& sysAddr, User* user) { if (!user) return; RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHARACTER_LIST_RESPONSE); std::vector characters = user->GetCharacters(); bitStream.Write(static_cast(characters.size())); bitStream.Write(static_cast(0)); //character index in front, just picking 0 for (uint32_t i = 0; i < characters.size(); ++i) { bitStream.Write(characters[i]->GetObjectID()); bitStream.Write(static_cast(0)); PacketUtils::WriteWString(bitStream, characters[i]->GetName(), 33); PacketUtils::WriteWString(bitStream, characters[i]->GetUnapprovedName(), 33); bitStream.Write(static_cast(characters[i]->GetNameRejected())); bitStream.Write(static_cast(false)); PacketUtils::WriteString(bitStream, "", 10); bitStream.Write(characters[i]->GetShirtColor()); bitStream.Write(characters[i]->GetShirtStyle()); bitStream.Write(characters[i]->GetPantsColor()); bitStream.Write(characters[i]->GetHairStyle()); bitStream.Write(characters[i]->GetHairColor()); bitStream.Write(characters[i]->GetLeftHand()); bitStream.Write(characters[i]->GetRightHand()); bitStream.Write(characters[i]->GetEyebrows()); bitStream.Write(characters[i]->GetEyes()); bitStream.Write(characters[i]->GetMouth()); bitStream.Write(static_cast(0)); bitStream.Write(static_cast(characters[i]->GetZoneID())); bitStream.Write(static_cast(characters[i]->GetZoneInstance())); bitStream.Write(characters[i]->GetZoneClone()); bitStream.Write(characters[i]->GetLastLogin()); const auto& equippedItems = characters[i]->GetEquippedItems(); bitStream.Write(static_cast(equippedItems.size())); for (uint32_t j = 0; j < equippedItems.size(); ++j) { bitStream.Write(equippedItems[j]); } } SEND_PACKET; } void WorldPackets::SendCharacterCreationResponse(const SystemAddress& sysAddr, eCharacterCreationResponse response) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHARACTER_CREATE_RESPONSE); bitStream.Write(response); SEND_PACKET; } void WorldPackets::SendCharacterRenameResponse(const SystemAddress& sysAddr, eRenameResponse response) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHARACTER_RENAME_RESPONSE); bitStream.Write(response); SEND_PACKET; } void WorldPackets::SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_DELETE_CHARACTER_RESPONSE); bitStream.Write(static_cast(response)); SEND_PACKET; } void WorldPackets::SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_TRANSFER_TO_WORLD); PacketUtils::WriteString(bitStream, serverIP, 33); bitStream.Write(static_cast(serverPort)); bitStream.Write(static_cast(mythranShift)); SEND_PACKET; } void WorldPackets::SendServerState(const SystemAddress& sysAddr) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_SERVER_STATES); bitStream.Write(static_cast(1)); //If the server is receiving this request, it probably is ready anyway. SEND_PACKET; } void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CREATE_CHARACTER); RakNet::BitStream data; data.Write(7); //LDF key count auto character = entity->GetComponent(); if (!character) { Game::logger->Log("WorldPackets", "Entity is not a character?? what??"); return; } LDFData* objid = new LDFData(u"objid", entity->GetObjectID()); LDFData* lot = new LDFData(u"template", 1); LDFData* xmlConfigData = new LDFData(u"xmlData", xmlData); LDFData* name = new LDFData(u"name", username); LDFData* gmlevel = new LDFData(u"gmlevel", static_cast(gm)); LDFData* chatmode = new LDFData(u"chatmode", static_cast(gm)); LDFData* reputation = new LDFData(u"reputation", character->GetReputation()); objid->WriteToPacket(&data); lot->WriteToPacket(&data); name->WriteToPacket(&data); gmlevel->WriteToPacket(&data); chatmode->WriteToPacket(&data); xmlConfigData->WriteToPacket(&data); reputation->WriteToPacket(&data); delete objid; delete lot; delete xmlConfigData; delete gmlevel; delete chatmode; delete name; delete reputation; //Compress the data before sending: const uint32_t reservedSize = ZCompression::GetMaxCompressedLength(data.GetNumberOfBytesUsed()); uint8_t* compressedData = new uint8_t[reservedSize]; // TODO There should be better handling here for not enough memory... if (!compressedData) return; size_t size = ZCompression::Compress(data.GetData(), data.GetNumberOfBytesUsed(), compressedData, reservedSize); assert(size <= reservedSize); bitStream.Write(size + 9); //size of data + header bytes (8) bitStream.Write(1); //compressed boolean, true bitStream.Write(data.GetNumberOfBytesUsed()); bitStream.Write(size); /** * In practice, this warning serves no purpose for us. We allocate the max memory needed on the heap * and then compress the data. In the off chance that the compression actually increases the size, * an assertion is done to prevent bad data from being saved or sent. */ #pragma warning(disable:6385) // C6385 Reading invalid data from 'compressedData'. for (size_t i = 0; i < size; i++) bitStream.Write(compressedData[i]); #pragma warning(default:6385) // PacketUtils::SavePacket("chardata.bin", (const char*)bitStream.GetData(), static_cast(bitStream.GetNumberOfBytesUsed())); SEND_PACKET; delete[] compressedData; Game::logger->Log("WorldPackets", "Sent CreateCharacter for ID: %llu", entity->GetObjectID()); } void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector> unacceptedItems) { CBITSTREAM; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHAT_MODERATION_STRING); bitStream.Write(unacceptedItems.empty()); // Is sentence ok? bitStream.Write(0x16); // Source ID, unknown bitStream.Write(static_cast(requestID)); // request ID bitStream.Write(static_cast(0)); // chat mode PacketUtils::WritePacketWString(receiver, 42, &bitStream); // receiver name for (auto it : unacceptedItems) { bitStream.Write(it.first); // start index bitStream.Write(it.second); // length } for (int i = unacceptedItems.size(); 64 > i; i++) { bitStream.Write(0); } SEND_PACKET; } void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel) { CBITSTREAM; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAKE_GM_RESPONSE); bitStream.Write(success); bitStream.Write(static_cast(highestLevel)); bitStream.Write(static_cast(prevLevel)); bitStream.Write(static_cast(newLevel)); SEND_PACKET; }