mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-06-24 13:49:56 +00:00
feat: add saving behaviors to the inventory (#1822)
* change behavior id to LWOOBJID Convert behavior ID to LWOOBJID length missed header fix sqlite field names sqlite brother * feat: add saving behaviors to the inventory consolidate copied code consolidate copied code Update ModelComponent.cpp remove ability to save loot behaviors
This commit is contained in:
parent
f7c9267ba4
commit
8ba35be64d
@ -7,7 +7,9 @@
|
|||||||
#include "BehaviorStates.h"
|
#include "BehaviorStates.h"
|
||||||
#include "ControlBehaviorMsgs.h"
|
#include "ControlBehaviorMsgs.h"
|
||||||
#include "tinyxml2.h"
|
#include "tinyxml2.h"
|
||||||
|
#include "InventoryComponent.h"
|
||||||
#include "SimplePhysicsComponent.h"
|
#include "SimplePhysicsComponent.h"
|
||||||
|
#include "eObjectBits.h"
|
||||||
|
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "DluAssert.h"
|
#include "DluAssert.h"
|
||||||
@ -70,22 +72,27 @@ void ModelComponent::LoadBehaviors() {
|
|||||||
const auto behaviorId = GeneralUtils::TryParse<LWOOBJID>(behavior);
|
const auto behaviorId = GeneralUtils::TryParse<LWOOBJID>(behavior);
|
||||||
if (!behaviorId.has_value() || behaviorId.value() == 0) continue;
|
if (!behaviorId.has_value() || behaviorId.value() == 0) continue;
|
||||||
|
|
||||||
LOG_DEBUG("Loading behavior %d", behaviorId.value());
|
// add behavior at the back
|
||||||
auto& inserted = m_Behaviors.emplace_back();
|
LoadBehavior(behaviorId.value(), m_Behaviors.size(), false);
|
||||||
inserted.SetBehaviorId(*behaviorId);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
const auto behaviorStr = Database::Get()->GetBehavior(behaviorID);
|
||||||
auto res = behaviorXml.Parse(behaviorStr.c_str(), behaviorStr.size());
|
|
||||||
LOG_DEBUG("Behavior %llu %d: %s", res, behaviorId.value(), behaviorStr.c_str());
|
|
||||||
|
|
||||||
const auto* const behaviorRoot = behaviorXml.FirstChildElement("Behavior");
|
tinyxml2::XMLDocument behaviorXml;
|
||||||
if (!behaviorRoot) {
|
auto res = behaviorXml.Parse(behaviorStr.c_str(), behaviorStr.size());
|
||||||
LOG("Failed to load behavior %d due to missing behavior root", behaviorId.value());
|
LOG_DEBUG("Behavior %i %llu: %s", res, behaviorID, behaviorStr.c_str());
|
||||||
continue;
|
|
||||||
}
|
const auto* const behaviorRoot = behaviorXml.FirstChildElement("Behavior");
|
||||||
|
if (behaviorRoot) {
|
||||||
inserted.Deserialize(*behaviorRoot);
|
inserted.Deserialize(*behaviorRoot);
|
||||||
|
} else {
|
||||||
|
LOG("Failed to load behavior %d due to missing behavior root", behaviorID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,6 +127,7 @@ void ModelComponent::UpdatePendingBehaviorId(const LWOOBJID newId, const LWOOBJI
|
|||||||
for (auto& behavior : m_Behaviors) {
|
for (auto& behavior : m_Behaviors) {
|
||||||
if (behavior.GetBehaviorId() != oldId) continue;
|
if (behavior.GetBehaviorId() != oldId) continue;
|
||||||
behavior.SetBehaviorId(newId);
|
behavior.SetBehaviorId(newId);
|
||||||
|
behavior.SetIsLoot(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,8 +154,21 @@ void ModelComponent::SendBehaviorBlocksToClient(const LWOOBJID behaviorToSend, A
|
|||||||
void ModelComponent::AddBehavior(AddMessage& msg) {
|
void ModelComponent::AddBehavior(AddMessage& msg) {
|
||||||
// Can only have 1 of the loot behaviors
|
// Can only have 1 of the loot behaviors
|
||||||
for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == msg.GetBehaviorId()) return;
|
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>();
|
auto* const simplePhysComponent = m_Parent->GetComponent<SimplePhysicsComponent>();
|
||||||
if (simplePhysComponent) {
|
if (simplePhysComponent) {
|
||||||
simplePhysComponent->SetPhysicsMotionState(1);
|
simplePhysComponent->SetPhysicsMotionState(1);
|
||||||
@ -155,8 +176,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;
|
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());
|
m_Behaviors.erase(m_Behaviors.begin() + msg.GetBehaviorIndex());
|
||||||
// TODO move to the inventory
|
// TODO move to the inventory
|
||||||
if (m_Behaviors.empty()) {
|
if (m_Behaviors.empty()) {
|
||||||
@ -175,15 +229,7 @@ std::array<std::pair<LWOOBJID, std::string>, 5> ModelComponent::GetBehaviorsForS
|
|||||||
if (behavior.GetBehaviorId() == -1) continue;
|
if (behavior.GetBehaviorId() == -1) continue;
|
||||||
auto& [id, behaviorData] = toReturn[i];
|
auto& [id, behaviorData] = toReturn[i];
|
||||||
id = behavior.GetBehaviorId();
|
id = behavior.GetBehaviorId();
|
||||||
|
behaviorData = SaveBehavior(behavior);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
@ -66,15 +66,18 @@ public:
|
|||||||
*
|
*
|
||||||
* @tparam Msg The message type to pass
|
* @tparam Msg The message type to pass
|
||||||
* @param args the arguments of the message to be deserialized
|
* @param args the arguments of the message to be deserialized
|
||||||
|
*
|
||||||
|
* @return returns true if a new behaviorID is needed.
|
||||||
*/
|
*/
|
||||||
template<typename Msg>
|
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");
|
static_assert(std::is_base_of_v<BehaviorMessageBase, Msg>, "Msg must be a BehaviorMessageBase");
|
||||||
Msg msg{ args };
|
Msg msg{ args };
|
||||||
for (auto&& behavior : m_Behaviors) {
|
for (auto&& behavior : m_Behaviors) {
|
||||||
if (behavior.GetBehaviorId() == msg.GetBehaviorId()) {
|
if (behavior.GetBehaviorId() == msg.GetBehaviorId()) {
|
||||||
|
behavior.CheckModifyState(msg);
|
||||||
behavior.HandleMsg(msg);
|
behavior.HandleMsg(msg);
|
||||||
return;
|
return msg.GetNeedsNewBehaviorID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,19 +85,21 @@ public:
|
|||||||
if (m_Behaviors.size() > 5) m_Behaviors.resize(5);
|
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!
|
// 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());
|
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.
|
// 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.
|
// 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.
|
// 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->SetBehaviorId(msg.GetBehaviorId());
|
||||||
|
newBehavior->CheckModifyState(msg);
|
||||||
newBehavior->HandleMsg(msg);
|
newBehavior->HandleMsg(msg);
|
||||||
|
return msg.GetNeedsNewBehaviorID();
|
||||||
};
|
};
|
||||||
|
|
||||||
void AddBehavior(AddMessage& msg);
|
void AddBehavior(AddMessage& msg);
|
||||||
|
|
||||||
void MoveToInventory(MoveToInventoryMessage& msg);
|
void RemoveBehavior(MoveToInventoryMessage& msg, const bool keepItem);
|
||||||
|
|
||||||
// Updates the pending behavior ID to the new ID.
|
// Updates the pending behavior ID to the new ID.
|
||||||
void UpdatePendingBehaviorId(const LWOOBJID newId, const LWOOBJID oldId);
|
void UpdatePendingBehaviorId(const LWOOBJID newId, const LWOOBJID oldId);
|
||||||
@ -141,6 +146,13 @@ public:
|
|||||||
|
|
||||||
void OnChatMessageReceived(const std::string& sMessage);
|
void OnChatMessageReceived(const std::string& sMessage);
|
||||||
private:
|
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.
|
// Number of Actions that are awaiting an UnSmash to finish.
|
||||||
uint32_t m_NumActiveUnSmash{};
|
uint32_t m_NumActiveUnSmash{};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "AddMessage.h"
|
#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");
|
const auto* const behaviorIndexValue = arguments.Get<double>("BehaviorIndex");
|
||||||
if (!behaviorIndexValue) return;
|
if (!behaviorIndexValue) return;
|
||||||
|
|
||||||
|
@ -9,11 +9,13 @@
|
|||||||
*/
|
*/
|
||||||
class AddMessage : public BehaviorMessageBase {
|
class AddMessage : public BehaviorMessageBase {
|
||||||
public:
|
public:
|
||||||
AddMessage(const AMFArrayValue& arguments);
|
AddMessage(const AMFArrayValue& arguments, const LWOOBJID _owningPlayerID);
|
||||||
[[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; };
|
[[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; };
|
||||||
|
[[nodiscard]] LWOOBJID GetOwningPlayerID() const noexcept { return m_OwningPlayerID; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_BehaviorIndex{ 0 };
|
uint32_t m_BehaviorIndex{ 0 };
|
||||||
|
LWOOBJID m_OwningPlayerID{};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__ADDMESSAGE__H__
|
#endif //!__ADDMESSAGE__H__
|
||||||
|
@ -19,11 +19,14 @@ public:
|
|||||||
BehaviorMessageBase(const AMFArrayValue& arguments) : m_BehaviorId{ GetBehaviorIdFromArgument(arguments) } {}
|
BehaviorMessageBase(const AMFArrayValue& arguments) : m_BehaviorId{ GetBehaviorIdFromArgument(arguments) } {}
|
||||||
[[nodiscard]] LWOOBJID 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 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:
|
protected:
|
||||||
[[nodiscard]] LWOOBJID GetBehaviorIdFromArgument(const AMFArrayValue& arguments);
|
[[nodiscard]] LWOOBJID GetBehaviorIdFromArgument(const AMFArrayValue& arguments);
|
||||||
[[nodiscard]] int32_t GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string_view keyName = "actionIndex") const;
|
[[nodiscard]] int32_t GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string_view keyName = "actionIndex") const;
|
||||||
LWOOBJID m_BehaviorId{ DefaultBehaviorId };
|
LWOOBJID m_BehaviorId{ DefaultBehaviorId };
|
||||||
|
bool m_NeedsNewBehaviorID{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__BEHAVIORMESSAGEBASE__H__
|
#endif //!__BEHAVIORMESSAGEBASE__H__
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "MoveToInventoryMessage.h"
|
#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");
|
const auto* const behaviorIndexValue = arguments.Get<double>("BehaviorIndex");
|
||||||
if (!behaviorIndexValue) return;
|
if (!behaviorIndexValue) return;
|
||||||
|
|
||||||
|
@ -10,11 +10,13 @@ class AMFArrayValue;
|
|||||||
*/
|
*/
|
||||||
class MoveToInventoryMessage : public BehaviorMessageBase {
|
class MoveToInventoryMessage : public BehaviorMessageBase {
|
||||||
public:
|
public:
|
||||||
MoveToInventoryMessage(const AMFArrayValue& arguments);
|
MoveToInventoryMessage(const AMFArrayValue& arguments, const LWOOBJID owningPlayerID);
|
||||||
[[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; };
|
[[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; };
|
||||||
|
[[nodiscard]] LWOOBJID GetOwningPlayerID() const noexcept { return m_OwningPlayerID; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_BehaviorIndex;
|
uint32_t m_BehaviorIndex;
|
||||||
|
LWOOBJID m_OwningPlayerID{};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__MOVETOINVENTORYMESSAGE__H__
|
#endif //!__MOVETOINVENTORYMESSAGE__H__
|
||||||
|
@ -107,9 +107,12 @@ void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayV
|
|||||||
if (!modelComponent) return;
|
if (!modelComponent) return;
|
||||||
|
|
||||||
ControlBehaviorContext context{ arguments, modelComponent, modelOwner };
|
ControlBehaviorContext context{ arguments, modelComponent, modelOwner };
|
||||||
|
bool needsNewBehaviorID = false;
|
||||||
|
|
||||||
if (command == "sendBehaviorListToClient") {
|
if (command == "sendBehaviorListToClient") {
|
||||||
SendBehaviorListToClient(context);
|
SendBehaviorListToClient(context);
|
||||||
|
} else if (command == "sendBehaviorBlocksToClient") {
|
||||||
|
SendBehaviorBlocksToClient(context);
|
||||||
} else if (command == "modelTypeChanged") {
|
} else if (command == "modelTypeChanged") {
|
||||||
const auto* const modelType = arguments.Get<double>("ModelType");
|
const auto* const modelType = arguments.Get<double>("ModelType");
|
||||||
if (!modelType) return;
|
if (!modelType) return;
|
||||||
@ -118,52 +121,54 @@ void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayV
|
|||||||
} else if (command == "toggleExecutionUpdates") {
|
} else if (command == "toggleExecutionUpdates") {
|
||||||
// TODO
|
// TODO
|
||||||
} else if (command == "addStrip") {
|
} else if (command == "addStrip") {
|
||||||
if (BehaviorMessageBase(context.arguments).IsDefaultBehaviorId()) RequestUpdatedID(context);
|
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<AddStripMessage>(context.arguments);
|
||||||
|
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<AddStripMessage>(context.arguments);
|
|
||||||
} else if (command == "removeStrip") {
|
} else if (command == "removeStrip") {
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<RemoveStripMessage>(arguments);
|
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<RemoveStripMessage>(arguments);
|
||||||
} else if (command == "mergeStrips") {
|
} else if (command == "mergeStrips") {
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<MergeStripsMessage>(arguments);
|
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<MergeStripsMessage>(arguments);
|
||||||
} else if (command == "splitStrip") {
|
} else if (command == "splitStrip") {
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<SplitStripMessage>(arguments);
|
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<SplitStripMessage>(arguments);
|
||||||
} else if (command == "updateStripUI") {
|
} else if (command == "updateStripUI") {
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<UpdateStripUiMessage>(arguments);
|
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<UpdateStripUiMessage>(arguments);
|
||||||
} else if (command == "addAction") {
|
} else if (command == "addAction") {
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<AddActionMessage>(arguments);
|
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<AddActionMessage>(arguments);
|
||||||
} else if (command == "migrateActions") {
|
} else if (command == "migrateActions") {
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<MigrateActionsMessage>(arguments);
|
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<MigrateActionsMessage>(arguments);
|
||||||
} else if (command == "rearrangeStrip") {
|
} else if (command == "rearrangeStrip") {
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<RearrangeStripMessage>(arguments);
|
needsNewBehaviorID = context.modelComponent->HandleControlBehaviorsMsg<RearrangeStripMessage>(arguments);
|
||||||
} else if (command == "add") {
|
|
||||||
AddMessage msg{ context.arguments };
|
|
||||||
context.modelComponent->AddBehavior(msg);
|
|
||||||
SendBehaviorListToClient(context);
|
|
||||||
} else if (command == "removeActions") {
|
} 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") {
|
} 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.
|
// Send the list back to the client so the name is updated.
|
||||||
SendBehaviorListToClient(context);
|
SendBehaviorListToClient(context);
|
||||||
} else if (command == "sendBehaviorBlocksToClient") {
|
} else if (command == "add") {
|
||||||
SendBehaviorBlocksToClient(context);
|
AddMessage msg{ context.arguments, context.modelOwner->GetObjectID() };
|
||||||
} else if (command == "moveToInventory") {
|
context.modelComponent->AddBehavior(msg);
|
||||||
MoveToInventoryMessage msg{ arguments };
|
SendBehaviorListToClient(context);
|
||||||
context.modelComponent->MoveToInventory(msg);
|
} 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>();
|
auto* characterComponent = modelOwner->GetComponent<CharacterComponent>();
|
||||||
if (!characterComponent) return;
|
if (!characterComponent) return;
|
||||||
|
|
||||||
AMFArrayValue args;
|
if (!isRemove) {
|
||||||
args.Insert("BehaviorID", std::to_string(msg.GetBehaviorId()));
|
AMFArrayValue args;
|
||||||
GameMessages::SendUIMessageServerToSingleClient(modelOwner, characterComponent->GetSystemAddress(), "BehaviorRemoved", args);
|
args.Insert("BehaviorID", std::to_string(msg.GetBehaviorId()));
|
||||||
|
GameMessages::SendUIMessageServerToSingleClient(modelOwner, characterComponent->GetSystemAddress(), "BehaviorRemoved", args);
|
||||||
|
}
|
||||||
|
|
||||||
SendBehaviorListToClient(context);
|
SendBehaviorListToClient(context);
|
||||||
} else if (command == "updateAction") {
|
|
||||||
context.modelComponent->HandleControlBehaviorsMsg<UpdateActionMessage>(arguments);
|
|
||||||
} else {
|
} else {
|
||||||
LOG("Unknown behavior command (%s)", command.data());
|
LOG("Unknown behavior command (%s)", command.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needsNewBehaviorID) RequestUpdatedID(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlBehaviors::ControlBehaviors() {
|
ControlBehaviors::ControlBehaviors() {
|
||||||
|
@ -8,9 +8,12 @@
|
|||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
PropertyBehavior::PropertyBehavior() {
|
PropertyBehavior::PropertyBehavior(bool _isTemplated) {
|
||||||
m_LastEditedState = BehaviorState::HOME_STATE;
|
m_LastEditedState = BehaviorState::HOME_STATE;
|
||||||
m_ActiveState = 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<>
|
template<>
|
||||||
@ -81,13 +84,6 @@ void PropertyBehavior::HandleMsg(RenameMessage& msg) {
|
|||||||
m_Name = msg.GetName();
|
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<>
|
template<>
|
||||||
void PropertyBehavior::HandleMsg(GameMessages::RequestUse& msg) {
|
void PropertyBehavior::HandleMsg(GameMessages::RequestUse& msg) {
|
||||||
m_States[m_ActiveState].HandleMsg(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);
|
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 {
|
void PropertyBehavior::SendBehaviorListToClient(AMFArrayValue& args) const {
|
||||||
args.Insert("id", std::to_string(m_BehaviorId));
|
args.Insert("id", std::to_string(m_BehaviorId));
|
||||||
args.Insert("name", m_Name);
|
args.Insert("name", m_Name);
|
||||||
@ -147,6 +149,9 @@ void PropertyBehavior::Serialize(tinyxml2::XMLElement& behavior) const {
|
|||||||
behavior.SetAttribute("isLocked", isLocked);
|
behavior.SetAttribute("isLocked", isLocked);
|
||||||
behavior.SetAttribute("isLoot", isLoot);
|
behavior.SetAttribute("isLoot", isLoot);
|
||||||
|
|
||||||
|
// CUSTOM XML ATTRIBUTE
|
||||||
|
behavior.SetAttribute("isTemplated", isTemplated);
|
||||||
|
|
||||||
for (const auto& [stateId, state] : m_States) {
|
for (const auto& [stateId, state] : m_States) {
|
||||||
if (state.IsEmpty()) continue;
|
if (state.IsEmpty()) continue;
|
||||||
auto* const stateElement = behavior.InsertNewChildElement("State");
|
auto* const stateElement = behavior.InsertNewChildElement("State");
|
||||||
@ -161,6 +166,9 @@ void PropertyBehavior::Deserialize(const tinyxml2::XMLElement& behavior) {
|
|||||||
behavior.QueryBoolAttribute("isLocked", &isLocked);
|
behavior.QueryBoolAttribute("isLocked", &isLocked);
|
||||||
behavior.QueryBoolAttribute("isLoot", &isLoot);
|
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")) {
|
for (const auto* stateElement = behavior.FirstChildElement("State"); stateElement; stateElement = stateElement->NextSiblingElement("State")) {
|
||||||
int32_t stateId = -1;
|
int32_t stateId = -1;
|
||||||
stateElement->QueryIntAttribute("id", &stateId);
|
stateElement->QueryIntAttribute("id", &stateId);
|
||||||
|
@ -10,6 +10,7 @@ namespace tinyxml2 {
|
|||||||
enum class BehaviorState : uint32_t;
|
enum class BehaviorState : uint32_t;
|
||||||
|
|
||||||
class AMFArrayValue;
|
class AMFArrayValue;
|
||||||
|
class BehaviorMessageBase;
|
||||||
class ModelComponent;
|
class ModelComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,7 +18,7 @@ class ModelComponent;
|
|||||||
*/
|
*/
|
||||||
class PropertyBehavior {
|
class PropertyBehavior {
|
||||||
public:
|
public:
|
||||||
PropertyBehavior();
|
PropertyBehavior(bool _isTemplated = false);
|
||||||
|
|
||||||
template <typename Msg>
|
template <typename Msg>
|
||||||
void HandleMsg(Msg& msg);
|
void HandleMsg(Msg& msg);
|
||||||
@ -26,10 +27,16 @@ public:
|
|||||||
void VerifyLastEditedState();
|
void VerifyLastEditedState();
|
||||||
void SendBehaviorListToClient(AMFArrayValue& args) const;
|
void SendBehaviorListToClient(AMFArrayValue& args) const;
|
||||||
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
||||||
|
void CheckModifyState(BehaviorMessageBase& msg);
|
||||||
|
|
||||||
[[nodiscard]] LWOOBJID GetBehaviorId() const noexcept { return m_BehaviorId; }
|
[[nodiscard]] LWOOBJID GetBehaviorId() const noexcept { return m_BehaviorId; }
|
||||||
void SetBehaviorId(LWOOBJID id) noexcept { m_BehaviorId = id; }
|
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 Serialize(tinyxml2::XMLElement& behavior) const;
|
||||||
void Deserialize(const tinyxml2::XMLElement& behavior);
|
void Deserialize(const tinyxml2::XMLElement& behavior);
|
||||||
|
|
||||||
@ -52,6 +59,9 @@ private:
|
|||||||
// Whether this behavior is custom or pre-fab.
|
// Whether this behavior is custom or pre-fab.
|
||||||
bool isLoot = false;
|
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.
|
// 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.
|
// If the last edited state has no strips, it will open to the first state that has strips.
|
||||||
BehaviorState m_LastEditedState;
|
BehaviorState m_LastEditedState;
|
||||||
|
@ -213,7 +213,7 @@ TEST_F(GameMessageTests, ControlBehaviorAdd) {
|
|||||||
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
|
||||||
|
|
||||||
const auto arr = ReadArrayFromBitStream(inStream);
|
const auto arr = ReadArrayFromBitStream(inStream);
|
||||||
AddMessage add(*arr);
|
AddMessage add(*arr, LWOOBJID_EMPTY);
|
||||||
|
|
||||||
ASSERT_EQ(add.GetBehaviorId(), 10446);
|
ASSERT_EQ(add.GetBehaviorId(), 10446);
|
||||||
ASSERT_EQ(add.GetBehaviorIndex(), 0);
|
ASSERT_EQ(add.GetBehaviorIndex(), 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user