Compare commits

...

6 Commits

Author SHA1 Message Date
0dc4fab531 fix some missed things 2025-09-12 23:25:49 -05:00
500a72dc11 Change LUBitstream to make more sense and only read what it needs from the bitstream at each level 2025-09-12 22:25:55 -05:00
b36b440eba remove stray log 2025-09-11 00:27:24 -05:00
d1e65f16f7 fix conflict 2025-09-10 23:14:05 -05:00
e854d6f56a chore: convert all auth packets to LUBitStreams
Split things out to their correct files as well
2025-09-10 23:04:55 -05:00
824d563fd2 WIP 2025-09-08 21:45:33 -05:00
23 changed files with 787 additions and 497 deletions

View File

@@ -20,6 +20,7 @@
//Auth includes: //Auth includes:
#include "AuthPackets.h" #include "AuthPackets.h"
#include "CommonPackets.h"
#include "ServiceType.h" #include "ServiceType.h"
#include "MessageType/Server.h" #include "MessageType/Server.h"
#include "MessageType/Auth.h" #include "MessageType/Auth.h"
@@ -164,17 +165,12 @@ int main(int argc, char** argv) {
} }
void HandlePacket(Packet* packet) { void HandlePacket(Packet* packet) {
if (packet->length < 4) return; CINSTREAM;
LUBitStream luBitStream;
if (packet->data[0] == ID_USER_PACKET_ENUM) { if (!luBitStream.ReadHeader(inStream) && luBitStream.rakNetID != ID_USER_PACKET_ENUM) return;
if (static_cast<ServiceType>(packet->data[1]) == ServiceType::COMMON) { else if (luBitStream.serviceType == ServiceType::COMMON) {
if (static_cast<MessageType::Server>(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) { CommonPackets::Handle(inStream, packet->systemAddress);
AuthPackets::HandleHandshake(Game::server, packet); } else if (luBitStream.serviceType == ServiceType::AUTH) {
} AuthPackets::Handle(inStream, packet->systemAddress);
} else if (static_cast<ServiceType>(packet->data[1]) == ServiceType::AUTH) {
if (static_cast<MessageType::Auth>(packet->data[3]) == MessageType::Auth::LOGIN_REQUEST) {
AuthPackets::HandleLoginRequest(Game::server, packet);
}
}
} }
} }

View File

@@ -1,24 +0,0 @@
#ifndef __ELOGINRESPONSE__H__
#define __ELOGINRESPONSE__H__
#include <cstdint>
enum class eLoginResponse : uint8_t {
GENERAL_FAILED = 0,
SUCCESS,
BANNED,
// Unused 3
// Unused 4
PERMISSIONS_NOT_HIGH_ENOUGH = 5,
INVALID_USER,
ACCOUNT_LOCKED,
WRONG_PASS,
ACCOUNT_ACTIVATION_PENDING,
ACCOUNT_DISABLED,
GAME_TIME_EXPIRED,
FREE_TRIAL_ENDED,
PLAY_SCHEDULE_TIME_UP,
ACCOUNT_NOT_ACTIVATED
};
#endif //!__ELOGINRESPONSE__H__

View File

@@ -1,24 +0,0 @@
#ifndef __ESERVERDISCONNECTIDENTIFIERS__H__
#define __ESERVERDISCONNECTIDENTIFIERS__H__
#include <cstdint>
enum class eServerDisconnectIdentifiers : uint32_t {
UNKNOWN_SERVER_ERROR = 0,
WRONG_GAME_VERSION,
WRONG_SERVER_VERSION,
CONNECTION_ON_INVALID_PORT,
DUPLICATE_LOGIN,
SERVER_SHUTDOWN,
SERVER_MAP_LOAD_FAILURE,
INVALID_SESSION_KEY,
ACCOUNT_NOT_IN_PENDING_LIST,
CHARACTER_NOT_FOUND,
CHARACTER_CORRUPTED,
KICK,
SAVE_FAILURE,
FREE_TRIAL_EXPIRED,
PLAY_SCHEDULE_TIME_DONE
};
#endif //!__ESERVERDISCONNECTIDENTIFIERS__H__

View File

@@ -5,12 +5,12 @@
#include "Logger.h" #include "Logger.h"
#include "Game.h" #include "Game.h"
#include "dZoneManager.h" #include "dZoneManager.h"
#include "eServerDisconnectIdentifiers.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "MessageType/Chat.h" #include "MessageType/Chat.h"
#include <chrono> #include <chrono>
#include <ctime> #include <ctime>
#include "CommonPackets.h"
User::User(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) { User::User(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) {
m_AccountID = 0; m_AccountID = 0;
@@ -132,7 +132,10 @@ void User::UserOutOfSync() {
if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) { if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) {
//YEET //YEET
LOG("User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed); LOG("User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed);
Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE); CommonPackets::DisconnectNotify notification;
notification.disconnectID = eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE;
notification.Send(this->m_SystemAddress);
Game::server->Disconnect(this->m_SystemAddress);
} }
} }

View File

@@ -34,7 +34,7 @@ namespace {
} }
namespace Mail { namespace Mail {
std::map<eMessageID, std::function<std::unique_ptr<MailLUBitStream>()>> g_Handlers = { std::map<eMessageID, std::function<std::unique_ptr<MailClientLUBitStream>()>> g_Handlers = {
{eMessageID::SendRequest, []() { {eMessageID::SendRequest, []() {
return std::make_unique<SendRequest>(); return std::make_unique<SendRequest>();
}}, }},
@@ -55,11 +55,11 @@ namespace Mail {
}}, }},
}; };
void MailLUBitStream::Serialize(RakNet::BitStream& bitStream) const { void MailClientLUBitStream::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(messageID); bitStream.Write(messageID);
} }
bool MailLUBitStream::Deserialize(RakNet::BitStream& bitstream) { bool MailClientLUBitStream::Deserialize(RakNet::BitStream& bitstream) {
VALIDATE_READ(bitstream.Read(messageID)); VALIDATE_READ(bitstream.Read(messageID));
return true; return true;
} }
@@ -133,16 +133,16 @@ namespace Mail {
response.status = eSendResponse::SenderAccountIsMuted; response.status = eSendResponse::SenderAccountIsMuted;
} }
LOG("Finished send with status %s", StringifiedEnum::ToString(response.status).data()); LOG("Finished send with status %s", StringifiedEnum::ToString(response.status).data());
response.Send(sysAddr); response.Send();
} }
void SendResponse::Serialize(RakNet::BitStream& bitStream) const { void SendResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream); MailClientLUBitStream::Serialize(bitStream);
bitStream.Write(status); bitStream.Write(status);
} }
void NotificationResponse::Serialize(RakNet::BitStream& bitStream) const { void NotificationResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream); MailClientLUBitStream::Serialize(bitStream);
bitStream.Write(status); bitStream.Write(status);
bitStream.Write<uint64_t>(0); // unused bitStream.Write<uint64_t>(0); // unused
bitStream.Write<uint64_t>(0); // unused bitStream.Write<uint64_t>(0); // unused
@@ -158,12 +158,12 @@ namespace Mail {
auto playerMail = Database::Get()->GetMailForPlayer(character->GetID(), 20); auto playerMail = Database::Get()->GetMailForPlayer(character->GetID(), 20);
DataResponse response; DataResponse response;
response.playerMail = playerMail; response.playerMail = playerMail;
response.Send(sysAddr); response.Send();
LOG("DataRequest"); LOG("DataRequest");
} }
void DataResponse::Serialize(RakNet::BitStream& bitStream) const { void DataResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream); MailClientLUBitStream::Serialize(bitStream);
bitStream.Write(this->throttled); bitStream.Write(this->throttled);
bitStream.Write<uint16_t>(this->playerMail.size()); bitStream.Write<uint16_t>(this->playerMail.size());
@@ -199,11 +199,11 @@ namespace Mail {
} }
} }
LOG("AttachmentCollectResponse %s", StringifiedEnum::ToString(response.status).data()); LOG("AttachmentCollectResponse %s", StringifiedEnum::ToString(response.status).data());
response.Send(sysAddr); response.Send();
} }
void AttachmentCollectResponse::Serialize(RakNet::BitStream& bitStream) const { void AttachmentCollectResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream); MailClientLUBitStream::Serialize(bitStream);
bitStream.Write(status); bitStream.Write(status);
bitStream.Write(mailID); bitStream.Write(mailID);
} }
@@ -230,11 +230,11 @@ namespace Mail {
response.status = eDeleteResponse::NotFound; response.status = eDeleteResponse::NotFound;
} }
LOG("DeleteRequest status %s", StringifiedEnum::ToString(response.status).data()); LOG("DeleteRequest status %s", StringifiedEnum::ToString(response.status).data());
response.Send(sysAddr); response.Send();
} }
void DeleteResponse::Serialize(RakNet::BitStream& bitStream) const { void DeleteResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream); MailClientLUBitStream::Serialize(bitStream);
bitStream.Write(status); bitStream.Write(status);
bitStream.Write(mailID); bitStream.Write(mailID);
} }
@@ -256,11 +256,11 @@ namespace Mail {
} }
LOG("ReadRequest %s", StringifiedEnum::ToString(response.status).data()); LOG("ReadRequest %s", StringifiedEnum::ToString(response.status).data());
response.Send(sysAddr); response.Send();
} }
void ReadResponse::Serialize(RakNet::BitStream& bitStream) const { void ReadResponse::Serialize(RakNet::BitStream& bitStream) const {
MailLUBitStream::Serialize(bitStream); MailClientLUBitStream::Serialize(bitStream);
bitStream.Write(status); bitStream.Write(status);
bitStream.Write(mailID); bitStream.Write(mailID);
} }
@@ -275,13 +275,13 @@ namespace Mail {
} }
LOG("NotificationRequest %s", StringifiedEnum::ToString(response.status).data()); LOG("NotificationRequest %s", StringifiedEnum::ToString(response.status).data());
response.Send(sysAddr); response.Send();
} }
} }
// Non Stuct Functions // Non Stuct Functions
void Mail::HandleMail(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player) { void Mail::Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player) {
MailLUBitStream data; MailClientLUBitStream data;
if (!data.Deserialize(inStream)) { if (!data.Deserialize(inStream)) {
LOG_DEBUG("Error Reading Mail header"); LOG_DEBUG("Error Reading Mail header");
return; return;
@@ -368,5 +368,5 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) return; // TODO: Echo to chat server if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) return; // TODO: Echo to chat server
NotificationResponse response; NotificationResponse response;
response.status = eNotificationResponse::NewMail; response.status = eNotificationResponse::NewMail;
response.Send(sysAddr); response.Send();
} }

View File

@@ -7,6 +7,8 @@
#include "dCommonVars.h" #include "dCommonVars.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "MailInfo.h" #include "MailInfo.h"
#include "MessageType/Client.h"
#include "ClientPackets.h"
class Entity; class Entity;
@@ -103,112 +105,111 @@ namespace Mail {
UnknownError UnknownError
}; };
struct MailLUBitStream : public LUBitStream { struct MailClientLUBitStream : public ClientPackets::ClientLUBitStream {
eMessageID messageID = eMessageID::UnknownError; eMessageID messageID = eMessageID::UnknownError;
SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS;
Entity* player = nullptr; Entity* player = nullptr;
MailLUBitStream() = default; MailClientLUBitStream() = default;
MailLUBitStream(eMessageID _messageID) : LUBitStream(ServiceType::CLIENT, MessageType::Client::MAIL), messageID{_messageID} {}; MailClientLUBitStream(eMessageID _messageID) : ClientPackets::ClientLUBitStream(MessageType::Client::MAIL), messageID{_messageID} {};
virtual void Serialize(RakNet::BitStream& bitStream) const override; virtual void Serialize(RakNet::BitStream& bitStream) const override;
virtual bool Deserialize(RakNet::BitStream& bitStream) override; virtual bool Deserialize(RakNet::BitStream& bitStream) override;
virtual void Handle() override {}; virtual void Handle() override {};
}; };
struct SendRequest : public MailLUBitStream { struct SendRequest : public MailClientLUBitStream {
MailInfo mailInfo; MailInfo mailInfo;
SendRequest() : MailLUBitStream(eMessageID::SendRequest) {} SendRequest() : MailClientLUBitStream(eMessageID::SendRequest) {}
bool Deserialize(RakNet::BitStream& bitStream) override; bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override; void Handle() override;
}; };
struct SendResponse :public MailLUBitStream { struct SendResponse :public MailClientLUBitStream {
eSendResponse status = eSendResponse::UnknownError; eSendResponse status = eSendResponse::UnknownError;
SendResponse() : MailLUBitStream(eMessageID::SendResponse) {} SendResponse() : MailClientLUBitStream(eMessageID::SendResponse) {}
void Serialize(RakNet::BitStream& bitStream) const override; void Serialize(RakNet::BitStream& bitStream) const override;
}; };
struct NotificationResponse : public MailLUBitStream { struct NotificationResponse : public MailClientLUBitStream {
eNotificationResponse status = eNotificationResponse::UnknownError; eNotificationResponse status = eNotificationResponse::UnknownError;
LWOOBJID auctionID = LWOOBJID_EMPTY; LWOOBJID auctionID = LWOOBJID_EMPTY;
uint32_t mailCount = 1; uint32_t mailCount = 1;
NotificationResponse() : MailLUBitStream(eMessageID::NotificationResponse) {}; NotificationResponse() : MailClientLUBitStream(eMessageID::NotificationResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override; void Serialize(RakNet::BitStream& bitStream) const override;
}; };
struct DataRequest : public MailLUBitStream { struct DataRequest : public MailClientLUBitStream {
DataRequest() : MailLUBitStream(eMessageID::DataRequest) {} DataRequest() : MailClientLUBitStream(eMessageID::DataRequest) {}
bool Deserialize(RakNet::BitStream& bitStream) override { return true; }; bool Deserialize(RakNet::BitStream& bitStream) override { return true; };
void Handle() override; void Handle() override;
}; };
struct DataResponse : public MailLUBitStream { struct DataResponse : public MailClientLUBitStream {
uint32_t throttled = 0; uint32_t throttled = 0;
std::vector<MailInfo> playerMail; std::vector<MailInfo> playerMail;
DataResponse() : MailLUBitStream(eMessageID::DataResponse) {}; DataResponse() : MailClientLUBitStream(eMessageID::DataResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override; void Serialize(RakNet::BitStream& bitStream) const override;
}; };
struct AttachmentCollectRequest : public MailLUBitStream { struct AttachmentCollectRequest : public MailClientLUBitStream {
uint64_t mailID = 0; uint64_t mailID = 0;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
AttachmentCollectRequest() : MailLUBitStream(eMessageID::AttachmentCollectRequest) {}; AttachmentCollectRequest() : MailClientLUBitStream(eMessageID::AttachmentCollectRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override; bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override; void Handle() override;
}; };
struct AttachmentCollectResponse : public MailLUBitStream { struct AttachmentCollectResponse : public MailClientLUBitStream {
eAttachmentCollectResponse status = eAttachmentCollectResponse::UnknownError; eAttachmentCollectResponse status = eAttachmentCollectResponse::UnknownError;
uint64_t mailID = 0; uint64_t mailID = 0;
AttachmentCollectResponse() : MailLUBitStream(eMessageID::AttachmentCollectResponse) {}; AttachmentCollectResponse() : MailClientLUBitStream(eMessageID::AttachmentCollectResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override; void Serialize(RakNet::BitStream& bitStream) const override;
}; };
struct DeleteRequest : public MailLUBitStream { struct DeleteRequest : public MailClientLUBitStream {
uint64_t mailID = 0; uint64_t mailID = 0;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
DeleteRequest() : MailLUBitStream(eMessageID::DeleteRequest) {}; DeleteRequest() : MailClientLUBitStream(eMessageID::DeleteRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override; bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override; void Handle() override;
}; };
struct DeleteResponse : public MailLUBitStream { struct DeleteResponse : public MailClientLUBitStream {
eDeleteResponse status = eDeleteResponse::UnknownError; eDeleteResponse status = eDeleteResponse::UnknownError;
uint64_t mailID = 0; uint64_t mailID = 0;
DeleteResponse() : MailLUBitStream(eMessageID::DeleteResponse) {}; DeleteResponse() : MailClientLUBitStream(eMessageID::DeleteResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override; void Serialize(RakNet::BitStream& bitStream) const override;
}; };
struct ReadRequest : public MailLUBitStream { struct ReadRequest : public MailClientLUBitStream {
uint64_t mailID = 0; uint64_t mailID = 0;
ReadRequest() : MailLUBitStream(eMessageID::ReadRequest) {}; ReadRequest() : MailClientLUBitStream(eMessageID::ReadRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override; bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override; void Handle() override;
}; };
struct ReadResponse : public MailLUBitStream { struct ReadResponse : public MailClientLUBitStream {
uint64_t mailID = 0; uint64_t mailID = 0;
eReadResponse status = eReadResponse::UnknownError; eReadResponse status = eReadResponse::UnknownError;
ReadResponse() : MailLUBitStream(eMessageID::ReadResponse) {}; ReadResponse() : MailClientLUBitStream(eMessageID::ReadResponse) {};
void Serialize(RakNet::BitStream& bitStream) const override; void Serialize(RakNet::BitStream& bitStream) const override;
}; };
struct NotificationRequest : public MailLUBitStream { struct NotificationRequest : public MailClientLUBitStream {
NotificationRequest() : MailLUBitStream(eMessageID::NotificationRequest) {}; NotificationRequest() : MailClientLUBitStream(eMessageID::NotificationRequest) {};
bool Deserialize(RakNet::BitStream& bitStream) override { return true; }; bool Deserialize(RakNet::BitStream& bitStream) override { return true; };
void Handle() override; void Handle() override;
}; };
void HandleMail(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player); void Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr, Entity* player);
void SendMail( void SendMail(
const Entity* recipient, const Entity* recipient,

View File

@@ -3,6 +3,7 @@
// Classes // Classes
#include "Character.h" #include "Character.h"
#include "ChatPackets.h" #include "ChatPackets.h"
#include "CommonPackets.h"
#include "dServer.h" #include "dServer.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "User.h" #include "User.h"
@@ -16,7 +17,6 @@
// Enums // Enums
#include "MessageType/Chat.h" #include "MessageType/Chat.h"
#include "eServerDisconnectIdentifiers.h"
#include "eObjectBits.h" #include "eObjectBits.h"
namespace GMGreaterThanZeroCommands { namespace GMGreaterThanZeroCommands {
@@ -31,8 +31,10 @@ namespace GMGreaterThanZeroCommands {
ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + username); ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + username);
return; return;
} }
CommonPackets::DisconnectNotify notification;
Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); notification.disconnectID = eServerDisconnectIdentifiers::KICK;
notification.Send(player->GetSystemAddress());
Game::server->Disconnect(player->GetSystemAddress());
ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username);
} else { } else {
@@ -69,7 +71,10 @@ namespace GMGreaterThanZeroCommands {
if (accountId != 0) Database::Get()->UpdateAccountBan(accountId, true); if (accountId != 0) Database::Get()->UpdateAccountBan(accountId, true);
if (player != nullptr) { if (player != nullptr) {
Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); CommonPackets::DisconnectNotify notification;
notification.disconnectID = eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED;
notification.Send(player->GetSystemAddress());
Game::server->Disconnect(player->GetSystemAddress());
} }
ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(splitArgs[0])); ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(splitArgs[0]));

View File

@@ -17,296 +17,244 @@
#include "Game.h" #include "Game.h"
#include "dConfig.h" #include "dConfig.h"
#include "eServerDisconnectIdentifiers.h"
#include "eLoginResponse.h"
#include "ServiceType.h" #include "ServiceType.h"
#include "MessageType/Server.h" #include "MessageType/Server.h"
#include "MessageType/Master.h" #include "MessageType/Master.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
#include "StringifiedEnum.h" #include "StringifiedEnum.h"
#include "CommonPackets.h"
#include "ClientPackets.h"
namespace { namespace {
std::vector<uint32_t> claimCodes; std::vector<uint32_t> claimCodes;
} }
void Stamp::Serialize(RakNet::BitStream& outBitStream){ namespace AuthPackets {
outBitStream.Write(type); std::map<MessageType::Auth, std::function<std::unique_ptr<LUBitStream>()>> g_Handlers = {
outBitStream.Write(value); {MessageType::Auth::LOGIN_REQUEST, []() {
outBitStream.Write(timestamp); return std::make_unique<LoginRequest>();
}; }}
};
// Struct Functions
void AuthLUBitStream::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(this->messageType);
bitStream.Write<uint8_t>(0); // padding
}
bool AuthLUBitStream::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(this->messageType));
uint8_t padding = 0;
VALIDATE_READ(bitStream.Read(padding));
return true;
}
bool LoginRequest::Deserialize(RakNet::BitStream& bitStream) {
LUWString usernameLUString;
VALIDATE_READ(bitStream.Read(usernameLUString));
username = usernameLUString.GetAsString();
LUWString passwordLUString(41);
VALIDATE_READ(bitStream.Read(passwordLUString));
password = passwordLUString.GetAsString();
VALIDATE_READ(bitStream.Read(locale_id));
VALIDATE_READ(bitStream.Read(clientOS));
LUWString memoryStatsLU(256);
VALIDATE_READ(bitStream.Read(memoryStatsLU));
computerInfo.memoryStats = memoryStatsLU.GetAsString();
LUWString videoCardLU(128);
VALIDATE_READ(bitStream.Read(videoCardLU));
computerInfo.videoCard = videoCardLU.GetAsString();
// Processor/CPU info
VALIDATE_READ(bitStream.Read(computerInfo.processorInfo.count));
VALIDATE_READ(bitStream.Read(computerInfo.processorInfo.type));
VALIDATE_READ(bitStream.Read(computerInfo.processorInfo.level));
VALIDATE_READ(bitStream.Read(computerInfo.processorInfo.revision));
// OS Info
VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.infoSize));
VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.majorVersion));
VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.minorVersion));
VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.buildNumber));
VALIDATE_READ(bitStream.Read(computerInfo.osVersionInfo.platformID));
return true;
}
void LoginRequest::Handle() {
LOG_DEBUG("Login Request from %s", username.c_str());
LOG_DEBUG("Password: %s", password.c_str());
LOG_DEBUG("Locale ID: %s", StringifiedEnum::ToString(locale_id).data());
LOG_DEBUG("Operating System: %s", StringifiedEnum::ToString(clientOS).data());
LOG_DEBUG("Memory Stats [%s]", computerInfo.memoryStats.c_str());
LOG_DEBUG("VideoCard Info: [%s]", computerInfo.videoCard.c_str());
LOG_DEBUG("CPU Info: [#Processors: %i, Processor Type: %i, Processor Level: %i, Processor Revision: %i]",
computerInfo.processorInfo.count,
computerInfo.processorInfo.type,
computerInfo.processorInfo.level,
computerInfo.processorInfo.revision
);
LOG_DEBUG("OS Info: [Size: %i, Version: %i.%i, Buid#: %i, platformID: %i]",
computerInfo.osVersionInfo.infoSize,
computerInfo.osVersionInfo.majorVersion,
computerInfo.osVersionInfo.minorVersion,
computerInfo.osVersionInfo.buildNumber,
computerInfo.osVersionInfo.platformID
);
ClientPackets::LoginResponse response;
response.sysAddr = this->sysAddr;
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_START, 0);
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_CLIENT_OS, 0);
response.events.push_back(LUString(Game::config->GetValue("event_1")));
response.events.push_back(LUString(Game::config->GetValue("event_2")));
response.events.push_back(LUString(Game::config->GetValue("event_3")));
response.events.push_back(LUString(Game::config->GetValue("event_4")));
response.events.push_back(LUString(Game::config->GetValue("event_5")));
response.events.push_back(LUString(Game::config->GetValue("event_6")));
response.events.push_back(LUString(Game::config->GetValue("event_7")));
response.events.push_back(LUString(Game::config->GetValue("event_8")));
response.version_major = GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_major")).value_or(ClientVersion::major);
response.version_current = GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_current")).value_or(ClientVersion::current);
response.version_minor = GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_minor")).value_or(ClientVersion::minor);
uint32_t sessionKey = GeneralUtils::GenerateRandomNumber<uint32_t>();
std::string userHash = std::to_string(sessionKey);
response.userKey = md5(userHash);
// Fetch account details
auto accountInfo = Database::Get()->GetAccountInfo(username);
if (!accountInfo) {
LOG("No user by name %s found!", username.c_str());
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
response.Send(sysAddr);
return;
}
//If we aren't running in live mode, then only GMs are allowed to enter:
const auto& closedToNonDevs = Game::config->GetValue("closed_to_non_devs");
if (closedToNonDevs.size() > 0 && bool(std::stoi(closedToNonDevs)) && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) {
response.stamps.emplace_back(eStamps::GM_REQUIRED, 1);
response.Send(sysAddr);
return;
}
if (Game::config->GetValue("dont_use_keys") != "1" && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) {
//Check to see if we have a play key:
if (accountInfo->playKeyId == 0) {
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
response.responseCode = eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH;
response.errorMessage = "Your account doesn't have a play key associated with it!";
response.Send(sysAddr);
LOG("User %s tried to log in, but they don't have a play key.", username.c_str());
return;
}
//Check if the play key is _valid_:
auto playKeyStatus = Database::Get()->IsPlaykeyActive(accountInfo->playKeyId);
if (!playKeyStatus) {
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
response.responseCode = eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH;
response.errorMessage = "Your account doesn't have a valid play key associated with it!";
response.Send(sysAddr);
return;
}
if (!playKeyStatus.value()) {
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
response.responseCode = eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH;
response.errorMessage = "Your play key has been disabled.";
response.Send(sysAddr);
LOG("User %s tried to log in, but their play key was disabled", username.c_str());
return;
}
} else if (Game::config->GetValue("dont_use_keys") == "1" || accountInfo->maxGmLevel > eGameMasterLevel::CIVILIAN) {
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_BYPASS, 1);
}
if (accountInfo->banned) {
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
response.responseCode = eLoginResponse::BANNED;
response.errorMessage = "Your account has been banned.";
response.Send(sysAddr);
return;
}
if (accountInfo->locked) {
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
response.responseCode = eLoginResponse::ACCOUNT_LOCKED;
response.errorMessage = "Your account is locked.";
response.Send(sysAddr);
return;
}
bool loginSuccess = ::bcrypt_checkpw(password.c_str(), accountInfo->bcryptPassword.c_str()) == 0;
if (!loginSuccess) {
response.stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
response.responseCode = eLoginResponse::WRONG_PASS;
response.Send(sysAddr);
} else {
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, 0, 0, false, [this, response, sessionKey](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string zoneIP, uint16_t zonePort) mutable {
response.responseCode = eLoginResponse::SUCCESS;
response.worldServerIP = LUString(zoneIP);
response.worldServerPort = zonePort;
response.Send();
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::MASTER, MessageType::Master::SET_SESSION_KEY);
bitStream.Write(sessionKey);
LOG_DEBUG("Sending session key for %s to master server", this->username.c_str());
bitStream.Write(LUString(this->username));
Game::server->SendToMaster(bitStream);
});
for (auto const code : claimCodes) {
Database::Get()->InsertRewardCode(accountInfo->id, code);
}
}
}
}
// Non Stuct Functions
void AuthPackets::LoadClaimCodes() { void AuthPackets::LoadClaimCodes() {
if(!claimCodes.empty()) return; if (!claimCodes.empty()) return;
auto rcstring = Game::config->GetValue("rewardcodes"); auto rcstring = Game::config->GetValue("rewardcodes");
auto codestrings = GeneralUtils::SplitString(rcstring, ','); auto codestrings = GeneralUtils::SplitString(rcstring, ',');
for(auto const &codestring: codestrings){ for (auto const& codestring : codestrings) {
const auto code = GeneralUtils::TryParse<uint32_t>(codestring); const auto code = GeneralUtils::TryParse<uint32_t>(codestring);
if (code && code.value() != -1) claimCodes.push_back(code.value()); if (code && code.value() != -1) claimCodes.push_back(code.value());
} }
} }
void AuthPackets::HandleHandshake(dServer* server, Packet* packet) { // Non Stuct Functions
CINSTREAM_SKIP_HEADER void AuthPackets::Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr) {
uint32_t clientVersion = 0; AuthLUBitStream authLUBitStream;
inStream.Read(clientVersion); if (!authLUBitStream.Deserialize(inStream)) return;
inStream.IgnoreBytes(4);
ServiceType serviceType; auto it = g_Handlers.find(authLUBitStream.messageType);
inStream.Read(serviceType); if (it != g_Handlers.end()) {
if (serviceType != ServiceType::CLIENT) LOG("WARNING: Service is not a Client!"); auto request = it->second();
inStream.IgnoreBytes(2); request->sysAddr = sysAddr;
if (!request->Deserialize(inStream)) {
uint32_t processID; LOG_DEBUG("Error Reading Auth Packet: %s", StringifiedEnum::ToString(authLUBitStream.messageType).data());
inStream.Read(processID);
uint16_t port;
inStream.Read(port);
if (port != packet->systemAddress.port) LOG("WARNING: Port written in packet does not match the port the client is connecting over!");
inStream.IgnoreBytes(33);
LOG_DEBUG("Client Data [Version: %i, Service: %s, Process: %u, Port: %u, Sysaddr Port: %u]", clientVersion, StringifiedEnum::ToString(serviceType).data(), processID, port, packet->systemAddress.port);
SendHandshake(server, packet->systemAddress, server->GetIP(), server->GetPort(), server->GetServerType());
}
void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServiceType serverType) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, ServiceType::COMMON, MessageType::Server::VERSION_CONFIRM);
const auto& clientNetVersionString = Game::config->GetValue("client_net_version");
const uint32_t clientNetVersion = GeneralUtils::TryParse<uint32_t>(clientNetVersionString).value_or(171022);
bitStream.Write<uint32_t>(clientNetVersion);
bitStream.Write<uint32_t>(861228100);
bitStream.Write(static_cast<uint32_t>(serverType));
bitStream.Write<uint64_t>(219818307120);
server->Send(bitStream, sysAddr, false);
}
std::string CleanReceivedString(const std::string& str) {
std::string toReturn = str;
const auto removed = std::ranges::find_if(toReturn, [](unsigned char c) { return isprint(c) == 0 && isblank(c) == 0; });
toReturn.erase(removed, toReturn.end());
return toReturn;
}
void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) {
CINSTREAM_SKIP_HEADER;
std::vector<Stamp> stamps;
stamps.emplace_back(eStamps::PASSPORT_AUTH_START, 0);
LUWString usernameLUString;
inStream.Read(usernameLUString);
const auto username = usernameLUString.GetAsString();
LUWString password(41);
inStream.Read(password);
LanguageCodeID locale_id;
inStream.Read(locale_id);
LOG_DEBUG("Locale ID: %s", StringifiedEnum::ToString(locale_id).data());
ClientOS clientOS;
inStream.Read(clientOS);
LOG_DEBUG("Operating System: %s", StringifiedEnum::ToString(clientOS).data());
stamps.emplace_back(eStamps::PASSPORT_AUTH_CLIENT_OS, 0);
LUWString memoryStats(256);
inStream.Read(memoryStats);
LOG_DEBUG("Memory Stats [%s]", CleanReceivedString(memoryStats.GetAsString()).c_str());
LUWString videoCard(128);
inStream.Read(videoCard);
LOG_DEBUG("VideoCard Info: [%s]", CleanReceivedString(videoCard.GetAsString()).c_str());
// Processor/CPU info
uint32_t numOfProcessors;
inStream.Read(numOfProcessors);
uint32_t processorType;
inStream.Read(processorType);
uint16_t processorLevel;
inStream.Read(processorLevel);
uint16_t processorRevision;
inStream.Read(processorRevision);
LOG_DEBUG("CPU Info: [#Processors: %i, Processor Type: %i, Processor Level: %i, Processor Revision: %i]", numOfProcessors, processorType, processorLevel, processorRevision);
// OS Info
uint32_t osVersionInfoSize;
inStream.Read(osVersionInfoSize);
uint32_t majorVersion;
inStream.Read(majorVersion);
uint32_t minorVersion;
inStream.Read(minorVersion);
uint32_t buildNumber;
inStream.Read(buildNumber);
uint32_t platformID;
inStream.Read(platformID);
LOG_DEBUG("OS Info: [Size: %i, Major: %i, Minor %i, Buid#: %i, platformID: %i]", osVersionInfoSize, majorVersion, minorVersion, buildNumber, platformID);
// Fetch account details
auto accountInfo = Database::Get()->GetAccountInfo(username);
if (!accountInfo) {
LOG("No user by name %s found!", username.c_str());
stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::INVALID_USER, "", "", 2001, username, stamps);
return;
}
//If we aren't running in live mode, then only GMs are allowed to enter:
const auto& closedToNonDevs = Game::config->GetValue("closed_to_non_devs");
if (closedToNonDevs.size() > 0 && bool(std::stoi(closedToNonDevs)) && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) {
stamps.emplace_back(eStamps::GM_REQUIRED, 1);
AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "The server is currently only open to developers.", "", 2001, username, stamps);
return;
}
if (Game::config->GetValue("dont_use_keys") != "1" && accountInfo->maxGmLevel == eGameMasterLevel::CIVILIAN) {
//Check to see if we have a play key:
if (accountInfo->playKeyId == 0) {
stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a play key associated with it!", "", 2001, username, stamps);
LOG("User %s tried to log in, but they don't have a play key.", username.c_str());
return; return;
} }
LOG_DEBUG("Received Auth Packet: %s", StringifiedEnum::ToString(authLUBitStream.messageType).data());
//Check if the play key is _valid_: request->Handle();
auto playKeyStatus = Database::Get()->IsPlaykeyActive(accountInfo->playKeyId);
if (!playKeyStatus) {
stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your account doesn't have a valid play key associated with it!", "", 2001, username, stamps);
return;
}
if (!playKeyStatus.value()) {
stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, "Your play key has been disabled.", "", 2001, username, stamps);
LOG("User %s tried to log in, but their play key was disabled", username.c_str());
return;
}
} else if (Game::config->GetValue("dont_use_keys") == "1" || accountInfo->maxGmLevel > eGameMasterLevel::CIVILIAN){
stamps.emplace_back(eStamps::PASSPORT_AUTH_BYPASS, 1);
}
if (accountInfo->banned) {
stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::BANNED, "", "", 2001, username, stamps);
return;
}
if (accountInfo->locked) {
stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::ACCOUNT_LOCKED, "", "", 2001, username, stamps);
return;
}
bool loginSuccess = ::bcrypt_checkpw(password.GetAsString().c_str(), accountInfo->bcryptPassword.c_str()) == 0;
if (!loginSuccess) {
stamps.emplace_back(eStamps::PASSPORT_AUTH_ERROR, 1);
AuthPackets::SendLoginResponse(server, packet->systemAddress, eLoginResponse::WRONG_PASS, "", "", 2001, username, stamps);
LOG("Wrong password used");
} else { } else {
SystemAddress system = packet->systemAddress; //Copy the sysAddr before the Packet gets destroyed from main LOG_DEBUG("Unhandled Auth Packet with ID: %i", authLUBitStream.messageType);
if (!server->GetIsConnectedToMaster()) {
stamps.emplace_back(eStamps::PASSPORT_AUTH_WORLD_DISCONNECT, 1);
AuthPackets::SendLoginResponse(server, system, eLoginResponse::GENERAL_FAILED, "", "", 0, username, stamps);
return;
}
stamps.emplace_back(eStamps::PASSPORT_AUTH_WORLD_SESSION_CONFIRM_TO_AUTH, 1);
ZoneInstanceManager::Instance()->RequestZoneTransfer(server, 0, 0, false, [system, server, username, stamps](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string zoneIP, uint16_t zonePort) mutable {
AuthPackets::SendLoginResponse(server, system, eLoginResponse::SUCCESS, "", zoneIP, zonePort, username, stamps);
});
}
for(auto const code: claimCodes){
Database::Get()->InsertRewardCode(accountInfo->id, code);
} }
} }
void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username, std::vector<Stamp>& stamps) {
stamps.emplace_back(eStamps::PASSPORT_AUTH_IM_LOGIN_START, 1);
RakNet::BitStream loginResponse;
BitStreamUtils::WriteHeader(loginResponse, ServiceType::CLIENT, MessageType::Client::LOGIN_RESPONSE);
loginResponse.Write(responseCode);
// Event Gating
loginResponse.Write(LUString(Game::config->GetValue("event_1")));
loginResponse.Write(LUString(Game::config->GetValue("event_2")));
loginResponse.Write(LUString(Game::config->GetValue("event_3")));
loginResponse.Write(LUString(Game::config->GetValue("event_4")));
loginResponse.Write(LUString(Game::config->GetValue("event_5")));
loginResponse.Write(LUString(Game::config->GetValue("event_6")));
loginResponse.Write(LUString(Game::config->GetValue("event_7")));
loginResponse.Write(LUString(Game::config->GetValue("event_8")));
const uint16_t version_major =
GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_major")).value_or(ClientVersion::major);
const uint16_t version_current =
GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_current")).value_or(ClientVersion::current);
const uint16_t version_minor =
GeneralUtils::TryParse<uint16_t>(Game::config->GetValue("version_minor")).value_or(ClientVersion::minor);
loginResponse.Write(version_major);
loginResponse.Write(version_current);
loginResponse.Write(version_minor);
// Writes the user key
uint32_t sessionKey = GeneralUtils::GenerateRandomNumber<uint32_t>();
std::string userHash = std::to_string(sessionKey);
userHash = md5(userHash);
loginResponse.Write(LUWString(userHash));
// World Server IP
loginResponse.Write(LUString(wServerIP));
// Chat Server IP (unused)
loginResponse.Write(LUString(""));
// World Server Redirect port
loginResponse.Write(wServerPort);
// Char Server Redirect port (unused)
loginResponse.Write(static_cast<uint16_t>(0));
// CDN Key
loginResponse.Write(LUString(""));
// CDN Ticket
loginResponse.Write(LUString("00000000-0000-0000-0000-000000000000", 37));
// Language
loginResponse.Write(Language::en_US);
// Write the localization
loginResponse.Write(LUString("US", 3));
loginResponse.Write<uint8_t>(false); // Just upgraded from F2P
loginResponse.Write<uint8_t>(false); // User is F2P
loginResponse.Write<uint64_t>(0); // Time Remaining in F2P
// Write custom error message
loginResponse.Write<uint16_t>(errorMsg.length());
loginResponse.Write(LUWString(errorMsg, static_cast<uint32_t>(errorMsg.length())));
stamps.emplace_back(eStamps::PASSPORT_AUTH_WORLD_COMMUNICATION_FINISH, 1);
loginResponse.Write<uint32_t>((sizeof(Stamp) * stamps.size()) + sizeof(uint32_t));
for (auto& stamp : stamps) stamp.Serialize(loginResponse);
server->Send(loginResponse, sysAddr, false);
//Inform the master server that we've created a session for this user:
if (responseCode == eLoginResponse::SUCCESS) {
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, ServiceType::MASTER, MessageType::Master::SET_SESSION_KEY);
bitStream.Write(sessionKey);
bitStream.Write(LUString(username));
server->SendToMaster(bitStream);
LOG("Set sessionKey: %i for user %s", sessionKey, username.c_str());
}
}

View File

@@ -5,67 +5,15 @@
#include "dCommonVars.h" #include "dCommonVars.h"
#include "dNetCommon.h" #include "dNetCommon.h"
#include "magic_enum.hpp" #include "magic_enum.hpp"
#include "BitStream.h"
#include "RakNetTypes.h"
#include "BitStreamUtils.h"
#include "MessageType/Auth.h"
enum class eLoginResponse : uint8_t; enum class eLoginResponse : uint8_t;
enum class ServiceType : uint16_t; enum class ServiceType : uint16_t;
class dServer; class dServer;
enum class eStamps : uint32_t {
PASSPORT_AUTH_START,
PASSPORT_AUTH_BYPASS,
PASSPORT_AUTH_ERROR,
PASSPORT_AUTH_DB_SELECT_START,
PASSPORT_AUTH_DB_SELECT_FINISH,
PASSPORT_AUTH_DB_INSERT_START,
PASSPORT_AUTH_DB_INSERT_FINISH,
PASSPORT_AUTH_LEGOINT_COMMUNICATION_START,
PASSPORT_AUTH_LEGOINT_RECEIVED,
PASSPORT_AUTH_LEGOINT_THREAD_SPAWN,
PASSPORT_AUTH_LEGOINT_WEBSERVICE_START,
PASSPORT_AUTH_LEGOINT_WEBSERVICE_FINISH,
PASSPORT_AUTH_LEGOINT_LEGOCLUB_START,
PASSPORT_AUTH_LEGOINT_LEGOCLUB_FINISH,
PASSPORT_AUTH_LEGOINT_THREAD_FINISH,
PASSPORT_AUTH_LEGOINT_REPLY,
PASSPORT_AUTH_LEGOINT_ERROR,
PASSPORT_AUTH_LEGOINT_COMMUNICATION_END,
PASSPORT_AUTH_LEGOINT_DISCONNECT,
PASSPORT_AUTH_WORLD_COMMUNICATION_START,
PASSPORT_AUTH_CLIENT_OS,
PASSPORT_AUTH_WORLD_PACKET_RECEIVED,
PASSPORT_AUTH_IM_COMMUNICATION_START,
PASSPORT_AUTH_IM_LOGIN_START,
PASSPORT_AUTH_IM_LOGIN_ALREADY_LOGGED_IN,
PASSPORT_AUTH_IM_OTHER_LOGIN_REMOVED,
PASSPORT_AUTH_IM_LOGIN_QUEUED,
PASSPORT_AUTH_IM_LOGIN_RESPONSE,
PASSPORT_AUTH_IM_COMMUNICATION_END,
PASSPORT_AUTH_WORLD_SESSION_CONFIRM_TO_AUTH,
PASSPORT_AUTH_WORLD_COMMUNICATION_FINISH,
PASSPORT_AUTH_WORLD_DISCONNECT,
NO_LEGO_INTERFACE,
DB_ERROR,
GM_REQUIRED,
NO_LEGO_WEBSERVICE_XML,
LEGO_WEBSERVICE_TIMEOUT,
LEGO_WEBSERVICE_ERROR,
NO_WORLD_SERVER
};
struct Stamp {
eStamps type;
uint32_t value;
uint64_t timestamp;
Stamp(eStamps type, uint32_t value, uint64_t timestamp = time(nullptr)){
this->type = type;
this->value = value;
this->timestamp = timestamp;
}
void Serialize(RakNet::BitStream& outBitStream);
};
enum class ClientOS : uint8_t { enum class ClientOS : uint8_t {
UNKNOWN, UNKNOWN,
WINDOWS, WINDOWS,
@@ -84,20 +32,50 @@ struct magic_enum::customize::enum_range<LanguageCodeID> {
static constexpr int max = 2057; static constexpr int max = 2057;
}; };
enum class Language : uint32_t {
en_US,
pl_US,
de_DE,
en_GB,
};
namespace AuthPackets { namespace AuthPackets {
void HandleHandshake(dServer* server, Packet* packet);
void SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServiceType serverType);
void HandleLoginRequest(dServer* server, Packet* packet); struct AuthLUBitStream : public LUBitStream {
void SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username, std::vector<Stamp>& stamps); MessageType::Auth messageType = MessageType::Auth::LOGIN_REQUEST;
AuthLUBitStream() : LUBitStream(ServiceType::AUTH) {};
AuthLUBitStream(MessageType::Auth _messageType) : LUBitStream(ServiceType::AUTH), messageType{_messageType} {};
virtual void Serialize(RakNet::BitStream& bitStream) const override;
virtual bool Deserialize(RakNet::BitStream& bitStream) override;
virtual void Handle() override {};
};
struct LoginRequest : public AuthLUBitStream {
std::string username;
std::string password;
LanguageCodeID locale_id;
ClientOS clientOS;
struct ComputerInfo {
std::string memoryStats;
std::string videoCard;
struct ProcessorInfo {
uint32_t count = 0;
uint32_t type = 0;
uint16_t level = 0;
uint16_t revision = 0;
} processorInfo;
struct OSVersionInfo {
uint32_t infoSize = 0;
uint32_t majorVersion = 0;
uint32_t minorVersion = 0;
uint32_t buildNumber = 0;
uint32_t platformID = 0;
} osVersionInfo;
} computerInfo;
LoginRequest() : AuthLUBitStream(MessageType::Auth::LOGIN_REQUEST) {}
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
// Non struct functions
void LoadClaimCodes(); void LoadClaimCodes();
void Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr);
} }

View File

@@ -6,18 +6,12 @@
void LUBitStream::WriteHeader(RakNet::BitStream& bitStream) const { void LUBitStream::WriteHeader(RakNet::BitStream& bitStream) const {
bitStream.Write<MessageID>(ID_USER_PACKET_ENUM); bitStream.Write<MessageID>(ID_USER_PACKET_ENUM);
bitStream.Write(this->connectionType); bitStream.Write(this->serviceType);
bitStream.Write(this->internalPacketID);
bitStream.Write<uint8_t>(0); // padding
} }
bool LUBitStream::ReadHeader(RakNet::BitStream& bitStream) { bool LUBitStream::ReadHeader(RakNet::BitStream& bitStream) {
MessageID messageID; VALIDATE_READ(bitStream.Read(this->rakNetID));
bitStream.Read(messageID); VALIDATE_READ(bitStream.Read(this->serviceType));
if (messageID != ID_USER_PACKET_ENUM) return false;
VALIDATE_READ(bitStream.Read(this->connectionType));
VALIDATE_READ(bitStream.Read(this->internalPacketID));
bitStream.IgnoreBytes(1);
return true; return true;
} }

View File

@@ -47,20 +47,22 @@ struct LUWString {
}; };
struct LUBitStream { struct LUBitStream {
ServiceType connectionType = ServiceType::UNKNOWN; // Common header data that is serialized
uint32_t internalPacketID = 0xFFFFFFFF; MessageID rakNetID = ID_USER_PACKET_ENUM;
ServiceType serviceType = ServiceType::UNKNOWN;
SystemAddress sysAddr = UNASSIGNED_SYSTEM_ADDRESS;
LUBitStream() = default; LUBitStream() = default;
template <typename T> LUBitStream(ServiceType serviceType) {
LUBitStream(ServiceType connectionType, T internalPacketID) { this->serviceType = serviceType;
this->connectionType = connectionType;
this->internalPacketID = static_cast<uint32_t>(internalPacketID);
} }
void WriteHeader(RakNet::BitStream& bitStream) const; void WriteHeader(RakNet::BitStream& bitStream) const;
bool ReadHeader(RakNet::BitStream& bitStream); bool ReadHeader(RakNet::BitStream& bitStream);
void Send(const SystemAddress& sysAddr) const; void Send(const SystemAddress& sysAddr) const;
void Send() const { Send(this->sysAddr); };
void Broadcast() const { Send(UNASSIGNED_SYSTEM_ADDRESS); }; void Broadcast() const { Send(UNASSIGNED_SYSTEM_ADDRESS); };
virtual void Serialize(RakNet::BitStream& bitStream) const {} virtual void Serialize(RakNet::BitStream& bitStream) const {}

View File

@@ -2,12 +2,14 @@ set(DNET_SOURCES "AuthPackets.cpp"
"BitStreamUtils.cpp" "BitStreamUtils.cpp"
"ChatPackets.cpp" "ChatPackets.cpp"
"ClientPackets.cpp" "ClientPackets.cpp"
"CommonPackets.cpp"
"dServer.cpp" "dServer.cpp"
"MailInfo.cpp" "MailInfo.cpp"
"MasterPackets.cpp" "MasterPackets.cpp"
"PacketUtils.cpp" "PacketUtils.cpp"
"WorldPackets.cpp" "WorldPackets.cpp"
"ZoneInstanceManager.cpp") "ZoneInstanceManager.cpp"
)
add_library(dNet STATIC ${DNET_SOURCES}) add_library(dNet STATIC ${DNET_SOURCES})
target_link_libraries(dNet PRIVATE bcrypt MD5 glm::glm) target_link_libraries(dNet PRIVATE bcrypt MD5 glm::glm)

View File

@@ -12,6 +12,20 @@
#include "ServiceType.h" #include "ServiceType.h"
#include "MessageType/Chat.h" #include "MessageType/Chat.h"
namespace ChatPackets {
// Struct Functions
void ChatLUBitStream::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(this->messageType);
bitStream.Write<uint8_t>(0); // padding
}
bool ChatLUBitStream::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(this->messageType));
uint8_t padding = 0;
VALIDATE_READ(bitStream.Read(padding));
return true;
}
}
void ShowAllRequest::Serialize(RakNet::BitStream& bitStream) { void ShowAllRequest::Serialize(RakNet::BitStream& bitStream) {
BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::SHOW_ALL); BitStreamUtils::WriteHeader(bitStream, ServiceType::CHAT, MessageType::Chat::SHOW_ALL);
bitStream.Write(this->requestor); bitStream.Write(this->requestor);
@@ -100,6 +114,7 @@ void ChatPackets::SendMessageFail(const SystemAddress& sysAddr) {
namespace ChatPackets { namespace ChatPackets {
void Announcement::Serialize(RakNet::BitStream& bitStream) const { void Announcement::Serialize(RakNet::BitStream& bitStream) const {
ChatLUBitStream::Serialize(bitStream);
bitStream.Write<uint32_t>(title.size()); bitStream.Write<uint32_t>(title.size());
bitStream.Write(title); bitStream.Write(title);
bitStream.Write<uint32_t>(message.size()); bitStream.Write<uint32_t>(message.size());
@@ -108,6 +123,7 @@ namespace ChatPackets {
} }
void ChatPackets::AchievementNotify::Serialize(RakNet::BitStream& bitstream) const { void ChatPackets::AchievementNotify::Serialize(RakNet::BitStream& bitstream) const {
ChatLUBitStream::Serialize(bitstream);
bitstream.Write<uint64_t>(0); // Packing bitstream.Write<uint64_t>(0); // Packing
bitstream.Write<uint32_t>(0); // Packing bitstream.Write<uint32_t>(0); // Packing
bitstream.Write<uint8_t>(0); // Packing bitstream.Write<uint8_t>(0); // Packing
@@ -133,6 +149,7 @@ bool ChatPackets::AchievementNotify::Deserialize(RakNet::BitStream& bitstream) {
} }
void ChatPackets::TeamInviteInitialResponse::Serialize(RakNet::BitStream& bitstream) const { void ChatPackets::TeamInviteInitialResponse::Serialize(RakNet::BitStream& bitstream) const {
ClientLUBitStream::Serialize(bitstream);
bitstream.Write<uint8_t>(inviteFailedToSend); bitstream.Write<uint8_t>(inviteFailedToSend);
bitstream.Write(playerName); bitstream.Write(playerName);
} }

View File

@@ -12,6 +12,7 @@ struct SystemAddress;
#include "dCommonVars.h" #include "dCommonVars.h"
#include "MessageType/Chat.h" #include "MessageType/Chat.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "ClientPackets.h"
struct ShowAllRequest{ struct ShowAllRequest{
LWOOBJID requestor = LWOOBJID_EMPTY; LWOOBJID requestor = LWOOBJID_EMPTY;
@@ -30,28 +31,39 @@ struct FindPlayerRequest{
namespace ChatPackets { namespace ChatPackets {
struct Announcement : public LUBitStream { struct ChatLUBitStream : public LUBitStream {
MessageType::Chat messageType = MessageType::Chat::GENERAL_CHAT_MESSAGE;
ChatLUBitStream() : LUBitStream(ServiceType::CHAT) {};
ChatLUBitStream(MessageType::Chat _messageType) : LUBitStream(ServiceType::CHAT), messageType{_messageType} {};
virtual void Serialize(RakNet::BitStream& bitStream) const override;
virtual bool Deserialize(RakNet::BitStream& bitStream) override;
virtual void Handle() override {};
};
struct Announcement : public ChatLUBitStream {
std::string title; std::string title;
std::string message; std::string message;
Announcement() : LUBitStream(ServiceType::CHAT, MessageType::Chat::GM_ANNOUNCE) {}; Announcement() : ChatLUBitStream(MessageType::Chat::GM_ANNOUNCE) {};
virtual void Serialize(RakNet::BitStream& bitStream) const override; virtual void Serialize(RakNet::BitStream& bitStream) const override;
}; };
struct AchievementNotify : public LUBitStream { struct AchievementNotify : public ChatLUBitStream {
LUWString targetPlayerName{}; LUWString targetPlayerName{};
uint32_t missionEmailID{}; uint32_t missionEmailID{};
LWOOBJID earningPlayerID{}; LWOOBJID earningPlayerID{};
LUWString earnerName{}; LUWString earnerName{};
AchievementNotify() : LUBitStream(ServiceType::CHAT, MessageType::Chat::ACHIEVEMENT_NOTIFY) {} AchievementNotify() : ChatLUBitStream(MessageType::Chat::ACHIEVEMENT_NOTIFY) {}
void Serialize(RakNet::BitStream& bitstream) const override; void Serialize(RakNet::BitStream& bitstream) const override;
bool Deserialize(RakNet::BitStream& bitstream) override; bool Deserialize(RakNet::BitStream& bitstream) override;
}; };
struct TeamInviteInitialResponse : public LUBitStream { struct TeamInviteInitialResponse : public ClientPackets::ClientLUBitStream {
bool inviteFailedToSend{}; bool inviteFailedToSend{};
LUWString playerName{}; LUWString playerName{};
TeamInviteInitialResponse() : LUBitStream(ServiceType::CLIENT, MessageType::Client::TEAM_INVITE_INITIAL_RESPONSE) {} TeamInviteInitialResponse() : ClientPackets::ClientLUBitStream(MessageType::Client::TEAM_INVITE_INITIAL_RESPONSE) {}
void Serialize(RakNet::BitStream& bitstream) const override; void Serialize(RakNet::BitStream& bitstream) const override;
// No Deserialize needed on our end // No Deserialize needed on our end

View File

@@ -6,6 +6,58 @@
#include "ClientPackets.h" #include "ClientPackets.h"
#include "dCommonVars.h" #include "dCommonVars.h"
#include "PositionUpdate.h" #include "PositionUpdate.h"
#include "StringifiedEnum.h"
namespace ClientPackets {
void Stamp::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(type);
bitStream.Write(value);
bitStream.Write(timestamp);
};
void ClientLUBitStream::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(this->messageType);
bitStream.Write<uint8_t>(0); // padding
}
bool ClientLUBitStream::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(this->messageType));
uint8_t padding = 0;
VALIDATE_READ(bitStream.Read(padding)); return true;
}
void LoginResponse::Serialize(RakNet::BitStream& bitStream) const {
ClientLUBitStream::Serialize(bitStream);
bitStream.Write(responseCode);
bitStream.Write(events[0]);
bitStream.Write(events[1]);
bitStream.Write(events[2]);
bitStream.Write(events[3]);
bitStream.Write(events[4]);
bitStream.Write(events[5]);
bitStream.Write(events[6]);
bitStream.Write(events[7]);
bitStream.Write(version_major);
bitStream.Write(version_current);
bitStream.Write(version_minor);
bitStream.Write(userKey);
bitStream.Write(worldServerIP);
bitStream.Write(chatServerIP);
bitStream.Write(worldServerPort);
bitStream.Write(chatServerPort);
bitStream.Write(cdnKey);
bitStream.Write(cdnTicket);
bitStream.Write(language);
bitStream.Write(localization);
bitStream.Write(static_cast<uint8_t>(justUpgradedFromF2P));
bitStream.Write(static_cast<uint8_t>(isF2P));
bitStream.Write(membershipTimeLeft);
bitStream.Write<uint16_t>(errorMessage.length());
bitStream.Write(LUWString(errorMessage, static_cast<uint32_t>(errorMessage.length())));
bitStream.Write<uint32_t>((sizeof(Stamp) * stamps.size()) + sizeof(uint32_t));
for (const auto& stampData : stamps) stampData.Serialize(bitStream);
};
}
ChatMessage ClientPackets::HandleChatMessage(Packet* packet) { ChatMessage ClientPackets::HandleChatMessage(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;

View File

@@ -8,6 +8,8 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include "BitStreamUtils.h"
#include "MessageType/Client.h"
class PositionUpdate; class PositionUpdate;
@@ -26,11 +28,132 @@ struct ChatModerationRequest {
std::string message; std::string message;
}; };
enum class eLoginResponse : uint8_t {
GENERAL_FAILED = 0,
SUCCESS,
BANNED,
// Unused 3
// Unused 4
PERMISSIONS_NOT_HIGH_ENOUGH = 5,
INVALID_USER,
ACCOUNT_LOCKED,
WRONG_PASS,
ACCOUNT_ACTIVATION_PENDING,
ACCOUNT_DISABLED,
GAME_TIME_EXPIRED,
FREE_TRIAL_ENDED,
PLAY_SCHEDULE_TIME_UP,
ACCOUNT_NOT_ACTIVATED
};
enum class eStamps : uint32_t {
PASSPORT_AUTH_START,
PASSPORT_AUTH_BYPASS,
PASSPORT_AUTH_ERROR,
PASSPORT_AUTH_DB_SELECT_START,
PASSPORT_AUTH_DB_SELECT_FINISH,
PASSPORT_AUTH_DB_INSERT_START,
PASSPORT_AUTH_DB_INSERT_FINISH,
PASSPORT_AUTH_LEGOINT_COMMUNICATION_START,
PASSPORT_AUTH_LEGOINT_RECEIVED,
PASSPORT_AUTH_LEGOINT_THREAD_SPAWN,
PASSPORT_AUTH_LEGOINT_WEBSERVICE_START,
PASSPORT_AUTH_LEGOINT_WEBSERVICE_FINISH,
PASSPORT_AUTH_LEGOINT_LEGOCLUB_START,
PASSPORT_AUTH_LEGOINT_LEGOCLUB_FINISH,
PASSPORT_AUTH_LEGOINT_THREAD_FINISH,
PASSPORT_AUTH_LEGOINT_REPLY,
PASSPORT_AUTH_LEGOINT_ERROR,
PASSPORT_AUTH_LEGOINT_COMMUNICATION_END,
PASSPORT_AUTH_LEGOINT_DISCONNECT,
PASSPORT_AUTH_WORLD_COMMUNICATION_START,
PASSPORT_AUTH_CLIENT_OS,
PASSPORT_AUTH_WORLD_PACKET_RECEIVED,
PASSPORT_AUTH_IM_COMMUNICATION_START,
PASSPORT_AUTH_IM_LOGIN_START,
PASSPORT_AUTH_IM_LOGIN_ALREADY_LOGGED_IN,
PASSPORT_AUTH_IM_OTHER_LOGIN_REMOVED,
PASSPORT_AUTH_IM_LOGIN_QUEUED,
PASSPORT_AUTH_IM_LOGIN_RESPONSE,
PASSPORT_AUTH_IM_COMMUNICATION_END,
PASSPORT_AUTH_WORLD_SESSION_CONFIRM_TO_AUTH,
PASSPORT_AUTH_WORLD_COMMUNICATION_FINISH,
PASSPORT_AUTH_WORLD_DISCONNECT,
NO_LEGO_INTERFACE,
DB_ERROR,
GM_REQUIRED,
NO_LEGO_WEBSERVICE_XML,
LEGO_WEBSERVICE_TIMEOUT,
LEGO_WEBSERVICE_ERROR,
NO_WORLD_SERVER
};
enum class Language : uint32_t {
en_US,
pl_US,
de_DE,
en_GB,
};
namespace ClientPackets { namespace ClientPackets {
// Structs
struct ClientLUBitStream : public LUBitStream {
MessageType::Client messageType = MessageType::Client::LOGIN_RESPONSE;
ClientLUBitStream() : LUBitStream(ServiceType::CLIENT) {};
ClientLUBitStream(MessageType::Client _messageType) : LUBitStream(ServiceType::CLIENT), messageType{_messageType} {};
virtual void Serialize(RakNet::BitStream& bitStream) const override;
virtual bool Deserialize(RakNet::BitStream& bitStream) override;
virtual void Handle() override {};
};
struct Stamp {
eStamps type;
uint32_t value;
uint64_t timestamp;
Stamp(eStamps type, uint32_t value, uint64_t timestamp = time(nullptr)) {
this->type = type;
this->value = value;
this->timestamp = timestamp;
}
void Serialize(RakNet::BitStream& bitStream) const;
};
struct LoginResponse : public ClientLUBitStream {
eLoginResponse responseCode = eLoginResponse::GENERAL_FAILED;
std::vector<LUString> events;
uint16_t version_major = 0;
uint16_t version_current = 0;
uint16_t version_minor = 0;
LUWString userKey;
LUString worldServerIP;
LUString chatServerIP = LUString(""); // unused
uint16_t worldServerPort = 0;
uint16_t chatServerPort = 0; // unused
LUString cdnKey = LUString("");
LUString cdnTicket = LUString("00000000-0000-0000-0000-000000000000", 37);
Language language = Language::en_US;
LUString localization = LUString("US", 3);
bool justUpgradedFromF2P = false; // written as uint8_t
bool isF2P = false; // written as uint8_t
uint64_t membershipTimeLeft = 0;
std::string errorMessage;
std::vector<Stamp> stamps;
LoginResponse() : ClientLUBitStream(MessageType::Client::LOGIN_RESPONSE) {}
void Serialize(RakNet::BitStream& bitStream) const override;
};
ChatMessage HandleChatMessage(Packet* packet); ChatMessage HandleChatMessage(Packet* packet);
PositionUpdate HandleClientPositionUpdate(Packet* packet); PositionUpdate HandleClientPositionUpdate(Packet* packet);
ChatModerationRequest HandleChatModerationRequest(Packet* packet); ChatModerationRequest HandleChatModerationRequest(Packet* packet);
int32_t SendTop5HelpIssues(Packet* packet); int32_t SendTop5HelpIssues(Packet* packet);
}; };
#endif // CLIENTPACKETS_H #endif // CLIENTPACKETS_H

100
dNet/CommonPackets.cpp Normal file
View File

@@ -0,0 +1,100 @@
#include "CommonPackets.h"
#include "dServer.h"
#include "Logger.h"
#include "Game.h"
#include "dServer.h"
#include "dConfig.h"
#include "StringifiedEnum.h"
#include "GeneralUtils.h"
namespace CommonPackets {
std::map<MessageType::Server, std::function<std::unique_ptr<LUBitStream>()>> g_Handlers = {
{MessageType::Server::VERSION_CONFIRM, []() {
return std::make_unique<VersionConfirm>();
}},
{MessageType::Server::DISCONNECT_NOTIFY, []() {
return std::make_unique<DisconnectNotify>();
}},
{MessageType::Server::GENERAL_NOTIFY, []() {
return std::make_unique<GeneralNotify>();
}}
};
// Struct Functions
void CommonLUBitStream::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(this->messageType);
bitStream.Write<uint8_t>(0); // padding
}
bool CommonLUBitStream::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(this->messageType));
uint8_t padding = 0;
VALIDATE_READ(bitStream.Read(padding));
return true;
}
void VersionConfirm::Serialize(RakNet::BitStream& bitStream) const {
CommonLUBitStream::Serialize(bitStream);
bitStream.Write<uint32_t>(netVersion);
bitStream.Write<uint32_t>(861228100);
bitStream.Write(static_cast<uint32_t>(serviceType));
bitStream.Write<uint64_t>(219818307120);
}
bool VersionConfirm::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(netVersion));
uint32_t unknown = 0;
VALIDATE_READ(bitStream.Read(unknown));
VALIDATE_READ(bitStream.Read(serviceType));
uint16_t unknown2 = 0;
VALIDATE_READ(bitStream.Read(unknown2));
VALIDATE_READ(bitStream.Read(processID));
VALIDATE_READ(bitStream.Read(port));
LUString unknownString;
VALIDATE_READ(bitStream.Read(unknownString));
return true;
}
void VersionConfirm::Handle() {
LOG_DEBUG("Client Data [Version: %i, Service: %s, Process: %u, Port: %u, Sysaddr Port: %u]", netVersion, StringifiedEnum::ToString(serviceType).data(), processID, port, sysAddr.port);
VersionConfirm response;
auto& serverNetVersionString = Game::config->GetValue("client_net_version");
const uint32_t serverNetVersion = GeneralUtils::TryParse<uint32_t>(serverNetVersionString).value_or(171022);
response.netVersion = serverNetVersion;
response.serviceType = Game::server->GetServerType();
response.Send(sysAddr);
}
void DisconnectNotify::Serialize(RakNet::BitStream& bitStream) const {
CommonLUBitStream::Serialize(bitStream);
bitStream.Write(disconnectID);
}
void GeneralNotify::Serialize(RakNet::BitStream& bitStream) const {
CommonLUBitStream::Serialize(bitStream);
bitStream.Write(notifyID);
bitStream.Write(notifyUser);
}
}
void CommonPackets::Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr) {
CommonLUBitStream lubitstream;
if (!lubitstream.Deserialize(inStream)) return;
auto it = g_Handlers.find(lubitstream.messageType);
if (it != g_Handlers.end()) {
auto request = it->second();
request->sysAddr = sysAddr;
if (!request->Deserialize(inStream)) {
LOG_DEBUG("Error Reading Common Packet: %s", StringifiedEnum::ToString(lubitstream.messageType).data());
return;
}
LOG_DEBUG("Received Common Packet: %s", StringifiedEnum::ToString(lubitstream.messageType).data());
request->Handle();
} else {
LOG_DEBUG("Unhandled Common Packet with ID: %i", lubitstream.messageType);
}
}

68
dNet/CommonPackets.h Normal file
View File

@@ -0,0 +1,68 @@
#include "dCommonVars.h"
#include "dNetCommon.h"
#include "BitStreamUtils.h"
#include "MessageType/Server.h"
enum class eServerDisconnectIdentifiers : uint32_t {
UNKNOWN_SERVER_ERROR = 0,
WRONG_GAME_VERSION,
WRONG_SERVER_VERSION,
CONNECTION_ON_INVALID_PORT,
DUPLICATE_LOGIN,
SERVER_SHUTDOWN,
SERVER_MAP_LOAD_FAILURE,
INVALID_SESSION_KEY,
ACCOUNT_NOT_IN_PENDING_LIST,
CHARACTER_NOT_FOUND,
CHARACTER_CORRUPTED,
KICK,
SAVE_FAILURE,
FREE_TRIAL_EXPIRED,
PLAY_SCHEDULE_TIME_DONE
};
// Packet Struct Functions
namespace CommonPackets {
// Structs
struct CommonLUBitStream : public LUBitStream {
MessageType::Server messageType = MessageType::Server::VERSION_CONFIRM;
CommonLUBitStream() : LUBitStream(ServiceType::COMMON) {};
CommonLUBitStream(MessageType::Server _messageType) : LUBitStream(ServiceType::COMMON), messageType{_messageType} {};
virtual void Serialize(RakNet::BitStream& bitStream) const override;
virtual bool Deserialize(RakNet::BitStream& bitStream) override;
virtual void Handle() override {};
};
struct VersionConfirm : public CommonLUBitStream {
uint32_t netVersion = 0;
ServiceType serviceType;
uint32_t processID = 0;
uint16_t port = 0;
VersionConfirm() : CommonLUBitStream(MessageType::Server::VERSION_CONFIRM) {}
void Serialize(RakNet::BitStream& bitStream) const override;
bool Deserialize(RakNet::BitStream& bitStream) override;
void Handle() override;
};
struct DisconnectNotify : public CommonLUBitStream {
eServerDisconnectIdentifiers disconnectID = eServerDisconnectIdentifiers::UNKNOWN_SERVER_ERROR;
DisconnectNotify() : CommonLUBitStream(MessageType::Server::DISCONNECT_NOTIFY) {}
void Serialize(RakNet::BitStream& bitStream) const override;
};
struct GeneralNotify : public CommonLUBitStream {
uint32_t notifyID = 0; // only one known value: 0, which is Duplicate account login
bool notifyUser = true;
GeneralNotify() : CommonLUBitStream(MessageType::Server::GENERAL_NOTIFY) {}
void Serialize(RakNet::BitStream& bitStream) const override;
};
// Non Struct functions
void Handle(RakNet::BitStream& inStream, const SystemAddress& sysAddr);
}

View File

@@ -12,6 +12,20 @@
#include <iostream> #include <iostream>
namespace WorldPackets {
// Struct Functions
void WorldLUBitStream::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(this->messageType);
bitStream.Write<uint8_t>(0); // padding
}
bool WorldLUBitStream::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(this->messageType));
uint8_t padding = 0;
VALIDATE_READ(bitStream.Read(padding));
return true;
}
}
void HTTPMonitorInfo::Serialize(RakNet::BitStream& bitStream) const { void HTTPMonitorInfo::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(port); bitStream.Write(port);
bitStream.Write<uint8_t>(openWeb); bitStream.Write<uint8_t>(openWeb);

View File

@@ -4,6 +4,7 @@
#include "dCommonVars.h" #include "dCommonVars.h"
#include <vector> #include <vector>
#include <string> #include <string>
#include "MessageType/World.h"
class User; class User;
struct SystemAddress; struct SystemAddress;
@@ -25,6 +26,16 @@ struct HTTPMonitorInfo {
}; };
namespace WorldPackets { namespace WorldPackets {
struct WorldLUBitStream : public LUBitStream {
MessageType::World messageType = MessageType::World::VALIDATION;
WorldLUBitStream() : LUBitStream(ServiceType::WORLD) {};
WorldLUBitStream(MessageType::World messageType) : LUBitStream(ServiceType::WORLD), messageType{messageType} {};
virtual void Serialize(RakNet::BitStream& bitStream) const override;
virtual bool Deserialize(RakNet::BitStream& bitStream) override;
virtual void Handle() override {};
};
void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone); void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone);
void SendCharacterCreationResponse(const SystemAddress& sysAddr, eCharacterCreationResponse response); void SendCharacterCreationResponse(const SystemAddress& sysAddr, eCharacterCreationResponse response);
void SendCharacterRenameResponse(const SystemAddress& sysAddr, eRenameResponse response); void SendCharacterRenameResponse(const SystemAddress& sysAddr, eRenameResponse response);

View File

@@ -197,12 +197,7 @@ void dServer::SendToMaster(RakNet::BitStream& bitStream) {
mMasterPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, mMasterSystemAddress, false); mMasterPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, mMasterSystemAddress, false);
} }
void dServer::Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID) { void dServer::Disconnect(const SystemAddress& sysAddr) {
RakNet::BitStream bitStream;
BitStreamUtils::WriteHeader(bitStream, ServiceType::COMMON, MessageType::Server::DISCONNECT_NOTIFY);
bitStream.Write(disconNotifyID);
mPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, sysAddr, false);
mPeer->CloseConnection(sysAddr, true); mPeer->CloseConnection(sysAddr, true);
} }

View File

@@ -43,7 +43,7 @@ public:
virtual void Send(RakNet::BitStream& bitStream, const SystemAddress& sysAddr, bool broadcast); virtual void Send(RakNet::BitStream& bitStream, const SystemAddress& sysAddr, bool broadcast);
void SendToMaster(RakNet::BitStream& bitStream); void SendToMaster(RakNet::BitStream& bitStream);
void Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID); void Disconnect(const SystemAddress& sysAddr);
bool IsConnected(const SystemAddress& sysAddr); bool IsConnected(const SystemAddress& sysAddr);
const std::string& GetIP() const { return mIP; } const std::string& GetIP() const { return mIP; }

View File

@@ -40,6 +40,7 @@
#include "dChatFilter.h" #include "dChatFilter.h"
#include "ClientPackets.h" #include "ClientPackets.h"
#include "CharacterComponent.h" #include "CharacterComponent.h"
#include "CommonPackets.h"
#include "EntityManager.h" #include "EntityManager.h"
#include "EntityInfo.h" #include "EntityInfo.h"
@@ -62,7 +63,6 @@
#include "eBlueprintSaveResponseType.h" #include "eBlueprintSaveResponseType.h"
#include "Amf3.h" #include "Amf3.h"
#include "NiPoint3.h" #include "NiPoint3.h"
#include "eServerDisconnectIdentifiers.h"
#include "eObjectBits.h" #include "eObjectBits.h"
#include "ServiceType.h" #include "ServiceType.h"
#include "MessageType/Server.h" #include "MessageType/Server.h"
@@ -78,7 +78,6 @@
#include "Server.h" #include "Server.h"
#include "PositionUpdate.h" #include "PositionUpdate.h"
#include "PlayerManager.h" #include "PlayerManager.h"
#include "eLoginResponse.h"
#include "MissionComponent.h" #include "MissionComponent.h"
#include "SlashCommandHandler.h" #include "SlashCommandHandler.h"
#include "InventoryComponent.h" #include "InventoryComponent.h"
@@ -703,7 +702,10 @@ void HandleMasterPacket(Packet* packet) {
//Verify it: //Verify it:
if (userHash != it->second.hash) { if (userHash != it->second.hash) {
LOG("SOMEONE IS TRYING TO HACK? SESSION KEY MISMATCH: ours: %s != master: %s", userHash.c_str(), it->second.hash.c_str()); LOG("SOMEONE IS TRYING TO HACK? SESSION KEY MISMATCH: ours: %s != master: %s", userHash.c_str(), it->second.hash.c_str());
Game::server->Disconnect(it->second.sysAddr, eServerDisconnectIdentifiers::INVALID_SESSION_KEY); CommonPackets::DisconnectNotify notification;
notification.disconnectID = eServerDisconnectIdentifiers::INVALID_SESSION_KEY;
notification.Send(it->second.sysAddr);
Game::server->Disconnect(it->second.sysAddr);
return; return;
} else { } else {
LOG("User %s authenticated with correct key.", username.GetAsString().c_str()); LOG("User %s authenticated with correct key.", username.GetAsString().c_str());
@@ -786,7 +788,10 @@ void HandleMasterPacket(Packet* packet) {
//Check the key: //Check the key:
if (sessionKey != std::atoi(user->GetSessionKey().c_str())) { if (sessionKey != std::atoi(user->GetSessionKey().c_str())) {
LOG("But the session key is invalid!", username.string.c_str()); LOG("But the session key is invalid!", username.string.c_str());
Game::server->Disconnect(user->GetSystemAddress(), eServerDisconnectIdentifiers::INVALID_SESSION_KEY); CommonPackets::DisconnectNotify notification;
notification.disconnectID = eServerDisconnectIdentifiers::INVALID_SESSION_KEY;
notification.Send(user->GetSystemAddress());
Game::server->Disconnect(user->GetSystemAddress());
return; return;
} }
break; break;
@@ -854,15 +859,15 @@ void HandlePacket(Packet* packet) {
LUBitStream luBitStream; LUBitStream luBitStream;
luBitStream.ReadHeader(inStream); luBitStream.ReadHeader(inStream);
if (luBitStream.connectionType == ServiceType::COMMON) { if (luBitStream.serviceType == ServiceType::COMMON) {
if (static_cast<MessageType::Server>(luBitStream.internalPacketID) == MessageType::Server::VERSION_CONFIRM) { CommonPackets::Handle(inStream, packet->systemAddress);
AuthPackets::HandleHandshake(Game::server, packet);
}
} }
if (luBitStream.connectionType != ServiceType::WORLD) return; if (luBitStream.serviceType != ServiceType::WORLD) return;
WorldPackets::WorldLUBitStream worldLUBitStream;
worldLUBitStream.Deserialize(inStream);
switch (static_cast<MessageType::World>(luBitStream.internalPacketID)) { switch (static_cast<MessageType::World>(worldLUBitStream.messageType)) {
case MessageType::World::VALIDATION: { case MessageType::World::VALIDATION: {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LUWString username; LUWString username;
@@ -879,7 +884,10 @@ void HandlePacket(Packet* packet) {
auto accountInfo = Database::Get()->GetAccountInfo(username.GetAsString()); auto accountInfo = Database::Get()->GetAccountInfo(username.GetAsString());
if (!accountInfo) { if (!accountInfo) {
LOG("Client's account does not exist in the database, aborting connection."); LOG("Client's account does not exist in the database, aborting connection.");
Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND); CommonPackets::DisconnectNotify notification;
notification.disconnectID = eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND;
notification.Send(packet->systemAddress);
Game::server->Disconnect(packet->systemAddress);
return; return;
} }
@@ -888,13 +896,13 @@ void HandlePacket(Packet* packet) {
if (accountInfo->maxGmLevel < eGameMasterLevel::DEVELOPER) { if (accountInfo->maxGmLevel < eGameMasterLevel::DEVELOPER) {
LOG("Client's database checksum does not match the server's, aborting connection."); LOG("Client's database checksum does not match the server's, aborting connection.");
std::vector<Stamp> stamps;
// Using the LoginResponse here since the UI is still in the login screen state // Using the LoginResponse here since the UI is still in the login screen state
// and we have a way to send a message about the client mismatch. // and we have a way to send a message about the client mismatch.
AuthPackets::SendLoginResponse( ClientPackets::LoginResponse response;
Game::server, packet->systemAddress, eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH, response.sysAddr = packet->systemAddress;
Game::config->GetValue("cdclient_mismatch_message"), "", 0, "", stamps); response.responseCode = eLoginResponse::PERMISSIONS_NOT_HIGH_ENOUGH;
response.errorMessage= Game::config->GetValue("cdclient_mismatch_message");
response.Send(packet->systemAddress);
return; return;
} else { } else {
AMFArrayValue args; AMFArrayValue args;
@@ -1207,7 +1215,10 @@ void HandlePacket(Packet* packet) {
} }
} else { } else {
LOG("Couldn't find character to log in with for user %s (%i)!", user->GetUsername().c_str(), user->GetAccountID()); LOG("Couldn't find character to log in with for user %s (%i)!", user->GetUsername().c_str(), user->GetAccountID());
Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND); CommonPackets::DisconnectNotify notification;
notification.disconnectID = eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND;
notification.Send(packet->systemAddress);
Game::server->Disconnect(packet->systemAddress);
} }
} else { } else {
LOG("Couldn't get user for level load complete!"); LOG("Couldn't get user for level load complete!");
@@ -1230,7 +1241,7 @@ void HandlePacket(Packet* packet) {
} }
case MessageType::World::MAIL: { case MessageType::World::MAIL: {
Mail::HandleMail(inStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity()); Mail::Handle(inStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity());
break; break;
} }
@@ -1386,7 +1397,11 @@ void HandlePacket(Packet* packet) {
if (user) { if (user) {
user->UserOutOfSync(); user->UserOutOfSync();
} else { } else {
Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::KICK); CommonPackets::DisconnectNotify notification;
notification.disconnectID = eServerDisconnectIdentifiers::KICK;
notification.Send(packet->systemAddress);
Game::server->Disconnect(packet->systemAddress);
} }
break; break;
} }
@@ -1463,8 +1478,10 @@ void WorldShutdownProcess(uint32_t zoneId) {
while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) { while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) {
const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0); const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0);
CommonPackets::DisconnectNotify notification;
Game::server->Disconnect(player, eServerDisconnectIdentifiers::SERVER_SHUTDOWN); notification.disconnectID = eServerDisconnectIdentifiers::SERVER_SHUTDOWN;
notification.Send(player);
Game::server->Disconnect(player);
} }
SendShutdownMessageToMaster(); SendShutdownMessageToMaster();
} }