mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-06-23 05:09:53 +00:00
feat: add chat behaviors (#1818)
* Move in all directions is functional * feat: add movement behaviors the following behaviors will function MoveRight MoveLeft FlyUp FlyDown MoveForward MoveBackward The behavior of the behaviors is once a move in an axis is active, that behavior must finish its movement before another one on that axis can do another movement on it. * feat: add chat behaviors Tested that models can correctly send chat messages, silently and publically. Tested as well that the filter is used by the client for behaviors and added a security check to not broadcast messages that fail the check if words are removed.
This commit is contained in:
parent
2f315d9288
commit
04487efa25
@ -237,3 +237,7 @@ bool ModelComponent::TrySetVelocity(const NiPoint3& velocity) const {
|
|||||||
void ModelComponent::SetVelocity(const NiPoint3& velocity) const {
|
void ModelComponent::SetVelocity(const NiPoint3& velocity) const {
|
||||||
m_Parent->SetVelocity(velocity);
|
m_Parent->SetVelocity(velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelComponent::OnChatMessageReceived(const std::string& sMessage) {
|
||||||
|
for (auto& behavior : m_Behaviors) behavior.OnChatMessageReceived(sMessage);
|
||||||
|
}
|
||||||
|
@ -138,6 +138,8 @@ public:
|
|||||||
|
|
||||||
// Force sets the velocity to a value.
|
// Force sets the velocity to a value.
|
||||||
void SetVelocity(const NiPoint3& velocity) const;
|
void SetVelocity(const NiPoint3& velocity) const;
|
||||||
|
|
||||||
|
void OnChatMessageReceived(const std::string& sMessage);
|
||||||
private:
|
private:
|
||||||
// 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{};
|
||||||
|
@ -817,3 +817,14 @@ void PropertyManagementComponent::SetOwnerId(const LWOOBJID value) {
|
|||||||
const std::map<LWOOBJID, LWOOBJID>& PropertyManagementComponent::GetModels() const {
|
const std::map<LWOOBJID, LWOOBJID>& PropertyManagementComponent::GetModels() const {
|
||||||
return models;
|
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; }
|
LWOOBJID GetId() const noexcept { return propertyId; }
|
||||||
|
|
||||||
|
|
||||||
|
void OnChatMessageReceived(const std::string& sMessage) const;
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* This
|
* This
|
||||||
@ -193,7 +195,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* The models that are placed on this property
|
* 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
|
* The name of this property
|
||||||
|
@ -20,6 +20,7 @@ target_include_directories(dPropertyBehaviors PUBLIC "." "ControlBehaviorMessage
|
|||||||
"${PROJECT_SOURCE_DIR}/dGame/dUtilities" # ObjectIdManager.h
|
"${PROJECT_SOURCE_DIR}/dGame/dUtilities" # ObjectIdManager.h
|
||||||
"${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # GameMessages.h
|
"${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # GameMessages.h
|
||||||
"${PROJECT_SOURCE_DIR}/dGame/dComponents" # ModelComponent.h
|
"${PROJECT_SOURCE_DIR}/dGame/dComponents" # ModelComponent.h
|
||||||
|
"${PROJECT_SOURCE_DIR}/dChatFilter" # dChatFilter.h
|
||||||
)
|
)
|
||||||
target_precompile_headers(dPropertyBehaviors REUSE_FROM dGameBase)
|
target_precompile_headers(dPropertyBehaviors REUSE_FROM dGameBase)
|
||||||
|
|
||||||
|
@ -172,3 +172,7 @@ 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);
|
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);
|
||||||
|
}
|
||||||
|
@ -34,6 +34,7 @@ public:
|
|||||||
void Deserialize(const tinyxml2::XMLElement& behavior);
|
void Deserialize(const tinyxml2::XMLElement& behavior);
|
||||||
|
|
||||||
void Update(float deltaTime, ModelComponent& modelComponent);
|
void Update(float deltaTime, ModelComponent& modelComponent);
|
||||||
|
void OnChatMessageReceived(const std::string& sMessage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 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.
|
||||||
|
@ -166,3 +166,7 @@ void State::Deserialize(const tinyxml2::XMLElement& state) {
|
|||||||
void State::Update(float deltaTime, ModelComponent& modelComponent) {
|
void State::Update(float deltaTime, ModelComponent& modelComponent) {
|
||||||
for (auto& strip : m_Strips) strip.Update(deltaTime, 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 Deserialize(const tinyxml2::XMLElement& state);
|
||||||
|
|
||||||
void Update(float deltaTime, ModelComponent& modelComponent);
|
void Update(float deltaTime, ModelComponent& modelComponent);
|
||||||
|
|
||||||
|
void OnChatMessageReceived(const std::string& sMessage);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// The strips contained within this state.
|
// The strips contained within this state.
|
||||||
|
@ -5,8 +5,12 @@
|
|||||||
#include "tinyxml2.h"
|
#include "tinyxml2.h"
|
||||||
#include "dEntity/EntityInfo.h"
|
#include "dEntity/EntityInfo.h"
|
||||||
#include "ModelComponent.h"
|
#include "ModelComponent.h"
|
||||||
|
#include "ChatPackets.h"
|
||||||
|
#include "PropertyManagementComponent.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
|
|
||||||
|
#include "dChatFilter.h"
|
||||||
|
|
||||||
#include "DluAssert.h"
|
#include "DluAssert.h"
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@ -103,6 +107,16 @@ void Strip::HandleMsg(GameMessages::ResetModelToDefaults& msg) {
|
|||||||
m_PreviousFramePosition = NiPoint3Constant::ZERO;
|
m_PreviousFramePosition = NiPoint3Constant::ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Strip::OnChatMessageReceived(const std::string& sMessage) {
|
||||||
|
if (m_PausedTime > 0.0f || !HasMinimumActions()) return;
|
||||||
|
|
||||||
|
const auto& nextAction = GetNextAction();
|
||||||
|
if (nextAction.GetValueParameterString() == sMessage) {
|
||||||
|
IncrementAction();
|
||||||
|
m_WaitingForAction = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Strip::IncrementAction() {
|
void Strip::IncrementAction() {
|
||||||
if (m_Actions.empty()) return;
|
if (m_Actions.empty()) return;
|
||||||
m_NextActionIndex++;
|
m_NextActionIndex++;
|
||||||
@ -131,6 +145,7 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
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 numberAsInt = static_cast<int32_t>(number);
|
auto numberAsInt = static_cast<int32_t>(number);
|
||||||
auto nextActionType = GetNextAction().GetType();
|
auto nextActionType = GetNextAction().GetType();
|
||||||
|
|
||||||
@ -183,6 +198,14 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
m_PausedTime = number;
|
m_PausedTime = number;
|
||||||
} else if (nextActionType == "Wait") {
|
} else if (nextActionType == "Wait") {
|
||||||
m_PausedTime = number;
|
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") {
|
} else if (nextActionType == "PlaySound") {
|
||||||
GameMessages::PlayBehaviorSound sound;
|
GameMessages::PlayBehaviorSound sound;
|
||||||
sound.target = modelComponent.GetParent()->GetObjectID();
|
sound.target = modelComponent.GetParent()->GetObjectID();
|
||||||
@ -304,6 +327,9 @@ void Strip::Update(float deltaTime, ModelComponent& modelComponent) {
|
|||||||
Game::entityManager->SerializeEntity(entity);
|
Game::entityManager->SerializeEntity(entity);
|
||||||
m_WaitingForAction = true;
|
m_WaitingForAction = true;
|
||||||
|
|
||||||
|
} else if (nextAction.GetType() == "OnChat") {
|
||||||
|
Game::entityManager->SerializeEntity(entity);
|
||||||
|
m_WaitingForAction = true;
|
||||||
}
|
}
|
||||||
} else { // should be a normal block
|
} else { // should be a normal block
|
||||||
ProcNormalAction(deltaTime, modelComponent);
|
ProcNormalAction(deltaTime, modelComponent);
|
||||||
|
@ -40,6 +40,8 @@ public:
|
|||||||
|
|
||||||
// 2 actions are required for strips to work
|
// 2 actions are required for strips to work
|
||||||
bool HasMinimumActions() const { return m_Actions.size() >= 2; }
|
bool HasMinimumActions() const { return m_Actions.size() >= 2; }
|
||||||
|
|
||||||
|
void OnChatMessageReceived(const std::string& sMessage);
|
||||||
private:
|
private:
|
||||||
// Indicates this Strip is waiting for an action to be taken upon it to progress to its actions
|
// Indicates this Strip is waiting for an action to be taken upon it to progress to its actions
|
||||||
bool m_WaitingForAction{ false };
|
bool m_WaitingForAction{ false };
|
||||||
|
@ -1367,6 +1367,7 @@ void HandlePacket(Packet* packet) {
|
|||||||
std::string sMessage = GeneralUtils::UTF16ToWTF8(chatMessage.message);
|
std::string sMessage = GeneralUtils::UTF16ToWTF8(chatMessage.message);
|
||||||
LOG("%s: %s", playerName.c_str(), sMessage.c_str());
|
LOG("%s: %s", playerName.c_str(), sMessage.c_str());
|
||||||
ChatPackets::SendChatMessage(packet->systemAddress, chatMessage.chatChannel, playerName, user->GetLoggedInChar(), isMythran, chatMessage.message);
|
ChatPackets::SendChatMessage(packet->systemAddress, chatMessage.chatChannel, playerName, user->GetLoggedInChar(), isMythran, chatMessage.message);
|
||||||
|
PropertyManagementComponent::Instance()->OnChatMessageReceived(sMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user