mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-16 20:24:39 -06:00
Compare commits
138 Commits
fix-racing
...
chat-http-
| Author | SHA1 | Date | |
|---|---|---|---|
| 214626222c | |||
| ce5bd68067 | |||
| 9192dca4e6 | |||
| 06607c9b55 | |||
| c3ea448be0 | |||
| ff721ed49b | |||
| bce03ca08d | |||
| faee5b72e7 | |||
| 77143fc2cf | |||
| 3801a97722 | |||
| 5e16c13a58 | |||
|
|
0367c67c85 | ||
|
|
8fdc212cda | ||
| 29e759f793 | |||
| 63f9a9f9d4 | |||
| 850ad2aa15 | |||
| ed7b33d8ab | |||
| 55a52b6cc0 | |||
| 99e7349f6c | |||
|
|
fafe2aefad | ||
|
|
5049f215ba | ||
|
|
3a6123fe36 | ||
|
|
b8b2b687e2 | ||
| d067a8d12f | |||
|
|
1ee45639af | ||
|
|
db192d2cde | ||
|
|
28ce8ac54d | ||
|
|
be0a2f6f14 | ||
|
|
3260a063cb | ||
| feeac2e041 | |||
|
|
18c27b14c8 | ||
|
|
bcfaa6c7fe | ||
|
|
06e7d57e0d | ||
|
|
b340d7c8f9 | ||
|
|
24de0e5fdb | ||
| 20408d8dfe | |||
|
|
c1c5db6593 | ||
|
|
884a41f36a | ||
|
|
bbc0908989 | ||
|
|
5996f3cbf4 | ||
|
|
150031861d | ||
|
|
9d8e0a9c4a | ||
|
|
bd9b790e1d | ||
|
|
39b81b6263 | ||
|
|
1e09ec92e3 | ||
|
|
2b253a8248 | ||
|
|
3262bc3a86 | ||
|
|
3a4e554da9 | ||
|
|
35ce8771e5 | ||
|
|
b9092a3cce | ||
|
|
0b4f70a76b | ||
|
|
4bc4624bc9 | ||
|
|
3a6313a3ba | ||
|
|
6e3b5acede | ||
|
|
fe4b29f643 | ||
|
|
fcb89b3c7a | ||
|
|
1a0aaf3123 | ||
|
|
9a26ba0a72 | ||
|
|
6c9c826e19 | ||
|
|
554a9a6806 | ||
| c4c1e93dc8 | |||
|
|
15504e693b | ||
|
|
7d626dc31b | ||
|
|
6df6e3e313 | ||
|
|
4ffdf851c6 | ||
| 43707952d2 | |||
|
|
ef3fdba621 | ||
| 398426545c | |||
|
|
366a80ffd2 | ||
|
|
c9a8be4fb9 | ||
|
|
424d54b98c | ||
|
|
b261e63233 | ||
|
|
75544e3eec | ||
|
|
9e0dd05d42 | ||
|
|
27d20dd8fa | ||
|
|
4b0079c817 | ||
|
|
30b9ef8ab2 | ||
|
|
7235423c7b | ||
|
|
94a467b361 | ||
|
|
c3743877df | ||
|
|
ab937055e7 | ||
|
|
5c1ed332c4 | ||
|
|
95d687846a | ||
| 192c8cf974 | |||
|
|
cf706d4974 | ||
| e729c7f846 | |||
|
|
1328850a8d | ||
|
|
721ea78bb4 | ||
|
|
5ae8fd8e0e | ||
|
|
f38537aece | ||
|
|
b6af92ef81 | ||
|
|
c7b3d9e817 | ||
|
|
c3fbc87f9e | ||
|
|
dfb2fd93b4 | ||
|
|
ddaac276fe | ||
|
|
f7e4a32621 | ||
| ecaaea3175 | |||
|
|
29666a1ff7 | ||
|
|
0c1ee0513d | ||
|
|
62b670d283 | ||
|
|
d2aeebcd46 | ||
|
|
dc29f5962d | ||
|
|
24f94edfeb | ||
|
|
e8aa491904 | ||
|
|
395e5c1c66 | ||
|
|
a88ef0c325 | ||
|
|
8e29148137 | ||
|
|
f0b6ad89d9 | ||
|
|
f2e7d2eaac | ||
|
|
050184c558 | ||
|
|
b23981e591 | ||
|
|
d78b50874c | ||
|
|
a0d51e21ca | ||
|
|
2f247b1fc9 | ||
|
|
54ded62757 | ||
|
|
5225c86d65 | ||
|
|
d5e757bd9d | ||
|
|
a1ac692b49 | ||
|
|
fcb9f671ae | ||
|
|
36f7b8a928 | ||
|
|
ea5360cb99 | ||
|
|
4f3b4f5f43 | ||
|
|
6bf084ef8f | ||
| 99b3705a76 | |||
|
|
c83ec8228c | ||
|
|
0a30430c4f | ||
| 6592bbea46 | |||
|
|
a62f6d63c6 | ||
| 0bc12141c3 | |||
|
|
8b6fb8fb44 | ||
|
|
929d029f12 | ||
|
|
66cc582a9a | ||
|
|
e0ddbce8e7 | ||
|
|
4a50c60559 | ||
|
|
fbdcc17bb5 | ||
|
|
e4469f997e | ||
| dbe4a0ced3 | |||
|
|
b683413a60 |
@@ -1,9 +1,7 @@
|
||||
# Full path to the LEGO Universe client
|
||||
CLIENT_PATH=/Users/someuser/LEGO Universe
|
||||
# Can improve build time
|
||||
BUILD_THREADS=1
|
||||
CLIENT_PATH=./client
|
||||
# Updates NET_VERSION in CMakeVariables.txt
|
||||
BUILD_VERSION=171022
|
||||
NET_VERSION=171022
|
||||
# make sure this is a long random string
|
||||
# grab a "SHA 256-bit Key" from here: https://keygen.io/
|
||||
ACCOUNT_MANAGER_SECRET=
|
||||
@@ -12,6 +10,5 @@ EXTERNAL_IP=localhost
|
||||
# Database values
|
||||
# Be careful with special characters here. It is more safe to use normal characters and/or numbers.
|
||||
MARIADB_USER=darkflame
|
||||
MARIADB_PASSWORD=SECRET_VALUE_CHANGE_ME
|
||||
MARIADB_ROOT_PASSWORD=SECRET_VALUE_CHANGE_ME
|
||||
MARIADB_PASSWORD=
|
||||
MARIADB_DATABASE=darkflame
|
||||
|
||||
10
.github/workflows/build-and-test.yml
vendored
10
.github/workflows/build-and-test.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-2022, ubuntu-20.04, macos-11 ]
|
||||
os: [ windows-2022, ubuntu-22.04, macos-13 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -25,9 +25,11 @@ jobs:
|
||||
with:
|
||||
vs-version: '[17,18)'
|
||||
msbuild-architecture: x64
|
||||
- name: Install libssl (Mac Only)
|
||||
if: ${{ matrix.os == 'macos-11' }}
|
||||
run: brew install openssl@3
|
||||
- name: Install libssl and switch to XCode 15.2 (Mac Only)
|
||||
if: ${{ matrix.os == 'macos-13' }}
|
||||
run: |
|
||||
brew install openssl@3
|
||||
sudo xcode-select -s /Applications/Xcode_15.2.app/Contents/Developer
|
||||
- name: cmake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
|
||||
132
CMakeLists.txt
132
CMakeLists.txt
@@ -1,8 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
project(Darkflame)
|
||||
include(CTest)
|
||||
|
||||
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")
|
||||
|
||||
# Read variables from file
|
||||
@@ -51,7 +55,7 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||
# Disabled no-register
|
||||
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
||||
if(UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -fPIC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wuninitialized -fPIC")
|
||||
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
|
||||
|
||||
if(NOT APPLE)
|
||||
@@ -69,13 +73,15 @@ if(UNIX)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
||||
elseif(MSVC)
|
||||
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
||||
add_compile_options("/wd4267" "/utf-8")
|
||||
# Also disable non-portable MSVC volatile behavior
|
||||
add_compile_options("/wd4267" "/utf-8" "/volatile:iso")
|
||||
elseif(WIN32)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
# Our output 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
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
||||
@@ -89,6 +95,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
find_package(MariaDB)
|
||||
find_package(JSON)
|
||||
|
||||
# Create a /resServer directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/resServer)
|
||||
|
||||
@@ -96,7 +105,7 @@ make_directory(${CMAKE_BINARY_DIR}/resServer)
|
||||
make_directory(${CMAKE_BINARY_DIR}/logs)
|
||||
|
||||
# Copy resource files on first build
|
||||
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
|
||||
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blocklist.dcf")
|
||||
message(STATUS "Checking resource file integrity")
|
||||
|
||||
include(Utils)
|
||||
@@ -178,7 +187,7 @@ file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PRO
|
||||
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
|
||||
|
||||
# Copy vanity files on first build
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "root.xml" "dev-tribute.xml" "atm.xml" "demo.xml")
|
||||
|
||||
foreach(file ${VANITY_FILES})
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
||||
@@ -201,88 +210,47 @@ foreach(file ${SQL_FILES})
|
||||
configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
|
||||
endforeach()
|
||||
|
||||
# Create our list of 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"
|
||||
|
||||
"dNavigation"
|
||||
"dNavigation/dTerrain"
|
||||
|
||||
"dZoneManager"
|
||||
|
||||
"dDatabase"
|
||||
"dDatabase/CDClientDatabase"
|
||||
"dDatabase/CDClientDatabase/CDClientTables"
|
||||
"dDatabase/GameDatabase"
|
||||
"dDatabase/GameDatabase/ITables"
|
||||
"dDatabase/GameDatabase/MySQL"
|
||||
"dDatabase/GameDatabase/MySQL/Tables"
|
||||
|
||||
"dNet"
|
||||
|
||||
"thirdparty/magic_enum/include/magic_enum"
|
||||
"thirdparty/raknet/Source"
|
||||
"thirdparty/tinyxml2"
|
||||
"thirdparty/recastnavigation"
|
||||
"thirdparty/SQLite"
|
||||
"thirdparty/cpplinq"
|
||||
"thirdparty/cpp-httplib"
|
||||
|
||||
"tests"
|
||||
"tests/dCommonTests"
|
||||
"tests/dGameTests"
|
||||
"tests/dGameTests/dComponentsTests"
|
||||
)
|
||||
|
||||
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
||||
if (APPLE)
|
||||
include_directories("/usr/local/include/")
|
||||
endif()
|
||||
|
||||
# Actually include the directories from our list
|
||||
foreach(dir ${INCLUDED_DIRECTORIES})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/${dir})
|
||||
endforeach()
|
||||
|
||||
if(NOT WIN32)
|
||||
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt")
|
||||
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)
|
||||
add_subdirectory(thirdparty SYSTEM)
|
||||
|
||||
# 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
|
||||
# Create our list of include directories
|
||||
include_directories(
|
||||
"dPhysics"
|
||||
|
||||
"dNavigation"
|
||||
|
||||
"dNet"
|
||||
|
||||
"tests"
|
||||
"tests/dCommonTests"
|
||||
"tests/dGameTests"
|
||||
"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)
|
||||
# TODO: Should probably not do this.
|
||||
if(APPLE)
|
||||
include_directories("/usr/local/include/")
|
||||
endif()
|
||||
|
||||
# Add linking directories:
|
||||
if (UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast -Werror") # Warning flags
|
||||
endif()
|
||||
file(
|
||||
GLOB HEADERS_DZONEMANAGER
|
||||
LIST_DIRECTORIES false
|
||||
@@ -317,7 +285,7 @@ add_subdirectory(dPhysics)
|
||||
add_subdirectory(dServer)
|
||||
|
||||
# Create a list of common libraries shared between all binaries
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum")
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "MariaDB::ConnCpp" "magic_enum" "nlohmann_json::nlohmann_json")
|
||||
|
||||
# Add platform specific common libraries
|
||||
if(UNIX)
|
||||
@@ -339,12 +307,6 @@ target_precompile_headers(
|
||||
${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(
|
||||
dCommon PRIVATE
|
||||
${HEADERS_DCOMMON}
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
"generator": "Unix Makefiles"
|
||||
},
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"name": "ci-ubuntu-22.04",
|
||||
"displayName": "CI configure step for Ubuntu",
|
||||
"description": "Same as default, Used in GitHub actions workflow",
|
||||
"inherits": "default"
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"name": "ci-macos-13",
|
||||
"displayName": "CI configure step for MacOS",
|
||||
"description": "Same as default, Used in GitHub actions workflow",
|
||||
"inherits": "default"
|
||||
@@ -67,15 +67,15 @@
|
||||
"jobs": 2
|
||||
},
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"configurePreset": "ci-ubuntu-20.04",
|
||||
"name": "ci-ubuntu-22.04",
|
||||
"configurePreset": "ci-ubuntu-22.04",
|
||||
"displayName": "Linux CI Build",
|
||||
"description": "This preset is used by the CI build on linux",
|
||||
"jobs": 2
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"name": "ci-macos-13",
|
||||
"configurePreset": "ci-macos-13",
|
||||
"displayName": "MacOS CI Build",
|
||||
"description": "This preset is used by the CI build on MacOS",
|
||||
"jobs": 2
|
||||
@@ -83,8 +83,8 @@
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"configurePreset": "ci-ubuntu-20.04",
|
||||
"name": "ci-ubuntu-22.04",
|
||||
"configurePreset": "ci-ubuntu-22.04",
|
||||
"displayName": "CI Tests on Linux",
|
||||
"description": "Runs all tests on a linux configuration",
|
||||
"execution": {
|
||||
@@ -95,8 +95,8 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"name": "ci-macos-13",
|
||||
"configurePreset": "ci-macos-13",
|
||||
"displayName": "CI Tests on MacOS",
|
||||
"description": "Runs all tests on a Mac configuration",
|
||||
"execution": {
|
||||
|
||||
@@ -23,8 +23,7 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Grab libraries and load them
|
||||
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
|
||||
COPY --from=build /app/build/mariadbcpp/libmariadbcpp.so /usr/local/lib/
|
||||
RUN ldconfig
|
||||
|
||||
# Server bins
|
||||
|
||||
50
README.md
50
README.md
@@ -51,7 +51,7 @@ git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
||||
|
||||
### 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.
|
||||
You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.18**</font> or later!).
|
||||
You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.25**</font> or later!).
|
||||
|
||||
### MacOS packages
|
||||
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
|
||||
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.
|
||||
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.
|
||||
You can check your CMake version by using the following command in a terminal.
|
||||
```bash
|
||||
cmake --version
|
||||
@@ -348,12 +348,44 @@ certutil -hashfile <file> SHA1
|
||||
Known good *SHA1* checksum of the Darkflame Universe client:
|
||||
- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed)
|
||||
|
||||
|
||||
# Docker
|
||||
|
||||
## Standalone
|
||||
The Darkflame Server is automatically built and published as a Docker Container / [OCI](https://opencontainers.org/) Image to the GitHub Container Registry at:
|
||||
[`ghcr.io/darkflameuniverse/darkflameserver`](https://github.com/DarkflameUniverse/DarkflameServer/pkgs/container/darkflameserver).
|
||||
|
||||
For standalone deployment, you can use the image provided via Github's Container Repository:
|
||||
`ghcr.io/darkflameuniverse/darkflameserver`
|
||||
## 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
|
||||
at once. For that:
|
||||
|
||||
- [Install Docker Desktop](https://docs.docker.com/get-docker/)
|
||||
- Open the directory that contains your LU Client
|
||||
- If the `legouniverse.exe` is in a subfolder called `client`, you're good to go. There may also be a folder `versions`.
|
||||
- Otherwise, create a new `client` folder and move the exe and everything else (e.g. `res` and `locale`) in there. This is necessary to work around a bug in the client that will prevent that you to log back in after getting disconnected.
|
||||
- Download the [docker-compose.yml](docker-compose.yml) file and place it next to `client`.
|
||||
- Download the [.env.example](.env.example) file and place it next to `client` with the file name `.env`
|
||||
- You may get warnings that this name starts with a dot, acknowledge those, this is intentional. Depending on your operating system, you may need to activate showing hidden files (e.g. Ctrl-H in Gnome on Linux) and/or file extensions ("File name extensions" in the "View" tab on Windows).
|
||||
- Update the `ACCOUNT_MANAGER_SECRET` and `MARIADB_PASSWORD` with strong random passwords.
|
||||
- Use a password generator like <https://keygen.io>
|
||||
- Avoid `:` and `@` characters
|
||||
- Once the database user is created, changing the password will not update it, so the server will just fail to connect.
|
||||
- Set `EXTERNAL_IP` to your LAN IP or public IP if you want to host the game for friends & family
|
||||
- Open a terminal in the folder with the `docker-compose.yml` and `client`
|
||||
- Run `docker compose up -d`
|
||||
- This might require `sudo` on Linux, and a recent version of [docker compose](https://docs.docker.com/compose/install/)
|
||||
- Run `docker exec -it dlu-darkflameserver-1 /app/MasterServer -a` and follow the instructions to create the initial admin account
|
||||
- Open <http://localhost:8000> to access Nexus Dashboard with the admin account to create normal users
|
||||
- Set `AUTHSERVERIP=0:localhost` in `client/boot.cfg`
|
||||
- Replace `localhost` with the value of `EXTERNAL_IP` if you changed that earlier.
|
||||
- Also make sure `UGCUSE3DSERVICES=7:` is set to `0`
|
||||
- Launch `legouniverse.exe`
|
||||
|
||||
## Standalone
|
||||
|
||||
This assumes that you have a database deployed to your host or in another docker container.
|
||||
|
||||
@@ -376,14 +408,6 @@ You will need to replace the `/path/to/`'s to reflect the paths on your host.
|
||||
|
||||
Any config option in the `.ini`'s can be overridden with environmental variables: Ex: `log_to_console=1` from `shared_config.ini` would be overidden like `-e LOG_TO_CONSOLE=0`
|
||||
|
||||
## Compose
|
||||
|
||||
See the [compose](docker-compose.yml) file in the root of the repo.
|
||||
|
||||
This compose file is for a full deployment: MariaDB, DarkflameServer, and Nexus Dashboard.
|
||||
|
||||
All of the environmental options are listed in the compose file so the can be pass through, or you can edit the compose file to suit your specific needs
|
||||
|
||||
# Development Documentation
|
||||
This is a Work in Progress, but below are some quick links to documentaion for systems and structs in the server
|
||||
[Networked message structs](https://lcdruniverse.org/lu_packets/lu_packets/index.html)
|
||||
|
||||
17
cmake/FindGoogleTest.cmake
Normal file
17
cmake/FindGoogleTest.cmake
Normal file
@@ -0,0 +1,17 @@
|
||||
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)
|
||||
20
cmake/FindJSON.cmake
Normal file
20
cmake/FindJSON.cmake
Normal file
@@ -0,0 +1,20 @@
|
||||
include(FetchContent)
|
||||
|
||||
message(STATUS "Fetching json...")
|
||||
|
||||
FetchContent_Declare(
|
||||
json
|
||||
GIT_REPOSITORY https://github.com/nlohmann/json
|
||||
GIT_TAG v3.11.3
|
||||
)
|
||||
|
||||
FetchContent_GetProperties(json)
|
||||
if(NOT json_POPULATED)
|
||||
FetchContent_Populate(json)
|
||||
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
FetchContent_MakeAvailable(json)
|
||||
|
||||
message(STATUS "json fetched and is now ready.")
|
||||
set(JSON_FOUND TRUE)
|
||||
@@ -23,14 +23,14 @@ if(WIN32 AND NOT MARIADB_BUILD_SOURCE)
|
||||
set(MARIADB_CONNECTOR_CPP_MSI "mariadb-connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}-win64.msi")
|
||||
|
||||
if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" )
|
||||
message("Downloading mariadb connector/c")
|
||||
message(STATUS "Downloading mariadb connector/c")
|
||||
file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_C_BUCKET}/Connectors/c/connector-c-${MARIADB_CONNECTOR_C_VERSION}/${MARIADB_CONNECTOR_C_MSI}
|
||||
"${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}"
|
||||
EXPECTED_HASH MD5=${MARIADB_CONNECTOR_C_MD5})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" )
|
||||
message("Downloading mariadb connector/c++")
|
||||
message(STATUS "Downloading mariadb connector/c++")
|
||||
file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_CPP_BUCKET}/Connectors/cpp/connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}/${MARIADB_CONNECTOR_CPP_MSI}
|
||||
"${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}"
|
||||
EXPECTED_HASH MD5=${MARIADB_CONNECTOR_CPP_MD5})
|
||||
@@ -43,27 +43,28 @@ if(WIN32 AND NOT MARIADB_BUILD_SOURCE)
|
||||
file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" MSI_DIR)
|
||||
execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR})
|
||||
endif()
|
||||
set(MARIADBC_SHARED_LIBRARY_LOCATION "${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll")
|
||||
|
||||
if(NOT EXISTS "${MARIADB_CPP_CONNECTOR_DIR}")
|
||||
file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" MSI_DIR)
|
||||
execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR})
|
||||
endif()
|
||||
|
||||
set(MARIADB_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll")
|
||||
set(MARIADBCPP_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll")
|
||||
set(MARIADB_IMPLIB_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.lib")
|
||||
set(MARIADB_INCLUDE_DIR "${MARIADB_CPP_CONNECTOR_DIR}/include/mariadb")
|
||||
|
||||
add_custom_target(mariadb_connector_cpp)
|
||||
add_custom_command(TARGET mariadb_connector_cpp POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll"
|
||||
"${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll"
|
||||
"${MARIADBCPP_SHARED_LIBRARY_LOCATION}"
|
||||
"${MARIADBC_SHARED_LIBRARY_LOCATION}"
|
||||
"${PROJECT_BINARY_DIR}")
|
||||
|
||||
# MariaDB uses plugins that the database needs to load, the prebuilt binaries by default will try to find the libraries in system directories,
|
||||
# so set this define and the servers will set the MARIADB_PLUGIN_DIR environment variable to the appropriate directory.
|
||||
# Plugin directory is determined at dll load time (this will happen before main()) so we need to delay the dll load so that we can set the environment variable
|
||||
add_link_options(/DELAYLOAD:${MARIADB_SHARED_LIBRARY_LOCATION})
|
||||
add_link_options(/DELAYLOAD:${MARIADBCPP_SHARED_LIBRARY_LOCATION})
|
||||
add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADB_CPP_CONNECTOR_DIR}/plugin")
|
||||
else() # Build from source
|
||||
|
||||
@@ -85,77 +86,61 @@ else() # Build from source
|
||||
-DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0)
|
||||
endif()
|
||||
|
||||
set(MARIADBCPP_INSTALL_DIR ${PROJECT_BINARY_DIR}/prefix)
|
||||
set(MARIADBCPP_LIBRARY_DIR ${PROJECT_BINARY_DIR}/mariadbcpp)
|
||||
set(MARIADBCPP_PLUGIN_DIR ${MARIADBCPP_LIBRARY_DIR}/plugin)
|
||||
set(MARIADBCPP_SOURCE_DIR ${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp)
|
||||
set(MARIADB_INCLUDE_DIR "${MARIADBCPP_SOURCE_DIR}/include")
|
||||
ExternalProject_Add(mariadb_connector_cpp
|
||||
SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp
|
||||
PREFIX "${PROJECT_BINARY_DIR}/thirdparty/mariadb-connector-cpp"
|
||||
SOURCE_DIR ${MARIADBCPP_SOURCE_DIR}
|
||||
INSTALL_DIR ${MARIADBCPP_INSTALL_DIR}
|
||||
CMAKE_ARGS -Wno-dev
|
||||
-DWITH_UNIT_TESTS=OFF
|
||||
-DMARIADB_LINK_DYNAMIC=OFF
|
||||
-DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN}
|
||||
-DCMAKE_INSTALL_PREFIX=./mariadbcpp # Points the connector to the correct plugin directory
|
||||
-DINSTALL_PLUGINDIR=plugin
|
||||
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
|
||||
-DINSTALL_LIBDIR=${MARIADBCPP_LIBRARY_DIR}
|
||||
-DINSTALL_PLUGINDIR=${MARIADBCPP_PLUGIN_DIR}
|
||||
${MARIADB_EXTRA_CMAKE_ARGS}
|
||||
PREFIX "${PROJECT_BINARY_DIR}/mariadbcpp"
|
||||
BUILD_COMMAND cmake --build . --config RelWithDebInfo -j${MARIADB_CONNECTOR_COMPILE_JOBS}
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
ExternalProject_Get_Property(mariadb_connector_cpp BINARY_DIR)
|
||||
BUILD_ALWAYS true
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(MARIADB_SHARED_LIBRARY_NAME mariadbcpp.dll)
|
||||
set(MARIADB_PLUGIN_SUFFIX .dll)
|
||||
set(MARIADB_IMPLIB_LOCATION "${BINARY_DIR}/RelWithDebInfo/mariadbcpp.lib")
|
||||
set(MARIADB_IMPLIB_LOCATION "${MARIADBCPP_LIBRARY_DIR}/mariadbcpp.lib")
|
||||
|
||||
# When built from source windows only seems to check same folder as exe instead specified folder, so use
|
||||
# environment variable to force it
|
||||
add_link_options(/DELAYLOAD:mariadbcpp.dll)
|
||||
add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${PROJECT_BINARY_DIR}/mariadbcpp/plugin")
|
||||
add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADBCPP_PLUGIN_DIR}")
|
||||
else()
|
||||
set(MARIADB_SHARED_LIBRARY_NAME libmariadbcpp${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
set(MARIADB_PLUGIN_SUFFIX .so)
|
||||
set(MARIADB_PLUGIN_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
endif()
|
||||
|
||||
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(isMultiConfig)
|
||||
set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/RelWithDebInfo/${MARIADB_SHARED_LIBRARY_NAME}")
|
||||
set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}/$<CONFIG>")
|
||||
set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb/RelWithDebInfo")
|
||||
else()
|
||||
set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}")
|
||||
set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}")
|
||||
set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb")
|
||||
set(MARIADBCPP_SHARED_LIBRARY_LOCATION "${MARIADBCPP_LIBRARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}")
|
||||
if(WIN32)
|
||||
set(MARIADBC_SHARED_LIBRARY_LOCATION "${MARIADBCPP_LIBRARY_DIR}/libmariadb.lib")
|
||||
endif()
|
||||
|
||||
set(MARIADB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include/")
|
||||
|
||||
add_custom_command(TARGET mariadb_connector_cpp POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
${BINARY_DIR}/mariadbcpp/plugin
|
||||
${MARIADB_SHARED_LIBRARY_COPY_LOCATION}
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${MARIADB_SHARED_LIBRARY_LOCATION}
|
||||
${MARIADB_SHARED_LIBRARY_COPY_LOCATION}
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${MARIADB_PLUGINS_LOCATION}/caching_sha2_password${MARIADB_PLUGIN_SUFFIX}
|
||||
${MARIADB_PLUGINS_LOCATION}/client_ed25519${MARIADB_PLUGIN_SUFFIX}
|
||||
${MARIADB_PLUGINS_LOCATION}/dialog${MARIADB_PLUGIN_SUFFIX}
|
||||
${MARIADB_PLUGINS_LOCATION}/mysql_clear_password${MARIADB_PLUGIN_SUFFIX}
|
||||
${MARIADB_PLUGINS_LOCATION}/sha256_password${MARIADB_PLUGIN_SUFFIX}
|
||||
${BINARY_DIR}/mariadbcpp/plugin)
|
||||
endif()
|
||||
|
||||
# Remove the CMakeLists.txt file from the tests folder for the maria-db-connector so we dont compile the tests.
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt")
|
||||
file(REMOVE "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt")
|
||||
endif()
|
||||
|
||||
# Create mariadb connector library object
|
||||
add_library(mariadbConnCpp SHARED IMPORTED GLOBAL)
|
||||
set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_LOCATION ${MARIADB_SHARED_LIBRARY_LOCATION})
|
||||
add_library(MariaDB::ConnCpp SHARED IMPORTED GLOBAL)
|
||||
add_dependencies(MariaDB::ConnCpp mariadb_connector_cpp)
|
||||
set_target_properties(MariaDB::ConnCpp PROPERTIES
|
||||
IMPORTED_LOCATION "${MARIADBCPP_SHARED_LIBRARY_LOCATION}")
|
||||
|
||||
if(WIN32)
|
||||
set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_IMPLIB ${MARIADB_IMPLIB_LOCATION})
|
||||
set_target_properties(MariaDB::ConnCpp PROPERTIES
|
||||
IMPORTED_IMPLIB "${MARIADB_IMPLIB_LOCATION}")
|
||||
elseif(APPLE)
|
||||
set_target_properties(MariaDB::ConnCpp PROPERTIES
|
||||
IMPORTED_SONAME "libmariadbcpp")
|
||||
endif()
|
||||
|
||||
# Add directories to include lists
|
||||
target_include_directories(mariadbConnCpp INTERFACE ${MARIADB_INCLUDE_DIR})
|
||||
add_dependencies(mariadbConnCpp mariadb_connector_cpp)
|
||||
target_include_directories(MariaDB::ConnCpp SYSTEM INTERFACE ${MARIADB_INCLUDE_DIR})
|
||||
|
||||
set(MariaDB_FOUND TRUE)
|
||||
@@ -82,11 +82,11 @@ int main(int argc, char** argv) {
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
|
||||
//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";
|
||||
GeneralUtils::TryParse(Game::config->GetValue("max_clients"), maxClients);
|
||||
GeneralUtils::TryParse(Game::config->GetValue("auth_server_port"), ourPort);
|
||||
const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999);
|
||||
|
||||
//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");
|
||||
if (!externalIPString.empty()) ourIP = externalIPString;
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
|
||||
ExportWordlistToDCF(filepath + ".dcf", true);
|
||||
}
|
||||
|
||||
if (BinaryIO::DoesFileExist("blacklist.dcf")) {
|
||||
ReadWordlistDCF("blacklist.dcf", false);
|
||||
if (BinaryIO::DoesFileExist("blocklist.dcf")) {
|
||||
ReadWordlistDCF("blocklist.dcf", false);
|
||||
}
|
||||
|
||||
//Read player names that are ok as well:
|
||||
@@ -44,20 +44,20 @@ dChatFilter::~dChatFilter() {
|
||||
m_DeniedWords.clear();
|
||||
}
|
||||
|
||||
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) {
|
||||
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool allowList) {
|
||||
std::ifstream file(filepath);
|
||||
if (file) {
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
||||
if (whiteList) m_ApprovedWords.push_back(CalculateHash(line));
|
||||
if (allowList) m_ApprovedWords.push_back(CalculateHash(line));
|
||||
else m_DeniedWords.push_back(CalculateHash(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
||||
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool allowList) {
|
||||
std::ifstream file(filepath, std::ios::binary);
|
||||
if (file) {
|
||||
fileHeader hdr;
|
||||
@@ -70,13 +70,13 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
||||
if (hdr.formatVersion == formatVersion) {
|
||||
size_t wordsToRead = 0;
|
||||
BinaryIO::BinaryRead(file, wordsToRead);
|
||||
if (whiteList) m_ApprovedWords.reserve(wordsToRead);
|
||||
if (allowList) m_ApprovedWords.reserve(wordsToRead);
|
||||
else m_DeniedWords.reserve(wordsToRead);
|
||||
|
||||
size_t word = 0;
|
||||
for (size_t i = 0; i < wordsToRead; ++i) {
|
||||
BinaryIO::BinaryRead(file, word);
|
||||
if (whiteList) m_ApprovedWords.push_back(word);
|
||||
if (allowList) m_ApprovedWords.push_back(word);
|
||||
else m_DeniedWords.push_back(word);
|
||||
}
|
||||
|
||||
@@ -90,14 +90,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) {
|
||||
void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool allowList) {
|
||||
std::ofstream file(filepath, std::ios::binary | std::ios_base::out);
|
||||
if (file) {
|
||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
|
||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
|
||||
BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size()));
|
||||
BinaryIO::BinaryWrite(file, size_t(allowList ? m_ApprovedWords.size() : m_DeniedWords.size()));
|
||||
|
||||
for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) {
|
||||
for (size_t word : allowList ? m_ApprovedWords : m_DeniedWords) {
|
||||
BinaryIO::BinaryWrite(file, word);
|
||||
}
|
||||
|
||||
@@ -105,10 +105,10 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) {
|
||||
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList) {
|
||||
if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
|
||||
if (message.empty()) return { };
|
||||
if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } };
|
||||
if (!allowList && m_DeniedWords.empty()) return { { 0, message.length() } };
|
||||
|
||||
std::stringstream sMessage(message);
|
||||
std::string segment;
|
||||
@@ -126,16 +126,16 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
|
||||
|
||||
size_t hash = CalculateHash(segment);
|
||||
|
||||
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) {
|
||||
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && allowList) {
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) {
|
||||
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && allowList) {
|
||||
m_UserUnapprovedWordCache.push_back(hash);
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) {
|
||||
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !allowList) {
|
||||
m_UserUnapprovedWordCache.push_back(hash);
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ public:
|
||||
dChatFilter(const std::string& filepath, bool dontGenerateDCF);
|
||||
~dChatFilter();
|
||||
|
||||
void ReadWordlistPlaintext(const std::string& filepath, bool whiteList);
|
||||
bool ReadWordlistDCF(const std::string& filepath, bool whiteList);
|
||||
void ExportWordlistToDCF(const std::string& filepath, bool whiteList);
|
||||
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true);
|
||||
void ReadWordlistPlaintext(const std::string& filepath, bool allowList);
|
||||
bool ReadWordlistDCF(const std::string& filepath, bool allowList);
|
||||
void ExportWordlistToDCF(const std::string& filepath, bool allowList);
|
||||
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList = true);
|
||||
|
||||
private:
|
||||
bool m_DontGenerateDCF;
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
set(DCHATSERVER_SOURCES
|
||||
"ChatWebApi.cpp"
|
||||
"ChatIgnoreList.cpp"
|
||||
"ChatPacketHandler.cpp"
|
||||
"PlayerContainer.cpp"
|
||||
)
|
||||
|
||||
add_executable(ChatServer "ChatServer.cpp")
|
||||
add_library(dChatServer ${DCHATSERVER_SOURCES})
|
||||
target_include_directories(dChatServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer)
|
||||
target_include_directories(ChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dChatFilter")
|
||||
add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
|
||||
add_library(dChatServer ${DCHATSERVER_SOURCES})
|
||||
target_include_directories(dChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dServer")
|
||||
|
||||
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
|
||||
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer)
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#include "ChatIgnoreList.h"
|
||||
#include "PlayerContainer.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "eChatMessageType.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "PacketUtils.h"
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
#include "eObjectBits.h"
|
||||
@@ -14,7 +13,7 @@
|
||||
// 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) {
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receivingPlayer);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -60,7 +59,7 @@ void ChatIgnoreList::GetIgnoreList(Packet* packet) {
|
||||
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) {
|
||||
@@ -82,7 +81,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
|
||||
|
||||
inStream.IgnoreBytes(4); // ignore some garbage zeros idk
|
||||
|
||||
LUWString toIgnoreName(33);
|
||||
LUWString toIgnoreName;
|
||||
inStream.Read(toIgnoreName);
|
||||
std::string toIgnoreStr = toIgnoreName.GetAsString();
|
||||
|
||||
@@ -132,7 +131,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
|
||||
bitStream.Write(playerNameSend);
|
||||
bitStream.Write(ignoredPlayerId);
|
||||
|
||||
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||
Game::server->Send(bitStream, packet->systemAddress, false);
|
||||
}
|
||||
|
||||
void ChatIgnoreList::RemoveIgnore(Packet* packet) {
|
||||
@@ -148,7 +147,7 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
|
||||
|
||||
inStream.IgnoreBytes(4); // ignore some garbage zeros idk
|
||||
|
||||
LUWString removedIgnoreName(33);
|
||||
LUWString removedIgnoreName;
|
||||
inStream.Read(removedIgnoreName);
|
||||
std::string removedIgnoreStr = removedIgnoreName.GetAsString();
|
||||
|
||||
@@ -168,5 +167,5 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
|
||||
LUWString playerNameSend(removedIgnoreStr, 33);
|
||||
bitStream.Write(playerNameSend);
|
||||
|
||||
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||
Game::server->Send(bitStream, packet->systemAddress, false);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "PlayerContainer.h"
|
||||
#include "Database.h"
|
||||
#include <vector>
|
||||
#include "PacketUtils.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "Game.h"
|
||||
#include "dServer.h"
|
||||
@@ -15,9 +14,11 @@
|
||||
#include "eObjectBits.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eChatMessageType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "eClientMessageType.h"
|
||||
#include "eGameMessageType.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "ChatPackets.h"
|
||||
|
||||
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
//Get from the packet which player we want to do something with:
|
||||
@@ -59,7 +60,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
|
||||
//Now, we need to send the friendlist to the server they came from:
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -78,31 +79,27 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
|
||||
void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
|
||||
LWOOBJID requestorPlayerID;
|
||||
inStream.Read(requestorPlayerID);
|
||||
uint32_t spacing{};
|
||||
inStream.Read(spacing);
|
||||
std::string playerName = "";
|
||||
uint16_t character;
|
||||
bool noMoreLettersInName = false;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
LUWString LUplayerName;
|
||||
char isBestFriendRequest{};
|
||||
|
||||
inStream.Read(requestorPlayerID);
|
||||
inStream.IgnoreBytes(4);
|
||||
inStream.Read(LUplayerName);
|
||||
inStream.Read(isBestFriendRequest);
|
||||
|
||||
auto playerName = LUplayerName.GetAsString();
|
||||
|
||||
auto& requestor = Game::playerContainer.GetPlayerDataMutable(requestorPlayerID);
|
||||
if (!requestor) {
|
||||
LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// you cannot friend yourself
|
||||
if (requestor.playerName == playerName) {
|
||||
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
|
||||
SendFriendResponse(requestor, requestor, eAddFriendResponseType::GENERALERROR);
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -141,6 +138,13 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
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) {
|
||||
|
||||
uint8_t oldBestFriendStatus{};
|
||||
@@ -218,15 +222,19 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
|
||||
void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
|
||||
eAddFriendResponseCode clientResponseCode = static_cast<eAddFriendResponseCode>(packet->data[0x14]);
|
||||
std::string friendName = PacketUtils::ReadString(0x15, packet, true);
|
||||
LWOOBJID playerID;
|
||||
eAddFriendResponseCode clientResponseCode;
|
||||
LUWString friendName;
|
||||
|
||||
inStream.Read(playerID);
|
||||
inStream.IgnoreBytes(4);
|
||||
inStream.Read(clientResponseCode);
|
||||
inStream.Read(friendName);
|
||||
|
||||
//Now to try and find both of these:
|
||||
auto& requestor = Game::playerContainer.GetPlayerDataMutable(playerID);
|
||||
auto& requestee = Game::playerContainer.GetPlayerDataMutable(friendName);
|
||||
auto& requestee = Game::playerContainer.GetPlayerDataMutable(friendName.GetAsString());
|
||||
if (!requestor || !requestee) return;
|
||||
|
||||
eAddFriendResponseType serverResponseCode{};
|
||||
@@ -288,8 +296,11 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
LWOOBJID playerID;
|
||||
LUWString LUFriendName;
|
||||
inStream.Read(playerID);
|
||||
std::string friendName = PacketUtils::ReadString(0x14, packet, true);
|
||||
inStream.IgnoreBytes(4);
|
||||
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.
|
||||
//First, we need to find their ID:
|
||||
@@ -335,123 +346,205 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void ChatPacketHandler::HandleWho(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
FindPlayerRequest request;
|
||||
request.Deserialize(inStream);
|
||||
|
||||
const auto& sender = Game::playerContainer.GetPlayerData(request.requestor);
|
||||
if (!sender) return;
|
||||
|
||||
const auto& player = Game::playerContainer.GetPlayerData(request.playerName.GetAsString());
|
||||
bool online = player;
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(request.requestor);
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::WHO_RESPONSE);
|
||||
bitStream.Write<uint8_t>(online);
|
||||
bitStream.Write(player.zoneID.GetMapID());
|
||||
bitStream.Write(player.zoneID.GetInstanceID());
|
||||
bitStream.Write(player.zoneID.GetCloneID());
|
||||
bitStream.Write(request.playerName);
|
||||
|
||||
SystemAddress sysAddr = sender.sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleShowAll(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
ShowAllRequest request;
|
||||
request.Deserialize(inStream);
|
||||
|
||||
const auto& sender = Game::playerContainer.GetPlayerData(request.requestor);
|
||||
if (!sender) return;
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(request.requestor);
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::SHOW_ALL_RESPONSE);
|
||||
bitStream.Write<uint8_t>(!request.displayZoneData && !request.displayIndividualPlayers);
|
||||
bitStream.Write(Game::playerContainer.GetPlayerCount());
|
||||
bitStream.Write(Game::playerContainer.GetSimCount());
|
||||
bitStream.Write<uint8_t>(request.displayIndividualPlayers);
|
||||
bitStream.Write<uint8_t>(request.displayZoneData);
|
||||
if (request.displayZoneData || request.displayIndividualPlayers){
|
||||
for (auto& [playerID, playerData ]: Game::playerContainer.GetAllPlayers()){
|
||||
if (!playerData) continue;
|
||||
bitStream.Write<uint8_t>(0); // structure packing
|
||||
if (request.displayIndividualPlayers) bitStream.Write(LUWString(playerData.playerName));
|
||||
if (request.displayZoneData) {
|
||||
bitStream.Write(playerData.zoneID.GetMapID());
|
||||
bitStream.Write(playerData.zoneID.GetInstanceID());
|
||||
bitStream.Write(playerData.zoneID.GetCloneID());
|
||||
}
|
||||
}
|
||||
}
|
||||
SystemAddress sysAddr = sender.sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
|
||||
const auto& sender = Game::playerContainer.GetPlayerData(playerID);
|
||||
if (!sender || sender.GetIsMuted()) return;
|
||||
|
||||
if (!sender) return;
|
||||
eChatChannel channel;
|
||||
uint32_t size;
|
||||
|
||||
if (sender.GetIsMuted()) return;
|
||||
|
||||
inStream.SetReadOffset(0x14 * 8);
|
||||
|
||||
uint8_t channel = 0;
|
||||
inStream.IgnoreBytes(4);
|
||||
inStream.Read(channel);
|
||||
inStream.Read(size);
|
||||
inStream.IgnoreBytes(77);
|
||||
|
||||
std::string message = PacketUtils::ReadString(0x66, packet, true, 512);
|
||||
LUWString message(size);
|
||||
inStream.Read(message);
|
||||
|
||||
LOG("Got a message from (%s) [%d]: %s", sender.playerName.c_str(), channel, message.c_str());
|
||||
|
||||
if (channel != 8) return;
|
||||
LOG("Got a message from (%s) via [%s]: %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str());
|
||||
|
||||
switch (channel) {
|
||||
case eChatChannel::TEAM: {
|
||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team == nullptr) return;
|
||||
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
const auto& otherMember = Game::playerContainer.GetPlayerData(memberId);
|
||||
|
||||
if (!otherMember) return;
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(otherMember.playerID);
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
||||
bitStream.Write(otherMember.playerID);
|
||||
bitStream.Write<uint8_t>(8);
|
||||
bitStream.Write<unsigned int>(69);
|
||||
bitStream.Write(LUWString(sender.playerName));
|
||||
bitStream.Write(sender.playerID);
|
||||
bitStream.Write<uint16_t>(0);
|
||||
bitStream.Write<uint8_t>(0); //not mythran nametag
|
||||
bitStream.Write(LUWString(otherMember.playerName));
|
||||
bitStream.Write<uint8_t>(0); //not mythran for receiver
|
||||
bitStream.Write<uint8_t>(0); //teams?
|
||||
bitStream.Write(LUWString(message, 512));
|
||||
|
||||
SystemAddress sysAddr = otherMember.sysAddr;
|
||||
SEND_PACKET;
|
||||
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) {
|
||||
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) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true);
|
||||
|
||||
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;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(routeTo.playerID);
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
||||
bitStream.Write(sender.playerID);
|
||||
bitStream.Write(channel);
|
||||
bitStream.Write<uint32_t>(0); // not used
|
||||
bitStream.Write(LUWString(sender.playerName));
|
||||
bitStream.Write(sender.playerID);
|
||||
bitStream.Write<uint16_t>(0); // sourceID
|
||||
bitStream.Write(sender.gmLevel);
|
||||
bitStream.Write(LUWString(receiver.playerName));
|
||||
bitStream.Write(receiver.gmLevel);
|
||||
bitStream.Write(responseCode);
|
||||
bitStream.Write(message);
|
||||
|
||||
SystemAddress sysAddr = routeTo.sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
|
||||
void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
|
||||
LWOOBJID playerID;
|
||||
LUWString invitedPlayer;
|
||||
|
||||
inStream.Read(playerID);
|
||||
inStream.IgnoreBytes(4);
|
||||
inStream.Read(invitedPlayer);
|
||||
|
||||
const auto& player = Game::playerContainer.GetPlayerData(playerID);
|
||||
|
||||
@@ -463,7 +556,7 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
|
||||
team = Game::playerContainer.CreateTeam(playerID);
|
||||
}
|
||||
|
||||
const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer);
|
||||
const auto& other = Game::playerContainer.GetPlayerData(invitedPlayer.GetAsString());
|
||||
|
||||
if (!other) return;
|
||||
|
||||
@@ -480,7 +573,7 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
|
||||
|
||||
SendTeamInvite(other, player);
|
||||
|
||||
LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
|
||||
LOG("Got team invite: %llu -> %s", playerID, invitedPlayer.GetAsString().c_str());
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
|
||||
@@ -534,21 +627,25 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
|
||||
|
||||
void ChatPacketHandler::HandleTeamKick(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
LUWString kickedPlayer;
|
||||
|
||||
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.c_str());
|
||||
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.GetAsString().c_str());
|
||||
|
||||
const auto& kicked = Game::playerContainer.GetPlayerData(kickedPlayer);
|
||||
const auto& kicked = Game::playerContainer.GetPlayerData(kickedPlayer.GetAsString());
|
||||
|
||||
LWOOBJID kickedId = LWOOBJID_EMPTY;
|
||||
|
||||
if (kicked) {
|
||||
kickedId = kicked.playerID;
|
||||
} else {
|
||||
kickedId = Game::playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
|
||||
kickedId = Game::playerContainer.GetId(kickedPlayer.string);
|
||||
}
|
||||
|
||||
if (kickedId == LWOOBJID_EMPTY) return;
|
||||
@@ -564,14 +661,17 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
|
||||
|
||||
void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
LUWString promotedPlayer;
|
||||
|
||||
inStream.Read(playerID);
|
||||
inStream.IgnoreBytes(4);
|
||||
inStream.Read(promotedPlayer);
|
||||
|
||||
std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true);
|
||||
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.GetAsString().c_str());
|
||||
|
||||
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
|
||||
|
||||
const auto& promoted = Game::playerContainer.GetPlayerData(promotedPlayer);
|
||||
const auto& promoted = Game::playerContainer.GetPlayerData(promotedPlayer.GetAsString());
|
||||
|
||||
if (!promoted) return;
|
||||
|
||||
@@ -657,7 +757,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
||||
|
||||
void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -672,7 +772,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) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -699,7 +799,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) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -724,7 +824,7 @@ void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64L
|
||||
|
||||
void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -741,7 +841,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) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -770,7 +870,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) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -796,7 +896,7 @@ void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bD
|
||||
|
||||
void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -830,7 +930,7 @@ void ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const Pla
|
||||
[bool] - is FTP*/
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(friendData.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -867,7 +967,7 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
|
||||
}
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -881,7 +981,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) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
// Portion that will get routed:
|
||||
@@ -904,7 +1004,7 @@ void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const Pla
|
||||
|
||||
void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
|
||||
@@ -7,14 +7,55 @@ struct PlayerData;
|
||||
|
||||
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 {
|
||||
void HandleFriendlistRequest(Packet* packet);
|
||||
void HandleFriendRequest(Packet* packet);
|
||||
void HandleFriendResponse(Packet* packet);
|
||||
void HandleRemoveFriend(Packet* packet);
|
||||
void HandleGMLevelUpdate(Packet* packet);
|
||||
void HandleWho(Packet* packet);
|
||||
void HandleShowAll(Packet* packet);
|
||||
|
||||
void HandleChatMessage(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 HandleTeamInviteResponse(Packet* packet);
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
#include "PlayerContainer.h"
|
||||
#include "ChatPacketHandler.h"
|
||||
#include "eChatMessageType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "eWorldMessageType.h"
|
||||
#include "ChatIgnoreList.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "ChatWebApi.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "Server.h"
|
||||
@@ -98,18 +99,15 @@ int main(int argc, char** argv) {
|
||||
masterPort = masterInfo->port;
|
||||
}
|
||||
//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";
|
||||
GeneralUtils::TryParse(Game::config->GetValue("max_clients"), maxClients);
|
||||
GeneralUtils::TryParse(Game::config->GetValue("chat_server_port"), ourPort);
|
||||
const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999);
|
||||
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("chat_server_port")).value_or(2005);
|
||||
const auto externalIPString = Game::config->GetValue("external_ip");
|
||||
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);
|
||||
|
||||
bool dontGenerateDCF = false;
|
||||
GeneralUtils::TryParse(Game::config->GetValue("dont_generate_dcf"), dontGenerateDCF);
|
||||
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false);
|
||||
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
|
||||
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
@@ -125,6 +123,9 @@ int main(int argc, char** argv) {
|
||||
uint32_t framesSinceMasterDisconnect = 0;
|
||||
uint32_t framesSinceLastSQLPing = 0;
|
||||
|
||||
// start the web api thread
|
||||
std::thread webAPIThread(ChatWebApi::Listen, ourPort);
|
||||
|
||||
Game::logger->Flush(); // once immediately before main loop
|
||||
while (!Game::ShouldShutdown()) {
|
||||
//Check if we're still connected to master:
|
||||
@@ -178,52 +179,39 @@ int main(int argc, char** argv) {
|
||||
delete Game::logger;
|
||||
delete Game::config;
|
||||
|
||||
// rejoin the web api thread
|
||||
ChatWebApi::Stop();
|
||||
webAPIThread.join();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void HandlePacket(Packet* packet) {
|
||||
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.");
|
||||
}
|
||||
|
||||
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
||||
} else if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
||||
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
|
||||
|
||||
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
|
||||
CINSTREAM;
|
||||
inStream.SetReadOffset(BYTES_TO_BITS(1));
|
||||
|
||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
|
||||
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
||||
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
||||
Game::playerContainer.InsertPlayer(packet);
|
||||
break;
|
||||
eConnectionType connection;
|
||||
eChatMessageType chatMessageID;
|
||||
|
||||
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
||||
Game::playerContainer.RemovePlayer(packet);
|
||||
break;
|
||||
inStream.Read(connection);
|
||||
if (connection != eConnectionType::CHAT) return;
|
||||
inStream.Read(chatMessageID);
|
||||
|
||||
case eChatInternalMessageType::MUTE_UPDATE:
|
||||
switch (chatMessageID) {
|
||||
case eChatMessageType::GM_MUTE:
|
||||
Game::playerContainer.MuteUpdate(packet);
|
||||
break;
|
||||
|
||||
case eChatInternalMessageType::CREATE_TEAM:
|
||||
case eChatMessageType::CREATE_TEAM:
|
||||
Game::playerContainer.CreateTeamServer(packet);
|
||||
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:
|
||||
ChatPacketHandler::HandleFriendlistRequest(packet);
|
||||
break;
|
||||
@@ -293,21 +281,73 @@ void HandlePacket(Packet* packet) {
|
||||
case eChatMessageType::TEAM_SET_LOOT:
|
||||
ChatPacketHandler::HandleTeamLootOption(packet);
|
||||
break;
|
||||
|
||||
default:
|
||||
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");
|
||||
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:
|
||||
ChatPacketHandler::HandleWho(packet);
|
||||
break;
|
||||
case eChatMessageType::SHOW_ALL:
|
||||
ChatPacketHandler::HandleShowAll(packet);
|
||||
break;
|
||||
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:
|
||||
LOG("Unknown World id: %i", int(packet->data[3]));
|
||||
}
|
||||
LOG("Unknown CHAT Message id: %i", chatMessageID);
|
||||
}
|
||||
}
|
||||
|
||||
93
dChatServer/ChatWebApi.cpp
Normal file
93
dChatServer/ChatWebApi.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
#include "ChatWebApi.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "dCommonVars.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eChatMessageType.h"
|
||||
#include "httplib.h"
|
||||
#include "dServer.h"
|
||||
#include "PlayerContainer.h"
|
||||
#include "dConfig.h"
|
||||
#include "httplib.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace {
|
||||
httplib::Server m_APIServer;
|
||||
}
|
||||
|
||||
void ChatWebApi::Listen(const uint32_t port) {
|
||||
if (Game::config->GetValue("enable_chat_web_api") != "1") {
|
||||
LOG("Chat Web API is disabled");
|
||||
return;
|
||||
}
|
||||
LOG("Chat Web API is enabled, starting web server...");
|
||||
|
||||
m_APIServer.Post("/announce", [](const httplib::Request& req, httplib::Response& res) {
|
||||
const json data = json::parse(req.body);
|
||||
if (!data.contains("title")) {
|
||||
res.set_content("{\"error\":\"Missing paramater: title\"}", "application/json");
|
||||
res.status = 400;
|
||||
return;
|
||||
}
|
||||
std::string title = data["title"];
|
||||
if (!data.contains("message")) {
|
||||
res.set_content("{\"error\":\"Missing paramater: message\"}", "application/json");
|
||||
res.status = 400;
|
||||
return;
|
||||
}
|
||||
std::string message = data["message"];
|
||||
// build and send the packet to all world servers
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GM_ANNOUNCE);
|
||||
bitStream.Write<uint32_t>(title.size());
|
||||
bitStream.Write(title);
|
||||
bitStream.Write<uint32_t>(message.size());
|
||||
bitStream.Write(message);
|
||||
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
});
|
||||
|
||||
m_APIServer.Get("/players", [](const httplib::Request& req, httplib::Response& res) {
|
||||
auto data = json::array();
|
||||
for (auto& [playerID, playerData ]: Game::playerContainer.GetAllPlayers()){
|
||||
if (!playerData) continue;
|
||||
data.push_back(playerData.to_json());
|
||||
}
|
||||
res.set_content(data.dump(), "application/json");
|
||||
if (data.empty()) res.status = 204;
|
||||
});
|
||||
|
||||
m_APIServer.Get("/teams", [](const httplib::Request& req, httplib::Response& res) {
|
||||
auto data = json::array();
|
||||
for (auto& teamData: Game::playerContainer.GetAllTeams()){
|
||||
if (!teamData) continue;
|
||||
json toInsert;
|
||||
toInsert["id"] = teamData->teamID;
|
||||
toInsert["loot_flag"] = teamData->lootFlag;
|
||||
toInsert["local"] = teamData->local;
|
||||
|
||||
auto& leader = Game::playerContainer.GetPlayerData(teamData->leaderID);
|
||||
toInsert["leader"] = leader.to_json();
|
||||
|
||||
json members;
|
||||
for (auto& member : teamData->memberIDs){
|
||||
auto playerData = Game::playerContainer.GetPlayerData(member);
|
||||
if (!playerData) continue;
|
||||
members.push_back(playerData.to_json());
|
||||
}
|
||||
toInsert["members"] = members;
|
||||
data.push_back(toInsert);
|
||||
}
|
||||
res.set_content(data.dump(), "application/json");
|
||||
if (data.empty()) res.status = 204;
|
||||
});
|
||||
|
||||
m_APIServer.listen(Game::config->GetValue("chat_web_api_listen_address").c_str(), port);
|
||||
};
|
||||
|
||||
void ChatWebApi::Stop(){
|
||||
LOG("Stopping Chat Web API server...");
|
||||
m_APIServer.stop();
|
||||
}
|
||||
6
dChatServer/ChatWebApi.h
Normal file
6
dChatServer/ChatWebApi.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <cstdint>
|
||||
|
||||
namespace ChatWebApi {
|
||||
void Listen(const uint32_t port);
|
||||
void Stop();
|
||||
};
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "PlayerContainer.h"
|
||||
#include "dNetCommon.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "dNetCommon.h"
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
#include "ChatPacketHandler.h"
|
||||
@@ -9,17 +11,32 @@
|
||||
#include "BitStreamUtils.h"
|
||||
#include "Database.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "dConfig.h"
|
||||
#include "eChatMessageType.h"
|
||||
|
||||
void PlayerContainer::Initialize() {
|
||||
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends"), m_MaxNumberOfBestFriends);
|
||||
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends"), m_MaxNumberOfFriends);
|
||||
using json = nlohmann::json;
|
||||
|
||||
const json PlayerData::to_json() const {
|
||||
json data;
|
||||
data["id"] = this->playerID;
|
||||
data["name"] = this->playerName;
|
||||
data["gm_level"] = this->gmLevel;
|
||||
data["muted"] = this->GetIsMuted();
|
||||
|
||||
json zoneID;
|
||||
zoneID["map_id"] = std::to_string(this->zoneID.GetMapID());
|
||||
zoneID["instance_id"] = std::to_string(this->zoneID.GetInstanceID());
|
||||
zoneID["clone_id"] = std::to_string(this->zoneID.GetCloneID());
|
||||
data["zone_id"] = zoneID;
|
||||
return data;
|
||||
}
|
||||
|
||||
PlayerContainer::~PlayerContainer() {
|
||||
m_Players.clear();
|
||||
void PlayerContainer::Initialize() {
|
||||
m_MaxNumberOfBestFriends =
|
||||
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_best_friends")).value_or(m_MaxNumberOfBestFriends);
|
||||
m_MaxNumberOfFriends =
|
||||
GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_number_of_friends")).value_or(m_MaxNumberOfFriends);
|
||||
}
|
||||
|
||||
TeamData::TeamData() {
|
||||
@@ -47,9 +64,11 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||
|
||||
inStream.Read(data.zoneID);
|
||||
inStream.Read(data.muteExpire);
|
||||
inStream.Read(data.gmLevel);
|
||||
data.sysAddr = packet->systemAddress;
|
||||
|
||||
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
|
||||
m_PlayerCount++;
|
||||
|
||||
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
|
||||
|
||||
@@ -88,6 +107,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||
}
|
||||
}
|
||||
|
||||
m_PlayerCount--;
|
||||
LOG("Removed user: %llu", playerID);
|
||||
m_Players.erase(playerID);
|
||||
|
||||
@@ -146,12 +166,12 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
|
||||
|
||||
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GM_MUTE);
|
||||
|
||||
bitStream.Write(player);
|
||||
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) {
|
||||
@@ -353,7 +373,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
||||
|
||||
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::TEAM_GET_STATUS);
|
||||
|
||||
bitStream.Write(team->teamID);
|
||||
bitStream.Write(deleteTeam);
|
||||
@@ -366,7 +386,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) {
|
||||
@@ -391,7 +411,7 @@ LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
|
||||
}
|
||||
|
||||
PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) {
|
||||
return m_Players[playerID];
|
||||
return m_Players.contains(playerID) ? m_Players[playerID] : m_Players[LWOOBJID_EMPTY];
|
||||
}
|
||||
|
||||
PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) {
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
#include "Game.h"
|
||||
#include "dServer.h"
|
||||
#include <unordered_map>
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
enum class eGameMasterLevel : uint8_t;
|
||||
|
||||
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 {
|
||||
return playerName == other;
|
||||
}
|
||||
@@ -34,6 +37,8 @@ struct PlayerData {
|
||||
return muteExpire == 1 || muteExpire > time(NULL);
|
||||
}
|
||||
|
||||
const nlohmann::json to_json() const;
|
||||
|
||||
SystemAddress sysAddr{};
|
||||
LWOZONEID zoneID{};
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
@@ -42,6 +47,8 @@ struct PlayerData {
|
||||
std::string playerName;
|
||||
std::vector<FriendData> friends;
|
||||
std::vector<IgnoreData> ignoredPlayers;
|
||||
eGameMasterLevel gmLevel = static_cast<eGameMasterLevel>(0); // CIVILLIAN
|
||||
bool isFTP = false;
|
||||
};
|
||||
|
||||
struct TeamData {
|
||||
@@ -56,8 +63,6 @@ struct TeamData {
|
||||
|
||||
class PlayerContainer {
|
||||
public:
|
||||
~PlayerContainer();
|
||||
|
||||
void Initialize();
|
||||
void InsertPlayer(Packet* packet);
|
||||
void RemovePlayer(Packet* packet);
|
||||
@@ -69,6 +74,9 @@ public:
|
||||
const PlayerData& GetPlayerData(const std::string& playerName);
|
||||
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
||||
PlayerData& GetPlayerDataMutable(const std::string& playerName);
|
||||
uint32_t GetPlayerCount() { return m_PlayerCount; };
|
||||
uint32_t GetSimCount() { return m_SimCount; };
|
||||
const std::map<LWOOBJID, PlayerData>& GetAllPlayers() { return m_Players; };
|
||||
|
||||
TeamData* CreateLocalTeam(std::vector<LWOOBJID> members);
|
||||
TeamData* CreateTeam(LWOOBJID leader, bool local = false);
|
||||
@@ -83,6 +91,7 @@ public:
|
||||
LWOOBJID GetId(const std::u16string& playerName);
|
||||
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
|
||||
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
|
||||
const std::vector<TeamData*>& GetAllTeams() { return mTeams;};
|
||||
|
||||
private:
|
||||
LWOOBJID m_TeamIDCounter = 0;
|
||||
@@ -91,5 +100,7 @@ private:
|
||||
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
||||
uint32_t m_MaxNumberOfBestFriends = 5;
|
||||
uint32_t m_MaxNumberOfFriends = 50;
|
||||
uint32_t m_PlayerCount = 0;
|
||||
uint32_t m_SimCount = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,12 +9,11 @@
|
||||
* AMF3 Deserializer written by EmosewaMC
|
||||
*/
|
||||
|
||||
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
|
||||
if (!inStream) return nullptr;
|
||||
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) {
|
||||
AMFBaseValue* returnValue = nullptr;
|
||||
// Read in the value type from the bitStream
|
||||
eAmf marker;
|
||||
inStream->Read(marker);
|
||||
inStream.Read(marker);
|
||||
// Based on the typing, create the value associated with that and return the base value class
|
||||
switch (marker) {
|
||||
case eAmf::Undefined: {
|
||||
@@ -79,13 +78,13 @@ AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
|
||||
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) {
|
||||
bool byteFlag = true;
|
||||
uint32_t actualNumber{};
|
||||
uint8_t numberOfBytesRead{};
|
||||
while (byteFlag && numberOfBytesRead < 4) {
|
||||
uint8_t byte{};
|
||||
inStream->Read(byte);
|
||||
inStream.Read(byte);
|
||||
// Parse the byte
|
||||
if (numberOfBytesRead < 3) {
|
||||
byteFlag = byte & static_cast<uint8_t>(1 << 7);
|
||||
@@ -101,7 +100,7 @@ uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
|
||||
return actualNumber;
|
||||
}
|
||||
|
||||
const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
|
||||
const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
|
||||
auto length = ReadU29(inStream);
|
||||
// Check if this is a reference
|
||||
bool isReference = length % 2 == 1;
|
||||
@@ -109,7 +108,7 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
|
||||
length = length >> 1;
|
||||
if (isReference) {
|
||||
std::string value(length, 0);
|
||||
inStream->Read(&value[0], length);
|
||||
inStream.Read(&value[0], length);
|
||||
// Empty strings are never sent by reference
|
||||
if (!value.empty()) accessedElements.push_back(value);
|
||||
return value;
|
||||
@@ -119,20 +118,20 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
|
||||
}
|
||||
}
|
||||
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
|
||||
double value;
|
||||
inStream->Read<double>(value);
|
||||
inStream.Read<double>(value);
|
||||
return new AMFDoubleValue(value);
|
||||
}
|
||||
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
|
||||
auto arrayValue = new AMFArrayValue();
|
||||
|
||||
// Read size of dense array
|
||||
auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
|
||||
const auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
|
||||
// Then read associative portion
|
||||
while (true) {
|
||||
auto key = ReadString(inStream);
|
||||
const auto key = ReadString(inStream);
|
||||
// No more associative values when we encounter an empty string key
|
||||
if (key.size() == 0) break;
|
||||
arrayValue->Insert(key, Read(inStream));
|
||||
@@ -144,10 +143,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
|
||||
return arrayValue;
|
||||
}
|
||||
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
|
||||
return new AMFStringValue(ReadString(inStream));
|
||||
}
|
||||
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
|
||||
return new AMFIntValue(ReadU29(inStream));
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
* @param inStream inStream to read value from.
|
||||
* @return Returns an AMFValue with all the information from the bitStream in it.
|
||||
*/
|
||||
AMFBaseValue* Read(RakNet::BitStream* inStream);
|
||||
AMFBaseValue* Read(RakNet::BitStream& inStream);
|
||||
private:
|
||||
/**
|
||||
* @brief Private method to read a U29 integer from a bitstream
|
||||
@@ -23,7 +23,7 @@ private:
|
||||
* @param inStream bitstream to read data from
|
||||
* @return The number as an unsigned 29 bit integer
|
||||
*/
|
||||
uint32_t ReadU29(RakNet::BitStream* inStream);
|
||||
static uint32_t ReadU29(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Reads a string from a bitstream
|
||||
@@ -31,7 +31,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @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
|
||||
@@ -39,7 +39,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Double value represented as an AMFValue
|
||||
*/
|
||||
AMFBaseValue* ReadAmfDouble(RakNet::BitStream* inStream);
|
||||
AMFBaseValue* ReadAmfDouble(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFArray from a bitStream
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Array value represented as an AMFValue
|
||||
*/
|
||||
AMFBaseValue* ReadAmfArray(RakNet::BitStream* inStream);
|
||||
AMFBaseValue* ReadAmfArray(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFString from a bitStream
|
||||
@@ -55,7 +55,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return String value represented as an AMFValue
|
||||
*/
|
||||
AMFBaseValue* ReadAmfString(RakNet::BitStream* inStream);
|
||||
AMFBaseValue* ReadAmfString(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFInteger from a bitStream
|
||||
@@ -63,7 +63,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Integer value represented as an AMFValue
|
||||
*/
|
||||
AMFBaseValue* ReadAmfInteger(RakNet::BitStream* inStream);
|
||||
AMFBaseValue* ReadAmfInteger(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* List of strings read so far saved to be read by reference.
|
||||
|
||||
245
dCommon/Amf3.h
245
dCommon/Amf3.h
@@ -31,54 +31,70 @@ enum class eAmf : uint8_t {
|
||||
|
||||
class AMFBaseValue {
|
||||
public:
|
||||
virtual eAmf GetValueType() { return eAmf::Undefined; };
|
||||
AMFBaseValue() {};
|
||||
virtual ~AMFBaseValue() {};
|
||||
[[nodiscard]] constexpr virtual eAmf GetValueType() const noexcept { return eAmf::Undefined; }
|
||||
constexpr AMFBaseValue() noexcept = default;
|
||||
constexpr virtual ~AMFBaseValue() noexcept = default;
|
||||
};
|
||||
|
||||
// AMFValue template class instantiations
|
||||
template <typename ValueType>
|
||||
class AMFValue : public AMFBaseValue {
|
||||
public:
|
||||
AMFValue() {};
|
||||
AMFValue(ValueType value) { SetValue(value); };
|
||||
virtual ~AMFValue() override {};
|
||||
AMFValue() = default;
|
||||
AMFValue(const ValueType value) : m_Data{ value } {}
|
||||
|
||||
eAmf GetValueType() override { return eAmf::Undefined; };
|
||||
virtual ~AMFValue() override = default;
|
||||
|
||||
[[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:
|
||||
ValueType data;
|
||||
ValueType m_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.
|
||||
template <>
|
||||
class AMFValue<const char*> : public AMFBaseValue {
|
||||
public:
|
||||
AMFValue() {};
|
||||
AMFValue(const char* value) { SetValue(std::string(value)); };
|
||||
virtual ~AMFValue() override {};
|
||||
AMFValue() = default;
|
||||
AMFValue(const char* value) { m_Data = value; }
|
||||
virtual ~AMFValue() override = default;
|
||||
|
||||
eAmf GetValueType() override { return eAmf::String; };
|
||||
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::String; }
|
||||
|
||||
const std::string& GetValue() { return data; };
|
||||
void SetValue(std::string value) { data = value; };
|
||||
[[nodiscard]] const std::string& GetValue() const { return m_Data; }
|
||||
void SetValue(const std::string& value) { m_Data = value; }
|
||||
protected:
|
||||
std::string data;
|
||||
std::string m_Data;
|
||||
};
|
||||
|
||||
typedef AMFValue<std::nullptr_t> AMFNullValue;
|
||||
typedef AMFValue<bool> AMFBoolValue;
|
||||
typedef AMFValue<int32_t> AMFIntValue;
|
||||
typedef AMFValue<std::string> AMFStringValue;
|
||||
typedef AMFValue<double> AMFDoubleValue;
|
||||
|
||||
template<> inline eAmf AMFValue<std::nullptr_t>::GetValueType() { return eAmf::Null; };
|
||||
template<> inline eAmf AMFValue<bool>::GetValueType() { return this->data ? eAmf::True : eAmf::False; };
|
||||
template<> inline eAmf AMFValue<int32_t>::GetValueType() { return eAmf::Integer; };
|
||||
template<> inline eAmf AMFValue<uint32_t>::GetValueType() { return eAmf::Integer; };
|
||||
template<> inline eAmf AMFValue<std::string>::GetValueType() { return eAmf::String; };
|
||||
template<> inline eAmf AMFValue<double>::GetValueType() { return eAmf::Double; };
|
||||
using AMFNullValue = AMFValue<std::nullptr_t>;
|
||||
using AMFBoolValue = AMFValue<bool>;
|
||||
using AMFIntValue = AMFValue<int32_t>;
|
||||
using AMFStringValue = AMFValue<std::string>;
|
||||
using AMFDoubleValue = AMFValue<double>;
|
||||
|
||||
/**
|
||||
* The AMFArrayValue object holds 2 types of lists:
|
||||
@@ -89,15 +105,14 @@ template<> inline eAmf AMFValue<double>::GetValueType() { return eAmf::Double; }
|
||||
* and are not to be deleted by a caller.
|
||||
*/
|
||||
class AMFArrayValue : public AMFBaseValue {
|
||||
|
||||
typedef std::unordered_map<std::string, AMFBaseValue*> AMFAssociative;
|
||||
typedef std::vector<AMFBaseValue*> AMFDense;
|
||||
using AMFAssociative = std::unordered_map<std::string, AMFBaseValue*>;
|
||||
using AMFDense = std::vector<AMFBaseValue*>;
|
||||
|
||||
public:
|
||||
eAmf GetValueType() override { return eAmf::Array; };
|
||||
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; }
|
||||
|
||||
~AMFArrayValue() override {
|
||||
for (auto valueToDelete : GetDense()) {
|
||||
for (const auto* valueToDelete : GetDense()) {
|
||||
if (valueToDelete) {
|
||||
delete valueToDelete;
|
||||
valueToDelete = nullptr;
|
||||
@@ -109,17 +124,17 @@ public:
|
||||
valueToDelete.second = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Associative portion of the object
|
||||
*/
|
||||
inline AMFAssociative& GetAssociative() { return this->associative; };
|
||||
[[nodiscard]] inline const AMFAssociative& GetAssociative() const noexcept { return m_Associative; }
|
||||
|
||||
/**
|
||||
* Returns the dense portion of the object
|
||||
*/
|
||||
inline AMFDense& GetDense() { return this->dense; };
|
||||
[[nodiscard]] inline const AMFDense& GetDense() const noexcept { return m_Dense; }
|
||||
|
||||
/**
|
||||
* Inserts an AMFValue into the associative portion with the given key.
|
||||
@@ -136,47 +151,47 @@ public:
|
||||
* or nullptr if a key existed and was not the same type
|
||||
*/
|
||||
template <typename ValueType>
|
||||
std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, ValueType value) {
|
||||
auto element = associative.find(key);
|
||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, const ValueType value) {
|
||||
const auto element = m_Associative.find(key);
|
||||
AMFValue<ValueType>* val = nullptr;
|
||||
bool found = true;
|
||||
if (element == associative.end()) {
|
||||
if (element == m_Associative.cend()) {
|
||||
val = new AMFValue<ValueType>(value);
|
||||
associative.insert(std::make_pair(key, val));
|
||||
m_Associative.emplace(key, val);
|
||||
} else {
|
||||
val = dynamic_cast<AMFValue<ValueType>*>(element->second);
|
||||
found = false;
|
||||
}
|
||||
return std::make_pair(val, found);
|
||||
};
|
||||
}
|
||||
|
||||
// Associates an array with a string key
|
||||
std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
|
||||
auto element = associative.find(key);
|
||||
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
|
||||
const auto element = m_Associative.find(key);
|
||||
AMFArrayValue* val = nullptr;
|
||||
bool found = true;
|
||||
if (element == associative.end()) {
|
||||
if (element == m_Associative.cend()) {
|
||||
val = new AMFArrayValue();
|
||||
associative.insert(std::make_pair(key, val));
|
||||
m_Associative.emplace(key, val);
|
||||
} else {
|
||||
val = dynamic_cast<AMFArrayValue*>(element->second);
|
||||
found = false;
|
||||
}
|
||||
return std::make_pair(val, found);
|
||||
};
|
||||
}
|
||||
|
||||
// Associates an array with an integer key
|
||||
std::pair<AMFBaseValue*, bool> Insert(const uint32_t& index) {
|
||||
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) {
|
||||
AMFArrayValue* val = nullptr;
|
||||
bool inserted = false;
|
||||
if (index >= dense.size()) {
|
||||
dense.resize(index + 1);
|
||||
if (index >= m_Dense.size()) {
|
||||
m_Dense.resize(index + 1);
|
||||
val = new AMFArrayValue();
|
||||
dense.at(index) = val;
|
||||
m_Dense.at(index) = val;
|
||||
inserted = true;
|
||||
}
|
||||
return std::make_pair(dynamic_cast<AMFArrayValue*>(dense.at(index)), inserted);
|
||||
};
|
||||
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index)), inserted);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an AMFValue into the AMFArray key'd by index.
|
||||
@@ -189,17 +204,17 @@ public:
|
||||
* what was at the index.
|
||||
*/
|
||||
template <typename ValueType>
|
||||
std::pair<AMFValue<ValueType>*, bool> Insert(const uint32_t& index, ValueType value) {
|
||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) {
|
||||
AMFValue<ValueType>* val = nullptr;
|
||||
bool inserted = false;
|
||||
if (index >= this->dense.size()) {
|
||||
this->dense.resize(index + 1);
|
||||
if (index >= m_Dense.size()) {
|
||||
m_Dense.resize(index + 1);
|
||||
val = new AMFValue<ValueType>(value);
|
||||
this->dense.at(index) = val;
|
||||
m_Dense.at(index) = val;
|
||||
inserted = true;
|
||||
}
|
||||
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(this->dense.at(index)), inserted);
|
||||
};
|
||||
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index)), inserted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an AMFValue into the associative portion with the given key.
|
||||
@@ -210,15 +225,15 @@ public:
|
||||
* @param key The key to associate with the value
|
||||
* @param value The value to insert
|
||||
*/
|
||||
void Insert(const std::string& key, AMFBaseValue* value) {
|
||||
auto element = associative.find(key);
|
||||
if (element != associative.end() && element->second) {
|
||||
void Insert(const std::string& key, AMFBaseValue* const value) {
|
||||
const auto element = m_Associative.find(key);
|
||||
if (element != m_Associative.cend() && element->second) {
|
||||
delete element->second;
|
||||
element->second = value;
|
||||
} else {
|
||||
associative.insert(std::make_pair(key, value));
|
||||
m_Associative.emplace(key, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Inserts an AMFValue into the associative portion with the given index.
|
||||
@@ -229,15 +244,15 @@ public:
|
||||
* @param key The key to associate with the value
|
||||
* @param value The value to insert
|
||||
*/
|
||||
void Insert(const uint32_t index, AMFBaseValue* value) {
|
||||
if (index < dense.size()) {
|
||||
AMFDense::iterator itr = dense.begin() + index;
|
||||
if (*itr) delete dense.at(index);
|
||||
void Insert(const size_t index, AMFBaseValue* const value) {
|
||||
if (index < m_Dense.size()) {
|
||||
const AMFDense::const_iterator itr = m_Dense.cbegin() + index;
|
||||
if (*itr) delete m_Dense.at(index);
|
||||
} else {
|
||||
dense.resize(index + 1);
|
||||
m_Dense.resize(index + 1);
|
||||
}
|
||||
m_Dense.at(index) = value;
|
||||
}
|
||||
dense.at(index) = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pushes an AMFValue into the back of the dense portion.
|
||||
@@ -250,9 +265,9 @@ public:
|
||||
* @return The inserted pointer, or nullptr should the key already be in use.
|
||||
*/
|
||||
template <typename ValueType>
|
||||
inline AMFValue<ValueType>* Push(ValueType value) {
|
||||
return Insert(this->dense.size(), value).first;
|
||||
};
|
||||
[[maybe_unused]] inline AMFValue<ValueType>* Push(const ValueType value) {
|
||||
return Insert(m_Dense.size(), value).first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the key from the associative portion
|
||||
@@ -261,52 +276,49 @@ public:
|
||||
*
|
||||
* @param key The key to remove from the associative portion
|
||||
*/
|
||||
void Remove(const std::string& key, bool deleteValue = true) {
|
||||
AMFAssociative::iterator it = this->associative.find(key);
|
||||
if (it != this->associative.end()) {
|
||||
void Remove(const std::string& key, const bool deleteValue = true) {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
if (it != m_Associative.cend()) {
|
||||
if (deleteValue) delete it->second;
|
||||
this->associative.erase(it);
|
||||
m_Associative.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops the last element in the dense portion, deleting it in the process.
|
||||
*/
|
||||
void Remove(const uint32_t index) {
|
||||
if (!this->dense.empty() && index < this->dense.size()) {
|
||||
auto itr = this->dense.begin() + index;
|
||||
void Remove(const size_t index) {
|
||||
if (!m_Dense.empty() && index < m_Dense.size()) {
|
||||
const auto itr = m_Dense.cbegin() + index;
|
||||
if (*itr) delete (*itr);
|
||||
this->dense.erase(itr);
|
||||
m_Dense.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void Pop() {
|
||||
if (!this->dense.empty()) Remove(this->dense.size() - 1);
|
||||
if (!m_Dense.empty()) Remove(m_Dense.size() - 1);
|
||||
}
|
||||
|
||||
AMFArrayValue* GetArray(const std::string& key) {
|
||||
AMFAssociative::const_iterator it = this->associative.find(key);
|
||||
if (it != this->associative.end()) {
|
||||
return dynamic_cast<AMFArrayValue*>(it->second);
|
||||
[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) const {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second) : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
AMFArrayValue* GetArray(const uint32_t index) {
|
||||
return index >= this->dense.size() ? nullptr : dynamic_cast<AMFArrayValue*>(this->dense.at(index));
|
||||
};
|
||||
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const {
|
||||
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index)) : nullptr;
|
||||
}
|
||||
|
||||
inline AMFArrayValue* InsertArray(const std::string& key) {
|
||||
[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string& key) {
|
||||
return static_cast<AMFArrayValue*>(Insert(key).first);
|
||||
};
|
||||
}
|
||||
|
||||
inline AMFArrayValue* InsertArray(const uint32_t index) {
|
||||
[[maybe_unused]] inline AMFArrayValue* InsertArray(const size_t index) {
|
||||
return static_cast<AMFArrayValue*>(Insert(index).first);
|
||||
};
|
||||
}
|
||||
|
||||
inline AMFArrayValue* PushArray() {
|
||||
return static_cast<AMFArrayValue*>(Insert(this->dense.size()).first);
|
||||
};
|
||||
[[maybe_unused]] inline AMFArrayValue* PushArray() {
|
||||
return static_cast<AMFArrayValue*>(Insert(m_Dense.size()).first);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an AMFValue by the key from the associative portion and converts it
|
||||
@@ -318,18 +330,18 @@ public:
|
||||
* @return The AMFValue
|
||||
*/
|
||||
template <typename AmfType>
|
||||
AMFValue<AmfType>* Get(const std::string& key) const {
|
||||
AMFAssociative::const_iterator it = this->associative.find(key);
|
||||
return it != this->associative.end() ?
|
||||
[[nodiscard]] AMFValue<AmfType>* Get(const std::string& key) const {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
return it != m_Associative.cend() ?
|
||||
dynamic_cast<AMFValue<AmfType>*>(it->second) :
|
||||
nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
// Get from the array but dont cast it
|
||||
AMFBaseValue* Get(const std::string& key) const {
|
||||
AMFAssociative::const_iterator it = this->associative.find(key);
|
||||
return it != this->associative.end() ? it->second : nullptr;
|
||||
};
|
||||
[[nodiscard]] AMFBaseValue* Get(const std::string& key) const {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
return it != m_Associative.cend() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get an AMFValue object at a position in the dense portion.
|
||||
@@ -341,27 +353,28 @@ public:
|
||||
* @return The casted object, or nullptr.
|
||||
*/
|
||||
template <typename AmfType>
|
||||
AMFValue<AmfType>* Get(uint32_t index) const {
|
||||
return index < this->dense.size() ?
|
||||
dynamic_cast<AMFValue<AmfType>*>(this->dense.at(index)) :
|
||||
[[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const {
|
||||
return index < m_Dense.size() ?
|
||||
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index)) :
|
||||
nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
// Get from the dense but dont cast it
|
||||
AMFBaseValue* Get(const uint32_t index) const {
|
||||
return index < this->dense.size() ? this->dense.at(index) : nullptr;
|
||||
};
|
||||
[[nodiscard]] AMFBaseValue* Get(const size_t index) const {
|
||||
return index < m_Dense.size() ? m_Dense.at(index) : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* The associative portion. These values are key'd with strings to an AMFValue.
|
||||
*/
|
||||
AMFAssociative associative;
|
||||
AMFAssociative m_Associative;
|
||||
|
||||
/**
|
||||
* The dense portion. These AMFValue's are stored one after
|
||||
* another with the most recent addition being at the back.
|
||||
*/
|
||||
AMFDense dense;
|
||||
AMFDense m_Dense;
|
||||
};
|
||||
|
||||
#endif //!__AMF3__H__
|
||||
|
||||
@@ -53,7 +53,7 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
|
||||
* A private function to write an value to a RakNet::BitStream
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
void WriteUInt29(RakNet::BitStream& bs, uint32_t v) {
|
||||
unsigned char b4 = static_cast<unsigned char>(v);
|
||||
if (v < 0x00200000) {
|
||||
b4 = b4 & 0x7F;
|
||||
@@ -65,10 +65,10 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
unsigned char b2;
|
||||
v = v >> 7;
|
||||
b2 = static_cast<unsigned char>(v) | 0x80;
|
||||
bs->Write(b2);
|
||||
bs.Write(b2);
|
||||
}
|
||||
|
||||
bs->Write(b3);
|
||||
bs.Write(b3);
|
||||
}
|
||||
} else {
|
||||
unsigned char b1;
|
||||
@@ -82,19 +82,19 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
v = v >> 7;
|
||||
b1 = static_cast<unsigned char>(v) | 0x80;
|
||||
|
||||
bs->Write(b1);
|
||||
bs->Write(b2);
|
||||
bs->Write(b3);
|
||||
bs.Write(b1);
|
||||
bs.Write(b2);
|
||||
bs.Write(b3);
|
||||
}
|
||||
|
||||
bs->Write(b4);
|
||||
bs.Write(b4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a flag number to a RakNet::BitStream
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
|
||||
void WriteFlagNumber(RakNet::BitStream& bs, uint32_t v) {
|
||||
v = (v << 1) | 0x01;
|
||||
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.
|
||||
*/
|
||||
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()));
|
||||
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.
|
||||
*/
|
||||
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
|
||||
bs->Write(value);
|
||||
void WriteAMFU16(RakNet::BitStream& bs, uint16_t 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.
|
||||
*/
|
||||
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
|
||||
bs->Write(value);
|
||||
void WriteAMFU32(RakNet::BitStream& bs, uint32_t 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.
|
||||
*/
|
||||
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
|
||||
bs->Write(value);
|
||||
void WriteAMFU64(RakNet::BitStream& bs, uint64_t value) {
|
||||
bs.Write(value);
|
||||
}
|
||||
|
||||
// Writes an AMFIntegerValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) {
|
||||
WriteUInt29(this, value.GetValue());
|
||||
WriteUInt29(*this, value.GetValue());
|
||||
}
|
||||
|
||||
// Writes an AMFDoubleValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
|
||||
double d = value.GetValue();
|
||||
WriteAMFU64(this, *reinterpret_cast<uint64_t*>(&d));
|
||||
WriteAMFU64(*this, *reinterpret_cast<uint64_t*>(&d));
|
||||
}
|
||||
|
||||
// Writes an AMFStringValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) {
|
||||
WriteAMFString(this, value.GetValue());
|
||||
WriteAMFString(*this, value.GetValue());
|
||||
}
|
||||
|
||||
// Writes an AMFArrayValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) {
|
||||
uint32_t denseSize = value.GetDense().size();
|
||||
WriteFlagNumber(this, denseSize);
|
||||
WriteFlagNumber(*this, denseSize);
|
||||
|
||||
auto it = value.GetAssociative().begin();
|
||||
auto end = value.GetAssociative().end();
|
||||
|
||||
while (it != end) {
|
||||
WriteAMFString(this, it->first);
|
||||
WriteAMFString(*this, it->first);
|
||||
this->Write<AMFBaseValue&>(*it->second);
|
||||
it++;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,9 @@ set(DCOMMON_SOURCES
|
||||
"Game.cpp"
|
||||
"GeneralUtils.cpp"
|
||||
"LDFFormat.cpp"
|
||||
"MD5.cpp"
|
||||
"Metrics.cpp"
|
||||
"NiPoint3.cpp"
|
||||
"NiQuaternion.cpp"
|
||||
"SHA512.cpp"
|
||||
"Demangler.cpp"
|
||||
"ZCompression.cpp"
|
||||
"BrickByBrickFix.cpp"
|
||||
@@ -20,17 +18,27 @@ set(DCOMMON_SOURCES
|
||||
"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)
|
||||
|
||||
foreach(file ${DCOMMON_DCLIENT_SOURCES})
|
||||
set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}")
|
||||
endforeach()
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
|
||||
|
||||
add_library(dCommon STATIC ${DCOMMON_SOURCES})
|
||||
|
||||
target_link_libraries(dCommon bcrypt dDatabase tinyxml2)
|
||||
target_include_directories(dCommon
|
||||
PUBLIC "." "dClient" "dEnums"
|
||||
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)
|
||||
find_package(ZLIB REQUIRED)
|
||||
@@ -61,4 +69,6 @@ else ()
|
||||
)
|
||||
endif ()
|
||||
|
||||
target_link_libraries(dCommon ZLIB::ZLIB)
|
||||
target_link_libraries(dCommon
|
||||
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
|
||||
INTERFACE dDatabase)
|
||||
|
||||
@@ -120,6 +120,8 @@ void CatchUnhandled(int sig) {
|
||||
if (eptr) std::rethrow_exception(eptr);
|
||||
} catch(const std::exception& e) {
|
||||
LOG("Caught exception: '%s'", e.what());
|
||||
} catch (...) {
|
||||
LOG("Caught unknown exception.");
|
||||
}
|
||||
|
||||
#ifndef INCLUDE_BACKTRACE
|
||||
|
||||
@@ -8,23 +8,23 @@
|
||||
#include <map>
|
||||
|
||||
template <typename T>
|
||||
inline size_t MinSize(size_t size, const std::basic_string_view<T>& string) {
|
||||
if (size == size_t(-1) || size > string.size()) {
|
||||
static inline size_t MinSize(const size_t size, const std::basic_string_view<T> string) {
|
||||
if (size == SIZE_MAX || size > string.size()) {
|
||||
return string.size();
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IsLeadSurrogate(char16_t c) {
|
||||
inline bool IsLeadSurrogate(const char16_t c) {
|
||||
return (0xD800 <= c) && (c <= 0xDBFF);
|
||||
}
|
||||
|
||||
inline bool IsTrailSurrogate(char16_t c) {
|
||||
inline bool IsTrailSurrogate(const char16_t c) {
|
||||
return (0xDC00 <= c) && (c <= 0xDFFF);
|
||||
}
|
||||
|
||||
inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
||||
inline void PushUTF8CodePoint(std::string& ret, const char32_t cp) {
|
||||
if (cp <= 0x007F) {
|
||||
ret.push_back(static_cast<uint8_t>(cp));
|
||||
} else if (cp <= 0x07FF) {
|
||||
@@ -46,16 +46,16 @@ inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
||||
|
||||
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
||||
|
||||
bool _IsSuffixChar(uint8_t c) {
|
||||
bool static _IsSuffixChar(const uint8_t c) {
|
||||
return (c & 0xC0) == 0x80;
|
||||
}
|
||||
|
||||
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
size_t rem = slice.length();
|
||||
bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
const size_t rem = slice.length();
|
||||
if (slice.empty()) return false;
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
||||
if (rem > 0) {
|
||||
uint8_t first = bytes[0];
|
||||
const uint8_t first = bytes[0];
|
||||
if (first < 0x80) { // 1 byte character
|
||||
out = static_cast<uint32_t>(first & 0x7F);
|
||||
slice.remove_prefix(1);
|
||||
@@ -64,7 +64,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
// middle byte, not valid at start, fall through
|
||||
} else if (first < 0xE0) { // two byte character
|
||||
if (rem > 1) {
|
||||
uint8_t second = bytes[1];
|
||||
const uint8_t second = bytes[1];
|
||||
if (_IsSuffixChar(second)) {
|
||||
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
||||
+ static_cast<uint32_t>(second & 0x3F);
|
||||
@@ -74,8 +74,8 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
}
|
||||
} else if (first < 0xF0) { // three byte character
|
||||
if (rem > 2) {
|
||||
uint8_t second = bytes[1];
|
||||
uint8_t third = bytes[2];
|
||||
const uint8_t second = bytes[1];
|
||||
const uint8_t third = bytes[2];
|
||||
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
||||
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
||||
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
||||
@@ -86,9 +86,9 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
}
|
||||
} else if (first < 0xF8) { // four byte character
|
||||
if (rem > 3) {
|
||||
uint8_t second = bytes[1];
|
||||
uint8_t third = bytes[2];
|
||||
uint8_t fourth = bytes[3];
|
||||
const uint8_t second = bytes[1];
|
||||
const uint8_t third = bytes[2];
|
||||
const uint8_t fourth = bytes[3];
|
||||
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
||||
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
||||
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
||||
@@ -107,7 +107,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
}
|
||||
|
||||
/// See <https://www.ietf.org/rfc/rfc2781.html#section-2.1>
|
||||
bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
||||
bool PushUTF16CodePoint(std::u16string& output, const uint32_t U, const size_t size) {
|
||||
if (output.length() >= size) return false;
|
||||
if (U < 0x10000) {
|
||||
// If U < 0x10000, encode U as a 16-bit unsigned integer and terminate.
|
||||
@@ -120,7 +120,7 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
||||
// Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
|
||||
// U' must be less than or equal to 0xFFFFF. That is, U' can be
|
||||
// represented in 20 bits.
|
||||
uint32_t Ut = U - 0x10000;
|
||||
const uint32_t Ut = U - 0x10000;
|
||||
|
||||
// Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
|
||||
// 0xDC00, respectively. These integers each have 10 bits free to
|
||||
@@ -141,25 +141,25 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
||||
} else return false;
|
||||
}
|
||||
|
||||
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view string, const size_t size) {
|
||||
const size_t newSize = MinSize(size, string);
|
||||
std::u16string output;
|
||||
output.reserve(newSize);
|
||||
std::string_view iterator = string;
|
||||
|
||||
uint32_t c;
|
||||
while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
||||
while (details::_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
||||
return output;
|
||||
}
|
||||
|
||||
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view string, const size_t size) {
|
||||
const size_t newSize = MinSize(size, string);
|
||||
std::u16string ret;
|
||||
ret.reserve(newSize);
|
||||
|
||||
for (size_t i = 0; i < newSize; i++) {
|
||||
char c = string[i];
|
||||
for (size_t i = 0; i < newSize; ++i) {
|
||||
const char c = string[i];
|
||||
// Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t
|
||||
ret.push_back((c > 0 && c <= 127) ? static_cast<char16_t>(c) : REPLACEMENT_CHARACTER);
|
||||
}
|
||||
@@ -169,18 +169,18 @@ std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t
|
||||
|
||||
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
|
||||
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view string, const size_t size) {
|
||||
const size_t newSize = MinSize(size, string);
|
||||
std::string ret;
|
||||
ret.reserve(newSize);
|
||||
|
||||
for (size_t i = 0; i < newSize; i++) {
|
||||
char16_t u = string[i];
|
||||
for (size_t i = 0; i < newSize; ++i) {
|
||||
const char16_t u = string[i];
|
||||
if (IsLeadSurrogate(u) && (i + 1) < newSize) {
|
||||
char16_t next = string[i + 1];
|
||||
const char16_t next = string[i + 1];
|
||||
if (IsTrailSurrogate(next)) {
|
||||
i += 1;
|
||||
char32_t cp = 0x10000
|
||||
const char32_t cp = 0x10000
|
||||
+ ((static_cast<char32_t>(u) - 0xD800) << 10)
|
||||
+ (static_cast<char32_t>(next) - 0xDC00);
|
||||
PushUTF8CodePoint(ret, cp);
|
||||
@@ -195,40 +195,40 @@ std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) {
|
||||
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b) {
|
||||
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); });
|
||||
}
|
||||
|
||||
// MARK: Bits
|
||||
|
||||
//! Sets a specific bit in a signed 64-bit integer
|
||||
int64_t GeneralUtils::SetBit(int64_t value, uint32_t index) {
|
||||
int64_t GeneralUtils::SetBit(int64_t value, const uint32_t index) {
|
||||
return value |= 1ULL << index;
|
||||
}
|
||||
|
||||
//! Clears a specific bit in a signed 64-bit integer
|
||||
int64_t GeneralUtils::ClearBit(int64_t value, uint32_t index) {
|
||||
int64_t GeneralUtils::ClearBit(int64_t value, const uint32_t index) {
|
||||
return value &= ~(1ULL << index);
|
||||
}
|
||||
|
||||
//! Checks a specific bit in a signed 64-bit integer
|
||||
bool GeneralUtils::CheckBit(int64_t value, uint32_t index) {
|
||||
bool GeneralUtils::CheckBit(int64_t value, const uint32_t index) {
|
||||
return value & (1ULL << index);
|
||||
}
|
||||
|
||||
bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) {
|
||||
size_t start_pos = str.find(from);
|
||||
bool GeneralUtils::ReplaceInString(std::string& str, const std::string_view from, const std::string_view to) {
|
||||
const size_t start_pos = str.find(from);
|
||||
if (start_pos == std::string::npos)
|
||||
return false;
|
||||
str.replace(start_pos, from.length(), to);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) {
|
||||
std::vector<std::wstring> GeneralUtils::SplitString(const std::wstring_view str, const wchar_t delimiter) {
|
||||
std::vector<std::wstring> vector = std::vector<std::wstring>();
|
||||
std::wstring current;
|
||||
|
||||
for (const auto& c : str) {
|
||||
for (const wchar_t c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = L"";
|
||||
@@ -237,15 +237,15 @@ std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t d
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(current);
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) {
|
||||
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string_view str, const char16_t delimiter) {
|
||||
std::vector<std::u16string> vector = std::vector<std::u16string>();
|
||||
std::u16string current;
|
||||
|
||||
for (const auto& c : str) {
|
||||
for (const char16_t c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = u"";
|
||||
@@ -254,17 +254,15 @@ std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str,
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(current);
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char delimiter) {
|
||||
std::vector<std::string> GeneralUtils::SplitString(const std::string_view str, const char delimiter) {
|
||||
std::vector<std::string> vector = std::vector<std::string>();
|
||||
std::string current = "";
|
||||
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
char c = str[i];
|
||||
|
||||
for (const char c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = "";
|
||||
@@ -273,53 +271,70 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(current);
|
||||
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) {
|
||||
std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
|
||||
uint32_t length;
|
||||
inStream->Read<uint32_t>(length);
|
||||
inStream.Read<uint32_t>(length);
|
||||
|
||||
std::u16string string;
|
||||
for (auto i = 0; i < length; i++) {
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
uint16_t c;
|
||||
inStream->Read(c);
|
||||
inStream.Read(c);
|
||||
string.push_back(c);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) {
|
||||
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string_view folder) {
|
||||
// Because we dont know how large the initial number before the first _ is we need to make it a map like so.
|
||||
std::map<uint32_t, std::string> filenames{};
|
||||
for (auto& t : std::filesystem::directory_iterator(folder)) {
|
||||
for (const auto& t : std::filesystem::directory_iterator(folder)) {
|
||||
auto filename = t.path().filename().string();
|
||||
auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
|
||||
filenames.insert(std::make_pair(index, filename));
|
||||
const auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
|
||||
filenames.emplace(index, std::move(filename));
|
||||
}
|
||||
|
||||
// Now sort the map by the oldest migration.
|
||||
std::vector<std::string> sortedFiles{};
|
||||
auto fileIterator = filenames.begin();
|
||||
std::map<uint32_t, std::string>::iterator oldest = filenames.begin();
|
||||
auto fileIterator = filenames.cbegin();
|
||||
auto oldest = filenames.cbegin();
|
||||
while (!filenames.empty()) {
|
||||
if (fileIterator == filenames.end()) {
|
||||
if (fileIterator == filenames.cend()) {
|
||||
sortedFiles.push_back(oldest->second);
|
||||
filenames.erase(oldest);
|
||||
fileIterator = filenames.begin();
|
||||
oldest = filenames.begin();
|
||||
fileIterator = filenames.cbegin();
|
||||
oldest = filenames.cbegin();
|
||||
continue;
|
||||
}
|
||||
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
||||
fileIterator++;
|
||||
++fileIterator;
|
||||
}
|
||||
|
||||
return sortedFiles;
|
||||
}
|
||||
|
||||
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);
|
||||
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924)
|
||||
|
||||
// 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
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
// C++
|
||||
#include <stdint.h>
|
||||
#include <random>
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include "BitStream.h"
|
||||
#include "NiPoint3.h"
|
||||
|
||||
#include "dPlatforms.h"
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
|
||||
@@ -29,29 +33,31 @@ namespace GeneralUtils {
|
||||
//! Converts a plain ASCII string to a UTF-16 string
|
||||
/*!
|
||||
\param string The string to convert
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||
\return An UTF-16 representation of the string
|
||||
*/
|
||||
std::u16string ASCIIToUTF16(const std::string_view& string, size_t size = -1);
|
||||
std::u16string ASCIIToUTF16(const std::string_view string, const size_t size = SIZE_MAX);
|
||||
|
||||
//! Converts a UTF-8 String to a UTF-16 string
|
||||
/*!
|
||||
\param string The string to convert
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||
\return An UTF-16 representation of the string
|
||||
*/
|
||||
std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1);
|
||||
std::u16string UTF8ToUTF16(const std::string_view string, const size_t size = SIZE_MAX);
|
||||
|
||||
namespace details {
|
||||
//! Internal, do not use
|
||||
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
||||
}
|
||||
|
||||
//! Converts a UTF-16 string to a UTF-8 string
|
||||
/*!
|
||||
\param string The string to convert
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||
\return An UTF-8 representation of the string
|
||||
*/
|
||||
std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1);
|
||||
std::string UTF16ToWTF8(const std::u16string_view string, const size_t size = SIZE_MAX);
|
||||
|
||||
/**
|
||||
* Compares two basic strings but does so ignoring case sensitivity
|
||||
@@ -59,7 +65,7 @@ namespace GeneralUtils {
|
||||
* \param b the second string to compare against the first string
|
||||
* @return if the two strings are equal
|
||||
*/
|
||||
bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b);
|
||||
bool CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b);
|
||||
|
||||
// MARK: Bits
|
||||
|
||||
@@ -67,9 +73,9 @@ namespace GeneralUtils {
|
||||
|
||||
//! Sets a bit on a numerical value
|
||||
template <typename T>
|
||||
inline void SetBit(T& value, eObjectBits bits) {
|
||||
inline void SetBit(T& value, const eObjectBits bits) {
|
||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||
auto index = static_cast<size_t>(bits);
|
||||
const auto index = static_cast<size_t>(bits);
|
||||
if (index > (sizeof(T) * 8) - 1) {
|
||||
return;
|
||||
}
|
||||
@@ -79,9 +85,9 @@ namespace GeneralUtils {
|
||||
|
||||
//! Clears a bit on a numerical value
|
||||
template <typename T>
|
||||
inline void ClearBit(T& value, eObjectBits bits) {
|
||||
inline void ClearBit(T& value, const eObjectBits bits) {
|
||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||
auto index = static_cast<size_t>(bits);
|
||||
const auto index = static_cast<size_t>(bits);
|
||||
if (index > (sizeof(T) * 8 - 1)) {
|
||||
return;
|
||||
}
|
||||
@@ -94,14 +100,14 @@ namespace GeneralUtils {
|
||||
\param value The value to set the bit for
|
||||
\param index The index of the bit
|
||||
*/
|
||||
int64_t SetBit(int64_t value, uint32_t index);
|
||||
int64_t SetBit(int64_t value, const uint32_t index);
|
||||
|
||||
//! Clears a specific bit in a signed 64-bit integer
|
||||
/*!
|
||||
\param value The value to clear the bit from
|
||||
\param index The index of the bit
|
||||
*/
|
||||
int64_t ClearBit(int64_t value, uint32_t index);
|
||||
int64_t ClearBit(int64_t value, const uint32_t index);
|
||||
|
||||
//! Checks a specific bit in a signed 64-bit integer
|
||||
/*!
|
||||
@@ -109,104 +115,128 @@ namespace GeneralUtils {
|
||||
\param index The index of the bit
|
||||
\return Whether or not the bit is set
|
||||
*/
|
||||
bool CheckBit(int64_t value, uint32_t index);
|
||||
bool CheckBit(int64_t value, const uint32_t index);
|
||||
|
||||
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
|
||||
bool ReplaceInString(std::string& str, const std::string_view from, const std::string_view 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(const std::wstring_view str, const wchar_t delimiter);
|
||||
|
||||
std::vector<std::u16string> SplitString(const std::u16string& str, char16_t delimiter);
|
||||
std::vector<std::u16string> SplitString(const std::u16string_view str, const char16_t delimiter);
|
||||
|
||||
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
||||
std::vector<std::string> SplitString(const std::string_view str, const char delimiter);
|
||||
|
||||
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
|
||||
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string_view folder);
|
||||
|
||||
// Concept constraining to enum types
|
||||
template <typename T>
|
||||
T Parse(const char* value);
|
||||
|
||||
template <>
|
||||
inline bool Parse(const char* value) {
|
||||
return std::stoi(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int32_t Parse(const char* value) {
|
||||
return std::stoi(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int64_t Parse(const char* value) {
|
||||
return std::stoll(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float Parse(const char* value) {
|
||||
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));
|
||||
}
|
||||
concept Enum = std::is_enum_v<T>;
|
||||
|
||||
// Concept constraining to numeric types
|
||||
template <typename T>
|
||||
bool TryParse(const char* value, T& dst) {
|
||||
concept Numeric = std::integral<T> || Enum<T> || std::floating_point<T>;
|
||||
|
||||
// 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 = uint8_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(std::string_view str) {
|
||||
numeric_parse_t<T> result;
|
||||
while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1);
|
||||
|
||||
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)
|
||||
|
||||
// MacOS floating-point parse helper function specializations
|
||||
namespace details {
|
||||
template <std::floating_point T>
|
||||
[[nodiscard]] T _parse(const std::string_view str, size_t& parseNum);
|
||||
}
|
||||
|
||||
/**
|
||||
* For floating-point values: Parses a string_view and returns an optional variable depending on the result.
|
||||
* Note that this function overload is only included for MacOS, as from_chars will fulfill its purpose otherwise.
|
||||
* @param str The string_view to be evaluated
|
||||
* @returns An std::optional containing the desired value if it is equivalent to the string
|
||||
*/
|
||||
template <std::floating_point T>
|
||||
[[nodiscard]] std::optional<T> TryParse(std::string_view str) noexcept
|
||||
try {
|
||||
dst = Parse<T>(value);
|
||||
while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1);
|
||||
|
||||
return true;
|
||||
size_t parseNum;
|
||||
const T result = details::_parse<T>(str, parseNum);
|
||||
const bool isParsed = str.length() == parseNum;
|
||||
|
||||
return isParsed ? result : std::optional<T>{};
|
||||
} catch (...) {
|
||||
return false;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#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_view strX, const std::string_view strY, const std::string_view 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 passing a span of three strings
|
||||
* @param str The string vector representing the X, Y, and Z coordinates
|
||||
* @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::span<const std::string> str) {
|
||||
return (str.size() == 3) ? TryParse<NiPoint3>(str[0], str[1], str[2]) : std::nullopt;
|
||||
}
|
||||
|
||||
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(const T value) {
|
||||
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
||||
}
|
||||
|
||||
// From boost::hash_combine
|
||||
template <class T>
|
||||
void hash_combine(std::size_t& s, const T& v) {
|
||||
constexpr void hash_combine(std::size_t& s, const T& v) {
|
||||
std::hash<T> h;
|
||||
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
|
||||
}
|
||||
@@ -219,7 +249,7 @@ namespace GeneralUtils {
|
||||
\param max The maximum to generate to
|
||||
*/
|
||||
template <typename T>
|
||||
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
|
||||
inline T GenerateRandomNumber(const std::size_t min, const std::size_t max) {
|
||||
// Make sure it is a numeric type
|
||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||
|
||||
@@ -239,11 +269,9 @@ namespace GeneralUtils {
|
||||
* @param entry Enum entry to cast
|
||||
* @returns The enum entry's value in its underlying type
|
||||
*/
|
||||
template <typename eType>
|
||||
inline constexpr typename std::underlying_type_t<eType> CastUnderlyingType(const eType entry) {
|
||||
static_assert(std::is_enum_v<eType>, "Not an enum");
|
||||
|
||||
return static_cast<typename std::underlying_type_t<eType>>(entry);
|
||||
template <Enum eType>
|
||||
constexpr std::underlying_type_t<eType> ToUnderlying(const eType entry) noexcept {
|
||||
return static_cast<std::underlying_type_t<eType>>(entry);
|
||||
}
|
||||
|
||||
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
||||
|
||||
@@ -61,33 +61,33 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||
}
|
||||
|
||||
case LDF_TYPE_S32: {
|
||||
int32_t data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
const auto data = GeneralUtils::TryParse<int32_t>(ldfTypeAndValue.second);
|
||||
if (!data) {
|
||||
LOG("Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<int32_t>(key, data);
|
||||
returnValue = new LDFData<int32_t>(key, data.value());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LDF_TYPE_FLOAT: {
|
||||
float data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
const auto data = GeneralUtils::TryParse<float>(ldfTypeAndValue.second);
|
||||
if (!data) {
|
||||
LOG("Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<float>(key, data);
|
||||
returnValue = new LDFData<float>(key, data.value());
|
||||
break;
|
||||
}
|
||||
|
||||
case LDF_TYPE_DOUBLE: {
|
||||
double data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
const auto data = GeneralUtils::TryParse<double>(ldfTypeAndValue.second);
|
||||
if (!data) {
|
||||
LOG("Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<double>(key, data);
|
||||
returnValue = new LDFData<double>(key, data.value());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -100,10 +100,12 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||
} else if (ldfTypeAndValue.second == "false") {
|
||||
data = 0;
|
||||
} else {
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
const auto dataOptional = GeneralUtils::TryParse<uint32_t>(ldfTypeAndValue.second);
|
||||
if (!dataOptional) {
|
||||
LOG("Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
data = dataOptional.value();
|
||||
}
|
||||
|
||||
returnValue = new LDFData<uint32_t>(key, data);
|
||||
@@ -118,10 +120,12 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||
} else if (ldfTypeAndValue.second == "false") {
|
||||
data = false;
|
||||
} else {
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
const auto dataOptional = GeneralUtils::TryParse<bool>(ldfTypeAndValue.second);
|
||||
if (!dataOptional) {
|
||||
LOG("Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
data = dataOptional.value();
|
||||
}
|
||||
|
||||
returnValue = new LDFData<bool>(key, data);
|
||||
@@ -129,22 +133,22 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||
}
|
||||
|
||||
case LDF_TYPE_U64: {
|
||||
uint64_t data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
const auto data = GeneralUtils::TryParse<uint64_t>(ldfTypeAndValue.second);
|
||||
if (!data) {
|
||||
LOG("Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<uint64_t>(key, data);
|
||||
returnValue = new LDFData<uint64_t>(key, data.value());
|
||||
break;
|
||||
}
|
||||
|
||||
case LDF_TYPE_OBJID: {
|
||||
LWOOBJID data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
const auto data = GeneralUtils::TryParse<LWOOBJID>(ldfTypeAndValue.second);
|
||||
if (!data) {
|
||||
LOG("Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<LWOOBJID>(key, data);
|
||||
returnValue = new LDFData<LWOOBJID>(key, data.value());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
|
||||
virtual ~LDFBaseData() {}
|
||||
|
||||
virtual void WriteToPacket(RakNet::BitStream* packet) = 0;
|
||||
virtual void WriteToPacket(RakNet::BitStream& packet) = 0;
|
||||
|
||||
virtual const std::u16string& GetKey() = 0;
|
||||
|
||||
@@ -62,17 +62,17 @@ private:
|
||||
T value;
|
||||
|
||||
//! Writes the key to the packet
|
||||
void WriteKey(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
||||
void WriteKey(RakNet::BitStream& packet) {
|
||||
packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
||||
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
|
||||
void WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
packet->Write(this->value);
|
||||
void WriteValue(RakNet::BitStream& packet) {
|
||||
packet.Write<uint8_t>(this->GetValueType());
|
||||
packet.Write(this->value);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
/*!
|
||||
\param packet The packet
|
||||
*/
|
||||
void WriteToPacket(RakNet::BitStream* packet) override {
|
||||
void WriteToPacket(RakNet::BitStream& packet) override {
|
||||
this->WriteKey(packet);
|
||||
this->WriteValue(packet);
|
||||
}
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
return new LDFData<T>(key, value);
|
||||
}
|
||||
|
||||
inline static T Default = {};
|
||||
inline static const T Default = {};
|
||||
};
|
||||
|
||||
// LDF Types
|
||||
@@ -178,31 +178,31 @@ template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF
|
||||
|
||||
// The specialized version for std::u16string (UTF-16)
|
||||
template<>
|
||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) {
|
||||
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) {
|
||||
packet->Write<uint16_t>(this->value[i]);
|
||||
packet.Write<uint16_t>(this->value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// The specialized version for bool
|
||||
template<>
|
||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) {
|
||||
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)
|
||||
template<>
|
||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) {
|
||||
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) {
|
||||
packet->Write<uint8_t>(this->value[i]);
|
||||
packet.Write<uint8_t>(this->value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,210 +1,24 @@
|
||||
#include "NiPoint3.h"
|
||||
#include "NiQuaternion.h"
|
||||
|
||||
// C++
|
||||
#include <cmath>
|
||||
|
||||
// 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
|
||||
// MARK: Member Functions
|
||||
|
||||
//! Gets the length of the vector
|
||||
float NiPoint3::Length(void) const {
|
||||
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)));
|
||||
float NiPoint3::Length() const {
|
||||
return std::sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
//! Unitize the vector
|
||||
NiPoint3 NiPoint3::Unitize(void) const {
|
||||
NiPoint3 NiPoint3::Unitize() const {
|
||||
float length = this->Length();
|
||||
|
||||
return length != 0 ? *this / length : NiPoint3::ZERO;
|
||||
return length != 0 ? *this / length : NiPoint3Constant::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
|
||||
|
||||
//! 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) {
|
||||
const auto dot = a.DotProduct(b);
|
||||
const auto lenA = a.SquaredLength();
|
||||
@@ -220,15 +34,7 @@ float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b) {
|
||||
return std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
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) {
|
||||
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, const float maxDistanceDelta) {
|
||||
float dx = target.x - current.x;
|
||||
float dy = target.y - current.y;
|
||||
float dz = target.z - current.z;
|
||||
@@ -249,29 +55,3 @@ NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target,
|
||||
float length = std::sqrt(lengthSquared);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef __NIPOINT3_H__
|
||||
#define __NIPOINT3_H__
|
||||
|
||||
/*!
|
||||
\file NiPoint3.hpp
|
||||
@@ -12,13 +13,13 @@ typedef NiPoint3 Vector3; //!< The Vector3 class is technically the NiPoin
|
||||
//! A custom class the defines a point in space
|
||||
class NiPoint3 {
|
||||
public:
|
||||
float x; //!< The x position
|
||||
float y; //!< The y position
|
||||
float z; //!< The z position
|
||||
float x{ 0 }; //!< The x position
|
||||
float y{ 0 }; //!< The y position
|
||||
float z{ 0 }; //!< The z position
|
||||
|
||||
|
||||
//! Initializer
|
||||
NiPoint3(void);
|
||||
constexpr NiPoint3() = default;
|
||||
|
||||
//! Initializer
|
||||
/*!
|
||||
@@ -26,23 +27,21 @@ public:
|
||||
\param y The y coordinate
|
||||
\param z The z coordinate
|
||||
*/
|
||||
NiPoint3(float x, float y, float z);
|
||||
constexpr NiPoint3(const float x, const float y, const float z) noexcept
|
||||
: x{ x }
|
||||
, y{ y }
|
||||
, z{ z } {
|
||||
}
|
||||
|
||||
//! Copy Constructor
|
||||
/*!
|
||||
\param point The point to copy
|
||||
*/
|
||||
NiPoint3(const NiPoint3& point);
|
||||
|
||||
//! Destructor
|
||||
~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)
|
||||
constexpr NiPoint3(const NiPoint3& point) noexcept
|
||||
: x{ point.x }
|
||||
, y{ point.y }
|
||||
, z{ point.z } {
|
||||
}
|
||||
|
||||
// MARK: Getters / Setters
|
||||
|
||||
@@ -50,38 +49,37 @@ public:
|
||||
/*!
|
||||
\return The x coordinate
|
||||
*/
|
||||
float GetX(void) const;
|
||||
[[nodiscard]] constexpr float GetX() const noexcept;
|
||||
|
||||
//! Sets the X coordinate
|
||||
/*!
|
||||
\param x The x coordinate
|
||||
*/
|
||||
void SetX(float x);
|
||||
constexpr void SetX(const float x) noexcept;
|
||||
|
||||
//! Gets the Y coordinate
|
||||
/*!
|
||||
\return The y coordinate
|
||||
*/
|
||||
float GetY(void) const;
|
||||
[[nodiscard]] constexpr float GetY() const noexcept;
|
||||
|
||||
//! Sets the Y coordinate
|
||||
/*!
|
||||
\param y The y coordinate
|
||||
*/
|
||||
void SetY(float y);
|
||||
constexpr void SetY(const float y) noexcept;
|
||||
|
||||
//! Gets the Z coordinate
|
||||
/*!
|
||||
\return The z coordinate
|
||||
*/
|
||||
float GetZ(void) const;
|
||||
[[nodiscard]] constexpr float GetZ() const noexcept;
|
||||
|
||||
//! Sets the Z coordinate
|
||||
/*!
|
||||
\param z The z coordinate
|
||||
*/
|
||||
void SetZ(float z);
|
||||
|
||||
constexpr void SetZ(const float z) noexcept;
|
||||
|
||||
// MARK: Member Functions
|
||||
|
||||
@@ -89,72 +87,70 @@ public:
|
||||
/*!
|
||||
\return The scalar length of the vector
|
||||
*/
|
||||
float Length(void) const;
|
||||
[[nodiscard]] float Length() const;
|
||||
|
||||
//! Gets the squared length of a vector
|
||||
/*!
|
||||
\return The squared length of a vector
|
||||
*/
|
||||
float SquaredLength(void) const;
|
||||
[[nodiscard]] constexpr float SquaredLength() const noexcept;
|
||||
|
||||
//! Returns the dot product of the vector dotted with another vector
|
||||
/*!
|
||||
\param vec The second vector
|
||||
\return The dot product of the two vectors
|
||||
*/
|
||||
float DotProduct(const Vector3& vec) const;
|
||||
[[nodiscard]] constexpr float DotProduct(const Vector3& vec) const noexcept;
|
||||
|
||||
//! Returns the cross product of the vector crossed with another vector
|
||||
/*!
|
||||
\param vec The second vector
|
||||
\return The cross product of the two vectors
|
||||
*/
|
||||
Vector3 CrossProduct(const Vector3& vec) const;
|
||||
[[nodiscard]] constexpr Vector3 CrossProduct(const Vector3& vec) const noexcept;
|
||||
|
||||
//! Unitize the vector
|
||||
/*!
|
||||
\returns The current vector
|
||||
*/
|
||||
NiPoint3 Unitize(void) const;
|
||||
|
||||
[[nodiscard]] NiPoint3 Unitize() const;
|
||||
|
||||
// MARK: Operators
|
||||
|
||||
//! Operator to check for equality
|
||||
bool operator==(const NiPoint3& point) const;
|
||||
constexpr bool operator==(const NiPoint3& point) const noexcept;
|
||||
|
||||
//! Operator to check for inequality
|
||||
bool operator!=(const NiPoint3& point) const;
|
||||
constexpr bool operator!=(const NiPoint3& point) const noexcept;
|
||||
|
||||
//! Operator for subscripting
|
||||
float& operator[](int i);
|
||||
constexpr float& operator[](const int i) noexcept;
|
||||
|
||||
//! Operator for subscripting
|
||||
const float& operator[](int i) const;
|
||||
constexpr const float& operator[](const int i) const noexcept;
|
||||
|
||||
//! Operator for addition of vectors
|
||||
NiPoint3 operator+(const NiPoint3& point) const;
|
||||
constexpr NiPoint3 operator+(const NiPoint3& point) const noexcept;
|
||||
|
||||
//! Operator for addition of vectors
|
||||
NiPoint3& operator+=(const NiPoint3& point);
|
||||
constexpr NiPoint3& operator+=(const NiPoint3& point) noexcept;
|
||||
|
||||
NiPoint3& operator*=(const float scalar);
|
||||
constexpr NiPoint3& operator*=(const float scalar) noexcept;
|
||||
|
||||
//! Operator for subtraction of vectors
|
||||
NiPoint3 operator-(const NiPoint3& point) const;
|
||||
constexpr NiPoint3 operator-(const NiPoint3& point) const noexcept;
|
||||
|
||||
//! Operator for addition of a scalar on all vector components
|
||||
NiPoint3 operator+(float fScalar) const;
|
||||
constexpr NiPoint3 operator+(const float fScalar) const noexcept;
|
||||
|
||||
//! Operator for subtraction of a scalar on all vector components
|
||||
NiPoint3 operator-(float fScalar) const;
|
||||
constexpr NiPoint3 operator-(const float fScalar) const noexcept;
|
||||
|
||||
//! Operator for scalar multiplication of a vector
|
||||
NiPoint3 operator*(float fScalar) const;
|
||||
constexpr NiPoint3 operator*(const float fScalar) const noexcept;
|
||||
|
||||
//! Operator for scalar division of a vector
|
||||
NiPoint3 operator/(float fScalar) const;
|
||||
|
||||
constexpr NiPoint3 operator/(const float fScalar) const noexcept;
|
||||
|
||||
// MARK: Helper Functions
|
||||
|
||||
@@ -164,14 +160,14 @@ public:
|
||||
\param maxPoint The maximum point of the bounding box
|
||||
\return Whether or not this point lies within the box
|
||||
*/
|
||||
bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint);
|
||||
[[nodiscard]] constexpr bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) noexcept;
|
||||
|
||||
//! Checks to see if the point (or vector) is within a sphere
|
||||
/*!
|
||||
\param sphereCenter The sphere center
|
||||
\param radius The radius
|
||||
*/
|
||||
bool IsWithinSpehere(const NiPoint3& sphereCenter, float radius);
|
||||
[[nodiscard]] constexpr bool IsWithinSphere(const NiPoint3& sphereCenter, const float radius) noexcept;
|
||||
|
||||
/*!
|
||||
\param a Start of line
|
||||
@@ -179,15 +175,30 @@ public:
|
||||
\param p Refrence point
|
||||
\return The point of line AB which is closest to P
|
||||
*/
|
||||
static NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p);
|
||||
[[nodiscard]] static constexpr NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) noexcept;
|
||||
|
||||
static float Angle(const NiPoint3& a, const NiPoint3& b);
|
||||
[[nodiscard]] static float Angle(const NiPoint3& a, const NiPoint3& b);
|
||||
|
||||
static float Distance(const NiPoint3& a, const NiPoint3& b);
|
||||
[[nodiscard]] static float Distance(const NiPoint3& a, const NiPoint3& b);
|
||||
|
||||
static float DistanceSquared(const NiPoint3& a, const NiPoint3& b);
|
||||
[[nodiscard]] static constexpr float DistanceSquared(const NiPoint3& a, const NiPoint3& b) noexcept;
|
||||
|
||||
static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta);
|
||||
[[nodiscard]] static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, const float maxDistanceDelta);
|
||||
|
||||
NiPoint3 RotateByQuaternion(const NiQuaternion& rotation);
|
||||
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible.
|
||||
[[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__
|
||||
|
||||
196
dCommon/NiPoint3.inl
Normal file
196
dCommon/NiPoint3.inl
Normal file
@@ -0,0 +1,196 @@
|
||||
#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;
|
||||
}
|
||||
@@ -3,89 +3,8 @@
|
||||
// C++
|
||||
#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
|
||||
|
||||
//! 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 angles;
|
||||
|
||||
@@ -111,22 +30,9 @@ Vector3 NiQuaternion::GetEulerAngles() const {
|
||||
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
|
||||
|
||||
//! Look from a specific point in space to another point in space
|
||||
//! Look from a specific point in space to another point in space (Y-locked)
|
||||
NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
|
||||
//To make sure we don't orient around the X/Z axis:
|
||||
NiPoint3 source = sourcePoint;
|
||||
@@ -136,7 +42,7 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
|
||||
|
||||
NiPoint3 forwardVector = NiPoint3(dest - source).Unitize();
|
||||
|
||||
NiPoint3 posZ = NiPoint3::UNIT_Z;
|
||||
NiPoint3 posZ = NiPoint3Constant::UNIT_Z;
|
||||
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
|
||||
|
||||
float dot = posZ.DotProduct(forwardVector);
|
||||
@@ -148,10 +54,11 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
|
||||
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) {
|
||||
NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize();
|
||||
|
||||
NiPoint3 posZ = NiPoint3::UNIT_Z;
|
||||
NiPoint3 posZ = NiPoint3Constant::UNIT_Z;
|
||||
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
|
||||
|
||||
float dot = posZ.DotProduct(forwardVector);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef __NIQUATERNION_H__
|
||||
#define __NIQUATERNION_H__
|
||||
|
||||
// Custom Classes
|
||||
#include "NiPoint3.h"
|
||||
@@ -14,14 +15,14 @@ typedef NiQuaternion Quaternion; //!< A typedef for a shorthand version o
|
||||
//! A class that defines a rotation in space
|
||||
class NiQuaternion {
|
||||
public:
|
||||
float w; //!< The w coordinate
|
||||
float x; //!< The x coordinate
|
||||
float y; //!< The y coordinate
|
||||
float z; //!< The z coordinate
|
||||
float w{ 1 }; //!< The w coordinate
|
||||
float x{ 0 }; //!< The x coordinate
|
||||
float y{ 0 }; //!< The y coordinate
|
||||
float z{ 0 }; //!< The z coordinate
|
||||
|
||||
|
||||
//! The initializer
|
||||
NiQuaternion(void);
|
||||
constexpr NiQuaternion() = default;
|
||||
|
||||
//! The initializer
|
||||
/*!
|
||||
@@ -30,13 +31,12 @@ public:
|
||||
\param y The y coordinate
|
||||
\param z The z coordinate
|
||||
*/
|
||||
NiQuaternion(float w, float x, float y, float z);
|
||||
|
||||
//! Destructor
|
||||
~NiQuaternion(void);
|
||||
|
||||
// MARK: Constants
|
||||
static const NiQuaternion IDENTITY; //!< Quaternion(1, 0, 0, 0)
|
||||
constexpr NiQuaternion(const float w, const float x, const float y, const float z) noexcept
|
||||
: w{ w }
|
||||
, x{ x }
|
||||
, y{ y }
|
||||
, z{ z } {
|
||||
}
|
||||
|
||||
// MARK: Setters / Getters
|
||||
|
||||
@@ -44,50 +44,49 @@ public:
|
||||
/*!
|
||||
\return The w coordinate
|
||||
*/
|
||||
float GetW(void) const;
|
||||
[[nodiscard]] constexpr float GetW() const noexcept;
|
||||
|
||||
//! Sets the W coordinate
|
||||
/*!
|
||||
\param w The w coordinate
|
||||
*/
|
||||
void SetW(float w);
|
||||
constexpr void SetW(const float w) noexcept;
|
||||
|
||||
//! Gets the X coordinate
|
||||
/*!
|
||||
\return The x coordinate
|
||||
*/
|
||||
float GetX(void) const;
|
||||
[[nodiscard]] constexpr float GetX() const noexcept;
|
||||
|
||||
//! Sets the X coordinate
|
||||
/*!
|
||||
\param x The x coordinate
|
||||
*/
|
||||
void SetX(float x);
|
||||
constexpr void SetX(const float x) noexcept;
|
||||
|
||||
//! Gets the Y coordinate
|
||||
/*!
|
||||
\return The y coordinate
|
||||
*/
|
||||
float GetY(void) const;
|
||||
[[nodiscard]] constexpr float GetY() const noexcept;
|
||||
|
||||
//! Sets the Y coordinate
|
||||
/*!
|
||||
\param y The y coordinate
|
||||
*/
|
||||
void SetY(float y);
|
||||
constexpr void SetY(const float y) noexcept;
|
||||
|
||||
//! Gets the Z coordinate
|
||||
/*!
|
||||
\return The z coordinate
|
||||
*/
|
||||
float GetZ(void) const;
|
||||
[[nodiscard]] constexpr float GetZ() const noexcept;
|
||||
|
||||
//! Sets the Z coordinate
|
||||
/*!
|
||||
\param z The z coordinate
|
||||
*/
|
||||
void SetZ(float z);
|
||||
|
||||
constexpr void SetZ(const float z) noexcept;
|
||||
|
||||
// MARK: Member Functions
|
||||
|
||||
@@ -95,31 +94,29 @@ public:
|
||||
/*!
|
||||
\return The forward vector of the quaternion
|
||||
*/
|
||||
Vector3 GetForwardVector(void) const;
|
||||
[[nodiscard]] constexpr Vector3 GetForwardVector() const noexcept;
|
||||
|
||||
//! Returns the up vector from the quaternion
|
||||
/*!
|
||||
\return The up vector fo the quaternion
|
||||
*/
|
||||
Vector3 GetUpVector(void) const;
|
||||
[[nodiscard]] constexpr Vector3 GetUpVector() const noexcept;
|
||||
|
||||
//! Returns the right vector from the quaternion
|
||||
/*!
|
||||
\return The right vector of the quaternion
|
||||
*/
|
||||
Vector3 GetRightVector(void) const;
|
||||
|
||||
Vector3 GetEulerAngles() const;
|
||||
[[nodiscard]] constexpr Vector3 GetRightVector() const noexcept;
|
||||
|
||||
[[nodiscard]] Vector3 GetEulerAngles() const;
|
||||
|
||||
// MARK: Operators
|
||||
|
||||
//! Operator to check for equality
|
||||
bool operator==(const NiQuaternion& rot) const;
|
||||
constexpr bool operator==(const NiQuaternion& rot) const noexcept;
|
||||
|
||||
//! Operator to check for inequality
|
||||
bool operator!=(const NiQuaternion& rot) const;
|
||||
|
||||
constexpr bool operator!=(const NiQuaternion& rot) const noexcept;
|
||||
|
||||
// MARK: Helper Functions
|
||||
|
||||
@@ -129,7 +126,7 @@ public:
|
||||
\param destPoint The destination location
|
||||
\return The Quaternion with the rotation towards the destination
|
||||
*/
|
||||
static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
|
||||
[[nodiscard]] static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
|
||||
|
||||
//! Look from a specific point in space to another point in space
|
||||
/*!
|
||||
@@ -137,7 +134,7 @@ public:
|
||||
\param destPoint The destination location
|
||||
\return The Quaternion with the rotation towards the destination
|
||||
*/
|
||||
static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
|
||||
[[nodiscard]] static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
|
||||
|
||||
//! Creates a Quaternion from a specific axis and angle relative to that axis
|
||||
/*!
|
||||
@@ -145,7 +142,17 @@ public:
|
||||
\param angle The angle relative to this axis
|
||||
\return A quaternion created from the axis and angle
|
||||
*/
|
||||
static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);
|
||||
[[nodiscard]] static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);
|
||||
|
||||
static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles);
|
||||
[[nodiscard]] 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__
|
||||
|
||||
75
dCommon/NiQuaternion.inl
Normal file
75
dCommon/NiQuaternion.inl
Normal file
@@ -0,0 +1,75 @@
|
||||
#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);
|
||||
}
|
||||
36
dCommon/PositionUpdate.h
Normal file
36
dCommon/PositionUpdate.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef __POSITIONUPDATE__H__
|
||||
#define __POSITIONUPDATE__H__
|
||||
|
||||
#include "NiPoint3.h"
|
||||
#include "NiQuaternion.h"
|
||||
|
||||
|
||||
struct RemoteInputInfo {
|
||||
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;
|
||||
}
|
||||
|
||||
float m_RemoteInputX = 0;
|
||||
float m_RemoteInputY = 0;
|
||||
bool m_IsPowersliding = false;
|
||||
bool m_IsModified = false;
|
||||
};
|
||||
|
||||
struct LocalSpaceInfo {
|
||||
LWOOBJID objectId = LWOOBJID_EMPTY;
|
||||
NiPoint3 position = NiPoint3Constant::ZERO;
|
||||
NiPoint3 linearVelocity = NiPoint3Constant::ZERO;
|
||||
};
|
||||
|
||||
struct PositionUpdate {
|
||||
NiPoint3 position = NiPoint3Constant::ZERO;
|
||||
NiQuaternion rotation = NiQuaternionConstant::IDENTITY;
|
||||
bool onGround = false;
|
||||
bool onRail = false;
|
||||
NiPoint3 velocity = NiPoint3Constant::ZERO;
|
||||
NiPoint3 angularVelocity = NiPoint3Constant::ZERO;
|
||||
LocalSpaceInfo localSpaceInfo;
|
||||
RemoteInputInfo remoteInputInfo;
|
||||
};
|
||||
|
||||
#endif //!__POSITIONUPDATE__H__
|
||||
@@ -1,154 +0,0 @@
|
||||
// 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);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
#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); \
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
set(DCOMMON_DCLIENT_SOURCES
|
||||
"AssetManager.cpp"
|
||||
"PackIndex.cpp"
|
||||
"Pack.cpp"
|
||||
"AssetManager.cpp"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
12
dCommon/dClient/ClientVersion.h
Normal file
12
dCommon/dClient/ClientVersion.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#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__
|
||||
@@ -9,15 +9,15 @@ namespace StringifiedEnum {
|
||||
const std::string_view ToString(const T e) {
|
||||
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(
|
||||
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; }
|
||||
);
|
||||
|
||||
std::string_view output;
|
||||
if (it != sv->end() && it->first == e) {
|
||||
if (it != sv.end() && it->first == e) {
|
||||
output = it->second;
|
||||
} else {
|
||||
output = "UNKNOWN";
|
||||
|
||||
@@ -34,91 +34,89 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
|
||||
#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 CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
||||
#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
|
||||
#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false);
|
||||
#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
|
||||
//=========== TYPEDEFS ==========
|
||||
|
||||
typedef int32_t LOT; //!< A LOT
|
||||
typedef int64_t LWOOBJID; //!< An object ID (should be unsigned actually but ok)
|
||||
typedef int32_t TSkillID; //!< A skill ID
|
||||
typedef uint32_t LWOCLONEID; //!< Used for Clone IDs
|
||||
typedef uint16_t LWOMAPID; //!< Used for Map IDs
|
||||
typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs
|
||||
typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs
|
||||
typedef uint32_t StripId;
|
||||
using LOT = int32_t; //!< A LOT
|
||||
using LWOOBJID = int64_t; //!< An object ID (should be unsigned actually but ok)
|
||||
using TSkillID = int32_t; //!< A skill ID
|
||||
using LWOCLONEID = uint32_t; //!< Used for Clone IDs
|
||||
using LWOMAPID = uint16_t; //!< Used for Map IDs
|
||||
using LWOINSTANCEID = uint16_t; //!< Used for Instance IDs
|
||||
using PROPERTYCLONELIST = uint32_t; //!< Used for Property Clone IDs
|
||||
using StripId = uint32_t;
|
||||
|
||||
const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID
|
||||
const LOT LOT_NULL = -1; //!< A null LOT
|
||||
const int32_t LOOTTYPE_NONE = 0; //!< No loot type available
|
||||
const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority
|
||||
const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size
|
||||
const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
|
||||
const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
|
||||
const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
|
||||
const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
|
||||
constexpr LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID
|
||||
constexpr LOT LOT_NULL = -1; //!< A null LOT
|
||||
constexpr int32_t LOOTTYPE_NONE = 0; //!< No loot type available
|
||||
constexpr float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority
|
||||
constexpr uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size
|
||||
constexpr LWOCLONEID LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
|
||||
constexpr LWOINSTANCEID LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
|
||||
constexpr LWOMAPID LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
|
||||
constexpr uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
|
||||
|
||||
const float PI = 3.14159f;
|
||||
constexpr float PI = 3.14159f;
|
||||
|
||||
//============ STRUCTS ==============
|
||||
|
||||
struct LWOSCENEID {
|
||||
public:
|
||||
LWOSCENEID() { m_sceneID = -1; m_layerID = 0; }
|
||||
LWOSCENEID(int sceneID) { m_sceneID = sceneID; m_layerID = 0; }
|
||||
LWOSCENEID(int sceneID, unsigned int layerID) { m_sceneID = sceneID; m_layerID = layerID; }
|
||||
constexpr LWOSCENEID() noexcept { m_sceneID = -1; m_layerID = 0; }
|
||||
constexpr LWOSCENEID(int32_t sceneID) noexcept { m_sceneID = sceneID; m_layerID = 0; }
|
||||
constexpr LWOSCENEID(int32_t sceneID, uint32_t layerID) noexcept { m_sceneID = sceneID; m_layerID = layerID; }
|
||||
|
||||
LWOSCENEID& operator=(const LWOSCENEID& rhs) { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; }
|
||||
LWOSCENEID& operator=(const int rhs) { m_sceneID = rhs; m_layerID = 0; return *this; }
|
||||
constexpr LWOSCENEID& operator=(const LWOSCENEID& rhs) noexcept { 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; }
|
||||
|
||||
bool operator<(const LWOSCENEID& rhs) const { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); }
|
||||
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_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 LWOSCENEID& rhs) const { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); }
|
||||
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); }
|
||||
constexpr bool operator==(const int32_t rhs) const noexcept { return m_sceneID == rhs; }
|
||||
|
||||
const int GetSceneID() const { return m_sceneID; }
|
||||
const unsigned int GetLayerID() const { return m_layerID; }
|
||||
constexpr int32_t GetSceneID() const noexcept { return m_sceneID; }
|
||||
constexpr uint32_t GetLayerID() const noexcept { return m_layerID; }
|
||||
|
||||
void SetSceneID(const int sceneID) { m_sceneID = sceneID; }
|
||||
void SetLayerID(const unsigned int layerID) { m_layerID = layerID; }
|
||||
constexpr void SetSceneID(const int32_t sceneID) noexcept { m_sceneID = sceneID; }
|
||||
constexpr void SetLayerID(const uint32_t layerID) noexcept { m_layerID = layerID; }
|
||||
|
||||
private:
|
||||
int m_sceneID;
|
||||
unsigned int m_layerID;
|
||||
int32_t m_sceneID;
|
||||
uint32_t m_layerID;
|
||||
};
|
||||
|
||||
struct LWOZONEID {
|
||||
public:
|
||||
const LWOMAPID& GetMapID() const { return m_MapID; }
|
||||
const LWOINSTANCEID& GetInstanceID() const { return m_InstanceID; }
|
||||
const LWOCLONEID& GetCloneID() const { return m_CloneID; }
|
||||
constexpr const LWOMAPID& GetMapID() const noexcept { return m_MapID; }
|
||||
constexpr const LWOINSTANCEID& GetInstanceID() const noexcept { return m_InstanceID; }
|
||||
constexpr const LWOCLONEID& GetCloneID() const noexcept { return m_CloneID; }
|
||||
|
||||
//In order: def constr, constr, assign op
|
||||
LWOZONEID() { m_MapID = LWOMAPID_INVALID; m_InstanceID = LWOINSTANCEID_INVALID; m_CloneID = LWOCLONEID_INVALID; }
|
||||
LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; }
|
||||
LWOZONEID(const LWOZONEID& replacement) { *this = replacement; }
|
||||
constexpr LWOZONEID() noexcept = default;
|
||||
constexpr LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) noexcept { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; }
|
||||
constexpr LWOZONEID(const LWOZONEID& replacement) noexcept { *this = replacement; }
|
||||
|
||||
private:
|
||||
LWOMAPID m_MapID; //1000 for VE, 1100 for AG, etc...
|
||||
LWOINSTANCEID m_InstanceID; //Instances host the same world, but on a different dWorld process.
|
||||
LWOCLONEID m_CloneID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds.
|
||||
LWOMAPID m_MapID = LWOMAPID_INVALID; //1000 for VE, 1100 for AG, etc...
|
||||
LWOINSTANCEID m_InstanceID = LWOINSTANCEID_INVALID; //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.
|
||||
};
|
||||
|
||||
const LWOSCENEID LWOSCENEID_INVALID = -1;
|
||||
constexpr LWOSCENEID LWOSCENEID_INVALID = -1;
|
||||
|
||||
struct LWONameValue {
|
||||
uint32_t length = 0; //!< The length of the name
|
||||
std::u16string name; //!< The name
|
||||
|
||||
LWONameValue(void) {}
|
||||
LWONameValue() = default;
|
||||
|
||||
LWONameValue(const std::u16string& name) {
|
||||
this->name = name;
|
||||
this->length = static_cast<uint32_t>(name.length());
|
||||
}
|
||||
|
||||
~LWONameValue(void) {}
|
||||
};
|
||||
|
||||
struct FriendData {
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
#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__
|
||||
@@ -72,7 +72,9 @@ enum class eChatMessageType :uint32_t {
|
||||
UPDATE_DONATION,
|
||||
PRG_CSR_COMMAND,
|
||||
HEARTBEAT_REQUEST_FROM_WORLD,
|
||||
UPDATE_FREE_TRIAL_STATUS
|
||||
UPDATE_FREE_TRIAL_STATUS,
|
||||
// CUSTOM DLU MESSAGE ID FOR INTERNAL USE
|
||||
CREATE_TEAM,
|
||||
};
|
||||
|
||||
#endif //!__ECHATMESSAGETYPE__H__
|
||||
|
||||
@@ -5,8 +5,7 @@ enum class eConnectionType : uint16_t {
|
||||
SERVER = 0,
|
||||
AUTH,
|
||||
CHAT,
|
||||
CHAT_INTERNAL,
|
||||
WORLD,
|
||||
WORLD = 4,
|
||||
CLIENT,
|
||||
MASTER
|
||||
};
|
||||
|
||||
@@ -629,7 +629,7 @@ enum class eGameMessageType : uint16_t {
|
||||
GET_INSTRUCTION_COUNT = 676,
|
||||
GET_IS_NPC = 677,
|
||||
ACTIVATE_BUBBLE_BUFF = 678,
|
||||
DECTIVATE_BUBBLE_BUFF = 679, // thanks netdevil
|
||||
DECTIVATE_BUBBLE_BUFF = 679, // This is spelled wrong in the client, so we misspell it here.
|
||||
EXHIBIT_VOTE = 680,
|
||||
ADD_PET_TO_PLAYER = 681,
|
||||
REMOVE_PET_FROM_PLAYER = 682,
|
||||
@@ -790,9 +790,10 @@ enum class eGameMessageType : uint16_t {
|
||||
GET_MISSION_TYPE_STATES = 853,
|
||||
GET_TIME_PLAYED = 854,
|
||||
SET_MISSION_VIEWED = 855,
|
||||
SLASH_COMMAND_TEXT_FEEDBACK = 856,
|
||||
HANDLE_SLASH_COMMAND_KORE_DEBUGGER = 857,
|
||||
HKX_VEHICLE_LOADED = 856,
|
||||
SLASH_COMMAND_TEXT_FEEDBACK = 857,
|
||||
BROADCAST_TEXT_TO_CHATBOX = 858,
|
||||
HANDLE_SLASH_COMMAND_KORE_DEBUGGER = 859,
|
||||
OPEN_PROPERTY_MANAGEMENT = 860,
|
||||
OPEN_PROPERTY_VENDOR = 861,
|
||||
VOTE_ON_PROPERTY = 862,
|
||||
|
||||
13
dCommon/dEnums/ePetAbilityType.h
Normal file
13
dCommon/dEnums/ePetAbilityType.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __EPETABILITYTYPE__H__
|
||||
#define __EPETABILITYTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class ePetAbilityType : uint32_t {
|
||||
Invalid,
|
||||
GoToObject,
|
||||
JumpOnObject,
|
||||
DigAtPosition
|
||||
};
|
||||
|
||||
#endif //!__EPETABILITYTYPE__H__
|
||||
@@ -106,7 +106,7 @@ enum class eReplicaComponentType : uint32_t {
|
||||
INTERACTION_MANAGER,
|
||||
DONATION_VENDOR,
|
||||
COMBAT_MEDIATOR,
|
||||
COMMENDATION_VENDOR,
|
||||
ACHIEVEMENT_VENDOR,
|
||||
GATE_RUSH_CONTROL,
|
||||
RAIL_ACTIVATOR,
|
||||
ROLLER,
|
||||
|
||||
15
dCommon/dEnums/eVendorTransactionResult.h
Normal file
15
dCommon/dEnums/eVendorTransactionResult.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#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__
|
||||
59
dCommon/dEnums/eWaypointCommandType.h
Normal file
59
dCommon/dEnums/eWaypointCommandType.h
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
#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__
|
||||
@@ -29,8 +29,8 @@ enum class eWorldMessageType : uint32_t {
|
||||
ROUTE_PACKET, // Social?
|
||||
POSITION_UPDATE,
|
||||
MAIL,
|
||||
WORD_CHECK, // Whitelist word check
|
||||
STRING_CHECK, // Whitelist string check
|
||||
WORD_CHECK, // AllowList word check
|
||||
STRING_CHECK, // AllowList string check
|
||||
GET_PLAYERS_IN_ZONE,
|
||||
REQUEST_UGC_MANIFEST_INFO,
|
||||
BLUEPRINT_GET_ALL_DATA_REQUEST,
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
// Static Variables
|
||||
static CppSQLite3DB* conn = new CppSQLite3DB();
|
||||
|
||||
// Status Variables
|
||||
bool CDClientDatabase::isConnected = false;
|
||||
|
||||
//! Opens a connection with the CDClient
|
||||
void CDClientDatabase::Connect(const std::string& filename) {
|
||||
conn->open(filename.c_str());
|
||||
isConnected = true;
|
||||
}
|
||||
|
||||
//! Queries the CDClient
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
|
||||
//! The CDClient Database namespace
|
||||
namespace CDClientDatabase {
|
||||
/**
|
||||
* Boolean defining the connection status of CDClient
|
||||
*/
|
||||
extern bool isConnected;
|
||||
|
||||
//! Opens a connection with the CDClient
|
||||
/*!
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "CDAnimationsTable.h"
|
||||
#include "CDBehaviorParameterTable.h"
|
||||
#include "CDBehaviorTemplateTable.h"
|
||||
#include "CDClientDatabase.h"
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
#include "CDCurrencyTableTable.h"
|
||||
#include "CDDestructibleComponentTable.h"
|
||||
@@ -24,6 +25,7 @@
|
||||
#include "CDScriptComponentTable.h"
|
||||
#include "CDSkillBehaviorTable.h"
|
||||
#include "CDZoneTableTable.h"
|
||||
#include "CDTamingBuildPuzzleTable.h"
|
||||
#include "CDVendorComponentTable.h"
|
||||
#include "CDActivitiesTable.h"
|
||||
#include "CDPackageComponentTable.h"
|
||||
@@ -38,6 +40,7 @@
|
||||
#include "CDFeatureGatingTable.h"
|
||||
#include "CDRailActivatorComponent.h"
|
||||
#include "CDRewardCodesTable.h"
|
||||
#include "CDPetComponentTable.h"
|
||||
|
||||
#ifndef CDCLIENT_CACHE_ALL
|
||||
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
|
||||
@@ -51,7 +54,61 @@
|
||||
#define CDCLIENT_DONT_CACHE_TABLE(x)
|
||||
#endif
|
||||
|
||||
CDClientManager::CDClientManager() {
|
||||
// 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(CDTamingBuildPuzzleTable);
|
||||
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
|
||||
DEFINE_TABLE_STORAGE(CDZoneTableTable);
|
||||
|
||||
void CDClientManager::LoadValuesFromDatabase() {
|
||||
if (!CDClientDatabase::isConnected) {
|
||||
throw std::runtime_error{ "CDClientDatabase is not connected!" };
|
||||
}
|
||||
|
||||
CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
|
||||
CDActivitiesTable::Instance().LoadValuesFromDatabase();
|
||||
CDCLIENT_DONT_CACHE_TABLE(CDAnimationsTable::Instance().LoadValuesFromDatabase());
|
||||
@@ -79,6 +136,7 @@ CDClientManager::CDClientManager() {
|
||||
CDCLIENT_DONT_CACHE_TABLE(CDObjectsTable::Instance().LoadValuesFromDatabase());
|
||||
CDPhysicsComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDPackageComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDPetComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDProximityMonitorComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDPropertyEntranceComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDPropertyTemplateTable::Instance().LoadValuesFromDatabase();
|
||||
@@ -89,6 +147,13 @@ CDClientManager::CDClientManager() {
|
||||
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
||||
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
||||
CDTamingBuildPuzzleTable::Instance().LoadValuesFromDatabase();
|
||||
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDZoneTableTable::Instance().LoadValuesFromDatabase();
|
||||
}
|
||||
|
||||
void CDClientManager::LoadValuesFromDefaults() {
|
||||
LOG("Loading default CDClient tables!");
|
||||
|
||||
CDPetComponentTable::Instance().LoadValuesFromDefaults();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "CDTable.h"
|
||||
|
||||
#include "Singleton.h"
|
||||
#ifndef __CDCLIENTMANAGER__H__
|
||||
#define __CDCLIENTMANAGER__H__
|
||||
|
||||
#define UNUSED_TABLE(v)
|
||||
|
||||
/**
|
||||
* Initialize the CDClient tables so they are all loaded into memory.
|
||||
*/
|
||||
class CDClientManager : public Singleton<CDClientManager> {
|
||||
public:
|
||||
CDClientManager();
|
||||
namespace CDClientManager {
|
||||
void LoadValuesFromDatabase();
|
||||
void LoadValuesFromDefaults();
|
||||
|
||||
/**
|
||||
* Fetch a table from CDClient
|
||||
@@ -20,7 +17,28 @@ public:
|
||||
* @return A pointer to the requested table.
|
||||
*/
|
||||
template<typename T>
|
||||
T* GetTable() {
|
||||
return &T::Instance();
|
||||
}
|
||||
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();
|
||||
};
|
||||
|
||||
#endif //!__CDCLIENTMANAGER__H__
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "CDActivitiesTable.h"
|
||||
|
||||
|
||||
void CDActivitiesTable::LoadValuesFromDatabase() {
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Activities");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -13,7 +14,8 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities");
|
||||
@@ -39,7 +41,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
|
||||
entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1);
|
||||
entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -48,7 +50,7 @@ void CDActivitiesTable::LoadValuesFromDatabase() {
|
||||
|
||||
std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) {
|
||||
|
||||
std::vector<CDActivities> data = cpplinq::from(this->entries)
|
||||
std::vector<CDActivities> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
|
||||
@@ -4,36 +4,31 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDActivities {
|
||||
unsigned int ActivityID;
|
||||
unsigned int locStatus;
|
||||
unsigned int instanceMapID;
|
||||
unsigned int minTeams;
|
||||
unsigned int maxTeams;
|
||||
unsigned int minTeamSize;
|
||||
unsigned int maxTeamSize;
|
||||
unsigned int waitTime;
|
||||
unsigned int startDelay;
|
||||
uint32_t ActivityID;
|
||||
uint32_t locStatus;
|
||||
uint32_t instanceMapID;
|
||||
uint32_t minTeams;
|
||||
uint32_t maxTeams;
|
||||
uint32_t minTeamSize;
|
||||
uint32_t maxTeamSize;
|
||||
uint32_t waitTime;
|
||||
uint32_t startDelay;
|
||||
bool requiresUniqueData;
|
||||
unsigned int leaderboardType;
|
||||
uint32_t leaderboardType;
|
||||
bool localize;
|
||||
int optionalCostLOT;
|
||||
int optionalCostCount;
|
||||
int32_t optionalCostLOT;
|
||||
int32_t optionalCostCount;
|
||||
bool showUIRewards;
|
||||
unsigned int CommunityActivityFlagID;
|
||||
uint32_t CommunityActivityFlagID;
|
||||
std::string gate_version;
|
||||
bool noTeamLootOnDeath;
|
||||
float optionalPercentage;
|
||||
};
|
||||
|
||||
class CDActivitiesTable : public CDTable<CDActivitiesTable> {
|
||||
private:
|
||||
std::vector<CDActivities> entries;
|
||||
|
||||
class CDActivitiesTable : public CDTable<CDActivitiesTable, std::vector<CDActivities>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDActivities> Query(std::function<bool(CDActivities)> predicate);
|
||||
|
||||
const std::vector<CDActivities>& GetEntries() const { return this->entries; }
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "CDActivityRewardsTable.h"
|
||||
|
||||
|
||||
void CDActivityRewardsTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ActivityRewards");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,7 +15,8 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards");
|
||||
@@ -28,7 +30,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
|
||||
entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1);
|
||||
entry.description = tableData.getStringField("description", "");
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -37,7 +39,7 @@ void CDActivityRewardsTable::LoadValuesFromDatabase() {
|
||||
|
||||
std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) {
|
||||
|
||||
std::vector<CDActivityRewards> data = cpplinq::from(this->entries)
|
||||
std::vector<CDActivityRewards> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
|
||||
@@ -4,24 +4,18 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDActivityRewards {
|
||||
unsigned int objectTemplate; //!< The object template (?)
|
||||
unsigned int ActivityRewardIndex; //!< The activity reward index
|
||||
int activityRating; //!< The activity rating
|
||||
unsigned int LootMatrixIndex; //!< The loot matrix index
|
||||
unsigned int CurrencyIndex; //!< The currency index
|
||||
unsigned int ChallengeRating; //!< The challenge rating
|
||||
uint32_t objectTemplate; //!< The object template (?)
|
||||
uint32_t ActivityRewardIndex; //!< The activity reward index
|
||||
int32_t activityRating; //!< The activity rating
|
||||
uint32_t LootMatrixIndex; //!< The loot matrix index
|
||||
uint32_t CurrencyIndex; //!< The currency index
|
||||
uint32_t ChallengeRating; //!< The challenge rating
|
||||
std::string description; //!< The description
|
||||
};
|
||||
|
||||
class CDActivityRewardsTable : public CDTable<CDActivityRewardsTable> {
|
||||
private:
|
||||
std::vector<CDActivityRewards> entries;
|
||||
|
||||
class CDActivityRewardsTable : public CDTable<CDActivityRewardsTable, std::vector<CDActivityRewards>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate);
|
||||
|
||||
std::vector<CDActivityRewards> GetEntries() const;
|
||||
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
void CDAnimationsTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations");
|
||||
auto& animations = GetEntriesMutable();
|
||||
while (!tableData.eof()) {
|
||||
std::string animation_type = tableData.getStringField("animation_type", "");
|
||||
DluAssert(!animation_type.empty());
|
||||
@@ -24,7 +25,7 @@ void CDAnimationsTable::LoadValuesFromDatabase() {
|
||||
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
|
||||
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
|
||||
|
||||
this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
|
||||
animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -35,6 +36,7 @@ bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
|
||||
auto tableData = queryToCache.execQuery();
|
||||
// If we received a bad lookup, cache it anyways so we do not run the query again.
|
||||
if (tableData.eof()) return false;
|
||||
auto& animations = GetEntriesMutable();
|
||||
|
||||
do {
|
||||
std::string animation_type = tableData.getStringField("animation_type", "");
|
||||
@@ -55,7 +57,7 @@ bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
|
||||
UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
|
||||
UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
|
||||
|
||||
this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
|
||||
animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
|
||||
tableData.nextRow();
|
||||
} while (!tableData.eof());
|
||||
|
||||
@@ -68,15 +70,17 @@ void CDAnimationsTable::CacheAnimations(const CDAnimationKey animationKey) {
|
||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?");
|
||||
query.bind(1, static_cast<int32_t>(animationKey.second));
|
||||
query.bind(2, animationKey.first.c_str());
|
||||
auto& animations = GetEntriesMutable();
|
||||
// If we received a bad lookup, cache it anyways so we do not run the query again.
|
||||
if (!CacheData(query)) {
|
||||
this->animations[animationKey];
|
||||
animations[animationKey];
|
||||
}
|
||||
}
|
||||
|
||||
void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
|
||||
auto animationEntryCached = this->animations.find(CDAnimationKey("", animationGroupID));
|
||||
if (animationEntryCached != this->animations.end()) {
|
||||
auto& animations = GetEntriesMutable();
|
||||
auto animationEntryCached = animations.find(CDAnimationKey("", animationGroupID));
|
||||
if (animationEntryCached != animations.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,28 +89,29 @@ void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
|
||||
|
||||
// Cache the query so we don't run the query again.
|
||||
CacheData(query);
|
||||
this->animations[CDAnimationKey("", animationGroupID)];
|
||||
animations[CDAnimationKey("", animationGroupID)];
|
||||
}
|
||||
|
||||
CDAnimationLookupResult CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) {
|
||||
std::optional<CDAnimation> CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) {
|
||||
auto& animations = GetEntriesMutable();
|
||||
CDAnimationKey animationKey(animationType, animationGroupID);
|
||||
auto animationEntryCached = this->animations.find(animationKey);
|
||||
if (animationEntryCached == this->animations.end()) {
|
||||
auto animationEntryCached = animations.find(animationKey);
|
||||
if (animationEntryCached == animations.end()) {
|
||||
this->CacheAnimations(animationKey);
|
||||
}
|
||||
|
||||
auto animationEntry = this->animations.find(animationKey);
|
||||
auto animationEntry = animations.find(animationKey);
|
||||
// If we have only one animation, return it regardless of the chance to play.
|
||||
if (animationEntry->second.size() == 1) {
|
||||
return CDAnimationLookupResult(animationEntry->second.front());
|
||||
return animationEntry->second.front();
|
||||
}
|
||||
auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1);
|
||||
|
||||
for (auto& animationEntry : animationEntry->second) {
|
||||
randomAnimation -= animationEntry.chance_to_play;
|
||||
// This is how the client gets the random animation.
|
||||
if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return CDAnimationLookupResult(animationEntry);
|
||||
if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return animationEntry;
|
||||
}
|
||||
|
||||
return CDAnimationLookupResult();
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,20 @@
|
||||
|
||||
#include "CDTable.h"
|
||||
#include <list>
|
||||
#include <optional>
|
||||
|
||||
typedef int32_t AnimationGroupID;
|
||||
typedef std::string AnimationID;
|
||||
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
|
||||
|
||||
struct CDAnimation {
|
||||
// unsigned int animationGroupID;
|
||||
// uint32_t animationGroupID;
|
||||
// std::string animation_type;
|
||||
// The above two are a pair to represent a primary key in the map.
|
||||
std::string animation_name; //!< The animation name
|
||||
float chance_to_play; //!< The chance to play the animation
|
||||
UNUSED_COLUMN(unsigned int min_loops;) //!< The minimum number of loops
|
||||
UNUSED_COLUMN(unsigned int max_loops;) //!< The maximum number of loops
|
||||
UNUSED_COLUMN(uint32_t min_loops;) //!< The minimum number of loops
|
||||
UNUSED_COLUMN(uint32_t max_loops;) //!< The maximum number of loops
|
||||
float animation_length; //!< The animation length
|
||||
UNUSED_COLUMN(bool hideEquip;) //!< Whether or not to hide the equip
|
||||
UNUSED_COLUMN(bool ignoreUpperBody;) //!< Whether or not to ignore the upper body
|
||||
@@ -20,12 +25,7 @@ struct CDAnimation {
|
||||
UNUSED_COLUMN(float blendTime;) //!< The blend time
|
||||
};
|
||||
|
||||
typedef LookupResult<CDAnimation> CDAnimationLookupResult;
|
||||
|
||||
class CDAnimationsTable : public CDTable<CDAnimationsTable> {
|
||||
typedef int32_t AnimationGroupID;
|
||||
typedef std::string AnimationID;
|
||||
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
|
||||
class CDAnimationsTable : public CDTable<CDAnimationsTable, std::map<CDAnimationKey, std::list<CDAnimation>>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
/**
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
* @param animationGroupID The animationGroupID to lookup
|
||||
* @return CDAnimationLookupResult
|
||||
*/
|
||||
[[nodiscard]] CDAnimationLookupResult GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID);
|
||||
[[nodiscard]] std::optional<CDAnimation> GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID);
|
||||
|
||||
/**
|
||||
* Cache a full AnimationGroup by its ID.
|
||||
@@ -58,10 +58,4 @@ private:
|
||||
* @return false
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#include "CDBehaviorParameterTable.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 key = behaviorID;
|
||||
key <<= 31U;
|
||||
@@ -11,6 +15,7 @@ uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
|
||||
|
||||
void CDBehaviorParameterTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
|
||||
auto& entries = GetEntriesMutable();
|
||||
while (!tableData.eof()) {
|
||||
uint32_t behaviorID = tableData.getIntField("behaviorID", -1);
|
||||
auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", ""));
|
||||
@@ -24,7 +29,7 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
|
||||
uint64_t hash = GetKey(behaviorID, parameterId);
|
||||
float value = tableData.getFloatField("value", -1.0f);
|
||||
|
||||
m_Entries.insert(std::make_pair(hash, value));
|
||||
entries.insert(std::make_pair(hash, value));
|
||||
|
||||
tableData.nextRow();
|
||||
}
|
||||
@@ -32,22 +37,24 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
|
||||
auto parameterID = this->m_ParametersList.find(name);
|
||||
if (parameterID == this->m_ParametersList.end()) return defaultValue;
|
||||
auto parameterID = m_ParametersList.find(name);
|
||||
if (parameterID == m_ParametersList.end()) return defaultValue;
|
||||
auto hash = GetKey(behaviorID, parameterID->second);
|
||||
|
||||
// Search for specific parameter
|
||||
auto it = m_Entries.find(hash);
|
||||
return it != m_Entries.end() ? it->second : defaultValue;
|
||||
auto& entries = GetEntriesMutable();
|
||||
auto it = entries.find(hash);
|
||||
return it != entries.end() ? it->second : defaultValue;
|
||||
}
|
||||
|
||||
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
uint64_t hashBase = behaviorID;
|
||||
std::map<std::string, float> returnInfo;
|
||||
for (auto& [parameterString, parameterId] : m_ParametersList) {
|
||||
uint64_t hash = GetKey(hashBase, parameterId);
|
||||
auto infoCandidate = m_Entries.find(hash);
|
||||
if (infoCandidate != m_Entries.end()) {
|
||||
auto infoCandidate = entries.find(hash);
|
||||
if (infoCandidate != entries.end()) {
|
||||
returnInfo.insert(std::make_pair(parameterString, infoCandidate->second));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,10 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable> {
|
||||
private:
|
||||
typedef uint64_t BehaviorParameterHash;
|
||||
typedef float BehaviorParameterValue;
|
||||
std::unordered_map<BehaviorParameterHash, BehaviorParameterValue> m_Entries;
|
||||
std::unordered_map<std::string, uint32_t> m_ParametersList;
|
||||
|
||||
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable, std::unordered_map<BehaviorParameterHash, BehaviorParameterValue>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#include "CDBehaviorTemplateTable.h"
|
||||
|
||||
namespace {
|
||||
std::unordered_set<std::string> m_EffectHandles;
|
||||
};
|
||||
|
||||
void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BehaviorTemplate");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -13,11 +17,9 @@ void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
|
||||
auto& entries = GetEntriesMutable();
|
||||
while (!tableData.eof()) {
|
||||
CDBehaviorTemplate entry;
|
||||
entry.behaviorID = tableData.getIntField("behaviorID", -1);
|
||||
@@ -31,30 +33,17 @@ void CDBehaviorTemplateTable::LoadValuesFromDatabase() {
|
||||
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
|
||||
}
|
||||
|
||||
this->entries.push_back(entry);
|
||||
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
|
||||
entries.insert(std::make_pair(entry.behaviorID, entry));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
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) {
|
||||
auto entry = this->entriesMappedByBehaviorID.find(behaviorID);
|
||||
if (entry == this->entriesMappedByBehaviorID.end()) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
auto entry = entries.find(behaviorID);
|
||||
if (entry == entries.end()) {
|
||||
CDBehaviorTemplate entryToReturn;
|
||||
entryToReturn.behaviorID = 0;
|
||||
entryToReturn.effectHandle = m_EffectHandles.end();
|
||||
|
||||
@@ -6,25 +6,15 @@
|
||||
#include <unordered_set>
|
||||
|
||||
struct CDBehaviorTemplate {
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
unsigned int templateID; //!< The Template ID (LOT)
|
||||
unsigned int effectID; //!< The Effect ID attached
|
||||
uint32_t behaviorID; //!< The Behavior ID
|
||||
uint32_t templateID; //!< The Template ID (LOT)
|
||||
uint32_t effectID; //!< The Effect ID attached
|
||||
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
|
||||
};
|
||||
|
||||
|
||||
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable> {
|
||||
private:
|
||||
std::vector<CDBehaviorTemplate> entries;
|
||||
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
|
||||
std::unordered_set<std::string> m_EffectHandles;
|
||||
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable, std::unordered_map<uint32_t, CDBehaviorTemplate>> {
|
||||
public:
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
void CDBrickIDTableTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BrickIDTable");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,7 +14,8 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable");
|
||||
@@ -23,7 +24,7 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
|
||||
entry.NDObjectID = tableData.getIntField("NDObjectID", -1);
|
||||
entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -31,15 +32,9 @@ void CDBrickIDTableTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) {
|
||||
|
||||
std::vector<CDBrickIDTable> data = cpplinq::from(this->entries)
|
||||
std::vector<CDBrickIDTable> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDBrickIDTable>& CDBrickIDTableTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,20 +10,15 @@
|
||||
|
||||
//! BrickIDTable Entry Struct
|
||||
struct CDBrickIDTable {
|
||||
unsigned int NDObjectID;
|
||||
unsigned int LEGOBrickID;
|
||||
uint32_t NDObjectID;
|
||||
uint32_t LEGOBrickID;
|
||||
};
|
||||
|
||||
|
||||
//! BrickIDTable table
|
||||
class CDBrickIDTableTable : public CDTable<CDBrickIDTableTable> {
|
||||
private:
|
||||
std::vector<CDBrickIDTable> entries;
|
||||
|
||||
class CDBrickIDTableTable : public CDTable<CDBrickIDTableTable, std::vector<CDBrickIDTable>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDBrickIDTable> Query(std::function<bool(CDBrickIDTable)> predicate);
|
||||
|
||||
const std::vector<CDBrickIDTable>& GetEntries() const;
|
||||
};
|
||||
|
||||
@@ -4,14 +4,15 @@
|
||||
void CDComponentsRegistryTable::LoadValuesFromDatabase() {
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry");
|
||||
auto& entries = GetEntriesMutable();
|
||||
while (!tableData.eof()) {
|
||||
CDComponentsRegistry entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
|
||||
entry.component_id = tableData.getIntField("component_id", -1);
|
||||
|
||||
this->mappedEntries.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(entry.id, 0);
|
||||
entries.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);
|
||||
|
||||
tableData.nextRow();
|
||||
}
|
||||
@@ -20,10 +21,11 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
|
||||
auto exists = mappedEntries.find(id);
|
||||
if (exists != mappedEntries.end()) {
|
||||
auto iter = mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
|
||||
return iter == mappedEntries.end() ? defaultValue : iter->second;
|
||||
auto& entries = GetEntriesMutable();
|
||||
auto exists = entries.find(id);
|
||||
if (exists != entries.end()) {
|
||||
auto iter = entries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
|
||||
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
|
||||
@@ -38,14 +40,14 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponent
|
||||
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
|
||||
entry.component_id = tableData.getIntField("component_id", -1);
|
||||
|
||||
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(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
|
||||
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
mappedEntries.insert_or_assign(id, 0);
|
||||
entries.insert_or_assign(id, 0);
|
||||
|
||||
auto iter = this->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 == this->mappedEntries.end() ? defaultValue : iter->second;
|
||||
return iter == entries.end() ? defaultValue : iter->second;
|
||||
}
|
||||
|
||||
@@ -7,16 +7,13 @@
|
||||
|
||||
enum class eReplicaComponentType : uint32_t;
|
||||
struct CDComponentsRegistry {
|
||||
unsigned int id; //!< The LOT is used as the ID
|
||||
uint32_t id; //!< The LOT is used as the ID
|
||||
eReplicaComponentType component_type; //!< See ComponentTypes enum for values
|
||||
unsigned int component_id; //!< The ID used within the component's table (0 may either mean it's non-networked, or that the ID is actually 0
|
||||
uint32_t component_id; //!< The ID used within the component's table (0 may either mean it's non-networked, or that the ID is actually 0
|
||||
};
|
||||
|
||||
|
||||
class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable> {
|
||||
private:
|
||||
std::unordered_map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
|
||||
|
||||
class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable, std::unordered_map<uint64_t, uint32_t>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
void CDCurrencyTableTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM CurrencyTable");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -15,7 +15,8 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable");
|
||||
@@ -27,7 +28,7 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
|
||||
entry.maxvalue = tableData.getIntField("maxvalue", -1);
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -35,15 +36,9 @@ void CDCurrencyTableTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCurrencyTable)> predicate) {
|
||||
|
||||
std::vector<CDCurrencyTable> data = cpplinq::from(this->entries)
|
||||
std::vector<CDCurrencyTable> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDCurrencyTable>& CDCurrencyTableTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,22 +10,17 @@
|
||||
|
||||
//! CurrencyTable Struct
|
||||
struct CDCurrencyTable {
|
||||
unsigned int currencyIndex; //!< The Currency Index
|
||||
unsigned int npcminlevel; //!< The minimum level of the npc
|
||||
unsigned int minvalue; //!< The minimum currency
|
||||
unsigned int maxvalue; //!< The maximum currency
|
||||
unsigned int id; //!< The ID of the currency index
|
||||
uint32_t currencyIndex; //!< The Currency Index
|
||||
uint32_t npcminlevel; //!< The minimum level of the npc
|
||||
uint32_t minvalue; //!< The minimum currency
|
||||
uint32_t maxvalue; //!< The maximum currency
|
||||
uint32_t id; //!< The ID of the currency index
|
||||
};
|
||||
|
||||
//! CurrencyTable table
|
||||
class CDCurrencyTableTable : public CDTable<CDCurrencyTableTable> {
|
||||
private:
|
||||
std::vector<CDCurrencyTable> entries;
|
||||
|
||||
class CDCurrencyTableTable : public CDTable<CDCurrencyTableTable, std::vector<CDCurrencyTable>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDCurrencyTable> Query(std::function<bool(CDCurrencyTable)> predicate);
|
||||
|
||||
const std::vector<CDCurrencyTable>& GetEntries() const;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
void CDDestructibleComponentTable::LoadValuesFromDatabase() {
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM DestructibleComponent");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -13,7 +13,8 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent");
|
||||
@@ -34,7 +35,7 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
|
||||
entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false;
|
||||
entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -42,15 +43,9 @@ void CDDestructibleComponentTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::function<bool(CDDestructibleComponent)> predicate) {
|
||||
|
||||
std::vector<CDDestructibleComponent> data = cpplinq::from(this->entries)
|
||||
std::vector<CDDestructibleComponent> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDDestructibleComponent>& CDDestructibleComponentTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,30 +4,25 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDDestructibleComponent {
|
||||
unsigned int id; //!< The component ID from the ComponentsRegistry Table
|
||||
int faction; //!< The Faction ID of the object
|
||||
uint32_t id; //!< The component ID from the ComponentsRegistry Table
|
||||
int32_t faction; //!< The Faction ID of the object
|
||||
std::string factionList; //!< A list of the faction IDs
|
||||
int life; //!< The amount of life of the object
|
||||
unsigned int imagination; //!< The amount of imagination of the object
|
||||
int LootMatrixIndex; //!< The Loot Matrix Index
|
||||
int CurrencyIndex; //!< The Currency Index
|
||||
unsigned int level; //!< ???
|
||||
int32_t life; //!< The amount of life of the object
|
||||
uint32_t imagination; //!< The amount of imagination of the object
|
||||
int32_t LootMatrixIndex; //!< The Loot Matrix Index
|
||||
int32_t CurrencyIndex; //!< The Currency Index
|
||||
uint32_t level; //!< ???
|
||||
float armor; //!< The amount of armor of the object
|
||||
unsigned int death_behavior; //!< The behavior ID of the death behavior
|
||||
uint32_t death_behavior; //!< The behavior ID of the death behavior
|
||||
bool isnpc; //!< Whether or not the object is an NPC
|
||||
unsigned int attack_priority; //!< ???
|
||||
uint32_t attack_priority; //!< ???
|
||||
bool isSmashable; //!< Whether or not the object is smashable
|
||||
int difficultyLevel; //!< ???
|
||||
int32_t difficultyLevel; //!< ???
|
||||
};
|
||||
|
||||
class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable> {
|
||||
private:
|
||||
std::vector<CDDestructibleComponent> entries;
|
||||
|
||||
class CDDestructibleComponentTable : public CDTable<CDDestructibleComponentTable, std::vector<CDDestructibleComponent>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDDestructibleComponent> Query(std::function<bool(CDDestructibleComponent)> predicate);
|
||||
|
||||
const std::vector<CDDestructibleComponent>& GetEntries(void) const;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
void CDEmoteTableTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes");
|
||||
auto& entries = GetEntriesMutable();
|
||||
while (!tableData.eof()) {
|
||||
CDEmoteTable entry;
|
||||
entry.ID = tableData.getIntField("id", -1);
|
||||
@@ -20,7 +21,8 @@ void CDEmoteTableTable::LoadValuesFromDatabase() {
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
|
||||
CDEmoteTable* CDEmoteTableTable::GetEmote(int32_t id) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
auto itr = entries.find(id);
|
||||
return itr != entries.end() ? &itr->second : nullptr;
|
||||
}
|
||||
|
||||
@@ -16,22 +16,19 @@ struct CDEmoteTable {
|
||||
gateVersion = "";
|
||||
}
|
||||
|
||||
int ID;
|
||||
int32_t ID;
|
||||
std::string animationName;
|
||||
std::string iconFilename;
|
||||
int locState;
|
||||
int channel;
|
||||
int32_t locState;
|
||||
int32_t channel;
|
||||
bool locked;
|
||||
bool localize;
|
||||
std::string gateVersion;
|
||||
};
|
||||
|
||||
class CDEmoteTableTable : public CDTable<CDEmoteTableTable> {
|
||||
private:
|
||||
std::map<int, CDEmoteTable> entries;
|
||||
|
||||
class CDEmoteTableTable : public CDTable<CDEmoteTableTable, std::map<int, CDEmoteTable>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Returns an emote by ID
|
||||
CDEmoteTable* GetEmote(int id);
|
||||
CDEmoteTable* GetEmote(int32_t id);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
void CDFeatureGatingTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM FeatureGating");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,7 +14,8 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating");
|
||||
@@ -26,7 +27,7 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
|
||||
entry.minor = tableData.getIntField("minor", -1);
|
||||
entry.description = tableData.getStringField("description", "");
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -35,7 +36,8 @@ void CDFeatureGatingTable::LoadValuesFromDatabase() {
|
||||
|
||||
std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFeatureGating)> predicate) {
|
||||
|
||||
std::vector<CDFeatureGating> data = cpplinq::from(this->entries)
|
||||
auto& entries = GetEntriesMutable();
|
||||
std::vector<CDFeatureGating> data = cpplinq::from(entries)
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
@@ -43,6 +45,7 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
|
||||
}
|
||||
|
||||
bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
|
||||
auto& entries = GetEntriesMutable();
|
||||
for (const auto& entry : entries) {
|
||||
if (entry.featureName == feature.featureName && feature >= entry) {
|
||||
return true;
|
||||
@@ -51,8 +54,3 @@ bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<CDFeatureGating>& CDFeatureGatingTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,7 @@ struct CDFeatureGating {
|
||||
}
|
||||
};
|
||||
|
||||
class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable> {
|
||||
private:
|
||||
std::vector<CDFeatureGating> entries;
|
||||
|
||||
class CDFeatureGatingTable : public CDTable<CDFeatureGatingTable, std::vector<CDFeatureGating>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
@@ -28,6 +25,4 @@ public:
|
||||
std::vector<CDFeatureGating> Query(std::function<bool(CDFeatureGating)> predicate);
|
||||
|
||||
bool FeatureUnlocked(const CDFeatureGating& feature) const;
|
||||
|
||||
const std::vector<CDFeatureGating>& GetEntries(void) const;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
void CDInventoryComponentTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM InventoryComponent");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,7 +14,8 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent");
|
||||
@@ -25,7 +26,7 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
|
||||
entry.count = tableData.getIntField("count", -1);
|
||||
entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false;
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -33,15 +34,9 @@ void CDInventoryComponentTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function<bool(CDInventoryComponent)> predicate) {
|
||||
|
||||
std::vector<CDInventoryComponent> data = cpplinq::from(this->entries)
|
||||
std::vector<CDInventoryComponent> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDInventoryComponent>& CDInventoryComponentTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,20 +4,15 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDInventoryComponent {
|
||||
unsigned int id; //!< The component ID for this object
|
||||
unsigned int itemid; //!< The LOT of the object
|
||||
unsigned int count; //!< The count of the items the object has
|
||||
uint32_t id; //!< The component ID for this object
|
||||
uint32_t itemid; //!< The LOT of the object
|
||||
uint32_t count; //!< The count of the items the object has
|
||||
bool equip; //!< Whether or not to equip the item
|
||||
};
|
||||
|
||||
class CDInventoryComponentTable : public CDTable<CDInventoryComponentTable> {
|
||||
private:
|
||||
std::vector<CDInventoryComponent> entries;
|
||||
|
||||
class CDInventoryComponentTable : public CDTable<CDInventoryComponentTable, std::vector<CDInventoryComponent>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDInventoryComponent> Query(std::function<bool(CDInventoryComponent)> predicate);
|
||||
|
||||
const std::vector<CDInventoryComponent>& GetEntries() const;
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ CDItemComponent CDItemComponentTable::Default = {};
|
||||
|
||||
void CDItemComponentTable::LoadValuesFromDatabase() {
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemComponent");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -17,6 +17,7 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent");
|
||||
auto& entries = GetEntriesMutable();
|
||||
while (!tableData.eof()) {
|
||||
CDItemComponent entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
@@ -62,16 +63,17 @@ void CDItemComponentTable::LoadValuesFromDatabase() {
|
||||
entry.forgeType = tableData.getIntField("forgeType", -1);
|
||||
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
|
||||
|
||||
this->entries.insert(std::make_pair(entry.id, entry));
|
||||
entries.insert(std::make_pair(entry.id, entry));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int skillID) {
|
||||
const auto& it = this->entries.find(skillID);
|
||||
if (it != this->entries.end()) {
|
||||
const CDItemComponent& CDItemComponentTable::GetItemComponentByID(uint32_t skillID) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
const auto& it = entries.find(skillID);
|
||||
if (it != entries.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -129,12 +131,12 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int s
|
||||
entry.forgeType = tableData.getIntField("forgeType", -1);
|
||||
entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f);
|
||||
|
||||
this->entries.insert(std::make_pair(entry.id, entry));
|
||||
entries.insert(std::make_pair(entry.id, entry));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
const auto& it2 = this->entries.find(skillID);
|
||||
if (it2 != this->entries.end()) {
|
||||
const auto& it2 = entries.find(skillID);
|
||||
if (it2 != entries.end()) {
|
||||
return it2->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,60 +5,57 @@
|
||||
#include "dCommonVars.h"
|
||||
|
||||
struct CDItemComponent {
|
||||
unsigned int id; //!< The Component ID
|
||||
uint32_t id; //!< The Component ID
|
||||
std::string equipLocation; //!< The equip location
|
||||
unsigned int baseValue; //!< The monetary base value of the item
|
||||
uint32_t baseValue; //!< The monetary base value of the item
|
||||
bool isKitPiece; //!< Whether or not the item belongs to a kit
|
||||
unsigned int rarity; //!< The rarity of the item
|
||||
unsigned int itemType; //!< The item type
|
||||
uint32_t rarity; //!< The rarity of the item
|
||||
uint32_t itemType; //!< The item type
|
||||
int64_t itemInfo; //!< The item info
|
||||
bool inLootTable; //!< Whether or not the item is in a loot table
|
||||
bool inVendor; //!< Whether or not the item is in a vendor inventory
|
||||
bool isUnique; //!< ???
|
||||
bool isBOP; //!< ???
|
||||
bool isBOE; //!< ???
|
||||
unsigned int reqFlagID; //!< User must have completed this flag to get the item
|
||||
unsigned int reqSpecialtyID; //!< ???
|
||||
unsigned int reqSpecRank; //!< ???
|
||||
unsigned int reqAchievementID; //!< The required achievement must be completed
|
||||
unsigned int stackSize; //!< The stack size of the item
|
||||
unsigned int color1; //!< Something to do with item color...
|
||||
unsigned int decal; //!< The decal of the item
|
||||
unsigned int offsetGroupID; //!< Something to do with group IDs
|
||||
unsigned int buildTypes; //!< Something to do with building
|
||||
uint32_t reqFlagID; //!< User must have completed this flag to get the item
|
||||
uint32_t reqSpecialtyID; //!< ???
|
||||
uint32_t reqSpecRank; //!< ???
|
||||
uint32_t reqAchievementID; //!< The required achievement must be completed
|
||||
uint32_t stackSize; //!< The stack size of the item
|
||||
uint32_t color1; //!< Something to do with item color...
|
||||
uint32_t decal; //!< The decal of the item
|
||||
uint32_t offsetGroupID; //!< Something to do with group IDs
|
||||
uint32_t buildTypes; //!< Something to do with building
|
||||
std::string reqPrecondition; //!< The required precondition
|
||||
unsigned int animationFlag; //!< The Animation Flag
|
||||
unsigned int equipEffects; //!< The effect played when the item is equipped
|
||||
uint32_t animationFlag; //!< The Animation Flag
|
||||
uint32_t equipEffects; //!< The effect played when the item is equipped
|
||||
bool readyForQA; //!< ???
|
||||
unsigned int itemRating; //!< ???
|
||||
uint32_t itemRating; //!< ???
|
||||
bool isTwoHanded; //!< Whether or not the item is double handed
|
||||
unsigned int minNumRequired; //!< Maybe the minimum number required for a mission, or to own this object?
|
||||
unsigned int delResIndex; //!< ???
|
||||
unsigned int currencyLOT; //!< ???
|
||||
unsigned int altCurrencyCost; //!< ???
|
||||
uint32_t minNumRequired; //!< Maybe the minimum number required for a mission, or to own this object?
|
||||
uint32_t delResIndex; //!< ???
|
||||
uint32_t currencyLOT; //!< ???
|
||||
uint32_t altCurrencyCost; //!< ???
|
||||
std::string subItems; //!< A comma seperate string of sub items (maybe for multi-itemed things like faction test gear set)
|
||||
UNUSED(std::string audioEventUse); //!< ???
|
||||
bool noEquipAnimation; //!< Whether or not there is an equip animation
|
||||
unsigned int commendationLOT; //!< The commendation LOT
|
||||
unsigned int commendationCost; //!< The commendation cost
|
||||
uint32_t commendationLOT; //!< The commendation LOT
|
||||
uint32_t commendationCost; //!< The commendation cost
|
||||
UNUSED(std::string audioEquipMetaEventSet); //!< ???
|
||||
std::string currencyCosts; //!< Used for crafting
|
||||
UNUSED(std::string ingredientInfo); //!< Unused
|
||||
unsigned int locStatus; //!< ???
|
||||
unsigned int forgeType; //!< Forge Type
|
||||
uint32_t locStatus; //!< ???
|
||||
uint32_t forgeType; //!< Forge Type
|
||||
float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced)
|
||||
};
|
||||
|
||||
class CDItemComponentTable : public CDTable<CDItemComponentTable> {
|
||||
private:
|
||||
std::map<unsigned int, CDItemComponent> entries;
|
||||
|
||||
class CDItemComponentTable : public CDTable<CDItemComponentTable, std::map<uint32_t, CDItemComponent>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
static std::map<LOT, uint32_t> ParseCraftingCurrencies(const CDItemComponent& itemComponent);
|
||||
|
||||
// Gets an entry by ID
|
||||
const CDItemComponent& GetItemComponentByID(unsigned int skillID);
|
||||
const CDItemComponent& GetItemComponentByID(uint32_t skillID);
|
||||
|
||||
static CDItemComponent Default;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
void CDItemSetSkillsTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSetSkills");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,7 +14,8 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills");
|
||||
@@ -24,7 +25,7 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
|
||||
entry.SkillID = tableData.getIntField("SkillID", -1);
|
||||
entry.SkillCastType = tableData.getIntField("SkillCastType", -1);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -32,22 +33,17 @@ void CDItemSetSkillsTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
std::vector<CDItemSetSkills> CDItemSetSkillsTable::Query(std::function<bool(CDItemSetSkills)> predicate) {
|
||||
|
||||
std::vector<CDItemSetSkills> data = cpplinq::from(this->entries)
|
||||
std::vector<CDItemSetSkills> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDItemSetSkills>& CDItemSetSkillsTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(unsigned int SkillSetID) {
|
||||
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(uint32_t SkillSetID) {
|
||||
std::vector<CDItemSetSkills> toReturn;
|
||||
|
||||
for (CDItemSetSkills entry : this->entries) {
|
||||
for (const auto& entry : GetEntries()) {
|
||||
if (entry.SkillSetID == SkillSetID) toReturn.push_back(entry);
|
||||
if (entry.SkillSetID > SkillSetID) return toReturn; //stop seeking in the db if it's not needed.
|
||||
}
|
||||
|
||||
@@ -4,21 +4,16 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDItemSetSkills {
|
||||
unsigned int SkillSetID; //!< The skill set ID
|
||||
unsigned int SkillID; //!< The skill ID
|
||||
unsigned int SkillCastType; //!< The skill cast type
|
||||
uint32_t SkillSetID; //!< The skill set ID
|
||||
uint32_t SkillID; //!< The skill ID
|
||||
uint32_t SkillCastType; //!< The skill cast type
|
||||
};
|
||||
|
||||
class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable> {
|
||||
private:
|
||||
std::vector<CDItemSetSkills> entries;
|
||||
|
||||
class CDItemSetSkillsTable : public CDTable<CDItemSetSkillsTable, std::vector<CDItemSetSkills>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDItemSetSkills> Query(std::function<bool(CDItemSetSkills)> predicate);
|
||||
|
||||
const std::vector<CDItemSetSkills>& GetEntries() const;
|
||||
|
||||
std::vector<CDItemSetSkills> GetBySkillID(unsigned int SkillSetID);
|
||||
std::vector<CDItemSetSkills> GetBySkillID(uint32_t SkillSetID);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
void CDItemSetsTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ItemSets");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,7 +14,8 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets");
|
||||
@@ -36,7 +37,7 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
|
||||
entry.kitID = tableData.getIntField("kitID", -1);
|
||||
entry.priority = tableData.getFloatField("priority", -1.0f);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -45,14 +46,9 @@ void CDItemSetsTable::LoadValuesFromDatabase() {
|
||||
|
||||
std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> predicate) {
|
||||
|
||||
std::vector<CDItemSets> data = cpplinq::from(this->entries)
|
||||
std::vector<CDItemSets> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDItemSets>& CDItemSetsTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,32 +4,27 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDItemSets {
|
||||
unsigned int setID; //!< The item set ID
|
||||
unsigned int locStatus; //!< The loc status
|
||||
uint32_t setID; //!< The item set ID
|
||||
uint32_t locStatus; //!< The loc status
|
||||
std::string itemIDs; //!< THe item IDs
|
||||
unsigned int kitType; //!< The item kit type
|
||||
unsigned int kitRank; //!< The item kit rank
|
||||
unsigned int kitImage; //!< The item kit image
|
||||
unsigned int skillSetWith2; //!< The skill set with 2
|
||||
unsigned int skillSetWith3; //!< The skill set with 3
|
||||
unsigned int skillSetWith4; //!< The skill set with 4
|
||||
unsigned int skillSetWith5; //!< The skill set with 5
|
||||
unsigned int skillSetWith6; //!< The skill set with 6
|
||||
uint32_t kitType; //!< The item kit type
|
||||
uint32_t kitRank; //!< The item kit rank
|
||||
uint32_t kitImage; //!< The item kit image
|
||||
uint32_t skillSetWith2; //!< The skill set with 2
|
||||
uint32_t skillSetWith3; //!< The skill set with 3
|
||||
uint32_t skillSetWith4; //!< The skill set with 4
|
||||
uint32_t skillSetWith5; //!< The skill set with 5
|
||||
uint32_t skillSetWith6; //!< The skill set with 6
|
||||
bool localize; //!< Whether or localize
|
||||
std::string gate_version; //!< The gate version
|
||||
unsigned int kitID; //!< The kit ID
|
||||
uint32_t kitID; //!< The kit ID
|
||||
float priority; //!< The priority
|
||||
};
|
||||
|
||||
class CDItemSetsTable : public CDTable<CDItemSetsTable> {
|
||||
private:
|
||||
std::vector<CDItemSets> entries;
|
||||
|
||||
class CDItemSetsTable : public CDTable<CDItemSetsTable, std::vector<CDItemSets>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDItemSets> Query(std::function<bool(CDItemSets)> predicate);
|
||||
|
||||
const std::vector<CDItemSets>& GetEntries(void) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LevelProgressionLookup");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,7 +14,8 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup");
|
||||
@@ -24,7 +25,7 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
|
||||
entry.requiredUScore = tableData.getIntField("requiredUScore", -1);
|
||||
entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", "");
|
||||
|
||||
this->entries.push_back(entry);
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -33,14 +34,9 @@ void CDLevelProgressionLookupTable::LoadValuesFromDatabase() {
|
||||
|
||||
std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::function<bool(CDLevelProgressionLookup)> predicate) {
|
||||
|
||||
std::vector<CDLevelProgressionLookup> data = cpplinq::from(this->entries)
|
||||
std::vector<CDLevelProgressionLookup> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDLevelProgressionLookup>& CDLevelProgressionLookupTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,20 +4,15 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDLevelProgressionLookup {
|
||||
unsigned int id; //!< The Level ID
|
||||
unsigned int requiredUScore; //!< The required LEGO Score
|
||||
uint32_t id; //!< The Level ID
|
||||
uint32_t requiredUScore; //!< The required LEGO Score
|
||||
std::string BehaviorEffect; //!< The behavior effect attached to this
|
||||
};
|
||||
|
||||
class CDLevelProgressionLookupTable : public CDTable<CDLevelProgressionLookupTable> {
|
||||
private:
|
||||
std::vector<CDLevelProgressionLookup> entries;
|
||||
|
||||
class CDLevelProgressionLookupTable : public CDTable<CDLevelProgressionLookupTable, std::vector<CDLevelProgressionLookup>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDLevelProgressionLookup> Query(std::function<bool(CDLevelProgressionLookup)> predicate);
|
||||
|
||||
const std::vector<CDLevelProgressionLookup>& GetEntries() const;
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ CDLootMatrix CDLootMatrixTable::ReadRow(CppSQLite3Query& tableData) const {
|
||||
void CDLootMatrixTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootMatrix");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -25,7 +25,8 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix");
|
||||
@@ -33,14 +34,15 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
|
||||
CDLootMatrix entry;
|
||||
uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
|
||||
|
||||
this->entries[lootMatrixIndex].push_back(ReadRow(tableData));
|
||||
entries[lootMatrixIndex].push_back(ReadRow(tableData));
|
||||
tableData.nextRow();
|
||||
}
|
||||
}
|
||||
|
||||
const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
|
||||
auto itr = this->entries.find(matrixId);
|
||||
if (itr != this->entries.end()) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
auto itr = entries.find(matrixId);
|
||||
if (itr != entries.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
@@ -49,10 +51,10 @@ const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
|
||||
|
||||
auto tableData = query.execQuery();
|
||||
while (!tableData.eof()) {
|
||||
this->entries[matrixId].push_back(ReadRow(tableData));
|
||||
entries[matrixId].push_back(ReadRow(tableData));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
return this->entries[matrixId];
|
||||
return entries[matrixId];
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDLootMatrix {
|
||||
unsigned int LootTableIndex; //!< The Loot Table Index
|
||||
unsigned int RarityTableIndex; //!< The Rarity Table Index
|
||||
uint32_t LootTableIndex; //!< The Loot Table Index
|
||||
uint32_t RarityTableIndex; //!< The Rarity Table Index
|
||||
float percent; //!< The percent that this matrix is used?
|
||||
unsigned int minToDrop; //!< The minimum amount of loot from this matrix to drop
|
||||
unsigned int maxToDrop; //!< The maximum amount of loot from this matrix to drop
|
||||
unsigned int flagID; //!< ???
|
||||
uint32_t minToDrop; //!< The minimum amount of loot from this matrix to drop
|
||||
uint32_t maxToDrop; //!< The maximum amount of loot from this matrix to drop
|
||||
uint32_t flagID; //!< ???
|
||||
UNUSED(std::string gate_version); //!< The Gate Version
|
||||
};
|
||||
|
||||
typedef uint32_t LootMatrixIndex;
|
||||
typedef std::vector<CDLootMatrix> LootMatrixEntries;
|
||||
|
||||
class CDLootMatrixTable : public CDTable<CDLootMatrixTable> {
|
||||
class CDLootMatrixTable : public CDTable<CDLootMatrixTable, std::unordered_map<LootMatrixIndex, LootMatrixEntries>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
@@ -24,6 +24,5 @@ public:
|
||||
const LootMatrixEntries& GetMatrix(uint32_t matrixId);
|
||||
private:
|
||||
CDLootMatrix ReadRow(CppSQLite3Query& tableData) const;
|
||||
std::unordered_map<LootMatrixIndex, LootMatrixEntries> entries;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
// Sort the tables by their rarity so the highest rarity items are first.
|
||||
void SortTable(LootTableEntries& table) {
|
||||
auto* componentsRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>();
|
||||
auto* itemComponentTable = CDClientManager::Instance().GetTable<CDItemComponentTable>();
|
||||
auto* componentsRegistryTable = CDClientManager::GetTable<CDComponentsRegistryTable>();
|
||||
auto* itemComponentTable = CDClientManager::GetTable<CDItemComponentTable>();
|
||||
// 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
|
||||
// of the outer loop.
|
||||
@@ -40,7 +40,7 @@ CDLootTable CDLootTableTable::ReadRow(CppSQLite3Query& tableData) const {
|
||||
void CDLootTableTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM LootTable");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -49,7 +49,8 @@ void CDLootTableTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable");
|
||||
@@ -57,17 +58,18 @@ void CDLootTableTable::LoadValuesFromDatabase() {
|
||||
CDLootTable entry;
|
||||
uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1);
|
||||
|
||||
this->entries[lootTableIndex].push_back(ReadRow(tableData));
|
||||
entries[lootTableIndex].emplace_back(ReadRow(tableData));
|
||||
tableData.nextRow();
|
||||
}
|
||||
for (auto& [id, table] : this->entries) {
|
||||
for (auto& [id, table] : entries) {
|
||||
SortTable(table);
|
||||
}
|
||||
}
|
||||
|
||||
const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
|
||||
auto itr = this->entries.find(tableId);
|
||||
if (itr != this->entries.end()) {
|
||||
const LootTableEntries& CDLootTableTable::GetTable(const uint32_t tableId) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
auto itr = entries.find(tableId);
|
||||
if (itr != entries.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
@@ -77,10 +79,10 @@ const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
|
||||
|
||||
while (!tableData.eof()) {
|
||||
CDLootTable entry;
|
||||
this->entries[tableId].push_back(ReadRow(tableData));
|
||||
entries[tableId].emplace_back(ReadRow(tableData));
|
||||
tableData.nextRow();
|
||||
}
|
||||
SortTable(this->entries[tableId]);
|
||||
SortTable(entries[tableId]);
|
||||
|
||||
return this->entries[tableId];
|
||||
return entries[tableId];
|
||||
}
|
||||
|
||||
@@ -3,24 +3,24 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDLootTable {
|
||||
unsigned int itemid; //!< The LOT of the item
|
||||
unsigned int LootTableIndex; //!< The Loot Table Index
|
||||
uint32_t itemid; //!< The LOT of the item
|
||||
uint32_t LootTableIndex; //!< The Loot Table Index
|
||||
bool MissionDrop; //!< Whether or not this loot table is a mission drop
|
||||
unsigned int sortPriority; //!< The sorting priority
|
||||
uint32_t sortPriority; //!< The sorting priority
|
||||
};
|
||||
|
||||
typedef uint32_t LootTableIndex;
|
||||
typedef std::vector<CDLootTable> LootTableEntries;
|
||||
|
||||
class CDLootTableTable : public CDTable<CDLootTableTable> {
|
||||
class CDLootTableTable : public CDTable<CDLootTableTable, std::unordered_map<LootTableIndex, LootTableEntries>> {
|
||||
private:
|
||||
CDLootTable ReadRow(CppSQLite3Query& tableData) const;
|
||||
std::unordered_map<LootTableIndex, LootTableEntries> entries;
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
const LootTableEntries& GetTable(uint32_t tableId);
|
||||
const LootTableEntries& GetTable(const uint32_t tableId);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "CDMissionEmailTable.h"
|
||||
|
||||
void CDMissionEmailTable::LoadValuesFromDatabase() {
|
||||
|
||||
void CDMissionEmailTable::LoadValuesFromDatabase() {
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionEmail");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,12 +14,13 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail");
|
||||
while (!tableData.eof()) {
|
||||
CDMissionEmail entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.ID = tableData.getIntField("ID", -1);
|
||||
entry.messageType = tableData.getIntField("messageType", -1);
|
||||
entry.notificationGroup = tableData.getIntField("notificationGroup", -1);
|
||||
@@ -29,24 +30,15 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
|
||||
entry.locStatus = tableData.getIntField("locStatus", -1);
|
||||
entry.gate_version = tableData.getStringField("gate_version", "");
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMissionEmail)> predicate) {
|
||||
|
||||
std::vector<CDMissionEmail> data = cpplinq::from(this->entries)
|
||||
std::vector<CDMissionEmail> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
const std::vector<CDMissionEmail>& CDMissionEmailTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
@@ -3,26 +3,23 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDMissionEmail {
|
||||
unsigned int ID;
|
||||
unsigned int messageType;
|
||||
unsigned int notificationGroup;
|
||||
unsigned int missionID;
|
||||
unsigned int attachmentLOT;
|
||||
uint32_t ID;
|
||||
uint32_t messageType;
|
||||
uint32_t notificationGroup;
|
||||
uint32_t missionID;
|
||||
uint32_t attachmentLOT;
|
||||
bool localize;
|
||||
unsigned int locStatus;
|
||||
uint32_t locStatus;
|
||||
std::string gate_version;
|
||||
};
|
||||
|
||||
|
||||
class CDMissionEmailTable : public CDTable<CDMissionEmailTable> {
|
||||
private:
|
||||
std::vector<CDMissionEmail> entries;
|
||||
|
||||
class CDMissionEmailTable : public CDTable<CDMissionEmailTable, std::vector<CDMissionEmail>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDMissionEmail> Query(std::function<bool(CDMissionEmail)> predicate);
|
||||
|
||||
const std::vector<CDMissionEmail>& GetEntries() const;
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionNPCComponent");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,37 +14,29 @@ void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent");
|
||||
while (!tableData.eof()) {
|
||||
CDMissionNPCComponent entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.missionID = tableData.getIntField("missionID", -1);
|
||||
entry.offersMission = tableData.getIntField("offersMission", -1) == 1 ? true : false;
|
||||
entry.acceptsMission = tableData.getIntField("acceptsMission", -1) == 1 ? true : false;
|
||||
entry.gate_version = tableData.getStringField("gate_version", "");
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::Query(std::function<bool(CDMissionNPCComponent)> predicate) {
|
||||
|
||||
std::vector<CDMissionNPCComponent> data = cpplinq::from(this->entries)
|
||||
std::vector<CDMissionNPCComponent> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
const std::vector<CDMissionNPCComponent>& CDMissionNPCComponentTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,25 +3,19 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDMissionNPCComponent {
|
||||
unsigned int id; //!< The ID
|
||||
unsigned int missionID; //!< The Mission ID
|
||||
uint32_t id; //!< The ID
|
||||
uint32_t missionID; //!< The Mission ID
|
||||
bool offersMission; //!< Whether or not this NPC offers a mission
|
||||
bool acceptsMission; //!< Whether or not this NPC accepts a mission
|
||||
std::string gate_version; //!< The gate version
|
||||
};
|
||||
|
||||
class CDMissionNPCComponentTable : public CDTable<CDMissionNPCComponentTable> {
|
||||
private:
|
||||
std::vector<CDMissionNPCComponent> entries;
|
||||
|
||||
class CDMissionNPCComponentTable : public CDTable<CDMissionNPCComponentTable, std::vector<CDMissionNPCComponent>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDMissionNPCComponent> Query(std::function<bool(CDMissionNPCComponent)> predicate);
|
||||
|
||||
// Gets all the entries in the table
|
||||
const std::vector<CDMissionNPCComponent>& GetEntries() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
void CDMissionTasksTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM MissionTasks");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -14,12 +14,13 @@ void CDMissionTasksTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionTasks");
|
||||
while (!tableData.eof()) {
|
||||
CDMissionTasks entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1));
|
||||
entry.taskType = tableData.getIntField("taskType", -1);
|
||||
@@ -34,26 +35,24 @@ void CDMissionTasksTable::LoadValuesFromDatabase() {
|
||||
UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false);
|
||||
UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
std::vector<CDMissionTasks> CDMissionTasksTable::Query(std::function<bool(CDMissionTasks)> predicate) {
|
||||
|
||||
std::vector<CDMissionTasks> data = cpplinq::from(this->entries)
|
||||
std::vector<CDMissionTasks> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(uint32_t missionID) {
|
||||
std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(const uint32_t missionID) {
|
||||
std::vector<CDMissionTasks*> tasks;
|
||||
|
||||
for (auto& entry : this->entries) {
|
||||
// TODO: this should not be linear(?) and also shouldnt need to be a pointer
|
||||
for (auto& entry : GetEntriesMutable()) {
|
||||
if (entry.id == missionID) {
|
||||
tasks.push_back(&entry);
|
||||
}
|
||||
@@ -62,7 +61,6 @@ std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(uint32_t missio
|
||||
return tasks;
|
||||
}
|
||||
|
||||
const std::vector<CDMissionTasks>& CDMissionTasksTable::GetEntries() const {
|
||||
return this->entries;
|
||||
const typename CDMissionTasksTable::StorageType& CDMissionTasksTable::GetEntries() const {
|
||||
return CDTable::GetEntries();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,33 +3,33 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDMissionTasks {
|
||||
unsigned int id; //!< The Mission ID that the task belongs to
|
||||
UNUSED(unsigned int locStatus); //!< ???
|
||||
unsigned int taskType; //!< The task type
|
||||
unsigned int target; //!< The mission target
|
||||
uint32_t id; //!< The Mission ID that the task belongs to
|
||||
UNUSED(uint32_t locStatus); //!< ???
|
||||
uint32_t taskType; //!< The task type
|
||||
uint32_t target; //!< The mission target
|
||||
std::string targetGroup; //!< The mission target group
|
||||
int targetValue; //!< The target value
|
||||
int32_t targetValue; //!< The target value
|
||||
std::string taskParam1; //!< The task param 1
|
||||
UNUSED(std::string largeTaskIcon); //!< ???
|
||||
UNUSED(unsigned int IconID); //!< ???
|
||||
unsigned int uid; //!< ???
|
||||
UNUSED(unsigned int largeTaskIconID); //!< ???
|
||||
UNUSED(uint32_t IconID); //!< ???
|
||||
uint32_t uid; //!< ???
|
||||
UNUSED(uint32_t largeTaskIconID); //!< ???
|
||||
UNUSED(bool localize); //!< Whether or not the task should be localized
|
||||
UNUSED(std::string gate_version); //!< ???
|
||||
};
|
||||
|
||||
class CDMissionTasksTable : public CDTable<CDMissionTasksTable> {
|
||||
private:
|
||||
std::vector<CDMissionTasks> entries;
|
||||
|
||||
class CDMissionTasksTable : public CDTable<CDMissionTasksTable, std::vector<CDMissionTasks>> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDMissionTasks> Query(std::function<bool(CDMissionTasks)> predicate);
|
||||
|
||||
std::vector<CDMissionTasks*> GetByMissionID(uint32_t missionID);
|
||||
std::vector<CDMissionTasks*> GetByMissionID(const uint32_t missionID);
|
||||
|
||||
const std::vector<CDMissionTasks>& GetEntries() const;
|
||||
// TODO: Remove this and replace it with a proper lookup function.
|
||||
const CDTable::StorageType& GetEntries() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ CDMissions CDMissionsTable::Default = {};
|
||||
void CDMissionsTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
uint32_t size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Missions");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
@@ -16,12 +16,13 @@ void CDMissionsTable::LoadValuesFromDatabase() {
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
auto& entries = GetEntriesMutable();
|
||||
entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Missions");
|
||||
while (!tableData.eof()) {
|
||||
CDMissions entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.defined_type = tableData.getStringField("defined_type", "");
|
||||
entry.defined_subtype = tableData.getStringField("defined_subtype", "");
|
||||
@@ -75,10 +76,8 @@ void CDMissionsTable::LoadValuesFromDatabase() {
|
||||
UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1));
|
||||
entry.reward_bankinventory = tableData.getIntField("reward_bankinventory", -1);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
|
||||
Default.id = -1;
|
||||
@@ -86,19 +85,15 @@ void CDMissionsTable::LoadValuesFromDatabase() {
|
||||
|
||||
std::vector<CDMissions> CDMissionsTable::Query(std::function<bool(CDMissions)> predicate) {
|
||||
|
||||
std::vector<CDMissions> data = cpplinq::from(this->entries)
|
||||
std::vector<CDMissions> data = cpplinq::from(GetEntries())
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDMissions>& CDMissionsTable::GetEntries(void) const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const {
|
||||
for (const auto& entry : entries) {
|
||||
for (const auto& entry : GetEntries()) {
|
||||
if (entry.id == missionID) {
|
||||
return const_cast<CDMissions*>(&entry);
|
||||
}
|
||||
@@ -108,7 +103,7 @@ const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const {
|
||||
}
|
||||
|
||||
const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& found) const {
|
||||
for (const auto& entry : entries) {
|
||||
for (const auto& entry : GetEntries()) {
|
||||
if (entry.id == missionID) {
|
||||
found = true;
|
||||
|
||||
@@ -121,3 +116,12 @@ const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& foun
|
||||
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;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user