Add loading from database

yahoo
This commit is contained in:
David Markowitz 2024-05-18 03:36:29 -07:00
parent fd1c6ab2ea
commit 0c4108e730
19 changed files with 149 additions and 19 deletions

View File

@ -8,14 +8,15 @@
class IBehaviors {
public:
struct Info {
LWOOBJID behaviorId{};
int32_t behaviorId{};
uint32_t characterId{};
std::string behaviorInfo;
};
// This Add also takes care of updating if it exists.
virtual void AddBehavior(const Info& info) = 0;
virtual void RemoveBehavior(const uint32_t behaviorId) = 0;
virtual std::string GetBehavior(const int32_t behaviorId) = 0;
virtual void RemoveBehavior(const int32_t behaviorId) = 0;
};
#endif //!__IBEHAVIORS__H__

View File

@ -16,7 +16,7 @@ public:
LWOOBJID id{};
LOT lot{};
uint32_t ugcId{};
std::array<LWOOBJID, 5> behaviors{};
std::array<int32_t, 5> behaviors{};
};
// Inserts a new UGC model into the database.
@ -33,7 +33,7 @@ public:
virtual void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) = 0;
// Update the model position and rotation for the given property id.
virtual void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, std::string>, 5>& behaviors) = 0;
virtual void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) = 0;
// Remove the model for the given property id.
virtual void RemoveModel(const LWOOBJID& modelId) = 0;

View File

@ -74,7 +74,7 @@ public:
std::vector<IPropertyContents::Model> GetPropertyModels(const LWOOBJID& propertyId) override;
void RemoveUnreferencedUgcModels() override;
void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) override;
void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, std::string>, 5>& behaviors) override;
void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) override;
void RemoveModel(const LWOOBJID& modelId) override;
void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override;
void InsertNewBugReport(const IBugReports::Info& info) override;
@ -109,7 +109,8 @@ public:
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
void AddBehavior(const IBehaviors::Info& info) override;
void RemoveBehavior(const uint32_t characterId) override;
std::string GetBehavior(const int32_t behaviorId) override;
void RemoveBehavior(const int32_t characterId) override;
private:
// Generic query functions that can be used for any query.

View File

@ -9,6 +9,11 @@ void MySQLDatabase::AddBehavior(const IBehaviors::Info& info) {
);
}
void MySQLDatabase::RemoveBehavior(const uint32_t behaviorId) {
void MySQLDatabase::RemoveBehavior(const int32_t behaviorId) {
ExecuteDelete("DELETE FROM behaviors WHERE behavior_id = ?", behaviorId);
}
std::string MySQLDatabase::GetBehavior(const int32_t behaviorId) {
auto result = ExecuteSelect("SELECT behavior_info FROM behaviors WHERE behavior_id = ?", behaviorId);
return result->next() ? result->getString("behavior_info").c_str() : "";
}

View File

@ -1,7 +1,10 @@
#include "MySQLDatabase.h"
std::vector<IPropertyContents::Model> MySQLDatabase::GetPropertyModels(const LWOOBJID& propertyId) {
auto result = ExecuteSelect("SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id FROM properties_contents WHERE property_id = ?;", propertyId);
auto result = ExecuteSelect(
"SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id, "
"behavior_1, behavior_2, behavior_3, behavior_4, behavior_5 "
"FROM properties_contents WHERE property_id = ?;", propertyId);
std::vector<IPropertyContents::Model> toReturn;
toReturn.reserve(result->rowsCount());
@ -17,6 +20,12 @@ std::vector<IPropertyContents::Model> MySQLDatabase::GetPropertyModels(const LWO
model.rotation.y = result->getFloat("ry");
model.rotation.z = result->getFloat("rz");
model.ugcId = result->getUInt64("ugc_id");
model.behaviors[0] = result->getInt("behavior_1");
model.behaviors[1] = result->getInt("behavior_2");
model.behaviors[2] = result->getInt("behavior_3");
model.behaviors[3] = result->getInt("behavior_4");
model.behaviors[4] = result->getInt("behavior_5");
toReturn.push_back(std::move(model));
}
return toReturn;
@ -43,7 +52,7 @@ void MySQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const IPr
}
}
void MySQLDatabase::UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, std::string>, 5>& behaviors) {
void MySQLDatabase::UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) {
ExecuteUpdate(
"UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ?, "
"behavior_1 = ?, behavior_2 = ?, behavior_3 = ?, behavior_4 = ?, behavior_5 = ? WHERE id = ?;",

View File

@ -225,7 +225,7 @@ void Entity::Initialize() {
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
AddComponent<ModelComponent>();
AddComponent<ModelComponent>()->LoadBehaviors();
AddComponent<RenderComponent>();
@ -649,7 +649,7 @@ void Entity::Initialize() {
}
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent<PetComponent>()) {
AddComponent<ModelComponent>();
AddComponent<ModelComponent>()->LoadBehaviors();
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) {
auto* destroyableComponent = AddComponent<DestroyableComponent>();
destroyableComponent->SetHealth(1);

View File

@ -8,6 +8,8 @@
#include "ControlBehaviorMsgs.h"
#include "tinyxml2.h"
#include "Database.h"
ModelComponent::ModelComponent(Entity* parent) : Component(parent) {
m_OriginalPosition = m_Parent->GetDefaultPosition();
m_OriginalRotation = m_Parent->GetDefaultRotation();
@ -15,6 +17,31 @@ ModelComponent::ModelComponent(Entity* parent) : Component(parent) {
m_userModelID = m_Parent->GetVarAs<LWOOBJID>(u"userModelID");
}
void ModelComponent::LoadBehaviors() {
auto behaviors = GeneralUtils::SplitString(m_Parent->GetVar<std::string>(u"userModelBehaviors"), ',');
for (const auto& behavior : behaviors) {
if (behavior.empty()) continue;
const auto behaviorId = GeneralUtils::TryParse<int32_t>(behavior);
if (!behaviorId.has_value() || behaviorId.value() == 0) continue;
LOG("Loading behavior %d", behaviorId.value());
auto& inserted = m_Behaviors.emplace_back();
inserted.SetBehaviorId(*behaviorId);
const auto behaviorStr = Database::Get()->GetBehavior(behaviorId.value());
tinyxml2::XMLDocument behaviorXml;
auto res = behaviorXml.Parse(behaviorStr.c_str(), behaviorStr.size());
LOG("Behavior %i %d: %s", res, behaviorId.value(), behaviorStr.c_str());
const auto* const behaviorRoot = behaviorXml.FirstChildElement("Behavior");
if (!behaviorRoot) {
LOG("Failed to load behavior %d due to missing behavior root", behaviorId.value());
continue;
}
inserted.Deserialize(*behaviorRoot);
}
}
void ModelComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
// ItemComponent Serialization. Pets do not get this serialization.
if (!m_Parent->HasComponent(eReplicaComponentType::PET)) {
@ -74,8 +101,8 @@ void ModelComponent::MoveToInventory(MoveToInventoryMessage& msg) {
// TODO move to the inventory
}
std::array<std::pair<LWOOBJID, std::string>, 5> ModelComponent::GetBehaviorsForSave() const {
std::array<std::pair<LWOOBJID, std::string>, 5> toReturn;
std::array<std::pair<int32_t, std::string>, 5> ModelComponent::GetBehaviorsForSave() const {
std::array<std::pair<int32_t, std::string>, 5> toReturn{};
for (auto i = 0; i < m_Behaviors.size(); i++) {
const auto& behavior = m_Behaviors.at(i);
if (behavior.GetBehaviorId() == -1) continue;
@ -86,7 +113,7 @@ std::array<std::pair<LWOOBJID, std::string>, 5> ModelComponent::GetBehaviorsForS
behavior.Serialize(*root);
doc.InsertFirstChild(root);
tinyxml2::XMLPrinter printer(0, false, 0);
tinyxml2::XMLPrinter printer(0, true, 0);
doc.Print(&printer);
behaviorData = printer.CStr();
}

View File

@ -28,6 +28,8 @@ public:
ModelComponent(Entity* parent);
void LoadBehaviors();
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
/**
@ -109,7 +111,7 @@ public:
void VerifyBehaviors();
std::array<std::pair<LWOOBJID, std::string>, 5> GetBehaviorsForSave() const;
std::array<std::pair<int32_t, std::string>, 5> GetBehaviorsForSave() const;
private:
/**

View File

@ -595,6 +595,17 @@ void PropertyManagementComponent::Load() {
settings.push_back(new LDFData<int>(u"componentWhitelist", 1));
}
std::ostringstream userModelBehavior;
bool firstAdded = false;
for (const auto& behavior : databaseModel.behaviors) {
if (behavior == LWOOBJID_EMPTY) continue;
if (firstAdded) userModelBehavior << ",";
userModelBehavior << behavior;
firstAdded = true;
}
settings.push_back(new LDFData<std::string>(u"userModelBehaviors", userModelBehavior.str()));
node->config = settings;
const auto spawnerId = Game::zoneManager->MakeSpawner(info);
@ -638,7 +649,7 @@ void PropertyManagementComponent::Save() {
// save the behaviors of the model
for (const auto& [behaviorId, behaviorStr] : modelBehaviors) {
if (behaviorStr.empty() || behaviorId == LWOOBJID_EMPTY) continue;
if (behaviorStr.empty() || behaviorId == -1 || behaviorId == 0) continue;
IBehaviors::Info info {
.behaviorId = behaviorId,
.characterId = character->GetID(),

View File

@ -40,9 +40,40 @@ void Action::Serialize(tinyxml2::XMLElement& action) const {
if (m_ValueParameterName.empty()) return;
action.SetAttribute("ValueParameterName", m_ValueParameterName.c_str());
if (m_ValueParameterName == "Message") {
action.SetAttribute(m_ValueParameterName.c_str(), m_ValueParameterString.c_str());
action.SetAttribute("Value", m_ValueParameterString.c_str());
} else {
action.SetAttribute(m_ValueParameterName.c_str(), m_ValueParameterDouble);
action.SetAttribute("Value", m_ValueParameterDouble);
}
}
void Action::Deserialize(const tinyxml2::XMLElement& action) {
const char* type = nullptr;
action.QueryAttribute("Type", &type);
if (!type) {
LOG("No type found for an action?");
return;
}
m_Type = type;
const char* valueParameterName = nullptr;
action.QueryAttribute("ValueParameterName", &valueParameterName);
if (valueParameterName) {
m_ValueParameterName = valueParameterName;
if (m_ValueParameterName == "Message") {
const char* value = nullptr;
action.QueryAttribute("Value", &value);
if (value) {
m_ValueParameterString = value;
} else {
LOG("No value found for an action message?");
}
} else {
action.QueryDoubleAttribute("Value", &m_ValueParameterDouble);
}
}
}

View File

@ -25,6 +25,7 @@ public:
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
void Serialize(tinyxml2::XMLElement& action) const;
void Deserialize(const tinyxml2::XMLElement& action);
private:
double m_ValueParameterDouble{ 0.0 };
std::string m_Type{ "" };

View File

@ -27,3 +27,8 @@ void StripUiPosition::Serialize(tinyxml2::XMLElement& position) const {
position.SetAttribute("x", m_XPosition);
position.SetAttribute("y", m_YPosition);
}
void StripUiPosition::Deserialize(const tinyxml2::XMLElement& position) {
position.QueryDoubleAttribute("x", &m_XPosition);
position.QueryDoubleAttribute("y", &m_YPosition);
}

View File

@ -20,6 +20,7 @@ public:
[[nodiscard]] double GetY() const noexcept { return m_YPosition; }
void Serialize(tinyxml2::XMLElement& position) const;
void Deserialize(const tinyxml2::XMLElement& position);
private:
double m_XPosition{ 0.0 };
double m_YPosition{ 0.0 };

View File

@ -139,3 +139,17 @@ void PropertyBehavior::Serialize(tinyxml2::XMLElement& behavior) const {
state.Serialize(*stateElement);
}
}
void PropertyBehavior::Deserialize(const tinyxml2::XMLElement& behavior) {
m_Name = behavior.Attribute("name");
behavior.QueryBoolAttribute("isLocked", &isLocked);
behavior.QueryBoolAttribute("isLoot", &isLoot);
for (const auto* stateElement = behavior.FirstChildElement("State"); stateElement; stateElement = stateElement->NextSiblingElement("State")) {
int32_t stateId = -1;
stateElement->QueryIntAttribute("id", &stateId);
if (stateId < 0 || stateId > 5) continue;
m_States[static_cast<BehaviorState>(stateId)].Deserialize(*stateElement);
}
}

View File

@ -30,6 +30,7 @@ public:
void SetBehaviorId(int32_t id) noexcept { m_BehaviorId = id; }
void Serialize(tinyxml2::XMLElement& behavior) const;
void Deserialize(const tinyxml2::XMLElement& behavior);
private:
// The states this behavior has.

View File

@ -145,3 +145,10 @@ void State::Serialize(tinyxml2::XMLElement& state) const {
strip.Serialize(*stripElement);
}
}
void State::Deserialize(const tinyxml2::XMLElement& state) {
for (const auto* stripElement = state.FirstChildElement("Strip"); stripElement; stripElement = stripElement->NextSiblingElement("Strip")) {
auto& strip = m_Strips.emplace_back();
strip.Deserialize(*stripElement);
}
}

View File

@ -18,6 +18,7 @@ public:
bool IsEmpty() const;
void Serialize(tinyxml2::XMLElement& state) const;
void Deserialize(const tinyxml2::XMLElement& state);
private:
std::vector<Strip> m_Strips;
};

View File

@ -94,3 +94,15 @@ void Strip::Serialize(tinyxml2::XMLElement& strip) const {
action.Serialize(*actionElement);
}
}
void Strip::Deserialize(const tinyxml2::XMLElement& strip) {
const auto* positionElement = strip.FirstChildElement("Position");
if (positionElement) {
m_Position.Deserialize(*positionElement);
}
for (const auto* actionElement = strip.FirstChildElement("Action"); actionElement; actionElement = actionElement->NextSiblingElement("Action")) {
auto& action = m_Actions.emplace_back();
action.Deserialize(*actionElement);
}
}

View File

@ -21,6 +21,7 @@ public:
bool IsEmpty() const noexcept { return m_Actions.empty(); }
void Serialize(tinyxml2::XMLElement& strip) const;
void Deserialize(const tinyxml2::XMLElement& strip);
private:
std::vector<Action> m_Actions;
StripUiPosition m_Position;