mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
The login response's stamps were a fixed list: START and CLIENT_OS at the
start, an ERROR or two, and IM_LOGIN_START / WORLD_COMMUNICATION_FINISH
appended to every response whatever happened. Now a Stamps list (new
dNet/Stamps.{h,cpp}: eStamps, Stamp and Stamps with Serialize /
Deserialize in the login response's layout, so server messages can carry
it too) is created when the login request arrives, and each step adds its
own stamp, with the time, where it happens: the request read (value: the
client's OS), the account lookup (found or not), the password check,
failed checks, the closed server and play key checks, database writes,
asking master for a world, master's answer, handing the session key to
master, and sending the player on. The response serializes whatever was
stamped; the auth server logs the list like the client does.
What the client does with stamps (1.10.64): PacketHandler_MSG_CLIENT_
LOGIN_RESPONSE @ 00b32f90 reads them (LoginResponse::ReadStamps @ 005ed3c0,
count = (size - 4) / 16) and only logs each with its name from
StampLookup @ 017e6e88 (the 39 eStamps names) and its time relative to the
first and previous stamp. Documented in Stamps.h.
Behaviour change: on success, master gets the session key just before the
client gets the response instead of just after, so the handoff can be
stamped (and master knows the key before the client can reach a world).
The client-facing layout is unchanged; tests pin the stamp bytes, check
the steps of a failed login in order, and round trip the list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
183 lines
5.6 KiB
C++
183 lines
5.6 KiB
C++
/*
|
|
* Darkflame Universe
|
|
* Copyright 2018
|
|
*/
|
|
|
|
#include "ClientPackets.h"
|
|
#include "dCommonVars.h"
|
|
#include "PositionUpdate.h"
|
|
#include "eLoginResponse.h"
|
|
|
|
namespace ClientPackets {
|
|
void LoginResponse::Serialize(RakNet::BitStream& bitStream) const {
|
|
bitStream.Write(responseCode);
|
|
for (const auto& event : events) bitStream.Write(event);
|
|
bitStream.Write(versionMajor);
|
|
bitStream.Write(versionCurrent);
|
|
bitStream.Write(versionMinor);
|
|
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<uint8_t>(justUpgradedFromF2P);
|
|
bitStream.Write<uint8_t>(isFreeToPlay);
|
|
bitStream.Write(freeToPlayTimeRemaining);
|
|
bitStream.Write<uint16_t>(errorMessage.length());
|
|
bitStream.Write(LUWString(errorMessage, static_cast<uint32_t>(errorMessage.length())));
|
|
stamps.Serialize(bitStream);
|
|
}
|
|
|
|
bool LoginResponse::Deserialize(RakNet::BitStream& bitStream) {
|
|
VALIDATE_READ(bitStream.Read(responseCode));
|
|
for (auto& event : events) VALIDATE_READ(bitStream.Read(event));
|
|
VALIDATE_READ(bitStream.Read(versionMajor));
|
|
VALIDATE_READ(bitStream.Read(versionCurrent));
|
|
VALIDATE_READ(bitStream.Read(versionMinor));
|
|
VALIDATE_READ(bitStream.Read(userKey));
|
|
VALIDATE_READ(bitStream.Read(worldServerIP));
|
|
VALIDATE_READ(bitStream.Read(chatServerIP));
|
|
VALIDATE_READ(bitStream.Read(worldServerPort));
|
|
VALIDATE_READ(bitStream.Read(chatServerPort));
|
|
VALIDATE_READ(bitStream.Read(cdnKey));
|
|
VALIDATE_READ(bitStream.Read(cdnTicket));
|
|
VALIDATE_READ(bitStream.Read(language));
|
|
VALIDATE_READ(bitStream.Read(localization));
|
|
uint8_t flag{};
|
|
VALIDATE_READ(bitStream.Read(flag));
|
|
justUpgradedFromF2P = flag != 0;
|
|
VALIDATE_READ(bitStream.Read(flag));
|
|
isFreeToPlay = flag != 0;
|
|
VALIDATE_READ(bitStream.Read(freeToPlayTimeRemaining));
|
|
uint16_t errorLength{};
|
|
VALIDATE_READ(bitStream.Read(errorLength));
|
|
LUWString error(errorLength);
|
|
if (errorLength > 0) VALIDATE_READ(bitStream.Read(error)); // RakNet fails reads of 0 bits
|
|
errorMessage = error.GetAsString();
|
|
VALIDATE_READ(stamps.Deserialize(bitStream));
|
|
return true;
|
|
}
|
|
}
|
|
|
|
ChatMessage ClientPackets::HandleChatMessage(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
|
|
ChatMessage message;
|
|
int32_t messageLength{};
|
|
|
|
inStream.Read(message.chatChannel);
|
|
inStream.Read(message.unknown);
|
|
inStream.Read(messageLength);
|
|
|
|
if (messageLength > MAX_MESSAGE_LENGTH || messageLength < 0) return message;
|
|
|
|
for (int32_t i = 0; i < (messageLength - 1); ++i) {
|
|
char16_t character;
|
|
inStream.Read(character);
|
|
message.message.push_back(character);
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
PositionUpdate ClientPackets::HandleClientPositionUpdate(Packet* packet) {
|
|
PositionUpdate update;
|
|
CINSTREAM_SKIP_HEADER;
|
|
|
|
inStream.Read(update.position.x);
|
|
inStream.Read(update.position.y);
|
|
inStream.Read(update.position.z);
|
|
|
|
inStream.Read(update.rotation.x);
|
|
inStream.Read(update.rotation.y);
|
|
inStream.Read(update.rotation.z);
|
|
inStream.Read(update.rotation.w);
|
|
|
|
inStream.Read(update.onGround);
|
|
inStream.Read(update.onRail);
|
|
|
|
bool velocityFlag = false;
|
|
inStream.Read(velocityFlag);
|
|
if (velocityFlag) {
|
|
inStream.Read(update.velocity.x);
|
|
inStream.Read(update.velocity.y);
|
|
inStream.Read(update.velocity.z);
|
|
}
|
|
|
|
bool angVelocityFlag = false;
|
|
inStream.Read(angVelocityFlag);
|
|
if (angVelocityFlag) {
|
|
inStream.Read(update.angularVelocity.x);
|
|
inStream.Read(update.angularVelocity.y);
|
|
inStream.Read(update.angularVelocity.z);
|
|
}
|
|
|
|
// TODO figure out how to use these. Ignoring for now, but reading in if they exist.
|
|
bool hasLocalSpaceInfo{};
|
|
if (inStream.Read(hasLocalSpaceInfo) && hasLocalSpaceInfo) {
|
|
inStream.Read(update.localSpaceInfo.objectId);
|
|
inStream.Read(update.localSpaceInfo.position.x);
|
|
inStream.Read(update.localSpaceInfo.position.y);
|
|
inStream.Read(update.localSpaceInfo.position.z);
|
|
bool hasLinearVelocity = false;
|
|
if (inStream.Read(hasLinearVelocity) && hasLinearVelocity) {
|
|
inStream.Read(update.localSpaceInfo.linearVelocity.x);
|
|
inStream.Read(update.localSpaceInfo.linearVelocity.y);
|
|
inStream.Read(update.localSpaceInfo.linearVelocity.z);
|
|
}
|
|
}
|
|
|
|
bool hasRemoteInputInfo{};
|
|
if (inStream.Read(hasRemoteInputInfo) && hasRemoteInputInfo) {
|
|
inStream.Read(update.remoteInputInfo.m_RemoteInputX);
|
|
inStream.Read(update.remoteInputInfo.m_RemoteInputY);
|
|
inStream.Read(update.remoteInputInfo.m_IsPowersliding);
|
|
inStream.Read(update.remoteInputInfo.m_IsModified);
|
|
}
|
|
|
|
return update;
|
|
}
|
|
|
|
ChatModerationRequest ClientPackets::HandleChatModerationRequest(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
|
|
ChatModerationRequest request;
|
|
|
|
inStream.Read(request.chatLevel);
|
|
inStream.Read(request.requestID);
|
|
|
|
for (uint32_t i = 0; i < 42; ++i) {
|
|
uint16_t character;
|
|
inStream.Read(character);
|
|
request.receiver.push_back(static_cast<uint8_t>(character));
|
|
}
|
|
|
|
if (!request.receiver.empty()) {
|
|
if (std::string(request.receiver.c_str(), 4) == "[GM]") { // Shift the string forward if we are speaking to a GM as the client appends "[GM]" if they are
|
|
request.receiver = std::string(request.receiver.c_str() + 4, request.receiver.size() - 4);
|
|
}
|
|
}
|
|
|
|
uint16_t messageLength;
|
|
inStream.Read(messageLength);
|
|
if (messageLength > MAX_MESSAGE_LENGTH) return request;
|
|
for (uint32_t i = 0; i < messageLength; ++i) {
|
|
uint16_t character;
|
|
inStream.Read(character);
|
|
request.message.push_back(static_cast<uint8_t>(character));
|
|
}
|
|
|
|
return request;
|
|
}
|
|
|
|
int32_t ClientPackets::SendTop5HelpIssues(Packet* packet) {
|
|
CINSTREAM_SKIP_HEADER;
|
|
int32_t language = 0;
|
|
inStream.Read(language);
|
|
return language;
|
|
}
|