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

View File

@@ -2,24 +2,33 @@
#define __GAMEMESSAGEDECODER__H__
#include <optional>
#include <vector>
#include "BitStream.h"
#include "json.hpp"
#include "MessageType/Game.h"
/**
* Reads a game message's fields for the dashboard's message inspector, using the server's own typed message struct
* and its Deserialize, so what is shown is exactly what the server reads. Messages the server has no typed struct
* for (the ones handled by reading the stream inline) aren't decoded; the inspector shows their bytes instead.
* Reads a game message's fields for the dashboard's message inspector and capture viewer, using the server's own
* message struct and its Deserialize, so what is shown is exactly what the server reads. Every wire message struct
* (NetGameMsg in *Messages.h) is registered; its members are listed by name by GameMessageFields.inc, which
* tools/gen_game_message_fields.py writes from the struct definitions. Messages the server has no struct for aren't
* decoded; the viewer shows their name and bytes.
*/
namespace GameMessageDecoder {
// Whether a message sent in this direction has a typed struct
// Whether a message sent in this direction has a struct that reads it
bool CanDecode(MessageType::Game messageId, bool toServer);
// Whether the server has a struct for the message at all (in either direction)
bool HasStruct(MessageType::Game messageId);
// The message's fields, read from `payload` (the bits after the object ID and message ID), or nullopt when it has
// no typed struct or doesn't read cleanly
// no struct or doesn't read cleanly. Whole bytes the struct left unread are reported as "(unread bits)".
std::optional<nlohmann::json> Decode(MessageType::Game messageId, bool toServer, RakNet::BitStream& payload);
// Every message ID with a struct that reads it
std::vector<MessageType::Game> Decodable();
/**
* Reads a message a client sent with the struct the server reads it with, and writes it again. nullopt when the
* server has no typed struct for it or it doesn't read; otherwise whether it read the whole message (padding