Commit Graph

12 Commits

Author SHA1 Message Date
Aaron Kimbrell
951edfdde2 fix(master): a server list's outdated flags are read all or none
A list cut short inside the flags was read as if complete; an older master's list, which has none, still
reads. The test checks every cut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:32:35 -05:00
Aaron Kimbrell
ebe77ee45c test(master): fix server list flag test compile
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:41:48 -05:00
Aaron Kimbrell
a919a57e5e test(master): server list outdated flags
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:35:45 -05:00
Aaron Kimbrell
ab395a1af9 feat(net): WORLD_FILES, WORLD_RELOAD and WORLD_FILES_STATUS master messages
Appended at the end of MessageType::Master (47-49); the pin test is
updated. A world sends its zone file list to master once it is ready.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:51:21 -05:00
Aaron Kimbrell
a93f5f810b feat(master): the server list names each server's port and machine
Master keeps the address and port auth, chat, the dashboard and the UGC
server report when they connect and sends them, with its own and every
world's, after the list's world states. A server's machine is the address
master sees its connection come from; loopback and master's external_ip are
master's machine. Servers can report another port than their RakNet one; the
UGC server reports its web port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:24 -05:00
Aaron Kimbrell
b05b84ff30 feat(net): CDCLIENT_RELOAD master message
Appended at the end of MessageType::Master (46); the pin test is updated.
With names it tells a server which fdb copy and CDServer.sqlite to switch
to; without them it asks master to check the client's fdb now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:20:20 -05:00
Aaron Kimbrell
79d69bf4ac fix(master): a rocket launch preps the clone the player is going to
Launching to a property started an extra clone 0 instance of the zone besides the property's own, because
the prep only carried the zone. PrepZone now carries the clone when there is one (written only then, so a
plain prep is unchanged).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 23:11:20 -05:00
Aaron Kimbrell
9d76fe9550 feat(ugc): placed models from the UGC server without 3D services
A placed model's client (1.10.64, UGCUSE3DSERVICES=7:0) always loads its
blueprint's NIF and HKX (its BlueprintComponent sets renderUserGen and
physicsUserGen itself) and its LXFML, asks the world for each file's
manifest first and waits for the answer with no timeout.

With ugc_manifest=1 and the new ugc_manifest_models=1 (default 0) the world:
- leaves the models whose mesh the UGC server made out of the LXFML it
  sends when a property loads,
- answers their NIF with the UGC server's checksum, their LXFML with the
  stored LXFML's (worked out once and kept) and their HKX as not known,
- sends a model that isn't made its LXFML (once for the three requests),
  so the client builds it itself and no model is left waiting.

When the UGC server writes a model's mesh with a new checksum it sends
UGC_MODELS_MADE (a new master message, appended) to the master, which
passes it to every world; a world with that model placed sends its
players the new NIF checksum and NotifyClientUGCModelReady (game message
909, the blueprint id), so clients switch to the served mesh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:15 -05:00
Aaron Kimbrell
dce2037d9d feat: worlds starting up on the dashboard; the prestarted worlds are a setting
The dashboard shows worlds master has launched but that aren't connected
yet (Starting) and those shutting down, on the main page's world list
and in /api/worlds (state: starting|stopping), without a shutdown
button. Master's server list now carries each world's state (appended
after the UGC fields, one byte per world) and master pushes the list to
the dashboard whenever a world is launched, becomes ready, is told to
shut down or goes away, instead of the dashboard only seeing it on its
30 second poll. Starting worlds are kept apart from the running ones,
so counts, events and shutdown requests still only see running worlds.

prestart_worlds (masterconfig.ini, zone ids) lists the worlds master
starts when prestart_servers is on, instead of the hardcoded character
select (0) and Venture Explorer (1000), which stay the default when it
is missing or empty. It is on the Settings page as a zone list (restart
only), shown when prestart_servers is on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:14 -05:00
Aaron Kimbrell
69803448bb feat(master): report the UGC server in the server list and wait for it on shutdown
The server list now carries whether master starts the UGC server, whether it
is connected and the pid it was started as. Settings reloads reach it like
auth and chat, and shutdown waits for it. The UGC server sends its totals and
storage with its traffic reports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:31:05 -05:00
Aaron Kimbrell
542f0a89f0 refactor: remove the packet macros, WriteHeader and PacketUtils
Nothing in the server writes or reads a packet by hand any more, so the
helpers for doing so go:
- CBITSTREAM, CMSGHEADER, CINSTREAM, CINSTREAM_SKIP_HEADER, SEND_PACKET,
  SEND_PACKET_BROADCAST and HEADER_SIZE leave dCommonVars.h;
- the free BitStreamUtils::WriteHeader (LUBitStream::WriteHeader writes the
  same bytes) and the unused PacketUtils::SavePacket are deleted.
The last raw reads are replaced: WorldServer builds its input stream
directly, the master packet logs read the header with
LUBitStream::ReadHeader instead of peeking at packet->data[1] and [3], and
MessageInspector reads a sent game message's header with the new
NetGameMsg::ReadPacketHeader (the counterpart of WritePacket) instead of
memcmp/memcpy. packet->data[0] is still compared with RakNet's own
connection IDs.

The frozen oracles keep using the macros verbatim through the test-only
tests/dGameTests/LegacyPacketMacros.h; the HeaderSkip tests, which only
tested CINSTREAM_SKIP_HEADER, are removed.

docs/PacketArchitecture.md: "where we are" now describes the final state
and what still touches raw bytes (RakNet IDs, replica headers, behavior bit
streams), and a new section collects the known wire discrepancies found
during the conversion, with client addresses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 22:30:56 -05:00
Aaron Kimbrell
5a9a3e380b refactor: master packets as structs
Every MASTER service packet is now an LUBitStream struct (docs/PacketArchitecture.md,
PR 14) and the master server's switch is a dispatch map (PacketDispatcher), as are the
master handlers of the world, chat and dashboard servers.

- dNet/MasterPackets.h: RequestZoneTransfer, RequestZoneTransferResponse, ServerInfo,
  RequestSessionKey, SetSessionKey, SessionKeyResponse, NewSessionAlert, PlayerAdded /
  PlayerRemoved, CreatePrivateZone, RequestPrivateZone (passwords still cut to 50
  characters when read), WorldReady, WorldReadyInfo (WORLD_READY to the dashboard),
  PrepZone, Shutdown, ShutdownResponse, WorldShutDown (SHUTDOWN_RESPONSE to the
  dashboard), ShutdownUniverse, AffirmTransferRequest/Response, RequestServerList,
  ServerListResponse, DashboardShutdown, ConfigReload, InstanceShutdown. The Send*
  functions are gone; MasterPackets::SendToMaster(msg) and SendTo(sysAddr, msg) send a
  struct.
- The dashboard and instance migration structs (PlayerAction, DataChanged, Dashboard
  messages, MessageCapture, InstanceMigration) are LUBitStreams of the MASTER service now
  and moved to dNet/master/, included by MasterPackets.h. Their payloads are unchanged;
  master forwards them by re-serializing the struct instead of copying raw bytes.
- InstanceManager, ZoneInstanceManager, MigrationCoordinator, dServer (server info, zone
  transfer response), auth (SET_SESSION_KEY), the world (session keys, player added and
  removed, world ready, shutdown response, affirmations, prep zone, shutdown universe) and
  the dashboard (server list, instance shutdown, config reload, announcements, player
  actions, message capture) send and read structs.
- The login stamps are a `stamps` field of RequestZoneTransfer and
  RequestZoneTransferResponse (read leniently as before: a message without them reads as
  empty); master adds its stamps in the REQUEST_ZONE_TRANSFER handler and when it answers,
  as it did.
- InstanceManager::GetInstanceBySysAddr takes a const address.

Verified: tests/dGameTests/dNetTests/Legacy/MasterPacketsLegacy.h is a verbatim copy of
the old writers and readers; MasterPacketsTests requires identical bytes for a grid of
inputs, checks the old readers read what the structs write, round trips and truncation,
hand written golden packets, that zone transfers without stamps still read, that the dashboard/migration structs write what
"header + Serialize" wrote, and that the dispatcher drops truncated packets. No wire
bytes changed.

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