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>
This commit is contained in:
Aaron Kimbrell
2026-09-30 04:23:32 -05:00
parent 8df9084a72
commit 5e40166cbd
7 changed files with 954 additions and 9 deletions

View File

@@ -97,7 +97,11 @@ namespace CaptureTools {
return fields.contains(name);
}
json RecordJson(const Record& record, size_t index, int64_t startUs, bool fields) {
uint64_t ReplicaConnection(const PacketRecordHeader& h) {
return (static_cast<uint64_t>(h.zoneId) << 48) ^ (static_cast<uint64_t>(h.instanceId) << 32) ^ h.cloneId;
}
json RecordJson(const Record& record, size_t index, int64_t startUs, bool fields, const json* replicaFields) {
const auto& h = record.header;
json out{
{"i", index},
@@ -130,7 +134,8 @@ namespace CaptureTools {
out["object"] = std::to_string(decoded.objectId);
}
if (decoded.failed) out["unreadable"] = true;
if (fields && decoded.fields) out["fields"] = *decoded.fields;
if (fields && replicaFields) out["fields"] = *replicaFields;
else if (fields && decoded.fields) out["fields"] = *decoded.fields;
return out;
}

View File

@@ -23,8 +23,13 @@ namespace CaptureTools {
// Whether a record went from a game client to a server
bool FromClient(const PacketRecordHeader& header);
// One record for the viewer: where it went, its name and, when `fields`, its decoded fields
nlohmann::json RecordJson(const CaptureBundle::Record& record, size_t index, int64_t startUs, bool fields);
// One record for the viewer: where it went, its name and, when `fields`, its decoded fields. `replicaFields`: the
// fields of a replica packet, which only a pass over the capture in order can read (ReplicaDecoder::Session)
nlohmann::json RecordJson(const CaptureBundle::Record& record, size_t index, int64_t startUs, bool fields,
const nlohmann::json* replicaFields = nullptr);
// Tells apart the network IDs of different world instances in one capture
uint64_t ReplicaConnection(const PacketRecordHeader& header);
struct Track {
LWOOBJID characterId{};