Compare commits

...

15 Commits

Author SHA1 Message Date
David Markowitz
8f6ee6327e add deep copy of config data 2024-05-24 21:17:56 -07:00
David Markowitz
d572ce1f1c add back deleter 2024-05-24 03:56:38 -07:00
David Markowitz
85cd609168 remove extra item code 2024-05-23 20:10:44 -07:00
David Markowitz
d4e6939dbd Merge branch 'main' into naming-of-models 2024-05-23 19:51:45 -07:00
David Markowitz
f8d5110290 Update PropertyManagementComponent.cpp
Revert "fix stale reference"

This reverts commit 03b17c0374787bca6dfec2da663da74ac76c26fb.

fix stale reference
2024-05-23 14:42:15 -07:00
David Markowitz
a153d0a78c add settings if they dont exist
add helper for spawnerinfo config data
2024-05-21 04:27:17 -07:00
David Markowitz
bfeb10c972 update ldf logic 2024-05-21 04:06:55 -07:00
David Markowitz
82507e642a add erase var helper for entity 2024-05-21 04:06:16 -07:00
David Markowitz
abd978c348 names and descriptions work 2024-05-20 22:39:56 -07:00
David Markowitz
10f8d40b69 saving changes 2024-05-20 21:24:52 -07:00
David Markowitz
37c2c5db5d remove extra map 2024-05-20 20:51:03 -07:00
David Markowitz
693a2fef35 move logic to Item 2024-05-20 20:49:42 -07:00
David Markowitz
787237c930 modularize loading for all possible extra data 2024-05-20 14:33:10 -07:00
David Markowitz
0464f37fab add declaration to header 2024-05-20 13:39:40 -07:00
David Markowitz
78ae8bc6b6 stubbing for saving item extra data 2024-05-20 13:38:59 -07:00
13 changed files with 166 additions and 69 deletions

View File

@@ -239,7 +239,7 @@ void Character::SaveXMLToDatabase() {
auto zoneInfo = Game::zoneManager->GetZone()->GetZoneID();
// lzid garbage, binary concat of zoneID, zoneInstance and zoneClone
if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0 && !Game::zoneManager->GetDisableSaveLocation()) {
// if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0 && !Game::zoneManager->GetDisableSaveLocation()) {
uint64_t lzidConcat = zoneInfo.GetCloneID();
lzidConcat = (lzidConcat << 16) | uint16_t(zoneInfo.GetInstanceID());
lzidConcat = (lzidConcat << 16) | uint16_t(zoneInfo.GetMapID());
@@ -251,7 +251,7 @@ void Character::SaveXMLToDatabase() {
// Set the target scene, custom attribute
character->SetAttribute("tscene", m_TargetScene.c_str());
}
// }
auto emotes = character->FirstChildElement("ue");
if (!emotes) emotes = m_Doc.NewElement("ue");

View File

@@ -660,7 +660,7 @@ void Entity::Initialize() {
}
PetComponent* petComponent;
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ITEM) > 0 && !TryGetComponent(eReplicaComponentType::PET, petComponent) && !HasComponent(eReplicaComponentType::MODEL)) {
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ITEM) > 0) {
AddComponent<ItemComponent>();
}
@@ -901,6 +901,14 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacke
for (size_t i = 0; i < name.size(); ++i) {
outBitStream.Write<uint16_t>(name[i]);
}
} else if (HasVar(u"userModelName")) {
const auto& name = GetVar<std::string>(u"userModelName");
outBitStream.Write<uint8_t>(uint8_t(name.size()));
for (size_t i = 0; i < name.size(); ++i) {
outBitStream.Write<uint16_t>(name[i]);
}
} else {
const auto& name = GetVar<std::string>(u"npcName");
outBitStream.Write<uint8_t>(uint8_t(name.size()));
@@ -2158,3 +2166,12 @@ void Entity::SetRespawnRot(const NiQuaternion& rotation) {
auto* characterComponent = GetComponent<CharacterComponent>();
if (characterComponent) characterComponent->SetRespawnRot(rotation);
}
void Entity::EraseVar(const std::u16string& name) {
for (auto it = m_Settings.begin(); it != m_Settings.end(); ++it) {
if ((*it)->GetKey() == name) {
m_Settings.erase(it);
return;
}
}
}

View File

@@ -299,6 +299,7 @@ public:
// Scale will only be communicated to the client when the construction packet is sent
void SetScale(const float scale) { m_Scale = scale; };
void EraseVar(const std::u16string& name);
protected:
LWOOBJID m_ObjectID;

View File

@@ -187,7 +187,7 @@ void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument& doc) {
auto zoneInfo = Game::zoneManager->GetZone()->GetZoneID();
if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0 && !Game::zoneManager->GetDisableSaveLocation()) {
// if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0 && !Game::zoneManager->GetDisableSaveLocation()) {
character->SetAttribute("lzx", m_Position.x);
character->SetAttribute("lzy", m_Position.y);
character->SetAttribute("lzz", m_Position.z);
@@ -195,7 +195,7 @@ void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument& doc) {
character->SetAttribute("lzry", m_Rotation.y);
character->SetAttribute("lzrz", m_Rotation.z);
character->SetAttribute("lzrw", m_Rotation.w);
}
// }
}
void ControllablePhysicsComponent::SetPosition(const NiPoint3& pos) {

View File

@@ -1,5 +1,29 @@
#include "ItemComponent.h"
void ItemComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) {
outBitStream.Write0();
ItemComponent::ItemComponent(Entity* entity) : Component(entity) {
m_UgcId = m_Parent->GetVarAs<LWOOBJID>(u"userModelID");
m_Description = GeneralUtils::ASCIIToUTF16(m_Parent->GetVar<std::string>(u"userModelDesc"));
m_Dirty = false;
m_ModerationStatus = 2;
LOG("%s", m_Parent->GetVarAsString(u"userModelDesc").c_str());
}
void ItemComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) {
outBitStream.Write(m_Dirty || isConstruction);
if (m_Dirty || isConstruction) {
outBitStream.Write(m_UgcId);
outBitStream.Write(m_ModerationStatus);
outBitStream.Write(!m_Description.empty());
if (!m_Description.empty()) {
outBitStream.Write<uint32_t>(m_Description.size());
outBitStream.Write(m_Description);
}
if (!isConstruction) m_Dirty = false;
}
}
void ItemComponent::UpdateDescription(const std::u16string& description) {
if (m_Description == description) return;
m_Dirty = true;
m_Description = description;
}

View File

@@ -8,9 +8,16 @@ class ItemComponent final : public Component {
public:
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::ITEM;
ItemComponent(Entity* entity) : Component(entity) {}
ItemComponent(Entity* entity);
void Serialize(RakNet::BitStream& bitStream, bool isConstruction) override;
void UpdateDescription(const std::u16string& description);
private:
std::u16string m_Description;
bool m_Dirty = false;
LWOOBJID m_UgcId = LWOOBJID_EMPTY;
uint32_t m_ModerationStatus = 0;
};
#endif //!__ITEMCOMPONENT__H__

View File

@@ -10,19 +10,9 @@
ModelComponent::ModelComponent(Entity* parent) : Component(parent) {
m_OriginalPosition = m_Parent->GetDefaultPosition();
m_OriginalRotation = m_Parent->GetDefaultRotation();
m_userModelID = m_Parent->GetVarAs<LWOOBJID>(u"userModelID");
}
void ModelComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
// ItemComponent Serialization. Pets do not get this serialization.
if (!m_Parent->HasComponent(eReplicaComponentType::PET)) {
outBitStream.Write1();
outBitStream.Write<LWOOBJID>(m_userModelID != LWOOBJID_EMPTY ? m_userModelID : m_Parent->GetObjectID());
outBitStream.Write<int>(0);
outBitStream.Write0();
}
//actual model component:
outBitStream.Write1(); // Yes we are writing model info
outBitStream.Write0(); // Is pickable

View File

@@ -126,9 +126,4 @@ private:
* The rotation original of the model
*/
NiQuaternion m_OriginalRotation;
/**
* The ID of the user that made the model
*/
LWOOBJID m_userModelID;
};

View File

@@ -21,7 +21,9 @@
#include "eObjectBits.h"
#include "CharacterComponent.h"
#include "PlayerManager.h"
#include "ItemComponent.h"
#include <ranges>
#include <vector>
#include "CppScripts.h"
@@ -152,12 +154,13 @@ void PropertyManagementComponent::SetPrivacyOption(PropertyPrivacyOption value)
Database::Get()->UpdatePropertyModerationInfo(info);
}
void PropertyManagementComponent::UpdatePropertyDetails(std::string name, std::string description) {
void PropertyManagementComponent::UpdatePropertyDetails(UpdatePropertyWithFilterCheck& update) {
if (owner == LWOOBJID_EMPTY) return;
propertyName = name;
if (update.isProperty) {
propertyName = update.name;
propertyDescription = description;
propertyDescription = update.description;
IProperty::Info info;
info.id = propertyId;
@@ -167,6 +170,33 @@ void PropertyManagementComponent::UpdatePropertyDetails(std::string name, std::s
Database::Get()->UpdatePropertyDetails(info);
OnQueryPropertyData(GetOwner(), UNASSIGNED_SYSTEM_ADDRESS);
} else {
auto* entity = Game::entityManager->GetEntity(update.worldId);
if (!entity) return;
if (update.name.empty()) {
entity->EraseVar(u"userModelName");
} else {
entity->SetVar<std::string>(u"userModelName", update.name);
}
if (update.description.empty()) {
entity->EraseVar(u"userModelDesc");
} else {
entity->SetVar<std::string>(u"userModelDesc", update.description);
}
auto* owner = GetOwner();
if (!owner) return;
GameMessages::SendSetName(update.worldId, GeneralUtils::ASCIIToUTF16(update.name), owner->GetSystemAddress());
auto* itemComponent = entity->GetComponent<ItemComponent>();
if (itemComponent) {
itemComponent->UpdateDescription(GeneralUtils::ASCIIToUTF16(update.description));
}
Game::entityManager->SerializeEntity(entity);
}
}
bool PropertyManagementComponent::Claim(const LWOOBJID playerId) {
@@ -195,7 +225,7 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) {
auto prop_path = zone->GetPath(m_Parent->GetVarAsString(u"propertyName"));
if (prop_path){
if (prop_path) {
if (!prop_path->property.displayName.empty()) name = prop_path->property.displayName;
description = prop_path->property.displayDesc;
}
@@ -325,12 +355,15 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N
return;
}
item->SetCount(item->GetCount() - 1);
auto* node = new SpawnerNode();
node->position = position;
node->rotation = rotation;
for (const auto config : item->GetConfig()) {
node->config.push_back(config->Copy());
}
item->SetCount(item->GetCount() - 1);
ObjectIDManager::RequestPersistentID([this, node, modelLOT, entity, position, rotation, originalRotation](uint32_t persistentId) {
SpawnerInfo info{};
@@ -352,11 +385,27 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N
auto* spawner = Game::zoneManager->GetSpawner(spawnerId);
info.nodes[0]->config.push_back(new LDFData<LWOOBJID>(u"modelBehaviors", 0));
info.nodes[0]->config.push_back(new LDFData<LWOOBJID>(u"userModelID", info.spawnerID));
info.nodes[0]->config.push_back(new LDFData<int>(u"modelType", 2));
info.nodes[0]->config.push_back(new LDFData<bool>(u"propertyObjectID", true));
info.nodes[0]->config.push_back(new LDFData<int>(u"componentWhitelist", 1));
// If empty, insert the default config data since it doesn't exist yet
if (!node->HasVar(u"modelBehaviors")) {
node->config.push_back(new LDFData<LWOOBJID>(u"modelBehaviors", 0));
}
if (!node->HasVar(u"userModelID")) {
node->config.push_back(new LDFData<LWOOBJID>(u"userModelID", info.spawnerID));
}
if (!node->HasVar(u"modelType")) {
node->config.push_back(new LDFData<int>(u"modelType", 2));
}
if (!node->HasVar(u"propertyObjectID")) {
node->config.push_back(new LDFData<bool>(u"propertyObjectID", true));
}
if (!node->HasVar(u"componentWhitelist")) {
node->config.push_back(new LDFData<int>(u"componentWhitelist", 1));
}
auto* model = spawner->Spawn();
@@ -436,7 +485,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
std::vector<LDFBaseData*> settings;
//fill our settings with BBB gurbage
LDFBaseData* ldfBlueprintID = new LDFData<LWOOBJID>(u"blueprintid", model->GetVar<LWOOBJID>(u"blueprintid"));
LDFBaseData* ldfBlueprintID = new LDFData<LWOOBJID>(u"blueprintID", model->GetVar<LWOOBJID>(u"blueprintID"));
LDFBaseData* userModelDesc = new LDFData<std::u16string>(u"userModelDesc", u"A cool model you made!");
LDFBaseData* userModelHasBhvr = new LDFData<bool>(u"userModelHasBhvr", false);
LDFBaseData* userModelID = new LDFData<LWOOBJID>(u"userModelID", model->GetVar<LWOOBJID>(u"userModelID"));
@@ -484,8 +533,9 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
return;
}
inventoryComponent->AddItem(model->GetLOT(), 1, eLootSourceType::DELETION, INVALID, {}, LWOOBJID_EMPTY, false);
inventoryComponent->AddItem(model->GetLOT(), 1, eLootSourceType::DELETION, INVALID, model->GetSettings(), LWOOBJID_EMPTY, false);
// figure out how to get the actual item we picked up instead of just the first lot we find
auto* item = inventoryComponent->FindItemByLot(model->GetLOT());
if (item == nullptr) {
@@ -572,28 +622,21 @@ void PropertyManagementComponent::Load() {
info.spawnerID = databaseModel.id;
std::vector<LDFBaseData*> settings;
//BBB property models need to have extra stuff set for them:
if (databaseModel.lot == 14) {
LWOOBJID blueprintID = databaseModel.ugcId;
GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER);
GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT);
settings.push_back(new LDFData<LWOOBJID>(u"blueprintid", blueprintID));
settings.push_back(new LDFData<int>(u"componentWhitelist", 1));
settings.push_back(new LDFData<int>(u"modelType", 2));
settings.push_back(new LDFData<bool>(u"propertyObjectID", true));
settings.push_back(new LDFData<LWOOBJID>(u"userModelID", databaseModel.id));
if (!node->HasVar(u"blueprintID")) node->config.push_back(new LDFData<LWOOBJID>(u"blueprintID", blueprintID));
} else {
settings.push_back(new LDFData<int>(u"modelType", 2));
settings.push_back(new LDFData<LWOOBJID>(u"userModelID", databaseModel.id));
settings.push_back(new LDFData<LWOOBJID>(u"modelBehaviors", 0));
settings.push_back(new LDFData<bool>(u"propertyObjectID", true));
settings.push_back(new LDFData<int>(u"componentWhitelist", 1));
if (!node->HasVar(u"modelBehaviors")) node->config.push_back(new LDFData<LWOOBJID>(u"modelBehaviors", 0));
}
node->config = settings;
if (!node->HasVar(u"modelType")) node->config.push_back(new LDFData<int>(u"modelType", 2));
if (!node->HasVar(u"componentWhitelist")) node->config.push_back(new LDFData<int>(u"componentWhitelist", 1));
if (!node->HasVar(u"propertyObjectID")) node->config.push_back(new LDFData<bool>(u"propertyObjectID", true));
if (!node->HasVar(u"userModelID")) node->config.push_back(new LDFData<LWOOBJID>(u"userModelID", databaseModel.id));
const auto spawnerId = Game::zoneManager->MakeSpawner(info);

View File

@@ -30,6 +30,13 @@ enum class PropertyPrivacyOption {
*/
class PropertyManagementComponent final : public Component {
public:
struct UpdatePropertyWithFilterCheck {
LWOOBJID objectId;
LWOOBJID worldId;
bool isProperty;
std::string name;
std::string description;
};
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_MANAGEMENT;
PropertyManagementComponent(Entity* parent);
static PropertyManagementComponent* Instance();
@@ -95,7 +102,7 @@ public:
* @param name the name to set for the property
* @param description the description to set for the property
*/
void UpdatePropertyDetails(std::string name, std::string description);
void UpdatePropertyDetails(UpdatePropertyWithFilterCheck& update);
/**
* Makes this property owned by the passed player ID, storing it in the database

View File

@@ -2207,19 +2207,17 @@ void GameMessages::HandleUnUseModel(RakNet::BitStream& inStream, Entity* entity,
}
void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
bool isProperty{};
LWOOBJID objectId{};
PropertyManagementComponent::UpdatePropertyWithFilterCheck filterCheck{};
LWOOBJID playerId{};
LWOOBJID worldId{};
uint32_t nameLength{};
std::u16string name{};
uint32_t descriptionLength{};
std::u16string description{};
inStream.Read(isProperty);
inStream.Read(objectId);
inStream.Read(filterCheck.isProperty);
inStream.Read(filterCheck.objectId);
inStream.Read(playerId);
inStream.Read(worldId);
inStream.Read(filterCheck.worldId);
inStream.Read(descriptionLength);
for (uint32_t i = 0; i < descriptionLength; ++i) {
@@ -2227,6 +2225,7 @@ void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream&
inStream.Read(character);
description.push_back(character);
}
filterCheck.description = GeneralUtils::UTF16ToWTF8(description);
inStream.Read(nameLength);
for (uint32_t i = 0; i < nameLength; ++i) {
@@ -2234,8 +2233,10 @@ void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream&
inStream.Read(character);
name.push_back(character);
}
filterCheck.name = GeneralUtils::UTF16ToWTF8(name);
LOG("names %s desc %s", filterCheck.name.c_str(), filterCheck.description.c_str());
PropertyManagementComponent::Instance()->UpdatePropertyDetails(GeneralUtils::UTF16ToWTF8(name), GeneralUtils::UTF16ToWTF8(description));
PropertyManagementComponent::Instance()->UpdatePropertyDetails(filterCheck);
}
void GameMessages::HandleQueryPropertyData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
@@ -2664,7 +2665,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* ent
info.spawnerID = entity->GetObjectID();
info.spawnerNodeID = 0;
info.settings.push_back(new LDFData<LWOOBJID>(u"blueprintid", blueprintID));
info.settings.push_back(new LDFData<LWOOBJID>(u"blueprintID", blueprintID));
info.settings.push_back(new LDFData<int>(u"componentWhitelist", 1));
info.settings.push_back(new LDFData<int>(u"modelType", 2));
info.settings.push_back(new LDFData<bool>(u"propertyObjectID", true));

View File

@@ -7,6 +7,15 @@
#include "GeneralUtils.h"
#include "dZoneManager.h"
bool SpawnerNode::HasVar(const std::u16string_view view) {
for (const auto* data : config) {
if (data->GetKey() == view) {
return true;
}
}
return false;
}
Spawner::Spawner(const SpawnerInfo info) {
m_Info = info;
m_Active = m_Info.activeOnLoad && info.spawnActivator;

View File

@@ -10,6 +10,7 @@
#include <functional>
#include "LDFFormat.h"
#include "EntityInfo.h"
#include <string_view>
struct SpawnerNode {
NiPoint3 position = NiPoint3Constant::ZERO;
@@ -18,6 +19,8 @@ struct SpawnerNode {
uint32_t nodeMax = 1;
std::vector<LWOOBJID> entities;
std::vector<LDFBaseData*> config;
bool HasVar(const std::u16string_view view);
};
struct SpawnerInfo {