Compare commits

..

5 Commits

Author SHA1 Message Date
David Markowitz
0dd3cce8ed Remove extra includes 2024-01-12 03:26:33 -08:00
David Markowitz
87d5bd0229 remove player cast 2024-01-12 03:17:01 -08:00
David Markowitz
f4a6086e4c Merge branch 'player-stuff' of https://github.com/DarkflameUniverse/DarkflameServer into player-stuff 2024-01-11 04:35:00 -08:00
David Markowitz
eccd6f691f Moving and organizing Player code
- Move code to CharacterComponent
- Remove extraneous interfaces
- Simplify some code greatly
- Change some types to return and take in const ref (only structs larger than 8 bytes benefit from this change.)
- Update code to use CharacterComponent for sending to zone instead of Player*.
- Remove static storage container (static containers can be destroyed before exit/terminate handler executes)
2024-01-11 04:34:55 -08:00
David Markowitz
a54085945f Moving and organizing Player code
- Move code to CharacterComponent
- Remove extraneous interfaces
- Simplify some code greatly
- Change some types to return and take in const ref (only structs larger than 8 bytes benefit from this change.)
- Update code to use CharacterComponent for sending to zone instead of Player*.
2024-01-11 04:33:53 -08:00
585 changed files with 8472 additions and 8750 deletions

View File

@@ -13,7 +13,7 @@ jobs:
continue-on-error: true continue-on-error: true
strategy: strategy:
matrix: matrix:
os: [ windows-2022, ubuntu-22.04, macos-13 ] os: [ windows-2022, ubuntu-20.04, macos-11 ]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@@ -25,11 +25,9 @@ jobs:
with: with:
vs-version: '[17,18)' vs-version: '[17,18)'
msbuild-architecture: x64 msbuild-architecture: x64
- name: Install libssl and switch to XCode 15.2 (Mac Only) - name: Install libssl (Mac Only)
if: ${{ matrix.os == 'macos-13' }} if: ${{ matrix.os == 'macos-11' }}
run: | run: brew install openssl@3
brew install openssl@3
sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
- name: cmake - name: cmake
uses: lukka/run-cmake@v10 uses: lukka/run-cmake@v10
with: with:

View File

@@ -1,26 +1,10 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.18)
project(Darkflame) project(Darkflame)
include(CTest) include(CTest)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export the compile commands for debugging
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Set C and C++ symbol visibility to hide inlined functions
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# Check if link-time-optimization is supported and apply it if possible in release builds
include(CheckIPOSupported)
check_ipo_supported(RESULT supported OUTPUT error)
if(supported)
message(STATUS "IPO / LTO enabled")
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
else()
message(STATUS "IPO / LTO not supported: <${error}>")
endif()
# Read variables from file # Read variables from file
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables) FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
@@ -92,7 +76,6 @@ endif()
# Our output dir # Our output dir
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR}) set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR})
#set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) # unfortunately, forces all libraries to be built in series, which will slow down the build process
# TODO make this not have to override the build type directories # TODO make this not have to override the build type directories
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
@@ -106,8 +89,6 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
find_package(MariaDB)
# Create a /resServer directory # Create a /resServer directory
make_directory(${CMAKE_BINARY_DIR}/resServer) make_directory(${CMAKE_BINARY_DIR}/resServer)
@@ -115,7 +96,7 @@ make_directory(${CMAKE_BINARY_DIR}/resServer)
make_directory(${CMAKE_BINARY_DIR}/logs) make_directory(${CMAKE_BINARY_DIR}/logs)
# Copy resource files on first build # Copy resource files on first build
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blocklist.dcf") set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
message(STATUS "Checking resource file integrity") message(STATUS "Checking resource file integrity")
include(Utils) include(Utils)
@@ -197,7 +178,7 @@ file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PRO
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip) file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
# Copy vanity files on first build # Copy vanity files on first build
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "root.xml" "dev-tribute.xml" "atm.xml" "demo.xml") set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
foreach(file ${VANITY_FILES}) foreach(file ${VANITY_FILES})
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY) configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
@@ -220,47 +201,88 @@ foreach(file ${SQL_FILES})
configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file}) configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
endforeach() endforeach()
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
if (APPLE)
include_directories("/usr/local/include/")
endif()
# Load all of our third party directories
add_subdirectory(thirdparty SYSTEM)
# Create our list of include directories # Create our list of include directories
include_directories( set(INCLUDED_DIRECTORIES
"dCommon"
"dCommon/dClient"
"dCommon/dEnums"
"dChatFilter"
"dGame"
"dGame/dBehaviors"
"dGame/dComponents"
"dGame/dGameMessages"
"dGame/dInventory"
"dGame/dMission"
"dGame/dEntity"
"dGame/dPropertyBehaviors"
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
"dGame/dUtilities"
"dPhysics" "dPhysics"
"dNavigation" "dNavigation"
"dNavigation/dTerrain"
"dZoneManager"
"dDatabase"
"dDatabase/CDClientDatabase"
"dDatabase/CDClientDatabase/CDClientTables"
"dDatabase/GameDatabase"
"dDatabase/GameDatabase/ITables"
"dDatabase/GameDatabase/MySQL"
"dDatabase/GameDatabase/MySQL/Tables"
"dNet" "dNet"
"thirdparty/magic_enum/include/magic_enum"
"thirdparty/raknet/Source"
"thirdparty/tinyxml2"
"thirdparty/recastnavigation"
"thirdparty/SQLite"
"thirdparty/cpplinq"
"thirdparty/cpp-httplib"
"tests" "tests"
"tests/dCommonTests" "tests/dCommonTests"
"tests/dGameTests" "tests/dGameTests"
"tests/dGameTests/dComponentsTests" "tests/dGameTests/dComponentsTests"
SYSTEM "thirdparty/magic_enum/include/magic_enum"
SYSTEM "thirdparty/raknet/Source"
SYSTEM "thirdparty/tinyxml2"
SYSTEM "thirdparty/recastnavigation"
SYSTEM "thirdparty/SQLite"
SYSTEM "thirdparty/cpplinq"
SYSTEM "thirdparty/cpp-httplib"
SYSTEM "thirdparty/MD5"
) )
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux) # Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
# TODO: Should probably not do this.
if(APPLE) if(APPLE)
include_directories("/usr/local/include/") include_directories("/usr/local/include/")
endif() endif()
# Add linking directories: # Actually include the directories from our list
if (UNIX) foreach(dir ${INCLUDED_DIRECTORIES})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast -Werror") # Warning flags include_directories(${PROJECT_SOURCE_DIR}/${dir})
endforeach()
if(NOT WIN32)
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt")
endif() endif()
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include")
# Add linking directories:
link_directories(${PROJECT_BINARY_DIR})
# Load all of our third party directories
add_subdirectory(thirdparty)
# Glob together all headers that need to be precompiled
file(
GLOB HEADERS_DDATABASE
LIST_DIRECTORIES false
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/*.h
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables/*.h
${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables/*.h
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
)
file( file(
GLOB HEADERS_DZONEMANAGER GLOB HEADERS_DZONEMANAGER
LIST_DIRECTORIES false LIST_DIRECTORIES false
@@ -295,7 +317,7 @@ add_subdirectory(dPhysics)
add_subdirectory(dServer) add_subdirectory(dServer)
# Create a list of common libraries shared between all binaries # Create a list of common libraries shared between all binaries
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "MariaDB::ConnCpp" "magic_enum") set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum")
# Add platform specific common libraries # Add platform specific common libraries
if(UNIX) if(UNIX)
@@ -317,6 +339,12 @@ target_precompile_headers(
${HEADERS_DZONEMANAGER} ${HEADERS_DZONEMANAGER}
) )
# Need to specify to use the CXX compiler language here or else we get errors including <string>.
target_precompile_headers(
dDatabase PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
)
target_precompile_headers( target_precompile_headers(
dCommon PRIVATE dCommon PRIVATE
${HEADERS_DCOMMON} ${HEADERS_DCOMMON}

View File

@@ -14,13 +14,13 @@
"generator": "Unix Makefiles" "generator": "Unix Makefiles"
}, },
{ {
"name": "ci-ubuntu-22.04", "name": "ci-ubuntu-20.04",
"displayName": "CI configure step for Ubuntu", "displayName": "CI configure step for Ubuntu",
"description": "Same as default, Used in GitHub actions workflow", "description": "Same as default, Used in GitHub actions workflow",
"inherits": "default" "inherits": "default"
}, },
{ {
"name": "ci-macos-13", "name": "ci-macos-11",
"displayName": "CI configure step for MacOS", "displayName": "CI configure step for MacOS",
"description": "Same as default, Used in GitHub actions workflow", "description": "Same as default, Used in GitHub actions workflow",
"inherits": "default" "inherits": "default"
@@ -67,15 +67,15 @@
"jobs": 2 "jobs": 2
}, },
{ {
"name": "ci-ubuntu-22.04", "name": "ci-ubuntu-20.04",
"configurePreset": "ci-ubuntu-22.04", "configurePreset": "ci-ubuntu-20.04",
"displayName": "Linux CI Build", "displayName": "Linux CI Build",
"description": "This preset is used by the CI build on linux", "description": "This preset is used by the CI build on linux",
"jobs": 2 "jobs": 2
}, },
{ {
"name": "ci-macos-13", "name": "ci-macos-11",
"configurePreset": "ci-macos-13", "configurePreset": "ci-macos-11",
"displayName": "MacOS CI Build", "displayName": "MacOS CI Build",
"description": "This preset is used by the CI build on MacOS", "description": "This preset is used by the CI build on MacOS",
"jobs": 2 "jobs": 2
@@ -83,8 +83,8 @@
], ],
"testPresets": [ "testPresets": [
{ {
"name": "ci-ubuntu-22.04", "name": "ci-ubuntu-20.04",
"configurePreset": "ci-ubuntu-22.04", "configurePreset": "ci-ubuntu-20.04",
"displayName": "CI Tests on Linux", "displayName": "CI Tests on Linux",
"description": "Runs all tests on a linux configuration", "description": "Runs all tests on a linux configuration",
"execution": { "execution": {
@@ -95,8 +95,8 @@
} }
}, },
{ {
"name": "ci-macos-13", "name": "ci-macos-11",
"configurePreset": "ci-macos-13", "configurePreset": "ci-macos-11",
"displayName": "CI Tests on MacOS", "displayName": "CI Tests on MacOS",
"description": "Runs all tests on a Mac configuration", "description": "Runs all tests on a Mac configuration",
"execution": { "execution": {

View File

@@ -23,7 +23,8 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
rm -rf /var/lib/apt/lists/* rm -rf /var/lib/apt/lists/*
# Grab libraries and load them # Grab libraries and load them
COPY --from=build /app/build/mariadbcpp/libmariadbcpp.so /usr/local/lib/ COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadbcpp.so /usr/local/lib/
COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadb/libmariadb/libmariadb.so.3 /usr/local/lib
RUN ldconfig RUN ldconfig
# Server bins # Server bins

View File

@@ -51,7 +51,7 @@ git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
### Windows packages ### Windows packages
Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed. Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed.
You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.25**</font> or later!). You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.18**</font> or later!).
### MacOS packages ### MacOS packages
Ensure you have [brew](https://brew.sh) installed. Ensure you have [brew](https://brew.sh) installed.
@@ -73,7 +73,7 @@ sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-serve
``` ```
#### Required CMake version #### Required CMake version
This project uses <font size="4">**CMake version 3.25**</font> or higher and as such you will need to ensure you have this version installed. This project uses <font size="4">**CMake version 3.18**</font> or higher and as such you will need to ensure you have this version installed.
You can check your CMake version by using the following command in a terminal. You can check your CMake version by using the following command in a terminal.
```bash ```bash
cmake --version cmake --version
@@ -356,10 +356,6 @@ The Darkflame Server is automatically built and published as a Docker Container
## Compose ## Compose
> [!WARNING]
> It seems that Docker Desktop on Windows with the WSL 2 backend has some issues with MariaDB (c.f. [mariadb-docker#331](https://github.com/MariaDB/mariadb-docker/issues/331)) triggered by NexusDashboard
> migrations, so this setup may not work for you. If that is the case, please tell us about your setup in [NexusDashboard#92](https://github.com/DarkflameUniverse/NexusDashboard/issues/92).
You can use the `docker-compose` tool to [setup a MariaDB database](#database-setup), run the Darkflame Server and manage it with [Nexus Dashboard](https://github.com/DarkflameUniverse/NexusDashboard) all You can use the `docker-compose` tool to [setup a MariaDB database](#database-setup), run the Darkflame Server and manage it with [Nexus Dashboard](https://github.com/DarkflameUniverse/NexusDashboard) all
at once. For that: at once. For that:

View File

@@ -1,17 +0,0 @@
include(FetchContent)
message(STATUS "Fetching gtest...")
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(GoogleTest)
message(STATUS "gtest fetched and is now ready.")
set(GoogleTest_FOUND TRUE)

View File

@@ -82,11 +82,11 @@ int main(int argc, char** argv) {
Game::randomEngine = std::mt19937(time(0)); Game::randomEngine = std::mt19937(time(0));
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 999;
uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
std::string ourIP = "localhost"; std::string ourIP = "localhost";
const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999); GeneralUtils::TryParse(Game::config->GetValue("max_clients"), maxClients);
GeneralUtils::TryParse(Game::config->GetValue("auth_server_port"), ourPort);
//LU client is hardcoded to use this for auth port, so I'm making it the default.
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("auth_server_port")).value_or(1001);
const auto externalIPString = Game::config->GetValue("external_ip"); const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString; if (!externalIPString.empty()) ourIP = externalIPString;

View File

@@ -27,8 +27,8 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
ExportWordlistToDCF(filepath + ".dcf", true); ExportWordlistToDCF(filepath + ".dcf", true);
} }
if (BinaryIO::DoesFileExist("blocklist.dcf")) { if (BinaryIO::DoesFileExist("blacklist.dcf")) {
ReadWordlistDCF("blocklist.dcf", false); ReadWordlistDCF("blacklist.dcf", false);
} }
//Read player names that are ok as well: //Read player names that are ok as well:
@@ -44,20 +44,20 @@ dChatFilter::~dChatFilter() {
m_DeniedWords.clear(); m_DeniedWords.clear();
} }
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool allowList) { void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) {
std::ifstream file(filepath); std::ifstream file(filepath);
if (file) { if (file) {
std::string line; std::string line;
while (std::getline(file, line)) { while (std::getline(file, line)) {
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
if (allowList) m_ApprovedWords.push_back(CalculateHash(line)); if (whiteList) m_ApprovedWords.push_back(CalculateHash(line));
else m_DeniedWords.push_back(CalculateHash(line)); else m_DeniedWords.push_back(CalculateHash(line));
} }
} }
} }
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool allowList) { bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
std::ifstream file(filepath, std::ios::binary); std::ifstream file(filepath, std::ios::binary);
if (file) { if (file) {
fileHeader hdr; fileHeader hdr;
@@ -70,13 +70,13 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool allowList) {
if (hdr.formatVersion == formatVersion) { if (hdr.formatVersion == formatVersion) {
size_t wordsToRead = 0; size_t wordsToRead = 0;
BinaryIO::BinaryRead(file, wordsToRead); BinaryIO::BinaryRead(file, wordsToRead);
if (allowList) m_ApprovedWords.reserve(wordsToRead); if (whiteList) m_ApprovedWords.reserve(wordsToRead);
else m_DeniedWords.reserve(wordsToRead); else m_DeniedWords.reserve(wordsToRead);
size_t word = 0; size_t word = 0;
for (size_t i = 0; i < wordsToRead; ++i) { for (size_t i = 0; i < wordsToRead; ++i) {
BinaryIO::BinaryRead(file, word); BinaryIO::BinaryRead(file, word);
if (allowList) m_ApprovedWords.push_back(word); if (whiteList) m_ApprovedWords.push_back(word);
else m_DeniedWords.push_back(word); else m_DeniedWords.push_back(word);
} }
@@ -90,14 +90,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool allowList) {
return false; return false;
} }
void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool allowList) { void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) {
std::ofstream file(filepath, std::ios::binary | std::ios_base::out); std::ofstream file(filepath, std::ios::binary | std::ios_base::out);
if (file) { if (file) {
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header)); BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion)); BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
BinaryIO::BinaryWrite(file, size_t(allowList ? m_ApprovedWords.size() : m_DeniedWords.size())); BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size()));
for (size_t word : allowList ? m_ApprovedWords : m_DeniedWords) { for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) {
BinaryIO::BinaryWrite(file, word); BinaryIO::BinaryWrite(file, word);
} }
@@ -105,10 +105,10 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool allowLis
} }
} }
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList) { std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) {
if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
if (message.empty()) return { }; if (message.empty()) return { };
if (!allowList && m_DeniedWords.empty()) return { { 0, message.length() } }; if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } };
std::stringstream sMessage(message); std::stringstream sMessage(message);
std::string segment; std::string segment;
@@ -126,16 +126,16 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
size_t hash = CalculateHash(segment); size_t hash = CalculateHash(segment);
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && allowList) { if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) {
listOfBadSegments.emplace_back(position, originalSegment.length()); listOfBadSegments.emplace_back(position, originalSegment.length());
} }
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && allowList) { if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) {
m_UserUnapprovedWordCache.push_back(hash); m_UserUnapprovedWordCache.push_back(hash);
listOfBadSegments.emplace_back(position, originalSegment.length()); listOfBadSegments.emplace_back(position, originalSegment.length());
} }
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !allowList) { if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) {
m_UserUnapprovedWordCache.push_back(hash); m_UserUnapprovedWordCache.push_back(hash);
listOfBadSegments.emplace_back(position, originalSegment.length()); listOfBadSegments.emplace_back(position, originalSegment.length());
} }

View File

@@ -21,10 +21,10 @@ public:
dChatFilter(const std::string& filepath, bool dontGenerateDCF); dChatFilter(const std::string& filepath, bool dontGenerateDCF);
~dChatFilter(); ~dChatFilter();
void ReadWordlistPlaintext(const std::string& filepath, bool allowList); void ReadWordlistPlaintext(const std::string& filepath, bool whiteList);
bool ReadWordlistDCF(const std::string& filepath, bool allowList); bool ReadWordlistDCF(const std::string& filepath, bool whiteList);
void ExportWordlistToDCF(const std::string& filepath, bool allowList); void ExportWordlistToDCF(const std::string& filepath, bool whiteList);
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList = true); std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true);
private: private:
bool m_DontGenerateDCF; bool m_DontGenerateDCF;

View File

@@ -5,11 +5,9 @@ set(DCHATSERVER_SOURCES
) )
add_executable(ChatServer "ChatServer.cpp") add_executable(ChatServer "ChatServer.cpp")
target_include_directories(ChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dChatFilter")
add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
add_library(dChatServer ${DCHATSERVER_SOURCES}) add_library(dChatServer ${DCHATSERVER_SOURCES})
target_include_directories(dChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dServer") target_include_directories(dChatServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer)
add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter) target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer) target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer)

View File

@@ -1,6 +1,6 @@
#include "ChatIgnoreList.h" #include "ChatIgnoreList.h"
#include "PlayerContainer.h" #include "PlayerContainer.h"
#include "eChatMessageType.h" #include "eChatInternalMessageType.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "Game.h" #include "Game.h"
#include "Logger.h" #include "Logger.h"
@@ -13,7 +13,7 @@
// The only thing not auto-handled is instance activities force joining the team on the server. // The only thing not auto-handled is instance activities force joining the team on the server.
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) { void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) {
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receivingPlayer); bitStream.Write(receivingPlayer);
//portion that will get routed: //portion that will get routed:
@@ -59,7 +59,7 @@ void ChatIgnoreList::GetIgnoreList(Packet* packet) {
bitStream.Write(LUWString(ignoredPlayer.playerName, 36)); bitStream.Write(LUWString(ignoredPlayer.playerName, 36));
} }
Game::server->Send(bitStream, packet->systemAddress, false); Game::server->Send(&bitStream, packet->systemAddress, false);
} }
void ChatIgnoreList::AddIgnore(Packet* packet) { void ChatIgnoreList::AddIgnore(Packet* packet) {
@@ -81,7 +81,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
inStream.IgnoreBytes(4); // ignore some garbage zeros idk inStream.IgnoreBytes(4); // ignore some garbage zeros idk
LUWString toIgnoreName; LUWString toIgnoreName(33);
inStream.Read(toIgnoreName); inStream.Read(toIgnoreName);
std::string toIgnoreStr = toIgnoreName.GetAsString(); std::string toIgnoreStr = toIgnoreName.GetAsString();
@@ -131,7 +131,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
bitStream.Write(playerNameSend); bitStream.Write(playerNameSend);
bitStream.Write(ignoredPlayerId); bitStream.Write(ignoredPlayerId);
Game::server->Send(bitStream, packet->systemAddress, false); Game::server->Send(&bitStream, packet->systemAddress, false);
} }
void ChatIgnoreList::RemoveIgnore(Packet* packet) { void ChatIgnoreList::RemoveIgnore(Packet* packet) {
@@ -147,7 +147,7 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
inStream.IgnoreBytes(4); // ignore some garbage zeros idk inStream.IgnoreBytes(4); // ignore some garbage zeros idk
LUWString removedIgnoreName; LUWString removedIgnoreName(33);
inStream.Read(removedIgnoreName); inStream.Read(removedIgnoreName);
std::string removedIgnoreStr = removedIgnoreName.GetAsString(); std::string removedIgnoreStr = removedIgnoreName.GetAsString();
@@ -167,5 +167,5 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
LUWString playerNameSend(removedIgnoreStr, 33); LUWString playerNameSend(removedIgnoreStr, 33);
bitStream.Write(playerNameSend); bitStream.Write(playerNameSend);
Game::server->Send(bitStream, packet->systemAddress, false); Game::server->Send(&bitStream, packet->systemAddress, false);
} }

View File

@@ -2,6 +2,7 @@
#include "PlayerContainer.h" #include "PlayerContainer.h"
#include "Database.h" #include "Database.h"
#include <vector> #include <vector>
#include "PacketUtils.h"
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "Game.h" #include "Game.h"
#include "dServer.h" #include "dServer.h"
@@ -14,10 +15,9 @@
#include "eObjectBits.h" #include "eObjectBits.h"
#include "eConnectionType.h" #include "eConnectionType.h"
#include "eChatMessageType.h" #include "eChatMessageType.h"
#include "eChatInternalMessageType.h"
#include "eClientMessageType.h" #include "eClientMessageType.h"
#include "eGameMessageType.h" #include "eGameMessageType.h"
#include "StringifiedEnum.h"
#include "eGameMasterLevel.h"
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Get from the packet which player we want to do something with: //Get from the packet which player we want to do something with:
@@ -59,7 +59,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Now, we need to send the friendlist to the server they came from: //Now, we need to send the friendlist to the server they came from:
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(playerID); bitStream.Write(playerID);
//portion that will get routed: //portion that will get routed:
@@ -78,17 +78,22 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
void ChatPacketHandler::HandleFriendRequest(Packet* packet) { void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID requestorPlayerID; LWOOBJID requestorPlayerID;
LUWString LUplayerName;
char isBestFriendRequest{};
inStream.Read(requestorPlayerID); inStream.Read(requestorPlayerID);
inStream.IgnoreBytes(4); uint32_t spacing{};
inStream.Read(LUplayerName); inStream.Read(spacing);
inStream.Read(isBestFriendRequest); std::string playerName = "";
uint16_t character;
bool noMoreLettersInName = false;
auto playerName = LUplayerName.GetAsString(); for (uint32_t j = 0; j < 33; j++) {
inStream.Read(character);
if (character == '\0') noMoreLettersInName = true;
if (!noMoreLettersInName) playerName.push_back(static_cast<char>(character));
}
char isBestFriendRequest{};
inStream.Read(isBestFriendRequest);
auto& requestor = Game::playerContainer.GetPlayerDataMutable(requestorPlayerID); auto& requestor = Game::playerContainer.GetPlayerDataMutable(requestorPlayerID);
if (!requestor) { if (!requestor) {
@@ -96,9 +101,8 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
return; return;
} }
// you cannot friend yourself
if (requestor.playerName == playerName) { if (requestor.playerName == playerName) {
SendFriendResponse(requestor, requestor, eAddFriendResponseType::GENERALERROR); SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
return; return;
}; };
@@ -137,13 +141,6 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
return; return;
} }
// Prevent GM friend spam
// If the player we are trying to be friends with is not a civilian and we are a civilian, abort the process
if (requestee.gmLevel > eGameMasterLevel::CIVILIAN && requestor.gmLevel == eGameMasterLevel::CIVILIAN ) {
SendFriendResponse(requestor, requestee, eAddFriendResponseType::MYTHRAN);
return;
}
if (isBestFriendRequest) { if (isBestFriendRequest) {
uint8_t oldBestFriendStatus{}; uint8_t oldBestFriendStatus{};
@@ -221,19 +218,15 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
void ChatPacketHandler::HandleFriendResponse(Packet* packet) { void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
eAddFriendResponseCode clientResponseCode;
LUWString friendName;
inStream.Read(playerID); inStream.Read(playerID);
inStream.IgnoreBytes(4);
inStream.Read(clientResponseCode); eAddFriendResponseCode clientResponseCode = static_cast<eAddFriendResponseCode>(packet->data[0x14]);
inStream.Read(friendName); std::string friendName = PacketUtils::ReadString(0x15, packet, true);
//Now to try and find both of these: //Now to try and find both of these:
auto& requestor = Game::playerContainer.GetPlayerDataMutable(playerID); auto& requestor = Game::playerContainer.GetPlayerDataMutable(playerID);
auto& requestee = Game::playerContainer.GetPlayerDataMutable(friendName.GetAsString()); auto& requestee = Game::playerContainer.GetPlayerDataMutable(friendName);
if (!requestor || !requestee) return; if (!requestor || !requestee) return;
eAddFriendResponseType serverResponseCode{}; eAddFriendResponseType serverResponseCode{};
@@ -295,11 +288,8 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
LUWString LUFriendName;
inStream.Read(playerID); inStream.Read(playerID);
inStream.IgnoreBytes(4); std::string friendName = PacketUtils::ReadString(0x14, packet, true);
inStream.Read(LUFriendName);
auto friendName = LUFriendName.GetAsString();
//we'll have to query the db here to find the user, since you can delete them while they're offline. //we'll have to query the db here to find the user, since you can delete them while they're offline.
//First, we need to find their ID: //First, we need to find their ID:
@@ -345,144 +335,123 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
SendRemoveFriend(goonB, goonAName, true); SendRemoveFriend(goonB, goonAName, true);
} }
void ChatPacketHandler::HandleGMLevelUpdate(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerID;
inStream.Read(playerID);
auto& player = Game::playerContainer.GetPlayerData(playerID);
if (!player) return;
inStream.Read(player.gmLevel);
}
// the structure the client uses to send this packet is shared in many chat messages
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages
void ChatPacketHandler::HandleChatMessage(Packet* packet) { void ChatPacketHandler::HandleChatMessage(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
const auto& sender = Game::playerContainer.GetPlayerData(playerID); const auto& sender = Game::playerContainer.GetPlayerData(playerID);
if (!sender || sender.GetIsMuted()) return;
eChatChannel channel; if (!sender) return;
uint32_t size;
inStream.IgnoreBytes(4); if (sender.GetIsMuted()) return;
inStream.SetReadOffset(0x14 * 8);
uint8_t channel = 0;
inStream.Read(channel); inStream.Read(channel);
inStream.Read(size);
inStream.IgnoreBytes(77);
LUWString message(size); std::string message = PacketUtils::ReadString(0x66, packet, true, 512);
inStream.Read(message);
LOG("Got a message from (%s) via [%s]: %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str()); LOG("Got a message from (%s) [%d]: %s", sender.playerName.c_str(), channel, message.c_str());
if (channel != 8) return;
switch (channel) {
case eChatChannel::TEAM: {
auto* team = Game::playerContainer.GetTeam(playerID); auto* team = Game::playerContainer.GetTeam(playerID);
if (team == nullptr) return; if (team == nullptr) return;
for (const auto memberId : team->memberIDs) { for (const auto memberId : team->memberIDs) {
const auto& otherMember = Game::playerContainer.GetPlayerData(memberId); const auto& otherMember = Game::playerContainer.GetPlayerData(memberId);
if (!otherMember) return; if (!otherMember) return;
SendPrivateChatMessage(sender, otherMember, otherMember, message, eChatChannel::TEAM, eChatMessageResponseCode::SENT);
}
break;
}
default:
LOG("Unhandled Chat channel [%s]", StringifiedEnum::ToString(channel).data());
break;
}
}
// the structure the client uses to send this packet is shared in many chat messages
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages
void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
CINSTREAM_SKIP_HEADER;
LWOOBJID playerID;
inStream.Read(playerID);
const auto& sender = Game::playerContainer.GetPlayerData(playerID);
if (!sender || sender.GetIsMuted()) return;
eChatChannel channel;
uint32_t size;
LUWString LUReceiverName;
inStream.IgnoreBytes(4);
inStream.Read(channel);
if (channel != eChatChannel::PRIVATE_CHAT) LOG("WARNING: Received Private chat with the wrong channel!");
inStream.Read(size);
inStream.IgnoreBytes(77);
inStream.Read(LUReceiverName);
auto receiverName = LUReceiverName.GetAsString();
inStream.IgnoreBytes(2);
LUWString message(size);
inStream.Read(message);
LOG("Got a message from (%s) via [%s]: %s to %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str(), receiverName.c_str());
const auto& receiver = Game::playerContainer.GetPlayerData(receiverName);
if (!receiver) {
PlayerData otherPlayer;
otherPlayer.playerName = receiverName;
auto responseType = Database::Get()->GetCharacterInfo(receiverName)
? eChatMessageResponseCode::NOTONLINE
: eChatMessageResponseCode::GENERALERROR;
SendPrivateChatMessage(sender, otherPlayer, sender, message, eChatChannel::GENERAL, responseType);
return;
}
// Check to see if they are friends
// only freinds can whispr each other
for (const auto& fr : receiver.friends) {
if (fr.friendID == sender.playerID) {
//To the sender:
SendPrivateChatMessage(sender, receiver, sender, message, eChatChannel::PRIVATE_CHAT, eChatMessageResponseCode::SENT);
//To the receiver:
SendPrivateChatMessage(sender, receiver, receiver, message, eChatChannel::PRIVATE_CHAT, eChatMessageResponseCode::RECEIVEDNEWWHISPER);
return;
}
}
SendPrivateChatMessage(sender, receiver, sender, message, eChatChannel::GENERAL, eChatMessageResponseCode::NOTFRIENDS);
}
void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(routeTo.playerID); bitStream.Write(otherMember.playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
bitStream.Write(sender.playerID); bitStream.Write(otherMember.playerID);
bitStream.Write(channel); bitStream.Write<uint8_t>(8);
bitStream.Write<uint32_t>(0); // not used bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(sender.playerName)); bitStream.Write(LUWString(sender.playerName));
bitStream.Write(sender.playerID); bitStream.Write(sender.playerID);
bitStream.Write<uint16_t>(0); // sourceID bitStream.Write<uint16_t>(0);
bitStream.Write(sender.gmLevel); bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(receiver.playerName)); bitStream.Write(LUWString(otherMember.playerName));
bitStream.Write(receiver.gmLevel); bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write(responseCode); bitStream.Write<uint8_t>(0); //teams?
bitStream.Write(message); bitStream.Write(LUWString(message, 512));
SystemAddress sysAddr = routeTo.sysAddr; SystemAddress sysAddr = otherMember.sysAddr;
SEND_PACKET; SEND_PACKET;
}
} }
void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
LWOOBJID senderID = PacketUtils::ReadS64(0x08, packet);
std::string receiverName = PacketUtils::ReadString(0x66, packet, true);
std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
//Get the bois:
const auto& goonA = Game::playerContainer.GetPlayerData(senderID);
const auto& goonB = Game::playerContainer.GetPlayerData(receiverName);
if (!goonA || !goonB) return;
if (goonA.GetIsMuted()) return;
//To the sender:
{
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(goonA.playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
bitStream.Write(goonA.playerID);
bitStream.Write<uint8_t>(7);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(goonA.playerName));
bitStream.Write(goonA.playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(goonB.playerName));
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(0); //success
bitStream.Write(LUWString(message, 512));
SystemAddress sysAddr = goonA.sysAddr;
SEND_PACKET;
}
//To the receiver:
{
CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(goonB.playerID);
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
bitStream.Write(goonA.playerID);
bitStream.Write<uint8_t>(7);
bitStream.Write<unsigned int>(69);
bitStream.Write(LUWString(goonA.playerName));
bitStream.Write(goonA.playerID);
bitStream.Write<uint16_t>(0);
bitStream.Write<uint8_t>(0); //not mythran nametag
bitStream.Write(LUWString(goonB.playerName));
bitStream.Write<uint8_t>(0); //not mythran for receiver
bitStream.Write<uint8_t>(3); //new whisper
bitStream.Write(LUWString(message, 512));
SystemAddress sysAddr = goonB.sysAddr;
SEND_PACKET;
}
}
void ChatPacketHandler::HandleTeamInvite(Packet* packet) { void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
LUWString invitedPlayer;
inStream.Read(playerID); inStream.Read(playerID);
inStream.IgnoreBytes(4); std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true);
inStream.Read(invitedPlayer);
const auto& player = Game::playerContainer.GetPlayerData(playerID); const auto& player = Game::playerContainer.GetPlayerData(playerID);
@@ -494,7 +463,7 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
team = Game::playerContainer.CreateTeam(playerID); team = Game::playerContainer.CreateTeam(playerID);
} }
const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer.GetAsString()); const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer);
if (!other) return; if (!other) return;
@@ -511,7 +480,7 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
SendTeamInvite(other, player); SendTeamInvite(other, player);
LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.GetAsString().c_str()); LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
} }
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) { void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
@@ -565,25 +534,21 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
void ChatPacketHandler::HandleTeamKick(Packet* packet) { void ChatPacketHandler::HandleTeamKick(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
LUWString kickedPlayer;
inStream.Read(playerID); inStream.Read(playerID);
inStream.IgnoreBytes(4);
inStream.Read(kickedPlayer);
std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true);
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.GetAsString().c_str()); LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
const auto& kicked = Game::playerContainer.GetPlayerData(kickedPlayer.GetAsString()); const auto& kicked = Game::playerContainer.GetPlayerData(kickedPlayer);
LWOOBJID kickedId = LWOOBJID_EMPTY; LWOOBJID kickedId = LWOOBJID_EMPTY;
if (kicked) { if (kicked) {
kickedId = kicked.playerID; kickedId = kicked.playerID;
} else { } else {
kickedId = Game::playerContainer.GetId(kickedPlayer.string); kickedId = Game::playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
} }
if (kickedId == LWOOBJID_EMPTY) return; if (kickedId == LWOOBJID_EMPTY) return;
@@ -599,17 +564,14 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
void ChatPacketHandler::HandleTeamPromote(Packet* packet) { void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
CINSTREAM_SKIP_HEADER; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
LUWString promotedPlayer;
inStream.Read(playerID); inStream.Read(playerID);
inStream.IgnoreBytes(4);
inStream.Read(promotedPlayer);
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.GetAsString().c_str()); std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true);
const auto& promoted = Game::playerContainer.GetPlayerData(promotedPlayer.GetAsString()); LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
const auto& promoted = Game::playerContainer.GetPlayerData(promotedPlayer);
if (!promoted) return; if (!promoted) return;
@@ -695,7 +657,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) { void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
@@ -710,7 +672,7 @@ void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerD
void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) { void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
@@ -737,7 +699,7 @@ void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool b
void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) { void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
@@ -762,7 +724,7 @@ void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64L
void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) { void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
@@ -779,7 +741,7 @@ void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i
void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) { void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
@@ -808,7 +770,7 @@ void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFr
void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) { void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
@@ -834,7 +796,7 @@ void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bD
void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) { void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
@@ -868,7 +830,7 @@ void ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const Pla
[bool] - is FTP*/ [bool] - is FTP*/
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(friendData.playerID); bitStream.Write(friendData.playerID);
//portion that will get routed: //portion that will get routed:
@@ -905,7 +867,7 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
} }
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:
@@ -919,7 +881,7 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) { void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
// Portion that will get routed: // Portion that will get routed:
@@ -942,7 +904,7 @@ void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const Pla
void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) { void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
bitStream.Write(receiver.playerID); bitStream.Write(receiver.playerID);
//portion that will get routed: //portion that will get routed:

View File

@@ -7,53 +7,14 @@ struct PlayerData;
enum class eAddFriendResponseType : uint8_t; enum class eAddFriendResponseType : uint8_t;
enum class eChatChannel : uint8_t {
SYSTEMNOTIFY = 0,
SYSTEMWARNING,
SYSTEMERROR,
BROADCAST,
LOCAL,
LOCALNOANIM,
EMOTE,
PRIVATE_CHAT,
TEAM,
TEAMLOCAL,
GUILD,
GUILDNOTIFY,
PROPERTY,
ADMIN,
COMBATDAMAGE,
COMBATHEALING,
COMBATLOOT,
COMBATEXP,
COMBATDEATH,
GENERAL,
TRADE,
LFG,
USER
};
enum class eChatMessageResponseCode : uint8_t {
SENT = 0,
NOTONLINE,
GENERALERROR,
RECEIVEDNEWWHISPER,
NOTFRIENDS,
SENDERFREETRIAL,
RECEIVERFREETRIAL,
};
namespace ChatPacketHandler { namespace ChatPacketHandler {
void HandleFriendlistRequest(Packet* packet); void HandleFriendlistRequest(Packet* packet);
void HandleFriendRequest(Packet* packet); void HandleFriendRequest(Packet* packet);
void HandleFriendResponse(Packet* packet); void HandleFriendResponse(Packet* packet);
void HandleRemoveFriend(Packet* packet); void HandleRemoveFriend(Packet* packet);
void HandleGMLevelUpdate(Packet* packet);
void HandleChatMessage(Packet* packet); void HandleChatMessage(Packet* packet);
void HandlePrivateChatMessage(Packet* packet); void HandlePrivateChatMessage(Packet* packet);
void SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode);
void HandleTeamInvite(Packet* packet); void HandleTeamInvite(Packet* packet);
void HandleTeamInviteResponse(Packet* packet); void HandleTeamInviteResponse(Packet* packet);

View File

@@ -17,9 +17,9 @@
#include "PlayerContainer.h" #include "PlayerContainer.h"
#include "ChatPacketHandler.h" #include "ChatPacketHandler.h"
#include "eChatMessageType.h" #include "eChatMessageType.h"
#include "eChatInternalMessageType.h"
#include "eWorldMessageType.h" #include "eWorldMessageType.h"
#include "ChatIgnoreList.h" #include "ChatIgnoreList.h"
#include "StringifiedEnum.h"
#include "Game.h" #include "Game.h"
#include "Server.h" #include "Server.h"
@@ -98,15 +98,18 @@ int main(int argc, char** argv) {
masterPort = masterInfo->port; masterPort = masterInfo->port;
} }
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 999;
uint32_t ourPort = 1501;
std::string ourIP = "localhost"; std::string ourIP = "localhost";
const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999); GeneralUtils::TryParse(Game::config->GetValue("max_clients"), maxClients);
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("chat_server_port")).value_or(2005); GeneralUtils::TryParse(Game::config->GetValue("chat_server_port"), ourPort);
const auto externalIPString = Game::config->GetValue("external_ip"); const auto externalIPString = Game::config->GetValue("external_ip");
if (!externalIPString.empty()) ourIP = externalIPString; if (!externalIPString.empty()) ourIP = externalIPString;
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal); Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false); bool dontGenerateDCF = false;
GeneralUtils::TryParse(Game::config->GetValue("dont_generate_dcf"), dontGenerateDCF);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
Game::randomEngine = std::mt19937(time(0)); Game::randomEngine = std::mt19937(time(0));
@@ -181,29 +184,46 @@ int main(int argc, char** argv) {
void HandlePacket(Packet* packet) { void HandlePacket(Packet* packet) {
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
LOG("A server has disconnected, erasing their connected players from the list."); LOG("A server has disconnected, erasing their connected players from the list.");
} else if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) { }
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
LOG("A server is connecting, awaiting user list."); LOG("A server is connecting, awaiting user list.");
} else if (packet->length < 4 || packet->data[0] != ID_USER_PACKET_ENUM) return; // Nothing left to process or not the right packet type }
CINSTREAM; if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
inStream.SetReadOffset(BYTES_TO_BITS(1));
eConnectionType connection; if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
eChatMessageType chatMessageID; switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
Game::playerContainer.InsertPlayer(packet);
break;
inStream.Read(connection); case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
if (connection != eConnectionType::CHAT) return; Game::playerContainer.RemovePlayer(packet);
inStream.Read(chatMessageID); break;
switch (chatMessageID) { case eChatInternalMessageType::MUTE_UPDATE:
case eChatMessageType::GM_MUTE:
Game::playerContainer.MuteUpdate(packet); Game::playerContainer.MuteUpdate(packet);
break; break;
case eChatMessageType::CREATE_TEAM: case eChatInternalMessageType::CREATE_TEAM:
Game::playerContainer.CreateTeamServer(packet); Game::playerContainer.CreateTeamServer(packet);
break; break;
case eChatInternalMessageType::ANNOUNCEMENT: {
//we just forward this packet to every connected server
CINSTREAM;
Game::server->Send(&inStream, packet->systemAddress, true); //send to everyone except origin
break;
}
default:
LOG("Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
}
}
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
switch (static_cast<eChatMessageType>(packet->data[3])) {
case eChatMessageType::GET_FRIENDS_LIST: case eChatMessageType::GET_FRIENDS_LIST:
ChatPacketHandler::HandleFriendlistRequest(packet); ChatPacketHandler::HandleFriendlistRequest(packet);
break; break;
@@ -273,69 +293,21 @@ void HandlePacket(Packet* packet) {
case eChatMessageType::TEAM_SET_LOOT: case eChatMessageType::TEAM_SET_LOOT:
ChatPacketHandler::HandleTeamLootOption(packet); ChatPacketHandler::HandleTeamLootOption(packet);
break; break;
case eChatMessageType::GMLEVEL_UPDATE:
ChatPacketHandler::HandleGMLevelUpdate(packet);
break;
case eChatMessageType::LOGIN_SESSION_NOTIFY:
Game::playerContainer.InsertPlayer(packet);
break;
case eChatMessageType::GM_ANNOUNCE:{
// we just forward this packet to every connected server
inStream.ResetReadPointer();
Game::server->Send(inStream, packet->systemAddress, true); // send to everyone except origin
}
break;
case eChatMessageType::UNEXPECTED_DISCONNECT:
Game::playerContainer.RemovePlayer(packet);
break;
case eChatMessageType::WHO:
case eChatMessageType::SHOW_ALL:
case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE:
case eChatMessageType::WORLD_DISCONNECT_REQUEST:
case eChatMessageType::WORLD_PROXIMITY_RESPONSE:
case eChatMessageType::WORLD_PARCEL_RESPONSE:
case eChatMessageType::TEAM_MISSED_INVITE_CHECK:
case eChatMessageType::GUILD_CREATE:
case eChatMessageType::GUILD_INVITE:
case eChatMessageType::GUILD_INVITE_RESPONSE:
case eChatMessageType::GUILD_LEAVE:
case eChatMessageType::GUILD_KICK:
case eChatMessageType::GUILD_GET_STATUS:
case eChatMessageType::GUILD_GET_ALL:
case eChatMessageType::BLUEPRINT_MODERATED:
case eChatMessageType::BLUEPRINT_MODEL_READY:
case eChatMessageType::PROPERTY_READY_FOR_APPROVAL:
case eChatMessageType::PROPERTY_MODERATION_CHANGED:
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED:
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED_REPORT:
case eChatMessageType::MAIL:
case eChatMessageType::WORLD_INSTANCE_LOCATION_REQUEST:
case eChatMessageType::REPUTATION_UPDATE:
case eChatMessageType::SEND_CANNED_TEXT:
case eChatMessageType::CHARACTER_NAME_CHANGE_REQUEST:
case eChatMessageType::CSR_REQUEST:
case eChatMessageType::CSR_REPLY:
case eChatMessageType::GM_KICK:
case eChatMessageType::WORLD_ROUTE_PACKET:
case eChatMessageType::GET_ZONE_POPULATIONS:
case eChatMessageType::REQUEST_MINIMUM_CHAT_MODE:
case eChatMessageType::MATCH_REQUEST:
case eChatMessageType::UGCMANIFEST_REPORT_MISSING_FILE:
case eChatMessageType::UGCMANIFEST_REPORT_DONE_FILE:
case eChatMessageType::UGCMANIFEST_REPORT_DONE_BLUEPRINT:
case eChatMessageType::UGCC_REQUEST:
case eChatMessageType::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE:
case eChatMessageType::ACHIEVEMENT_NOTIFY:
case eChatMessageType::GM_CLOSE_PRIVATE_CHAT_WINDOW:
case eChatMessageType::PLAYER_READY:
case eChatMessageType::GET_DONATION_TOTAL:
case eChatMessageType::UPDATE_DONATION:
case eChatMessageType::PRG_CSR_COMMAND:
case eChatMessageType::HEARTBEAT_REQUEST_FROM_WORLD:
case eChatMessageType::UPDATE_FREE_TRIAL_STATUS:
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chatMessageID).data(), chatMessageID);
break;
default: default:
LOG("Unknown CHAT Message id: %i", chatMessageID); LOG("Unknown CHAT id: %i", int(packet->data[3]));
}
}
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::WORLD) {
switch (static_cast<eWorldMessageType>(packet->data[3])) {
case eWorldMessageType::ROUTE_PACKET: {
LOG("Routing packet from world");
break;
}
default:
LOG("Unknown World id: %i", int(packet->data[3]));
}
} }
} }

View File

@@ -9,15 +9,17 @@
#include "BitStreamUtils.h" #include "BitStreamUtils.h"
#include "Database.h" #include "Database.h"
#include "eConnectionType.h" #include "eConnectionType.h"
#include "eChatInternalMessageType.h"
#include "ChatPackets.h" #include "ChatPackets.h"
#include "dConfig.h" #include "dConfig.h"
#include "eChatMessageType.h"
void PlayerContainer::Initialize() { void PlayerContainer::Initialize() {
m_MaxNumberOfBestFriends = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends"), m_MaxNumberOfBestFriends);
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends")).value_or(m_MaxNumberOfBestFriends); GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends"), m_MaxNumberOfFriends);
m_MaxNumberOfFriends = }
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends")).value_or(m_MaxNumberOfFriends);
PlayerContainer::~PlayerContainer() {
m_Players.clear();
} }
TeamData::TeamData() { TeamData::TeamData() {
@@ -45,7 +47,6 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
inStream.Read(data.zoneID); inStream.Read(data.zoneID);
inStream.Read(data.muteExpire); inStream.Read(data.muteExpire);
inStream.Read(data.gmLevel);
data.sysAddr = packet->systemAddress; data.sysAddr = packet->systemAddress;
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName); m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
@@ -145,12 +146,12 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) { void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GM_MUTE); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
bitStream.Write(player); bitStream.Write(player);
bitStream.Write(time); bitStream.Write(time);
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
} }
TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) { TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
@@ -352,7 +353,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) { void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
CBITSTREAM; CBITSTREAM;
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::TEAM_GET_STATUS); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
bitStream.Write(team->teamID); bitStream.Write(team->teamID);
bitStream.Write(deleteTeam); bitStream.Write(deleteTeam);
@@ -365,7 +366,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
} }
} }
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
} }
std::u16string PlayerContainer::GetName(LWOOBJID playerID) { std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
@@ -390,7 +391,7 @@ LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
} }
PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) { PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) {
return m_Players.contains(playerID) ? m_Players[playerID] : m_Players[LWOOBJID_EMPTY]; return m_Players[playerID];
} }
PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) { PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) {

View File

@@ -7,10 +7,8 @@
#include "dServer.h" #include "dServer.h"
#include <unordered_map> #include <unordered_map>
enum class eGameMasterLevel : uint8_t;
struct IgnoreData { struct IgnoreData {
IgnoreData(const std::string& name, const LWOOBJID& id) : playerName{ name }, playerId{ id } {} IgnoreData(const std::string& name, const LWOOBJID& id) : playerName(name), playerId(id) {}
inline bool operator==(const std::string& other) const noexcept { inline bool operator==(const std::string& other) const noexcept {
return playerName == other; return playerName == other;
} }
@@ -44,8 +42,6 @@ struct PlayerData {
std::string playerName; std::string playerName;
std::vector<FriendData> friends; std::vector<FriendData> friends;
std::vector<IgnoreData> ignoredPlayers; std::vector<IgnoreData> ignoredPlayers;
eGameMasterLevel gmLevel = static_cast<eGameMasterLevel>(0); // CIVILLIAN
bool isFTP = false;
}; };
struct TeamData { struct TeamData {
@@ -60,6 +56,8 @@ struct TeamData {
class PlayerContainer { class PlayerContainer {
public: public:
~PlayerContainer();
void Initialize(); void Initialize();
void InsertPlayer(Packet* packet); void InsertPlayer(Packet* packet);
void RemovePlayer(Packet* packet); void RemovePlayer(Packet* packet);

View File

@@ -9,11 +9,12 @@
* AMF3 Deserializer written by EmosewaMC * AMF3 Deserializer written by EmosewaMC
*/ */
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
if (!inStream) return nullptr;
AMFBaseValue* returnValue = nullptr; AMFBaseValue* returnValue = nullptr;
// Read in the value type from the bitStream // Read in the value type from the bitStream
eAmf marker; eAmf marker;
inStream.Read(marker); inStream->Read(marker);
// Based on the typing, create the value associated with that and return the base value class // Based on the typing, create the value associated with that and return the base value class
switch (marker) { switch (marker) {
case eAmf::Undefined: { case eAmf::Undefined: {
@@ -78,13 +79,13 @@ AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) {
return returnValue; return returnValue;
} }
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) { uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
bool byteFlag = true; bool byteFlag = true;
uint32_t actualNumber{}; uint32_t actualNumber{};
uint8_t numberOfBytesRead{}; uint8_t numberOfBytesRead{};
while (byteFlag && numberOfBytesRead < 4) { while (byteFlag && numberOfBytesRead < 4) {
uint8_t byte{}; uint8_t byte{};
inStream.Read(byte); inStream->Read(byte);
// Parse the byte // Parse the byte
if (numberOfBytesRead < 3) { if (numberOfBytesRead < 3) {
byteFlag = byte & static_cast<uint8_t>(1 << 7); byteFlag = byte & static_cast<uint8_t>(1 << 7);
@@ -100,7 +101,7 @@ uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) {
return actualNumber; return actualNumber;
} }
const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) { const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
auto length = ReadU29(inStream); auto length = ReadU29(inStream);
// Check if this is a reference // Check if this is a reference
bool isReference = length % 2 == 1; bool isReference = length % 2 == 1;
@@ -108,7 +109,7 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
length = length >> 1; length = length >> 1;
if (isReference) { if (isReference) {
std::string value(length, 0); std::string value(length, 0);
inStream.Read(&value[0], length); inStream->Read(&value[0], length);
// Empty strings are never sent by reference // Empty strings are never sent by reference
if (!value.empty()) accessedElements.push_back(value); if (!value.empty()) accessedElements.push_back(value);
return value; return value;
@@ -118,20 +119,20 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
} }
} }
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
double value; double value;
inStream.Read<double>(value); inStream->Read<double>(value);
return new AMFDoubleValue(value); return new AMFDoubleValue(value);
} }
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
auto arrayValue = new AMFArrayValue(); auto arrayValue = new AMFArrayValue();
// Read size of dense array // Read size of dense array
const auto sizeOfDenseArray = (ReadU29(inStream) >> 1); auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
// Then read associative portion // Then read associative portion
while (true) { while (true) {
const auto key = ReadString(inStream); auto key = ReadString(inStream);
// No more associative values when we encounter an empty string key // No more associative values when we encounter an empty string key
if (key.size() == 0) break; if (key.size() == 0) break;
arrayValue->Insert(key, Read(inStream)); arrayValue->Insert(key, Read(inStream));
@@ -143,10 +144,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
return arrayValue; return arrayValue;
} }
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
return new AMFStringValue(ReadString(inStream)); return new AMFStringValue(ReadString(inStream));
} }
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) { AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
return new AMFIntValue(ReadU29(inStream)); return new AMFIntValue(ReadU29(inStream));
} }

View File

@@ -15,7 +15,7 @@ public:
* @param inStream inStream to read value from. * @param inStream inStream to read value from.
* @return Returns an AMFValue with all the information from the bitStream in it. * @return Returns an AMFValue with all the information from the bitStream in it.
*/ */
AMFBaseValue* Read(RakNet::BitStream& inStream); AMFBaseValue* Read(RakNet::BitStream* inStream);
private: private:
/** /**
* @brief Private method to read a U29 integer from a bitstream * @brief Private method to read a U29 integer from a bitstream
@@ -23,7 +23,7 @@ private:
* @param inStream bitstream to read data from * @param inStream bitstream to read data from
* @return The number as an unsigned 29 bit integer * @return The number as an unsigned 29 bit integer
*/ */
static uint32_t ReadU29(RakNet::BitStream& inStream); uint32_t ReadU29(RakNet::BitStream* inStream);
/** /**
* @brief Reads a string from a bitstream * @brief Reads a string from a bitstream
@@ -31,7 +31,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return The read string * @return The read string
*/ */
const std::string ReadString(RakNet::BitStream& inStream); const std::string ReadString(RakNet::BitStream* inStream);
/** /**
* @brief Read an AMFDouble value from a bitStream * @brief Read an AMFDouble value from a bitStream
@@ -39,7 +39,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Double value represented as an AMFValue * @return Double value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfDouble(RakNet::BitStream& inStream); AMFBaseValue* ReadAmfDouble(RakNet::BitStream* inStream);
/** /**
* @brief Read an AMFArray from a bitStream * @brief Read an AMFArray from a bitStream
@@ -47,7 +47,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Array value represented as an AMFValue * @return Array value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfArray(RakNet::BitStream& inStream); AMFBaseValue* ReadAmfArray(RakNet::BitStream* inStream);
/** /**
* @brief Read an AMFString from a bitStream * @brief Read an AMFString from a bitStream
@@ -55,7 +55,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return String value represented as an AMFValue * @return String value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfString(RakNet::BitStream& inStream); AMFBaseValue* ReadAmfString(RakNet::BitStream* inStream);
/** /**
* @brief Read an AMFInteger from a bitStream * @brief Read an AMFInteger from a bitStream
@@ -63,7 +63,7 @@ private:
* @param inStream bitStream to read data from * @param inStream bitStream to read data from
* @return Integer value represented as an AMFValue * @return Integer value represented as an AMFValue
*/ */
AMFBaseValue* ReadAmfInteger(RakNet::BitStream& inStream); AMFBaseValue* ReadAmfInteger(RakNet::BitStream* inStream);
/** /**
* List of strings read so far saved to be read by reference. * List of strings read so far saved to be read by reference.

View File

@@ -31,70 +31,54 @@ enum class eAmf : uint8_t {
class AMFBaseValue { class AMFBaseValue {
public: public:
[[nodiscard]] constexpr virtual eAmf GetValueType() const noexcept { return eAmf::Undefined; } virtual eAmf GetValueType() { return eAmf::Undefined; };
constexpr AMFBaseValue() noexcept = default; AMFBaseValue() {};
constexpr virtual ~AMFBaseValue() noexcept = default; virtual ~AMFBaseValue() {};
}; };
// AMFValue template class instantiations template<typename ValueType>
template <typename ValueType>
class AMFValue : public AMFBaseValue { class AMFValue : public AMFBaseValue {
public: public:
AMFValue() = default; AMFValue() {};
AMFValue(const ValueType value) : m_Data{ value } {} AMFValue(ValueType value) { SetValue(value); };
virtual ~AMFValue() override {};
virtual ~AMFValue() override = default; eAmf GetValueType() override { return eAmf::Undefined; };
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override;
[[nodiscard]] const ValueType& GetValue() const { return m_Data; }
void SetValue(const ValueType value) { m_Data = value; }
const ValueType& GetValue() { return data; };
void SetValue(ValueType value) { data = value; };
protected: protected:
ValueType m_Data; ValueType data;
}; };
// Explicit template class instantiations
template class AMFValue<std::nullptr_t>;
template class AMFValue<bool>;
template class AMFValue<int32_t>;
template class AMFValue<uint32_t>;
template class AMFValue<std::string>;
template class AMFValue<double>;
// AMFValue template class member function instantiations
template <> [[nodiscard]] constexpr eAmf AMFValue<std::nullptr_t>::GetValueType() const noexcept { return eAmf::Null; }
template <> [[nodiscard]] constexpr eAmf AMFValue<bool>::GetValueType() const noexcept { return m_Data ? eAmf::True : eAmf::False; }
template <> [[nodiscard]] constexpr eAmf AMFValue<int32_t>::GetValueType() const noexcept { return eAmf::Integer; }
template <> [[nodiscard]] constexpr eAmf AMFValue<uint32_t>::GetValueType() const noexcept { return eAmf::Integer; }
template <> [[nodiscard]] constexpr eAmf AMFValue<std::string>::GetValueType() const noexcept { return eAmf::String; }
template <> [[nodiscard]] constexpr eAmf AMFValue<double>::GetValueType() const noexcept { return eAmf::Double; }
template <typename ValueType>
[[nodiscard]] constexpr eAmf AMFValue<ValueType>::GetValueType() const noexcept { return eAmf::Undefined; }
// As a string this is much easier to write and read from a BitStream. // As a string this is much easier to write and read from a BitStream.
template <> template<>
class AMFValue<const char*> : public AMFBaseValue { class AMFValue<const char*> : public AMFBaseValue {
public: public:
AMFValue() = default; AMFValue() {};
AMFValue(const char* value) { m_Data = value; } AMFValue(const char* value) { SetValue(std::string(value)); };
virtual ~AMFValue() override = default; virtual ~AMFValue() override {};
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::String; } eAmf GetValueType() override { return eAmf::String; };
[[nodiscard]] const std::string& GetValue() const { return m_Data; } const std::string& GetValue() { return data; };
void SetValue(const std::string& value) { m_Data = value; } void SetValue(std::string value) { data = value; };
protected: protected:
std::string m_Data; std::string data;
}; };
using AMFNullValue = AMFValue<std::nullptr_t>; typedef AMFValue<std::nullptr_t> AMFNullValue;
using AMFBoolValue = AMFValue<bool>; typedef AMFValue<bool> AMFBoolValue;
using AMFIntValue = AMFValue<int32_t>; typedef AMFValue<int32_t> AMFIntValue;
using AMFStringValue = AMFValue<std::string>; typedef AMFValue<std::string> AMFStringValue;
using AMFDoubleValue = AMFValue<double>; 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: * The AMFArrayValue object holds 2 types of lists:
@@ -105,14 +89,15 @@ using AMFDoubleValue = AMFValue<double>;
* and are not to be deleted by a caller. * and are not to be deleted by a caller.
*/ */
class AMFArrayValue : public AMFBaseValue { class AMFArrayValue : public AMFBaseValue {
using AMFAssociative = std::unordered_map<std::string, AMFBaseValue*>;
using AMFDense = std::vector<AMFBaseValue*>; typedef std::unordered_map<std::string, AMFBaseValue*> AMFAssociative;
typedef std::vector<AMFBaseValue*> AMFDense;
public: public:
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; } eAmf GetValueType() override { return eAmf::Array; };
~AMFArrayValue() override { ~AMFArrayValue() override {
for (const auto* valueToDelete : GetDense()) { for (auto valueToDelete : GetDense()) {
if (valueToDelete) { if (valueToDelete) {
delete valueToDelete; delete valueToDelete;
valueToDelete = nullptr; valueToDelete = nullptr;
@@ -124,17 +109,17 @@ public:
valueToDelete.second = nullptr; valueToDelete.second = nullptr;
} }
} }
} };
/** /**
* Returns the Associative portion of the object * Returns the Associative portion of the object
*/ */
[[nodiscard]] inline const AMFAssociative& GetAssociative() const noexcept { return m_Associative; } inline AMFAssociative& GetAssociative() { return this->associative; };
/** /**
* Returns the dense portion of the object * Returns the dense portion of the object
*/ */
[[nodiscard]] inline const AMFDense& GetDense() const noexcept { return m_Dense; } inline AMFDense& GetDense() { return this->dense; };
/** /**
* Inserts an AMFValue into the associative portion with the given key. * Inserts an AMFValue into the associative portion with the given key.
@@ -150,48 +135,48 @@ public:
* @return The inserted element if the type matched, * @return The inserted element if the type matched,
* or nullptr if a key existed and was not the same type * or nullptr if a key existed and was not the same type
*/ */
template <typename ValueType> template<typename ValueType>
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, const ValueType value) { std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, ValueType value) {
const auto element = m_Associative.find(key); auto element = associative.find(key);
AMFValue<ValueType>* val = nullptr; AMFValue<ValueType>* val = nullptr;
bool found = true; bool found = true;
if (element == m_Associative.cend()) { if (element == associative.end()) {
val = new AMFValue<ValueType>(value); val = new AMFValue<ValueType>(value);
m_Associative.emplace(key, val); associative.insert(std::make_pair(key, val));
} else { } else {
val = dynamic_cast<AMFValue<ValueType>*>(element->second); val = dynamic_cast<AMFValue<ValueType>*>(element->second);
found = false; found = false;
} }
return std::make_pair(val, found); return std::make_pair(val, found);
} };
// Associates an array with a string key // Associates an array with a string key
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string& key) { std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
const auto element = m_Associative.find(key); auto element = associative.find(key);
AMFArrayValue* val = nullptr; AMFArrayValue* val = nullptr;
bool found = true; bool found = true;
if (element == m_Associative.cend()) { if (element == associative.end()) {
val = new AMFArrayValue(); val = new AMFArrayValue();
m_Associative.emplace(key, val); associative.insert(std::make_pair(key, val));
} else { } else {
val = dynamic_cast<AMFArrayValue*>(element->second); val = dynamic_cast<AMFArrayValue*>(element->second);
found = false; found = false;
} }
return std::make_pair(val, found); return std::make_pair(val, found);
} };
// Associates an array with an integer key // Associates an array with an integer key
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) { std::pair<AMFBaseValue*, bool> Insert(const uint32_t& index) {
AMFArrayValue* val = nullptr; AMFArrayValue* val = nullptr;
bool inserted = false; bool inserted = false;
if (index >= m_Dense.size()) { if (index >= dense.size()) {
m_Dense.resize(index + 1); dense.resize(index + 1);
val = new AMFArrayValue(); val = new AMFArrayValue();
m_Dense.at(index) = val; dense.at(index) = val;
inserted = true; inserted = true;
} }
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index)), inserted); return std::make_pair(dynamic_cast<AMFArrayValue*>(dense.at(index)), inserted);
} };
/** /**
* @brief Inserts an AMFValue into the AMFArray key'd by index. * @brief Inserts an AMFValue into the AMFArray key'd by index.
@@ -203,18 +188,18 @@ public:
* @return The inserted element, or nullptr if the type did not match * @return The inserted element, or nullptr if the type did not match
* what was at the index. * what was at the index.
*/ */
template <typename ValueType> template<typename ValueType>
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) { std::pair<AMFValue<ValueType>*, bool> Insert(const uint32_t& index, ValueType value) {
AMFValue<ValueType>* val = nullptr; AMFValue<ValueType>* val = nullptr;
bool inserted = false; bool inserted = false;
if (index >= m_Dense.size()) { if (index >= this->dense.size()) {
m_Dense.resize(index + 1); this->dense.resize(index + 1);
val = new AMFValue<ValueType>(value); val = new AMFValue<ValueType>(value);
m_Dense.at(index) = val; this->dense.at(index) = val;
inserted = true; inserted = true;
} }
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index)), inserted); return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(this->dense.at(index)), inserted);
} };
/** /**
* Inserts an AMFValue into the associative portion with the given key. * Inserts an AMFValue into the associative portion with the given key.
@@ -225,15 +210,15 @@ public:
* @param key The key to associate with the value * @param key The key to associate with the value
* @param value The value to insert * @param value The value to insert
*/ */
void Insert(const std::string& key, AMFBaseValue* const value) { void Insert(const std::string& key, AMFBaseValue* value) {
const auto element = m_Associative.find(key); auto element = associative.find(key);
if (element != m_Associative.cend() && element->second) { if (element != associative.end() && element->second) {
delete element->second; delete element->second;
element->second = value; element->second = value;
} else { } else {
m_Associative.emplace(key, value); associative.insert(std::make_pair(key, value));
}
} }
};
/** /**
* Inserts an AMFValue into the associative portion with the given index. * Inserts an AMFValue into the associative portion with the given index.
@@ -244,15 +229,15 @@ public:
* @param key The key to associate with the value * @param key The key to associate with the value
* @param value The value to insert * @param value The value to insert
*/ */
void Insert(const size_t index, AMFBaseValue* const value) { void Insert(const uint32_t index, AMFBaseValue* value) {
if (index < m_Dense.size()) { if (index < dense.size()) {
const AMFDense::const_iterator itr = m_Dense.cbegin() + index; AMFDense::iterator itr = dense.begin() + index;
if (*itr) delete m_Dense.at(index); if (*itr) delete dense.at(index);
} else { } else {
m_Dense.resize(index + 1); dense.resize(index + 1);
}
m_Dense.at(index) = value;
} }
dense.at(index) = value;
};
/** /**
* Pushes an AMFValue into the back of the dense portion. * Pushes an AMFValue into the back of the dense portion.
@@ -264,10 +249,10 @@ public:
* *
* @return The inserted pointer, or nullptr should the key already be in use. * @return The inserted pointer, or nullptr should the key already be in use.
*/ */
template <typename ValueType> template<typename ValueType>
[[maybe_unused]] inline AMFValue<ValueType>* Push(const ValueType value) { inline AMFValue<ValueType>* Push(ValueType value) {
return Insert(m_Dense.size(), value).first; return Insert(this->dense.size(), value).first;
} };
/** /**
* Removes the key from the associative portion * Removes the key from the associative portion
@@ -276,49 +261,52 @@ public:
* *
* @param key The key to remove from the associative portion * @param key The key to remove from the associative portion
*/ */
void Remove(const std::string& key, const bool deleteValue = true) { void Remove(const std::string& key, bool deleteValue = true) {
const AMFAssociative::const_iterator it = m_Associative.find(key); AMFAssociative::iterator it = this->associative.find(key);
if (it != m_Associative.cend()) { if (it != this->associative.end()) {
if (deleteValue) delete it->second; if (deleteValue) delete it->second;
m_Associative.erase(it); this->associative.erase(it);
} }
} }
/** /**
* Pops the last element in the dense portion, deleting it in the process. * Pops the last element in the dense portion, deleting it in the process.
*/ */
void Remove(const size_t index) { void Remove(const uint32_t index) {
if (!m_Dense.empty() && index < m_Dense.size()) { if (!this->dense.empty() && index < this->dense.size()) {
const auto itr = m_Dense.cbegin() + index; auto itr = this->dense.begin() + index;
if (*itr) delete (*itr); if (*itr) delete (*itr);
m_Dense.erase(itr); this->dense.erase(itr);
} }
} }
void Pop() { void Pop() {
if (!m_Dense.empty()) Remove(m_Dense.size() - 1); if (!this->dense.empty()) Remove(this->dense.size() - 1);
} }
[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) const { AMFArrayValue* GetArray(const std::string& key) {
const AMFAssociative::const_iterator it = m_Associative.find(key); AMFAssociative::const_iterator it = this->associative.find(key);
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second) : nullptr; if (it != this->associative.end()) {
return dynamic_cast<AMFArrayValue*>(it->second);
} }
return nullptr;
};
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const { AMFArrayValue* GetArray(const uint32_t index) {
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index)) : nullptr; return index >= this->dense.size() ? nullptr : dynamic_cast<AMFArrayValue*>(this->dense.at(index));
} };
[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string& key) { inline AMFArrayValue* InsertArray(const std::string& key) {
return static_cast<AMFArrayValue*>(Insert(key).first); return static_cast<AMFArrayValue*>(Insert(key).first);
} };
[[maybe_unused]] inline AMFArrayValue* InsertArray(const size_t index) { inline AMFArrayValue* InsertArray(const uint32_t index) {
return static_cast<AMFArrayValue*>(Insert(index).first); return static_cast<AMFArrayValue*>(Insert(index).first);
} };
[[maybe_unused]] inline AMFArrayValue* PushArray() { inline AMFArrayValue* PushArray() {
return static_cast<AMFArrayValue*>(Insert(m_Dense.size()).first); return static_cast<AMFArrayValue*>(Insert(this->dense.size()).first);
} };
/** /**
* Gets an AMFValue by the key from the associative portion and converts it * Gets an AMFValue by the key from the associative portion and converts it
@@ -330,18 +318,18 @@ public:
* @return The AMFValue * @return The AMFValue
*/ */
template <typename AmfType> template <typename AmfType>
[[nodiscard]] AMFValue<AmfType>* Get(const std::string& key) const { AMFValue<AmfType>* Get(const std::string& key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key); AMFAssociative::const_iterator it = this->associative.find(key);
return it != m_Associative.cend() ? return it != this->associative.end() ?
dynamic_cast<AMFValue<AmfType>*>(it->second) : dynamic_cast<AMFValue<AmfType>*>(it->second) :
nullptr; nullptr;
} };
// Get from the array but dont cast it // Get from the array but dont cast it
[[nodiscard]] AMFBaseValue* Get(const std::string& key) const { AMFBaseValue* Get(const std::string& key) const {
const AMFAssociative::const_iterator it = m_Associative.find(key); AMFAssociative::const_iterator it = this->associative.find(key);
return it != m_Associative.cend() ? it->second : nullptr; return it != this->associative.end() ? it->second : nullptr;
} };
/** /**
* @brief Get an AMFValue object at a position in the dense portion. * @brief Get an AMFValue object at a position in the dense portion.
@@ -353,28 +341,27 @@ public:
* @return The casted object, or nullptr. * @return The casted object, or nullptr.
*/ */
template <typename AmfType> template <typename AmfType>
[[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const { AMFValue<AmfType>* Get(uint32_t index) const {
return index < m_Dense.size() ? return index < this->dense.size() ?
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index)) : dynamic_cast<AMFValue<AmfType>*>(this->dense.at(index)) :
nullptr; nullptr;
} };
// Get from the dense but dont cast it // Get from the dense but dont cast it
[[nodiscard]] AMFBaseValue* Get(const size_t index) const { AMFBaseValue* Get(const uint32_t index) const {
return index < m_Dense.size() ? m_Dense.at(index) : nullptr; return index < this->dense.size() ? this->dense.at(index) : nullptr;
} };
private: private:
/** /**
* The associative portion. These values are key'd with strings to an AMFValue. * The associative portion. These values are key'd with strings to an AMFValue.
*/ */
AMFAssociative m_Associative; AMFAssociative associative;
/** /**
* The dense portion. These AMFValue's are stored one after * The dense portion. These AMFValue's are stored one after
* another with the most recent addition being at the back. * another with the most recent addition being at the back.
*/ */
AMFDense m_Dense; AMFDense dense;
}; };
#endif //!__AMF3__H__ #endif //!__AMF3__H__

View File

@@ -53,7 +53,7 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
* A private function to write an value to a RakNet::BitStream * A private function to write an value to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteUInt29(RakNet::BitStream& bs, uint32_t v) { void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
unsigned char b4 = static_cast<unsigned char>(v); unsigned char b4 = static_cast<unsigned char>(v);
if (v < 0x00200000) { if (v < 0x00200000) {
b4 = b4 & 0x7F; b4 = b4 & 0x7F;
@@ -65,10 +65,10 @@ void WriteUInt29(RakNet::BitStream& bs, uint32_t v) {
unsigned char b2; unsigned char b2;
v = v >> 7; v = v >> 7;
b2 = static_cast<unsigned char>(v) | 0x80; b2 = static_cast<unsigned char>(v) | 0x80;
bs.Write(b2); bs->Write(b2);
} }
bs.Write(b3); bs->Write(b3);
} }
} else { } else {
unsigned char b1; unsigned char b1;
@@ -82,19 +82,19 @@ void WriteUInt29(RakNet::BitStream& bs, uint32_t v) {
v = v >> 7; v = v >> 7;
b1 = static_cast<unsigned char>(v) | 0x80; b1 = static_cast<unsigned char>(v) | 0x80;
bs.Write(b1); bs->Write(b1);
bs.Write(b2); bs->Write(b2);
bs.Write(b3); bs->Write(b3);
} }
bs.Write(b4); bs->Write(b4);
} }
/** /**
* Writes a flag number to a RakNet::BitStream * Writes a flag number to a RakNet::BitStream
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteFlagNumber(RakNet::BitStream& bs, uint32_t v) { void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
v = (v << 1) | 0x01; v = (v << 1) | 0x01;
WriteUInt29(bs, v); WriteUInt29(bs, v);
} }
@@ -104,9 +104,9 @@ void WriteFlagNumber(RakNet::BitStream& bs, uint32_t v) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFString(RakNet::BitStream& bs, const std::string& str) { void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
WriteFlagNumber(bs, static_cast<uint32_t>(str.size())); WriteFlagNumber(bs, static_cast<uint32_t>(str.size()));
bs.Write(str.c_str(), static_cast<uint32_t>(str.size())); bs->Write(str.c_str(), static_cast<uint32_t>(str.size()));
} }
/** /**
@@ -114,8 +114,8 @@ void WriteAMFString(RakNet::BitStream& bs, const std::string& str) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU16(RakNet::BitStream& bs, uint16_t value) { void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
bs.Write(value); bs->Write(value);
} }
/** /**
@@ -123,8 +123,8 @@ void WriteAMFU16(RakNet::BitStream& bs, uint16_t value) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU32(RakNet::BitStream& bs, uint32_t value) { void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
bs.Write(value); bs->Write(value);
} }
/** /**
@@ -132,40 +132,40 @@ void WriteAMFU32(RakNet::BitStream& bs, uint32_t value) {
* *
* RakNet writes in the correct byte order - do not reverse this. * RakNet writes in the correct byte order - do not reverse this.
*/ */
void WriteAMFU64(RakNet::BitStream& bs, uint64_t value) { void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
bs.Write(value); bs->Write(value);
} }
// Writes an AMFIntegerValue to BitStream // Writes an AMFIntegerValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) { void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) {
WriteUInt29(*this, value.GetValue()); WriteUInt29(this, value.GetValue());
} }
// Writes an AMFDoubleValue to BitStream // Writes an AMFDoubleValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) { void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
double d = value.GetValue(); double d = value.GetValue();
WriteAMFU64(*this, *reinterpret_cast<uint64_t*>(&d)); WriteAMFU64(this, *reinterpret_cast<uint64_t*>(&d));
} }
// Writes an AMFStringValue to BitStream // Writes an AMFStringValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) { void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) {
WriteAMFString(*this, value.GetValue()); WriteAMFString(this, value.GetValue());
} }
// Writes an AMFArrayValue to BitStream // Writes an AMFArrayValue to BitStream
template<> template<>
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) { void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) {
uint32_t denseSize = value.GetDense().size(); uint32_t denseSize = value.GetDense().size();
WriteFlagNumber(*this, denseSize); WriteFlagNumber(this, denseSize);
auto it = value.GetAssociative().begin(); auto it = value.GetAssociative().begin();
auto end = value.GetAssociative().end(); auto end = value.GetAssociative().end();
while (it != end) { while (it != end) {
WriteAMFString(*this, it->first); WriteAMFString(this, it->first);
this->Write<AMFBaseValue&>(*it->second); this->Write<AMFBaseValue&>(*it->second);
it++; it++;
} }

View File

@@ -8,9 +8,11 @@ set(DCOMMON_SOURCES
"Game.cpp" "Game.cpp"
"GeneralUtils.cpp" "GeneralUtils.cpp"
"LDFFormat.cpp" "LDFFormat.cpp"
"MD5.cpp"
"Metrics.cpp" "Metrics.cpp"
"NiPoint3.cpp" "NiPoint3.cpp"
"NiQuaternion.cpp" "NiQuaternion.cpp"
"SHA512.cpp"
"Demangler.cpp" "Demangler.cpp"
"ZCompression.cpp" "ZCompression.cpp"
"BrickByBrickFix.cpp" "BrickByBrickFix.cpp"
@@ -18,27 +20,17 @@ set(DCOMMON_SOURCES
"FdbToSqlite.cpp" "FdbToSqlite.cpp"
) )
# Workaround for compiler bug where the optimized code could result in a memcpy of 0 bytes, even though that isnt possible.
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97185
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_source_files_properties("FdbToSqlite.cpp" PROPERTIES COMPILE_FLAGS "-Wno-stringop-overflow")
endif()
add_subdirectory(dClient) add_subdirectory(dClient)
foreach(file ${DCOMMON_DCLIENT_SOURCES}) foreach(file ${DCOMMON_DCLIENT_SOURCES})
set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}") set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}")
endforeach() endforeach()
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
add_library(dCommon STATIC ${DCOMMON_SOURCES}) add_library(dCommon STATIC ${DCOMMON_SOURCES})
target_include_directories(dCommon
PUBLIC "." "dClient" "dEnums" target_link_libraries(dCommon bcrypt dDatabase tinyxml2)
PRIVATE
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase"
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables"
"${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase"
"${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include"
)
if (UNIX) if (UNIX)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
@@ -69,6 +61,4 @@ else ()
) )
endif () endif ()
target_link_libraries(dCommon target_link_libraries(dCommon ZLIB::ZLIB)
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
INTERFACE dDatabase)

View File

@@ -278,14 +278,14 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
return vector; return vector;
} }
std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) { std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) {
uint32_t length; uint32_t length;
inStream.Read<uint32_t>(length); inStream->Read<uint32_t>(length);
std::u16string string; std::u16string string;
for (auto i = 0; i < length; i++) { for (auto i = 0; i < length; i++) {
uint16_t c; uint16_t c;
inStream.Read(c); inStream->Read(c);
string.push_back(c); string.push_back(c);
} }
@@ -320,24 +320,6 @@ std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::stri
return sortedFiles; return sortedFiles;
} }
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924) bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) {
return TryParse<float>(x.c_str(), dst.x) && TryParse<float>(y.c_str(), dst.y) && TryParse<float>(z.c_str(), dst.z);
// MacOS floating-point parse function specializations
namespace GeneralUtils::details {
template <>
[[nodiscard]] float _parse<float>(const std::string_view str, size_t& parseNum) {
return std::stof(std::string{ str }, &parseNum);
}
template <>
[[nodiscard]] double _parse<double>(const std::string_view str, size_t& parseNum) {
return std::stod(std::string{ str }, &parseNum);
}
template <>
[[nodiscard]] long double _parse<long double>(const std::string_view str, size_t& parseNum) {
return std::stold(std::string{ str }, &parseNum);
}
} }
#endif

View File

@@ -1,20 +1,17 @@
#pragma once #pragma once
// C++ // C++
#include <charconv> #include <stdint.h>
#include <cstdint>
#include <random> #include <random>
#include <ctime> #include <time.h>
#include <string> #include <string>
#include <string_view> #include <type_traits>
#include <optional>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
#include <stdexcept> #include <stdexcept>
#include "BitStream.h" #include "BitStream.h"
#include "NiPoint3.h" #include "NiPoint3.h"
#include "dPlatforms.h"
#include "Game.h" #include "Game.h"
#include "Logger.h" #include "Logger.h"
@@ -116,7 +113,7 @@ namespace GeneralUtils {
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to); bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
std::u16string ReadWString(RakNet::BitStream& inStream); std::u16string ReadWString(RakNet::BitStream* inStream);
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter); std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
@@ -126,111 +123,90 @@ namespace GeneralUtils {
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder); std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
// Concept constraining to enum types
template <typename T> template <typename T>
concept Enum = std::is_enum_v<T>; T Parse(const char* value);
// Concept constraining to numeric types template <>
template <typename T> inline bool Parse(const char* value) {
concept Numeric = std::integral<T> || Enum<T> || std::floating_point<T>; return std::stoi(value);
// Concept trickery to enable parsing underlying numeric types
template <Numeric T>
struct numeric_parse { using type = T; };
// If an enum, present an alias to its underlying type for parsing
template <Numeric T> requires Enum<T>
struct numeric_parse<T> { using type = std::underlying_type_t<T>; };
// If a boolean, present an alias to an intermediate integral type for parsing
template <Numeric T> requires std::same_as<T, bool>
struct numeric_parse<T> { using type = uint32_t; };
// Shorthand type alias
template <Numeric T>
using numeric_parse_t = numeric_parse<T>::type;
/**
* For numeric values: Parses a string_view and returns an optional variable depending on the result.
* @param str The string_view to be evaluated
* @returns An std::optional containing the desired value if it is equivalent to the string
*/
template <Numeric T>
[[nodiscard]] std::optional<T> TryParse(const std::string_view str) {
numeric_parse_t<T> result;
const char* const strEnd = str.data() + str.size();
const auto [parseEnd, ec] = std::from_chars(str.data(), strEnd, result);
const bool isParsed = parseEnd == strEnd && ec == std::errc{};
return isParsed ? static_cast<T>(result) : std::optional<T>{};
} }
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924) template <>
inline int32_t Parse(const char* value) {
// MacOS floating-point parse helper function specializations return std::stoi(value);
namespace details {
template <std::floating_point T>
[[nodiscard]] T _parse(const std::string_view str, size_t& parseNum);
} }
/** template <>
* For floating-point values: Parses a string_view and returns an optional variable depending on the result. inline int64_t Parse(const char* value) {
* Note that this function overload is only included for MacOS, as from_chars will fulfill its purpose otherwise. return std::stoll(value);
* @param str The string_view to be evaluated }
* @returns An std::optional containing the desired value if it is equivalent to the string
*/ template <>
template <std::floating_point T> inline float Parse(const char* value) {
[[nodiscard]] std::optional<T> TryParse(const std::string_view str) noexcept return std::stof(value);
}
template <>
inline double Parse(const char* value) {
return std::stod(value);
}
template <>
inline uint16_t Parse(const char* value) {
return std::stoul(value);
}
template <>
inline uint32_t Parse(const char* value) {
return std::stoul(value);
}
template <>
inline uint64_t Parse(const char* value) {
return std::stoull(value);
}
template <>
inline eInventoryType Parse(const char* value) {
return static_cast<eInventoryType>(std::stoul(value));
}
template <>
inline eReplicaComponentType Parse(const char* value) {
return static_cast<eReplicaComponentType>(std::stoul(value));
}
template <typename T>
bool TryParse(const char* value, T& dst) {
try { try {
size_t parseNum; dst = Parse<T>(value);
const T result = details::_parse<T>(str, parseNum);
const bool isParsed = str.length() == parseNum;
return isParsed ? result : std::optional<T>{}; return true;
} catch (...) { } catch (...) {
return std::nullopt; return false;
} }
#endif
/**
* The TryParse overload for handling NiPoint3 by passing 3 seperate string references
* @param strX The string representing the X coordinate
* @param strY The string representing the Y coordinate
* @param strZ The string representing the Z coordinate
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
*/
template <typename T>
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string& strX, const std::string& strY, const std::string& strZ) {
const auto x = TryParse<float>(strX);
if (!x) return std::nullopt;
const auto y = TryParse<float>(strY);
if (!y) return std::nullopt;
const auto z = TryParse<float>(strZ);
return z ? std::make_optional<NiPoint3>(x.value(), y.value(), z.value()) : std::nullopt;
}
/**
* The TryParse overload for handling NiPoint3 by passingn a reference to a vector of three strings
* @param str The string vector representing the X, Y, and Xcoordinates
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
*/
template <typename T>
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::vector<std::string>& str) {
return (str.size() == 3) ? TryParse<NiPoint3>(str[0], str[1], str[2]) : std::nullopt;
} }
template <typename T> template <typename T>
T Parse(const std::string& value) {
return Parse<T>(value.c_str());
}
template <typename T>
bool TryParse(const std::string& value, T& dst) {
return TryParse<T>(value.c_str(), dst);
}
bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst);
template<typename T>
std::u16string to_u16string(T value) { std::u16string to_u16string(T value) {
return GeneralUtils::ASCIIToUTF16(std::to_string(value)); return GeneralUtils::ASCIIToUTF16(std::to_string(value));
} }
// From boost::hash_combine // From boost::hash_combine
template <class T> template <class T>
constexpr void hash_combine(std::size_t& s, const T& v) { void hash_combine(std::size_t& s, const T& v) {
std::hash<T> h; std::hash<T> h;
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
} }
@@ -263,9 +239,11 @@ namespace GeneralUtils {
* @param entry Enum entry to cast * @param entry Enum entry to cast
* @returns The enum entry's value in its underlying type * @returns The enum entry's value in its underlying type
*/ */
template <Enum eType> template <typename eType>
constexpr std::underlying_type_t<eType> ToUnderlying(const eType entry) noexcept { inline constexpr typename std::underlying_type_t<eType> CastUnderlyingType(const eType entry) {
return static_cast<std::underlying_type_t<eType>>(entry); static_assert(std::is_enum_v<eType>, "Not an enum");
return static_cast<typename std::underlying_type_t<eType>>(entry);
} }
// on Windows we need to undef these or else they conflict with our numeric limits calls // on Windows we need to undef these or else they conflict with our numeric limits calls

View File

@@ -61,33 +61,33 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} }
case LDF_TYPE_S32: { case LDF_TYPE_S32: {
const auto data = GeneralUtils::TryParse<int32_t>(ldfTypeAndValue.second); int32_t data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<int32_t>(key, data.value()); returnValue = new LDFData<int32_t>(key, data);
break; break;
} }
case LDF_TYPE_FLOAT: { case LDF_TYPE_FLOAT: {
const auto data = GeneralUtils::TryParse<float>(ldfTypeAndValue.second); float data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<float>(key, data.value()); returnValue = new LDFData<float>(key, data);
break; break;
} }
case LDF_TYPE_DOUBLE: { case LDF_TYPE_DOUBLE: {
const auto data = GeneralUtils::TryParse<double>(ldfTypeAndValue.second); double data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<double>(key, data.value()); returnValue = new LDFData<double>(key, data);
break; break;
} }
@@ -100,12 +100,10 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") { } else if (ldfTypeAndValue.second == "false") {
data = 0; data = 0;
} else { } else {
const auto dataOptional = GeneralUtils::TryParse<uint32_t>(ldfTypeAndValue.second); if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
if (!dataOptional) {
LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
data = dataOptional.value();
} }
returnValue = new LDFData<uint32_t>(key, data); returnValue = new LDFData<uint32_t>(key, data);
@@ -120,12 +118,10 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} else if (ldfTypeAndValue.second == "false") { } else if (ldfTypeAndValue.second == "false") {
data = false; data = false;
} else { } else {
const auto dataOptional = GeneralUtils::TryParse<bool>(ldfTypeAndValue.second); if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
if (!dataOptional) {
LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
data = dataOptional.value();
} }
returnValue = new LDFData<bool>(key, data); returnValue = new LDFData<bool>(key, data);
@@ -133,22 +129,22 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
} }
case LDF_TYPE_U64: { case LDF_TYPE_U64: {
const auto data = GeneralUtils::TryParse<uint64_t>(ldfTypeAndValue.second); uint64_t data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<uint64_t>(key, data.value()); returnValue = new LDFData<uint64_t>(key, data);
break; break;
} }
case LDF_TYPE_OBJID: { case LDF_TYPE_OBJID: {
const auto data = GeneralUtils::TryParse<LWOOBJID>(ldfTypeAndValue.second); LWOOBJID data;
if (!data) { if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data()); LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
return nullptr; return nullptr;
} }
returnValue = new LDFData<LWOOBJID>(key, data.value()); returnValue = new LDFData<LWOOBJID>(key, data);
break; break;
} }

View File

@@ -31,7 +31,7 @@ public:
virtual ~LDFBaseData() {} virtual ~LDFBaseData() {}
virtual void WriteToPacket(RakNet::BitStream& packet) = 0; virtual void WriteToPacket(RakNet::BitStream* packet) = 0;
virtual const std::u16string& GetKey() = 0; virtual const std::u16string& GetKey() = 0;
@@ -62,17 +62,17 @@ private:
T value; T value;
//! Writes the key to the packet //! Writes the key to the packet
void WriteKey(RakNet::BitStream& packet) { void WriteKey(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t)); packet->Write<uint8_t>(this->key.length() * sizeof(uint16_t));
for (uint32_t i = 0; i < this->key.length(); ++i) { for (uint32_t i = 0; i < this->key.length(); ++i) {
packet.Write<uint16_t>(this->key[i]); packet->Write<uint16_t>(this->key[i]);
} }
} }
//! Writes the value to the packet //! Writes the value to the packet
void WriteValue(RakNet::BitStream& packet) { void WriteValue(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->GetValueType()); packet->Write<uint8_t>(this->GetValueType());
packet.Write(this->value); packet->Write(this->value);
} }
public: public:
@@ -108,7 +108,7 @@ public:
/*! /*!
\param packet The packet \param packet The packet
*/ */
void WriteToPacket(RakNet::BitStream& packet) override { void WriteToPacket(RakNet::BitStream* packet) override {
this->WriteKey(packet); this->WriteKey(packet);
this->WriteValue(packet); this->WriteValue(packet);
} }
@@ -162,7 +162,7 @@ public:
return new LDFData<T>(key, value); return new LDFData<T>(key, value);
} }
inline static const T Default = {}; inline static T Default = {};
}; };
// LDF Types // LDF Types
@@ -178,31 +178,31 @@ template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF
// The specialized version for std::u16string (UTF-16) // The specialized version for std::u16string (UTF-16)
template<> template<>
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) { inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->GetValueType()); packet->Write<uint8_t>(this->GetValueType());
packet.Write<uint32_t>(this->value.length()); packet->Write<uint32_t>(this->value.length());
for (uint32_t i = 0; i < this->value.length(); ++i) { for (uint32_t i = 0; i < this->value.length(); ++i) {
packet.Write<uint16_t>(this->value[i]); packet->Write<uint16_t>(this->value[i]);
} }
} }
// The specialized version for bool // The specialized version for bool
template<> template<>
inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) { inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->GetValueType()); packet->Write<uint8_t>(this->GetValueType());
packet.Write<uint8_t>(this->value); packet->Write<uint8_t>(this->value);
} }
// The specialized version for std::string (UTF-8) // The specialized version for std::string (UTF-8)
template<> template<>
inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) { inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
packet.Write<uint8_t>(this->GetValueType()); packet->Write<uint8_t>(this->GetValueType());
packet.Write<uint32_t>(this->value.length()); packet->Write<uint32_t>(this->value.length());
for (uint32_t i = 0; i < this->value.length(); ++i) { for (uint32_t i = 0; i < this->value.length(); ++i) {
packet.Write<uint8_t>(this->value[i]); packet->Write<uint8_t>(this->value[i]);
} }
} }

View File

@@ -1,24 +1,210 @@
#include "NiPoint3.h" #include "NiPoint3.h"
#include "NiQuaternion.h"
// C++ // C++
#include <cmath> #include <cmath>
// MARK: Member Functions // Static Variables
const NiPoint3 NiPoint3::ZERO(0.0f, 0.0f, 0.0f);
const NiPoint3 NiPoint3::UNIT_X(1.0f, 0.0f, 0.0f);
const NiPoint3 NiPoint3::UNIT_Y(0.0f, 1.0f, 0.0f);
const NiPoint3 NiPoint3::UNIT_Z(0.0f, 0.0f, 1.0f);
const NiPoint3 NiPoint3::UNIT_ALL(1.0f, 1.0f, 1.0f);
//! Initializer
NiPoint3::NiPoint3(void) {
this->x = 0;
this->y = 0;
this->z = 0;
}
//! Initializer
NiPoint3::NiPoint3(float x, float y, float z) {
this->x = x;
this->y = y;
this->z = z;
}
//! Copy Constructor
NiPoint3::NiPoint3(const NiPoint3& point) {
this->x = point.x;
this->y = point.y;
this->z = point.z;
}
//! Destructor
NiPoint3::~NiPoint3(void) {}
// MARK: Getters / Setters
//! Gets the X coordinate
float NiPoint3::GetX(void) const {
return this->x;
}
//! Sets the X coordinate
void NiPoint3::SetX(float x) {
this->x = x;
}
//! Gets the Y coordinate
float NiPoint3::GetY(void) const {
return this->y;
}
//! Sets the Y coordinate
void NiPoint3::SetY(float y) {
this->y = y;
}
//! Gets the Z coordinate
float NiPoint3::GetZ(void) const {
return this->z;
}
//! Sets the Z coordinate
void NiPoint3::SetZ(float z) {
this->z = z;
}
// MARK: Functions
//! Gets the length of the vector //! Gets the length of the vector
float NiPoint3::Length() const { float NiPoint3::Length(void) const {
return std::sqrt(x * x + y * y + z * z); return sqrt(x * x + y * y + z * z);
}
//! Gets the squared length of a vector
float NiPoint3::SquaredLength(void) const {
return (x * x + y * y + z * z);
}
//! Returns the dot product of the vector dotted with another vector
float NiPoint3::DotProduct(const Vector3& vec) const {
return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z));
}
//! Returns the cross product of the vector crossed with another vector
Vector3 NiPoint3::CrossProduct(const Vector3& vec) const {
return Vector3(((this->y * vec.z) - (this->z * vec.y)),
((this->z * vec.x) - (this->x * vec.z)),
((this->x * vec.y) - (this->y * vec.x)));
} }
//! Unitize the vector //! Unitize the vector
NiPoint3 NiPoint3::Unitize() const { NiPoint3 NiPoint3::Unitize(void) const {
float length = this->Length(); float length = this->Length();
return length != 0 ? *this / length : NiPoint3Constant::ZERO; return length != 0 ? *this / length : NiPoint3::ZERO;
} }
// MARK: Operators
//! Operator to check for equality
bool NiPoint3::operator==(const NiPoint3& point) const {
return point.x == this->x && point.y == this->y && point.z == this->z;
}
//! Operator to check for inequality
bool NiPoint3::operator!=(const NiPoint3& point) const {
return !(*this == point);
}
//! Operator for subscripting
float& NiPoint3::operator[](int i) {
float* base = &x;
return base[i];
}
//! Operator for subscripting
const float& NiPoint3::operator[](int i) const {
const float* base = &x;
return base[i];
}
//! Operator for addition of vectors
NiPoint3 NiPoint3::operator+(const NiPoint3& point) const {
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
}
//! Operator for addition of vectors
NiPoint3& NiPoint3::operator+=(const NiPoint3& point) {
this->x += point.x;
this->y += point.y;
this->z += point.z;
return *this;
}
NiPoint3& NiPoint3::operator*=(const float scalar) {
this->x *= scalar;
this->y *= scalar;
this->z *= scalar;
return *this;
}
//! Operator for subtraction of vectors
NiPoint3 NiPoint3::operator-(const NiPoint3& point) const {
return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z);
}
//! Operator for addition of a scalar on all vector components
NiPoint3 NiPoint3::operator+(float fScalar) const {
return NiPoint3(this->x + fScalar, this->y + fScalar, this->z + fScalar);
}
//! Operator for subtraction of a scalar on all vector components
NiPoint3 NiPoint3::operator-(float fScalar) const {
return NiPoint3(this->x - fScalar, this->y - fScalar, this->z - fScalar);
}
//! Operator for scalar multiplication of a vector
NiPoint3 NiPoint3::operator*(float fScalar) const {
return NiPoint3(this->x * fScalar, this->y * fScalar, this->z * fScalar);
}
//! Operator for scalar division of a vector
NiPoint3 NiPoint3::operator/(float fScalar) const {
float retX = this->x != 0 ? this->x / fScalar : 0;
float retY = this->y != 0 ? this->y / fScalar : 0;
float retZ = this->z != 0 ? this->z / fScalar : 0;
return NiPoint3(retX, retY, retZ);
}
// MARK: Helper Functions // MARK: Helper Functions
//! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box
bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) {
if (this->x < minPoint.x) return false;
if (this->x > maxPoint.x) return false;
if (this->y < minPoint.y) return false;
if (this->y > maxPoint.y) return false;
return (this->z < maxPoint.z && this->z > minPoint.z);
}
//! Checks to see if the point (or vector) is within a sphere
bool NiPoint3::IsWithinSpehere(const NiPoint3& sphereCenter, float radius) {
Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ());
return (diffVec.SquaredLength() <= (radius * radius));
}
NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) {
if (a == b) return a;
const auto pa = p - a;
const auto ab = b - a;
const auto t = pa.DotProduct(ab) / ab.SquaredLength();
if (t <= 0.0f) return a;
if (t >= 1.0f) return b;
return a + ab * t;
}
float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b) { float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b) {
const auto dot = a.DotProduct(b); const auto dot = a.DotProduct(b);
const auto lenA = a.SquaredLength(); const auto lenA = a.SquaredLength();
@@ -34,7 +220,15 @@ float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b) {
return std::sqrt(dx * dx + dy * dy + dz * dz); return std::sqrt(dx * dx + dy * dy + dz * dz);
} }
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, const float maxDistanceDelta) { float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b) {
const auto dx = a.x - b.x;
const auto dy = a.y - b.y;
const auto dz = a.z - b.z;
return dx * dx + dy * dy + dz * dz;
}
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta) {
float dx = target.x - current.x; float dx = target.x - current.x;
float dy = target.y - current.y; float dy = target.y - current.y;
float dz = target.z - current.z; float dz = target.z - current.z;
@@ -55,3 +249,29 @@ NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target,
float length = std::sqrt(lengthSquared); float length = std::sqrt(lengthSquared);
return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta); return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta);
} }
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible.
NiPoint3 NiPoint3::RotateByQuaternion(const NiQuaternion& rotation) {
Vector3 vector;
float num12 = rotation.x + rotation.x;
float num2 = rotation.y + rotation.y;
float num = rotation.z + rotation.z;
float num11 = rotation.w * num12;
float num10 = rotation.w * num2;
float num9 = rotation.w * num;
float num8 = rotation.x * num12;
float num7 = rotation.x * num2;
float num6 = rotation.x * num;
float num5 = rotation.y * num2;
float num4 = rotation.y * num;
float num3 = rotation.z * num;
NiPoint3 value = *this;
float num15 = ((value.x * ((1.0f - num5) - num3)) + (value.y * (num7 - num9))) + (value.z * (num6 + num10));
float num14 = ((value.x * (num7 + num9)) + (value.y * ((1.0f - num8) - num3))) + (value.z * (num4 - num11));
float num13 = ((value.x * (num6 - num10)) + (value.y * (num4 + num11))) + (value.z * ((1.0f - num8) - num5));
vector.x = num15;
vector.y = num14;
vector.z = num13;
return vector;
}

View File

@@ -1,5 +1,4 @@
#ifndef __NIPOINT3_H__ #pragma once
#define __NIPOINT3_H__
/*! /*!
\file NiPoint3.hpp \file NiPoint3.hpp
@@ -13,13 +12,13 @@ typedef NiPoint3 Vector3; //!< The Vector3 class is technically the NiPoin
//! A custom class the defines a point in space //! A custom class the defines a point in space
class NiPoint3 { class NiPoint3 {
public: public:
float x{ 0 }; //!< The x position float x; //!< The x position
float y{ 0 }; //!< The y position float y; //!< The y position
float z{ 0 }; //!< The z position float z; //!< The z position
//! Initializer //! Initializer
constexpr NiPoint3() = default; NiPoint3(void);
//! Initializer //! Initializer
/*! /*!
@@ -27,21 +26,23 @@ public:
\param y The y coordinate \param y The y coordinate
\param z The z coordinate \param z The z coordinate
*/ */
constexpr NiPoint3(const float x, const float y, const float z) noexcept NiPoint3(float x, float y, float z);
: x{ x }
, y{ y }
, z{ z } {
}
//! Copy Constructor //! Copy Constructor
/*! /*!
\param point The point to copy \param point The point to copy
*/ */
constexpr NiPoint3(const NiPoint3& point) noexcept NiPoint3(const NiPoint3& point);
: x{ point.x }
, y{ point.y } //! Destructor
, z{ point.z } { ~NiPoint3(void);
}
// MARK: Constants
static const NiPoint3 ZERO; //!< Point(0, 0, 0)
static const NiPoint3 UNIT_X; //!< Point(1, 0, 0)
static const NiPoint3 UNIT_Y; //!< Point(0, 1, 0)
static const NiPoint3 UNIT_Z; //!< Point(0, 0, 1)
static const NiPoint3 UNIT_ALL; //!< Point(1, 1, 1)
// MARK: Getters / Setters // MARK: Getters / Setters
@@ -49,37 +50,38 @@ public:
/*! /*!
\return The x coordinate \return The x coordinate
*/ */
[[nodiscard]] constexpr float GetX() const noexcept; float GetX(void) const;
//! Sets the X coordinate //! Sets the X coordinate
/*! /*!
\param x The x coordinate \param x The x coordinate
*/ */
constexpr void SetX(const float x) noexcept; void SetX(float x);
//! Gets the Y coordinate //! Gets the Y coordinate
/*! /*!
\return The y coordinate \return The y coordinate
*/ */
[[nodiscard]] constexpr float GetY() const noexcept; float GetY(void) const;
//! Sets the Y coordinate //! Sets the Y coordinate
/*! /*!
\param y The y coordinate \param y The y coordinate
*/ */
constexpr void SetY(const float y) noexcept; void SetY(float y);
//! Gets the Z coordinate //! Gets the Z coordinate
/*! /*!
\return The z coordinate \return The z coordinate
*/ */
[[nodiscard]] constexpr float GetZ() const noexcept; float GetZ(void) const;
//! Sets the Z coordinate //! Sets the Z coordinate
/*! /*!
\param z The z coordinate \param z The z coordinate
*/ */
constexpr void SetZ(const float z) noexcept; void SetZ(float z);
// MARK: Member Functions // MARK: Member Functions
@@ -87,70 +89,72 @@ public:
/*! /*!
\return The scalar length of the vector \return The scalar length of the vector
*/ */
[[nodiscard]] float Length() const; float Length(void) const;
//! Gets the squared length of a vector //! Gets the squared length of a vector
/*! /*!
\return The squared length of a vector \return The squared length of a vector
*/ */
[[nodiscard]] constexpr float SquaredLength() const noexcept; float SquaredLength(void) const;
//! Returns the dot product of the vector dotted with another vector //! Returns the dot product of the vector dotted with another vector
/*! /*!
\param vec The second vector \param vec The second vector
\return The dot product of the two vectors \return The dot product of the two vectors
*/ */
[[nodiscard]] constexpr float DotProduct(const Vector3& vec) const noexcept; float DotProduct(const Vector3& vec) const;
//! Returns the cross product of the vector crossed with another vector //! Returns the cross product of the vector crossed with another vector
/*! /*!
\param vec The second vector \param vec The second vector
\return The cross product of the two vectors \return The cross product of the two vectors
*/ */
[[nodiscard]] constexpr Vector3 CrossProduct(const Vector3& vec) const noexcept; Vector3 CrossProduct(const Vector3& vec) const;
//! Unitize the vector //! Unitize the vector
/*! /*!
\returns The current vector \returns The current vector
*/ */
[[nodiscard]] NiPoint3 Unitize() const; NiPoint3 Unitize(void) const;
// MARK: Operators // MARK: Operators
//! Operator to check for equality //! Operator to check for equality
constexpr bool operator==(const NiPoint3& point) const noexcept; bool operator==(const NiPoint3& point) const;
//! Operator to check for inequality //! Operator to check for inequality
constexpr bool operator!=(const NiPoint3& point) const noexcept; bool operator!=(const NiPoint3& point) const;
//! Operator for subscripting //! Operator for subscripting
constexpr float& operator[](const int i) noexcept; float& operator[](int i);
//! Operator for subscripting //! Operator for subscripting
constexpr const float& operator[](const int i) const noexcept; const float& operator[](int i) const;
//! Operator for addition of vectors //! Operator for addition of vectors
constexpr NiPoint3 operator+(const NiPoint3& point) const noexcept; NiPoint3 operator+(const NiPoint3& point) const;
//! Operator for addition of vectors //! Operator for addition of vectors
constexpr NiPoint3& operator+=(const NiPoint3& point) noexcept; NiPoint3& operator+=(const NiPoint3& point);
constexpr NiPoint3& operator*=(const float scalar) noexcept; NiPoint3& operator*=(const float scalar);
//! Operator for subtraction of vectors //! Operator for subtraction of vectors
constexpr NiPoint3 operator-(const NiPoint3& point) const noexcept; NiPoint3 operator-(const NiPoint3& point) const;
//! Operator for addition of a scalar on all vector components //! Operator for addition of a scalar on all vector components
constexpr NiPoint3 operator+(const float fScalar) const noexcept; NiPoint3 operator+(float fScalar) const;
//! Operator for subtraction of a scalar on all vector components //! Operator for subtraction of a scalar on all vector components
constexpr NiPoint3 operator-(const float fScalar) const noexcept; NiPoint3 operator-(float fScalar) const;
//! Operator for scalar multiplication of a vector //! Operator for scalar multiplication of a vector
constexpr NiPoint3 operator*(const float fScalar) const noexcept; NiPoint3 operator*(float fScalar) const;
//! Operator for scalar division of a vector //! Operator for scalar division of a vector
constexpr NiPoint3 operator/(const float fScalar) const noexcept; NiPoint3 operator/(float fScalar) const;
// MARK: Helper Functions // MARK: Helper Functions
@@ -160,14 +164,14 @@ public:
\param maxPoint The maximum point of the bounding box \param maxPoint The maximum point of the bounding box
\return Whether or not this point lies within the box \return Whether or not this point lies within the box
*/ */
[[nodiscard]] constexpr bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) noexcept; bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint);
//! Checks to see if the point (or vector) is within a sphere //! Checks to see if the point (or vector) is within a sphere
/*! /*!
\param sphereCenter The sphere center \param sphereCenter The sphere center
\param radius The radius \param radius The radius
*/ */
[[nodiscard]] constexpr bool IsWithinSphere(const NiPoint3& sphereCenter, const float radius) noexcept; bool IsWithinSpehere(const NiPoint3& sphereCenter, float radius);
/*! /*!
\param a Start of line \param a Start of line
@@ -175,30 +179,15 @@ public:
\param p Refrence point \param p Refrence point
\return The point of line AB which is closest to P \return The point of line AB which is closest to P
*/ */
[[nodiscard]] static constexpr NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) noexcept; static NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p);
[[nodiscard]] static float Angle(const NiPoint3& a, const NiPoint3& b); static float Angle(const NiPoint3& a, const NiPoint3& b);
[[nodiscard]] static float Distance(const NiPoint3& a, const NiPoint3& b); static float Distance(const NiPoint3& a, const NiPoint3& b);
[[nodiscard]] static constexpr float DistanceSquared(const NiPoint3& a, const NiPoint3& b) noexcept; static float DistanceSquared(const NiPoint3& a, const NiPoint3& b);
[[nodiscard]] static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, const float maxDistanceDelta); static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta);
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible. NiPoint3 RotateByQuaternion(const NiQuaternion& rotation);
[[nodiscard]] constexpr NiPoint3 RotateByQuaternion(const NiQuaternion& rotation) noexcept;
}; };
// Static Variables
namespace NiPoint3Constant {
constexpr NiPoint3 ZERO(0.0f, 0.0f, 0.0f);
constexpr NiPoint3 UNIT_X(1.0f, 0.0f, 0.0f);
constexpr NiPoint3 UNIT_Y(0.0f, 1.0f, 0.0f);
constexpr NiPoint3 UNIT_Z(0.0f, 0.0f, 1.0f);
constexpr NiPoint3 UNIT_ALL(1.0f, 1.0f, 1.0f);
}
// .inl file needed for code organization and to circumvent circular dependency issues
#include "NiPoint3.inl"
#endif // !__NIPOINT3_H__

View File

@@ -1,196 +0,0 @@
#pragma once
#ifndef __NIPOINT3_H__
#error "This should only be included inline in NiPoint3.h: Do not include directly!"
#endif
#include "NiQuaternion.h"
// MARK: Getters / Setters
//! Gets the X coordinate
constexpr float NiPoint3::GetX() const noexcept {
return this->x;
}
//! Sets the X coordinate
constexpr void NiPoint3::SetX(const float x) noexcept {
this->x = x;
}
//! Gets the Y coordinate
constexpr float NiPoint3::GetY() const noexcept {
return this->y;
}
//! Sets the Y coordinate
constexpr void NiPoint3::SetY(const float y) noexcept {
this->y = y;
}
//! Gets the Z coordinate
constexpr float NiPoint3::GetZ() const noexcept {
return this->z;
}
//! Sets the Z coordinate
constexpr void NiPoint3::SetZ(const float z) noexcept {
this->z = z;
}
// MARK: Member Functions
//! Gets the squared length of a vector
constexpr float NiPoint3::SquaredLength() const noexcept {
return (x * x + y * y + z * z);
}
//! Returns the dot product of the vector dotted with another vector
constexpr float NiPoint3::DotProduct(const Vector3& vec) const noexcept {
return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z));
}
//! Returns the cross product of the vector crossed with another vector
constexpr Vector3 NiPoint3::CrossProduct(const Vector3& vec) const noexcept {
return Vector3(((this->y * vec.z) - (this->z * vec.y)),
((this->z * vec.x) - (this->x * vec.z)),
((this->x * vec.y) - (this->y * vec.x)));
}
// MARK: Operators
//! Operator to check for equality
constexpr bool NiPoint3::operator==(const NiPoint3& point) const noexcept {
return point.x == this->x && point.y == this->y && point.z == this->z;
}
//! Operator to check for inequality
constexpr bool NiPoint3::operator!=(const NiPoint3& point) const noexcept {
return !(*this == point);
}
//! Operator for subscripting
constexpr float& NiPoint3::operator[](const int i) noexcept {
float* base = &x;
return base[i];
}
//! Operator for subscripting
constexpr const float& NiPoint3::operator[](const int i) const noexcept {
const float* base = &x;
return base[i];
}
//! Operator for addition of vectors
constexpr NiPoint3 NiPoint3::operator+(const NiPoint3& point) const noexcept {
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
}
//! Operator for addition of vectors
constexpr NiPoint3& NiPoint3::operator+=(const NiPoint3& point) noexcept {
this->x += point.x;
this->y += point.y;
this->z += point.z;
return *this;
}
constexpr NiPoint3& NiPoint3::operator*=(const float scalar) noexcept {
this->x *= scalar;
this->y *= scalar;
this->z *= scalar;
return *this;
}
//! Operator for subtraction of vectors
constexpr NiPoint3 NiPoint3::operator-(const NiPoint3& point) const noexcept {
return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z);
}
//! Operator for addition of a scalar on all vector components
constexpr NiPoint3 NiPoint3::operator+(const float fScalar) const noexcept {
return NiPoint3(this->x + fScalar, this->y + fScalar, this->z + fScalar);
}
//! Operator for subtraction of a scalar on all vector components
constexpr NiPoint3 NiPoint3::operator-(const float fScalar) const noexcept {
return NiPoint3(this->x - fScalar, this->y - fScalar, this->z - fScalar);
}
//! Operator for scalar multiplication of a vector
constexpr NiPoint3 NiPoint3::operator*(const float fScalar) const noexcept {
return NiPoint3(this->x * fScalar, this->y * fScalar, this->z * fScalar);
}
//! Operator for scalar division of a vector
constexpr NiPoint3 NiPoint3::operator/(const float fScalar) const noexcept {
float retX = this->x != 0 ? this->x / fScalar : 0;
float retY = this->y != 0 ? this->y / fScalar : 0;
float retZ = this->z != 0 ? this->z / fScalar : 0;
return NiPoint3(retX, retY, retZ);
}
// MARK: Helper Functions
//! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box
constexpr bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) noexcept {
if (this->x < minPoint.x) return false;
if (this->x > maxPoint.x) return false;
if (this->y < minPoint.y) return false;
if (this->y > maxPoint.y) return false;
return (this->z < maxPoint.z && this->z > minPoint.z);
}
//! Checks to see if the point (or vector) is within a sphere
constexpr bool NiPoint3::IsWithinSphere(const NiPoint3& sphereCenter, const float radius) noexcept {
Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ());
return (diffVec.SquaredLength() <= (radius * radius));
}
constexpr NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) noexcept {
if (a == b) return a;
const auto pa = p - a;
const auto ab = b - a;
const auto t = pa.DotProduct(ab) / ab.SquaredLength();
if (t <= 0.0f) return a;
if (t >= 1.0f) return b;
return a + ab * t;
}
constexpr float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b) noexcept {
const auto dx = a.x - b.x;
const auto dy = a.y - b.y;
const auto dz = a.z - b.z;
return dx * dx + dy * dy + dz * dz;
}
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible.
constexpr NiPoint3 NiPoint3::RotateByQuaternion(const NiQuaternion& rotation) noexcept {
Vector3 vector;
float num12 = rotation.x + rotation.x;
float num2 = rotation.y + rotation.y;
float num = rotation.z + rotation.z;
float num11 = rotation.w * num12;
float num10 = rotation.w * num2;
float num9 = rotation.w * num;
float num8 = rotation.x * num12;
float num7 = rotation.x * num2;
float num6 = rotation.x * num;
float num5 = rotation.y * num2;
float num4 = rotation.y * num;
float num3 = rotation.z * num;
NiPoint3 value = *this;
float num15 = ((value.x * ((1.0f - num5) - num3)) + (value.y * (num7 - num9))) + (value.z * (num6 + num10));
float num14 = ((value.x * (num7 + num9)) + (value.y * ((1.0f - num8) - num3))) + (value.z * (num4 - num11));
float num13 = ((value.x * (num6 - num10)) + (value.y * (num4 + num11))) + (value.z * ((1.0f - num8) - num5));
vector.x = num15;
vector.y = num14;
vector.z = num13;
return vector;
}

View File

@@ -3,8 +3,89 @@
// C++ // C++
#include <cmath> #include <cmath>
// Static Variables
const NiQuaternion NiQuaternion::IDENTITY(1, 0, 0, 0);
//! The initializer
NiQuaternion::NiQuaternion(void) {
this->w = 1;
this->x = 0;
this->y = 0;
this->z = 0;
}
//! The initializer
NiQuaternion::NiQuaternion(float w, float x, float y, float z) {
this->w = w;
this->x = x;
this->y = y;
this->z = z;
}
//! Destructor
NiQuaternion::~NiQuaternion(void) {}
// MARK: Setters / Getters
//! Gets the W coordinate
float NiQuaternion::GetW(void) const {
return this->w;
}
//! Sets the W coordinate
void NiQuaternion::SetW(float w) {
this->w = w;
}
//! Gets the X coordinate
float NiQuaternion::GetX(void) const {
return this->x;
}
//! Sets the X coordinate
void NiQuaternion::SetX(float x) {
this->x = x;
}
//! Gets the Y coordinate
float NiQuaternion::GetY(void) const {
return this->y;
}
//! Sets the Y coordinate
void NiQuaternion::SetY(float y) {
this->y = y;
}
//! Gets the Z coordinate
float NiQuaternion::GetZ(void) const {
return this->z;
}
//! Sets the Z coordinate
void NiQuaternion::SetZ(float z) {
this->z = z;
}
// MARK: Member Functions // MARK: Member Functions
//! Returns the forward vector from the quaternion
Vector3 NiQuaternion::GetForwardVector(void) const {
return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
}
//! Returns the up vector from the quaternion
Vector3 NiQuaternion::GetUpVector(void) const {
return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
}
//! Returns the right vector from the quaternion
Vector3 NiQuaternion::GetRightVector(void) const {
return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
}
Vector3 NiQuaternion::GetEulerAngles() const { Vector3 NiQuaternion::GetEulerAngles() const {
Vector3 angles; Vector3 angles;
@@ -30,9 +111,22 @@ Vector3 NiQuaternion::GetEulerAngles() const {
return angles; return angles;
} }
// MARK: Operators
//! Operator to check for equality
bool NiQuaternion::operator==(const NiQuaternion& rot) const {
return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w;
}
//! Operator to check for inequality
bool NiQuaternion::operator!=(const NiQuaternion& rot) const {
return !(*this == rot);
}
// MARK: Helper Functions // MARK: Helper Functions
//! Look from a specific point in space to another point in space (Y-locked) //! Look from a specific point in space to another point in space
NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint) { NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
//To make sure we don't orient around the X/Z axis: //To make sure we don't orient around the X/Z axis:
NiPoint3 source = sourcePoint; NiPoint3 source = sourcePoint;
@@ -42,7 +136,7 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
NiPoint3 forwardVector = NiPoint3(dest - source).Unitize(); NiPoint3 forwardVector = NiPoint3(dest - source).Unitize();
NiPoint3 posZ = NiPoint3Constant::UNIT_Z; NiPoint3 posZ = NiPoint3::UNIT_Z;
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize(); NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
float dot = posZ.DotProduct(forwardVector); float dot = posZ.DotProduct(forwardVector);
@@ -54,11 +148,10 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle); return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
} }
//! Look from a specific point in space to another point in space
NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) { NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize(); NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize();
NiPoint3 posZ = NiPoint3Constant::UNIT_Z; NiPoint3 posZ = NiPoint3::UNIT_Z;
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize(); NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
float dot = posZ.DotProduct(forwardVector); float dot = posZ.DotProduct(forwardVector);

View File

@@ -1,5 +1,4 @@
#ifndef __NIQUATERNION_H__ #pragma once
#define __NIQUATERNION_H__
// Custom Classes // Custom Classes
#include "NiPoint3.h" #include "NiPoint3.h"
@@ -15,14 +14,14 @@ typedef NiQuaternion Quaternion; //!< A typedef for a shorthand version o
//! A class that defines a rotation in space //! A class that defines a rotation in space
class NiQuaternion { class NiQuaternion {
public: public:
float w{ 1 }; //!< The w coordinate float w; //!< The w coordinate
float x{ 0 }; //!< The x coordinate float x; //!< The x coordinate
float y{ 0 }; //!< The y coordinate float y; //!< The y coordinate
float z{ 0 }; //!< The z coordinate float z; //!< The z coordinate
//! The initializer //! The initializer
constexpr NiQuaternion() = default; NiQuaternion(void);
//! The initializer //! The initializer
/*! /*!
@@ -31,12 +30,13 @@ public:
\param y The y coordinate \param y The y coordinate
\param z The z coordinate \param z The z coordinate
*/ */
constexpr NiQuaternion(const float w, const float x, const float y, const float z) noexcept NiQuaternion(float w, float x, float y, float z);
: w{ w }
, x{ x } //! Destructor
, y{ y } ~NiQuaternion(void);
, z{ z } {
} // MARK: Constants
static const NiQuaternion IDENTITY; //!< Quaternion(1, 0, 0, 0)
// MARK: Setters / Getters // MARK: Setters / Getters
@@ -44,49 +44,50 @@ public:
/*! /*!
\return The w coordinate \return The w coordinate
*/ */
[[nodiscard]] constexpr float GetW() const noexcept; float GetW(void) const;
//! Sets the W coordinate //! Sets the W coordinate
/*! /*!
\param w The w coordinate \param w The w coordinate
*/ */
constexpr void SetW(const float w) noexcept; void SetW(float w);
//! Gets the X coordinate //! Gets the X coordinate
/*! /*!
\return The x coordinate \return The x coordinate
*/ */
[[nodiscard]] constexpr float GetX() const noexcept; float GetX(void) const;
//! Sets the X coordinate //! Sets the X coordinate
/*! /*!
\param x The x coordinate \param x The x coordinate
*/ */
constexpr void SetX(const float x) noexcept; void SetX(float x);
//! Gets the Y coordinate //! Gets the Y coordinate
/*! /*!
\return The y coordinate \return The y coordinate
*/ */
[[nodiscard]] constexpr float GetY() const noexcept; float GetY(void) const;
//! Sets the Y coordinate //! Sets the Y coordinate
/*! /*!
\param y The y coordinate \param y The y coordinate
*/ */
constexpr void SetY(const float y) noexcept; void SetY(float y);
//! Gets the Z coordinate //! Gets the Z coordinate
/*! /*!
\return The z coordinate \return The z coordinate
*/ */
[[nodiscard]] constexpr float GetZ() const noexcept; float GetZ(void) const;
//! Sets the Z coordinate //! Sets the Z coordinate
/*! /*!
\param z The z coordinate \param z The z coordinate
*/ */
constexpr void SetZ(const float z) noexcept; void SetZ(float z);
// MARK: Member Functions // MARK: Member Functions
@@ -94,29 +95,31 @@ public:
/*! /*!
\return The forward vector of the quaternion \return The forward vector of the quaternion
*/ */
[[nodiscard]] constexpr Vector3 GetForwardVector() const noexcept; Vector3 GetForwardVector(void) const;
//! Returns the up vector from the quaternion //! Returns the up vector from the quaternion
/*! /*!
\return The up vector fo the quaternion \return The up vector fo the quaternion
*/ */
[[nodiscard]] constexpr Vector3 GetUpVector() const noexcept; Vector3 GetUpVector(void) const;
//! Returns the right vector from the quaternion //! Returns the right vector from the quaternion
/*! /*!
\return The right vector of the quaternion \return The right vector of the quaternion
*/ */
[[nodiscard]] constexpr Vector3 GetRightVector() const noexcept; Vector3 GetRightVector(void) const;
Vector3 GetEulerAngles() const;
[[nodiscard]] Vector3 GetEulerAngles() const;
// MARK: Operators // MARK: Operators
//! Operator to check for equality //! Operator to check for equality
constexpr bool operator==(const NiQuaternion& rot) const noexcept; bool operator==(const NiQuaternion& rot) const;
//! Operator to check for inequality //! Operator to check for inequality
constexpr bool operator!=(const NiQuaternion& rot) const noexcept; bool operator!=(const NiQuaternion& rot) const;
// MARK: Helper Functions // MARK: Helper Functions
@@ -126,7 +129,7 @@ public:
\param destPoint The destination location \param destPoint The destination location
\return The Quaternion with the rotation towards the destination \return The Quaternion with the rotation towards the destination
*/ */
[[nodiscard]] static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint); static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
//! Look from a specific point in space to another point in space //! Look from a specific point in space to another point in space
/*! /*!
@@ -134,7 +137,7 @@ public:
\param destPoint The destination location \param destPoint The destination location
\return The Quaternion with the rotation towards the destination \return The Quaternion with the rotation towards the destination
*/ */
[[nodiscard]] static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint); static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
//! Creates a Quaternion from a specific axis and angle relative to that axis //! Creates a Quaternion from a specific axis and angle relative to that axis
/*! /*!
@@ -142,17 +145,7 @@ public:
\param angle The angle relative to this axis \param angle The angle relative to this axis
\return A quaternion created from the axis and angle \return A quaternion created from the axis and angle
*/ */
[[nodiscard]] static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle); static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);
[[nodiscard]] static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles); static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles);
}; };
// Static Variables
namespace NiQuaternionConstant {
constexpr NiQuaternion IDENTITY(1, 0, 0, 0);
}
// Include constexpr and inline function definitions in a seperate file for readability
#include "NiQuaternion.inl"
#endif // !__NIQUATERNION_H__

View File

@@ -1,75 +0,0 @@
#pragma once
#ifndef __NIQUATERNION_H__
#error "This should only be included inline in NiQuaternion.h: Do not include directly!"
#endif
// MARK: Setters / Getters
//! Gets the W coordinate
constexpr float NiQuaternion::GetW() const noexcept {
return this->w;
}
//! Sets the W coordinate
constexpr void NiQuaternion::SetW(const float w) noexcept {
this->w = w;
}
//! Gets the X coordinate
constexpr float NiQuaternion::GetX() const noexcept {
return this->x;
}
//! Sets the X coordinate
constexpr void NiQuaternion::SetX(const float x) noexcept {
this->x = x;
}
//! Gets the Y coordinate
constexpr float NiQuaternion::GetY() const noexcept {
return this->y;
}
//! Sets the Y coordinate
constexpr void NiQuaternion::SetY(const float y) noexcept {
this->y = y;
}
//! Gets the Z coordinate
constexpr float NiQuaternion::GetZ() const noexcept {
return this->z;
}
//! Sets the Z coordinate
constexpr void NiQuaternion::SetZ(const float z) noexcept {
this->z = z;
}
// MARK: Member Functions
//! Returns the forward vector from the quaternion
constexpr Vector3 NiQuaternion::GetForwardVector() const noexcept {
return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
}
//! Returns the up vector from the quaternion
constexpr Vector3 NiQuaternion::GetUpVector() const noexcept {
return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
}
//! Returns the right vector from the quaternion
constexpr Vector3 NiQuaternion::GetRightVector() const noexcept {
return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
}
// MARK: Operators
//! Operator to check for equality
constexpr bool NiQuaternion::operator==(const NiQuaternion& rot) const noexcept {
return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w;
}
//! Operator to check for inequality
constexpr bool NiQuaternion::operator!=(const NiQuaternion& rot) const noexcept {
return !(*this == rot);
}

View File

@@ -6,29 +6,43 @@
struct RemoteInputInfo { struct RemoteInputInfo {
RemoteInputInfo() {
m_RemoteInputX = 0;
m_RemoteInputY = 0;
m_IsPowersliding = false;
m_IsModified = false;
}
void operator=(const RemoteInputInfo& other) {
m_RemoteInputX = other.m_RemoteInputX;
m_RemoteInputY = other.m_RemoteInputY;
m_IsPowersliding = other.m_IsPowersliding;
m_IsModified = other.m_IsModified;
}
bool operator==(const RemoteInputInfo& other) { bool operator==(const RemoteInputInfo& other) {
return m_RemoteInputX == other.m_RemoteInputX && m_RemoteInputY == other.m_RemoteInputY && m_IsPowersliding == other.m_IsPowersliding && m_IsModified == other.m_IsModified; return m_RemoteInputX == other.m_RemoteInputX && m_RemoteInputY == other.m_RemoteInputY && m_IsPowersliding == other.m_IsPowersliding && m_IsModified == other.m_IsModified;
} }
float m_RemoteInputX = 0; float m_RemoteInputX;
float m_RemoteInputY = 0; float m_RemoteInputY;
bool m_IsPowersliding = false; bool m_IsPowersliding;
bool m_IsModified = false; bool m_IsModified;
}; };
struct LocalSpaceInfo { struct LocalSpaceInfo {
LWOOBJID objectId = LWOOBJID_EMPTY; LWOOBJID objectId = LWOOBJID_EMPTY;
NiPoint3 position = NiPoint3Constant::ZERO; NiPoint3 position = NiPoint3::ZERO;
NiPoint3 linearVelocity = NiPoint3Constant::ZERO; NiPoint3 linearVelocity = NiPoint3::ZERO;
}; };
struct PositionUpdate { struct PositionUpdate {
NiPoint3 position = NiPoint3Constant::ZERO; NiPoint3 position = NiPoint3::ZERO;
NiQuaternion rotation = NiQuaternionConstant::IDENTITY; NiQuaternion rotation = NiQuaternion::IDENTITY;
bool onGround = false; bool onGround = false;
bool onRail = false; bool onRail = false;
NiPoint3 velocity = NiPoint3Constant::ZERO; NiPoint3 velocity = NiPoint3::ZERO;
NiPoint3 angularVelocity = NiPoint3Constant::ZERO; NiPoint3 angularVelocity = NiPoint3::ZERO;
LocalSpaceInfo localSpaceInfo; LocalSpaceInfo localSpaceInfo;
RemoteInputInfo remoteInputInfo; RemoteInputInfo remoteInputInfo;
}; };

154
dCommon/SHA512.cpp Normal file
View File

@@ -0,0 +1,154 @@
// Source: http://www.zedwood.com/article/cpp-sha512-function
#include "SHA512.h"
#include <cstring>
#include <fstream>
const unsigned long long SHA512::sha512_k[80] = //ULL = uint64
{ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
void SHA512::transform(const unsigned char* message, unsigned int block_nb) {
uint64 w[80];
uint64 wv[8];
uint64 t1, t2;
const unsigned char* sub_block;
int i, j;
for (i = 0; i < (int)block_nb; i++) {
sub_block = message + (i << 7);
for (j = 0; j < 16; j++) {
SHA2_PACK64(&sub_block[j << 3], &w[j]);
}
for (j = 16; j < 80; j++) {
w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16];
}
for (j = 0; j < 8; j++) {
wv[j] = m_h[j];
}
for (j = 0; j < 80; j++) {
t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6])
+ sha512_k[j] + w[j];
t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
wv[5] = wv[4];
wv[4] = wv[3] + t1;
wv[3] = wv[2];
wv[2] = wv[1];
wv[1] = wv[0];
wv[0] = t1 + t2;
}
for (j = 0; j < 8; j++) {
m_h[j] += wv[j];
}
}
}
void SHA512::init() {
m_h[0] = 0x6a09e667f3bcc908ULL;
m_h[1] = 0xbb67ae8584caa73bULL;
m_h[2] = 0x3c6ef372fe94f82bULL;
m_h[3] = 0xa54ff53a5f1d36f1ULL;
m_h[4] = 0x510e527fade682d1ULL;
m_h[5] = 0x9b05688c2b3e6c1fULL;
m_h[6] = 0x1f83d9abfb41bd6bULL;
m_h[7] = 0x5be0cd19137e2179ULL;
m_len = 0;
m_tot_len = 0;
}
void SHA512::update(const unsigned char* message, unsigned int len) {
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char* shifted_message;
tmp_len = SHA384_512_BLOCK_SIZE - m_len;
rem_len = len < tmp_len ? len : tmp_len;
memcpy(&m_block[m_len], message, rem_len);
if (m_len + len < SHA384_512_BLOCK_SIZE) {
m_len += len;
return;
}
new_len = len - rem_len;
block_nb = new_len / SHA384_512_BLOCK_SIZE;
shifted_message = message + rem_len;
transform(m_block, 1);
transform(shifted_message, block_nb);
rem_len = new_len % SHA384_512_BLOCK_SIZE;
memcpy(m_block, &shifted_message[block_nb << 7], rem_len);
m_len = rem_len;
m_tot_len += (block_nb + 1) << 7;
}
void SHA512::final(unsigned char* digest) {
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
int i;
block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17)
< (m_len % SHA384_512_BLOCK_SIZE));
len_b = (m_tot_len + m_len) << 3;
pm_len = block_nb << 7;
memset(m_block + m_len, 0, pm_len - m_len);
m_block[m_len] = 0x80;
SHA2_UNPACK32(len_b, m_block + pm_len - 4);
transform(m_block, block_nb);
for (i = 0; i < 8; i++) {
SHA2_UNPACK64(m_h[i], &digest[i << 3]);
}
}
std::string sha512(std::string input) {
unsigned char digest[SHA512::DIGEST_SIZE];
memset(digest, 0, SHA512::DIGEST_SIZE);
class SHA512 ctx;
ctx.init();
ctx.update((unsigned char*)input.c_str(), input.length());
ctx.final(digest);
char buf[2 * SHA512::DIGEST_SIZE + 1];
buf[2 * SHA512::DIGEST_SIZE] = 0;
for (int i = 0; i < SHA512::DIGEST_SIZE; i++)
sprintf(buf + i * 2, "%02x", digest[i]);
return std::string(buf);
}

68
dCommon/SHA512.h Normal file
View File

@@ -0,0 +1,68 @@
#pragma once
// C++
#include <string>
class SHA512 {
protected:
typedef unsigned char uint8;
typedef unsigned int uint32;
typedef unsigned long long uint64;
const static uint64 sha512_k[];
static const unsigned int SHA384_512_BLOCK_SIZE = (1024 / 8);
public:
void init();
void update(const unsigned char* message, unsigned int len);
void final(unsigned char* digest);
static const unsigned int DIGEST_SIZE = (512 / 8);
protected:
void transform(const unsigned char* message, unsigned int block_nb);
unsigned int m_tot_len;
unsigned int m_len;
unsigned char m_block[2 * SHA384_512_BLOCK_SIZE];
uint64 m_h[8];
};
std::string sha512(std::string input);
#define SHA2_SHFR(x, n) (x >> n)
#define SHA2_ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n)))
#define SHA2_ROTL(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n)))
#define SHA2_CH(x, y, z) ((x & y) ^ (~x & z))
#define SHA2_MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define SHA512_F1(x) (SHA2_ROTR(x, 28) ^ SHA2_ROTR(x, 34) ^ SHA2_ROTR(x, 39))
#define SHA512_F2(x) (SHA2_ROTR(x, 14) ^ SHA2_ROTR(x, 18) ^ SHA2_ROTR(x, 41))
#define SHA512_F3(x) (SHA2_ROTR(x, 1) ^ SHA2_ROTR(x, 8) ^ SHA2_SHFR(x, 7))
#define SHA512_F4(x) (SHA2_ROTR(x, 19) ^ SHA2_ROTR(x, 61) ^ SHA2_SHFR(x, 6))
#define SHA2_UNPACK32(x, str) \
{ \
*((str) + 3) = (uint8) ((x) ); \
*((str) + 2) = (uint8) ((x) >> 8); \
*((str) + 1) = (uint8) ((x) >> 16); \
*((str) + 0) = (uint8) ((x) >> 24); \
}
#define SHA2_UNPACK64(x, str) \
{ \
*((str) + 7) = (uint8) ((x) ); \
*((str) + 6) = (uint8) ((x) >> 8); \
*((str) + 5) = (uint8) ((x) >> 16); \
*((str) + 4) = (uint8) ((x) >> 24); \
*((str) + 3) = (uint8) ((x) >> 32); \
*((str) + 2) = (uint8) ((x) >> 40); \
*((str) + 1) = (uint8) ((x) >> 48); \
*((str) + 0) = (uint8) ((x) >> 56); \
}
#define SHA2_PACK64(str, x) \
{ \
*(x) = ((uint64) *((str) + 7) ) \
| ((uint64) *((str) + 6) << 8) \
| ((uint64) *((str) + 5) << 16) \
| ((uint64) *((str) + 4) << 24) \
| ((uint64) *((str) + 3) << 32) \
| ((uint64) *((str) + 2) << 40) \
| ((uint64) *((str) + 1) << 48) \
| ((uint64) *((str) + 0) << 56); \
}

View File

@@ -1,6 +1,6 @@
set(DCOMMON_DCLIENT_SOURCES set(DCOMMON_DCLIENT_SOURCES
"AssetManager.cpp"
"PackIndex.cpp" "PackIndex.cpp"
"Pack.cpp" "Pack.cpp"
"AssetManager.cpp"
PARENT_SCOPE PARENT_SCOPE
) )

View File

@@ -1,12 +0,0 @@
#ifndef __CLIENTVERSION_H__
#define __CLIENTVERSION_H__
#include <cstdint>
namespace ClientVersion {
constexpr uint16_t major = 1;
constexpr uint16_t current = 10;
constexpr uint16_t minor = 64;
}
#endif // !__CLIENTVERSION_H__

View File

@@ -9,15 +9,15 @@ namespace StringifiedEnum {
const std::string_view ToString(const T e) { const std::string_view ToString(const T e) {
static_assert(std::is_enum_v<T>, "Not an enum"); // Check type static_assert(std::is_enum_v<T>, "Not an enum"); // Check type
constexpr auto& sv = magic_enum::enum_entries<T>(); constexpr auto sv = &magic_enum::enum_entries<T>();
const auto it = std::lower_bound( const auto it = std::lower_bound(
sv.begin(), sv.end(), e, sv->begin(), sv->end(), e,
[&](const std::pair<T, std::string_view>& lhs, const T rhs) { return lhs.first < rhs; } [&](const std::pair<T, std::string_view>& lhs, const T rhs) { return lhs.first < rhs; }
); );
std::string_view output; std::string_view output;
if (it != sv.end() && it->first == e) { if (it != sv->end() && it->first == e) {
output = it->second; output = it->second;
} else { } else {
output = "UNKNOWN"; output = "UNKNOWN";

View File

@@ -34,89 +34,91 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false); #define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits()); #define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); #define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false); #define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); #define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
//=========== TYPEDEFS ========== //=========== TYPEDEFS ==========
using LOT = int32_t; //!< A LOT typedef int32_t LOT; //!< A LOT
using LWOOBJID = int64_t; //!< An object ID (should be unsigned actually but ok) typedef int64_t LWOOBJID; //!< An object ID (should be unsigned actually but ok)
using TSkillID = int32_t; //!< A skill ID typedef int32_t TSkillID; //!< A skill ID
using LWOCLONEID = uint32_t; //!< Used for Clone IDs typedef uint32_t LWOCLONEID; //!< Used for Clone IDs
using LWOMAPID = uint16_t; //!< Used for Map IDs typedef uint16_t LWOMAPID; //!< Used for Map IDs
using LWOINSTANCEID = uint16_t; //!< Used for Instance IDs typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs
using PROPERTYCLONELIST = uint32_t; //!< Used for Property Clone IDs typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs
using StripId = uint32_t; typedef uint32_t StripId;
constexpr LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID
constexpr LOT LOT_NULL = -1; //!< A null LOT const LOT LOT_NULL = -1; //!< A null LOT
constexpr int32_t LOOTTYPE_NONE = 0; //!< No loot type available const int32_t LOOTTYPE_NONE = 0; //!< No loot type available
constexpr float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority
constexpr uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size
constexpr LWOCLONEID LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
constexpr LWOINSTANCEID LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
constexpr LWOMAPID LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
constexpr uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
constexpr float PI = 3.14159f; const float PI = 3.14159f;
//============ STRUCTS ============== //============ STRUCTS ==============
struct LWOSCENEID { struct LWOSCENEID {
public: public:
constexpr LWOSCENEID() noexcept { m_sceneID = -1; m_layerID = 0; } LWOSCENEID() { m_sceneID = -1; m_layerID = 0; }
constexpr LWOSCENEID(int32_t sceneID) noexcept { m_sceneID = sceneID; m_layerID = 0; } LWOSCENEID(int sceneID) { m_sceneID = sceneID; m_layerID = 0; }
constexpr LWOSCENEID(int32_t sceneID, uint32_t layerID) noexcept { m_sceneID = sceneID; m_layerID = layerID; } LWOSCENEID(int sceneID, unsigned int layerID) { m_sceneID = sceneID; m_layerID = layerID; }
constexpr LWOSCENEID& operator=(const LWOSCENEID& rhs) noexcept { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; } LWOSCENEID& operator=(const LWOSCENEID& rhs) { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; }
constexpr LWOSCENEID& operator=(const int32_t rhs) noexcept { m_sceneID = rhs; m_layerID = 0; return *this; } LWOSCENEID& operator=(const int rhs) { m_sceneID = rhs; m_layerID = 0; return *this; }
constexpr bool operator<(const LWOSCENEID& rhs) const noexcept { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); } bool operator<(const LWOSCENEID& rhs) const { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); }
constexpr bool operator<(const int32_t rhs) const noexcept { return m_sceneID < rhs; } bool operator<(const int rhs) const { return m_sceneID < rhs; }
constexpr bool operator==(const LWOSCENEID& rhs) const noexcept { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); } bool operator==(const LWOSCENEID& rhs) const { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); }
constexpr bool operator==(const int32_t rhs) const noexcept { return m_sceneID == rhs; } bool operator==(const int rhs) const { return m_sceneID == rhs; }
constexpr int32_t GetSceneID() const noexcept { return m_sceneID; } const int GetSceneID() const { return m_sceneID; }
constexpr uint32_t GetLayerID() const noexcept { return m_layerID; } const unsigned int GetLayerID() const { return m_layerID; }
constexpr void SetSceneID(const int32_t sceneID) noexcept { m_sceneID = sceneID; } void SetSceneID(const int sceneID) { m_sceneID = sceneID; }
constexpr void SetLayerID(const uint32_t layerID) noexcept { m_layerID = layerID; } void SetLayerID(const unsigned int layerID) { m_layerID = layerID; }
private: private:
int32_t m_sceneID; int m_sceneID;
uint32_t m_layerID; unsigned int m_layerID;
}; };
struct LWOZONEID { struct LWOZONEID {
public: public:
constexpr const LWOMAPID& GetMapID() const noexcept { return m_MapID; } const LWOMAPID& GetMapID() const { return m_MapID; }
constexpr const LWOINSTANCEID& GetInstanceID() const noexcept { return m_InstanceID; } const LWOINSTANCEID& GetInstanceID() const { return m_InstanceID; }
constexpr const LWOCLONEID& GetCloneID() const noexcept { return m_CloneID; } const LWOCLONEID& GetCloneID() const { return m_CloneID; }
//In order: def constr, constr, assign op //In order: def constr, constr, assign op
constexpr LWOZONEID() noexcept = default; LWOZONEID() { m_MapID = LWOMAPID_INVALID; m_InstanceID = LWOINSTANCEID_INVALID; m_CloneID = LWOCLONEID_INVALID; }
constexpr LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) noexcept { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; } LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; }
constexpr LWOZONEID(const LWOZONEID& replacement) noexcept { *this = replacement; } LWOZONEID(const LWOZONEID& replacement) { *this = replacement; }
private: private:
LWOMAPID m_MapID = LWOMAPID_INVALID; //1000 for VE, 1100 for AG, etc... LWOMAPID m_MapID; //1000 for VE, 1100 for AG, etc...
LWOINSTANCEID m_InstanceID = LWOINSTANCEID_INVALID; //Instances host the same world, but on a different dWorld process. LWOINSTANCEID m_InstanceID; //Instances host the same world, but on a different dWorld process.
LWOCLONEID m_CloneID = LWOCLONEID_INVALID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds. LWOCLONEID m_CloneID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds.
}; };
constexpr LWOSCENEID LWOSCENEID_INVALID = -1; const LWOSCENEID LWOSCENEID_INVALID = -1;
struct LWONameValue { struct LWONameValue {
uint32_t length = 0; //!< The length of the name uint32_t length = 0; //!< The length of the name
std::u16string name; //!< The name std::u16string name; //!< The name
LWONameValue() = default; LWONameValue(void) {}
LWONameValue(const std::u16string& name) { LWONameValue(const std::u16string& name) {
this->name = name; this->name = name;
this->length = static_cast<uint32_t>(name.length()); this->length = static_cast<uint32_t>(name.length());
} }
~LWONameValue(void) {}
}; };
struct FriendData { struct FriendData {

View File

@@ -0,0 +1,31 @@
#ifndef __ECHATINTERNALMESSAGETYPE__H__
#define __ECHATINTERNALMESSAGETYPE__H__
#include <cstdint>
enum eChatInternalMessageType : uint32_t {
PLAYER_ADDED_NOTIFICATION = 0,
PLAYER_REMOVED_NOTIFICATION,
ADD_FRIEND,
ADD_BEST_FRIEND,
ADD_TO_TEAM,
ADD_BLOCK,
REMOVE_FRIEND,
REMOVE_BLOCK,
REMOVE_FROM_TEAM,
DELETE_TEAM,
REPORT,
PRIVATE_CHAT,
PRIVATE_CHAT_RESPONSE,
ANNOUNCEMENT,
MAIL_COUNT_UPDATE,
MAIL_SEND_NOTIFY,
REQUEST_USER_LIST,
FRIEND_LIST,
ROUTE_TO_PLAYER,
TEAM_UPDATE,
MUTE_UPDATE,
CREATE_TEAM,
};
#endif //!__ECHATINTERNALMESSAGETYPE__H__

View File

@@ -72,9 +72,7 @@ enum class eChatMessageType :uint32_t {
UPDATE_DONATION, UPDATE_DONATION,
PRG_CSR_COMMAND, PRG_CSR_COMMAND,
HEARTBEAT_REQUEST_FROM_WORLD, HEARTBEAT_REQUEST_FROM_WORLD,
UPDATE_FREE_TRIAL_STATUS, UPDATE_FREE_TRIAL_STATUS
// CUSTOM DLU MESSAGE ID FOR INTERNAL USE
CREATE_TEAM,
}; };
#endif //!__ECHATMESSAGETYPE__H__ #endif //!__ECHATMESSAGETYPE__H__

View File

@@ -5,7 +5,8 @@ enum class eConnectionType : uint16_t {
SERVER = 0, SERVER = 0,
AUTH, AUTH,
CHAT, CHAT,
WORLD = 4, CHAT_INTERNAL,
WORLD,
CLIENT, CLIENT,
MASTER MASTER
}; };

View File

@@ -106,7 +106,7 @@ enum class eReplicaComponentType : uint32_t {
INTERACTION_MANAGER, INTERACTION_MANAGER,
DONATION_VENDOR, DONATION_VENDOR,
COMBAT_MEDIATOR, COMBAT_MEDIATOR,
ACHIEVEMENT_VENDOR, COMMENDATION_VENDOR,
GATE_RUSH_CONTROL, GATE_RUSH_CONTROL,
RAIL_ACTIVATOR, RAIL_ACTIVATOR,
ROLLER, ROLLER,

View File

@@ -1,15 +0,0 @@
#ifndef __EVENDORTRANSACTIONRESULT__
#define __EVENDORTRANSACTIONRESULT__
#include <cstdint>
enum class eVendorTransactionResult : uint32_t {
SELL_SUCCESS = 0,
SELL_FAIL,
PURCHASE_SUCCESS,
PURCHASE_FAIL,
DONATION_FAIL,
DONATION_FULL
};
#endif // !__EVENDORTRANSACTIONRESULT__

View File

@@ -1,59 +0,0 @@
#ifndef __EWAYPOINTCOMMANDTYPES__H__
#define __EWAYPOINTCOMMANDTYPES__H__
#include <cstdint>
enum class eWaypointCommandType : uint32_t {
INVALID,
BOUNCE,
STOP,
GROUP_EMOTE,
SET_VARIABLE,
CAST_SKILL,
EQUIP_INVENTORY,
UNEQUIP_INVENTORY,
DELAY,
EMOTE,
TELEPORT,
PATH_SPEED,
REMOVE_NPC,
CHANGE_WAYPOINT,
DELETE_SELF,
KILL_SELF,
SPAWN_OBJECT,
PLAY_SOUND,
};
class WaypointCommandType {
public:
static eWaypointCommandType StringToWaypointCommandType(std::string commandString) {
const std::map<std::string, eWaypointCommandType> WaypointCommandTypeMap = {
{"bounce", eWaypointCommandType::BOUNCE},
{"stop", eWaypointCommandType::STOP},
{"groupemote", eWaypointCommandType::GROUP_EMOTE},
{"setvar", eWaypointCommandType::SET_VARIABLE},
{"castskill", eWaypointCommandType::CAST_SKILL},
{"eqInvent", eWaypointCommandType::EQUIP_INVENTORY},
{"unInvent", eWaypointCommandType::UNEQUIP_INVENTORY},
{"delay", eWaypointCommandType::DELAY},
{"femote", eWaypointCommandType::EMOTE},
{"emote", eWaypointCommandType::EMOTE},
{"teleport", eWaypointCommandType::TELEPORT},
{"pathspeed", eWaypointCommandType::PATH_SPEED},
{"removeNPC", eWaypointCommandType::REMOVE_NPC},
{"changeWP", eWaypointCommandType::CHANGE_WAYPOINT},
{"DeleteSelf", eWaypointCommandType::DELETE_SELF},
{"killself", eWaypointCommandType::KILL_SELF},
{"removeself", eWaypointCommandType::DELETE_SELF},
{"spawnOBJ", eWaypointCommandType::SPAWN_OBJECT},
{"playSound", eWaypointCommandType::PLAY_SOUND},
};
auto intermed = WaypointCommandTypeMap.find(commandString);
return (intermed != WaypointCommandTypeMap.end()) ? intermed->second : eWaypointCommandType::INVALID;
};
};
#endif //!__EWAYPOINTCOMMANDTYPES__H__

View File

@@ -29,8 +29,8 @@ enum class eWorldMessageType : uint32_t {
ROUTE_PACKET, // Social? ROUTE_PACKET, // Social?
POSITION_UPDATE, POSITION_UPDATE,
MAIL, MAIL,
WORD_CHECK, // AllowList word check WORD_CHECK, // Whitelist word check
STRING_CHECK, // AllowList string check STRING_CHECK, // Whitelist string check
GET_PLAYERS_IN_ZONE, GET_PLAYERS_IN_ZONE,
REQUEST_UGC_MANIFEST_INFO, REQUEST_UGC_MANIFEST_INFO,
BLUEPRINT_GET_ALL_DATA_REQUEST, BLUEPRINT_GET_ALL_DATA_REQUEST,

View File

@@ -39,7 +39,6 @@
#include "CDFeatureGatingTable.h" #include "CDFeatureGatingTable.h"
#include "CDRailActivatorComponent.h" #include "CDRailActivatorComponent.h"
#include "CDRewardCodesTable.h" #include "CDRewardCodesTable.h"
#include "CDPetComponentTable.h"
#include <exception> #include <exception>
@@ -62,55 +61,6 @@ public:
} }
}; };
// Using a macro to reduce repetitive code and issues from copy and paste.
// As a note, ## in a macro is used to concatenate two tokens together.
#define SPECIALIZE_TABLE_STORAGE(table) \
template<> typename table::StorageType& CDClientManager::GetEntriesMutable<table>() { return table##Entries; };
#define DEFINE_TABLE_STORAGE(table) namespace { table::StorageType table##Entries; }; SPECIALIZE_TABLE_STORAGE(table)
DEFINE_TABLE_STORAGE(CDActivityRewardsTable);
DEFINE_TABLE_STORAGE(CDActivitiesTable);
DEFINE_TABLE_STORAGE(CDAnimationsTable);
DEFINE_TABLE_STORAGE(CDBehaviorParameterTable);
DEFINE_TABLE_STORAGE(CDBehaviorTemplateTable);
DEFINE_TABLE_STORAGE(CDBrickIDTableTable);
DEFINE_TABLE_STORAGE(CDComponentsRegistryTable);
DEFINE_TABLE_STORAGE(CDCurrencyTableTable);
DEFINE_TABLE_STORAGE(CDDestructibleComponentTable);
DEFINE_TABLE_STORAGE(CDEmoteTableTable);
DEFINE_TABLE_STORAGE(CDFeatureGatingTable);
DEFINE_TABLE_STORAGE(CDInventoryComponentTable);
DEFINE_TABLE_STORAGE(CDItemComponentTable);
DEFINE_TABLE_STORAGE(CDItemSetSkillsTable);
DEFINE_TABLE_STORAGE(CDItemSetsTable);
DEFINE_TABLE_STORAGE(CDLevelProgressionLookupTable);
DEFINE_TABLE_STORAGE(CDLootMatrixTable);
DEFINE_TABLE_STORAGE(CDLootTableTable);
DEFINE_TABLE_STORAGE(CDMissionEmailTable);
DEFINE_TABLE_STORAGE(CDMissionNPCComponentTable);
DEFINE_TABLE_STORAGE(CDMissionTasksTable);
DEFINE_TABLE_STORAGE(CDMissionsTable);
DEFINE_TABLE_STORAGE(CDMovementAIComponentTable);
DEFINE_TABLE_STORAGE(CDObjectSkillsTable);
DEFINE_TABLE_STORAGE(CDObjectsTable);
DEFINE_TABLE_STORAGE(CDPhysicsComponentTable);
DEFINE_TABLE_STORAGE(CDPackageComponentTable);
DEFINE_TABLE_STORAGE(CDPetComponentTable);
DEFINE_TABLE_STORAGE(CDProximityMonitorComponentTable);
DEFINE_TABLE_STORAGE(CDPropertyEntranceComponentTable);
DEFINE_TABLE_STORAGE(CDPropertyTemplateTable);
DEFINE_TABLE_STORAGE(CDRailActivatorComponentTable);
DEFINE_TABLE_STORAGE(CDRarityTableTable);
DEFINE_TABLE_STORAGE(CDRebuildComponentTable);
DEFINE_TABLE_STORAGE(CDRewardCodesTable);
DEFINE_TABLE_STORAGE(CDRewardsTable);
DEFINE_TABLE_STORAGE(CDScriptComponentTable);
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
DEFINE_TABLE_STORAGE(CDZoneTableTable);
void CDClientManager::LoadValuesFromDatabase() { void CDClientManager::LoadValuesFromDatabase() {
if (!CDClientDatabase::isConnected) throw CDClientConnectionException(); if (!CDClientDatabase::isConnected) throw CDClientConnectionException();

View File

@@ -1,12 +1,18 @@
#ifndef __CDCLIENTMANAGER__H__ #pragma once
#define __CDCLIENTMANAGER__H__
#include "CDTable.h"
#include "Singleton.h"
#define UNUSED_TABLE(v) #define UNUSED_TABLE(v)
/** /**
* Initialize the CDClient tables so they are all loaded into memory. * Initialize the CDClient tables so they are all loaded into memory.
*/ */
namespace CDClientManager { class CDClientManager : public Singleton<CDClientManager> {
public:
CDClientManager() = default;
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
void LoadValuesFromDefaults(); void LoadValuesFromDefaults();
@@ -17,28 +23,7 @@ namespace CDClientManager {
* @return A pointer to the requested table. * @return A pointer to the requested table.
*/ */
template<typename T> template<typename T>
T* GetTable(); T* GetTable() {
/**
* Fetch a table from CDClient
* Note: Calling this function without a template specialization in CDClientManager.cpp will cause a linker error.
*
* @tparam Table type to fetch
* @return A pointer to the requested table.
*/
template<typename T>
typename T::StorageType& GetEntriesMutable();
};
// These are included after the CDClientManager namespace declaration as CDTable as of Jan 29 2024 relies on CDClientManager in Templated code.
#include "CDTable.h"
#include "Singleton.h"
template<typename T>
T* CDClientManager::GetTable() {
return &T::Instance(); return &T::Instance();
}
}; };
#endif //!__CDCLIENTMANAGER__H__

View File

@@ -1,6 +1,5 @@
#include "CDActivitiesTable.h" #include "CDActivitiesTable.h"
void CDActivitiesTable::LoadValuesFromDatabase() { void CDActivitiesTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; uint32_t size = 0;
@@ -14,8 +13,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities");
@@ -41,7 +39,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1); entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1);
entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f); entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -50,7 +48,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) { std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) {
std::vector<CDActivities> data = cpplinq::from(GetEntries()) std::vector<CDActivities> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();

View File

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

View File

@@ -1,6 +1,5 @@
#include "CDActivityRewardsTable.h" #include "CDActivityRewardsTable.h"
void CDActivityRewardsTable::LoadValuesFromDatabase() { void CDActivityRewardsTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
@@ -15,8 +14,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards");
@@ -30,7 +28,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1); entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1);
entry.description = tableData.getStringField("description", ""); entry.description = tableData.getStringField("description", "");
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -39,7 +37,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) { std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) {
std::vector<CDActivityRewards> data = cpplinq::from(GetEntries()) std::vector<CDActivityRewards> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();

View File

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

View File

@@ -5,7 +5,6 @@
void CDAnimationsTable::LoadValuesFromDatabase() { void CDAnimationsTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations");
auto& animations = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
std::string animation_type = tableData.getStringField("animation_type", ""); std::string animation_type = tableData.getStringField("animation_type", "");
DluAssert(!animation_type.empty()); DluAssert(!animation_type.empty());
@@ -25,7 +24,7 @@ void CDAnimationsTable::LoadValuesFromDatabase() {
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);) UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);) UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry); this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -36,7 +35,6 @@ bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
auto tableData = queryToCache.execQuery(); auto tableData = queryToCache.execQuery();
// If we received a bad lookup, cache it anyways so we do not run the query again. // If we received a bad lookup, cache it anyways so we do not run the query again.
if (tableData.eof()) return false; if (tableData.eof()) return false;
auto& animations = GetEntriesMutable();
do { do {
std::string animation_type = tableData.getStringField("animation_type", ""); std::string animation_type = tableData.getStringField("animation_type", "");
@@ -57,7 +55,7 @@ bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);) UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);) UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry); this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow(); tableData.nextRow();
} while (!tableData.eof()); } while (!tableData.eof());
@@ -70,17 +68,15 @@ void CDAnimationsTable::CacheAnimations(const CDAnimationKey animationKey) {
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?"); auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?");
query.bind(1, static_cast<int32_t>(animationKey.second)); query.bind(1, static_cast<int32_t>(animationKey.second));
query.bind(2, animationKey.first.c_str()); query.bind(2, animationKey.first.c_str());
auto& animations = GetEntriesMutable();
// If we received a bad lookup, cache it anyways so we do not run the query again. // If we received a bad lookup, cache it anyways so we do not run the query again.
if (!CacheData(query)) { if (!CacheData(query)) {
animations[animationKey]; this->animations[animationKey];
} }
} }
void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) { void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
auto& animations = GetEntriesMutable(); auto animationEntryCached = this->animations.find(CDAnimationKey("", animationGroupID));
auto animationEntryCached = animations.find(CDAnimationKey("", animationGroupID)); if (animationEntryCached != this->animations.end()) {
if (animationEntryCached != animations.end()) {
return; return;
} }
@@ -89,29 +85,28 @@ void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
// Cache the query so we don't run the query again. // Cache the query so we don't run the query again.
CacheData(query); CacheData(query);
animations[CDAnimationKey("", animationGroupID)]; this->animations[CDAnimationKey("", animationGroupID)];
} }
std::optional<CDAnimation> CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) { CDAnimationLookupResult CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) {
auto& animations = GetEntriesMutable();
CDAnimationKey animationKey(animationType, animationGroupID); CDAnimationKey animationKey(animationType, animationGroupID);
auto animationEntryCached = animations.find(animationKey); auto animationEntryCached = this->animations.find(animationKey);
if (animationEntryCached == animations.end()) { if (animationEntryCached == this->animations.end()) {
this->CacheAnimations(animationKey); this->CacheAnimations(animationKey);
} }
auto animationEntry = animations.find(animationKey); auto animationEntry = this->animations.find(animationKey);
// If we have only one animation, return it regardless of the chance to play. // If we have only one animation, return it regardless of the chance to play.
if (animationEntry->second.size() == 1) { if (animationEntry->second.size() == 1) {
return animationEntry->second.front(); return CDAnimationLookupResult(animationEntry->second.front());
} }
auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1); auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1);
for (auto& animationEntry : animationEntry->second) { for (auto& animationEntry : animationEntry->second) {
randomAnimation -= animationEntry.chance_to_play; randomAnimation -= animationEntry.chance_to_play;
// This is how the client gets the random animation. // This is how the client gets the random animation.
if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return animationEntry; if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return CDAnimationLookupResult(animationEntry);
} }
return std::nullopt; return CDAnimationLookupResult();
} }

View File

@@ -2,11 +2,6 @@
#include "CDTable.h" #include "CDTable.h"
#include <list> #include <list>
#include <optional>
typedef int32_t AnimationGroupID;
typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
struct CDAnimation { struct CDAnimation {
// uint32_t animationGroupID; // uint32_t animationGroupID;
@@ -25,7 +20,12 @@ struct CDAnimation {
UNUSED_COLUMN(float blendTime;) //!< The blend time UNUSED_COLUMN(float blendTime;) //!< The blend time
}; };
class CDAnimationsTable : public CDTable<CDAnimationsTable, std::map<CDAnimationKey, std::list<CDAnimation>>> { typedef LookupResult<CDAnimation> CDAnimationLookupResult;
class CDAnimationsTable : public CDTable<CDAnimationsTable> {
typedef int32_t AnimationGroupID;
typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
/** /**
@@ -38,7 +38,7 @@ public:
* @param animationGroupID The animationGroupID to lookup * @param animationGroupID The animationGroupID to lookup
* @return CDAnimationLookupResult * @return CDAnimationLookupResult
*/ */
[[nodiscard]] std::optional<CDAnimation> GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID); [[nodiscard]] CDAnimationLookupResult GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID);
/** /**
* Cache a full AnimationGroup by its ID. * Cache a full AnimationGroup by its ID.
@@ -58,4 +58,10 @@ private:
* @return false * @return false
*/ */
bool CacheData(CppSQLite3Statement& queryToCache); bool CacheData(CppSQLite3Statement& queryToCache);
/**
* 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<CDAnimationKey, std::list<CDAnimation>> animations;
}; };

View File

@@ -1,10 +1,6 @@
#include "CDBehaviorParameterTable.h" #include "CDBehaviorParameterTable.h"
#include "GeneralUtils.h" #include "GeneralUtils.h"
namespace {
std::unordered_map<std::string, uint32_t> m_ParametersList;
};
uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) { uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
uint64_t key = behaviorID; uint64_t key = behaviorID;
key <<= 31U; key <<= 31U;
@@ -15,7 +11,6 @@ uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
void CDBehaviorParameterTable::LoadValuesFromDatabase() { void CDBehaviorParameterTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
uint32_t behaviorID = tableData.getIntField("behaviorID", -1); uint32_t behaviorID = tableData.getIntField("behaviorID", -1);
auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", "")); auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", ""));
@@ -29,7 +24,7 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
uint64_t hash = GetKey(behaviorID, parameterId); uint64_t hash = GetKey(behaviorID, parameterId);
float value = tableData.getFloatField("value", -1.0f); float value = tableData.getFloatField("value", -1.0f);
entries.insert(std::make_pair(hash, value)); m_Entries.insert(std::make_pair(hash, value));
tableData.nextRow(); tableData.nextRow();
} }
@@ -37,24 +32,22 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
} }
float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) { float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
auto parameterID = m_ParametersList.find(name); auto parameterID = this->m_ParametersList.find(name);
if (parameterID == m_ParametersList.end()) return defaultValue; if (parameterID == this->m_ParametersList.end()) return defaultValue;
auto hash = GetKey(behaviorID, parameterID->second); auto hash = GetKey(behaviorID, parameterID->second);
// Search for specific parameter // Search for specific parameter
auto& entries = GetEntriesMutable(); auto it = m_Entries.find(hash);
auto it = entries.find(hash); return it != m_Entries.end() ? it->second : defaultValue;
return it != entries.end() ? it->second : defaultValue;
} }
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
auto& entries = GetEntriesMutable();
uint64_t hashBase = behaviorID; uint64_t hashBase = behaviorID;
std::map<std::string, float> returnInfo; std::map<std::string, float> returnInfo;
for (auto& [parameterString, parameterId] : m_ParametersList) { for (auto& [parameterString, parameterId] : m_ParametersList) {
uint64_t hash = GetKey(hashBase, parameterId); uint64_t hash = GetKey(hashBase, parameterId);
auto infoCandidate = entries.find(hash); auto infoCandidate = m_Entries.find(hash);
if (infoCandidate != entries.end()) { if (infoCandidate != m_Entries.end()) {
returnInfo.insert(std::make_pair(parameterString, infoCandidate->second)); returnInfo.insert(std::make_pair(parameterString, infoCandidate->second));
} }
} }

View File

@@ -5,10 +5,12 @@
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
typedef uint64_t BehaviorParameterHash; class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable> {
typedef float BehaviorParameterValue; private:
typedef uint64_t BehaviorParameterHash;
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable, std::unordered_map<BehaviorParameterHash, BehaviorParameterValue>> { typedef float BehaviorParameterValue;
std::unordered_map<BehaviorParameterHash, BehaviorParameterValue> m_Entries;
std::unordered_map<std::string, uint32_t> m_ParametersList;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();

View File

@@ -1,9 +1,5 @@
#include "CDBehaviorTemplateTable.h" #include "CDBehaviorTemplateTable.h"
namespace {
std::unordered_set<std::string> m_EffectHandles;
};
void CDBehaviorTemplateTable::LoadValuesFromDatabase() { void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
@@ -17,9 +13,11 @@ void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDBehaviorTemplate entry; CDBehaviorTemplate entry;
entry.behaviorID = tableData.getIntField("behaviorID", -1); entry.behaviorID = tableData.getIntField("behaviorID", -1);
@@ -33,17 +31,30 @@ void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first; entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
} }
entries.insert(std::make_pair(entry.behaviorID, entry)); this->entries.push_back(entry);
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize(); tableData.finalize();
} }
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<bool(CDBehaviorTemplate)> predicate) {
std::vector<CDBehaviorTemplate> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
}
const std::vector<CDBehaviorTemplate>& CDBehaviorTemplateTable::GetEntries() const {
return this->entries;
}
const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) { const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) {
auto& entries = GetEntriesMutable(); auto entry = this->entriesMappedByBehaviorID.find(behaviorID);
auto entry = entries.find(behaviorID); if (entry == this->entriesMappedByBehaviorID.end()) {
if (entry == entries.end()) {
CDBehaviorTemplate entryToReturn; CDBehaviorTemplate entryToReturn;
entryToReturn.behaviorID = 0; entryToReturn.behaviorID = 0;
entryToReturn.effectHandle = m_EffectHandles.end(); entryToReturn.effectHandle = m_EffectHandles.end();

View File

@@ -12,9 +12,19 @@ struct CDBehaviorTemplate {
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
}; };
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable, std::unordered_map<uint32_t, CDBehaviorTemplate>> {
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: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
const std::vector<CDBehaviorTemplate>& GetEntries(void) const;
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID); const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
}; };

View File

@@ -14,8 +14,7 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable");
@@ -24,7 +23,7 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
entry.NDObjectID = tableData.getIntField("NDObjectID", -1); entry.NDObjectID = tableData.getIntField("NDObjectID", -1);
entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1); entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -32,9 +31,15 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
} }
std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) { std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) {
std::vector<CDBrickIDTable> data = cpplinq::from(GetEntries())
std::vector<CDBrickIDTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDBrickIDTable>& CDBrickIDTableTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -4,15 +4,14 @@
void CDComponentsRegistryTable::LoadValuesFromDatabase() { void CDComponentsRegistryTable::LoadValuesFromDatabase() {
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDComponentsRegistry entry; CDComponentsRegistry entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0)); entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
entry.component_id = tableData.getIntField("component_id", -1); entry.component_id = tableData.getIntField("component_id", -1);
entries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id); this->mappedEntries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
entries.insert_or_assign(entry.id, 0); this->mappedEntries.insert_or_assign(entry.id, 0);
tableData.nextRow(); tableData.nextRow();
} }
@@ -21,11 +20,10 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
} }
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) { int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
auto& entries = GetEntriesMutable(); auto exists = mappedEntries.find(id);
auto exists = entries.find(id); if (exists != mappedEntries.end()) {
if (exists != entries.end()) { auto iter = mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
auto iter = entries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id)); return iter == mappedEntries.end() ? defaultValue : iter->second;
return iter == entries.end() ? defaultValue : iter->second;
} }
// Now get the data. Get all components of this entity so we dont do a query for each component // Now get the data. Get all components of this entity so we dont do a query for each component
@@ -40,14 +38,14 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponent
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0)); entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
entry.component_id = tableData.getIntField("component_id", -1); entry.component_id = tableData.getIntField("component_id", -1);
entries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id); this->mappedEntries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
tableData.nextRow(); tableData.nextRow();
} }
entries.insert_or_assign(id, 0); mappedEntries.insert_or_assign(id, 0);
auto iter = entries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id)); auto iter = this->mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
return iter == entries.end() ? defaultValue : iter->second; return iter == this->mappedEntries.end() ? defaultValue : iter->second;
} }

View File

@@ -13,7 +13,10 @@ struct CDComponentsRegistry {
}; };
class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable, std::unordered_map<uint64_t, uint32_t>> { class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable> {
private:
std::unordered_map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0); int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0);

View File

@@ -15,8 +15,7 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable");
@@ -28,7 +27,7 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
entry.maxvalue = tableData.getIntField("maxvalue", -1); entry.maxvalue = tableData.getIntField("maxvalue", -1);
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -36,9 +35,15 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
} }
std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCurrencyTable)> predicate) { std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCurrencyTable)> predicate) {
std::vector<CDCurrencyTable> data = cpplinq::from(GetEntries())
std::vector<CDCurrencyTable> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDCurrencyTable>& CDCurrencyTableTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -13,8 +13,7 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent");
@@ -35,7 +34,7 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false; entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false;
entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1); entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -43,9 +42,15 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
} }
std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::function<bool(CDDestructibleComponent)> predicate) { std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::function<bool(CDDestructibleComponent)> predicate) {
std::vector<CDDestructibleComponent> data = cpplinq::from(GetEntries())
std::vector<CDDestructibleComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDDestructibleComponent>& CDDestructibleComponentTable::GetEntries() const {
return this->entries;
}

View File

@@ -20,9 +20,14 @@ struct CDDestructibleComponent {
int32_t difficultyLevel; //!< ??? int32_t difficultyLevel; //!< ???
}; };
class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable, std::vector<CDDestructibleComponent>> { class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable> {
private:
std::vector<CDDestructibleComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate); std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate);
const std::vector<CDDestructibleComponent>& GetEntries(void) const;
}; };

View File

@@ -2,7 +2,6 @@
void CDEmoteTableTable::LoadValuesFromDatabase() { void CDEmoteTableTable::LoadValuesFromDatabase() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDEmoteTable entry; CDEmoteTable entry;
entry.ID = tableData.getIntField("id", -1); entry.ID = tableData.getIntField("id", -1);
@@ -22,7 +21,6 @@ void CDEmoteTableTable::LoadValuesFromDatabase() {
} }
CDEmoteTable* CDEmoteTableTable::GetEmote(int32_t id) { CDEmoteTable* CDEmoteTableTable::GetEmote(int32_t id) {
auto& entries = GetEntriesMutable();
auto itr = entries.find(id); auto itr = entries.find(id);
return itr != entries.end() ? &itr->second : nullptr; return itr != entries.end() ? &itr->second : nullptr;
} }

View File

@@ -26,7 +26,10 @@ struct CDEmoteTable {
std::string gateVersion; std::string gateVersion;
}; };
class CDEmoteTableTable : public CDTable<CDEmoteTableTable, std::map<int, CDEmoteTable>> { class CDEmoteTableTable : public CDTable<CDEmoteTableTable> {
private:
std::map<int, CDEmoteTable> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Returns an emote by ID // Returns an emote by ID

View File

@@ -14,8 +14,7 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating");
@@ -27,7 +26,7 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
entry.minor = tableData.getIntField("minor", -1); entry.minor = tableData.getIntField("minor", -1);
entry.description = tableData.getStringField("description", ""); entry.description = tableData.getStringField("description", "");
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -36,8 +35,7 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFeatureGating)> predicate) { std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFeatureGating)> predicate) {
auto& entries = GetEntriesMutable(); std::vector<CDFeatureGating> data = cpplinq::from(this->entries)
std::vector<CDFeatureGating> data = cpplinq::from(entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
@@ -45,7 +43,6 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
} }
bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const { bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
auto& entries = GetEntriesMutable();
for (const auto& entry : entries) { for (const auto& entry : entries) {
if (entry.featureName == feature.featureName && feature >= entry) { if (entry.featureName == feature.featureName && feature >= entry) {
return true; return true;
@@ -54,3 +51,8 @@ bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const
return false; return false;
} }
const std::vector<CDFeatureGating>& CDFeatureGatingTable::GetEntries() const {
return this->entries;
}

View File

@@ -17,7 +17,10 @@ struct CDFeatureGating {
} }
}; };
class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable, std::vector<CDFeatureGating>> { class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable> {
private:
std::vector<CDFeatureGating> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
@@ -25,4 +28,6 @@ public:
std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate); std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
bool FeatureUnlocked(const CDFeatureGating& feature) const; bool FeatureUnlocked(const CDFeatureGating& feature) const;
const std::vector<CDFeatureGating>& GetEntries(void) const;
}; };

View File

@@ -14,8 +14,7 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent");
@@ -26,7 +25,7 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
entry.count = tableData.getIntField("count", -1); entry.count = tableData.getIntField("count", -1);
entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false; entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false;
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -34,9 +33,15 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
} }
std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function<bool(CDInventoryComponent)> predicate) { std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function<bool(CDInventoryComponent)> predicate) {
std::vector<CDInventoryComponent> data = cpplinq::from(GetEntries())
std::vector<CDInventoryComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDInventoryComponent>& CDInventoryComponentTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -17,7 +17,6 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
CDItemComponent entry; CDItemComponent entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
@@ -63,7 +62,7 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
entry.forgeType = tableData.getIntField("forgeType", -1); entry.forgeType = tableData.getIntField("forgeType", -1);
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
entries.insert(std::make_pair(entry.id, entry)); this->entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow(); tableData.nextRow();
} }
@@ -71,9 +70,8 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
} }
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skillID) { const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skillID) {
auto& entries = GetEntriesMutable(); const auto& it = this->entries.find(skillID);
const auto& it = entries.find(skillID); if (it != this->entries.end()) {
if (it != entries.end()) {
return it->second; return it->second;
} }
@@ -131,12 +129,12 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skill
entry.forgeType = tableData.getIntField("forgeType", -1); entry.forgeType = tableData.getIntField("forgeType", -1);
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
entries.insert(std::make_pair(entry.id, entry)); this->entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow(); tableData.nextRow();
} }
const auto& it2 = entries.find(skillID); const auto& it2 = this->entries.find(skillID);
if (it2 != entries.end()) { if (it2 != this->entries.end()) {
return it2->second; return it2->second;
} }

View File

@@ -49,7 +49,10 @@ struct CDItemComponent {
float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced) float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced)
}; };
class CDItemComponentTable : public CDTable<CDItemComponentTable, std::map<uint32_t, CDItemComponent>> { class CDItemComponentTable : public CDTable<CDItemComponentTable> {
private:
std::map<uint32_t, CDItemComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent); static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent);

View File

@@ -14,8 +14,7 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills");
@@ -25,7 +24,7 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
entry.SkillID = tableData.getIntField("SkillID", -1); entry.SkillID = tableData.getIntField("SkillID", -1);
entry.SkillCastType = tableData.getIntField("SkillCastType", -1); entry.SkillCastType = tableData.getIntField("SkillCastType", -1);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -33,17 +32,22 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
} }
std::vector<CDItemSetSkills> CDItemSetSkillsTable::Query(std::function<bool(CDItemSetSkills)> predicate) { std::vector<CDItemSetSkills> CDItemSetSkillsTable::Query(std::function<bool(CDItemSetSkills)> predicate) {
std::vector<CDItemSetSkills> data = cpplinq::from(GetEntries())
std::vector<CDItemSetSkills> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDItemSetSkills>& CDItemSetSkillsTable::GetEntries() const {
return this->entries;
}
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(uint32_t SkillSetID) { std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(uint32_t SkillSetID) {
std::vector<CDItemSetSkills> toReturn; std::vector<CDItemSetSkills> toReturn;
for (const auto& entry : GetEntries()) { for (CDItemSetSkills entry : this->entries) {
if (entry.SkillSetID == SkillSetID) toReturn.push_back(entry); if (entry.SkillSetID == SkillSetID) toReturn.push_back(entry);
if (entry.SkillSetID > SkillSetID) return toReturn; //stop seeking in the db if it's not needed. if (entry.SkillSetID > SkillSetID) return toReturn; //stop seeking in the db if it's not needed.
} }

View File

@@ -9,11 +9,16 @@ struct CDItemSetSkills {
uint32_t SkillCastType; //!< The skill cast type uint32_t SkillCastType; //!< The skill cast type
}; };
class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable, std::vector<CDItemSetSkills>> { class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable> {
private:
std::vector<CDItemSetSkills> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate); std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate);
const std::vector<CDItemSetSkills>& GetEntries() const;
std::vector<CDItemSetSkills> GetBySkillID(uint32_t SkillSetID); std::vector<CDItemSetSkills> GetBySkillID(uint32_t SkillSetID);
}; };

View File

@@ -14,8 +14,7 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets");
@@ -37,7 +36,7 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
entry.kitID = tableData.getIntField("kitID", -1); entry.kitID = tableData.getIntField("kitID", -1);
entry.priority = tableData.getFloatField("priority", -1.0f); entry.priority = tableData.getFloatField("priority", -1.0f);
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -46,9 +45,14 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> predicate) { std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> predicate) {
std::vector<CDItemSets> data = cpplinq::from(GetEntries()) std::vector<CDItemSets> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDItemSets>& CDItemSetsTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -14,8 +14,7 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup");
@@ -25,7 +24,7 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
entry.requiredUScore = tableData.getIntField("requiredUScore", -1); entry.requiredUScore = tableData.getIntField("requiredUScore", -1);
entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", ""); entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", "");
entries.push_back(entry); this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -34,9 +33,14 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::function<bool(CDLevelProgressionLookup)> predicate) { std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::function<bool(CDLevelProgressionLookup)> predicate) {
std::vector<CDLevelProgressionLookup> data = cpplinq::from(GetEntries()) std::vector<CDLevelProgressionLookup> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDLevelProgressionLookup>& CDLevelProgressionLookupTable::GetEntries() const {
return this->entries;
}

View File

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

View File

@@ -25,8 +25,7 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
} }
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix");
@@ -34,15 +33,14 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
CDLootMatrix entry; CDLootMatrix entry;
uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
entries[lootMatrixIndex].push_back(ReadRow(tableData)); this->entries[lootMatrixIndex].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
} }
const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) { const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
auto& entries = GetEntriesMutable(); auto itr = this->entries.find(matrixId);
auto itr = entries.find(matrixId); if (itr != this->entries.end()) {
if (itr != entries.end()) {
return itr->second; return itr->second;
} }
@@ -51,10 +49,10 @@ const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
auto tableData = query.execQuery(); auto tableData = query.execQuery();
while (!tableData.eof()) { while (!tableData.eof()) {
entries[matrixId].push_back(ReadRow(tableData)); this->entries[matrixId].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
return entries[matrixId]; return this->entries[matrixId];
} }

View File

@@ -16,7 +16,7 @@ struct CDLootMatrix {
typedef uint32_t LootMatrixIndex; typedef uint32_t LootMatrixIndex;
typedef std::vector<CDLootMatrix> LootMatrixEntries; typedef std::vector<CDLootMatrix> LootMatrixEntries;
class CDLootMatrixTable : public CDTable<CDLootMatrixTable, std::unordered_map<LootMatrixIndex, LootMatrixEntries>> { class CDLootMatrixTable : public CDTable<CDLootMatrixTable> {
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
@@ -24,5 +24,6 @@ public:
const LootMatrixEntries& GetMatrix(uint32_t matrixId); const LootMatrixEntries& GetMatrix(uint32_t matrixId);
private: private:
CDLootMatrix ReadRow(CppSQLite3Query& tableData) const; CDLootMatrix ReadRow(CppSQLite3Query& tableData) const;
std::unordered_map<LootMatrixIndex, LootMatrixEntries> entries;
}; };

View File

@@ -6,8 +6,8 @@
// Sort the tables by their rarity so the highest rarity items are first. // Sort the tables by their rarity so the highest rarity items are first.
void SortTable(LootTableEntries& table) { void SortTable(LootTableEntries& table) {
auto* componentsRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>(); auto* componentsRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
auto* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>(); auto* itemComponentTable = CDClientManager::Instance().GetTable<CDItemComponentTable>();
// We modify the table in place so the outer loop keeps track of what is sorted // We modify the table in place so the outer loop keeps track of what is sorted
// and the inner loop finds the highest rarity item and swaps it with the current position // and the inner loop finds the highest rarity item and swaps it with the current position
// of the outer loop. // of the outer loop.
@@ -49,8 +49,7 @@ void CDLootTableTable::LoadValuesFromDatabase() {
} }
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable");
@@ -58,18 +57,17 @@ void CDLootTableTable::LoadValuesFromDatabase() {
CDLootTable entry; CDLootTable entry;
uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1); uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1);
entries[lootTableIndex].emplace_back(ReadRow(tableData)); this->entries[lootTableIndex].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
for (auto& [id, table] : entries) { for (auto& [id, table] : this->entries) {
SortTable(table); SortTable(table);
} }
} }
const LootTableEntries& CDLootTableTable::GetTable(const uint32_t tableId) { const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
auto& entries = GetEntriesMutable(); auto itr = this->entries.find(tableId);
auto itr = entries.find(tableId); if (itr != this->entries.end()) {
if (itr != entries.end()) {
return itr->second; return itr->second;
} }
@@ -79,10 +77,10 @@ const LootTableEntries& CDLootTableTable::GetTable(const uint32_t tableId) {
while (!tableData.eof()) { while (!tableData.eof()) {
CDLootTable entry; CDLootTable entry;
entries[tableId].emplace_back(ReadRow(tableData)); this->entries[tableId].push_back(ReadRow(tableData));
tableData.nextRow(); tableData.nextRow();
} }
SortTable(entries[tableId]); SortTable(this->entries[tableId]);
return entries[tableId]; return this->entries[tableId];
} }

View File

@@ -3,8 +3,6 @@
// Custom Classes // Custom Classes
#include "CDTable.h" #include "CDTable.h"
#include <cstdint>
struct CDLootTable { struct CDLootTable {
uint32_t itemid; //!< The LOT of the item uint32_t itemid; //!< The LOT of the item
uint32_t LootTableIndex; //!< The Loot Table Index uint32_t LootTableIndex; //!< The Loot Table Index
@@ -15,12 +13,14 @@ struct CDLootTable {
typedef uint32_t LootTableIndex; typedef uint32_t LootTableIndex;
typedef std::vector<CDLootTable> LootTableEntries; typedef std::vector<CDLootTable> LootTableEntries;
class CDLootTableTable : public CDTable<CDLootTableTable, std::unordered_map<LootTableIndex, LootTableEntries>> { class CDLootTableTable : public CDTable<CDLootTableTable> {
private: private:
CDLootTable ReadRow(CppSQLite3Query& tableData) const; CDLootTable ReadRow(CppSQLite3Query& tableData) const;
std::unordered_map<LootTableIndex, LootTableEntries> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
const LootTableEntries& GetTable(const uint32_t tableId); const LootTableEntries& GetTable(uint32_t tableId);
}; };

View File

@@ -1,7 +1,7 @@
#include "CDMissionEmailTable.h" #include "CDMissionEmailTable.h"
void CDMissionEmailTable::LoadValuesFromDatabase() { void CDMissionEmailTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; uint32_t size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionEmail"); auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionEmail");
@@ -14,13 +14,12 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail");
while (!tableData.eof()) { while (!tableData.eof()) {
auto& entry = entries.emplace_back(); CDMissionEmail entry;
entry.ID = tableData.getIntField("ID", -1); entry.ID = tableData.getIntField("ID", -1);
entry.messageType = tableData.getIntField("messageType", -1); entry.messageType = tableData.getIntField("messageType", -1);
entry.notificationGroup = tableData.getIntField("notificationGroup", -1); entry.notificationGroup = tableData.getIntField("notificationGroup", -1);
@@ -30,15 +29,24 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
entry.locStatus = tableData.getIntField("locStatus", -1); entry.locStatus = tableData.getIntField("locStatus", -1);
entry.gate_version = tableData.getStringField("gate_version", ""); entry.gate_version = tableData.getStringField("gate_version", "");
this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize();
} }
//! Queries the table with a custom "where" clause //! Queries the table with a custom "where" clause
std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMissionEmail)> predicate) { std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMissionEmail)> predicate) {
std::vector<CDMissionEmail> data = cpplinq::from(GetEntries())
std::vector<CDMissionEmail> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
//! Gets all the entries in the table
const std::vector<CDMissionEmail>& CDMissionEmailTable::GetEntries() const {
return this->entries;
}

View File

@@ -3,8 +3,6 @@
// Custom Classes // Custom Classes
#include "CDTable.h" #include "CDTable.h"
#include <cstdint>
struct CDMissionEmail { struct CDMissionEmail {
uint32_t ID; uint32_t ID;
uint32_t messageType; uint32_t messageType;
@@ -17,9 +15,14 @@ struct CDMissionEmail {
}; };
class CDMissionEmailTable : public CDTable<CDMissionEmailTable, std::vector<CDMissionEmail>> { class CDMissionEmailTable : public CDTable<CDMissionEmailTable> {
private:
std::vector<CDMissionEmail> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDMissionEmail> Query(std::function<bool(CDMissionEmail)> predicate); std::vector<CDMissionEmail> Query(std::function<bool(CDMissionEmail)> predicate);
const std::vector<CDMissionEmail>& GetEntries() const;
}; };

View File

@@ -14,29 +14,37 @@ void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent");
while (!tableData.eof()) { while (!tableData.eof()) {
auto& entry = entries.emplace_back(); CDMissionNPCComponent entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entry.missionID = tableData.getIntField("missionID", -1); entry.missionID = tableData.getIntField("missionID", -1);
entry.offersMission = tableData.getIntField("offersMission", -1) == 1 ? true : false; entry.offersMission = tableData.getIntField("offersMission", -1) == 1 ? true : false;
entry.acceptsMission = tableData.getIntField("acceptsMission", -1) == 1 ? true : false; entry.acceptsMission = tableData.getIntField("acceptsMission", -1) == 1 ? true : false;
entry.gate_version = tableData.getStringField("gate_version", ""); entry.gate_version = tableData.getStringField("gate_version", "");
this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize();
} }
//! Queries the table with a custom "where" clause //! Queries the table with a custom "where" clause
std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::Query(std::function<bool(CDMissionNPCComponent)> predicate) { std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::Query(std::function<bool(CDMissionNPCComponent)> predicate) {
std::vector<CDMissionNPCComponent> data = cpplinq::from(GetEntries()) std::vector<CDMissionNPCComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
//! Gets all the entries in the table
const std::vector<CDMissionNPCComponent>& CDMissionNPCComponentTable::GetEntries() const {
return this->entries;
}

View File

@@ -3,8 +3,6 @@
// Custom Classes // Custom Classes
#include "CDTable.h" #include "CDTable.h"
#include <cstdint>
struct CDMissionNPCComponent { struct CDMissionNPCComponent {
uint32_t id; //!< The ID uint32_t id; //!< The ID
uint32_t missionID; //!< The Mission ID uint32_t missionID; //!< The Mission ID
@@ -13,9 +11,17 @@ struct CDMissionNPCComponent {
std::string gate_version; //!< The gate version std::string gate_version; //!< The gate version
}; };
class CDMissionNPCComponentTable : public CDTable<CDMissionNPCComponentTable, std::vector<CDMissionNPCComponent>> { class CDMissionNPCComponentTable : public CDTable<CDMissionNPCComponentTable> {
private:
std::vector<CDMissionNPCComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDMissionNPCComponent> Query(std::function<bool(CDMissionNPCComponent)> predicate); std::vector<CDMissionNPCComponent> Query(std::function<bool(CDMissionNPCComponent)> predicate);
// Gets all the entries in the table
const std::vector<CDMissionNPCComponent>& GetEntries() const;
}; };

View File

@@ -14,13 +14,12 @@ void CDMissionTasksTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionTasks"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionTasks");
while (!tableData.eof()) { while (!tableData.eof()) {
auto& entry = entries.emplace_back(); CDMissionTasks entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1));
entry.taskType = tableData.getIntField("taskType", -1); entry.taskType = tableData.getIntField("taskType", -1);
@@ -35,24 +34,26 @@ void CDMissionTasksTable::LoadValuesFromDatabase() {
UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false); UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false);
UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize();
} }
std::vector<CDMissionTasks> CDMissionTasksTable::Query(std::function<bool(CDMissionTasks)> predicate) { std::vector<CDMissionTasks> CDMissionTasksTable::Query(std::function<bool(CDMissionTasks)> predicate) {
std::vector<CDMissionTasks> data = cpplinq::from(GetEntries()) std::vector<CDMissionTasks> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(const uint32_t missionID) { std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(uint32_t missionID) {
std::vector<CDMissionTasks*> tasks; std::vector<CDMissionTasks*> tasks;
// TODO: this should not be linear(?) and also shouldnt need to be a pointer for (auto& entry : this->entries) {
for (auto& entry : GetEntriesMutable()) {
if (entry.id == missionID) { if (entry.id == missionID) {
tasks.push_back(&entry); tasks.push_back(&entry);
} }
@@ -61,6 +62,7 @@ std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(const uint32_t
return tasks; return tasks;
} }
const typename CDMissionTasksTable::StorageType& CDMissionTasksTable::GetEntries() const { const std::vector<CDMissionTasks>& CDMissionTasksTable::GetEntries() const {
return CDTable::GetEntries(); return this->entries;
} }

View File

@@ -3,8 +3,6 @@
// Custom Classes // Custom Classes
#include "CDTable.h" #include "CDTable.h"
#include <cstdint>
struct CDMissionTasks { struct CDMissionTasks {
uint32_t id; //!< The Mission ID that the task belongs to uint32_t id; //!< The Mission ID that the task belongs to
UNUSED(uint32_t locStatus); //!< ??? UNUSED(uint32_t locStatus); //!< ???
@@ -21,15 +19,17 @@ struct CDMissionTasks {
UNUSED(std::string gate_version); //!< ??? UNUSED(std::string gate_version); //!< ???
}; };
class CDMissionTasksTable : public CDTable<CDMissionTasksTable, std::vector<CDMissionTasks>> { class CDMissionTasksTable : public CDTable<CDMissionTasksTable> {
private:
std::vector<CDMissionTasks> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDMissionTasks> Query(std::function<bool(CDMissionTasks)> predicate); std::vector<CDMissionTasks> Query(std::function<bool(CDMissionTasks)> predicate);
std::vector<CDMissionTasks*> GetByMissionID(const uint32_t missionID); std::vector<CDMissionTasks*> GetByMissionID(uint32_t missionID);
// TODO: Remove this and replace it with a proper lookup function. const std::vector<CDMissionTasks>& GetEntries() const;
const CDTable::StorageType& GetEntries() const;
}; };

View File

@@ -16,13 +16,12 @@ void CDMissionsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Missions"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Missions");
while (!tableData.eof()) { while (!tableData.eof()) {
auto& entry = entries.emplace_back(); CDMissions entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entry.defined_type = tableData.getStringField("defined_type", ""); entry.defined_type = tableData.getStringField("defined_type", "");
entry.defined_subtype = tableData.getStringField("defined_subtype", ""); entry.defined_subtype = tableData.getStringField("defined_subtype", "");
@@ -76,8 +75,10 @@ void CDMissionsTable::LoadValuesFromDatabase() {
UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1));
entry.reward_bankinventory = tableData.getIntField("reward_bankinventory", -1); entry.reward_bankinventory = tableData.getIntField("reward_bankinventory", -1);
this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize(); tableData.finalize();
Default.id = -1; Default.id = -1;
@@ -85,15 +86,19 @@ void CDMissionsTable::LoadValuesFromDatabase() {
std::vector<CDMissions> CDMissionsTable::Query(std::function<bool(CDMissions)> predicate) { std::vector<CDMissions> CDMissionsTable::Query(std::function<bool(CDMissions)> predicate) {
std::vector<CDMissions> data = cpplinq::from(GetEntries()) std::vector<CDMissions> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDMissions>& CDMissionsTable::GetEntries(void) const {
return this->entries;
}
const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const { const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const {
for (const auto& entry : GetEntries()) { for (const auto& entry : entries) {
if (entry.id == missionID) { if (entry.id == missionID) {
return const_cast<CDMissions*>(&entry); return const_cast<CDMissions*>(&entry);
} }
@@ -103,7 +108,7 @@ const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const {
} }
const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& found) const { const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& found) const {
for (const auto& entry : GetEntries()) { for (const auto& entry : entries) {
if (entry.id == missionID) { if (entry.id == missionID) {
found = true; found = true;
@@ -116,12 +121,3 @@ const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& foun
return Default; return Default;
} }
const std::set<int32_t> CDMissionsTable::GetMissionsForReward(LOT lot) {
std::set<int32_t> toReturn {};
for (const auto& entry : GetEntries()) {
if (lot == entry.reward_item1 || lot == entry.reward_item2 || lot == entry.reward_item3 || lot == entry.reward_item4) {
toReturn.insert(entry.id);
}
}
return toReturn;
}

View File

@@ -60,18 +60,22 @@ struct CDMissions {
int32_t reward_bankinventory; //!< The amount of bank space this mission rewards int32_t reward_bankinventory; //!< The amount of bank space this mission rewards
}; };
class CDMissionsTable : public CDTable<CDMissionsTable, std::vector<CDMissions>> { class CDMissionsTable : public CDTable<CDMissionsTable> {
private:
std::vector<CDMissions> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDMissions> Query(std::function<bool(CDMissions)> predicate); std::vector<CDMissions> Query(std::function<bool(CDMissions)> predicate);
// Gets all the entries in the table
const std::vector<CDMissions>& GetEntries() const;
const CDMissions* GetPtrByMissionID(uint32_t missionID) const; const CDMissions* GetPtrByMissionID(uint32_t missionID) const;
const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const; const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const;
const std::set<int32_t> GetMissionsForReward(LOT lot);
static CDMissions Default; static CDMissions Default;
}; };

View File

@@ -14,13 +14,12 @@ void CDMovementAIComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MovementAIComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MovementAIComponent");
while (!tableData.eof()) { while (!tableData.eof()) {
auto& entry = entries.emplace_back(); CDMovementAIComponent entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entry.MovementType = tableData.getStringField("MovementType", ""); entry.MovementType = tableData.getStringField("MovementType", "");
entry.WanderChance = tableData.getFloatField("WanderChance", -1.0f); entry.WanderChance = tableData.getFloatField("WanderChance", -1.0f);
@@ -30,15 +29,23 @@ void CDMovementAIComponentTable::LoadValuesFromDatabase() {
entry.WanderRadius = tableData.getFloatField("WanderRadius", -1.0f); entry.WanderRadius = tableData.getFloatField("WanderRadius", -1.0f);
entry.attachedPath = tableData.getStringField("attachedPath", ""); entry.attachedPath = tableData.getStringField("attachedPath", "");
this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize();
} }
std::vector<CDMovementAIComponent> CDMovementAIComponentTable::Query(std::function<bool(CDMovementAIComponent)> predicate) { std::vector<CDMovementAIComponent> CDMovementAIComponentTable::Query(std::function<bool(CDMovementAIComponent)> predicate) {
std::vector<CDMovementAIComponent> data = cpplinq::from(GetEntries()) std::vector<CDMovementAIComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDMovementAIComponent>& CDMovementAIComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -3,8 +3,6 @@
// Custom Classes // Custom Classes
#include "CDTable.h" #include "CDTable.h"
#include <cstdint>
struct CDMovementAIComponent { struct CDMovementAIComponent {
uint32_t id; uint32_t id;
std::string MovementType; std::string MovementType;
@@ -16,9 +14,15 @@ struct CDMovementAIComponent {
std::string attachedPath; std::string attachedPath;
}; };
class CDMovementAIComponentTable : public CDTable<CDMovementAIComponentTable, std::vector<CDMovementAIComponent>> { class CDMovementAIComponentTable : public CDTable<CDMovementAIComponentTable> {
private:
std::vector<CDMovementAIComponent> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDMovementAIComponent> Query(std::function<bool(CDMovementAIComponent)> predicate); std::vector<CDMovementAIComponent> Query(std::function<bool(CDMovementAIComponent)> predicate);
// Gets all the entries in the table
const std::vector<CDMovementAIComponent>& GetEntries() const;
}; };

View File

@@ -14,27 +14,33 @@ void CDObjectSkillsTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
// Reserve the size // Reserve the size
auto& entries = GetEntriesMutable(); this->entries.reserve(size);
entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ObjectSkills"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ObjectSkills");
while (!tableData.eof()) { while (!tableData.eof()) {
auto &entry = entries.emplace_back(); CDObjectSkills entry;
entry.objectTemplate = tableData.getIntField("objectTemplate", -1); entry.objectTemplate = tableData.getIntField("objectTemplate", -1);
entry.skillID = tableData.getIntField("skillID", -1); entry.skillID = tableData.getIntField("skillID", -1);
entry.castOnType = tableData.getIntField("castOnType", -1); entry.castOnType = tableData.getIntField("castOnType", -1);
entry.AICombatWeight = tableData.getIntField("AICombatWeight", -1); entry.AICombatWeight = tableData.getIntField("AICombatWeight", -1);
this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize();
} }
std::vector<CDObjectSkills> CDObjectSkillsTable::Query(std::function<bool(CDObjectSkills)> predicate) { std::vector<CDObjectSkills> CDObjectSkillsTable::Query(std::function<bool(CDObjectSkills)> predicate) {
std::vector<CDObjectSkills> data = cpplinq::from(GetEntries()) std::vector<CDObjectSkills> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
const std::vector<CDObjectSkills>& CDObjectSkillsTable::GetEntries() const {
return this->entries;
}

View File

@@ -3,8 +3,6 @@
// Custom Classes // Custom Classes
#include "CDTable.h" #include "CDTable.h"
#include <cstdint>
struct CDObjectSkills { struct CDObjectSkills {
uint32_t objectTemplate; //!< The LOT of the item uint32_t objectTemplate; //!< The LOT of the item
uint32_t skillID; //!< The Skill ID of the object uint32_t skillID; //!< The Skill ID of the object
@@ -12,10 +10,17 @@ struct CDObjectSkills {
uint32_t AICombatWeight; //!< ??? uint32_t AICombatWeight; //!< ???
}; };
class CDObjectSkillsTable : public CDTable<CDObjectSkillsTable, std::vector<CDObjectSkills>> { class CDObjectSkillsTable : public CDTable<CDObjectSkillsTable> {
private:
std::vector<CDObjectSkills> entries;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Queries the table with a custom "where" clause // Queries the table with a custom "where" clause
std::vector<CDObjectSkills> Query(std::function<bool(CDObjectSkills)> predicate); std::vector<CDObjectSkills> Query(std::function<bool(CDObjectSkills)> predicate);
// Gets all the entries in the table
const std::vector<CDObjectSkills>& GetEntries() const;
}; };

View File

@@ -1,9 +1,5 @@
#include "CDObjectsTable.h" #include "CDObjectsTable.h"
namespace {
CDObjects ObjDefault;
};
void CDObjectsTable::LoadValuesFromDatabase() { void CDObjectsTable::LoadValuesFromDatabase() {
// First, get the size of the table // First, get the size of the table
uint32_t size = 0; uint32_t size = 0;
@@ -18,12 +14,9 @@ void CDObjectsTable::LoadValuesFromDatabase() {
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Objects"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Objects");
auto& entries = GetEntriesMutable();
while (!tableData.eof()) { while (!tableData.eof()) {
const uint32_t lot = tableData.getIntField("id", 0); CDObjects entry;
entry.id = tableData.getIntField("id", -1);
auto& entry = entries[lot];
entry.id = lot;
entry.name = tableData.getStringField("name", ""); entry.name = tableData.getStringField("name", "");
UNUSED_COLUMN(entry.placeable = tableData.getIntField("placeable", -1);) UNUSED_COLUMN(entry.placeable = tableData.getIntField("placeable", -1);)
entry.type = tableData.getStringField("type", ""); entry.type = tableData.getStringField("type", "");
@@ -38,34 +31,34 @@ void CDObjectsTable::LoadValuesFromDatabase() {
UNUSED_COLUMN(entry.gate_version = tableData.getStringField("gate_version", "");) UNUSED_COLUMN(entry.gate_version = tableData.getStringField("gate_version", "");)
UNUSED_COLUMN(entry.HQ_valid = tableData.getIntField("HQ_valid", -1);) UNUSED_COLUMN(entry.HQ_valid = tableData.getIntField("HQ_valid", -1);)
this->entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow(); tableData.nextRow();
} }
ObjDefault.id = 0; tableData.finalize();
m_default.id = 0;
} }
const CDObjects& CDObjectsTable::GetByID(const uint32_t lot) { const CDObjects& CDObjectsTable::GetByID(uint32_t LOT) {
auto& entries = GetEntriesMutable(); const auto& it = this->entries.find(LOT);
const auto& it = entries.find(lot); if (it != this->entries.end()) {
if (it != entries.end()) {
return it->second; return it->second;
} }
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Objects WHERE id = ?;"); auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Objects WHERE id = ?;");
query.bind(1, static_cast<int32_t>(lot)); query.bind(1, static_cast<int32_t>(LOT));
auto tableData = query.execQuery(); auto tableData = query.execQuery();
if (tableData.eof()) { if (tableData.eof()) {
entries.emplace(lot, ObjDefault); this->entries.insert(std::make_pair(LOT, m_default));
return ObjDefault; return m_default;
} }
// Now get the data // Now get the data
while (!tableData.eof()) { while (!tableData.eof()) {
const uint32_t lot = tableData.getIntField("id", 0); CDObjects entry;
entry.id = tableData.getIntField("id", -1);
auto& entry = entries[lot];
entry.id = lot;
entry.name = tableData.getStringField("name", ""); entry.name = tableData.getStringField("name", "");
UNUSED(entry.placeable = tableData.getIntField("placeable", -1)); UNUSED(entry.placeable = tableData.getIntField("placeable", -1));
entry.type = tableData.getStringField("type", ""); entry.type = tableData.getStringField("type", "");
@@ -80,15 +73,17 @@ const CDObjects& CDObjectsTable::GetByID(const uint32_t lot) {
UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
UNUSED(entry.HQ_valid = tableData.getIntField("HQ_valid", -1)); UNUSED(entry.HQ_valid = tableData.getIntField("HQ_valid", -1));
this->entries.insert(std::make_pair(entry.id, entry));
tableData.nextRow(); tableData.nextRow();
} }
tableData.finalize(); tableData.finalize();
const auto& it2 = entries.find(lot); const auto& it2 = entries.find(LOT);
if (it2 != entries.end()) { if (it2 != entries.end()) {
return it2->second; return it2->second;
} }
return ObjDefault; return m_default;
} }

View File

@@ -3,8 +3,6 @@
// Custom Classes // Custom Classes
#include "CDTable.h" #include "CDTable.h"
#include <cstdint>
struct CDObjects { struct CDObjects {
uint32_t id; //!< The LOT of the object uint32_t id; //!< The LOT of the object
std::string name; //!< The internal name of the object std::string name; //!< The internal name of the object
@@ -22,10 +20,14 @@ struct CDObjects {
UNUSED(uint32_t HQ_valid); //!< Probably used for the Nexus HQ database on LEGOUniverse.com UNUSED(uint32_t HQ_valid); //!< Probably used for the Nexus HQ database on LEGOUniverse.com
}; };
class CDObjectsTable : public CDTable<CDObjectsTable, std::map<uint32_t, CDObjects>> { class CDObjectsTable : public CDTable<CDObjectsTable> {
private:
std::map<uint32_t, CDObjects> entries;
CDObjects m_default;
public: public:
void LoadValuesFromDatabase(); void LoadValuesFromDatabase();
// Gets an entry by ID // Gets an entry by ID
const CDObjects& GetByID(const uint32_t lot); const CDObjects& GetByID(uint32_t LOT);
}; };

View File

@@ -13,17 +13,18 @@ void CDPackageComponentTable::LoadValuesFromDatabase() {
tableSize.finalize(); tableSize.finalize();
auto& entries = GetEntriesMutable(); // Reserve the size
entries.reserve(size); this->entries.reserve(size);
// Now get the data // Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PackageComponent"); auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PackageComponent");
while (!tableData.eof()) { while (!tableData.eof()) {
auto& entry = entries.emplace_back(); CDPackageComponent entry;
entry.id = tableData.getIntField("id", -1); entry.id = tableData.getIntField("id", -1);
entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
entry.packageType = tableData.getIntField("packageType", -1); entry.packageType = tableData.getIntField("packageType", -1);
this->entries.push_back(entry);
tableData.nextRow(); tableData.nextRow();
} }
@@ -33,9 +34,15 @@ void CDPackageComponentTable::LoadValuesFromDatabase() {
//! Queries the table with a custom "where" clause //! Queries the table with a custom "where" clause
std::vector<CDPackageComponent> CDPackageComponentTable::Query(std::function<bool(CDPackageComponent)> predicate) { std::vector<CDPackageComponent> CDPackageComponentTable::Query(std::function<bool(CDPackageComponent)> predicate) {
std::vector<CDPackageComponent> data = cpplinq::from(GetEntries()) std::vector<CDPackageComponent> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate) >> cpplinq::where(predicate)
>> cpplinq::to_vector(); >> cpplinq::to_vector();
return data; return data;
} }
//! Gets all the entries in the table
const std::vector<CDPackageComponent>& CDPackageComponentTable::GetEntries() const {
return this->entries;
}

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