DarkflameServer/dNet/WorldPackets.cpp
Aaron Kimbrell 99e7349f6c
feat: slashcommands for showall, findplayer, get/openhttpmoninfo, and debug world packet (#1545)
* feat: showall, findplayer, get/openhttpmoninfo

http monitor info is planned to be used later, just putting in info that i've since reverse engineered and don't want lost

Additionally add debug world packet for duture dev use

Tested all new commands and variation of command arguments

* fix missing newline at eofs

* address most feedback

* Compormise and use struct with (de)serialize

* remove httpmoninfo commands
2024-04-17 21:47:28 -05:00

187 lines
7.1 KiB
C++

#include "WorldPackets.h"
#include "dCommonVars.h"
#include "BitStream.h"
#include "GeneralUtils.h"
#include "Logger.h"
#include "Game.h"
#include "LDFFormat.h"
#include "dServer.h"
#include "ZCompression.h"
#include "eConnectionType.h"
#include "BitStreamUtils.h"
#include <iostream>
void HTTPMonitorInfo::Serialize(RakNet::BitStream &bitStream) const {
bitStream.Write(port);
bitStream.Write<uint8_t>(openWeb);
bitStream.Write<uint8_t>(supportsSum);
bitStream.Write<uint8_t>(supportsDetail);
bitStream.Write<uint8_t>(supportsWho);
bitStream.Write<uint8_t>(supportsObjects);
}
void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::LOAD_STATIC_ZONE);
bitStream.Write<uint16_t>(zone.GetMapID());
bitStream.Write<uint16_t>(zone.GetInstanceID());
//bitStream.Write<uint32_t>(zone.GetCloneID());
bitStream.Write(0);
bitStream.Write(checksum);
bitStream.Write<uint16_t>(0); // ??
bitStream.Write(x);
bitStream.Write(y);
bitStream.Write(z);
bitStream.Write<uint32_t>(0); // Change this to eventually use 4 on activity worlds
SEND_PACKET;
}
void WorldPackets::SendCharacterCreationResponse(const SystemAddress& sysAddr, eCharacterCreationResponse response) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_CREATE_RESPONSE);
bitStream.Write(response);
SEND_PACKET;
}
void WorldPackets::SendCharacterRenameResponse(const SystemAddress& sysAddr, eRenameResponse response) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_RENAME_RESPONSE);
bitStream.Write(response);
SEND_PACKET;
}
void WorldPackets::SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::DELETE_CHARACTER_RESPONSE);
bitStream.Write<uint8_t>(response);
SEND_PACKET;
}
void WorldPackets::SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TRANSFER_TO_WORLD);
bitStream.Write(LUString(serverIP));
bitStream.Write<uint16_t>(serverPort);
bitStream.Write<uint8_t>(mythranShift);
SEND_PACKET;
}
void WorldPackets::SendServerState(const SystemAddress& sysAddr) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::SERVER_STATES);
bitStream.Write<uint8_t>(1); //If the server is receiving this request, it probably is ready anyway.
SEND_PACKET;
}
void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CREATE_CHARACTER);
RakNet::BitStream data;
data.Write<uint32_t>(7); //LDF key count
std::unique_ptr<LDFData<LWOOBJID>> objid(new LDFData<LWOOBJID>(u"objid", player));
std::unique_ptr<LDFData<LOT>> lot(new LDFData<LOT>(u"template", 1));
std::unique_ptr<LDFData<std::string>> xmlConfigData(new LDFData<std::string>(u"xmlData", xmlData));
std::unique_ptr<LDFData<std::u16string>> name(new LDFData<std::u16string>(u"name", username));
std::unique_ptr<LDFData<int32_t>> gmlevel(new LDFData<int32_t>(u"gmlevel", static_cast<int32_t>(gm)));
std::unique_ptr<LDFData<int32_t>> chatmode(new LDFData<int32_t>(u"chatmode", static_cast<int32_t>(gm)));
std::unique_ptr<LDFData<int64_t>> reputationLdf(new LDFData<int64_t>(u"reputation", reputation));
objid->WriteToPacket(data);
lot->WriteToPacket(data);
name->WriteToPacket(data);
gmlevel->WriteToPacket(data);
chatmode->WriteToPacket(data);
xmlConfigData->WriteToPacket(data);
reputationLdf->WriteToPacket(data);
//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<uint32_t>(size + 9); //size of data + header bytes (8)
bitStream.Write<uint8_t>(1); //compressed boolean, true
bitStream.Write<uint32_t>(data.GetNumberOfBytesUsed());
bitStream.Write<uint32_t>(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'.
bitStream.WriteAlignedBytes(compressedData, size);
#pragma warning(default:6385)
SEND_PACKET;
delete[] compressedData;
LOG("Sent CreateCharacter for ID: %llu", player);
}
void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHAT_MODERATION_STRING);
bitStream.Write<uint8_t>(unacceptedItems.empty()); // Is sentence ok?
bitStream.Write<uint16_t>(0x16); // Source ID, unknown
bitStream.Write<uint8_t>(requestID); // request ID
bitStream.Write<char>(0); // chat mode
bitStream.Write(LUWString(receiver, 42)); // receiver name
for (auto it : unacceptedItems) {
bitStream.Write<uint8_t>(it.first); // start index
bitStream.Write<uint8_t>(it.second); // length
}
for (int i = unacceptedItems.size(); 64 > i; i++) {
bitStream.Write<uint16_t>(0);
}
SEND_PACKET;
}
void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAKE_GM_RESPONSE);
bitStream.Write<uint8_t>(success);
bitStream.Write(static_cast<uint16_t>(highestLevel));
bitStream.Write(static_cast<uint16_t>(prevLevel));
bitStream.Write(static_cast<uint16_t>(newLevel));
SEND_PACKET;
}
void WorldPackets::SendHTTPMonitorInfo(const SystemAddress& sysAddr, const HTTPMonitorInfo& info) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::HTTP_MONITOR_INFO_RESPONSE);
info.Serialize(bitStream);
SEND_PACKET;
}
void WorldPackets::SendDebugOuput(const SystemAddress& sysAddr, const std::string& data){
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::DEBUG_OUTPUT);
bitStream.Write<uint32_t>(data.size());
bitStream.Write(data);
SEND_PACKET;
}