refactor: building game messages and blueprint packets as structs

Converts build mode, arranging, modular build and brick by brick
messages to NetGameMsgs in BuildingMessages.{h,cpp}: StartArrangingWithItem,
FinishArrangingWithItem, ModularBuildEnd and SetBuildModeConfirmed
(sent), and StartBuildingWithItem, DoneArrangingWithItem,
ModularBuildFinish, ModularBuildMoveAndEquip, ModularBuildConvertModel,
SetBuildMode, BuildModeSet, UnUseBBBModel, BBBLoadItemRequest and
BBBSaveRequest (received, registered in GameMessageHandler's map with
their handlers' logic kept). The BLUEPRINT_SAVE_RESPONSE and
BLUEPRINT_LOAD_RESPONSE_ITEMID client packets become the LUBitStream
structs ClientPackets::BlueprintSaveResponse and BlueprintLoadItemResponse,
also used by WorldServer's level load. The never-called
SendBBBSaveResponse is gone.

SetBuildModeConfirmed keeps writing modeValue's and startPos's default
flags as always set, as DLU did. BuildModeSet and UnUseBBBModel now read
their whole client layout (DLU read only the first fields).

No wire change and no change in recipients. Verified byte for byte
against a frozen verbatim copy of the old functions and inline packet
writes over an input grid, received messages compared with the old
handlers' read sequences with every truncated payload rejected, hand
computed golden bytes, round trips and a mutation check. Layouts
confirmed against the 1.10.64 client in Ghidra.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-26 23:21:34 -05:00
parent 9458230f0b
commit 0c2727ad3c
14 changed files with 1807 additions and 858 deletions

View File

@@ -440,3 +440,46 @@ namespace ClientPackets {
return true;
}
}
void ClientPackets::BlueprintSaveResponse::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(localId);
bitStream.Write(reasonCode);
bitStream.Write<uint32_t>(models.size());
for (const auto& model : models) {
bitStream.Write(model.blueprintId);
bitStream.Write<uint32_t>(model.data.size());
bitStream.WriteAlignedBytes(reinterpret_cast<const unsigned char*>(model.data.data()), model.data.size());
}
}
bool ClientPackets::BlueprintSaveResponse::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(localId));
VALIDATE_READ(bitStream.Read(reasonCode));
uint32_t count{};
VALIDATE_READ(bitStream.Read(count));
models.clear();
for (uint32_t i = 0; i < count; i++) {
auto& model = models.emplace_back();
VALIDATE_READ(bitStream.Read(model.blueprintId));
uint32_t size{};
VALIDATE_READ(bitStream.Read(size));
bitStream.AlignReadToByteBoundary();
if (static_cast<uint64_t>(size) * 8 > bitStream.GetNumberOfUnreadBits()) return false;
model.data.resize(size);
if (size != 0) VALIDATE_READ(bitStream.ReadAlignedBytes(reinterpret_cast<unsigned char*>(model.data.data()), size));
}
return true;
}
void ClientPackets::BlueprintLoadItemResponse::Serialize(RakNet::BitStream& bitStream) const {
bitStream.Write(success);
bitStream.Write(itemId);
bitStream.Write(destItemId);
}
bool ClientPackets::BlueprintLoadItemResponse::Deserialize(RakNet::BitStream& bitStream) {
VALIDATE_READ(bitStream.Read(success));
VALIDATE_READ(bitStream.Read(itemId));
VALIDATE_READ(bitStream.Read(destItemId));
return true;
}