CMake refuses to configure when pointers aren't 8 bytes, and dCommonVars.h
asserts it, so sent and stored sizes can't silently change width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every live capture decoded: 83 of 60,659 constructions and 5 of 609,919
serializations now don't read exactly (was about 1 in 10 constructions, and
the decode aborted on text that isn't UTF-8).
- trigger component (header trigger bit): a bit and the trigger ID, last
- BBB component on objects listing component 107 (characters)
- local space info, buff immunities, phantom physics distance, skills in
progress, a choice build's setting
- moving platform: path when dirty, then subcomponents while a 1 bit comes
before one (mover and simple mover)
- pet: names under the dirty bit, on updates too; no item or model component
- models: the plain model block, or the mutable one (behaviors, editing
info) when the config has propertyObjectID or inInventory; the UGC block
is the item's
- zone file variants: markedAsPhantom (phantom physics) and renderDisabled
(no render data)
- compressed LDF: u32 uncompressed and compressed sizes, inflated and shown
as entries
- narrow text that isn't UTF-8 is shown byte by byte, and the capture tool
prints invalid text with replacements instead of aborting
Tests use live byte samples for each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client makes the mutable model component, which reads the behaviors and
editing info, only when the object's config has propertyObjectID or
inInventory (ObjectLoader2::LoadModelBehaviorsComponent); every other model
gets the plain one, which reads only the model block, as live wrote it. DLU
wrote the behaviors for every model, which the client then read as the next
component's data (the render effects). Tested with the capture decoder.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client reads the moderation and names bit whenever the pet component is
dirty, on updates as well as on construction (LWOPetComponent::Deserialize),
and live wrote a 0 there on updates. DLU wrote it only on construction, so
on an update the client took the next component's first bit (a combat AI's
dirty bit) for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client reads a moving platform's subcomponents while a 1 bit comes
before one (LWOMovingPlatformComponent::Deserialize), as live wrote them.
DLU wrote the mover without the closing 0 bit, so the client took the next
component's first bit for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The client's word check before sending is a light one; the server is the full filter. In normal (whitelist) chat, block list phrases are now stopped even when each word is allowed, and allowed phrases (from the dashboard or a line with spaces in the allowed words file) let their words through together. The dashboard can allow phrases and its message test explains both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>