From 72c93c8913957062eead0005fa0c15f3b6249650 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Mon, 13 Feb 2023 18:55:44 -0800 Subject: [PATCH] Further implement Property Behavior parsing (#936) Further implements the ControlBehavior processing and adds preparations for cheat detection --- CMakeLists.txt | 1 + dCommon/dEnums/dCommonVars.h | 3 +- dGame/dGameMessages/GameMessages.cpp | 2 +- dGame/dPropertyBehaviors/BehaviorStates.h | 5 +- dGame/dPropertyBehaviors/BlockDefinition.cpp | 9 + dGame/dPropertyBehaviors/BlockDefinition.h | 25 + dGame/dPropertyBehaviors/CMakeLists.txt | 10 +- .../AddActionMessage.cpp | 39 ++ .../AddActionMessage.h | 30 + .../ControlBehaviorMessages/AddMessage.cpp | 13 + .../ControlBehaviorMessages/AddMessage.h | 16 + .../AddStripMessage.cpp | 56 ++ .../ControlBehaviorMessages/AddStripMessage.h | 32 ++ .../BehaviorMessageBase.h | 48 ++ .../ControlBehaviorMessages/CMakeLists.txt | 16 + .../MergeStripsMessage.cpp | 20 + .../MergeStripsMessage.h | 26 + .../MigrateActionsMessage.cpp | 24 + .../MigrateActionsMessage.h | 28 + .../MoveToInventoryMessage.cpp | 11 + .../MoveToInventoryMessage.h | 19 + .../RearrangeStripMessage.cpp | 16 + .../RearrangeStripMessage.h | 22 + .../RemoveActionsMessage.cpp | 15 + .../RemoveActionsMessage.h | 22 + .../RemoveStripMessage.cpp | 8 + .../RemoveStripMessage.h | 18 + .../ControlBehaviorMessages/RenameMessage.cpp | 11 + .../ControlBehaviorMessages/RenameMessage.h | 18 + .../SplitStripMessage.cpp | 29 + .../SplitStripMessage.h | 30 + .../UpdateActionMessage.cpp | 38 ++ .../UpdateActionMessage.h | 30 + .../UpdateStripUiMessage.cpp | 20 + .../UpdateStripUiMessage.h | 24 + dGame/dPropertyBehaviors/ControlBehaviors.cpp | 540 +++++++----------- dGame/dPropertyBehaviors/ControlBehaviors.h | 47 +- tests/dGameTests/CMakeLists.txt | 2 + .../dGameMessagesTests/CMakeLists.txt | 5 + .../dGameMessagesTests/GameMessageTests.cpp | 191 ++++++- .../TestBitStreams/CMakeLists.txt | 24 + .../dGameMessagesTests/TestBitStreams/add | Bin 0 -> 1024 bytes .../TestBitStreams/addAction | Bin 0 -> 1024 bytes .../TestBitStreams/addStrip | Bin 0 -> 1024 bytes .../TestBitStreams/mergeStrips | Bin 0 -> 1024 bytes .../TestBitStreams/migrateActions | Bin 0 -> 1024 bytes .../TestBitStreams/modelTypeChanged | Bin 0 -> 1024 bytes .../TestBitStreams/rearrangeStrip | Bin 0 -> 1024 bytes .../TestBitStreams/removeActions | Bin 0 -> 1024 bytes .../TestBitStreams/removeStrip | Bin 0 -> 1024 bytes .../dGameMessagesTests/TestBitStreams/rename | Bin 0 -> 1024 bytes .../TestBitStreams/sendBehaviorListToClient | Bin 0 -> 1024 bytes .../TestBitStreams/splitStrip | Bin 0 -> 1024 bytes .../TestBitStreams/toggleExecutionUpdates | Bin 0 -> 1024 bytes .../TestBitStreams/updateAction | Bin 0 -> 1024 bytes .../TestBitStreams/updateStripUI | Bin 0 -> 1024 bytes 56 files changed, 1181 insertions(+), 362 deletions(-) create mode 100644 dGame/dPropertyBehaviors/BlockDefinition.cpp create mode 100644 dGame/dPropertyBehaviors/BlockDefinition.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp create mode 100644 dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/add create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/addAction create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/mergeStrips create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/migrateActions create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/removeStrip create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/rename create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/splitStrip create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction create mode 100644 tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI diff --git a/CMakeLists.txt b/CMakeLists.txt index 54f0d0dd..41d4219f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,7 @@ set(INCLUDED_DIRECTORIES "dGame/dMission" "dGame/dEntity" "dGame/dPropertyBehaviors" + "dGame/dPropertyBehaviors/ControlBehaviorMessages" "dGame/dUtilities" "dPhysics" "dNavigation" diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index c90fd8e6..1d4a4c55 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -43,8 +43,7 @@ typedef uint32_t LWOCLONEID; //!< Used for Clone IDs typedef uint16_t LWOMAPID; //!< Used for Map IDs typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs -typedef uint32_t STRIPID; -typedef uint32_t BEHAVIORSTATE; +typedef uint32_t StripId; typedef int32_t PetTamingPiece; //!< Pet Taming Pieces diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 58d72d3c..1d897727 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -2475,7 +2475,7 @@ void GameMessages::HandleControlBehaviors(RakNet::BitStream* inStream, Entity* e auto owner = PropertyManagementComponent::Instance()->GetOwner(); if (!owner) return; - ControlBehaviors::ProcessCommand(entity, sysAddr, static_cast(amfArguments.get()), command, owner); + ControlBehaviors::Instance().ProcessCommand(entity, sysAddr, static_cast(amfArguments.get()), command, owner); } void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { diff --git a/dGame/dPropertyBehaviors/BehaviorStates.h b/dGame/dPropertyBehaviors/BehaviorStates.h index e09e45ba..80cb1dbb 100644 --- a/dGame/dPropertyBehaviors/BehaviorStates.h +++ b/dGame/dPropertyBehaviors/BehaviorStates.h @@ -3,12 +3,9 @@ #ifndef __BEHAVIORSTATES__H__ #define __BEHAVIORSTATES__H__ -#include #include -#include "dCommonVars.h" - -enum States : BEHAVIORSTATE { +enum class BehaviorState : uint32_t { HOME_STATE = 0, //!< The HOME behavior state CIRCLE_STATE, //!< The CIRCLE behavior state SQUARE_STATE, //!< The SQUARE behavior state diff --git a/dGame/dPropertyBehaviors/BlockDefinition.cpp b/dGame/dPropertyBehaviors/BlockDefinition.cpp new file mode 100644 index 00000000..2950ac82 --- /dev/null +++ b/dGame/dPropertyBehaviors/BlockDefinition.cpp @@ -0,0 +1,9 @@ +#include "BlockDefinition.h" + +BlockDefinition BlockDefinition::blockDefinitionDefault{}; + +BlockDefinition::BlockDefinition(std::string defaultValue, float minimumValue, float maximumValue) { + this->defaultValue = defaultValue; + this->minimumValue = minimumValue; + this->maximumValue = maximumValue; +} diff --git a/dGame/dPropertyBehaviors/BlockDefinition.h b/dGame/dPropertyBehaviors/BlockDefinition.h new file mode 100644 index 00000000..3a5a6bf1 --- /dev/null +++ b/dGame/dPropertyBehaviors/BlockDefinition.h @@ -0,0 +1,25 @@ +#ifndef __BLOCKDEFINITION__H__ +#define __BLOCKDEFINITION__H__ + +#include + +class AMFArrayValue; + +class BlockDefinition { +public: + BlockDefinition(std::string defaultValue = "", float minimumValue = 0.0f, float maximumValue = 0.0f); + static BlockDefinition blockDefinitionDefault; + + std::string& GetDefaultValue() { return defaultValue; }; + float GetMinimumValue() { return minimumValue; }; + float GetMaximumValue() { return maximumValue; }; + void SetDefaultValue(std::string value) { defaultValue = value; }; + void SetMinimumValue(float value) { minimumValue = value; }; + void SetMaximumValue(float value) { maximumValue = value; }; +private: + std::string defaultValue; + float minimumValue; + float maximumValue; +}; + +#endif //!__BLOCKDEFINITION__H__ diff --git a/dGame/dPropertyBehaviors/CMakeLists.txt b/dGame/dPropertyBehaviors/CMakeLists.txt index 4f5d60aa..5e33a5f5 100644 --- a/dGame/dPropertyBehaviors/CMakeLists.txt +++ b/dGame/dPropertyBehaviors/CMakeLists.txt @@ -1,4 +1,12 @@ set(DGAME_DPROPERTYBEHAVIORS_SOURCES + "BlockDefinition.cpp" "ControlBehaviors.cpp" - PARENT_SCOPE ) + +add_subdirectory(ControlBehaviorMessages) + +foreach(file ${DGAME_DPROPERTYBEHAVIORS_CONTROLBEHAVIORMESSAGES}) + set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} "ControlBehaviorMessages/${file}") +endforeach() + +set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} PARENT_SCOPE) diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp new file mode 100644 index 00000000..f91512fe --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp @@ -0,0 +1,39 @@ +#include "AddActionMessage.h" + +AddActionMessage::AddActionMessage(AMFArrayValue* arguments) { + auto* actionIndexAmf = arguments->FindValue("actionIndex"); + if (!actionIndexAmf) return; + + actionIndex = static_cast(actionIndexAmf->GetDoubleValue()); + + stripId = GetStripIDFromArgument(arguments); + + stateId = GetBehaviorStateFromArgument(arguments); + + type = ""; + valueParameterName = ""; + valueParameterString = ""; + valueParameterDouble = 0.0; + auto* action = arguments->FindValue("action"); + if (!action) return; + + for (auto& typeValueMap : action->GetAssociativeMap()) { + if (typeValueMap.first == "Type") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + type = static_cast(typeValueMap.second)->GetStringValue(); + } else { + valueParameterName = typeValueMap.first; + // Message is the only known string parameter + if (valueParameterName == "Message") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + valueParameterString = static_cast(typeValueMap.second)->GetStringValue(); + } else { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFDouble) continue; + valueParameterDouble = static_cast(typeValueMap.second)->GetDoubleValue(); + } + } + } + + behaviorId = GetBehaviorIDFromArgument(arguments); + Game::logger->LogDebug("AddActionMessage", "acnNdx %i stpId %i sttId %i t %s vpn %s vps %s vpd %f bhId %i", actionIndex, stripId, stateId, type.c_str(), valueParameterName.c_str(), valueParameterString.c_str(), valueParameterDouble, behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h new file mode 100644 index 00000000..1f1577ec --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h @@ -0,0 +1,30 @@ +#ifndef __ADDACTIONMESSAGE__H__ +#define __ADDACTIONMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class AddActionMessage : public BehaviorMessageBase { +public: + AddActionMessage(AMFArrayValue* arguments); + const uint32_t GetActionIndex() { return actionIndex; }; + const StripId GetStripId() { return stripId; }; + const BehaviorState GetStateId() { return stateId; }; + const std::string& GetType() { return type; }; + const std::string& GetValueParameterName() { return valueParameterName; }; + const std::string& GetValueParameterString() { return valueParameterString; }; + const double GetValueParameterDouble() { return valueParameterDouble; }; + const uint32_t GetBehaviorId() { return behaviorId; }; +private: + uint32_t actionIndex; + StripId stripId; + BehaviorState stateId; + std::string type; + std::string valueParameterName; + std::string valueParameterString; + double valueParameterDouble; + uint32_t behaviorId; +}; + +#endif //!__ADDACTIONMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp new file mode 100644 index 00000000..ecddb8e3 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp @@ -0,0 +1,13 @@ +#include "AddMessage.h" + +AddMessage::AddMessage(AMFArrayValue* arguments) { + behaviorId = GetBehaviorIDFromArgument(arguments); + + behaviorIndex = 0; + auto* behaviorIndexValue = arguments->FindValue("BehaviorIndex"); + + if (!behaviorIndexValue) return; + + behaviorIndex = static_cast(behaviorIndexValue->GetDoubleValue()); + Game::logger->LogDebug("AddMessage", "bhId %i ndx %i", behaviorId, behaviorIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h new file mode 100644 index 00000000..ff8e0c8b --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h @@ -0,0 +1,16 @@ +#ifndef __ADDMESSAGE__H__ +#define __ADDMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AddMessage : public BehaviorMessageBase { +public: + AddMessage(AMFArrayValue* arguments); + const uint32_t GetBehaviorIndex() { return behaviorIndex; }; + const uint32_t GetBehaviorId() { return behaviorId; }; +private: + uint32_t behaviorId; + uint32_t behaviorIndex; +}; + +#endif //!__ADDMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp new file mode 100644 index 00000000..23662174 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp @@ -0,0 +1,56 @@ +#include "AddStripMessage.h" + +AddStripMessage::AddStripMessage(AMFArrayValue* arguments) { + auto* strip = arguments->FindValue("strip"); + if (!strip) return; + + auto* actions = strip->FindValue("actions"); + if (!actions) return; + + auto* uiArray = arguments->FindValue("ui"); + if (!uiArray) return; + + auto* xPositionValue = uiArray->FindValue("x"); + if (!xPositionValue) return; + + xPosition = xPositionValue->GetDoubleValue(); + + auto* yPositionValue = uiArray->FindValue("y"); + if (!yPositionValue) return; + + yPosition = yPositionValue->GetDoubleValue(); + + stripId = GetStripIDFromArgument(arguments); + + stateId = GetBehaviorStateFromArgument(arguments); + + behaviorId = GetBehaviorIDFromArgument(arguments); + + type = ""; + valueParameterName = ""; + valueParameterString = ""; + valueParameterDouble = 0.0; + for (uint32_t position = 0; position < actions->GetDenseValueSize(); position++) { + auto* actionAsArray = actions->GetValueAt(position); + if (!actionAsArray) continue; + + for (auto& typeValueMap : actionAsArray->GetAssociativeMap()) { + if (typeValueMap.first == "Type") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + + type = static_cast(typeValueMap.second)->GetStringValue(); + } else { + valueParameterName = typeValueMap.first; + // Message is the only known string parameter + if (valueParameterName == "Message") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + valueParameterString = static_cast(typeValueMap.second)->GetStringValue(); + } else { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFDouble) continue; + valueParameterDouble = static_cast(typeValueMap.second)->GetDoubleValue(); + } + } + } + Game::logger->LogDebug("AddStripMessage", "x %f y %f stpId %i sttId %i bhId %i t %s vpn %s vps %s vpd %f", xPosition, yPosition, stripId, stateId, behaviorId, type.c_str(), valueParameterName.c_str(), valueParameterString.c_str(), valueParameterDouble); + } +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h new file mode 100644 index 00000000..bb720bae --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h @@ -0,0 +1,32 @@ +#ifndef __ADDSTRIPMESSAGE__H__ +#define __ADDSTRIPMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class AddStripMessage : public BehaviorMessageBase { +public: + AddStripMessage(AMFArrayValue* arguments); + const StripId GetStripId() { return stripId; }; + const BehaviorState GetStateId() { return stateId; }; + const std::string& GetType() { return type; }; + const std::string& GetValueParameterName() { return valueParameterName; }; + const std::string& GetValueParameterString() { return valueParameterString; }; + const double GetXPosition() { return xPosition; }; + const double GetYPosition() { return yPosition; }; + const double GetValueParameterDouble() { return valueParameterDouble; }; + const uint32_t GetBehaviorId() { return behaviorId; }; +private: + double xPosition; + double yPosition; + StripId stripId; + BehaviorState stateId; + uint32_t behaviorId; + std::string type; + std::string valueParameterName; + std::string valueParameterString; + double valueParameterDouble; +}; + +#endif //!__ADDSTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h new file mode 100644 index 00000000..78025672 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h @@ -0,0 +1,48 @@ +#ifndef __BEHAVIORMESSAGEBASE__H__ +#define __BEHAVIORMESSAGEBASE__H__ + +#include +#include + +#include "AMFFormat.h" +#include "BehaviorStates.h" +#include "dCommonVars.h" + +#include "Game.h" +#include "dLogger.h" + +class BehaviorMessageBase { +public: + uint32_t GetBehaviorIDFromArgument(AMFArrayValue* arguments, const std::string& key = "BehaviorID") { + auto* behaviorIDValue = arguments->FindValue(key); + uint32_t behaviorID = -1; + + if (behaviorIDValue) { + behaviorID = std::stoul(behaviorIDValue->GetStringValue()); + } else if (arguments->FindValue(key) == nullptr) { + throw std::invalid_argument("Unable to find behavior ID from argument \"" + key + "\""); + } + + return behaviorID; + } + + BehaviorState GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key = "stateID") { + auto* stateIDValue = arguments->FindValue(key); + if (!stateIDValue) throw std::invalid_argument("Unable to find behavior state from argument \"" + key + "\""); + + BehaviorState stateID = static_cast(stateIDValue->GetDoubleValue()); + + return stateID; + } + + StripId GetStripIDFromArgument(AMFArrayValue* arguments, const std::string& key = "stripID") { + auto* stripIDValue = arguments->FindValue(key); + if (!stripIDValue) throw std::invalid_argument("Unable to find strip ID from argument \"" + key + "\""); + + StripId stripID = static_cast(stripIDValue->GetDoubleValue()); + + return stripID; + } +}; + +#endif //!__BEHAVIORMESSAGEBASE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt b/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt new file mode 100644 index 00000000..8390cd22 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt @@ -0,0 +1,16 @@ +set(DGAME_DPROPERTYBEHAVIORS_CONTROLBEHAVIORMESSAGES + "AddActionMessage.cpp" + "AddMessage.cpp" + "AddStripMessage.cpp" + "MergeStripsMessage.cpp" + "MigrateActionsMessage.cpp" + "MoveToInventoryMessage.cpp" + "RearrangeStripMessage.cpp" + "RemoveActionsMessage.cpp" + "RemoveStripMessage.cpp" + "RenameMessage.cpp" + "SplitStripMessage.cpp" + "UpdateActionMessage.cpp" + "UpdateStripUiMessage.cpp" + PARENT_SCOPE +) diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp new file mode 100644 index 00000000..d810e861 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp @@ -0,0 +1,20 @@ +#include "MergeStripsMessage.h" + +MergeStripsMessage::MergeStripsMessage(AMFArrayValue* arguments) { + srcStripID = GetStripIDFromArgument(arguments, "srcStripID"); + + dstStateID = GetBehaviorStateFromArgument(arguments, "dstStateID"); + + srcStateID = GetBehaviorStateFromArgument(arguments, "srcStateID"); + + auto* dstActionIndexValue = arguments->FindValue("dstActionIndex"); + if (!dstActionIndexValue) return; + + dstActionIndex = static_cast(dstActionIndexValue->GetDoubleValue()); + + dstStripID = GetStripIDFromArgument(arguments, "dstStripID"); + + behaviorID = GetBehaviorIDFromArgument(arguments); + Game::logger->LogDebug("MergeStripsMessage", "srcStpId %i dstStpId %i srcSttId %i dstSttId %i dstAcnNdx %i bhId %i", srcStripID, dstStripID, srcStateID, dstStateID, dstActionIndex, behaviorID); +} + diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h new file mode 100644 index 00000000..af3aa16f --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h @@ -0,0 +1,26 @@ +#ifndef __MERGESTRIPSMESSAGE__H__ +#define __MERGESTRIPSMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class MergeStripsMessage : public BehaviorMessageBase { +public: + MergeStripsMessage(AMFArrayValue* arguments); + const StripId GetSrcStripID() { return srcStripID; }; + const BehaviorState GetDstStateID() { return dstStateID; }; + const BehaviorState GetSrcStateID() { return srcStateID; }; + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + const StripId GetDstStripID() { return dstStripID; }; + const uint32_t GetBehaviorID() { return behaviorID; }; +private: + StripId srcStripID; + BehaviorState dstStateID; + BehaviorState srcStateID; + uint32_t dstActionIndex; + StripId dstStripID; + uint32_t behaviorID; +}; + +#endif //!__MERGESTRIPSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp new file mode 100644 index 00000000..8bb4e819 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp @@ -0,0 +1,24 @@ +#include "MigrateActionsMessage.h" + +MigrateActionsMessage::MigrateActionsMessage(AMFArrayValue* arguments) { + auto* srcActionIndexAmf = arguments->FindValue("srcActionIndex"); + if (!srcActionIndexAmf) return; + + srcActionIndex = static_cast(srcActionIndexAmf->GetDoubleValue()); + + srcStripID = GetStripIDFromArgument(arguments, "srcStripID"); + + srcStateID = GetBehaviorStateFromArgument(arguments, "srcStateID"); + + auto* dstActionIndexAmf = arguments->FindValue("dstActionIndex"); + if (!dstActionIndexAmf) return; + + dstActionIndex = static_cast(dstActionIndexAmf->GetDoubleValue()); + + dstStripID = GetStripIDFromArgument(arguments, "dstStripID"); + + dstStateID = GetBehaviorStateFromArgument(arguments, "dstStateID"); + + behaviorID = GetBehaviorIDFromArgument(arguments); + Game::logger->LogDebug("MigrateActionsMessage", "srcAcnNdx %i dstAcnNdx %i srcStpId %i dstStpId %i srcSttId %i dstSttId %i bhid %i", srcActionIndex, dstActionIndex, srcStripID, dstStripID, srcStateID, dstStateID, behaviorID); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h new file mode 100644 index 00000000..26018d69 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h @@ -0,0 +1,28 @@ +#ifndef __MIGRATEACTIONSMESSAGE__H__ +#define __MIGRATEACTIONSMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class MigrateActionsMessage : public BehaviorMessageBase { +public: + MigrateActionsMessage(AMFArrayValue* arguments); + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + const StripId GetSrcStripID() { return srcStripID; }; + const BehaviorState GetSrcStateID() { return srcStateID; }; + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + const StripId GetDstStripID() { return dstStripID; }; + const BehaviorState GetDstStateID() { return dstStateID; }; + const uint32_t GetBehaviorID() { return behaviorID; }; +private: + uint32_t srcActionIndex; + StripId srcStripID; + BehaviorState srcStateID; + uint32_t dstActionIndex; + StripId dstStripID; + BehaviorState dstStateID; + uint32_t behaviorID; +}; + +#endif //!__MIGRATEACTIONSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp new file mode 100644 index 00000000..7ad7a875 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp @@ -0,0 +1,11 @@ +#include "MoveToInventoryMessage.h" + +MoveToInventoryMessage::MoveToInventoryMessage(AMFArrayValue* arguments) { + behaviorID = GetBehaviorIDFromArgument(arguments); + + auto* behaviorIndexValue = arguments->FindValue("BehaviorIndex"); + if (!behaviorIndexValue) return; + + behaviorIndex = static_cast(behaviorIndexValue->GetDoubleValue()); + Game::logger->LogDebug("MoveToInventoryMessage", "bhId %i bhNdx %i", behaviorID, behaviorIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h new file mode 100644 index 00000000..2cf71f3c --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h @@ -0,0 +1,19 @@ +#ifndef __MOVETOINVENTORYMESSAGE__H__ +#define __MOVETOINVENTORYMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +#pragma warning("This Control Behavior Message does not have a test yet. Non-developers can ignore this warning.") +class MoveToInventoryMessage: public BehaviorMessageBase { +public: + MoveToInventoryMessage(AMFArrayValue* arguments); + const uint32_t GetBehaviorID() { return behaviorID; }; + const uint32_t GetBehaviorIndex() { return behaviorIndex; }; +private: + uint32_t behaviorID; + uint32_t behaviorIndex; +}; + +#endif //!__MOVETOINVENTORYMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp new file mode 100644 index 00000000..0347aca6 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp @@ -0,0 +1,16 @@ +#include "RearrangeStripMessage.h" + +RearrangeStripMessage::RearrangeStripMessage(AMFArrayValue* arguments) { + auto* srcActionIndexValue = arguments->FindValue("srcActionIndex"); + srcActionIndex = static_cast(srcActionIndexValue->GetDoubleValue()); + + stripID = GetStripIDFromArgument(arguments); + + behaviorID = GetBehaviorIDFromArgument(arguments); + + auto* dstActionIndexValue = arguments->FindValue("dstActionIndex"); + dstActionIndex = static_cast(dstActionIndexValue->GetDoubleValue()); + + stateID = GetBehaviorStateFromArgument(arguments); + Game::logger->LogDebug("RearrangeStripMessage", "srcAcnNdx %i dstAcnNdx %i stpId %i bhId %i sttId %i", srcActionIndex, dstActionIndex, stripID, behaviorID, stateID); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h new file mode 100644 index 00000000..4cca0827 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h @@ -0,0 +1,22 @@ +#ifndef __REARRANGESTRIPMESSAGE__H__ +#define __REARRANGESTRIPMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class RearrangeStripMessage : public BehaviorMessageBase { +public: + RearrangeStripMessage(AMFArrayValue* arguments); + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + const uint32_t GetStripID() { return stripID; }; + const uint32_t GetBehaviorID() { return behaviorID; }; + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + const BehaviorState GetStateID() { return stateID; }; +private: + uint32_t srcActionIndex; + uint32_t stripID; + uint32_t behaviorID; + uint32_t dstActionIndex; + BehaviorState stateID; +}; + +#endif //!__REARRANGESTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp new file mode 100644 index 00000000..cb1226e3 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp @@ -0,0 +1,15 @@ +#include "RemoveActionsMessage.h" + +RemoveActionsMessage::RemoveActionsMessage(AMFArrayValue* arguments) { + behaviorID = GetBehaviorIDFromArgument(arguments); + + auto* actionIndexAmf = arguments->FindValue("actionIndex"); + if (!actionIndexAmf) return; + + actionIndex = static_cast(actionIndexAmf->GetDoubleValue()); + + stripID = GetStripIDFromArgument(arguments); + + stateID = GetBehaviorStateFromArgument(arguments); + Game::logger->LogDebug("RemoveActionsMessage", "bhId %i acnNdx %i stpId %i sttId %i", behaviorID, actionIndex, stripID, stateID); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h new file mode 100644 index 00000000..33678f59 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h @@ -0,0 +1,22 @@ +#ifndef __REMOVEACTIONSMESSAGE__H__ +#define __REMOVEACTIONSMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class RemoveActionsMessage : public BehaviorMessageBase { +public: + RemoveActionsMessage(AMFArrayValue* arguments); + const uint32_t GetBehaviorID() { return behaviorID; }; + const uint32_t GetActionIndex() { return actionIndex; }; + const StripId GetStripID() { return stripID; }; + const BehaviorState GetStateID() { return stateID; }; +private: + uint32_t behaviorID; + uint32_t actionIndex; + StripId stripID; + BehaviorState stateID; +}; + +#endif //!__REMOVEACTIONSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp new file mode 100644 index 00000000..3c48ed16 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp @@ -0,0 +1,8 @@ +#include "RemoveStripMessage.h" + +RemoveStripMessage::RemoveStripMessage(AMFArrayValue* arguments) { + stripId = GetStripIDFromArgument(arguments); + behaviorState = GetBehaviorStateFromArgument(arguments); + behaviorId = GetBehaviorIDFromArgument(arguments); + Game::logger->LogDebug("RemoveStripMessage", "stpId %i bhStt %i bhId %i", stripId, behaviorState, behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h new file mode 100644 index 00000000..312bab31 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h @@ -0,0 +1,18 @@ +#ifndef __REMOVESTRIPMESSAGE__H__ +#define __REMOVESTRIPMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class RemoveStripMessage : public BehaviorMessageBase { +public: + RemoveStripMessage(AMFArrayValue* arguments); + const StripId GetStripId() { return stripId; }; + const BehaviorState GetBehaviorState() { return behaviorState; }; + const uint32_t GetBehaviorId() { return behaviorId; }; +private: + StripId stripId; + BehaviorState behaviorState; + uint32_t behaviorId; +}; + +#endif //!__REMOVESTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp new file mode 100644 index 00000000..38c49462 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp @@ -0,0 +1,11 @@ +#include "RenameMessage.h" + +RenameMessage::RenameMessage(AMFArrayValue* arguments) { + behaviorID = GetBehaviorIDFromArgument(arguments); + + auto* nameAmf = arguments->FindValue("Name"); + if (!nameAmf) return; + + name = nameAmf->GetStringValue(); + Game::logger->LogDebug("RenameMessage", "bhId %i n %s", behaviorID, name.c_str()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h new file mode 100644 index 00000000..be42d66f --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h @@ -0,0 +1,18 @@ +#ifndef __RENAMEMESSAGE__H__ +#define __RENAMEMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class RenameMessage : public BehaviorMessageBase { +public: + RenameMessage(AMFArrayValue* arguments); + const uint32_t GetBehaviorID() { return behaviorID; }; + const std::string& GetName() { return name; }; +private: + uint32_t behaviorID; + std::string name; +}; + +#endif //!__RENAMEMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp new file mode 100644 index 00000000..d3493aeb --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp @@ -0,0 +1,29 @@ +#include "SplitStripMessage.h" + +SplitStripMessage::SplitStripMessage(AMFArrayValue* arguments) { + auto* srcActionIndexValue = arguments->FindValue("srcActionIndex"); + if (!srcActionIndexValue) return; + + srcActionIndex = static_cast(srcActionIndexValue->GetDoubleValue()); + + srcStripId = GetStripIDFromArgument(arguments, "srcStripID"); + + srcStateId = GetBehaviorStateFromArgument(arguments, "srcStateID"); + + dstStripId = GetStripIDFromArgument(arguments, "dstStripID"); + + dstStateId = GetBehaviorStateFromArgument(arguments, "dstStateID"); + + auto* dstStripUiArray = arguments->FindValue("dstStripUI"); + if (!dstStripUiArray) return; + + auto* xPositionValue = dstStripUiArray->FindValue("x"); + auto* yPositionValue = dstStripUiArray->FindValue("y"); + if (!xPositionValue || !yPositionValue) return; + + yPosition = yPositionValue->GetDoubleValue(); + xPosition = xPositionValue->GetDoubleValue(); + + behaviorId = GetBehaviorIDFromArgument(arguments); + Game::logger->LogDebug("SplitStripMessage", "bhid %i x %f y %f srcStp %i dstStp %i srcStt %i dstStt %i srcActNdx %i", behaviorId, xPosition, yPosition, srcStripId, dstStripId, srcStateId, dstStateId, srcActionIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h new file mode 100644 index 00000000..e06a9dc4 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h @@ -0,0 +1,30 @@ +#ifndef __SPLITSTRIPMESSAGE__H__ +#define __SPLITSTRIPMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class SplitStripMessage : public BehaviorMessageBase { +public: + SplitStripMessage(AMFArrayValue* arguments); + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + const StripId GetSrcStripId() { return srcStripId; }; + const BehaviorState GetSrcStateId() { return srcStateId; }; + const StripId GetDstStripId() { return dstStripId; }; + const BehaviorState GetDstStateId() { return dstStateId; }; + const double GetYPosition() { return yPosition; }; + const double GetXPosition() { return xPosition; }; + const uint32_t GetBehaviorId() { return behaviorId; }; +private: + uint32_t srcActionIndex; + StripId srcStripId; + BehaviorState srcStateId; + StripId dstStripId; + BehaviorState dstStateId; + double yPosition; + double xPosition; + uint32_t behaviorId; +}; + +#endif //!__SPLITSTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp new file mode 100644 index 00000000..1d4cc868 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp @@ -0,0 +1,38 @@ +#include "UpdateActionMessage.h" + +UpdateActionMessage::UpdateActionMessage(AMFArrayValue* arguments) { + type = ""; + valueParameterName = ""; + valueParameterString = ""; + valueParameterDouble = 0.0; + auto* actionAsArray = arguments->FindValue("action"); + if (!actionAsArray) return; + for (auto& typeValueMap : actionAsArray->GetAssociativeMap()) { + if (typeValueMap.first == "Type") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + type = static_cast(typeValueMap.second)->GetStringValue(); + } else { + valueParameterName = typeValueMap.first; + // Message is the only known string parameter + if (valueParameterName == "Message") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + valueParameterString = static_cast(typeValueMap.second)->GetStringValue(); + } else { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFDouble) continue; + valueParameterDouble = static_cast(typeValueMap.second)->GetDoubleValue(); + } + } + } + + behaviorID = GetBehaviorIDFromArgument(arguments); + + auto* actionIndexValue = arguments->FindValue("actionIndex"); + if (!actionIndexValue) return; + + actionIndex = static_cast(actionIndexValue->GetDoubleValue()); + + stripID = GetStripIDFromArgument(arguments); + + stateID = GetBehaviorStateFromArgument(arguments); + Game::logger->LogDebug("UpdateActionMessage", "t %s vpn %s vps %s vpd %f bhId %i acnNdx %i stpId %i sttId %i", type.c_str(), valueParameterName.c_str(), valueParameterString.c_str(), valueParameterDouble, behaviorID, actionIndex, stripID, stateID); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h new file mode 100644 index 00000000..a42be22b --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h @@ -0,0 +1,30 @@ +#ifndef __UPDATEACTIONMESSAGE__H__ +#define __UPDATEACTIONMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class UpdateActionMessage : public BehaviorMessageBase { +public: + UpdateActionMessage(AMFArrayValue* arguments); + const std::string& GetType() { return type; }; + const std::string& GetValueParameterName() { return valueParameterName; }; + const std::string& GetValueParameterString() { return valueParameterString; }; + const double GetValueParameterDouble() { return valueParameterDouble; }; + const uint32_t GetBehaviorID() { return behaviorID; }; + const uint32_t GetActionIndex() { return actionIndex; }; + const StripId GetStripID() { return stripID; }; + const BehaviorState GetStateID() { return stateID; }; +private: + std::string type; + std::string valueParameterName; + std::string valueParameterString; + double valueParameterDouble; + uint32_t behaviorID; + uint32_t actionIndex; + StripId stripID; + BehaviorState stateID; +}; + +#endif //!__UPDATEACTIONMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp new file mode 100644 index 00000000..60e2f0f3 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp @@ -0,0 +1,20 @@ +#include "UpdateStripUiMessage.h" + +UpdateStripUiMessage::UpdateStripUiMessage(AMFArrayValue* arguments) { + auto* uiArray = arguments->FindValue("ui"); + if (!uiArray) return; + + auto* xPositionValue = uiArray->FindValue("x"); + auto* yPositionValue = uiArray->FindValue("y"); + if (!xPositionValue || !yPositionValue) return; + + yPosition = yPositionValue->GetDoubleValue(); + xPosition = xPositionValue->GetDoubleValue(); + + stripID = GetStripIDFromArgument(arguments); + + stateID = GetBehaviorStateFromArgument(arguments); + + behaviorID = GetBehaviorIDFromArgument(arguments); + Game::logger->LogDebug("UpdateStripUIMessage", "x %f y %f stpId %i sttId %i bhId %i", xPosition, yPosition, stripID, stateID, behaviorID); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h new file mode 100644 index 00000000..ca626120 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h @@ -0,0 +1,24 @@ +#ifndef __UPDATESTRIPUIMESSAGE__H__ +#define __UPDATESTRIPUIMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +class UpdateStripUiMessage : public BehaviorMessageBase { +public: + UpdateStripUiMessage(AMFArrayValue* arguments); + const double GetYPosition() { return yPosition; }; + const double GetXPosition() { return xPosition; }; + const StripId GetStripID() { return stripID; }; + const BehaviorState GetStateID() { return stateID; }; + const uint32_t GetBehaviorID() { return behaviorID; }; +private: + double yPosition; + double xPosition; + StripId stripID; + BehaviorState stateID; + uint32_t behaviorID; +}; + +#endif //!__UPDATESTRIPUIMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.cpp b/dGame/dPropertyBehaviors/ControlBehaviors.cpp index 278b6929..3e8bbacc 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviors.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviors.cpp @@ -7,40 +7,29 @@ #include "ModelComponent.h" #include "../../dWorldServer/ObjectIDManager.h" #include "dLogger.h" +#include "BehaviorStates.h" +#include "AssetManager.h" +#include "BlockDefinition.h" #include "User.h" +#include "tinyxml2.h" +#include "CDClientDatabase.h" -uint32_t GetBehaviorIDFromArgument(AMFArrayValue* arguments, const std::string& key = "BehaviorID") { - auto* behaviorIDValue = arguments->FindValue(key); - uint32_t behaviorID = -1; +// Message includes +#include "AddActionMessage.h" +#include "AddStripMessage.h" +#include "AddMessage.h" +#include "MigrateActionsMessage.h" +#include "MoveToInventoryMessage.h" +#include "MergeStripsMessage.h" +#include "RearrangeStripMessage.h" +#include "RemoveActionsMessage.h" +#include "RemoveStripMessage.h" +#include "RenameMessage.h" +#include "SplitStripMessage.h" +#include "UpdateActionMessage.h" +#include "UpdateStripUiMessage.h" - if (behaviorIDValue) { - behaviorID = std::stoul(behaviorIDValue->GetStringValue()); - } else if (arguments->FindValue(key) == nullptr){ - throw std::invalid_argument("Unable to find behavior ID from argument \"" + key + "\""); - } - - return behaviorID; -} - -BEHAVIORSTATE GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key = "stateID") { - auto* stateIDValue = arguments->FindValue(key); - if (!stateIDValue) throw std::invalid_argument("Unable to find behavior state from argument \"" + key + "\""); - - BEHAVIORSTATE stateID = static_cast(stateIDValue->GetDoubleValue()); - - return stateID; -} - -STRIPID GetStripIDFromArgument(AMFArrayValue* arguments, const std::string& key = "stripID") { - auto* stripIDValue = arguments->FindValue(key); - if (!stripIDValue) throw std::invalid_argument("Unable to find strip ID from argument \"" + key + "\""); - - STRIPID stripID = static_cast(stripIDValue->GetDoubleValue()); - - return stripID; -} - -void RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr) { +void ControlBehaviors::RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr) { // auto behavior = modelComponent->FindBehavior(behaviorID); // if (behavior->GetBehaviorID() == -1 || behavior->GetShouldSetNewID()) { // ObjectIDManager::Instance()->RequestPersistentID( @@ -66,11 +55,7 @@ void RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity // } } -void SendBehaviorListToClient( - Entity* modelEntity, - const SystemAddress& sysAddr, - Entity* modelOwner - ) { +void ControlBehaviors::SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner) { auto* modelComponent = modelEntity->GetComponent(); if (!modelComponent) return; @@ -98,7 +83,7 @@ void SendBehaviorListToClient( GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorList", &behaviorsToSerialize); } -void ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent) { +void ControlBehaviors::ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent) { auto* modelTypeAmf = arguments->FindValue("ModelType"); if (!modelTypeAmf) return; @@ -107,292 +92,57 @@ void ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent) //TODO Update the model type here } -void ToggleExecutionUpdates() { +void ControlBehaviors::ToggleExecutionUpdates() { //TODO do something with this info } -void AddStrip(AMFArrayValue* arguments) { - auto* strip = arguments->FindValue("strip"); - if (!strip) return; - - auto* actions = strip->FindValue("actions"); - if (!actions) return; - - auto* uiArray = arguments->FindValue("ui"); - if (!uiArray) return; - - auto* xPositionValue = uiArray->FindValue("x"); - if (!xPositionValue) return; - - double xPosition = xPositionValue->GetDoubleValue(); - - auto* yPositionValue = uiArray->FindValue("y"); - if (!yPositionValue) return; - - double yPosition = yPositionValue->GetDoubleValue(); - - STRIPID stripID = GetStripIDFromArgument(arguments); - - BEHAVIORSTATE stateID = GetBehaviorStateFromArgument(arguments); - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - std::string type = ""; - std::string valueParameterName = ""; - std::string valueParameterString = ""; - double valueParameterDouble = 0.0; - for (uint32_t position = 0; position < actions->GetDenseValueSize(); position++) { - auto* actionAsArray = actions->GetValueAt(position); - if (!actionAsArray) continue; - - for (auto& typeValueMap : actionAsArray->GetAssociativeMap()) { - if (typeValueMap.first == "Type") { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; - - type = static_cast(typeValueMap.second)->GetStringValue(); - } else { - valueParameterName = typeValueMap.first; - // Message is the only known string parameter - if (valueParameterName == "Message") { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; - valueParameterString = static_cast(typeValueMap.second)->GetStringValue(); - } else { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFDouble) continue; - valueParameterDouble = static_cast(typeValueMap.second)->GetDoubleValue(); - } - } - } - // modelComponent->AddStrip(stateID, stripID, type, behaviorID, valueParameterName, valueParameterString, valueParameterDouble, "", xPosition, yPosition); - type.clear(); - valueParameterName.clear(); - valueParameterString.clear(); - valueParameterDouble = 0.0; - } - // RequestUpdatedID(behaviorID); +void ControlBehaviors::AddStrip(AMFArrayValue* arguments) { + AddStripMessage addStripMessage(arguments); } -void RemoveStrip(AMFArrayValue* arguments) { - STRIPID stripID = GetStripIDFromArgument(arguments); - - BEHAVIORSTATE stateID = GetBehaviorStateFromArgument(arguments); - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - // modelComponent->RemoveStrip(stateID, stripID, behaviorID); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::RemoveStrip(AMFArrayValue* arguments) { + RemoveStripMessage removeStrip(arguments); } -void MergeStrips(AMFArrayValue* arguments) { - STRIPID srcStripID = GetStripIDFromArgument(arguments, "srcStripID"); - - BEHAVIORSTATE dstStateID = GetBehaviorStateFromArgument(arguments, "dstStateID"); - - BEHAVIORSTATE srcStateID = GetBehaviorStateFromArgument(arguments, "srcStateID"); - - auto* dstActionIndexValue = arguments->FindValue("dstActionIndex"); - if (!dstActionIndexValue) return; - - uint32_t dstActionIndex = static_cast(dstActionIndexValue->GetDoubleValue()); - - STRIPID dstStripID = GetStripIDFromArgument(arguments, "dstStripID"); - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - // modelComponent->MergeStrips(srcStripID, dstStripID, srcStateID, dstStateID, behaviorID, dstActionIndex); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::MergeStrips(AMFArrayValue* arguments) { + MergeStripsMessage mergeStripsMessage(arguments); } -void SplitStrip(AMFArrayValue* arguments) { - auto* srcActionIndexValue = arguments->FindValue("srcActionIndex"); - if (!srcActionIndexValue) return; - - uint32_t srcActionIndex = static_cast(srcActionIndexValue->GetDoubleValue()); - - STRIPID srcStripID = GetStripIDFromArgument(arguments, "srcStripID"); - - BEHAVIORSTATE srcStateID = GetBehaviorStateFromArgument(arguments, "srcStateID"); - - STRIPID dstStripID = GetStripIDFromArgument(arguments, "dstStripID"); - - BEHAVIORSTATE dstStateID = GetBehaviorStateFromArgument(arguments, "dstStateID"); - - auto* dstStripUIArray = arguments->FindValue("dstStripUI"); - if (!dstStripUIArray) return; - - auto* xPositionValue = dstStripUIArray->FindValue("x"); - auto* yPositionValue = dstStripUIArray->FindValue("y"); - if (!xPositionValue || !yPositionValue) return; - - // x and y position 15 are just where the game puts the strip by default if none is given. - double yPosition = yPositionValue->GetDoubleValue(); - double xPosition = xPositionValue->GetDoubleValue(); - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - // modelComponent->SplitStrip(srcActionIndex, srcStripID, srcStateID, dstStripID, dstStateID, behaviorID, yPosition, xPosition); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::SplitStrip(AMFArrayValue* arguments) { + SplitStripMessage splitStripMessage(arguments); } -void UpdateStripUI(AMFArrayValue* arguments) { - auto* uiArray = arguments->FindValue("ui"); - if (!uiArray) return; - - auto* xPositionValue = uiArray->FindValue("x"); - auto* yPositionValue = uiArray->FindValue("y"); - if (!xPositionValue || !yPositionValue) return; - - double yPosition = yPositionValue->GetDoubleValue(); - double xPosition = xPositionValue->GetDoubleValue(); - - STRIPID stripID = GetStripIDFromArgument(arguments); - - BEHAVIORSTATE stateID = GetBehaviorStateFromArgument(arguments); - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - // modelComponent->UpdateUIOfStrip(stateID, stripID, xPosition, yPosition, behaviorID); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::UpdateStripUI(AMFArrayValue* arguments) { + UpdateStripUiMessage updateStripUiMessage(arguments); } -void AddAction(AMFArrayValue* arguments) { - auto* actionIndexAmf = arguments->FindValue("actionIndex"); - if (!actionIndexAmf) return; - - uint32_t actionIndex = static_cast(actionIndexAmf->GetDoubleValue()); - - STRIPID stripID = GetStripIDFromArgument(arguments); - - BEHAVIORSTATE stateID = GetBehaviorStateFromArgument(arguments); - - std::string type = ""; - std::string valueParameterName = ""; - std::string valueParameterString = ""; - double valueParameterDouble = 0.0; - auto* action = arguments->FindValue("action"); - if (!action) return; - - for (auto& typeValueMap : action->GetAssociativeMap()) { - if (typeValueMap.first == "Type") { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; - type = static_cast(typeValueMap.second)->GetStringValue(); - } else { - valueParameterName = typeValueMap.first; - // Message is the only known string parameter - if (valueParameterName == "Message") { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; - valueParameterString = static_cast(typeValueMap.second)->GetStringValue(); - } else { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFDouble) continue; - valueParameterDouble = static_cast(typeValueMap.second)->GetDoubleValue(); - } - } - } - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - // modelComponent->AddAction(stateID, stripID, type, valueParameterName, valueParameterString, valueParameterDouble, "", actionIndex, behaviorID); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::AddAction(AMFArrayValue* arguments) { + AddActionMessage addActionMessage(arguments); } -void MigrateActions(AMFArrayValue* arguments) { - auto* srcActionIndexAmf = arguments->FindValue("srcActionIndex"); - if (!srcActionIndexAmf) return; - - uint32_t srcActionIndex = static_cast(srcActionIndexAmf->GetDoubleValue()); - - STRIPID srcStripID = GetStripIDFromArgument(arguments, "srcStripID"); - - BEHAVIORSTATE srcStateID = GetBehaviorStateFromArgument(arguments, "srcStateID"); - - auto* dstActionIndexAmf = arguments->FindValue("dstActionIndex"); - if (!dstActionIndexAmf) return; - - uint32_t dstActionIndex = static_cast(dstActionIndexAmf->GetDoubleValue()); - - STRIPID dstStripID = GetStripIDFromArgument(arguments, "dstStripID"); - - BEHAVIORSTATE dstStateID = GetBehaviorStateFromArgument(arguments, "dstStateID"); - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - // modelComponent->MigrateActions(srcActionIndex, srcStripID, srcStateID, dstActionIndex, dstStripID, dstStateID, behaviorID); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::MigrateActions(AMFArrayValue* arguments) { + MigrateActionsMessage migrateActionsMessage(arguments); } -void RearrangeStrip(AMFArrayValue* arguments) { - auto* srcActionIndexValue = arguments->FindValue("srcActionIndex"); - uint32_t srcActionIndex = static_cast(srcActionIndexValue->GetDoubleValue()); - - uint32_t stripID = GetStripIDFromArgument(arguments); - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - auto* dstActionIndexValue = arguments->FindValue("dstActionIndex"); - uint32_t dstActionIndex = static_cast(dstActionIndexValue->GetDoubleValue()); - - BEHAVIORSTATE stateID = GetBehaviorStateFromArgument(arguments); - - // modelComponent->RearrangeStrip(stateID, stripID, srcActionIndex, dstActionIndex, behaviorID); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::RearrangeStrip(AMFArrayValue* arguments) { + RearrangeStripMessage rearrangeStripMessage(arguments); } -void Add(AMFArrayValue* arguments) { - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - uint32_t behaviorIndex = 0; - auto* behaviorIndexAmf = arguments->FindValue("BehaviorIndex"); - - if (!behaviorIndexAmf) return; - - behaviorIndex = static_cast(behaviorIndexAmf->GetDoubleValue()); - - // modelComponent->AddBehavior(behaviorID, behaviorIndex, modelOwner); - - // SendBehaviorListToClient(); +void ControlBehaviors::Add(AMFArrayValue* arguments) { + AddMessage addMessage(arguments); } -void RemoveActions(AMFArrayValue* arguments) { - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - auto* actionIndexAmf = arguments->FindValue("actionIndex"); - if (!actionIndexAmf) return; - - uint32_t actionIndex = static_cast(actionIndexAmf->GetDoubleValue()); - - STRIPID stripID = GetStripIDFromArgument(arguments); - - BEHAVIORSTATE stateID = GetBehaviorStateFromArgument(arguments); - - // modelComponent->RemoveAction(stateID, stripID, actionIndex, behaviorID); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::RemoveActions(AMFArrayValue* arguments) { + RemoveActionsMessage removeActionsMessage(arguments); } -void Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - auto* nameAmf = arguments->FindValue("Name"); - if (!nameAmf) return; - - auto name = nameAmf->GetStringValue(); - - // modelComponent->Rename(behaviorID, name); - - SendBehaviorListToClient(modelEntity, sysAddr, modelOwner); - - // RequestUpdatedID(behaviorID); +void ControlBehaviors::Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { + RenameMessage renameMessage(arguments); } // TODO This is also supposed to serialize the state of the behaviors in progress but those aren't implemented yet -void SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); +void ControlBehaviors::SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { + // uint32_t behaviorID = ControlBehaviors::GetBehaviorIDFromArgument(arguments); // auto modelBehavior = modelComponent->FindBehavior(behaviorID); @@ -496,47 +246,26 @@ void SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddr // GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorBlocks", &behaviorInfo); } -void UpdateAction(AMFArrayValue* arguments) { - std::string type = ""; - std::string valueParameterName = ""; - std::string valueParameterString = ""; - double valueParameterDouble = 0.0; - auto* actionAsArray = arguments->FindValue("action"); - if (!actionAsArray) return; - for (auto& typeValueMap : actionAsArray->GetAssociativeMap()) { - if (typeValueMap.first == "Type") { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; - type = static_cast(typeValueMap.second)->GetStringValue(); - } else { - valueParameterName = typeValueMap.first; - // Message is the only known string parameter - if (valueParameterName == "Message") { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; - valueParameterString = static_cast(typeValueMap.second)->GetStringValue(); - } else { - if (typeValueMap.second->GetValueType() != AMFValueType::AMFDouble) continue; - valueParameterDouble = static_cast(typeValueMap.second)->GetDoubleValue(); - } +void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) { + UpdateActionMessage updateActionMessage(arguments); + auto* blockDefinition = GetBlockInfo(updateActionMessage.GetType()); + + if (updateActionMessage.GetValueParameterString().size() > 0) { + if (updateActionMessage.GetValueParameterString().size() < blockDefinition->GetMinimumValue() || + updateActionMessage.GetValueParameterString().size() > blockDefinition->GetMaximumValue()) { + Game::logger->Log("ControlBehaviors", "Updated block %s is out of range. Ignoring update", updateActionMessage.GetType().c_str()); + return; + } + } else { + if (updateActionMessage.GetValueParameterDouble() < blockDefinition->GetMinimumValue() || + updateActionMessage.GetValueParameterDouble() > blockDefinition->GetMaximumValue()) { + Game::logger->Log("ControlBehaviors", "Updated block %s is out of range. Ignoring update", updateActionMessage.GetType().c_str()); + return; } } - - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - auto* actionIndexValue = arguments->FindValue("actionIndex"); - if (!actionIndexValue) return; - - uint32_t actionIndex = static_cast(actionIndexValue->GetDoubleValue()); - - STRIPID stripID = GetStripIDFromArgument(arguments); - - BEHAVIORSTATE stateID = GetBehaviorStateFromArgument(arguments); - - // modelComponent->UpdateAction(stateID, stripID, type, valueParameterName, valueParameterString, valueParameterDouble, "", actionIndex, behaviorID); - - // RequestUpdatedID(behaviorID); } -void MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { +void ControlBehaviors::MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { // This closes the UI menu should it be open while the player is removing behaviors AMFArrayValue args; @@ -545,20 +274,13 @@ void MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAdd GameMessages::SendUIMessageServerToSingleClient(modelOwner, modelOwner->GetParentUser()->GetSystemAddress(), "ToggleBehaviorEditor", &args); - uint32_t behaviorID = GetBehaviorIDFromArgument(arguments); - - auto* behaviorIndexValue = arguments->FindValue("BehaviorIndex"); - if (!behaviorIndexValue) return; - - uint32_t behaviorIndex = static_cast(behaviorIndexValue->GetDoubleValue()); - - // modelComponent->MoveBehaviorToInventory(behaviorID, behaviorIndex, modelOwner); + MoveToInventoryMessage moveToInventoryMessage(arguments); SendBehaviorListToClient(modelComponent->GetParent(), sysAddr, modelOwner); } void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner) { - if (!modelEntity || !modelOwner || !arguments) return; + if (!isInitialized || !modelEntity || !modelOwner || !arguments) return; auto* modelComponent = modelEntity->GetComponent(); if (!modelComponent) return; @@ -600,3 +322,135 @@ void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& else Game::logger->Log("ControlBehaviors", "Unknown behavior command (%s)\n", command.c_str()); } + +ControlBehaviors::ControlBehaviors() { + auto blocksDefStreamBuffer = Game::assetManager->GetFileAsBuffer("ui\\ingame\\blocksdef.xml"); + if (!blocksDefStreamBuffer.m_Success) { + Game::logger->Log("ControlBehaviors", "failed to open blocksdef"); + return; + } + std::istream blocksBuffer(&blocksDefStreamBuffer); + if (!blocksBuffer.good()) { + Game::logger->Log("ControlBehaviors", "Blocks buffer is not good!"); + return; + } + + tinyxml2::XMLDocument m_Doc; + + std::string read{}; + + std::string buffer{}; + bool commentBlockStart = false; + while (std::getline(blocksBuffer, read)) { + // tinyxml2 should handle comment blocks but the client has one that fails the processing. + // This preprocessing just removes all comments from the read file out of an abundance of caution. + if (read.find("") != std::string::npos) { + commentBlockStart = false; + continue; + } + if (!commentBlockStart) buffer += read; + } + + auto ret = m_Doc.Parse(buffer.c_str()); + if (ret == tinyxml2::XML_SUCCESS) { + Game::logger->LogDebug("ControlBehaviors", "Successfully parsed the blocksdef file!"); + } else { + Game::logger->Log("Character", "Failed to parse BlocksDef xmlData due to error %i!", ret); + return; + } + auto* blockLibrary = m_Doc.FirstChildElement(); + if (!blockLibrary) { + Game::logger->Log("ControlBehaviors", "No Block Library child element found."); + return; + } + + // Now parse the blocksdef for the cheat detection server side. + // The client does these checks, but a bad actor can bypass the client checks + auto* blockSections = blockLibrary->FirstChildElement(); + while (blockSections) { + auto* block = blockSections->FirstChildElement(); + std::string blockName{}; + while (block) { + blockName = block->Name(); + + BlockDefinition* blockDefinition = new BlockDefinition(); + std::string name{}; + std::string typeName{}; + + auto* argument = block->FirstChildElement("Argument"); + if (argument) { + auto* defaultDefinition = argument->FirstChildElement("DefaultValue"); + if (defaultDefinition) blockDefinition->SetDefaultValue(defaultDefinition->GetText()); + + auto* typeDefinition = argument->FirstChildElement("Type"); + if (typeDefinition) typeName = typeDefinition->GetText(); + + auto* nameDefinition = argument->FirstChildElement("Name"); + if (nameDefinition) name = nameDefinition->GetText(); + + // Now we parse the blocksdef file for the relevant information + if (typeName == "String") { + blockDefinition->SetMaximumValue(50); // The client has a hardcoded limit of 50 characters in a string field + } else if (typeName == "Float" || typeName == "Integer") { + auto* maximumDefinition = argument->FirstChildElement("Maximum"); + if (maximumDefinition) blockDefinition->SetMaximumValue(std::stof(maximumDefinition->GetText())); + + auto* minimumDefinition = argument->FirstChildElement("Minimum"); + if (minimumDefinition) blockDefinition->SetMinimumValue(std::stof(minimumDefinition->GetText())); + } else if (typeName == "Enumeration") { + auto* values = argument->FirstChildElement("Values"); + if (values) { + auto* value = values->FirstChildElement("Value"); + while (value) { + if (value->GetText() == blockDefinition->GetDefaultValue()) blockDefinition->GetDefaultValue() = std::to_string(blockDefinition->GetMaximumValue()); + blockDefinition->SetMaximumValue(blockDefinition->GetMaximumValue() + 1); + value = value->NextSiblingElement("Value"); + } + blockDefinition->SetMaximumValue(blockDefinition->GetMaximumValue() - 1); // Maximum value is 0 indexed + } else { + values = argument->FirstChildElement("EnumerationSource"); + if (!values) { + Game::logger->Log("ControlBehaviors", "Failed to parse EnumerationSource from block (%s)", blockName.c_str()); + continue; + } + + auto* serviceNameNode = values->FirstChildElement("ServiceName"); + if (!serviceNameNode) { + Game::logger->Log("ControlBehaviors", "Failed to parse ServiceName from block (%s)", blockName.c_str()); + continue; + } + + std::string serviceName = serviceNameNode->GetText(); + if (serviceName == "GetBehaviorSoundList") { + auto res = CDClientDatabase::ExecuteQuery("SELECT MAX(id) as countSounds FROM UGBehaviorSounds;"); + blockDefinition->SetMaximumValue(res.getIntField("countSounds")); + blockDefinition->SetDefaultValue("0"); + } else { + Game::logger->Log("ControlBehaviors", "Unsupported Enumeration ServiceType (%s)", serviceName.c_str()); + continue; + } + } + } else { + Game::logger->Log("ControlBehaviors", "Unsupported block value type (%s)!", typeName.c_str()); + continue; + } + } + blockTypes.insert(std::make_pair(blockName, blockDefinition)); + block = block->NextSiblingElement(); + } + blockSections = blockSections->NextSiblingElement(); + } + isInitialized = true; + Game::logger->LogDebug("ControlBehaviors", "Created all base block classes"); + for (auto b : blockTypes) { + Game::logger->LogDebug("ControlBehaviors", "block name is %s default %s min %f max %f", b.first.c_str(), b.second->GetDefaultValue().c_str(), b.second->GetMinimumValue(), b.second->GetMaximumValue()); + } +} + +BlockDefinition* ControlBehaviors::GetBlockInfo(const BlockName& blockName) { + auto blockDefinition = blockTypes.find(blockName); + return blockDefinition != blockTypes.end() ? blockDefinition->second : &BlockDefinition::blockDefinitionDefault; +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.h b/dGame/dPropertyBehaviors/ControlBehaviors.h index d487f929..a562aafe 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviors.h +++ b/dGame/dPropertyBehaviors/ControlBehaviors.h @@ -3,15 +3,23 @@ #ifndef __CONTROLBEHAVIORS__H__ #define __CONTROLBEHAVIORS__H__ +#include #include -#include "RakNetTypes.h" +#include "Singleton.h" -class Entity; class AMFArrayValue; +class BlockDefinition; +class Entity; class ModelComponent; +class SystemAddress; -namespace ControlBehaviors { +// Type definition to clarify what is used where +typedef std::string BlockName; //! A block name + +class ControlBehaviors: public Singleton { +public: + ControlBehaviors(); /** * @brief Main driver for processing Property Behavior commands * @@ -22,6 +30,39 @@ namespace ControlBehaviors { * @param modelOwner The owner of the model which sent this command */ void ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner); + + /** + * @brief Gets a blocks parameter values by the name + * No exception will be thrown in this function. + * + * @param blockName The block name to get the parameters of + * + * @return A pair of the block parameter name to its typing + */ + BlockDefinition* GetBlockInfo(const BlockName& blockName); +private: + void RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr); + void SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner); + void ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent); + void ToggleExecutionUpdates(); + void AddStrip(AMFArrayValue* arguments); + void RemoveStrip(AMFArrayValue* arguments); + void MergeStrips(AMFArrayValue* arguments); + void SplitStrip(AMFArrayValue* arguments); + void UpdateStripUI(AMFArrayValue* arguments); + void AddAction(AMFArrayValue* arguments); + void MigrateActions(AMFArrayValue* arguments); + void RearrangeStrip(AMFArrayValue* arguments); + void Add(AMFArrayValue* arguments); + void RemoveActions(AMFArrayValue* arguments); + void Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + void SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + void UpdateAction(AMFArrayValue* arguments); + void MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + std::map blockTypes{}; + + // If false, property behaviors will not be able to be edited. + bool isInitialized = false; }; #endif //!__CONTROLBEHAVIORS__H__ diff --git a/tests/dGameTests/CMakeLists.txt b/tests/dGameTests/CMakeLists.txt index ba7d4d1c..b1fdaa07 100644 --- a/tests/dGameTests/CMakeLists.txt +++ b/tests/dGameTests/CMakeLists.txt @@ -8,6 +8,8 @@ list(APPEND DGAMETEST_SOURCES ${DCOMPONENTS_TESTS}) add_subdirectory(dGameMessagesTests) list(APPEND DGAMETEST_SOURCES ${DGAMEMESSAGES_TESTS}) +file(COPY ${GAMEMESSAGE_TESTBITSTREAMS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + # Add the executable. Remember to add all tests above this! add_executable(dGameTests ${DGAMETEST_SOURCES}) diff --git a/tests/dGameTests/dGameMessagesTests/CMakeLists.txt b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt index 2417d29c..54c43777 100644 --- a/tests/dGameTests/dGameMessagesTests/CMakeLists.txt +++ b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt @@ -5,5 +5,10 @@ SET(DGAMEMESSAGES_TESTS get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) list(TRANSFORM DGAMEMESSAGES_TESTS PREPEND "${thisFolderName}/") +# Copy test files to testing directory +add_subdirectory(TestBitStreams) +list(TRANSFORM GAMEMESSAGE_TESTBITSTREAMS PREPEND "${thisFolderName}/") +set(GAMEMESSAGE_TESTBITSTREAMS ${GAMEMESSAGE_TESTBITSTREAMS} PARENT_SCOPE) + # Export to parent scope set(DGAMEMESSAGES_TESTS ${DGAMEMESSAGES_TESTS} PARENT_SCOPE) diff --git a/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp index 3d8b2d04..7905c19a 100644 --- a/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp +++ b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp @@ -1,15 +1,50 @@ #include "GameMessages.h" #include "GameDependencies.h" -#include +#include "AMFDeserialize.h" -class GameMessageTests : public GameDependenciesTest { - protected: - void SetUp() override { - SetUpDependencies(); - } - void TearDown() override { - TearDownDependencies(); +#include "AddActionMessage.h" +#include "AddStripMessage.h" +#include "AddMessage.h" +#include "MigrateActionsMessage.h" +#include "MoveToInventoryMessage.h" +#include "MergeStripsMessage.h" +#include "RearrangeStripMessage.h" +#include "RemoveActionsMessage.h" +#include "RemoveStripMessage.h" +#include "RenameMessage.h" +#include "SplitStripMessage.h" +#include "UpdateActionMessage.h" +#include "UpdateStripUiMessage.h" + +#include +#include + +class GameMessageTests: public GameDependenciesTest { +protected: + void SetUp() override { + SetUpDependencies(); + } + void TearDown() override { + TearDownDependencies(); + } + + std::string ReadFromFile(std::string filename) { + std::ifstream file(filename, std::ios::binary); + std::string readFile; + while (file.good()) { + char readCharacter = file.get(); + readFile.push_back(readCharacter); } + + return readFile; + } + + AMFArrayValue* ReadArrayFromBitStream(RakNet::BitStream* inStream) { + AMFDeserialize des; + AMFValue* readArray = des.Read(inStream); + EXPECT_EQ(readArray->GetValueType(), AMFValueType::AMFArray); + return static_cast(readArray); + } }; /** @@ -50,3 +85,143 @@ TEST_F(GameMessageTests, SendBlueprintLoadItemResponse) { ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0); } + +TEST_F(GameMessageTests, ControlBehaviorAddStrip) { + auto data = ReadFromFile("addStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddStripMessage addStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_FLOAT_EQ(addStrip.GetXPosition(), 50.65); + ASSERT_FLOAT_EQ(addStrip.GetYPosition(), 178.05); + ASSERT_EQ(addStrip.GetStripId(), 0); + ASSERT_EQ(static_cast(addStrip.GetStateId()), 0); + ASSERT_EQ(addStrip.GetBehaviorId(), -1); + ASSERT_EQ(addStrip.GetType(), "DropImagination"); + ASSERT_EQ(addStrip.GetValueParameterName(), "Amount"); + ASSERT_EQ(addStrip.GetValueParameterString(), ""); + ASSERT_FLOAT_EQ(addStrip.GetValueParameterDouble(), 1.0); +} + +TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) { + auto data = ReadFromFile("removeStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RemoveStripMessage removeStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(static_cast(removeStrip.GetStripId()), 1); + ASSERT_EQ(static_cast(removeStrip.GetBehaviorState()), 0); + ASSERT_EQ(removeStrip.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorMergeStrips) { + auto data = ReadFromFile("mergeStrips"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + MergeStripsMessage mergeStrips(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(mergeStrips.GetSrcStripID(), 2); + ASSERT_EQ(mergeStrips.GetDstStripID(), 0); + ASSERT_EQ(static_cast(mergeStrips.GetSrcStateID()), 0); + ASSERT_EQ(static_cast(mergeStrips.GetDstStateID()), 0); + ASSERT_EQ(mergeStrips.GetDstActionIndex(), 0); + ASSERT_EQ(mergeStrips.GetBehaviorID(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorSplitStrip) { + auto data = ReadFromFile("splitStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + SplitStripMessage splitStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(splitStrip.GetBehaviorId(), -1); + + ASSERT_FLOAT_EQ(splitStrip.GetXPosition(), 275.65); + ASSERT_FLOAT_EQ(splitStrip.GetYPosition(), 28.7); + ASSERT_EQ(splitStrip.GetSrcStripId(), 0); + ASSERT_EQ(splitStrip.GetDstStripId(), 2); + ASSERT_EQ(static_cast(splitStrip.GetSrcStateId()), 0); + ASSERT_EQ(static_cast(splitStrip.GetDstStateId()), 0); + ASSERT_EQ(splitStrip.GetSrcActionIndex(), 1); +} + +TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) { + auto data = ReadFromFile("updateStripUI"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + UpdateStripUiMessage updateStripUi(ReadArrayFromBitStream(&inStream)); + ASSERT_FLOAT_EQ(updateStripUi.GetXPosition(), 116.65); + ASSERT_FLOAT_EQ(updateStripUi.GetYPosition(), 35.35); + ASSERT_EQ(updateStripUi.GetStripID(), 0); + ASSERT_EQ(static_cast(updateStripUi.GetStateID()), 0); + ASSERT_EQ(updateStripUi.GetBehaviorID(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorAddAction) { + auto data = ReadFromFile("addAction"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddActionMessage addAction(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(addAction.GetActionIndex(), 3); + ASSERT_EQ(addAction.GetStripId(), 0); + ASSERT_EQ(static_cast(addAction.GetStateId()), 0); + ASSERT_EQ(addAction.GetType(), "DoDamage"); + ASSERT_EQ(addAction.GetValueParameterName(), ""); + ASSERT_EQ(addAction.GetValueParameterString(), ""); + ASSERT_EQ(addAction.GetValueParameterDouble(), 0.0); + ASSERT_EQ(addAction.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorMigrateActions) { + auto data = ReadFromFile("migrateActions"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + MigrateActionsMessage migrateActions(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(migrateActions.GetSrcActionIndex(), 1); + ASSERT_EQ(migrateActions.GetDstActionIndex(), 2); + ASSERT_EQ(migrateActions.GetSrcStripID(), 1); + ASSERT_EQ(migrateActions.GetDstStripID(), 0); + ASSERT_EQ(static_cast(migrateActions.GetSrcStateID()), 0); + ASSERT_EQ(static_cast(migrateActions.GetDstStateID()), 0); + ASSERT_EQ(migrateActions.GetBehaviorID(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) { + auto data = ReadFromFile("rearrangeStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RearrangeStripMessage rearrangeStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(rearrangeStrip.GetSrcActionIndex(), 2); + ASSERT_EQ(rearrangeStrip.GetDstActionIndex(), 1); + ASSERT_EQ(rearrangeStrip.GetStripID(), 0); + ASSERT_EQ(rearrangeStrip.GetBehaviorID(), -1); + ASSERT_EQ(static_cast(rearrangeStrip.GetStateID()), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorAdd) { + auto data = ReadFromFile("add"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddMessage add(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(add.GetBehaviorId(), 10446); + ASSERT_EQ(add.GetBehaviorIndex(), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorRemoveActions) { + auto data = ReadFromFile("removeActions"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RemoveActionsMessage removeActions(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(removeActions.GetBehaviorID(), -1); + ASSERT_EQ(removeActions.GetActionIndex(), 1); + ASSERT_EQ(removeActions.GetStripID(), 0); + ASSERT_EQ(static_cast(removeActions.GetStateID()), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorRename) { + auto data = ReadFromFile("rename"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RenameMessage rename(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(rename.GetName(), "test"); + ASSERT_EQ(rename.GetBehaviorID(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorUpdateAction) { + auto data = ReadFromFile("updateAction"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + UpdateActionMessage updateAction(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(updateAction.GetType(), "FlyDown"); + ASSERT_EQ(updateAction.GetValueParameterName(), "Distance"); + ASSERT_EQ(updateAction.GetValueParameterString(), ""); + ASSERT_EQ(updateAction.GetValueParameterDouble(), 50.0); + ASSERT_EQ(updateAction.GetBehaviorID(), -1); + ASSERT_EQ(updateAction.GetActionIndex(), 1); + ASSERT_EQ(updateAction.GetStripID(), 0); + ASSERT_EQ(static_cast(updateAction.GetStateID()), 0); +} diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt b/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt new file mode 100644 index 00000000..e32ed3ef --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt @@ -0,0 +1,24 @@ +set(GAMEMESSAGE_TESTBITSTREAMS +"sendBehaviorListToClient" +"modelTypeChanged" +"toggleExecutionUpdates" +"addStrip" +"removeStrip" +"mergeStrips" +"splitStrip" +"updateStripUI" +"addAction" +"migrateActions" +"rearrangeStrip" +"add" +"removeActions" +"rename" +"updateAction" +) + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM GAMEMESSAGE_TESTBITSTREAMS PREPEND "${thisFolderName}/") + +# Export our list of files +set(GAMEMESSAGE_TESTBITSTREAMS ${GAMEMESSAGE_TESTBITSTREAMS} PARENT_SCOPE) diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/add b/tests/dGameTests/dGameMessagesTests/TestBitStreams/add new file mode 100644 index 0000000000000000000000000000000000000000..13c0dd922c3979d837799c25c92ac420f602bd1f GIT binary patch literal 1024 zcmd;N6m?3?NG!|DFY0HlG~!I2Tj0AW^6mI($x6&wna6$BU$P?Nw3BcKsLV-y~+@T?db+RzRRMvB10%>$K(_~%6lE5G#ZZVEAg>&V^ME)Sh;z<`PQG5xzyP!j z1xP@74X3Y80?8-*TXy0V{Qn1JFSK1|#Jst!hhAnIZMg{e3A4+$5TdYFGLCW?a1FSGFmhX+g^Myo^hO_&5x2QxVfndlV;V7h|oXXI*|j4b}t1elyA_1T`1y5k(S z`krG{^wWJH`8f|#>_PO0euz65p!UP)2M;As!f67-RIt4k|E7TH3$fF|bj3aB85 zgQ!z#Mq*iJevzjO15ig|Nh*>KMoysC#FP|AuoXZysz4s59r%sofEX7Ha+m`a8$}!# zk(EH*jYQP|+2uf-2gK1poO3R8^7VQK1{NS28Aw1m4X3Y80?8-*TXy0{tlMsh8eDEy-Fc>{xTR>0m@*9(gFf42SN6Ld;tPXKn&u; z#2r9_NB|@cvl~em&P4Yw%-uKMC>{ox3j;9wVE#oH-*F709_C+|dV~LvaDl0Z`PX8i zDA@cm8*gxUz~o`HI#l0;Nf31~a|EFJHbCtYIL-k!2S#g~R)WoY71ai&1sEYFelZih z!r;Kb0@KgP)ixO<0~3F0!oc7(sn7P5)E(!r)%P5uqMz;q$68srh@IY_%{ViUx=L!remHTwtXk-B<|4%iEo&`3s8T;_-r7{fB-}b0I_mx z6;EC;7sm^-^z0>JhiIKt2YO4nNfCR7_k literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip new file mode 100644 index 0000000000000000000000000000000000000000..60ba6521b2c17299eb4d6ced8ac2edd5a427a1a9 GIT binary patch literal 1024 zcmd;NVPyb=5B8iPl?AD6@-9XB1)jNy z>6v+nAhnFFrJ09z*X@f6!C*C z_jG})6m?3?NG!|DFYMd7)2g`HA3|F;YrI0&+8H}p{Ww1kO0fCl-AbUU_1py`?2JvCy4j@4!0FsB1X6>n+%eH zi9a=AU~rn$XM0NOj&s=RdyY}jPxpc3=R8QU2hkt;A?{#++7F{2Jd{8QrwI&G!S-7G zn*ydU#7+m(G0zX%zLRwl_vnMfH%#9Js6SzRHjrgN0HOteSUI)|tp8zEf@9jV>&|J< zJ|7C&@#dgy*Ij3ihZ#-`(DdSvDh_c6l%Ft70foo@ZW4Y6Z+JsD2dl85p^N7UiZErKf^zE{0h9!Jd&1B%YaG1T-3AR&h=y&~~71 zxZ@a*9mijc;xZ8jMh>6}i76>yJrHA&$r>Q19EkIPI2wp^&V^3CUeCb50%Rit2`H!G z^wmiq`GkMVPW%VbEl}D5O3z$$04#3+Rlj0kE7&}kddt<{!SW#gf`O{_Duvwn%V1mu zD1#kJ3kb9v1la@f1qd(!F^CTncK`_@0gyb*ZX{ti6WzZsci(uUco<|Z48ZJz`4?S$ z$1#X{n15mF4gN#I1*RV6UyF&NVDrmtyuslClZVmjP<<07LDa#_5rFF30JTrxI0x7q z7_Dtu2{!LlR2!HUV1$_X#Z2@Hg98H#Og|%6+hmXoO#G<{1B26~KHF1Lcbvmk-*b$L ze!34NKj%S;J&69$4{-+r)P5NK;GqOcI89)f3bxnc-xM%?A$B^Lj`<%l`=qRsxJMr( zzG3<Z2hvwU3X4<_W4lIjyDHwyY4!BJj`%nfTkCR tRB?zqp!|es3MhOA<3ERxk*5oTXi9NO za7kiGDqNm{0ip+0OctmP(|iU8h<;@A85kJ(fR^WGrWXN?faodC$pqR0R0VSc&=Mp^ z@E4=FK*WKO1872GN(xvH#4E^T4Ukg~#Cbp*4a7O;LMLCZXJB9fvXOxVl+$qf>LieS z!oOuF{sZY2C~X0yXD&JbmN$T^U$L+iY#vO#AnIZM zg{e3A4+$5TdYFGLCW?a1FSGFmhX+g^Myo^hO_&5x2Qx0ml${U4FjvQFY2eUSKu>AL{+ zCydVqvJ417v;Yt*$5w&$Kdee{OnY|SIqli!LqR*<9JKAa>+JC`!-)Z!UK~=zA?|?k p6Q(Jk@EMH%972xI2lfzt0>g4}x`ny3izNVT--dk*9iVi*6#%+o9`*nL literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged b/tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged new file mode 100644 index 0000000000000000000000000000000000000000..ef282ce2757f0f91ef87f904b07b6db11cfd7697 GIT binary patch literal 1024 zcmd;N6!y(eNzDnVEJ$T#fC5GVAR`wh?3|I9m!6sekz?cr(nYDc`DLlWB}JJ9i6yC? zE^v*a#YM@%C8%PuDa9p@$t9Wjd7gPGsTDA_4x&JDun|c58TmjKXQmecjezJW&dG$R zLbAjuH6yVsGr!2wg@L~q#WoQKMh>6}i76>ylOawMd7)2g`#(4GdJR zS1IJqUk2kUKpE^%T0o%XAjlq&FF=3^h(UaqxC2NK34r8bb|VSHndtt7x%{l|5{8G1)E=H;|&fEm^_SDhw7U!38D^WjsR5O z2B>`k$2q{}z-VpLO0apaqT0Z;03*c2FJ_`w7#tW_VEP%k+9rc!VB$|r7#N%;_1T`1 zy5k(S`krG{^wWJH`8f|#>_PO0euz65p!UP)2M;As!f67-RIt4k|E7TH3$fF|bd3N1 zyVqr%#69{T@eR{=0qRc}pABRg5P)bv(JZucDy-g+jZC3 z<6(vq12nxjq>4k_0p%x5Q$XP}82>qh9G?&DA^Ze}<=}J+b7vPz0N6f<{R|zTbiEY- D3ceex literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip new file mode 100644 index 0000000000000000000000000000000000000000..06dda90b137e18dae0c1b41e46f13a57bc5a6ef0 GIT binary patch literal 1024 zcmd;Nlr1hwc1$kG%+K@8OG&L@Wq<$&{^F9N%mPmrm;i&QQ))(HS!RBbrwfB@N^uFM zrVsW&O^GF`NSYY=fW{T2CKeSX=B1|wgN$TIOi6+0&4ZeTsfz=s3#bgNz64BScL$nI z5eG(OolvhJQ8hqzIS}UoaWoL;oC}?Ny`F)A1;|DQ5>QUV>8q1K@(KTzo%j!=TcETB zl%Bch09f7ts(!`7RKv9D}Hb`4^_%;6Ef>VCrH1 zwU{UhHowfq8yp@mc^It@)i+@hL>@D z%tWs+I54ol^fPj`O$N!p#GjflFgQ)>vppqs$2n~EJ;$i%r~5$ia~`DFgXja69)Soau8^|&s0MP#noM!we?|XnJu-6^FP3%1@Z4fWl`m{&NU9 eJ|Eaa_z4Wl!RZ#}&MuY!uze5qF?4{^^;Q6QY9CVo literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions new file mode 100644 index 0000000000000000000000000000000000000000..56e158e5ec08c6615aa73733fc0cc81386f4c837 GIT binary patch literal 1024 zcmd;N6m?3?NG!|DFY) zp1J4%Sl$4te#OF8uz4``maD&m<+)*ot6Hy8$eq6o##Mka*rBw5K+8dpJs@9z022^{ z_%Lw?kRTEO$;0eM5{5I;{R?yVjW>#iLFU2$%s!ZZ(ZzQhgQ$o37pC6eKO|gW>S6x1 zm?#Q1zs$xP93C)v7_AP~H(?S)9n2g7sJ;zQ`vi`2fX#u?+NPCY^Ik=@foTCoh>2g! zM6WP7FtEV%Gjg>}2Fbw0pPDc*I8ExaJtcL=Ic)Vk$EfJ1`#|z@9;DcV=nwr6cQ8Qh zhtUrnN}z<(1cs?#doBJ=0n-;^r-SL3=Z9_I$vTO9^g-eqrtbpOpD;cf$TA=R(E>oM z99sp}|F9~-G40uP=d@>^4+ZUbbI`WyuCvF(3?~L?dT~exWa`ktxJSfz_K-GGcLhk%!Fs=fW z!49Pb1X>P)>;d@#1ekyr#D|GHfCP~MNFHW4k}#Z!?q8U@Z@f`F3^Er6VD`cMi!Q$7 z7(_kHzcBR%{~_T5QxEg6#Y9oC`DHfV;P8OS!)SG=z6p~c>R{#wK=o~a+9ze?|HG;T$FyhHoztFuJ`}X$%|Y9)yUrdDGn^Qp>BS*c s9O4crKVg~z3ZKFF&mrXad|(gZCon7rr(2jiyI2Ci_8Dwa0_)!j0E?>|zW@LL literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/rename b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rename new file mode 100644 index 0000000000000000000000000000000000000000..bc8827dcd5a07c742276cec210f2fad51750cf97 GIT binary patch literal 1024 zcmd;N_v7Z znobc1Mr55}XQB`_Kwdcz=K*mv5a*l=oqWBXfq@0cMg|g4PQ&S|lR)wb|CXKj52Rb5 zv;~x&x#$2`-T64H;RWr=E4BXKA3;e#djQosE7F%rrzK`BwS$X zVg9w4C<->e%*GoW9x!UVG=|g%p3uzz70_O1deln&4JO{rj=mxUPZNmX#qxv ziC@e_uP`_;u)y>)awj34;F$L8x^vpI&xe9`yg6vwb=TSBVTKa}G`%>aibLE1%5O-_^021LB;s5{u literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient b/tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient new file mode 100644 index 0000000000000000000000000000000000000000..fcca696dc1b93ff923a04242791f4642f65fe9f5 GIT binary patch literal 1024 zcmd;NWRzfFU?@(_OL0ogNG!|DFY?JOE(ytZ&dE&8D*;L|Fff(@F(;5A0Om3=B!Flp zCJr!{;eZ2>24V+CMj!)(SvgrI7ywmpC`?umU|{5UEWp6R0^&0`Uwtd(;K0CQ*m{6L z0B9UX1moQGG5kPH0w;`sMgWabc)-H1=3)a>?<8@Afe~b0V}r!@+T#U4qj(G&AVx7U zI23uhFz^?bB$lLly08LO0fC4EBgj#SDJj7vMVSR)F%+T($SVipJRpt+;+%7#ldsn^ zFaT{s0iZAefrispCxPS>{w+K4A4s=AX$vSlbI}2?JkYmbuwr2=*gTke%hlh(^4w5) z236}-3c2%_!MF-g20N4%5NJ6FvIiQp3`{_A5FaM)096O0K=LrVVPeQMx_@ErzVSx! zFvwgOfY}H0FS_`SV-WQ)|H9N8{D*`KOg+rM786Cm=9k%cgTn(R52Mwg`X)?*sDqg! z0M)kvYM;Py4zM{eTHCY|Y~HJ=HZUy!N*+M)#Z2@H12A2|^fPj`O-2@fY6477llp8= zN!@V{TYb+lD*EX@ko=qnDfS@xLqEhF3{d-F^n-^IDB(1LVJg^Oi+@wV^o7{zU^?dc zVcU1IPU0SYkobn_y8!hkjL!zL3+JC`!wHsN98$$0?trGBglP&Wd>~dh_0y?C) zASV-O3s45TBlwF^Tp;4W$N|)qn34k41MvznSp(#h192V@M+0%rxzNei>lqkWfNW$S z0p&EDzB&mcpYU(liT^;l1xi~$>6wcTfaMLK>Q^jm1)B#`Z@KzASe_eZxT^Ikh1~he zU|a<#gB?l>2(%mo*#q(g2rvOLhz}EY00|-ikUY$8Bw;uc-M=t*-*}^V7-TLC!0dzh z7hQbEF^GDYe_`qk{zJkArXJ>Bi;1FO^UG|!!QlauhtcX#eG?`@)WOUVfa==-wNKzU z2iP1Kt!-KfHt$tb8<-YggqZlnO!Nwa0|N_8KO1j`5!X-q^y&; zM;|1|zN3+ZS+*p#zkzw*mkF+Z`$Z literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates b/tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates new file mode 100644 index 0000000000000000000000000000000000000000..02a72181616c6a1ab46e82146e603ec296fa3031 GIT binary patch literal 1024 zcmd;NS%{T(dN z4V7n5wO*x=JAWCBs{m!NLumnlmV+RBpg{`^YX$}oA13YqRR^O$@-Vw$V#qYQe_`&v z@ka45$XpnJ*$4A4y7-P`5cM$s!qgl5hlC4EJ}Mizf+0!&Vm z`fN{0-Ej_Eea|r}`sqH9{G10V_8|I0Kg1mjQ2Sx@gNG6*;WU9^D%f6&e^bEph1ls} zI_CLd+jp`~;vRjF_=f4b0QDz~&jzv#2tYJ2`7X$mNO2ID`6kmK`#J%pdYupFFjVeaf=2>{#oU>`#V IC|z#_09Q>B!~g&Q literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction new file mode 100644 index 0000000000000000000000000000000000000000..e007d5e6b3f2d5b0ac733e3e925bcbf4ed522314 GIT binary patch literal 1024 zcmd;NYFeLq7G(`094-wsC@#*Il$(?Xl>I< zuz9bd+Q75`BgDinW};VsiGc;CpOLF=GDrp{{?vql!D&*T?J21{&S9(XIYvc4-3OAN z^B~0@M1SaqxPt*|Ka76xPy!{KCNN9|+iUS}3YfkSI~`2N=AdoYU1yJn8BPq)^x}{z4si#R ppD;}Uh0kF8=MZvyKCp-I6Bw3*(=E)MT`U1$`!?)j=m4ebtpEV}6u|%h literal 0 HcmV?d00001 diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI new file mode 100644 index 0000000000000000000000000000000000000000..7d0eed926857d88dbe03d3ab1f097239101fb2a1 GIT binary patch literal 1024 zcmd;NWG&6)WMr;nJ#_{M);KyaSFp~S2?Uz44veBssTql7nfXPYE)4v|B}JJ9o-V8m zPyiH2EJ;NYVB`hLloq4_MT0?VLp?z%MN^7Pz+7aN+(3!k)S`5V!eWp*28IvzjC?>U zH#5BmXoO>ONoIataZV;gH^N>tM?s5 z$iHBqYQ0J!cm6UMR{_dkhtdK9EeApNfP4W0Oh63c!^9mxf=B=)53?Id7|ulZFU;LH z-Y6ahnF|9j`(XY>7vFIVq8{d7n0kZ%kZ^&ihxylHqA1w>G8=Djc);Xgv^rGZgh>!} zFmnW;`ZhrA6FANRHU~y)n^uC&dll6NrUe)wCVnv!y~5zYzyj0H$kjF(Bm)zFYQn(a zG^x+_l++#Pu+{e*qoSYg1If>MkYW#_KlDS~!2q=%Mn8Bcff7y=7^Z^lwfHv$Okaqd z4yI$){}DMY>m=^c2Z?W(z6(%)!uV_;%YXnx3jnclY!z7l!>R{acU=QIZFf0eBTbMh$SOUQIJ=n+4 I0ZP|f0dLVDp#T5? literal 0 HcmV?d00001