Compare commits

..

29 Commits

Author SHA1 Message Date
Jett
844516f159 Update build-and-test.yml 2023-05-13 20:43:14 +01:00
Jett
677a0c9bdb Update versions.txt 2023-05-10 11:26:04 +01:00
Jett
ff95a37b20 Update versions.txt 2023-05-10 11:05:23 +01:00
Jett
40a5d5ebab Update publishing.yml 2023-05-10 11:04:48 +01:00
Jett
bd8e519479 Update versions.txt 2023-05-10 10:32:31 +01:00
Jett
669785577a Update publishing.yml 2023-05-10 10:31:50 +01:00
Jett
031fd237be Update versions.txt 2023-05-10 00:17:37 +01:00
Jett
0655a1d64f Update publishing.yml 2023-05-10 00:16:55 +01:00
Jett
d5c1840f70 Update versions.txt 2023-05-10 00:04:45 +01:00
Jett
4b86312317 Update publishing.yml 2023-05-10 00:04:36 +01:00
Jett
1934c112f2 Update versions.txt 2023-05-09 23:46:00 +01:00
Jett
bb4fa39d12 Update publishing.yml 2023-05-09 23:45:33 +01:00
Jett
a94729afb7 Update versions.txt 2023-05-09 23:28:55 +01:00
Jett
180b1d1bfc Update publishing.yml 2023-05-09 23:28:38 +01:00
Jett
f4bb7c8b0c Update versions.txt 2023-05-09 23:16:27 +01:00
Jett
4ee3db2c64 Update publishing.yml 2023-05-09 23:15:26 +01:00
Jett
208af68ca0 Update versions.txt 2023-05-09 23:02:07 +01:00
Jett
4212e56654 Update publishing.yml 2023-05-09 22:59:01 +01:00
Jett
20faad8f14 Update versions.txt 2023-05-09 22:42:33 +01:00
Jett
66b5dd0d54 Update publishing.yml 2023-05-09 22:42:16 +01:00
Jett
912999ff7f Update versions.txt 2023-05-09 22:33:34 +01:00
Jett
2965bd8f8c Update publishing.yml 2023-05-09 22:33:15 +01:00
Jett
be66da0fb0 Update versions.txt 2023-05-09 22:18:39 +01:00
Jett
d38aec016b Update publishing.yml 2023-05-09 22:18:21 +01:00
Jett
2aa029d598 Update versions.txt 2023-05-09 21:55:36 +01:00
Jett
00647a45a9 Update publishing.yml 2023-05-09 21:55:09 +01:00
Jett
eec595594c Update versions.txt 2023-05-09 21:33:29 +01:00
Jett
a16b8a2339 Update publishing.yml 2023-05-09 21:33:13 +01:00
Jett
f1bf3b25dc Create publishing.yml 2023-05-09 21:32:50 +01:00
330 changed files with 3196 additions and 2848 deletions

View File

@@ -2,9 +2,9 @@ name: CI
on:
push:
branches: [ main ]
branches: [ main, automation ]
pull_request:
branches: [ main ]
branches: [ main, automation ]
jobs:
build-and-test:

116
.github/workflows/publishing.yml vendored Normal file
View File

@@ -0,0 +1,116 @@
name: CI
on:
push:
paths:
- versions.txt
jobs:
build-and-test:
name: Build & Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
continue-on-error: true
strategy:
matrix:
os: [ windows-2022, ubuntu-20.04, macos-11 ]
steps:
- uses: actions/checkout@v3
with:
submodules: true
- name: Add msbuild to PATH (Windows only)
if: ${{ matrix.os == 'windows-2022' }}
uses: microsoft/setup-msbuild@v1.1
with:
vs-version: '[17,18)'
msbuild-architecture: x64
- name: Install libssl (Mac Only)
if: ${{ matrix.os == 'macos-11' }}
run: brew install openssl@3
- name: cmake
uses: lukka/run-cmake@v10
with:
configurePreset: "ci-${{matrix.os}}"
buildPreset: "ci-${{matrix.os}}"
testPreset: "ci-${{matrix.os}}"
- name: artifacts
uses: actions/upload-artifact@v3
with:
name: build-${{matrix.os}}
path: |
build/*Server*
build/*.ini
build/*.so
build/*.dll
build/vanity/
build/navmeshes/
build/migrations/
build/*.dcf
!build/*.pdb
!build/d*/
draft-release:
needs: build-and-test
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Get Previous Tag
id: previoustag
uses: "WyriHaximus/github-action-get-previous-tag@v1"
with:
fallback: v1.0
- name: Generate Changelog
uses: Bullrich/generate-release-changelog@master
id: changelog
env:
REPO: ${{ github.repository }}
with:
from-tag: ${{ steps.previoustag.outputs.tag }}
to-tag: HEAD
- name: Take a gander at versions.txt to get updated information
run: |
IFS=" - " read -ra PARTS <<< "$(head -n 1 versions.txt)"
echo "VERSION=${PARTS[0]}" >> $GITHUB_ENV
echo "DESCRIPTION=$(IFS=' '; echo "${PARTS[*]:1}")" >> $GITHUB_ENV
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ env.VERSION }}
release_name: Release v${{ env.VERSION }}
body: "Draft release for version v${{ env.VERSION }} \n\n ${{ env.DESCRIPTION }} \n\n ${{ steps.changelog.outputs.changelog }}"
draft: true
- name: Download all workflow run artifacts
uses: actions/download-artifact@v3
with:
path: artifacts
- name: Upload Release Assets
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cd artifacts
for folder in */; do
zip -r "${folder%/}.zip" "$folder"
done
ls
for file in *.zip; do
echo "Uploading $file"
curl --progress-bar \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: token ${{ env.GITHUB_TOKEN }}" \
--upload-file "$file" \
-H "Content-Type: $(file --mime-type -b $file)" \
"https://uploads.github.com/repos/${{ github.repository }}/releases/${{ steps.create_release.outputs.id }}/assets?name=$(basename $file)"
done

View File

@@ -338,7 +338,7 @@ This is a Work in Progress, but below are some quick links to documentaion for s
## Former Contributors
* TheMachine
* Matthew
* [Raine](https://github.com/uwainium)
* [Raine](https://github.com/Rainebannister)
* Bricknave
## Special Thanks

View File

@@ -1,79 +1,77 @@
#include "AMFDeserialize.h"
#include <stdexcept>
#include "Amf3.h"
#include "AMFFormat.h"
/**
* AMF3 Reference document https://rtmp.veriskope.com/pdf/amf3-file-format-spec.pdf
* AMF3 Deserializer written by EmosewaMC
*/
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
AMFValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
if (!inStream) return nullptr;
AMFBaseValue* returnValue = nullptr;
AMFValue* returnValue = nullptr;
// Read in the value type from the bitStream
eAmf marker;
int8_t 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();
case AMFValueType::AMFUndefined: {
returnValue = new AMFUndefinedValue();
break;
}
case eAmf::Null: {
case AMFValueType::AMFNull: {
returnValue = new AMFNullValue();
break;
}
case eAmf::False: {
returnValue = new AMFBoolValue(false);
case AMFValueType::AMFFalse: {
returnValue = new AMFFalseValue();
break;
}
case eAmf::True: {
returnValue = new AMFBoolValue(true);
case AMFValueType::AMFTrue: {
returnValue = new AMFTrueValue();
break;
}
case eAmf::Integer: {
case AMFValueType::AMFInteger: {
returnValue = ReadAmfInteger(inStream);
break;
}
case eAmf::Double: {
case AMFValueType::AMFDouble: {
returnValue = ReadAmfDouble(inStream);
break;
}
case eAmf::String: {
case AMFValueType::AMFString: {
returnValue = ReadAmfString(inStream);
break;
}
case eAmf::Array: {
case AMFValueType::AMFArray: {
returnValue = ReadAmfArray(inStream);
break;
}
// 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:
case eAmf::Date:
case eAmf::Object:
case eAmf::XML:
case eAmf::ByteArray:
case eAmf::VectorInt:
case eAmf::VectorUInt:
case eAmf::VectorDouble:
case eAmf::VectorObject:
case eAmf::Dictionary: {
throw marker;
// TODO We do not need these values, but if someone wants to implement them
// then please do so and add the corresponding unit tests.
case AMFValueType::AMFXMLDoc:
case AMFValueType::AMFDate:
case AMFValueType::AMFObject:
case AMFValueType::AMFXML:
case AMFValueType::AMFByteArray:
case AMFValueType::AMFVectorInt:
case AMFValueType::AMFVectorUInt:
case AMFValueType::AMFVectorDouble:
case AMFValueType::AMFVectorObject:
case AMFValueType::AMFDictionary: {
throw static_cast<AMFValueType>(marker);
break;
}
default:
throw std::invalid_argument("Invalid AMF3 marker" + std::to_string(static_cast<int32_t>(marker)));
throw static_cast<AMFValueType>(marker);
break;
}
return returnValue;
@@ -101,7 +99,7 @@ uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
return actualNumber;
}
const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
auto length = ReadU29(inStream);
// Check if this is a reference
bool isReference = length % 2 == 1;
@@ -115,39 +113,48 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
return value;
} else {
// Length is a reference to a previous index - use that as the read in value
return accessedElements.at(length);
return accessedElements[length];
}
}
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
AMFValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
auto doubleValue = new AMFDoubleValue();
double value;
inStream->Read<double>(value);
return new AMFDoubleValue(value);
doubleValue->SetDoubleValue(value);
return doubleValue;
}
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
AMFValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
auto arrayValue = new AMFArrayValue();
// Read size of dense array
auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
// Then read associative portion
// Then read Key'd portion
while (true) {
auto key = ReadString(inStream);
// No more associative values when we encounter an empty string key
// No more values when we encounter an empty string
if (key.size() == 0) break;
arrayValue->Insert(key, Read(inStream));
arrayValue->InsertValue(key, Read(inStream));
}
// Finally read dense portion
for (uint32_t i = 0; i < sizeOfDenseArray; i++) {
arrayValue->Insert(i, Read(inStream));
arrayValue->PushBackValue(Read(inStream));
}
return arrayValue;
}
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
return new AMFStringValue(ReadString(inStream));
AMFValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
auto stringValue = new AMFStringValue();
stringValue->SetStringValue(ReadString(inStream));
return stringValue;
}
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
return new AMFIntValue(ReadU29(inStream));
AMFValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
auto integerValue = new AMFIntegerValue();
integerValue->SetIntegerValue(ReadU29(inStream));
return integerValue;
}

View File

@@ -5,8 +5,7 @@
#include <vector>
#include <string>
class AMFBaseValue;
class AMFValue;
class AMFDeserialize {
public:
/**
@@ -15,7 +14,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);
AMFValue* Read(RakNet::BitStream* inStream);
private:
/**
* @brief Private method to read a U29 integer from a bitstream
@@ -31,7 +30,7 @@ private:
* @param inStream bitStream to read data from
* @return The read string
*/
const std::string ReadString(RakNet::BitStream* inStream);
std::string ReadString(RakNet::BitStream* inStream);
/**
* @brief Read an AMFDouble value from a bitStream
@@ -39,7 +38,7 @@ private:
* @param inStream bitStream to read data from
* @return Double value represented as an AMFValue
*/
AMFBaseValue* ReadAmfDouble(RakNet::BitStream* inStream);
AMFValue* ReadAmfDouble(RakNet::BitStream* inStream);
/**
* @brief Read an AMFArray from a bitStream
@@ -47,7 +46,7 @@ private:
* @param inStream bitStream to read data from
* @return Array value represented as an AMFValue
*/
AMFBaseValue* ReadAmfArray(RakNet::BitStream* inStream);
AMFValue* ReadAmfArray(RakNet::BitStream* inStream);
/**
* @brief Read an AMFString from a bitStream
@@ -55,7 +54,7 @@ private:
* @param inStream bitStream to read data from
* @return String value represented as an AMFValue
*/
AMFBaseValue* ReadAmfString(RakNet::BitStream* inStream);
AMFValue* ReadAmfString(RakNet::BitStream* inStream);
/**
* @brief Read an AMFInteger from a bitStream
@@ -63,7 +62,7 @@ private:
* @param inStream bitStream to read data from
* @return Integer value represented as an AMFValue
*/
AMFBaseValue* ReadAmfInteger(RakNet::BitStream* inStream);
AMFValue* ReadAmfInteger(RakNet::BitStream* inStream);
/**
* List of strings read so far saved to be read by reference.

156
dCommon/AMFFormat.cpp Normal file
View File

@@ -0,0 +1,156 @@
#include "AMFFormat.h"
// AMFInteger
void AMFIntegerValue::SetIntegerValue(uint32_t value) {
this->value = value;
}
uint32_t AMFIntegerValue::GetIntegerValue() {
return this->value;
}
// AMFDouble
void AMFDoubleValue::SetDoubleValue(double value) {
this->value = value;
}
double AMFDoubleValue::GetDoubleValue() {
return this->value;
}
// AMFString
void AMFStringValue::SetStringValue(const std::string& value) {
this->value = value;
}
std::string AMFStringValue::GetStringValue() {
return this->value;
}
// AMFXMLDoc
void AMFXMLDocValue::SetXMLDocValue(const std::string& value) {
this->xmlData = value;
}
std::string AMFXMLDocValue::GetXMLDocValue() {
return this->xmlData;
}
// AMFDate
void AMFDateValue::SetDateValue(uint64_t value) {
this->millisecondTimestamp = value;
}
uint64_t AMFDateValue::GetDateValue() {
return this->millisecondTimestamp;
}
// AMFArray Insert Value
void AMFArrayValue::InsertValue(const std::string& key, AMFValue* value) {
this->associative.insert(std::make_pair(key, value));
}
// AMFArray Remove Value
void AMFArrayValue::RemoveValue(const std::string& key) {
_AMFArrayMap_::iterator it = this->associative.find(key);
if (it != this->associative.end()) {
this->associative.erase(it);
}
}
// AMFArray Get Associative Iterator Begin
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueBegin() {
return this->associative.begin();
}
// AMFArray Get Associative Iterator End
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueEnd() {
return this->associative.end();
}
// AMFArray Push Back Value
void AMFArrayValue::PushBackValue(AMFValue* value) {
this->dense.push_back(value);
}
// AMFArray Pop Back Value
void AMFArrayValue::PopBackValue() {
this->dense.pop_back();
}
// AMFArray Get Dense List Size
uint32_t AMFArrayValue::GetDenseValueSize() {
return (uint32_t)this->dense.size();
}
// AMFArray Get Dense Iterator Begin
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorBegin() {
return this->dense.begin();
}
// AMFArray Get Dense Iterator End
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorEnd() {
return this->dense.end();
}
AMFArrayValue::~AMFArrayValue() {
for (auto valueToDelete : GetDenseArray()) {
if (valueToDelete) delete valueToDelete;
}
for (auto valueToDelete : GetAssociativeMap()) {
if (valueToDelete.second) delete valueToDelete.second;
}
}
// AMFObject Constructor
AMFObjectValue::AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits) {
this->traits.reserve(traits.size());
std::vector<std::pair<std::string, AMFValueType>>::iterator it = traits.begin();
while (it != traits.end()) {
this->traits.insert(std::make_pair(it->first, std::make_pair(it->second, new AMFNullValue())));
it++;
}
}
// AMFObject Set Value
void AMFObjectValue::SetTraitValue(const std::string& trait, AMFValue* value) {
if (value) {
_AMFObjectTraits_::iterator it = this->traits.find(trait);
if (it != this->traits.end()) {
if (it->second.first == value->GetValueType()) {
it->second.second = value;
}
}
}
}
// AMFObject Get Value
AMFValue* AMFObjectValue::GetTraitValue(const std::string& trait) {
_AMFObjectTraits_::iterator it = this->traits.find(trait);
if (it != this->traits.end()) {
return it->second.second;
}
return nullptr;
}
// AMFObject Get Trait Iterator Begin
_AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorBegin() {
return this->traits.begin();
}
// AMFObject Get Trait Iterator End
_AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorEnd() {
return this->traits.end();
}
// AMFObject Get Trait Size
uint32_t AMFObjectValue::GetTraitArrayCount() {
return (uint32_t)this->traits.size();
}
AMFObjectValue::~AMFObjectValue() {
for (auto valueToDelete = GetTraitsIteratorBegin(); valueToDelete != GetTraitsIteratorEnd(); valueToDelete++) {
if (valueToDelete->second.second) delete valueToDelete->second.second;
}
}

413
dCommon/AMFFormat.h Normal file
View File

@@ -0,0 +1,413 @@
#pragma once
// Custom Classes
#include "dCommonVars.h"
// C++
#include <unordered_map>
#include <vector>
/*!
\file AMFFormat.hpp
\brief A class for managing AMF values
*/
class AMFValue; // Forward declaration
// Definitions
#define _AMFArrayMap_ std::unordered_map<std::string, AMFValue*>
#define _AMFArrayList_ std::vector<AMFValue*>
#define _AMFObjectTraits_ std::unordered_map<std::string, std::pair<AMFValueType, AMFValue*>>
#define _AMFObjectDynamicTraits_ std::unordered_map<std::string, AMFValue*>
//! An enum for each AMF value type
enum AMFValueType : unsigned char {
AMFUndefined = 0x00, //!< An undefined AMF Value
AMFNull = 0x01, //!< A null AMF value
AMFFalse = 0x02, //!< A false AMF value
AMFTrue = 0x03, //!< A true AMF value
AMFInteger = 0x04, //!< An integer AMF value
AMFDouble = 0x05, //!< A double AMF value
AMFString = 0x06, //!< A string AMF value
AMFXMLDoc = 0x07, //!< An XML Doc AMF value
AMFDate = 0x08, //!< A date AMF value
AMFArray = 0x09, //!< An array AMF value
AMFObject = 0x0A, //!< An object AMF value
AMFXML = 0x0B, //!< An XML AMF value
AMFByteArray = 0x0C, //!< A byte array AMF value
AMFVectorInt = 0x0D, //!< An integer vector AMF value
AMFVectorUInt = 0x0E, //!< An unsigned integer AMF value
AMFVectorDouble = 0x0F, //!< A double vector AMF value
AMFVectorObject = 0x10, //!< An object vector AMF value
AMFDictionary = 0x11 //!< A dictionary AMF value
};
//! An enum for the object value types
enum AMFObjectValueType : unsigned char {
AMFObjectAnonymous = 0x01,
AMFObjectTyped = 0x02,
AMFObjectDynamic = 0x03,
AMFObjectExternalizable = 0x04
};
//! The base AMF value class
class AMFValue {
public:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
virtual AMFValueType GetValueType() = 0;
virtual ~AMFValue() {};
};
//! A typedef for a pointer to an AMF value
typedef AMFValue* NDGFxValue;
// The various AMF value types
//! The undefined value AMF type
class AMFUndefinedValue : public AMFValue {
private:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFUndefined;
};
//! The null value AMF type
class AMFNullValue : public AMFValue {
private:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFNull;
};
//! The false value AMF type
class AMFFalseValue : public AMFValue {
private:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFFalse;
};
//! The true value AMF type
class AMFTrueValue : public AMFValue {
private:
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFTrue;
};
//! The integer value AMF type
class AMFIntegerValue : public AMFValue {
private:
uint32_t value; //!< The value of the AMF type
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFInteger;
//! Sets the integer value
/*!
\param value The value to set
*/
void SetIntegerValue(uint32_t value);
//! Gets the integer value
/*!
\return The integer value
*/
uint32_t GetIntegerValue();
};
//! The double value AMF type
class AMFDoubleValue : public AMFValue {
private:
double value; //!< The value of the AMF type
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFDouble;
//! Sets the double value
/*!
\param value The value to set to
*/
void SetDoubleValue(double value);
//! Gets the double value
/*!
\return The double value
*/
double GetDoubleValue();
};
//! The string value AMF type
class AMFStringValue : public AMFValue {
private:
std::string value; //!< The value of the AMF type
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFString;
//! Sets the string value
/*!
\param value The string value to set to
*/
void SetStringValue(const std::string& value);
//! Gets the string value
/*!
\return The string value
*/
std::string GetStringValue();
};
//! The XML doc value AMF type
class AMFXMLDocValue : public AMFValue {
private:
std::string xmlData; //!< The value of the AMF type
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFXMLDoc;
//! Sets the XML Doc value
/*!
\param value The value to set to
*/
void SetXMLDocValue(const std::string& value);
//! Gets the XML Doc value
/*!
\return The XML Doc value
*/
std::string GetXMLDocValue();
};
//! The date value AMF type
class AMFDateValue : public AMFValue {
private:
uint64_t millisecondTimestamp; //!< The time in milliseconds since the ephoch
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() { return ValueType; }
public:
static const AMFValueType ValueType = AMFDate;
//! Sets the date time
/*!
\param value The value to set to
*/
void SetDateValue(uint64_t value);
//! Gets the date value
/*!
\return The date value in milliseconds since the epoch
*/
uint64_t GetDateValue();
};
//! The array value AMF type
// This object will manage it's own memory map and list. Do not delete its values.
class AMFArrayValue : public AMFValue {
private:
_AMFArrayMap_ associative; //!< The array map (associative part)
_AMFArrayList_ dense; //!< The array list (dense part)
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() override { return ValueType; }
public:
static const AMFValueType ValueType = AMFArray;
~AMFArrayValue() override;
//! Inserts an item into the array map for a specific key
/*!
\param key The key to set
\param value The value to add
*/
void InsertValue(const std::string& key, AMFValue* value);
//! Removes an item for a specific key
/*!
\param key The key to remove
*/
void RemoveValue(const std::string& key);
//! Finds an AMF value
/*!
\return The AMF value if found, nullptr otherwise
*/
template <typename T>
T* FindValue(const std::string& key) const {
_AMFArrayMap_::const_iterator it = this->associative.find(key);
if (it != this->associative.end() && T::ValueType == it->second->GetValueType()) {
return dynamic_cast<T*>(it->second);
}
return nullptr;
};
//! Returns where the associative iterator begins
/*!
\return Where the array map iterator begins
*/
_AMFArrayMap_::iterator GetAssociativeIteratorValueBegin();
//! Returns where the associative iterator ends
/*!
\return Where the array map iterator ends
*/
_AMFArrayMap_::iterator GetAssociativeIteratorValueEnd();
//! Pushes back a value into the array list
/*!
\param value The value to push back
*/
void PushBackValue(AMFValue* value);
//! Pops back the last value in the array list
void PopBackValue();
//! Gets the count of the dense list
/*!
\return The dense list size
*/
uint32_t GetDenseValueSize();
//! Gets a specific value from the list for the specified index
/*!
\param index The index to get
*/
template <typename T>
T* GetValueAt(uint32_t index) {
if (index >= this->dense.size()) return nullptr;
AMFValue* foundValue = this->dense.at(index);
return T::ValueType == foundValue->GetValueType() ? dynamic_cast<T*>(foundValue) : nullptr;
};
//! Returns where the dense iterator begins
/*!
\return Where the iterator begins
*/
_AMFArrayList_::iterator GetDenseIteratorBegin();
//! Returns where the dense iterator ends
/*!
\return Where the iterator ends
*/
_AMFArrayList_::iterator GetDenseIteratorEnd();
//! Returns the associative map
/*!
\return The associative map
*/
_AMFArrayMap_ GetAssociativeMap() { return this->associative; };
//! Returns the dense array
/*!
\return The dense array
*/
_AMFArrayList_ GetDenseArray() { return this->dense; };
};
//! The anonymous object value AMF type
class AMFObjectValue : public AMFValue {
private:
_AMFObjectTraits_ traits; //!< The object traits
//! Returns the AMF value type
/*!
\return The AMF value type
*/
AMFValueType GetValueType() override { return ValueType; }
~AMFObjectValue() override;
public:
static const AMFValueType ValueType = AMFObject;
//! Constructor
/*!
\param traits The traits to set
*/
AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits);
//! Gets the object value type
/*!
\return The object value type
*/
virtual AMFObjectValueType GetObjectValueType() { return AMFObjectAnonymous; }
//! Sets the value of a trait
/*!
\param trait The trait to set the value for
\param value The AMF value to set
*/
void SetTraitValue(const std::string& trait, AMFValue* value);
//! Gets a trait value
/*!
\param trait The trait to get the value for
\return The trait value
*/
AMFValue* GetTraitValue(const std::string& trait);
//! Gets the beginning of the object traits iterator
/*!
\return The AMF trait array iterator begin
*/
_AMFObjectTraits_::iterator GetTraitsIteratorBegin();
//! Gets the end of the object traits iterator
/*!
\return The AMF trait array iterator begin
*/
_AMFObjectTraits_::iterator GetTraitsIteratorEnd();
//! Gets the amount of traits
/*!
\return The amount of traits
*/
uint32_t GetTraitArrayCount();
};

View File

@@ -0,0 +1,259 @@
#include "AMFFormat_BitStream.h"
// Writes an AMFValue pointer to a RakNet::BitStream
template<>
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
if (value != nullptr) {
AMFValueType type = value->GetValueType();
switch (type) {
case AMFUndefined: {
AMFUndefinedValue* v = (AMFUndefinedValue*)value;
this->Write(*v);
break;
}
case AMFNull: {
AMFNullValue* v = (AMFNullValue*)value;
this->Write(*v);
break;
}
case AMFFalse: {
AMFFalseValue* v = (AMFFalseValue*)value;
this->Write(*v);
break;
}
case AMFTrue: {
AMFTrueValue* v = (AMFTrueValue*)value;
this->Write(*v);
break;
}
case AMFInteger: {
AMFIntegerValue* v = (AMFIntegerValue*)value;
this->Write(*v);
break;
}
case AMFDouble: {
AMFDoubleValue* v = (AMFDoubleValue*)value;
this->Write(*v);
break;
}
case AMFString: {
AMFStringValue* v = (AMFStringValue*)value;
this->Write(*v);
break;
}
case AMFXMLDoc: {
AMFXMLDocValue* v = (AMFXMLDocValue*)value;
this->Write(*v);
break;
}
case AMFDate: {
AMFDateValue* v = (AMFDateValue*)value;
this->Write(*v);
break;
}
case AMFArray: {
this->Write((AMFArrayValue*)value);
break;
}
case AMFObject:
case AMFXML:
case AMFByteArray:
case AMFVectorInt:
case AMFVectorUInt:
case AMFVectorDouble:
case AMFVectorObject:
case AMFDictionary:
break;
}
}
}
/**
* A private function to write an value to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
unsigned char b4 = (unsigned char)v;
if (v < 0x00200000) {
b4 = b4 & 0x7F;
if (v > 0x7F) {
unsigned char b3;
v = v >> 7;
b3 = ((unsigned char)(v)) | 0x80;
if (v > 0x7F) {
unsigned char b2;
v = v >> 7;
b2 = ((unsigned char)(v)) | 0x80;
bs->Write(b2);
}
bs->Write(b3);
}
} else {
unsigned char b1;
unsigned char b2;
unsigned char b3;
v = v >> 8;
b3 = ((unsigned char)(v)) | 0x80;
v = v >> 7;
b2 = ((unsigned char)(v)) | 0x80;
v = v >> 7;
b1 = ((unsigned char)(v)) | 0x80;
bs->Write(b1);
bs->Write(b2);
bs->Write(b3);
}
bs->Write(b4);
}
/**
* Writes a flag number to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
v = (v << 1) | 0x01;
WriteUInt29(bs, v);
}
/**
* Writes an AMFString to a RakNet::BitStream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
WriteFlagNumber(bs, (uint32_t)str.size());
bs->Write(str.c_str(), (uint32_t)str.size());
}
/**
* Writes an U16 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
bs->Write(value);
}
/**
* Writes an U32 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
bs->Write(value);
}
/**
* Writes an U64 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
bs->Write(value);
}
// Writes an AMFUndefinedValue to BitStream
template<>
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value) {
this->Write(AMFUndefined);
}
// Writes an AMFNullValue to BitStream
template<>
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value) {
this->Write(AMFNull);
}
// Writes an AMFFalseValue to BitStream
template<>
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value) {
this->Write(AMFFalse);
}
// Writes an AMFTrueValue to BitStream
template<>
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value) {
this->Write(AMFTrue);
}
// Writes an AMFIntegerValue to BitStream
template<>
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value) {
this->Write(AMFInteger);
WriteUInt29(this, value.GetIntegerValue());
}
// Writes an AMFDoubleValue to BitStream
template<>
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value) {
this->Write(AMFDouble);
double d = value.GetDoubleValue();
WriteAMFU64(this, *((unsigned long long*) & d));
}
// Writes an AMFStringValue to BitStream
template<>
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value) {
this->Write(AMFString);
std::string v = value.GetStringValue();
WriteAMFString(this, v);
}
// Writes an AMFXMLDocValue to BitStream
template<>
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value) {
this->Write(AMFXMLDoc);
std::string v = value.GetXMLDocValue();
WriteAMFString(this, v);
}
// Writes an AMFDateValue to BitStream
template<>
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value) {
this->Write(AMFDate);
uint64_t date = value.GetDateValue();
WriteAMFU64(this, date);
}
// Writes an AMFArrayValue to BitStream
template<>
void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value) {
this->Write(AMFArray);
uint32_t denseSize = value->GetDenseValueSize();
WriteFlagNumber(this, denseSize);
_AMFArrayMap_::iterator it = value->GetAssociativeIteratorValueBegin();
_AMFArrayMap_::iterator end = value->GetAssociativeIteratorValueEnd();
while (it != end) {
WriteAMFString(this, it->first);
this->Write(it->second);
it++;
}
this->Write(AMFNull);
if (denseSize > 0) {
_AMFArrayList_::iterator it2 = value->GetDenseIteratorBegin();
_AMFArrayList_::iterator end2 = value->GetDenseIteratorEnd();
while (it2 != end2) {
this->Write(*it2);
it2++;
}
}
}

View File

@@ -0,0 +1,92 @@
#pragma once
// Custom Classes
#include "AMFFormat.h"
// RakNet
#include <BitStream.h>
/*!
\file AMFFormat_BitStream.h
\brief A class that implements native writing of AMF values to RakNet::BitStream
*/
// We are using the RakNet namespace
namespace RakNet {
//! Writes an AMFValue pointer to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value);
//! Writes an AMFUndefinedValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value);
//! Writes an AMFNullValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value);
//! Writes an AMFFalseValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value);
//! Writes an AMFTrueValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value);
//! Writes an AMFIntegerValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value);
//! Writes an AMFDoubleValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value);
//! Writes an AMFStringValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value);
//! Writes an AMFXMLDocValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value);
//! Writes an AMFDateValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value);
//! Writes an AMFArrayValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value);
} // namespace RakNet

View File

@@ -1,367 +0,0 @@
#ifndef __AMF3__H__
#define __AMF3__H__
#include "dCommonVars.h"
#include "dLogger.h"
#include "Game.h"
#include <unordered_map>
#include <vector>
enum class eAmf : uint8_t {
Undefined = 0x00, // An undefined AMF Value
Null = 0x01, // A null AMF value
False = 0x02, // A false AMF value
True = 0x03, // A true AMF value
Integer = 0x04, // An integer AMF value
Double = 0x05, // A double AMF value
String = 0x06, // A string AMF value
XMLDoc = 0x07, // Unused in the live client and cannot be serialized without modification. An XML Doc AMF value
Date = 0x08, // Unused in the live client and cannot be serialized without modification. A date AMF value
Array = 0x09, // An array AMF value
Object = 0x0A, // Unused in the live client and cannot be serialized without modification. An object AMF value
XML = 0x0B, // Unused in the live client and cannot be serialized without modification. An XML AMF value
ByteArray = 0x0C, // Unused in the live client and cannot be serialized without modification. A byte array AMF value
VectorInt = 0x0D, // Unused in the live client and cannot be serialized without modification. An integer vector AMF value
VectorUInt = 0x0E, // Unused in the live client and cannot be serialized without modification. An unsigned integer AMF value
VectorDouble = 0x0F, // Unused in the live client and cannot be serialized without modification. A double vector AMF value
VectorObject = 0x10, // Unused in the live client and cannot be serialized without modification. An object vector AMF value
Dictionary = 0x11 // Unused in the live client and cannot be serialized without modification. A dictionary AMF value
};
class AMFBaseValue {
public:
virtual eAmf GetValueType() { return eAmf::Undefined; };
AMFBaseValue() {};
virtual ~AMFBaseValue() {};
};
template<typename ValueType>
class AMFValue : public AMFBaseValue {
public:
AMFValue() {};
AMFValue(ValueType value) { SetValue(value); };
virtual ~AMFValue() override {};
eAmf GetValueType() override { return eAmf::Undefined; };
const ValueType& GetValue() { return data; };
void SetValue(ValueType value) { data = value; };
protected:
ValueType data;
};
// As a string this is much easier to write and read from a BitStream.
template<>
class AMFValue<const char*> : public AMFBaseValue {
public:
AMFValue() {};
AMFValue(const char* value) { SetValue(std::string(value)); };
virtual ~AMFValue() override {};
eAmf GetValueType() override { return eAmf::String; };
const std::string& GetValue() { return data; };
void SetValue(std::string value) { data = value; };
protected:
std::string data;
};
typedef AMFValue<std::nullptr_t> AMFNullValue;
typedef AMFValue<bool> AMFBoolValue;
typedef AMFValue<int32_t> AMFIntValue;
typedef AMFValue<std::string> AMFStringValue;
typedef AMFValue<double> AMFDoubleValue;
template<> inline eAmf AMFValue<std::nullptr_t>::GetValueType() { return eAmf::Null; };
template<> inline eAmf AMFValue<bool>::GetValueType() { return this->data ? eAmf::True : eAmf::False; };
template<> inline eAmf AMFValue<int32_t>::GetValueType() { return eAmf::Integer; };
template<> inline eAmf AMFValue<uint32_t>::GetValueType() { return eAmf::Integer; };
template<> inline eAmf AMFValue<std::string>::GetValueType() { return eAmf::String; };
template<> inline eAmf AMFValue<double>::GetValueType() { return eAmf::Double; };
/**
* The AMFArrayValue object holds 2 types of lists:
* An associative list where a key maps to a value
* A Dense list where elements are stored back to back
*
* Objects that are Registered are owned by this object
* and are not to be deleted by a caller.
*/
class AMFArrayValue : public AMFBaseValue {
typedef std::unordered_map<std::string, AMFBaseValue*> AMFAssociative;
typedef std::vector<AMFBaseValue*> AMFDense;
public:
eAmf GetValueType() override { return eAmf::Array; };
~AMFArrayValue() override {
for (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
*/
inline AMFAssociative& GetAssociative() { return this->associative; };
/**
* Returns the dense portion of the object
*/
inline AMFDense& GetDense() { return this->dense; };
/**
* Inserts an AMFValue into the associative portion with the given key.
* If a duplicate is attempted to be inserted, it is ignored and the
* first value with that key is kept in the map.
*
* These objects are not to be deleted by the caller as they are owned by
* the AMFArray object which manages its own memory.
*
* @param key The key to associate with the value
* @param value The value to insert
*
* @return The inserted element if the type matched,
* or nullptr if a key existed and was not the same type
*/
template<typename ValueType>
std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, ValueType value) {
auto element = associative.find(key);
AMFValue<ValueType>* val = nullptr;
bool found = true;
if (element == associative.end()) {
val = new AMFValue<ValueType>(value);
associative.insert(std::make_pair(key, val));
} else {
val = dynamic_cast<AMFValue<ValueType>*>(element->second);
found = false;
}
return std::make_pair(val, found);
};
// Associates an array with a string key
std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
auto element = associative.find(key);
AMFArrayValue* val = nullptr;
bool found = true;
if (element == associative.end()) {
val = new AMFArrayValue();
associative.insert(std::make_pair(key, val));
} else {
val = dynamic_cast<AMFArrayValue*>(element->second);
found = false;
}
return std::make_pair(val, found);
};
// Associates an array with an integer key
std::pair<AMFBaseValue*, bool> Insert(const uint32_t& index) {
AMFArrayValue* val = nullptr;
bool inserted = false;
if (index >= dense.size()) {
dense.resize(index + 1);
val = new AMFArrayValue();
dense.at(index) = val;
inserted = true;
}
return std::make_pair(dynamic_cast<AMFArrayValue*>(dense.at(index)), inserted);
};
/**
* @brief Inserts an AMFValue into the AMFArray key'd by index.
* Attempting to insert the same key to the same value twice overwrites
* the previous value with the new one.
*
* @param index The index to associate with the value
* @param value The value to insert
* @return The inserted element, or nullptr if the type did not match
* what was at the index.
*/
template<typename ValueType>
std::pair<AMFValue<ValueType>*, bool> Insert(const uint32_t& index, ValueType value) {
AMFValue<ValueType>* val = nullptr;
bool inserted = false;
if (index >= this->dense.size()) {
this->dense.resize(index + 1);
val = new AMFValue<ValueType>(value);
this->dense.at(index) = val;
inserted = true;
}
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(this->dense.at(index)), inserted);
};
/**
* Inserts an AMFValue into the associative portion with the given key.
* If a duplicate is attempted to be inserted, it replaces the original
*
* The inserted element is now owned by this object and is not to be deleted
*
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const std::string& key, AMFBaseValue* value) {
auto element = associative.find(key);
if (element != associative.end() && element->second) {
delete element->second;
element->second = value;
} else {
associative.insert(std::make_pair(key, value));
}
};
/**
* Inserts an AMFValue into the associative portion with the given index.
* If a duplicate is attempted to be inserted, it replaces the original
*
* The inserted element is now owned by this object and is not to be deleted
*
* @param key The key to associate with the value
* @param value The value to insert
*/
void Insert(const uint32_t index, AMFBaseValue* value) {
if (index < dense.size()) {
AMFDense::iterator itr = dense.begin() + index;
if (*itr) delete dense.at(index);
} else {
dense.resize(index + 1);
}
dense.at(index) = value;
};
/**
* Pushes an AMFValue into the back of the dense portion.
*
* These objects are not to be deleted by the caller as they are owned by
* the AMFArray object which manages its own memory.
*
* @param value The value to insert
*
* @return The inserted pointer, or nullptr should the key already be in use.
*/
template<typename ValueType>
inline AMFValue<ValueType>* Push(ValueType value) {
return Insert(this->dense.size(), value).first;
};
/**
* Removes the key from the associative portion
*
* The pointer removed is now no longer managed by this container
*
* @param key The key to remove from the associative portion
*/
void Remove(const std::string& key, bool deleteValue = true) {
AMFAssociative::iterator it = this->associative.find(key);
if (it != this->associative.end()) {
if (deleteValue) delete it->second;
this->associative.erase(it);
}
}
/**
* Pops the last element in the dense portion, deleting it in the process.
*/
void Remove(const uint32_t index) {
if (!this->dense.empty() && index < this->dense.size()) {
auto itr = this->dense.begin() + index;
if (*itr) delete (*itr);
this->dense.erase(itr);
}
}
void Pop() {
if (!this->dense.empty()) Remove(this->dense.size() - 1);
}
AMFArrayValue* GetArray(const std::string& key) {
AMFAssociative::const_iterator it = this->associative.find(key);
if (it != this->associative.end()) {
return dynamic_cast<AMFArrayValue*>(it->second);
}
return nullptr;
};
AMFArrayValue* GetArray(const uint32_t index) {
return index >= this->dense.size() ? nullptr : dynamic_cast<AMFArrayValue*>(this->dense.at(index));
};
inline AMFArrayValue* InsertArray(const std::string& key) {
return static_cast<AMFArrayValue*>(Insert(key).first);
};
inline AMFArrayValue* InsertArray(const uint32_t index) {
return static_cast<AMFArrayValue*>(Insert(index).first);
};
inline AMFArrayValue* PushArray() {
return static_cast<AMFArrayValue*>(Insert(this->dense.size()).first);
};
/**
* Gets an AMFValue by the key from the associative portion and converts it
* to the AmfValue template type. If the key did not exist, it is inserted.
*
* @tparam The target object type
* @param key The key to lookup
*
* @return The AMFValue
*/
template <typename AmfType>
AMFValue<AmfType>* Get(const std::string& key) const {
AMFAssociative::const_iterator it = this->associative.find(key);
return it != this->associative.end() ?
dynamic_cast<AMFValue<AmfType>*>(it->second) :
nullptr;
};
// Get from the array but dont cast it
AMFBaseValue* Get(const std::string& key) const {
AMFAssociative::const_iterator it = this->associative.find(key);
return it != this->associative.end() ? it->second : nullptr;
};
/**
* @brief Get an AMFValue object at a position in the dense portion.
* Gets an AMFValue by the index from the dense portion and converts it
* to the AmfValue template type. If the index did not exist, it is inserted.
*
* @tparam The target object type
* @param index The index to get
* @return The casted object, or nullptr.
*/
template <typename AmfType>
AMFValue<AmfType>* Get(uint32_t index) const {
return index < this->dense.size() ?
dynamic_cast<AMFValue<AmfType>*>(this->dense.at(index)) :
nullptr;
};
// Get from the dense but dont cast it
AMFBaseValue* Get(const uint32_t index) const {
return index < this->dense.size() ? this->dense.at(index) : nullptr;
};
private:
/**
* The associative portion. These values are key'd with strings to an AMFValue.
*/
AMFAssociative associative;
/**
* The dense portion. These AMFValue's are stored one after
* another with the most recent addition being at the back.
*/
AMFDense dense;
};
#endif //!__AMF3__H__

View File

@@ -1,184 +0,0 @@
#include "AmfSerialize.h"
#include "Game.h"
#include "dLogger.h"
// Writes an AMFValue pointer to a RakNet::BitStream
template<>
void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
eAmf type = value.GetValueType();
this->Write(type);
switch (type) {
case eAmf::Integer: {
this->Write<AMFIntValue&>(*static_cast<AMFIntValue*>(&value));
break;
}
case eAmf::Double: {
this->Write<AMFDoubleValue&>(*static_cast<AMFDoubleValue*>(&value));
break;
}
case eAmf::String: {
this->Write<AMFStringValue&>(*static_cast<AMFStringValue*>(&value));
break;
}
case eAmf::Array: {
this->Write<AMFArrayValue&>(*static_cast<AMFArrayValue*>(&value));
break;
}
default: {
Game::logger->Log("AmfSerialize", "Encountered unwritable AMFType %i!", type);
}
case eAmf::Undefined:
case eAmf::Null:
case eAmf::False:
case eAmf::True:
case eAmf::Date:
case eAmf::Object:
case eAmf::XML:
case eAmf::XMLDoc:
case eAmf::ByteArray:
case eAmf::VectorInt:
case eAmf::VectorUInt:
case eAmf::VectorDouble:
case eAmf::VectorObject:
case eAmf::Dictionary:
break;
}
}
/**
* A private function to write an value to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
unsigned char b4 = (unsigned char)v;
if (v < 0x00200000) {
b4 = b4 & 0x7F;
if (v > 0x7F) {
unsigned char b3;
v = v >> 7;
b3 = ((unsigned char)(v)) | 0x80;
if (v > 0x7F) {
unsigned char b2;
v = v >> 7;
b2 = ((unsigned char)(v)) | 0x80;
bs->Write(b2);
}
bs->Write(b3);
}
} else {
unsigned char b1;
unsigned char b2;
unsigned char b3;
v = v >> 8;
b3 = ((unsigned char)(v)) | 0x80;
v = v >> 7;
b2 = ((unsigned char)(v)) | 0x80;
v = v >> 7;
b1 = ((unsigned char)(v)) | 0x80;
bs->Write(b1);
bs->Write(b2);
bs->Write(b3);
}
bs->Write(b4);
}
/**
* Writes a flag number to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
v = (v << 1) | 0x01;
WriteUInt29(bs, v);
}
/**
* Writes an AMFString to a RakNet::BitStream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
WriteFlagNumber(bs, (uint32_t)str.size());
bs->Write(str.c_str(), (uint32_t)str.size());
}
/**
* Writes an U16 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
bs->Write(value);
}
/**
* Writes an U32 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
bs->Write(value);
}
/**
* Writes an U64 to a bitstream
*
* RakNet writes in the correct byte order - do not reverse this.
*/
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
bs->Write(value);
}
// Writes an AMFIntegerValue to BitStream
template<>
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) {
WriteUInt29(this, value.GetValue());
}
// Writes an AMFDoubleValue to BitStream
template<>
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
double d = value.GetValue();
WriteAMFU64(this, *reinterpret_cast<uint64_t*>(&d));
}
// Writes an AMFStringValue to BitStream
template<>
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) {
WriteAMFString(this, value.GetValue());
}
// Writes an AMFArrayValue to BitStream
template<>
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) {
uint32_t denseSize = value.GetDense().size();
WriteFlagNumber(this, denseSize);
auto it = value.GetAssociative().begin();
auto end = value.GetAssociative().end();
while (it != end) {
WriteAMFString(this, it->first);
this->Write<AMFBaseValue&>(*it->second);
it++;
}
this->Write(eAmf::Null);
if (denseSize > 0) {
auto it2 = value.GetDense().begin();
auto end2 = value.GetDense().end();
while (it2 != end2) {
this->Write<AMFBaseValue&>(**it2);
it2++;
}
}
}

View File

@@ -1,50 +0,0 @@
#pragma once
// Custom Classes
#include "Amf3.h"
// RakNet
#include <BitStream.h>
/*!
\file AmfSerialize.h
\brief A class that implements native writing of AMF values to RakNet::BitStream
*/
// We are using the RakNet namespace
namespace RakNet {
//! Writes an AMFValue pointer to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value);
//! Writes an AMFIntegerValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value);
//! Writes an AMFDoubleValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value);
//! Writes an AMFStringValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value);
//! Writes an AMFArrayValue to a RakNet::BitStream
/*!
\param value The value to write
*/
template <>
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value);
} // namespace RakNet

View File

@@ -1,6 +1,6 @@
set(DCOMMON_SOURCES
set(DCOMMON_SOURCES "AMFFormat.cpp"
"AMFDeserialize.cpp"
"AmfSerialize.cpp"
"AMFFormat_BitStream.cpp"
"BinaryIO.cpp"
"dConfig.cpp"
"Diagnostics.cpp"

View File

@@ -1,12 +0,0 @@
#ifndef __DLUASSERT__H__
#define __DLUASSERT__H__
#include <assert.h>
#ifdef _DEBUG
# define DluAssert(expression) assert(expression)
#else
# define DluAssert(expression)
#endif
#endif //!__DLUASSERT__H__

View File

@@ -10,7 +10,6 @@ class dConfig;
class RakPeerInterface;
class AssetManager;
struct SystemAddress;
class EntityManager;
namespace Game {
extern dLogger* logger;
@@ -23,5 +22,4 @@ namespace Game {
extern AssetManager* assetManager;
extern SystemAddress chatSysAddr;
extern bool shouldShutdown;
extern EntityManager* entityManager;
}

View File

@@ -107,7 +107,7 @@ enum class eReplicaComponentType : uint32_t {
DONATION_VENDOR,
COMBAT_MEDIATOR,
COMMENDATION_VENDOR,
GATE_RUSH_CONTROL,
UNKNOWN_103,
RAIL_ACTIVATOR,
ROLLER,
PLAYER_FORCED_MOVEMENT,
@@ -119,7 +119,7 @@ enum class eReplicaComponentType : uint32_t {
UNKNOWN_112,
PROPERTY_PLAQUE,
BUILD_BORDER,
UNKNOWN_115,
UNKOWN_115,
CULLING_PLANE,
DESTROYABLE = 1000 // Actually 7
};

View File

@@ -16,6 +16,9 @@
// Enable this to cache all entries in each table for fast access, comes with more memory cost
//#define CDCLIENT_CACHE_ALL
// Enable this to skip some unused columns in some tables
#define UNUSED(v)
/*!
\file CDClientDatabase.hpp
\brief An interface between the CDClient.sqlite file and the server

View File

@@ -0,0 +1,80 @@
#include "CDClientManager.h"
#include "CDActivityRewardsTable.h"
#include "CDAnimationsTable.h"
#include "CDBehaviorParameterTable.h"
#include "CDBehaviorTemplateTable.h"
#include "CDComponentsRegistryTable.h"
#include "CDCurrencyTableTable.h"
#include "CDDestructibleComponentTable.h"
#include "CDEmoteTable.h"
#include "CDInventoryComponentTable.h"
#include "CDItemComponentTable.h"
#include "CDItemSetsTable.h"
#include "CDItemSetSkillsTable.h"
#include "CDLevelProgressionLookupTable.h"
#include "CDLootMatrixTable.h"
#include "CDLootTableTable.h"
#include "CDMissionNPCComponentTable.h"
#include "CDMissionTasksTable.h"
#include "CDMissionsTable.h"
#include "CDObjectSkillsTable.h"
#include "CDObjectsTable.h"
#include "CDPhysicsComponentTable.h"
#include "CDRebuildComponentTable.h"
#include "CDScriptComponentTable.h"
#include "CDSkillBehaviorTable.h"
#include "CDZoneTableTable.h"
#include "CDVendorComponentTable.h"
#include "CDActivitiesTable.h"
#include "CDPackageComponentTable.h"
#include "CDProximityMonitorComponentTable.h"
#include "CDMovementAIComponentTable.h"
#include "CDBrickIDTableTable.h"
#include "CDRarityTableTable.h"
#include "CDMissionEmailTable.h"
#include "CDRewardsTable.h"
#include "CDPropertyEntranceComponentTable.h"
#include "CDPropertyTemplateTable.h"
#include "CDFeatureGatingTable.h"
#include "CDRailActivatorComponent.h"
CDClientManager::CDClientManager() {
CDActivityRewardsTable::Instance();
UNUSED(CDAnimationsTable::Instance());
CDBehaviorParameterTable::Instance();
CDBehaviorTemplateTable::Instance();
CDComponentsRegistryTable::Instance();
CDCurrencyTableTable::Instance();
CDDestructibleComponentTable::Instance();
CDEmoteTableTable::Instance();
CDInventoryComponentTable::Instance();
CDItemComponentTable::Instance();
CDItemSetsTable::Instance();
CDItemSetSkillsTable::Instance();
CDLevelProgressionLookupTable::Instance();
CDLootMatrixTable::Instance();
CDLootTableTable::Instance();
CDMissionNPCComponentTable::Instance();
CDMissionTasksTable::Instance();
CDMissionsTable::Instance();
CDObjectSkillsTable::Instance();
CDObjectsTable::Instance();
CDPhysicsComponentTable::Instance();
CDRebuildComponentTable::Instance();
CDScriptComponentTable::Instance();
CDSkillBehaviorTable::Instance();
CDZoneTableTable::Instance();
CDVendorComponentTable::Instance();
CDActivitiesTable::Instance();
CDPackageComponentTable::Instance();
CDProximityMonitorComponentTable::Instance();
CDMovementAIComponentTable::Instance();
CDBrickIDTableTable::Instance();
CDRarityTableTable::Instance();
CDMissionEmailTable::Instance();
CDRewardsTable::Instance();
CDPropertyEntranceComponentTable::Instance();
CDPropertyTemplateTable::Instance();
CDFeatureGatingTable::Instance();
CDRailActivatorComponentTable::Instance();
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "CDTable.h"
#include "Singleton.h"
/**
* Initialize the CDClient tables so they are all loaded into memory.
*/
class CDClientManager : public Singleton<CDClientManager> {
public:
CDClientManager();
/**
* Fetch a table from CDClient
*
* @tparam Table type to fetch
* @return A pointer to the requested table.
*/
template<typename T>
T* GetTable() {
return &T::Instance();
}
};

View File

@@ -1,4 +1,5 @@
set(DDATABASE_SOURCES "CDClientDatabase.cpp"
"CDClientManager.cpp"
"Database.cpp"
"MigrationRunner.cpp")

View File

@@ -1,10 +1,7 @@
#include "CDActivitiesTable.h"
namespace {
std::vector<CDActivities> entries;
};
CDActivitiesTable::CDActivitiesTable(void) {
void CDActivitiesTable::LoadTableIntoMemory() {
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Activities");
@@ -17,7 +14,7 @@ void CDActivitiesTable::LoadTableIntoMemory() {
tableSize.finalize();
// Reserve the size
entries.reserve(size);
this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities");
@@ -43,7 +40,7 @@ void CDActivitiesTable::LoadTableIntoMemory() {
entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1);
entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f);
entries.push_back(entry);
this->entries.push_back(entry);
tableData.nextRow();
}
@@ -52,9 +49,14 @@ void CDActivitiesTable::LoadTableIntoMemory() {
std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) {
std::vector<CDActivities> data = cpplinq::from(entries)
std::vector<CDActivities> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
}
std::vector<CDActivities> CDActivitiesTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -25,8 +25,14 @@ struct CDActivities {
float optionalPercentage;
};
namespace CDActivitiesTable {
void LoadTableIntoMemory();
class CDActivitiesTable : public CDTable<CDActivitiesTable> {
private:
std::vector<CDActivities> entries;
public:
CDActivitiesTable();
// Queries the table with a custom "where" clause
std::vector<CDActivities> Query(std::function<bool(CDActivities)> predicate);
std::vector<CDActivities> GetEntries(void) const;
};

View File

@@ -1,10 +1,7 @@
#include "CDActivityRewardsTable.h"
namespace {
std::vector<CDActivityRewards> entries;
};
CDActivityRewardsTable::CDActivityRewardsTable(void) {
void CDActivityRewardsTable::LoadTableIntoMemory() {
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ActivityRewards");
@@ -17,7 +14,7 @@ void CDActivityRewardsTable::LoadTableIntoMemory() {
tableSize.finalize();
// Reserve the size
entries.reserve(size);
this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards");
@@ -31,7 +28,7 @@ void CDActivityRewardsTable::LoadTableIntoMemory() {
entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1);
entry.description = tableData.getStringField("description", "");
entries.push_back(entry);
this->entries.push_back(entry);
tableData.nextRow();
}
@@ -40,9 +37,14 @@ void CDActivityRewardsTable::LoadTableIntoMemory() {
std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) {
std::vector<CDActivityRewards> data = cpplinq::from(entries)
std::vector<CDActivityRewards> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
}
std::vector<CDActivityRewards> CDActivityRewardsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -13,8 +13,15 @@ struct CDActivityRewards {
std::string description; //!< The description
};
namespace CDActivityRewardsTable {
void LoadTableIntoMemory();
class CDActivityRewardsTable : public CDTable<CDActivityRewardsTable> {
private:
std::vector<CDActivityRewards> entries;
public:
CDActivityRewardsTable();
// Queries the table with a custom "where" clause
std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate);
std::vector<CDActivityRewards> GetEntries(void) const;
};

View File

@@ -1,97 +1,56 @@
#include "CDAnimationsTable.h"
#include "GeneralUtils.h"
#include "Game.h"
namespace {
/**
* Cache all animations given a premade key
*/
void CacheAnimations(const CDAnimationsTable::CDAnimationKey animationKey) {
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?");
query.bind(1, static_cast<int32_t>(animationKey.second));
query.bind(2, animationKey.first.c_str());
// If we received a bad lookup, cache it anyways so we do not run the query again.
if (!CacheData(query)) {
animations[animationKey];
}
CDAnimationsTable::CDAnimationsTable(void) {
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Animations");
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);
tableSize.nextRow();
}
/**
* Run the query responsible for caching the data.
*/
bool CacheData(CppSQLite3Statement& queryToCache) {
auto tableData = queryToCache.execQuery();
// If we received a bad lookup, cache it anyways so we do not run the query again.
if (tableData.eof()) return false;
tableSize.finalize();
do {
std::string animation_type = tableData.getStringField("animation_type", "");
DluAssert(!animation_type.empty());
CDAnimationsTable::AnimationGroupID animationGroupID = tableData.getIntField("animationGroupID", -1);
DluAssert(animationGroupID != -1);
// Reserve the size
this->entries.reserve(size);
CDAnimation entry;
entry.animation_name = tableData.getStringField("animation_name", "");
entry.chance_to_play = tableData.getFloatField("chance_to_play", 1.0f);
UNUSED_COLUMN(entry.min_loops = tableData.getIntField("min_loops", 0););
UNUSED_COLUMN(entry.max_loops = tableData.getIntField("max_loops", 0););
entry.animation_length = tableData.getFloatField("animation_length", 0.0f);
UNUSED_COLUMN(entry.hideEquip = tableData.getIntField("hideEquip", 0) == 1;);
UNUSED_COLUMN(entry.ignoreUpperBody = tableData.getIntField("ignoreUpperBody", 0) == 1;);
UNUSED_COLUMN(entry.restartable = tableData.getIntField("restartable", 0) == 1;);
UNUSED_COLUMN(entry.face_animation_name = tableData.getStringField("face_animation_name", ""););
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f););
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f););
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations");
while (!tableData.eof()) {
CDAnimations entry;
entry.animationGroupID = tableData.getIntField("animationGroupID", -1);
entry.animation_type = tableData.getStringField("animation_type", "");
entry.animation_name = tableData.getStringField("animation_name", "");
entry.chance_to_play = tableData.getFloatField("chance_to_play", -1.0f);
entry.min_loops = tableData.getIntField("min_loops", -1);
entry.max_loops = tableData.getIntField("max_loops", -1);
entry.animation_length = tableData.getFloatField("animation_length", -1.0f);
entry.hideEquip = tableData.getIntField("hideEquip", -1) == 1 ? true : false;
entry.ignoreUpperBody = tableData.getIntField("ignoreUpperBody", -1) == 1 ? true : false;
entry.restartable = tableData.getIntField("restartable", -1) == 1 ? true : false;
entry.face_animation_name = tableData.getStringField("face_animation_name", "");
entry.priority = tableData.getFloatField("priority", -1.0f);
entry.blendTime = tableData.getFloatField("blendTime", -1.0f);
animations[CDAnimationsTable::CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow();
} while (!tableData.eof());
tableData.finalize();
return true;
this->entries.push_back(entry);
tableData.nextRow();
}
/**
* Each animation is key'd by its animationName and its animationGroupID. Each
* animation has a possible list of animations. This is because there can be animations have a percent chance to play so one is selected at random.
*/
std::map<CDAnimationsTable::CDAnimationKey, std::list<CDAnimation>> animations;
};
void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
auto animationEntryCached = animations.find(CDAnimationKey("", animationGroupID));
if (animationEntryCached != animations.end()) {
return;
}
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ?");
query.bind(1, static_cast<int32_t>(animationGroupID));
// Cache the query so we don't run the query again.
CacheData(query);
animations[CDAnimationKey("", animationGroupID)];
tableData.finalize();
}
CDAnimationLookupResult CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) {
CDAnimationKey animationKey(animationType, animationGroupID);
auto animationEntryCached = animations.find(animationKey);
if (animationEntryCached == animations.end()) {
CacheAnimations(animationKey);
}
std::vector<CDAnimations> CDAnimationsTable::Query(std::function<bool(CDAnimations)> predicate) {
auto animationEntry = animations.find(animationKey);
// If we have only one animation, return it regardless of the chance to play.
if (animationEntry->second.size() == 1) {
return CDAnimationLookupResult(animationEntry->second.front());
}
auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1);
std::vector<CDAnimations> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
for (auto& animationEntry : animationEntry->second) {
randomAnimation -= animationEntry.chance_to_play;
// This is how the client gets the random animation.
if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return CDAnimationLookupResult(animationEntry);
}
return CDAnimationLookupResult();
return data;
}
std::vector<CDAnimations> CDAnimationsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -1,46 +1,33 @@
#pragma once
// Custom Classes
#include "CDTable.h"
#include <list>
struct CDAnimation {
// unsigned int animationGroupID;
// std::string animation_type;
// The above two are a pair to represent a primary key in the map.
struct CDAnimations {
unsigned int animationGroupID; //!< The animation group ID
std::string animation_type; //!< The animation type
std::string animation_name; //!< The animation name
float chance_to_play; //!< The chance to play the animation
UNUSED_COLUMN(unsigned int min_loops;) //!< The minimum number of loops
UNUSED_COLUMN(unsigned int max_loops;) //!< The maximum number of loops
unsigned int min_loops; //!< The minimum number of loops
unsigned int max_loops; //!< The maximum number of loops
float animation_length; //!< The animation length
UNUSED_COLUMN(bool hideEquip;) //!< Whether or not to hide the equip
UNUSED_COLUMN(bool ignoreUpperBody;) //!< Whether or not to ignore the upper body
UNUSED_COLUMN(bool restartable;) //!< Whether or not the animation is restartable
UNUSED_COLUMN(std::string face_animation_name;) //!< The face animation name
UNUSED_COLUMN(float priority;) //!< The priority
UNUSED_COLUMN(float blendTime;) //!< The blend time
bool hideEquip; //!< Whether or not to hide the equip
bool ignoreUpperBody; //!< Whether or not to ignore the upper body
bool restartable; //!< Whether or not the animation is restartable
std::string face_animation_name; //!< The face animation name
float priority; //!< The priority
float blendTime; //!< The blend time
};
typedef LookupResult<CDAnimation> CDAnimationLookupResult;
namespace CDAnimationsTable {
typedef int32_t AnimationGroupID;
typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
void LoadTableIntoMemory();
/**
* Given an animationType and the previousAnimationName played, return the next animationType to play.
* If there are more than 1 animationTypes that can be played, one is selected at random but also does not allow
* the previousAnimationName to be played twice.
*
* @param animationType The animationID to lookup
* @param previousAnimationName The previously played animation
* @param animationGroupID The animationGroupID to lookup
* @return CDAnimationLookupResult
*/
[[nodiscard]] CDAnimationLookupResult GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID);
class CDAnimationsTable : public CDTable<CDAnimationsTable> {
private:
std::vector<CDAnimations> entries;
/**
* Cache a full AnimationGroup by its ID.
*/
void CacheAnimationGroup(AnimationGroupID animationGroupID);
public:
CDAnimationsTable();
// Queries the table with a custom "where" clause
std::vector<CDAnimations> Query(std::function<bool(CDAnimations)> predicate);
std::vector<CDAnimations> GetEntries(void) const;
};

View File

@@ -1,12 +1,7 @@
#include "CDBehaviorParameterTable.h"
#include "GeneralUtils.h"
namespace {
std::unordered_map<uint64_t, CDBehaviorParameter> m_Entries;
std::unordered_map<std::string, uint32_t> m_ParametersList;
};
void CDBehaviorParameterTable::LoadTableIntoMemory() {
CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
uint32_t uniqueParameterId = 0;
uint64_t hash = 0;
@@ -33,8 +28,8 @@ void CDBehaviorParameterTable::LoadTableIntoMemory() {
}
float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
auto parameterID = m_ParametersList.find(name);
if (parameterID == m_ParametersList.end()) return defaultValue;
auto parameterID = this->m_ParametersList.find(name);
if (parameterID == this->m_ParametersList.end()) return defaultValue;
uint64_t hash = behaviorID;

View File

@@ -11,9 +11,13 @@ struct CDBehaviorParameter {
float value; //!< The value of the behavior template
};
namespace CDBehaviorParameterTable {
void LoadTableIntoMemory();
float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0.0f);
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable> {
private:
std::unordered_map<uint64_t, CDBehaviorParameter> m_Entries;
std::unordered_map<std::string, uint32_t> m_ParametersList;
public:
CDBehaviorParameterTable();
float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0);
std::map<std::string, float> GetParametersByBehaviorID(uint32_t behaviorID);
};

View File

@@ -1,12 +1,6 @@
#include "CDBehaviorTemplateTable.h"
namespace {
std::vector<CDBehaviorTemplate> entries;
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
std::unordered_set<std::string> m_EffectHandles;
};
void CDBehaviorTemplateTable::LoadTableIntoMemory() {
CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -20,7 +14,7 @@ void CDBehaviorTemplateTable::LoadTableIntoMemory() {
tableSize.finalize();
// Reserve the size
entries.reserve(size);
this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
@@ -37,8 +31,8 @@ void CDBehaviorTemplateTable::LoadTableIntoMemory() {
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
}
entries.push_back(entry);
entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
this->entries.push_back(entry);
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
tableData.nextRow();
}
@@ -47,16 +41,20 @@ void CDBehaviorTemplateTable::LoadTableIntoMemory() {
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<bool(CDBehaviorTemplate)> predicate) {
std::vector<CDBehaviorTemplate> data = cpplinq::from(entries)
std::vector<CDBehaviorTemplate> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
}
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
return this->entries;
}
const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) {
auto entry = entriesMappedByBehaviorID.find(behaviorID);
if (entry == entriesMappedByBehaviorID.end()) {
auto entry = this->entriesMappedByBehaviorID.find(behaviorID);
if (entry == this->entriesMappedByBehaviorID.end()) {
CDBehaviorTemplate entryToReturn;
entryToReturn.behaviorID = 0;
entryToReturn.effectHandle = m_EffectHandles.end();

View File

@@ -6,17 +6,24 @@
#include <unordered_set>
struct CDBehaviorTemplate {
uint32_t behaviorID; //!< The Behavior ID
uint32_t templateID; //!< The Template ID (LOT)
uint32_t effectID; //!< The Effect ID attached
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
unsigned int behaviorID; //!< The Behavior ID
unsigned int templateID; //!< The Template ID (LOT)
unsigned int effectID; //!< The Effect ID attached
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
};
namespace CDBehaviorTemplateTable {
void LoadTableIntoMemory();
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable> {
private:
std::vector<CDBehaviorTemplate> entries;
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
std::unordered_set<std::string> m_EffectHandles;
public:
CDBehaviorTemplateTable();
// Queries the table with a custom "where" clause
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
std::vector<CDBehaviorTemplate> GetEntries(void) const;
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
};

View File

@@ -1,10 +1,6 @@
#include "CDBrickIDTableTable.h"
namespace {
std::vector<CDBrickIDTable> entries;
};
void CDBrickIDTableTable::LoadTableIntoMemory() {
CDBrickIDTableTable::CDBrickIDTableTable(void) {
// First, get the size of the table
unsigned int size = 0;
@@ -18,7 +14,7 @@ void CDBrickIDTableTable::LoadTableIntoMemory() {
tableSize.finalize();
// Reserve the size
entries.reserve(size);
this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable");
@@ -27,7 +23,7 @@ void CDBrickIDTableTable::LoadTableIntoMemory() {
entry.NDObjectID = tableData.getIntField("NDObjectID", -1);
entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1);
entries.push_back(entry);
this->entries.push_back(entry);
tableData.nextRow();
}
@@ -36,9 +32,14 @@ void CDBrickIDTableTable::LoadTableIntoMemory() {
std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) {
std::vector<CDBrickIDTable> data = cpplinq::from(entries)
std::vector<CDBrickIDTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
}
std::vector<CDBrickIDTable> CDBrickIDTableTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -16,8 +16,14 @@ struct CDBrickIDTable {
//! BrickIDTable table
namespace CDBrickIDTableTable {
void LoadTableIntoMemory();
class CDBrickIDTableTable : public CDTable<CDBrickIDTableTable> {
private:
std::vector<CDBrickIDTable> entries;
public:
CDBrickIDTableTable();
// Queries the table with a custom "where" clause
std::vector<CDBrickIDTable> Query(std::function<bool(CDBrickIDTable)> predicate);
std::vector<CDBrickIDTable> GetEntries(void) const;
};

View File

@@ -11,9 +11,11 @@ struct CDComponentsRegistry {
};
namespace CDComponentsRegistryTable {
class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable> {
private:
std::map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
void LoadTableIntoMemory();
public:
CDComponentsRegistryTable();
int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0);
};

View File

@@ -18,12 +18,12 @@ struct CDCurrencyTable {
};
//! CurrencyTable table
namespace CDCurrencyTableTable {
class CDCurrencyTableTable : public CDTable<CDCurrencyTableTable> {
private:
std::vector<CDCurrencyTable> entries;
public:
void LoadTableIntoMemory();
CDCurrencyTableTable();
// Queries the table with a custom "where" clause
std::vector<CDCurrencyTable> Query(std::function<bool(CDCurrencyTable)> predicate);

View File

@@ -20,12 +20,12 @@ struct CDDestructibleComponent {
int difficultyLevel; //!< ???
};
namespace CDDestructibleComponentTable {
class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable> {
private:
std::vector<CDDestructibleComponent> entries;
public:
void LoadTableIntoMemory();
CDDestructibleComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate);

View File

@@ -1,30 +1,40 @@
#include "CDEmoteTable.h"
namespace {
std::map<int, CDEmoteTable> entries;
};
void CDEmoteTableTable::LoadTableIntoMemory() {
//! Constructor
CDEmoteTableTable::CDEmoteTableTable(void) {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes");
while (!tableData.eof()) {
CDEmoteTable entry;
entry.ID = tableData.getIntField("id", -1);
entry.animationName = tableData.getStringField("animationName", "");
entry.iconFilename = tableData.getStringField("iconFilename", "");
entry.channel = tableData.getIntField("channel", -1);
entry.locked = tableData.getIntField("locked", -1) != 0;
entry.localize = tableData.getIntField("localize", -1) != 0;
entry.locState = tableData.getIntField("locStatus", -1);
entry.gateVersion = tableData.getStringField("gate_version", "");
CDEmoteTable* entry = new CDEmoteTable();
entry->ID = tableData.getIntField("id", -1);
entry->animationName = tableData.getStringField("animationName", "");
entry->iconFilename = tableData.getStringField("iconFilename", "");
entry->channel = tableData.getIntField("channel", -1);
entry->locked = tableData.getIntField("locked", -1) != 0;
entry->localize = tableData.getIntField("localize", -1) != 0;
entry->locState = tableData.getIntField("locStatus", -1);
entry->gateVersion = tableData.getStringField("gate_version", "");
entries.insert(std::make_pair(entry.ID, entry));
entries.insert(std::make_pair(entry->ID, entry));
tableData.nextRow();
}
tableData.finalize();
}
CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
return entries.find(id) != entries.end() ? &entries[id] : nullptr;
//! Destructor
CDEmoteTableTable::~CDEmoteTableTable(void) {
for (auto e : entries) {
if (e.second) delete e.second;
}
entries.clear();
}
CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
for (auto e : entries) {
if (e.first == id) return e.second;
}
return nullptr;
}

View File

@@ -26,8 +26,13 @@ struct CDEmoteTable {
std::string gateVersion;
};
namespace CDEmoteTableTable {
void LoadTableIntoMemory();
class CDEmoteTableTable : public CDTable<CDEmoteTableTable> {
private:
std::map<int, CDEmoteTable*> entries;
public:
CDEmoteTableTable();
~CDEmoteTableTable();
// Returns an emote by ID
CDEmoteTable* GetEmote(int id);
};

View File

@@ -11,12 +11,12 @@ struct CDFeatureGating {
std::string description;
};
namespace CDFeatureGatingTable {
class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable> {
private:
std::vector<CDFeatureGating> entries;
public:
void LoadTableIntoMemory();
CDFeatureGatingTable();
// Queries the table with a custom "where" clause
std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);

View File

@@ -10,12 +10,12 @@ struct CDInventoryComponent {
bool equip; //!< Whether or not to equip the item
};
namespace CDInventoryComponentTable {
class CDInventoryComponentTable : public CDTable<CDInventoryComponentTable> {
private:
std::vector<CDInventoryComponent> entries;
public:
void LoadTableIntoMemory();
CDInventoryComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDInventoryComponent> Query(std::function<bool(CDInventoryComponent)> predicate);

View File

@@ -49,12 +49,12 @@ struct CDItemComponent {
float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced)
};
namespace CDItemComponentTable {
class CDItemComponentTable : public CDTable<CDItemComponentTable> {
private:
std::map<unsigned int, CDItemComponent> entries;
public:
void LoadTableIntoMemory();
CDItemComponentTable();
static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent);
// Gets an entry by ID

View File

@@ -9,12 +9,12 @@ struct CDItemSetSkills {
unsigned int SkillCastType; //!< The skill cast type
};
namespace CDItemSetSkillsTable {
class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable> {
private:
std::vector<CDItemSetSkills> entries;
public:
void LoadTableIntoMemory();
CDItemSetSkillsTable();
// Queries the table with a custom "where" clause
std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate);

View File

@@ -21,12 +21,12 @@ struct CDItemSets {
float priority; //!< The priority
};
namespace CDItemSetsTable {
class CDItemSetsTable : public CDTable<CDItemSetsTable> {
private:
std::vector<CDItemSets> entries;
public:
void LoadTableIntoMemory();
CDItemSetsTable();
// Queries the table with a custom "where" clause
std::vector<CDItemSets> Query(std::function<bool(CDItemSets)> predicate);

View File

@@ -9,12 +9,12 @@ struct CDLevelProgressionLookup {
std::string BehaviorEffect; //!< The behavior effect attached to this
};
namespace CDLevelProgressionLookupTable {
class CDLevelProgressionLookupTable : public CDTable<CDLevelProgressionLookupTable> {
private:
std::vector<CDLevelProgressionLookup> entries;
public:
void LoadTableIntoMemory();
CDLevelProgressionLookupTable();
// Queries the table with a custom "where" clause
std::vector<CDLevelProgressionLookup> Query(std::function<bool(CDLevelProgressionLookup)> predicate);

View File

@@ -15,12 +15,12 @@ struct CDLootMatrix {
UNUSED(std::string gate_version); //!< The Gate Version
};
namespace CDLootMatrixTable {
class CDLootMatrixTable : public CDTable<CDLootMatrixTable> {
private:
std::vector<CDLootMatrix> entries;
public:
void LoadTableIntoMemory();
CDLootMatrixTable();
// Queries the table with a custom "where" clause
std::vector<CDLootMatrix> Query(std::function<bool(CDLootMatrix)> predicate);

View File

@@ -11,12 +11,12 @@ struct CDLootTable {
unsigned int sortPriority; //!< The sorting priority
};
namespace CDLootTableTable {
class CDLootTableTable : public CDTable<CDLootTableTable> {
private:
std::vector<CDLootTable> entries;
public:
void LoadTableIntoMemory();
CDLootTableTable();
// Queries the table with a custom "where" clause
std::vector<CDLootTable> Query(std::function<bool(CDLootTable)> predicate);

View File

@@ -15,12 +15,12 @@ struct CDMissionEmail {
};
namespace CDMissionEmailTable {
class CDMissionEmailTable : public CDTable<CDMissionEmailTable> {
private:
std::vector<CDMissionEmail> entries;
public:
void LoadTableIntoMemory();
CDMissionEmailTable();
// Queries the table with a custom "where" clause
std::vector<CDMissionEmail> Query(std::function<bool(CDMissionEmail)> predicate);

View File

@@ -11,12 +11,12 @@ struct CDMissionNPCComponent {
std::string gate_version; //!< The gate version
};
namespace CDMissionNPCComponentTable {
class CDMissionNPCComponentTable : public CDTable<CDMissionNPCComponentTable> {
private:
std::vector<CDMissionNPCComponent> entries;
public:
void LoadTableIntoMemory();
CDMissionNPCComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDMissionNPCComponent> Query(std::function<bool(CDMissionNPCComponent)> predicate);

View File

@@ -19,12 +19,12 @@ struct CDMissionTasks {
UNUSED(std::string gate_version); //!< ???
};
namespace CDMissionTasksTable {
class CDMissionTasksTable : public CDTable<CDMissionTasksTable> {
private:
std::vector<CDMissionTasks> entries;
public:
void LoadTableIntoMemory();
CDMissionTasksTable();
// Queries the table with a custom "where" clause
std::vector<CDMissionTasks> Query(std::function<bool(CDMissionTasks)> predicate);

View File

@@ -60,12 +60,12 @@ struct CDMissions {
int reward_bankinventory; //!< The amount of bank space this mission rewards
};
namespace CDMissionsTable {
class CDMissionsTable : public CDTable<CDMissionsTable> {
private:
std::vector<CDMissions> entries;
public:
void LoadTableIntoMemory();
CDMissionsTable();
// Queries the table with a custom "where" clause
std::vector<CDMissions> Query(std::function<bool(CDMissions)> predicate);

View File

@@ -14,12 +14,12 @@ struct CDMovementAIComponent {
std::string attachedPath;
};
namespace CDMovementAIComponentTable {
class CDMovementAIComponentTable : public CDTable<CDMovementAIComponentTable> {
private:
std::vector<CDMovementAIComponent> entries;
public:
void LoadTableIntoMemory();
CDMovementAIComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDMovementAIComponent> Query(std::function<bool(CDMovementAIComponent)> predicate);

View File

@@ -10,12 +10,12 @@ struct CDObjectSkills {
unsigned int AICombatWeight; //!< ???
};
namespace CDObjectSkillsTable {
class CDObjectSkillsTable : public CDTable<CDObjectSkillsTable> {
private:
std::vector<CDObjectSkills> entries;
public:
void LoadTableIntoMemory();
CDObjectSkillsTable();
// Queries the table with a custom "where" clause
std::vector<CDObjectSkills> Query(std::function<bool(CDObjectSkills)> predicate);

View File

@@ -20,13 +20,13 @@ struct CDObjects {
UNUSED(unsigned int HQ_valid); //!< Probably used for the Nexus HQ database on LEGOUniverse.com
};
namespace CDObjectsTable {
class CDObjectsTable : public CDTable<CDObjectsTable> {
private:
std::map<unsigned int, CDObjects> entries;
CDObjects m_default;
public:
void LoadTableIntoMemory();
CDObjectsTable();
// Gets an entry by ID
const CDObjects& GetByID(unsigned int LOT);
};

View File

@@ -9,7 +9,7 @@ struct CDPackageComponent {
unsigned int packageType;
};
namespace CDPackageComponentTable {
class CDPackageComponentTable : public CDTable<CDPackageComponentTable> {
private:
std::vector<CDPackageComponent> entries;

View File

@@ -21,9 +21,10 @@ struct CDPhysicsComponent {
UNUSED(std::string gravityVolumeAsset);
};
namespace CDPhysicsComponentTable {
class CDPhysicsComponentTable : public CDTable<CDPhysicsComponentTable> {
public:
void LoadTableIntoMemory();
CDPhysicsComponentTable();
~CDPhysicsComponentTable();
static const std::string GetTableName() { return "PhysicsComponent"; };
CDPhysicsComponent* GetByID(unsigned int componentID);

View File

@@ -9,9 +9,9 @@ struct CDPropertyEntranceComponent {
std::string groupType;
};
namespace CDPropertyEntranceComponentTable {
class CDPropertyEntranceComponentTable : public CDTable<CDPropertyEntranceComponentTable> {
public:
void LoadTableIntoMemory();
CDPropertyEntranceComponentTable();
// Queries the table with a custom "where" clause
CDPropertyEntranceComponent GetByID(uint32_t id);

View File

@@ -8,9 +8,9 @@ struct CDPropertyTemplate {
std::string spawnName;
};
namespace CDPropertyTemplateTable {
class CDPropertyTemplateTable : public CDTable<CDPropertyTemplateTable> {
public:
void LoadTableIntoMemory();
CDPropertyTemplateTable();
static const std::string GetTableName() { return "PropertyTemplate"; };
CDPropertyTemplate GetByMapID(uint32_t mapID);

View File

@@ -10,7 +10,7 @@ struct CDProximityMonitorComponent {
bool LoadOnServer;
};
namespace CDProximityMonitorComponentTable {
class CDProximityMonitorComponentTable : public CDTable<CDProximityMonitorComponentTable> {
private:
std::vector<CDProximityMonitorComponent> entries;

View File

@@ -20,9 +20,9 @@ struct CDRailActivatorComponent {
bool showNameBillboard;
};
namespace CDRailActivatorComponentTable {
class CDRailActivatorComponentTable : public CDTable<CDRailActivatorComponentTable> {
public:
void LoadTableIntoMemory();
CDRailActivatorComponentTable();
static const std::string GetTableName() { return "RailActivatorComponent"; };
[[nodiscard]] CDRailActivatorComponent GetEntryByID(int32_t id) const;
[[nodiscard]] std::vector<CDRailActivatorComponent> GetEntries() const;

View File

@@ -26,12 +26,12 @@ struct CDRarityTable {
}
};
namespace CDRarityTableTable {
class CDRarityTableTable : public CDTable<CDRarityTableTable> {
private:
std::vector<CDRarityTable> entries;
public:
void LoadTableIntoMemory();
CDRarityTableTable();
// Queries the table with a custom "where" clause
std::vector<CDRarityTable> Query(std::function<bool(CDRarityTable)> predicate);

View File

@@ -16,12 +16,12 @@ struct CDRebuildComponent {
float time_before_smash; //!< The time before smash
};
namespace CDRebuildComponentTable {
class CDRebuildComponentTable : public CDTable<CDRebuildComponentTable> {
private:
std::vector<CDRebuildComponent> entries;
public:
void LoadTableIntoMemory();
CDRebuildComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDRebuildComponent> Query(std::function<bool(CDRebuildComponent)> predicate);

View File

@@ -11,9 +11,10 @@ struct CDRewards {
int32_t count;
};
namespace CDRewardsTable {
class CDRewardsTable : public CDTable<CDRewardsTable> {
public:
void LoadTableIntoMemory();
CDRewardsTable();
~CDRewardsTable();
static const std::string GetTableName() { return "Rewards"; };
std::vector<CDRewards*> GetByLevelID(uint32_t levelID);

View File

@@ -9,13 +9,13 @@ struct CDScriptComponent {
std::string client_script_name; //!< The client script name
};
namespace CDScriptComponentTable {
class CDScriptComponentTable : public CDTable<CDScriptComponentTable> {
private:
std::map<unsigned int, CDScriptComponent> entries;
CDScriptComponent m_ToReturnWhenNoneFound;
public:
void LoadTableIntoMemory();
CDScriptComponentTable();
// Gets an entry by scriptID
const CDScriptComponent& GetByID(unsigned int id);
};

View File

@@ -25,13 +25,13 @@ struct CDSkillBehavior {
UNUSED(unsigned int cancelType); //!< The cancel type (?)
};
namespace CDSkillBehaviorTable {
class CDSkillBehaviorTable : public CDTable<CDSkillBehaviorTable> {
private:
std::map<unsigned int, CDSkillBehavior> entries;
CDSkillBehavior m_empty;
public:
void LoadTableIntoMemory();
CDSkillBehaviorTable();
// Queries the table with a custom "where" clause
std::vector<CDSkillBehavior> Query(std::function<bool(CDSkillBehavior)> predicate);

View File

@@ -2,7 +2,6 @@
#include "CDClientDatabase.h"
#include "Singleton.h"
#include "DluAssert.h"
#include <functional>
#include <string>
@@ -16,23 +15,11 @@
#endif
#include "cpplinq.hpp"
// Used for legacy
#define UNUSED(x)
// Enable this to skip some unused columns in some tables
#define UNUSED_COLUMN(v)
#pragma warning (disable : 4244) //Disable double to float conversion warnings
#pragma warning (disable : 4715) //Disable "not all control paths return a value"
template<class T>
class LookupResult {
typedef std::pair<T, bool> DataType;
public:
LookupResult() { m_data.first = T(); m_data.second = false; };
LookupResult(T& data) { m_data.first = data; m_data.second = true; };
inline const T& Data() { return m_data.first; };
inline const bool& FoundData() { return m_data.second; };
private:
DataType m_data;
template<class Table>
class CDTable : public Singleton<Table> {
protected:
virtual ~CDTable() = default;
};

View File

@@ -11,12 +11,12 @@ struct CDVendorComponent {
unsigned int LootMatrixIndex; //!< LootMatrixIndex of the vendor's items
};
namespace CDVendorComponentTable {
class CDVendorComponentTable : public CDTable<CDVendorComponentTable> {
private:
std::vector<CDVendorComponent> entries;
public:
void LoadTableIntoMemory();
CDVendorComponentTable();
// Queries the table with a custom "where" clause
std::vector<CDVendorComponent> Query(std::function<bool(CDVendorComponent)> predicate);

View File

@@ -33,12 +33,12 @@ struct CDZoneTable {
UNUSED(bool mountsAllowed); //!< Whether or not mounts are allowed
};
namespace CDZoneTableTable {
class CDZoneTableTable : public CDTable<CDZoneTableTable> {
private:
std::map<unsigned int, CDZoneTable> m_Entries;
public:
void LoadTableIntoMemory();
CDZoneTableTable();
// Queries the table with a zoneID to find.
const CDZoneTable* Query(unsigned int zoneID);

View File

@@ -290,7 +290,7 @@ void Character::DoQuickXMLDataParse() {
void Character::UnlockEmote(int emoteID) {
m_UnlockedEmotes.push_back(emoteID);
GameMessages::SendSetEmoteLockState(Game::entityManager->GetEntity(m_ObjectID), false, emoteID);
GameMessages::SendSetEmoteLockState(EntityManager::Instance()->GetEntity(m_ObjectID), false, emoteID);
}
void Character::SetBuildMode(bool buildMode) {
@@ -418,13 +418,13 @@ void Character::WriteToDatabase() {
delete printer;
}
void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {
void Character::SetPlayerFlag(const int32_t flagId, const bool value) {
// If the flag is already set, we don't have to recalculate it
if (GetPlayerFlag(flagId) == value) return;
if (value) {
// Update the mission component:
auto* player = Game::entityManager->GetEntity(m_ObjectID);
auto* player = EntityManager::Instance()->GetEntity(m_ObjectID);
if (player != nullptr) {
auto* missionComponent = player->GetComponent<MissionComponent>();
@@ -465,7 +465,7 @@ void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {
GameMessages::SendNotifyClientFlagChange(m_ObjectID, flagId, value, m_ParentUser->GetSystemAddress());
}
bool Character::GetPlayerFlag(const uint32_t flagId) const {
bool Character::GetPlayerFlag(const int32_t flagId) const {
// Calculate the index first
const auto flagIndex = uint32_t(std::floor(flagId / 64));
@@ -602,7 +602,7 @@ void Character::SetCoins(int64_t newCoins, eLootSourceType lootSource) {
m_Coins = newCoins;
GameMessages::SendSetCurrency(Game::entityManager->GetEntity(m_ObjectID), m_Coins, 0, 0, 0, 0, true, lootSource);
GameMessages::SendSetCurrency(EntityManager::Instance()->GetEntity(m_ObjectID), m_Coins, 0, 0, 0, 0, true, lootSource);
}
bool Character::HasBeenToWorld(LWOMAPID mapID) const {

View File

@@ -415,14 +415,14 @@ public:
* @param flagId the ID of the flag to set
* @param value the value to set for the flag
*/
void SetPlayerFlag(uint32_t flagId, bool value);
void SetPlayerFlag(int32_t flagId, bool value);
/**
* Gets the value for a certain character flag
* @param flagId the ID of the flag to get a value for
* @return the value of the flag given the ID (the default is false, obviously)
*/
bool GetPlayerFlag(uint32_t flagId) const;
bool GetPlayerFlag(int32_t flagId) const;
/**
* Notifies the character that they're now muted

View File

@@ -263,7 +263,7 @@ void Entity::Initialize() {
NiQuaternion rot;
const auto& targetSceneName = m_Character->GetTargetScene();
auto* targetScene = Game::entityManager->GetSpawnPointEntity(targetSceneName);
auto* targetScene = EntityManager::Instance()->GetSpawnPointEntity(targetSceneName);
if (m_Character->HasBeenToWorld(mapID) && targetSceneName.empty()) {
pos = m_Character->GetRespawnPoint(mapID);
@@ -386,8 +386,8 @@ void Entity::Initialize() {
comp->SetMaxCoins(currencyValues[0].maxvalue);
}
// extraInfo overrides. Client ORs the database smashable and the luz smashable.
comp->SetIsSmashable(comp->GetIsSmashable() | (GetVarAs<int32_t>(u"is_smashable") != 0));
// extraInfo overrides
comp->SetIsSmashable(GetVarAs<int32_t>(u"is_smashable") != 0);
}
} else {
comp->SetHealth(1);
@@ -595,9 +595,8 @@ void Entity::Initialize() {
m_Components.insert(std::make_pair(eReplicaComponentType::BOUNCER, comp));
}
int32_t renderComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER);
if ((renderComponentId > 0 && m_TemplateID != 2365) || m_Character) {
RenderComponent* render = new RenderComponent(this, renderComponentId);
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER) > 0 && m_TemplateID != 2365) || m_Character) {
RenderComponent* render = new RenderComponent(this);
m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render));
}
@@ -708,13 +707,6 @@ void Entity::Initialize() {
// TODO: create movementAIcomp and set path
}
}*/
} else {
// else we still need to setup moving platform if it has a moving platform comp but no path
int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
if (movingPlatformComponentId >= 0) {
MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat));
}
}
int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR);
@@ -735,7 +727,7 @@ void Entity::Initialize() {
}
});
if (!m_Character && Game::entityManager->GetGhostingEnabled()) {
if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) {
// Don't ghost what is likely large scene elements
if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) {
goto no_ghosting;
@@ -1284,12 +1276,12 @@ void Entity::Update(const float deltaTime) {
}
if (m_ShouldDestroyAfterUpdate) {
Game::entityManager->DestroyEntity(this->GetObjectID());
EntityManager::Instance()->DestroyEntity(this->GetObjectID());
}
}
void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxName, const std::string& status) {
Entity* other = Game::entityManager->GetEntity(otherEntity);
Entity* other = EntityManager::Instance()->GetEntity(otherEntity);
if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@@ -1303,7 +1295,7 @@ void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxN
}
void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {
auto* other = Game::entityManager->GetEntity(otherEntity);
auto* other = EntityManager::Instance()->GetEntity(otherEntity);
if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@@ -1350,7 +1342,7 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {
}
void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) {
auto* other = Game::entityManager->GetEntity(otherEntity);
auto* other = EntityManager::Instance()->GetEntity(otherEntity);
if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@@ -1493,24 +1485,18 @@ void Entity::OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16s
}
}
void Entity::RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
script->OnRequestActivityExit(sender, player, canceled);
}
}
void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType) {
if (!m_PlayerIsReadyForUpdates) return;
auto* destroyableComponent = GetComponent<DestroyableComponent>();
if (destroyableComponent == nullptr) {
Kill(Game::entityManager->GetEntity(source));
Kill(EntityManager::Instance()->GetEntity(source));
return;
}
auto* possessorComponent = GetComponent<PossessorComponent>();
if (possessorComponent) {
if (possessorComponent->GetPossessable() != LWOOBJID_EMPTY) {
auto* mount = Game::entityManager->GetEntity(possessorComponent->GetPossessable());
auto* mount = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable());
if (mount) possessorComponent->Dismount(mount, true);
}
}
@@ -1538,7 +1524,7 @@ void Entity::Kill(Entity* murderer) {
}
if (!IsPlayer()) {
Game::entityManager->DestroyEntity(this);
EntityManager::Instance()->DestroyEntity(this);
}
const auto& grpNameQBShowBricks = GetVar<std::string>(u"grpNameQBShowBricks");
@@ -1719,7 +1705,7 @@ void Entity::CancelCallbackTimers() {
void Entity::ScheduleKillAfterUpdate(Entity* murderer) {
//if (m_Info.spawner) m_Info.spawner->ScheduleKill(this);
Game::entityManager->ScheduleForKill(this);
EntityManager::Instance()->ScheduleForKill(this);
if (murderer) m_ScheduleKiller = murderer;
}
@@ -1763,7 +1749,7 @@ void Entity::TriggerEvent(eTriggerEventType event, Entity* optionalTarget) {
Entity* Entity::GetOwner() const {
if (m_OwnerOverride != LWOOBJID_EMPTY) {
auto* other = Game::entityManager->GetEntity(m_OwnerOverride);
auto* other = EntityManager::Instance()->GetEntity(m_OwnerOverride);
if (other != nullptr) {
return other->GetOwner();
@@ -1827,6 +1813,8 @@ bool Entity::IsSleeping() const {
const NiPoint3& Entity::GetPosition() const {
if (!this) return NiPoint3::ZERO;
auto* controllable = GetComponent<ControllablePhysicsComponent>();
if (controllable != nullptr) {
@@ -1907,7 +1895,7 @@ void Entity::SetPosition(NiPoint3 position) {
vehicel->SetPosition(position);
}
Game::entityManager->SerializeEntity(this);
EntityManager::Instance()->SerializeEntity(this);
}
void Entity::SetRotation(NiQuaternion rotation) {
@@ -1935,7 +1923,7 @@ void Entity::SetRotation(NiQuaternion rotation) {
vehicel->SetRotation(rotation);
}
Game::entityManager->SerializeEntity(this);
EntityManager::Instance()->SerializeEntity(this);
}
bool Entity::GetBoolean(const std::u16string& name) const {
@@ -1987,7 +1975,7 @@ std::vector<LWOOBJID>& Entity::GetTargetsInPhantom() {
for (auto i = 0u; i < m_TargetsInPhantom.size(); ++i) {
const auto id = m_TargetsInPhantom.at(i);
auto* entity = Game::entityManager->GetEntity(id);
auto* entity = EntityManager::Instance()->GetEntity(id);
if (entity == nullptr) {
continue;

View File

@@ -207,7 +207,6 @@ public:
void OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData);
void OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier);
void RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled);
void Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"");
void Kill(Entity* murderer = nullptr);

View File

@@ -25,6 +25,8 @@
#include "eReplicaComponentType.h"
#include "eReplicaPacketType.h"
EntityManager* EntityManager::m_Address = nullptr;
// Configure which zones have ghosting disabled, mostly small worlds.
std::vector<LWOMAPID> EntityManager::m_GhostingExcludedZones = {
// Small zones
@@ -78,6 +80,9 @@ void EntityManager::Initialize() {
if (dZoneManager::Instance()->GetZoneID().GetCloneID() != 0) m_HardcoreMode = false;
}
EntityManager::~EntityManager() {
}
Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentEntity, const bool controller, const LWOOBJID explicitId) {
// Determine the objectID for the new entity

View File

@@ -1,13 +1,12 @@
#ifndef ENTITYMANAGER_H
#define ENTITYMANAGER_H
#include "dCommonVars.h"
#include <map>
#include <stack>
#include <vector>
#include <unordered_map>
#include "dCommonVars.h"
class Entity;
class EntityInfo;
class Player;
@@ -18,8 +17,19 @@ struct SystemAddress;
class EntityManager {
public:
static EntityManager* Instance() {
if (!m_Address) {
m_Address = new EntityManager();
m_Address->Initialize();
}
return m_Address;
}
void Initialize();
~EntityManager();
void UpdateEntities(float deltaTime);
Entity* CreateEntity(EntityInfo info, User* user = nullptr, Entity* parentEntity = nullptr, bool controller = false, LWOOBJID explicitId = LWOOBJID_EMPTY);
void DestroyEntity(const LWOOBJID& objectID);
@@ -79,6 +89,7 @@ private:
void KillEntities();
void DeleteEntities();
static EntityManager* m_Address; //For singleton method
static std::vector<LWOMAPID> m_GhostingExcludedZones;
static std::vector<LOT> m_GhostingExcludedLOTs;

View File

@@ -66,14 +66,14 @@ uint32_t Leaderboard::GetInfoType() const {
}
void Leaderboard::Send(LWOOBJID targetID) const {
auto* player = Game::entityManager->GetEntity(relatedPlayer);
auto* player = EntityManager::Instance()->GetEntity(relatedPlayer);
if (player != nullptr) {
GameMessages::SendActivitySummaryLeaderboardData(targetID, this, player->GetSystemAddress());
}
}
void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t score, uint32_t time) {
const auto* player = Game::entityManager->GetEntity(playerID);
const auto* player = EntityManager::Instance()->GetEntity(playerID);
if (player == nullptr)
return;
@@ -235,7 +235,7 @@ Leaderboard* LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoTy
if (infoType == Standings || infoType == Friends) {
auto characterID = 0;
const auto* player = Game::entityManager->GetEntity(playerID);
const auto* player = EntityManager::Instance()->GetEntity(playerID);
if (player != nullptr) {
auto* character = player->GetCharacter();
if (character != nullptr)

View File

@@ -85,7 +85,7 @@ void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) {
const auto objid = GetObjectID();
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneId, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
auto* entity = Game::entityManager->GetEntity(objid);
auto* entity = EntityManager::Instance()->GetEntity(objid);
if (entity == nullptr) {
return;
@@ -108,7 +108,7 @@ void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) {
WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift);
Game::entityManager->DestructEntity(entity);
EntityManager::Instance()->DestructEntity(entity);
return;
});
}
@@ -135,13 +135,13 @@ void Player::RemoveLimboConstruction(LWOOBJID objectId) {
void Player::ConstructLimboEntities() {
for (const auto objectId : m_LimboConstructions) {
auto* entity = Game::entityManager->GetEntity(objectId);
auto* entity = EntityManager::Instance()->GetEntity(objectId);
if (entity == nullptr) {
continue;
}
Game::entityManager->ConstructEntity(entity, m_SystemAddress);
EntityManager::Instance()->ConstructEntity(entity, m_SystemAddress);
}
m_LimboConstructions.clear();
@@ -224,7 +224,7 @@ Player* Player::GetPlayer(const SystemAddress& sysAddr) {
}
Player* Player::GetPlayer(const std::string& name) {
const auto characters = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER);
const auto characters = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER);
for (auto* character : characters) {
if (!character->IsPlayer()) continue;
@@ -269,7 +269,7 @@ Player::~Player() {
continue;
}
auto* entity = Game::entityManager->GetGhostCandidate(id);
auto* entity = EntityManager::Instance()->GetGhostCandidate(id);
if (entity != nullptr) {
entity->SetObservers(entity->GetObservers() - 1);
@@ -285,12 +285,12 @@ Player::~Player() {
}
if (IsPlayer()) {
Entity* zoneControl = Game::entityManager->GetZoneControlEntity();
Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity();
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) {
script->OnPlayerExit(zoneControl, this);
}
std::vector<Entity*> scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
std::vector<Entity*> scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
for (Entity* scriptEntity : scriptedActs) {
if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds
for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) {

View File

@@ -40,11 +40,11 @@ LWOOBJID Trade::GetParticipantB() const {
}
Entity* Trade::GetParticipantAEntity() const {
return Game::entityManager->GetEntity(m_ParticipantA);
return EntityManager::Instance()->GetEntity(m_ParticipantA);
}
Entity* Trade::GetParticipantBEntity() const {
return Game::entityManager->GetEntity(m_ParticipantB);
return EntityManager::Instance()->GetEntity(m_ParticipantB);
}
void Trade::SetCoins(LWOOBJID participant, uint64_t coins) {

View File

@@ -220,7 +220,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
skillComponent->Reset();
}
Game::entityManager->DestroyEntity(chars[i]->GetEntity());
EntityManager::Instance()->DestroyEntity(chars[i]->GetEntity());
chars[i]->SaveXMLToDatabase();

View File

@@ -39,7 +39,7 @@ void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitS
auto* behavior = CreateBehavior(behaviorId);
if (Game::entityManager->GetEntity(target) != nullptr) {
if (EntityManager::Instance()->GetEntity(target) != nullptr) {
branch.target = target;
}

View File

@@ -6,7 +6,7 @@
void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* entity = Game::entityManager->GetEntity(branch.target == LWOOBJID_EMPTY ? context->originator : branch.target);
auto* entity = EntityManager::Instance()->GetEntity(branch.target == LWOOBJID_EMPTY ? context->originator : branch.target);
if (entity == nullptr) return;
@@ -19,7 +19,7 @@ void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
}
void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
auto* entity = Game::entityManager->GetEntity(branch.target);
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
if (entity == nullptr) return;

View File

@@ -47,7 +47,7 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b
}
void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* self = Game::entityManager->GetEntity(context->caster);
auto* self = EntityManager::Instance()->GetEntity(context->caster);
if (self == nullptr) {
Game::logger->Log("AreaOfEffectBehavior", "Invalid self for (%llu)!", context->originator);
@@ -58,7 +58,7 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream
std::vector<Entity*> targets;
auto* presetTarget = Game::entityManager->GetEntity(branch.target);
auto* presetTarget = EntityManager::Instance()->GetEntity(branch.target);
if (presetTarget != nullptr) {
if (this->m_radius * this->m_radius >= Vector3::DistanceSquared(reference, presetTarget->GetPosition())) {
@@ -75,7 +75,7 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream
// Gets all of the valid targets, passing in if should target enemies and friends
for (auto validTarget : context->GetValidTargets(m_ignoreFaction, includeFaction, m_TargetSelf == 1, m_targetEnemy == 1, m_targetFriend == 1)) {
auto* entity = Game::entityManager->GetEntity(validTarget);
auto* entity = EntityManager::Instance()->GetEntity(validTarget);
if (entity == nullptr) {
Game::logger->Log("AreaOfEffectBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator);

View File

@@ -9,7 +9,7 @@
void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
if (context->unmanaged) {
auto* entity = Game::entityManager->GetEntity(branch.target);
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (destroyableComponent != nullptr) {
@@ -38,7 +38,7 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
}
void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* targetEntity = Game::entityManager->GetEntity(branch.target);
auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target);
if (!targetEntity) {
Game::logger->Log("BasicAttackBehavior", "Target targetEntity %llu not found.", branch.target);
return;
@@ -61,7 +61,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
if (isBlocked) {
destroyableComponent->SetAttacksToBlock(std::min(destroyableComponent->GetAttacksToBlock() - 1, 0U));
Game::entityManager->SerializeEntity(targetEntity);
EntityManager::Instance()->SerializeEntity(targetEntity);
this->m_OnFailBlocked->Handle(context, bitStream, branch);
return;
}
@@ -155,7 +155,7 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream*
}
void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* targetEntity = Game::entityManager->GetEntity(branch.target);
auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target);
if (!targetEntity) {
Game::logger->Log("BasicAttackBehavior", "Target entity %llu is null!", branch.target);
return;
@@ -173,7 +173,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
if (isBlocking) {
destroyableComponent->SetAttacksToBlock(destroyableComponent->GetAttacksToBlock() - 1);
Game::entityManager->SerializeEntity(targetEntity);
EntityManager::Instance()->SerializeEntity(targetEntity);
this->m_OnFailBlocked->Calculate(context, bitStream, branch);
return;
}

View File

@@ -61,7 +61,6 @@
#include "SpeedBehavior.h"
#include "DamageReductionBehavior.h"
#include "JetPackBehavior.h"
#include "FallSpeedBehavior.h"
#include "ChangeIdleFlagsBehavior.h"
#include "DarkInspirationBehavior.h"
@@ -165,9 +164,7 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) {
case BehaviorTemplates::BEHAVIOR_CAR_BOOST:
behavior = new CarBoostBehavior(behaviorId);
break;
case BehaviorTemplates::BEHAVIOR_FALL_SPEED:
behavior = new FallSpeedBehavior(behaviorId);
break;
case BehaviorTemplates::BEHAVIOR_FALL_SPEED: break;
case BehaviorTemplates::BEHAVIOR_SHIELD: break;
case BehaviorTemplates::BEHAVIOR_REPAIR_ARMOR:
behavior = new RepairBehavior(behaviorId);
@@ -314,7 +311,7 @@ BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) {
// For use with enemies, to display the correct damage animations on the players
void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID secondary) {
auto* targetEntity = Game::entityManager->GetEntity(target);
auto* targetEntity = EntityManager::Instance()->GetEntity(target);
if (targetEntity == nullptr) {
return;

View File

@@ -11,7 +11,7 @@
struct BehaviorContext;
struct BehaviorBranchContext;
namespace CDBehaviorParameterTable; {
class CDBehaviorParameterTable;
class Behavior
{

View File

@@ -27,7 +27,7 @@ BehaviorEndEntry::BehaviorEndEntry() {
}
uint32_t BehaviorContext::GetUniqueSkillId() const {
auto* entity = Game::entityManager->GetEntity(this->originator);
auto* entity = EntityManager::Instance()->GetEntity(this->originator);
if (entity == nullptr) {
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
@@ -94,11 +94,11 @@ void BehaviorContext::ScheduleUpdate(const LWOOBJID id) {
void BehaviorContext::ExecuteUpdates() {
for (const auto& id : this->scheduledUpdates) {
auto* entity = Game::entityManager->GetEntity(id);
auto* entity = EntityManager::Instance()->GetEntity(id);
if (entity == nullptr) continue;
Game::entityManager->SerializeEntity(entity);
EntityManager::Instance()->SerializeEntity(entity);
}
this->scheduledUpdates.clear();
@@ -308,7 +308,7 @@ void BehaviorContext::Reset() {
}
std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const {
auto* entity = Game::entityManager->GetEntity(this->caster);
auto* entity = EntityManager::Instance()->GetEntity(this->caster);
std::vector<LWOOBJID> targets;
@@ -320,7 +320,7 @@ std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, in
if (!ignoreFaction && !includeFaction) {
for (auto entry : entity->GetTargetsInPhantom()) {
auto* instance = Game::entityManager->GetEntity(entry);
auto* instance = EntityManager::Instance()->GetEntity(entry);
if (instance == nullptr) {
continue;
@@ -336,7 +336,7 @@ std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, in
return targets;
}
auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS);
auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS);
for (auto* candidate : entities) {
const auto id = candidate->GetObjectID();

View File

@@ -10,7 +10,7 @@
void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
const auto target = context->originator;
auto* entity = Game::entityManager->GetEntity(target);
auto* entity = EntityManager::Instance()->GetEntity(target);
if (entity == nullptr) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
@@ -40,7 +40,7 @@ void BlockBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitSt
void BlockBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
const auto target = context->originator;
auto* entity = Game::entityManager->GetEntity(target);
auto* entity = EntityManager::Instance()->GetEntity(target);
if (entity == nullptr) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);

View File

@@ -10,7 +10,7 @@
void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator;
auto* entity = Game::entityManager->GetEntity(target);
auto* entity = EntityManager::Instance()->GetEntity(target);
if (entity == nullptr) {
Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target);
@@ -30,7 +30,7 @@ void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
component->SetMaxArmor(component->GetMaxArmor() + this->m_armor);
component->SetMaxImagination(component->GetMaxImagination() + this->m_imagination);
Game::entityManager->SerializeEntity(entity);
EntityManager::Instance()->SerializeEntity(entity);
if (!context->unmanaged) {
if (branch.duration > 0) {
@@ -44,7 +44,7 @@ void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator;
auto* entity = Game::entityManager->GetEntity(target);
auto* entity = EntityManager::Instance()->GetEntity(target);
if (entity == nullptr) {
Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target);
@@ -64,7 +64,7 @@ void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch
component->SetMaxArmor(component->GetMaxArmor() - this->m_armor);
component->SetMaxImagination(component->GetMaxImagination() - this->m_imagination);
Game::entityManager->SerializeEntity(entity);
EntityManager::Instance()->SerializeEntity(entity);
}
void BuffBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, LWOOBJID second) {

View File

@@ -22,7 +22,6 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp"
"DurationBehavior.cpp"
"EmptyBehavior.cpp"
"EndBehavior.cpp"
"FallSpeedBehavior.cpp"
"ForceMovementBehavior.cpp"
"HealBehavior.cpp"
"ImaginationBehavior.cpp"

View File

@@ -11,7 +11,7 @@
void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
GameMessages::SendVehicleAddPassiveBoostAction(branch.target, UNASSIGNED_SYSTEM_ADDRESS);
auto* entity = Game::entityManager->GetEntity(context->originator);
auto* entity = EntityManager::Instance()->GetEntity(context->originator);
if (entity == nullptr) {
return;
@@ -22,7 +22,7 @@ void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt
auto* possessableComponent = entity->GetComponent<PossessableComponent>();
if (possessableComponent != nullptr) {
auto* possessor = Game::entityManager->GetEntity(possessableComponent->GetPossessor());
auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor());
if (possessor != nullptr) {
auto* characterComponent = possessor->GetComponent<CharacterComponent>();

View File

@@ -5,14 +5,14 @@
void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
Entity* sourceEntity;
if (this->m_orientCaster) sourceEntity = Game::entityManager->GetEntity(context->originator);
else sourceEntity = Game::entityManager->GetEntity(branch.target);
if (this->m_orientCaster) sourceEntity = EntityManager::Instance()->GetEntity(context->originator);
else sourceEntity = EntityManager::Instance()->GetEntity(branch.target);
if (!sourceEntity) return;
if (this->m_toTarget) {
Entity* destinationEntity;
if (this->m_orientCaster) destinationEntity = Game::entityManager->GetEntity(branch.target);
else destinationEntity = Game::entityManager->GetEntity(context->originator);
if (this->m_orientCaster) destinationEntity = EntityManager::Instance()->GetEntity(branch.target);
else destinationEntity = EntityManager::Instance()->GetEntity(context->originator);
if (!destinationEntity) return;
sourceEntity->SetRotation(
@@ -23,7 +23,7 @@ void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitS
if (this->m_relative) baseAngle += sourceEntity->GetRotation().GetForwardVector();
sourceEntity->SetRotation(NiQuaternion::FromEulerAngles(baseAngle));
} else return;
Game::entityManager->SerializeEntity(sourceEntity);
EntityManager::Instance()->SerializeEntity(sourceEntity);
return;
}

View File

@@ -8,7 +8,7 @@
#include "DestroyableComponent.h"
void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = Game::entityManager->GetEntity(branch.target);
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (target == nullptr) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
@@ -34,7 +34,7 @@ void DamageAbsorptionBehavior::Calculate(BehaviorContext* context, RakNet::BitSt
}
void DamageAbsorptionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) {
auto* target = Game::entityManager->GetEntity(second);
auto* target = EntityManager::Instance()->GetEntity(second);
if (target == nullptr) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);

View File

@@ -8,7 +8,7 @@
#include "DestroyableComponent.h"
void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = Game::entityManager->GetEntity(branch.target);
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (target == nullptr) {
Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", branch.target);
@@ -32,7 +32,7 @@ void DamageReductionBehavior::Calculate(BehaviorContext* context, RakNet::BitStr
}
void DamageReductionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) {
auto* target = Game::entityManager->GetEntity(second);
auto* target = EntityManager::Instance()->GetEntity(second);
if (target == nullptr) {
Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", second);

View File

@@ -7,7 +7,7 @@
#include "BehaviorContext.h"
void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = Game::entityManager->GetEntity(branch.target);
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (target == nullptr) {
Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target);
@@ -26,7 +26,7 @@ void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream
}
void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* target = Game::entityManager->GetEntity(branch.target);
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (target == nullptr) {
Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target);

View File

@@ -1,50 +0,0 @@
#include "FallSpeedBehavior.h"
#include "ControllablePhysicsComponent.h"
#include "BehaviorContext.h"
#include "BehaviorBranchContext.h"
void FallSpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
// make sure required parameter has non-default value
if (m_PercentSlowed == 0.0f) return;
auto* target = Game::entityManager->GetEntity(branch.target);
if (!target) return;
auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->SetGravityScale(m_PercentSlowed);
Game::entityManager->SerializeEntity(target);
if (branch.duration > 0.0f) {
context->RegisterTimerBehavior(this, branch);
} else if (branch.start > 0) {
context->RegisterEndBehavior(this, branch);
}
}
void FallSpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
Handle(context, bitStream, branch);
}
void FallSpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
End(context, branch, second);
}
void FallSpeedBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
End(context, branch, LWOOBJID_EMPTY);
}
void FallSpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
auto* target = Game::entityManager->GetEntity(branch.target);
if (!target) return;
auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->SetGravityScale(1);
Game::entityManager->SerializeEntity(target);
}
void FallSpeedBehavior::Load(){
m_PercentSlowed = GetFloat("percent_slowed");
}

View File

@@ -1,18 +0,0 @@
#pragma once
#include "Behavior.h"
class FallSpeedBehavior final : public Behavior
{
public:
explicit FallSpeedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {}
void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override;
void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override;
void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override;
void Load() override;
private:
float m_PercentSlowed;
};

View File

@@ -42,7 +42,7 @@ void ForceMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStrea
return;
}
auto* casterEntity = Game::entityManager->GetEntity(context->caster);
auto* casterEntity = EntityManager::Instance()->GetEntity(context->caster);
if (casterEntity != nullptr) {
auto* controllablePhysicsComponent = casterEntity->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent != nullptr) {
@@ -51,7 +51,7 @@ void ForceMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStrea
controllablePhysicsComponent->SetVelocity(controllablePhysicsComponent->GetRotation().GetForwardVector() * 25);
}
Game::entityManager->SerializeEntity(casterEntity);
EntityManager::Instance()->SerializeEntity(casterEntity);
}
}
@@ -72,7 +72,7 @@ void ForceMovementBehavior::Load() {
}
void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* casterEntity = Game::entityManager->GetEntity(context->caster);
auto* casterEntity = EntityManager::Instance()->GetEntity(context->caster);
if (casterEntity != nullptr) {
auto* controllablePhysicsComponent = casterEntity->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent != nullptr) {
@@ -80,7 +80,7 @@ void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::Bi
controllablePhysicsComponent->SetPosition(controllablePhysicsComponent->GetPosition() + controllablePhysicsComponent->GetVelocity() * m_Duration);
controllablePhysicsComponent->SetVelocity({});
Game::entityManager->SerializeEntity(casterEntity);
EntityManager::Instance()->SerializeEntity(casterEntity);
}
}

View File

@@ -8,7 +8,7 @@
void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) {
auto* entity = Game::entityManager->GetEntity(branch.target);
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
if (entity == nullptr) {
Game::logger->Log("HealBehavior", "Failed to find entity for (%llu)!", branch.target);

View File

@@ -7,7 +7,7 @@
void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) {
auto* entity = Game::entityManager->GetEntity(branch.target);
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
if (entity == nullptr) {
return;

View File

@@ -10,7 +10,7 @@
#include "eStateChangeType.h"
void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = Game::entityManager->GetEntity(branch.target);
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (!target) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
@@ -56,7 +56,7 @@ void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bi
}
void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) {
auto* target = Game::entityManager->GetEntity(second);
auto* target = EntityManager::Instance()->GetEntity(second);
if (!target) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);

View File

@@ -42,7 +42,7 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
if (branch.target == context->originator) return;
auto* target = Game::entityManager->GetEntity(branch.target);
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (target == nullptr) return;
@@ -67,7 +67,7 @@ void InterruptBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* b
if (branch.target == context->originator) return;
auto* target = Game::entityManager->GetEntity(branch.target);
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (target == nullptr) return;

View File

@@ -6,7 +6,7 @@
#include "Character.h"
void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) {
auto* entity = Game::entityManager->GetEntity(branch.target);
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
GameMessages::SendSetJetPackMode(entity, true, this->m_BypassChecks, this->m_EnableHover, this->m_effectId, this->m_Airspeed, this->m_MaxAirspeed, this->m_VerticalVelocity, this->m_WarningEffectID);
@@ -20,7 +20,7 @@ void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_st
}
void JetPackBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
auto* entity = Game::entityManager->GetEntity(branch.target);
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
GameMessages::SendSetJetPackMode(entity, false);

View File

@@ -21,7 +21,7 @@ void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
bool blocked = false;
auto* target = Game::entityManager->GetEntity(branch.target);
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (target != nullptr) {
auto* destroyableComponent = target->GetComponent<DestroyableComponent>();

Some files were not shown because too many files have changed in this diff Show More