The guild packets of the 1.10.64 client (docs/Guilds.md) as Serialize/Deserialize structs, laid out the way the client's
packet handlers read them: GUILD_CREATE_RESPONSE, GUILD_INVITE, GUILD_INVITE_INITIAL_RESPONSE, _FINAL_RESPONSE,
_CONFIRM, GUILD_ADD_PLAYER, GUILD_REMOVE_PLAYER, GUILD_LOGIN_LOGOUT and GUILD_DATA (ClientPackets), the world packet
TMP_GUILD_CREATE the create box sends, the chat packets the client sends through its world (GUILD_INVITE,
GUILD_INVITE_RESPONSE, GUILD_LEAVE, GUILD_GET_ALL), DLU's world <-> chat packets (GUILD_CREATE, GUILD_KICK,
GUILD_GET_STATUS as the chat server's guild update to a world, and GUILD_SET_RANK and GUILD_DISBAND appended to
MessageType::Chat after CREATE_TEAM) and the game message DisplayGuildCreateBox (626). Fixed-size names always keep a
NUL, since the client reads them as C strings. Enums eGuildCreateResponse, eGuildInviteResponse,
eGuildInviteFinalResponse, eGuildRank and eGuildLeaveReason. Nothing sends them yet.
Check: GuildPacketsTests compares every packet with the bytes at the client's offsets. Nothing to check in game.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
World packet 120 (UgcDownloadFailed: resType u32, blueprint ID, status
u32, character ID; lu_packets, 31 bytes after the 0x53 as the client
sends it) was logged as an unknown world packet. The client sends it
from LWOResMgr2Interface::FinishResourceRequest (0x0105e5c0) for every
blueprint file (player model, car or rocket build) whose request did not
end with HTTP 200, including files it did not download at all (status
0). Live: 1525 packets, 1520 with status 0 (all four file types, around
load and FetchModelMetadataRequest), 5 with 404. Live sent nothing back
and the sessions carried on.
The logout the client does on failed UGC downloads
(NET_DISCONNECT_FAILED_DOWNLOAD_UGC, MainThread_LogoutDueToConnectionFailures
0x0102b9c0) is its own decision after repeated connection failures to the
UGC HTTP server; there is no server message that prevents or triggers it.
So the server only records it: a log line for an HTTP failure (for
finding missing files on the UGC server), a debug line for status 0.
MessageType::World gains UGC_DOWNLOAD_FAILED = 120 (appended; the magic
enum range goes to 120).
Check in game: nothing changes for the player. With a property that has
models, load it: the world server log has no "Unknown world packet 120"
lines; if a model file is missing on the UGC server there is one "failed
to download blueprint" line naming it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With UGCUSE3DSERVICES=7:0 (the client's default) the client asks its world for
a blueprint file's MD5 and size (REQUEST_UGC_MANIFEST_INFO, world 27) and then
downloads BrickModels/UserMade/<id % 1000>/<id>.<ext>.sd0. Layouts checked in
the 1.10.64 client: the request is a u64 blueprint id and a u8 resource type;
the answer (UGC_MANIFEST_RESPONSE, client 60) repeats them and adds a u8 valid,
the u32 size and the 16 byte MD5 of the inflated file, 37 bytes after the 0x53
exactly or the client drops it.
- dNet: WorldPackets::RequestUgcManifestInfo, ClientPackets::UgcManifestResponse
(eUgcResourceType), with byte tests against the client's layouts.
- Database: ugc_file_checksums (per model or module combination and file) and
ugc_modular_build.combination_id (migrations 89 / 72), GetUgcFileChecksum
looks a blueprint up as a model, else as a build through its combination.
- UGC server: every download is also written as .sd0 (Sd0::Compress); workers
hand the checksums back and the main thread stores them; old items get their
sd0 icon and checksum, and builds their combination id, once at start-up, a
few per tick; serves <dir>/BrickModels/UserMade/<bucket>/<id>.<ext>.sd0 under
client_path, /<folder>/UserBrickModels and the root (.hkx 404).
- World: UgcManifest answers on the main thread with one indexed query per
request; files not made yet are answered when they are (looked at again
every 5 seconds), and a model in its quiet period is made right away. No
worker threads, HTTP or file reads in the world.
Off by default (ugc_manifest=0): checked in game, the client then downloads
from http://127.0.0.1:80/lwoclient/UserBrickModels/ whatever its boot.cfg says
and logs the player out when it can't connect, so icons need the UGC server on
port 80 of each player's machine. docs/UgcServer.md has the details.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WorldPackets now holds what a client sends a world server, one struct per
packet with Serialize/Deserialize: Validation, CharacterListRequest,
CharacterCreateRequest, CharacterLoginRequest, GameMessage,
CharacterDeleteRequest, CharacterRenameRequest, LevelLoadComplete,
PositionUpdate, MailPacket, RoutePacket, StringCheck, GeneralChatMessage,
HandleFunness, UIHelpTop5. WorldServer's switch became a dispatch map of
handlers (each overrides Handle in WorldServer.cpp, logic unchanged:
dashboard hooks, LoadPlayer, chat logging, migration checks, message
inspector capture all still run); a packet that does not deserialize is
logged and dropped. UserManager's create/delete/rename take the structs.
The answers are ClientPackets (the CLIENT service): LoadStaticZone,
CharacterListResponse, CharacterCreateResponse, CharacterRenameResponse,
DeleteCharacterResponse, TransferToWorld, ServerStates, CreateCharacter,
ChatModerationString, MakeGMResponse, HTTPMonitorInfoResponse and
DebugOutput, built at the call sites (world server, UserManager, slash
commands, dashboard actions, components, migration). The world -> chat
forward of a routed packet is ChatPackets::RoutedFromClient. All
WorldPackets::Send* functions, HTTPMonitorInfo and the ClientPackets parse
functions are gone. The architecture doc now states the file rule: a
packet lives in the file of the ServiceType in its header.
No wire change. Verified against frozen verbatim copies of the old code
(tests/dGameTests/dNetTests/Legacy/WorldPacketsLegacy.h): every response
is sent through the old function and the struct over grids of inputs
(all enum values, strings of every length class, IDs, >64 moderation
segments, big XML) and must match byte for byte; every request is read
by the old code and the struct and must give the same values; plus
golden bytes, round trips, truncation checks and a field width mutation
that made the tests fail. Only differences: malformed requests are
dropped instead of handled with partial values, and LevelLoadComplete now
reads the zone ID the client sends after it (lu_packets and captures show
the 1.10.64 client always sends it; DLU ignored it).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Break out changes into a smaller subset
* NL@EOF
* fix windows bs
add player ws updates
add websocket docs
* tested everything to make sure it works
* Address Feedback
* 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
* Breakout rest of the enums from dcommonvars
so we don't have to deal with merge conflicts
ePlayerFlags is not a scoped enum, yet, due to it's complexity
* address feedback
* make player flag types consistent
* fix typo
* breakout gmlevel enum and make it a class
tested that things still work
slash command,
chat restrictions,
packets and serializations
* fix GM level for some slash commands
* fix new use of this enum