Files
DarkflameServer/dNet/Stamps.h
Aaron Kimbrell efa08ac1d0 feat(master): login stamps travel through master and back
The login's Stamps now go with auth's REQUEST_ZONE_TRANSFER to master and
come back in REQUEST_ZONE_TRANSFER_RESPONSE, so master stamps the steps it
performs itself, with its own time: got the request
(WORLD_PACKET_RECEIVED, zone), the world is still starting and the request
waits (IM_LOGIN_QUEUED, instance), answered with a world
(WORLD_SESSION_CONFIRM_TO_AUTH, instance). Auth sends what comes back in
the login response.

Server to server wire change (message IDs unchanged): both messages end
with a Stamps list (u32 16 * count + 4, then the stamps); it is empty
(4 bytes) when a world server asks for a transfer. Touched:
- MasterPackets::SendZoneTransferRequest / SendZoneTransferResponse: take
  and write the stamps (default empty)
- MasterServer.cpp REQUEST_ZONE_TRANSFER: reads them, stamps, keeps them
  in the PendingInstanceRequest (new stamps member, InstanceManager.h)
- InstanceManager::ReadyInstance / AffirmTransfer: stamp and send them back
- ZoneInstanceManager: HandleRequestZoneTransferResponse reads them; a
  RequestZoneTransfer overload takes stamps and a callback that gets them
- AuthPackets LoginRequest::Handle uses that overload

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:48 -05:00

130 lines
5.6 KiB
C++

#ifndef STAMPS_H
#define STAMPS_H
#include "BitStream.h"
#include <cstdint>
#include <ctime>
#include <string>
#include <vector>
/**
* Login stamps: a trace of the steps the auth server went through for one login, sent at the end of the login
* response (ClientPackets::LoginResponse::stamps).
*
* On the wire: a u32 holding 16 * count + 4, then count stamps of { u32 type, u32 value, u64 timestamp }.
*
* What the 1.10.64 client does with them (PacketHandler_MSG_CLIENT_LOGIN_RESPONSE @ 00b32f90, which reads them
* through LoginResponse::ReadVariableData @ 005ed4f0 and LoginResponse::ReadStamps @ 005ed3c0): count is
* (size - 4) / 16, and it only logs each one, "Stamp %s(%d) at %I64d (start+%d, last+%d)", with the type's name
* from StampLookup @ 017e6e88 and the timestamp relative to the first and to the previous stamp. Nothing else
* reads them, so no type is required and the order is free. The type must be one of the values below (the name
* table has exactly these 39 entries; a larger value reads past it).
*
* Live servers stamped real steps with unix timestamps in seconds: START, the LEGOINT_* steps (the LEGO account
* web service, which checked the password), DB_INSERT_*, CLIENT_OS, then the WORLD_* / IM_* steps of handing the
* session to the instance manager and picking a world server, ending with WORLD_COMMUNICATION_FINISH. The values
* were step results (1 for done) or ids (such as the server the step talked to).
*
* What DLU stamps (AuthPackets::LoginStamps; every step adds its stamp as it happens):
* START (0) the login request arrived
* CLIENT_OS (the ClientOS) the request was read
* DB_SELECT_START / _FINISH looking up the account (FINISH value: 1 found, 0 not)
* LEGOINT_WEBSERVICE_START / _FINISH checking the password (live asked the LEGO web service; DLU checks it
* itself; FINISH value: 1 matches, 0 not)
* ERROR (1) a check failed: unknown user, wrong password, play key, banned, locked
* GM_REQUIRED (1) the server is closed to non developers
* BYPASS (1) no play key needed (keys off, or a GM account)
* DB_INSERT_START / _FINISH writing to the database (lifting an expired ban, recording the address)
* WORLD_DISCONNECT (1) no master server to ask for a world
* WORLD_COMMUNICATION_START (0) auth asked master for a world server (the stamps go along)
* WORLD_PACKET_RECEIVED (zone) master: got the request
* IM_LOGIN_QUEUED (instance) master: the world is still starting, the request waits for it
* WORLD_SESSION_CONFIRM_TO_AUTH (instance) master: answered auth with the world (the stamps come back)
* IM_COMMUNICATION_START / IM_LOGIN_START / IM_COMMUNICATION_END (1) auth gave the session key to master
* WORLD_COMMUNICATION_FINISH (world port) auth sends the player to the world
* The auth server logs the same lines as the client (debug log) when it sends the response.
*/
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() = default;
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) const;
bool Deserialize(RakNet::BitStream& inBitStream);
};
// The stamps of one login. Each step adds its stamp when it happens, on whichever server performs it: the list
// travels with the login from auth to master and back inside the server messages (REQUEST_ZONE_TRANSFER and
// REQUEST_ZONE_TRANSFER_RESPONSE end with it; empty when a world asks), and the login response finally carries it
// to the client.
// Written as a u32 holding 16 * count + 4, then the stamps (the login response's layout).
struct Stamps {
std::vector<Stamp> list{};
Stamps() = default;
explicit Stamps(std::vector<Stamp> stamps) : list(std::move(stamps)) {}
// Stamps a step that just happened, with the current time
void Add(eStamps type, uint32_t value = 0);
bool empty() const { return list.empty(); }
size_t size() const { return list.size(); }
void Serialize(RakNet::BitStream& bitStream) const;
bool Deserialize(RakNet::BitStream& bitStream);
// Logs each stamp (debug log) the way the client does
void Log(const std::string& context) const;
};
#endif // STAMPS_H