mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-27 23:17:14 +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:
@@ -603,6 +603,110 @@ namespace GameMessages {
|
||||
return true;
|
||||
}
|
||||
|
||||
void UGObjectMetadata::Serialize(RakNet::BitStream& bitStream) const {
|
||||
bitStream.Write(userModelID);
|
||||
bitStream.Write(blueprintID);
|
||||
BitStreamUtils::WriteLengthPrefixed(bitStream, userModelName);
|
||||
BitStreamUtils::WriteLengthPrefixed(bitStream, userModelDesc);
|
||||
bitStream.Write(owningPlayerID);
|
||||
bitStream.Write(accountID);
|
||||
BitStreamUtils::WriteLengthPrefixed(bitStream, owningPlayerName);
|
||||
const auto count = static_cast<uint8_t>(std::min<size_t>(userModelBehaviors.size(), UINT8_MAX));
|
||||
bitStream.Write(count);
|
||||
for (uint8_t i = 0; i < count; i++) bitStream.Write(userModelBehaviors[i]);
|
||||
}
|
||||
|
||||
bool UGObjectMetadata::Deserialize(RakNet::BitStream& bitStream) {
|
||||
VALIDATE_READ(bitStream.Read(userModelID));
|
||||
VALIDATE_READ(bitStream.Read(blueprintID));
|
||||
VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, userModelName));
|
||||
VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, userModelDesc));
|
||||
VALIDATE_READ(bitStream.Read(owningPlayerID));
|
||||
VALIDATE_READ(bitStream.Read(accountID));
|
||||
VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, owningPlayerName));
|
||||
uint8_t count{};
|
||||
VALIDATE_READ(bitStream.Read(count));
|
||||
userModelBehaviors.resize(count);
|
||||
for (auto& behavior : userModelBehaviors) VALIDATE_READ(bitStream.Read(behavior));
|
||||
return true;
|
||||
}
|
||||
|
||||
void BlueprintMetadata::Serialize(RakNet::BitStream& bitStream) const {
|
||||
bitStream.Write(blueprintID);
|
||||
bitStream.Write(blueprintCreationTimestamp);
|
||||
bitStream.Write(userModelMod);
|
||||
bitStream.Write(modelBoxMins);
|
||||
bitStream.Write(modelBoxMaxs);
|
||||
bitStream.Write(userModelOpt);
|
||||
bitStream.Write(ugcIconReady);
|
||||
BitStreamUtils::WriteLengthPrefixed(bitStream, brickListColonDelim);
|
||||
bitStream.Write(neverFalseIfPresentInCaps);
|
||||
bitStream.Write(numberOfBricks);
|
||||
}
|
||||
|
||||
bool BlueprintMetadata::Deserialize(RakNet::BitStream& bitStream) {
|
||||
VALIDATE_READ(bitStream.Read(blueprintID));
|
||||
VALIDATE_READ(bitStream.Read(blueprintCreationTimestamp));
|
||||
VALIDATE_READ(bitStream.Read(userModelMod));
|
||||
VALIDATE_READ(bitStream.Read(modelBoxMins));
|
||||
VALIDATE_READ(bitStream.Read(modelBoxMaxs));
|
||||
VALIDATE_READ(bitStream.Read(userModelOpt));
|
||||
VALIDATE_READ(bitStream.Read(ugcIconReady));
|
||||
VALIDATE_READ(BitStreamUtils::ReadLengthPrefixed(bitStream, brickListColonDelim));
|
||||
VALIDATE_READ(bitStream.Read(neverFalseIfPresentInCaps));
|
||||
VALIDATE_READ(bitStream.Read(numberOfBricks));
|
||||
return true;
|
||||
}
|
||||
|
||||
void FetchModelMetadataRequest::Serialize(RakNet::BitStream& bitStream) const {
|
||||
bitStream.Write(context);
|
||||
bitStream.Write(objectID);
|
||||
bitStream.Write(requestorID);
|
||||
bitStream.Write(ugID);
|
||||
}
|
||||
|
||||
bool FetchModelMetadataRequest::Deserialize(RakNet::BitStream& bitStream) {
|
||||
VALIDATE_READ(bitStream.Read(context));
|
||||
VALIDATE_READ(bitStream.Read(objectID));
|
||||
VALIDATE_READ(bitStream.Read(requestorID));
|
||||
VALIDATE_READ(bitStream.Read(ugID));
|
||||
return true;
|
||||
}
|
||||
|
||||
void FetchModelMetadataRequest::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
||||
FetchModelMetadataResponse response;
|
||||
response.target = entity.GetObjectID();
|
||||
response.ugID = ugID;
|
||||
response.objectID = objectID;
|
||||
response.requestorID = requestorID;
|
||||
response.context = context;
|
||||
BrickByBrick::FillModelMetadata(entity, ugID, response);
|
||||
response.Send(sysAddr);
|
||||
}
|
||||
|
||||
void FetchModelMetadataResponse::Serialize(RakNet::BitStream& bitStream) const {
|
||||
bitStream.Write(ugID);
|
||||
bitStream.Write(objectID);
|
||||
bitStream.Write(requestorID);
|
||||
bitStream.Write(context);
|
||||
bitStream.Write(bHasUGData);
|
||||
bitStream.Write(bHasBPData);
|
||||
if (bHasUGData) ugData.Serialize(bitStream);
|
||||
if (bHasBPData) bpData.Serialize(bitStream);
|
||||
}
|
||||
|
||||
bool FetchModelMetadataResponse::Deserialize(RakNet::BitStream& bitStream) {
|
||||
VALIDATE_READ(bitStream.Read(ugID));
|
||||
VALIDATE_READ(bitStream.Read(objectID));
|
||||
VALIDATE_READ(bitStream.Read(requestorID));
|
||||
VALIDATE_READ(bitStream.Read(context));
|
||||
VALIDATE_READ(bitStream.Read(bHasUGData));
|
||||
VALIDATE_READ(bitStream.Read(bHasBPData));
|
||||
if (bHasUGData) VALIDATE_READ(ugData.Deserialize(bitStream));
|
||||
if (bHasBPData) VALIDATE_READ(bpData.Deserialize(bitStream));
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetModelToBuild::Serialize(RakNet::BitStream& bitStream) const {
|
||||
bitStream.Write(modelLot != -1);
|
||||
if (modelLot != -1) bitStream.Write(modelLot);
|
||||
|
||||
@@ -242,6 +242,70 @@ namespace GameMessages {
|
||||
int32_t count{};
|
||||
};
|
||||
|
||||
// A model's user generated data (UGObjectMetadata::Serialize, 0x00f5f590)
|
||||
struct UGObjectMetadata {
|
||||
LWOOBJID userModelID{};
|
||||
LWOOBJID blueprintID{};
|
||||
std::u16string userModelName;
|
||||
std::u16string userModelDesc;
|
||||
LWOOBJID owningPlayerID{};
|
||||
LWOOBJID accountID{};
|
||||
std::u16string owningPlayerName;
|
||||
std::vector<LWOOBJID> userModelBehaviors; // a u8 count on the wire; live always sent 5
|
||||
|
||||
void Serialize(RakNet::BitStream& bitStream) const;
|
||||
bool Deserialize(RakNet::BitStream& bitStream);
|
||||
};
|
||||
|
||||
// A brick built model's blueprint data (BlueprintMetadata::Serialize, 0x00f5f760)
|
||||
struct BlueprintMetadata {
|
||||
LWOOBJID blueprintID{};
|
||||
int64_t blueprintCreationTimestamp{}; // Unix seconds
|
||||
int32_t userModelMod{ 1 };
|
||||
NiPoint3 modelBoxMins{}; // the model's box, relative to its origin (the exhibit checks its size)
|
||||
NiPoint3 modelBoxMaxs{};
|
||||
bool userModelOpt{ true };
|
||||
bool ugcIconReady{ true };
|
||||
std::u16string brickListColonDelim; // every brick's LOT, each followed by ':'
|
||||
bool neverFalseIfPresentInCaps{ true };
|
||||
int32_t numberOfBricks{};
|
||||
|
||||
void Serialize(RakNet::BitStream& bitStream) const;
|
||||
bool Deserialize(RakNet::BitStream& bitStream);
|
||||
};
|
||||
|
||||
// Client -> server. The client wants the name, owner, behaviors and blueprint of a model (its UGID) it has no
|
||||
// metadata for: a brick built model item's tooltip (LWOInventoryComponent_Client::FillinDetailsBlueprint, 0x00cddb40, via
|
||||
// UGModelMetadataCache::GetModelMetadata, 0x00b5e680), a model on the property, an exhibit.
|
||||
struct FetchModelMetadataRequest : public NetGameMsg {
|
||||
FetchModelMetadataRequest() : NetGameMsg(MessageType::Game::FETCH_MODEL_METADATA_REQUEST) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
bool Deserialize(RakNet::BitStream& bitStream) override;
|
||||
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||
|
||||
int32_t context{};
|
||||
LWOOBJID objectID{};
|
||||
LWOOBJID requestorID{};
|
||||
LWOOBJID ugID{};
|
||||
};
|
||||
|
||||
// Server -> client. The answer: the client caches it by UGID and blueprint id and writes it into the config of
|
||||
// the inventory item objectID (LWOInventoryComponent_Client::msgFetchModelMetadataResponse, 0x00c64300).
|
||||
struct FetchModelMetadataResponse : public NetGameMsg {
|
||||
FetchModelMetadataResponse() : NetGameMsg(MessageType::Game::FETCH_MODEL_METADATA_RESPONSE) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
bool Deserialize(RakNet::BitStream& bitStream) override;
|
||||
|
||||
LWOOBJID ugID{};
|
||||
LWOOBJID objectID{};
|
||||
LWOOBJID requestorID{};
|
||||
int32_t context{};
|
||||
bool bHasUGData{};
|
||||
bool bHasBPData{};
|
||||
UGObjectMetadata ugData; // when bHasUGData
|
||||
BlueprintMetadata bpData; // when bHasBPData
|
||||
};
|
||||
|
||||
struct SetModelToBuild : public NetGameMsg {
|
||||
SetModelToBuild() : NetGameMsg(MessageType::Game::SET_MODEL_TO_BUILD) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
|
||||
@@ -141,6 +141,7 @@ namespace {
|
||||
{ SET_BUILD_MODE, []() { return std::make_unique<SetBuildMode>(); } },
|
||||
{ BUILD_MODE_SET, []() { return std::make_unique<BuildModeSet>(); } },
|
||||
{ UN_USE_BBB_MODEL, []() { return std::make_unique<UnUseBBBModel>(); } },
|
||||
{ FETCH_MODEL_METADATA_REQUEST, []() { return std::make_unique<FetchModelMetadataRequest>(); } },
|
||||
{ BBB_LOAD_ITEM_REQUEST, []() { return std::make_unique<BBBLoadItemRequest>(); } },
|
||||
{ BBB_SAVE_REQUEST, []() { return std::make_unique<BBBSaveRequest>(); } },
|
||||
{ SET_BBB_AUTOSAVE, []() { return std::make_unique<SetBBBAutosave>(); } },
|
||||
|
||||
Reference in New Issue
Block a user