mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-20 03:32:48 +00:00
feat(bbb): answer FetchModelMetadataRequest for brick built models
The client asks for a model's metadata (name, owner, behaviors and its blueprint's bricks and box) when it shows a brick built model item's tooltip, a model on a property or an exhibit, and shows BBB_LOADING_BLUEPRINT until it gets it. The world server never answered. It now does as live did: UG data for the model (found among the player's items by subkey, else among placed models) and, for a brick built model, the blueprint data from its ugc row and LXFML. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -411,3 +411,22 @@ TEST(LxfmlTests, DeepCloneDepthProtection) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LxfmlTests, ReadContentsListsBricksAndTheirBox) {
|
||||
const std::string lxfml = R"(<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||
<LXFML versionMajor="5" versionMinor="0">
|
||||
<Bricks>
|
||||
<Brick refID="0" designID="3710"><Part refID="0" designID="3710" materials="21"><Bone refID="0" transformation="1,0,0,0,1,0,0,0,1,-1.2,0,0.4"/></Part></Brick>
|
||||
<Brick refID="1" designID="3001;A"><Part refID="1" designID="3001" materials="1"><Bone refID="1" transformation="1,0,0,0,1,0,0,0,1,0.8,0.96,-0.4"/></Part></Brick>
|
||||
</Bricks>
|
||||
</LXFML>)";
|
||||
const auto contents = Lxfml::ReadContents(lxfml);
|
||||
EXPECT_EQ(contents.designIds, (std::vector<uint32_t>{ 3710, 3001 }));
|
||||
EXPECT_EQ(contents.boxMin, NiPoint3(-1.2f, 0.0f, -0.4f));
|
||||
EXPECT_EQ(contents.boxMax, NiPoint3(0.8f, 0.96f, 0.4f));
|
||||
|
||||
const auto nothing = Lxfml::ReadContents("");
|
||||
EXPECT_TRUE(nothing.designIds.empty());
|
||||
EXPECT_EQ(nothing.boxMin, NiPoint3Constant::ZERO);
|
||||
EXPECT_TRUE(Lxfml::ReadContents("<LXFML><Bricks/></LXFML>").designIds.empty());
|
||||
}
|
||||
|
||||
@@ -119,3 +119,14 @@ TEST_F(BrickByBrickTests, AReturnedModelIsNeverUsedUpByTheAutosave) {
|
||||
ASSERT_TRUE(saved.has_value());
|
||||
EXPECT_EQ(saved->sourceItems, (std::vector<LWOOBJID>{ 8 }));
|
||||
}
|
||||
|
||||
TEST_F(BrickByBrickTests, ModelMetadataHasFiveBehaviorsAndAColonBrickList) {
|
||||
EXPECT_EQ(BrickByBrick::BehaviorIds(""), std::vector<LWOOBJID>(5, 0));
|
||||
EXPECT_EQ(BrickByBrick::BehaviorIds("0,0,0,0,0"), std::vector<LWOOBJID>(5, 0));
|
||||
EXPECT_EQ(BrickByBrick::BehaviorIds("10449,7"), (std::vector<LWOOBJID>{ 10449, 7, 0, 0, 0 }));
|
||||
EXPECT_EQ(BrickByBrick::BehaviorIds("1,2,3,4,5,6"), (std::vector<LWOOBJID>{ 1, 2, 3, 4, 5 }));
|
||||
|
||||
EXPECT_EQ(BrickByBrick::BrickList({}), u"");
|
||||
EXPECT_EQ(BrickByBrick::BrickList({ 66 }), u"66:");
|
||||
EXPECT_EQ(BrickByBrick::BrickList({ 529, 529, 41 }), u"529:529:41:");
|
||||
}
|
||||
|
||||
@@ -435,3 +435,58 @@ TEST_F(BuildingMessagesTests, BrickModeMessagesRoundTrip) {
|
||||
EXPECT_EQ(RoundTrip(rebuilt).count, 2);
|
||||
ExpectTruncatedFails(rebuilt);
|
||||
}
|
||||
|
||||
// FetchModelMetadataRequest / Response as the client writes and reads them (GameMessage::FetchModelMetadataResponse::
|
||||
// Serialize, 0x00e3ccb0; UGObjectMetadata::Serialize, 0x00f5f590; BlueprintMetadata::Serialize, 0x00f5f760)
|
||||
TEST_F(BuildingMessagesTests, FetchModelMetadataWire) {
|
||||
GameMessages::FetchModelMetadataRequest request;
|
||||
request.context = 1;
|
||||
request.objectID = 2;
|
||||
request.requestorID = 3;
|
||||
request.ugID = 4;
|
||||
EXPECT_PACKET_EQ(FromHex("01 00 00 00 02 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00"), Payload(request));
|
||||
const auto requestCopy = RoundTrip(request);
|
||||
EXPECT_EQ(requestCopy.context, 1);
|
||||
EXPECT_EQ(requestCopy.objectID, 2);
|
||||
EXPECT_EQ(requestCopy.requestorID, 3);
|
||||
EXPECT_EQ(requestCopy.ugID, 4);
|
||||
ExpectTruncatedFails(request);
|
||||
|
||||
// Nothing known: ugID, objectID, requestorID, context, then the two flags
|
||||
GameMessages::FetchModelMetadataResponse none;
|
||||
none.ugID = 4;
|
||||
EXPECT_EQ(Bits(none), 8 * 28 + 2);
|
||||
|
||||
GameMessages::FetchModelMetadataResponse full;
|
||||
full.ugID = 4;
|
||||
full.bHasUGData = true;
|
||||
full.bHasBPData = true;
|
||||
full.ugData.userModelID = 4;
|
||||
full.ugData.blueprintID = 5;
|
||||
full.ugData.userModelName = u"Car";
|
||||
full.ugData.owningPlayerID = 6;
|
||||
full.ugData.accountID = 7;
|
||||
full.ugData.owningPlayerName = u"Builder";
|
||||
full.ugData.userModelBehaviors = { 8, 0, 0, 0, 0 };
|
||||
full.bpData.blueprintID = 5;
|
||||
full.bpData.modelBoxMins = NiPoint3(-1.6f, 0.0f, -0.8f);
|
||||
full.bpData.modelBoxMaxs = NiPoint3(1.6f, 0.5f, 0.8f);
|
||||
full.bpData.brickListColonDelim = u"66:";
|
||||
full.bpData.numberOfBricks = 1;
|
||||
// UG: 2 ids, name (4 + 6), desc (4), 2 ids, owner name (4 + 14), u8 count, 5 ids
|
||||
const uint32_t ugBits = 8 * (16 + 10 + 4 + 16 + 18 + 1 + 40);
|
||||
// BP: id, timestamp, mod, 2 points, 2 flags, bricks (4 + 6), flag, count
|
||||
const uint32_t bpBits = 8 * (8 + 8 + 4 + 24 + 10 + 4) + 3;
|
||||
EXPECT_EQ(Bits(full), 8 * 28 + 2 + ugBits + bpBits);
|
||||
const auto copy = RoundTrip(full);
|
||||
EXPECT_EQ(copy.ugData.userModelName, u"Car");
|
||||
EXPECT_EQ(copy.ugData.owningPlayerName, u"Builder");
|
||||
EXPECT_EQ(copy.ugData.userModelBehaviors, full.ugData.userModelBehaviors);
|
||||
EXPECT_EQ(copy.bpData.brickListColonDelim, u"66:");
|
||||
EXPECT_EQ(copy.bpData.modelBoxMaxs, full.bpData.modelBoxMaxs);
|
||||
EXPECT_EQ(copy.bpData.numberOfBricks, 1);
|
||||
EXPECT_TRUE(copy.bpData.userModelOpt);
|
||||
EXPECT_TRUE(copy.bpData.ugcIconReady);
|
||||
EXPECT_TRUE(copy.bpData.neverFalseIfPresentInCaps);
|
||||
ExpectTruncatedFails(full);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user