mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-17 12:04:27 -06:00
Compare commits
15 Commits
waypointpa
...
reset-enti
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e76d70c9c4 | ||
|
|
1f580491c7 | ||
|
|
2618e9a864 | ||
|
|
0f0d0a6dee | ||
|
|
f63a9a6bea | ||
|
|
f0f98a6108 | ||
|
|
4ed7bd6767 | ||
|
|
9f92f48a0f | ||
|
|
48e3471831 | ||
|
|
3c244cce27 | ||
|
|
8ba35be64d | ||
|
|
f7c9267ba4 | ||
|
|
b6e9d6872d | ||
|
|
c83797984a | ||
|
|
04487efa25 |
@@ -20,6 +20,7 @@ set(DCOMMON_SOURCES
|
||||
"TinyXmlUtils.cpp"
|
||||
"Sd0.cpp"
|
||||
"Lxfml.cpp"
|
||||
"LxfmlBugged.cpp"
|
||||
)
|
||||
|
||||
# Workaround for compiler bug where the optimized code could result in a memcpy of 0 bytes, even though that isnt possible.
|
||||
|
||||
@@ -27,7 +27,7 @@ Lxfml::Result Lxfml::NormalizePosition(const std::string_view data) {
|
||||
// First get all the positions of bricks
|
||||
for (const auto& brick : lxfml["Bricks"]) {
|
||||
const auto* part = brick.FirstChildElement("Part");
|
||||
if (part) {
|
||||
while (part) {
|
||||
const auto* bone = part->FirstChildElement("Bone");
|
||||
if (bone) {
|
||||
auto* transformation = bone->Attribute("transformation");
|
||||
@@ -36,6 +36,7 @@ Lxfml::Result Lxfml::NormalizePosition(const std::string_view data) {
|
||||
if (refID) transformations[refID] = transformation;
|
||||
}
|
||||
}
|
||||
part = part->NextSiblingElement("Part");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +93,7 @@ Lxfml::Result Lxfml::NormalizePosition(const std::string_view data) {
|
||||
// Finally write the new transformation back into the lxfml
|
||||
for (auto& brick : lxfml["Bricks"]) {
|
||||
auto* part = brick.FirstChildElement("Part");
|
||||
if (part) {
|
||||
while (part) {
|
||||
auto* bone = part->FirstChildElement("Bone");
|
||||
if (bone) {
|
||||
auto* transformation = bone->Attribute("transformation");
|
||||
@@ -103,6 +104,7 @@ Lxfml::Result Lxfml::NormalizePosition(const std::string_view data) {
|
||||
}
|
||||
}
|
||||
}
|
||||
part = part->NextSiblingElement("Part");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,10 @@ namespace Lxfml {
|
||||
// Normalizes a LXFML model to be positioned relative to its local 0, 0, 0 rather than a game worlds 0, 0, 0.
|
||||
// Returns a struct of its new center and the updated LXFML containing these edits.
|
||||
[[nodiscard]] Result NormalizePosition(const std::string_view data);
|
||||
|
||||
// these are only for the migrations due to a bug in one of the implementations.
|
||||
[[nodiscard]] Result NormalizePositionOnlyFirstPart(const std::string_view data);
|
||||
[[nodiscard]] Result NormalizePositionAfterFirstPart(const std::string_view data, const NiPoint3& position);
|
||||
};
|
||||
|
||||
#endif //!LXFML_H
|
||||
|
||||
210
dCommon/LxfmlBugged.cpp
Normal file
210
dCommon/LxfmlBugged.cpp
Normal file
@@ -0,0 +1,210 @@
|
||||
#include "Lxfml.h"
|
||||
|
||||
#include "GeneralUtils.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "TinyXmlUtils.h"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
// this file should not be touched
|
||||
|
||||
Lxfml::Result Lxfml::NormalizePositionOnlyFirstPart(const std::string_view data) {
|
||||
Result toReturn;
|
||||
tinyxml2::XMLDocument doc;
|
||||
const auto err = doc.Parse(data.data());
|
||||
if (err != tinyxml2::XML_SUCCESS) {
|
||||
LOG("Failed to parse xml %s.", StringifiedEnum::ToString(err).data());
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
TinyXmlUtils::DocumentReader reader(doc);
|
||||
std::map<std::string/* refID */, std::string> transformations;
|
||||
|
||||
auto lxfml = reader["LXFML"];
|
||||
if (!lxfml) {
|
||||
LOG("Failed to find LXFML element.");
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
// First get all the positions of bricks
|
||||
for (const auto& brick : lxfml["Bricks"]) {
|
||||
const auto* part = brick.FirstChildElement("Part");
|
||||
if (part) {
|
||||
const auto* bone = part->FirstChildElement("Bone");
|
||||
if (bone) {
|
||||
auto* transformation = bone->Attribute("transformation");
|
||||
if (transformation) {
|
||||
auto* refID = bone->Attribute("refID");
|
||||
if (refID) transformations[refID] = transformation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// These points are well out of bounds for an actual player
|
||||
NiPoint3 lowest{ 10'000.0f, 10'000.0f, 10'000.0f };
|
||||
NiPoint3 highest{ -10'000.0f, -10'000.0f, -10'000.0f };
|
||||
|
||||
// Calculate the lowest and highest points on the entire model
|
||||
for (const auto& transformation : transformations | std::views::values) {
|
||||
auto split = GeneralUtils::SplitString(transformation, ',');
|
||||
if (split.size() < 12) {
|
||||
LOG("Not enough in the split?");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto x = GeneralUtils::TryParse<float>(split[9]).value();
|
||||
auto y = GeneralUtils::TryParse<float>(split[10]).value();
|
||||
auto z = GeneralUtils::TryParse<float>(split[11]).value();
|
||||
if (x < lowest.x) lowest.x = x;
|
||||
if (y < lowest.y) lowest.y = y;
|
||||
if (z < lowest.z) lowest.z = z;
|
||||
|
||||
if (highest.x < x) highest.x = x;
|
||||
if (highest.y < y) highest.y = y;
|
||||
if (highest.z < z) highest.z = z;
|
||||
}
|
||||
|
||||
auto delta = (highest - lowest) / 2.0f;
|
||||
auto newRootPos = lowest + delta;
|
||||
|
||||
// Clamp the Y to the lowest point on the model
|
||||
newRootPos.y = lowest.y;
|
||||
|
||||
// Adjust all positions to account for the new origin
|
||||
for (auto& transformation : transformations | std::views::values) {
|
||||
auto split = GeneralUtils::SplitString(transformation, ',');
|
||||
if (split.size() < 12) {
|
||||
LOG("Not enough in the split?");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto x = GeneralUtils::TryParse<float>(split[9]).value() - newRootPos.x;
|
||||
auto y = GeneralUtils::TryParse<float>(split[10]).value() - newRootPos.y;
|
||||
auto z = GeneralUtils::TryParse<float>(split[11]).value() - newRootPos.z;
|
||||
std::stringstream stream;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
stream << split[i];
|
||||
stream << ',';
|
||||
}
|
||||
stream << x << ',' << y << ',' << z;
|
||||
transformation = stream.str();
|
||||
}
|
||||
|
||||
// Finally write the new transformation back into the lxfml
|
||||
for (auto& brick : lxfml["Bricks"]) {
|
||||
auto* part = brick.FirstChildElement("Part");
|
||||
if (part) {
|
||||
auto* bone = part->FirstChildElement("Bone");
|
||||
if (bone) {
|
||||
auto* transformation = bone->Attribute("transformation");
|
||||
if (transformation) {
|
||||
auto* refID = bone->Attribute("refID");
|
||||
if (refID) {
|
||||
bone->SetAttribute("transformation", transformations[refID].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tinyxml2::XMLPrinter printer;
|
||||
doc.Print(&printer);
|
||||
|
||||
toReturn.lxfml = printer.CStr();
|
||||
toReturn.center = newRootPos;
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
Lxfml::Result Lxfml::NormalizePositionAfterFirstPart(const std::string_view data, const NiPoint3& position) {
|
||||
Result toReturn;
|
||||
tinyxml2::XMLDocument doc;
|
||||
const auto err = doc.Parse(data.data());
|
||||
if (err != tinyxml2::XML_SUCCESS) {
|
||||
LOG("Failed to parse xml %s.", StringifiedEnum::ToString(err).data());
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
TinyXmlUtils::DocumentReader reader(doc);
|
||||
std::map<std::string/* refID */, std::string> transformations;
|
||||
|
||||
auto lxfml = reader["LXFML"];
|
||||
if (!lxfml) {
|
||||
LOG("Failed to find LXFML element.");
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
// First get all the positions of bricks
|
||||
for (const auto& brick : lxfml["Bricks"]) {
|
||||
const auto* part = brick.FirstChildElement("Part");
|
||||
bool firstPart = true;
|
||||
while (part) {
|
||||
if (firstPart) {
|
||||
firstPart = false;
|
||||
} else {
|
||||
LOG("Found extra bricks");
|
||||
const auto* bone = part->FirstChildElement("Bone");
|
||||
if (bone) {
|
||||
auto* transformation = bone->Attribute("transformation");
|
||||
if (transformation) {
|
||||
auto* refID = bone->Attribute("refID");
|
||||
if (refID) transformations[refID] = transformation;
|
||||
}
|
||||
}
|
||||
}
|
||||
part = part->NextSiblingElement("Part");
|
||||
}
|
||||
}
|
||||
|
||||
auto newRootPos = position;
|
||||
|
||||
// Adjust all positions to account for the new origin
|
||||
for (auto& transformation : transformations | std::views::values) {
|
||||
auto split = GeneralUtils::SplitString(transformation, ',');
|
||||
if (split.size() < 12) {
|
||||
LOG("Not enough in the split?");
|
||||
continue;
|
||||
}
|
||||
|
||||
auto x = GeneralUtils::TryParse<float>(split[9]).value() - newRootPos.x;
|
||||
auto y = GeneralUtils::TryParse<float>(split[10]).value() - newRootPos.y;
|
||||
auto z = GeneralUtils::TryParse<float>(split[11]).value() - newRootPos.z;
|
||||
std::stringstream stream;
|
||||
for (int i = 0; i < 9; i++) {
|
||||
stream << split[i];
|
||||
stream << ',';
|
||||
}
|
||||
stream << x << ',' << y << ',' << z;
|
||||
transformation = stream.str();
|
||||
}
|
||||
|
||||
// Finally write the new transformation back into the lxfml
|
||||
for (auto& brick : lxfml["Bricks"]) {
|
||||
auto* part = brick.FirstChildElement("Part");
|
||||
bool firstPart = true;
|
||||
while (part) {
|
||||
if (firstPart) {
|
||||
firstPart = false;
|
||||
} else {
|
||||
auto* bone = part->FirstChildElement("Bone");
|
||||
if (bone) {
|
||||
auto* transformation = bone->Attribute("transformation");
|
||||
if (transformation) {
|
||||
auto* refID = bone->Attribute("refID");
|
||||
if (refID) {
|
||||
bone->SetAttribute("transformation", transformations[refID].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
part = part->NextSiblingElement("Part");
|
||||
}
|
||||
}
|
||||
|
||||
tinyxml2::XMLPrinter printer;
|
||||
doc.Print(&printer);
|
||||
|
||||
toReturn.lxfml = printer.CStr();
|
||||
toReturn.center = newRootPos;
|
||||
return toReturn;
|
||||
}
|
||||
@@ -8,15 +8,15 @@
|
||||
class IBehaviors {
|
||||
public:
|
||||
struct Info {
|
||||
int32_t behaviorId{};
|
||||
LWOOBJID 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 std::string GetBehavior(const int32_t behaviorId) = 0;
|
||||
virtual void RemoveBehavior(const int32_t behaviorId) = 0;
|
||||
virtual std::string GetBehavior(const LWOOBJID behaviorId) = 0;
|
||||
virtual void RemoveBehavior(const LWOOBJID behaviorId) = 0;
|
||||
};
|
||||
|
||||
#endif //!IBEHAVIORS_H
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
LWOOBJID id{};
|
||||
LOT lot{};
|
||||
uint32_t ugcId{};
|
||||
std::array<int32_t, 5> behaviors{};
|
||||
std::array<LWOOBJID, 5> behaviors{};
|
||||
};
|
||||
|
||||
// Inserts a new UGC model into the database.
|
||||
@@ -34,9 +34,9 @@ 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& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) = 0;
|
||||
virtual void UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<int32_t, 5> behaviorIDs) {
|
||||
std::array<std::pair<int32_t, std::string>, 5> behaviors;
|
||||
virtual void UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, std::string>, 5>& behaviors) = 0;
|
||||
virtual void UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<LWOOBJID, 5> behaviorIDs) {
|
||||
std::array<std::pair<LWOOBJID, std::string>, 5> behaviors;
|
||||
for (int32_t i = 0; i < behaviors.size(); i++) behaviors[i].first = behaviorIDs[i];
|
||||
UpdateModel(modelID, position, rotation, behaviors);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,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& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) override;
|
||||
void UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, 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;
|
||||
@@ -110,8 +110,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;
|
||||
std::string GetBehavior(const int32_t behaviorId) override;
|
||||
void RemoveBehavior(const int32_t characterId) override;
|
||||
std::string GetBehavior(const LWOOBJID behaviorId) override;
|
||||
void RemoveBehavior(const LWOOBJID characterId) override;
|
||||
void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) override;
|
||||
std::optional<IProperty::PropertyEntranceResult> GetProperties(const IProperty::PropertyLookup& params) override;
|
||||
std::vector<ILeaderboard::Entry> GetDescendingLeaderboard(const uint32_t activityId) override;
|
||||
|
||||
@@ -9,11 +9,11 @@ void MySQLDatabase::AddBehavior(const IBehaviors::Info& info) {
|
||||
);
|
||||
}
|
||||
|
||||
void MySQLDatabase::RemoveBehavior(const int32_t behaviorId) {
|
||||
void MySQLDatabase::RemoveBehavior(const LWOOBJID behaviorId) {
|
||||
ExecuteDelete("DELETE FROM behaviors WHERE behavior_id = ?", behaviorId);
|
||||
}
|
||||
|
||||
std::string MySQLDatabase::GetBehavior(const int32_t behaviorId) {
|
||||
std::string MySQLDatabase::GetBehavior(const LWOOBJID behaviorId) {
|
||||
auto result = ExecuteSelect("SELECT behavior_info FROM behaviors WHERE behavior_id = ?", behaviorId);
|
||||
return result->next() ? result->getString("behavior_info").c_str() : "";
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@ 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");
|
||||
model.behaviors[0] = result->getUInt64("behavior_1");
|
||||
model.behaviors[1] = result->getUInt64("behavior_2");
|
||||
model.behaviors[2] = result->getUInt64("behavior_3");
|
||||
model.behaviors[3] = result->getUInt64("behavior_4");
|
||||
model.behaviors[4] = result->getUInt64("behavior_5");
|
||||
|
||||
toReturn.push_back(std::move(model));
|
||||
}
|
||||
@@ -52,7 +52,7 @@ void MySQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const IPr
|
||||
}
|
||||
}
|
||||
|
||||
void MySQLDatabase::UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) {
|
||||
void MySQLDatabase::UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, 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 = ?;",
|
||||
@@ -79,11 +79,11 @@ IPropertyContents::Model MySQLDatabase::GetModel(const LWOOBJID modelID) {
|
||||
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");
|
||||
model.behaviors[0] = result->getUInt64("behavior_1");
|
||||
model.behaviors[1] = result->getUInt64("behavior_2");
|
||||
model.behaviors[2] = result->getUInt64("behavior_3");
|
||||
model.behaviors[3] = result->getUInt64("behavior_4");
|
||||
model.behaviors[4] = result->getUInt64("behavior_5");
|
||||
}
|
||||
|
||||
return model;
|
||||
|
||||
@@ -73,7 +73,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& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) override;
|
||||
void UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, 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;
|
||||
@@ -108,8 +108,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;
|
||||
std::string GetBehavior(const int32_t behaviorId) override;
|
||||
void RemoveBehavior(const int32_t characterId) override;
|
||||
std::string GetBehavior(const LWOOBJID behaviorId) override;
|
||||
void RemoveBehavior(const LWOOBJID characterId) override;
|
||||
void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) override;
|
||||
std::optional<IProperty::PropertyEntranceResult> GetProperties(const IProperty::PropertyLookup& params) override;
|
||||
std::vector<ILeaderboard::Entry> GetDescendingLeaderboard(const uint32_t activityId) override;
|
||||
|
||||
@@ -9,11 +9,11 @@ void SQLiteDatabase::AddBehavior(const IBehaviors::Info& info) {
|
||||
);
|
||||
}
|
||||
|
||||
void SQLiteDatabase::RemoveBehavior(const int32_t behaviorId) {
|
||||
void SQLiteDatabase::RemoveBehavior(const LWOOBJID behaviorId) {
|
||||
ExecuteDelete("DELETE FROM behaviors WHERE behavior_id = ?", behaviorId);
|
||||
}
|
||||
|
||||
std::string SQLiteDatabase::GetBehavior(const int32_t behaviorId) {
|
||||
std::string SQLiteDatabase::GetBehavior(const LWOOBJID behaviorId) {
|
||||
auto [_, result] = ExecuteSelect("SELECT behavior_info FROM behaviors WHERE behavior_id = ?", behaviorId);
|
||||
return !result.eof() ? result.getStringField("behavior_info") : "";
|
||||
}
|
||||
|
||||
@@ -19,11 +19,11 @@ std::vector<IPropertyContents::Model> SQLiteDatabase::GetPropertyModels(const LW
|
||||
model.rotation.y = result.getFloatField("ry");
|
||||
model.rotation.z = result.getFloatField("rz");
|
||||
model.ugcId = result.getInt64Field("ugc_id");
|
||||
model.behaviors[0] = result.getIntField("behavior_1");
|
||||
model.behaviors[1] = result.getIntField("behavior_2");
|
||||
model.behaviors[2] = result.getIntField("behavior_3");
|
||||
model.behaviors[3] = result.getIntField("behavior_4");
|
||||
model.behaviors[4] = result.getIntField("behavior_5");
|
||||
model.behaviors[0] = result.getInt64Field("behavior_1");
|
||||
model.behaviors[1] = result.getInt64Field("behavior_2");
|
||||
model.behaviors[2] = result.getInt64Field("behavior_3");
|
||||
model.behaviors[3] = result.getInt64Field("behavior_4");
|
||||
model.behaviors[4] = result.getInt64Field("behavior_5");
|
||||
|
||||
toReturn.push_back(std::move(model));
|
||||
result.nextRow();
|
||||
@@ -52,7 +52,7 @@ void SQLiteDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const IP
|
||||
}
|
||||
}
|
||||
|
||||
void SQLiteDatabase::UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) {
|
||||
void SQLiteDatabase::UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, 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 = ?;",
|
||||
@@ -80,11 +80,11 @@ IPropertyContents::Model SQLiteDatabase::GetModel(const LWOOBJID modelID) {
|
||||
model.rotation.y = result.getFloatField("ry");
|
||||
model.rotation.z = result.getFloatField("rz");
|
||||
model.ugcId = result.getInt64Field("ugc_id");
|
||||
model.behaviors[0] = result.getIntField("behavior_1");
|
||||
model.behaviors[1] = result.getIntField("behavior_2");
|
||||
model.behaviors[2] = result.getIntField("behavior_3");
|
||||
model.behaviors[3] = result.getIntField("behavior_4");
|
||||
model.behaviors[4] = result.getIntField("behavior_5");
|
||||
model.behaviors[0] = result.getInt64Field("behavior_1");
|
||||
model.behaviors[1] = result.getInt64Field("behavior_2");
|
||||
model.behaviors[2] = result.getInt64Field("behavior_3");
|
||||
model.behaviors[3] = result.getInt64Field("behavior_4");
|
||||
model.behaviors[4] = result.getInt64Field("behavior_5");
|
||||
} while (result.nextRow());
|
||||
}
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ void TestSQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const I
|
||||
|
||||
}
|
||||
|
||||
void TestSQLDatabase::UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) {
|
||||
void TestSQLDatabase::UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, std::string>, 5>& behaviors) {
|
||||
|
||||
}
|
||||
|
||||
@@ -292,11 +292,11 @@ void TestSQLDatabase::AddBehavior(const IBehaviors::Info& info) {
|
||||
|
||||
}
|
||||
|
||||
std::string TestSQLDatabase::GetBehavior(const int32_t behaviorId) {
|
||||
std::string TestSQLDatabase::GetBehavior(const LWOOBJID behaviorId) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void TestSQLDatabase::RemoveBehavior(const int32_t behaviorId) {
|
||||
void TestSQLDatabase::RemoveBehavior(const LWOOBJID behaviorId) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ class TestSQLDatabase : public GameDatabase {
|
||||
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& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) override;
|
||||
void UpdateModel(const LWOOBJID& modelID, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<LWOOBJID, 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;
|
||||
@@ -87,8 +87,8 @@ class TestSQLDatabase : public GameDatabase {
|
||||
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;
|
||||
std::string GetBehavior(const int32_t behaviorId) override;
|
||||
void RemoveBehavior(const int32_t behaviorId) override;
|
||||
std::string GetBehavior(const LWOOBJID behaviorId) override;
|
||||
void RemoveBehavior(const LWOOBJID behaviorId) override;
|
||||
void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) override;
|
||||
std::optional<IProperty::PropertyEntranceResult> GetProperties(const IProperty::PropertyLookup& params) override { return {}; };
|
||||
std::vector<ILeaderboard::Entry> GetDescendingLeaderboard(const uint32_t activityId) override { return {}; };
|
||||
|
||||
@@ -47,6 +47,7 @@ void MigrationRunner::RunMigrations() {
|
||||
std::string finalSQL = "";
|
||||
bool runSd0Migrations = false;
|
||||
bool runNormalizeMigrations = false;
|
||||
bool runNormalizeAfterFirstPartMigrations = false;
|
||||
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/" / migrationFolder).string())) {
|
||||
auto migration = LoadMigration("dlu/" + migrationFolder + "/", entry);
|
||||
|
||||
@@ -61,6 +62,8 @@ void MigrationRunner::RunMigrations() {
|
||||
runSd0Migrations = true;
|
||||
} else if (migration.name.ends_with("_normalize_model_positions.sql")) {
|
||||
runNormalizeMigrations = true;
|
||||
} else if (migration.name.ends_with("_normalize_model_positions_after_first_part.sql")) {
|
||||
runNormalizeAfterFirstPartMigrations = true;
|
||||
} else {
|
||||
finalSQL.append(migration.data.c_str());
|
||||
}
|
||||
@@ -68,7 +71,7 @@ void MigrationRunner::RunMigrations() {
|
||||
Database::Get()->InsertMigration(migration.name);
|
||||
}
|
||||
|
||||
if (finalSQL.empty() && !runSd0Migrations && !runNormalizeMigrations) {
|
||||
if (finalSQL.empty() && !runSd0Migrations && !runNormalizeMigrations && !runNormalizeAfterFirstPartMigrations) {
|
||||
LOG("Server database is up to date.");
|
||||
return;
|
||||
}
|
||||
@@ -96,6 +99,10 @@ void MigrationRunner::RunMigrations() {
|
||||
if (runNormalizeMigrations) {
|
||||
ModelNormalizeMigration::Run();
|
||||
}
|
||||
|
||||
if (runNormalizeAfterFirstPartMigrations) {
|
||||
ModelNormalizeMigration::RunAfterFirstPart();
|
||||
}
|
||||
}
|
||||
|
||||
void MigrationRunner::RunSQLiteMigrations() {
|
||||
|
||||
@@ -14,7 +14,7 @@ void ModelNormalizeMigration::Run() {
|
||||
|
||||
Sd0 sd0(lxfmlData);
|
||||
const auto asStr = sd0.GetAsStringUncompressed();
|
||||
const auto [newLxfml, newCenter] = Lxfml::NormalizePosition(asStr);
|
||||
const auto [newLxfml, newCenter] = Lxfml::NormalizePositionOnlyFirstPart(asStr);
|
||||
if (newCenter == NiPoint3Constant::ZERO) {
|
||||
LOG("Failed to update model %llu due to failure reading xml.");
|
||||
continue;
|
||||
@@ -28,3 +28,23 @@ void ModelNormalizeMigration::Run() {
|
||||
}
|
||||
Database::Get()->SetAutoCommit(oldCommit);
|
||||
}
|
||||
|
||||
void ModelNormalizeMigration::RunAfterFirstPart() {
|
||||
const auto oldCommit = Database::Get()->GetAutoCommit();
|
||||
Database::Get()->SetAutoCommit(false);
|
||||
for (auto& [lxfmlData, id, modelID] : Database::Get()->GetAllUgcModels()) {
|
||||
const auto model = Database::Get()->GetModel(modelID);
|
||||
// only BBB models (lot 14) need to have their position fixed from the above blunder
|
||||
if (model.lot != 14) continue;
|
||||
|
||||
Sd0 sd0(lxfmlData);
|
||||
const auto asStr = sd0.GetAsStringUncompressed();
|
||||
const auto [newLxfml, newCenter] = Lxfml::NormalizePositionAfterFirstPart(asStr, model.position);
|
||||
|
||||
sd0.FromData(reinterpret_cast<const uint8_t*>(newLxfml.data()), newLxfml.size());
|
||||
auto asStream = sd0.GetAsStream();
|
||||
Database::Get()->UpdateModel(model.id, newCenter, model.rotation, model.behaviors);
|
||||
Database::Get()->UpdateUgcModelData(id, asStream);
|
||||
}
|
||||
Database::Get()->SetAutoCommit(oldCommit);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
namespace ModelNormalizeMigration {
|
||||
void Run();
|
||||
void RunAfterFirstPart();
|
||||
};
|
||||
|
||||
#endif //!MODELNORMALIZEMIGRATION_H
|
||||
|
||||
534
dGame/Entity.cpp
534
dGame/Entity.cpp
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,6 @@ namespace tinyxml2 {
|
||||
};
|
||||
|
||||
class Player;
|
||||
class EntityInfo;
|
||||
class User;
|
||||
class Spawner;
|
||||
class ScriptComponent;
|
||||
@@ -45,6 +44,7 @@ class Item;
|
||||
class Character;
|
||||
class EntityCallbackTimer;
|
||||
class PositionUpdate;
|
||||
struct EntityInfo;
|
||||
enum class eTriggerEventType;
|
||||
enum class eGameMasterLevel : uint8_t;
|
||||
enum class eReplicaComponentType : uint32_t;
|
||||
@@ -60,7 +60,7 @@ namespace CppScripts {
|
||||
*/
|
||||
class Entity {
|
||||
public:
|
||||
explicit Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser = nullptr, Entity* parentEntity = nullptr);
|
||||
Entity(const LWOOBJID& objectID, const EntityInfo& info, User* parentUser = nullptr, Entity* parentEntity = nullptr);
|
||||
~Entity();
|
||||
|
||||
void Initialize();
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
|
||||
float GetDefaultScale() const;
|
||||
|
||||
const NiPoint3& GetPosition() const;
|
||||
NiPoint3 GetPosition() const;
|
||||
|
||||
const NiQuaternion& GetRotation() const;
|
||||
|
||||
@@ -146,9 +146,9 @@ public:
|
||||
|
||||
void SetRotation(const NiQuaternion& rotation);
|
||||
|
||||
void SetRespawnPos(const NiPoint3& position);
|
||||
void SetRespawnPos(const NiPoint3& position) const;
|
||||
|
||||
void SetRespawnRot(const NiQuaternion& rotation);
|
||||
void SetRespawnRot(const NiQuaternion& rotation) const;
|
||||
|
||||
void SetVelocity(const NiPoint3& velocity);
|
||||
|
||||
@@ -169,7 +169,7 @@ public:
|
||||
void AddComponent(eReplicaComponentType componentId, Component* component);
|
||||
|
||||
// This is expceted to never return nullptr, an assert checks this.
|
||||
CppScripts::Script* const GetScript();
|
||||
CppScripts::Script* const GetScript() const;
|
||||
|
||||
void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName);
|
||||
void Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName);
|
||||
@@ -182,8 +182,8 @@ public:
|
||||
void RemoveParent();
|
||||
|
||||
// Adds a timer to start next frame with the given name and time.
|
||||
void AddTimer(std::string name, float time);
|
||||
void AddCallbackTimer(float time, std::function<void()> callback);
|
||||
void AddTimer(const std::string& name, float time);
|
||||
void AddCallbackTimer(float time, const std::function<void()> callback);
|
||||
bool HasTimer(const std::string& name);
|
||||
void CancelCallbackTimers();
|
||||
void CancelAllTimers();
|
||||
@@ -195,7 +195,7 @@ public:
|
||||
std::unordered_map<eReplicaComponentType, Component*>& GetComponents() { return m_Components; } // TODO: Remove
|
||||
|
||||
void WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacketType packetType);
|
||||
void WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType packetType);
|
||||
void WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType packetType) const;
|
||||
void UpdateXMLDoc(tinyxml2::XMLDocument& doc);
|
||||
void Update(float deltaTime);
|
||||
|
||||
@@ -242,21 +242,21 @@ public:
|
||||
void AddDieCallback(const std::function<void()>& callback);
|
||||
void Resurrect();
|
||||
|
||||
void AddLootItem(const Loot::Info& info);
|
||||
void PickupItem(const LWOOBJID& objectID);
|
||||
void AddLootItem(const Loot::Info& info) const;
|
||||
void PickupItem(const LWOOBJID& objectID) const;
|
||||
|
||||
bool CanPickupCoins(uint64_t count);
|
||||
void RegisterCoinDrop(uint64_t count);
|
||||
bool PickupCoins(uint64_t count) const;
|
||||
void RegisterCoinDrop(uint64_t count) const;
|
||||
|
||||
void ScheduleKillAfterUpdate(Entity* murderer = nullptr);
|
||||
void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr);
|
||||
void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr) const;
|
||||
void ScheduleDestructionAfterUpdate() { m_ShouldDestroyAfterUpdate = true; }
|
||||
|
||||
const NiPoint3& GetRespawnPosition() const;
|
||||
const NiQuaternion& GetRespawnRotation() const;
|
||||
|
||||
void Sleep();
|
||||
void Wake();
|
||||
void Sleep() const;
|
||||
void Wake() const;
|
||||
bool IsSleeping() const;
|
||||
|
||||
/*
|
||||
@@ -266,7 +266,7 @@ public:
|
||||
* Retroactively corrects the model vault size due to incorrect initialization in a previous patch.
|
||||
*
|
||||
*/
|
||||
void RetroactiveVaultSize();
|
||||
void RetroactiveVaultSize() const;
|
||||
bool GetBoolean(const std::u16string& name) const;
|
||||
int32_t GetI32(const std::u16string& name) const;
|
||||
int64_t GetI64(const std::u16string& name) const;
|
||||
@@ -334,7 +334,8 @@ public:
|
||||
*/
|
||||
static Observable<Entity*, const PositionUpdate&> OnPlayerPositionUpdate;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void WriteLDFData(const std::vector<LDFBaseData*>& ldf, RakNet::BitStream& outBitStream) const;
|
||||
LWOOBJID m_ObjectID;
|
||||
|
||||
LOT m_TemplateID;
|
||||
@@ -357,7 +358,6 @@ protected:
|
||||
Entity* m_ParentEntity; //For spawners and the like
|
||||
std::vector<Entity*> m_ChildEntities;
|
||||
eGameMasterLevel m_GMLevel;
|
||||
uint16_t m_CollectibleID;
|
||||
std::vector<std::string> m_Groups;
|
||||
uint16_t m_NetworkID;
|
||||
std::vector<std::function<void()>> m_DieCallbacks;
|
||||
@@ -383,6 +383,8 @@ protected:
|
||||
|
||||
bool m_IsParentChildDirty = true;
|
||||
|
||||
bool m_IsSleeping = false;
|
||||
|
||||
/*
|
||||
* Collision
|
||||
*/
|
||||
@@ -391,7 +393,7 @@ protected:
|
||||
// objectID of receiver and map of notification name to script
|
||||
std::map<LWOOBJID, std::map<std::string, CppScripts::Script*>> m_Subscriptions;
|
||||
|
||||
std::multimap<MessageType::Game, std::function<bool(GameMessages::GameMsg&)>> m_MsgHandlers;
|
||||
std::unordered_multimap<MessageType::Game, std::function<bool(GameMessages::GameMsg&)>> m_MsgHandlers;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -394,7 +394,7 @@ void EntityManager::ConstructAllEntities(const SystemAddress& sysAddr) {
|
||||
}
|
||||
}
|
||||
|
||||
UpdateGhosting(PlayerManager::GetPlayer(sysAddr));
|
||||
UpdateGhosting(PlayerManager::GetPlayer(sysAddr), true);
|
||||
}
|
||||
|
||||
void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) {
|
||||
@@ -417,7 +417,7 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr)
|
||||
|
||||
void EntityManager::SerializeEntity(Entity* entity) {
|
||||
if (!entity) return;
|
||||
|
||||
|
||||
EntityManager::SerializeEntity(*entity);
|
||||
}
|
||||
|
||||
@@ -463,7 +463,7 @@ void EntityManager::UpdateGhosting() {
|
||||
m_PlayersToUpdateGhosting.clear();
|
||||
}
|
||||
|
||||
void EntityManager::UpdateGhosting(Entity* player) {
|
||||
void EntityManager::UpdateGhosting(Entity* player, const bool constructAll) {
|
||||
if (!player) return;
|
||||
|
||||
auto* missionComponent = player->GetComponent<MissionComponent>();
|
||||
@@ -511,9 +511,12 @@ void EntityManager::UpdateGhosting(Entity* player) {
|
||||
|
||||
ghostComponent->ObserveEntity(id);
|
||||
|
||||
ConstructEntity(entity, player->GetSystemAddress());
|
||||
|
||||
entity->SetObservers(entity->GetObservers() + 1);
|
||||
|
||||
// TODO: figure out if zone control should be ghosted at all
|
||||
if (constructAll && entity->GetObjectID() == GetZoneControlEntity()->GetObjectID()) continue;
|
||||
|
||||
ConstructEntity(entity, player->GetSystemAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "dCommonVars.h"
|
||||
|
||||
class Entity;
|
||||
class EntityInfo;
|
||||
struct EntityInfo;
|
||||
class Player;
|
||||
class User;
|
||||
enum class eReplicaComponentType : uint32_t;
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
void SetGhostDistanceMin(float value);
|
||||
void QueueGhostUpdate(LWOOBJID playerID);
|
||||
void UpdateGhosting();
|
||||
void UpdateGhosting(Entity* player);
|
||||
void UpdateGhosting(Entity* player, const bool constructAll = false);
|
||||
void CheckGhosting(Entity* entity);
|
||||
Entity* GetGhostCandidate(LWOOBJID id) const;
|
||||
bool GetGhostingEnabled() const;
|
||||
|
||||
@@ -526,7 +526,7 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
|
||||
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneID, character->GetZoneClone(), false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
|
||||
LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort);
|
||||
if (character) {
|
||||
auto* entity = character->GetEntity();
|
||||
auto* entity = Game::entityManager->GetEntity(character->GetObjectID());
|
||||
if (entity) {
|
||||
auto* characterComponent = entity->GetComponent<CharacterComponent>();
|
||||
if (characterComponent) {
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include "BehaviorStates.h"
|
||||
#include "ControlBehaviorMsgs.h"
|
||||
#include "tinyxml2.h"
|
||||
#include "InventoryComponent.h"
|
||||
#include "SimplePhysicsComponent.h"
|
||||
#include "eObjectBits.h"
|
||||
|
||||
#include "Database.h"
|
||||
#include "DluAssert.h"
|
||||
@@ -35,6 +37,7 @@ bool ModelComponent::OnResetModelToDefaults(GameMessages::GameMsg& msg) {
|
||||
m_Parent->SetRotation(m_OriginalRotation);
|
||||
m_Parent->SetVelocity(NiPoint3Constant::ZERO);
|
||||
|
||||
m_Speed = 3.0f;
|
||||
m_NumListeningInteract = 0;
|
||||
m_NumActiveUnSmash = 0;
|
||||
m_Dirty = true;
|
||||
@@ -67,25 +70,30 @@ void ModelComponent::LoadBehaviors() {
|
||||
for (const auto& behavior : behaviors) {
|
||||
if (behavior.empty()) continue;
|
||||
|
||||
const auto behaviorId = GeneralUtils::TryParse<int32_t>(behavior);
|
||||
const auto behaviorId = GeneralUtils::TryParse<LWOOBJID>(behavior);
|
||||
if (!behaviorId.has_value() || behaviorId.value() == 0) continue;
|
||||
|
||||
LOG_DEBUG("Loading behavior %d", behaviorId.value());
|
||||
auto& inserted = m_Behaviors.emplace_back();
|
||||
inserted.SetBehaviorId(*behaviorId);
|
||||
// add behavior at the back
|
||||
LoadBehavior(behaviorId.value(), m_Behaviors.size(), false);
|
||||
}
|
||||
}
|
||||
|
||||
const auto behaviorStr = Database::Get()->GetBehavior(behaviorId.value());
|
||||
void ModelComponent::LoadBehavior(const LWOOBJID behaviorID, const size_t index, const bool isIndexed) {
|
||||
LOG_DEBUG("Loading behavior %d", behaviorID);
|
||||
auto& inserted = *m_Behaviors.emplace(m_Behaviors.begin() + index, PropertyBehavior(isIndexed));
|
||||
inserted.SetBehaviorId(behaviorID);
|
||||
|
||||
tinyxml2::XMLDocument behaviorXml;
|
||||
auto res = behaviorXml.Parse(behaviorStr.c_str(), behaviorStr.size());
|
||||
LOG_DEBUG("Behavior %i %d: %s", res, behaviorId.value(), behaviorStr.c_str());
|
||||
const auto behaviorStr = Database::Get()->GetBehavior(behaviorID);
|
||||
|
||||
const auto* const behaviorRoot = behaviorXml.FirstChildElement("Behavior");
|
||||
if (!behaviorRoot) {
|
||||
LOG("Failed to load behavior %d due to missing behavior root", behaviorId.value());
|
||||
continue;
|
||||
}
|
||||
tinyxml2::XMLDocument behaviorXml;
|
||||
auto res = behaviorXml.Parse(behaviorStr.c_str(), behaviorStr.size());
|
||||
LOG_DEBUG("Behavior %i %llu: %s", res, behaviorID, behaviorStr.c_str());
|
||||
|
||||
const auto* const behaviorRoot = behaviorXml.FirstChildElement("Behavior");
|
||||
if (behaviorRoot) {
|
||||
inserted.Deserialize(*behaviorRoot);
|
||||
} else {
|
||||
LOG("Failed to load behavior %d due to missing behavior root", behaviorID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,8 +124,12 @@ void ModelComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialU
|
||||
if (bIsInitialUpdate) outBitStream.Write0(); // We are not writing model editing info
|
||||
}
|
||||
|
||||
void ModelComponent::UpdatePendingBehaviorId(const int32_t newId) {
|
||||
for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == -1) behavior.SetBehaviorId(newId);
|
||||
void ModelComponent::UpdatePendingBehaviorId(const LWOOBJID newId, const LWOOBJID oldId) {
|
||||
for (auto& behavior : m_Behaviors) {
|
||||
if (behavior.GetBehaviorId() != oldId) continue;
|
||||
behavior.SetBehaviorId(newId);
|
||||
behavior.SetIsLoot(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelComponent::SendBehaviorListToClient(AMFArrayValue& args) const {
|
||||
@@ -134,7 +146,7 @@ void ModelComponent::VerifyBehaviors() {
|
||||
for (auto& behavior : m_Behaviors) behavior.VerifyLastEditedState();
|
||||
}
|
||||
|
||||
void ModelComponent::SendBehaviorBlocksToClient(int32_t behaviorToSend, AMFArrayValue& args) const {
|
||||
void ModelComponent::SendBehaviorBlocksToClient(const LWOOBJID behaviorToSend, AMFArrayValue& args) const {
|
||||
args.Insert("BehaviorID", std::to_string(behaviorToSend));
|
||||
args.Insert("objectID", std::to_string(m_Parent->GetObjectID()));
|
||||
for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == behaviorToSend) behavior.SendBehaviorBlocksToClient(args);
|
||||
@@ -143,8 +155,21 @@ void ModelComponent::SendBehaviorBlocksToClient(int32_t behaviorToSend, AMFArray
|
||||
void ModelComponent::AddBehavior(AddMessage& msg) {
|
||||
// Can only have 1 of the loot behaviors
|
||||
for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == msg.GetBehaviorId()) return;
|
||||
m_Behaviors.insert(m_Behaviors.begin() + msg.GetBehaviorIndex(), PropertyBehavior());
|
||||
m_Behaviors.at(msg.GetBehaviorIndex()).HandleMsg(msg);
|
||||
|
||||
// If we're loading a behavior from an ADD, it is from the database.
|
||||
// Mark it as not modified by default to prevent wasting persistentIDs.
|
||||
LoadBehavior(msg.GetBehaviorId(), msg.GetBehaviorIndex(), true);
|
||||
auto& insertedBehavior = m_Behaviors[msg.GetBehaviorIndex()];
|
||||
|
||||
auto* const playerEntity = Game::entityManager->GetEntity(msg.GetOwningPlayerID());
|
||||
if (playerEntity) {
|
||||
auto* inventoryComponent = playerEntity->GetComponent<InventoryComponent>();
|
||||
if (inventoryComponent) {
|
||||
// Check if this behavior is able to be found via lot (if so, its a loot behavior).
|
||||
insertedBehavior.SetIsLoot(inventoryComponent->FindItemByLot(msg.GetBehaviorId(), eInventoryType::BEHAVIORS));
|
||||
}
|
||||
}
|
||||
|
||||
auto* const simplePhysComponent = m_Parent->GetComponent<SimplePhysicsComponent>();
|
||||
if (simplePhysComponent) {
|
||||
simplePhysComponent->SetPhysicsMotionState(1);
|
||||
@@ -152,8 +177,41 @@ void ModelComponent::AddBehavior(AddMessage& msg) {
|
||||
}
|
||||
}
|
||||
|
||||
void ModelComponent::MoveToInventory(MoveToInventoryMessage& msg) {
|
||||
std::string ModelComponent::SaveBehavior(const PropertyBehavior& behavior) const {
|
||||
tinyxml2::XMLDocument doc;
|
||||
auto* root = doc.NewElement("Behavior");
|
||||
behavior.Serialize(*root);
|
||||
doc.InsertFirstChild(root);
|
||||
|
||||
tinyxml2::XMLPrinter printer(0, true, 0);
|
||||
doc.Print(&printer);
|
||||
return printer.CStr();
|
||||
}
|
||||
|
||||
void ModelComponent::RemoveBehavior(MoveToInventoryMessage& msg, const bool keepItem) {
|
||||
if (msg.GetBehaviorIndex() >= m_Behaviors.size() || m_Behaviors.at(msg.GetBehaviorIndex()).GetBehaviorId() != msg.GetBehaviorId()) return;
|
||||
const auto behavior = m_Behaviors[msg.GetBehaviorIndex()];
|
||||
if (keepItem) {
|
||||
auto* const playerEntity = Game::entityManager->GetEntity(msg.GetOwningPlayerID());
|
||||
if (playerEntity) {
|
||||
auto* const inventoryComponent = playerEntity->GetComponent<InventoryComponent>();
|
||||
if (inventoryComponent && !behavior.GetIsLoot()) {
|
||||
// config is owned by the item
|
||||
std::vector<LDFBaseData*> config;
|
||||
config.push_back(new LDFData<std::string>(u"userModelName", behavior.GetName()));
|
||||
inventoryComponent->AddItem(7965, 1, eLootSourceType::PROPERTY, eInventoryType::BEHAVIORS, config, LWOOBJID_EMPTY, true, false, msg.GetBehaviorId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save the behavior before deleting it so players can re-add them
|
||||
IBehaviors::Info info{};
|
||||
info.behaviorId = msg.GetBehaviorId();
|
||||
info.behaviorInfo = SaveBehavior(behavior);
|
||||
info.characterId = msg.GetOwningPlayerID();
|
||||
|
||||
Database::Get()->AddBehavior(info);
|
||||
|
||||
m_Behaviors.erase(m_Behaviors.begin() + msg.GetBehaviorIndex());
|
||||
// TODO move to the inventory
|
||||
if (m_Behaviors.empty()) {
|
||||
@@ -165,22 +223,14 @@ void ModelComponent::MoveToInventory(MoveToInventoryMessage& msg) {
|
||||
}
|
||||
}
|
||||
|
||||
std::array<std::pair<int32_t, std::string>, 5> ModelComponent::GetBehaviorsForSave() const {
|
||||
std::array<std::pair<int32_t, std::string>, 5> toReturn{};
|
||||
std::array<std::pair<LWOOBJID, std::string>, 5> ModelComponent::GetBehaviorsForSave() const {
|
||||
std::array<std::pair<LWOOBJID, 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;
|
||||
auto& [id, behaviorData] = toReturn[i];
|
||||
id = behavior.GetBehaviorId();
|
||||
|
||||
tinyxml2::XMLDocument doc;
|
||||
auto* root = doc.NewElement("Behavior");
|
||||
behavior.Serialize(*root);
|
||||
doc.InsertFirstChild(root);
|
||||
|
||||
tinyxml2::XMLPrinter printer(0, true, 0);
|
||||
doc.Print(&printer);
|
||||
behaviorData = printer.CStr();
|
||||
behaviorData = SaveBehavior(behavior);
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
@@ -230,6 +280,7 @@ bool ModelComponent::TrySetVelocity(const NiPoint3& velocity) const {
|
||||
currentVelocity = velocity;
|
||||
}
|
||||
|
||||
currentVelocity *= m_Speed;
|
||||
m_Parent->SetVelocity(currentVelocity);
|
||||
return true;
|
||||
}
|
||||
@@ -237,3 +288,7 @@ bool ModelComponent::TrySetVelocity(const NiPoint3& velocity) const {
|
||||
void ModelComponent::SetVelocity(const NiPoint3& velocity) const {
|
||||
m_Parent->SetVelocity(velocity);
|
||||
}
|
||||
|
||||
void ModelComponent::OnChatMessageReceived(const std::string& sMessage) {
|
||||
for (auto& behavior : m_Behaviors) behavior.OnChatMessageReceived(sMessage);
|
||||
}
|
||||
|
||||
@@ -66,15 +66,18 @@ public:
|
||||
*
|
||||
* @tparam Msg The message type to pass
|
||||
* @param args the arguments of the message to be deserialized
|
||||
*
|
||||
* @return returns true if a new behaviorID is needed.
|
||||
*/
|
||||
template<typename Msg>
|
||||
void HandleControlBehaviorsMsg(const AMFArrayValue& args) {
|
||||
bool HandleControlBehaviorsMsg(const AMFArrayValue& args) {
|
||||
static_assert(std::is_base_of_v<BehaviorMessageBase, Msg>, "Msg must be a BehaviorMessageBase");
|
||||
Msg msg{ args };
|
||||
for (auto&& behavior : m_Behaviors) {
|
||||
if (behavior.GetBehaviorId() == msg.GetBehaviorId()) {
|
||||
behavior.CheckModifyState(msg);
|
||||
behavior.HandleMsg(msg);
|
||||
return;
|
||||
return msg.GetNeedsNewBehaviorID();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,22 +85,24 @@ public:
|
||||
if (m_Behaviors.size() > 5) m_Behaviors.resize(5);
|
||||
|
||||
// Do not allow more than 5 to be added. The client UI will break if you do!
|
||||
if (m_Behaviors.size() == 5) return;
|
||||
if (m_Behaviors.size() == 5) return false;
|
||||
|
||||
auto newBehavior = m_Behaviors.insert(m_Behaviors.begin(), PropertyBehavior());
|
||||
// Generally if we are inserting a new behavior, it is because the client is creating a new behavior.
|
||||
// However if we are testing behaviors the behavior will not exist on the initial pass, so we set the ID here to that of the msg.
|
||||
// This will either set the ID to -1 (no change in the current default) or set the ID to the ID of the behavior we are testing.
|
||||
newBehavior->SetBehaviorId(msg.GetBehaviorId());
|
||||
newBehavior->CheckModifyState(msg);
|
||||
newBehavior->HandleMsg(msg);
|
||||
return msg.GetNeedsNewBehaviorID();
|
||||
};
|
||||
|
||||
void AddBehavior(AddMessage& msg);
|
||||
|
||||
void MoveToInventory(MoveToInventoryMessage& msg);
|
||||
void RemoveBehavior(MoveToInventoryMessage& msg, const bool keepItem);
|
||||
|
||||
// Updates the pending behavior ID to the new ID.
|
||||
void UpdatePendingBehaviorId(const int32_t newId);
|
||||
void UpdatePendingBehaviorId(const LWOOBJID newId, const LWOOBJID oldId);
|
||||
|
||||
// Sends the behavior list to the client.
|
||||
|
||||
@@ -112,11 +117,11 @@ public:
|
||||
*/
|
||||
void SendBehaviorListToClient(AMFArrayValue& args) const;
|
||||
|
||||
void SendBehaviorBlocksToClient(int32_t behaviorToSend, AMFArrayValue& args) const;
|
||||
void SendBehaviorBlocksToClient(const LWOOBJID behaviorToSend, AMFArrayValue& args) const;
|
||||
|
||||
void VerifyBehaviors();
|
||||
|
||||
std::array<std::pair<int32_t, std::string>, 5> GetBehaviorsForSave() const;
|
||||
std::array<std::pair<LWOOBJID, std::string>, 5> GetBehaviorsForSave() const;
|
||||
|
||||
const std::vector<PropertyBehavior>& GetBehaviors() const { return m_Behaviors; };
|
||||
|
||||
@@ -138,7 +143,18 @@ public:
|
||||
|
||||
// Force sets the velocity to a value.
|
||||
void SetVelocity(const NiPoint3& velocity) const;
|
||||
|
||||
void OnChatMessageReceived(const std::string& sMessage);
|
||||
|
||||
void SetSpeed(const float newSpeed) { m_Speed = newSpeed; }
|
||||
private:
|
||||
|
||||
// Loads a behavior from the database.
|
||||
void LoadBehavior(const LWOOBJID behaviorID, const size_t index, const bool isIndexed);
|
||||
|
||||
// Writes a behavior to a string so it can be saved.
|
||||
std::string SaveBehavior(const PropertyBehavior& behavior) const;
|
||||
|
||||
// Number of Actions that are awaiting an UnSmash to finish.
|
||||
uint32_t m_NumActiveUnSmash{};
|
||||
|
||||
@@ -171,4 +187,7 @@ private:
|
||||
* The ID of the user that made the model
|
||||
*/
|
||||
LWOOBJID m_userModelID;
|
||||
|
||||
// The speed at which this model moves
|
||||
float m_Speed{ 3.0f };
|
||||
};
|
||||
|
||||
@@ -29,6 +29,13 @@ PhysicsComponent::PhysicsComponent(Entity* parent, int32_t componentId) : Compon
|
||||
}
|
||||
|
||||
if (m_Parent->HasVar(u"CollisionGroupID")) m_CollisionGroup = m_Parent->GetVar<int32_t>(u"CollisionGroupID");
|
||||
|
||||
RegisterMsg(MessageType::Game::GET_POSITION, this, &PhysicsComponent::OnGetPosition);
|
||||
}
|
||||
|
||||
bool PhysicsComponent::OnGetPosition(GameMessages::GameMsg& msg) {
|
||||
static_cast<GameMessages::GetPosition&>(msg).pos = GetPosition();
|
||||
return true;
|
||||
}
|
||||
|
||||
void PhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
|
||||
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
||||
|
||||
const NiPoint3& GetPosition() const { return m_Position; }
|
||||
const NiPoint3& GetPosition() const noexcept { return m_Position; }
|
||||
virtual void SetPosition(const NiPoint3& pos) { if (m_Position == pos) return; m_Position = pos; m_DirtyPosition = true; }
|
||||
|
||||
const NiQuaternion& GetRotation() const { return m_Rotation; }
|
||||
@@ -35,6 +35,8 @@ protected:
|
||||
|
||||
void SpawnVertices(dpEntity* entity) const;
|
||||
|
||||
bool OnGetPosition(GameMessages::GameMsg& msg);
|
||||
|
||||
NiPoint3 m_Position;
|
||||
|
||||
NiQuaternion m_Rotation;
|
||||
|
||||
@@ -817,3 +817,14 @@ void PropertyManagementComponent::SetOwnerId(const LWOOBJID value) {
|
||||
const std::map<LWOOBJID, LWOOBJID>& PropertyManagementComponent::GetModels() const {
|
||||
return models;
|
||||
}
|
||||
|
||||
void PropertyManagementComponent::OnChatMessageReceived(const std::string& sMessage) const {
|
||||
for (const auto& modelID : models | std::views::keys) {
|
||||
auto* const model = Game::entityManager->GetEntity(modelID);
|
||||
if (!model) continue;
|
||||
auto* const modelComponent = model->GetComponent<ModelComponent>();
|
||||
if (!modelComponent) continue;
|
||||
|
||||
modelComponent->OnChatMessageReceived(sMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +164,8 @@ public:
|
||||
|
||||
LWOOBJID GetId() const noexcept { return propertyId; }
|
||||
|
||||
|
||||
void OnChatMessageReceived(const std::string& sMessage) const;
|
||||
private:
|
||||
/**
|
||||
* This
|
||||
@@ -193,7 +195,7 @@ private:
|
||||
/**
|
||||
* The models that are placed on this property
|
||||
*/
|
||||
std::map<LWOOBJID, LWOOBJID> models = {};
|
||||
std::map<LWOOBJID /* ObjectID */, LWOOBJID /* SpawnerID */> models = {};
|
||||
|
||||
/**
|
||||
* The name of this property
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
#include "EntityManager.h"
|
||||
#include "ScriptedActivityComponent.h"
|
||||
|
||||
ShootingGalleryComponent::ShootingGalleryComponent(Entity* parent) : Component(parent) {
|
||||
ShootingGalleryComponent::ShootingGalleryComponent(Entity* parent, int32_t activityID) : ActivityComponent(parent, activityID) {
|
||||
}
|
||||
|
||||
ShootingGalleryComponent::~ShootingGalleryComponent() = default;
|
||||
|
||||
void ShootingGalleryComponent::SetStaticParams(const StaticShootingGalleryParams& params) {
|
||||
m_StaticParams = params;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Entity.h"
|
||||
#include "Component.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "ActivityComponent.h"
|
||||
|
||||
/**
|
||||
* Parameters for the shooting gallery that change during playtime
|
||||
@@ -71,12 +72,11 @@ struct StaticShootingGalleryParams {
|
||||
* A very ancient component that was used to guide shooting galleries, it's still kind of used but a lot of logic is
|
||||
* also in the related scripts.
|
||||
*/
|
||||
class ShootingGalleryComponent final : public Component {
|
||||
class ShootingGalleryComponent final : public ActivityComponent {
|
||||
public:
|
||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::SHOOTING_GALLERY;
|
||||
|
||||
explicit ShootingGalleryComponent(Entity* parent);
|
||||
~ShootingGalleryComponent();
|
||||
explicit ShootingGalleryComponent(Entity* parent, int32_t activityID);
|
||||
void Serialize(RakNet::BitStream& outBitStream, bool isInitialUpdate) override;
|
||||
|
||||
/**
|
||||
|
||||
@@ -158,6 +158,10 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
|
||||
|
||||
inv->AddItemSkills(item.lot);
|
||||
}
|
||||
|
||||
// Fixes a bug where testmapping too fast causes large item inventories to become invisible.
|
||||
// Only affects item inventory
|
||||
GameMessages::SendSetInventorySize(entity, eInventoryType::ITEMS, inv->GetInventory(eInventoryType::ITEMS)->GetSize());
|
||||
}
|
||||
|
||||
GameMessages::SendRestoreToPostLoadStats(entity, sysAddr);
|
||||
|
||||
@@ -5207,7 +5207,7 @@ void GameMessages::HandlePickupCurrency(RakNet::BitStream& inStream, Entity* ent
|
||||
if (currency == 0) return;
|
||||
|
||||
auto* ch = entity->GetCharacter();
|
||||
if (ch && entity->CanPickupCoins(currency)) {
|
||||
if (ch && entity->PickupCoins(currency)) {
|
||||
ch->SetCoins(ch->GetCoins() + currency, eLootSourceType::PICKUP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -843,5 +843,10 @@ namespace GameMessages {
|
||||
LWOOBJID targetID;
|
||||
};
|
||||
|
||||
struct GetPosition : public GameMsg {
|
||||
GetPosition() : GameMsg(MessageType::Game::GET_POSITION) {}
|
||||
|
||||
NiPoint3 pos{};
|
||||
};
|
||||
};
|
||||
#endif // GAMEMESSAGES_H
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "eUseItemResponse.h"
|
||||
#include "dZoneManager.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "MissionComponent.h"
|
||||
#include "eMissionTaskType.h"
|
||||
|
||||
#include "CDBrickIDTableTable.h"
|
||||
#include "CDObjectSkillsTable.h"
|
||||
@@ -268,9 +270,9 @@ bool Item::IsEquipped() const {
|
||||
}
|
||||
|
||||
bool Item::Consume() {
|
||||
auto* skillsTable = CDClientManager::GetTable<CDObjectSkillsTable>();
|
||||
auto* const skillsTable = CDClientManager::GetTable<CDObjectSkillsTable>();
|
||||
|
||||
auto skills = skillsTable->Query([this](const CDObjectSkills entry) {
|
||||
const auto skills = skillsTable->Query([this](const CDObjectSkills& entry) {
|
||||
return entry.objectTemplate == static_cast<uint32_t>(lot);
|
||||
});
|
||||
|
||||
@@ -288,7 +290,12 @@ bool Item::Consume() {
|
||||
GameMessages::SendUseItemResult(inventory->GetComponent()->GetParent(), lot, success);
|
||||
|
||||
if (success) {
|
||||
// Save this because if this is the last item in the inventory
|
||||
// we may delete ourself (lol)
|
||||
const auto myLot = this->lot;
|
||||
inventory->GetComponent()->RemoveItem(lot, 1);
|
||||
auto* missionComponent = inventory->GetComponent()->GetParent()->GetComponent<MissionComponent>();
|
||||
if (missionComponent) missionComponent->Progress(eMissionTaskType::GATHER, myLot, LWOOBJID_EMPTY, "", -1);
|
||||
}
|
||||
|
||||
return success;
|
||||
|
||||
@@ -20,6 +20,7 @@ target_include_directories(dPropertyBehaviors PUBLIC "." "ControlBehaviorMessage
|
||||
"${PROJECT_SOURCE_DIR}/dGame/dUtilities" # ObjectIdManager.h
|
||||
"${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # GameMessages.h
|
||||
"${PROJECT_SOURCE_DIR}/dGame/dComponents" # ModelComponent.h
|
||||
"${PROJECT_SOURCE_DIR}/dChatFilter" # dChatFilter.h
|
||||
)
|
||||
target_precompile_headers(dPropertyBehaviors REUSE_FROM dGameBase)
|
||||
|
||||
|
||||
@@ -10,5 +10,5 @@ AddActionMessage::AddActionMessage(const AMFArrayValue& arguments)
|
||||
|
||||
m_Action = Action{ *actionValue };
|
||||
|
||||
LOG_DEBUG("actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f m_BehaviorId %i", m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_Action.GetType().data(), m_Action.GetValueParameterName().data(), m_Action.GetValueParameterString().data(), m_Action.GetValueParameterDouble(), m_BehaviorId);
|
||||
LOG_DEBUG("actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f m_BehaviorId %llu", m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_Action.GetType().data(), m_Action.GetValueParameterName().data(), m_Action.GetValueParameterString().data(), m_Action.GetValueParameterDouble(), m_BehaviorId);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "AddMessage.h"
|
||||
|
||||
AddMessage::AddMessage(const AMFArrayValue& arguments) : BehaviorMessageBase{ arguments } {
|
||||
AddMessage::AddMessage(const AMFArrayValue& arguments, const LWOOBJID _owningPlayerID) : m_OwningPlayerID{ _owningPlayerID }, BehaviorMessageBase { arguments } {
|
||||
const auto* const behaviorIndexValue = arguments.Get<double>("BehaviorIndex");
|
||||
if (!behaviorIndexValue) return;
|
||||
|
||||
m_BehaviorIndex = static_cast<uint32_t>(behaviorIndexValue->GetValue());
|
||||
LOG_DEBUG("behaviorId %i index %i", m_BehaviorId, m_BehaviorIndex);
|
||||
LOG_DEBUG("behaviorId %llu index %i", m_BehaviorId, m_BehaviorIndex);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
*/
|
||||
class AddMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
AddMessage(const AMFArrayValue& arguments);
|
||||
AddMessage(const AMFArrayValue& arguments, const LWOOBJID _owningPlayerID);
|
||||
[[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; };
|
||||
[[nodiscard]] LWOOBJID GetOwningPlayerID() const noexcept { return m_OwningPlayerID; };
|
||||
|
||||
private:
|
||||
uint32_t m_BehaviorIndex{ 0 };
|
||||
LWOOBJID m_OwningPlayerID{};
|
||||
};
|
||||
|
||||
#endif //!__ADDMESSAGE__H__
|
||||
|
||||
@@ -19,7 +19,7 @@ AddStripMessage::AddStripMessage(const AMFArrayValue& arguments)
|
||||
|
||||
m_ActionsToAdd.emplace_back(*actionValue);
|
||||
|
||||
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId, m_ActionsToAdd.back().GetType().data(), m_ActionsToAdd.back().GetValueParameterName().data(), m_ActionsToAdd.back().GetValueParameterString().data(), m_ActionsToAdd.back().GetValueParameterDouble());
|
||||
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %llu t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId, m_ActionsToAdd.back().GetType().data(), m_ActionsToAdd.back().GetValueParameterName().data(), m_ActionsToAdd.back().GetValueParameterString().data(), m_ActionsToAdd.back().GetValueParameterDouble());
|
||||
}
|
||||
LOG_DEBUG("number of actions %i", m_ActionsToAdd.size());
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
#include "BehaviorStates.h"
|
||||
#include "dCommonVars.h"
|
||||
|
||||
int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(const AMFArrayValue& arguments) {
|
||||
LWOOBJID BehaviorMessageBase::GetBehaviorIdFromArgument(const AMFArrayValue& arguments) {
|
||||
static constexpr std::string_view key = "BehaviorID";
|
||||
const auto* const behaviorIDValue = arguments.Get<std::string>(key);
|
||||
int32_t behaviorId = DefaultBehaviorId;
|
||||
LWOOBJID behaviorId = DefaultBehaviorId;
|
||||
|
||||
if (behaviorIDValue && behaviorIDValue->GetValueType() == eAmf::String) {
|
||||
behaviorId =
|
||||
GeneralUtils::TryParse<int32_t>(behaviorIDValue->GetValue()).value_or(behaviorId);
|
||||
GeneralUtils::TryParse<LWOOBJID>(behaviorIDValue->GetValue()).value_or(behaviorId);
|
||||
} else if (arguments.Get(key) && arguments.Get(key)->GetValueType() != eAmf::Undefined) {
|
||||
throw std::invalid_argument("Unable to find behavior ID");
|
||||
}
|
||||
|
||||
@@ -11,19 +11,22 @@ enum class BehaviorState : uint32_t;
|
||||
|
||||
/**
|
||||
* @brief The behaviorID target of this ControlBehaviors message
|
||||
*
|
||||
*
|
||||
*/
|
||||
class BehaviorMessageBase {
|
||||
public:
|
||||
static constexpr int32_t DefaultBehaviorId{ -1 };
|
||||
static constexpr LWOOBJID DefaultBehaviorId{ -1 };
|
||||
BehaviorMessageBase(const AMFArrayValue& arguments) : m_BehaviorId{ GetBehaviorIdFromArgument(arguments) } {}
|
||||
[[nodiscard]] int32_t GetBehaviorId() const noexcept { return m_BehaviorId; }
|
||||
[[nodiscard]] LWOOBJID GetBehaviorId() const noexcept { return m_BehaviorId; }
|
||||
[[nodiscard]] bool IsDefaultBehaviorId() const noexcept { return m_BehaviorId == DefaultBehaviorId; }
|
||||
[[nodiscard]] bool GetNeedsNewBehaviorID() const noexcept { return m_NeedsNewBehaviorID; }
|
||||
void SetNeedsNewBehaviorID(const bool val) noexcept { m_NeedsNewBehaviorID = val; }
|
||||
|
||||
protected:
|
||||
[[nodiscard]] int32_t GetBehaviorIdFromArgument(const AMFArrayValue& arguments);
|
||||
[[nodiscard]] LWOOBJID GetBehaviorIdFromArgument(const AMFArrayValue& arguments);
|
||||
[[nodiscard]] int32_t GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string_view keyName = "actionIndex") const;
|
||||
int32_t m_BehaviorId{ DefaultBehaviorId };
|
||||
LWOOBJID m_BehaviorId{ DefaultBehaviorId };
|
||||
bool m_NeedsNewBehaviorID{ false };
|
||||
};
|
||||
|
||||
#endif //!__BEHAVIORMESSAGEBASE__H__
|
||||
|
||||
@@ -6,6 +6,6 @@ MergeStripsMessage::MergeStripsMessage(const AMFArrayValue& arguments)
|
||||
, m_SourceActionContext{ arguments, "srcStateID", "srcStripID" }
|
||||
, m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" } {
|
||||
|
||||
LOG_DEBUG("srcstripId %i dststripId %i srcstateId %i dststateId %i dstactionIndex %i behaviorId %i", m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_DstActionIndex, m_BehaviorId);
|
||||
LOG_DEBUG("srcstripId %i dststripId %i srcstateId %i dststateId %i dstactionIndex %i behaviorId %llu", m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_DstActionIndex, m_BehaviorId);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,5 +7,5 @@ MigrateActionsMessage::MigrateActionsMessage(const AMFArrayValue& arguments)
|
||||
, m_SourceActionContext{ arguments, "srcStateID", "srcStripID" }
|
||||
, m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" } {
|
||||
|
||||
LOG_DEBUG("srcactionIndex %i dstactionIndex %i srcstripId %i dststripId %i srcstateId %i dststateId %i behaviorId %i", m_SrcActionIndex, m_DstActionIndex, m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_BehaviorId);
|
||||
LOG_DEBUG("srcactionIndex %i dstactionIndex %i srcstripId %i dststripId %i srcstateId %i dststateId %i behaviorId %llu", m_SrcActionIndex, m_DstActionIndex, m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_BehaviorId);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "MoveToInventoryMessage.h"
|
||||
|
||||
MoveToInventoryMessage::MoveToInventoryMessage(const AMFArrayValue& arguments) : BehaviorMessageBase{ arguments } {
|
||||
MoveToInventoryMessage::MoveToInventoryMessage(const AMFArrayValue& arguments, const LWOOBJID _owningPlayerID) : m_OwningPlayerID{ _owningPlayerID }, BehaviorMessageBase{ arguments } {
|
||||
const auto* const behaviorIndexValue = arguments.Get<double>("BehaviorIndex");
|
||||
if (!behaviorIndexValue) return;
|
||||
|
||||
m_BehaviorIndex = static_cast<uint32_t>(behaviorIndexValue->GetValue());
|
||||
LOG_DEBUG("behaviorId %i behaviorIndex %i", m_BehaviorId, m_BehaviorIndex);
|
||||
LOG_DEBUG("behaviorId %llu behaviorIndex %i", m_BehaviorId, m_BehaviorIndex);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,13 @@ class AMFArrayValue;
|
||||
*/
|
||||
class MoveToInventoryMessage : public BehaviorMessageBase {
|
||||
public:
|
||||
MoveToInventoryMessage(const AMFArrayValue& arguments);
|
||||
MoveToInventoryMessage(const AMFArrayValue& arguments, const LWOOBJID owningPlayerID);
|
||||
[[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; };
|
||||
[[nodiscard]] LWOOBJID GetOwningPlayerID() const noexcept { return m_OwningPlayerID; };
|
||||
|
||||
private:
|
||||
uint32_t m_BehaviorIndex;
|
||||
LWOOBJID m_OwningPlayerID{};
|
||||
};
|
||||
|
||||
#endif //!__MOVETOINVENTORYMESSAGE__H__
|
||||
|
||||
@@ -6,5 +6,5 @@ RearrangeStripMessage::RearrangeStripMessage(const AMFArrayValue& arguments)
|
||||
, m_DstActionIndex{ GetActionIndexFromArgument(arguments, "dstActionIndex") }
|
||||
, m_ActionContext{ arguments } {
|
||||
|
||||
LOG_DEBUG("srcactionIndex %i dstactionIndex %i stripId %i behaviorId %i stateId %i", m_SrcActionIndex, m_DstActionIndex, m_ActionContext.GetStripId(), m_BehaviorId, m_ActionContext.GetStateId());
|
||||
LOG_DEBUG("srcactionIndex %i dstactionIndex %i stripId %i behaviorId %llu stateId %i", m_SrcActionIndex, m_DstActionIndex, m_ActionContext.GetStripId(), m_BehaviorId, m_ActionContext.GetStateId());
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ RemoveActionsMessage::RemoveActionsMessage(const AMFArrayValue& arguments)
|
||||
, m_ActionIndex{ GetActionIndexFromArgument(arguments) }
|
||||
, m_ActionContext{ arguments } {
|
||||
|
||||
LOG_DEBUG("behaviorId %i actionIndex %i stripId %i stateId %i", m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId());
|
||||
LOG_DEBUG("behaviorId %llu actionIndex %i stripId %i stateId %i", m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId());
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ RemoveStripMessage::RemoveStripMessage(const AMFArrayValue& arguments)
|
||||
: BehaviorMessageBase{ arguments }
|
||||
, m_ActionContext{ arguments } {
|
||||
|
||||
LOG_DEBUG("stripId %i stateId %i behaviorId %i", m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId);
|
||||
LOG_DEBUG("stripId %i stateId %i behaviorId %llu", m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId);
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ RenameMessage::RenameMessage(const AMFArrayValue& arguments) : BehaviorMessageBa
|
||||
if (!nameAmf) return;
|
||||
|
||||
m_Name = nameAmf->GetValue();
|
||||
LOG_DEBUG("behaviorId %i n %s", m_BehaviorId, m_Name.c_str());
|
||||
LOG_DEBUG("behaviorId %llu n %s", m_BehaviorId, m_Name.c_str());
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ SplitStripMessage::SplitStripMessage(const AMFArrayValue& arguments)
|
||||
, m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" }
|
||||
, m_DestinationPosition{ arguments, "dstStripUI" } {
|
||||
|
||||
LOG_DEBUG("behaviorId %i xPosition %f yPosition %f sourceStrip %i destinationStrip %i sourceState %i destinationState %i srcActindex %i", m_BehaviorId, m_DestinationPosition.GetX(), m_DestinationPosition.GetY(), m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_SrcActionIndex);
|
||||
LOG_DEBUG("behaviorId %llu xPosition %f yPosition %f sourceStrip %i destinationStrip %i sourceState %i destinationState %i srcActindex %i", m_BehaviorId, m_DestinationPosition.GetX(), m_DestinationPosition.GetY(), m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_SrcActionIndex);
|
||||
}
|
||||
|
||||
@@ -12,5 +12,5 @@ UpdateActionMessage::UpdateActionMessage(const AMFArrayValue& arguments)
|
||||
|
||||
m_Action = Action{ *actionValue };
|
||||
|
||||
LOG_DEBUG("type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", m_Action.GetType().data(), m_Action.GetValueParameterName().data(), m_Action.GetValueParameterString().data(), m_Action.GetValueParameterDouble(), m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId());
|
||||
LOG_DEBUG("type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %llu actionIndex %i stripId %i stateId %i", m_Action.GetType().data(), m_Action.GetValueParameterName().data(), m_Action.GetValueParameterString().data(), m_Action.GetValueParameterDouble(), m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId());
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ UpdateStripUiMessage::UpdateStripUiMessage(const AMFArrayValue& arguments)
|
||||
, m_Position{ arguments }
|
||||
, m_ActionContext{ arguments } {
|
||||
|
||||
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId);
|
||||
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %llu", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId);
|
||||
}
|
||||
|
||||
@@ -30,22 +30,27 @@
|
||||
#include "SplitStripMessage.h"
|
||||
#include "UpdateActionMessage.h"
|
||||
#include "UpdateStripUiMessage.h"
|
||||
#include "eObjectBits.h"
|
||||
|
||||
void ControlBehaviors::RequestUpdatedID(ControlBehaviorContext& context) {
|
||||
BehaviorMessageBase msgBase{ context.arguments };
|
||||
const auto oldBehaviorID = msgBase.GetBehaviorId();
|
||||
ObjectIDManager::RequestPersistentID(
|
||||
[context](uint32_t persistentId) {
|
||||
[context, oldBehaviorID](uint32_t persistentId) {
|
||||
if (!context) {
|
||||
LOG("Model to update behavior ID for is null. Cannot update ID.");
|
||||
return;
|
||||
}
|
||||
LWOOBJID persistentIdBig = persistentId;
|
||||
GeneralUtils::SetBit(persistentIdBig, eObjectBits::CHARACTER);
|
||||
// This updates the behavior ID of the behavior should this be a new behavior
|
||||
AMFArrayValue args;
|
||||
|
||||
args.Insert("behaviorID", std::to_string(persistentId));
|
||||
args.Insert("behaviorID", std::to_string(persistentIdBig));
|
||||
args.Insert("objectID", std::to_string(context.modelComponent->GetParent()->GetObjectID()));
|
||||
|
||||
GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorID", args);
|
||||
context.modelComponent->UpdatePendingBehaviorId(persistentId);
|
||||
context.modelComponent->UpdatePendingBehaviorId(persistentIdBig, oldBehaviorID);
|
||||
|
||||
ControlBehaviors::Instance().SendBehaviorListToClient(context);
|
||||
});
|
||||
@@ -102,9 +107,12 @@ void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayV
|
||||
if (!modelComponent) return;
|
||||
|
||||
ControlBehaviorContext context{ arguments, modelComponent, modelOwner };
|
||||
bool needsNewBehaviorID = false;
|
||||
|
||||
if (command == "sendBehaviorListToClient") {
|
||||
SendBehaviorListToClient(context);
|
||||
} else if (command == "sendBehaviorBlocksToClient") {
|
||||
SendBehaviorBlocksToClient(context);
|
||||
} else if (command == "modelTypeChanged") {
|
||||
const auto* const modelType = arguments.Get<double>("ModelType");
|
||||
if (!modelType) return;
|
||||
@@ -113,52 +121,54 @@ void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayV
|
||||
} else if (command == "toggleExecutionUpdates") {
|
||||
// TODO
|
||||
} else if (command == "addStrip") {
|
||||
if (BehaviorMessageBase(context.arguments).IsDefaultBehaviorId()) RequestUpdatedID(context);
|
||||
|
||||
context.modelComponent->HandleControlBehaviorsMsg<AddStripMessage>(context.arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<AddStripMessage>(context.arguments);
|
||||
} else if (command == "removeStrip") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<RemoveStripMessage>(arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<RemoveStripMessage>(arguments);
|
||||
} else if (command == "mergeStrips") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<MergeStripsMessage>(arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<MergeStripsMessage>(arguments);
|
||||
} else if (command == "splitStrip") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<SplitStripMessage>(arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<SplitStripMessage>(arguments);
|
||||
} else if (command == "updateStripUI") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<UpdateStripUiMessage>(arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<UpdateStripUiMessage>(arguments);
|
||||
} else if (command == "addAction") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<AddActionMessage>(arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<AddActionMessage>(arguments);
|
||||
} else if (command == "migrateActions") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<MigrateActionsMessage>(arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<MigrateActionsMessage>(arguments);
|
||||
} else if (command == "rearrangeStrip") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<RearrangeStripMessage>(arguments);
|
||||
} else if (command == "add") {
|
||||
AddMessage msg{ context.arguments };
|
||||
context.modelComponent->AddBehavior(msg);
|
||||
SendBehaviorListToClient(context);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<RearrangeStripMessage>(arguments);
|
||||
} else if (command == "removeActions") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<RemoveActionsMessage>(arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<RemoveActionsMessage>(arguments);
|
||||
} else if (command == "updateAction") {
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<UpdateActionMessage>(arguments);
|
||||
} else if (command == "rename") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<RenameMessage>(arguments);
|
||||
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<RenameMessage>(arguments);
|
||||
|
||||
// Send the list back to the client so the name is updated.
|
||||
SendBehaviorListToClient(context);
|
||||
} else if (command == "sendBehaviorBlocksToClient") {
|
||||
SendBehaviorBlocksToClient(context);
|
||||
} else if (command == "moveToInventory") {
|
||||
MoveToInventoryMessage msg{ arguments };
|
||||
context.modelComponent->MoveToInventory(msg);
|
||||
} else if (command == "add") {
|
||||
AddMessage msg{ context.arguments, context.modelOwner->GetObjectID() };
|
||||
context.modelComponent->AddBehavior(msg);
|
||||
SendBehaviorListToClient(context);
|
||||
} else if (command == "moveToInventory" || command == "remove") {
|
||||
// both moveToInventory and remove use the same args
|
||||
const bool isRemove = command != "remove";
|
||||
MoveToInventoryMessage msg{ arguments, modelOwner->GetObjectID() };
|
||||
context.modelComponent->RemoveBehavior(msg, isRemove);
|
||||
auto* characterComponent = modelOwner->GetComponent<CharacterComponent>();
|
||||
if (!characterComponent) return;
|
||||
|
||||
AMFArrayValue args;
|
||||
args.Insert("BehaviorID", std::to_string(msg.GetBehaviorId()));
|
||||
GameMessages::SendUIMessageServerToSingleClient(modelOwner, characterComponent->GetSystemAddress(), "BehaviorRemoved", args);
|
||||
if (!isRemove) {
|
||||
AMFArrayValue args;
|
||||
args.Insert("BehaviorID", std::to_string(msg.GetBehaviorId()));
|
||||
GameMessages::SendUIMessageServerToSingleClient(modelOwner, characterComponent->GetSystemAddress(), "BehaviorRemoved", args);
|
||||
}
|
||||
|
||||
SendBehaviorListToClient(context);
|
||||
} else if (command == "updateAction") {
|
||||
context.modelComponent->HandleControlBehaviorsMsg<UpdateActionMessage>(arguments);
|
||||
} else {
|
||||
LOG("Unknown behavior command (%s)", command.data());
|
||||
}
|
||||
|
||||
if (needsNewBehaviorID) RequestUpdatedID(context);
|
||||
}
|
||||
|
||||
ControlBehaviors::ControlBehaviors() {
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
|
||||
#include <ranges>
|
||||
|
||||
PropertyBehavior::PropertyBehavior() {
|
||||
PropertyBehavior::PropertyBehavior(bool _isTemplated) {
|
||||
m_LastEditedState = BehaviorState::HOME_STATE;
|
||||
m_ActiveState = BehaviorState::HOME_STATE;
|
||||
|
||||
// Starts off as true so that only specific ways of adding behaviors allow a new id to be requested.
|
||||
isTemplated = _isTemplated;
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -81,13 +84,6 @@ void PropertyBehavior::HandleMsg(RenameMessage& msg) {
|
||||
m_Name = msg.GetName();
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(AddMessage& msg) {
|
||||
// TODO Parse the corresponding behavior xml file.
|
||||
m_BehaviorId = msg.GetBehaviorId();
|
||||
isLoot = m_BehaviorId != 7965;
|
||||
};
|
||||
|
||||
template<>
|
||||
void PropertyBehavior::HandleMsg(GameMessages::RequestUse& msg) {
|
||||
m_States[m_ActiveState].HandleMsg(msg);
|
||||
@@ -99,6 +95,12 @@ void PropertyBehavior::HandleMsg(GameMessages::ResetModelToDefaults& msg) {
|
||||
for (auto& state : m_States | std::views::values) state.HandleMsg(msg);
|
||||
}
|
||||
|
||||
void PropertyBehavior::CheckModifyState(BehaviorMessageBase& msg) {
|
||||
if (!isTemplated && m_BehaviorId != BehaviorMessageBase::DefaultBehaviorId) return;
|
||||
isTemplated = false;
|
||||
msg.SetNeedsNewBehaviorID(true);
|
||||
}
|
||||
|
||||
void PropertyBehavior::SendBehaviorListToClient(AMFArrayValue& args) const {
|
||||
args.Insert("id", std::to_string(m_BehaviorId));
|
||||
args.Insert("name", m_Name);
|
||||
@@ -147,6 +149,9 @@ void PropertyBehavior::Serialize(tinyxml2::XMLElement& behavior) const {
|
||||
behavior.SetAttribute("isLocked", isLocked);
|
||||
behavior.SetAttribute("isLoot", isLoot);
|
||||
|
||||
// CUSTOM XML ATTRIBUTE
|
||||
behavior.SetAttribute("isTemplated", isTemplated);
|
||||
|
||||
for (const auto& [stateId, state] : m_States) {
|
||||
if (state.IsEmpty()) continue;
|
||||
auto* const stateElement = behavior.InsertNewChildElement("State");
|
||||
@@ -161,6 +166,9 @@ void PropertyBehavior::Deserialize(const tinyxml2::XMLElement& behavior) {
|
||||
behavior.QueryBoolAttribute("isLocked", &isLocked);
|
||||
behavior.QueryBoolAttribute("isLoot", &isLoot);
|
||||
|
||||
// CUSTOM XML ATTRIBUTE
|
||||
if (!isTemplated) behavior.QueryBoolAttribute("isTemplated", &isTemplated);
|
||||
|
||||
for (const auto* stateElement = behavior.FirstChildElement("State"); stateElement; stateElement = stateElement->NextSiblingElement("State")) {
|
||||
int32_t stateId = -1;
|
||||
stateElement->QueryIntAttribute("id", &stateId);
|
||||
@@ -172,3 +180,7 @@ void PropertyBehavior::Deserialize(const tinyxml2::XMLElement& behavior) {
|
||||
void PropertyBehavior::Update(float deltaTime, ModelComponent& modelComponent) {
|
||||
for (auto& state : m_States | std::views::values) state.Update(deltaTime, modelComponent);
|
||||
}
|
||||
|
||||
void PropertyBehavior::OnChatMessageReceived(const std::string& sMessage) {
|
||||
for (auto& state : m_States | std::views::values) state.OnChatMessageReceived(sMessage);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace tinyxml2 {
|
||||
enum class BehaviorState : uint32_t;
|
||||
|
||||
class AMFArrayValue;
|
||||
class BehaviorMessageBase;
|
||||
class ModelComponent;
|
||||
|
||||
/**
|
||||
@@ -17,7 +18,7 @@ class ModelComponent;
|
||||
*/
|
||||
class PropertyBehavior {
|
||||
public:
|
||||
PropertyBehavior();
|
||||
PropertyBehavior(bool _isTemplated = false);
|
||||
|
||||
template <typename Msg>
|
||||
void HandleMsg(Msg& msg);
|
||||
@@ -26,14 +27,21 @@ public:
|
||||
void VerifyLastEditedState();
|
||||
void SendBehaviorListToClient(AMFArrayValue& args) const;
|
||||
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
||||
void CheckModifyState(BehaviorMessageBase& msg);
|
||||
|
||||
[[nodiscard]] int32_t GetBehaviorId() const noexcept { return m_BehaviorId; }
|
||||
void SetBehaviorId(int32_t id) noexcept { m_BehaviorId = id; }
|
||||
[[nodiscard]] LWOOBJID GetBehaviorId() const noexcept { return m_BehaviorId; }
|
||||
void SetBehaviorId(LWOOBJID id) noexcept { m_BehaviorId = id; }
|
||||
|
||||
bool GetIsLoot() const noexcept { return isLoot; }
|
||||
void SetIsLoot(const bool val) noexcept { isLoot = val; }
|
||||
|
||||
const std::string& GetName() const noexcept { return m_Name; }
|
||||
|
||||
void Serialize(tinyxml2::XMLElement& behavior) const;
|
||||
void Deserialize(const tinyxml2::XMLElement& behavior);
|
||||
|
||||
void Update(float deltaTime, ModelComponent& modelComponent);
|
||||
void OnChatMessageReceived(const std::string& sMessage);
|
||||
|
||||
private:
|
||||
// The current active behavior state. Behaviors can only be in ONE state at a time.
|
||||
@@ -51,13 +59,16 @@ private:
|
||||
// Whether this behavior is custom or pre-fab.
|
||||
bool isLoot = false;
|
||||
|
||||
// Whether or not the behavior has been modified from its original state.
|
||||
bool isTemplated;
|
||||
|
||||
// The last state that was edited. This is used so when the client re-opens the behavior editor, it will open to the last edited state.
|
||||
// If the last edited state has no strips, it will open to the first state that has strips.
|
||||
BehaviorState m_LastEditedState;
|
||||
|
||||
// The behavior id for this behavior. This is expected to be fully unique, however an id of -1 means this behavior was just created
|
||||
// and needs to be assigned an id.
|
||||
int32_t m_BehaviorId = -1;
|
||||
LWOOBJID m_BehaviorId = -1;
|
||||
};
|
||||
|
||||
#endif //!__PROPERTYBEHAVIOR__H__
|
||||
|
||||
@@ -166,3 +166,7 @@ void State::Deserialize(const tinyxml2::XMLElement& state) {
|
||||
void State::Update(float deltaTime, ModelComponent& modelComponent) {
|
||||
for (auto& strip : m_Strips) strip.Update(deltaTime, modelComponent);
|
||||
}
|
||||
|
||||
void State::OnChatMessageReceived(const std::string& sMessage) {
|
||||
for (auto& strip : m_Strips) strip.OnChatMessageReceived(sMessage);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ public:
|
||||
void Deserialize(const tinyxml2::XMLElement& state);
|
||||
|
||||
void Update(float deltaTime, ModelComponent& modelComponent);
|
||||
|
||||
void OnChatMessageReceived(const std::string& sMessage);
|
||||
private:
|
||||
|
||||
// The strips contained within this state.
|
||||
|
||||
@@ -5,7 +5,12 @@
|
||||
#include "tinyxml2.h"
|
||||
#include "dEntity/EntityInfo.h"
|
||||
#include "ModelComponent.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "PropertyManagementComponent.h"
|
||||
#include "PlayerManager.h"
|
||||
#include "SimplePhysicsComponent.h"
|
||||
|
||||
#include "dChatFilter.h"
|
||||
|
||||
#include "DluAssert.h"
|
||||
|
||||
@@ -103,6 +108,16 @@ void Strip::HandleMsg(GameMessages::ResetModelToDefaults& msg) {
|
||||
m_PreviousFramePosition = NiPoint3Constant::ZERO;
|
||||
}
|
||||
|
||||
void Strip::OnChatMessageReceived(const std::string& sMessage) {
|
||||
if (m_PausedTime > 0.0f || !HasMinimumActions()) return;
|
||||
|
||||
const auto& nextAction = GetNextAction();
|
||||
if (nextAction.GetType() == "OnChat" && nextAction.GetValueParameterString() == sMessage) {
|
||||
IncrementAction();
|
||||
m_WaitingForAction = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Strip::IncrementAction() {
|
||||
if (m_Actions.empty()) return;
|
||||
m_NextActionIndex++;
|
||||
@@ -131,6 +146,7 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
||||
auto& entity = *modelComponent.GetParent();
|
||||
auto& nextAction = GetNextAction();
|
||||
auto number = nextAction.GetValueParameterDouble();
|
||||
auto valueStr = nextAction.GetValueParameterString();
|
||||
auto numberAsInt = static_cast<int32_t>(number);
|
||||
auto nextActionType = GetNextAction().GetType();
|
||||
|
||||
@@ -139,16 +155,18 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
||||
if (nextActionType == "MoveRight" || nextActionType == "MoveLeft") {
|
||||
// X axis
|
||||
bool isMoveLeft = nextActionType == "MoveLeft";
|
||||
int negative = isMoveLeft ? -1 : 1;
|
||||
// Default velocity is 3 units per second.
|
||||
if (modelComponent.TrySetVelocity(NiPoint3{ isMoveLeft ? -3.0f : 3.0f, 0.0f, 0.0f })) {
|
||||
if (modelComponent.TrySetVelocity(NiPoint3Constant::UNIT_X * negative)) {
|
||||
m_PreviousFramePosition = entity.GetPosition();
|
||||
m_InActionMove.x = isMoveLeft ? -number : number;
|
||||
}
|
||||
} else if (nextActionType == "FlyUp" || nextActionType == "FlyDown") {
|
||||
// Y axis
|
||||
bool isFlyDown = nextActionType == "FlyDown";
|
||||
int negative = isFlyDown ? -1 : 1;
|
||||
// Default velocity is 3 units per second.
|
||||
if (modelComponent.TrySetVelocity(NiPoint3{ 0.0f, isFlyDown ? -3.0f : 3.0f, 0.0f })) {
|
||||
if (modelComponent.TrySetVelocity(NiPoint3Constant::UNIT_Y * negative)) {
|
||||
m_PreviousFramePosition = entity.GetPosition();
|
||||
m_InActionMove.y = isFlyDown ? -number : number;
|
||||
}
|
||||
@@ -156,14 +174,21 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
||||
} else if (nextActionType == "MoveForward" || nextActionType == "MoveBackward") {
|
||||
// Z axis
|
||||
bool isMoveBackward = nextActionType == "MoveBackward";
|
||||
int negative = isMoveBackward ? -1 : 1;
|
||||
// Default velocity is 3 units per second.
|
||||
if (modelComponent.TrySetVelocity(NiPoint3{ 0.0f, 0.0f, isMoveBackward ? -3.0f : 3.0f })) {
|
||||
if (modelComponent.TrySetVelocity(NiPoint3Constant::UNIT_Z * negative)) {
|
||||
m_PreviousFramePosition = entity.GetPosition();
|
||||
m_InActionMove.z = isMoveBackward ? -number : number;
|
||||
}
|
||||
}
|
||||
/* END Move */
|
||||
|
||||
/* BEGIN Navigation */
|
||||
else if (nextActionType == "SetSpeed") {
|
||||
modelComponent.SetSpeed(number);
|
||||
}
|
||||
/* END Navigation */
|
||||
|
||||
/* BEGIN Action */
|
||||
else if (nextActionType == "Smash") {
|
||||
if (!modelComponent.IsUnSmashing()) {
|
||||
@@ -183,6 +208,14 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
||||
m_PausedTime = number;
|
||||
} else if (nextActionType == "Wait") {
|
||||
m_PausedTime = number;
|
||||
} else if (nextActionType == "Chat") {
|
||||
bool isOk = Game::chatFilter->IsSentenceOkay(valueStr.data(), eGameMasterLevel::CIVILIAN).empty();
|
||||
// In case a word is removed from the whitelist after it was approved
|
||||
const auto modelName = "%[Objects_" + std::to_string(entity.GetLOT()) + "_name]";
|
||||
if (isOk) ChatPackets::SendChatMessage(UNASSIGNED_SYSTEM_ADDRESS, 12, modelName, entity.GetObjectID(), false, GeneralUtils::ASCIIToUTF16(valueStr));
|
||||
PropertyManagementComponent::Instance()->OnChatMessageReceived(valueStr.data());
|
||||
} else if (nextActionType == "PrivateMessage") {
|
||||
PropertyManagementComponent::Instance()->OnChatMessageReceived(valueStr.data());
|
||||
} else if (nextActionType == "PlaySound") {
|
||||
GameMessages::PlayBehaviorSound sound;
|
||||
sound.target = modelComponent.GetParent()->GetObjectID();
|
||||
@@ -304,6 +337,9 @@ void Strip::Update(float deltaTime, ModelComponent& modelComponent) {
|
||||
Game::entityManager->SerializeEntity(entity);
|
||||
m_WaitingForAction = true;
|
||||
|
||||
} else if (nextAction.GetType() == "OnChat") {
|
||||
Game::entityManager->SerializeEntity(entity);
|
||||
m_WaitingForAction = true;
|
||||
}
|
||||
} else { // should be a normal block
|
||||
ProcNormalAction(deltaTime, modelComponent);
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
|
||||
// 2 actions are required for strips to work
|
||||
bool HasMinimumActions() const { return m_Actions.size() >= 2; }
|
||||
|
||||
void OnChatMessageReceived(const std::string& sMessage);
|
||||
private:
|
||||
// Indicates this Strip is waiting for an action to be taken upon it to progress to its actions
|
||||
bool m_WaitingForAction{ false };
|
||||
|
||||
@@ -24,9 +24,8 @@ namespace {
|
||||
}
|
||||
|
||||
void Loot::CacheMatrix(uint32_t matrixIndex) {
|
||||
if (CachedMatrices.find(matrixIndex) != CachedMatrices.end()) {
|
||||
return;
|
||||
}
|
||||
if (CachedMatrices.contains(matrixIndex)) return;
|
||||
|
||||
CachedMatrices.insert(matrixIndex);
|
||||
CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||
CDItemComponentTable* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||
|
||||
@@ -132,6 +132,7 @@ namespace Mail {
|
||||
} else {
|
||||
response.status = eSendResponse::SenderAccountIsMuted;
|
||||
}
|
||||
LOG("Finished send with status %s", StringifiedEnum::ToString(response.status).data());
|
||||
response.Send(sysAddr);
|
||||
}
|
||||
|
||||
@@ -158,6 +159,7 @@ namespace Mail {
|
||||
DataResponse response;
|
||||
response.playerMail = playerMail;
|
||||
response.Send(sysAddr);
|
||||
LOG("DataRequest");
|
||||
}
|
||||
|
||||
void DataResponse::Serialize(RakNet::BitStream& bitStream) const {
|
||||
@@ -196,6 +198,7 @@ namespace Mail {
|
||||
response.status = eAttachmentCollectResponse::Success;
|
||||
}
|
||||
}
|
||||
LOG("AttachmentCollectResponse %s", StringifiedEnum::ToString(response.status).data());
|
||||
response.Send(sysAddr);
|
||||
}
|
||||
|
||||
@@ -218,14 +221,15 @@ namespace Mail {
|
||||
response.mailID = mailID;
|
||||
|
||||
auto mailData = Database::Get()->GetMail(mailID);
|
||||
if (mailData && !(mailData->itemLOT != 0 && mailData->itemCount > 0)) {
|
||||
if (mailData && !(mailData->itemLOT > 0 && mailData->itemCount > 0)) {
|
||||
Database::Get()->DeleteMail(mailID);
|
||||
response.status = eDeleteResponse::Success;
|
||||
} else if (mailData && mailData->itemLOT != 0 && mailData->itemCount > 0) {
|
||||
} else if (mailData && mailData->itemLOT > 0 && mailData->itemCount > 0) {
|
||||
response.status = eDeleteResponse::HasAttachments;
|
||||
} else {
|
||||
response.status = eDeleteResponse::NotFound;
|
||||
}
|
||||
LOG("DeleteRequest status %s", StringifiedEnum::ToString(response.status).data());
|
||||
response.Send(sysAddr);
|
||||
}
|
||||
|
||||
@@ -249,7 +253,9 @@ namespace Mail {
|
||||
if (Database::Get()->GetMail(mailID)) {
|
||||
response.status = eReadResponse::Success;
|
||||
Database::Get()->MarkMailRead(mailID);
|
||||
}
|
||||
}
|
||||
|
||||
LOG("ReadRequest %s", StringifiedEnum::ToString(response.status).data());
|
||||
response.Send(sysAddr);
|
||||
}
|
||||
|
||||
@@ -267,6 +273,8 @@ namespace Mail {
|
||||
response.status = eNotificationResponse::NewMail;
|
||||
response.mailCount = unreadMailCount;
|
||||
}
|
||||
|
||||
LOG("NotificationRequest %s", StringifiedEnum::ToString(response.status).data());
|
||||
response.Send(sysAddr);
|
||||
}
|
||||
}
|
||||
@@ -288,6 +296,7 @@ void Mail::HandleMail(RakNet::BitStream& inStream, const SystemAddress& sysAddr,
|
||||
LOG_DEBUG("Error Reading Mail Request: %s", StringifiedEnum::ToString(data.messageID).data());
|
||||
return;
|
||||
}
|
||||
LOG("Received mail message %s", StringifiedEnum::ToString(data.messageID).data());
|
||||
request->Handle();
|
||||
} else {
|
||||
LOG_DEBUG("Unhandled Mail Request with ID: %i", data.messageID);
|
||||
|
||||
@@ -119,12 +119,15 @@ namespace Mail {
|
||||
struct SendRequest : public MailLUBitStream {
|
||||
MailInfo mailInfo;
|
||||
|
||||
SendRequest() : MailLUBitStream(eMessageID::SendRequest) {}
|
||||
bool Deserialize(RakNet::BitStream& bitStream) override;
|
||||
void Handle() override;
|
||||
};
|
||||
|
||||
struct SendResponse :public MailLUBitStream {
|
||||
eSendResponse status = eSendResponse::UnknownError;
|
||||
|
||||
SendResponse() : MailLUBitStream(eMessageID::SendResponse) {}
|
||||
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||
};
|
||||
|
||||
@@ -137,6 +140,7 @@ namespace Mail {
|
||||
};
|
||||
|
||||
struct DataRequest : public MailLUBitStream {
|
||||
DataRequest() : MailLUBitStream(eMessageID::DataRequest) {}
|
||||
bool Deserialize(RakNet::BitStream& bitStream) override { return true; };
|
||||
void Handle() override;
|
||||
};
|
||||
|
||||
@@ -1514,6 +1514,7 @@ namespace DEVGMCommands {
|
||||
}
|
||||
|
||||
if (!closest) return;
|
||||
LOG("%llu", closest->GetObjectID());
|
||||
|
||||
Game::entityManager->SerializeEntity(closest);
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ bool MailInfo::Deserialize(RakNet::BitStream& bitStream) {
|
||||
bitStream.IgnoreBytes(4); // padding
|
||||
|
||||
DluAssert(bitStream.GetNumberOfUnreadBits() == 0);
|
||||
LOG_DEBUG("MailInfo: %llu, %s, %s, %s, %llu, %i, %llu, %i, %llu, %i", id, subject.GetAsString().c_str(), body.GetAsString().c_str(), recipientName.GetAsString().c_str(), itemID, itemLOT, itemSubkey, itemCount, timeSent, wasRead);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ void NjMonastryBossInstance::OnPlayerLoaded(Entity* self, Entity* player) {
|
||||
// Join the player in the activity
|
||||
UpdatePlayer(self, player->GetObjectID());
|
||||
|
||||
TakeActivityCost(self, player->GetObjectID());
|
||||
|
||||
// Buff the player
|
||||
auto* destroyableComponent = player->GetComponent<DestroyableComponent>();
|
||||
if (destroyableComponent != nullptr) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <algorithm>
|
||||
#include "Logger.h"
|
||||
#include "Loot.h"
|
||||
#include "ShootingGalleryComponent.h"
|
||||
|
||||
bool ActivityManager::IsPlayerInActivity(Entity* self, LWOOBJID playerID) {
|
||||
const auto* sac = self->GetComponent<ScriptedActivityComponent>();
|
||||
@@ -93,15 +94,16 @@ void ActivityManager::SaveScore(Entity* self, const LWOOBJID playerID, const flo
|
||||
}
|
||||
|
||||
bool ActivityManager::TakeActivityCost(const Entity* self, const LWOOBJID playerID) {
|
||||
auto* sac = self->GetComponent<ScriptedActivityComponent>();
|
||||
if (sac == nullptr)
|
||||
return false;
|
||||
ActivityComponent* activityComponent = self->GetComponent<ScriptedActivityComponent>();
|
||||
if (activityComponent == nullptr) {
|
||||
activityComponent = self->GetComponent<ShootingGalleryComponent>();
|
||||
}
|
||||
|
||||
auto* player = Game::entityManager->GetEntity(playerID);
|
||||
if (player == nullptr)
|
||||
return false;
|
||||
|
||||
return sac->TakeCost(player);
|
||||
return activityComponent->TakeCost(player);
|
||||
}
|
||||
|
||||
uint32_t ActivityManager::CalculateActivityRating(Entity* self, const LWOOBJID playerID) {
|
||||
|
||||
@@ -1367,6 +1367,7 @@ void HandlePacket(Packet* packet) {
|
||||
std::string sMessage = GeneralUtils::UTF16ToWTF8(chatMessage.message);
|
||||
LOG("%s: %s", playerName.c_str(), sMessage.c_str());
|
||||
ChatPackets::SendChatMessage(packet->systemAddress, chatMessage.chatChannel, playerName, user->GetLoggedInChar(), isMythran, chatMessage.message);
|
||||
if (PropertyManagementComponent::Instance()) PropertyManagementComponent::Instance()->OnChatMessageReceived(sMessage);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
21
migrations/dlu/mysql/20_behavior_ids_object_bits.sql
Normal file
21
migrations/dlu/mysql/20_behavior_ids_object_bits.sql
Normal file
@@ -0,0 +1,21 @@
|
||||
UPDATE behaviors SET behavior_id = behavior_id | 0x1000000000000000;
|
||||
ALTER TABLE properties_contents MODIFY behavior_1 BIGINT DEFAULT 0;
|
||||
ALTER TABLE properties_contents MODIFY behavior_2 BIGINT DEFAULT 0;
|
||||
ALTER TABLE properties_contents MODIFY behavior_3 BIGINT DEFAULT 0;
|
||||
ALTER TABLE properties_contents MODIFY behavior_4 BIGINT DEFAULT 0;
|
||||
ALTER TABLE properties_contents MODIFY behavior_5 BIGINT DEFAULT 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_1 = behavior_1 | 0x1000000000000000
|
||||
WHERE behavior_1 != 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_2 = behavior_2 | 0x1000000000000000
|
||||
WHERE behavior_2 != 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_3 = behavior_3 | 0x1000000000000000
|
||||
WHERE behavior_3 != 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_4 = behavior_4 | 0x1000000000000000
|
||||
WHERE behavior_4 != 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_5 = behavior_5 | 0x1000000000000000
|
||||
WHERE behavior_5 != 0;
|
||||
@@ -0,0 +1 @@
|
||||
/* See ModelNormalizeMigration.cpp for details */
|
||||
31
migrations/dlu/sqlite/3_behavior_ids_object_bits.sql
Normal file
31
migrations/dlu/sqlite/3_behavior_ids_object_bits.sql
Normal file
@@ -0,0 +1,31 @@
|
||||
UPDATE behaviors SET behavior_id = behavior_id | 0x1000000000000000;
|
||||
ALTER TABLE properties_contents ADD COLUMN behavior_1_1 BIGINT DEFAULT 0;
|
||||
ALTER TABLE properties_contents ADD COLUMN behavior_2_1 BIGINT DEFAULT 0;
|
||||
ALTER TABLE properties_contents ADD COLUMN behavior_3_1 BIGINT DEFAULT 0;
|
||||
ALTER TABLE properties_contents ADD COLUMN behavior_4_1 BIGINT DEFAULT 0;
|
||||
ALTER TABLE properties_contents ADD COLUMN behavior_5_1 BIGINT DEFAULT 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_1_1 = behavior_1 | 0x1000000000000000
|
||||
WHERE behavior_1 != 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_2_1 = behavior_2 | 0x1000000000000000
|
||||
WHERE behavior_2 != 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_3_1 = behavior_3 | 0x1000000000000000
|
||||
WHERE behavior_3 != 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_4_1 = behavior_4 | 0x1000000000000000
|
||||
WHERE behavior_4 != 0;
|
||||
UPDATE properties_contents SET
|
||||
behavior_5_1 = behavior_5 | 0x1000000000000000
|
||||
WHERE behavior_5 != 0;
|
||||
ALTER TABLE properties_contents DROP COLUMN behavior_1;
|
||||
ALTER TABLE properties_contents DROP COLUMN behavior_2;
|
||||
ALTER TABLE properties_contents DROP COLUMN behavior_3;
|
||||
ALTER TABLE properties_contents DROP COLUMN behavior_4;
|
||||
ALTER TABLE properties_contents DROP COLUMN behavior_5;
|
||||
ALTER TABLE properties_contents RENAME COLUMN behavior_1_1 TO behavior_1;
|
||||
ALTER TABLE properties_contents RENAME COLUMN behavior_2_1 TO behavior_2;
|
||||
ALTER TABLE properties_contents RENAME COLUMN behavior_3_1 TO behavior_3;
|
||||
ALTER TABLE properties_contents RENAME COLUMN behavior_4_1 TO behavior_4;
|
||||
ALTER TABLE properties_contents RENAME COLUMN behavior_5_1 TO behavior_5;
|
||||
@@ -0,0 +1 @@
|
||||
/* See ModelNormalizeMigration.cpp for details */
|
||||
@@ -213,7 +213,7 @@ TEST_F(GameMessageTests, ControlBehaviorAdd) {
|
||||
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
||||
|
||||
const auto arr = ReadArrayFromBitStream(inStream);
|
||||
AddMessage add(*arr);
|
||||
AddMessage add(*arr, LWOOBJID_EMPTY);
|
||||
|
||||
ASSERT_EQ(add.GetBehaviorId(), 10446);
|
||||
ASSERT_EQ(add.GetBehaviorIndex(), 0);
|
||||
|
||||
Reference in New Issue
Block a user