David Markowitz 04487efa25
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.
2025-06-17 17:34:52 -05:00

173 lines
4.6 KiB
C++

#include "State.h"
#include "Amf3.h"
#include "ControlBehaviorMsgs.h"
#include "tinyxml2.h"
template <>
void State::HandleMsg(AddStripMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
m_Strips.resize(msg.GetActionContext().GetStripId() + 1);
}
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template <>
void State::HandleMsg(AddActionMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template <>
void State::HandleMsg(UpdateStripUiMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template <>
void State::HandleMsg(RemoveActionsMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template <>
void State::HandleMsg(RearrangeStripMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template <>
void State::HandleMsg(UpdateActionMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template <>
void State::HandleMsg(RemoveStripMessage& msg) {
if (m_Strips.size() <= msg.GetActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg);
};
template <>
void State::HandleMsg(SplitStripMessage& msg) {
if (msg.GetTransferredActions().empty()) {
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetSourceActionContext().GetStripId()).HandleMsg(msg);
} else {
if (m_Strips.size() <= msg.GetDestinationActionContext().GetStripId()) {
m_Strips.resize(msg.GetDestinationActionContext().GetStripId() + 1);
}
m_Strips.at(msg.GetDestinationActionContext().GetStripId()).HandleMsg(msg);
}
};
template <>
void State::HandleMsg(MergeStripsMessage& msg) {
if (msg.GetMigratedActions().empty()) {
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetSourceActionContext().GetStripId()).HandleMsg(msg);
} else {
if (m_Strips.size() <= msg.GetDestinationActionContext().GetStripId()) {
m_Strips.resize(msg.GetDestinationActionContext().GetStripId() + 1);
}
m_Strips.at(msg.GetDestinationActionContext().GetStripId()).HandleMsg(msg);
}
};
template <>
void State::HandleMsg(MigrateActionsMessage& msg) {
if (msg.GetMigratedActions().empty()) {
if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) {
return;
}
m_Strips.at(msg.GetSourceActionContext().GetStripId()).HandleMsg(msg);
} else {
if (m_Strips.size() <= msg.GetDestinationActionContext().GetStripId()) {
m_Strips.resize(msg.GetDestinationActionContext().GetStripId() + 1);
}
m_Strips.at(msg.GetDestinationActionContext().GetStripId()).HandleMsg(msg);
}
};
template<>
void State::HandleMsg(GameMessages::RequestUse& msg) {
for (auto& strip : m_Strips) strip.HandleMsg(msg);
}
template<>
void State::HandleMsg(GameMessages::ResetModelToDefaults& msg) {
for (auto& strip : m_Strips) strip.HandleMsg(msg);
}
bool State::IsEmpty() const {
for (const auto& strip : m_Strips) {
if (!strip.IsEmpty()) return false;
}
return true;
}
void State::SendBehaviorBlocksToClient(AMFArrayValue& args) const {
auto* const strips = args.InsertArray("strips");
for (size_t stripId = 0; stripId < m_Strips.size(); ++stripId) {
const auto& strip = m_Strips.at(stripId);
if (strip.IsEmpty()) continue;
auto* const stripArgs = strips->PushArray();
stripArgs->Insert("id", static_cast<double>(stripId));
strip.SendBehaviorBlocksToClient(*stripArgs);
}
}
void State::Serialize(tinyxml2::XMLElement& state) const {
for (const auto& strip : m_Strips) {
if (strip.IsEmpty()) continue;
auto* const stripElement = state.InsertNewChildElement("Strip");
strip.Serialize(*stripElement);
}
}
void State::Deserialize(const tinyxml2::XMLElement& state) {
for (const auto* stripElement = state.FirstChildElement("Strip"); stripElement; stripElement = stripElement->NextSiblingElement("Strip")) {
auto& strip = m_Strips.emplace_back();
strip.Deserialize(*stripElement);
}
}
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);
}