mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-08-09 20:24:16 +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:
@@ -1,6 +1,6 @@
|
||||
#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;
|
||||
|
||||
|
@@ -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,11 +19,14 @@ public:
|
||||
BehaviorMessageBase(const AMFArrayValue& arguments) : m_BehaviorId{ GetBehaviorIdFromArgument(arguments) } {}
|
||||
[[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]] LWOOBJID GetBehaviorIdFromArgument(const AMFArrayValue& arguments);
|
||||
[[nodiscard]] int32_t GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string_view keyName = "actionIndex") const;
|
||||
LWOOBJID m_BehaviorId{ DefaultBehaviorId };
|
||||
bool m_NeedsNewBehaviorID{ false };
|
||||
};
|
||||
|
||||
#endif //!__BEHAVIORMESSAGEBASE__H__
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#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;
|
||||
|
||||
|
@@ -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__
|
||||
|
@@ -107,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;
|
||||
@@ -118,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);
|
||||
|
@@ -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,10 +27,16 @@ public:
|
||||
void VerifyLastEditedState();
|
||||
void SendBehaviorListToClient(AMFArrayValue& args) const;
|
||||
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
|
||||
void CheckModifyState(BehaviorMessageBase& msg);
|
||||
|
||||
[[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);
|
||||
|
||||
@@ -52,6 +59,9 @@ 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;
|
||||
|
Reference in New Issue
Block a user