mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-10-22 15:28:07 +00:00
feat: behavior states (#1918)
This commit is contained in:
@@ -29,19 +29,22 @@ ModelComponent::ModelComponent(Entity* parent, const int32_t componentID) : Comp
|
|||||||
|
|
||||||
bool ModelComponent::OnResetModelToDefaults(GameMessages::GameMsg& msg) {
|
bool ModelComponent::OnResetModelToDefaults(GameMessages::GameMsg& msg) {
|
||||||
auto& reset = static_cast<GameMessages::ResetModelToDefaults&>(msg);
|
auto& reset = static_cast<GameMessages::ResetModelToDefaults&>(msg);
|
||||||
for (auto& behavior : m_Behaviors) behavior.HandleMsg(reset);
|
if (reset.bResetBehaviors) for (auto& behavior : m_Behaviors) behavior.HandleMsg(reset);
|
||||||
GameMessages::UnSmash unsmash;
|
|
||||||
unsmash.target = GetParent()->GetObjectID();
|
|
||||||
unsmash.duration = 0.0f;
|
|
||||||
unsmash.Send(UNASSIGNED_SYSTEM_ADDRESS);
|
|
||||||
|
|
||||||
m_Parent->SetPosition(m_OriginalPosition);
|
if (reset.bUnSmash) {
|
||||||
m_Parent->SetRotation(m_OriginalRotation);
|
GameMessages::UnSmash unsmash;
|
||||||
|
unsmash.target = GetParent()->GetObjectID();
|
||||||
|
unsmash.duration = 0.0f;
|
||||||
|
unsmash.Send(UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
|
m_NumActiveUnSmash = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset.bResetPos) m_Parent->SetPosition(m_OriginalPosition);
|
||||||
|
if (reset.bResetRot) m_Parent->SetRotation(m_OriginalRotation);
|
||||||
m_Parent->SetVelocity(NiPoint3Constant::ZERO);
|
m_Parent->SetVelocity(NiPoint3Constant::ZERO);
|
||||||
|
|
||||||
m_Speed = 3.0f;
|
m_Speed = 3.0f;
|
||||||
m_NumListeningInteract = 0;
|
m_NumListeningInteract = 0;
|
||||||
m_NumActiveUnSmash = 0;
|
|
||||||
|
|
||||||
m_NumActiveAttack = 0;
|
m_NumActiveAttack = 0;
|
||||||
GameMessages::SetFaction set{};
|
GameMessages::SetFaction set{};
|
||||||
|
@@ -848,6 +848,11 @@ namespace GameMessages {
|
|||||||
|
|
||||||
struct ResetModelToDefaults : public GameMsg {
|
struct ResetModelToDefaults : public GameMsg {
|
||||||
ResetModelToDefaults() : GameMsg(MessageType::Game::RESET_MODEL_TO_DEFAULTS) {}
|
ResetModelToDefaults() : GameMsg(MessageType::Game::RESET_MODEL_TO_DEFAULTS) {}
|
||||||
|
|
||||||
|
bool bResetPos{ true };
|
||||||
|
bool bResetRot{ true };
|
||||||
|
bool bUnSmash{ true };
|
||||||
|
bool bResetBehaviors{ true };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EmotePlayed : public GameMsg {
|
struct EmotePlayed : public GameMsg {
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
#include "ControlBehaviorMsgs.h"
|
#include "ControlBehaviorMsgs.h"
|
||||||
#include "tinyxml2.h"
|
#include "tinyxml2.h"
|
||||||
#include "ModelComponent.h"
|
#include "ModelComponent.h"
|
||||||
|
#include "StringifiedEnum.h"
|
||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
@@ -178,13 +179,33 @@ void PropertyBehavior::Deserialize(const tinyxml2::XMLElement& behavior) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PropertyBehavior::Update(float deltaTime, ModelComponent& modelComponent) {
|
void PropertyBehavior::Update(float deltaTime, ModelComponent& modelComponent) {
|
||||||
for (auto& state : m_States | std::views::values) state.Update(deltaTime, modelComponent);
|
auto& activeState = GetActiveState();
|
||||||
|
UpdateResult updateResult{};
|
||||||
|
activeState.Update(deltaTime, modelComponent, updateResult);
|
||||||
|
if (updateResult.newState.has_value() && updateResult.newState.value() != m_ActiveState) {
|
||||||
|
LOG("Behavior %llu is changing from state %s to %s", StringifiedEnum::ToString(m_ActiveState).data(), StringifiedEnum::ToString(updateResult.newState.value()).data());
|
||||||
|
GameMessages::ResetModelToDefaults resetMsg{};
|
||||||
|
resetMsg.bResetPos = false;
|
||||||
|
resetMsg.bResetRot = false;
|
||||||
|
resetMsg.bUnSmash = false;
|
||||||
|
resetMsg.bResetBehaviors = false;
|
||||||
|
modelComponent.OnResetModelToDefaults(resetMsg);
|
||||||
|
HandleMsg(resetMsg);
|
||||||
|
m_ActiveState = updateResult.newState.value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertyBehavior::OnChatMessageReceived(const std::string& sMessage) {
|
void PropertyBehavior::OnChatMessageReceived(const std::string& sMessage) {
|
||||||
for (auto& state : m_States | std::views::values) state.OnChatMessageReceived(sMessage);
|
auto& activeState = GetActiveState();
|
||||||
|
activeState.OnChatMessageReceived(sMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertyBehavior::OnHit() {
|
void PropertyBehavior::OnHit() {
|
||||||
for (auto& state : m_States | std::views::values) state.OnHit();
|
auto& activeState = GetActiveState();
|
||||||
|
activeState.OnHit();
|
||||||
|
}
|
||||||
|
|
||||||
|
State& PropertyBehavior::GetActiveState() {
|
||||||
|
DluAssert(m_States.contains(m_ActiveState));
|
||||||
|
return m_States[m_ActiveState];
|
||||||
}
|
}
|
||||||
|
@@ -1,18 +1,23 @@
|
|||||||
#ifndef __PROPERTYBEHAVIOR__H__
|
#ifndef __PROPERTYBEHAVIOR__H__
|
||||||
#define __PROPERTYBEHAVIOR__H__
|
#define __PROPERTYBEHAVIOR__H__
|
||||||
|
|
||||||
|
#include "BehaviorStates.h"
|
||||||
#include "State.h"
|
#include "State.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
namespace tinyxml2 {
|
namespace tinyxml2 {
|
||||||
class XMLElement;
|
class XMLElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class BehaviorState : uint32_t;
|
|
||||||
|
|
||||||
class AMFArrayValue;
|
class AMFArrayValue;
|
||||||
class BehaviorMessageBase;
|
class BehaviorMessageBase;
|
||||||
class ModelComponent;
|
class ModelComponent;
|
||||||
|
|
||||||
|
struct UpdateResult {
|
||||||
|
std::optional<BehaviorState> newState;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the Entity of a Property Behavior and holds data associated with the behavior
|
* Represents the Entity of a Property Behavior and holds data associated with the behavior
|
||||||
*/
|
*/
|
||||||
@@ -45,6 +50,7 @@ public:
|
|||||||
void OnHit();
|
void OnHit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
State& GetActiveState();
|
||||||
// The current active behavior state. Behaviors can only be in ONE state at a time.
|
// The current active behavior state. Behaviors can only be in ONE state at a time.
|
||||||
BehaviorState m_ActiveState;
|
BehaviorState m_ActiveState;
|
||||||
|
|
||||||
|
@@ -163,8 +163,8 @@ void State::Deserialize(const tinyxml2::XMLElement& state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::Update(float deltaTime, ModelComponent& modelComponent) {
|
void State::Update(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult) {
|
||||||
for (auto& strip : m_Strips) strip.Update(deltaTime, modelComponent);
|
for (auto& strip : m_Strips) strip.Update(deltaTime, modelComponent, updateResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
void State::OnChatMessageReceived(const std::string& sMessage) {
|
void State::OnChatMessageReceived(const std::string& sMessage) {
|
||||||
|
@@ -9,6 +9,7 @@ namespace tinyxml2 {
|
|||||||
|
|
||||||
class AMFArrayValue;
|
class AMFArrayValue;
|
||||||
class ModelComponent;
|
class ModelComponent;
|
||||||
|
struct UpdateResult;
|
||||||
|
|
||||||
class State {
|
class State {
|
||||||
public:
|
public:
|
||||||
@@ -21,7 +22,7 @@ public:
|
|||||||
void Serialize(tinyxml2::XMLElement& state) const;
|
void Serialize(tinyxml2::XMLElement& state) const;
|
||||||
void Deserialize(const tinyxml2::XMLElement& state);
|
void Deserialize(const tinyxml2::XMLElement& state);
|
||||||
|
|
||||||
void Update(float deltaTime, ModelComponent& modelComponent);
|
void Update(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult);
|
||||||
|
|
||||||
void OnChatMessageReceived(const std::string& sMessage);
|
void OnChatMessageReceived(const std::string& sMessage);
|
||||||
void OnHit();
|
void OnHit();
|
||||||
|
@@ -160,13 +160,14 @@ void Strip::SpawnDrop(LOT dropLOT, Entity& entity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult) {
|
||||||
auto& entity = *modelComponent.GetParent();
|
auto& entity = *modelComponent.GetParent();
|
||||||
auto& nextAction = GetNextAction();
|
auto& nextAction = GetNextAction();
|
||||||
auto number = nextAction.GetValueParameterDouble();
|
auto number = nextAction.GetValueParameterDouble();
|
||||||
auto valueStr = nextAction.GetValueParameterString();
|
auto valueStr = nextAction.GetValueParameterString();
|
||||||
auto numberAsInt = static_cast<int32_t>(number);
|
auto numberAsInt = static_cast<int32_t>(number);
|
||||||
auto nextActionType = GetNextAction().GetType();
|
auto nextActionType = GetNextAction().GetType();
|
||||||
|
LOG_DEBUG("Processing Strip Action: %s with number %.2f and string %s", nextActionType.data(), number, valueStr.data());
|
||||||
|
|
||||||
// TODO replace with switch case and nextActionType with enum
|
// TODO replace with switch case and nextActionType with enum
|
||||||
/* BEGIN Move */
|
/* BEGIN Move */
|
||||||
@@ -223,7 +224,8 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
unsmash.Send(UNASSIGNED_SYSTEM_ADDRESS);
|
unsmash.Send(UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
modelComponent.AddUnSmash();
|
modelComponent.AddUnSmash();
|
||||||
|
|
||||||
m_PausedTime = number;
|
// since it may take time for the message to relay to clients
|
||||||
|
m_PausedTime = number + 0.5f;
|
||||||
} else if (nextActionType == "Wait") {
|
} else if (nextActionType == "Wait") {
|
||||||
m_PausedTime = number;
|
m_PausedTime = number;
|
||||||
} else if (nextActionType == "Chat") {
|
} else if (nextActionType == "Chat") {
|
||||||
@@ -258,6 +260,21 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
for (; numberAsInt > 0; numberAsInt--) SpawnDrop(6431, entity); // 1 Armor powerup
|
for (; numberAsInt > 0; numberAsInt--) SpawnDrop(6431, entity); // 1 Armor powerup
|
||||||
}
|
}
|
||||||
/* END Gameplay */
|
/* END Gameplay */
|
||||||
|
/* BEGIN StateMachine */
|
||||||
|
else if (nextActionType == "ChangeStateHome") {
|
||||||
|
updateResult.newState = BehaviorState::HOME_STATE;
|
||||||
|
} else if (nextActionType == "ChangeStateCircle") {
|
||||||
|
updateResult.newState = BehaviorState::CIRCLE_STATE;
|
||||||
|
} else if (nextActionType == "ChangeStateSquare") {
|
||||||
|
updateResult.newState = BehaviorState::SQUARE_STATE;
|
||||||
|
} else if (nextActionType == "ChangeStateDiamond") {
|
||||||
|
updateResult.newState = BehaviorState::DIAMOND_STATE;
|
||||||
|
} else if (nextActionType == "ChangeStateTriangle") {
|
||||||
|
updateResult.newState = BehaviorState::TRIANGLE_STATE;
|
||||||
|
} else if (nextActionType == "ChangeStateStar") {
|
||||||
|
updateResult.newState = BehaviorState::STAR_STATE;
|
||||||
|
}
|
||||||
|
/* END StateMachine*/
|
||||||
else {
|
else {
|
||||||
static std::set<std::string> g_WarnedActions;
|
static std::set<std::string> g_WarnedActions;
|
||||||
if (!g_WarnedActions.contains(nextActionType.data())) {
|
if (!g_WarnedActions.contains(nextActionType.data())) {
|
||||||
@@ -330,7 +347,7 @@ bool Strip::CheckMovement(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
return moveFinished;
|
return moveFinished;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Strip::Update(float deltaTime, ModelComponent& modelComponent) {
|
void Strip::Update(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult) {
|
||||||
// No point in running a strip with only one action.
|
// No point in running a strip with only one action.
|
||||||
// Strips are also designed to have 2 actions or more to run.
|
// Strips are also designed to have 2 actions or more to run.
|
||||||
if (!HasMinimumActions()) return;
|
if (!HasMinimumActions()) return;
|
||||||
@@ -354,9 +371,9 @@ void Strip::Update(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
|
|
||||||
// Check for trigger blocks and if not a trigger block proc this blocks action
|
// Check for trigger blocks and if not a trigger block proc this blocks action
|
||||||
if (m_NextActionIndex == 0) {
|
if (m_NextActionIndex == 0) {
|
||||||
|
LOG("Behavior strip started %s", nextAction.GetType().data());
|
||||||
if (nextAction.GetType() == "OnInteract") {
|
if (nextAction.GetType() == "OnInteract") {
|
||||||
modelComponent.AddInteract();
|
modelComponent.AddInteract();
|
||||||
|
|
||||||
} else if (nextAction.GetType() == "OnChat") {
|
} else if (nextAction.GetType() == "OnChat") {
|
||||||
// logic here if needed
|
// logic here if needed
|
||||||
} else if (nextAction.GetType() == "OnAttack") {
|
} else if (nextAction.GetType() == "OnAttack") {
|
||||||
@@ -365,7 +382,7 @@ void Strip::Update(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
Game::entityManager->SerializeEntity(entity);
|
Game::entityManager->SerializeEntity(entity);
|
||||||
m_WaitingForAction = true;
|
m_WaitingForAction = true;
|
||||||
} else { // should be a normal block
|
} else { // should be a normal block
|
||||||
ProcNormalAction(deltaTime, modelComponent);
|
ProcNormalAction(deltaTime, modelComponent, updateResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,6 +12,7 @@ namespace tinyxml2 {
|
|||||||
|
|
||||||
class AMFArrayValue;
|
class AMFArrayValue;
|
||||||
class ModelComponent;
|
class ModelComponent;
|
||||||
|
struct UpdateResult;
|
||||||
|
|
||||||
class Strip {
|
class Strip {
|
||||||
public:
|
public:
|
||||||
@@ -33,9 +34,9 @@ public:
|
|||||||
// Checks the movement logic for whether or not to proceed
|
// Checks the movement logic for whether or not to proceed
|
||||||
// Returns true if the movement can continue, false if it needs to wait more.
|
// Returns true if the movement can continue, false if it needs to wait more.
|
||||||
bool CheckMovement(float deltaTime, ModelComponent& modelComponent);
|
bool CheckMovement(float deltaTime, ModelComponent& modelComponent);
|
||||||
void Update(float deltaTime, ModelComponent& modelComponent);
|
void Update(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult);
|
||||||
void SpawnDrop(LOT dropLOT, Entity& entity);
|
void SpawnDrop(LOT dropLOT, Entity& entity);
|
||||||
void ProcNormalAction(float deltaTime, ModelComponent& modelComponent);
|
void ProcNormalAction(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult);
|
||||||
void RemoveStates(ModelComponent& modelComponent) const;
|
void RemoveStates(ModelComponent& modelComponent) const;
|
||||||
|
|
||||||
// 2 actions are required for strips to work
|
// 2 actions are required for strips to work
|
||||||
|
Reference in New Issue
Block a user