mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-20 11:59:40 -06:00
Compare commits
160 Commits
chatpacket
...
ecs-experi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a36b611367 | ||
|
|
85eb5a7261 | ||
|
|
93dcfddac5 | ||
|
|
82f510c642 | ||
|
|
ae4d9c4bcb | ||
|
|
b9e4aa5344 | ||
|
|
eab57e4022 | ||
|
|
179f0cf32d | ||
|
|
427b7c1047 | ||
|
|
e1c20192f7 | ||
|
|
0f8c5b436d | ||
| 53242ad5d5 | |||
|
|
a8919c8c14 | ||
|
|
5ff121612e | ||
|
|
afc2966507 | ||
| 34618607c3 | |||
|
|
02b76adb7a | ||
|
|
3beb414b55 | ||
|
|
1dadeeb36f | ||
|
|
aa7c3b9061 | ||
|
|
1644d9448d | ||
|
|
8b56b0b7ba | ||
|
|
4a1c289fb1 | ||
|
|
32a1e5ece5 | ||
|
|
7fcbb9507b | ||
|
|
730533c690 | ||
|
|
129d9fd0b9 | ||
|
|
ec4ec2133b | ||
|
|
218a3f2d0d | ||
|
|
c37a0c86c1 | ||
|
|
9e7ef8c4ee | ||
|
|
ec501831e6 | ||
|
|
5b8d2b19a3 | ||
| 17f81d13a3 | |||
|
|
53877a0bc3 | ||
|
|
83f8646936 | ||
|
|
d8b86072d4 | ||
|
|
112c2367cc | ||
|
|
c7dd8205a4 | ||
|
|
652f42ccf2 | ||
|
|
fedd039e00 | ||
|
|
84d7c65717 | ||
|
|
adc9cd2876 | ||
|
|
008e2d4dce | ||
|
|
677e7c1097 | ||
|
|
628ac9807e | ||
|
|
de3fe93100 | ||
|
|
af943278fb | ||
|
|
bfe6900c26 | ||
|
|
0d218fc5c7 | ||
|
|
102e3556cf | ||
|
|
33a8efdd22 | ||
|
|
8d54db7851 | ||
|
|
6213aed8e5 | ||
|
|
d57c5101f4 | ||
|
|
6be65569de | ||
|
|
94b9731a2b | ||
|
|
aaf446fe6e | ||
|
|
2c70f1503c | ||
|
|
49b4748ed3 | ||
|
|
ffeb0108d0 | ||
|
|
c3f6ef5a1d | ||
|
|
999995b2fb | ||
|
|
84fff7c380 | ||
|
|
59c4b35479 | ||
|
|
f2d72e7ed5 | ||
|
|
b648b43c4d | ||
|
|
2628470482 | ||
|
|
f82a82f254 | ||
|
|
9400ee1dc0 | ||
|
|
54b8c25754 | ||
|
|
b984cd6a0b | ||
|
|
bcf1058759 | ||
|
|
6ad6e930c7 | ||
|
|
fee0238e79 | ||
|
|
1454fcd003 | ||
|
|
af651f0d63 | ||
| ff38503597 | |||
| 3f22bf5cc0 | |||
| 9d5d2a68ee | |||
| 1a14c29c39 | |||
| 2ef45bd7ee | |||
| b56d077892 | |||
|
|
a54600b41e | ||
|
|
342da927f5 | ||
|
|
01086d05c8 | ||
|
|
cce5755366 | ||
|
|
e966d3a644 | ||
|
|
9328021339 | ||
|
|
d1134fdd62 | ||
|
|
efa658bc31 | ||
|
|
e59525d2ae | ||
|
|
0348db72a5 | ||
|
|
debc2a96e2 | ||
| 86f335d64b | |||
| 8ca05241f2 | |||
|
|
8ae1a8ff7c | ||
|
|
f0960d48b2 | ||
|
|
dc430d9758 | ||
|
|
dea10c6d56 | ||
|
|
ed00551982 | ||
|
|
d6cac65a8d | ||
|
|
d8f079cb1b | ||
|
|
db2d4f02b5 | ||
|
|
00f36f3f28 | ||
|
|
a50b256689 | ||
|
|
b3548de7da | ||
|
|
387c37505c | ||
|
|
0c4108e730 | ||
|
|
fd1c6ab2ea | ||
|
|
f2bf9a2a28 | ||
|
|
c8e0bb0db0 | ||
|
|
d9d262d3f1 | ||
|
|
d0a5678290 | ||
|
|
35321b22d9 | ||
|
|
8837b110ab | ||
|
|
09a8c99f3e | ||
|
|
e3b108e00e | ||
|
|
9f382aca42 | ||
|
|
4d1395e522 | ||
| 9e36510c6b | |||
|
|
2ca61c3e57 | ||
| 07cb19cc30 | |||
|
|
794b254fe7 | ||
|
|
ab7f6f0b57 | ||
|
|
58cc569c75 | ||
|
|
35c463656d | ||
| 3801a97722 | |||
|
|
0367c67c85 | ||
|
|
8fdc212cda | ||
| 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 |
@@ -73,4 +73,4 @@ cpp_space_around_assignment_operator=insert
|
|||||||
cpp_space_pointer_reference_alignment=left
|
cpp_space_pointer_reference_alignment=left
|
||||||
cpp_space_around_ternary_operator=insert
|
cpp_space_around_ternary_operator=insert
|
||||||
cpp_wrap_preserve_blocks=one_liners
|
cpp_wrap_preserve_blocks=one_liners
|
||||||
cpp_indent_comment=fasle
|
cpp_indent_comment=false
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ CLIENT_PATH=./client
|
|||||||
# Updates NET_VERSION in CMakeVariables.txt
|
# Updates NET_VERSION in CMakeVariables.txt
|
||||||
NET_VERSION=171022
|
NET_VERSION=171022
|
||||||
# make sure this is a long random string
|
# make sure this is a long random string
|
||||||
# grab a "SHA 256-bit Key" from here: https://keygen.io/
|
# generate a "SHA 256-bit Key" from here: https://gchq.github.io/CyberChef/#recipe=Pseudo-Random_Number_Generator(256,'Hex')
|
||||||
ACCOUNT_MANAGER_SECRET=
|
ACCOUNT_MANAGER_SECRET=
|
||||||
# Should be the externally facing IP of your server host
|
# Should be the externally facing IP of your server host
|
||||||
EXTERNAL_IP=localhost
|
EXTERNAL_IP=localhost
|
||||||
|
|||||||
31
.github/workflows/build-and-test.yml
vendored
31
.github/workflows/build-and-test.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
|||||||
os: [ windows-2022, ubuntu-22.04, macos-13 ]
|
os: [ windows-2022, ubuntu-22.04, macos-13 ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Add msbuild to PATH (Windows only)
|
- name: Add msbuild to PATH (Windows only)
|
||||||
if: ${{ matrix.os == 'windows-2022' }}
|
if: ${{ matrix.os == 'windows-2022' }}
|
||||||
uses: microsoft/setup-msbuild@v1.1
|
uses: microsoft/setup-msbuild@v2
|
||||||
with:
|
with:
|
||||||
vs-version: '[17,18)'
|
vs-version: '[17,18)'
|
||||||
msbuild-architecture: x64
|
msbuild-architecture: x64
|
||||||
@@ -33,21 +33,20 @@ jobs:
|
|||||||
- name: cmake
|
- name: cmake
|
||||||
uses: lukka/run-cmake@v10
|
uses: lukka/run-cmake@v10
|
||||||
with:
|
with:
|
||||||
configurePreset: "ci-${{matrix.os}}"
|
workflowPreset: "ci-${{matrix.os}}"
|
||||||
buildPreset: "ci-${{matrix.os}}"
|
|
||||||
testPreset: "ci-${{matrix.os}}"
|
|
||||||
- name: artifacts
|
- name: artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: build-${{matrix.os}}
|
name: build-${{matrix.os}}
|
||||||
path: |
|
path: |
|
||||||
build/*Server*
|
build/*/*Server*
|
||||||
build/*.ini
|
build/*/*.ini
|
||||||
build/*.so
|
build/*/*.so
|
||||||
build/*.dll
|
build/*/*.dll
|
||||||
build/vanity/
|
build/*/*.dylib
|
||||||
build/navmeshes/
|
build/*/vanity/
|
||||||
build/migrations/
|
build/*/navmeshes/
|
||||||
build/*.dcf
|
build/*/migrations/
|
||||||
!build/*.pdb
|
build/*/*.dcf
|
||||||
!build/d*/
|
!build/*/*.pdb
|
||||||
|
!build/*/d*/
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -4,6 +4,7 @@ RelWithDebInfo/
|
|||||||
docker/configs
|
docker/configs
|
||||||
|
|
||||||
# Third party libraries
|
# Third party libraries
|
||||||
|
thirdparty/magic_enum
|
||||||
thirdparty/mysql/
|
thirdparty/mysql/
|
||||||
thirdparty/mysql_linux/
|
thirdparty/mysql_linux/
|
||||||
CMakeVariables.txt
|
CMakeVariables.txt
|
||||||
@@ -95,6 +96,7 @@ ipch/
|
|||||||
|
|
||||||
# Exceptions:
|
# Exceptions:
|
||||||
CMakeSettings.json
|
CMakeSettings.json
|
||||||
|
CMakeUserPresets.json
|
||||||
*.vcxproj
|
*.vcxproj
|
||||||
*.filters
|
*.filters
|
||||||
*.cmake
|
*.cmake
|
||||||
@@ -122,4 +124,7 @@ docker/__pycache__
|
|||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
|
|
||||||
!*Test.bin
|
!*Test.bin
|
||||||
|
|
||||||
|
# CMake scripts
|
||||||
!cmake/*
|
!cmake/*
|
||||||
|
!cmake/toolchains/*
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -14,6 +14,3 @@
|
|||||||
path = thirdparty/mariadb-connector-cpp
|
path = thirdparty/mariadb-connector-cpp
|
||||||
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
|
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
|
||||||
ignore = dirty
|
ignore = dirty
|
||||||
[submodule "thirdparty/magic_enum"]
|
|
||||||
path = thirdparty/magic_enum
|
|
||||||
url = https://github.com/Neargye/magic_enum.git
|
|
||||||
|
|||||||
120
CMakeLists.txt
120
CMakeLists.txt
@@ -1,11 +1,23 @@
|
|||||||
cmake_minimum_required(VERSION 3.25)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(Darkflame)
|
project(Darkflame
|
||||||
|
HOMEPAGE_URL "https://github.com/DarkflameUniverse/DarkflameServer"
|
||||||
|
LANGUAGES C CXX
|
||||||
|
)
|
||||||
|
|
||||||
|
# check if the path to the source directory contains a space
|
||||||
|
if("${CMAKE_SOURCE_DIR}" MATCHES " ")
|
||||||
|
message(FATAL_ERROR "The server cannot build in the path (" ${CMAKE_SOURCE_DIR} ") because it contains a space. Please move the server to a path without spaces.")
|
||||||
|
endif()
|
||||||
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_VISIBILITY_PRESET hidden) # Set C++ symbol visibility to default to hidden
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export the compile commands for debugging
|
||||||
|
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects
|
||||||
|
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Set C and C++ symbol visibility to hide inlined functions
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
# Read variables from file
|
# Read variables from file
|
||||||
@@ -54,34 +66,37 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
|
|||||||
# Disabled no-register
|
# Disabled no-register
|
||||||
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wuninitialized -fPIC")
|
add_link_options("-Wl,-rpath,$ORIGIN/")
|
||||||
|
add_compile_options("-fPIC")
|
||||||
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
|
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
|
||||||
|
|
||||||
if(NOT APPLE)
|
# For all except Clang and Apple Clang
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -lstdc++fs")
|
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
add_compile_options("-static-libgcc" "-lstdc++fs")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${DYNAMIC} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if(${DYNAMIC} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
|
add_link_options("-export-dynamic")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${GGDB})
|
if(${GGDB})
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
|
add_compile_options("-ggdb")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
|
||||||
elseif(MSVC)
|
elseif(MSVC)
|
||||||
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
# 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" "/Zc:inline")
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Our output dir
|
# 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
|
#set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) # unfortunately, forces all libraries to be built in series, which will slow down the build process
|
||||||
|
|
||||||
# TODO make this not have to override the build type directories
|
# TODO make this not have to override the build type directories
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
||||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
||||||
@@ -95,37 +110,62 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|||||||
|
|
||||||
find_package(MariaDB)
|
find_package(MariaDB)
|
||||||
|
|
||||||
|
# Fetch third party dependencies
|
||||||
|
set(DLU_THIRDPARTY_SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
magic_enum
|
||||||
|
SYSTEM
|
||||||
|
# SOURCE_DIR ${DLU_THIRDPARTY_SOURCE_DIR}/magic_enum
|
||||||
|
GIT_REPOSITORY https://github.com/Neargye/magic_enum.git
|
||||||
|
GIT_TAG v0.9.7
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(magic_enum)
|
||||||
|
|
||||||
|
include(CMakePrintHelpers)
|
||||||
|
cmake_print_properties(TARGETS magic_enum::magic_enum PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES)
|
||||||
|
|
||||||
# Create a /resServer directory
|
# Create a /resServer directory
|
||||||
make_directory(${CMAKE_BINARY_DIR}/resServer)
|
make_directory(${CMAKE_BINARY_DIR}/resServer)
|
||||||
|
|
||||||
# Create a /logs directory
|
# Create a /logs directory
|
||||||
make_directory(${CMAKE_BINARY_DIR}/logs)
|
make_directory(${CMAKE_BINARY_DIR}/logs)
|
||||||
|
|
||||||
|
# Get DLU config directory
|
||||||
|
if(DEFINED ENV{DLU_CONFIG_DIR})
|
||||||
|
set(DLU_CONFIG_DIR $ENV{DLU_CONFIG_DIR})
|
||||||
|
else()
|
||||||
|
set(DLU_CONFIG_DIR ${PROJECT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
message(STATUS "Variable: DLU_CONFIG_DIR = ${DLU_CONFIG_DIR}")
|
||||||
|
|
||||||
# Copy resource files on first build
|
# Copy resource files on first build
|
||||||
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
|
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blocklist.dcf")
|
||||||
message(STATUS "Checking resource file integrity")
|
message(STATUS "Checking resource file integrity")
|
||||||
|
|
||||||
include(Utils)
|
include(Utils)
|
||||||
UpdateConfigOption(${PROJECT_BINARY_DIR}/authconfig.ini "port" "auth_server_port")
|
UpdateConfigOption(${DLU_CONFIG_DIR}/authconfig.ini "port" "auth_server_port")
|
||||||
UpdateConfigOption(${PROJECT_BINARY_DIR}/chatconfig.ini "port" "chat_server_port")
|
UpdateConfigOption(${DLU_CONFIG_DIR}/chatconfig.ini "port" "chat_server_port")
|
||||||
UpdateConfigOption(${PROJECT_BINARY_DIR}/masterconfig.ini "port" "master_server_port")
|
UpdateConfigOption(${DLU_CONFIG_DIR}/masterconfig.ini "port" "master_server_port")
|
||||||
|
|
||||||
foreach(resource_file ${RESOURCE_FILES})
|
foreach(resource_file ${RESOURCE_FILES})
|
||||||
set(file_size 0)
|
set(file_size 0)
|
||||||
|
|
||||||
if(EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
|
if(EXISTS ${DLU_CONFIG_DIR}/${resource_file})
|
||||||
file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size)
|
file(SIZE ${DLU_CONFIG_DIR}/${resource_file} file_size)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${file_size} EQUAL 0)
|
if(${file_size} EQUAL 0)
|
||||||
configure_file(
|
configure_file(
|
||||||
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
|
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${DLU_CONFIG_DIR}/${resource_file}
|
||||||
COPYONLY
|
COPYONLY
|
||||||
)
|
)
|
||||||
message(STATUS "Moved " ${resource_file} " to project binary directory")
|
message(STATUS "Moved " ${resource_file} " to DLU config directory")
|
||||||
elseif(resource_file MATCHES ".ini")
|
elseif(resource_file MATCHES ".ini")
|
||||||
message(STATUS "Checking " ${resource_file} " for missing config options")
|
message(STATUS "Checking " ${resource_file} " for missing config options")
|
||||||
file(READ ${PROJECT_BINARY_DIR}/${resource_file} current_file_contents)
|
file(READ ${DLU_CONFIG_DIR}/${resource_file} current_file_contents)
|
||||||
string(REPLACE "\\\n" "" current_file_contents ${current_file_contents})
|
string(REPLACE "\\\n" "" current_file_contents ${current_file_contents})
|
||||||
string(REPLACE "\n" ";" current_file_contents ${current_file_contents})
|
string(REPLACE "\n" ";" current_file_contents ${current_file_contents})
|
||||||
set(parsed_current_file_contents "")
|
set(parsed_current_file_contents "")
|
||||||
@@ -156,10 +196,10 @@ foreach(resource_file ${RESOURCE_FILES})
|
|||||||
set(line_to_add ${line_to_add} ${line})
|
set(line_to_add ${line_to_add} ${line})
|
||||||
|
|
||||||
foreach(line_to_append ${line_to_add})
|
foreach(line_to_append ${line_to_add})
|
||||||
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append})
|
file(APPEND ${DLU_CONFIG_DIR}/${resource_file} "\n" ${line_to_append})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n")
|
file(APPEND ${DLU_CONFIG_DIR}/${resource_file} "\n")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(line_to_add "")
|
set(line_to_add "")
|
||||||
@@ -228,14 +268,14 @@ include_directories(
|
|||||||
"tests/dGameTests"
|
"tests/dGameTests"
|
||||||
"tests/dGameTests/dComponentsTests"
|
"tests/dGameTests/dComponentsTests"
|
||||||
|
|
||||||
SYSTEM "thirdparty/magic_enum/include/magic_enum"
|
SYSTEM
|
||||||
SYSTEM "thirdparty/raknet/Source"
|
"thirdparty/raknet/Source"
|
||||||
SYSTEM "thirdparty/tinyxml2"
|
"thirdparty/tinyxml2"
|
||||||
SYSTEM "thirdparty/recastnavigation"
|
"thirdparty/recastnavigation"
|
||||||
SYSTEM "thirdparty/SQLite"
|
"thirdparty/SQLite"
|
||||||
SYSTEM "thirdparty/cpplinq"
|
"thirdparty/cpplinq"
|
||||||
SYSTEM "thirdparty/cpp-httplib"
|
"thirdparty/cpp-httplib"
|
||||||
SYSTEM "thirdparty/MD5"
|
"thirdparty/MD5"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
||||||
@@ -244,10 +284,17 @@ if(APPLE)
|
|||||||
include_directories("/usr/local/include/")
|
include_directories("/usr/local/include/")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Add linking directories:
|
# Set warning flags
|
||||||
if (UNIX)
|
if(MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast -Werror") # Warning flags
|
# add_compile_options("/W4")
|
||||||
|
# Want to enable warnings eventually, but WAY too much noise right now
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||||
|
add_compile_options("-Wuninitialized" "-Wold-style-cast")
|
||||||
|
else()
|
||||||
|
message(WARNING "Unknown compiler: '${CMAKE_CXX_COMPILER_ID}' - No warning flags enabled.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Add linking directories:
|
||||||
file(
|
file(
|
||||||
GLOB HEADERS_DZONEMANAGER
|
GLOB HEADERS_DZONEMANAGER
|
||||||
LIST_DIRECTORIES false
|
LIST_DIRECTORIES false
|
||||||
@@ -272,6 +319,7 @@ file(
|
|||||||
# Add our library subdirectories for creation of the library object
|
# Add our library subdirectories for creation of the library object
|
||||||
add_subdirectory(dCommon)
|
add_subdirectory(dCommon)
|
||||||
add_subdirectory(dDatabase)
|
add_subdirectory(dDatabase)
|
||||||
|
add_subdirectory(dECS)
|
||||||
add_subdirectory(dChatFilter)
|
add_subdirectory(dChatFilter)
|
||||||
add_subdirectory(dNet)
|
add_subdirectory(dNet)
|
||||||
add_subdirectory(dScripts) # Add for dGame to use
|
add_subdirectory(dScripts) # Add for dGame to use
|
||||||
@@ -282,7 +330,7 @@ add_subdirectory(dPhysics)
|
|||||||
add_subdirectory(dServer)
|
add_subdirectory(dServer)
|
||||||
|
|
||||||
# Create a list of common libraries shared between all binaries
|
# Create a list of common libraries shared between all binaries
|
||||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "MariaDB::ConnCpp" "magic_enum")
|
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "magic_enum::magic_enum")
|
||||||
|
|
||||||
# Add platform specific common libraries
|
# Add platform specific common libraries
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
|
|||||||
@@ -1,128 +1,638 @@
|
|||||||
{
|
{
|
||||||
"version": 3,
|
"version": 6,
|
||||||
"cmakeMinimumRequired": {
|
"cmakeMinimumRequired": {
|
||||||
"major": 3,
|
"major": 3,
|
||||||
"minor": 14,
|
"minor": 25,
|
||||||
"patch": 0
|
"patch": 0
|
||||||
},
|
},
|
||||||
"configurePresets": [
|
"configurePresets": [
|
||||||
{
|
{
|
||||||
"name": "default",
|
"name": "default",
|
||||||
"displayName": "Default configure step",
|
"displayName": "Default configure step",
|
||||||
"description": "Use 'build' dir and Unix makefiles",
|
"description": "Use 'build' dir and Unix makefiles",
|
||||||
"binaryDir": "${sourceDir}/build",
|
"binaryDir": "${sourceDir}/build",
|
||||||
"generator": "Unix Makefiles"
|
"generator": "Unix Makefiles"
|
||||||
},
|
|
||||||
{
|
|
||||||
"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-13",
|
|
||||||
"displayName": "CI configure step for MacOS",
|
|
||||||
"description": "Same as default, Used in GitHub actions workflow",
|
|
||||||
"inherits": "default"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ci-windows-2022",
|
|
||||||
"displayName": "CI configure step for Windows",
|
|
||||||
"description": "Set architecture to 64-bit (b/c RakNet)",
|
|
||||||
"inherits": "default",
|
|
||||||
"generator": "Visual Studio 17 2022",
|
|
||||||
"architecture": {
|
|
||||||
"value": "x64"
|
|
||||||
},
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "windows-default",
|
|
||||||
"inherits": "ci-windows-2022",
|
|
||||||
"displayName": "Windows only Configure Settings",
|
|
||||||
"description": "Sets build and install directories",
|
|
||||||
"generator": "Ninja",
|
|
||||||
"architecture": {
|
|
||||||
"value": "x64",
|
|
||||||
"strategy": "external"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buildPresets": [
|
|
||||||
{
|
|
||||||
"name": "default",
|
|
||||||
"configurePreset": "default",
|
|
||||||
"displayName": "Default Build",
|
|
||||||
"description": "Default Build",
|
|
||||||
"jobs": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ci-windows-2022",
|
|
||||||
"configurePreset": "ci-windows-2022",
|
|
||||||
"displayName": "Windows CI Build",
|
|
||||||
"description": "This preset is used by the CI build on windows",
|
|
||||||
"configuration": "RelWithDebInfo",
|
|
||||||
"jobs": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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-13",
|
|
||||||
"configurePreset": "ci-macos-13",
|
|
||||||
"displayName": "MacOS CI Build",
|
|
||||||
"description": "This preset is used by the CI build on MacOS",
|
|
||||||
"jobs": 2
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"testPresets": [
|
|
||||||
{
|
|
||||||
"name": "ci-ubuntu-22.04",
|
|
||||||
"configurePreset": "ci-ubuntu-22.04",
|
|
||||||
"displayName": "CI Tests on Linux",
|
|
||||||
"description": "Runs all tests on a linux configuration",
|
|
||||||
"execution": {
|
|
||||||
"jobs": 2
|
|
||||||
},
|
},
|
||||||
"output": {
|
{
|
||||||
"outputOnFailure": true
|
"name": "debug-config",
|
||||||
}
|
"hidden": true,
|
||||||
},
|
"cacheVariables": {
|
||||||
{
|
"CMAKE_BUILD_TYPE": "Debug"
|
||||||
"name": "ci-macos-13",
|
|
||||||
"configurePreset": "ci-macos-13",
|
|
||||||
"displayName": "CI Tests on MacOS",
|
|
||||||
"description": "Runs all tests on a Mac configuration",
|
|
||||||
"execution": {
|
|
||||||
"jobs": 2
|
|
||||||
},
|
|
||||||
"output": {
|
|
||||||
"outputOnFailure": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "ci-windows-2022",
|
|
||||||
"configurePreset": "ci-windows-2022",
|
|
||||||
"displayName": "CI Tests on windows",
|
|
||||||
"description": "Runs all tests on a windows configuration",
|
|
||||||
"configuration": "RelWithDebInfo",
|
|
||||||
"execution": {
|
|
||||||
"jobs": 2
|
|
||||||
},
|
|
||||||
"output": {
|
|
||||||
"outputOnFailure": true
|
|
||||||
},
|
|
||||||
"filter": {
|
|
||||||
"exclude": {
|
|
||||||
"name": "((example)|(minigzip))+"
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "relwithdebinfo-config",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "release-config",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clang-config",
|
||||||
|
"hidden": true,
|
||||||
|
"toolchainFile": "${sourceDir}/cmake/toolchains/linux-clang.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "gnu-config",
|
||||||
|
"hidden": true,
|
||||||
|
"toolchainFile": "${sourceDir}/cmake/toolchains/linux-gnu.cmake"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc",
|
||||||
|
"inherits": "default",
|
||||||
|
"displayName": "[Multi] Windows (MSVC)",
|
||||||
|
"description": "Set architecture to 64-bit (b/c RakNet)",
|
||||||
|
"generator": "Visual Studio 17 2022",
|
||||||
|
"binaryDir": "${sourceDir}/build/msvc",
|
||||||
|
"architecture": {
|
||||||
|
"value": "x64"
|
||||||
|
},
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-default",
|
||||||
|
"inherits": "windows-msvc",
|
||||||
|
"displayName": "Windows only Configure Settings",
|
||||||
|
"description": "Sets build and install directories",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
},
|
||||||
|
"architecture": {
|
||||||
|
"value": "x64"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-config",
|
||||||
|
"inherits": "default",
|
||||||
|
"hidden": true,
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Linux"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-debug",
|
||||||
|
"inherits": [
|
||||||
|
"linux-config",
|
||||||
|
"clang-config",
|
||||||
|
"debug-config"
|
||||||
|
],
|
||||||
|
"displayName": "EXPERIMENTAL - [Debug] Linux (Clang)",
|
||||||
|
"description": "Create a debug build using the Clang toolchain for Linux",
|
||||||
|
"binaryDir": "${sourceDir}/build/clang-debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-relwithdebinfo",
|
||||||
|
"inherits": [
|
||||||
|
"linux-config",
|
||||||
|
"clang-config",
|
||||||
|
"relwithdebinfo-config"
|
||||||
|
],
|
||||||
|
"displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)",
|
||||||
|
"description": "Create a release build with debug info using the Clang toolchain for Linux",
|
||||||
|
"binaryDir": "${sourceDir}/build/clang-relwithdebinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-release",
|
||||||
|
"inherits": [
|
||||||
|
"linux-config",
|
||||||
|
"clang-config",
|
||||||
|
"release-config"
|
||||||
|
],
|
||||||
|
"displayName": "EXPERIMENTAL - [Release] Linux (Clang)",
|
||||||
|
"description": "Create a release build using the Clang toolchain for Linux",
|
||||||
|
"binaryDir": "${sourceDir}/build/clang-release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-debug",
|
||||||
|
"inherits": [
|
||||||
|
"linux-config",
|
||||||
|
"gnu-config",
|
||||||
|
"debug-config"
|
||||||
|
],
|
||||||
|
"displayName": "[Debug] Linux (GNU)",
|
||||||
|
"description": "Create a debug build using the GNU toolchain for Linux",
|
||||||
|
"binaryDir": "${sourceDir}/build/gnu-debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-relwithdebinfo",
|
||||||
|
"inherits": [
|
||||||
|
"linux-config",
|
||||||
|
"gnu-config",
|
||||||
|
"relwithdebinfo-config"
|
||||||
|
],
|
||||||
|
"displayName": "[RelWithDebInfo] Linux (GNU)",
|
||||||
|
"description": "Create a release build with debug info using the GNU toolchain for Linux",
|
||||||
|
"binaryDir": "${sourceDir}/build/gnu-relwithdebinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-release",
|
||||||
|
"inherits": [
|
||||||
|
"linux-config",
|
||||||
|
"gnu-config",
|
||||||
|
"release-config"
|
||||||
|
],
|
||||||
|
"displayName": "[Release] Linux (GNU)",
|
||||||
|
"description": "Create a release build using the GNU toolchain for Linux",
|
||||||
|
"binaryDir": "${sourceDir}/build/gnu-release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos",
|
||||||
|
"inherits": "default",
|
||||||
|
"displayName": "[Multi] MacOS",
|
||||||
|
"description": "Create a build for MacOS",
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Darwin"
|
||||||
|
},
|
||||||
|
"binaryDir": "${sourceDir}/build/macos"
|
||||||
}
|
}
|
||||||
}
|
],
|
||||||
]
|
"buildPresets": [
|
||||||
}
|
{
|
||||||
|
"name": "default",
|
||||||
|
"configurePreset": "default",
|
||||||
|
"displayName": "Default Build",
|
||||||
|
"description": "Default Build",
|
||||||
|
"jobs": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-debug",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "windows-msvc",
|
||||||
|
"displayName": "[Debug] Windows (MSVC)",
|
||||||
|
"description": "This preset is used to build in debug mode using the MSVC toolchain on Windows",
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-relwithdebinfo",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "windows-msvc",
|
||||||
|
"displayName": "[RelWithDebInfo] Windows (MSVC)",
|
||||||
|
"description": "This preset is used to build in debug mode using the MSVC toolchain on Windows",
|
||||||
|
"configuration": "RelWithDebInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-release",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "windows-msvc",
|
||||||
|
"displayName": "[Release] Windows (MSVC)",
|
||||||
|
"description": "This preset is used to build in release mode using the MSVC toolchain on Windows",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-debug",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-clang-debug",
|
||||||
|
"displayName": "EXPERIMENTAL - [Debug] Linux (Clang)",
|
||||||
|
"description": "This preset is used to build in debug mode using the Clang toolchain on Linux",
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-relwithdebinfo",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-clang-relwithdebinfo",
|
||||||
|
"displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)",
|
||||||
|
"description": "This preset is used to build in release mode with debug info using the Clang toolchain on Linux",
|
||||||
|
"configuration": "RelWithDebInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-release",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-clang-release",
|
||||||
|
"displayName": "EXPERIMENTAL - [Release] Linux (Clang)",
|
||||||
|
"description": "This preset is used to build in release mode using the Clang toolchain on Linux",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-debug",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-gnu-debug",
|
||||||
|
"displayName": "[Debug] Linux (GNU)",
|
||||||
|
"description": "This preset is used to build in debug mode using the GNU toolchain on Linux",
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-relwithdebinfo",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-gnu-relwithdebinfo",
|
||||||
|
"displayName": "[RelWithDebInfo] Linux (GNU)",
|
||||||
|
"description": "This preset is used to build in release mode with debug info using the GNU toolchain on Linux",
|
||||||
|
"configuration": "RelWithDebInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-release",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-gnu-release",
|
||||||
|
"displayName": "[Release] Linux (GNU)",
|
||||||
|
"description": "This preset is used to build in release mode using the GNU toolchain on Linux",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos-debug",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "macos",
|
||||||
|
"displayName": "[Debug] MacOS",
|
||||||
|
"description": "This preset is used to build in debug mode on MacOS",
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos-relwithdebinfo",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "macos",
|
||||||
|
"displayName": "[RelWithDebInfo] MacOS",
|
||||||
|
"description": "This preset is used to build in release mode with debug info on MacOS",
|
||||||
|
"configuration": "RelWithDebInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos-release",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "macos",
|
||||||
|
"displayName": "[Release] MacOS",
|
||||||
|
"description": "This preset is used to build in release mode on MacOS",
|
||||||
|
"configuration": "Release"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"testPresets": [
|
||||||
|
{
|
||||||
|
"name": "default",
|
||||||
|
"configurePreset": "default",
|
||||||
|
"execution": {
|
||||||
|
"jobs": 2
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"outputOnFailure": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-test",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "windows-msvc",
|
||||||
|
"hidden": true,
|
||||||
|
"filter": {
|
||||||
|
"exclude": {
|
||||||
|
"name": "((example)|(minigzip))+"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-debug",
|
||||||
|
"inherits": "windows-msvc-test",
|
||||||
|
"configurePreset": "windows-msvc",
|
||||||
|
"displayName": "[Debug] Windows (MSVC)",
|
||||||
|
"description": "Runs all tests on a Windows configuration",
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-relwithdebinfo",
|
||||||
|
"inherits": "windows-msvc-test",
|
||||||
|
"configurePreset": "windows-msvc",
|
||||||
|
"displayName": "[RelWithDebInfo] Windows (MSVC)",
|
||||||
|
"description": "Runs all tests on a Windows configuration",
|
||||||
|
"configuration": "RelWithDebInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-release",
|
||||||
|
"inherits": "windows-msvc-test",
|
||||||
|
"configurePreset": "windows-msvc",
|
||||||
|
"displayName": "[Release] Windows (MSVC)",
|
||||||
|
"description": "Runs all tests on a Windows configuration",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-debug",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-clang-debug",
|
||||||
|
"displayName": "EXPERIMENTAL - [Debug] Linux (Clang)",
|
||||||
|
"description": "Runs all tests on a Linux Clang configuration",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-relwithdebinfo",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-clang-relwithdebinfo",
|
||||||
|
"displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)",
|
||||||
|
"description": "Runs all tests on a Linux Clang configuration",
|
||||||
|
"configuration": "RelWithDebInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-release",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-clang-release",
|
||||||
|
"displayName": "EXPERIMENTAL - [Release] Linux (Clang)",
|
||||||
|
"description": "Runs all tests on a Linux Clang configuration",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-debug",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-gnu-debug",
|
||||||
|
"displayName": "[Debug] Linux (GNU)",
|
||||||
|
"description": "Runs all tests on a Linux GNU configuration",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-relwithdebinfo",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-gnu-relwithdebinfo",
|
||||||
|
"displayName": "[RelWithDebInfo] Linux (GNU)",
|
||||||
|
"description": "Runs all tests on a Linux GNU configuration",
|
||||||
|
"configuration": "RelWithDebInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-release",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "linux-gnu-release",
|
||||||
|
"displayName": "[Release] Linux (GNU)",
|
||||||
|
"description": "Runs all tests on a Linux GNU configuration",
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos-debug",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "macos",
|
||||||
|
"displayName": "[Debug] MacOS",
|
||||||
|
"description": "Runs all tests on a MacOS configuration",
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos-relwithdebinfo",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "macos",
|
||||||
|
"displayName": "[RelWithDebInfo] MacOS",
|
||||||
|
"description": "Runs all tests on a MacOS configuration",
|
||||||
|
"configuration": "RelWithDebInfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos-release",
|
||||||
|
"inherits": "default",
|
||||||
|
"configurePreset": "macos",
|
||||||
|
"displayName": "[Release] MacOS",
|
||||||
|
"description": "Runs all tests on a MacOS configuration",
|
||||||
|
"configuration": "Release"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"workflowPresets": [
|
||||||
|
{
|
||||||
|
"name": "default",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "default"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "default"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-debug",
|
||||||
|
"displayName": "[Debug] Windows (MSVC)",
|
||||||
|
"description": "MSVC debug workflow preset for Windows",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "windows-msvc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "windows-msvc-debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "windows-msvc-debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "windows-msvc-relwithdebinfo",
|
||||||
|
"displayName": "[RelWithDebInfo] Windows (MSVC)",
|
||||||
|
"description": "MSVC release with debug info workflow preset for Windows",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "windows-msvc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "windows-msvc-relwithdebinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "windows-msvc-relwithdebinfo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-windows-2022",
|
||||||
|
"displayName": "[Release] Windows (MSVC)",
|
||||||
|
"description": "CI workflow preset for Windows",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "windows-msvc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "windows-msvc-release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "windows-msvc-release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-debug",
|
||||||
|
"displayName": "[Debug] Linux (GNU)",
|
||||||
|
"description": "GNU debug workflow preset for Linux",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "linux-gnu-debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "linux-gnu-debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "linux-gnu-debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-gnu-relwithdebinfo",
|
||||||
|
"displayName": "[RelWithDebInfo] Linux (GNU)",
|
||||||
|
"description": "GNU release with debug info workflow preset for Linux",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "linux-gnu-relwithdebinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "linux-gnu-relwithdebinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "linux-gnu-relwithdebinfo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-ubuntu-22.04",
|
||||||
|
"displayName": "[Release] Linux (GNU)",
|
||||||
|
"description": "CI workflow preset for Ubuntu",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "linux-gnu-release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "linux-gnu-release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "linux-gnu-release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-debug",
|
||||||
|
"displayName": "EXPERIMENTAL - [Debug] Linux (Clang)",
|
||||||
|
"description": "Clang debug workflow preset for Linux",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "linux-clang-debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "linux-clang-debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "linux-clang-debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-relwithdebinfo",
|
||||||
|
"displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)",
|
||||||
|
"description": "Clang release with debug info workflow preset for Linux",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "linux-clang-relwithdebinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "linux-clang-relwithdebinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "linux-clang-relwithdebinfo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "linux-clang-release",
|
||||||
|
"displayName": "EXPERIMENTAL - [Release] Linux (Clang)",
|
||||||
|
"description": "Clang release workflow preset for Linux",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "linux-clang-release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "linux-clang-release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "linux-clang-release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos-debug",
|
||||||
|
"displayName": "[Debug] MacOS",
|
||||||
|
"description": "Release workflow preset for MacOS",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "macos"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "macos-debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "macos-debug"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macos-relwithdebinfo",
|
||||||
|
"displayName": "[RelWithDebInfo] MacOS",
|
||||||
|
"description": "Release with debug info workflow preset for MacOS",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "macos"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "macos-relwithdebinfo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "macos-relwithdebinfo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-macos-13",
|
||||||
|
"displayName": "[Release] MacOS",
|
||||||
|
"description": "CI workflow preset for MacOS",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"type": "configure",
|
||||||
|
"name": "macos"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "build",
|
||||||
|
"name": "macos-release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "test",
|
||||||
|
"name": "macos-release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
PROJECT_VERSION_MAJOR=1
|
PROJECT_VERSION_MAJOR=2
|
||||||
PROJECT_VERSION_MINOR=1
|
PROJECT_VERSION_MINOR=3
|
||||||
PROJECT_VERSION_PATCH=1
|
PROJECT_VERSION_PATCH=0
|
||||||
|
|
||||||
# Debugging
|
# Debugging
|
||||||
# Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
# Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ COPY --from=build /app/build/*Server /app/
|
|||||||
|
|
||||||
# Necessary suplimentary files
|
# Necessary suplimentary files
|
||||||
COPY --from=build /app/build/*.ini /app/configs/
|
COPY --from=build /app/build/*.ini /app/configs/
|
||||||
COPY --from=build /app/build/vanity/*.* /app/vanity/*
|
COPY --from=build /app/build/vanity/*.* /app/vanity/
|
||||||
COPY --from=build /app/build/navmeshes /app/navmeshes
|
COPY --from=build /app/build/navmeshes /app/navmeshes
|
||||||
COPY --from=build /app/build/migrations /app/migrations
|
COPY --from=build /app/build/migrations /app/migrations
|
||||||
COPY --from=build /app/build/*.dcf /app/
|
COPY --from=build /app/build/*.dcf /app/
|
||||||
@@ -39,7 +39,7 @@ COPY --from=build /app/build/*.dcf /app/
|
|||||||
# backup of config and vanity files to copy to the host incase
|
# backup of config and vanity files to copy to the host incase
|
||||||
# of a mount clobbering the copy from above
|
# of a mount clobbering the copy from above
|
||||||
COPY --from=build /app/build/*.ini /app/default-configs/
|
COPY --from=build /app/build/*.ini /app/default-configs/
|
||||||
COPY --from=build /app/build/vanity/*.* /app/default-vanity/*
|
COPY --from=build /app/build/vanity/*.* /app/default-vanity/
|
||||||
|
|
||||||
# needed as the container runs with the root user
|
# needed as the container runs with the root user
|
||||||
# and therefore sudo doesn't exist
|
# and therefore sudo doesn't exist
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-serve
|
|||||||
```
|
```
|
||||||
|
|
||||||
#### Required CMake version
|
#### Required CMake version
|
||||||
This project uses <font size="4">**CMake version 3.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.
|
You can check your CMake version by using the following command in a terminal.
|
||||||
```bash
|
```bash
|
||||||
cmake --version
|
cmake --version
|
||||||
@@ -371,7 +371,7 @@ at once. For that:
|
|||||||
- Download the [.env.example](.env.example) file and place it next to `client` with the file name `.env`
|
- 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).
|
- 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.
|
- Update the `ACCOUNT_MANAGER_SECRET` and `MARIADB_PASSWORD` with strong random passwords.
|
||||||
- Use a password generator like <https://keygen.io>
|
- Use a password generator <https://gchq.github.io/CyberChef/#recipe=Pseudo-Random_Number_Generator(256,'Hex')>
|
||||||
- Avoid `:` and `@` characters
|
- Avoid `:` and `@` characters
|
||||||
- Once the database user is created, changing the password will not update it, so the server will just fail to connect.
|
- 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
|
- Set `EXTERNAL_IP` to your LAN IP or public IP if you want to host the game for friends & family
|
||||||
|
|||||||
3
build.sh
3
build.sh
@@ -6,8 +6,7 @@ mkdir -p build
|
|||||||
cd build
|
cd build
|
||||||
|
|
||||||
# Run cmake to generate make files
|
# Run cmake to generate make files
|
||||||
cmake ..
|
cmake -DCMAKE_BUILD_TYPE="Release" ..
|
||||||
|
|
||||||
# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8'
|
# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8'
|
||||||
cmake --build . --config Release $1
|
cmake --build . --config Release $1
|
||||||
|
|
||||||
|
|||||||
14
cmake/toolchains/linux-clang.cmake
Normal file
14
cmake/toolchains/linux-clang.cmake
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Try and find a clang-16 install, falling back to a generic clang install otherwise
|
||||||
|
find_program(CLANG_C_COMPILER clang-16 | clang REQUIRED)
|
||||||
|
find_program(CLANG_CXX_COMPILER clang++-16 | clang++ REQUIRED)
|
||||||
|
|
||||||
|
# Debug messages
|
||||||
|
message(DEBUG "CLANG_C_COMPILER = ${CLANG_C_COMPILER}")
|
||||||
|
message(DEBUG "CLANG_CXX_COMPILER = ${CLANG_CXX_COMPILER}")
|
||||||
|
|
||||||
|
# Set compilers to clang (need to cache for VSCode tools to work correctly)
|
||||||
|
set(CMAKE_C_COMPILER ${CLANG_C_COMPILER} CACHE STRING "Set C compiler")
|
||||||
|
set(CMAKE_CXX_COMPILER ${CLANG_CXX_COMPILER} CACHE STRING "Set C++ compiler")
|
||||||
|
|
||||||
|
# Set linker to lld
|
||||||
|
add_link_options("-fuse-ld=lld")
|
||||||
11
cmake/toolchains/linux-gnu.cmake
Normal file
11
cmake/toolchains/linux-gnu.cmake
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Try and find a gcc/g++ install
|
||||||
|
find_program(GNU_C_COMPILER cc | gcc REQUIRED)
|
||||||
|
find_program(GNU_CXX_COMPILER c++ | g++ REQUIRED)
|
||||||
|
|
||||||
|
# Debug messages
|
||||||
|
message(DEBUG "GNU_C_COMPILER = ${GNU_C_COMPILER}")
|
||||||
|
message(DEBUG "GNU_CXX_COMPILER = ${GNU_CXX_COMPILER}")
|
||||||
|
|
||||||
|
# Set compilers to GNU (need to cache for VSCode tools to work correctly)
|
||||||
|
set(CMAKE_C_COMPILER ${GNU_C_COMPILER} CACHE STRING "Set C compiler")
|
||||||
|
set(CMAKE_CXX_COMPILER ${GNU_CXX_COMPILER} CACHE STRING "Set C++ compiler")
|
||||||
@@ -21,8 +21,8 @@
|
|||||||
//Auth includes:
|
//Auth includes:
|
||||||
#include "AuthPackets.h"
|
#include "AuthPackets.h"
|
||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "eServerMessageType.h"
|
#include "MessageType/Server.h"
|
||||||
#include "eAuthMessageType.h"
|
#include "MessageType/Auth.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Server.h"
|
#include "Server.h"
|
||||||
@@ -60,7 +60,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Database::Connect();
|
Database::Connect();
|
||||||
} catch (sql::SQLException& ex) {
|
} catch (std::exception& ex) {
|
||||||
LOG("Got an error while connecting to the database: %s", ex.what());
|
LOG("Got an error while connecting to the database: %s", ex.what());
|
||||||
Database::Destroy("AuthServer");
|
Database::Destroy("AuthServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
@@ -166,11 +166,11 @@ void HandlePacket(Packet* packet) {
|
|||||||
|
|
||||||
if (packet->data[0] == ID_USER_PACKET_ENUM) {
|
if (packet->data[0] == ID_USER_PACKET_ENUM) {
|
||||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) {
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) {
|
||||||
if (static_cast<eServerMessageType>(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) {
|
if (static_cast<MessageType::Server>(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) {
|
||||||
AuthPackets::HandleHandshake(Game::server, packet);
|
AuthPackets::HandleHandshake(Game::server, packet);
|
||||||
}
|
}
|
||||||
} else if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::AUTH) {
|
} else if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::AUTH) {
|
||||||
if (static_cast<eAuthMessageType>(packet->data[3]) == eAuthMessageType::LOGIN_REQUEST) {
|
if (static_cast<MessageType::Auth>(packet->data[3]) == MessageType::Auth::LOGIN_REQUEST) {
|
||||||
AuthPackets::HandleLoginRequest(Game::server, packet);
|
AuthPackets::HandleLoginRequest(Game::server, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
|
|||||||
ExportWordlistToDCF(filepath + ".dcf", true);
|
ExportWordlistToDCF(filepath + ".dcf", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BinaryIO::DoesFileExist("blacklist.dcf")) {
|
if (BinaryIO::DoesFileExist("blocklist.dcf")) {
|
||||||
ReadWordlistDCF("blacklist.dcf", false);
|
ReadWordlistDCF("blocklist.dcf", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read player names that are ok as well:
|
//Read player names that are ok as well:
|
||||||
@@ -44,20 +44,20 @@ dChatFilter::~dChatFilter() {
|
|||||||
m_DeniedWords.clear();
|
m_DeniedWords.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) {
|
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool allowList) {
|
||||||
std::ifstream file(filepath);
|
std::ifstream file(filepath);
|
||||||
if (file) {
|
if (file) {
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(file, line)) {
|
||||||
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
||||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
||||||
if (whiteList) m_ApprovedWords.push_back(CalculateHash(line));
|
if (allowList) m_ApprovedWords.push_back(CalculateHash(line));
|
||||||
else m_DeniedWords.push_back(CalculateHash(line));
|
else m_DeniedWords.push_back(CalculateHash(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool allowList) {
|
||||||
std::ifstream file(filepath, std::ios::binary);
|
std::ifstream file(filepath, std::ios::binary);
|
||||||
if (file) {
|
if (file) {
|
||||||
fileHeader hdr;
|
fileHeader hdr;
|
||||||
@@ -70,13 +70,13 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
|||||||
if (hdr.formatVersion == formatVersion) {
|
if (hdr.formatVersion == formatVersion) {
|
||||||
size_t wordsToRead = 0;
|
size_t wordsToRead = 0;
|
||||||
BinaryIO::BinaryRead(file, wordsToRead);
|
BinaryIO::BinaryRead(file, wordsToRead);
|
||||||
if (whiteList) m_ApprovedWords.reserve(wordsToRead);
|
if (allowList) m_ApprovedWords.reserve(wordsToRead);
|
||||||
else m_DeniedWords.reserve(wordsToRead);
|
else m_DeniedWords.reserve(wordsToRead);
|
||||||
|
|
||||||
size_t word = 0;
|
size_t word = 0;
|
||||||
for (size_t i = 0; i < wordsToRead; ++i) {
|
for (size_t i = 0; i < wordsToRead; ++i) {
|
||||||
BinaryIO::BinaryRead(file, word);
|
BinaryIO::BinaryRead(file, word);
|
||||||
if (whiteList) m_ApprovedWords.push_back(word);
|
if (allowList) m_ApprovedWords.push_back(word);
|
||||||
else m_DeniedWords.push_back(word);
|
else m_DeniedWords.push_back(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,14 +90,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
|||||||
return false;
|
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);
|
std::ofstream file(filepath, std::ios::binary | std::ios_base::out);
|
||||||
if (file) {
|
if (file) {
|
||||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
|
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
|
||||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
|
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
|
||||||
BinaryIO::BinaryWrite(file, size_t(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);
|
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 (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
|
||||||
if (message.empty()) return { };
|
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::stringstream sMessage(message);
|
||||||
std::string segment;
|
std::string segment;
|
||||||
@@ -126,16 +126,16 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
|
|||||||
|
|
||||||
size_t hash = CalculateHash(segment);
|
size_t hash = CalculateHash(segment);
|
||||||
|
|
||||||
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) {
|
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && allowList) {
|
||||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) {
|
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && allowList) {
|
||||||
m_UserUnapprovedWordCache.push_back(hash);
|
m_UserUnapprovedWordCache.push_back(hash);
|
||||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) {
|
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !allowList) {
|
||||||
m_UserUnapprovedWordCache.push_back(hash);
|
m_UserUnapprovedWordCache.push_back(hash);
|
||||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ public:
|
|||||||
dChatFilter(const std::string& filepath, bool dontGenerateDCF);
|
dChatFilter(const std::string& filepath, bool dontGenerateDCF);
|
||||||
~dChatFilter();
|
~dChatFilter();
|
||||||
|
|
||||||
void ReadWordlistPlaintext(const std::string& filepath, bool whiteList);
|
void ReadWordlistPlaintext(const std::string& filepath, bool allowList);
|
||||||
bool ReadWordlistDCF(const std::string& filepath, bool whiteList);
|
bool ReadWordlistDCF(const std::string& filepath, bool allowList);
|
||||||
void ExportWordlistToDCF(const std::string& filepath, bool whiteList);
|
void ExportWordlistToDCF(const std::string& filepath, bool allowList);
|
||||||
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true);
|
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_DontGenerateDCF;
|
bool m_DontGenerateDCF;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "ChatIgnoreList.h"
|
#include "ChatIgnoreList.h"
|
||||||
#include "PlayerContainer.h"
|
#include "PlayerContainer.h"
|
||||||
#include "eChatInternalMessageType.h"
|
#include "MessageType/Chat.h"
|
||||||
#include "BitStreamUtils.h"
|
#include "BitStreamUtils.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
// The only thing not auto-handled is instance activities force joining the team on the server.
|
// The only thing not auto-handled is instance activities force joining the team on the server.
|
||||||
|
|
||||||
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) {
|
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) {
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receivingPlayer);
|
bitStream.Write(receivingPlayer);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
#include "eObjectBits.h"
|
#include "eObjectBits.h"
|
||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "eChatMessageType.h"
|
#include "MessageType/Chat.h"
|
||||||
#include "eChatInternalMessageType.h"
|
#include "MessageType/Client.h"
|
||||||
#include "eClientMessageType.h"
|
#include "MessageType/Game.h"
|
||||||
#include "eGameMessageType.h"
|
|
||||||
#include "StringifiedEnum.h"
|
#include "StringifiedEnum.h"
|
||||||
#include "eGameMasterLevel.h"
|
#include "eGameMasterLevel.h"
|
||||||
|
#include "ChatPackets.h"
|
||||||
|
|
||||||
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||||
//Get from the packet which player we want to do something with:
|
//Get from the packet which player we want to do something with:
|
||||||
@@ -60,11 +60,11 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
|||||||
|
|
||||||
//Now, we need to send the friendlist to the server they came from:
|
//Now, we need to send the friendlist to the server they came from:
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(playerID);
|
bitStream.Write(playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GET_FRIENDS_LIST_RESPONSE);
|
||||||
bitStream.Write<uint8_t>(0);
|
bitStream.Write<uint8_t>(0);
|
||||||
bitStream.Write<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it.
|
bitStream.Write<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it.
|
||||||
bitStream.Write<uint16_t>(player.friends.size());
|
bitStream.Write<uint16_t>(player.friends.size());
|
||||||
@@ -355,6 +355,67 @@ void ChatPacketHandler::HandleGMLevelUpdate(Packet* packet) {
|
|||||||
inStream.Read(player.gmLevel);
|
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, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
|
bitStream.Write(request.requestor);
|
||||||
|
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::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, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
|
bitStream.Write(request.requestor);
|
||||||
|
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::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
|
// 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
|
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages
|
||||||
void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||||
@@ -454,10 +515,10 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
|||||||
|
|
||||||
void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) {
|
void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(routeTo.playerID);
|
bitStream.Write(routeTo.playerID);
|
||||||
|
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::PRIVATE_CHAT_MESSAGE);
|
||||||
bitStream.Write(sender.playerID);
|
bitStream.Write(sender.playerID);
|
||||||
bitStream.Write(channel);
|
bitStream.Write(channel);
|
||||||
bitStream.Write<uint32_t>(0); // not used
|
bitStream.Write<uint32_t>(0); // not used
|
||||||
@@ -696,11 +757,11 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
|||||||
|
|
||||||
void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) {
|
void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TEAM_INVITE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::TEAM_INVITE);
|
||||||
|
|
||||||
bitStream.Write(LUWString(sender.playerName.c_str()));
|
bitStream.Write(LUWString(sender.playerName.c_str()));
|
||||||
bitStream.Write(sender.playerID);
|
bitStream.Write(sender.playerID);
|
||||||
@@ -711,14 +772,14 @@ void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerD
|
|||||||
|
|
||||||
void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
|
void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
CMSGHEADER;
|
CMSGHEADER;
|
||||||
|
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
bitStream.Write(eGameMessageType::TEAM_INVITE_CONFIRM);
|
bitStream.Write(MessageType::Game::TEAM_INVITE_CONFIRM);
|
||||||
|
|
||||||
bitStream.Write(bLeaderIsFreeTrial);
|
bitStream.Write(bLeaderIsFreeTrial);
|
||||||
bitStream.Write(i64LeaderID);
|
bitStream.Write(i64LeaderID);
|
||||||
@@ -738,14 +799,14 @@ void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool b
|
|||||||
|
|
||||||
void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
|
void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
CMSGHEADER;
|
CMSGHEADER;
|
||||||
|
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
bitStream.Write(eGameMessageType::TEAM_GET_STATUS_RESPONSE);
|
bitStream.Write(MessageType::Game::TEAM_GET_STATUS_RESPONSE);
|
||||||
|
|
||||||
bitStream.Write(i64LeaderID);
|
bitStream.Write(i64LeaderID);
|
||||||
bitStream.Write(i64LeaderZoneID);
|
bitStream.Write(i64LeaderZoneID);
|
||||||
@@ -763,14 +824,14 @@ void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64L
|
|||||||
|
|
||||||
void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) {
|
void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
CMSGHEADER;
|
CMSGHEADER;
|
||||||
|
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
bitStream.Write(eGameMessageType::TEAM_SET_LEADER);
|
bitStream.Write(MessageType::Game::TEAM_SET_LEADER);
|
||||||
|
|
||||||
bitStream.Write(i64PlayerID);
|
bitStream.Write(i64PlayerID);
|
||||||
|
|
||||||
@@ -780,14 +841,14 @@ void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i
|
|||||||
|
|
||||||
void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
|
void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
CMSGHEADER;
|
CMSGHEADER;
|
||||||
|
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
bitStream.Write(eGameMessageType::TEAM_ADD_PLAYER);
|
bitStream.Write(MessageType::Game::TEAM_ADD_PLAYER);
|
||||||
|
|
||||||
bitStream.Write(bIsFreeTrial);
|
bitStream.Write(bIsFreeTrial);
|
||||||
bitStream.Write(bLocal);
|
bitStream.Write(bLocal);
|
||||||
@@ -809,14 +870,14 @@ void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFr
|
|||||||
|
|
||||||
void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
|
void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
CMSGHEADER;
|
CMSGHEADER;
|
||||||
|
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
bitStream.Write(eGameMessageType::TEAM_REMOVE_PLAYER);
|
bitStream.Write(MessageType::Game::TEAM_REMOVE_PLAYER);
|
||||||
|
|
||||||
bitStream.Write(bDisband);
|
bitStream.Write(bDisband);
|
||||||
bitStream.Write(bIsKicked);
|
bitStream.Write(bIsKicked);
|
||||||
@@ -835,14 +896,14 @@ void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bD
|
|||||||
|
|
||||||
void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
|
void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
CMSGHEADER;
|
CMSGHEADER;
|
||||||
|
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
bitStream.Write(eGameMessageType::TEAM_SET_OFF_WORLD_FLAG);
|
bitStream.Write(MessageType::Game::TEAM_SET_OFF_WORLD_FLAG);
|
||||||
|
|
||||||
bitStream.Write(i64PlayerID);
|
bitStream.Write(i64PlayerID);
|
||||||
if (receiver.zoneID.GetCloneID() == zoneID.GetCloneID()) {
|
if (receiver.zoneID.GetCloneID() == zoneID.GetCloneID()) {
|
||||||
@@ -869,11 +930,11 @@ void ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const Pla
|
|||||||
[bool] - is FTP*/
|
[bool] - is FTP*/
|
||||||
|
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(friendData.playerID);
|
bitStream.Write(friendData.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::UPDATE_FRIEND_NOTIFY);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::UPDATE_FRIEND_NOTIFY);
|
||||||
bitStream.Write<uint8_t>(notifyType);
|
bitStream.Write<uint8_t>(notifyType);
|
||||||
|
|
||||||
std::string playerName = playerData.playerName.c_str();
|
std::string playerName = playerData.playerName.c_str();
|
||||||
@@ -906,11 +967,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
|
|||||||
}
|
}
|
||||||
|
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_REQUEST);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::ADD_FRIEND_REQUEST);
|
||||||
bitStream.Write(LUWString(sender.playerName));
|
bitStream.Write(LUWString(sender.playerName));
|
||||||
bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
|
bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
|
||||||
|
|
||||||
@@ -920,11 +981,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
|
|||||||
|
|
||||||
void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
|
void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
// Portion that will get routed:
|
// Portion that will get routed:
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_RESPONSE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::ADD_FRIEND_RESPONSE);
|
||||||
bitStream.Write(responseCode);
|
bitStream.Write(responseCode);
|
||||||
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
|
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
|
||||||
bitStream.Write<uint8_t>(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender.sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
|
bitStream.Write<uint8_t>(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender.sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
@@ -943,11 +1004,11 @@ void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const Pla
|
|||||||
|
|
||||||
void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) {
|
void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||||
bitStream.Write(receiver.playerID);
|
bitStream.Write(receiver.playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::REMOVE_FRIEND_RESPONSE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::REMOVE_FRIEND_RESPONSE);
|
||||||
bitStream.Write<uint8_t>(isSuccessful); //isOnline
|
bitStream.Write<uint8_t>(isSuccessful); //isOnline
|
||||||
bitStream.Write(LUWString(personToRemove));
|
bitStream.Write(LUWString(personToRemove));
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ namespace ChatPacketHandler {
|
|||||||
void HandleFriendResponse(Packet* packet);
|
void HandleFriendResponse(Packet* packet);
|
||||||
void HandleRemoveFriend(Packet* packet);
|
void HandleRemoveFriend(Packet* packet);
|
||||||
void HandleGMLevelUpdate(Packet* packet);
|
void HandleGMLevelUpdate(Packet* packet);
|
||||||
|
void HandleWho(Packet* packet);
|
||||||
|
void HandleShowAll(Packet* packet);
|
||||||
|
|
||||||
void HandleChatMessage(Packet* packet);
|
void HandleChatMessage(Packet* packet);
|
||||||
void HandlePrivateChatMessage(Packet* packet);
|
void HandlePrivateChatMessage(Packet* packet);
|
||||||
|
|||||||
@@ -16,9 +16,8 @@
|
|||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "PlayerContainer.h"
|
#include "PlayerContainer.h"
|
||||||
#include "ChatPacketHandler.h"
|
#include "ChatPacketHandler.h"
|
||||||
#include "eChatMessageType.h"
|
#include "MessageType/Chat.h"
|
||||||
#include "eChatInternalMessageType.h"
|
#include "MessageType/World.h"
|
||||||
#include "eWorldMessageType.h"
|
|
||||||
#include "ChatIgnoreList.h"
|
#include "ChatIgnoreList.h"
|
||||||
#include "StringifiedEnum.h"
|
#include "StringifiedEnum.h"
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ int main(int argc, char** argv) {
|
|||||||
//Connect to the MySQL Database
|
//Connect to the MySQL Database
|
||||||
try {
|
try {
|
||||||
Database::Connect();
|
Database::Connect();
|
||||||
} catch (sql::SQLException& ex) {
|
} catch (std::exception& ex) {
|
||||||
LOG("Got an error while connecting to the database: %s", ex.what());
|
LOG("Got an error while connecting to the database: %s", ex.what());
|
||||||
Database::Destroy("ChatServer");
|
Database::Destroy("ChatServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
@@ -180,185 +179,168 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandlePacket(Packet* packet) {
|
void HandlePacket(Packet* packet) {
|
||||||
|
if (packet->length < 1) return;
|
||||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||||
LOG("A server has disconnected, erasing their connected players from the list.");
|
LOG("A server has disconnected, erasing their connected players from the list.");
|
||||||
}
|
} else if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
||||||
|
|
||||||
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
|
||||||
LOG("A server is connecting, awaiting user list.");
|
LOG("A server is connecting, awaiting user list.");
|
||||||
}
|
} else if (packet->length < 4 || packet->data[0] != ID_USER_PACKET_ENUM) return; // Nothing left to process or not the right packet type
|
||||||
|
|
||||||
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) {
|
eConnectionType connection;
|
||||||
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
MessageType::Chat chatMessageID;
|
||||||
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
|
||||||
Game::playerContainer.InsertPlayer(packet);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
inStream.Read(connection);
|
||||||
Game::playerContainer.RemovePlayer(packet);
|
if (connection != eConnectionType::CHAT) return;
|
||||||
break;
|
inStream.Read(chatMessageID);
|
||||||
|
|
||||||
case eChatInternalMessageType::MUTE_UPDATE:
|
switch (chatMessageID) {
|
||||||
|
case MessageType::Chat::GM_MUTE:
|
||||||
Game::playerContainer.MuteUpdate(packet);
|
Game::playerContainer.MuteUpdate(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::CREATE_TEAM:
|
case MessageType::Chat::CREATE_TEAM:
|
||||||
Game::playerContainer.CreateTeamServer(packet);
|
Game::playerContainer.CreateTeamServer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::ANNOUNCEMENT: {
|
case MessageType::Chat::GET_FRIENDS_LIST:
|
||||||
//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) {
|
|
||||||
eChatMessageType chat_message_type = static_cast<eChatMessageType>(packet->data[3]);
|
|
||||||
switch (chat_message_type) {
|
|
||||||
case eChatMessageType::GET_FRIENDS_LIST:
|
|
||||||
ChatPacketHandler::HandleFriendlistRequest(packet);
|
ChatPacketHandler::HandleFriendlistRequest(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::GET_IGNORE_LIST:
|
case MessageType::Chat::GET_IGNORE_LIST:
|
||||||
ChatIgnoreList::GetIgnoreList(packet);
|
ChatIgnoreList::GetIgnoreList(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::ADD_IGNORE:
|
case MessageType::Chat::ADD_IGNORE:
|
||||||
ChatIgnoreList::AddIgnore(packet);
|
ChatIgnoreList::AddIgnore(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::REMOVE_IGNORE:
|
case MessageType::Chat::REMOVE_IGNORE:
|
||||||
ChatIgnoreList::RemoveIgnore(packet);
|
ChatIgnoreList::RemoveIgnore(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_GET_STATUS:
|
case MessageType::Chat::TEAM_GET_STATUS:
|
||||||
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::ADD_FRIEND_REQUEST:
|
case MessageType::Chat::ADD_FRIEND_REQUEST:
|
||||||
//this involves someone sending the initial request, the response is below, response as in from the other player.
|
//this involves someone sending the initial request, the response is below, response as in from the other player.
|
||||||
//We basically just check to see if this player is online or not and route the packet.
|
//We basically just check to see if this player is online or not and route the packet.
|
||||||
ChatPacketHandler::HandleFriendRequest(packet);
|
ChatPacketHandler::HandleFriendRequest(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::ADD_FRIEND_RESPONSE:
|
case MessageType::Chat::ADD_FRIEND_RESPONSE:
|
||||||
//This isn't the response a server sent, rather it is a player's response to a received request.
|
//This isn't the response a server sent, rather it is a player's response to a received request.
|
||||||
//Here, we'll actually have to add them to eachother's friend lists depending on the response code.
|
//Here, we'll actually have to add them to eachother's friend lists depending on the response code.
|
||||||
ChatPacketHandler::HandleFriendResponse(packet);
|
ChatPacketHandler::HandleFriendResponse(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::REMOVE_FRIEND:
|
case MessageType::Chat::REMOVE_FRIEND:
|
||||||
ChatPacketHandler::HandleRemoveFriend(packet);
|
ChatPacketHandler::HandleRemoveFriend(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::GENERAL_CHAT_MESSAGE:
|
case MessageType::Chat::GENERAL_CHAT_MESSAGE:
|
||||||
ChatPacketHandler::HandleChatMessage(packet);
|
ChatPacketHandler::HandleChatMessage(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::PRIVATE_CHAT_MESSAGE:
|
case MessageType::Chat::PRIVATE_CHAT_MESSAGE:
|
||||||
//This message is supposed to be echo'd to both the sender and the receiver
|
//This message is supposed to be echo'd to both the sender and the receiver
|
||||||
//BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up.
|
//BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up.
|
||||||
ChatPacketHandler::HandlePrivateChatMessage(packet);
|
ChatPacketHandler::HandlePrivateChatMessage(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_INVITE:
|
case MessageType::Chat::TEAM_INVITE:
|
||||||
ChatPacketHandler::HandleTeamInvite(packet);
|
ChatPacketHandler::HandleTeamInvite(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_INVITE_RESPONSE:
|
case MessageType::Chat::TEAM_INVITE_RESPONSE:
|
||||||
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_LEAVE:
|
case MessageType::Chat::TEAM_LEAVE:
|
||||||
ChatPacketHandler::HandleTeamLeave(packet);
|
ChatPacketHandler::HandleTeamLeave(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_SET_LEADER:
|
case MessageType::Chat::TEAM_SET_LEADER:
|
||||||
ChatPacketHandler::HandleTeamPromote(packet);
|
ChatPacketHandler::HandleTeamPromote(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_KICK:
|
case MessageType::Chat::TEAM_KICK:
|
||||||
ChatPacketHandler::HandleTeamKick(packet);
|
ChatPacketHandler::HandleTeamKick(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_SET_LOOT:
|
case MessageType::Chat::TEAM_SET_LOOT:
|
||||||
ChatPacketHandler::HandleTeamLootOption(packet);
|
ChatPacketHandler::HandleTeamLootOption(packet);
|
||||||
break;
|
break;
|
||||||
case eChatMessageType::GMLEVEL_UPDATE:
|
case MessageType::Chat::GMLEVEL_UPDATE:
|
||||||
ChatPacketHandler::HandleGMLevelUpdate(packet);
|
ChatPacketHandler::HandleGMLevelUpdate(packet);
|
||||||
break;
|
break;
|
||||||
case eChatMessageType::LOGIN_SESSION_NOTIFY:
|
case MessageType::Chat::LOGIN_SESSION_NOTIFY:
|
||||||
case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE:
|
Game::playerContainer.InsertPlayer(packet);
|
||||||
case eChatMessageType::WORLD_DISCONNECT_REQUEST:
|
break;
|
||||||
case eChatMessageType::WORLD_PROXIMITY_RESPONSE:
|
case MessageType::Chat::GM_ANNOUNCE:{
|
||||||
case eChatMessageType::WORLD_PARCEL_RESPONSE:
|
// we just forward this packet to every connected server
|
||||||
case eChatMessageType::TEAM_MISSED_INVITE_CHECK:
|
inStream.ResetReadPointer();
|
||||||
case eChatMessageType::GUILD_CREATE:
|
Game::server->Send(inStream, packet->systemAddress, true); // send to everyone except origin
|
||||||
case eChatMessageType::GUILD_INVITE:
|
}
|
||||||
case eChatMessageType::GUILD_INVITE_RESPONSE:
|
break;
|
||||||
case eChatMessageType::GUILD_LEAVE:
|
case MessageType::Chat::UNEXPECTED_DISCONNECT:
|
||||||
case eChatMessageType::GUILD_KICK:
|
Game::playerContainer.RemovePlayer(packet);
|
||||||
case eChatMessageType::GUILD_GET_STATUS:
|
break;
|
||||||
case eChatMessageType::GUILD_GET_ALL:
|
case MessageType::Chat::WHO:
|
||||||
case eChatMessageType::SHOW_ALL:
|
ChatPacketHandler::HandleWho(packet);
|
||||||
case eChatMessageType::BLUEPRINT_MODERATED:
|
break;
|
||||||
case eChatMessageType::BLUEPRINT_MODEL_READY:
|
case MessageType::Chat::SHOW_ALL:
|
||||||
case eChatMessageType::PROPERTY_READY_FOR_APPROVAL:
|
ChatPacketHandler::HandleShowAll(packet);
|
||||||
case eChatMessageType::PROPERTY_MODERATION_CHANGED:
|
break;
|
||||||
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED:
|
case MessageType::Chat::USER_CHANNEL_CHAT_MESSAGE:
|
||||||
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED_REPORT:
|
case MessageType::Chat::WORLD_DISCONNECT_REQUEST:
|
||||||
case eChatMessageType::MAIL:
|
case MessageType::Chat::WORLD_PROXIMITY_RESPONSE:
|
||||||
case eChatMessageType::WORLD_INSTANCE_LOCATION_REQUEST:
|
case MessageType::Chat::WORLD_PARCEL_RESPONSE:
|
||||||
case eChatMessageType::REPUTATION_UPDATE:
|
case MessageType::Chat::TEAM_MISSED_INVITE_CHECK:
|
||||||
case eChatMessageType::SEND_CANNED_TEXT:
|
case MessageType::Chat::GUILD_CREATE:
|
||||||
case eChatMessageType::CHARACTER_NAME_CHANGE_REQUEST:
|
case MessageType::Chat::GUILD_INVITE:
|
||||||
case eChatMessageType::CSR_REQUEST:
|
case MessageType::Chat::GUILD_INVITE_RESPONSE:
|
||||||
case eChatMessageType::CSR_REPLY:
|
case MessageType::Chat::GUILD_LEAVE:
|
||||||
case eChatMessageType::GM_KICK:
|
case MessageType::Chat::GUILD_KICK:
|
||||||
case eChatMessageType::GM_ANNOUNCE:
|
case MessageType::Chat::GUILD_GET_STATUS:
|
||||||
case eChatMessageType::WORLD_ROUTE_PACKET:
|
case MessageType::Chat::GUILD_GET_ALL:
|
||||||
case eChatMessageType::GET_ZONE_POPULATIONS:
|
case MessageType::Chat::BLUEPRINT_MODERATED:
|
||||||
case eChatMessageType::REQUEST_MINIMUM_CHAT_MODE:
|
case MessageType::Chat::BLUEPRINT_MODEL_READY:
|
||||||
case eChatMessageType::MATCH_REQUEST:
|
case MessageType::Chat::PROPERTY_READY_FOR_APPROVAL:
|
||||||
case eChatMessageType::UGCMANIFEST_REPORT_MISSING_FILE:
|
case MessageType::Chat::PROPERTY_MODERATION_CHANGED:
|
||||||
case eChatMessageType::UGCMANIFEST_REPORT_DONE_FILE:
|
case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED:
|
||||||
case eChatMessageType::UGCMANIFEST_REPORT_DONE_BLUEPRINT:
|
case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED_REPORT:
|
||||||
case eChatMessageType::UGCC_REQUEST:
|
case MessageType::Chat::MAIL:
|
||||||
case eChatMessageType::WHO:
|
case MessageType::Chat::WORLD_INSTANCE_LOCATION_REQUEST:
|
||||||
case eChatMessageType::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE:
|
case MessageType::Chat::REPUTATION_UPDATE:
|
||||||
case eChatMessageType::ACHIEVEMENT_NOTIFY:
|
case MessageType::Chat::SEND_CANNED_TEXT:
|
||||||
case eChatMessageType::GM_CLOSE_PRIVATE_CHAT_WINDOW:
|
case MessageType::Chat::CHARACTER_NAME_CHANGE_REQUEST:
|
||||||
case eChatMessageType::UNEXPECTED_DISCONNECT:
|
case MessageType::Chat::CSR_REQUEST:
|
||||||
case eChatMessageType::PLAYER_READY:
|
case MessageType::Chat::CSR_REPLY:
|
||||||
case eChatMessageType::GET_DONATION_TOTAL:
|
case MessageType::Chat::GM_KICK:
|
||||||
case eChatMessageType::UPDATE_DONATION:
|
case MessageType::Chat::WORLD_ROUTE_PACKET:
|
||||||
case eChatMessageType::PRG_CSR_COMMAND:
|
case MessageType::Chat::GET_ZONE_POPULATIONS:
|
||||||
case eChatMessageType::HEARTBEAT_REQUEST_FROM_WORLD:
|
case MessageType::Chat::REQUEST_MINIMUM_CHAT_MODE:
|
||||||
case eChatMessageType::UPDATE_FREE_TRIAL_STATUS:
|
case MessageType::Chat::MATCH_REQUEST:
|
||||||
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chat_message_type).data(), chat_message_type);
|
case MessageType::Chat::UGCMANIFEST_REPORT_MISSING_FILE:
|
||||||
|
case MessageType::Chat::UGCMANIFEST_REPORT_DONE_FILE:
|
||||||
|
case MessageType::Chat::UGCMANIFEST_REPORT_DONE_BLUEPRINT:
|
||||||
|
case MessageType::Chat::UGCC_REQUEST:
|
||||||
|
case MessageType::Chat::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE:
|
||||||
|
case MessageType::Chat::ACHIEVEMENT_NOTIFY:
|
||||||
|
case MessageType::Chat::GM_CLOSE_PRIVATE_CHAT_WINDOW:
|
||||||
|
case MessageType::Chat::PLAYER_READY:
|
||||||
|
case MessageType::Chat::GET_DONATION_TOTAL:
|
||||||
|
case MessageType::Chat::UPDATE_DONATION:
|
||||||
|
case MessageType::Chat::PRG_CSR_COMMAND:
|
||||||
|
case MessageType::Chat::HEARTBEAT_REQUEST_FROM_WORLD:
|
||||||
|
case MessageType::Chat::UPDATE_FREE_TRIAL_STATUS:
|
||||||
|
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chatMessageID).data(), chatMessageID);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG("Unknown CHAT Message id: %i", chat_message_type);
|
LOG("Unknown CHAT Message id: %i", chatMessageID);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::WORLD) {
|
|
||||||
switch (static_cast<eWorldMessageType>(packet->data[3])) {
|
|
||||||
case eWorldMessageType::ROUTE_PACKET: {
|
|
||||||
LOG("Routing packet from world");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
LOG("Unknown World id: %i", int(packet->data[3]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
#include "BitStreamUtils.h"
|
#include "BitStreamUtils.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "eChatInternalMessageType.h"
|
|
||||||
#include "ChatPackets.h"
|
#include "ChatPackets.h"
|
||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
|
#include "MessageType/Chat.h"
|
||||||
|
|
||||||
void PlayerContainer::Initialize() {
|
void PlayerContainer::Initialize() {
|
||||||
m_MaxNumberOfBestFriends =
|
m_MaxNumberOfBestFriends =
|
||||||
@@ -36,19 +36,23 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
|
|||||||
data.playerID = playerId;
|
data.playerID = playerId;
|
||||||
|
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
inStream.Read<uint32_t>(len);
|
if (!inStream.Read<uint32_t>(len)) return;
|
||||||
|
|
||||||
for (int i = 0; i < len; i++) {
|
if (len > 33) {
|
||||||
char character; inStream.Read<char>(character);
|
LOG("Received a really long player name, probably a fake packet %i.", len);
|
||||||
data.playerName += character;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
inStream.Read(data.zoneID);
|
data.playerName.resize(len);
|
||||||
inStream.Read(data.muteExpire);
|
inStream.ReadAlignedBytes(reinterpret_cast<unsigned char*>(data.playerName.data()), len);
|
||||||
inStream.Read(data.gmLevel);
|
|
||||||
|
if (!inStream.Read(data.zoneID)) return;
|
||||||
|
if (!inStream.Read(data.muteExpire)) return;
|
||||||
|
if (!inStream.Read(data.gmLevel)) return;
|
||||||
data.sysAddr = packet->systemAddress;
|
data.sysAddr = packet->systemAddress;
|
||||||
|
|
||||||
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
|
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());
|
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
|
||||||
|
|
||||||
@@ -87,6 +91,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_PlayerCount--;
|
||||||
LOG("Removed user: %llu", playerID);
|
LOG("Removed user: %llu", playerID);
|
||||||
m_Players.erase(playerID);
|
m_Players.erase(playerID);
|
||||||
|
|
||||||
@@ -120,6 +125,11 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
|
|||||||
size_t membersSize = 0;
|
size_t membersSize = 0;
|
||||||
inStream.Read(membersSize);
|
inStream.Read(membersSize);
|
||||||
|
|
||||||
|
if (membersSize >= 4) {
|
||||||
|
LOG("Tried to create a team with more than 4 players");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<LWOOBJID> members;
|
std::vector<LWOOBJID> members;
|
||||||
|
|
||||||
members.reserve(membersSize);
|
members.reserve(membersSize);
|
||||||
@@ -138,14 +148,13 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
|
|||||||
|
|
||||||
if (team != nullptr) {
|
if (team != nullptr) {
|
||||||
team->zoneId = zoneId;
|
team->zoneId = zoneId;
|
||||||
|
UpdateTeamsOnWorld(team, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTeamsOnWorld(team, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_MUTE);
|
||||||
|
|
||||||
bitStream.Write(player);
|
bitStream.Write(player);
|
||||||
bitStream.Write(time);
|
bitStream.Write(time);
|
||||||
@@ -352,7 +361,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
|||||||
|
|
||||||
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::TEAM_GET_STATUS);
|
||||||
|
|
||||||
bitStream.Write(team->teamID);
|
bitStream.Write(team->teamID);
|
||||||
bitStream.Write(deleteTeam);
|
bitStream.Write(deleteTeam);
|
||||||
@@ -390,7 +399,7 @@ LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) {
|
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) {
|
PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) {
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ public:
|
|||||||
const PlayerData& GetPlayerData(const std::string& playerName);
|
const PlayerData& GetPlayerData(const std::string& playerName);
|
||||||
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
||||||
PlayerData& GetPlayerDataMutable(const std::string& playerName);
|
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* CreateLocalTeam(std::vector<LWOOBJID> members);
|
||||||
TeamData* CreateTeam(LWOOBJID leader, bool local = false);
|
TeamData* CreateTeam(LWOOBJID leader, bool local = false);
|
||||||
@@ -93,5 +96,7 @@ private:
|
|||||||
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
||||||
uint32_t m_MaxNumberOfBestFriends = 5;
|
uint32_t m_MaxNumberOfBestFriends = 5;
|
||||||
uint32_t m_MaxNumberOfFriends = 50;
|
uint32_t m_MaxNumberOfFriends = 50;
|
||||||
|
uint32_t m_PlayerCount = 0;
|
||||||
|
uint32_t m_SimCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,73 +9,54 @@
|
|||||||
* AMF3 Deserializer written by EmosewaMC
|
* AMF3 Deserializer written by EmosewaMC
|
||||||
*/
|
*/
|
||||||
|
|
||||||
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) {
|
std::unique_ptr<AMFBaseValue> AMFDeserialize::Read(RakNet::BitStream& inStream) {
|
||||||
AMFBaseValue* returnValue = nullptr;
|
|
||||||
// Read in the value type from the bitStream
|
// Read in the value type from the bitStream
|
||||||
eAmf marker;
|
eAmf marker;
|
||||||
inStream.Read(marker);
|
inStream.Read(marker);
|
||||||
// Based on the typing, create the value associated with that and return the base value class
|
// Based on the typing, create the value associated with that and return the base value class
|
||||||
switch (marker) {
|
switch (marker) {
|
||||||
case eAmf::Undefined: {
|
case eAmf::Undefined:
|
||||||
returnValue = new AMFBaseValue();
|
return std::make_unique<AMFBaseValue>();
|
||||||
break;
|
case eAmf::Null:
|
||||||
}
|
return std::make_unique<AMFNullValue>();
|
||||||
|
case eAmf::False:
|
||||||
case eAmf::Null: {
|
return std::make_unique<AMFBoolValue>(false);
|
||||||
returnValue = new AMFNullValue();
|
case eAmf::True:
|
||||||
break;
|
return std::make_unique<AMFBoolValue>(true);
|
||||||
}
|
case eAmf::Integer:
|
||||||
|
return ReadAmfInteger(inStream);
|
||||||
case eAmf::False: {
|
case eAmf::Double:
|
||||||
returnValue = new AMFBoolValue(false);
|
return ReadAmfDouble(inStream);
|
||||||
break;
|
case eAmf::String:
|
||||||
}
|
return ReadAmfString(inStream);
|
||||||
|
case eAmf::Array:
|
||||||
case eAmf::True: {
|
return ReadAmfArray(inStream);
|
||||||
returnValue = new AMFBoolValue(true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case eAmf::Integer: {
|
|
||||||
returnValue = ReadAmfInteger(inStream);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case eAmf::Double: {
|
|
||||||
returnValue = ReadAmfDouble(inStream);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case eAmf::String: {
|
|
||||||
returnValue = ReadAmfString(inStream);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case eAmf::Array: {
|
|
||||||
returnValue = ReadAmfArray(inStream);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// These values are unimplemented in the live client and will remain unimplemented
|
// These values are unimplemented in the live client and will remain unimplemented
|
||||||
// unless someone modifies the client to allow serializing of these values.
|
// unless someone modifies the client to allow serializing of these values.
|
||||||
case eAmf::XMLDoc:
|
case eAmf::XMLDoc:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::Date:
|
case eAmf::Date:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::Object:
|
case eAmf::Object:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::XML:
|
case eAmf::XML:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::ByteArray:
|
case eAmf::ByteArray:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::VectorInt:
|
case eAmf::VectorInt:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::VectorUInt:
|
case eAmf::VectorUInt:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::VectorDouble:
|
case eAmf::VectorDouble:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::VectorObject:
|
case eAmf::VectorObject:
|
||||||
case eAmf::Dictionary: {
|
[[fallthrough]];
|
||||||
|
case eAmf::Dictionary:
|
||||||
throw marker;
|
throw marker;
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
throw std::invalid_argument("Invalid AMF3 marker" + std::to_string(static_cast<int32_t>(marker)));
|
throw std::invalid_argument("Invalid AMF3 marker" + std::to_string(static_cast<int32_t>(marker)));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return returnValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) {
|
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) {
|
||||||
@@ -118,14 +99,14 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
|
std::unique_ptr<AMFDoubleValue> AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
|
||||||
double value;
|
double value;
|
||||||
inStream.Read<double>(value);
|
inStream.Read<double>(value);
|
||||||
return new AMFDoubleValue(value);
|
return std::make_unique<AMFDoubleValue>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
|
std::unique_ptr<AMFArrayValue> AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
|
||||||
auto arrayValue = new AMFArrayValue();
|
auto arrayValue = std::make_unique<AMFArrayValue>();
|
||||||
|
|
||||||
// Read size of dense array
|
// Read size of dense array
|
||||||
const auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
|
const auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
|
||||||
@@ -143,10 +124,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
|
|||||||
return arrayValue;
|
return arrayValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
|
std::unique_ptr<AMFStringValue> AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
|
||||||
return new AMFStringValue(ReadString(inStream));
|
return std::make_unique<AMFStringValue>(ReadString(inStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
|
std::unique_ptr<AMFIntValue> AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
|
||||||
return new AMFIntValue(ReadU29(inStream));
|
return std::make_unique<AMFIntValue>(ReadU29(inStream)); // NOTE: NARROWING CONVERSION FROM UINT TO INT. IS THIS INTENDED?
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Amf3.h"
|
||||||
#include "BitStream.h"
|
#include "BitStream.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class AMFBaseValue;
|
|
||||||
|
|
||||||
class AMFDeserialize {
|
class AMFDeserialize {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -15,7 +15,7 @@ public:
|
|||||||
* @param inStream inStream to read value from.
|
* @param inStream inStream to read value from.
|
||||||
* @return Returns an AMFValue with all the information from the bitStream in it.
|
* @return Returns an AMFValue with all the information from the bitStream in it.
|
||||||
*/
|
*/
|
||||||
AMFBaseValue* Read(RakNet::BitStream& inStream);
|
std::unique_ptr<AMFBaseValue> Read(RakNet::BitStream& inStream);
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Private method to read a U29 integer from a bitstream
|
* @brief Private method to read a U29 integer from a bitstream
|
||||||
@@ -39,7 +39,7 @@ private:
|
|||||||
* @param inStream bitStream to read data from
|
* @param inStream bitStream to read data from
|
||||||
* @return Double value represented as an AMFValue
|
* @return Double value represented as an AMFValue
|
||||||
*/
|
*/
|
||||||
AMFBaseValue* ReadAmfDouble(RakNet::BitStream& inStream);
|
static std::unique_ptr<AMFDoubleValue> ReadAmfDouble(RakNet::BitStream& inStream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read an AMFArray from a bitStream
|
* @brief Read an AMFArray from a bitStream
|
||||||
@@ -47,7 +47,7 @@ private:
|
|||||||
* @param inStream bitStream to read data from
|
* @param inStream bitStream to read data from
|
||||||
* @return Array value represented as an AMFValue
|
* @return Array value represented as an AMFValue
|
||||||
*/
|
*/
|
||||||
AMFBaseValue* ReadAmfArray(RakNet::BitStream& inStream);
|
std::unique_ptr<AMFArrayValue> ReadAmfArray(RakNet::BitStream& inStream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read an AMFString from a bitStream
|
* @brief Read an AMFString from a bitStream
|
||||||
@@ -55,7 +55,7 @@ private:
|
|||||||
* @param inStream bitStream to read data from
|
* @param inStream bitStream to read data from
|
||||||
* @return String value represented as an AMFValue
|
* @return String value represented as an AMFValue
|
||||||
*/
|
*/
|
||||||
AMFBaseValue* ReadAmfString(RakNet::BitStream& inStream);
|
std::unique_ptr<AMFStringValue> ReadAmfString(RakNet::BitStream& inStream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read an AMFInteger from a bitStream
|
* @brief Read an AMFInteger from a bitStream
|
||||||
@@ -63,7 +63,7 @@ private:
|
|||||||
* @param inStream bitStream to read data from
|
* @param inStream bitStream to read data from
|
||||||
* @return Integer value represented as an AMFValue
|
* @return Integer value represented as an AMFValue
|
||||||
*/
|
*/
|
||||||
AMFBaseValue* ReadAmfInteger(RakNet::BitStream& inStream);
|
static std::unique_ptr<AMFIntValue> ReadAmfInteger(RakNet::BitStream& inStream);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of strings read so far saved to be read by reference.
|
* List of strings read so far saved to be read by reference.
|
||||||
|
|||||||
@@ -105,27 +105,14 @@ using AMFDoubleValue = AMFValue<double>;
|
|||||||
* and are not to be deleted by a caller.
|
* and are not to be deleted by a caller.
|
||||||
*/
|
*/
|
||||||
class AMFArrayValue : public AMFBaseValue {
|
class AMFArrayValue : public AMFBaseValue {
|
||||||
using AMFAssociative = std::unordered_map<std::string, AMFBaseValue*>;
|
using AMFAssociative =
|
||||||
using AMFDense = std::vector<AMFBaseValue*>;
|
std::unordered_map<std::string, std::unique_ptr<AMFBaseValue>, GeneralUtils::transparent_string_hash, std::equal_to<>>;
|
||||||
|
|
||||||
|
using AMFDense = std::vector<std::unique_ptr<AMFBaseValue>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; }
|
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; }
|
||||||
|
|
||||||
~AMFArrayValue() override {
|
|
||||||
for (const auto* valueToDelete : GetDense()) {
|
|
||||||
if (valueToDelete) {
|
|
||||||
delete valueToDelete;
|
|
||||||
valueToDelete = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (auto valueToDelete : GetAssociative()) {
|
|
||||||
if (valueToDelete.second) {
|
|
||||||
delete valueToDelete.second;
|
|
||||||
valueToDelete.second = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Associative portion of the object
|
* Returns the Associative portion of the object
|
||||||
*/
|
*/
|
||||||
@@ -151,30 +138,32 @@ public:
|
|||||||
* or nullptr if a key existed and was not the same type
|
* or nullptr if a key existed and was not the same type
|
||||||
*/
|
*/
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, const ValueType value) {
|
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string_view key, const ValueType value) {
|
||||||
const auto element = m_Associative.find(key);
|
const auto element = m_Associative.find(key);
|
||||||
AMFValue<ValueType>* val = nullptr;
|
AMFValue<ValueType>* val = nullptr;
|
||||||
bool found = true;
|
bool found = true;
|
||||||
if (element == m_Associative.cend()) {
|
if (element == m_Associative.cend()) {
|
||||||
val = new AMFValue<ValueType>(value);
|
auto newVal = std::make_unique<AMFValue<ValueType>>(value);
|
||||||
m_Associative.emplace(key, val);
|
val = newVal.get();
|
||||||
|
m_Associative.emplace(key, std::move(newVal));
|
||||||
} else {
|
} else {
|
||||||
val = dynamic_cast<AMFValue<ValueType>*>(element->second);
|
val = dynamic_cast<AMFValue<ValueType>*>(element->second.get());
|
||||||
found = false;
|
found = false;
|
||||||
}
|
}
|
||||||
return std::make_pair(val, found);
|
return std::make_pair(val, found);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Associates an array with a string key
|
// Associates an array with a string key
|
||||||
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
|
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string_view key) {
|
||||||
const auto element = m_Associative.find(key);
|
const auto element = m_Associative.find(key);
|
||||||
AMFArrayValue* val = nullptr;
|
AMFArrayValue* val = nullptr;
|
||||||
bool found = true;
|
bool found = true;
|
||||||
if (element == m_Associative.cend()) {
|
if (element == m_Associative.cend()) {
|
||||||
val = new AMFArrayValue();
|
auto newVal = std::make_unique<AMFArrayValue>();
|
||||||
m_Associative.emplace(key, val);
|
val = newVal.get();
|
||||||
|
m_Associative.emplace(key, std::move(newVal));
|
||||||
} else {
|
} else {
|
||||||
val = dynamic_cast<AMFArrayValue*>(element->second);
|
val = dynamic_cast<AMFArrayValue*>(element->second.get());
|
||||||
found = false;
|
found = false;
|
||||||
}
|
}
|
||||||
return std::make_pair(val, found);
|
return std::make_pair(val, found);
|
||||||
@@ -182,15 +171,13 @@ public:
|
|||||||
|
|
||||||
// Associates an array with an integer key
|
// Associates an array with an integer key
|
||||||
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) {
|
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) {
|
||||||
AMFArrayValue* val = nullptr;
|
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
if (index >= m_Dense.size()) {
|
if (index >= m_Dense.size()) {
|
||||||
m_Dense.resize(index + 1);
|
m_Dense.resize(index + 1);
|
||||||
val = new AMFArrayValue();
|
m_Dense.at(index) = std::make_unique<AMFArrayValue>();
|
||||||
m_Dense.at(index) = val;
|
|
||||||
inserted = true;
|
inserted = true;
|
||||||
}
|
}
|
||||||
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index)), inserted);
|
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()), inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,15 +192,13 @@ public:
|
|||||||
*/
|
*/
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) {
|
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) {
|
||||||
AMFValue<ValueType>* val = nullptr;
|
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
if (index >= m_Dense.size()) {
|
if (index >= m_Dense.size()) {
|
||||||
m_Dense.resize(index + 1);
|
m_Dense.resize(index + 1);
|
||||||
val = new AMFValue<ValueType>(value);
|
m_Dense.at(index) = std::make_unique<AMFValue<ValueType>>(value);
|
||||||
m_Dense.at(index) = val;
|
|
||||||
inserted = true;
|
inserted = true;
|
||||||
}
|
}
|
||||||
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index)), inserted);
|
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index).get()), inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -225,13 +210,12 @@ public:
|
|||||||
* @param key The key to associate with the value
|
* @param key The key to associate with the value
|
||||||
* @param value The value to insert
|
* @param value The value to insert
|
||||||
*/
|
*/
|
||||||
void Insert(const std::string& key, AMFBaseValue* const value) {
|
void Insert(const std::string_view key, std::unique_ptr<AMFBaseValue> value) {
|
||||||
const auto element = m_Associative.find(key);
|
const auto element = m_Associative.find(key);
|
||||||
if (element != m_Associative.cend() && element->second) {
|
if (element != m_Associative.cend() && element->second) {
|
||||||
delete element->second;
|
element->second = std::move(value);
|
||||||
element->second = value;
|
|
||||||
} else {
|
} else {
|
||||||
m_Associative.emplace(key, value);
|
m_Associative.emplace(key, std::move(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,14 +228,11 @@ public:
|
|||||||
* @param key The key to associate with the value
|
* @param key The key to associate with the value
|
||||||
* @param value The value to insert
|
* @param value The value to insert
|
||||||
*/
|
*/
|
||||||
void Insert(const size_t index, AMFBaseValue* const value) {
|
void Insert(const size_t index, std::unique_ptr<AMFBaseValue> value) {
|
||||||
if (index < m_Dense.size()) {
|
if (index >= m_Dense.size()) {
|
||||||
const AMFDense::const_iterator itr = m_Dense.cbegin() + index;
|
|
||||||
if (*itr) delete m_Dense.at(index);
|
|
||||||
} else {
|
|
||||||
m_Dense.resize(index + 1);
|
m_Dense.resize(index + 1);
|
||||||
}
|
}
|
||||||
m_Dense.at(index) = value;
|
m_Dense.at(index) = std::move(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -279,8 +260,7 @@ public:
|
|||||||
void Remove(const std::string& key, const bool deleteValue = true) {
|
void Remove(const std::string& key, const bool deleteValue = true) {
|
||||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||||
if (it != m_Associative.cend()) {
|
if (it != m_Associative.cend()) {
|
||||||
if (deleteValue) delete it->second;
|
if (deleteValue) m_Associative.erase(it);
|
||||||
m_Associative.erase(it);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +270,6 @@ public:
|
|||||||
void Remove(const size_t index) {
|
void Remove(const size_t index) {
|
||||||
if (!m_Dense.empty() && index < m_Dense.size()) {
|
if (!m_Dense.empty() && index < m_Dense.size()) {
|
||||||
const auto itr = m_Dense.cbegin() + index;
|
const auto itr = m_Dense.cbegin() + index;
|
||||||
if (*itr) delete (*itr);
|
|
||||||
m_Dense.erase(itr);
|
m_Dense.erase(itr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,16 +278,16 @@ public:
|
|||||||
if (!m_Dense.empty()) Remove(m_Dense.size() - 1);
|
if (!m_Dense.empty()) Remove(m_Dense.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) const {
|
[[nodiscard]] AMFArrayValue* GetArray(const std::string_view key) const {
|
||||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||||
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second) : nullptr;
|
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second.get()) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const {
|
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const {
|
||||||
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index)) : nullptr;
|
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string& key) {
|
[[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string_view key) {
|
||||||
return static_cast<AMFArrayValue*>(Insert(key).first);
|
return static_cast<AMFArrayValue*>(Insert(key).first);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -330,17 +309,17 @@ public:
|
|||||||
* @return The AMFValue
|
* @return The AMFValue
|
||||||
*/
|
*/
|
||||||
template <typename AmfType>
|
template <typename AmfType>
|
||||||
[[nodiscard]] AMFValue<AmfType>* Get(const std::string& key) const {
|
[[nodiscard]] AMFValue<AmfType>* Get(const std::string_view key) const {
|
||||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||||
return it != m_Associative.cend() ?
|
return it != m_Associative.cend() ?
|
||||||
dynamic_cast<AMFValue<AmfType>*>(it->second) :
|
dynamic_cast<AMFValue<AmfType>*>(it->second.get()) :
|
||||||
nullptr;
|
nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get from the array but dont cast it
|
// Get from the array but dont cast it
|
||||||
[[nodiscard]] AMFBaseValue* Get(const std::string& key) const {
|
[[nodiscard]] AMFBaseValue* Get(const std::string_view key) const {
|
||||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||||
return it != m_Associative.cend() ? it->second : nullptr;
|
return it != m_Associative.cend() ? it->second.get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -355,13 +334,13 @@ public:
|
|||||||
template <typename AmfType>
|
template <typename AmfType>
|
||||||
[[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const {
|
[[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const {
|
||||||
return index < m_Dense.size() ?
|
return index < m_Dense.size() ?
|
||||||
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index)) :
|
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index).get()) :
|
||||||
nullptr;
|
nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get from the dense but dont cast it
|
// Get from the dense but dont cast it
|
||||||
[[nodiscard]] AMFBaseValue* Get(const size_t index) const {
|
[[nodiscard]] AMFBaseValue* Get(const size_t index) const {
|
||||||
return index < m_Dense.size() ? m_Dense.at(index) : nullptr;
|
return index < m_Dense.size() ? m_Dense.at(index).get() : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
|
|||||||
Database::Get()->UpdateUgcModelData(model.id, outputStringStream);
|
Database::Get()->UpdateUgcModelData(model.id, outputStringStream);
|
||||||
LOG("Updated model %i to sd0", model.id);
|
LOG("Updated model %i to sd0", model.id);
|
||||||
updatedModels++;
|
updatedModels++;
|
||||||
} catch (sql::SQLException exception) {
|
} catch (std::exception& exception) {
|
||||||
LOG("Failed to update model %i. This model should be inspected manually to see why."
|
LOG("Failed to update model %i. This model should be inspected manually to see why."
|
||||||
"The database error is %s", model.id, exception.what());
|
"The database error is %s", model.id, exception.what());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,5 +70,6 @@ else ()
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_link_libraries(dCommon
|
target_link_libraries(dCommon
|
||||||
|
PUBLIC magic_enum::magic_enum
|
||||||
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
|
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
|
||||||
INTERFACE dDatabase)
|
INTERFACE dDatabase)
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ void CatchUnhandled(int sig) {
|
|||||||
if (eptr) std::rethrow_exception(eptr);
|
if (eptr) std::rethrow_exception(eptr);
|
||||||
} catch(const std::exception& e) {
|
} catch(const std::exception& e) {
|
||||||
LOG("Caught exception: '%s'", e.what());
|
LOG("Caught exception: '%s'", e.what());
|
||||||
|
} catch (...) {
|
||||||
|
LOG("Caught unknown exception.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef INCLUDE_BACKTRACE
|
#ifndef INCLUDE_BACKTRACE
|
||||||
@@ -199,7 +201,7 @@ void OnTerminate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MakeBacktrace() {
|
void MakeBacktrace() {
|
||||||
struct sigaction sigact;
|
struct sigaction sigact{};
|
||||||
|
|
||||||
sigact.sa_sigaction = CritErrHdlr;
|
sigact.sa_sigaction = CritErrHdlr;
|
||||||
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||||
|
|||||||
@@ -8,23 +8,23 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline size_t MinSize(size_t size, const std::basic_string_view<T>& string) {
|
static inline size_t MinSize(const size_t size, const std::basic_string_view<T> string) {
|
||||||
if (size == size_t(-1) || size > string.size()) {
|
if (size == SIZE_MAX || size > string.size()) {
|
||||||
return string.size();
|
return string.size();
|
||||||
} else {
|
} else {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsLeadSurrogate(char16_t c) {
|
inline bool IsLeadSurrogate(const char16_t c) {
|
||||||
return (0xD800 <= c) && (c <= 0xDBFF);
|
return (0xD800 <= c) && (c <= 0xDBFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsTrailSurrogate(char16_t c) {
|
inline bool IsTrailSurrogate(const char16_t c) {
|
||||||
return (0xDC00 <= c) && (c <= 0xDFFF);
|
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) {
|
if (cp <= 0x007F) {
|
||||||
ret.push_back(static_cast<uint8_t>(cp));
|
ret.push_back(static_cast<uint8_t>(cp));
|
||||||
} else if (cp <= 0x07FF) {
|
} else if (cp <= 0x07FF) {
|
||||||
@@ -46,16 +46,16 @@ inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
|||||||
|
|
||||||
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
||||||
|
|
||||||
bool _IsSuffixChar(uint8_t c) {
|
bool static _IsSuffixChar(const uint8_t c) {
|
||||||
return (c & 0xC0) == 0x80;
|
return (c & 0xC0) == 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||||
size_t rem = slice.length();
|
const size_t rem = slice.length();
|
||||||
if (slice.empty()) return false;
|
if (slice.empty()) return false;
|
||||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
||||||
if (rem > 0) {
|
if (rem > 0) {
|
||||||
uint8_t first = bytes[0];
|
const uint8_t first = bytes[0];
|
||||||
if (first < 0x80) { // 1 byte character
|
if (first < 0x80) { // 1 byte character
|
||||||
out = static_cast<uint32_t>(first & 0x7F);
|
out = static_cast<uint32_t>(first & 0x7F);
|
||||||
slice.remove_prefix(1);
|
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
|
// middle byte, not valid at start, fall through
|
||||||
} else if (first < 0xE0) { // two byte character
|
} else if (first < 0xE0) { // two byte character
|
||||||
if (rem > 1) {
|
if (rem > 1) {
|
||||||
uint8_t second = bytes[1];
|
const uint8_t second = bytes[1];
|
||||||
if (_IsSuffixChar(second)) {
|
if (_IsSuffixChar(second)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
||||||
+ static_cast<uint32_t>(second & 0x3F);
|
+ 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
|
} else if (first < 0xF0) { // three byte character
|
||||||
if (rem > 2) {
|
if (rem > 2) {
|
||||||
uint8_t second = bytes[1];
|
const uint8_t second = bytes[1];
|
||||||
uint8_t third = bytes[2];
|
const uint8_t third = bytes[2];
|
||||||
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
||||||
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
+ (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
|
} else if (first < 0xF8) { // four byte character
|
||||||
if (rem > 3) {
|
if (rem > 3) {
|
||||||
uint8_t second = bytes[1];
|
const uint8_t second = bytes[1];
|
||||||
uint8_t third = bytes[2];
|
const uint8_t third = bytes[2];
|
||||||
uint8_t fourth = bytes[3];
|
const uint8_t fourth = bytes[3];
|
||||||
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
||||||
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
+ (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>
|
/// 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 (output.length() >= size) return false;
|
||||||
if (U < 0x10000) {
|
if (U < 0x10000) {
|
||||||
// If U < 0x10000, encode U as a 16-bit unsigned integer and terminate.
|
// 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,
|
// 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
|
// U' must be less than or equal to 0xFFFFF. That is, U' can be
|
||||||
// represented in 20 bits.
|
// 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
|
// Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
|
||||||
// 0xDC00, respectively. These integers each have 10 bits free to
|
// 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;
|
} else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) {
|
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view string, const size_t size) {
|
||||||
size_t newSize = MinSize(size, string);
|
const size_t newSize = MinSize(size, string);
|
||||||
std::u16string output;
|
std::u16string output;
|
||||||
output.reserve(newSize);
|
output.reserve(newSize);
|
||||||
std::string_view iterator = string;
|
std::string_view iterator = string;
|
||||||
|
|
||||||
uint32_t c;
|
uint32_t c;
|
||||||
while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
while (details::_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
||||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) {
|
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view string, const size_t size) {
|
||||||
size_t newSize = MinSize(size, string);
|
const size_t newSize = MinSize(size, string);
|
||||||
std::u16string ret;
|
std::u16string ret;
|
||||||
ret.reserve(newSize);
|
ret.reserve(newSize);
|
||||||
|
|
||||||
for (size_t i = 0; i < newSize; i++) {
|
for (size_t i = 0; i < newSize; ++i) {
|
||||||
char c = string[i];
|
const char c = string[i];
|
||||||
// Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t
|
// 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);
|
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
|
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
|
||||||
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
||||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) {
|
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view string, const size_t size) {
|
||||||
size_t newSize = MinSize(size, string);
|
const size_t newSize = MinSize(size, string);
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret.reserve(newSize);
|
ret.reserve(newSize);
|
||||||
|
|
||||||
for (size_t i = 0; i < newSize; i++) {
|
for (size_t i = 0; i < newSize; ++i) {
|
||||||
char16_t u = string[i];
|
const char16_t u = string[i];
|
||||||
if (IsLeadSurrogate(u) && (i + 1) < newSize) {
|
if (IsLeadSurrogate(u) && (i + 1) < newSize) {
|
||||||
char16_t next = string[i + 1];
|
const char16_t next = string[i + 1];
|
||||||
if (IsTrailSurrogate(next)) {
|
if (IsTrailSurrogate(next)) {
|
||||||
i += 1;
|
i += 1;
|
||||||
char32_t cp = 0x10000
|
const char32_t cp = 0x10000
|
||||||
+ ((static_cast<char32_t>(u) - 0xD800) << 10)
|
+ ((static_cast<char32_t>(u) - 0xD800) << 10)
|
||||||
+ (static_cast<char32_t>(next) - 0xDC00);
|
+ (static_cast<char32_t>(next) - 0xDC00);
|
||||||
PushUTF8CodePoint(ret, cp);
|
PushUTF8CodePoint(ret, cp);
|
||||||
@@ -195,40 +195,40 @@ std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t
|
|||||||
return ret;
|
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); });
|
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Bits
|
// MARK: Bits
|
||||||
|
|
||||||
//! Sets a specific bit in a signed 64-bit integer
|
//! 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;
|
return value |= 1ULL << index;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Clears a specific bit in a signed 64-bit integer
|
//! 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);
|
return value &= ~(1ULL << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Checks a specific bit in a signed 64-bit integer
|
//! 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);
|
return value & (1ULL << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) {
|
bool GeneralUtils::ReplaceInString(std::string& str, const std::string_view from, const std::string_view to) {
|
||||||
size_t start_pos = str.find(from);
|
const size_t start_pos = str.find(from);
|
||||||
if (start_pos == std::string::npos)
|
if (start_pos == std::string::npos)
|
||||||
return false;
|
return false;
|
||||||
str.replace(start_pos, from.length(), to);
|
str.replace(start_pos, from.length(), to);
|
||||||
return true;
|
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::vector<std::wstring> vector = std::vector<std::wstring>();
|
||||||
std::wstring current;
|
std::wstring current;
|
||||||
|
|
||||||
for (const auto& c : str) {
|
for (const wchar_t c : str) {
|
||||||
if (c == delimiter) {
|
if (c == delimiter) {
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = L"";
|
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;
|
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::vector<std::u16string> vector = std::vector<std::u16string>();
|
||||||
std::u16string current;
|
std::u16string current;
|
||||||
|
|
||||||
for (const auto& c : str) {
|
for (const char16_t c : str) {
|
||||||
if (c == delimiter) {
|
if (c == delimiter) {
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = u"";
|
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;
|
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::vector<std::string> vector = std::vector<std::string>();
|
||||||
std::string current = "";
|
std::string current = "";
|
||||||
|
|
||||||
for (size_t i = 0; i < str.length(); i++) {
|
for (const char c : str) {
|
||||||
char c = str[i];
|
|
||||||
|
|
||||||
if (c == delimiter) {
|
if (c == delimiter) {
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = "";
|
current = "";
|
||||||
@@ -273,8 +271,7 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector.push_back(current);
|
vector.push_back(std::move(current));
|
||||||
|
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +280,7 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
|
|||||||
inStream.Read<uint32_t>(length);
|
inStream.Read<uint32_t>(length);
|
||||||
|
|
||||||
std::u16string string;
|
std::u16string string;
|
||||||
for (auto i = 0; i < length; i++) {
|
for (uint32_t i = 0; i < length; ++i) {
|
||||||
uint16_t c;
|
uint16_t c;
|
||||||
inStream.Read(c);
|
inStream.Read(c);
|
||||||
string.push_back(c);
|
string.push_back(c);
|
||||||
@@ -292,35 +289,35 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
|
|||||||
return string;
|
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.
|
// 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{};
|
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 filename = t.path().filename().string();
|
||||||
auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
|
const auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
|
||||||
filenames.insert(std::make_pair(index, filename));
|
filenames.emplace(index, std::move(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now sort the map by the oldest migration.
|
// Now sort the map by the oldest migration.
|
||||||
std::vector<std::string> sortedFiles{};
|
std::vector<std::string> sortedFiles{};
|
||||||
auto fileIterator = filenames.begin();
|
auto fileIterator = filenames.cbegin();
|
||||||
std::map<uint32_t, std::string>::iterator oldest = filenames.begin();
|
auto oldest = filenames.cbegin();
|
||||||
while (!filenames.empty()) {
|
while (!filenames.empty()) {
|
||||||
if (fileIterator == filenames.end()) {
|
if (fileIterator == filenames.cend()) {
|
||||||
sortedFiles.push_back(oldest->second);
|
sortedFiles.push_back(oldest->second);
|
||||||
filenames.erase(oldest);
|
filenames.erase(oldest);
|
||||||
fileIterator = filenames.begin();
|
fileIterator = filenames.cbegin();
|
||||||
oldest = filenames.begin();
|
oldest = filenames.cbegin();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
||||||
fileIterator++;
|
++fileIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortedFiles;
|
return sortedFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DARKFLAME_PLATFORM_MACOS
|
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924)
|
||||||
|
|
||||||
// MacOS floating-point parse function specializations
|
// MacOS floating-point parse function specializations
|
||||||
namespace GeneralUtils::details {
|
namespace GeneralUtils::details {
|
||||||
|
|||||||
@@ -3,17 +3,18 @@
|
|||||||
// C++
|
// C++
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <random>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <random>
|
||||||
|
#include <span>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <optional>
|
|
||||||
#include <functional>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
|
||||||
#include "BitStream.h"
|
#include "BitStream.h"
|
||||||
#include "NiPoint3.h"
|
#include "NiPoint3.h"
|
||||||
|
|
||||||
#include "dPlatforms.h"
|
#include "dPlatforms.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
@@ -32,29 +33,31 @@ namespace GeneralUtils {
|
|||||||
//! Converts a plain ASCII string to a UTF-16 string
|
//! Converts a plain ASCII string to a UTF-16 string
|
||||||
/*!
|
/*!
|
||||||
\param string The string to convert
|
\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
|
\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
|
//! Converts a UTF-8 String to a UTF-16 string
|
||||||
/*!
|
/*!
|
||||||
\param string The string to convert
|
\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
|
\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);
|
||||||
|
|
||||||
//! Internal, do not use
|
namespace details {
|
||||||
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
//! Internal, do not use
|
||||||
|
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
||||||
|
}
|
||||||
|
|
||||||
//! Converts a UTF-16 string to a UTF-8 string
|
//! Converts a UTF-16 string to a UTF-8 string
|
||||||
/*!
|
/*!
|
||||||
\param string The string to convert
|
\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
|
\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
|
* Compares two basic strings but does so ignoring case sensitivity
|
||||||
@@ -62,7 +65,7 @@ namespace GeneralUtils {
|
|||||||
* \param b the second string to compare against the first string
|
* \param b the second string to compare against the first string
|
||||||
* @return if the two strings are equal
|
* @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
|
// MARK: Bits
|
||||||
|
|
||||||
@@ -70,9 +73,9 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
//! Sets a bit on a numerical value
|
//! Sets a bit on a numerical value
|
||||||
template <typename T>
|
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");
|
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) {
|
if (index > (sizeof(T) * 8) - 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -82,9 +85,9 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
//! Clears a bit on a numerical value
|
//! Clears a bit on a numerical value
|
||||||
template <typename T>
|
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");
|
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)) {
|
if (index > (sizeof(T) * 8 - 1)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -97,14 +100,14 @@ namespace GeneralUtils {
|
|||||||
\param value The value to set the bit for
|
\param value The value to set the bit for
|
||||||
\param index The index of the bit
|
\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
|
//! Clears a specific bit in a signed 64-bit integer
|
||||||
/*!
|
/*!
|
||||||
\param value The value to clear the bit from
|
\param value The value to clear the bit from
|
||||||
\param index The index of the bit
|
\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
|
//! Checks a specific bit in a signed 64-bit integer
|
||||||
/*!
|
/*!
|
||||||
@@ -112,19 +115,42 @@ namespace GeneralUtils {
|
|||||||
\param index The index of the bit
|
\param index The index of the bit
|
||||||
\return Whether or not the bit is set
|
\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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transparent string hasher - used to allow string_view key lookups for maps storing std::string keys
|
||||||
|
* https://www.reddit.com/r/cpp_questions/comments/12xw3sn/find_stdstring_view_in_unordered_map_with/jhki225/
|
||||||
|
* https://godbolt.org/z/789xv8Eeq
|
||||||
|
*/
|
||||||
|
template <typename... Bases>
|
||||||
|
struct overload : Bases... {
|
||||||
|
using is_transparent = void;
|
||||||
|
using Bases::operator() ... ;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct char_pointer_hash {
|
||||||
|
auto operator()(const char* const ptr) const noexcept {
|
||||||
|
return std::hash<std::string_view>{}(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using transparent_string_hash = overload<
|
||||||
|
std::hash<std::string>,
|
||||||
|
std::hash<std::string_view>,
|
||||||
|
char_pointer_hash
|
||||||
|
>;
|
||||||
|
|
||||||
// Concept constraining to enum types
|
// Concept constraining to enum types
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -144,7 +170,7 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
// If a boolean, present an alias to an intermediate integral type for parsing
|
// If a boolean, present an alias to an intermediate integral type for parsing
|
||||||
template <Numeric T> requires std::same_as<T, bool>
|
template <Numeric T> requires std::same_as<T, bool>
|
||||||
struct numeric_parse<T> { using type = uint32_t; };
|
struct numeric_parse<T> { using type = uint8_t; };
|
||||||
|
|
||||||
// Shorthand type alias
|
// Shorthand type alias
|
||||||
template <Numeric T>
|
template <Numeric T>
|
||||||
@@ -156,8 +182,9 @@ namespace GeneralUtils {
|
|||||||
* @returns An std::optional containing the desired value if it is equivalent to the string
|
* @returns An std::optional containing the desired value if it is equivalent to the string
|
||||||
*/
|
*/
|
||||||
template <Numeric T>
|
template <Numeric T>
|
||||||
[[nodiscard]] std::optional<T> TryParse(const std::string_view str) {
|
[[nodiscard]] std::optional<T> TryParse(std::string_view str) {
|
||||||
numeric_parse_t<T> result;
|
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 char* const strEnd = str.data() + str.size();
|
||||||
const auto [parseEnd, ec] = std::from_chars(str.data(), strEnd, result);
|
const auto [parseEnd, ec] = std::from_chars(str.data(), strEnd, result);
|
||||||
@@ -166,7 +193,7 @@ namespace GeneralUtils {
|
|||||||
return isParsed ? static_cast<T>(result) : std::optional<T>{};
|
return isParsed ? static_cast<T>(result) : std::optional<T>{};
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DARKFLAME_PLATFORM_MACOS
|
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924)
|
||||||
|
|
||||||
// MacOS floating-point parse helper function specializations
|
// MacOS floating-point parse helper function specializations
|
||||||
namespace details {
|
namespace details {
|
||||||
@@ -181,8 +208,10 @@ namespace GeneralUtils {
|
|||||||
* @returns An std::optional containing the desired value if it is equivalent to the string
|
* @returns An std::optional containing the desired value if it is equivalent to the string
|
||||||
*/
|
*/
|
||||||
template <std::floating_point T>
|
template <std::floating_point T>
|
||||||
[[nodiscard]] std::optional<T> TryParse(const std::string_view str) noexcept
|
[[nodiscard]] std::optional<T> TryParse(std::string_view str) noexcept
|
||||||
try {
|
try {
|
||||||
|
while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1);
|
||||||
|
|
||||||
size_t parseNum;
|
size_t parseNum;
|
||||||
const T result = details::_parse<T>(str, parseNum);
|
const T result = details::_parse<T>(str, parseNum);
|
||||||
const bool isParsed = str.length() == parseNum;
|
const bool isParsed = str.length() == parseNum;
|
||||||
@@ -202,7 +231,7 @@ namespace GeneralUtils {
|
|||||||
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string& strX, const std::string& strY, const std::string& strZ) {
|
[[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);
|
const auto x = TryParse<float>(strX);
|
||||||
if (!x) return std::nullopt;
|
if (!x) return std::nullopt;
|
||||||
|
|
||||||
@@ -214,17 +243,17 @@ namespace GeneralUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The TryParse overload for handling NiPoint3 by passingn a reference to a vector of three strings
|
* The TryParse overload for handling NiPoint3 by passing a span of three strings
|
||||||
* @param str The string vector representing the X, Y, and Xcoordinates
|
* @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
|
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::vector<std::string>& str) {
|
[[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;
|
return (str.size() == 3) ? TryParse<NiPoint3>(str[0], str[1], str[2]) : std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::u16string to_u16string(T value) {
|
std::u16string to_u16string(const T value) {
|
||||||
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +272,7 @@ namespace GeneralUtils {
|
|||||||
\param max The maximum to generate to
|
\param max The maximum to generate to
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
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
|
// Make sure it is a numeric type
|
||||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||||
|
|
||||||
@@ -270,10 +299,10 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
||||||
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T GenerateRandomNumber() {
|
inline T GenerateRandomNumber() {
|
||||||
|
|||||||
92
dCommon/Implementation.h
Normal file
92
dCommon/Implementation.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#ifndef __IMPLEMENTATION_H__
|
||||||
|
#define __IMPLEMENTATION_H__
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A way to defer the implementation of an action.
|
||||||
|
*
|
||||||
|
* @tparam R The result of the action.
|
||||||
|
* @tparam T The types of the arguments that the implementation requires.
|
||||||
|
*/
|
||||||
|
template <typename R, typename... T>
|
||||||
|
class Implementation {
|
||||||
|
public:
|
||||||
|
typedef std::function<std::optional<R>(T...)> ImplementationFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the implementation of the action.
|
||||||
|
*
|
||||||
|
* @param implementation The implementation of the action.
|
||||||
|
*/
|
||||||
|
void SetImplementation(const ImplementationFunction& implementation) {
|
||||||
|
this->implementation = implementation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the implementation of the action.
|
||||||
|
*/
|
||||||
|
void ClearImplementation() {
|
||||||
|
implementation.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the implementation is set.
|
||||||
|
*
|
||||||
|
* @return true If the implementation is set.
|
||||||
|
* @return false If the implementation is not set.
|
||||||
|
*/
|
||||||
|
bool IsSet() const {
|
||||||
|
return implementation.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Executes the implementation if it is set.
|
||||||
|
*
|
||||||
|
* @param args The arguments to pass to the implementation.
|
||||||
|
* @return std::optional<R> The optional result of the implementation. If the result is not set, it indicates that the default action should be taken.
|
||||||
|
*/
|
||||||
|
std::optional<R> Execute(T... args) const {
|
||||||
|
return IsSet() ? implementation.value()(args...) : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exectues the implementation if it is set, otherwise returns a default value.
|
||||||
|
*
|
||||||
|
* @param args The arguments to pass to the implementation.
|
||||||
|
* @param defaultValue The default value to return if the implementation is not set or should not be deferred.
|
||||||
|
*/
|
||||||
|
R ExecuteWithDefault(T... args, const R& defaultValue) const {
|
||||||
|
return Execute(args...).value_or(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* = operator overload.
|
||||||
|
*/
|
||||||
|
Implementation& operator=(const Implementation& other) {
|
||||||
|
implementation = other.implementation;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* = operator overload.
|
||||||
|
*/
|
||||||
|
Implementation& operator=(const ImplementationFunction& implementation) {
|
||||||
|
this->implementation = implementation;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* () operator overload.
|
||||||
|
*/
|
||||||
|
std::optional<R> operator()(T... args) {
|
||||||
|
return !IsSet() ? std::nullopt : implementation(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::optional<ImplementationFunction> implementation;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__IMPLEMENTATION_H__
|
||||||
@@ -31,22 +31,22 @@ public:
|
|||||||
|
|
||||||
virtual ~LDFBaseData() {}
|
virtual ~LDFBaseData() {}
|
||||||
|
|
||||||
virtual void WriteToPacket(RakNet::BitStream& packet) = 0;
|
virtual void WriteToPacket(RakNet::BitStream& packet) const = 0;
|
||||||
|
|
||||||
virtual const std::u16string& GetKey() = 0;
|
virtual const std::u16string& GetKey() const = 0;
|
||||||
|
|
||||||
virtual eLDFType GetValueType() = 0;
|
virtual eLDFType GetValueType() const = 0;
|
||||||
|
|
||||||
/** Gets a string from the key/value pair
|
/** Gets a string from the key/value pair
|
||||||
* @param includeKey Whether or not to include the key in the data
|
* @param includeKey Whether or not to include the key in the data
|
||||||
* @param includeTypeId Whether or not to include the type id in the data
|
* @param includeTypeId Whether or not to include the type id in the data
|
||||||
* @return The string representation of the data
|
* @return The string representation of the data
|
||||||
*/
|
*/
|
||||||
virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0;
|
virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) const = 0;
|
||||||
|
|
||||||
virtual std::string GetValueAsString() = 0;
|
virtual std::string GetValueAsString() const = 0;
|
||||||
|
|
||||||
virtual LDFBaseData* Copy() = 0;
|
virtual LDFBaseData* Copy() const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an input string, return the data as a LDF key.
|
* Given an input string, return the data as a LDF key.
|
||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
T value;
|
T value;
|
||||||
|
|
||||||
//! Writes the key to the packet
|
//! Writes the key to the packet
|
||||||
void WriteKey(RakNet::BitStream& packet) {
|
void WriteKey(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
||||||
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
||||||
packet.Write<uint16_t>(this->key[i]);
|
packet.Write<uint16_t>(this->key[i]);
|
||||||
@@ -70,7 +70,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Writes the value to the packet
|
//! Writes the value to the packet
|
||||||
void WriteValue(RakNet::BitStream& packet) {
|
void WriteValue(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->GetValueType());
|
packet.Write<uint8_t>(this->GetValueType());
|
||||||
packet.Write(this->value);
|
packet.Write(this->value);
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
\return The value
|
\return The value
|
||||||
*/
|
*/
|
||||||
const T& GetValue(void) { return this->value; }
|
const T& GetValue(void) const { return this->value; }
|
||||||
|
|
||||||
//! Sets the value
|
//! Sets the value
|
||||||
/*!
|
/*!
|
||||||
@@ -102,13 +102,13 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
\return The value string
|
\return The value string
|
||||||
*/
|
*/
|
||||||
std::string GetValueString(void) { return ""; }
|
std::string GetValueString(void) const { return ""; }
|
||||||
|
|
||||||
//! Writes the data to a packet
|
//! Writes the data to a packet
|
||||||
/*!
|
/*!
|
||||||
\param packet The packet
|
\param packet The packet
|
||||||
*/
|
*/
|
||||||
void WriteToPacket(RakNet::BitStream& packet) override {
|
void WriteToPacket(RakNet::BitStream& packet) const override {
|
||||||
this->WriteKey(packet);
|
this->WriteKey(packet);
|
||||||
this->WriteValue(packet);
|
this->WriteValue(packet);
|
||||||
}
|
}
|
||||||
@@ -117,13 +117,13 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
\return The key
|
\return The key
|
||||||
*/
|
*/
|
||||||
const std::u16string& GetKey(void) override { return this->key; }
|
const std::u16string& GetKey(void) const override { return this->key; }
|
||||||
|
|
||||||
//! Gets the LDF Type
|
//! Gets the LDF Type
|
||||||
/*!
|
/*!
|
||||||
\return The LDF value type
|
\return The LDF value type
|
||||||
*/
|
*/
|
||||||
eLDFType GetValueType(void) override { return LDF_TYPE_UNKNOWN; }
|
eLDFType GetValueType(void) const override { return LDF_TYPE_UNKNOWN; }
|
||||||
|
|
||||||
//! Gets the string data
|
//! Gets the string data
|
||||||
/*!
|
/*!
|
||||||
@@ -131,7 +131,7 @@ public:
|
|||||||
\param includeTypeId Whether or not to include the type id in the data
|
\param includeTypeId Whether or not to include the type id in the data
|
||||||
\return The string representation of the data
|
\return The string representation of the data
|
||||||
*/
|
*/
|
||||||
std::string GetString(const bool includeKey = true, const bool includeTypeId = true) override {
|
std::string GetString(const bool includeKey = true, const bool includeTypeId = true) const override {
|
||||||
if (GetValueType() == -1) {
|
if (GetValueType() == -1) {
|
||||||
return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>";
|
return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>";
|
||||||
}
|
}
|
||||||
@@ -154,11 +154,11 @@ public:
|
|||||||
return stream.str();
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetValueAsString() override {
|
std::string GetValueAsString() const override {
|
||||||
return this->GetValueString();
|
return this->GetValueString();
|
||||||
}
|
}
|
||||||
|
|
||||||
LDFBaseData* Copy() override {
|
LDFBaseData* Copy() const override {
|
||||||
return new LDFData<T>(key, value);
|
return new LDFData<T>(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,19 +166,19 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
// LDF Types
|
// LDF Types
|
||||||
template<> inline eLDFType LDFData<std::u16string>::GetValueType(void) { return LDF_TYPE_UTF_16; };
|
template<> inline eLDFType LDFData<std::u16string>::GetValueType(void) const { return LDF_TYPE_UTF_16; };
|
||||||
template<> inline eLDFType LDFData<int32_t>::GetValueType(void) { return LDF_TYPE_S32; };
|
template<> inline eLDFType LDFData<int32_t>::GetValueType(void) const { return LDF_TYPE_S32; };
|
||||||
template<> inline eLDFType LDFData<float>::GetValueType(void) { return LDF_TYPE_FLOAT; };
|
template<> inline eLDFType LDFData<float>::GetValueType(void) const { return LDF_TYPE_FLOAT; };
|
||||||
template<> inline eLDFType LDFData<double>::GetValueType(void) { return LDF_TYPE_DOUBLE; };
|
template<> inline eLDFType LDFData<double>::GetValueType(void) const { return LDF_TYPE_DOUBLE; };
|
||||||
template<> inline eLDFType LDFData<uint32_t>::GetValueType(void) { return LDF_TYPE_U32; };
|
template<> inline eLDFType LDFData<uint32_t>::GetValueType(void) const { return LDF_TYPE_U32; };
|
||||||
template<> inline eLDFType LDFData<bool>::GetValueType(void) { return LDF_TYPE_BOOLEAN; };
|
template<> inline eLDFType LDFData<bool>::GetValueType(void) const { return LDF_TYPE_BOOLEAN; };
|
||||||
template<> inline eLDFType LDFData<uint64_t>::GetValueType(void) { return LDF_TYPE_U64; };
|
template<> inline eLDFType LDFData<uint64_t>::GetValueType(void) const { return LDF_TYPE_U64; };
|
||||||
template<> inline eLDFType LDFData<LWOOBJID>::GetValueType(void) { return LDF_TYPE_OBJID; };
|
template<> inline eLDFType LDFData<LWOOBJID>::GetValueType(void) const { return LDF_TYPE_OBJID; };
|
||||||
template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF_TYPE_UTF_8; };
|
template<> inline eLDFType LDFData<std::string>::GetValueType(void) const { return LDF_TYPE_UTF_8; };
|
||||||
|
|
||||||
// The specialized version for std::u16string (UTF-16)
|
// The specialized version for std::u16string (UTF-16)
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) {
|
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->GetValueType());
|
packet.Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet.Write<uint32_t>(this->value.length());
|
packet.Write<uint32_t>(this->value.length());
|
||||||
@@ -189,7 +189,7 @@ inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) {
|
|||||||
|
|
||||||
// The specialized version for bool
|
// The specialized version for bool
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) {
|
inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->GetValueType());
|
packet.Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet.Write<uint8_t>(this->value);
|
packet.Write<uint8_t>(this->value);
|
||||||
@@ -197,7 +197,7 @@ inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) {
|
|||||||
|
|
||||||
// The specialized version for std::string (UTF-8)
|
// The specialized version for std::string (UTF-8)
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) {
|
inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) const {
|
||||||
packet.Write<uint8_t>(this->GetValueType());
|
packet.Write<uint8_t>(this->GetValueType());
|
||||||
|
|
||||||
packet.Write<uint32_t>(this->value.length());
|
packet.Write<uint32_t>(this->value.length());
|
||||||
@@ -206,18 +206,18 @@ inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline std::string LDFData<std::u16string>::GetValueString() {
|
template<> inline std::string LDFData<std::u16string>::GetValueString() const {
|
||||||
return GeneralUtils::UTF16ToWTF8(this->value, this->value.size());
|
return GeneralUtils::UTF16ToWTF8(this->value, this->value.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline std::string LDFData<int32_t>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<int32_t>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<float>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<float>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<double>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<double>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<uint32_t>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<uint32_t>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<bool>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<bool>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<uint64_t>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<uint64_t>::GetValueString() const { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<LWOOBJID>::GetValueString() { return std::to_string(this->value); }
|
template<> inline std::string LDFData<LWOOBJID>::GetValueString() const { return std::to_string(this->value); }
|
||||||
|
|
||||||
template<> inline std::string LDFData<std::string>::GetValueString() { return this->value; }
|
template<> inline std::string LDFData<std::string>::GetValueString() const { return this->value; }
|
||||||
|
|
||||||
#endif //!__LDFFORMAT__H__
|
#endif //!__LDFFORMAT__H__
|
||||||
|
|||||||
73
dCommon/Observable.h
Normal file
73
dCommon/Observable.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#ifndef __OBSERVABLE_H__
|
||||||
|
#define __OBSERVABLE_H__
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief An event which can be observed by multiple observers.
|
||||||
|
*
|
||||||
|
* @tparam T The types of the arguments to be passed to the observers.
|
||||||
|
*/
|
||||||
|
template <typename... T>
|
||||||
|
class Observable {
|
||||||
|
public:
|
||||||
|
typedef std::function<void(T...)> Observer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds an observer to the event.
|
||||||
|
*
|
||||||
|
* @param observer The observer to add.
|
||||||
|
*/
|
||||||
|
void AddObserver(const Observer& observer) {
|
||||||
|
observers.push_back(observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes an observer from the event.
|
||||||
|
*
|
||||||
|
* @param observer The observer to remove.
|
||||||
|
*/
|
||||||
|
void RemoveObserver(const Observer& observer) {
|
||||||
|
observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Notifies all observers of the event.
|
||||||
|
*
|
||||||
|
* @param args The arguments to pass to the observers.
|
||||||
|
*/
|
||||||
|
void Notify(T... args) {
|
||||||
|
for (const auto& observer : observers) {
|
||||||
|
observer(args...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* += operator overload.
|
||||||
|
*/
|
||||||
|
Observable& operator+=(const Observer& observer) {
|
||||||
|
AddObserver(observer);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* -= operator overload.
|
||||||
|
*/
|
||||||
|
Observable& operator-=(const Observer& observer) {
|
||||||
|
RemoveObserver(observer);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* () operator overload.
|
||||||
|
*/
|
||||||
|
void operator()(T... args) {
|
||||||
|
Notify(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Observer> observers;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__OBSERVABLE_H__
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "BinaryPathFinder.h"
|
#include "BinaryPathFinder.h"
|
||||||
#include "GeneralUtils.h"
|
#include "GeneralUtils.h"
|
||||||
|
|||||||
13
dCommon/dEnums/MessageType/Auth.h
Normal file
13
dCommon/dEnums/MessageType/Auth.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace MessageType {
|
||||||
|
enum class Auth : uint32_t {
|
||||||
|
LOGIN_REQUEST = 0,
|
||||||
|
LOGOUT_REQUEST,
|
||||||
|
CREATE_NEW_ACCOUNT_REQUEST,
|
||||||
|
LEGOINTERFACE_AUTH_RESPONSE,
|
||||||
|
SESSIONKEY_RECEIVED_CONFIRM,
|
||||||
|
RUNTIME_CONFIG
|
||||||
|
};
|
||||||
|
}
|
||||||
78
dCommon/dEnums/MessageType/Chat.h
Normal file
78
dCommon/dEnums/MessageType/Chat.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace MessageType {
|
||||||
|
//! The Internal Chat Packet Identifiers
|
||||||
|
enum class Chat : uint32_t {
|
||||||
|
LOGIN_SESSION_NOTIFY = 0,
|
||||||
|
GENERAL_CHAT_MESSAGE,
|
||||||
|
PRIVATE_CHAT_MESSAGE,
|
||||||
|
USER_CHANNEL_CHAT_MESSAGE,
|
||||||
|
WORLD_DISCONNECT_REQUEST,
|
||||||
|
WORLD_PROXIMITY_RESPONSE,
|
||||||
|
WORLD_PARCEL_RESPONSE,
|
||||||
|
ADD_FRIEND_REQUEST,
|
||||||
|
ADD_FRIEND_RESPONSE,
|
||||||
|
REMOVE_FRIEND,
|
||||||
|
GET_FRIENDS_LIST,
|
||||||
|
ADD_IGNORE,
|
||||||
|
REMOVE_IGNORE,
|
||||||
|
GET_IGNORE_LIST,
|
||||||
|
TEAM_MISSED_INVITE_CHECK,
|
||||||
|
TEAM_INVITE,
|
||||||
|
TEAM_INVITE_RESPONSE,
|
||||||
|
TEAM_KICK,
|
||||||
|
TEAM_LEAVE,
|
||||||
|
TEAM_SET_LOOT,
|
||||||
|
TEAM_SET_LEADER,
|
||||||
|
TEAM_GET_STATUS,
|
||||||
|
GUILD_CREATE,
|
||||||
|
GUILD_INVITE,
|
||||||
|
GUILD_INVITE_RESPONSE,
|
||||||
|
GUILD_LEAVE,
|
||||||
|
GUILD_KICK,
|
||||||
|
GUILD_GET_STATUS,
|
||||||
|
GUILD_GET_ALL,
|
||||||
|
SHOW_ALL,
|
||||||
|
BLUEPRINT_MODERATED,
|
||||||
|
BLUEPRINT_MODEL_READY,
|
||||||
|
PROPERTY_READY_FOR_APPROVAL,
|
||||||
|
PROPERTY_MODERATION_CHANGED,
|
||||||
|
PROPERTY_BUILDMODE_CHANGED,
|
||||||
|
PROPERTY_BUILDMODE_CHANGED_REPORT,
|
||||||
|
MAIL,
|
||||||
|
WORLD_INSTANCE_LOCATION_REQUEST,
|
||||||
|
REPUTATION_UPDATE,
|
||||||
|
SEND_CANNED_TEXT,
|
||||||
|
GMLEVEL_UPDATE,
|
||||||
|
CHARACTER_NAME_CHANGE_REQUEST,
|
||||||
|
CSR_REQUEST,
|
||||||
|
CSR_REPLY,
|
||||||
|
GM_KICK,
|
||||||
|
GM_ANNOUNCE,
|
||||||
|
GM_MUTE,
|
||||||
|
ACTIVITY_UPDATE,
|
||||||
|
WORLD_ROUTE_PACKET,
|
||||||
|
GET_ZONE_POPULATIONS,
|
||||||
|
REQUEST_MINIMUM_CHAT_MODE,
|
||||||
|
REQUEST_MINIMUM_CHAT_MODE_PRIVATE,
|
||||||
|
MATCH_REQUEST,
|
||||||
|
UGCMANIFEST_REPORT_MISSING_FILE,
|
||||||
|
UGCMANIFEST_REPORT_DONE_FILE,
|
||||||
|
UGCMANIFEST_REPORT_DONE_BLUEPRINT,
|
||||||
|
UGCC_REQUEST,
|
||||||
|
WHO,
|
||||||
|
WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE,
|
||||||
|
ACHIEVEMENT_NOTIFY,
|
||||||
|
GM_CLOSE_PRIVATE_CHAT_WINDOW,
|
||||||
|
UNEXPECTED_DISCONNECT,
|
||||||
|
PLAYER_READY,
|
||||||
|
GET_DONATION_TOTAL,
|
||||||
|
UPDATE_DONATION,
|
||||||
|
PRG_CSR_COMMAND,
|
||||||
|
HEARTBEAT_REQUEST_FROM_WORLD,
|
||||||
|
UPDATE_FREE_TRIAL_STATUS,
|
||||||
|
// CUSTOM DLU MESSAGE ID FOR INTERNAL USE
|
||||||
|
CREATE_TEAM,
|
||||||
|
};
|
||||||
|
}
|
||||||
74
dCommon/dEnums/MessageType/Client.h
Normal file
74
dCommon/dEnums/MessageType/Client.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace MessageType {
|
||||||
|
enum class Client : uint32_t {
|
||||||
|
LOGIN_RESPONSE = 0,
|
||||||
|
LOGOUT_RESPONSE,
|
||||||
|
LOAD_STATIC_ZONE,
|
||||||
|
CREATE_OBJECT,
|
||||||
|
CREATE_CHARACTER,
|
||||||
|
CREATE_CHARACTER_EXTENDED,
|
||||||
|
CHARACTER_LIST_RESPONSE,
|
||||||
|
CHARACTER_CREATE_RESPONSE,
|
||||||
|
CHARACTER_RENAME_RESPONSE,
|
||||||
|
CHAT_CONNECT_RESPONSE,
|
||||||
|
AUTH_ACCOUNT_CREATE_RESPONSE,
|
||||||
|
DELETE_CHARACTER_RESPONSE,
|
||||||
|
GAME_MSG,
|
||||||
|
CONNECT_CHAT,
|
||||||
|
TRANSFER_TO_WORLD,
|
||||||
|
IMPENDING_RELOAD_NOTIFY,
|
||||||
|
MAKE_GM_RESPONSE,
|
||||||
|
HTTP_MONITOR_INFO_RESPONSE,
|
||||||
|
SLASH_PUSH_MAP_RESPONSE,
|
||||||
|
SLASH_PULL_MAP_RESPONSE,
|
||||||
|
SLASH_LOCK_MAP_RESPONSE,
|
||||||
|
BLUEPRINT_SAVE_RESPONSE,
|
||||||
|
BLUEPRINT_LUP_SAVE_RESPONSE,
|
||||||
|
BLUEPRINT_LOAD_RESPONSE_ITEMID,
|
||||||
|
BLUEPRINT_GET_ALL_DATA_RESPONSE,
|
||||||
|
MODEL_INSTANTIATE_RESPONSE,
|
||||||
|
DEBUG_OUTPUT,
|
||||||
|
ADD_FRIEND_REQUEST,
|
||||||
|
ADD_FRIEND_RESPONSE,
|
||||||
|
REMOVE_FRIEND_RESPONSE,
|
||||||
|
GET_FRIENDS_LIST_RESPONSE,
|
||||||
|
UPDATE_FRIEND_NOTIFY,
|
||||||
|
ADD_IGNORE_RESPONSE,
|
||||||
|
REMOVE_IGNORE_RESPONSE,
|
||||||
|
GET_IGNORE_LIST_RESPONSE,
|
||||||
|
TEAM_INVITE,
|
||||||
|
TEAM_INVITE_INITIAL_RESPONSE,
|
||||||
|
GUILD_CREATE_RESPONSE,
|
||||||
|
GUILD_GET_STATUS_RESPONSE,
|
||||||
|
GUILD_INVITE,
|
||||||
|
GUILD_INVITE_INITIAL_RESPONSE,
|
||||||
|
GUILD_INVITE_FINAL_RESPONSE,
|
||||||
|
GUILD_INVITE_CONFIRM,
|
||||||
|
GUILD_ADD_PLAYER,
|
||||||
|
GUILD_REMOVE_PLAYER,
|
||||||
|
GUILD_LOGIN_LOGOUT,
|
||||||
|
GUILD_RANK_CHANGE,
|
||||||
|
GUILD_DATA,
|
||||||
|
GUILD_STATUS,
|
||||||
|
MAIL,
|
||||||
|
DB_PROXY_RESULT,
|
||||||
|
SHOW_ALL_RESPONSE,
|
||||||
|
WHO_RESPONSE,
|
||||||
|
SEND_CANNED_TEXT,
|
||||||
|
UPDATE_CHARACTER_NAME,
|
||||||
|
SET_NETWORK_SIMULATOR,
|
||||||
|
INVALID_CHAT_MESSAGE,
|
||||||
|
MINIMUM_CHAT_MODE_RESPONSE,
|
||||||
|
MINIMUM_CHAT_MODE_RESPONSE_PRIVATE,
|
||||||
|
CHAT_MODERATION_STRING,
|
||||||
|
UGC_MANIFEST_RESPONSE,
|
||||||
|
IN_LOGIN_QUEUE,
|
||||||
|
SERVER_STATES,
|
||||||
|
GM_CLOSE_TARGET_CHAT_WINDOW,
|
||||||
|
GENERAL_TEXT_FOR_LOCALIZATION,
|
||||||
|
UPDATE_FREE_TRIAL_STATUS,
|
||||||
|
UGC_DOWNLOAD_FAILED = 120
|
||||||
|
};
|
||||||
|
}
|
||||||
1612
dCommon/dEnums/MessageType/Game.h
Normal file
1612
dCommon/dEnums/MessageType/Game.h
Normal file
File diff suppressed because it is too large
Load Diff
34
dCommon/dEnums/MessageType/Master.h
Normal file
34
dCommon/dEnums/MessageType/Master.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace MessageType {
|
||||||
|
enum class Master : uint32_t {
|
||||||
|
REQUEST_PERSISTENT_ID = 1,
|
||||||
|
REQUEST_PERSISTENT_ID_RESPONSE,
|
||||||
|
REQUEST_ZONE_TRANSFER,
|
||||||
|
REQUEST_ZONE_TRANSFER_RESPONSE,
|
||||||
|
SERVER_INFO,
|
||||||
|
REQUEST_SESSION_KEY,
|
||||||
|
SET_SESSION_KEY,
|
||||||
|
SESSION_KEY_RESPONSE,
|
||||||
|
PLAYER_ADDED,
|
||||||
|
PLAYER_REMOVED,
|
||||||
|
|
||||||
|
CREATE_PRIVATE_ZONE,
|
||||||
|
REQUEST_PRIVATE_ZONE,
|
||||||
|
|
||||||
|
WORLD_READY,
|
||||||
|
PREP_ZONE,
|
||||||
|
|
||||||
|
SHUTDOWN,
|
||||||
|
SHUTDOWN_RESPONSE,
|
||||||
|
SHUTDOWN_IMMEDIATE,
|
||||||
|
|
||||||
|
SHUTDOWN_UNIVERSE,
|
||||||
|
|
||||||
|
AFFIRM_TRANSFER_REQUEST,
|
||||||
|
AFFIRM_TRANSFER_RESPONSE,
|
||||||
|
|
||||||
|
NEW_SESSION_ALERT
|
||||||
|
};
|
||||||
|
}
|
||||||
11
dCommon/dEnums/MessageType/Server.h
Normal file
11
dCommon/dEnums/MessageType/Server.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace MessageType {
|
||||||
|
//! The Internal Server Packet Identifiers
|
||||||
|
enum class Server : uint32_t {
|
||||||
|
VERSION_CONFIRM = 0,
|
||||||
|
DISCONNECT_NOTIFY,
|
||||||
|
GENERAL_NOTIFY
|
||||||
|
};
|
||||||
|
}
|
||||||
49
dCommon/dEnums/MessageType/World.h
Normal file
49
dCommon/dEnums/MessageType/World.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <magic_enum/magic_enum.hpp>
|
||||||
|
|
||||||
|
namespace MessageType {
|
||||||
|
enum class World : uint32_t {
|
||||||
|
VALIDATION = 1, // Session info
|
||||||
|
CHARACTER_LIST_REQUEST,
|
||||||
|
CHARACTER_CREATE_REQUEST,
|
||||||
|
LOGIN_REQUEST, // Character selected
|
||||||
|
GAME_MSG,
|
||||||
|
CHARACTER_DELETE_REQUEST,
|
||||||
|
CHARACTER_RENAME_REQUEST,
|
||||||
|
HAPPY_FLOWER_MODE_NOTIFY,
|
||||||
|
SLASH_RELOAD_MAP, // Reload map cmp
|
||||||
|
SLASH_PUSH_MAP_REQUEST, // Push map req cmd
|
||||||
|
SLASH_PUSH_MAP, // Push map cmd
|
||||||
|
SLASH_PULL_MAP, // Pull map cmd
|
||||||
|
LOCK_MAP_REQUEST,
|
||||||
|
GENERAL_CHAT_MESSAGE, // General chat message
|
||||||
|
HTTP_MONITOR_INFO_REQUEST,
|
||||||
|
SLASH_DEBUG_SCRIPTS, // Debug scripts cmd
|
||||||
|
MODELS_CLEAR,
|
||||||
|
EXHIBIT_INSERT_MODEL,
|
||||||
|
LEVEL_LOAD_COMPLETE, // Character data request
|
||||||
|
TMP_GUILD_CREATE,
|
||||||
|
ROUTE_PACKET, // Social?
|
||||||
|
POSITION_UPDATE,
|
||||||
|
MAIL,
|
||||||
|
WORD_CHECK, // AllowList word check
|
||||||
|
STRING_CHECK, // AllowList string check
|
||||||
|
GET_PLAYERS_IN_ZONE,
|
||||||
|
REQUEST_UGC_MANIFEST_INFO,
|
||||||
|
BLUEPRINT_GET_ALL_DATA_REQUEST,
|
||||||
|
CANCEL_MAP_QUEUE,
|
||||||
|
HANDLE_FUNNESS,
|
||||||
|
FAKE_PRG_CSR_MESSAGE,
|
||||||
|
REQUEST_FREE_TRIAL_REFRESH,
|
||||||
|
GM_SET_FREE_TRIAL_STATUS,
|
||||||
|
UI_HELP_TOP_5 = 91
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct magic_enum::customize::enum_range<MessageType::World> {
|
||||||
|
static constexpr int min = 0;
|
||||||
|
static constexpr int max = 91;
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
#define __STRINGIFIEDENUM_H__
|
#define __STRINGIFIEDENUM_H__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "magic_enum.hpp"
|
#include <magic_enum/magic_enum.hpp>
|
||||||
|
|
||||||
namespace StringifiedEnum {
|
namespace StringifiedEnum {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include "BitStream.h"
|
#include "BitStream.h"
|
||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "eClientMessageType.h"
|
#include "MessageType/Client.h"
|
||||||
#include "BitStreamUtils.h"
|
#include "BitStreamUtils.h"
|
||||||
|
|
||||||
#pragma warning (disable:4251) //Disables SQL warnings
|
#pragma warning (disable:4251) //Disables SQL warnings
|
||||||
@@ -33,7 +33,7 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
|
|||||||
#define CBITSTREAM RakNet::BitStream bitStream;
|
#define CBITSTREAM RakNet::BitStream bitStream;
|
||||||
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
|
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||||
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
|
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
|
||||||
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GAME_MSG);
|
||||||
#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false);
|
#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false);
|
||||||
#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
#ifndef __EAUTHMESSAGETYPE__H__
|
|
||||||
#define __EAUTHMESSAGETYPE__H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
enum class eAuthMessageType : uint32_t {
|
|
||||||
LOGIN_REQUEST = 0,
|
|
||||||
LOGOUT_REQUEST,
|
|
||||||
CREATE_NEW_ACCOUNT_REQUEST,
|
|
||||||
LEGOINTERFACE_AUTH_RESPONSE,
|
|
||||||
SESSIONKEY_RECEIVED_CONFIRM,
|
|
||||||
RUNTIME_CONFIG
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //!__EAUTHMESSAGETYPE__H__
|
|
||||||
@@ -15,7 +15,8 @@ enum class eCharacterVersion : uint32_t {
|
|||||||
// Fixes vault size value
|
// Fixes vault size value
|
||||||
VAULT_SIZE,
|
VAULT_SIZE,
|
||||||
// Fixes speed base value in level component
|
// Fixes speed base value in level component
|
||||||
UP_TO_DATE, // will become SPEED_BASE
|
SPEED_BASE,
|
||||||
|
UP_TO_DATE, // will become NJ_JAYMISSIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__ECHARACTERVERSION__H__
|
#endif //!__ECHARACTERVERSION__H__
|
||||||
|
|||||||
@@ -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__
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
#ifndef __ECHATMESSAGETYPE__H__
|
|
||||||
#define __ECHATMESSAGETYPE__H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
//! The Internal Chat Packet Identifiers
|
|
||||||
enum class eChatMessageType :uint32_t {
|
|
||||||
LOGIN_SESSION_NOTIFY = 0,
|
|
||||||
GENERAL_CHAT_MESSAGE,
|
|
||||||
PRIVATE_CHAT_MESSAGE,
|
|
||||||
USER_CHANNEL_CHAT_MESSAGE,
|
|
||||||
WORLD_DISCONNECT_REQUEST,
|
|
||||||
WORLD_PROXIMITY_RESPONSE,
|
|
||||||
WORLD_PARCEL_RESPONSE,
|
|
||||||
ADD_FRIEND_REQUEST,
|
|
||||||
ADD_FRIEND_RESPONSE,
|
|
||||||
REMOVE_FRIEND,
|
|
||||||
GET_FRIENDS_LIST,
|
|
||||||
ADD_IGNORE,
|
|
||||||
REMOVE_IGNORE,
|
|
||||||
GET_IGNORE_LIST,
|
|
||||||
TEAM_MISSED_INVITE_CHECK,
|
|
||||||
TEAM_INVITE,
|
|
||||||
TEAM_INVITE_RESPONSE,
|
|
||||||
TEAM_KICK,
|
|
||||||
TEAM_LEAVE,
|
|
||||||
TEAM_SET_LOOT,
|
|
||||||
TEAM_SET_LEADER,
|
|
||||||
TEAM_GET_STATUS,
|
|
||||||
GUILD_CREATE,
|
|
||||||
GUILD_INVITE,
|
|
||||||
GUILD_INVITE_RESPONSE,
|
|
||||||
GUILD_LEAVE,
|
|
||||||
GUILD_KICK,
|
|
||||||
GUILD_GET_STATUS,
|
|
||||||
GUILD_GET_ALL,
|
|
||||||
SHOW_ALL,
|
|
||||||
BLUEPRINT_MODERATED,
|
|
||||||
BLUEPRINT_MODEL_READY,
|
|
||||||
PROPERTY_READY_FOR_APPROVAL,
|
|
||||||
PROPERTY_MODERATION_CHANGED,
|
|
||||||
PROPERTY_BUILDMODE_CHANGED,
|
|
||||||
PROPERTY_BUILDMODE_CHANGED_REPORT,
|
|
||||||
MAIL,
|
|
||||||
WORLD_INSTANCE_LOCATION_REQUEST,
|
|
||||||
REPUTATION_UPDATE,
|
|
||||||
SEND_CANNED_TEXT,
|
|
||||||
GMLEVEL_UPDATE,
|
|
||||||
CHARACTER_NAME_CHANGE_REQUEST,
|
|
||||||
CSR_REQUEST,
|
|
||||||
CSR_REPLY,
|
|
||||||
GM_KICK,
|
|
||||||
GM_ANNOUNCE,
|
|
||||||
GM_MUTE,
|
|
||||||
ACTIVITY_UPDATE,
|
|
||||||
WORLD_ROUTE_PACKET,
|
|
||||||
GET_ZONE_POPULATIONS,
|
|
||||||
REQUEST_MINIMUM_CHAT_MODE,
|
|
||||||
REQUEST_MINIMUM_CHAT_MODE_PRIVATE,
|
|
||||||
MATCH_REQUEST,
|
|
||||||
UGCMANIFEST_REPORT_MISSING_FILE,
|
|
||||||
UGCMANIFEST_REPORT_DONE_FILE,
|
|
||||||
UGCMANIFEST_REPORT_DONE_BLUEPRINT,
|
|
||||||
UGCC_REQUEST,
|
|
||||||
WHO,
|
|
||||||
WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE,
|
|
||||||
ACHIEVEMENT_NOTIFY,
|
|
||||||
GM_CLOSE_PRIVATE_CHAT_WINDOW,
|
|
||||||
UNEXPECTED_DISCONNECT,
|
|
||||||
PLAYER_READY,
|
|
||||||
GET_DONATION_TOTAL,
|
|
||||||
UPDATE_DONATION,
|
|
||||||
PRG_CSR_COMMAND,
|
|
||||||
HEARTBEAT_REQUEST_FROM_WORLD,
|
|
||||||
UPDATE_FREE_TRIAL_STATUS
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //!__ECHATMESSAGETYPE__H__
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
#ifndef __ECLIENTMESSAGETYPE__H__
|
|
||||||
#define __ECLIENTMESSAGETYPE__H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
enum class eClientMessageType : uint32_t {
|
|
||||||
LOGIN_RESPONSE = 0,
|
|
||||||
LOGOUT_RESPONSE,
|
|
||||||
LOAD_STATIC_ZONE,
|
|
||||||
CREATE_OBJECT,
|
|
||||||
CREATE_CHARACTER,
|
|
||||||
CREATE_CHARACTER_EXTENDED,
|
|
||||||
CHARACTER_LIST_RESPONSE,
|
|
||||||
CHARACTER_CREATE_RESPONSE,
|
|
||||||
CHARACTER_RENAME_RESPONSE,
|
|
||||||
CHAT_CONNECT_RESPONSE,
|
|
||||||
AUTH_ACCOUNT_CREATE_RESPONSE,
|
|
||||||
DELETE_CHARACTER_RESPONSE,
|
|
||||||
GAME_MSG,
|
|
||||||
CONNECT_CHAT,
|
|
||||||
TRANSFER_TO_WORLD,
|
|
||||||
IMPENDING_RELOAD_NOTIFY,
|
|
||||||
MAKE_GM_RESPONSE,
|
|
||||||
HTTP_MONITOR_INFO_RESPONSE,
|
|
||||||
SLASH_PUSH_MAP_RESPONSE,
|
|
||||||
SLASH_PULL_MAP_RESPONSE,
|
|
||||||
SLASH_LOCK_MAP_RESPONSE,
|
|
||||||
BLUEPRINT_SAVE_RESPONSE,
|
|
||||||
BLUEPRINT_LUP_SAVE_RESPONSE,
|
|
||||||
BLUEPRINT_LOAD_RESPONSE_ITEMID,
|
|
||||||
BLUEPRINT_GET_ALL_DATA_RESPONSE,
|
|
||||||
MODEL_INSTANTIATE_RESPONSE,
|
|
||||||
DEBUG_OUTPUT,
|
|
||||||
ADD_FRIEND_REQUEST,
|
|
||||||
ADD_FRIEND_RESPONSE,
|
|
||||||
REMOVE_FRIEND_RESPONSE,
|
|
||||||
GET_FRIENDS_LIST_RESPONSE,
|
|
||||||
UPDATE_FRIEND_NOTIFY,
|
|
||||||
ADD_IGNORE_RESPONSE,
|
|
||||||
REMOVE_IGNORE_RESPONSE,
|
|
||||||
GET_IGNORE_LIST_RESPONSE,
|
|
||||||
TEAM_INVITE,
|
|
||||||
TEAM_INVITE_INITIAL_RESPONSE,
|
|
||||||
GUILD_CREATE_RESPONSE,
|
|
||||||
GUILD_GET_STATUS_RESPONSE,
|
|
||||||
GUILD_INVITE,
|
|
||||||
GUILD_INVITE_INITIAL_RESPONSE,
|
|
||||||
GUILD_INVITE_FINAL_RESPONSE,
|
|
||||||
GUILD_INVITE_CONFIRM,
|
|
||||||
GUILD_ADD_PLAYER,
|
|
||||||
GUILD_REMOVE_PLAYER,
|
|
||||||
GUILD_LOGIN_LOGOUT,
|
|
||||||
GUILD_RANK_CHANGE,
|
|
||||||
GUILD_DATA,
|
|
||||||
GUILD_STATUS,
|
|
||||||
MAIL,
|
|
||||||
DB_PROXY_RESULT,
|
|
||||||
SHOW_ALL_RESPONSE,
|
|
||||||
WHO_RESPONSE,
|
|
||||||
SEND_CANNED_TEXT,
|
|
||||||
UPDATE_CHARACTER_NAME,
|
|
||||||
SET_NETWORK_SIMULATOR,
|
|
||||||
INVALID_CHAT_MESSAGE,
|
|
||||||
MINIMUM_CHAT_MODE_RESPONSE,
|
|
||||||
MINIMUM_CHAT_MODE_RESPONSE_PRIVATE,
|
|
||||||
CHAT_MODERATION_STRING,
|
|
||||||
UGC_MANIFEST_RESPONSE,
|
|
||||||
IN_LOGIN_QUEUE,
|
|
||||||
SERVER_STATES,
|
|
||||||
GM_CLOSE_TARGET_CHAT_WINDOW,
|
|
||||||
GENERAL_TEXT_FOR_LOCALIZATION,
|
|
||||||
UPDATE_FREE_TRIAL_STATUS,
|
|
||||||
UGC_DOWNLOAD_FAILED = 120
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //!__ECLIENTMESSAGETYPE__H__
|
|
||||||
@@ -5,8 +5,7 @@ enum class eConnectionType : uint16_t {
|
|||||||
SERVER = 0,
|
SERVER = 0,
|
||||||
AUTH,
|
AUTH,
|
||||||
CHAT,
|
CHAT,
|
||||||
CHAT_INTERNAL,
|
WORLD = 4,
|
||||||
WORLD,
|
|
||||||
CLIENT,
|
CLIENT,
|
||||||
MASTER
|
MASTER
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,9 @@
|
|||||||
#define __EINVENTORYTYPE__H__
|
#define __EINVENTORYTYPE__H__
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <magic_enum/magic_enum.hpp>
|
||||||
|
|
||||||
static const uint8_t NUMBER_OF_INVENTORIES = 17;
|
static const uint8_t NUMBER_OF_INVENTORIES = 17;
|
||||||
/**
|
/**
|
||||||
* Represents the different types of inventories an entity may have
|
* Represents the different types of inventories an entity may have
|
||||||
@@ -56,4 +59,10 @@ public:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct magic_enum::customize::enum_range<eInventoryType> {
|
||||||
|
static constexpr int min = 0;
|
||||||
|
static constexpr int max = 16;
|
||||||
|
};
|
||||||
|
|
||||||
#endif //!__EINVENTORYTYPE__H__
|
#endif //!__EINVENTORYTYPE__H__
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
#ifndef __EMASTERMESSAGETYPE__H__
|
|
||||||
#define __EMASTERMESSAGETYPE__H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
enum class eMasterMessageType : uint32_t {
|
|
||||||
REQUEST_PERSISTENT_ID = 1,
|
|
||||||
REQUEST_PERSISTENT_ID_RESPONSE,
|
|
||||||
REQUEST_ZONE_TRANSFER,
|
|
||||||
REQUEST_ZONE_TRANSFER_RESPONSE,
|
|
||||||
SERVER_INFO,
|
|
||||||
REQUEST_SESSION_KEY,
|
|
||||||
SET_SESSION_KEY,
|
|
||||||
SESSION_KEY_RESPONSE,
|
|
||||||
PLAYER_ADDED,
|
|
||||||
PLAYER_REMOVED,
|
|
||||||
|
|
||||||
CREATE_PRIVATE_ZONE,
|
|
||||||
REQUEST_PRIVATE_ZONE,
|
|
||||||
|
|
||||||
WORLD_READY,
|
|
||||||
PREP_ZONE,
|
|
||||||
|
|
||||||
SHUTDOWN,
|
|
||||||
SHUTDOWN_RESPONSE,
|
|
||||||
SHUTDOWN_IMMEDIATE,
|
|
||||||
|
|
||||||
SHUTDOWN_UNIVERSE,
|
|
||||||
|
|
||||||
AFFIRM_TRANSFER_REQUEST,
|
|
||||||
AFFIRM_TRANSFER_RESPONSE,
|
|
||||||
|
|
||||||
NEW_SESSION_ALERT
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //!__EMASTERMESSAGETYPE__H__
|
|
||||||
11
dCommon/dEnums/ePropertySortType.h
Normal file
11
dCommon/dEnums/ePropertySortType.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef EPROPERTYSORTTYPE_H
|
||||||
|
#define EPROPERTYSORTTYPE_H
|
||||||
|
|
||||||
|
enum ePropertySortType : int32_t {
|
||||||
|
SORT_TYPE_FRIENDS = 0,
|
||||||
|
SORT_TYPE_REPUTATION = 1,
|
||||||
|
SORT_TYPE_RECENT = 3,
|
||||||
|
SORT_TYPE_FEATURED = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!EPROPERTYSORTTYPE_H
|
||||||
21
dCommon/dEnums/eReponseMoveItemBetweenInventoryTypeCode.h
Normal file
21
dCommon/dEnums/eReponseMoveItemBetweenInventoryTypeCode.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef __EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__
|
||||||
|
#define __EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t {
|
||||||
|
SUCCESS,
|
||||||
|
FAIL_GENERIC,
|
||||||
|
FAIL_INV_FULL,
|
||||||
|
FAIL_ITEM_NOT_FOUND,
|
||||||
|
FAIL_CANT_MOVE_TO_THAT_INV_TYPE,
|
||||||
|
FAIL_NOT_NEAR_BANK,
|
||||||
|
FAIL_CANT_SWAP_ITEMS,
|
||||||
|
FAIL_SOURCE_TYPE,
|
||||||
|
FAIL_WRONG_DEST_TYPE,
|
||||||
|
FAIL_SWAP_DEST_TYPE,
|
||||||
|
FAIL_CANT_MOVE_THINKING_HAT,
|
||||||
|
FAIL_DISMOUNT_BEFORE_MOVING
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#ifndef __ESERVERMESSAGETYPE__H__
|
|
||||||
#define __ESERVERMESSAGETYPE__H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
//! The Internal Server Packet Identifiers
|
|
||||||
enum class eServerMessageType : uint32_t {
|
|
||||||
VERSION_CONFIRM = 0,
|
|
||||||
DISCONNECT_NOTIFY,
|
|
||||||
GENERAL_NOTIFY
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //!__ESERVERMESSAGETYPE__H__
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
#ifndef __EWORLDMESSAGETYPE__H__
|
|
||||||
#define __EWORLDMESSAGETYPE__H__
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
#include "magic_enum.hpp"
|
|
||||||
|
|
||||||
enum class eWorldMessageType : uint32_t {
|
|
||||||
VALIDATION = 1, // Session info
|
|
||||||
CHARACTER_LIST_REQUEST,
|
|
||||||
CHARACTER_CREATE_REQUEST,
|
|
||||||
LOGIN_REQUEST, // Character selected
|
|
||||||
GAME_MSG,
|
|
||||||
CHARACTER_DELETE_REQUEST,
|
|
||||||
CHARACTER_RENAME_REQUEST,
|
|
||||||
HAPPY_FLOWER_MODE_NOTIFY,
|
|
||||||
SLASH_RELOAD_MAP, // Reload map cmp
|
|
||||||
SLASH_PUSH_MAP_REQUEST, // Push map req cmd
|
|
||||||
SLASH_PUSH_MAP, // Push map cmd
|
|
||||||
SLASH_PULL_MAP, // Pull map cmd
|
|
||||||
LOCK_MAP_REQUEST,
|
|
||||||
GENERAL_CHAT_MESSAGE, // General chat message
|
|
||||||
HTTP_MONITOR_INFO_REQUEST,
|
|
||||||
SLASH_DEBUG_SCRIPTS, // Debug scripts cmd
|
|
||||||
MODELS_CLEAR,
|
|
||||||
EXHIBIT_INSERT_MODEL,
|
|
||||||
LEVEL_LOAD_COMPLETE, // Character data request
|
|
||||||
TMP_GUILD_CREATE,
|
|
||||||
ROUTE_PACKET, // Social?
|
|
||||||
POSITION_UPDATE,
|
|
||||||
MAIL,
|
|
||||||
WORD_CHECK, // Whitelist word check
|
|
||||||
STRING_CHECK, // Whitelist string check
|
|
||||||
GET_PLAYERS_IN_ZONE,
|
|
||||||
REQUEST_UGC_MANIFEST_INFO,
|
|
||||||
BLUEPRINT_GET_ALL_DATA_REQUEST,
|
|
||||||
CANCEL_MAP_QUEUE,
|
|
||||||
HANDLE_FUNNESS,
|
|
||||||
FAKE_PRG_CSR_MESSAGE,
|
|
||||||
REQUEST_FREE_TRIAL_REFRESH,
|
|
||||||
GM_SET_FREE_TRIAL_STATUS,
|
|
||||||
UI_HELP_TOP_5 = 91
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct magic_enum::customize::enum_range<eWorldMessageType> {
|
|
||||||
static constexpr int min = 0;
|
|
||||||
static constexpr int max = 91;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //!__EWORLDMESSAGETYPE__H__
|
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "CDScriptComponentTable.h"
|
#include "CDScriptComponentTable.h"
|
||||||
#include "CDSkillBehaviorTable.h"
|
#include "CDSkillBehaviorTable.h"
|
||||||
#include "CDZoneTableTable.h"
|
#include "CDZoneTableTable.h"
|
||||||
|
#include "CDTamingBuildPuzzleTable.h"
|
||||||
#include "CDVendorComponentTable.h"
|
#include "CDVendorComponentTable.h"
|
||||||
#include "CDActivitiesTable.h"
|
#include "CDActivitiesTable.h"
|
||||||
#include "CDPackageComponentTable.h"
|
#include "CDPackageComponentTable.h"
|
||||||
@@ -41,8 +42,6 @@
|
|||||||
#include "CDRewardCodesTable.h"
|
#include "CDRewardCodesTable.h"
|
||||||
#include "CDPetComponentTable.h"
|
#include "CDPetComponentTable.h"
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
#ifndef CDCLIENT_CACHE_ALL
|
#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.
|
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
|
||||||
// A vanilla CDClient takes about 46MB of memory + the regular world data.
|
// A vanilla CDClient takes about 46MB of memory + the regular world data.
|
||||||
@@ -55,13 +54,6 @@
|
|||||||
#define CDCLIENT_DONT_CACHE_TABLE(x)
|
#define CDCLIENT_DONT_CACHE_TABLE(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class CDClientConnectionException : public std::exception {
|
|
||||||
public:
|
|
||||||
virtual const char* what() const throw() {
|
|
||||||
return "CDClientDatabase is not connected!";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Using a macro to reduce repetitive code and issues from copy and paste.
|
// 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.
|
// As a note, ## in a macro is used to concatenate two tokens together.
|
||||||
|
|
||||||
@@ -108,11 +100,14 @@ DEFINE_TABLE_STORAGE(CDRewardCodesTable);
|
|||||||
DEFINE_TABLE_STORAGE(CDRewardsTable);
|
DEFINE_TABLE_STORAGE(CDRewardsTable);
|
||||||
DEFINE_TABLE_STORAGE(CDScriptComponentTable);
|
DEFINE_TABLE_STORAGE(CDScriptComponentTable);
|
||||||
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
|
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
|
||||||
|
DEFINE_TABLE_STORAGE(CDTamingBuildPuzzleTable);
|
||||||
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
|
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
|
||||||
DEFINE_TABLE_STORAGE(CDZoneTableTable);
|
DEFINE_TABLE_STORAGE(CDZoneTableTable);
|
||||||
|
|
||||||
void CDClientManager::LoadValuesFromDatabase() {
|
void CDClientManager::LoadValuesFromDatabase() {
|
||||||
if (!CDClientDatabase::isConnected) throw CDClientConnectionException();
|
if (!CDClientDatabase::isConnected) {
|
||||||
|
throw std::runtime_error{ "CDClientDatabase is not connected!" };
|
||||||
|
}
|
||||||
|
|
||||||
CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
|
CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
|
||||||
CDActivitiesTable::Instance().LoadValuesFromDatabase();
|
CDActivitiesTable::Instance().LoadValuesFromDatabase();
|
||||||
@@ -152,6 +147,7 @@ void CDClientManager::LoadValuesFromDatabase() {
|
|||||||
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
||||||
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
||||||
|
CDTamingBuildPuzzleTable::Instance().LoadValuesFromDatabase();
|
||||||
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
|
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDZoneTableTable::Instance().LoadValuesFromDatabase();
|
CDZoneTableTable::Instance().LoadValuesFromDatabase();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ void CDPetComponentTable::LoadValuesFromDatabase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CDPetComponentTable::LoadValuesFromDefaults() {
|
void CDPetComponentTable::LoadValuesFromDefaults() {
|
||||||
GetEntriesMutable().insert(std::make_pair(defaultEntry.id, defaultEntry));
|
GetEntriesMutable().emplace(defaultEntry.id, defaultEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
CDPetComponent& CDPetComponentTable::GetByID(const uint32_t componentID) {
|
CDPetComponent& CDPetComponentTable::GetByID(const uint32_t componentID) {
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include "CDTamingBuildPuzzleTable.h"
|
||||||
|
|
||||||
|
void CDTamingBuildPuzzleTable::LoadValuesFromDatabase() {
|
||||||
|
// First, get the size of the table
|
||||||
|
uint32_t size = 0;
|
||||||
|
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM TamingBuildPuzzles");
|
||||||
|
while (!tableSize.eof()) {
|
||||||
|
size = tableSize.getIntField(0, 0);
|
||||||
|
tableSize.nextRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserve the size
|
||||||
|
auto& entries = GetEntriesMutable();
|
||||||
|
entries.reserve(size);
|
||||||
|
|
||||||
|
// Now get the data
|
||||||
|
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM TamingBuildPuzzles");
|
||||||
|
while (!tableData.eof()) {
|
||||||
|
const auto lot = static_cast<LOT>(tableData.getIntField("NPCLot", LOT_NULL));
|
||||||
|
entries.emplace(lot, CDTamingBuildPuzzle{
|
||||||
|
.puzzleModelLot = lot,
|
||||||
|
.validPieces{ tableData.getStringField("ValidPiecesLXF") },
|
||||||
|
.timeLimit = static_cast<float>(tableData.getFloatField("Timelimit", 30.0f)),
|
||||||
|
.numValidPieces = tableData.getIntField("NumValidPieces", 6),
|
||||||
|
.imaginationCost = tableData.getIntField("imagCostPerBuild", 10)
|
||||||
|
});
|
||||||
|
tableData.nextRow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CDTamingBuildPuzzle* CDTamingBuildPuzzleTable::GetByLOT(const LOT lot) const {
|
||||||
|
const auto& entries = GetEntries();
|
||||||
|
const auto itr = entries.find(lot);
|
||||||
|
return itr != entries.cend() ? &itr->second : nullptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "CDTable.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information for the minigame to be completed
|
||||||
|
*/
|
||||||
|
struct CDTamingBuildPuzzle {
|
||||||
|
UNUSED_COLUMN(uint32_t id = 0;)
|
||||||
|
|
||||||
|
// The LOT of the object that is to be created
|
||||||
|
LOT puzzleModelLot = LOT_NULL;
|
||||||
|
|
||||||
|
// The LOT of the NPC
|
||||||
|
UNUSED_COLUMN(LOT npcLot = LOT_NULL;)
|
||||||
|
|
||||||
|
// The .lxfml file that contains the bricks required to build the model
|
||||||
|
std::string validPieces{};
|
||||||
|
|
||||||
|
// The .lxfml file that contains the bricks NOT required to build the model
|
||||||
|
UNUSED_COLUMN(std::string invalidPieces{};)
|
||||||
|
|
||||||
|
// Difficulty value
|
||||||
|
UNUSED_COLUMN(int32_t difficulty = 1;)
|
||||||
|
|
||||||
|
// The time limit to complete the build
|
||||||
|
float timeLimit = 30.0f;
|
||||||
|
|
||||||
|
// The number of pieces required to complete the minigame
|
||||||
|
int32_t numValidPieces = 6;
|
||||||
|
|
||||||
|
// Number of valid pieces
|
||||||
|
UNUSED_COLUMN(int32_t totalNumPieces = 16;)
|
||||||
|
|
||||||
|
// Model name
|
||||||
|
UNUSED_COLUMN(std::string modelName{};)
|
||||||
|
|
||||||
|
// The .lxfml file that contains the full model
|
||||||
|
UNUSED_COLUMN(std::string fullModel{};)
|
||||||
|
|
||||||
|
// The duration of the pet taming minigame
|
||||||
|
UNUSED_COLUMN(float duration = 45.0f;)
|
||||||
|
|
||||||
|
// The imagination cost for the tamer to start the minigame
|
||||||
|
int32_t imaginationCost = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDTamingBuildPuzzleTable : public CDTable<CDTamingBuildPuzzleTable, std::unordered_map<LOT, CDTamingBuildPuzzle>> {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Load values from the CD client database
|
||||||
|
*/
|
||||||
|
void LoadValuesFromDatabase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pet ability table corresponding to the pet LOT
|
||||||
|
* @returns A pointer to the corresponding table, or nullptr if one cannot be found
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
const CDTamingBuildPuzzle* GetByLOT(const LOT lot) const;
|
||||||
|
};
|
||||||
@@ -36,5 +36,6 @@ set(DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES "CDActivitiesTable.cpp"
|
|||||||
"CDRewardsTable.cpp"
|
"CDRewardsTable.cpp"
|
||||||
"CDScriptComponentTable.cpp"
|
"CDScriptComponentTable.cpp"
|
||||||
"CDSkillBehaviorTable.cpp"
|
"CDSkillBehaviorTable.cpp"
|
||||||
|
"CDTamingBuildPuzzleTable.cpp"
|
||||||
"CDVendorComponentTable.cpp"
|
"CDVendorComponentTable.cpp"
|
||||||
"CDZoneTableTable.cpp" PARENT_SCOPE)
|
"CDZoneTableTable.cpp" PARENT_SCOPE)
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ add_subdirectory(GameDatabase)
|
|||||||
add_library(dDatabase STATIC "MigrationRunner.cpp")
|
add_library(dDatabase STATIC "MigrationRunner.cpp")
|
||||||
target_include_directories(dDatabase PUBLIC ".")
|
target_include_directories(dDatabase PUBLIC ".")
|
||||||
target_link_libraries(dDatabase
|
target_link_libraries(dDatabase
|
||||||
PUBLIC dDatabaseCDClient dDatabaseGame)
|
PUBLIC magic_enum::magic_enum dDatabaseCDClient dDatabaseGame)
|
||||||
|
|||||||
@@ -8,9 +8,15 @@ foreach(file ${DDATABSE_DATABSES_MYSQL_SOURCES})
|
|||||||
set(DDATABASE_GAMEDATABASE_SOURCES ${DDATABASE_GAMEDATABASE_SOURCES} "MySQL/${file}")
|
set(DDATABASE_GAMEDATABASE_SOURCES ${DDATABASE_GAMEDATABASE_SOURCES} "MySQL/${file}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
add_subdirectory(TestSQL)
|
||||||
|
|
||||||
|
foreach(file ${DDATABSE_DATABSES_TEST_SQL_SOURCES})
|
||||||
|
set(DDATABASE_GAMEDATABASE_SOURCES ${DDATABASE_GAMEDATABASE_SOURCES} "TestSQL/${file}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
add_library(dDatabaseGame STATIC ${DDATABASE_GAMEDATABASE_SOURCES})
|
add_library(dDatabaseGame STATIC ${DDATABASE_GAMEDATABASE_SOURCES})
|
||||||
target_include_directories(dDatabaseGame PUBLIC "."
|
target_include_directories(dDatabaseGame PUBLIC "."
|
||||||
"ITables" PRIVATE "MySQL"
|
"ITables" PRIVATE "MySQL" "TestSQL"
|
||||||
"${PROJECT_SOURCE_DIR}/dCommon"
|
"${PROJECT_SOURCE_DIR}/dCommon"
|
||||||
"${PROJECT_SOURCE_DIR}/dCommon/dEnums"
|
"${PROJECT_SOURCE_DIR}/dCommon/dEnums"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -38,3 +38,8 @@ void Database::Destroy(std::string source) {
|
|||||||
LOG("Trying to destroy database when it's not connected!");
|
LOG("Trying to destroy database when it's not connected!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Database::_setDatabase(GameDatabase* const db) {
|
||||||
|
if (database) delete database;
|
||||||
|
database = db;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <conncpp.hpp>
|
|
||||||
|
|
||||||
#include "GameDatabase.h"
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
@@ -9,4 +8,8 @@ namespace Database {
|
|||||||
void Connect();
|
void Connect();
|
||||||
GameDatabase* Get();
|
GameDatabase* Get();
|
||||||
void Destroy(std::string source = "");
|
void Destroy(std::string source = "");
|
||||||
|
|
||||||
|
// Used for assigning a test database as the handler for database logic.
|
||||||
|
// Do not use in production code.
|
||||||
|
void _setDatabase(GameDatabase* const db);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include "IActivityLog.h"
|
#include "IActivityLog.h"
|
||||||
#include "IIgnoreList.h"
|
#include "IIgnoreList.h"
|
||||||
#include "IAccountsRewardCodes.h"
|
#include "IAccountsRewardCodes.h"
|
||||||
|
#include "IBehaviors.h"
|
||||||
|
#include "IUgcModularBuild.h"
|
||||||
|
|
||||||
namespace sql {
|
namespace sql {
|
||||||
class Statement;
|
class Statement;
|
||||||
@@ -40,7 +42,8 @@ class GameDatabase :
|
|||||||
public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports,
|
public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports,
|
||||||
public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
|
public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
|
||||||
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
|
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
|
||||||
public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList {
|
public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList,
|
||||||
|
public IBehaviors, public IUgcModularBuild {
|
||||||
public:
|
public:
|
||||||
virtual ~GameDatabase() = default;
|
virtual ~GameDatabase() = default;
|
||||||
// TODO: These should be made private.
|
// TODO: These should be made private.
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ public:
|
|||||||
|
|
||||||
// Add a new account to the database.
|
// Add a new account to the database.
|
||||||
virtual void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) = 0;
|
virtual void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) = 0;
|
||||||
|
|
||||||
|
// Update the GameMaster level of an account.
|
||||||
|
virtual void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__IACCOUNTS__H__
|
#endif //!__IACCOUNTS__H__
|
||||||
|
|||||||
22
dDatabase/GameDatabase/ITables/IBehaviors.h
Normal file
22
dDatabase/GameDatabase/ITables/IBehaviors.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef IBEHAVIORS_H
|
||||||
|
#define IBEHAVIORS_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "dCommonVars.h"
|
||||||
|
|
||||||
|
class IBehaviors {
|
||||||
|
public:
|
||||||
|
struct Info {
|
||||||
|
int32_t behaviorId{};
|
||||||
|
uint32_t characterId{};
|
||||||
|
std::string behaviorInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This Add also takes care of updating if it exists.
|
||||||
|
virtual void AddBehavior(const Info& info) = 0;
|
||||||
|
virtual std::string GetBehavior(const int32_t behaviorId) = 0;
|
||||||
|
virtual void RemoveBehavior(const int32_t behaviorId) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!IBEHAVIORS_H
|
||||||
@@ -3,12 +3,45 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class ILeaderboard {
|
class ILeaderboard {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
uint32_t charId{};
|
||||||
|
uint32_t lastPlayedTimestamp{};
|
||||||
|
float primaryScore{};
|
||||||
|
float secondaryScore{};
|
||||||
|
uint32_t tertiaryScore{};
|
||||||
|
uint32_t numWins{};
|
||||||
|
uint32_t numTimesPlayed{};
|
||||||
|
uint32_t ranking{};
|
||||||
|
std::string name{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Score {
|
||||||
|
auto operator<=>(const Score& rhs) const = default;
|
||||||
|
|
||||||
|
float primaryScore{ 0.0f };
|
||||||
|
float secondaryScore{ 0.0f };
|
||||||
|
float tertiaryScore{ 0.0f };
|
||||||
|
};
|
||||||
|
|
||||||
// Get the donation total for the given activity id.
|
// Get the donation total for the given activity id.
|
||||||
virtual std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) = 0;
|
virtual std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) = 0;
|
||||||
|
|
||||||
|
virtual std::vector<ILeaderboard::Entry> GetDescendingLeaderboard(const uint32_t activityId) = 0;
|
||||||
|
virtual std::vector<ILeaderboard::Entry> GetAscendingLeaderboard(const uint32_t activityId) = 0;
|
||||||
|
virtual std::vector<ILeaderboard::Entry> GetNsLeaderboard(const uint32_t activityId) = 0;
|
||||||
|
virtual std::vector<ILeaderboard::Entry> GetAgsLeaderboard(const uint32_t activityId) = 0;
|
||||||
|
virtual std::optional<Score> GetPlayerScore(const uint32_t playerId, const uint32_t gameId) = 0;
|
||||||
|
|
||||||
|
virtual void SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) = 0;
|
||||||
|
virtual void UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) = 0;
|
||||||
|
virtual void IncrementNumWins(const uint32_t playerId, const uint32_t gameId) = 0;
|
||||||
|
virtual void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__ILEADERBOARD__H__
|
#endif //!__ILEADERBOARD__H__
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
enum ePropertySortType : int32_t;
|
||||||
|
|
||||||
class IProperty {
|
class IProperty {
|
||||||
public:
|
public:
|
||||||
struct Info {
|
struct Info {
|
||||||
@@ -18,11 +20,33 @@ public:
|
|||||||
uint32_t lastUpdatedTime{};
|
uint32_t lastUpdatedTime{};
|
||||||
uint32_t claimedTime{};
|
uint32_t claimedTime{};
|
||||||
uint32_t reputation{};
|
uint32_t reputation{};
|
||||||
|
float performanceCost{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PropertyLookup {
|
||||||
|
uint32_t mapId{};
|
||||||
|
std::string searchString;
|
||||||
|
ePropertySortType sortChoice{};
|
||||||
|
uint32_t playerId{};
|
||||||
|
uint32_t numResults{};
|
||||||
|
uint32_t startIndex{};
|
||||||
|
uint32_t playerSort{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PropertyEntranceResult {
|
||||||
|
int32_t totalEntriesMatchingQuery{};
|
||||||
|
// The entries that match the query. This should only contain up to 12 entries.
|
||||||
|
std::vector<IProperty::Info> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get the property info for the given property id.
|
// Get the property info for the given property id.
|
||||||
virtual std::optional<IProperty::Info> GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) = 0;
|
virtual std::optional<IProperty::Info> GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) = 0;
|
||||||
|
|
||||||
|
// Get the properties for the given property lookup params.
|
||||||
|
// This is expected to return a result set of up to 12 properties
|
||||||
|
// so as not to transfer too much data at once.
|
||||||
|
virtual std::optional<IProperty::PropertyEntranceResult> GetProperties(const PropertyLookup& params) = 0;
|
||||||
|
|
||||||
// Update the property moderation info for the given property id.
|
// Update the property moderation info for the given property id.
|
||||||
virtual void UpdatePropertyModerationInfo(const IProperty::Info& info) = 0;
|
virtual void UpdatePropertyModerationInfo(const IProperty::Info& info) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef __IPROPERTIESCONTENTS__H__
|
#ifndef __IPROPERTIESCONTENTS__H__
|
||||||
#define __IPROPERTIESCONTENTS__H__
|
#define __IPROPERTIESCONTENTS__H__
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ public:
|
|||||||
LWOOBJID id{};
|
LWOOBJID id{};
|
||||||
LOT lot{};
|
LOT lot{};
|
||||||
uint32_t ugcId{};
|
uint32_t ugcId{};
|
||||||
|
std::array<int32_t, 5> behaviors{};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inserts a new UGC model into the database.
|
// Inserts a new UGC model into the database.
|
||||||
@@ -32,7 +34,7 @@ public:
|
|||||||
virtual void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) = 0;
|
virtual void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) = 0;
|
||||||
|
|
||||||
// Update the model position and rotation for the given property id.
|
// Update the model position and rotation for the given property id.
|
||||||
virtual void UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) = 0;
|
virtual void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) = 0;
|
||||||
|
|
||||||
// Remove the model for the given property id.
|
// Remove the model for the given property id.
|
||||||
virtual void RemoveModel(const LWOOBJID& modelId) = 0;
|
virtual void RemoveModel(const LWOOBJID& modelId) = 0;
|
||||||
|
|||||||
14
dDatabase/GameDatabase/ITables/IUgcModularBuild.h
Normal file
14
dDatabase/GameDatabase/ITables/IUgcModularBuild.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef IUGCMODULARBUILD_H
|
||||||
|
#define IUGCMODULARBUILD_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class IUgcModularBuild {
|
||||||
|
public:
|
||||||
|
virtual void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) = 0;
|
||||||
|
virtual void DeleteUgcBuild(const LWOOBJID bigId) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!IUGCMODULARBUILD_H
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
#include "dPlatforms.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::string databaseName;
|
std::string databaseName;
|
||||||
@@ -39,14 +40,13 @@ void MySQLDatabase::Connect() {
|
|||||||
properties["autoReconnect"] = "true";
|
properties["autoReconnect"] = "true";
|
||||||
|
|
||||||
databaseName = Game::config->GetValue("mysql_database").c_str();
|
databaseName = Game::config->GetValue("mysql_database").c_str();
|
||||||
|
|
||||||
// `connect(const Properties& props)` segfaults in windows debug, but
|
// `connect(const Properties& props)` segfaults in windows debug, but
|
||||||
// `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly
|
// `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly
|
||||||
if (properties.find("localSocket") != properties.end() || properties.find("pipe") != properties.end()) {
|
#if defined(DARKFLAME_PLATFORM_WIN32) && defined(_DEBUG)
|
||||||
con = driver->connect(properties);
|
|
||||||
} else {
|
|
||||||
con = driver->connect(properties["hostName"].c_str(), properties["user"].c_str(), properties["password"].c_str());
|
con = driver->connect(properties["hostName"].c_str(), properties["user"].c_str(), properties["password"].c_str());
|
||||||
}
|
#else
|
||||||
|
con = driver->connect(properties);
|
||||||
|
#endif
|
||||||
con->setSchema(databaseName.c_str());
|
con->setSchema(databaseName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "GameDatabase.h"
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
typedef std::unique_ptr<sql::PreparedStatement>& UniquePreppedStmtRef;
|
typedef std::unique_ptr<sql::PreparedStatement>& UniquePreppedStmtRef;
|
||||||
|
typedef std::unique_ptr<sql::ResultSet> UniqueResultSet;
|
||||||
|
|
||||||
// Purposefully no definition for this to provide linker errors in the case someone tries to
|
// Purposefully no definition for this to provide linker errors in the case someone tries to
|
||||||
// bind a parameter to a type that isn't defined.
|
// bind a parameter to a type that isn't defined.
|
||||||
@@ -74,7 +75,7 @@ public:
|
|||||||
std::vector<IPropertyContents::Model> GetPropertyModels(const LWOOBJID& propertyId) override;
|
std::vector<IPropertyContents::Model> GetPropertyModels(const LWOOBJID& propertyId) override;
|
||||||
void RemoveUnreferencedUgcModels() override;
|
void RemoveUnreferencedUgcModels() override;
|
||||||
void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) override;
|
void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) override;
|
||||||
void UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) override;
|
void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) override;
|
||||||
void RemoveModel(const LWOOBJID& modelId) override;
|
void RemoveModel(const LWOOBJID& modelId) override;
|
||||||
void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override;
|
void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override;
|
||||||
void InsertNewBugReport(const IBugReports::Info& info) override;
|
void InsertNewBugReport(const IBugReports::Info& info) override;
|
||||||
@@ -108,6 +109,22 @@ public:
|
|||||||
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
|
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
|
||||||
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
|
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
|
||||||
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
|
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
|
||||||
|
void AddBehavior(const IBehaviors::Info& info) override;
|
||||||
|
std::string GetBehavior(const int32_t behaviorId) override;
|
||||||
|
void RemoveBehavior(const int32_t characterId) override;
|
||||||
|
void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) override;
|
||||||
|
std::optional<IProperty::PropertyEntranceResult> GetProperties(const IProperty::PropertyLookup& params) override;
|
||||||
|
std::vector<ILeaderboard::Entry> GetDescendingLeaderboard(const uint32_t activityId) override;
|
||||||
|
std::vector<ILeaderboard::Entry> GetAscendingLeaderboard(const uint32_t activityId) override;
|
||||||
|
std::vector<ILeaderboard::Entry> GetNsLeaderboard(const uint32_t activityId) override;
|
||||||
|
std::vector<ILeaderboard::Entry> GetAgsLeaderboard(const uint32_t activityId) override;
|
||||||
|
void SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override;
|
||||||
|
void UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override;
|
||||||
|
std::optional<ILeaderboard::Score> GetPlayerScore(const uint32_t playerId, const uint32_t gameId) override;
|
||||||
|
void IncrementNumWins(const uint32_t playerId, const uint32_t gameId) override;
|
||||||
|
void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) override;
|
||||||
|
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override;
|
||||||
|
void DeleteUgcBuild(const LWOOBJID bigId) override;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Generic query functions that can be used for any query.
|
// Generic query functions that can be used for any query.
|
||||||
|
|||||||
@@ -35,3 +35,7 @@ void MySQLDatabase::UpdateAccountPassword(const uint32_t accountId, const std::s
|
|||||||
void MySQLDatabase::InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) {
|
void MySQLDatabase::InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) {
|
||||||
ExecuteInsert("INSERT INTO accounts (name, password, gm_level) VALUES (?, ?, ?);", username, bcryptpassword, static_cast<int32_t>(eGameMasterLevel::OPERATOR));
|
ExecuteInsert("INSERT INTO accounts (name, password, gm_level) VALUES (?, ?, ?);", username, bcryptpassword, static_cast<int32_t>(eGameMasterLevel::OPERATOR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) {
|
||||||
|
ExecuteUpdate("UPDATE accounts SET gm_level = ? WHERE id = ?;", static_cast<int32_t>(gmLevel), accountId);
|
||||||
|
}
|
||||||
|
|||||||
19
dDatabase/GameDatabase/MySQL/Tables/Behaviors.cpp
Normal file
19
dDatabase/GameDatabase/MySQL/Tables/Behaviors.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "IBehaviors.h"
|
||||||
|
|
||||||
|
#include "MySQLDatabase.h"
|
||||||
|
|
||||||
|
void MySQLDatabase::AddBehavior(const IBehaviors::Info& info) {
|
||||||
|
ExecuteInsert(
|
||||||
|
"INSERT INTO behaviors (behavior_info, character_id, behavior_id) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE behavior_info = ?",
|
||||||
|
info.behaviorInfo, info.characterId, info.behaviorId, info.behaviorInfo
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::RemoveBehavior(const int32_t behaviorId) {
|
||||||
|
ExecuteDelete("DELETE FROM behaviors WHERE behavior_id = ?", behaviorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MySQLDatabase::GetBehavior(const int32_t behaviorId) {
|
||||||
|
auto result = ExecuteSelect("SELECT behavior_info FROM behaviors WHERE behavior_id = ?", behaviorId);
|
||||||
|
return result->next() ? result->getString("behavior_info").c_str() : "";
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
|
|||||||
"Accounts.cpp"
|
"Accounts.cpp"
|
||||||
"AccountsRewardCodes.cpp"
|
"AccountsRewardCodes.cpp"
|
||||||
"ActivityLog.cpp"
|
"ActivityLog.cpp"
|
||||||
|
"Behaviors.cpp"
|
||||||
"BugReports.cpp"
|
"BugReports.cpp"
|
||||||
"CharInfo.cpp"
|
"CharInfo.cpp"
|
||||||
"CharXml.cpp"
|
"CharXml.cpp"
|
||||||
@@ -19,6 +20,7 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
|
|||||||
"PropertyContents.cpp"
|
"PropertyContents.cpp"
|
||||||
"Servers.cpp"
|
"Servers.cpp"
|
||||||
"Ugc.cpp"
|
"Ugc.cpp"
|
||||||
|
"UgcModularBuild.cpp"
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#include "MySQLDatabase.h"
|
#include "MySQLDatabase.h"
|
||||||
|
|
||||||
|
#include "Game.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
#include "dConfig.h"
|
||||||
|
|
||||||
std::optional<uint32_t> MySQLDatabase::GetDonationTotal(const uint32_t activityId) {
|
std::optional<uint32_t> MySQLDatabase::GetDonationTotal(const uint32_t activityId) {
|
||||||
auto donation_total = ExecuteSelect("SELECT SUM(primaryScore) as donation_total FROM leaderboard WHERE game_id = ?;", activityId);
|
auto donation_total = ExecuteSelect("SELECT SUM(primaryScore) as donation_total FROM leaderboard WHERE game_id = ?;", activityId);
|
||||||
|
|
||||||
@@ -9,3 +13,79 @@ std::optional<uint32_t> MySQLDatabase::GetDonationTotal(const uint32_t activityI
|
|||||||
|
|
||||||
return donation_total->getUInt("donation_total");
|
return donation_total->getUInt("donation_total");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<ILeaderboard::Entry> ProcessQuery(UniqueResultSet& rows) {
|
||||||
|
std::vector<ILeaderboard::Entry> entries;
|
||||||
|
entries.reserve(rows->rowsCount());
|
||||||
|
|
||||||
|
while (rows->next()) {
|
||||||
|
auto& entry = entries.emplace_back();
|
||||||
|
|
||||||
|
entry.charId = rows->getUInt("character_id");
|
||||||
|
entry.lastPlayedTimestamp = rows->getUInt("lp_unix");
|
||||||
|
entry.primaryScore = rows->getFloat("primaryScore");
|
||||||
|
entry.secondaryScore = rows->getFloat("secondaryScore");
|
||||||
|
entry.tertiaryScore = rows->getFloat("tertiaryScore");
|
||||||
|
entry.numWins = rows->getUInt("numWins");
|
||||||
|
entry.numTimesPlayed = rows->getUInt("timesPlayed");
|
||||||
|
entry.name = rows->getString("char_name");
|
||||||
|
// entry.ranking is never set because its calculated in leaderboard in code.
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ILeaderboard::Entry> MySQLDatabase::GetDescendingLeaderboard(const uint32_t activityId) {
|
||||||
|
auto leaderboard = ExecuteSelect("SELECT *, UNIX_TIMESTAMP(last_played) as lp_unix, ci.name as char_name FROM leaderboard lb JOIN charinfo ci on ci.id = lb.character_id where game_id = ? ORDER BY primaryscore DESC, secondaryscore DESC, tertiaryScore DESC, last_played ASC;", activityId);
|
||||||
|
return ProcessQuery(leaderboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ILeaderboard::Entry> MySQLDatabase::GetAscendingLeaderboard(const uint32_t activityId) {
|
||||||
|
auto leaderboard = ExecuteSelect("SELECT *, UNIX_TIMESTAMP(last_played) as lp_unix, ci.name as char_name FROM leaderboard lb JOIN charinfo ci on ci.id = lb.character_id where game_id = ? ORDER BY primaryscore ASC, secondaryscore ASC, tertiaryScore ASC, last_played ASC;", activityId);
|
||||||
|
return ProcessQuery(leaderboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ILeaderboard::Entry> MySQLDatabase::GetAgsLeaderboard(const uint32_t activityId) {
|
||||||
|
auto query = Game::config->GetValue("classic_survival_scoring") != "1" ?
|
||||||
|
"SELECT *, UNIX_TIMESTAMP(last_played) as lp_unix, ci.name as char_name FROM leaderboard lb JOIN charinfo ci on ci.id = lb.character_id where game_id = ? ORDER BY primaryscore DESC, secondaryscore DESC, tertiaryScore DESC, last_played ASC;" :
|
||||||
|
"SELECT *, UNIX_TIMESTAMP(last_played) as lp_unix, ci.name as char_name FROM leaderboard lb JOIN charinfo ci on ci.id = lb.character_id where game_id = ? ORDER BY secondaryscore DESC, primaryscore DESC, tertiaryScore DESC, last_played ASC;";
|
||||||
|
auto leaderboard = ExecuteSelect(query, activityId);
|
||||||
|
return ProcessQuery(leaderboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ILeaderboard::Entry> MySQLDatabase::GetNsLeaderboard(const uint32_t activityId) {
|
||||||
|
auto leaderboard = ExecuteSelect("SELECT *, UNIX_TIMESTAMP(last_played) as lp_unix, ci.name as char_name FROM leaderboard lb JOIN charinfo ci on ci.id = lb.character_id where game_id = ? ORDER BY primaryscore DESC, secondaryscore ASC, tertiaryScore DESC, last_played ASC;", activityId);
|
||||||
|
return ProcessQuery(leaderboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) {
|
||||||
|
ExecuteInsert("INSERT leaderboard SET primaryScore = ?, secondaryScore = ?, tertiaryScore = ?, character_id = ?, game_id = ?;",
|
||||||
|
score.primaryScore, score.secondaryScore, score.tertiaryScore, playerId, gameId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) {
|
||||||
|
ExecuteInsert("UPDATE leaderboard SET primaryScore = ?, secondaryScore = ?, tertiaryScore = ?, timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;",
|
||||||
|
score.primaryScore, score.secondaryScore, score.tertiaryScore, playerId, gameId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) {
|
||||||
|
ExecuteUpdate("UPDATE leaderboard SET timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;", playerId, gameId);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ILeaderboard::Score> MySQLDatabase::GetPlayerScore(const uint32_t playerId, const uint32_t gameId) {
|
||||||
|
std::optional<ILeaderboard::Score> toReturn = std::nullopt;
|
||||||
|
auto res = ExecuteSelect("SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;", playerId, gameId);
|
||||||
|
if (res->next()) {
|
||||||
|
toReturn = ILeaderboard::Score{
|
||||||
|
.primaryScore = res->getFloat("primaryScore"),
|
||||||
|
.secondaryScore = res->getFloat("secondaryScore"),
|
||||||
|
.tertiaryScore = res->getFloat("tertiaryScore")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::IncrementNumWins(const uint32_t playerId, const uint32_t gameId) {
|
||||||
|
ExecuteUpdate("UPDATE leaderboard SET numWins = numWins + 1 WHERE character_id = ? AND game_id = ?;", playerId, gameId);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,140 @@
|
|||||||
#include "MySQLDatabase.h"
|
#include "MySQLDatabase.h"
|
||||||
|
#include "ePropertySortType.h"
|
||||||
|
|
||||||
|
std::optional<IProperty::PropertyEntranceResult> MySQLDatabase::GetProperties(const IProperty::PropertyLookup& params) {
|
||||||
|
std::optional<IProperty::PropertyEntranceResult> result;
|
||||||
|
std::string query;
|
||||||
|
std::unique_ptr<sql::ResultSet> properties;
|
||||||
|
|
||||||
|
if (params.sortChoice == SORT_TYPE_FEATURED || params.sortChoice == SORT_TYPE_FRIENDS) {
|
||||||
|
query = R"QUERY(
|
||||||
|
FROM properties as p
|
||||||
|
JOIN charinfo as ci
|
||||||
|
ON ci.prop_clone_id = p.clone_id
|
||||||
|
where p.zone_id = ?
|
||||||
|
AND (
|
||||||
|
p.description LIKE ?
|
||||||
|
OR p.name LIKE ?
|
||||||
|
OR ci.name LIKE ?
|
||||||
|
)
|
||||||
|
AND p.privacy_option >= ?
|
||||||
|
AND p.owner_id IN (
|
||||||
|
SELECT fr.requested_player AS player FROM (
|
||||||
|
SELECT CASE
|
||||||
|
WHEN player_id = ? THEN friend_id
|
||||||
|
WHEN friend_id = ? THEN player_id
|
||||||
|
END AS requested_player FROM friends
|
||||||
|
) AS fr
|
||||||
|
JOIN charinfo AS ci ON ci.id = fr.requested_player
|
||||||
|
WHERE fr.requested_player IS NOT NULL AND fr.requested_player != ?
|
||||||
|
) ORDER BY ci.name ASC
|
||||||
|
)QUERY";
|
||||||
|
const auto completeQuery = "SELECT p.* " + query + " LIMIT ? OFFSET ?;";
|
||||||
|
properties = ExecuteSelect(
|
||||||
|
completeQuery,
|
||||||
|
params.mapId,
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
params.playerSort,
|
||||||
|
params.playerId,
|
||||||
|
params.playerId,
|
||||||
|
params.playerId,
|
||||||
|
params.numResults,
|
||||||
|
params.startIndex
|
||||||
|
);
|
||||||
|
const auto countQuery = "SELECT COUNT(*) as count" + query + ";";
|
||||||
|
auto count = ExecuteSelect(
|
||||||
|
countQuery,
|
||||||
|
params.mapId,
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
params.playerSort,
|
||||||
|
params.playerId,
|
||||||
|
params.playerId,
|
||||||
|
params.playerId
|
||||||
|
);
|
||||||
|
if (count->next()) {
|
||||||
|
result->totalEntriesMatchingQuery = count->getUInt("count");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (params.sortChoice == SORT_TYPE_REPUTATION) {
|
||||||
|
query = R"QUERY(
|
||||||
|
FROM properties as p
|
||||||
|
JOIN charinfo as ci
|
||||||
|
ON ci.prop_clone_id = p.clone_id
|
||||||
|
where p.zone_id = ?
|
||||||
|
AND (
|
||||||
|
p.description LIKE ?
|
||||||
|
OR p.name LIKE ?
|
||||||
|
OR ci.name LIKE ?
|
||||||
|
)
|
||||||
|
AND p.privacy_option >= ?
|
||||||
|
ORDER BY p.reputation DESC, p.last_updated DESC
|
||||||
|
)QUERY";
|
||||||
|
} else {
|
||||||
|
query = R"QUERY(
|
||||||
|
FROM properties as p
|
||||||
|
JOIN charinfo as ci
|
||||||
|
ON ci.prop_clone_id = p.clone_id
|
||||||
|
where p.zone_id = ?
|
||||||
|
AND (
|
||||||
|
p.description LIKE ?
|
||||||
|
OR p.name LIKE ?
|
||||||
|
OR ci.name LIKE ?
|
||||||
|
)
|
||||||
|
AND p.privacy_option >= ?
|
||||||
|
ORDER BY p.last_updated DESC
|
||||||
|
)QUERY";
|
||||||
|
}
|
||||||
|
const auto completeQuery = "SELECT p.* " + query + " LIMIT ? OFFSET ?;";
|
||||||
|
properties = ExecuteSelect(
|
||||||
|
completeQuery,
|
||||||
|
params.mapId,
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
params.playerSort,
|
||||||
|
params.numResults,
|
||||||
|
params.startIndex
|
||||||
|
);
|
||||||
|
const auto countQuery = "SELECT COUNT(*) as count" + query + ";";
|
||||||
|
auto count = ExecuteSelect(
|
||||||
|
countQuery,
|
||||||
|
params.mapId,
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
"%" + params.searchString + "%",
|
||||||
|
params.playerSort
|
||||||
|
);
|
||||||
|
if (count->next()) {
|
||||||
|
result->totalEntriesMatchingQuery = count->getUInt("count");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (properties->next()) {
|
||||||
|
auto& entry = result->entries.emplace_back();
|
||||||
|
entry.id = properties->getUInt64("id");
|
||||||
|
entry.ownerId = properties->getUInt64("owner_id");
|
||||||
|
entry.cloneId = properties->getUInt64("clone_id");
|
||||||
|
entry.name = properties->getString("name").c_str();
|
||||||
|
entry.description = properties->getString("description").c_str();
|
||||||
|
entry.privacyOption = properties->getInt("privacy_option");
|
||||||
|
entry.rejectionReason = properties->getString("rejection_reason").c_str();
|
||||||
|
entry.lastUpdatedTime = properties->getUInt("last_updated");
|
||||||
|
entry.claimedTime = properties->getUInt("time_claimed");
|
||||||
|
entry.reputation = properties->getUInt("reputation");
|
||||||
|
entry.modApproved = properties->getUInt("mod_approved");
|
||||||
|
entry.performanceCost = properties->getFloat("performance_cost");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<IProperty::Info> MySQLDatabase::GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) {
|
std::optional<IProperty::Info> MySQLDatabase::GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) {
|
||||||
auto propertyEntry = ExecuteSelect(
|
auto propertyEntry = ExecuteSelect(
|
||||||
"SELECT id, owner_id, clone_id, name, description, privacy_option, rejection_reason, last_updated, time_claimed, reputation, mod_approved "
|
"SELECT id, owner_id, clone_id, name, description, privacy_option, rejection_reason, last_updated, time_claimed, reputation, mod_approved, performance_cost "
|
||||||
"FROM properties WHERE zone_id = ? AND clone_id = ?;", mapId, cloneId);
|
"FROM properties WHERE zone_id = ? AND clone_id = ?;", mapId, cloneId);
|
||||||
|
|
||||||
if (!propertyEntry->next()) {
|
if (!propertyEntry->next()) {
|
||||||
@@ -21,6 +153,7 @@ std::optional<IProperty::Info> MySQLDatabase::GetPropertyInfo(const LWOMAPID map
|
|||||||
toReturn.claimedTime = propertyEntry->getUInt("time_claimed");
|
toReturn.claimedTime = propertyEntry->getUInt("time_claimed");
|
||||||
toReturn.reputation = propertyEntry->getUInt("reputation");
|
toReturn.reputation = propertyEntry->getUInt("reputation");
|
||||||
toReturn.modApproved = propertyEntry->getUInt("mod_approved");
|
toReturn.modApproved = propertyEntry->getUInt("mod_approved");
|
||||||
|
toReturn.performanceCost = propertyEntry->getFloat("performance_cost");
|
||||||
|
|
||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
#include "MySQLDatabase.h"
|
#include "MySQLDatabase.h"
|
||||||
|
|
||||||
std::vector<IPropertyContents::Model> MySQLDatabase::GetPropertyModels(const LWOOBJID& propertyId) {
|
std::vector<IPropertyContents::Model> MySQLDatabase::GetPropertyModels(const LWOOBJID& propertyId) {
|
||||||
auto result = ExecuteSelect("SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id FROM properties_contents WHERE property_id = ?;", propertyId);
|
auto result = ExecuteSelect(
|
||||||
|
"SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id, "
|
||||||
|
"behavior_1, behavior_2, behavior_3, behavior_4, behavior_5 "
|
||||||
|
"FROM properties_contents WHERE property_id = ?;", propertyId);
|
||||||
|
|
||||||
std::vector<IPropertyContents::Model> toReturn;
|
std::vector<IPropertyContents::Model> toReturn;
|
||||||
toReturn.reserve(result->rowsCount());
|
toReturn.reserve(result->rowsCount());
|
||||||
@@ -17,6 +20,12 @@ std::vector<IPropertyContents::Model> MySQLDatabase::GetPropertyModels(const LWO
|
|||||||
model.rotation.y = result->getFloat("ry");
|
model.rotation.y = result->getFloat("ry");
|
||||||
model.rotation.z = result->getFloat("rz");
|
model.rotation.z = result->getFloat("rz");
|
||||||
model.ugcId = result->getUInt64("ugc_id");
|
model.ugcId = result->getUInt64("ugc_id");
|
||||||
|
model.behaviors[0] = result->getInt("behavior_1");
|
||||||
|
model.behaviors[1] = result->getInt("behavior_2");
|
||||||
|
model.behaviors[2] = result->getInt("behavior_3");
|
||||||
|
model.behaviors[3] = result->getInt("behavior_4");
|
||||||
|
model.behaviors[4] = result->getInt("behavior_5");
|
||||||
|
|
||||||
toReturn.push_back(std::move(model));
|
toReturn.push_back(std::move(model));
|
||||||
}
|
}
|
||||||
return toReturn;
|
return toReturn;
|
||||||
@@ -32,21 +41,23 @@ void MySQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const IPr
|
|||||||
model.id, propertyId, model.ugcId == 0 ? std::nullopt : std::optional(model.ugcId), static_cast<uint32_t>(model.lot),
|
model.id, propertyId, model.ugcId == 0 ? std::nullopt : std::optional(model.ugcId), static_cast<uint32_t>(model.lot),
|
||||||
model.position.x, model.position.y, model.position.z, model.rotation.x, model.rotation.y, model.rotation.z, model.rotation.w,
|
model.position.x, model.position.y, model.position.z, model.rotation.x, model.rotation.y, model.rotation.z, model.rotation.w,
|
||||||
name, "", // Model description. TODO implement this.
|
name, "", // Model description. TODO implement this.
|
||||||
0, // behavior 1. TODO implement this.
|
model.behaviors[0], // behavior 1
|
||||||
0, // behavior 2. TODO implement this.
|
model.behaviors[1], // behavior 2
|
||||||
0, // behavior 3. TODO implement this.
|
model.behaviors[2], // behavior 3
|
||||||
0, // behavior 4. TODO implement this.
|
model.behaviors[3], // behavior 4
|
||||||
0 // behavior 5. TODO implement this.
|
model.behaviors[4] // behavior 5
|
||||||
);
|
);
|
||||||
} catch (sql::SQLException& e) {
|
} catch (sql::SQLException& e) {
|
||||||
LOG("Error inserting new property model: %s", e.what());
|
LOG("Error inserting new property model: %s", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySQLDatabase::UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) {
|
void MySQLDatabase::UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) {
|
||||||
ExecuteUpdate(
|
ExecuteUpdate(
|
||||||
"UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ? WHERE id = ?;",
|
"UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ?, "
|
||||||
position.x, position.y, position.z, rotation.x, rotation.y, rotation.z, rotation.w, propertyId);
|
"behavior_1 = ?, behavior_2 = ?, behavior_3 = ?, behavior_4 = ?, behavior_5 = ? WHERE id = ?;",
|
||||||
|
position.x, position.y, position.z, rotation.x, rotation.y, rotation.z, rotation.w,
|
||||||
|
behaviors[0].first, behaviors[1].first, behaviors[2].first, behaviors[3].first, behaviors[4].first, propertyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MySQLDatabase::RemoveModel(const LWOOBJID& modelId) {
|
void MySQLDatabase::RemoveModel(const LWOOBJID& modelId) {
|
||||||
|
|||||||
9
dDatabase/GameDatabase/MySQL/Tables/UgcModularBuild.cpp
Normal file
9
dDatabase/GameDatabase/MySQL/Tables/UgcModularBuild.cpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include "MySQLDatabase.h"
|
||||||
|
|
||||||
|
void MySQLDatabase::InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) {
|
||||||
|
ExecuteInsert("INSERT INTO ugc_modular_build (ugc_id, ldf_config, character_id) VALUES (?,?,?)", bigId, modules, characterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::DeleteUgcBuild(const LWOOBJID bigId) {
|
||||||
|
ExecuteDelete("DELETE FROM ugc_modular_build WHERE ugc_id = ?;", bigId);
|
||||||
|
}
|
||||||
4
dDatabase/GameDatabase/TestSQL/CMakeLists.txt
Normal file
4
dDatabase/GameDatabase/TestSQL/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
SET(DDATABSE_DATABSES_TEST_SQL_SOURCES
|
||||||
|
"TestSQLDatabase.cpp"
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
306
dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp
Normal file
306
dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
#include "TestSQLDatabase.h"
|
||||||
|
|
||||||
|
void TestSQLDatabase::Connect() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::Destroy(std::string source) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sql::PreparedStatement* TestSQLDatabase::CreatePreppedStmt(const std::string& query) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::Commit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestSQLDatabase::GetAutoCommit() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::SetAutoCommit(bool value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::ExecuteCustomQuery(const std::string_view query) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IServers::MasterInfo> TestSQLDatabase::GetMasterInfo() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> TestSQLDatabase::GetApprovedCharacterNames() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<FriendData> TestSQLDatabase::GetFriendsList(uint32_t charID) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IFriends::BestFriendStatus> TestSQLDatabase::GetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateActivityLog(const uint32_t characterId, const eActivityType activityType, const LWOMAPID mapId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::DeleteUgcModelData(const LWOOBJID& modelId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IUgc::Model> TestSQLDatabase::GetAllUgcModels() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::CreateMigrationHistoryTable() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestSQLDatabase::IsMigrationRun(const std::string_view str) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertMigration(const std::string_view str) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ICharInfo::Info> TestSQLDatabase::GetCharacterInfo(const uint32_t charId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ICharInfo::Info> TestSQLDatabase::GetCharacterInfo(const std::string_view charId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TestSQLDatabase::GetCharacterXml(const uint32_t accountId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateCharacterXml(const uint32_t characterId, const std::string_view lxfml) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IAccounts::Info> TestSQLDatabase::GetAccountInfo(const std::string_view username) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertNewCharacter(const ICharInfo::Info info) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> TestSQLDatabase::GetAccountCharacterIds(uint32_t accountId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::DeleteCharacter(const uint32_t characterId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::SetCharacterName(const uint32_t characterId, const std::string_view name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::SetPendingCharacterName(const uint32_t characterId, const std::string_view name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::SetPetNameModerationStatus(const LWOOBJID& petId, const IPetNames::Info& info) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IPetNames::Info> TestSQLDatabase::GetPetNameInfo(const LWOOBJID& petId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IProperty::Info> TestSQLDatabase::GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdatePropertyModerationInfo(const IProperty::Info& info) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdatePropertyDetails(const IProperty::Info& info) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertNewProperty(const IProperty::Info& info, const uint32_t templateId, const LWOZONEID& zoneId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IPropertyContents::Model> TestSQLDatabase::GetPropertyModels(const LWOOBJID& propertyId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::RemoveUnreferencedUgcModels() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::RemoveModel(const LWOOBJID& modelId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertNewBugReport(const IBugReports::Info& info) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertCheatDetection(const IPlayerCheatDetections::Info& info) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertNewMail(const IMail::MailInfo& mail) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertNewUgcModel(std::istringstream& sd0Data, const uint32_t blueprintId, const uint32_t accountId, const uint32_t characterId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IMail::MailInfo> TestSQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<IMail::MailInfo> TestSQLDatabase::GetMail(const uint64_t mailId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TestSQLDatabase::GetUnreadMailCount(const uint32_t characterId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::MarkMailRead(const uint64_t mailId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::DeleteMail(const uint64_t mailId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::ClaimMailItem(const uint64_t mailId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateAccountUnmuteTime(const uint32_t accountId, const uint64_t timeToUnmute) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateAccountBan(const uint32_t accountId, const bool banned) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<uint32_t> TestSQLDatabase::GetCurrentPersistentId() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertDefaultPersistentId() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdatePersistentId(const uint32_t id) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<uint32_t> TestSQLDatabase::GetDonationTotal(const uint32_t activityId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<bool> TestSQLDatabase::IsPlaykeyActive(const int32_t playkeyId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IUgc::Model> TestSQLDatabase::GetUgcModels(const LWOOBJID& propertyId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<IIgnoreList::Info> TestSQLDatabase::GetIgnoreList(const uint32_t playerId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> TestSQLDatabase::GetRewardCodesByAccountID(const uint32_t account_id) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::AddBehavior(const IBehaviors::Info& info) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TestSQLDatabase::GetBehavior(const int32_t behaviorId) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::RemoveBehavior(const int32_t behaviorId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestSQLDatabase::UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
107
dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h
Normal file
107
dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#ifndef TESTSQLDATABASE_H
|
||||||
|
#define TESTSQLDATABASE_H
|
||||||
|
|
||||||
|
#include "GameDatabase.h"
|
||||||
|
|
||||||
|
class TestSQLDatabase : public GameDatabase {
|
||||||
|
void Connect() override;
|
||||||
|
void Destroy(std::string source = "") override;
|
||||||
|
|
||||||
|
sql::PreparedStatement* CreatePreppedStmt(const std::string& query) override;
|
||||||
|
void Commit() override;
|
||||||
|
bool GetAutoCommit() override;
|
||||||
|
void SetAutoCommit(bool value) override;
|
||||||
|
void ExecuteCustomQuery(const std::string_view query) override;
|
||||||
|
|
||||||
|
// Overloaded queries
|
||||||
|
std::optional<IServers::MasterInfo> GetMasterInfo() override;
|
||||||
|
|
||||||
|
std::vector<std::string> GetApprovedCharacterNames() override;
|
||||||
|
|
||||||
|
std::vector<FriendData> GetFriendsList(uint32_t charID) override;
|
||||||
|
|
||||||
|
std::optional<IFriends::BestFriendStatus> GetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId) override;
|
||||||
|
void SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) override;
|
||||||
|
void AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) override;
|
||||||
|
void RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) override;
|
||||||
|
void UpdateActivityLog(const uint32_t characterId, const eActivityType activityType, const LWOMAPID mapId) override;
|
||||||
|
void DeleteUgcModelData(const LWOOBJID& modelId) override;
|
||||||
|
void UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) override;
|
||||||
|
std::vector<IUgc::Model> GetAllUgcModels() override;
|
||||||
|
void CreateMigrationHistoryTable() override;
|
||||||
|
bool IsMigrationRun(const std::string_view str) override;
|
||||||
|
void InsertMigration(const std::string_view str) override;
|
||||||
|
std::optional<ICharInfo::Info> GetCharacterInfo(const uint32_t charId) override;
|
||||||
|
std::optional<ICharInfo::Info> GetCharacterInfo(const std::string_view charId) override;
|
||||||
|
std::string GetCharacterXml(const uint32_t accountId) override;
|
||||||
|
void UpdateCharacterXml(const uint32_t characterId, const std::string_view lxfml) override;
|
||||||
|
std::optional<IAccounts::Info> GetAccountInfo(const std::string_view username) override;
|
||||||
|
void InsertNewCharacter(const ICharInfo::Info info) override;
|
||||||
|
void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) override;
|
||||||
|
std::vector<uint32_t> GetAccountCharacterIds(uint32_t accountId) override;
|
||||||
|
void DeleteCharacter(const uint32_t characterId) override;
|
||||||
|
void SetCharacterName(const uint32_t characterId, const std::string_view name) override;
|
||||||
|
void SetPendingCharacterName(const uint32_t characterId, const std::string_view name) override;
|
||||||
|
void UpdateLastLoggedInCharacter(const uint32_t characterId) override;
|
||||||
|
void SetPetNameModerationStatus(const LWOOBJID& petId, const IPetNames::Info& info) override;
|
||||||
|
std::optional<IPetNames::Info> GetPetNameInfo(const LWOOBJID& petId) override;
|
||||||
|
std::optional<IProperty::Info> GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) override;
|
||||||
|
void UpdatePropertyModerationInfo(const IProperty::Info& info) override;
|
||||||
|
void UpdatePropertyDetails(const IProperty::Info& info) override;
|
||||||
|
void InsertNewProperty(const IProperty::Info& info, const uint32_t templateId, const LWOZONEID& zoneId) override;
|
||||||
|
std::vector<IPropertyContents::Model> GetPropertyModels(const LWOOBJID& propertyId) override;
|
||||||
|
void RemoveUnreferencedUgcModels() override;
|
||||||
|
void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) override;
|
||||||
|
void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array<std::pair<int32_t, std::string>, 5>& behaviors) override;
|
||||||
|
void RemoveModel(const LWOOBJID& modelId) override;
|
||||||
|
void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override;
|
||||||
|
void InsertNewBugReport(const IBugReports::Info& info) override;
|
||||||
|
void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override;
|
||||||
|
void InsertNewMail(const IMail::MailInfo& mail) override;
|
||||||
|
void InsertNewUgcModel(
|
||||||
|
std::istringstream& sd0Data,
|
||||||
|
const uint32_t blueprintId,
|
||||||
|
const uint32_t accountId,
|
||||||
|
const uint32_t characterId) override;
|
||||||
|
std::vector<IMail::MailInfo> GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override;
|
||||||
|
std::optional<IMail::MailInfo> GetMail(const uint64_t mailId) override;
|
||||||
|
uint32_t GetUnreadMailCount(const uint32_t characterId) override;
|
||||||
|
void MarkMailRead(const uint64_t mailId) override;
|
||||||
|
void DeleteMail(const uint64_t mailId) override;
|
||||||
|
void ClaimMailItem(const uint64_t mailId) override;
|
||||||
|
void InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) override;
|
||||||
|
void UpdateAccountUnmuteTime(const uint32_t accountId, const uint64_t timeToUnmute) override;
|
||||||
|
void UpdateAccountBan(const uint32_t accountId, const bool banned) override;
|
||||||
|
void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override;
|
||||||
|
void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override;
|
||||||
|
void SetMasterIp(const std::string_view ip, const uint32_t port) override;
|
||||||
|
std::optional<uint32_t> GetCurrentPersistentId() override;
|
||||||
|
void InsertDefaultPersistentId() override;
|
||||||
|
void UpdatePersistentId(const uint32_t id) override;
|
||||||
|
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
|
||||||
|
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
|
||||||
|
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
|
||||||
|
void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
|
||||||
|
void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
|
||||||
|
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
|
||||||
|
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
|
||||||
|
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
|
||||||
|
void AddBehavior(const IBehaviors::Info& info) override;
|
||||||
|
std::string GetBehavior(const int32_t behaviorId) override;
|
||||||
|
void RemoveBehavior(const int32_t behaviorId) override;
|
||||||
|
void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) override;
|
||||||
|
std::optional<IProperty::PropertyEntranceResult> GetProperties(const IProperty::PropertyLookup& params) override { return {}; };
|
||||||
|
std::vector<ILeaderboard::Entry> GetDescendingLeaderboard(const uint32_t activityId) override { return {}; };
|
||||||
|
std::vector<ILeaderboard::Entry> GetAscendingLeaderboard(const uint32_t activityId) override { return {}; };
|
||||||
|
std::vector<ILeaderboard::Entry> GetNsLeaderboard(const uint32_t activityId) override { return {}; };
|
||||||
|
std::vector<ILeaderboard::Entry> GetAgsLeaderboard(const uint32_t activityId) override { return {}; };
|
||||||
|
void SaveScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override {};
|
||||||
|
void UpdateScore(const uint32_t playerId, const uint32_t gameId, const Score& score) override {};
|
||||||
|
std::optional<ILeaderboard::Score> GetPlayerScore(const uint32_t playerId, const uint32_t gameId) override { return {}; };
|
||||||
|
void IncrementNumWins(const uint32_t playerId, const uint32_t gameId) override {};
|
||||||
|
void IncrementTimesPlayed(const uint32_t playerId, const uint32_t gameId) override {};
|
||||||
|
void InsertUgcBuild(const std::string& modules, const LWOOBJID bigId, const std::optional<uint32_t> characterId) override {};
|
||||||
|
void DeleteUgcBuild(const LWOOBJID bigId) override {};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!TESTSQLDATABASE_H
|
||||||
@@ -34,7 +34,7 @@ Migration LoadMigration(std::string path) {
|
|||||||
void MigrationRunner::RunMigrations() {
|
void MigrationRunner::RunMigrations() {
|
||||||
Database::Get()->CreateMigrationHistoryTable();
|
Database::Get()->CreateMigrationHistoryTable();
|
||||||
|
|
||||||
sql::SQLString finalSQL = "";
|
std::string finalSQL = "";
|
||||||
bool runSd0Migrations = false;
|
bool runSd0Migrations = false;
|
||||||
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/").string())) {
|
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/").string())) {
|
||||||
auto migration = LoadMigration("dlu/" + entry);
|
auto migration = LoadMigration("dlu/" + entry);
|
||||||
@@ -61,12 +61,12 @@ void MigrationRunner::RunMigrations() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!finalSQL.empty()) {
|
if (!finalSQL.empty()) {
|
||||||
auto migration = GeneralUtils::SplitString(static_cast<std::string>(finalSQL), ';');
|
auto migration = GeneralUtils::SplitString(finalSQL, ';');
|
||||||
for (auto& query : migration) {
|
for (auto& query : migration) {
|
||||||
try {
|
try {
|
||||||
if (query.empty()) continue;
|
if (query.empty()) continue;
|
||||||
Database::Get()->ExecuteCustomQuery(query.c_str());
|
Database::Get()->ExecuteCustomQuery(query);
|
||||||
} catch (sql::SQLException& e) {
|
} catch (std::exception& e) {
|
||||||
LOG("Encountered error running migration: %s", e.what());
|
LOG("Encountered error running migration: %s", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
dECS/CMakeLists.txt
Normal file
15
dECS/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
|
||||||
|
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
|
||||||
|
|
||||||
|
add_library(dECS STATIC
|
||||||
|
"Core.h"
|
||||||
|
"Iter.h"
|
||||||
|
"Core.cpp"
|
||||||
|
"System.cpp"
|
||||||
|
)
|
||||||
|
target_include_directories(dECS PUBLIC .)
|
||||||
|
target_link_libraries(dECS PRIVATE dCommon magic_enum::magic_enum)
|
||||||
|
target_compile_options(dECS PRIVATE
|
||||||
|
"$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra>>"
|
||||||
|
"$<${msvc_cxx}:$<BUILD_INTERFACE:/W3>>"
|
||||||
|
)
|
||||||
70
dECS/Core.cpp
Normal file
70
dECS/Core.cpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#include <atomic>
|
||||||
|
#include <magic_enum/magic_enum_containers.hpp>
|
||||||
|
#include <eReplicaComponentType.h>
|
||||||
|
#include "Core.h"
|
||||||
|
|
||||||
|
namespace dECS {
|
||||||
|
struct WorldData {
|
||||||
|
using CompSignature = magic_enum::containers::bitset<eReplicaComponentType>;
|
||||||
|
using CompMap = std::unordered_map<LWOOBJID, CompSignature>;
|
||||||
|
using CompStorage = std::unordered_map<eReplicaComponentType, std::unique_ptr<IStorage>>;
|
||||||
|
|
||||||
|
std::atomic<LWOOBJID> nextId = 1;
|
||||||
|
CompMap map;
|
||||||
|
CompStorage data;
|
||||||
|
};
|
||||||
|
|
||||||
|
World::World() : m_World{ std::make_shared<WorldData>() } {};
|
||||||
|
|
||||||
|
Entity World::MakeEntity() {
|
||||||
|
return Entity{ m_World->nextId.fetch_add(1, std::memory_order::relaxed),
|
||||||
|
m_World };
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Entity::AddComponent(const eReplicaComponentType kind, const StorageConstructor storageConstructor) {
|
||||||
|
if (auto w = m_World.lock()) {
|
||||||
|
// Add to kind signature
|
||||||
|
w->map[m_Id].set(kind, true);
|
||||||
|
|
||||||
|
// Get or add storage
|
||||||
|
auto storageIt = w->data.find(kind);
|
||||||
|
if (storageIt == w->data.cend()) {
|
||||||
|
bool inserted = false;
|
||||||
|
std::tie(storageIt, inserted) = w->data.try_emplace(kind, storageConstructor());
|
||||||
|
if (!inserted) throw "storage emplacement failure";
|
||||||
|
}
|
||||||
|
auto& storage = *storageIt->second;
|
||||||
|
|
||||||
|
// Return reference if already mapped, otherwise add component
|
||||||
|
auto compIt = storage.rowMap.find(m_Id);
|
||||||
|
if (compIt == storage.rowMap.cend()) {
|
||||||
|
const auto curSize = storage.rowMap.size();
|
||||||
|
storage.rowMap.emplace(m_Id, curSize);
|
||||||
|
return storage.emplace_back();
|
||||||
|
}
|
||||||
|
const auto row = compIt->second;
|
||||||
|
return storage.at(row);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void* Entity::GetComponent(const eReplicaComponentType kind) const {
|
||||||
|
if (auto const w = m_World.lock()) {
|
||||||
|
// Check that the entity has this component
|
||||||
|
if (!w->map[m_Id].test(kind)) return nullptr;
|
||||||
|
|
||||||
|
// Get the location where it's stored
|
||||||
|
const auto& storage = *w->data.at(kind);
|
||||||
|
const auto it = storage.rowMap.find(m_Id);
|
||||||
|
if (it == storage.rowMap.cend()) return nullptr;
|
||||||
|
const auto row = it->second;
|
||||||
|
return storage.at(row);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Entity::GetComponent(const eReplicaComponentType kind) {
|
||||||
|
// Casting away const for this overload is safe, if not at all pretty
|
||||||
|
return const_cast<void*>(std::as_const(*this).GetComponent(kind));
|
||||||
|
}
|
||||||
|
}
|
||||||
180
dECS/Core.h
Normal file
180
dECS/Core.h
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Component;
|
||||||
|
enum class eReplicaComponentType : uint32_t;
|
||||||
|
using LWOOBJID = int64_t;
|
||||||
|
|
||||||
|
namespace dECS {
|
||||||
|
// template <typename C>
|
||||||
|
// concept IsComponent = std::derived_from<C, Component>;
|
||||||
|
|
||||||
|
// Data structures
|
||||||
|
struct WorldData;
|
||||||
|
class World;
|
||||||
|
|
||||||
|
template <typename... Cs>
|
||||||
|
class System;
|
||||||
|
|
||||||
|
class Entity;
|
||||||
|
struct IStorage;
|
||||||
|
|
||||||
|
template <typename C>
|
||||||
|
class Storage;
|
||||||
|
|
||||||
|
using WorldPtr = std::shared_ptr<WorldData>;
|
||||||
|
using WeakWorldPtr = std::weak_ptr<WorldData>;
|
||||||
|
|
||||||
|
class World {
|
||||||
|
public:
|
||||||
|
World();
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
Entity MakeEntity();
|
||||||
|
|
||||||
|
template <typename... Cs>
|
||||||
|
[[nodiscard]]
|
||||||
|
System<Cs...> MakeSystem() {
|
||||||
|
return System<Cs...>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Cs, typename S>
|
||||||
|
[[nodiscard]]
|
||||||
|
System<Cs...> MakeSystem(S&& name) {
|
||||||
|
return System<Cs...>{ std::forward<S>(name) };
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
WorldPtr m_World;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Cs>
|
||||||
|
class System {
|
||||||
|
public:
|
||||||
|
friend System World::MakeSystem<Cs...>();
|
||||||
|
|
||||||
|
template <typename... Ts, typename S>
|
||||||
|
friend System<Ts...> World::MakeSystem(S&&);
|
||||||
|
|
||||||
|
/*template <typename Fn>
|
||||||
|
requires std::is_invocable_r_v<void, Fn(Cs...), ObjId, Cs...>
|
||||||
|
void ForEach(Fn&& f) {
|
||||||
|
for (ObjId i = 0; i < mT.size(); ++i) {
|
||||||
|
auto& c = mT[i];
|
||||||
|
f(i, std::get<Cs>(c)...);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
template <typename Fn>
|
||||||
|
requires std::is_invocable_r_v<void, Fn(Cs...), Cs...>
|
||||||
|
void ForEach(Fn&& fn) {
|
||||||
|
std::tuple<Cs...> comps; // some sort of iterator that returns a tuple each 'step?'
|
||||||
|
for (size_t i = 0; i < 5; ++i) {
|
||||||
|
fn(std::get<Cs>(comps)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
System() = default;
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
explicit System(S&& name)
|
||||||
|
: m_name{ std::forward<S>(name) }
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Entity {
|
||||||
|
public:
|
||||||
|
friend Entity World::MakeEntity();
|
||||||
|
|
||||||
|
using StorageConstructor = std::function<std::unique_ptr<IStorage>()>;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr LWOOBJID GetObjectID() const noexcept {
|
||||||
|
return m_Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
void* AddComponent(eReplicaComponentType, StorageConstructor);
|
||||||
|
|
||||||
|
template <typename C>
|
||||||
|
[[maybe_unused]]
|
||||||
|
C* AddComponent() {
|
||||||
|
return static_cast<C*>(AddComponent(C::ComponentType, std::make_unique<Storage<C>>));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const void* GetComponent(eReplicaComponentType) const;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
void* GetComponent(eReplicaComponentType);
|
||||||
|
|
||||||
|
template <typename C>
|
||||||
|
[[nodiscard]]
|
||||||
|
const C* GetComponent() const {
|
||||||
|
return static_cast<const C*>(GetComponent(C::ComponentType));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename C>
|
||||||
|
[[nodiscard]]
|
||||||
|
C* GetComponent() {
|
||||||
|
return static_cast<C*>(GetComponent(C::ComponentType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Entity(const LWOOBJID id, const WeakWorldPtr world)
|
||||||
|
: m_Id{ id }
|
||||||
|
, m_World { world }
|
||||||
|
{}
|
||||||
|
|
||||||
|
LWOOBJID m_Id;
|
||||||
|
|
||||||
|
WeakWorldPtr m_World;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IStorage {
|
||||||
|
using RowMap = std::unordered_map<LWOOBJID, size_t>;
|
||||||
|
|
||||||
|
virtual ~IStorage() = default;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual void* at(size_t) = 0;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual const void* at(size_t) const = 0;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
virtual void* emplace_back() = 0;
|
||||||
|
|
||||||
|
RowMap rowMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename C>
|
||||||
|
class Storage : public IStorage {
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
void* at(const size_t index) override {
|
||||||
|
return static_cast<void*>(&m_Vec.at(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const void* at(const size_t index) const override {
|
||||||
|
return static_cast<const void*>(&m_Vec.at(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
void* emplace_back() override {
|
||||||
|
return static_cast<void*>(&m_Vec.emplace_back());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<C> m_Vec;
|
||||||
|
};
|
||||||
|
}
|
||||||
12
dECS/Iter.h
Normal file
12
dECS/Iter.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#include "Core.h"
|
||||||
|
|
||||||
|
namespace dECS {
|
||||||
|
class Iter {
|
||||||
|
public:
|
||||||
|
[[nodiscard]]
|
||||||
|
bool Next();
|
||||||
|
|
||||||
|
private:
|
||||||
|
WeakWorldPtr m_World;
|
||||||
|
};
|
||||||
|
}
|
||||||
52
dECS/System.cpp
Normal file
52
dECS/System.cpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#include "PetComponent.h"
|
||||||
|
#include "MovementAIComponent.h"
|
||||||
|
#include "MissionComponent.h"
|
||||||
|
#include "eMissionState.h"
|
||||||
|
|
||||||
|
using Pet = PetComponent;
|
||||||
|
using Mission = MissionComponent;
|
||||||
|
using MovementAI = MovementAIComponent;
|
||||||
|
|
||||||
|
struct Position : NiPoint3 {};
|
||||||
|
struct Treasure {};
|
||||||
|
|
||||||
|
namespace decs {
|
||||||
|
template <typename... Cs>
|
||||||
|
class System {
|
||||||
|
public:
|
||||||
|
template <typename Fn>
|
||||||
|
void each(Fn&& fn) {
|
||||||
|
fn();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Scene {
|
||||||
|
public:
|
||||||
|
template <typename... Cs>
|
||||||
|
System<Cs...> system() {
|
||||||
|
return System<Cs...>{};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
auto scene = decs::Scene{};
|
||||||
|
|
||||||
|
scene.system<Pet>()
|
||||||
|
.each([](Pet& pet) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
scene.system<Pet, MovementAI>()
|
||||||
|
.each([](Pet& pet, MovementAI& move) {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
scene.system<Pet, const Mission, const Position>()
|
||||||
|
.each([](Pet& pet, Mission const& mission, Position const& pos) {
|
||||||
|
auto const digUnlocked = mission.GetMissionState(842) == eMissionState::COMPLETE;
|
||||||
|
auto const treasurePos = PetDigServer::GetClosestTreasure(pos);
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -27,12 +27,11 @@ Character::Character(uint32_t id, User* parentUser) {
|
|||||||
m_ID = id;
|
m_ID = id;
|
||||||
m_ParentUser = parentUser;
|
m_ParentUser = parentUser;
|
||||||
m_OurEntity = nullptr;
|
m_OurEntity = nullptr;
|
||||||
m_Doc = nullptr;
|
m_GMLevel = eGameMasterLevel::CIVILIAN;
|
||||||
|
m_PermissionMap = static_cast<ePermissionMap>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Character::~Character() {
|
Character::~Character() {
|
||||||
if (m_Doc) delete m_Doc;
|
|
||||||
m_Doc = nullptr;
|
|
||||||
m_OurEntity = nullptr;
|
m_OurEntity = nullptr;
|
||||||
m_ParentUser = nullptr;
|
m_ParentUser = nullptr;
|
||||||
}
|
}
|
||||||
@@ -55,8 +54,6 @@ void Character::UpdateInfoFromDatabase() {
|
|||||||
m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused.
|
m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused.
|
||||||
m_ZoneCloneID = 0;
|
m_ZoneCloneID = 0;
|
||||||
|
|
||||||
m_Doc = nullptr;
|
|
||||||
|
|
||||||
//Quickly and dirtly parse the xmlData to get the info we need:
|
//Quickly and dirtly parse the xmlData to get the info we need:
|
||||||
DoQuickXMLDataParse();
|
DoQuickXMLDataParse();
|
||||||
|
|
||||||
@@ -70,26 +67,21 @@ void Character::UpdateInfoFromDatabase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Character::UpdateFromDatabase() {
|
void Character::UpdateFromDatabase() {
|
||||||
if (m_Doc) delete m_Doc;
|
|
||||||
UpdateInfoFromDatabase();
|
UpdateInfoFromDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Character::DoQuickXMLDataParse() {
|
void Character::DoQuickXMLDataParse() {
|
||||||
if (m_XMLData.size() == 0) return;
|
if (m_XMLData.size() == 0) return;
|
||||||
|
|
||||||
delete m_Doc;
|
if (m_Doc.Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) {
|
||||||
m_Doc = new tinyxml2::XMLDocument();
|
|
||||||
if (!m_Doc) return;
|
|
||||||
|
|
||||||
if (m_Doc->Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) {
|
|
||||||
LOG("Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID);
|
LOG("Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID);
|
||||||
} else {
|
} else {
|
||||||
LOG("Failed to load xmlData!");
|
LOG("Failed to load xmlData (%i) (%s) (%s)!", m_Doc.ErrorID(), m_Doc.ErrorIDToName(m_Doc.ErrorID()), m_Doc.ErrorStr());
|
||||||
//Server::rakServer->CloseConnection(m_ParentUser->GetSystemAddress(), true);
|
//Server::rakServer->CloseConnection(m_ParentUser->GetSystemAddress(), true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tinyxml2::XMLElement* mf = m_Doc->FirstChildElement("obj")->FirstChildElement("mf");
|
tinyxml2::XMLElement* mf = m_Doc.FirstChildElement("obj")->FirstChildElement("mf");
|
||||||
if (!mf) {
|
if (!mf) {
|
||||||
LOG("Failed to find mf tag!");
|
LOG("Failed to find mf tag!");
|
||||||
return;
|
return;
|
||||||
@@ -108,7 +100,7 @@ void Character::DoQuickXMLDataParse() {
|
|||||||
mf->QueryAttribute("ess", &m_Eyes);
|
mf->QueryAttribute("ess", &m_Eyes);
|
||||||
mf->QueryAttribute("ms", &m_Mouth);
|
mf->QueryAttribute("ms", &m_Mouth);
|
||||||
|
|
||||||
tinyxml2::XMLElement* inv = m_Doc->FirstChildElement("obj")->FirstChildElement("inv");
|
tinyxml2::XMLElement* inv = m_Doc.FirstChildElement("obj")->FirstChildElement("inv");
|
||||||
if (!inv) {
|
if (!inv) {
|
||||||
LOG("Char has no inv!");
|
LOG("Char has no inv!");
|
||||||
return;
|
return;
|
||||||
@@ -141,7 +133,7 @@ void Character::DoQuickXMLDataParse() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char");
|
tinyxml2::XMLElement* character = m_Doc.FirstChildElement("obj")->FirstChildElement("char");
|
||||||
if (character) {
|
if (character) {
|
||||||
character->QueryAttribute("cc", &m_Coins);
|
character->QueryAttribute("cc", &m_Coins);
|
||||||
int32_t gm_level = 0;
|
int32_t gm_level = 0;
|
||||||
@@ -205,7 +197,7 @@ void Character::DoQuickXMLDataParse() {
|
|||||||
character->QueryAttribute("lzrw", &m_OriginalRotation.w);
|
character->QueryAttribute("lzrw", &m_OriginalRotation.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag");
|
auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag");
|
||||||
if (flags) {
|
if (flags) {
|
||||||
auto* currentChild = flags->FirstChildElement();
|
auto* currentChild = flags->FirstChildElement();
|
||||||
while (currentChild) {
|
while (currentChild) {
|
||||||
@@ -239,12 +231,10 @@ void Character::SetBuildMode(bool buildMode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Character::SaveXMLToDatabase() {
|
void Character::SaveXMLToDatabase() {
|
||||||
if (!m_Doc) return;
|
|
||||||
|
|
||||||
//For metrics, we'll record the time it took to save:
|
//For metrics, we'll record the time it took to save:
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
|
|
||||||
tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char");
|
tinyxml2::XMLElement* character = m_Doc.FirstChildElement("obj")->FirstChildElement("char");
|
||||||
if (character) {
|
if (character) {
|
||||||
character->SetAttribute("gm", static_cast<uint32_t>(m_GMLevel));
|
character->SetAttribute("gm", static_cast<uint32_t>(m_GMLevel));
|
||||||
character->SetAttribute("cc", m_Coins);
|
character->SetAttribute("cc", m_Coins);
|
||||||
@@ -266,11 +256,11 @@ void Character::SaveXMLToDatabase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto emotes = character->FirstChildElement("ue");
|
auto emotes = character->FirstChildElement("ue");
|
||||||
if (!emotes) emotes = m_Doc->NewElement("ue");
|
if (!emotes) emotes = m_Doc.NewElement("ue");
|
||||||
|
|
||||||
emotes->DeleteChildren();
|
emotes->DeleteChildren();
|
||||||
for (int emoteID : m_UnlockedEmotes) {
|
for (int emoteID : m_UnlockedEmotes) {
|
||||||
auto emote = m_Doc->NewElement("e");
|
auto emote = m_Doc.NewElement("e");
|
||||||
emote->SetAttribute("id", emoteID);
|
emote->SetAttribute("id", emoteID);
|
||||||
|
|
||||||
emotes->LinkEndChild(emote);
|
emotes->LinkEndChild(emote);
|
||||||
@@ -280,15 +270,15 @@ void Character::SaveXMLToDatabase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Export our flags:
|
//Export our flags:
|
||||||
auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag");
|
auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag");
|
||||||
if (!flags) {
|
if (!flags) {
|
||||||
flags = m_Doc->NewElement("flag"); //Create a flags tag if we don't have one
|
flags = m_Doc.NewElement("flag"); //Create a flags tag if we don't have one
|
||||||
m_Doc->FirstChildElement("obj")->LinkEndChild(flags); //Link it to the obj tag so we can find next time
|
m_Doc.FirstChildElement("obj")->LinkEndChild(flags); //Link it to the obj tag so we can find next time
|
||||||
}
|
}
|
||||||
|
|
||||||
flags->DeleteChildren(); //Clear it if we have anything, so that we can fill it up again without dupes
|
flags->DeleteChildren(); //Clear it if we have anything, so that we can fill it up again without dupes
|
||||||
for (std::pair<uint32_t, uint64_t> flag : m_PlayerFlags) {
|
for (std::pair<uint32_t, uint64_t> flag : m_PlayerFlags) {
|
||||||
auto* f = m_Doc->NewElement("f");
|
auto* f = m_Doc.NewElement("f");
|
||||||
f->SetAttribute("id", flag.first);
|
f->SetAttribute("id", flag.first);
|
||||||
|
|
||||||
//Because of the joy that is tinyxml2, it doesn't offer a function to set a uint64 as an attribute.
|
//Because of the joy that is tinyxml2, it doesn't offer a function to set a uint64 as an attribute.
|
||||||
@@ -301,7 +291,7 @@ void Character::SaveXMLToDatabase() {
|
|||||||
|
|
||||||
// Prevents the news feed from showing up on world transfers
|
// Prevents the news feed from showing up on world transfers
|
||||||
if (GetPlayerFlag(ePlayerFlag::IS_NEWS_SCREEN_VISIBLE)) {
|
if (GetPlayerFlag(ePlayerFlag::IS_NEWS_SCREEN_VISIBLE)) {
|
||||||
auto* s = m_Doc->NewElement("s");
|
auto* s = m_Doc.NewElement("s");
|
||||||
s->SetAttribute("si", ePlayerFlag::IS_NEWS_SCREEN_VISIBLE);
|
s->SetAttribute("si", ePlayerFlag::IS_NEWS_SCREEN_VISIBLE);
|
||||||
flags->LinkEndChild(s);
|
flags->LinkEndChild(s);
|
||||||
}
|
}
|
||||||
@@ -326,7 +316,7 @@ void Character::SaveXMLToDatabase() {
|
|||||||
|
|
||||||
void Character::SetIsNewLogin() {
|
void Character::SetIsNewLogin() {
|
||||||
// If we dont have a flag element, then we cannot have a s element as a child of flag.
|
// If we dont have a flag element, then we cannot have a s element as a child of flag.
|
||||||
auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag");
|
auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag");
|
||||||
if (!flags) return;
|
if (!flags) return;
|
||||||
|
|
||||||
auto* currentChild = flags->FirstChildElement();
|
auto* currentChild = flags->FirstChildElement();
|
||||||
@@ -344,7 +334,7 @@ void Character::SetIsNewLogin() {
|
|||||||
void Character::WriteToDatabase() {
|
void Character::WriteToDatabase() {
|
||||||
//Dump our xml into m_XMLData:
|
//Dump our xml into m_XMLData:
|
||||||
tinyxml2::XMLPrinter printer(0, true, 0);
|
tinyxml2::XMLPrinter printer(0, true, 0);
|
||||||
m_Doc->Print(&printer);
|
m_Doc.Print(&printer);
|
||||||
|
|
||||||
//Finally, save to db:
|
//Finally, save to db:
|
||||||
Database::Get()->UpdateCharacterXml(m_ID, printer.CStr());
|
Database::Get()->UpdateCharacterXml(m_ID, printer.CStr());
|
||||||
@@ -421,15 +411,15 @@ void Character::SetRetroactiveFlags() {
|
|||||||
|
|
||||||
void Character::SaveXmlRespawnCheckpoints() {
|
void Character::SaveXmlRespawnCheckpoints() {
|
||||||
//Export our respawn points:
|
//Export our respawn points:
|
||||||
auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res");
|
auto* points = m_Doc.FirstChildElement("obj")->FirstChildElement("res");
|
||||||
if (!points) {
|
if (!points) {
|
||||||
points = m_Doc->NewElement("res");
|
points = m_Doc.NewElement("res");
|
||||||
m_Doc->FirstChildElement("obj")->LinkEndChild(points);
|
m_Doc.FirstChildElement("obj")->LinkEndChild(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
points->DeleteChildren();
|
points->DeleteChildren();
|
||||||
for (const auto& point : m_WorldRespawnCheckpoints) {
|
for (const auto& point : m_WorldRespawnCheckpoints) {
|
||||||
auto* r = m_Doc->NewElement("r");
|
auto* r = m_Doc.NewElement("r");
|
||||||
r->SetAttribute("w", point.first);
|
r->SetAttribute("w", point.first);
|
||||||
|
|
||||||
r->SetAttribute("x", point.second.x);
|
r->SetAttribute("x", point.second.x);
|
||||||
@@ -443,7 +433,7 @@ void Character::SaveXmlRespawnCheckpoints() {
|
|||||||
void Character::LoadXmlRespawnCheckpoints() {
|
void Character::LoadXmlRespawnCheckpoints() {
|
||||||
m_WorldRespawnCheckpoints.clear();
|
m_WorldRespawnCheckpoints.clear();
|
||||||
|
|
||||||
auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res");
|
auto* points = m_Doc.FirstChildElement("obj")->FirstChildElement("res");
|
||||||
if (!points) {
|
if (!points) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ public:
|
|||||||
void LoadXmlRespawnCheckpoints();
|
void LoadXmlRespawnCheckpoints();
|
||||||
|
|
||||||
const std::string& GetXMLData() const { return m_XMLData; }
|
const std::string& GetXMLData() const { return m_XMLData; }
|
||||||
tinyxml2::XMLDocument* GetXMLDoc() const { return m_Doc; }
|
const tinyxml2::XMLDocument& GetXMLDoc() const { return m_Doc; }
|
||||||
|
void _setXmlDoc(tinyxml2::XMLDocument& doc) { doc.DeepCopy(&m_Doc); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Out of abundance of safety and clarity of what this saves, this is its own function.
|
* Out of abundance of safety and clarity of what this saves, this is its own function.
|
||||||
@@ -459,27 +460,31 @@ public:
|
|||||||
|
|
||||||
User* GetParentUser() const { return m_ParentUser; }
|
User* GetParentUser() const { return m_ParentUser; }
|
||||||
|
|
||||||
|
void _doQuickXMLDataParse() { DoQuickXMLDataParse(); }
|
||||||
|
|
||||||
|
void _setXmlData(const std::string& xmlData) { m_XMLData = xmlData; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UpdateInfoFromDatabase();
|
void UpdateInfoFromDatabase();
|
||||||
/**
|
/**
|
||||||
* The ID of this character. First 32 bits of the ObjectID.
|
* The ID of this character. First 32 bits of the ObjectID.
|
||||||
*/
|
*/
|
||||||
uint32_t m_ID;
|
uint32_t m_ID{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The 64-bit unique ID used in the game.
|
* The 64-bit unique ID used in the game.
|
||||||
*/
|
*/
|
||||||
LWOOBJID m_ObjectID;
|
LWOOBJID m_ObjectID{ LWOOBJID_EMPTY };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The user that owns this character.
|
* The user that owns this character.
|
||||||
*/
|
*/
|
||||||
User* m_ParentUser;
|
User* m_ParentUser{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the character is in game, this is the entity that it represents, else nullptr.
|
* If the character is in game, this is the entity that it represents, else nullptr.
|
||||||
*/
|
*/
|
||||||
Entity* m_OurEntity;
|
Entity* m_OurEntity{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 0-9, the Game Master level of this character.
|
* 0-9, the Game Master level of this character.
|
||||||
@@ -506,17 +511,17 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Whether the custom name of this character is rejected
|
* Whether the custom name of this character is rejected
|
||||||
*/
|
*/
|
||||||
bool m_NameRejected;
|
bool m_NameRejected{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current amount of coins of this character
|
* The current amount of coins of this character
|
||||||
*/
|
*/
|
||||||
int64_t m_Coins;
|
int64_t m_Coins{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the character is building
|
* Whether the character is building
|
||||||
*/
|
*/
|
||||||
bool m_BuildMode;
|
bool m_BuildMode{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The items equipped by the character on world load
|
* The items equipped by the character on world load
|
||||||
@@ -583,7 +588,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* The ID of the properties of this character
|
* The ID of the properties of this character
|
||||||
*/
|
*/
|
||||||
uint32_t m_PropertyCloneID;
|
uint32_t m_PropertyCloneID{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The XML data for this character, stored as string
|
* The XML data for this character, stored as string
|
||||||
@@ -613,7 +618,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* The last time this character logged in
|
* The last time this character logged in
|
||||||
*/
|
*/
|
||||||
uint64_t m_LastLogin;
|
uint64_t m_LastLogin{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The gameplay flags this character has (not just true values)
|
* The gameplay flags this character has (not just true values)
|
||||||
@@ -623,7 +628,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* The character XML belonging to this character
|
* The character XML belonging to this character
|
||||||
*/
|
*/
|
||||||
tinyxml2::XMLDocument* m_Doc;
|
tinyxml2::XMLDocument m_Doc;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Title of an announcement this character made (reserved for GMs)
|
* Title of an announcement this character made (reserved for GMs)
|
||||||
|
|||||||
106
dGame/Entity.cpp
106
dGame/Entity.cpp
@@ -24,7 +24,7 @@
|
|||||||
#include "eTriggerEventType.h"
|
#include "eTriggerEventType.h"
|
||||||
#include "eObjectBits.h"
|
#include "eObjectBits.h"
|
||||||
#include "PositionUpdate.h"
|
#include "PositionUpdate.h"
|
||||||
#include "eChatMessageType.h"
|
#include "MessageType/Chat.h"
|
||||||
#include "PlayerManager.h"
|
#include "PlayerManager.h"
|
||||||
|
|
||||||
//Component includes:
|
//Component includes:
|
||||||
@@ -83,6 +83,7 @@
|
|||||||
#include "ItemComponent.h"
|
#include "ItemComponent.h"
|
||||||
#include "GhostComponent.h"
|
#include "GhostComponent.h"
|
||||||
#include "AchievementVendorComponent.h"
|
#include "AchievementVendorComponent.h"
|
||||||
|
#include "VanityUtilities.h"
|
||||||
|
|
||||||
// Table includes
|
// Table includes
|
||||||
#include "CDComponentsRegistryTable.h"
|
#include "CDComponentsRegistryTable.h"
|
||||||
@@ -96,6 +97,10 @@
|
|||||||
#include "CDSkillBehaviorTable.h"
|
#include "CDSkillBehaviorTable.h"
|
||||||
#include "CDZoneTableTable.h"
|
#include "CDZoneTableTable.h"
|
||||||
|
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
|
Observable<Entity*, const PositionUpdate&> Entity::OnPlayerPositionUpdate;
|
||||||
|
|
||||||
Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Entity* parentEntity) {
|
Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Entity* parentEntity) {
|
||||||
m_ObjectID = objectID;
|
m_ObjectID = objectID;
|
||||||
m_TemplateID = info.lot;
|
m_TemplateID = info.lot;
|
||||||
@@ -225,7 +230,7 @@ void Entity::Initialize() {
|
|||||||
|
|
||||||
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
|
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
|
||||||
|
|
||||||
AddComponent<ModelComponent>();
|
AddComponent<ModelComponent>()->LoadBehaviors();
|
||||||
|
|
||||||
AddComponent<RenderComponent>();
|
AddComponent<RenderComponent>();
|
||||||
|
|
||||||
@@ -283,8 +288,9 @@ void Entity::Initialize() {
|
|||||||
AddComponent<PropertyEntranceComponent>(propertyEntranceComponentID);
|
AddComponent<PropertyEntranceComponent>(propertyEntranceComponentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS) > 0) {
|
const int32_t controllablePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS);
|
||||||
auto* controllablePhysics = AddComponent<ControllablePhysicsComponent>();
|
if (controllablePhysicsComponentID > 0) {
|
||||||
|
auto* controllablePhysics = AddComponent<ControllablePhysicsComponent>(controllablePhysicsComponentID);
|
||||||
|
|
||||||
if (m_Character) {
|
if (m_Character) {
|
||||||
controllablePhysics->LoadFromXml(m_Character->GetXMLDoc());
|
controllablePhysics->LoadFromXml(m_Character->GetXMLDoc());
|
||||||
@@ -327,16 +333,19 @@ void Entity::Initialize() {
|
|||||||
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
|
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS) > 0) {
|
const int32_t rigidBodyPhantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS);
|
||||||
AddComponent<RigidbodyPhantomPhysicsComponent>();
|
if (rigidBodyPhantomPhysicsComponentID > 0) {
|
||||||
|
AddComponent<RigidbodyPhantomPhysicsComponent>(rigidBodyPhantomPhysicsComponentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS) > 0) {
|
const int32_t phantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS);
|
||||||
AddComponent<PhantomPhysicsComponent>()->SetPhysicsEffectActive(false);
|
if (markedAsPhantom || phantomPhysicsComponentID > 0) {
|
||||||
|
AddComponent<PhantomPhysicsComponent>(phantomPhysicsComponentID)->SetPhysicsEffectActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS) > 0) {
|
const int32_t havokVehiclePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS);
|
||||||
auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>();
|
if (havokVehiclePhysicsComponentID > 0) {
|
||||||
|
auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>(havokVehiclePhysicsComponentID);
|
||||||
havokVehiclePhysicsComponent->SetPosition(m_DefaultPosition);
|
havokVehiclePhysicsComponent->SetPosition(m_DefaultPosition);
|
||||||
havokVehiclePhysicsComponent->SetRotation(m_DefaultRotation);
|
havokVehiclePhysicsComponent->SetRotation(m_DefaultRotation);
|
||||||
}
|
}
|
||||||
@@ -476,8 +485,7 @@ void Entity::Initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) {
|
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) {
|
||||||
auto* xmlDoc = m_Character ? m_Character->GetXMLDoc() : nullptr;
|
AddComponent<InventoryComponent>();
|
||||||
AddComponent<InventoryComponent>(xmlDoc);
|
|
||||||
}
|
}
|
||||||
// if this component exists, then we initialize it. it's value is always 0
|
// if this component exists, then we initialize it. it's value is always 0
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MULTI_ZONE_ENTRANCE, -1) != -1) {
|
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MULTI_ZONE_ENTRANCE, -1) != -1) {
|
||||||
@@ -650,7 +658,7 @@ void Entity::Initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent<PetComponent>()) {
|
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent<PetComponent>()) {
|
||||||
AddComponent<ModelComponent>();
|
AddComponent<ModelComponent>()->LoadBehaviors();
|
||||||
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) {
|
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) {
|
||||||
auto* destroyableComponent = AddComponent<DestroyableComponent>();
|
auto* destroyableComponent = AddComponent<DestroyableComponent>();
|
||||||
destroyableComponent->SetHealth(1);
|
destroyableComponent->SetHealth(1);
|
||||||
@@ -731,15 +739,21 @@ void Entity::Initialize() {
|
|||||||
// if we have a moving platform path, then we need a moving platform component
|
// if we have a moving platform path, then we need a moving platform component
|
||||||
if (path->pathType == PathType::MovingPlatform) {
|
if (path->pathType == PathType::MovingPlatform) {
|
||||||
AddComponent<MovingPlatformComponent>(pathName);
|
AddComponent<MovingPlatformComponent>(pathName);
|
||||||
// else if we are a movement path
|
} else if (path->pathType == PathType::Movement) {
|
||||||
} /*else if (path->pathType == PathType::Movement) {
|
auto movementAIcomponent = GetComponent<MovementAIComponent>();
|
||||||
auto movementAIcomp = GetComponent<MovementAIComponent>();
|
if (movementAIcomponent && combatAiId == 0) {
|
||||||
if (movementAIcomp){
|
movementAIcomponent->SetPath(pathName);
|
||||||
// TODO: set path in existing movementAIComp
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: create movementAIcomp and set path
|
MovementAIInfo moveInfo = MovementAIInfo();
|
||||||
|
moveInfo.movementType = "";
|
||||||
|
moveInfo.wanderChance = 0;
|
||||||
|
moveInfo.wanderRadius = 16;
|
||||||
|
moveInfo.wanderSpeed = 2.5f;
|
||||||
|
moveInfo.wanderDelayMax = 5;
|
||||||
|
moveInfo.wanderDelayMin = 2;
|
||||||
|
AddComponent<MovementAIComponent>(moveInfo);
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
} else {
|
} else {
|
||||||
// else we still need to setup moving platform if it has a moving platform comp but no path
|
// else we still need to setup moving platform if it has a moving platform comp but no path
|
||||||
int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
|
int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
|
||||||
@@ -876,7 +890,7 @@ void Entity::SetGMLevel(eGameMasterLevel value) {
|
|||||||
// Update the chat server of our GM Level
|
// Update the chat server of our GM Level
|
||||||
{
|
{
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GMLEVEL_UPDATE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GMLEVEL_UPDATE);
|
||||||
bitStream.Write(m_ObjectID);
|
bitStream.Write(m_ObjectID);
|
||||||
bitStream.Write(m_GMLevel);
|
bitStream.Write(m_GMLevel);
|
||||||
|
|
||||||
@@ -1238,7 +1252,7 @@ void Entity::WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType
|
|||||||
outBitStream.Write0();
|
outBitStream.Write0();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) {
|
void Entity::UpdateXMLDoc(tinyxml2::XMLDocument& doc) {
|
||||||
//This function should only ever be called from within Character, meaning doc should always exist when this is called.
|
//This function should only ever be called from within Character, meaning doc should always exist when this is called.
|
||||||
//Naturally, we don't include any non-player components in this update function.
|
//Naturally, we don't include any non-player components in this update function.
|
||||||
|
|
||||||
@@ -1264,6 +1278,7 @@ void Entity::Update(const float deltaTime) {
|
|||||||
auto timerName = timer.GetName();
|
auto timerName = timer.GetName();
|
||||||
m_Timers.erase(m_Timers.begin() + timerPosition);
|
m_Timers.erase(m_Timers.begin() + timerPosition);
|
||||||
GetScript()->OnTimerDone(this, timerName);
|
GetScript()->OnTimerDone(this, timerName);
|
||||||
|
VanityUtilities::OnTimerDone(this, timerName);
|
||||||
|
|
||||||
TriggerEvent(eTriggerEventType::TIMER_DONE, this);
|
TriggerEvent(eTriggerEventType::TIMER_DONE, this);
|
||||||
} else {
|
} else {
|
||||||
@@ -1327,6 +1342,7 @@ void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxN
|
|||||||
if (!other) return;
|
if (!other) return;
|
||||||
|
|
||||||
GetScript()->OnProximityUpdate(this, other, proxName, status);
|
GetScript()->OnProximityUpdate(this, other, proxName, status);
|
||||||
|
VanityUtilities::OnProximityUpdate(this, other, proxName, status);
|
||||||
|
|
||||||
RocketLaunchpadControlComponent* rocketComp = GetComponent<RocketLaunchpadControlComponent>();
|
RocketLaunchpadControlComponent* rocketComp = GetComponent<RocketLaunchpadControlComponent>();
|
||||||
if (!rocketComp) return;
|
if (!rocketComp) return;
|
||||||
@@ -1346,7 +1362,7 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {
|
|||||||
|
|
||||||
SwitchComponent* switchComp = GetComponent<SwitchComponent>();
|
SwitchComponent* switchComp = GetComponent<SwitchComponent>();
|
||||||
if (switchComp) {
|
if (switchComp) {
|
||||||
switchComp->EntityEnter(other);
|
switchComp->OnUse(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
TriggerEvent(eTriggerEventType::ENTER, other);
|
TriggerEvent(eTriggerEventType::ENTER, other);
|
||||||
@@ -1529,7 +1545,7 @@ void Entity::Kill(Entity* murderer, const eKillType killType) {
|
|||||||
bool waitForDeathAnimation = false;
|
bool waitForDeathAnimation = false;
|
||||||
|
|
||||||
if (destroyableComponent) {
|
if (destroyableComponent) {
|
||||||
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0 && killType != eKillType::SILENT;
|
waitForDeathAnimation = !destroyableComponent->GetIsSmashable() && destroyableComponent->GetDeathBehavior() == 0 && killType != eKillType::SILENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!
|
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!
|
||||||
@@ -1629,10 +1645,8 @@ void Entity::PickupItem(const LWOOBJID& objectID) {
|
|||||||
CDObjectSkillsTable* skillsTable = CDClientManager::GetTable<CDObjectSkillsTable>();
|
CDObjectSkillsTable* skillsTable = CDClientManager::GetTable<CDObjectSkillsTable>();
|
||||||
std::vector<CDObjectSkills> skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == p.second.lot); });
|
std::vector<CDObjectSkills> skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == p.second.lot); });
|
||||||
for (CDObjectSkills skill : skills) {
|
for (CDObjectSkills skill : skills) {
|
||||||
CDSkillBehaviorTable* skillBehTable = CDClientManager::GetTable<CDSkillBehaviorTable>();
|
|
||||||
|
|
||||||
auto* skillComponent = GetComponent<SkillComponent>();
|
auto* skillComponent = GetComponent<SkillComponent>();
|
||||||
if (skillComponent) skillComponent->CastSkill(skill.skillID, GetObjectID(), GetObjectID());
|
if (skillComponent) skillComponent->CastSkill(skill.skillID, GetObjectID(), GetObjectID(), skill.castOnType, NiQuaternion(0, 0, 0, 0));
|
||||||
|
|
||||||
auto* missionComponent = GetComponent<MissionComponent>();
|
auto* missionComponent = GetComponent<MissionComponent>();
|
||||||
|
|
||||||
@@ -1837,6 +1851,12 @@ const NiPoint3& Entity::GetPosition() const {
|
|||||||
return vehicel->GetPosition();
|
return vehicel->GetPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* rigidBodyPhantomPhysicsComponent = GetComponent<RigidbodyPhantomPhysicsComponent>();
|
||||||
|
|
||||||
|
if (rigidBodyPhantomPhysicsComponent != nullptr) {
|
||||||
|
return rigidBodyPhantomPhysicsComponent->GetPosition();
|
||||||
|
}
|
||||||
|
|
||||||
return NiPoint3Constant::ZERO;
|
return NiPoint3Constant::ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1865,6 +1885,12 @@ const NiQuaternion& Entity::GetRotation() const {
|
|||||||
return vehicel->GetRotation();
|
return vehicel->GetRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* rigidBodyPhantomPhysicsComponent = GetComponent<RigidbodyPhantomPhysicsComponent>();
|
||||||
|
|
||||||
|
if (rigidBodyPhantomPhysicsComponent != nullptr) {
|
||||||
|
return rigidBodyPhantomPhysicsComponent->GetRotation();
|
||||||
|
}
|
||||||
|
|
||||||
return NiQuaternionConstant::IDENTITY;
|
return NiQuaternionConstant::IDENTITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1893,6 +1919,12 @@ void Entity::SetPosition(const NiPoint3& position) {
|
|||||||
vehicel->SetPosition(position);
|
vehicel->SetPosition(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* rigidBodyPhantomPhysicsComponent = GetComponent<RigidbodyPhantomPhysicsComponent>();
|
||||||
|
|
||||||
|
if (rigidBodyPhantomPhysicsComponent != nullptr) {
|
||||||
|
rigidBodyPhantomPhysicsComponent->SetPosition(position);
|
||||||
|
}
|
||||||
|
|
||||||
Game::entityManager->SerializeEntity(this);
|
Game::entityManager->SerializeEntity(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1921,6 +1953,12 @@ void Entity::SetRotation(const NiQuaternion& rotation) {
|
|||||||
vehicel->SetRotation(rotation);
|
vehicel->SetRotation(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* rigidBodyPhantomPhysicsComponent = GetComponent<RigidbodyPhantomPhysicsComponent>();
|
||||||
|
|
||||||
|
if (rigidBodyPhantomPhysicsComponent != nullptr) {
|
||||||
|
rigidBodyPhantomPhysicsComponent->SetRotation(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
Game::entityManager->SerializeEntity(this);
|
Game::entityManager->SerializeEntity(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2106,6 +2144,8 @@ void Entity::ProcessPositionUpdate(PositionUpdate& update) {
|
|||||||
Game::entityManager->QueueGhostUpdate(GetObjectID());
|
Game::entityManager->QueueGhostUpdate(GetObjectID());
|
||||||
|
|
||||||
if (updateChar) Game::entityManager->SerializeEntity(this);
|
if (updateChar) Game::entityManager->SerializeEntity(this);
|
||||||
|
|
||||||
|
OnPlayerPositionUpdate.Notify(this, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
const SystemAddress& Entity::GetSystemAddress() const {
|
const SystemAddress& Entity::GetSystemAddress() const {
|
||||||
@@ -2127,7 +2167,19 @@ void Entity::SetRespawnPos(const NiPoint3& position) {
|
|||||||
auto* characterComponent = GetComponent<CharacterComponent>();
|
auto* characterComponent = GetComponent<CharacterComponent>();
|
||||||
if (characterComponent) characterComponent->SetRespawnPos(position);
|
if (characterComponent) characterComponent->SetRespawnPos(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::SetRespawnRot(const NiQuaternion& rotation) {
|
void Entity::SetRespawnRot(const NiQuaternion& rotation) {
|
||||||
auto* characterComponent = GetComponent<CharacterComponent>();
|
auto* characterComponent = GetComponent<CharacterComponent>();
|
||||||
if (characterComponent) characterComponent->SetRespawnRot(rotation);
|
if (characterComponent) characterComponent->SetRespawnRot(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t Entity::GetCollisionGroup() const {
|
||||||
|
for (const auto* component : m_Components | std::views::values) {
|
||||||
|
auto* compToCheck = dynamic_cast<const PhysicsComponent*>(component);
|
||||||
|
if (compToCheck) {
|
||||||
|
return compToCheck->GetCollisionGroup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "NiQuaternion.h"
|
#include "NiQuaternion.h"
|
||||||
#include "LDFFormat.h"
|
#include "LDFFormat.h"
|
||||||
#include "eKillType.h"
|
#include "eKillType.h"
|
||||||
|
#include "Observable.h"
|
||||||
|
|
||||||
namespace Loot {
|
namespace Loot {
|
||||||
class Info;
|
class Info;
|
||||||
@@ -106,6 +107,11 @@ public:
|
|||||||
|
|
||||||
const SystemAddress& GetSystemAddress() const;
|
const SystemAddress& GetSystemAddress() const;
|
||||||
|
|
||||||
|
// Returns the collision group for this entity.
|
||||||
|
// Because the collision group is stored on a base component, this will look for a physics component
|
||||||
|
// then return the collision group from that.
|
||||||
|
int32_t GetCollisionGroup() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setters
|
* Setters
|
||||||
*/
|
*/
|
||||||
@@ -174,7 +180,7 @@ public:
|
|||||||
|
|
||||||
void WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacketType packetType);
|
void WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacketType packetType);
|
||||||
void WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType packetType);
|
void WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType packetType);
|
||||||
void UpdateXMLDoc(tinyxml2::XMLDocument* doc);
|
void UpdateXMLDoc(tinyxml2::XMLDocument& doc);
|
||||||
void Update(float deltaTime);
|
void Update(float deltaTime);
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
@@ -299,6 +305,11 @@ public:
|
|||||||
// Scale will only be communicated to the client when the construction packet is sent
|
// Scale will only be communicated to the client when the construction packet is sent
|
||||||
void SetScale(const float scale) { m_Scale = scale; };
|
void SetScale(const float scale) { m_Scale = scale; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The observable for player entity position updates.
|
||||||
|
*/
|
||||||
|
static Observable<Entity*, const PositionUpdate&> OnPlayerPositionUpdate;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
LWOOBJID m_ObjectID;
|
LWOOBJID m_ObjectID;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "LeaderboardManager.h"
|
#include "LeaderboardManager.h"
|
||||||
|
|
||||||
|
#include <ranges>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -72,197 +73,191 @@ void Leaderboard::Serialize(RakNet::BitStream& bitStream) const {
|
|||||||
bitStream.Write0();
|
bitStream.Write0();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Leaderboard::QueryToLdf(std::unique_ptr<sql::ResultSet>& rows) {
|
// Takes the resulting query from a leaderboard lookup and converts it to the LDF we need
|
||||||
Clear();
|
// to send it to a client.
|
||||||
if (rows->rowsCount() == 0) return;
|
void QueryToLdf(Leaderboard& leaderboard, const std::vector<ILeaderboard::Entry>& leaderboardEntries) {
|
||||||
|
using enum Leaderboard::Type;
|
||||||
|
leaderboard.Clear();
|
||||||
|
if (leaderboardEntries.empty()) return;
|
||||||
|
|
||||||
this->entries.reserve(rows->rowsCount());
|
for (const auto& leaderboardEntry : leaderboardEntries) {
|
||||||
while (rows->next()) {
|
|
||||||
constexpr int32_t MAX_NUM_DATA_PER_ROW = 9;
|
constexpr int32_t MAX_NUM_DATA_PER_ROW = 9;
|
||||||
this->entries.push_back(std::vector<LDFBaseData*>());
|
auto& entry = leaderboard.PushBackEntry();
|
||||||
auto& entry = this->entries.back();
|
|
||||||
entry.reserve(MAX_NUM_DATA_PER_ROW);
|
entry.reserve(MAX_NUM_DATA_PER_ROW);
|
||||||
entry.push_back(new LDFData<uint64_t>(u"CharacterID", rows->getInt("character_id")));
|
entry.push_back(new LDFData<uint64_t>(u"CharacterID", leaderboardEntry.charId));
|
||||||
entry.push_back(new LDFData<uint64_t>(u"LastPlayed", rows->getUInt64("lastPlayed")));
|
entry.push_back(new LDFData<uint64_t>(u"LastPlayed", leaderboardEntry.lastPlayedTimestamp));
|
||||||
entry.push_back(new LDFData<int32_t>(u"NumPlayed", rows->getInt("timesPlayed")));
|
entry.push_back(new LDFData<int32_t>(u"NumPlayed", leaderboardEntry.numTimesPlayed));
|
||||||
entry.push_back(new LDFData<std::u16string>(u"name", GeneralUtils::ASCIIToUTF16(rows->getString("name").c_str())));
|
entry.push_back(new LDFData<std::u16string>(u"name", GeneralUtils::ASCIIToUTF16(leaderboardEntry.name)));
|
||||||
entry.push_back(new LDFData<uint64_t>(u"RowNumber", rows->getInt("ranking")));
|
entry.push_back(new LDFData<uint64_t>(u"RowNumber", leaderboardEntry.ranking));
|
||||||
switch (leaderboardType) {
|
switch (leaderboard.GetLeaderboardType()) {
|
||||||
case Type::ShootingGallery:
|
case ShootingGallery:
|
||||||
entry.push_back(new LDFData<int32_t>(u"Score", rows->getInt("primaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Score", leaderboardEntry.primaryScore));
|
||||||
// Score:1
|
// Score:1
|
||||||
entry.push_back(new LDFData<int32_t>(u"Streak", rows->getInt("secondaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Streak", leaderboardEntry.secondaryScore));
|
||||||
// Streak:1
|
// Streak:1
|
||||||
entry.push_back(new LDFData<float>(u"HitPercentage", (rows->getInt("tertiaryScore") / 100.0f)));
|
entry.push_back(new LDFData<float>(u"HitPercentage", (leaderboardEntry.tertiaryScore / 100.0f)));
|
||||||
// HitPercentage:3 between 0 and 1
|
// HitPercentage:3 between 0 and 1
|
||||||
break;
|
break;
|
||||||
case Type::Racing:
|
case Racing:
|
||||||
entry.push_back(new LDFData<float>(u"BestTime", rows->getDouble("primaryScore")));
|
entry.push_back(new LDFData<float>(u"BestTime", leaderboardEntry.primaryScore));
|
||||||
// BestLapTime:3
|
// BestLapTime:3
|
||||||
entry.push_back(new LDFData<float>(u"BestLapTime", rows->getDouble("secondaryScore")));
|
entry.push_back(new LDFData<float>(u"BestLapTime", leaderboardEntry.secondaryScore));
|
||||||
// BestTime:3
|
// BestTime:3
|
||||||
entry.push_back(new LDFData<int32_t>(u"License", 1));
|
entry.push_back(new LDFData<int32_t>(u"License", 1));
|
||||||
// License:1 - 1 if player has completed mission 637 and 0 otherwise
|
// License:1 - 1 if player has completed mission 637 and 0 otherwise
|
||||||
entry.push_back(new LDFData<int32_t>(u"NumWins", rows->getInt("numWins")));
|
entry.push_back(new LDFData<int32_t>(u"NumWins", leaderboardEntry.numWins));
|
||||||
// NumWins:1
|
// NumWins:1
|
||||||
break;
|
break;
|
||||||
case Type::UnusedLeaderboard4:
|
case UnusedLeaderboard4:
|
||||||
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Points", leaderboardEntry.primaryScore));
|
||||||
// Points:1
|
// Points:1
|
||||||
break;
|
break;
|
||||||
case Type::MonumentRace:
|
case MonumentRace:
|
||||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("primaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Time", leaderboardEntry.primaryScore));
|
||||||
// Time:1(?)
|
// Time:1(?)
|
||||||
break;
|
break;
|
||||||
case Type::FootRace:
|
case FootRace:
|
||||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("primaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Time", leaderboardEntry.primaryScore));
|
||||||
// Time:1
|
// Time:1
|
||||||
break;
|
break;
|
||||||
case Type::Survival:
|
case Survival:
|
||||||
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Points", leaderboardEntry.primaryScore));
|
||||||
// Points:1
|
// Points:1
|
||||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("secondaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Time", leaderboardEntry.secondaryScore));
|
||||||
// Time:1
|
// Time:1
|
||||||
break;
|
break;
|
||||||
case Type::SurvivalNS:
|
case SurvivalNS:
|
||||||
entry.push_back(new LDFData<int32_t>(u"Wave", rows->getInt("primaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Wave", leaderboardEntry.primaryScore));
|
||||||
// Wave:1
|
// Wave:1
|
||||||
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("secondaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Time", leaderboardEntry.secondaryScore));
|
||||||
// Time:1
|
// Time:1
|
||||||
break;
|
break;
|
||||||
case Type::Donations:
|
case Donations:
|
||||||
entry.push_back(new LDFData<int32_t>(u"Score", rows->getInt("primaryScore")));
|
entry.push_back(new LDFData<int32_t>(u"Score", leaderboardEntry.primaryScore));
|
||||||
// Score:1
|
// Score:1
|
||||||
break;
|
break;
|
||||||
case Type::None:
|
case None:
|
||||||
// This type is included here simply to resolve a compiler warning on mac about unused enum types
|
[[fallthrough]];
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string_view Leaderboard::GetOrdering(Leaderboard::Type leaderboardType) {
|
std::vector<ILeaderboard::Entry> FilterTo10(const std::vector<ILeaderboard::Entry>& leaderboard, const uint32_t relatedPlayer, const Leaderboard::InfoType infoType) {
|
||||||
// Use a switch case and return desc for all 3 columns if higher is better and asc if lower is better
|
std::vector<ILeaderboard::Entry> toReturn;
|
||||||
switch (leaderboardType) {
|
|
||||||
case Type::Racing:
|
int32_t index = 0;
|
||||||
case Type::MonumentRace:
|
// for friends and top, we dont need to find this players index.
|
||||||
return "primaryScore ASC, secondaryScore ASC, tertiaryScore ASC";
|
if (infoType == Leaderboard::InfoType::MyStanding || infoType == Leaderboard::InfoType::Friends) {
|
||||||
case Type::Survival:
|
for (; index < leaderboard.size(); index++) {
|
||||||
return Game::config->GetValue("classic_survival_scoring") == "1" ?
|
if (leaderboard[index].charId == relatedPlayer) break;
|
||||||
"secondaryScore DESC, primaryScore DESC, tertiaryScore DESC" :
|
}
|
||||||
"primaryScore DESC, secondaryScore DESC, tertiaryScore DESC";
|
|
||||||
case Type::SurvivalNS:
|
|
||||||
return "primaryScore DESC, secondaryScore ASC, tertiaryScore DESC";
|
|
||||||
case Type::ShootingGallery:
|
|
||||||
case Type::FootRace:
|
|
||||||
case Type::UnusedLeaderboard4:
|
|
||||||
case Type::Donations:
|
|
||||||
case Type::None:
|
|
||||||
default:
|
|
||||||
return "primaryScore DESC, secondaryScore DESC, tertiaryScore DESC";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (leaderboard.size() < 10) {
|
||||||
|
toReturn.assign(leaderboard.begin(), leaderboard.end());
|
||||||
|
index = 0;
|
||||||
|
} else if (index < 10) {
|
||||||
|
toReturn.assign(leaderboard.begin(), leaderboard.begin() + 10); // get the top 10 since we are in the top 10
|
||||||
|
index = 0;
|
||||||
|
} else if (index > leaderboard.size() - 10) {
|
||||||
|
toReturn.assign(leaderboard.end() - 10, leaderboard.end()); // get the bottom 10 since we are in the bottom 10
|
||||||
|
index = leaderboard.size() - 10;
|
||||||
|
} else {
|
||||||
|
toReturn.assign(leaderboard.begin() + index - 5, leaderboard.begin() + index + 5); // get the 5 above and below
|
||||||
|
index -= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t i = index;
|
||||||
|
for (auto& entry : toReturn) {
|
||||||
|
entry.ranking = ++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Leaderboard::SetupLeaderboard(bool weekly, uint32_t resultStart, uint32_t resultEnd) {
|
std::vector<ILeaderboard::Entry> FilterWeeklies(const std::vector<ILeaderboard::Entry>& leaderboard) {
|
||||||
resultStart++;
|
// Filter the leaderboard to only include entries from the last week
|
||||||
resultEnd++;
|
const auto currentTime = std::chrono::system_clock::now();
|
||||||
// We need everything except 1 column so i'm selecting * from leaderboard
|
auto epochTime = currentTime.time_since_epoch().count();
|
||||||
const std::string queryBase =
|
constexpr auto SECONDS_IN_A_WEEK = 60 * 60 * 24 * 7; // if you think im taking leap seconds into account thats cute.
|
||||||
R"QUERY(
|
|
||||||
WITH leaderboardsRanked AS (
|
|
||||||
SELECT leaderboard.*, charinfo.name,
|
|
||||||
RANK() OVER
|
|
||||||
(
|
|
||||||
ORDER BY %s, UNIX_TIMESTAMP(last_played) ASC, id DESC
|
|
||||||
) AS ranking
|
|
||||||
FROM leaderboard JOIN charinfo on charinfo.id = leaderboard.character_id
|
|
||||||
WHERE game_id = ? %s
|
|
||||||
),
|
|
||||||
myStanding AS (
|
|
||||||
SELECT
|
|
||||||
ranking as myRank
|
|
||||||
FROM leaderboardsRanked
|
|
||||||
WHERE id = ?
|
|
||||||
),
|
|
||||||
lowestRanking AS (
|
|
||||||
SELECT MAX(ranking) AS lowestRank
|
|
||||||
FROM leaderboardsRanked
|
|
||||||
)
|
|
||||||
SELECT leaderboardsRanked.*, character_id, UNIX_TIMESTAMP(last_played) as lastPlayed, leaderboardsRanked.name, leaderboardsRanked.ranking FROM leaderboardsRanked, myStanding, lowestRanking
|
|
||||||
WHERE leaderboardsRanked.ranking
|
|
||||||
BETWEEN
|
|
||||||
LEAST(GREATEST(CAST(myRank AS SIGNED) - 5, %i), CAST(lowestRanking.lowestRank AS SIGNED) - 9)
|
|
||||||
AND
|
|
||||||
LEAST(GREATEST(myRank + 5, %i), lowestRanking.lowestRank)
|
|
||||||
ORDER BY ranking ASC;
|
|
||||||
)QUERY";
|
|
||||||
|
|
||||||
std::string friendsFilter =
|
std::vector<ILeaderboard::Entry> weeklyLeaderboard;
|
||||||
R"QUERY(
|
for (const auto& entry : leaderboard) {
|
||||||
AND (
|
if (epochTime - entry.lastPlayedTimestamp < SECONDS_IN_A_WEEK) {
|
||||||
character_id IN (
|
weeklyLeaderboard.push_back(entry);
|
||||||
SELECT fr.requested_player FROM (
|
}
|
||||||
SELECT CASE
|
|
||||||
WHEN player_id = ? THEN friend_id
|
|
||||||
WHEN friend_id = ? THEN player_id
|
|
||||||
END AS requested_player
|
|
||||||
FROM friends
|
|
||||||
) AS fr
|
|
||||||
JOIN charinfo AS ci
|
|
||||||
ON ci.id = fr.requested_player
|
|
||||||
WHERE fr.requested_player IS NOT NULL
|
|
||||||
)
|
|
||||||
OR character_id = ?
|
|
||||||
)
|
|
||||||
)QUERY";
|
|
||||||
|
|
||||||
std::string weeklyFilter = " AND UNIX_TIMESTAMP(last_played) BETWEEN UNIX_TIMESTAMP(date_sub(now(),INTERVAL 1 WEEK)) AND UNIX_TIMESTAMP(now()) ";
|
|
||||||
|
|
||||||
std::string filter;
|
|
||||||
// Setup our filter based on the query type
|
|
||||||
if (this->infoType == InfoType::Friends) filter += friendsFilter;
|
|
||||||
if (this->weekly) filter += weeklyFilter;
|
|
||||||
const auto orderBase = GetOrdering(this->leaderboardType);
|
|
||||||
|
|
||||||
// For top query, we want to just rank all scores, but for all others we need the scores around a specific player
|
|
||||||
std::string baseLookup;
|
|
||||||
if (this->infoType == InfoType::Top) {
|
|
||||||
baseLookup = "SELECT id, last_played FROM leaderboard WHERE game_id = ? " + (this->weekly ? weeklyFilter : std::string("")) + " ORDER BY ";
|
|
||||||
baseLookup += orderBase.data();
|
|
||||||
} else {
|
|
||||||
baseLookup = "SELECT id, last_played FROM leaderboard WHERE game_id = ? " + (this->weekly ? weeklyFilter : std::string("")) + " AND character_id = ";
|
|
||||||
baseLookup += std::to_string(static_cast<uint32_t>(this->relatedPlayer));
|
|
||||||
}
|
}
|
||||||
baseLookup += " LIMIT 1";
|
|
||||||
LOG_DEBUG("query is %s", baseLookup.c_str());
|
|
||||||
std::unique_ptr<sql::PreparedStatement> baseQuery(Database::Get()->CreatePreppedStmt(baseLookup));
|
|
||||||
baseQuery->setInt(1, this->gameID);
|
|
||||||
std::unique_ptr<sql::ResultSet> baseResult(baseQuery->executeQuery());
|
|
||||||
|
|
||||||
if (!baseResult->next()) return; // In this case, there are no entries in the leaderboard for this game.
|
return weeklyLeaderboard;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t relatedPlayerLeaderboardId = baseResult->getInt("id");
|
std::vector<ILeaderboard::Entry> FilterFriends(const std::vector<ILeaderboard::Entry>& leaderboard, const uint32_t relatedPlayer) {
|
||||||
|
// Filter the leaderboard to only include friends of the player
|
||||||
// Create and execute the actual save here. Using a heap allocated buffer to avoid stack overflow
|
auto friendOfPlayer = Database::Get()->GetFriendsList(relatedPlayer);
|
||||||
constexpr uint16_t STRING_LENGTH = 4096;
|
std::vector<ILeaderboard::Entry> friendsLeaderboard;
|
||||||
std::unique_ptr<char[]> lookupBuffer = std::make_unique<char[]>(STRING_LENGTH);
|
for (const auto& entry : leaderboard) {
|
||||||
int32_t res = snprintf(lookupBuffer.get(), STRING_LENGTH, queryBase.c_str(), orderBase.data(), filter.c_str(), resultStart, resultEnd);
|
const auto res = std::ranges::find_if(friendOfPlayer, [&entry, relatedPlayer](const FriendData& data) {
|
||||||
DluAssert(res != -1);
|
return entry.charId == data.friendID || entry.charId == relatedPlayer;
|
||||||
std::unique_ptr<sql::PreparedStatement> query(Database::Get()->CreatePreppedStmt(lookupBuffer.get()));
|
});
|
||||||
LOG_DEBUG("Query is %s vars are %i %i %i", lookupBuffer.get(), this->gameID, this->relatedPlayer, relatedPlayerLeaderboardId);
|
if (res != friendOfPlayer.cend()) {
|
||||||
query->setInt(1, this->gameID);
|
friendsLeaderboard.push_back(entry);
|
||||||
if (this->infoType == InfoType::Friends) {
|
}
|
||||||
query->setInt(2, this->relatedPlayer);
|
|
||||||
query->setInt(3, this->relatedPlayer);
|
|
||||||
query->setInt(4, this->relatedPlayer);
|
|
||||||
query->setInt(5, relatedPlayerLeaderboardId);
|
|
||||||
} else {
|
|
||||||
query->setInt(2, relatedPlayerLeaderboardId);
|
|
||||||
}
|
}
|
||||||
std::unique_ptr<sql::ResultSet> result(query->executeQuery());
|
|
||||||
QueryToLdf(result);
|
return friendsLeaderboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ILeaderboard::Entry> ProcessLeaderboard(
|
||||||
|
const std::vector<ILeaderboard::Entry>& leaderboard,
|
||||||
|
const bool weekly,
|
||||||
|
const Leaderboard::InfoType infoType,
|
||||||
|
const uint32_t relatedPlayer) {
|
||||||
|
std::vector<ILeaderboard::Entry> toReturn;
|
||||||
|
|
||||||
|
if (infoType == Leaderboard::InfoType::Friends) {
|
||||||
|
const auto friendsLeaderboard = FilterFriends(leaderboard, relatedPlayer);
|
||||||
|
toReturn = FilterTo10(weekly ? FilterWeeklies(friendsLeaderboard) : friendsLeaderboard, relatedPlayer, infoType);
|
||||||
|
} else {
|
||||||
|
toReturn = FilterTo10(weekly ? FilterWeeklies(leaderboard) : leaderboard, relatedPlayer, infoType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Leaderboard::SetupLeaderboard(bool weekly) {
|
||||||
|
const auto leaderboardType = LeaderboardManager::GetLeaderboardType(gameID);
|
||||||
|
std::vector<ILeaderboard::Entry> leaderboardRes;
|
||||||
|
|
||||||
|
switch (leaderboardType) {
|
||||||
|
case Type::SurvivalNS:
|
||||||
|
leaderboardRes = Database::Get()->GetNsLeaderboard(gameID);
|
||||||
|
break;
|
||||||
|
case Type::Survival:
|
||||||
|
leaderboardRes = Database::Get()->GetAgsLeaderboard(gameID);
|
||||||
|
break;
|
||||||
|
case Type::Racing:
|
||||||
|
[[fallthrough]];
|
||||||
|
case Type::MonumentRace:
|
||||||
|
leaderboardRes = Database::Get()->GetAscendingLeaderboard(gameID);
|
||||||
|
break;
|
||||||
|
case Type::ShootingGallery:
|
||||||
|
[[fallthrough]];
|
||||||
|
case Type::FootRace:
|
||||||
|
[[fallthrough]];
|
||||||
|
case Type::Donations:
|
||||||
|
[[fallthrough]];
|
||||||
|
case Type::None:
|
||||||
|
[[fallthrough]];
|
||||||
|
default:
|
||||||
|
leaderboardRes = Database::Get()->GetDescendingLeaderboard(gameID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto processedLeaderboard = ProcessLeaderboard(leaderboardRes, weekly, infoType, relatedPlayer);
|
||||||
|
|
||||||
|
QueryToLdf(*this, processedLeaderboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Leaderboard::Send(const LWOOBJID targetID) const {
|
void Leaderboard::Send(const LWOOBJID targetID) const {
|
||||||
@@ -272,129 +267,43 @@ void Leaderboard::Send(const LWOOBJID targetID) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FormatInsert(const Leaderboard::Type& type, const Score& score, const bool useUpdate) {
|
|
||||||
std::string insertStatement;
|
|
||||||
if (useUpdate) {
|
|
||||||
insertStatement =
|
|
||||||
R"QUERY(
|
|
||||||
UPDATE leaderboard
|
|
||||||
SET primaryScore = %f, secondaryScore = %f, tertiaryScore = %f,
|
|
||||||
timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;
|
|
||||||
)QUERY";
|
|
||||||
} else {
|
|
||||||
insertStatement =
|
|
||||||
R"QUERY(
|
|
||||||
INSERT leaderboard SET
|
|
||||||
primaryScore = %f, secondaryScore = %f, tertiaryScore = %f,
|
|
||||||
character_id = ?, game_id = ?;
|
|
||||||
)QUERY";
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr uint16_t STRING_LENGTH = 400;
|
|
||||||
// Then fill in our score
|
|
||||||
char finishedQuery[STRING_LENGTH];
|
|
||||||
int32_t res = snprintf(finishedQuery, STRING_LENGTH, insertStatement.c_str(), score.GetPrimaryScore(), score.GetSecondaryScore(), score.GetTertiaryScore());
|
|
||||||
DluAssert(res != -1);
|
|
||||||
return finishedQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID activityId, const float primaryScore, const float secondaryScore, const float tertiaryScore) {
|
void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID activityId, const float primaryScore, const float secondaryScore, const float tertiaryScore) {
|
||||||
const Leaderboard::Type leaderboardType = GetLeaderboardType(activityId);
|
const Leaderboard::Type leaderboardType = GetLeaderboardType(activityId);
|
||||||
|
|
||||||
std::unique_ptr<sql::PreparedStatement> query(Database::Get()->CreatePreppedStmt("SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;"));
|
const auto oldScore = Database::Get()->GetPlayerScore(playerID, activityId);
|
||||||
query->setInt(1, playerID);
|
|
||||||
query->setInt(2, activityId);
|
|
||||||
std::unique_ptr<sql::ResultSet> myScoreResult(query->executeQuery());
|
|
||||||
|
|
||||||
std::string saveQuery("UPDATE leaderboard SET timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;");
|
ILeaderboard::Score newScore{ .primaryScore = primaryScore, .secondaryScore = secondaryScore, .tertiaryScore = tertiaryScore };
|
||||||
Score newScore(primaryScore, secondaryScore, tertiaryScore);
|
if (oldScore.has_value()) {
|
||||||
if (myScoreResult->next()) {
|
bool lowerScoreBetter = leaderboardType == Leaderboard::Type::Racing || leaderboardType == Leaderboard::Type::MonumentRace;
|
||||||
Score oldScore;
|
|
||||||
bool lowerScoreBetter = false;
|
|
||||||
switch (leaderboardType) {
|
|
||||||
// Higher score better
|
|
||||||
case Leaderboard::Type::ShootingGallery: {
|
|
||||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
|
||||||
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
|
|
||||||
oldScore.SetTertiaryScore(myScoreResult->getInt("tertiaryScore"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Leaderboard::Type::FootRace: {
|
|
||||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Leaderboard::Type::Survival: {
|
|
||||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
|
||||||
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Leaderboard::Type::SurvivalNS: {
|
|
||||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
|
||||||
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Leaderboard::Type::UnusedLeaderboard4:
|
|
||||||
case Leaderboard::Type::Donations: {
|
|
||||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
|
||||||
newScore.SetPrimaryScore(oldScore.GetPrimaryScore() + newScore.GetPrimaryScore());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Leaderboard::Type::Racing: {
|
|
||||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
|
||||||
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
|
|
||||||
|
|
||||||
// For wins we dont care about the score, just the time, so zero out the tertiary.
|
|
||||||
// Wins are updated later.
|
|
||||||
oldScore.SetTertiaryScore(0);
|
|
||||||
newScore.SetTertiaryScore(0);
|
|
||||||
lowerScoreBetter = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Leaderboard::Type::MonumentRace: {
|
|
||||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
|
||||||
lowerScoreBetter = true;
|
|
||||||
// Do score checking here
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Leaderboard::Type::None:
|
|
||||||
default:
|
|
||||||
LOG("Unknown leaderboard type %i for game %i. Cannot save score!", leaderboardType, activityId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool newHighScore = lowerScoreBetter ? newScore < oldScore : newScore > oldScore;
|
bool newHighScore = lowerScoreBetter ? newScore < oldScore : newScore > oldScore;
|
||||||
// Nimbus station has a weird leaderboard where we need a custom scoring system
|
// Nimbus station has a weird leaderboard where we need a custom scoring system
|
||||||
if (leaderboardType == Leaderboard::Type::SurvivalNS) {
|
if (leaderboardType == Leaderboard::Type::SurvivalNS) {
|
||||||
newHighScore = newScore.GetPrimaryScore() > oldScore.GetPrimaryScore() ||
|
newHighScore = newScore.primaryScore > oldScore->primaryScore ||
|
||||||
(newScore.GetPrimaryScore() == oldScore.GetPrimaryScore() && newScore.GetSecondaryScore() < oldScore.GetSecondaryScore());
|
(newScore.primaryScore == oldScore->primaryScore && newScore.secondaryScore < oldScore->secondaryScore);
|
||||||
} else if (leaderboardType == Leaderboard::Type::Survival && Game::config->GetValue("classic_survival_scoring") == "1") {
|
} else if (leaderboardType == Leaderboard::Type::Survival && Game::config->GetValue("classic_survival_scoring") == "1") {
|
||||||
Score oldScoreFlipped(oldScore.GetSecondaryScore(), oldScore.GetPrimaryScore());
|
ILeaderboard::Score oldScoreFlipped{oldScore->secondaryScore, oldScore->primaryScore, oldScore->tertiaryScore};
|
||||||
Score newScoreFlipped(newScore.GetSecondaryScore(), newScore.GetPrimaryScore());
|
ILeaderboard::Score newScoreFlipped{newScore.secondaryScore, newScore.primaryScore, newScore.tertiaryScore};
|
||||||
newHighScore = newScoreFlipped > oldScoreFlipped;
|
newHighScore = newScoreFlipped > oldScoreFlipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newHighScore) {
|
if (newHighScore) {
|
||||||
saveQuery = FormatInsert(leaderboardType, newScore, true);
|
Database::Get()->UpdateScore(playerID, activityId, newScore);
|
||||||
|
} else {
|
||||||
|
Database::Get()->IncrementTimesPlayed(playerID, activityId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
saveQuery = FormatInsert(leaderboardType, newScore, false);
|
Database::Get()->SaveScore(playerID, activityId, newScore);
|
||||||
}
|
}
|
||||||
LOG("save query %s %i %i", saveQuery.c_str(), playerID, activityId);
|
|
||||||
std::unique_ptr<sql::PreparedStatement> saveStatement(Database::Get()->CreatePreppedStmt(saveQuery));
|
|
||||||
saveStatement->setInt(1, playerID);
|
|
||||||
saveStatement->setInt(2, activityId);
|
|
||||||
saveStatement->execute();
|
|
||||||
|
|
||||||
// track wins separately
|
// track wins separately
|
||||||
if (leaderboardType == Leaderboard::Type::Racing && tertiaryScore != 0.0f) {
|
if (leaderboardType == Leaderboard::Type::Racing && tertiaryScore != 0.0f) {
|
||||||
std::unique_ptr<sql::PreparedStatement> winUpdate(Database::Get()->CreatePreppedStmt("UPDATE leaderboard SET numWins = numWins + 1 WHERE character_id = ? AND game_id = ?;"));
|
Database::Get()->IncrementNumWins(playerID, activityId);
|
||||||
winUpdate->setInt(1, playerID);
|
|
||||||
winUpdate->setInt(2, activityId);
|
|
||||||
winUpdate->execute();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaderboardManager::SendLeaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID, const LWOOBJID targetID, const uint32_t resultStart, const uint32_t resultEnd) {
|
void LeaderboardManager::SendLeaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID, const LWOOBJID targetID) {
|
||||||
Leaderboard leaderboard(gameID, infoType, weekly, playerID, GetLeaderboardType(gameID));
|
Leaderboard leaderboard(gameID, infoType, weekly, playerID, GetLeaderboardType(gameID));
|
||||||
leaderboard.SetupLeaderboard(weekly, resultStart, resultEnd);
|
leaderboard.SetupLeaderboard(weekly);
|
||||||
leaderboard.Send(targetID);
|
leaderboard.Send(targetID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,46 +9,10 @@
|
|||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
#include "LDFFormat.h"
|
#include "LDFFormat.h"
|
||||||
|
|
||||||
namespace sql {
|
|
||||||
class ResultSet;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace RakNet {
|
namespace RakNet {
|
||||||
class BitStream;
|
class BitStream;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Score {
|
|
||||||
public:
|
|
||||||
Score() {
|
|
||||||
primaryScore = 0;
|
|
||||||
secondaryScore = 0;
|
|
||||||
tertiaryScore = 0;
|
|
||||||
}
|
|
||||||
Score(const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0) {
|
|
||||||
this->primaryScore = primaryScore;
|
|
||||||
this->secondaryScore = secondaryScore;
|
|
||||||
this->tertiaryScore = tertiaryScore;
|
|
||||||
}
|
|
||||||
bool operator<(const Score& rhs) const {
|
|
||||||
return primaryScore < rhs.primaryScore || (primaryScore == rhs.primaryScore && secondaryScore < rhs.secondaryScore) || (primaryScore == rhs.primaryScore && secondaryScore == rhs.secondaryScore && tertiaryScore < rhs.tertiaryScore);
|
|
||||||
}
|
|
||||||
bool operator>(const Score& rhs) const {
|
|
||||||
return primaryScore > rhs.primaryScore || (primaryScore == rhs.primaryScore && secondaryScore > rhs.secondaryScore) || (primaryScore == rhs.primaryScore && secondaryScore == rhs.secondaryScore && tertiaryScore > rhs.tertiaryScore);
|
|
||||||
}
|
|
||||||
void SetPrimaryScore(const float score) { primaryScore = score; }
|
|
||||||
float GetPrimaryScore() const { return primaryScore; }
|
|
||||||
|
|
||||||
void SetSecondaryScore(const float score) { secondaryScore = score; }
|
|
||||||
float GetSecondaryScore() const { return secondaryScore; }
|
|
||||||
|
|
||||||
void SetTertiaryScore(const float score) { tertiaryScore = score; }
|
|
||||||
float GetTertiaryScore() const { return tertiaryScore; }
|
|
||||||
private:
|
|
||||||
float primaryScore;
|
|
||||||
float secondaryScore;
|
|
||||||
float tertiaryScore;
|
|
||||||
};
|
|
||||||
|
|
||||||
using GameID = uint32_t;
|
using GameID = uint32_t;
|
||||||
|
|
||||||
class Leaderboard {
|
class Leaderboard {
|
||||||
@@ -96,20 +60,16 @@ public:
|
|||||||
* @param resultStart The index to start the leaderboard at. Zero indexed.
|
* @param resultStart The index to start the leaderboard at. Zero indexed.
|
||||||
* @param resultEnd The index to end the leaderboard at. Zero indexed.
|
* @param resultEnd The index to end the leaderboard at. Zero indexed.
|
||||||
*/
|
*/
|
||||||
void SetupLeaderboard(bool weekly, uint32_t resultStart = 0, uint32_t resultEnd = 10);
|
void SetupLeaderboard(bool weekly);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends the leaderboard to the client specified by targetID.
|
* Sends the leaderboard to the client specified by targetID.
|
||||||
*/
|
*/
|
||||||
void Send(const LWOOBJID targetID) const;
|
void Send(const LWOOBJID targetID) const;
|
||||||
|
|
||||||
// Helper function to get the columns, ordering and insert format for a leaderboard
|
|
||||||
static const std::string_view GetOrdering(Type leaderboardType);
|
|
||||||
private:
|
|
||||||
// Takes the resulting query from a leaderboard lookup and converts it to the LDF we need
|
|
||||||
// to send it to a client.
|
|
||||||
void QueryToLdf(std::unique_ptr<sql::ResultSet>& rows);
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
using LeaderboardEntry = std::vector<LDFBaseData*>;
|
using LeaderboardEntry = std::vector<LDFBaseData*>;
|
||||||
using LeaderboardEntries = std::vector<LeaderboardEntry>;
|
using LeaderboardEntries = std::vector<LeaderboardEntry>;
|
||||||
|
|
||||||
@@ -119,10 +79,18 @@ private:
|
|||||||
InfoType infoType;
|
InfoType infoType;
|
||||||
Leaderboard::Type leaderboardType;
|
Leaderboard::Type leaderboardType;
|
||||||
bool weekly;
|
bool weekly;
|
||||||
|
public:
|
||||||
|
LeaderboardEntry& PushBackEntry() {
|
||||||
|
return entries.emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type GetLeaderboardType() const {
|
||||||
|
return leaderboardType;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace LeaderboardManager {
|
namespace LeaderboardManager {
|
||||||
void SendLeaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID, const LWOOBJID targetID, const uint32_t resultStart = 0, const uint32_t resultEnd = 10);
|
void SendLeaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID, const LWOOBJID targetID);
|
||||||
|
|
||||||
void SaveScore(const LWOOBJID& playerID, const GameID activityId, const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0);
|
void SaveScore(const LWOOBJID& playerID, const GameID activityId, const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std:
|
|||||||
m_AccountID = 0;
|
m_AccountID = 0;
|
||||||
m_Username = "";
|
m_Username = "";
|
||||||
m_SessionKey = "";
|
m_SessionKey = "";
|
||||||
|
m_MuteExpire = 0;
|
||||||
|
|
||||||
m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters
|
m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters
|
||||||
m_LastCharID = 0;
|
m_LastCharID = 0;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public:
|
|||||||
User& operator=(const User& other);
|
User& operator=(const User& other);
|
||||||
bool operator==(const User& other) const;
|
bool operator==(const User& other) const;
|
||||||
|
|
||||||
uint32_t GetAccountID() { return m_AccountID; }
|
uint32_t GetAccountID() const noexcept { return m_AccountID; }
|
||||||
std::string& GetUsername() { return m_Username; }
|
std::string& GetUsername() { return m_Username; }
|
||||||
std::string& GetSessionKey() { return m_SessionKey; }
|
std::string& GetSessionKey() { return m_SessionKey; }
|
||||||
SystemAddress& GetSystemAddress() { return m_SystemAddress; }
|
SystemAddress& GetSystemAddress() { return m_SystemAddress; }
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "eCharacterCreationResponse.h"
|
#include "eCharacterCreationResponse.h"
|
||||||
#include "eRenameResponse.h"
|
#include "eRenameResponse.h"
|
||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "eChatInternalMessageType.h"
|
#include "MessageType/Chat.h"
|
||||||
#include "BitStreamUtils.h"
|
#include "BitStreamUtils.h"
|
||||||
#include "CheatDetection.h"
|
#include "CheatDetection.h"
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ void UserManager::Initialize() {
|
|||||||
auto chatListStream = Game::assetManager->GetFile("chatplus_en_us.txt");
|
auto chatListStream = Game::assetManager->GetFile("chatplus_en_us.txt");
|
||||||
if (!chatListStream) {
|
if (!chatListStream) {
|
||||||
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str());
|
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str());
|
||||||
throw std::runtime_error("Aborting initialization due to missing chat whitelist file.");
|
throw std::runtime_error("Aborting initialization due to missing chat allowlist file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (std::getline(chatListStream, line, '\n')) {
|
while (std::getline(chatListStream, line, '\n')) {
|
||||||
@@ -216,7 +216,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RakNet::BitStream bitStream;
|
RakNet::BitStream bitStream;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_LIST_RESPONSE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::CHARACTER_LIST_RESPONSE);
|
||||||
|
|
||||||
std::vector<Character*> characters = u->GetCharacters();
|
std::vector<Character*> characters = u->GetCharacters();
|
||||||
bitStream.Write<uint8_t>(characters.size());
|
bitStream.Write<uint8_t>(characters.size());
|
||||||
@@ -422,7 +422,7 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
|
|||||||
Database::Get()->DeleteCharacter(charID);
|
Database::Get()->DeleteCharacter(charID);
|
||||||
|
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::UNEXPECTED_DISCONNECT);
|
||||||
bitStream.Write(objectID);
|
bitStream.Write(objectID);
|
||||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||||
|
|
||||||
@@ -536,13 +536,13 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
|
|||||||
uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
||||||
try {
|
try {
|
||||||
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
||||||
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?"
|
"select obj.id as objectId from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?"
|
||||||
);
|
);
|
||||||
stmt.bind(1, "character create shirt");
|
stmt.bind(1, "character create shirt");
|
||||||
stmt.bind(2, static_cast<int>(shirtColor));
|
stmt.bind(2, static_cast<int>(shirtColor));
|
||||||
stmt.bind(3, static_cast<int>(shirtStyle));
|
stmt.bind(3, static_cast<int>(shirtStyle));
|
||||||
auto tableData = stmt.execQuery();
|
auto tableData = stmt.execQuery();
|
||||||
auto shirtLOT = tableData.getIntField(0, 4069);
|
auto shirtLOT = tableData.getIntField("objectId", 4069);
|
||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
return shirtLOT;
|
return shirtLOT;
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
@@ -555,12 +555,12 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
|||||||
uint32_t FindCharPantsID(uint32_t pantsColor) {
|
uint32_t FindCharPantsID(uint32_t pantsColor) {
|
||||||
try {
|
try {
|
||||||
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
||||||
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?"
|
"select obj.id as objectId from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?"
|
||||||
);
|
);
|
||||||
stmt.bind(1, "cc pants");
|
stmt.bind(1, "cc pants");
|
||||||
stmt.bind(2, static_cast<int>(pantsColor));
|
stmt.bind(2, static_cast<int>(pantsColor));
|
||||||
auto tableData = stmt.execQuery();
|
auto tableData = stmt.execQuery();
|
||||||
auto pantsLOT = tableData.getIntField(0, 2508);
|
auto pantsLOT = tableData.getIntField("objectId", 2508);
|
||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
return pantsLOT;
|
return pantsLOT;
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user