refactor: Rewrite AMF and property behavior logic to use smart pointers, references, and string_views over raw pointers and std::string& (#1452)

* Rewrite AMF and behavior logic to use smart pointers, references, and string_views over raw pointers and std::string&

* fix m_BehaviorID initialization

* Fix BlockDefinition member naming

* remove redundant reset()s

* Replace UB forward template declarations with header include

* remove unneeded comment

* remove non-const ref getters

* simplify default behavior id initialization

* Fix invalidated use of Getter to set a value

* Update AddStripMessage.cpp - change push_back to emplace_back

* fix pointer to ref conversion mistake (should not have directly grabbed from the other branch commit)

* deref

* VERY experimental testing of forward declaration of templates - probably will revert

* Revert changes (as expected)

* Update BlockDefinition.h - remove extraneous semicolons

* Update BlockDefinition.h - remove linebreak

* Update Amf3.h member naming scheme

* fix duplicated code

* const iterators

* const pointers

* reviving this branch

* update read switch cases
This commit is contained in:
jadebenn 2024-11-18 20:45:24 -06:00 committed by GitHub
parent 83f8646936
commit 53877a0bc3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 200 additions and 181 deletions

View File

@ -73,4 +73,4 @@ cpp_space_around_assignment_operator=insert
cpp_space_pointer_reference_alignment=left
cpp_space_around_ternary_operator=insert
cpp_wrap_preserve_blocks=one_liners
cpp_indent_comment=fasle
cpp_indent_comment=false

View File

@ -9,73 +9,54 @@
* AMF3 Deserializer written by EmosewaMC
*/
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) {
AMFBaseValue* returnValue = nullptr;
std::unique_ptr<AMFBaseValue> AMFDeserialize::Read(RakNet::BitStream& inStream) {
// Read in the value type from the bitStream
eAmf marker;
inStream.Read(marker);
// Based on the typing, create the value associated with that and return the base value class
switch (marker) {
case eAmf::Undefined: {
returnValue = new AMFBaseValue();
break;
}
case eAmf::Null: {
returnValue = new AMFNullValue();
break;
}
case eAmf::False: {
returnValue = new AMFBoolValue(false);
break;
}
case eAmf::True: {
returnValue = new AMFBoolValue(true);
break;
}
case eAmf::Integer: {
returnValue = ReadAmfInteger(inStream);
break;
}
case eAmf::Double: {
returnValue = ReadAmfDouble(inStream);
break;
}
case eAmf::String: {
returnValue = ReadAmfString(inStream);
break;
}
case eAmf::Array: {
returnValue = ReadAmfArray(inStream);
break;
}
case eAmf::Undefined:
return std::make_unique<AMFBaseValue>();
case eAmf::Null:
return std::make_unique<AMFNullValue>();
case eAmf::False:
return std::make_unique<AMFBoolValue>(false);
case eAmf::True:
return std::make_unique<AMFBoolValue>(true);
case eAmf::Integer:
return ReadAmfInteger(inStream);
case eAmf::Double:
return ReadAmfDouble(inStream);
case eAmf::String:
return ReadAmfString(inStream);
case eAmf::Array:
return ReadAmfArray(inStream);
// These values are unimplemented in the live client and will remain unimplemented
// unless someone modifies the client to allow serializing of these values.
case eAmf::XMLDoc:
[[fallthrough]];
case eAmf::Date:
[[fallthrough]];
case eAmf::Object:
[[fallthrough]];
case eAmf::XML:
[[fallthrough]];
case eAmf::ByteArray:
[[fallthrough]];
case eAmf::VectorInt:
[[fallthrough]];
case eAmf::VectorUInt:
[[fallthrough]];
case eAmf::VectorDouble:
[[fallthrough]];
case eAmf::VectorObject:
case eAmf::Dictionary: {
[[fallthrough]];
case eAmf::Dictionary:
throw marker;
break;
}
default:
throw std::invalid_argument("Invalid AMF3 marker" + std::to_string(static_cast<int32_t>(marker)));
break;
}
return returnValue;
}
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) {
@ -118,14 +99,14 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
}
}
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
std::unique_ptr<AMFDoubleValue> AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
double value;
inStream.Read<double>(value);
return new AMFDoubleValue(value);
return std::make_unique<AMFDoubleValue>(value);
}
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
auto arrayValue = new AMFArrayValue();
std::unique_ptr<AMFArrayValue> AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
auto arrayValue = std::make_unique<AMFArrayValue>();
// Read size of dense array
const auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
@ -143,10 +124,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
return arrayValue;
}
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
return new AMFStringValue(ReadString(inStream));
std::unique_ptr<AMFStringValue> AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
return std::make_unique<AMFStringValue>(ReadString(inStream));
}
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
return new AMFIntValue(ReadU29(inStream));
std::unique_ptr<AMFIntValue> AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
return std::make_unique<AMFIntValue>(ReadU29(inStream)); // NOTE: NARROWING CONVERSION FROM UINT TO INT. IS THIS INTENDED?
}

View File

@ -1,12 +1,12 @@
#pragma once
#include "Amf3.h"
#include "BitStream.h"
#include <memory>
#include <vector>
#include <string>
class AMFBaseValue;
class AMFDeserialize {
public:
/**
@ -15,7 +15,7 @@ public:
* @param inStream inStream to read value from.
* @return Returns an AMFValue with all the information from the bitStream in it.
*/
AMFBaseValue* Read(RakNet::BitStream& inStream);
std::unique_ptr<AMFBaseValue> Read(RakNet::BitStream& inStream);
private:
/**
* @brief Private method to read a U29 integer from a bitstream
@ -39,7 +39,7 @@ private:
* @param inStream bitStream to read data from
* @return Double value represented as an AMFValue
*/
AMFBaseValue* ReadAmfDouble(RakNet::BitStream& inStream);
static std::unique_ptr<AMFDoubleValue> ReadAmfDouble(RakNet::BitStream& inStream);
/**
* @brief Read an AMFArray from a bitStream
@ -47,7 +47,7 @@ private:
* @param inStream bitStream to read data from
* @return Array value represented as an AMFValue
*/
AMFBaseValue* ReadAmfArray(RakNet::BitStream& inStream);
std::unique_ptr<AMFArrayValue> ReadAmfArray(RakNet::BitStream& inStream);
/**
* @brief Read an AMFString from a bitStream
@ -55,7 +55,7 @@ private:
* @param inStream bitStream to read data from
* @return String value represented as an AMFValue
*/
AMFBaseValue* ReadAmfString(RakNet::BitStream& inStream);
std::unique_ptr<AMFStringValue> ReadAmfString(RakNet::BitStream& inStream);
/**
* @brief Read an AMFInteger from a bitStream
@ -63,7 +63,7 @@ private:
* @param inStream bitStream to read data from
* @return Integer value represented as an AMFValue
*/
AMFBaseValue* ReadAmfInteger(RakNet::BitStream& inStream);
static std::unique_ptr<AMFIntValue> ReadAmfInteger(RakNet::BitStream& inStream);
/**
* List of strings read so far saved to be read by reference.

View File

@ -105,27 +105,14 @@ using AMFDoubleValue = AMFValue<double>;
* and are not to be deleted by a caller.
*/
class AMFArrayValue : public AMFBaseValue {
using AMFAssociative = std::unordered_map<std::string, AMFBaseValue*>;
using AMFDense = std::vector<AMFBaseValue*>;
using AMFAssociative =
std::unordered_map<std::string, std::unique_ptr<AMFBaseValue>, GeneralUtils::transparent_string_hash, std::equal_to<>>;
using AMFDense = std::vector<std::unique_ptr<AMFBaseValue>>;
public:
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; }
~AMFArrayValue() override {
for (const auto* valueToDelete : GetDense()) {
if (valueToDelete) {
delete valueToDelete;
valueToDelete = nullptr;
}
}
for (auto valueToDelete : GetAssociative()) {
if (valueToDelete.second) {
delete valueToDelete.second;
valueToDelete.second = nullptr;
}
}
}
/**
* Returns the Associative portion of the object
*/
@ -151,30 +138,32 @@ public:
* or nullptr if a key existed and was not the same type
*/
template <typename ValueType>
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, const ValueType value) {
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string_view key, const ValueType value) {
const auto element = m_Associative.find(key);
AMFValue<ValueType>* val = nullptr;
bool found = true;
if (element == m_Associative.cend()) {
val = new AMFValue<ValueType>(value);
m_Associative.emplace(key, val);
auto newVal = std::make_unique<AMFValue<ValueType>>(value);
val = newVal.get();
m_Associative.emplace(key, std::move(newVal));
} else {
val = dynamic_cast<AMFValue<ValueType>*>(element->second);
val = dynamic_cast<AMFValue<ValueType>*>(element->second.get());
found = false;
}
return std::make_pair(val, found);
}
// Associates an array with a string key
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string_view key) {
const auto element = m_Associative.find(key);
AMFArrayValue* val = nullptr;
bool found = true;
if (element == m_Associative.cend()) {
val = new AMFArrayValue();
m_Associative.emplace(key, val);
auto newVal = std::make_unique<AMFArrayValue>();
val = newVal.get();
m_Associative.emplace(key, std::move(newVal));
} else {
val = dynamic_cast<AMFArrayValue*>(element->second);
val = dynamic_cast<AMFArrayValue*>(element->second.get());
found = false;
}
return std::make_pair(val, found);
@ -182,15 +171,13 @@ public:
// Associates an array with an integer key
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) {
AMFArrayValue* val = nullptr;
bool inserted = false;
if (index >= m_Dense.size()) {
m_Dense.resize(index + 1);
val = new AMFArrayValue();
m_Dense.at(index) = val;
m_Dense.at(index) = std::make_unique<AMFArrayValue>();
inserted = true;
}
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index)), inserted);
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()), inserted);
}
/**
@ -205,15 +192,13 @@ public:
*/
template <typename ValueType>
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) {
AMFValue<ValueType>* val = nullptr;
bool inserted = false;
if (index >= m_Dense.size()) {
m_Dense.resize(index + 1);
val = new AMFValue<ValueType>(value);
m_Dense.at(index) = val;
m_Dense.at(index) = std::make_unique<AMFValue<ValueType>>(value);
inserted = true;
}
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index)), inserted);
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index).get()), inserted);
}
/**
@ -225,13 +210,12 @@ public:
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const std::string& key, AMFBaseValue* const value) {
void Insert(const std::string_view key, std::unique_ptr<AMFBaseValue> value) {
const auto element = m_Associative.find(key);
if (element != m_Associative.cend() && element->second) {
delete element->second;
element->second = value;
element->second = std::move(value);
} else {
m_Associative.emplace(key, value);
m_Associative.emplace(key, std::move(value));
}
}
@ -244,14 +228,11 @@ public:
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const size_t index, AMFBaseValue* const value) {
if (index < m_Dense.size()) {
const AMFDense::const_iterator itr = m_Dense.cbegin() + index;
if (*itr) delete m_Dense.at(index);
} else {
void Insert(const size_t index, std::unique_ptr<AMFBaseValue> value) {
if (index >= m_Dense.size()) {
m_Dense.resize(index + 1);
}
m_Dense.at(index) = value;
m_Dense.at(index) = std::move(value);
}
/**
@ -279,8 +260,7 @@ public:
void Remove(const std::string& key, const bool deleteValue = true) {
const AMFAssociative::const_iterator it = m_Associative.find(key);
if (it != m_Associative.cend()) {
if (deleteValue) delete it->second;
m_Associative.erase(it);
if (deleteValue) m_Associative.erase(it);
}
}
@ -290,7 +270,6 @@ public:
void Remove(const size_t index) {
if (!m_Dense.empty() && index < m_Dense.size()) {
const auto itr = m_Dense.cbegin() + index;
if (*itr) delete (*itr);
m_Dense.erase(itr);
}
}
@ -299,16 +278,16 @@ public:
if (!m_Dense.empty()) Remove(m_Dense.size() - 1);
}
[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) const {
[[nodiscard]] AMFArrayValue* GetArray(const std::string_view key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key);
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second) : nullptr;
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second.get()) : nullptr;
}
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const {
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index)) : nullptr;
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()) : nullptr;
}
[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string& key) {
[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string_view key) {
return static_cast<AMFArrayValue*>(Insert(key).first);
}
@ -330,17 +309,17 @@ public:
* @return The AMFValue
*/
template <typename AmfType>
[[nodiscard]] AMFValue<AmfType>* Get(const std::string& key) const {
[[nodiscard]] AMFValue<AmfType>* Get(const std::string_view key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key);
return it != m_Associative.cend() ?
dynamic_cast<AMFValue<AmfType>*>(it->second) :
dynamic_cast<AMFValue<AmfType>*>(it->second.get()) :
nullptr;
}
// Get from the array but dont cast it
[[nodiscard]] AMFBaseValue* Get(const std::string& key) const {
[[nodiscard]] AMFBaseValue* Get(const std::string_view key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key);
return it != m_Associative.cend() ? it->second : nullptr;
return it != m_Associative.cend() ? it->second.get() : nullptr;
}
/**
@ -355,13 +334,13 @@ public:
template <typename AmfType>
[[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const {
return index < m_Dense.size() ?
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index)) :
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index).get()) :
nullptr;
}
// Get from the dense but dont cast it
[[nodiscard]] AMFBaseValue* Get(const size_t index) const {
return index < m_Dense.size() ? m_Dense.at(index) : nullptr;
return index < m_Dense.size() ? m_Dense.at(index).get() : nullptr;
}
private:

View File

@ -129,6 +129,29 @@ namespace GeneralUtils {
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string_view folder);
/**
* Transparent string hasher - used to allow string_view key lookups for maps storing std::string keys
* https://www.reddit.com/r/cpp_questions/comments/12xw3sn/find_stdstring_view_in_unordered_map_with/jhki225/
* https://godbolt.org/z/789xv8Eeq
*/
template <typename... Bases>
struct overload : Bases... {
using is_transparent = void;
using Bases::operator() ... ;
};
struct char_pointer_hash {
auto operator()(const char* const ptr) const noexcept {
return std::hash<std::string_view>{}(ptr);
}
};
using transparent_string_hash = overload<
std::hash<std::string>,
std::hash<std::string_view>,
char_pointer_hash
>;
// Concept constraining to enum types
template <typename T>
concept Enum = std::is_enum_v<T>;

View File

@ -66,8 +66,8 @@ public:
template<typename Msg>
void HandleControlBehaviorsMsg(const AMFArrayValue& args) {
static_assert(std::is_base_of_v<BehaviorMessageBase, Msg>, "Msg must be a BehaviorMessageBase");
Msg msg(args);
for (auto& behavior : m_Behaviors) {
Msg msg{ args };
for (auto&& behavior : m_Behaviors) {
if (behavior.GetBehaviorId() == msg.GetBehaviorId()) {
behavior.HandleMsg(msg);
return;

View File

@ -2492,7 +2492,7 @@ void GameMessages::SendUnSmash(Entity* entity, LWOOBJID builderID, float duratio
void GameMessages::HandleControlBehaviors(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) {
AMFDeserialize reader;
std::unique_ptr<AMFArrayValue> amfArguments{ static_cast<AMFArrayValue*>(reader.Read(inStream)) };
std::unique_ptr<AMFArrayValue> amfArguments{ static_cast<AMFArrayValue*>(reader.Read(inStream).release()) };
if (amfArguments->GetValueType() != eAmf::Array) return;
uint32_t commandLength{};

View File

@ -2,7 +2,7 @@
BlockDefinition BlockDefinition::blockDefinitionDefault{};
BlockDefinition::BlockDefinition(const std::string& defaultValue, const float minimumValue, const float maximumValue)
BlockDefinition::BlockDefinition(const std::string_view defaultValue, const float minimumValue, const float maximumValue)
: m_DefaultValue{ defaultValue }
, m_MinimumValue{ minimumValue }
, m_MaximumValue{ maximumValue } {

View File

@ -7,13 +7,13 @@ class AMFArrayValue;
class BlockDefinition {
public:
BlockDefinition(const std::string& defaultValue = "", const float minimumValue = 0.0f, const float maximumValue = 0.0f);
BlockDefinition(const std::string_view defaultValue = "", const float minimumValue = 0.0f, const float maximumValue = 0.0f);
static BlockDefinition blockDefinitionDefault;
[[nodiscard]] const std::string& GetDefaultValue() const { return m_DefaultValue; }
[[nodiscard]] std::string_view GetDefaultValue() const { return m_DefaultValue; }
[[nodiscard]] float GetMinimumValue() const noexcept { return m_MinimumValue; }
[[nodiscard]] float GetMaximumValue() const noexcept { return m_MaximumValue; }
void SetDefaultValue(const std::string& value) { m_DefaultValue = value; }
void SetDefaultValue(const std::string_view value) { m_DefaultValue = std::string{ value }; }
void SetMinimumValue(const float value) noexcept { m_MinimumValue = value; }
void SetMaximumValue(const float value) noexcept { m_MaximumValue = value; }

View File

@ -7,16 +7,16 @@ Action::Action(const AMFArrayValue& arguments) {
for (const auto& [paramName, paramValue] : arguments.GetAssociative()) {
if (paramName == "Type") {
if (paramValue->GetValueType() != eAmf::String) continue;
m_Type = static_cast<AMFStringValue*>(paramValue)->GetValue();
m_Type = static_cast<AMFStringValue*>(paramValue.get())->GetValue();
} else {
m_ValueParameterName = paramName;
// Message is the only known string parameter
if (m_ValueParameterName == "Message") {
if (paramValue->GetValueType() != eAmf::String) continue;
m_ValueParameterString = static_cast<AMFStringValue*>(paramValue)->GetValue();
m_ValueParameterString = static_cast<AMFStringValue*>(paramValue.get())->GetValue();
} else {
if (paramValue->GetValueType() != eAmf::Double) continue;
m_ValueParameterDouble = static_cast<AMFDoubleValue*>(paramValue)->GetValue();
m_ValueParameterDouble = static_cast<AMFDoubleValue*>(paramValue.get())->GetValue();
}
}
}

View File

@ -17,9 +17,9 @@ class Action {
public:
Action() = default;
Action(const AMFArrayValue& arguments);
[[nodiscard]] const std::string& GetType() const { return m_Type; };
[[nodiscard]] const std::string& GetValueParameterName() const { return m_ValueParameterName; };
[[nodiscard]] const std::string& GetValueParameterString() const { return m_ValueParameterString; };
[[nodiscard]] std::string_view GetType() const { return m_Type; };
[[nodiscard]] std::string_view GetValueParameterName() const { return m_ValueParameterName; };
[[nodiscard]] std::string_view GetValueParameterString() const { return m_ValueParameterString; };
[[nodiscard]] double GetValueParameterDouble() const noexcept { return m_ValueParameterDouble; };
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;

View File

@ -4,21 +4,21 @@
#include "Amf3.h"
ActionContext::ActionContext(const AMFArrayValue& arguments, const std::string& customStateKey, const std::string& customStripKey)
ActionContext::ActionContext(const AMFArrayValue& arguments, const std::string_view customStateKey, const std::string_view customStripKey)
: m_StripId{ GetStripIdFromArgument(arguments, customStripKey) }
, m_StateId{ GetBehaviorStateFromArgument(arguments, customStateKey) } {
}
BehaviorState ActionContext::GetBehaviorStateFromArgument(const AMFArrayValue& arguments, const std::string& key) const {
BehaviorState ActionContext::GetBehaviorStateFromArgument(const AMFArrayValue& arguments, const std::string_view key) const {
const auto* const stateIDValue = arguments.Get<double>(key);
if (!stateIDValue) throw std::invalid_argument("Unable to find behavior state from argument \"" + key + "\"");
if (!stateIDValue) throw std::invalid_argument("Unable to find behavior state from argument \"" + std::string{ key } + "\"");
return static_cast<BehaviorState>(stateIDValue->GetValue());
}
StripId ActionContext::GetStripIdFromArgument(const AMFArrayValue& arguments, const std::string& key) const {
StripId ActionContext::GetStripIdFromArgument(const AMFArrayValue& arguments, const std::string_view key) const {
const auto* const stripIdValue = arguments.Get<double>(key);
if (!stripIdValue) throw std::invalid_argument("Unable to find strip ID from argument \"" + key + "\"");
if (!stripIdValue) throw std::invalid_argument("Unable to find strip ID from argument \"" + std::string{ key } + "\"");
return static_cast<StripId>(stripIdValue->GetValue());
}

View File

@ -4,6 +4,8 @@
#include "BehaviorStates.h"
#include "dCommonVars.h"
#include <string_view>
class AMFArrayValue;
/**
@ -13,13 +15,13 @@ class AMFArrayValue;
class ActionContext {
public:
ActionContext() noexcept = default;
ActionContext(const AMFArrayValue& arguments, const std::string& customStateKey = "stateID", const std::string& customStripKey = "stripID");
ActionContext(const AMFArrayValue& arguments, const std::string_view customStateKey = "stateID", const std::string_view customStripKey = "stripID");
[[nodiscard]] StripId GetStripId() const noexcept { return m_StripId; };
[[nodiscard]] BehaviorState GetStateId() const noexcept { return m_StateId; };
private:
[[nodiscard]] BehaviorState GetBehaviorStateFromArgument(const AMFArrayValue& arguments, const std::string& key) const;
[[nodiscard]] StripId GetStripIdFromArgument(const AMFArrayValue& arguments, const std::string& key) const;
[[nodiscard]] BehaviorState GetBehaviorStateFromArgument(const AMFArrayValue& arguments, const std::string_view key) const;
[[nodiscard]] StripId GetStripIdFromArgument(const AMFArrayValue& arguments, const std::string_view key) const;
StripId m_StripId{ 0 };
BehaviorState m_StateId{ BehaviorState::HOME_STATE };
};

View File

@ -10,5 +10,5 @@ AddActionMessage::AddActionMessage(const AMFArrayValue& arguments)
m_Action = Action{ *actionValue };
LOG_DEBUG("actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f m_BehaviorId %i", m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_Action.GetType().c_str(), m_Action.GetValueParameterName().c_str(), m_Action.GetValueParameterString().c_str(), m_Action.GetValueParameterDouble(), m_BehaviorId);
LOG_DEBUG("actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f m_BehaviorId %i", m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_Action.GetType().data(), m_Action.GetValueParameterName().data(), m_Action.GetValueParameterString().data(), m_Action.GetValueParameterDouble(), m_BehaviorId);
}

View File

@ -19,7 +19,7 @@ AddStripMessage::AddStripMessage(const AMFArrayValue& arguments)
m_ActionsToAdd.emplace_back(*actionValue);
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId, m_ActionsToAdd.back().GetType().c_str(), m_ActionsToAdd.back().GetValueParameterName().c_str(), m_ActionsToAdd.back().GetValueParameterString().c_str(), m_ActionsToAdd.back().GetValueParameterDouble());
LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId, m_ActionsToAdd.back().GetType().data(), m_ActionsToAdd.back().GetValueParameterName().data(), m_ActionsToAdd.back().GetValueParameterString().data(), m_ActionsToAdd.back().GetValueParameterDouble());
}
LOG_DEBUG("number of actions %i", m_ActionsToAdd.size());
}

View File

@ -5,7 +5,7 @@
#include "dCommonVars.h"
int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(const AMFArrayValue& arguments) {
static constexpr const char* key = "BehaviorID";
static constexpr std::string_view key = "BehaviorID";
const auto* const behaviorIDValue = arguments.Get<std::string>(key);
int32_t behaviorId = DefaultBehaviorId;
@ -19,7 +19,7 @@ int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(const AMFArrayValue& argu
return behaviorId;
}
int32_t BehaviorMessageBase::GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string& keyName) const {
int32_t BehaviorMessageBase::GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string_view keyName) const {
const auto* const actionIndexAmf = arguments.Get<double>(keyName);
if (!actionIndexAmf) throw std::invalid_argument("Unable to find actionIndex");

View File

@ -22,7 +22,7 @@ public:
protected:
[[nodiscard]] int32_t GetBehaviorIdFromArgument(const AMFArrayValue& arguments);
[[nodiscard]] int32_t GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string& keyName = "actionIndex") const;
[[nodiscard]] int32_t GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string_view keyName = "actionIndex") const;
int32_t m_BehaviorId{ DefaultBehaviorId };
};

View File

@ -11,7 +11,7 @@ class AMFArrayValue;
class RenameMessage : public BehaviorMessageBase {
public:
RenameMessage(const AMFArrayValue& arguments);
[[nodiscard]] const std::string& GetName() const { return m_Name; };
[[nodiscard]] std::string_view GetName() const { return m_Name; };
private:
std::string m_Name;

View File

@ -3,7 +3,7 @@
#include "Amf3.h"
#include "tinyxml2.h"
StripUiPosition::StripUiPosition(const AMFArrayValue& arguments, const std::string& uiKeyName) {
StripUiPosition::StripUiPosition(const AMFArrayValue& arguments, const std::string_view uiKeyName) {
const auto* const uiArray = arguments.GetArray(uiKeyName);
if (!uiArray) return;

View File

@ -14,7 +14,7 @@ namespace tinyxml2 {
class StripUiPosition {
public:
StripUiPosition() noexcept = default;
StripUiPosition(const AMFArrayValue& arguments, const std::string& uiKeyName = "ui");
StripUiPosition(const AMFArrayValue& arguments, const std::string_view uiKeyName = "ui");
void SendBehaviorBlocksToClient(AMFArrayValue& args) const;
[[nodiscard]] double GetX() const noexcept { return m_XPosition; }
[[nodiscard]] double GetY() const noexcept { return m_YPosition; }

View File

@ -12,5 +12,5 @@ UpdateActionMessage::UpdateActionMessage(const AMFArrayValue& arguments)
m_Action = Action{ *actionValue };
LOG_DEBUG("type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", m_Action.GetType().c_str(), m_Action.GetValueParameterName().c_str(), m_Action.GetValueParameterString().c_str(), m_Action.GetValueParameterDouble(), m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId());
LOG_DEBUG("type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", m_Action.GetType().data(), m_Action.GetValueParameterName().data(), m_Action.GetValueParameterString().data(), m_Action.GetValueParameterDouble(), m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId());
}

View File

@ -76,26 +76,26 @@ void ControlBehaviors::UpdateAction(const AMFArrayValue& arguments) {
auto blockDefinition = GetBlockInfo(updateActionMessage.GetAction().GetType());
if (!blockDefinition) {
LOG("Received undefined block type %s. Ignoring.", updateActionMessage.GetAction().GetType().c_str());
LOG("Received undefined block type %s. Ignoring.", updateActionMessage.GetAction().GetType().data());
return;
}
if (updateActionMessage.GetAction().GetValueParameterString().size() > 0) {
if (updateActionMessage.GetAction().GetValueParameterString().size() < blockDefinition->GetMinimumValue() ||
updateActionMessage.GetAction().GetValueParameterString().size() > blockDefinition->GetMaximumValue()) {
LOG("Updated block %s is out of range. Ignoring update", updateActionMessage.GetAction().GetType().c_str());
LOG("Updated block %s is out of range. Ignoring update", updateActionMessage.GetAction().GetType().data());
return;
}
} else {
if (updateActionMessage.GetAction().GetValueParameterDouble() < blockDefinition->GetMinimumValue() ||
updateActionMessage.GetAction().GetValueParameterDouble() > blockDefinition->GetMaximumValue()) {
LOG("Updated block %s is out of range. Ignoring update", updateActionMessage.GetAction().GetType().c_str());
LOG("Updated block %s is out of range. Ignoring update", updateActionMessage.GetAction().GetType().data());
return;
}
}
}
void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayValue& arguments, const std::string& command, Entity* const modelOwner) {
void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayValue& arguments, const std::string_view command, Entity* const modelOwner) {
if (!isInitialized || !modelEntity || !modelOwner) return;
auto* const modelComponent = modelEntity->GetComponent<ModelComponent>();
@ -157,7 +157,7 @@ void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayV
} else if (command == "updateAction") {
context.modelComponent->HandleControlBehaviorsMsg<UpdateActionMessage>(arguments);
} else {
LOG("Unknown behavior command (%s)", command.c_str());
LOG("Unknown behavior command (%s)", command.data());
}
}
@ -279,11 +279,11 @@ ControlBehaviors::ControlBehaviors() {
isInitialized = true;
LOG_DEBUG("Created all base block classes");
for (auto& [name, block] : blockTypes) {
LOG_DEBUG("block name is %s default %s min %f max %f", name.c_str(), block.GetDefaultValue().c_str(), block.GetMinimumValue(), block.GetMaximumValue());
LOG_DEBUG("block name is %s default %s min %f max %f", name.data(), block.GetDefaultValue().data(), block.GetMinimumValue(), block.GetMaximumValue());
}
}
std::optional<BlockDefinition> ControlBehaviors::GetBlockInfo(const std::string& blockName) {
std::optional<BlockDefinition> ControlBehaviors::GetBlockInfo(const std::string_view blockName) {
auto blockDefinition = blockTypes.find(blockName);
return blockDefinition != blockTypes.end() ? std::optional(blockDefinition->second) : std::nullopt;
}

View File

@ -43,7 +43,7 @@ public:
* @param command The command to perform
* @param modelOwner The owner of the model which sent this command
*/
void ProcessCommand(Entity* const modelEntity, const AMFArrayValue& arguments, const std::string& command, Entity* const modelOwner);
void ProcessCommand(Entity* const modelEntity, const AMFArrayValue& arguments, const std::string_view command, Entity* const modelOwner);
/**
* @brief Gets a blocks parameter values by the name
@ -53,7 +53,7 @@ public:
*
* @return A pair of the block parameter name to its typing
*/
[[nodiscard]] std::optional<BlockDefinition> GetBlockInfo(const std::string& blockName);
[[nodiscard]] std::optional<BlockDefinition> GetBlockInfo(const std::string_view blockName);
private:
void RequestUpdatedID(ControlBehaviorContext& context);
void SendBehaviorListToClient(const ControlBehaviorContext& context);

View File

@ -13,8 +13,7 @@
*/
std::unique_ptr<AMFBaseValue> ReadFromBitStream(RakNet::BitStream& bitStream) {
AMFDeserialize deserializer;
AMFBaseValue* returnValue(deserializer.Read(bitStream));
return std::unique_ptr<AMFBaseValue>{ returnValue };
return deserializer.Read(bitStream);
}
/**
@ -254,7 +253,7 @@ TEST(dCommonTests, AMFDeserializeLivePacketTest) {
ASSERT_EQ(strips.size(), 1);
auto* stripsPosition0 = dynamic_cast<AMFArrayValue*>(strips[0]);
auto* stripsPosition0 = dynamic_cast<AMFArrayValue*>(strips[0].get());
auto* actionIndex = stripsPosition0->Get<double>("actionIndex");
@ -272,7 +271,7 @@ TEST(dCommonTests, AMFDeserializeLivePacketTest) {
ASSERT_EQ(states.size(), 1);
auto* firstState = dynamic_cast<AMFArrayValue*>(states[0]);
auto* firstState = dynamic_cast<AMFArrayValue*>(states[0].get());
auto* stateID = firstState->Get<double>("id");
@ -282,7 +281,7 @@ TEST(dCommonTests, AMFDeserializeLivePacketTest) {
ASSERT_EQ(stripsInState.size(), 1);
auto* firstStrip = dynamic_cast<AMFArrayValue*>(stripsInState[0]);
auto* firstStrip = dynamic_cast<AMFArrayValue*>(stripsInState[0].get());
auto& actionsInFirstStrip = firstStrip->GetArray("actions")->GetDense();
@ -304,7 +303,7 @@ TEST(dCommonTests, AMFDeserializeLivePacketTest) {
ASSERT_EQ(stripId->GetValue(), 0.0f);
auto* firstAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[0]);
auto* firstAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[0].get());
auto* firstType = firstAction->Get<std::string>("Type");
@ -314,7 +313,7 @@ TEST(dCommonTests, AMFDeserializeLivePacketTest) {
ASSERT_EQ(firstCallback->GetValue(), "");
auto* secondAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[1]);
auto* secondAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[1].get());
auto* secondType = secondAction->Get<std::string>("Type");
@ -328,7 +327,7 @@ TEST(dCommonTests, AMFDeserializeLivePacketTest) {
ASSERT_EQ(secondDistance->GetValue(), 25.0f);
auto* thirdAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[2]);
auto* thirdAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[2].get());
auto* thirdType = thirdAction->Get<std::string>("Type");

View File

@ -38,11 +38,11 @@ protected:
}
return readFile;
}
const AMFArrayValue& ReadArrayFromBitStream(RakNet::BitStream& inStream) {
std::unique_ptr<AMFArrayValue> ReadArrayFromBitStream(RakNet::BitStream& inStream) {
AMFDeserialize des;
AMFBaseValue* readArray = des.Read(inStream);
AMFBaseValue* readArray = des.Read(inStream).release();
EXPECT_EQ(readArray->GetValueType(), eAmf::Array);
return static_cast<AMFArrayValue&>(*readArray);
return std::unique_ptr<AMFArrayValue>{ static_cast<AMFArrayValue*>(readArray) };
}
};
@ -88,7 +88,10 @@ TEST_F(GameMessageTests, SendBlueprintLoadItemResponse) {
TEST_F(GameMessageTests, ControlBehaviorAddStrip) {
auto data = ReadFromFile("addStrip");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
AddStripMessage addStrip(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
AddStripMessage addStrip(*arr);
ASSERT_FLOAT_EQ(addStrip.GetPosition().GetX(), 50.65);
ASSERT_FLOAT_EQ(addStrip.GetPosition().GetY(), 178.05);
ASSERT_EQ(addStrip.GetActionContext().GetStripId(), 0);
@ -103,7 +106,10 @@ TEST_F(GameMessageTests, ControlBehaviorAddStrip) {
TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) {
auto data = ReadFromFile("removeStrip");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
RemoveStripMessage removeStrip(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
RemoveStripMessage removeStrip(*arr);
ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStripId()), 1);
ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStateId()), 0);
ASSERT_EQ(removeStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
@ -112,7 +118,10 @@ TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) {
TEST_F(GameMessageTests, ControlBehaviorMergeStrips) {
auto data = ReadFromFile("mergeStrips");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
MergeStripsMessage mergeStrips(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
MergeStripsMessage mergeStrips(*arr);
ASSERT_EQ(mergeStrips.GetSourceActionContext().GetStripId(), 2);
ASSERT_EQ(mergeStrips.GetDestinationActionContext().GetStripId(), 0);
ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetSourceActionContext().GetStateId()), 0);
@ -124,9 +133,11 @@ TEST_F(GameMessageTests, ControlBehaviorMergeStrips) {
TEST_F(GameMessageTests, ControlBehaviorSplitStrip) {
auto data = ReadFromFile("splitStrip");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
SplitStripMessage splitStrip(ReadArrayFromBitStream(inStream));
ASSERT_EQ(splitStrip.GetBehaviorId(), -1);
const auto arr = ReadArrayFromBitStream(inStream);
SplitStripMessage splitStrip(*arr);
ASSERT_EQ(splitStrip.GetBehaviorId(), -1);
ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetX(), 275.65);
ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetY(), 28.7);
ASSERT_EQ(splitStrip.GetSourceActionContext().GetStripId(), 0);
@ -139,7 +150,10 @@ TEST_F(GameMessageTests, ControlBehaviorSplitStrip) {
TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) {
auto data = ReadFromFile("updateStripUI");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
UpdateStripUiMessage updateStripUi(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
UpdateStripUiMessage updateStripUi(*arr);
ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetX(), 116.65);
ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetY(), 35.35);
ASSERT_EQ(updateStripUi.GetActionContext().GetStripId(), 0);
@ -150,7 +164,10 @@ TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) {
TEST_F(GameMessageTests, ControlBehaviorAddAction) {
auto data = ReadFromFile("addAction");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
AddActionMessage addAction(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
AddActionMessage addAction(*arr);
ASSERT_EQ(addAction.GetActionIndex(), 3);
ASSERT_EQ(addAction.GetActionContext().GetStripId(), 0);
ASSERT_EQ(static_cast<uint32_t>(addAction.GetActionContext().GetStateId()), 0);
@ -164,7 +181,10 @@ TEST_F(GameMessageTests, ControlBehaviorAddAction) {
TEST_F(GameMessageTests, ControlBehaviorMigrateActions) {
auto data = ReadFromFile("migrateActions");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
MigrateActionsMessage migrateActions(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
MigrateActionsMessage migrateActions(*arr);
ASSERT_EQ(migrateActions.GetSrcActionIndex(), 1);
ASSERT_EQ(migrateActions.GetDstActionIndex(), 2);
ASSERT_EQ(migrateActions.GetSourceActionContext().GetStripId(), 1);
@ -177,7 +197,10 @@ TEST_F(GameMessageTests, ControlBehaviorMigrateActions) {
TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) {
auto data = ReadFromFile("rearrangeStrip");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
RearrangeStripMessage rearrangeStrip(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
RearrangeStripMessage rearrangeStrip(*arr);
ASSERT_EQ(rearrangeStrip.GetSrcActionIndex(), 2);
ASSERT_EQ(rearrangeStrip.GetDstActionIndex(), 1);
ASSERT_EQ(rearrangeStrip.GetActionContext().GetStripId(), 0);
@ -188,7 +211,10 @@ TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) {
TEST_F(GameMessageTests, ControlBehaviorAdd) {
auto data = ReadFromFile("add");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
AddMessage add(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
AddMessage add(*arr);
ASSERT_EQ(add.GetBehaviorId(), 10446);
ASSERT_EQ(add.GetBehaviorIndex(), 0);
}
@ -196,7 +222,10 @@ TEST_F(GameMessageTests, ControlBehaviorAdd) {
TEST_F(GameMessageTests, ControlBehaviorRemoveActions) {
auto data = ReadFromFile("removeActions");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
RemoveActionsMessage removeActions(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
RemoveActionsMessage removeActions(*arr);
ASSERT_EQ(removeActions.GetBehaviorId(), -1);
ASSERT_EQ(removeActions.GetActionIndex(), 1);
ASSERT_EQ(removeActions.GetActionContext().GetStripId(), 0);
@ -206,7 +235,10 @@ TEST_F(GameMessageTests, ControlBehaviorRemoveActions) {
TEST_F(GameMessageTests, ControlBehaviorRename) {
auto data = ReadFromFile("rename");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
RenameMessage rename(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
RenameMessage rename(*arr);
ASSERT_EQ(rename.GetName(), "test");
ASSERT_EQ(rename.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId);
}
@ -214,7 +246,10 @@ TEST_F(GameMessageTests, ControlBehaviorRename) {
TEST_F(GameMessageTests, ControlBehaviorUpdateAction) {
auto data = ReadFromFile("updateAction");
RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true);
UpdateActionMessage updateAction(ReadArrayFromBitStream(inStream));
const auto arr = ReadArrayFromBitStream(inStream);
UpdateActionMessage updateAction(*arr);
ASSERT_EQ(updateAction.GetAction().GetType(), "FlyDown");
ASSERT_EQ(updateAction.GetAction().GetValueParameterName(), "Distance");
ASSERT_EQ(updateAction.GetAction().GetValueParameterString(), "");