Commit Graph

2547 Commits

Author SHA1 Message Date
Aaron Kimbrell
056aad5568 feat(dashboard): the models placed on a property now, for World 3D replays
/api/world3d/property_models?zone=&clone= lists the saved property's models
(LOT, name, UGC ID, position, rotation), for replays of recorded positions,
which don't record models.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:52:35 -05:00
Aaron Kimbrell
575b58f475 feat(dashboard): a packet capture's properties route
/api/inspector/sessions/:id/property serves CaptureProperty's worlds, built
once per loaded capture on a worker after the replica pass, with the zone's
and the models' names from the locale and the property saved now for each
zone and clone (read on the main thread) for links and UGC meshes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:52:35 -05:00
Aaron Kimbrell
045999a252 feat(capture): a property's models, data and events from a capture
CaptureProperty::Build reads, per world of a capture, the property it was:
each model (constructed with a model component, or a brick built model) with
its LOT, object, spawner, blueprint and behavior count and where it stood per
time span, from its constructions, serializations and destruction; the
DownloadPropertyData of that map and the GetModelsOnProperty counts; and the
events: placed (a PlaceModelResponse with the model made at that position,
before or after it), moved, removed (with the DeleteModelFromClient reason),
editing, and behavior messages.

CaptureTool property <bundle> --cdserver prints it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:40:09 -05:00
Aaron Kimbrell
e043a8f6b5 fix(capture): read compressed configs and placed models in replica packets
A compressed construction config is a u32 uncompressed size, a u32 compressed
size and the zlib bytes: the reader took the first size for the second and lost
its place, so live model constructions never read. It now inflates and reads
the entries.

A model's item component isn't made (Entity::Initialize): its model component
writes the item info. The layout left the registry's item component in, so a
premade model's components read one block twice and didn't match. Live writes
the same bits from its item component, so both now read exactly.

Tested with a live placed model's construction and the server's own model.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:40:03 -05:00
Aaron Kimbrell
3c8b7c2807 Merge exp/dcf-hash: portable chat filter hash, blocklist from text, blocked phrases 2026-09-30 08:06:05 -05:00
Aaron Kimbrell
d94d84b5cb feat(dashboard): browse every client system info report, per account and across accounts
The account page lists the account's reports as a table and the Client System Info page lists every report (or each account's newest), sortable and searchable by account name or video card; a row opens every field. Values that say little about the real system are marked, and every caveat is a tooltip on the value and column.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:06:02 -05:00
Aaron Kimbrell
9658014b4f docs(chat-filter): block list file, portable format, phrases
How to build blocklist.dcf from blocklist.txt and where it goes, the
version 3 layout and hash, what happens to old files, and blocked
phrases; README "This branch" line. issue 215

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:05:26 -05:00
Aaron Kimbrell
cef170ae47 feat(dashboard): chat filter page shows phrases and the block list's state
Blocked entries marked Phrase, no Allow for a phrase, phrase matches named
in the message test, and the Word files section says when blocklist.dcf
is in the old format and how to rebuild it from blocklist.txt. issue 215

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:05:18 -05:00
Aaron Kimbrell
b279d187ca fix(chat-filter): shipped blocklist.dcf in the portable format
The shipped list's hashes are 64-bit FNV-1a (checked against a sample of
its words), so it is written again as version 3: same hashes, duplicates
dropped, sorted. Nothing else changes; it can be replaced by building
from blocklist.txt. issue 215

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:05:18 -05:00
Aaron Kimbrell
c1bcda8dd1 fix(chat-filter): portable .dcf hashing, block list phrases
The filter stored and compared words by std::hash<std::string> in size_t,
which differs between standard libraries and platforms, so a .dcf made on
one system never matched on another and the block list never worked
there (issue 215).

- ChatFilterCore.h: 64-bit FNV-1a over the entry's bytes, ASCII lower
  case, fixed-width uint64_t everywhere stored or compared.
- .dcf version 3: little-endian magic, version, longest entry in words,
  uint64 count and sorted uint64 hashes. Version 2 files are refused:
  the allowed words cache is rebuilt from its .txt, an old
  blocklist.dcf is logged as unreadable.
- The servers build blocklist.dcf from a plain blocklist.txt next to
  them (one word or phrase per line) when it is newer.
- Blocked entries can be phrases: runs of consecutive words up to the
  longest entry, the whole run marked. Whitelist chat still checks one
  word at a time, as the client does.
- Dashboard: the chat filter API reads blocklist.dcf the same way
  (status, phrase length), accepts blocked phrases, refuses allowed
  ones, and explains phrase matches in its message test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:05:13 -05:00
Aaron Kimbrell
bd13297947 fix(dashboard): capture worlds route holds the cached capture by shared pointer
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 08:01:44 -05:00
Aaron Kimbrell
b7f8e2ba5d doc: README covers item source keys, pet walls and carver-only objects
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:50:05 -05:00
Aaron Kimbrell
1d2269257d Merge exp/loot-blocker-followups: item source keys, quickbuild cost source, pet blockers, carver_only walls 2026-09-30 07:49:50 -05:00
Aaron Kimbrell
f6659d35f9 test(ai): pets at pet blockers, carver_only walls and hedge sizes
A pet chasing across a "PR - Pet Blocker" stops in front of it; a
carver_only navmesh carver added without an object stops an enemy and goes
away with the physics world; carver_only alone blocks nothing; a Robot City
hedge's blocker has the size and offset of its collision shape.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:49:19 -05:00
Aaron Kimbrell
da9ae3b3c4 feat(zone): don't spawn carver_only objects, keep them as walls
The client never loads a level object whose config has carver_only set (its
resource manager skips the load; LWOBasePhysComponent::LoadConfigData
0x00c495c9 reads the flag next to navmesh_carver), and live never sent one:
none of the 331 carver_only placements (mostly Crux Prime's trigger boxes)
shows up among the live constructions, where their zones' other objects do.
DLU spawned them as objects.

They are skipped now. The ones that carve the navmesh (53, in six zones,
among them the Avant Gardens Sentinel camp walls) still stop the server's movers: their shape
goes into the world's movement blockers without an object, owned by the
physics world (dpWorld::AddOwnedMovementBlocker) and freed when it shuts
down. None of them has a script, trigger or group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:49:13 -05:00
Aaron Kimbrell
175d2930b7 feat(physics): real sizes for the navmesh carvers the server didn't know
Walls whose asset shape the server doesn't know are left out of the movement
blockers (a stand in cube would be a guess), which left out every navmesh
carver in Robot City (hedges, hedge corners, potted bushes, greebles, robot
statues) and the Ninjago Monastery benches. Their sizes now come from the
client's own collision shapes (res/physics): the bounds of all of a shape's
parts, with the offset of the box from the object's position. The hedge
corner is an L, so its box also covers the inside of the corner.

The same bounds match two shapes the server already had (misc_phys_10x1x5:
10 x 5 x 1; Trigger_Rectangle_Box: 8 x 8 x 4).

CreatePhysicsEntity's shape lookup becomes CreateAssetShape, which needs no
component, for walls without an object.

Still unknown: the Ninjago Monastery cave's primitive model carver (a 77.6
cube whose origin, centre or base, isn't known).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:48:56 -05:00
Aaron Kimbrell
53c03515a7 feat(ai): pets stop at the walls their group can't cross
Pets are walked by the server's MovementAI like enemies, but only enemies'
paths were cut at movement blockers, so pets walked through the Nimbus Station
pet ranch's "PR - Pet Blocker" walls. Their collision group (3) is the one
the pet blocker's group (18) touches in the client's collision filter, so a
pet's path now stops at them (and at navmesh carvers), whether wandering or
following its owner; a pet left behind still warps to its owner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:46:20 -05:00
Aaron Kimbrell
e77535984d test(loot): item source keys and the quickbuild item cost's source
Covers the key names and name value types, a pickup from an object, from the
player and from an object that is gone, metrics after an item's config (and
not kept on the item), a removal's loot source, and a quickbuild taking its
item cost with itself as the source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:46:13 -05:00
Aaron Kimbrell
a5126536a4 fix(quickbuild): the item cost is taken with the quickbuild as its source
Live's RemoveItemFromInventory for a quickbuild's item cost (the FV Stone
Warrior pedestal's 5 Maelstrom Infected Bricks, taken when the build starts)
had the loot source Quickbuild and the quickbuild's object ID as the loot
source object. DLU sent loot source None with no source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:46:13 -05:00
Aaron Kimbrell
ed2d329781 feat(loot): rewards, purchases, mail and trades say where items came from
The other item sources live marked in AddItemToInventoryClientSync's extra
info, with the keys and values live sent:
- mission and achievement rewards: _Metric_Mission_ID_Int and source LOT 1,
  the player (225 of 225 live rewards)
- activity rewards: _Metric_Activity_ID_Int and the activity object's LOT
- vendor purchases: the vendor's LOT and _Metric_Currency_Delta_Int, the coins
  paid as a negative number (left out when the item costs no coins)
- mail attachments: _Metric_Mail_ID_Int64
- traded items: _Metric_Transaction_ID_Int64, the trade's ID

Loot::GiveLoot gains overloads that pass them on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:46:05 -05:00
Aaron Kimbrell
898ae024f0 feat(loot): a picked up item says which object it dropped from
Live's AddItemToInventoryClientSync for a picked up drop had
_Metric_Souce_LOT_Int in its extra info on all 2,344 live pickups: the LOT
of the DropClientLoot's source object, 1 when a player was the source
(activity rewards and chests, which drop from the player). DLU sent none.

The drop remembers its source object's LOT when it is registered for the
player, and the pickup sends it. A source object already gone when it drops sends
no key. Package contents keep sending none, as live's did.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:45:59 -05:00
Aaron Kimbrell
a1ee18fce7 feat(inventory): items can carry where they came from to the client
Live servers put _Metric_ keys in AddItemToInventoryClientSync's extra info,
after the item's own config, saying where the items came from: the source
object's LOT (_Metric_Souce_LOT_Int, misspelt as live had it), the mission,
activity, coins paid, mail or trade. LootMetrics holds them and writes them
with the key names and name value types live used (the mail ID as type 8,
the trade ID as type 9). AddItem, ReceiveItem (its options), the new item
constructor and Item::SetCount pass them through to the message; the item
does not keep them.

RemoveItem and Item::SetCount can also say what took items away
(ItemRemovalSource), filling RemoveItemFromInventory's loot source and
source object instead of none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:45:50 -05:00
Aaron Kimbrell
f309cf0528 fix(dashboard): World 3D plays a packet capture at 1x
The replay speed saved for recorded positions (60x by default) is for scrubbing through hours of movement. A capture is minutes long and played too fast at that speed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 07:41:13 -05:00
Aaron Kimbrell
3018312f29 test(capture): decoders cover the matchmaking chat packets; position fields are under update
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:41:52 -05:00
Aaron Kimbrell
4d7bea6f06 test(capture): decoder coverage, replica read-back and generator check; docs
Every LU MessageType has a struct or is listed as never used by this server; every game message struct reads;
samples of each family and of sent game messages read back; replica constructions, updates and destructions written
by the server's own serializers read back. Generator finds constructors defined in the .cpp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:32:46 -05:00
Aaron Kimbrell
d1ea2992e4 feat(dashboard): capture viewer decodes game messages and replica packets
Links the game for its message structs, reads the components of every LOT at startup, and decodes a capture's
replica packets once, in timeline order, on a worker thread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:32:35 -05:00
Aaron Kimbrell
5e40166cbd feat(capture): read replica constructions, serializations and destructions
ReplicaDecoder mirrors Entity::WriteBaseReplicaData and each component's Serialize, keeps what each network ID is
per world instance, and shows the rest as bits when no layout fits. CaptureTool links the game: game messages are
decoded (and compared in replays), and decode --cdserver reads replica packets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:32:35 -05:00
Aaron Kimbrell
8df9084a72 feat(capture): decode every game message both ways by its struct
GameMessageDecoder reads every NetGameMsg struct (generated member lists in GameMessageFields.inc) instead of 10
hand-written ones; DisplayTooltip gets the Deserialize it lacked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:32:35 -05:00
Aaron Kimbrell
19aa691ff7 feat(capture): decode every LU packet with its own struct
The capture viewer's LU packet fields come from each struct's Deserialize and a member list generated from the
struct definitions (tools/gen_game_message_fields.py -> dNet/PacketFields.inc), replacing the hand-written list of
25. Secret members are never listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 06:32:35 -05:00
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
5d3adfc683 docs: activity matchmaking across worlds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:59 -05:00
Aaron Kimbrell
289a1acfdf feat(world): activity lobbies join, ready and leave through the chat server
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:59 -05:00
Aaron Kimbrell
2ae086d933 feat(chat): keep activity lobbies of every world and start their instances through master
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:59 -05:00
Aaron Kimbrell
4a7cac4f35 feat(chat): activity lobby state machine for matchmaking across worlds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:59 -05:00
Aaron Kimbrell
e11493008d feat(net): MATCH_REQUEST and MATCH_TRANSFER chat packets and the chat server's MatchUpdate
MATCH_TRANSFER is appended after GUILD_DISBAND (71); the chat ids from
CREATE_TEAM on are pinned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:59 -05:00
Aaron Kimbrell
9a4282e6b3 docs: properties stay out of live updates and world reloads
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:54 -05:00
Aaron Kimbrell
4c93c8fea7 feat(dashboard): draining (old version) badge; properties update when empty
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:54 -05:00
Aaron Kimbrell
d71e44f3e1 feat(world-reload): keep properties until empty
Busy property instances on changed files are kept (KEEP_UNTIL_EMPTY) instead
of saved, frozen and moved. Every instance acted on is marked outdated; the
files status carries the flag (bit 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:54 -05:00
Aaron Kimbrell
891f21daa9 feat(live-update): never move properties; mark old instances outdated
Property instances are left out of the replace plan. Once the database is
up to date every instance running at the start is marked outdated, and a
zone that already got a new instance is not started again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:54 -05:00
Aaron Kimbrell
8f891229e6 feat(master): outdated instances take nobody new and stop once empty
Instances on an old binary or old zone files are marked outdated: routing,
private passwords and merges skip them. Outdated properties remind their
players every 10 minutes that an update is waiting (ANNOUNCE) and stop once
empty. A new instance of the same property waits for the old one to be gone
before its world server starts, so two worlds never save one property.
The server list carries the flag after the endpoints (read when present).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 04:29:54 -05:00
Aaron Kimbrell
c6831ac80e fix(dashboard): light the UGC model view like the game
Metal was drawn with metalness 1 in the room environment at half strength with one
sun, so metal groups came out nearly black. The game's metal keeps the vertex
color (lit, plus a reflection tinted by it), so metal is now part metal with a
stronger reflection, the environment is brighter and a sky over ground fill
lights the sides away from the sun.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:50:37 -05:00
Aaron Kimbrell
19b6443fb4 fix(ugc): metal look only from the client's material types
LU Toolbox's metallic table also has colors the client's Materials.xml types
shinyPlastic, such as 131, the grey of many baseplates, so whole baseplates went
into S88_Metal_Model. Metal now comes from the Materials.xml types (shinySteel)
and the settings' colors only; the table still gives colors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:50:37 -05:00
Aaron Kimbrell
5265da7b2e docs: following a player across worlds
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:21:54 -05:00
Aaron Kimbrell
826ba058ff feat(dashboard): world change markers on the packet capture timeline
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:21:53 -05:00
Aaron Kimbrell
9bbdc45f4f feat(world3d): follow a player across worlds, live and in capture playback
Live: when the position feed reports the followed player only in another world,
load its scene, keep following and toast where they went. Capture playback: load
every zone's movement, switch the scene at the followed character's world change
(forward and when seeking back), follow a lone captured character from the start,
and mark world changes on the replay slider.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:21:53 -05:00
Aaron Kimbrell
12c5b34a5d feat(world3d): scene switch and world marker rules for following across worlds
followedMove (live feed), worldAt/captureSwitch (capture playback), worldMarkers and
markersHtml, with node tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:21:53 -05:00
Aaron Kimbrell
601a27343f feat(dashboard): capture worlds route, every zone's movement in positions
/api/inspector/sessions/:id/worlds lists the captured characters' moves between
world servers with the zone's name from the locale; /positions also returns them,
takes ?zone=all and names each track's character and zone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:21:53 -05:00
Aaron Kimbrell
d8900c5d68 feat(net): CaptureTools::Worlds lists each captured character's world visits
One entry each time the packets a character's client sends carry another zone or
instance, in time order, for following them across world servers in playback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 03:21:53 -05:00