mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-16 20:24:39 -06:00
Compare commits
282 Commits
movingPlat
...
v3.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
306d959a83 | ||
|
|
e4c2eecbc7 | ||
|
|
1b3cdc6d9c | ||
|
|
d860552776 | ||
|
|
b0d993de33 | ||
|
|
dc602a94eb | ||
| 3faf9eea45 | |||
| 9542216650 | |||
| 5b8fe2cba0 | |||
|
|
f4b55915bc | ||
|
|
a0913ff23d | ||
|
|
b738504812 | ||
|
|
c968dc9028 | ||
|
|
2209a4432f | ||
|
|
c855a6b9cf | ||
|
|
8abc545bd1 | ||
|
|
136133dde2 | ||
|
|
23551d4ed8 | ||
|
|
7599a2e81e | ||
| 72ae55981b | |||
|
|
c31bf3fad4 | ||
| 0aa1be01d2 | |||
| d8172e2126 | |||
| 88376c233c | |||
| f3b4143698 | |||
| 55a1209c75 | |||
| a6c6d892cf | |||
| f7228a6495 | |||
|
|
fb32534ae3 | ||
|
|
c8fcb3788d | ||
| 7a99e8ee6b | |||
| a5e8fd86ac | |||
| 210bc48149 | |||
|
|
e757086465 | ||
|
|
915e9f75d1 | ||
|
|
e9ee3e21cf | ||
| deddf0f256 | |||
|
|
ca38139ff5 | ||
| 41a001e242 | |||
| 4e57b4aa7e | |||
|
|
86b419735b | ||
|
|
631980af3a | ||
|
|
9e16e01b8d | ||
|
|
6e66c5c362 | ||
| ee590c49c1 | |||
| 7aaa69e42d | |||
| 181bb0ce14 | |||
| 2b325165aa | |||
| 94d53fa77c | |||
| 846ba894a4 | |||
| 2ce2f4e363 | |||
| fd1ce75380 | |||
| 3578076eca | |||
| 7d06d012b5 | |||
| 126701b5fe | |||
| 2d08ec641c | |||
| 9387a8e3d1 | |||
| e86f4e011b | |||
| 070bec697c | |||
|
|
9936bb0d00 | ||
|
|
beffad42ea | ||
|
|
3ecbd1013b | ||
|
|
ff4546c027 | ||
|
|
71baa5ce90 | ||
|
|
5ccd15a7d8 | ||
|
|
35bcaf6e95 | ||
|
|
900c9b6abe | ||
|
|
94e7cfc211 | ||
|
|
021db0ecd1 | ||
|
|
0b261e934f | ||
|
|
1b9f7e44c7 | ||
|
|
08a168de88 | ||
|
|
0c948a8df6 | ||
|
|
6ed6efa921 | ||
|
|
dcc9e023a6 | ||
|
|
8509ec8856 | ||
|
|
18295017c1 | ||
|
|
e8f011b830 | ||
|
|
a787673baf | ||
|
|
e869c0ad03 | ||
|
|
b2af3fa9d4 | ||
|
|
2560bb00da | ||
|
|
1ae21c423f | ||
|
|
0ae9eb4a96 | ||
|
|
fced6d753a | ||
|
|
15dc5feeb5 | ||
|
|
a60865cd19 | ||
|
|
77b42daca1 | ||
|
|
ba364800fe | ||
|
|
e1c20192f7 | ||
|
|
0f8c5b436d | ||
| 53242ad5d5 | |||
|
|
a8919c8c14 | ||
|
|
5ff121612e | ||
| 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 | ||
|
|
35ce8771e5 | ||
|
|
b9092a3cce | ||
|
|
0b4f70a76b | ||
|
|
4bc4624bc9 | ||
|
|
3a6313a3ba | ||
|
|
6e3b5acede | ||
|
|
fe4b29f643 | ||
|
|
fcb89b3c7a | ||
|
|
1a0aaf3123 | ||
|
|
9a26ba0a72 | ||
|
|
6c9c826e19 | ||
|
|
554a9a6806 | ||
| c4c1e93dc8 | |||
|
|
15504e693b | ||
|
|
7d626dc31b | ||
|
|
6df6e3e313 | ||
|
|
4ffdf851c6 | ||
| 43707952d2 | |||
|
|
ef3fdba621 | ||
| 398426545c | |||
|
|
366a80ffd2 | ||
|
|
c9a8be4fb9 | ||
|
|
424d54b98c | ||
|
|
b261e63233 | ||
|
|
75544e3eec | ||
|
|
9e0dd05d42 | ||
|
|
27d20dd8fa | ||
|
|
4b0079c817 | ||
|
|
30b9ef8ab2 | ||
|
|
7235423c7b | ||
|
|
94a467b361 | ||
|
|
c3743877df | ||
|
|
ab937055e7 | ||
|
|
5c1ed332c4 | ||
|
|
95d687846a | ||
| 192c8cf974 | |||
|
|
cf706d4974 | ||
| e729c7f846 | |||
|
|
1328850a8d | ||
|
|
721ea78bb4 | ||
|
|
5ae8fd8e0e | ||
|
|
f38537aece | ||
|
|
b6af92ef81 |
@@ -73,4 +73,4 @@ cpp_space_around_assignment_operator=insert
|
||||
cpp_space_pointer_reference_alignment=left
|
||||
cpp_space_around_ternary_operator=insert
|
||||
cpp_wrap_preserve_blocks=one_liners
|
||||
cpp_indent_comment=fasle
|
||||
cpp_indent_comment=false
|
||||
|
||||
10
.env.example
10
.env.example
@@ -3,12 +3,20 @@ CLIENT_PATH=./client
|
||||
# Updates NET_VERSION in CMakeVariables.txt
|
||||
NET_VERSION=171022
|
||||
# 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=
|
||||
# Should be the externally facing IP of your server host
|
||||
EXTERNAL_IP=localhost
|
||||
|
||||
# The database type that will be used.
|
||||
# Acceptable values are `sqlite`, `mysql`, `mariadb`, `maria`.
|
||||
# Case insensitive.
|
||||
DATABASE_TYPE=mariadb
|
||||
SQLITE_DATABASE_PATH=resServer/dlu.sqlite
|
||||
|
||||
# Database values
|
||||
# Be careful with special characters here. It is more safe to use normal characters and/or numbers.
|
||||
MARIADB_USER=darkflame
|
||||
MARIADB_PASSWORD=
|
||||
MARIADB_DATABASE=darkflame
|
||||
SKIP_ACCOUNT_CREATION=1
|
||||
|
||||
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 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Add msbuild to PATH (Windows only)
|
||||
if: ${{ matrix.os == 'windows-2022' }}
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
with:
|
||||
vs-version: '[17,18)'
|
||||
msbuild-architecture: x64
|
||||
@@ -33,21 +33,20 @@ jobs:
|
||||
- name: cmake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
configurePreset: "ci-${{matrix.os}}"
|
||||
buildPreset: "ci-${{matrix.os}}"
|
||||
testPreset: "ci-${{matrix.os}}"
|
||||
workflowPreset: "ci-${{matrix.os}}"
|
||||
- name: artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-${{matrix.os}}
|
||||
path: |
|
||||
build/*Server*
|
||||
build/*.ini
|
||||
build/*.so
|
||||
build/*.dll
|
||||
build/vanity/
|
||||
build/navmeshes/
|
||||
build/migrations/
|
||||
build/*.dcf
|
||||
!build/*.pdb
|
||||
!build/d*/
|
||||
build/*/*Server*
|
||||
build/*/*.ini
|
||||
build/*/*.so
|
||||
build/*/*.dll
|
||||
build/*/*.dylib
|
||||
build/*/vanity/
|
||||
build/*/navmeshes/
|
||||
build/*/migrations/
|
||||
build/*/*.dcf
|
||||
!build/*/*.pdb
|
||||
!build/*/d*/
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -6,7 +6,6 @@ docker/configs
|
||||
# Third party libraries
|
||||
thirdparty/mysql/
|
||||
thirdparty/mysql_linux/
|
||||
CMakeVariables.txt
|
||||
|
||||
# Build folders
|
||||
build/
|
||||
@@ -95,6 +94,7 @@ ipch/
|
||||
|
||||
# Exceptions:
|
||||
CMakeSettings.json
|
||||
CMakeUserPresets.json
|
||||
*.vcxproj
|
||||
*.filters
|
||||
*.cmake
|
||||
@@ -122,4 +122,7 @@ docker/__pycache__
|
||||
docker-compose.override.yml
|
||||
|
||||
!*Test.bin
|
||||
|
||||
# CMake scripts
|
||||
!cmake/*
|
||||
!cmake/toolchains/*
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "thirdparty/cpp-httplib"]
|
||||
path = thirdparty/cpp-httplib
|
||||
url = https://github.com/yhirose/cpp-httplib
|
||||
[submodule "thirdparty/tinyxml2"]
|
||||
path = thirdparty/tinyxml2
|
||||
url = https://github.com/leethomason/tinyxml2
|
||||
|
||||
196
CMakeLists.txt
196
CMakeLists.txt
@@ -1,9 +1,23 @@
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(Darkflame)
|
||||
cmake_minimum_required(VERSION 3.25)
|
||||
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)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export the compile commands for debugging
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects
|
||||
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Set C and C++ symbol visibility to hide inlined functions
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
# Read variables from file
|
||||
@@ -52,33 +66,37 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||
# Disabled no-register
|
||||
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
||||
if(UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -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)
|
||||
|
||||
if(NOT APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -lstdc++fs")
|
||||
# For all except Clang and Apple Clang
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
add_compile_options("-static-libgcc" "-lstdc++fs")
|
||||
endif()
|
||||
|
||||
if(${DYNAMIC} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
|
||||
add_link_options("-export-dynamic")
|
||||
endif()
|
||||
|
||||
if(${GGDB})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
|
||||
add_compile_options("-ggdb")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
||||
elseif(MSVC)
|
||||
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
||||
add_compile_options("/wd4267" "/utf-8")
|
||||
# Also disable non-portable MSVC volatile behavior
|
||||
add_compile_options("/wd4267" "/utf-8" "/volatile:iso" "/Zc:inline")
|
||||
elseif(WIN32)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
# Our output dir
|
||||
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR})
|
||||
#set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) # unfortunately, forces all libraries to be built in series, which will slow down the build process
|
||||
|
||||
# TODO make this not have to override the build type directories
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_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_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR})
|
||||
@@ -90,37 +108,47 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
find_package(MariaDB)
|
||||
|
||||
# Create a /resServer directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/resServer)
|
||||
|
||||
# Create a /logs directory
|
||||
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
|
||||
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
|
||||
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blocklist.dcf")
|
||||
message(STATUS "Checking resource file integrity")
|
||||
|
||||
include(Utils)
|
||||
UpdateConfigOption(${PROJECT_BINARY_DIR}/authconfig.ini "port" "auth_server_port")
|
||||
UpdateConfigOption(${PROJECT_BINARY_DIR}/chatconfig.ini "port" "chat_server_port")
|
||||
UpdateConfigOption(${PROJECT_BINARY_DIR}/masterconfig.ini "port" "master_server_port")
|
||||
UpdateConfigOption(${DLU_CONFIG_DIR}/authconfig.ini "port" "auth_server_port")
|
||||
UpdateConfigOption(${DLU_CONFIG_DIR}/chatconfig.ini "port" "chat_server_port")
|
||||
UpdateConfigOption(${DLU_CONFIG_DIR}/masterconfig.ini "port" "master_server_port")
|
||||
|
||||
foreach(resource_file ${RESOURCE_FILES})
|
||||
set(file_size 0)
|
||||
|
||||
if(EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
|
||||
file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size)
|
||||
if(EXISTS ${DLU_CONFIG_DIR}/${resource_file})
|
||||
file(SIZE ${DLU_CONFIG_DIR}/${resource_file} file_size)
|
||||
endif()
|
||||
|
||||
if(${file_size} EQUAL 0)
|
||||
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
|
||||
)
|
||||
message(STATUS "Moved " ${resource_file} " to project binary directory")
|
||||
message(STATUS "Moved " ${resource_file} " to DLU config directory")
|
||||
elseif(resource_file MATCHES ".ini")
|
||||
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})
|
||||
set(parsed_current_file_contents "")
|
||||
@@ -147,16 +175,18 @@ foreach(resource_file ${RESOURCE_FILES})
|
||||
list(GET line_split 0 variable_name)
|
||||
|
||||
if(NOT ${parsed_current_file_contents} MATCHES ${variable_name})
|
||||
message(STATUS "Adding missing config option " ${variable_name} " to " ${resource_file})
|
||||
set(line_to_add ${line_to_add} ${line})
|
||||
# For backwards compatibility with older setup versions, dont add this option.
|
||||
if(NOT ${variable_name} MATCHES "database_type")
|
||||
message(STATUS "Adding missing config option " ${variable_name} " to " ${resource_file})
|
||||
set(line_to_add ${line_to_add} ${line})
|
||||
|
||||
foreach(line_to_append ${line_to_add})
|
||||
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append})
|
||||
endforeach()
|
||||
foreach(line_to_append ${line_to_add})
|
||||
file(APPEND ${DLU_CONFIG_DIR}/${resource_file} "\n" ${line_to_append})
|
||||
endforeach()
|
||||
|
||||
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n")
|
||||
file(APPEND ${DLU_CONFIG_DIR}/${resource_file} "\n")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(line_to_add "")
|
||||
else()
|
||||
set(line_to_add ${line_to_add} ${line})
|
||||
@@ -179,114 +209,66 @@ file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PRO
|
||||
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
|
||||
|
||||
# Copy vanity files on first build
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "root.xml" "dev-tribute.xml" "atm.xml" "demo.xml")
|
||||
|
||||
foreach(file ${VANITY_FILES})
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
||||
endforeach()
|
||||
|
||||
# Move our migrations for MasterServer to run
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/dlu/)
|
||||
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql)
|
||||
file(REMOVE_RECURSE ${PROJECT_BINARY_DIR}/migrations)
|
||||
file(COPY ${CMAKE_SOURCE_DIR}/migrations DESTINATION ${CMAKE_BINARY_DIR})
|
||||
|
||||
foreach(file ${SQL_FILES})
|
||||
get_filename_component(file ${file} NAME)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/dlu/${file})
|
||||
endforeach()
|
||||
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
||||
if (APPLE)
|
||||
include_directories("/usr/local/include/")
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/cdserver/)
|
||||
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/cdserver/*.sql)
|
||||
|
||||
foreach(file ${SQL_FILES})
|
||||
get_filename_component(file ${file} NAME)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
|
||||
endforeach()
|
||||
# Load all of our third party directories
|
||||
add_subdirectory(thirdparty SYSTEM)
|
||||
|
||||
# Create our list of include directories
|
||||
set(INCLUDED_DIRECTORIES
|
||||
"dCommon"
|
||||
"dCommon/dClient"
|
||||
"dCommon/dEnums"
|
||||
|
||||
"dChatFilter"
|
||||
|
||||
"dGame"
|
||||
"dGame/dBehaviors"
|
||||
"dGame/dComponents"
|
||||
"dGame/dGameMessages"
|
||||
"dGame/dInventory"
|
||||
"dGame/dMission"
|
||||
"dGame/dEntity"
|
||||
"dGame/dPropertyBehaviors"
|
||||
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
|
||||
"dGame/dUtilities"
|
||||
|
||||
include_directories(
|
||||
"dPhysics"
|
||||
|
||||
"dNavigation"
|
||||
"dNavigation/dTerrain"
|
||||
|
||||
"dZoneManager"
|
||||
|
||||
"dDatabase"
|
||||
"dDatabase/CDClientDatabase"
|
||||
"dDatabase/CDClientDatabase/CDClientTables"
|
||||
"dDatabase/GameDatabase"
|
||||
"dDatabase/GameDatabase/ITables"
|
||||
"dDatabase/GameDatabase/MySQL"
|
||||
"dDatabase/GameDatabase/MySQL/Tables"
|
||||
|
||||
"dNet"
|
||||
|
||||
"tests"
|
||||
"tests/dCommonTests"
|
||||
"tests/dGameTests"
|
||||
"tests/dGameTests/dComponentsTests"
|
||||
|
||||
SYSTEM
|
||||
"thirdparty/magic_enum/include/magic_enum"
|
||||
"thirdparty/raknet/Source"
|
||||
"thirdparty/tinyxml2"
|
||||
"thirdparty/recastnavigation"
|
||||
"thirdparty/SQLite"
|
||||
"thirdparty/cpplinq"
|
||||
"thirdparty/cpp-httplib"
|
||||
"thirdparty/MD5"
|
||||
|
||||
"tests"
|
||||
"tests/dCommonTests"
|
||||
"tests/dGameTests"
|
||||
"tests/dGameTests/dComponentsTests"
|
||||
"thirdparty/nlohmann"
|
||||
"thirdparty/mongoose"
|
||||
)
|
||||
|
||||
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
||||
# TODO: Should probably not do this.
|
||||
if(APPLE)
|
||||
include_directories("/usr/local/include/")
|
||||
endif()
|
||||
|
||||
# Actually include the directories from our list
|
||||
foreach(dir ${INCLUDED_DIRECTORIES})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/${dir})
|
||||
endforeach()
|
||||
|
||||
if(NOT WIN32)
|
||||
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt")
|
||||
# Set warning flags
|
||||
if(MSVC)
|
||||
# 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()
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include")
|
||||
|
||||
# Add linking directories:
|
||||
link_directories(${PROJECT_BINARY_DIR})
|
||||
|
||||
# Load all of our third party directories
|
||||
add_subdirectory(thirdparty)
|
||||
if (UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
|
||||
endif()
|
||||
# Glob together all headers that need to be precompiled
|
||||
file(
|
||||
GLOB HEADERS_DDATABASE
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/*.h
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables/*.h
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables/*.h
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
||||
)
|
||||
|
||||
file(
|
||||
GLOB HEADERS_DZONEMANAGER
|
||||
LIST_DIRECTORIES false
|
||||
@@ -321,7 +303,7 @@ add_subdirectory(dPhysics)
|
||||
add_subdirectory(dServer)
|
||||
|
||||
# Create a list of common libraries shared between all binaries
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum" "MD5")
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "magic_enum")
|
||||
|
||||
# Add platform specific common libraries
|
||||
if(UNIX)
|
||||
@@ -343,12 +325,6 @@ target_precompile_headers(
|
||||
${HEADERS_DZONEMANAGER}
|
||||
)
|
||||
|
||||
# Need to specify to use the CXX compiler language here or else we get errors including <string>.
|
||||
target_precompile_headers(
|
||||
dDatabase PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
|
||||
)
|
||||
|
||||
target_precompile_headers(
|
||||
dCommon PRIVATE
|
||||
${HEADERS_DCOMMON}
|
||||
|
||||
@@ -1,128 +1,638 @@
|
||||
{
|
||||
"version": 3,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 14,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "default",
|
||||
"displayName": "Default configure step",
|
||||
"description": "Use 'build' dir and Unix makefiles",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"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
|
||||
"version": 6,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 25,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "default",
|
||||
"displayName": "Default configure step",
|
||||
"description": "Use 'build' dir and Unix makefiles",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"generator": "Unix Makefiles"
|
||||
},
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "debug-config",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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_MINOR=1
|
||||
PROJECT_VERSION_PATCH=1
|
||||
PROJECT_VERSION_MAJOR=3
|
||||
PROJECT_VERSION_MINOR=0
|
||||
PROJECT_VERSION_PATCH=0
|
||||
|
||||
# Debugging
|
||||
# Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
||||
|
||||
@@ -23,8 +23,7 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Grab libraries and load them
|
||||
COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadbcpp.so /usr/local/lib/
|
||||
COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadb/libmariadb/libmariadb.so.3 /usr/local/lib
|
||||
COPY --from=build /app/build/mariadbcpp/libmariadbcpp.so /usr/local/lib/
|
||||
RUN ldconfig
|
||||
|
||||
# Server bins
|
||||
@@ -32,7 +31,7 @@ COPY --from=build /app/build/*Server /app/
|
||||
|
||||
# Necessary suplimentary files
|
||||
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/migrations /app/migrations
|
||||
COPY --from=build /app/build/*.dcf /app/
|
||||
@@ -40,7 +39,7 @@ COPY --from=build /app/build/*.dcf /app/
|
||||
# backup of config and vanity files to copy to the host incase
|
||||
# of a mount clobbering the copy from above
|
||||
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
|
||||
# and therefore sudo doesn't exist
|
||||
|
||||
101
README.md
101
README.md
@@ -13,21 +13,35 @@ Darkflame Universe is licensed under AGPLv3, please read [LICENSE](LICENSE). Som
|
||||
* You must disclose any changes you make to the code when you distribute it
|
||||
* Hosting a server for others counts as distribution
|
||||
|
||||
## Disclaimers
|
||||
### Setup difficulty
|
||||
Throughout the entire build and setup process a level of familiarity with the command line and preferably a Unix-like development environment is greatly advantageous.
|
||||
|
||||
### Hosting a server
|
||||
We do not recommend hosting public servers. Darkflame Universe is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks.
|
||||
|
||||
### Supply of resource files
|
||||
Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed [here](#verifying-your-client-files) to see if a client will work.
|
||||
|
||||
## Step by step walkthrough for a single-player server
|
||||
If you would like a setup for a single player server only on a Windows machine, use the [Native Windows Setup Guide by HailStorm](https://gist.github.com/HailStorm32/169df65a47a104199b5cc57d10fa57de) and skip this README.
|
||||
## Setting up a single player server
|
||||
* If you don't know what WSL is, skip this warning.
|
||||
Warning: WSL version 1 does NOT support using sqlite as a database due to how it handles filesystem synchronization.
|
||||
You must use Version 2 if you must run the server under WSL. Not doing so will result in save data loss.
|
||||
* Single player installs now no longer require building the server from source or installing development tools.
|
||||
* Download the [latest windows release](https://github.com/DarkflameUniverse/DarkflameServer/releases) (or whichever release you need) and extract the files into a folder inside your client. Note that this setup is expecting that when double clicking the folder that you put in the same folder as `legouniverse.exe`, the file `MasterServer.exe` is in there.
|
||||
* You should be able to see the folder with the server files in the same folder as `legouniverse.exe`.
|
||||
* Go into the server files folder and open `sharedconfig.ini`. Find the line that says `client_location` and put `..` after it so the line reads `client_location=..`.
|
||||
* To run the server, double-click `MasterServer.exe`.
|
||||
* You will be asked to create an account the first time you run the server. After you have created the account, the server will shutdown and need to be restarted.
|
||||
* To connect to the server, either delete the file `boot.cfg` which is found in your LEGO Universe client, rename the file `boot.cfg` to something else or follow the steps [here](#allowing-a-user-to-connect-to-your-server) if you wish to keep the file.
|
||||
* When shutting down the server, it is highly recommended to click the `MasterServer.exe` window and hold `ctrl` while pressing `c` to stop the server.
|
||||
* We are working on a way to make it so when you close the game, the server stops automatically alongside when you open the game, the server starts automatically.
|
||||
* If you are not setting a server up on mac, you can ignore this note
|
||||
* Note: you'll need to allow through System Preferences `AuthServer`, `ChatServer`, `MasterServer`, `WorldServer` and `libmariadbcpp.dylib` to run. The initial pop-up will block it due to the binaries being unsigned, after allowing them to run the servers will run as normal.
|
||||
|
||||
## Steps to setup server
|
||||
<font size="32">**If you are not planning on hosting a server for others, working in the codebase or wanting to use MariaDB for a database, you can stop reading here.**</font>
|
||||
|
||||
If you would like to use a MariaDB as a database instead of the default of sqlite, follow the steps [here](#database-setup).
|
||||
|
||||
# Steps to setup a development environment
|
||||
* [Clone this repository](#clone-the-repository)
|
||||
* [Setting up a development environment](#setting-up-a-development-environment)
|
||||
* [Install dependencies](#install-dependencies)
|
||||
* [Database setup](#database-setup)
|
||||
* [Build the server](#build-the-server)
|
||||
@@ -39,6 +53,13 @@ If you would like a setup for a single player server only on a Windows machine,
|
||||
* [User Guide](#user-guide)
|
||||
* [Docker](#docker)
|
||||
|
||||
## Disclaimers
|
||||
### Setup difficulty
|
||||
Throughout the entire build and setup process a level of familiarity with the command line and preferably a Unix-like development environment is greatly advantageous.
|
||||
|
||||
## Step by step walkthrough for building a single-player Windows server from source
|
||||
If you would like a setup for a single player server only on a Windows machine built from source, use the [Native Windows Setup Guide by HailStorm](https://gist.github.com/HailStorm32/169df65a47a104199b5cc57d10fa57de) and skip this README.
|
||||
|
||||
## Clone the repository
|
||||
If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win)
|
||||
|
||||
@@ -49,9 +70,15 @@ git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
||||
|
||||
## Install dependencies
|
||||
|
||||
### Required compiler versions
|
||||
- g++11 or greater
|
||||
- MSVC unchecked
|
||||
- clang unchecked
|
||||
- appleclang unchecked
|
||||
|
||||
### Windows packages
|
||||
Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed.
|
||||
You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.18**</font> or later!).
|
||||
You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.25**</font> or later!).
|
||||
|
||||
### MacOS packages
|
||||
Ensure you have [brew](https://brew.sh) installed.
|
||||
@@ -73,7 +100,7 @@ sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-serve
|
||||
```
|
||||
|
||||
#### Required CMake version
|
||||
This project uses <font size="4">**CMake version 3.18**</font> or higher and as such you will need to ensure you have this version installed.
|
||||
This project uses <font size="4">**CMake version 3.25**</font> or higher and as such you will need to ensure you have this version installed.
|
||||
You can check your CMake version by using the following command in a terminal.
|
||||
```bash
|
||||
cmake --version
|
||||
@@ -183,6 +210,7 @@ If you would like to build the server faster, append `-j<number>` where number i
|
||||
### Notes
|
||||
Depending on your operating system, you may need to adjust some pre-processor defines in [CMakeVariables.txt](./CMakeVariables.txt) before building:
|
||||
* If you are on MacOS, ensure OPENSSL_ROOT_DIR is pointing to the openssl root directory.
|
||||
* By default it should be set to the correct directory.
|
||||
* If you are using a Darkflame Universe client, ensure `client_net_version` in `build/sharedconfig.ini` is changed to 171023.
|
||||
|
||||
## Configuring your server
|
||||
@@ -205,28 +233,41 @@ Navigate to `build/sharedconfig.ini` and fill in the following fields:
|
||||
* `chatconfig.ini` contains a port option.
|
||||
* `masterconfig.ini` contains options related to permissions you want to run your servers with.
|
||||
* `sharedconfig.ini` contains several options that are shared across all servers
|
||||
* `worldconfig.ini` contains several options to turn on QOL improvements should you want them. If you would like the most vanilla experience possible, you will need to turn some of these settings off.
|
||||
* `worldconfig.ini` contains several options to turn on Quality of Life improvements should you want them. If you would like the most vanilla experience possible, you will need to turn some of these settings off.
|
||||
|
||||
## Verify your setup
|
||||
Your build directory should now look like this:
|
||||
* AuthServer
|
||||
* ChatServer
|
||||
* MasterServer
|
||||
* WorldServer
|
||||
* authconfig.ini
|
||||
* chatconfig.ini
|
||||
* masterconfig.ini
|
||||
Your build directory should contain at a minimum all of the following files.
|
||||
All listed files are required for a server to start.
|
||||
`ini` files can be located at the environment variable `DLU_CONFIG_DIR` and do not need to be located in this directory.
|
||||
(windows will have .exe at the end of the executables):
|
||||
* sharedconfig.ini
|
||||
* AuthServer(.exe)
|
||||
* authconfig.ini
|
||||
* ChatServer(.exe)
|
||||
* chatconfig.ini
|
||||
* MasterServer(.exe)
|
||||
* masterconfig.ini
|
||||
* WorldServer(.exe)
|
||||
* worldconfig.ini
|
||||
* ...
|
||||
* blocklist.dcf
|
||||
* migrations
|
||||
* vanity
|
||||
* navmeshes
|
||||
* 1 of the following lists based on platform
|
||||
* windows
|
||||
* libmariadb.dll
|
||||
* mariadbcpp.dll
|
||||
* zlib.dll
|
||||
* MacOS
|
||||
* libmariadbcpp.dylib
|
||||
* *nix
|
||||
* libmariadbcpp.so
|
||||
|
||||
## Running the server
|
||||
If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the `AuthServer` binary network permissions or run it under sudo.
|
||||
To give `AuthServer` network permissions and not require sudo, run the following command
|
||||
If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you have to give the `AuthServer` binary network permissions by running the following command:
|
||||
```bash
|
||||
sudo setcap 'cap_net_bind_service=+ep' AuthServer
|
||||
```
|
||||
and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0.
|
||||
|
||||
### Linux Service
|
||||
If you are running this on a linux based system, it will use your terminal to run the program interactively, preventing you using it for other tasks and requiring it to be open to run the server.
|
||||
@@ -266,8 +307,8 @@ systemctl stop darkflame.service
|
||||
journalctl -xeu darkflame.service
|
||||
```
|
||||
|
||||
### First admin user
|
||||
Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users!
|
||||
### First user or adding more users.
|
||||
The first time you run `MasterServer`, you will be prompted to create an account. To create more accounts from the command line, `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users!
|
||||
|
||||
### Account management tool (Nexus Dashboard)
|
||||
**If you are just using this server for yourself, you can skip setting up Nexus Dashboard**
|
||||
@@ -289,8 +330,14 @@ To connect to a server follow these steps:
|
||||
* Replace the contents after to `:` and the following `,` with what you configured as the server's public facing IP. For example `AUTHSERVERIP=0:localhost` for locally hosted servers
|
||||
* Next locate the line `UGCUSE3DSERVICES=7:`
|
||||
* Ensure the number after the 7 is a `0`
|
||||
* Alternatively, remove the line with `UGCUSE3DSERVICES` altogether
|
||||
* Launch `legouniverse.exe`, through `wine` if on a Unix-like operating system
|
||||
* Note that if you are on WSL2, you will need to configure the public IP in the server and client to be the IP of the WSL2 instance and not localhost, which can be found by running `ifconfig` in the terminal. Windows defaults to WSL1, so this will not apply to most users.
|
||||
As an example, here is what the boot.cfg is required to contain for a server with the ip 12.34.56.78
|
||||
```cfg
|
||||
AUTHSERVERIP=0:12.34.56.78,
|
||||
UGCUSE3DSERVICES=7:0
|
||||
```
|
||||
|
||||
## Updating your server
|
||||
To update your server to the latest version navigate to your cloned directory
|
||||
@@ -307,6 +354,10 @@ Now follow the [build](#build-the-server) section for your system and your serve
|
||||
## In-game commands
|
||||
* A list of all in-game commands can be found [here](./docs/Commands.md).
|
||||
|
||||
## Chat Web API
|
||||
* The Chat server has an API that can be enabled via `chatconfig.ini`.
|
||||
* You can view the OpenAPI doc for the API here [here](./docs/ChatWebAPI.yaml).
|
||||
|
||||
## Verifying your client files
|
||||
|
||||
### LEGO® Universe 1.10.64
|
||||
@@ -371,7 +422,7 @@ at once. For that:
|
||||
- Download the [.env.example](.env.example) file and place it next to `client` with the file name `.env`
|
||||
- You may get warnings that this name starts with a dot, acknowledge those, this is intentional. Depending on your operating system, you may need to activate showing hidden files (e.g. Ctrl-H in Gnome on Linux) and/or file extensions ("File name extensions" in the "View" tab on Windows).
|
||||
- Update the `ACCOUNT_MANAGER_SECRET` and `MARIADB_PASSWORD` with strong random passwords.
|
||||
- Use a password generator like <https://keygen.io>
|
||||
- Use a password generator <https://gchq.github.io/CyberChef/#recipe=Pseudo-Random_Number_Generator(256,'Hex')>
|
||||
- Avoid `:` and `@` characters
|
||||
- Once the database user is created, changing the password will not update it, so the server will just fail to connect.
|
||||
- Set `EXTERNAL_IP` to your LAN IP or public IP if you want to host the game for friends & family
|
||||
|
||||
3
build.sh
3
build.sh
@@ -6,8 +6,7 @@ mkdir -p build
|
||||
cd build
|
||||
|
||||
# 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'
|
||||
cmake --build . --config Release $1
|
||||
|
||||
|
||||
17
cmake/FindGoogleTest.cmake
Normal file
17
cmake/FindGoogleTest.cmake
Normal file
@@ -0,0 +1,17 @@
|
||||
include(FetchContent)
|
||||
|
||||
message(STATUS "Fetching gtest...")
|
||||
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG release-1.12.1
|
||||
)
|
||||
|
||||
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
FetchContent_MakeAvailable(GoogleTest)
|
||||
|
||||
message(STATUS "gtest fetched and is now ready.")
|
||||
set(GoogleTest_FOUND TRUE)
|
||||
@@ -23,14 +23,14 @@ if(WIN32 AND NOT MARIADB_BUILD_SOURCE)
|
||||
set(MARIADB_CONNECTOR_CPP_MSI "mariadb-connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}-win64.msi")
|
||||
|
||||
if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" )
|
||||
message("Downloading mariadb connector/c")
|
||||
message(STATUS "Downloading mariadb connector/c")
|
||||
file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_C_BUCKET}/Connectors/c/connector-c-${MARIADB_CONNECTOR_C_VERSION}/${MARIADB_CONNECTOR_C_MSI}
|
||||
"${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}"
|
||||
EXPECTED_HASH MD5=${MARIADB_CONNECTOR_C_MD5})
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" )
|
||||
message("Downloading mariadb connector/c++")
|
||||
message(STATUS "Downloading mariadb connector/c++")
|
||||
file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_CPP_BUCKET}/Connectors/cpp/connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}/${MARIADB_CONNECTOR_CPP_MSI}
|
||||
"${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}"
|
||||
EXPECTED_HASH MD5=${MARIADB_CONNECTOR_CPP_MD5})
|
||||
@@ -43,27 +43,28 @@ if(WIN32 AND NOT MARIADB_BUILD_SOURCE)
|
||||
file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" MSI_DIR)
|
||||
execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR})
|
||||
endif()
|
||||
set(MARIADBC_SHARED_LIBRARY_LOCATION "${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll")
|
||||
|
||||
if(NOT EXISTS "${MARIADB_CPP_CONNECTOR_DIR}")
|
||||
file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" MSI_DIR)
|
||||
execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR})
|
||||
endif()
|
||||
|
||||
set(MARIADB_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll")
|
||||
set(MARIADBCPP_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll")
|
||||
set(MARIADB_IMPLIB_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.lib")
|
||||
set(MARIADB_INCLUDE_DIR "${MARIADB_CPP_CONNECTOR_DIR}/include/mariadb")
|
||||
|
||||
add_custom_target(mariadb_connector_cpp)
|
||||
add_custom_command(TARGET mariadb_connector_cpp POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll"
|
||||
"${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll"
|
||||
"${MARIADBCPP_SHARED_LIBRARY_LOCATION}"
|
||||
"${MARIADBC_SHARED_LIBRARY_LOCATION}"
|
||||
"${PROJECT_BINARY_DIR}")
|
||||
|
||||
# MariaDB uses plugins that the database needs to load, the prebuilt binaries by default will try to find the libraries in system directories,
|
||||
# so set this define and the servers will set the MARIADB_PLUGIN_DIR environment variable to the appropriate directory.
|
||||
# Plugin directory is determined at dll load time (this will happen before main()) so we need to delay the dll load so that we can set the environment variable
|
||||
add_link_options(/DELAYLOAD:${MARIADB_SHARED_LIBRARY_LOCATION})
|
||||
add_link_options(/DELAYLOAD:${MARIADBCPP_SHARED_LIBRARY_LOCATION})
|
||||
add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADB_CPP_CONNECTOR_DIR}/plugin")
|
||||
else() # Build from source
|
||||
|
||||
@@ -85,77 +86,61 @@ else() # Build from source
|
||||
-DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0)
|
||||
endif()
|
||||
|
||||
set(MARIADBCPP_INSTALL_DIR ${PROJECT_BINARY_DIR}/prefix)
|
||||
set(MARIADBCPP_LIBRARY_DIR ${PROJECT_BINARY_DIR}/mariadbcpp)
|
||||
set(MARIADBCPP_PLUGIN_DIR ${MARIADBCPP_LIBRARY_DIR}/plugin)
|
||||
set(MARIADBCPP_SOURCE_DIR ${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp)
|
||||
set(MARIADB_INCLUDE_DIR "${MARIADBCPP_SOURCE_DIR}/include")
|
||||
ExternalProject_Add(mariadb_connector_cpp
|
||||
SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp
|
||||
CMAKE_ARGS -Wno-dev
|
||||
-DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN}
|
||||
-DCMAKE_INSTALL_PREFIX=./mariadbcpp # Points the connector to the correct plugin directory
|
||||
-DINSTALL_PLUGINDIR=plugin
|
||||
${MARIADB_EXTRA_CMAKE_ARGS}
|
||||
PREFIX "${PROJECT_BINARY_DIR}/mariadbcpp"
|
||||
BUILD_COMMAND cmake --build . --config RelWithDebInfo -j${MARIADB_CONNECTOR_COMPILE_JOBS}
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
ExternalProject_Get_Property(mariadb_connector_cpp BINARY_DIR)
|
||||
PREFIX "${PROJECT_BINARY_DIR}/thirdparty/mariadb-connector-cpp"
|
||||
SOURCE_DIR ${MARIADBCPP_SOURCE_DIR}
|
||||
INSTALL_DIR ${MARIADBCPP_INSTALL_DIR}
|
||||
CMAKE_ARGS -Wno-dev
|
||||
-DWITH_UNIT_TESTS=OFF
|
||||
-DMARIADB_LINK_DYNAMIC=OFF
|
||||
-DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN}
|
||||
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
|
||||
-DINSTALL_LIBDIR=${MARIADBCPP_LIBRARY_DIR}
|
||||
-DINSTALL_PLUGINDIR=${MARIADBCPP_PLUGIN_DIR}
|
||||
${MARIADB_EXTRA_CMAKE_ARGS}
|
||||
BUILD_ALWAYS true
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set(MARIADB_SHARED_LIBRARY_NAME mariadbcpp.dll)
|
||||
set(MARIADB_PLUGIN_SUFFIX .dll)
|
||||
set(MARIADB_IMPLIB_LOCATION "${BINARY_DIR}/RelWithDebInfo/mariadbcpp.lib")
|
||||
set(MARIADB_IMPLIB_LOCATION "${MARIADBCPP_LIBRARY_DIR}/mariadbcpp.lib")
|
||||
|
||||
# When built from source windows only seems to check same folder as exe instead specified folder, so use
|
||||
# environment variable to force it
|
||||
add_link_options(/DELAYLOAD:mariadbcpp.dll)
|
||||
add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${PROJECT_BINARY_DIR}/mariadbcpp/plugin")
|
||||
add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADBCPP_PLUGIN_DIR}")
|
||||
else()
|
||||
set(MARIADB_SHARED_LIBRARY_NAME libmariadbcpp${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
set(MARIADB_PLUGIN_SUFFIX .so)
|
||||
set(MARIADB_PLUGIN_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
|
||||
endif()
|
||||
|
||||
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if(isMultiConfig)
|
||||
set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/RelWithDebInfo/${MARIADB_SHARED_LIBRARY_NAME}")
|
||||
set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}/$<CONFIG>")
|
||||
set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb/RelWithDebInfo")
|
||||
else()
|
||||
set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}")
|
||||
set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}")
|
||||
set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb")
|
||||
set(MARIADBCPP_SHARED_LIBRARY_LOCATION "${MARIADBCPP_LIBRARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}")
|
||||
if(WIN32)
|
||||
set(MARIADBC_SHARED_LIBRARY_LOCATION "${MARIADBCPP_LIBRARY_DIR}/libmariadb.lib")
|
||||
endif()
|
||||
|
||||
set(MARIADB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include/")
|
||||
|
||||
add_custom_command(TARGET mariadb_connector_cpp POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
${BINARY_DIR}/mariadbcpp/plugin
|
||||
${MARIADB_SHARED_LIBRARY_COPY_LOCATION}
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${MARIADB_SHARED_LIBRARY_LOCATION}
|
||||
${MARIADB_SHARED_LIBRARY_COPY_LOCATION}
|
||||
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${MARIADB_PLUGINS_LOCATION}/caching_sha2_password${MARIADB_PLUGIN_SUFFIX}
|
||||
${MARIADB_PLUGINS_LOCATION}/client_ed25519${MARIADB_PLUGIN_SUFFIX}
|
||||
${MARIADB_PLUGINS_LOCATION}/dialog${MARIADB_PLUGIN_SUFFIX}
|
||||
${MARIADB_PLUGINS_LOCATION}/mysql_clear_password${MARIADB_PLUGIN_SUFFIX}
|
||||
${MARIADB_PLUGINS_LOCATION}/sha256_password${MARIADB_PLUGIN_SUFFIX}
|
||||
${BINARY_DIR}/mariadbcpp/plugin)
|
||||
endif()
|
||||
|
||||
# Remove the CMakeLists.txt file from the tests folder for the maria-db-connector so we dont compile the tests.
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt")
|
||||
file(REMOVE "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt")
|
||||
endif()
|
||||
|
||||
# Create mariadb connector library object
|
||||
add_library(mariadbConnCpp SHARED IMPORTED GLOBAL)
|
||||
set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_LOCATION ${MARIADB_SHARED_LIBRARY_LOCATION})
|
||||
add_library(MariaDB::ConnCpp SHARED IMPORTED GLOBAL)
|
||||
add_dependencies(MariaDB::ConnCpp mariadb_connector_cpp)
|
||||
set_target_properties(MariaDB::ConnCpp PROPERTIES
|
||||
IMPORTED_LOCATION "${MARIADBCPP_SHARED_LIBRARY_LOCATION}")
|
||||
|
||||
if(WIN32)
|
||||
set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_IMPLIB ${MARIADB_IMPLIB_LOCATION})
|
||||
set_target_properties(MariaDB::ConnCpp PROPERTIES
|
||||
IMPORTED_IMPLIB "${MARIADB_IMPLIB_LOCATION}")
|
||||
elseif(APPLE)
|
||||
set_target_properties(MariaDB::ConnCpp PROPERTIES
|
||||
IMPORTED_SONAME "libmariadbcpp")
|
||||
endif()
|
||||
|
||||
# Add directories to include lists
|
||||
target_include_directories(mariadbConnCpp INTERFACE ${MARIADB_INCLUDE_DIR})
|
||||
add_dependencies(mariadbConnCpp mariadb_connector_cpp)
|
||||
target_include_directories(MariaDB::ConnCpp SYSTEM INTERFACE ${MARIADB_INCLUDE_DIR})
|
||||
|
||||
set(MariaDB_FOUND TRUE)
|
||||
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,13 +21,12 @@
|
||||
//Auth includes:
|
||||
#include "AuthPackets.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eServerMessageType.h"
|
||||
#include "eAuthMessageType.h"
|
||||
#include "MessageType/Server.h"
|
||||
#include "MessageType/Auth.h"
|
||||
|
||||
#include "Game.h"
|
||||
#include "Server.h"
|
||||
|
||||
|
||||
namespace Game {
|
||||
Logger* logger = nullptr;
|
||||
dServer* server = nullptr;
|
||||
@@ -60,7 +59,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
try {
|
||||
Database::Connect();
|
||||
} catch (sql::SQLException& ex) {
|
||||
} catch (std::exception& ex) {
|
||||
LOG("Got an error while connecting to the database: %s", ex.what());
|
||||
Database::Destroy("AuthServer");
|
||||
delete Game::server;
|
||||
@@ -71,12 +70,15 @@ int main(int argc, char** argv) {
|
||||
//Find out the master's IP:
|
||||
std::string masterIP;
|
||||
uint32_t masterPort = 1500;
|
||||
std::string masterPassword;
|
||||
|
||||
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||
if (masterInfo) {
|
||||
masterIP = masterInfo->ip;
|
||||
masterPort = masterInfo->port;
|
||||
masterPassword = masterInfo->password;
|
||||
}
|
||||
|
||||
LOG("Master is at %s:%d", masterIP.c_str(), masterPort);
|
||||
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
@@ -90,7 +92,7 @@ int main(int argc, char** argv) {
|
||||
const auto externalIPString = Game::config->GetValue("external_ip");
|
||||
if (!externalIPString.empty()) ourIP = externalIPString;
|
||||
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal);
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal, masterPassword);
|
||||
|
||||
//Run it until server gets a kill message from Master:
|
||||
auto t = std::chrono::high_resolution_clock::now();
|
||||
@@ -102,7 +104,7 @@ int main(int argc, char** argv) {
|
||||
uint32_t framesSinceLastSQLPing = 0;
|
||||
|
||||
AuthPackets::LoadClaimCodes();
|
||||
|
||||
|
||||
Game::logger->Flush(); // once immediately before main loop
|
||||
while (!Game::ShouldShutdown()) {
|
||||
//Check if we're still connected to master:
|
||||
@@ -166,11 +168,11 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
if (packet->data[0] == ID_USER_PACKET_ENUM) {
|
||||
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);
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
add_executable(AuthServer "AuthServer.cpp")
|
||||
|
||||
target_link_libraries(AuthServer ${COMMON_LIBRARIES} dServer)
|
||||
|
||||
target_include_directories(AuthServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer)
|
||||
|
||||
add_compile_definitions(AuthServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
|
||||
@@ -27,8 +27,8 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
|
||||
ExportWordlistToDCF(filepath + ".dcf", true);
|
||||
}
|
||||
|
||||
if (BinaryIO::DoesFileExist("blacklist.dcf")) {
|
||||
ReadWordlistDCF("blacklist.dcf", false);
|
||||
if (BinaryIO::DoesFileExist("blocklist.dcf")) {
|
||||
ReadWordlistDCF("blocklist.dcf", false);
|
||||
}
|
||||
|
||||
//Read player names that are ok as well:
|
||||
@@ -44,20 +44,20 @@ dChatFilter::~dChatFilter() {
|
||||
m_DeniedWords.clear();
|
||||
}
|
||||
|
||||
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) {
|
||||
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool allowList) {
|
||||
std::ifstream file(filepath);
|
||||
if (file) {
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
||||
if (whiteList) m_ApprovedWords.push_back(CalculateHash(line));
|
||||
if (allowList) m_ApprovedWords.push_back(CalculateHash(line));
|
||||
else m_DeniedWords.push_back(CalculateHash(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
||||
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool allowList) {
|
||||
std::ifstream file(filepath, std::ios::binary);
|
||||
if (file) {
|
||||
fileHeader hdr;
|
||||
@@ -70,13 +70,13 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
||||
if (hdr.formatVersion == formatVersion) {
|
||||
size_t wordsToRead = 0;
|
||||
BinaryIO::BinaryRead(file, wordsToRead);
|
||||
if (whiteList) m_ApprovedWords.reserve(wordsToRead);
|
||||
if (allowList) m_ApprovedWords.reserve(wordsToRead);
|
||||
else m_DeniedWords.reserve(wordsToRead);
|
||||
|
||||
size_t word = 0;
|
||||
for (size_t i = 0; i < wordsToRead; ++i) {
|
||||
BinaryIO::BinaryRead(file, word);
|
||||
if (whiteList) m_ApprovedWords.push_back(word);
|
||||
if (allowList) m_ApprovedWords.push_back(word);
|
||||
else m_DeniedWords.push_back(word);
|
||||
}
|
||||
|
||||
@@ -90,14 +90,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) {
|
||||
void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool allowList) {
|
||||
std::ofstream file(filepath, std::ios::binary | std::ios_base::out);
|
||||
if (file) {
|
||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
|
||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
|
||||
BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size()));
|
||||
BinaryIO::BinaryWrite(file, size_t(allowList ? m_ApprovedWords.size() : m_DeniedWords.size()));
|
||||
|
||||
for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) {
|
||||
for (size_t word : allowList ? m_ApprovedWords : m_DeniedWords) {
|
||||
BinaryIO::BinaryWrite(file, word);
|
||||
}
|
||||
|
||||
@@ -105,10 +105,10 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) {
|
||||
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList) {
|
||||
if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
|
||||
if (message.empty()) return { };
|
||||
if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } };
|
||||
if (!allowList && m_DeniedWords.empty()) return { { 0, message.length() } };
|
||||
|
||||
std::stringstream sMessage(message);
|
||||
std::string segment;
|
||||
@@ -126,16 +126,16 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
|
||||
|
||||
size_t hash = CalculateHash(segment);
|
||||
|
||||
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) {
|
||||
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && allowList) {
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) {
|
||||
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && allowList) {
|
||||
m_UserUnapprovedWordCache.push_back(hash);
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) {
|
||||
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !allowList) {
|
||||
m_UserUnapprovedWordCache.push_back(hash);
|
||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ public:
|
||||
dChatFilter(const std::string& filepath, bool dontGenerateDCF);
|
||||
~dChatFilter();
|
||||
|
||||
void ReadWordlistPlaintext(const std::string& filepath, bool whiteList);
|
||||
bool ReadWordlistDCF(const std::string& filepath, bool whiteList);
|
||||
void ExportWordlistToDCF(const std::string& filepath, bool whiteList);
|
||||
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true);
|
||||
void ReadWordlistPlaintext(const std::string& filepath, bool allowList);
|
||||
bool ReadWordlistDCF(const std::string& filepath, bool allowList);
|
||||
void ExportWordlistToDCF(const std::string& filepath, bool allowList);
|
||||
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList = true);
|
||||
|
||||
private:
|
||||
bool m_DontGenerateDCF;
|
||||
|
||||
@@ -2,13 +2,17 @@ set(DCHATSERVER_SOURCES
|
||||
"ChatIgnoreList.cpp"
|
||||
"ChatPacketHandler.cpp"
|
||||
"PlayerContainer.cpp"
|
||||
"ChatWebAPI.cpp"
|
||||
"JSONUtils.cpp"
|
||||
)
|
||||
|
||||
add_executable(ChatServer "ChatServer.cpp")
|
||||
add_library(dChatServer ${DCHATSERVER_SOURCES})
|
||||
target_include_directories(dChatServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer)
|
||||
target_include_directories(ChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dChatFilter")
|
||||
add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
|
||||
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
|
||||
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer)
|
||||
add_library(dChatServer ${DCHATSERVER_SOURCES})
|
||||
target_include_directories(dChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dServer")
|
||||
|
||||
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
|
||||
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer mongoose)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "ChatIgnoreList.h"
|
||||
#include "PlayerContainer.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "MessageType/Chat.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
@@ -13,7 +13,7 @@
|
||||
// The only thing not auto-handled is instance activities force joining the team on the server.
|
||||
|
||||
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) {
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receivingPlayer);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -59,7 +59,7 @@ void ChatIgnoreList::GetIgnoreList(Packet* packet) {
|
||||
bitStream.Write(LUWString(ignoredPlayer.playerName, 36));
|
||||
}
|
||||
|
||||
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||
Game::server->Send(bitStream, packet->systemAddress, false);
|
||||
}
|
||||
|
||||
void ChatIgnoreList::AddIgnore(Packet* packet) {
|
||||
@@ -131,7 +131,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) {
|
||||
bitStream.Write(playerNameSend);
|
||||
bitStream.Write(ignoredPlayerId);
|
||||
|
||||
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||
Game::server->Send(bitStream, packet->systemAddress, false);
|
||||
}
|
||||
|
||||
void ChatIgnoreList::RemoveIgnore(Packet* packet) {
|
||||
@@ -167,5 +167,5 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) {
|
||||
LUWString playerNameSend(removedIgnoreStr, 33);
|
||||
bitStream.Write(playerNameSend);
|
||||
|
||||
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||
Game::server->Send(bitStream, packet->systemAddress, false);
|
||||
}
|
||||
|
||||
@@ -13,12 +13,12 @@
|
||||
#include "dConfig.h"
|
||||
#include "eObjectBits.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eChatMessageType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "eClientMessageType.h"
|
||||
#include "eGameMessageType.h"
|
||||
#include "MessageType/Chat.h"
|
||||
#include "MessageType/Client.h"
|
||||
#include "MessageType/Game.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "ChatPackets.h"
|
||||
|
||||
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
//Get from the packet which player we want to do something with:
|
||||
@@ -49,7 +49,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
fd.zoneID = fr.zoneID;
|
||||
|
||||
//Since this friend is online, we need to update them on the fact that we've just logged in:
|
||||
SendFriendUpdate(fr, player, 1, fd.isBestFriend);
|
||||
if (player.isLogin) SendFriendUpdate(fr, player, 1, fd.isBestFriend);
|
||||
} else {
|
||||
fd.isOnline = false;
|
||||
fd.zoneID = LWOZONEID();
|
||||
@@ -60,11 +60,11 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
|
||||
//Now, we need to send the friendlist to the server they came from:
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(playerID);
|
||||
|
||||
//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<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it.
|
||||
bitStream.Write<uint16_t>(player.friends.size());
|
||||
@@ -103,7 +103,8 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
return;
|
||||
};
|
||||
|
||||
auto& requestee = Game::playerContainer.GetPlayerDataMutable(playerName);
|
||||
// Intentional copy
|
||||
PlayerData requestee = Game::playerContainer.GetPlayerData(playerName);
|
||||
|
||||
// Check if player is online first
|
||||
if (isBestFriendRequest && !requestee) {
|
||||
@@ -140,7 +141,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
|
||||
// Prevent GM friend spam
|
||||
// If the player we are trying to be friends with is not a civilian and we are a civilian, abort the process
|
||||
if (requestee.gmLevel > eGameMasterLevel::CIVILIAN && requestor.gmLevel == eGameMasterLevel::CIVILIAN ) {
|
||||
if (requestee.gmLevel > eGameMasterLevel::CIVILIAN && requestor.gmLevel == eGameMasterLevel::CIVILIAN) {
|
||||
SendFriendResponse(requestor, requestee, eAddFriendResponseType::MYTHRAN);
|
||||
return;
|
||||
}
|
||||
@@ -188,19 +189,24 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
Database::Get()->SetBestFriendStatus(requestorPlayerID, requestee.playerID, bestFriendStatus);
|
||||
// Sent the best friend update here if the value is 3
|
||||
if (bestFriendStatus == 3U) {
|
||||
requestee.countOfBestFriends += 1;
|
||||
requestor.countOfBestFriends += 1;
|
||||
if (requestee.sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee, requestor, eAddFriendResponseType::ACCEPTED, false, true);
|
||||
if (requestor.sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee, eAddFriendResponseType::ACCEPTED, false, true);
|
||||
|
||||
for (auto& friendData : requestor.friends) {
|
||||
if (friendData.friendID == requestee.playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
}
|
||||
}
|
||||
for (auto& friendData : requestee.friends) {
|
||||
if (friendData.friendID == requestor.playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
requestor.countOfBestFriends += 1;
|
||||
|
||||
auto& toModify = Game::playerContainer.GetPlayerDataMutable(playerName);
|
||||
if (toModify) {
|
||||
for (auto& friendData : toModify.friends) {
|
||||
if (friendData.friendID == requestor.playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
}
|
||||
}
|
||||
toModify.countOfBestFriends += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -355,7 +361,68 @@ void ChatPacketHandler::HandleGMLevelUpdate(Packet* packet) {
|
||||
inStream.Read(player.gmLevel);
|
||||
}
|
||||
|
||||
// the structure the client uses to send this packet is shared in many chat messages
|
||||
|
||||
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
|
||||
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages
|
||||
void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
@@ -367,7 +434,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
|
||||
eChatChannel channel;
|
||||
uint32_t size;
|
||||
|
||||
|
||||
inStream.IgnoreBytes(4);
|
||||
inStream.Read(channel);
|
||||
inStream.Read(size);
|
||||
@@ -375,7 +442,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
|
||||
LUWString message(size);
|
||||
inStream.Read(message);
|
||||
|
||||
|
||||
LOG("Got a message from (%s) via [%s]: %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str());
|
||||
|
||||
switch (channel) {
|
||||
@@ -396,7 +463,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* 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
|
||||
void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
@@ -423,7 +490,7 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
|
||||
LUWString message(size);
|
||||
inStream.Read(message);
|
||||
|
||||
|
||||
LOG("Got a message from (%s) via [%s]: %s to %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str(), receiverName.c_str());
|
||||
|
||||
const auto& receiver = Game::playerContainer.GetPlayerData(receiverName);
|
||||
@@ -454,10 +521,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) {
|
||||
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);
|
||||
|
||||
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(channel);
|
||||
bitStream.Write<uint32_t>(0); // not used
|
||||
@@ -696,11 +763,11 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
||||
|
||||
void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//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(sender.playerID);
|
||||
@@ -711,14 +778,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) {
|
||||
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);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver.playerID);
|
||||
bitStream.Write(eGameMessageType::TEAM_INVITE_CONFIRM);
|
||||
bitStream.Write(MessageType::Game::TEAM_INVITE_CONFIRM);
|
||||
|
||||
bitStream.Write(bLeaderIsFreeTrial);
|
||||
bitStream.Write(i64LeaderID);
|
||||
@@ -738,14 +805,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) {
|
||||
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);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver.playerID);
|
||||
bitStream.Write(eGameMessageType::TEAM_GET_STATUS_RESPONSE);
|
||||
bitStream.Write(MessageType::Game::TEAM_GET_STATUS_RESPONSE);
|
||||
|
||||
bitStream.Write(i64LeaderID);
|
||||
bitStream.Write(i64LeaderZoneID);
|
||||
@@ -763,14 +830,14 @@ void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64L
|
||||
|
||||
void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver.playerID);
|
||||
bitStream.Write(eGameMessageType::TEAM_SET_LEADER);
|
||||
bitStream.Write(MessageType::Game::TEAM_SET_LEADER);
|
||||
|
||||
bitStream.Write(i64PlayerID);
|
||||
|
||||
@@ -780,14 +847,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) {
|
||||
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);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver.playerID);
|
||||
bitStream.Write(eGameMessageType::TEAM_ADD_PLAYER);
|
||||
bitStream.Write(MessageType::Game::TEAM_ADD_PLAYER);
|
||||
|
||||
bitStream.Write(bIsFreeTrial);
|
||||
bitStream.Write(bLocal);
|
||||
@@ -809,14 +876,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) {
|
||||
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);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver.playerID);
|
||||
bitStream.Write(eGameMessageType::TEAM_REMOVE_PLAYER);
|
||||
bitStream.Write(MessageType::Game::TEAM_REMOVE_PLAYER);
|
||||
|
||||
bitStream.Write(bDisband);
|
||||
bitStream.Write(bIsKicked);
|
||||
@@ -835,14 +902,14 @@ void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bD
|
||||
|
||||
void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
CMSGHEADER;
|
||||
|
||||
bitStream.Write(receiver.playerID);
|
||||
bitStream.Write(eGameMessageType::TEAM_SET_OFF_WORLD_FLAG);
|
||||
bitStream.Write(MessageType::Game::TEAM_SET_OFF_WORLD_FLAG);
|
||||
|
||||
bitStream.Write(i64PlayerID);
|
||||
if (receiver.zoneID.GetCloneID() == zoneID.GetCloneID()) {
|
||||
@@ -869,11 +936,11 @@ void ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const Pla
|
||||
[bool] - is FTP*/
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(friendData.playerID);
|
||||
|
||||
//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);
|
||||
|
||||
std::string playerName = playerData.playerName.c_str();
|
||||
@@ -906,11 +973,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//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<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
|
||||
|
||||
@@ -920,11 +987,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) {
|
||||
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);
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
@@ -943,11 +1010,11 @@ void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const Pla
|
||||
|
||||
void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET);
|
||||
bitStream.Write(receiver.playerID);
|
||||
|
||||
//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(LUWString(personToRemove));
|
||||
|
||||
|
||||
@@ -50,6 +50,8 @@ namespace ChatPacketHandler {
|
||||
void HandleFriendResponse(Packet* packet);
|
||||
void HandleRemoveFriend(Packet* packet);
|
||||
void HandleGMLevelUpdate(Packet* packet);
|
||||
void HandleWho(Packet* packet);
|
||||
void HandleShowAll(Packet* packet);
|
||||
|
||||
void HandleChatMessage(Packet* packet);
|
||||
void HandlePrivateChatMessage(Packet* packet);
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
#include "eConnectionType.h"
|
||||
#include "PlayerContainer.h"
|
||||
#include "ChatPacketHandler.h"
|
||||
#include "eChatMessageType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "eWorldMessageType.h"
|
||||
#include "MessageType/Chat.h"
|
||||
#include "MessageType/World.h"
|
||||
#include "ChatIgnoreList.h"
|
||||
#include "StringifiedEnum.h"
|
||||
|
||||
@@ -29,6 +28,8 @@
|
||||
#include "RakNetDefines.h"
|
||||
#include "MessageIdentifiers.h"
|
||||
|
||||
#include "ChatWebAPI.h"
|
||||
|
||||
namespace Game {
|
||||
Logger* logger = nullptr;
|
||||
dServer* server = nullptr;
|
||||
@@ -75,41 +76,56 @@ int main(int argc, char** argv) {
|
||||
Game::assetManager = new AssetManager(clientPath);
|
||||
} catch (std::runtime_error& ex) {
|
||||
LOG("Got an error while setting up assets: %s", ex.what());
|
||||
|
||||
delete Game::logger;
|
||||
delete Game::config;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
//Connect to the MySQL Database
|
||||
try {
|
||||
Database::Connect();
|
||||
} catch (sql::SQLException& ex) {
|
||||
} catch (std::exception& ex) {
|
||||
LOG("Got an error while connecting to the database: %s", ex.what());
|
||||
Database::Destroy("ChatServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
delete Game::config;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// seyup the chat api web server
|
||||
bool web_server_enabled = Game::config->GetValue("web_server_enabled") == "1";
|
||||
ChatWebAPI chatwebapi;
|
||||
if (web_server_enabled && !chatwebapi.Startup()){
|
||||
// if we want the web api and it fails to start, exit
|
||||
LOG("Failed to start web server, shutting down.");
|
||||
Database::Destroy("ChatServer");
|
||||
delete Game::logger;
|
||||
delete Game::config;
|
||||
return EXIT_FAILURE;
|
||||
};
|
||||
|
||||
//Find out the master's IP:
|
||||
std::string masterIP;
|
||||
uint32_t masterPort = 1000;
|
||||
std::string masterPassword;
|
||||
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||
if (masterInfo) {
|
||||
masterIP = masterInfo->ip;
|
||||
masterPort = masterInfo->port;
|
||||
masterPassword = masterInfo->password;
|
||||
}
|
||||
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
||||
std::string ourIP = "localhost";
|
||||
const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999);
|
||||
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("chat_server_port")).value_or(1501);
|
||||
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("chat_server_port")).value_or(2005);
|
||||
const auto externalIPString = Game::config->GetValue("external_ip");
|
||||
if (!externalIPString.empty()) ourIP = externalIPString;
|
||||
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal, masterPassword);
|
||||
|
||||
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false);
|
||||
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
|
||||
|
||||
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
|
||||
Game::playerContainer.Initialize();
|
||||
@@ -123,6 +139,8 @@ int main(int argc, char** argv) {
|
||||
uint32_t framesSinceMasterDisconnect = 0;
|
||||
uint32_t framesSinceLastSQLPing = 0;
|
||||
|
||||
auto lastTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
Game::logger->Flush(); // once immediately before main loop
|
||||
while (!Game::ShouldShutdown()) {
|
||||
//Check if we're still connected to master:
|
||||
@@ -133,7 +151,11 @@ int main(int argc, char** argv) {
|
||||
break; //Exit our loop, shut down.
|
||||
} else framesSinceMasterDisconnect = 0;
|
||||
|
||||
//In world we'd update our other systems here.
|
||||
const auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
const float deltaTime = std::chrono::duration<float>(currentTime - lastTime).count();
|
||||
lastTime = currentTime;
|
||||
|
||||
Game::playerContainer.Update(deltaTime);
|
||||
|
||||
//Check for packets here:
|
||||
Game::server->ReceiveFromMaster(); //ReceiveFromMaster also handles the master packets if needed.
|
||||
@@ -144,6 +166,11 @@ int main(int argc, char** argv) {
|
||||
packet = nullptr;
|
||||
}
|
||||
|
||||
//Check and handle web requests:
|
||||
if (web_server_enabled) {
|
||||
chatwebapi.ReceiveRequests();
|
||||
}
|
||||
|
||||
//Push our log every 30s:
|
||||
if (framesSinceLastFlush >= logFlushTime) {
|
||||
Game::logger->Flush();
|
||||
@@ -169,7 +196,7 @@ int main(int argc, char** argv) {
|
||||
t += std::chrono::milliseconds(chatFrameDelta); //Chat can run at a lower "fps"
|
||||
std::this_thread::sleep_until(t);
|
||||
}
|
||||
|
||||
Game::playerContainer.Shutdown();
|
||||
//Delete our objects here:
|
||||
Database::Destroy("ChatServer");
|
||||
delete Game::server;
|
||||
@@ -180,185 +207,167 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
void HandlePacket(Packet* packet) {
|
||||
if (packet->length < 1) return;
|
||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||
LOG("A server has disconnected, erasing their connected players from the list.");
|
||||
}
|
||||
|
||||
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
||||
} else if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
||||
LOG("A server is connecting, awaiting user list.");
|
||||
}
|
||||
} else if (packet->length < 4 || packet->data[0] != ID_USER_PACKET_ENUM) return; // Nothing left to process or not the right packet type
|
||||
|
||||
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
|
||||
CINSTREAM;
|
||||
inStream.SetReadOffset(BYTES_TO_BITS(1));
|
||||
|
||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
|
||||
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
||||
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
||||
Game::playerContainer.InsertPlayer(packet);
|
||||
break;
|
||||
eConnectionType connection;
|
||||
MessageType::Chat chatMessageID;
|
||||
|
||||
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
||||
Game::playerContainer.RemovePlayer(packet);
|
||||
break;
|
||||
inStream.Read(connection);
|
||||
if (connection != eConnectionType::CHAT) return;
|
||||
inStream.Read(chatMessageID);
|
||||
|
||||
case eChatInternalMessageType::MUTE_UPDATE:
|
||||
Game::playerContainer.MuteUpdate(packet);
|
||||
break;
|
||||
switch (chatMessageID) {
|
||||
case MessageType::Chat::GM_MUTE:
|
||||
Game::playerContainer.MuteUpdate(packet);
|
||||
break;
|
||||
|
||||
case eChatInternalMessageType::CREATE_TEAM:
|
||||
Game::playerContainer.CreateTeamServer(packet);
|
||||
break;
|
||||
case MessageType::Chat::CREATE_TEAM:
|
||||
Game::playerContainer.CreateTeamServer(packet);
|
||||
break;
|
||||
|
||||
case eChatInternalMessageType::ANNOUNCEMENT: {
|
||||
//we just forward this packet to every connected server
|
||||
CINSTREAM;
|
||||
Game::server->Send(&inStream, packet->systemAddress, true); //send to everyone except origin
|
||||
break;
|
||||
}
|
||||
case MessageType::Chat::GET_FRIENDS_LIST:
|
||||
ChatPacketHandler::HandleFriendlistRequest(packet);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG("Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
|
||||
}
|
||||
}
|
||||
case MessageType::Chat::GET_IGNORE_LIST:
|
||||
ChatIgnoreList::GetIgnoreList(packet);
|
||||
break;
|
||||
|
||||
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);
|
||||
break;
|
||||
case MessageType::Chat::ADD_IGNORE:
|
||||
ChatIgnoreList::AddIgnore(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::GET_IGNORE_LIST:
|
||||
ChatIgnoreList::GetIgnoreList(packet);
|
||||
break;
|
||||
case MessageType::Chat::REMOVE_IGNORE:
|
||||
ChatIgnoreList::RemoveIgnore(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::ADD_IGNORE:
|
||||
ChatIgnoreList::AddIgnore(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_GET_STATUS:
|
||||
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::REMOVE_IGNORE:
|
||||
ChatIgnoreList::RemoveIgnore(packet);
|
||||
break;
|
||||
case MessageType::Chat::ADD_FRIEND_REQUEST:
|
||||
//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.
|
||||
ChatPacketHandler::HandleFriendRequest(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::TEAM_GET_STATUS:
|
||||
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
||||
break;
|
||||
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.
|
||||
//Here, we'll actually have to add them to eachother's friend lists depending on the response code.
|
||||
ChatPacketHandler::HandleFriendResponse(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::ADD_FRIEND_REQUEST:
|
||||
//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.
|
||||
ChatPacketHandler::HandleFriendRequest(packet);
|
||||
break;
|
||||
case MessageType::Chat::REMOVE_FRIEND:
|
||||
ChatPacketHandler::HandleRemoveFriend(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::ADD_FRIEND_RESPONSE:
|
||||
//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.
|
||||
ChatPacketHandler::HandleFriendResponse(packet);
|
||||
break;
|
||||
case MessageType::Chat::GENERAL_CHAT_MESSAGE:
|
||||
ChatPacketHandler::HandleChatMessage(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::REMOVE_FRIEND:
|
||||
ChatPacketHandler::HandleRemoveFriend(packet);
|
||||
break;
|
||||
case MessageType::Chat::PRIVATE_CHAT_MESSAGE:
|
||||
//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.
|
||||
ChatPacketHandler::HandlePrivateChatMessage(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::GENERAL_CHAT_MESSAGE:
|
||||
ChatPacketHandler::HandleChatMessage(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_INVITE:
|
||||
ChatPacketHandler::HandleTeamInvite(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::PRIVATE_CHAT_MESSAGE:
|
||||
//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.
|
||||
ChatPacketHandler::HandlePrivateChatMessage(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_INVITE_RESPONSE:
|
||||
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::TEAM_INVITE:
|
||||
ChatPacketHandler::HandleTeamInvite(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_LEAVE:
|
||||
ChatPacketHandler::HandleTeamLeave(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::TEAM_INVITE_RESPONSE:
|
||||
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_SET_LEADER:
|
||||
ChatPacketHandler::HandleTeamPromote(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::TEAM_LEAVE:
|
||||
ChatPacketHandler::HandleTeamLeave(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_KICK:
|
||||
ChatPacketHandler::HandleTeamKick(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::TEAM_SET_LEADER:
|
||||
ChatPacketHandler::HandleTeamPromote(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::TEAM_KICK:
|
||||
ChatPacketHandler::HandleTeamKick(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::TEAM_SET_LOOT:
|
||||
ChatPacketHandler::HandleTeamLootOption(packet);
|
||||
break;
|
||||
case eChatMessageType::GMLEVEL_UPDATE:
|
||||
ChatPacketHandler::HandleGMLevelUpdate(packet);
|
||||
break;
|
||||
case eChatMessageType::LOGIN_SESSION_NOTIFY:
|
||||
case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE:
|
||||
case eChatMessageType::WORLD_DISCONNECT_REQUEST:
|
||||
case eChatMessageType::WORLD_PROXIMITY_RESPONSE:
|
||||
case eChatMessageType::WORLD_PARCEL_RESPONSE:
|
||||
case eChatMessageType::TEAM_MISSED_INVITE_CHECK:
|
||||
case eChatMessageType::GUILD_CREATE:
|
||||
case eChatMessageType::GUILD_INVITE:
|
||||
case eChatMessageType::GUILD_INVITE_RESPONSE:
|
||||
case eChatMessageType::GUILD_LEAVE:
|
||||
case eChatMessageType::GUILD_KICK:
|
||||
case eChatMessageType::GUILD_GET_STATUS:
|
||||
case eChatMessageType::GUILD_GET_ALL:
|
||||
case eChatMessageType::SHOW_ALL:
|
||||
case eChatMessageType::BLUEPRINT_MODERATED:
|
||||
case eChatMessageType::BLUEPRINT_MODEL_READY:
|
||||
case eChatMessageType::PROPERTY_READY_FOR_APPROVAL:
|
||||
case eChatMessageType::PROPERTY_MODERATION_CHANGED:
|
||||
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED:
|
||||
case eChatMessageType::PROPERTY_BUILDMODE_CHANGED_REPORT:
|
||||
case eChatMessageType::MAIL:
|
||||
case eChatMessageType::WORLD_INSTANCE_LOCATION_REQUEST:
|
||||
case eChatMessageType::REPUTATION_UPDATE:
|
||||
case eChatMessageType::SEND_CANNED_TEXT:
|
||||
case eChatMessageType::CHARACTER_NAME_CHANGE_REQUEST:
|
||||
case eChatMessageType::CSR_REQUEST:
|
||||
case eChatMessageType::CSR_REPLY:
|
||||
case eChatMessageType::GM_KICK:
|
||||
case eChatMessageType::GM_ANNOUNCE:
|
||||
case eChatMessageType::WORLD_ROUTE_PACKET:
|
||||
case eChatMessageType::GET_ZONE_POPULATIONS:
|
||||
case eChatMessageType::REQUEST_MINIMUM_CHAT_MODE:
|
||||
case eChatMessageType::MATCH_REQUEST:
|
||||
case eChatMessageType::UGCMANIFEST_REPORT_MISSING_FILE:
|
||||
case eChatMessageType::UGCMANIFEST_REPORT_DONE_FILE:
|
||||
case eChatMessageType::UGCMANIFEST_REPORT_DONE_BLUEPRINT:
|
||||
case eChatMessageType::UGCC_REQUEST:
|
||||
case eChatMessageType::WHO:
|
||||
case eChatMessageType::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE:
|
||||
case eChatMessageType::ACHIEVEMENT_NOTIFY:
|
||||
case eChatMessageType::GM_CLOSE_PRIVATE_CHAT_WINDOW:
|
||||
case eChatMessageType::UNEXPECTED_DISCONNECT:
|
||||
case eChatMessageType::PLAYER_READY:
|
||||
case eChatMessageType::GET_DONATION_TOTAL:
|
||||
case eChatMessageType::UPDATE_DONATION:
|
||||
case eChatMessageType::PRG_CSR_COMMAND:
|
||||
case eChatMessageType::HEARTBEAT_REQUEST_FROM_WORLD:
|
||||
case eChatMessageType::UPDATE_FREE_TRIAL_STATUS:
|
||||
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chat_message_type).data(), chat_message_type);
|
||||
break;
|
||||
default:
|
||||
LOG("Unknown CHAT Message id: %i", chat_message_type);
|
||||
}
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
||||
case MessageType::Chat::TEAM_SET_LOOT:
|
||||
ChatPacketHandler::HandleTeamLootOption(packet);
|
||||
break;
|
||||
case MessageType::Chat::GMLEVEL_UPDATE:
|
||||
ChatPacketHandler::HandleGMLevelUpdate(packet);
|
||||
break;
|
||||
case MessageType::Chat::LOGIN_SESSION_NOTIFY:
|
||||
Game::playerContainer.InsertPlayer(packet);
|
||||
break;
|
||||
case MessageType::Chat::GM_ANNOUNCE:
|
||||
// we just forward this packet to every connected server
|
||||
inStream.ResetReadPointer();
|
||||
Game::server->Send(inStream, packet->systemAddress, true); // send to everyone except origin
|
||||
break;
|
||||
case MessageType::Chat::UNEXPECTED_DISCONNECT:
|
||||
Game::playerContainer.ScheduleRemovePlayer(packet);
|
||||
break;
|
||||
case MessageType::Chat::WHO:
|
||||
ChatPacketHandler::HandleWho(packet);
|
||||
break;
|
||||
case MessageType::Chat::SHOW_ALL:
|
||||
ChatPacketHandler::HandleShowAll(packet);
|
||||
break;
|
||||
case MessageType::Chat::USER_CHANNEL_CHAT_MESSAGE:
|
||||
case MessageType::Chat::WORLD_DISCONNECT_REQUEST:
|
||||
case MessageType::Chat::WORLD_PROXIMITY_RESPONSE:
|
||||
case MessageType::Chat::WORLD_PARCEL_RESPONSE:
|
||||
case MessageType::Chat::TEAM_MISSED_INVITE_CHECK:
|
||||
case MessageType::Chat::GUILD_CREATE:
|
||||
case MessageType::Chat::GUILD_INVITE:
|
||||
case MessageType::Chat::GUILD_INVITE_RESPONSE:
|
||||
case MessageType::Chat::GUILD_LEAVE:
|
||||
case MessageType::Chat::GUILD_KICK:
|
||||
case MessageType::Chat::GUILD_GET_STATUS:
|
||||
case MessageType::Chat::GUILD_GET_ALL:
|
||||
case MessageType::Chat::BLUEPRINT_MODERATED:
|
||||
case MessageType::Chat::BLUEPRINT_MODEL_READY:
|
||||
case MessageType::Chat::PROPERTY_READY_FOR_APPROVAL:
|
||||
case MessageType::Chat::PROPERTY_MODERATION_CHANGED:
|
||||
case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED:
|
||||
case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED_REPORT:
|
||||
case MessageType::Chat::MAIL:
|
||||
case MessageType::Chat::WORLD_INSTANCE_LOCATION_REQUEST:
|
||||
case MessageType::Chat::REPUTATION_UPDATE:
|
||||
case MessageType::Chat::SEND_CANNED_TEXT:
|
||||
case MessageType::Chat::CHARACTER_NAME_CHANGE_REQUEST:
|
||||
case MessageType::Chat::CSR_REQUEST:
|
||||
case MessageType::Chat::CSR_REPLY:
|
||||
case MessageType::Chat::GM_KICK:
|
||||
case MessageType::Chat::WORLD_ROUTE_PACKET:
|
||||
case MessageType::Chat::GET_ZONE_POPULATIONS:
|
||||
case MessageType::Chat::REQUEST_MINIMUM_CHAT_MODE:
|
||||
case MessageType::Chat::MATCH_REQUEST:
|
||||
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;
|
||||
default:
|
||||
LOG("Unknown CHAT Message id: %i", chatMessageID);
|
||||
}
|
||||
}
|
||||
|
||||
196
dChatServer/ChatWebAPI.cpp
Normal file
196
dChatServer/ChatWebAPI.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
#include "ChatWebAPI.h"
|
||||
|
||||
#include "Logger.h"
|
||||
#include "Game.h"
|
||||
#include "json.hpp"
|
||||
#include "dCommonVars.h"
|
||||
#include "MessageType/Chat.h"
|
||||
#include "dServer.h"
|
||||
#include "dConfig.h"
|
||||
#include "PlayerContainer.h"
|
||||
#include "JSONUtils.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "eHTTPMethod.h"
|
||||
#include "magic_enum.hpp"
|
||||
#include "ChatPackets.h"
|
||||
#include "StringifiedEnum.h"
|
||||
#include "Database.h"
|
||||
|
||||
#ifdef DARKFLAME_PLATFORM_WIN32
|
||||
#pragma push_macro("DELETE")
|
||||
#undef DELETE
|
||||
#endif
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
typedef struct mg_connection mg_connection;
|
||||
typedef struct mg_http_message mg_http_message;
|
||||
|
||||
namespace {
|
||||
const char* json_content_type = "Content-Type: application/json\r\n";
|
||||
std::map<std::pair<eHTTPMethod, std::string>, WebAPIHTTPRoute> Routes {};
|
||||
}
|
||||
|
||||
bool ValidateAuthentication(const mg_http_message* http_msg) {
|
||||
// TO DO: This is just a placeholder for now
|
||||
// use tokens or something at a later point if we want to implement authentication
|
||||
// bit using the listen bind address to limit external access is good enough to start with
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ValidateJSON(std::optional<json> data, HTTPReply& reply) {
|
||||
if (!data) {
|
||||
reply.status = eHTTPStatusCode::BAD_REQUEST;
|
||||
reply.message = "{\"error\":\"Invalid JSON\"}";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandlePlayersRequest(HTTPReply& reply, std::string body) {
|
||||
const json data = Game::playerContainer;
|
||||
reply.status = data.empty() ? eHTTPStatusCode::NO_CONTENT : eHTTPStatusCode::OK;
|
||||
reply.message = data.empty() ? "{\"error\":\"No Players Online\"}" : data.dump();
|
||||
}
|
||||
|
||||
void HandleTeamsRequest(HTTPReply& reply, std::string body) {
|
||||
const json data = Game::playerContainer.GetTeamContainer();
|
||||
reply.status = data.empty() ? eHTTPStatusCode::NO_CONTENT : eHTTPStatusCode::OK;
|
||||
reply.message = data.empty() ? "{\"error\":\"No Teams Online\"}" : data.dump();
|
||||
}
|
||||
|
||||
void HandleAnnounceRequest(HTTPReply& reply, std::string body) {
|
||||
auto data = GeneralUtils::TryParse<json>(body);
|
||||
if (!ValidateJSON(data, reply)) return;
|
||||
|
||||
const auto& good_data = data.value();
|
||||
auto check = JSONUtils::CheckRequiredData(good_data, { "title", "message" });
|
||||
if (!check.empty()) {
|
||||
reply.status = eHTTPStatusCode::BAD_REQUEST;
|
||||
reply.message = check;
|
||||
} else {
|
||||
|
||||
ChatPackets::Announcement announcement;
|
||||
announcement.title = good_data["title"];
|
||||
announcement.message = good_data["message"];
|
||||
announcement.Send();
|
||||
|
||||
reply.status = eHTTPStatusCode::OK;
|
||||
reply.message = "{\"status\":\"Announcement Sent\"}";
|
||||
}
|
||||
}
|
||||
|
||||
void HandleInvalidRoute(HTTPReply& reply) {
|
||||
reply.status = eHTTPStatusCode::NOT_FOUND;
|
||||
reply.message = "{\"error\":\"Invalid Route\"}";
|
||||
}
|
||||
|
||||
void HandleHTTPMessage(mg_connection* connection, const mg_http_message* http_msg) {
|
||||
HTTPReply reply;
|
||||
|
||||
if (!http_msg) {
|
||||
reply.status = eHTTPStatusCode::BAD_REQUEST;
|
||||
reply.message = "{\"error\":\"Invalid Request\"}";
|
||||
} else if (ValidateAuthentication(http_msg)) {
|
||||
|
||||
// convert method from cstring to std string
|
||||
std::string method_string(http_msg->method.buf, http_msg->method.len);
|
||||
// get mehtod from mg to enum
|
||||
const eHTTPMethod method = magic_enum::enum_cast<eHTTPMethod>(method_string).value_or(eHTTPMethod::INVALID);
|
||||
|
||||
// convert uri from cstring to std string
|
||||
std::string uri(http_msg->uri.buf, http_msg->uri.len);
|
||||
std::transform(uri.begin(), uri.end(), uri.begin(), ::tolower);
|
||||
|
||||
// convert body from cstring to std string
|
||||
std::string body(http_msg->body.buf, http_msg->body.len);
|
||||
|
||||
|
||||
const auto routeItr = Routes.find({method, uri});
|
||||
|
||||
if (routeItr != Routes.end()) {
|
||||
const auto& [_, route] = *routeItr;
|
||||
route.handle(reply, body);
|
||||
} else HandleInvalidRoute(reply);
|
||||
} else {
|
||||
reply.status = eHTTPStatusCode::UNAUTHORIZED;
|
||||
reply.message = "{\"error\":\"Unauthorized\"}";
|
||||
}
|
||||
mg_http_reply(connection, static_cast<int>(reply.status), json_content_type, reply.message.c_str());
|
||||
}
|
||||
|
||||
|
||||
void HandleRequests(mg_connection* connection, int request, void* request_data) {
|
||||
switch (request) {
|
||||
case MG_EV_HTTP_MSG:
|
||||
HandleHTTPMessage(connection, static_cast<mg_http_message*>(request_data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ChatWebAPI::RegisterHTTPRoutes(WebAPIHTTPRoute route) {
|
||||
auto [_, success] = Routes.try_emplace({ route.method, route.path }, route);
|
||||
if (!success) {
|
||||
LOG_DEBUG("Failed to register route %s", route.path.c_str());
|
||||
} else {
|
||||
LOG_DEBUG("Registered route %s", route.path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ChatWebAPI::ChatWebAPI() {
|
||||
mg_log_set(MG_LL_NONE);
|
||||
mg_mgr_init(&mgr); // Initialize event manager
|
||||
}
|
||||
|
||||
ChatWebAPI::~ChatWebAPI() {
|
||||
mg_mgr_free(&mgr);
|
||||
}
|
||||
|
||||
bool ChatWebAPI::Startup() {
|
||||
// Make listen address
|
||||
std::string listen_ip = Game::config->GetValue("web_server_listen_ip");
|
||||
if (listen_ip == "localhost") listen_ip = "127.0.0.1";
|
||||
|
||||
const std::string& listen_port = Game::config->GetValue("web_server_listen_port");
|
||||
const std::string& listen_address = "http://" + listen_ip + ":" + listen_port;
|
||||
LOG("Starting web server on %s", listen_address.c_str());
|
||||
|
||||
// Create HTTP listener
|
||||
if (!mg_http_listen(&mgr, listen_address.c_str(), HandleRequests, NULL)) {
|
||||
LOG("Failed to create web server listener on %s", listen_port.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Register routes
|
||||
|
||||
// API v1 routes
|
||||
std::string v1_route = "/api/v1/";
|
||||
RegisterHTTPRoutes({
|
||||
.path = v1_route + "players",
|
||||
.method = eHTTPMethod::GET,
|
||||
.handle = HandlePlayersRequest
|
||||
});
|
||||
|
||||
RegisterHTTPRoutes({
|
||||
.path = v1_route + "teams",
|
||||
.method = eHTTPMethod::GET,
|
||||
.handle = HandleTeamsRequest
|
||||
});
|
||||
|
||||
RegisterHTTPRoutes({
|
||||
.path = v1_route + "announce",
|
||||
.method = eHTTPMethod::POST,
|
||||
.handle = HandleAnnounceRequest
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
void ChatWebAPI::ReceiveRequests() {
|
||||
mg_mgr_poll(&mgr, 15);
|
||||
}
|
||||
|
||||
#ifdef DARKFLAME_PLATFORM_WIN32
|
||||
#pragma pop_macro("DELETE")
|
||||
#endif
|
||||
36
dChatServer/ChatWebAPI.h
Normal file
36
dChatServer/ChatWebAPI.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef __CHATWEBAPI_H__
|
||||
#define __CHATWEBAPI_H__
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
#include "mongoose.h"
|
||||
#include "eHTTPStatusCode.h"
|
||||
|
||||
enum class eHTTPMethod;
|
||||
|
||||
typedef struct mg_mgr mg_mgr;
|
||||
|
||||
struct HTTPReply {
|
||||
eHTTPStatusCode status = eHTTPStatusCode::NOT_FOUND;
|
||||
std::string message = "{\"error\":\"Not Found\"}";
|
||||
};
|
||||
|
||||
struct WebAPIHTTPRoute {
|
||||
std::string path;
|
||||
eHTTPMethod method;
|
||||
std::function<void(HTTPReply&, const std::string&)> handle;
|
||||
};
|
||||
|
||||
class ChatWebAPI {
|
||||
public:
|
||||
ChatWebAPI();
|
||||
~ChatWebAPI();
|
||||
void ReceiveRequests();
|
||||
void RegisterHTTPRoutes(WebAPIHTTPRoute route);
|
||||
bool Startup();
|
||||
private:
|
||||
mg_mgr mgr;
|
||||
|
||||
};
|
||||
|
||||
#endif // __CHATWEBAPI_H__
|
||||
62
dChatServer/JSONUtils.cpp
Normal file
62
dChatServer/JSONUtils.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "JSONUtils.h"
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
void to_json(json& data, const PlayerData& playerData) {
|
||||
data["id"] = playerData.playerID;
|
||||
data["name"] = playerData.playerName;
|
||||
data["gm_level"] = playerData.gmLevel;
|
||||
data["muted"] = playerData.GetIsMuted();
|
||||
|
||||
auto& zoneID = data["zone_id"];
|
||||
zoneID["map_id"] = playerData.zoneID.GetMapID();
|
||||
zoneID["instance_id"] = playerData.zoneID.GetInstanceID();
|
||||
zoneID["clone_id"] = playerData.zoneID.GetCloneID();
|
||||
}
|
||||
|
||||
void to_json(json& data, const PlayerContainer& playerContainer) {
|
||||
data = json::array();
|
||||
for(auto& playerData : playerContainer.GetAllPlayers()) {
|
||||
if (playerData.first == LWOOBJID_EMPTY) continue;
|
||||
data.push_back(playerData.second);
|
||||
}
|
||||
}
|
||||
|
||||
void to_json(json& data, const TeamContainer& teamContainer) {
|
||||
for (auto& teamData : Game::playerContainer.GetTeams()) {
|
||||
if (!teamData) continue;
|
||||
data.push_back(*teamData);
|
||||
}
|
||||
}
|
||||
|
||||
void to_json(json& data, const TeamData& teamData) {
|
||||
data["id"] = teamData.teamID;
|
||||
data["loot_flag"] = teamData.lootFlag;
|
||||
data["local"] = teamData.local;
|
||||
|
||||
auto& leader = Game::playerContainer.GetPlayerData(teamData.leaderID);
|
||||
data["leader"] = leader.playerName;
|
||||
|
||||
auto& members = data["members"];
|
||||
for (auto& member : teamData.memberIDs) {
|
||||
auto& playerData = Game::playerContainer.GetPlayerData(member);
|
||||
|
||||
if (!playerData) continue;
|
||||
members.push_back(playerData);
|
||||
}
|
||||
}
|
||||
|
||||
std::string JSONUtils::CheckRequiredData(const json& data, const std::vector<std::string>& requiredData) {
|
||||
json check;
|
||||
check["error"] = json::array();
|
||||
for (const auto& required : requiredData) {
|
||||
if (!data.contains(required)) {
|
||||
check["error"].push_back("Missing Parameter: " + required);
|
||||
} else if (data[required] == "") {
|
||||
check["error"].push_back("Empty Parameter: " + required);
|
||||
}
|
||||
}
|
||||
return check["error"].empty() ? "" : check.dump();
|
||||
}
|
||||
17
dChatServer/JSONUtils.h
Normal file
17
dChatServer/JSONUtils.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef __JSONUTILS_H__
|
||||
#define __JSONUTILS_H__
|
||||
|
||||
#include "json_fwd.hpp"
|
||||
#include "PlayerContainer.h"
|
||||
|
||||
void to_json(nlohmann::json& data, const PlayerData& playerData);
|
||||
void to_json(nlohmann::json& data, const PlayerContainer& playerContainer);
|
||||
void to_json(nlohmann::json& data, const TeamContainer& teamData);
|
||||
void to_json(nlohmann::json& data, const TeamData& teamData);
|
||||
|
||||
namespace JSONUtils {
|
||||
// check required data for reqeust
|
||||
std::string CheckRequiredData(const nlohmann::json& data, const std::vector<std::string>& requiredData);
|
||||
}
|
||||
|
||||
#endif // __JSONUTILS_H__
|
||||
@@ -9,9 +9,9 @@
|
||||
#include "BitStreamUtils.h"
|
||||
#include "Database.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "ChatPackets.h"
|
||||
#include "dConfig.h"
|
||||
#include "MessageType/Chat.h"
|
||||
|
||||
void PlayerContainer::Initialize() {
|
||||
m_MaxNumberOfBestFriends =
|
||||
@@ -32,34 +32,60 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto isLogin = !m_Players.contains(playerId);
|
||||
auto& data = m_Players[playerId];
|
||||
data = PlayerData();
|
||||
data.isLogin = isLogin;
|
||||
data.playerID = playerId;
|
||||
|
||||
uint32_t len;
|
||||
inStream.Read<uint32_t>(len);
|
||||
if (!inStream.Read<uint32_t>(len)) return;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
char character; inStream.Read<char>(character);
|
||||
data.playerName += character;
|
||||
if (len > 33) {
|
||||
LOG("Received a really long player name, probably a fake packet %i.", len);
|
||||
return;
|
||||
}
|
||||
|
||||
inStream.Read(data.zoneID);
|
||||
inStream.Read(data.muteExpire);
|
||||
inStream.Read(data.gmLevel);
|
||||
data.playerName.resize(len);
|
||||
inStream.ReadAlignedBytes(reinterpret_cast<unsigned char*>(data.playerName.data()), len);
|
||||
|
||||
if (!inStream.Read(data.zoneID)) return;
|
||||
if (!inStream.Read(data.muteExpire)) return;
|
||||
if (!inStream.Read(data.gmLevel)) return;
|
||||
data.sysAddr = packet->systemAddress;
|
||||
|
||||
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
|
||||
m_PlayerCount++;
|
||||
|
||||
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
|
||||
|
||||
Database::Get()->UpdateActivityLog(data.playerID, eActivityType::PlayerLoggedIn, data.zoneID.GetMapID());
|
||||
m_PlayersToRemove.erase(playerId);
|
||||
}
|
||||
|
||||
void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||
void PlayerContainer::ScheduleRemovePlayer(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
LWOOBJID playerID;
|
||||
LWOOBJID playerID{ LWOOBJID_EMPTY };
|
||||
inStream.Read(playerID);
|
||||
constexpr float updatePlayerOnLogoutTime = 20.0f;
|
||||
if (playerID != LWOOBJID_EMPTY) m_PlayersToRemove.insert_or_assign(playerID, updatePlayerOnLogoutTime);
|
||||
}
|
||||
|
||||
void PlayerContainer::Update(const float deltaTime) {
|
||||
for (auto it = m_PlayersToRemove.begin(); it != m_PlayersToRemove.end();) {
|
||||
auto& [id, time] = *it;
|
||||
time -= deltaTime;
|
||||
|
||||
if (time <= 0.0f) {
|
||||
RemovePlayer(id);
|
||||
it = m_PlayersToRemove.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerContainer::RemovePlayer(const LWOOBJID playerID) {
|
||||
//Before they get kicked, we need to also send a message to their friends saying that they disconnected.
|
||||
const auto& player = GetPlayerData(playerID);
|
||||
|
||||
@@ -87,6 +113,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||
}
|
||||
}
|
||||
|
||||
m_PlayerCount--;
|
||||
LOG("Removed user: %llu", playerID);
|
||||
m_Players.erase(playerID);
|
||||
|
||||
@@ -120,6 +147,11 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
|
||||
size_t membersSize = 0;
|
||||
inStream.Read(membersSize);
|
||||
|
||||
if (membersSize >= 4) {
|
||||
LOG("Tried to create a team with more than 4 players");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<LWOOBJID> members;
|
||||
|
||||
members.reserve(membersSize);
|
||||
@@ -138,19 +170,18 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
|
||||
|
||||
if (team != nullptr) {
|
||||
team->zoneId = zoneId;
|
||||
UpdateTeamsOnWorld(team, false);
|
||||
}
|
||||
|
||||
UpdateTeamsOnWorld(team, false);
|
||||
}
|
||||
|
||||
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_MUTE);
|
||||
|
||||
bitStream.Write(player);
|
||||
bitStream.Write(time);
|
||||
|
||||
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
}
|
||||
|
||||
TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
|
||||
@@ -188,7 +219,7 @@ TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) {
|
||||
team->leaderID = leader;
|
||||
team->local = local;
|
||||
|
||||
mTeams.push_back(team);
|
||||
GetTeamsMut().push_back(team);
|
||||
|
||||
AddMember(team, leader);
|
||||
|
||||
@@ -196,7 +227,7 @@ TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) {
|
||||
}
|
||||
|
||||
TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
|
||||
for (auto* team : mTeams) {
|
||||
for (auto* team : GetTeams()) {
|
||||
if (std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID) == team->memberIDs.end()) continue;
|
||||
|
||||
return team;
|
||||
@@ -304,9 +335,9 @@ void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) {
|
||||
}
|
||||
|
||||
void PlayerContainer::DisbandTeam(TeamData* team) {
|
||||
const auto index = std::find(mTeams.begin(), mTeams.end(), team);
|
||||
const auto index = std::find(GetTeams().begin(), GetTeams().end(), team);
|
||||
|
||||
if (index == mTeams.end()) return;
|
||||
if (index == GetTeams().end()) return;
|
||||
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
const auto& otherMember = GetPlayerData(memberId);
|
||||
@@ -321,15 +352,15 @@ void PlayerContainer::DisbandTeam(TeamData* team) {
|
||||
|
||||
UpdateTeamsOnWorld(team, true);
|
||||
|
||||
mTeams.erase(index);
|
||||
GetTeamsMut().erase(index);
|
||||
|
||||
delete team;
|
||||
}
|
||||
|
||||
void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
||||
const auto index = std::find(mTeams.begin(), mTeams.end(), team);
|
||||
const auto index = std::find(GetTeams().begin(), GetTeams().end(), team);
|
||||
|
||||
if (index == mTeams.end()) return;
|
||||
if (index == GetTeams().end()) return;
|
||||
|
||||
const auto& leader = GetPlayerData(team->leaderID);
|
||||
|
||||
@@ -352,7 +383,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
||||
|
||||
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::TEAM_GET_STATUS);
|
||||
|
||||
bitStream.Write(team->teamID);
|
||||
bitStream.Write(deleteTeam);
|
||||
@@ -365,7 +396,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
||||
}
|
||||
}
|
||||
|
||||
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
}
|
||||
|
||||
std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
|
||||
@@ -390,7 +421,7 @@ LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
|
||||
}
|
||||
|
||||
PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) {
|
||||
return m_Players[playerID];
|
||||
return m_Players.contains(playerID) ? m_Players[playerID] : m_Players[LWOOBJID_EMPTY];
|
||||
}
|
||||
|
||||
PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) {
|
||||
@@ -408,3 +439,13 @@ const PlayerData& PlayerContainer::GetPlayerData(const LWOOBJID& playerID) {
|
||||
const PlayerData& PlayerContainer::GetPlayerData(const std::string& playerName) {
|
||||
return GetPlayerDataMutable(playerName);
|
||||
}
|
||||
|
||||
void PlayerContainer::Shutdown() {
|
||||
m_Players.erase(LWOOBJID_EMPTY);
|
||||
while (!m_Players.empty()) {
|
||||
const auto& [id, playerData] = *m_Players.begin();
|
||||
Database::Get()->UpdateActivityLog(id, eActivityType::PlayerLoggedOut, playerData.zoneID.GetMapID());
|
||||
m_Players.erase(m_Players.begin());
|
||||
}
|
||||
for (auto* team : GetTeams()) if (team) delete team;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
|
||||
enum class eGameMasterLevel : uint8_t;
|
||||
|
||||
struct TeamData;
|
||||
|
||||
struct TeamContainer {
|
||||
std::vector<TeamData*> mTeams;
|
||||
};
|
||||
|
||||
struct IgnoreData {
|
||||
IgnoreData(const std::string& name, const LWOOBJID& id) : playerName{ name }, playerId{ id } {}
|
||||
inline bool operator==(const std::string& other) const noexcept {
|
||||
@@ -46,8 +52,10 @@ struct PlayerData {
|
||||
std::vector<IgnoreData> ignoredPlayers;
|
||||
eGameMasterLevel gmLevel = static_cast<eGameMasterLevel>(0); // CIVILLIAN
|
||||
bool isFTP = false;
|
||||
bool isLogin = false;
|
||||
};
|
||||
|
||||
|
||||
struct TeamData {
|
||||
TeamData();
|
||||
LWOOBJID teamID = LWOOBJID_EMPTY; // Internal use
|
||||
@@ -62,15 +70,20 @@ class PlayerContainer {
|
||||
public:
|
||||
void Initialize();
|
||||
void InsertPlayer(Packet* packet);
|
||||
void RemovePlayer(Packet* packet);
|
||||
void ScheduleRemovePlayer(Packet* packet);
|
||||
void RemovePlayer(const LWOOBJID playerID);
|
||||
void MuteUpdate(Packet* packet);
|
||||
void CreateTeamServer(Packet* packet);
|
||||
void BroadcastMuteUpdate(LWOOBJID player, time_t time);
|
||||
void Shutdown();
|
||||
|
||||
const PlayerData& GetPlayerData(const LWOOBJID& playerID);
|
||||
const PlayerData& GetPlayerData(const std::string& playerName);
|
||||
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
||||
PlayerData& GetPlayerDataMutable(const std::string& playerName);
|
||||
uint32_t GetPlayerCount() { return m_PlayerCount; };
|
||||
uint32_t GetSimCount() { return m_SimCount; };
|
||||
const std::map<LWOOBJID, PlayerData>& GetAllPlayers() const { return m_Players; };
|
||||
|
||||
TeamData* CreateLocalTeam(std::vector<LWOOBJID> members);
|
||||
TeamData* CreateTeam(LWOOBJID leader, bool local = false);
|
||||
@@ -85,13 +98,22 @@ public:
|
||||
LWOOBJID GetId(const std::u16string& playerName);
|
||||
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
|
||||
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
|
||||
const TeamContainer& GetTeamContainer() { return m_TeamContainer; }
|
||||
std::vector<TeamData*>& GetTeamsMut() { return m_TeamContainer.mTeams; };
|
||||
const std::vector<TeamData*>& GetTeams() { return GetTeamsMut(); };
|
||||
|
||||
void Update(const float deltaTime);
|
||||
bool PlayerBeingRemoved(const LWOOBJID playerID) { return m_PlayersToRemove.contains(playerID); }
|
||||
|
||||
private:
|
||||
LWOOBJID m_TeamIDCounter = 0;
|
||||
std::map<LWOOBJID, PlayerData> m_Players;
|
||||
std::vector<TeamData*> mTeams;
|
||||
TeamContainer m_TeamContainer{};
|
||||
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
||||
std::map<LWOOBJID, float> m_PlayersToRemove;
|
||||
uint32_t m_MaxNumberOfBestFriends = 5;
|
||||
uint32_t m_MaxNumberOfFriends = 50;
|
||||
uint32_t m_PlayerCount = 0;
|
||||
uint32_t m_SimCount = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,83 +9,63 @@
|
||||
* AMF3 Deserializer written by EmosewaMC
|
||||
*/
|
||||
|
||||
AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
|
||||
if (!inStream) return nullptr;
|
||||
AMFBaseValue* returnValue = nullptr;
|
||||
std::unique_ptr<AMFBaseValue> AMFDeserialize::Read(RakNet::BitStream& inStream) {
|
||||
// Read in the value type from the bitStream
|
||||
eAmf marker;
|
||||
inStream->Read(marker);
|
||||
inStream.Read(marker);
|
||||
// Based on the typing, create the value associated with that and return the base value class
|
||||
switch (marker) {
|
||||
case eAmf::Undefined: {
|
||||
returnValue = new AMFBaseValue();
|
||||
break;
|
||||
}
|
||||
|
||||
case eAmf::Null: {
|
||||
returnValue = new AMFNullValue();
|
||||
break;
|
||||
}
|
||||
|
||||
case eAmf::False: {
|
||||
returnValue = new AMFBoolValue(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case eAmf::True: {
|
||||
returnValue = new AMFBoolValue(true);
|
||||
break;
|
||||
}
|
||||
|
||||
case eAmf::Integer: {
|
||||
returnValue = ReadAmfInteger(inStream);
|
||||
break;
|
||||
}
|
||||
|
||||
case eAmf::Double: {
|
||||
returnValue = ReadAmfDouble(inStream);
|
||||
break;
|
||||
}
|
||||
|
||||
case eAmf::String: {
|
||||
returnValue = ReadAmfString(inStream);
|
||||
break;
|
||||
}
|
||||
|
||||
case eAmf::Array: {
|
||||
returnValue = ReadAmfArray(inStream);
|
||||
break;
|
||||
}
|
||||
case eAmf::Undefined:
|
||||
return std::make_unique<AMFBaseValue>();
|
||||
case eAmf::Null:
|
||||
return std::make_unique<AMFNullValue>();
|
||||
case eAmf::False:
|
||||
return std::make_unique<AMFBoolValue>(false);
|
||||
case eAmf::True:
|
||||
return std::make_unique<AMFBoolValue>(true);
|
||||
case eAmf::Integer:
|
||||
return ReadAmfInteger(inStream);
|
||||
case eAmf::Double:
|
||||
return ReadAmfDouble(inStream);
|
||||
case eAmf::String:
|
||||
return ReadAmfString(inStream);
|
||||
case eAmf::Array:
|
||||
return ReadAmfArray(inStream);
|
||||
|
||||
// These values are unimplemented in the live client and will remain unimplemented
|
||||
// unless someone modifies the client to allow serializing of these values.
|
||||
case eAmf::XMLDoc:
|
||||
[[fallthrough]];
|
||||
case eAmf::Date:
|
||||
[[fallthrough]];
|
||||
case eAmf::Object:
|
||||
[[fallthrough]];
|
||||
case eAmf::XML:
|
||||
[[fallthrough]];
|
||||
case eAmf::ByteArray:
|
||||
[[fallthrough]];
|
||||
case eAmf::VectorInt:
|
||||
[[fallthrough]];
|
||||
case eAmf::VectorUInt:
|
||||
[[fallthrough]];
|
||||
case eAmf::VectorDouble:
|
||||
[[fallthrough]];
|
||||
case eAmf::VectorObject:
|
||||
case eAmf::Dictionary: {
|
||||
[[fallthrough]];
|
||||
case eAmf::Dictionary:
|
||||
throw marker;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::invalid_argument("Invalid AMF3 marker" + std::to_string(static_cast<int32_t>(marker)));
|
||||
break;
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
|
||||
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) {
|
||||
bool byteFlag = true;
|
||||
uint32_t actualNumber{};
|
||||
uint8_t numberOfBytesRead{};
|
||||
while (byteFlag && numberOfBytesRead < 4) {
|
||||
uint8_t byte{};
|
||||
inStream->Read(byte);
|
||||
inStream.Read(byte);
|
||||
// Parse the byte
|
||||
if (numberOfBytesRead < 3) {
|
||||
byteFlag = byte & static_cast<uint8_t>(1 << 7);
|
||||
@@ -101,7 +81,7 @@ uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
|
||||
return actualNumber;
|
||||
}
|
||||
|
||||
const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
|
||||
const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) {
|
||||
auto length = ReadU29(inStream);
|
||||
// Check if this is a reference
|
||||
bool isReference = length % 2 == 1;
|
||||
@@ -109,7 +89,7 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
|
||||
length = length >> 1;
|
||||
if (isReference) {
|
||||
std::string value(length, 0);
|
||||
inStream->Read(&value[0], length);
|
||||
inStream.Read(&value[0], length);
|
||||
// Empty strings are never sent by reference
|
||||
if (!value.empty()) accessedElements.push_back(value);
|
||||
return value;
|
||||
@@ -119,20 +99,20 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
|
||||
}
|
||||
}
|
||||
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
|
||||
std::unique_ptr<AMFDoubleValue> AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) {
|
||||
double value;
|
||||
inStream->Read<double>(value);
|
||||
return new AMFDoubleValue(value);
|
||||
inStream.Read<double>(value);
|
||||
return std::make_unique<AMFDoubleValue>(value);
|
||||
}
|
||||
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
|
||||
auto arrayValue = new AMFArrayValue();
|
||||
std::unique_ptr<AMFArrayValue> AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) {
|
||||
auto arrayValue = std::make_unique<AMFArrayValue>();
|
||||
|
||||
// Read size of dense array
|
||||
auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
|
||||
const auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
|
||||
// Then read associative portion
|
||||
while (true) {
|
||||
auto key = ReadString(inStream);
|
||||
const auto key = ReadString(inStream);
|
||||
// No more associative values when we encounter an empty string key
|
||||
if (key.size() == 0) break;
|
||||
arrayValue->Insert(key, Read(inStream));
|
||||
@@ -144,10 +124,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
|
||||
return arrayValue;
|
||||
}
|
||||
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
|
||||
return new AMFStringValue(ReadString(inStream));
|
||||
std::unique_ptr<AMFStringValue> AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) {
|
||||
return std::make_unique<AMFStringValue>(ReadString(inStream));
|
||||
}
|
||||
|
||||
AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
|
||||
return new AMFIntValue(ReadU29(inStream));
|
||||
std::unique_ptr<AMFIntValue> AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) {
|
||||
return std::make_unique<AMFIntValue>(ReadU29(inStream)); // NOTE: NARROWING CONVERSION FROM UINT TO INT. IS THIS INTENDED?
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Amf3.h"
|
||||
#include "BitStream.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class AMFBaseValue;
|
||||
|
||||
class AMFDeserialize {
|
||||
public:
|
||||
/**
|
||||
@@ -15,7 +15,7 @@ public:
|
||||
* @param inStream inStream to read value from.
|
||||
* @return Returns an AMFValue with all the information from the bitStream in it.
|
||||
*/
|
||||
AMFBaseValue* Read(RakNet::BitStream* inStream);
|
||||
std::unique_ptr<AMFBaseValue> Read(RakNet::BitStream& inStream);
|
||||
private:
|
||||
/**
|
||||
* @brief Private method to read a U29 integer from a bitstream
|
||||
@@ -23,7 +23,7 @@ private:
|
||||
* @param inStream bitstream to read data from
|
||||
* @return The number as an unsigned 29 bit integer
|
||||
*/
|
||||
uint32_t ReadU29(RakNet::BitStream* inStream);
|
||||
static uint32_t ReadU29(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Reads a string from a bitstream
|
||||
@@ -31,7 +31,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return The read string
|
||||
*/
|
||||
const std::string ReadString(RakNet::BitStream* inStream);
|
||||
const std::string ReadString(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFDouble value from a bitStream
|
||||
@@ -39,7 +39,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Double value represented as an AMFValue
|
||||
*/
|
||||
AMFBaseValue* ReadAmfDouble(RakNet::BitStream* inStream);
|
||||
static std::unique_ptr<AMFDoubleValue> ReadAmfDouble(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFArray from a bitStream
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Array value represented as an AMFValue
|
||||
*/
|
||||
AMFBaseValue* ReadAmfArray(RakNet::BitStream* inStream);
|
||||
std::unique_ptr<AMFArrayValue> ReadAmfArray(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFString from a bitStream
|
||||
@@ -55,7 +55,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return String value represented as an AMFValue
|
||||
*/
|
||||
AMFBaseValue* ReadAmfString(RakNet::BitStream* inStream);
|
||||
std::unique_ptr<AMFStringValue> ReadAmfString(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* @brief Read an AMFInteger from a bitStream
|
||||
@@ -63,7 +63,7 @@ private:
|
||||
* @param inStream bitStream to read data from
|
||||
* @return Integer value represented as an AMFValue
|
||||
*/
|
||||
AMFBaseValue* ReadAmfInteger(RakNet::BitStream* inStream);
|
||||
static std::unique_ptr<AMFIntValue> ReadAmfInteger(RakNet::BitStream& inStream);
|
||||
|
||||
/**
|
||||
* List of strings read so far saved to be read by reference.
|
||||
|
||||
191
dCommon/Amf3.h
191
dCommon/Amf3.h
@@ -5,6 +5,7 @@
|
||||
#include "Logger.h"
|
||||
#include "Game.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -39,22 +40,34 @@ public:
|
||||
// AMFValue template class instantiations
|
||||
template <typename ValueType>
|
||||
class AMFValue : public AMFBaseValue {
|
||||
static_assert(!std::is_same_v<ValueType, std::string_view>, "AMFValue cannot be instantiated with std::string_view");
|
||||
public:
|
||||
AMFValue() = default;
|
||||
AMFValue(const ValueType value) { m_Data = value; }
|
||||
AMFValue(const ValueType value) : m_Data{ value } {}
|
||||
|
||||
virtual ~AMFValue() override = default;
|
||||
|
||||
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override;
|
||||
|
||||
[[nodiscard]] const ValueType& GetValue() const { return m_Data; }
|
||||
|
||||
void SetValue(const ValueType value) { m_Data = value; }
|
||||
|
||||
AMFValue<ValueType>& operator=(const AMFValue<ValueType>& other) {
|
||||
return operator=(other.m_Data);
|
||||
}
|
||||
|
||||
AMFValue<ValueType>& operator=(const ValueType& other) {
|
||||
m_Data = other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
ValueType m_Data;
|
||||
};
|
||||
|
||||
// Explicit template class instantiations
|
||||
template class AMFValue<std::nullptr_t>;
|
||||
template class AMFValue<std::nullptr_t>;
|
||||
template class AMFValue<bool>;
|
||||
template class AMFValue<int32_t>;
|
||||
template class AMFValue<uint32_t>;
|
||||
@@ -103,36 +116,23 @@ using AMFDoubleValue = AMFValue<double>;
|
||||
* and are not to be deleted by a caller.
|
||||
*/
|
||||
class AMFArrayValue : public AMFBaseValue {
|
||||
using AMFAssociative = std::unordered_map<std::string, AMFBaseValue*>;
|
||||
using AMFDense = std::vector<AMFBaseValue*>;
|
||||
using AMFAssociative =
|
||||
std::unordered_map<std::string, std::unique_ptr<AMFBaseValue>, GeneralUtils::transparent_string_hash, std::equal_to<>>;
|
||||
|
||||
using AMFDense = std::vector<std::unique_ptr<AMFBaseValue>>;
|
||||
|
||||
public:
|
||||
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; }
|
||||
|
||||
~AMFArrayValue() override {
|
||||
for (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
|
||||
*/
|
||||
[[nodiscard]] inline AMFAssociative& GetAssociative() noexcept { return this->associative; }
|
||||
[[nodiscard]] inline const AMFAssociative& GetAssociative() const noexcept { return m_Associative; }
|
||||
|
||||
/**
|
||||
* Returns the dense portion of the object
|
||||
*/
|
||||
[[nodiscard]] inline AMFDense& GetDense() noexcept { return this->dense; }
|
||||
[[nodiscard]] inline const AMFDense& GetDense() const noexcept { return m_Dense; }
|
||||
|
||||
/**
|
||||
* Inserts an AMFValue into the associative portion with the given key.
|
||||
@@ -149,30 +149,32 @@ public:
|
||||
* or nullptr if a key existed and was not the same type
|
||||
*/
|
||||
template <typename ValueType>
|
||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string& key, const ValueType value) {
|
||||
auto element = associative.find(key);
|
||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string_view key, const ValueType value) {
|
||||
const auto element = m_Associative.find(key);
|
||||
AMFValue<ValueType>* val = nullptr;
|
||||
bool found = true;
|
||||
if (element == associative.end()) {
|
||||
val = new AMFValue<ValueType>(value);
|
||||
associative.insert(std::make_pair(key, val));
|
||||
if (element == m_Associative.cend()) {
|
||||
auto newVal = std::make_unique<AMFValue<ValueType>>(value);
|
||||
val = newVal.get();
|
||||
m_Associative.emplace(key, std::move(newVal));
|
||||
} else {
|
||||
val = dynamic_cast<AMFValue<ValueType>*>(element->second);
|
||||
val = dynamic_cast<AMFValue<ValueType>*>(element->second.get());
|
||||
found = false;
|
||||
}
|
||||
return std::make_pair(val, found);
|
||||
}
|
||||
|
||||
// Associates an array with a string key
|
||||
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string& key) {
|
||||
auto element = associative.find(key);
|
||||
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const std::string_view key) {
|
||||
const auto element = m_Associative.find(key);
|
||||
AMFArrayValue* val = nullptr;
|
||||
bool found = true;
|
||||
if (element == associative.end()) {
|
||||
val = new AMFArrayValue();
|
||||
associative.insert(std::make_pair(key, val));
|
||||
if (element == m_Associative.cend()) {
|
||||
auto newVal = std::make_unique<AMFArrayValue>();
|
||||
val = newVal.get();
|
||||
m_Associative.emplace(key, std::move(newVal));
|
||||
} else {
|
||||
val = dynamic_cast<AMFArrayValue*>(element->second);
|
||||
val = dynamic_cast<AMFArrayValue*>(element->second.get());
|
||||
found = false;
|
||||
}
|
||||
return std::make_pair(val, found);
|
||||
@@ -180,15 +182,13 @@ public:
|
||||
|
||||
// Associates an array with an integer key
|
||||
[[maybe_unused]] std::pair<AMFBaseValue*, bool> Insert(const size_t index) {
|
||||
AMFArrayValue* val = nullptr;
|
||||
bool inserted = false;
|
||||
if (index >= dense.size()) {
|
||||
dense.resize(index + 1);
|
||||
val = new AMFArrayValue();
|
||||
dense.at(index) = val;
|
||||
if (index >= m_Dense.size()) {
|
||||
m_Dense.resize(index + 1);
|
||||
m_Dense.at(index) = std::make_unique<AMFArrayValue>();
|
||||
inserted = true;
|
||||
}
|
||||
return std::make_pair(dynamic_cast<AMFArrayValue*>(dense.at(index)), inserted);
|
||||
return std::make_pair(dynamic_cast<AMFArrayValue*>(m_Dense.at(index).get()), inserted);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,15 +203,13 @@ public:
|
||||
*/
|
||||
template <typename ValueType>
|
||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) {
|
||||
AMFValue<ValueType>* val = nullptr;
|
||||
bool inserted = false;
|
||||
if (index >= this->dense.size()) {
|
||||
this->dense.resize(index + 1);
|
||||
val = new AMFValue<ValueType>(value);
|
||||
this->dense.at(index) = val;
|
||||
if (index >= m_Dense.size()) {
|
||||
m_Dense.resize(index + 1);
|
||||
m_Dense.at(index) = std::make_unique<AMFValue<ValueType>>(value);
|
||||
inserted = true;
|
||||
}
|
||||
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(this->dense.at(index)), inserted);
|
||||
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index).get()), inserted);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,14 +221,17 @@ public:
|
||||
* @param key The key to associate with the value
|
||||
* @param value The value to insert
|
||||
*/
|
||||
void Insert(const std::string& key, AMFBaseValue* const value) {
|
||||
auto element = associative.find(key);
|
||||
if (element != associative.end() && element->second) {
|
||||
delete element->second;
|
||||
element->second = value;
|
||||
template<typename AmfType>
|
||||
AmfType& Insert(const std::string_view key, std::unique_ptr<AmfType> value) {
|
||||
const auto element = m_Associative.find(key);
|
||||
auto& toReturn = *value;
|
||||
if (element != m_Associative.cend() && element->second) {
|
||||
element->second = std::move(value);
|
||||
} else {
|
||||
associative.insert(std::make_pair(key, value));
|
||||
m_Associative.emplace(key, std::move(value));
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,14 +243,15 @@ public:
|
||||
* @param key The key to associate with the value
|
||||
* @param value The value to insert
|
||||
*/
|
||||
void Insert(const size_t index, AMFBaseValue* const value) {
|
||||
if (index < dense.size()) {
|
||||
AMFDense::iterator itr = dense.begin() + index;
|
||||
if (*itr) delete dense.at(index);
|
||||
} else {
|
||||
dense.resize(index + 1);
|
||||
template<typename AmfType>
|
||||
AmfType& Insert(const size_t index, std::unique_ptr<AmfType> value) {
|
||||
auto& toReturn = *value;
|
||||
if (index >= m_Dense.size()) {
|
||||
m_Dense.resize(index + 1);
|
||||
}
|
||||
dense.at(index) = value;
|
||||
|
||||
m_Dense.at(index) = std::move(value);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,7 +266,7 @@ public:
|
||||
*/
|
||||
template <typename ValueType>
|
||||
[[maybe_unused]] inline AMFValue<ValueType>* Push(const ValueType value) {
|
||||
return Insert(this->dense.size(), value).first;
|
||||
return Insert(m_Dense.size(), value).first;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -274,11 +276,10 @@ public:
|
||||
*
|
||||
* @param key The key to remove from the associative portion
|
||||
*/
|
||||
void Remove(const std::string& key, const bool deleteValue = true) {
|
||||
AMFAssociative::iterator it = this->associative.find(key);
|
||||
if (it != this->associative.end()) {
|
||||
if (deleteValue) delete it->second;
|
||||
this->associative.erase(it);
|
||||
void Remove(const std::string& key) {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
if (it != m_Associative.cend()) {
|
||||
m_Associative.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,30 +287,26 @@ public:
|
||||
* Pops the last element in the dense portion, deleting it in the process.
|
||||
*/
|
||||
void Remove(const size_t index) {
|
||||
if (!this->dense.empty() && index < this->dense.size()) {
|
||||
auto itr = this->dense.begin() + index;
|
||||
if (*itr) delete (*itr);
|
||||
this->dense.erase(itr);
|
||||
if (!m_Dense.empty() && index < m_Dense.size()) {
|
||||
const auto itr = m_Dense.cbegin() + index;
|
||||
m_Dense.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
void Pop() {
|
||||
if (!this->dense.empty()) Remove(this->dense.size() - 1);
|
||||
if (!m_Dense.empty()) Remove(m_Dense.size() - 1);
|
||||
}
|
||||
|
||||
[[nodiscard]] AMFArrayValue* GetArray(const std::string& key) {
|
||||
AMFAssociative::const_iterator it = this->associative.find(key);
|
||||
if (it != this->associative.end()) {
|
||||
return dynamic_cast<AMFArrayValue*>(it->second);
|
||||
}
|
||||
return nullptr;
|
||||
[[nodiscard]] AMFArrayValue* GetArray(const std::string_view key) const {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
return it != m_Associative.cend() ? dynamic_cast<AMFArrayValue*>(it->second.get()) : nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) {
|
||||
return index >= this->dense.size() ? nullptr : dynamic_cast<AMFArrayValue*>(this->dense.at(index));
|
||||
[[nodiscard]] AMFArrayValue* GetArray(const size_t index) const {
|
||||
return index < m_Dense.size() ? dynamic_cast<AMFArrayValue*>(m_Dense.at(index).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);
|
||||
}
|
||||
|
||||
@@ -318,7 +315,7 @@ public:
|
||||
}
|
||||
|
||||
[[maybe_unused]] inline AMFArrayValue* PushArray() {
|
||||
return static_cast<AMFArrayValue*>(Insert(this->dense.size()).first);
|
||||
return static_cast<AMFArrayValue*>(Insert(m_Dense.size()).first);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,17 +328,17 @@ public:
|
||||
* @return The AMFValue
|
||||
*/
|
||||
template <typename AmfType>
|
||||
[[nodiscard]] AMFValue<AmfType>* Get(const std::string& key) const {
|
||||
AMFAssociative::const_iterator it = this->associative.find(key);
|
||||
return it != this->associative.end() ?
|
||||
dynamic_cast<AMFValue<AmfType>*>(it->second) :
|
||||
[[nodiscard]] AMFValue<AmfType>* Get(const std::string_view key) const {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
return it != m_Associative.cend() ?
|
||||
dynamic_cast<AMFValue<AmfType>*>(it->second.get()) :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
// Get from the array but dont cast it
|
||||
[[nodiscard]] AMFBaseValue* Get(const std::string& key) const {
|
||||
AMFAssociative::const_iterator it = this->associative.find(key);
|
||||
return it != this->associative.end() ? it->second : nullptr;
|
||||
[[nodiscard]] AMFBaseValue* Get(const std::string_view key) const {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
return it != m_Associative.cend() ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,27 +352,39 @@ public:
|
||||
*/
|
||||
template <typename AmfType>
|
||||
[[nodiscard]] AMFValue<AmfType>* Get(const size_t index) const {
|
||||
return index < this->dense.size() ?
|
||||
dynamic_cast<AMFValue<AmfType>*>(this->dense.at(index)) :
|
||||
return index < m_Dense.size() ?
|
||||
dynamic_cast<AMFValue<AmfType>*>(m_Dense.at(index).get()) :
|
||||
nullptr;
|
||||
}
|
||||
|
||||
// Get from the dense but dont cast it
|
||||
[[nodiscard]] AMFBaseValue* Get(const size_t index) const {
|
||||
return index < this->dense.size() ? this->dense.at(index) : nullptr;
|
||||
return index < m_Dense.size() ? m_Dense.at(index).get() : nullptr;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
m_Associative.clear();
|
||||
m_Dense.clear();
|
||||
}
|
||||
|
||||
template<typename AmfType = AMFArrayValue>
|
||||
AmfType& PushDebug(const std::string_view name) {
|
||||
auto* value = PushArray();
|
||||
value->Insert("name", name.data());
|
||||
return value->Insert<AmfType>("value", std::make_unique<AmfType>());
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* The associative portion. These values are key'd with strings to an AMFValue.
|
||||
*/
|
||||
AMFAssociative associative;
|
||||
AMFAssociative m_Associative;
|
||||
|
||||
/**
|
||||
* The dense portion. These AMFValue's are stored one after
|
||||
* another with the most recent addition being at the back.
|
||||
*/
|
||||
AMFDense dense;
|
||||
AMFDense m_Dense;
|
||||
};
|
||||
|
||||
#endif //!__AMF3__H__
|
||||
|
||||
@@ -53,7 +53,7 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
|
||||
* A private function to write an value to a RakNet::BitStream
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
void WriteUInt29(RakNet::BitStream& bs, uint32_t v) {
|
||||
unsigned char b4 = static_cast<unsigned char>(v);
|
||||
if (v < 0x00200000) {
|
||||
b4 = b4 & 0x7F;
|
||||
@@ -65,10 +65,10 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
unsigned char b2;
|
||||
v = v >> 7;
|
||||
b2 = static_cast<unsigned char>(v) | 0x80;
|
||||
bs->Write(b2);
|
||||
bs.Write(b2);
|
||||
}
|
||||
|
||||
bs->Write(b3);
|
||||
bs.Write(b3);
|
||||
}
|
||||
} else {
|
||||
unsigned char b1;
|
||||
@@ -82,19 +82,19 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
v = v >> 7;
|
||||
b1 = static_cast<unsigned char>(v) | 0x80;
|
||||
|
||||
bs->Write(b1);
|
||||
bs->Write(b2);
|
||||
bs->Write(b3);
|
||||
bs.Write(b1);
|
||||
bs.Write(b2);
|
||||
bs.Write(b3);
|
||||
}
|
||||
|
||||
bs->Write(b4);
|
||||
bs.Write(b4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a flag number to a RakNet::BitStream
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
|
||||
void WriteFlagNumber(RakNet::BitStream& bs, uint32_t v) {
|
||||
v = (v << 1) | 0x01;
|
||||
WriteUInt29(bs, v);
|
||||
}
|
||||
@@ -104,9 +104,9 @@ void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
|
||||
*
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
|
||||
void WriteAMFString(RakNet::BitStream& bs, const std::string& str) {
|
||||
WriteFlagNumber(bs, static_cast<uint32_t>(str.size()));
|
||||
bs->Write(str.c_str(), static_cast<uint32_t>(str.size()));
|
||||
bs.Write(str.c_str(), static_cast<uint32_t>(str.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,8 +114,8 @@ void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
|
||||
*
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
|
||||
bs->Write(value);
|
||||
void WriteAMFU16(RakNet::BitStream& bs, uint16_t value) {
|
||||
bs.Write(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,8 +123,8 @@ void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
|
||||
*
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
|
||||
bs->Write(value);
|
||||
void WriteAMFU32(RakNet::BitStream& bs, uint32_t value) {
|
||||
bs.Write(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,40 +132,40 @@ void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
|
||||
*
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
|
||||
bs->Write(value);
|
||||
void WriteAMFU64(RakNet::BitStream& bs, uint64_t value) {
|
||||
bs.Write(value);
|
||||
}
|
||||
|
||||
// Writes an AMFIntegerValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) {
|
||||
WriteUInt29(this, value.GetValue());
|
||||
WriteUInt29(*this, value.GetValue());
|
||||
}
|
||||
|
||||
// Writes an AMFDoubleValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
|
||||
double d = value.GetValue();
|
||||
WriteAMFU64(this, *reinterpret_cast<uint64_t*>(&d));
|
||||
WriteAMFU64(*this, *reinterpret_cast<uint64_t*>(&d));
|
||||
}
|
||||
|
||||
// Writes an AMFStringValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFStringValue&>(AMFStringValue& value) {
|
||||
WriteAMFString(this, value.GetValue());
|
||||
WriteAMFString(*this, value.GetValue());
|
||||
}
|
||||
|
||||
// Writes an AMFArrayValue to BitStream
|
||||
template<>
|
||||
void RakNet::BitStream::Write<AMFArrayValue&>(AMFArrayValue& value) {
|
||||
uint32_t denseSize = value.GetDense().size();
|
||||
WriteFlagNumber(this, denseSize);
|
||||
WriteFlagNumber(*this, denseSize);
|
||||
|
||||
auto it = value.GetAssociative().begin();
|
||||
auto end = value.GetAssociative().end();
|
||||
|
||||
while (it != end) {
|
||||
WriteAMFString(this, it->first);
|
||||
WriteAMFString(*this, it->first);
|
||||
this->Write<AMFBaseValue&>(*it->second);
|
||||
it++;
|
||||
}
|
||||
|
||||
@@ -2,16 +2,25 @@
|
||||
#include <string>
|
||||
|
||||
//For reading null-terminated strings
|
||||
std::string BinaryIO::ReadString(std::istream& instream) {
|
||||
std::string toReturn;
|
||||
char buffer;
|
||||
template<typename StringType>
|
||||
StringType ReadString(std::istream& instream) {
|
||||
StringType toReturn{};
|
||||
typename StringType::value_type buffer{};
|
||||
|
||||
BinaryIO::BinaryRead(instream, buffer);
|
||||
|
||||
while (buffer != 0x00) {
|
||||
toReturn += buffer;
|
||||
BinaryRead(instream, buffer);
|
||||
BinaryIO::BinaryRead(instream, buffer);
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
std::string BinaryIO::ReadString(std::istream& instream) {
|
||||
return ::ReadString<std::string>(instream);
|
||||
}
|
||||
|
||||
std::u8string BinaryIO::ReadU8String(std::istream& instream) {
|
||||
return ::ReadString<std::u8string>(instream);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ namespace BinaryIO {
|
||||
|
||||
std::string ReadString(std::istream& instream);
|
||||
|
||||
std::u8string ReadU8String(std::istream& instream);
|
||||
|
||||
inline bool DoesFileExist(const std::string& name) {
|
||||
std::ifstream f(name.c_str());
|
||||
return f.good();
|
||||
|
||||
@@ -123,7 +123,7 @@ uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
|
||||
Database::Get()->UpdateUgcModelData(model.id, outputStringStream);
|
||||
LOG("Updated model %i to sd0", model.id);
|
||||
updatedModels++;
|
||||
} catch (sql::SQLException exception) {
|
||||
} catch (std::exception& exception) {
|
||||
LOG("Failed to update model %i. This model should be inspected manually to see why."
|
||||
"The database error is %s", model.id, exception.what());
|
||||
}
|
||||
|
||||
@@ -30,11 +30,14 @@ foreach(file ${DCOMMON_DCLIENT_SOURCES})
|
||||
set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}")
|
||||
endforeach()
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
|
||||
|
||||
add_library(dCommon STATIC ${DCOMMON_SOURCES})
|
||||
|
||||
target_link_libraries(dCommon bcrypt dDatabase tinyxml2)
|
||||
target_include_directories(dCommon
|
||||
PUBLIC "." "dClient" "dEnums"
|
||||
PRIVATE
|
||||
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase"
|
||||
"${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables"
|
||||
"${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase"
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
find_package(ZLIB REQUIRED)
|
||||
@@ -65,4 +68,6 @@ else ()
|
||||
)
|
||||
endif ()
|
||||
|
||||
target_link_libraries(dCommon ZLIB::ZLIB)
|
||||
target_link_libraries(dCommon
|
||||
PRIVATE ZLIB::ZLIB bcrypt tinyxml2
|
||||
INTERFACE dDatabase)
|
||||
|
||||
@@ -120,6 +120,8 @@ void CatchUnhandled(int sig) {
|
||||
if (eptr) std::rethrow_exception(eptr);
|
||||
} catch(const std::exception& e) {
|
||||
LOG("Caught exception: '%s'", e.what());
|
||||
} catch (...) {
|
||||
LOG("Caught unknown exception.");
|
||||
}
|
||||
|
||||
#ifndef INCLUDE_BACKTRACE
|
||||
@@ -199,7 +201,7 @@ void OnTerminate() {
|
||||
}
|
||||
|
||||
void MakeBacktrace() {
|
||||
struct sigaction sigact;
|
||||
struct sigaction sigact{};
|
||||
|
||||
sigact.sa_sigaction = CritErrHdlr;
|
||||
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
|
||||
@@ -65,13 +65,14 @@ int64_t FdbToSqlite::Convert::ReadInt64(std::istream& cdClientBuffer) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// cdclient is encoded in latin1
|
||||
std::string FdbToSqlite::Convert::ReadString(std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
auto readString = BinaryIO::ReadString(cdClientBuffer);
|
||||
const auto readString = BinaryIO::ReadU8String(cdClientBuffer);
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
return readString;
|
||||
return GeneralUtils::Latin1ToUTF8(readString);
|
||||
}
|
||||
|
||||
int32_t FdbToSqlite::Convert::SeekPointer(std::istream& cdClientBuffer) {
|
||||
|
||||
@@ -7,24 +7,28 @@
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
|
||||
#include "json.hpp"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
template <typename T>
|
||||
inline size_t MinSize(size_t size, const std::basic_string_view<T>& string) {
|
||||
if (size == size_t(-1) || size > string.size()) {
|
||||
static inline size_t MinSize(const size_t size, const std::basic_string_view<T> string) {
|
||||
if (size == SIZE_MAX || size > string.size()) {
|
||||
return string.size();
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IsLeadSurrogate(char16_t c) {
|
||||
inline bool IsLeadSurrogate(const char16_t c) {
|
||||
return (0xD800 <= c) && (c <= 0xDBFF);
|
||||
}
|
||||
|
||||
inline bool IsTrailSurrogate(char16_t c) {
|
||||
inline bool IsTrailSurrogate(const char16_t c) {
|
||||
return (0xDC00 <= c) && (c <= 0xDFFF);
|
||||
}
|
||||
|
||||
inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
||||
inline void PushUTF8CodePoint(std::string& ret, const char32_t cp) {
|
||||
if (cp <= 0x007F) {
|
||||
ret.push_back(static_cast<uint8_t>(cp));
|
||||
} else if (cp <= 0x07FF) {
|
||||
@@ -46,16 +50,16 @@ inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
||||
|
||||
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
||||
|
||||
bool _IsSuffixChar(uint8_t c) {
|
||||
bool static _IsSuffixChar(const uint8_t c) {
|
||||
return (c & 0xC0) == 0x80;
|
||||
}
|
||||
|
||||
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
size_t rem = slice.length();
|
||||
bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
const size_t rem = slice.length();
|
||||
if (slice.empty()) return false;
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
||||
if (rem > 0) {
|
||||
uint8_t first = bytes[0];
|
||||
const uint8_t first = bytes[0];
|
||||
if (first < 0x80) { // 1 byte character
|
||||
out = static_cast<uint32_t>(first & 0x7F);
|
||||
slice.remove_prefix(1);
|
||||
@@ -64,7 +68,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
// middle byte, not valid at start, fall through
|
||||
} else if (first < 0xE0) { // two byte character
|
||||
if (rem > 1) {
|
||||
uint8_t second = bytes[1];
|
||||
const uint8_t second = bytes[1];
|
||||
if (_IsSuffixChar(second)) {
|
||||
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
||||
+ static_cast<uint32_t>(second & 0x3F);
|
||||
@@ -74,8 +78,8 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
}
|
||||
} else if (first < 0xF0) { // three byte character
|
||||
if (rem > 2) {
|
||||
uint8_t second = bytes[1];
|
||||
uint8_t third = bytes[2];
|
||||
const uint8_t second = bytes[1];
|
||||
const uint8_t third = bytes[2];
|
||||
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
||||
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
||||
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
||||
@@ -86,9 +90,9 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
}
|
||||
} else if (first < 0xF8) { // four byte character
|
||||
if (rem > 3) {
|
||||
uint8_t second = bytes[1];
|
||||
uint8_t third = bytes[2];
|
||||
uint8_t fourth = bytes[3];
|
||||
const uint8_t second = bytes[1];
|
||||
const uint8_t third = bytes[2];
|
||||
const uint8_t fourth = bytes[3];
|
||||
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
||||
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
||||
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
||||
@@ -107,7 +111,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
}
|
||||
|
||||
/// See <https://www.ietf.org/rfc/rfc2781.html#section-2.1>
|
||||
bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
||||
bool PushUTF16CodePoint(std::u16string& output, const uint32_t U, const size_t size) {
|
||||
if (output.length() >= size) return false;
|
||||
if (U < 0x10000) {
|
||||
// If U < 0x10000, encode U as a 16-bit unsigned integer and terminate.
|
||||
@@ -120,7 +124,7 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
||||
// Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
|
||||
// U' must be less than or equal to 0xFFFFF. That is, U' can be
|
||||
// represented in 20 bits.
|
||||
uint32_t Ut = U - 0x10000;
|
||||
const uint32_t Ut = U - 0x10000;
|
||||
|
||||
// Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
|
||||
// 0xDC00, respectively. These integers each have 10 bits free to
|
||||
@@ -141,25 +145,25 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
||||
} else return false;
|
||||
}
|
||||
|
||||
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view string, const size_t size) {
|
||||
const size_t newSize = MinSize(size, string);
|
||||
std::u16string output;
|
||||
output.reserve(newSize);
|
||||
std::string_view iterator = string;
|
||||
|
||||
uint32_t c;
|
||||
while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
||||
while (details::_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
||||
return output;
|
||||
}
|
||||
|
||||
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view string, const size_t size) {
|
||||
const size_t newSize = MinSize(size, string);
|
||||
std::u16string ret;
|
||||
ret.reserve(newSize);
|
||||
|
||||
for (size_t i = 0; i < newSize; i++) {
|
||||
char c = string[i];
|
||||
for (size_t i = 0; i < newSize; ++i) {
|
||||
const char c = string[i];
|
||||
// Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t
|
||||
ret.push_back((c > 0 && c <= 127) ? static_cast<char16_t>(c) : REPLACEMENT_CHARACTER);
|
||||
}
|
||||
@@ -167,20 +171,29 @@ std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string GeneralUtils::Latin1ToUTF8(const std::u8string_view string, const size_t size) {
|
||||
std::string toReturn{};
|
||||
|
||||
for (const auto u : string) {
|
||||
PushUTF8CodePoint(toReturn, u);
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
|
||||
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) {
|
||||
size_t newSize = MinSize(size, string);
|
||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view string, const size_t size) {
|
||||
const size_t newSize = MinSize(size, string);
|
||||
std::string ret;
|
||||
ret.reserve(newSize);
|
||||
|
||||
for (size_t i = 0; i < newSize; i++) {
|
||||
char16_t u = string[i];
|
||||
for (size_t i = 0; i < newSize; ++i) {
|
||||
const auto u = string[i];
|
||||
if (IsLeadSurrogate(u) && (i + 1) < newSize) {
|
||||
char16_t next = string[i + 1];
|
||||
const auto next = string[i + 1];
|
||||
if (IsTrailSurrogate(next)) {
|
||||
i += 1;
|
||||
char32_t cp = 0x10000
|
||||
const char32_t cp = 0x10000
|
||||
+ ((static_cast<char32_t>(u) - 0xD800) << 10)
|
||||
+ (static_cast<char32_t>(next) - 0xDC00);
|
||||
PushUTF8CodePoint(ret, cp);
|
||||
@@ -195,40 +208,40 @@ std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) {
|
||||
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b) {
|
||||
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); });
|
||||
}
|
||||
|
||||
// MARK: Bits
|
||||
|
||||
//! Sets a specific bit in a signed 64-bit integer
|
||||
int64_t GeneralUtils::SetBit(int64_t value, uint32_t index) {
|
||||
int64_t GeneralUtils::SetBit(int64_t value, const uint32_t index) {
|
||||
return value |= 1ULL << index;
|
||||
}
|
||||
|
||||
//! Clears a specific bit in a signed 64-bit integer
|
||||
int64_t GeneralUtils::ClearBit(int64_t value, uint32_t index) {
|
||||
int64_t GeneralUtils::ClearBit(int64_t value, const uint32_t index) {
|
||||
return value &= ~(1ULL << index);
|
||||
}
|
||||
|
||||
//! Checks a specific bit in a signed 64-bit integer
|
||||
bool GeneralUtils::CheckBit(int64_t value, uint32_t index) {
|
||||
bool GeneralUtils::CheckBit(int64_t value, const uint32_t index) {
|
||||
return value & (1ULL << index);
|
||||
}
|
||||
|
||||
bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) {
|
||||
size_t start_pos = str.find(from);
|
||||
bool GeneralUtils::ReplaceInString(std::string& str, const std::string_view from, const std::string_view to) {
|
||||
const size_t start_pos = str.find(from);
|
||||
if (start_pos == std::string::npos)
|
||||
return false;
|
||||
str.replace(start_pos, from.length(), to);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) {
|
||||
std::vector<std::wstring> GeneralUtils::SplitString(const std::wstring_view str, const wchar_t delimiter) {
|
||||
std::vector<std::wstring> vector = std::vector<std::wstring>();
|
||||
std::wstring current;
|
||||
|
||||
for (const auto& c : str) {
|
||||
for (const wchar_t c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = L"";
|
||||
@@ -237,15 +250,15 @@ std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t d
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(current);
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) {
|
||||
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string_view str, const char16_t delimiter) {
|
||||
std::vector<std::u16string> vector = std::vector<std::u16string>();
|
||||
std::u16string current;
|
||||
|
||||
for (const auto& c : str) {
|
||||
for (const char16_t c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = u"";
|
||||
@@ -254,17 +267,15 @@ std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str,
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(current);
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char delimiter) {
|
||||
std::vector<std::string> GeneralUtils::SplitString(const std::string_view str, const char delimiter) {
|
||||
std::vector<std::string> vector = std::vector<std::string>();
|
||||
std::string current = "";
|
||||
|
||||
for (size_t i = 0; i < str.length(); i++) {
|
||||
char c = str[i];
|
||||
|
||||
for (const char c : str) {
|
||||
if (c == delimiter) {
|
||||
vector.push_back(current);
|
||||
current = "";
|
||||
@@ -273,49 +284,82 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
|
||||
}
|
||||
}
|
||||
|
||||
vector.push_back(current);
|
||||
|
||||
vector.push_back(std::move(current));
|
||||
return vector;
|
||||
}
|
||||
|
||||
std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) {
|
||||
std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
|
||||
uint32_t length;
|
||||
inStream->Read<uint32_t>(length);
|
||||
inStream.Read<uint32_t>(length);
|
||||
|
||||
std::u16string string;
|
||||
for (auto i = 0; i < length; i++) {
|
||||
for (uint32_t i = 0; i < length; ++i) {
|
||||
uint16_t c;
|
||||
inStream->Read(c);
|
||||
inStream.Read(c);
|
||||
string.push_back(c);
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) {
|
||||
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string_view folder) {
|
||||
// Because we dont know how large the initial number before the first _ is we need to make it a map like so.
|
||||
std::map<uint32_t, std::string> filenames{};
|
||||
for (auto& t : std::filesystem::directory_iterator(folder)) {
|
||||
auto filename = t.path().filename().string();
|
||||
auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
|
||||
filenames.insert(std::make_pair(index, filename));
|
||||
std::map<uint32_t, std::string> filenames{};
|
||||
for (const auto& t : std::filesystem::directory_iterator(folder)) {
|
||||
if (t.is_directory() || t.is_symlink()) continue;
|
||||
auto filename = t.path().filename().string();
|
||||
const auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
|
||||
filenames.emplace(index, std::move(filename));
|
||||
}
|
||||
|
||||
// Now sort the map by the oldest migration.
|
||||
std::vector<std::string> sortedFiles{};
|
||||
auto fileIterator = filenames.begin();
|
||||
std::map<uint32_t, std::string>::iterator oldest = filenames.begin();
|
||||
while (!filenames.empty()) {
|
||||
if (fileIterator == filenames.end()) {
|
||||
sortedFiles.push_back(oldest->second);
|
||||
filenames.erase(oldest);
|
||||
fileIterator = filenames.begin();
|
||||
oldest = filenames.begin();
|
||||
continue;
|
||||
auto fileIterator = filenames.cbegin();
|
||||
auto oldest = filenames.cbegin();
|
||||
while (!filenames.empty()) {
|
||||
if (fileIterator == filenames.cend()) {
|
||||
sortedFiles.push_back(oldest->second);
|
||||
filenames.erase(oldest);
|
||||
fileIterator = filenames.cbegin();
|
||||
oldest = filenames.cbegin();
|
||||
continue;
|
||||
}
|
||||
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
||||
fileIterator++;
|
||||
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
||||
++fileIterator;
|
||||
}
|
||||
|
||||
return sortedFiles;
|
||||
}
|
||||
|
||||
template<>
|
||||
[[nodiscard]] std::optional<json> GeneralUtils::TryParse(std::string_view str) {
|
||||
try {
|
||||
return json::parse(str);
|
||||
} catch (const std::exception& e) {
|
||||
return std::nullopt;
|
||||
} catch (...) {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924)
|
||||
|
||||
// MacOS floating-point parse function specializations
|
||||
namespace GeneralUtils::details {
|
||||
template <>
|
||||
[[nodiscard]] float _parse<float>(const std::string_view str, size_t& parseNum) {
|
||||
return std::stof(std::string{ str }, &parseNum);
|
||||
}
|
||||
|
||||
template <>
|
||||
[[nodiscard]] double _parse<double>(const std::string_view str, size_t& parseNum) {
|
||||
return std::stod(std::string{ str }, &parseNum);
|
||||
}
|
||||
|
||||
template <>
|
||||
[[nodiscard]] long double _parse<long double>(const std::string_view str, size_t& parseNum) {
|
||||
return std::stold(std::string{ str }, &parseNum);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
// C++
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
#include <span>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "BitStream.h"
|
||||
#include "NiPoint3.h"
|
||||
|
||||
#include "dPlatforms.h"
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
@@ -32,29 +33,39 @@ namespace GeneralUtils {
|
||||
//! Converts a plain ASCII string to a UTF-16 string
|
||||
/*!
|
||||
\param string The string to convert
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||
\return An UTF-16 representation of the string
|
||||
*/
|
||||
std::u16string ASCIIToUTF16(const std::string_view& string, size_t size = -1);
|
||||
std::u16string ASCIIToUTF16(const std::string_view string, const size_t size = SIZE_MAX);
|
||||
|
||||
//! Converts a UTF-8 String to a UTF-16 string
|
||||
/*!
|
||||
\param string The string to convert
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||
\return An UTF-16 representation of the string
|
||||
*/
|
||||
std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1);
|
||||
std::u16string UTF8ToUTF16(const std::string_view string, const size_t size = SIZE_MAX);
|
||||
|
||||
//! Internal, do not use
|
||||
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
||||
namespace details {
|
||||
//! Internal, do not use
|
||||
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
||||
}
|
||||
|
||||
//! Converts a Latin1 string to a UTF-8 string
|
||||
/*!
|
||||
\param string The string to convert
|
||||
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||
\return An UTF-8 representation of the string
|
||||
*/
|
||||
std::string Latin1ToUTF8(const std::u8string_view string, const size_t size = SIZE_MAX);
|
||||
|
||||
//! Converts a UTF-16 string to a UTF-8 string
|
||||
/*!
|
||||
\param string The string to convert
|
||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||
\return An UTF-8 representation of the string
|
||||
*/
|
||||
std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1);
|
||||
std::string UTF16ToWTF8(const std::u16string_view string, const size_t size = SIZE_MAX);
|
||||
|
||||
/**
|
||||
* Compares two basic strings but does so ignoring case sensitivity
|
||||
@@ -62,7 +73,7 @@ namespace GeneralUtils {
|
||||
* \param b the second string to compare against the first string
|
||||
* @return if the two strings are equal
|
||||
*/
|
||||
bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b);
|
||||
bool CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b);
|
||||
|
||||
// MARK: Bits
|
||||
|
||||
@@ -70,9 +81,9 @@ namespace GeneralUtils {
|
||||
|
||||
//! Sets a bit on a numerical value
|
||||
template <typename T>
|
||||
inline void SetBit(T& value, eObjectBits bits) {
|
||||
inline void SetBit(T& value, const eObjectBits bits) {
|
||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||
auto index = static_cast<size_t>(bits);
|
||||
const auto index = static_cast<size_t>(bits);
|
||||
if (index > (sizeof(T) * 8) - 1) {
|
||||
return;
|
||||
}
|
||||
@@ -82,9 +93,9 @@ namespace GeneralUtils {
|
||||
|
||||
//! Clears a bit on a numerical value
|
||||
template <typename T>
|
||||
inline void ClearBit(T& value, eObjectBits bits) {
|
||||
inline void ClearBit(T& value, const eObjectBits bits) {
|
||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||
auto index = static_cast<size_t>(bits);
|
||||
const auto index = static_cast<size_t>(bits);
|
||||
if (index > (sizeof(T) * 8 - 1)) {
|
||||
return;
|
||||
}
|
||||
@@ -97,14 +108,14 @@ namespace GeneralUtils {
|
||||
\param value The value to set the bit for
|
||||
\param index The index of the bit
|
||||
*/
|
||||
int64_t SetBit(int64_t value, uint32_t index);
|
||||
int64_t SetBit(int64_t value, const uint32_t index);
|
||||
|
||||
//! Clears a specific bit in a signed 64-bit integer
|
||||
/*!
|
||||
\param value The value to clear the bit from
|
||||
\param index The index of the bit
|
||||
*/
|
||||
int64_t ClearBit(int64_t value, uint32_t index);
|
||||
int64_t ClearBit(int64_t value, const uint32_t index);
|
||||
|
||||
//! Checks a specific bit in a signed 64-bit integer
|
||||
/*!
|
||||
@@ -112,19 +123,42 @@ namespace GeneralUtils {
|
||||
\param index The index of the bit
|
||||
\return Whether or not the bit is set
|
||||
*/
|
||||
bool CheckBit(int64_t value, uint32_t index);
|
||||
bool CheckBit(int64_t value, const uint32_t index);
|
||||
|
||||
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
|
||||
bool ReplaceInString(std::string& str, const std::string_view from, const std::string_view to);
|
||||
|
||||
std::u16string ReadWString(RakNet::BitStream* inStream);
|
||||
std::u16string ReadWString(RakNet::BitStream& inStream);
|
||||
|
||||
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
|
||||
std::vector<std::wstring> SplitString(const std::wstring_view str, const wchar_t delimiter);
|
||||
|
||||
std::vector<std::u16string> SplitString(const std::u16string& str, char16_t delimiter);
|
||||
std::vector<std::u16string> SplitString(const std::u16string_view str, const char16_t delimiter);
|
||||
|
||||
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
||||
std::vector<std::string> SplitString(const std::string_view str, const char delimiter);
|
||||
|
||||
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
|
||||
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string_view folder);
|
||||
|
||||
/**
|
||||
* Transparent string hasher - used to allow string_view key lookups for maps storing std::string keys
|
||||
* https://www.reddit.com/r/cpp_questions/comments/12xw3sn/find_stdstring_view_in_unordered_map_with/jhki225/
|
||||
* https://godbolt.org/z/789xv8Eeq
|
||||
*/
|
||||
template <typename... Bases>
|
||||
struct overload : Bases... {
|
||||
using is_transparent = void;
|
||||
using Bases::operator() ... ;
|
||||
};
|
||||
|
||||
struct char_pointer_hash {
|
||||
auto operator()(const char* const ptr) const noexcept {
|
||||
return std::hash<std::string_view>{}(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
using transparent_string_hash = overload<
|
||||
std::hash<std::string>,
|
||||
std::hash<std::string_view>,
|
||||
char_pointer_hash
|
||||
>;
|
||||
|
||||
// Concept constraining to enum types
|
||||
template <typename T>
|
||||
@@ -144,7 +178,7 @@ namespace GeneralUtils {
|
||||
|
||||
// If a boolean, present an alias to an intermediate integral type for parsing
|
||||
template <Numeric T> requires std::same_as<T, bool>
|
||||
struct numeric_parse<T> { using type = uint32_t; };
|
||||
struct numeric_parse<T> { using type = uint8_t; };
|
||||
|
||||
// Shorthand type alias
|
||||
template <Numeric T>
|
||||
@@ -156,8 +190,9 @@ namespace GeneralUtils {
|
||||
* @returns An std::optional containing the desired value if it is equivalent to the string
|
||||
*/
|
||||
template <Numeric T>
|
||||
[[nodiscard]] std::optional<T> TryParse(const std::string_view str) {
|
||||
[[nodiscard]] std::optional<T> TryParse(std::string_view str) {
|
||||
numeric_parse_t<T> result;
|
||||
while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1);
|
||||
|
||||
const char* const strEnd = str.data() + str.size();
|
||||
const auto [parseEnd, ec] = std::from_chars(str.data(), strEnd, result);
|
||||
@@ -166,27 +201,16 @@ namespace GeneralUtils {
|
||||
return isParsed ? static_cast<T>(result) : std::optional<T>{};
|
||||
}
|
||||
|
||||
#ifdef DARKFLAME_PLATFORM_MACOS
|
||||
template<typename T>
|
||||
requires(!Numeric<T>)
|
||||
[[nodiscard]] std::optional<T> TryParse(std::string_view str);
|
||||
|
||||
// Anonymous namespace containing MacOS floating-point parse function specializations
|
||||
namespace {
|
||||
#if !(__GNUC__ >= 11 || _MSC_VER >= 1924)
|
||||
|
||||
// MacOS floating-point parse helper function specializations
|
||||
namespace details {
|
||||
template <std::floating_point T>
|
||||
[[nodiscard]] T Parse(const std::string_view str, size_t* parseNum);
|
||||
|
||||
template <>
|
||||
[[nodiscard]] float Parse<float>(const std::string_view str, size_t* parseNum) {
|
||||
return std::stof(std::string{ str }, parseNum);
|
||||
}
|
||||
|
||||
template <>
|
||||
[[nodiscard]] double Parse<double>(const std::string_view str, size_t* parseNum) {
|
||||
return std::stod(std::string{ str }, parseNum);
|
||||
}
|
||||
|
||||
template <>
|
||||
[[nodiscard]] long double Parse<long double>(const std::string_view str, size_t* parseNum) {
|
||||
return std::stold(std::string{ str }, parseNum);
|
||||
}
|
||||
[[nodiscard]] T _parse(const std::string_view str, size_t& parseNum);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,9 +220,12 @@ namespace GeneralUtils {
|
||||
* @returns An std::optional containing the desired value if it is equivalent to the string
|
||||
*/
|
||||
template <std::floating_point T>
|
||||
[[nodiscard]] std::optional<T> TryParse(const std::string_view str) noexcept try {
|
||||
[[nodiscard]] std::optional<T> TryParse(std::string_view str) noexcept
|
||||
try {
|
||||
while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1);
|
||||
|
||||
size_t parseNum;
|
||||
const T result = Parse<T>(str, &parseNum);
|
||||
const T result = details::_parse<T>(str, parseNum);
|
||||
const bool isParsed = str.length() == parseNum;
|
||||
|
||||
return isParsed ? result : std::optional<T>{};
|
||||
@@ -216,7 +243,7 @@ namespace GeneralUtils {
|
||||
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string& strX, const std::string& strY, const std::string& strZ) {
|
||||
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string_view strX, const std::string_view strY, const std::string_view strZ) {
|
||||
const auto x = TryParse<float>(strX);
|
||||
if (!x) return std::nullopt;
|
||||
|
||||
@@ -228,17 +255,17 @@ namespace GeneralUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* The TryParse overload for handling NiPoint3 by passingn a reference to a vector of three strings
|
||||
* @param str The string vector representing the X, Y, and Xcoordinates
|
||||
* The TryParse overload for handling NiPoint3 by passing a span of three strings
|
||||
* @param str The string vector representing the X, Y, and Z coordinates
|
||||
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
||||
*/
|
||||
template <typename T>
|
||||
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::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;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::u16string to_u16string(T value) {
|
||||
std::u16string to_u16string(const T value) {
|
||||
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
||||
}
|
||||
|
||||
@@ -257,7 +284,7 @@ namespace GeneralUtils {
|
||||
\param max The maximum to generate to
|
||||
*/
|
||||
template <typename T>
|
||||
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
|
||||
inline T GenerateRandomNumber(const std::size_t min, const std::size_t max) {
|
||||
// Make sure it is a numeric type
|
||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||
|
||||
@@ -278,16 +305,16 @@ namespace GeneralUtils {
|
||||
* @returns The enum entry's value in its underlying type
|
||||
*/
|
||||
template <Enum eType>
|
||||
constexpr typename std::underlying_type_t<eType> CastUnderlyingType(const eType entry) noexcept {
|
||||
return static_cast<typename std::underlying_type_t<eType>>(entry);
|
||||
constexpr std::underlying_type_t<eType> ToUnderlying(const eType entry) noexcept {
|
||||
return static_cast<std::underlying_type_t<eType>>(entry);
|
||||
}
|
||||
|
||||
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
||||
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
||||
#ifdef _WIN32
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
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 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
|
||||
* @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
|
||||
* @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.
|
||||
@@ -62,17 +62,17 @@ private:
|
||||
T value;
|
||||
|
||||
//! Writes the key to the packet
|
||||
void WriteKey(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
||||
void WriteKey(RakNet::BitStream& packet) const {
|
||||
packet.Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
||||
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
||||
packet->Write<uint16_t>(this->key[i]);
|
||||
packet.Write<uint16_t>(this->key[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//! Writes the value to the packet
|
||||
void WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
packet->Write(this->value);
|
||||
void WriteValue(RakNet::BitStream& packet) const {
|
||||
packet.Write<uint8_t>(this->GetValueType());
|
||||
packet.Write(this->value);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
/*!
|
||||
\return The value
|
||||
*/
|
||||
const T& GetValue(void) { return this->value; }
|
||||
const T& GetValue(void) const { return this->value; }
|
||||
|
||||
//! Sets the value
|
||||
/*!
|
||||
@@ -102,13 +102,13 @@ public:
|
||||
/*!
|
||||
\return The value string
|
||||
*/
|
||||
std::string GetValueString(void) { return ""; }
|
||||
std::string GetValueString(void) const { return ""; }
|
||||
|
||||
//! Writes the data to a packet
|
||||
/*!
|
||||
\param packet The packet
|
||||
*/
|
||||
void WriteToPacket(RakNet::BitStream* packet) override {
|
||||
void WriteToPacket(RakNet::BitStream& packet) const override {
|
||||
this->WriteKey(packet);
|
||||
this->WriteValue(packet);
|
||||
}
|
||||
@@ -117,13 +117,13 @@ public:
|
||||
/*!
|
||||
\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
|
||||
/*!
|
||||
\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
|
||||
/*!
|
||||
@@ -131,7 +131,7 @@ public:
|
||||
\param includeTypeId Whether or not to include the type id in 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) {
|
||||
return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>";
|
||||
}
|
||||
@@ -154,11 +154,11 @@ public:
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::string GetValueAsString() override {
|
||||
std::string GetValueAsString() const override {
|
||||
return this->GetValueString();
|
||||
}
|
||||
|
||||
LDFBaseData* Copy() override {
|
||||
LDFBaseData* Copy() const override {
|
||||
return new LDFData<T>(key, value);
|
||||
}
|
||||
|
||||
@@ -166,58 +166,58 @@ public:
|
||||
};
|
||||
|
||||
// LDF Types
|
||||
template<> inline eLDFType LDFData<std::u16string>::GetValueType(void) { return LDF_TYPE_UTF_16; };
|
||||
template<> inline eLDFType LDFData<int32_t>::GetValueType(void) { return LDF_TYPE_S32; };
|
||||
template<> inline eLDFType LDFData<float>::GetValueType(void) { return LDF_TYPE_FLOAT; };
|
||||
template<> inline eLDFType LDFData<double>::GetValueType(void) { return LDF_TYPE_DOUBLE; };
|
||||
template<> inline eLDFType LDFData<uint32_t>::GetValueType(void) { return LDF_TYPE_U32; };
|
||||
template<> inline eLDFType LDFData<bool>::GetValueType(void) { return LDF_TYPE_BOOLEAN; };
|
||||
template<> inline eLDFType LDFData<uint64_t>::GetValueType(void) { return LDF_TYPE_U64; };
|
||||
template<> inline eLDFType LDFData<LWOOBJID>::GetValueType(void) { return LDF_TYPE_OBJID; };
|
||||
template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF_TYPE_UTF_8; };
|
||||
template<> inline eLDFType LDFData<std::u16string>::GetValueType(void) const { return LDF_TYPE_UTF_16; };
|
||||
template<> inline eLDFType LDFData<int32_t>::GetValueType(void) const { return LDF_TYPE_S32; };
|
||||
template<> inline eLDFType LDFData<float>::GetValueType(void) const { return LDF_TYPE_FLOAT; };
|
||||
template<> inline eLDFType LDFData<double>::GetValueType(void) const { return LDF_TYPE_DOUBLE; };
|
||||
template<> inline eLDFType LDFData<uint32_t>::GetValueType(void) const { return LDF_TYPE_U32; };
|
||||
template<> inline eLDFType LDFData<bool>::GetValueType(void) const { return LDF_TYPE_BOOLEAN; };
|
||||
template<> inline eLDFType LDFData<uint64_t>::GetValueType(void) const { return LDF_TYPE_U64; };
|
||||
template<> inline eLDFType LDFData<LWOOBJID>::GetValueType(void) const { return LDF_TYPE_OBJID; };
|
||||
template<> inline eLDFType LDFData<std::string>::GetValueType(void) const { return LDF_TYPE_UTF_8; };
|
||||
|
||||
// The specialized version for std::u16string (UTF-16)
|
||||
template<>
|
||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream& packet) const {
|
||||
packet.Write<uint8_t>(this->GetValueType());
|
||||
|
||||
packet->Write<uint32_t>(this->value.length());
|
||||
packet.Write<uint32_t>(this->value.length());
|
||||
for (uint32_t i = 0; i < this->value.length(); ++i) {
|
||||
packet->Write<uint16_t>(this->value[i]);
|
||||
packet.Write<uint16_t>(this->value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// The specialized version for bool
|
||||
template<>
|
||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream& packet) const {
|
||||
packet.Write<uint8_t>(this->GetValueType());
|
||||
|
||||
packet->Write<uint8_t>(this->value);
|
||||
packet.Write<uint8_t>(this->value);
|
||||
}
|
||||
|
||||
// The specialized version for std::string (UTF-8)
|
||||
template<>
|
||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream& packet) const {
|
||||
packet.Write<uint8_t>(this->GetValueType());
|
||||
|
||||
packet->Write<uint32_t>(this->value.length());
|
||||
packet.Write<uint32_t>(this->value.length());
|
||||
for (uint32_t i = 0; i < this->value.length(); ++i) {
|
||||
packet->Write<uint8_t>(this->value[i]);
|
||||
packet.Write<uint8_t>(this->value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
template<> inline std::string LDFData<int32_t>::GetValueString() { return std::to_string(this->value); }
|
||||
template<> inline std::string LDFData<float>::GetValueString() { return std::to_string(this->value); }
|
||||
template<> inline std::string LDFData<double>::GetValueString() { 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<bool>::GetValueString() { 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<LWOOBJID>::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() const { 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() const { 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() const { 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__
|
||||
|
||||
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__
|
||||
@@ -6,28 +6,14 @@
|
||||
|
||||
|
||||
struct RemoteInputInfo {
|
||||
RemoteInputInfo() {
|
||||
m_RemoteInputX = 0;
|
||||
m_RemoteInputY = 0;
|
||||
m_IsPowersliding = false;
|
||||
m_IsModified = false;
|
||||
}
|
||||
|
||||
void operator=(const RemoteInputInfo& other) {
|
||||
m_RemoteInputX = other.m_RemoteInputX;
|
||||
m_RemoteInputY = other.m_RemoteInputY;
|
||||
m_IsPowersliding = other.m_IsPowersliding;
|
||||
m_IsModified = other.m_IsModified;
|
||||
}
|
||||
|
||||
bool operator==(const RemoteInputInfo& other) {
|
||||
return m_RemoteInputX == other.m_RemoteInputX && m_RemoteInputY == other.m_RemoteInputY && m_IsPowersliding == other.m_IsPowersliding && m_IsModified == other.m_IsModified;
|
||||
}
|
||||
|
||||
float m_RemoteInputX;
|
||||
float m_RemoteInputY;
|
||||
bool m_IsPowersliding;
|
||||
bool m_IsModified;
|
||||
float m_RemoteInputX = 0;
|
||||
float m_RemoteInputY = 0;
|
||||
bool m_IsPowersliding = false;
|
||||
bool m_IsModified = false;
|
||||
};
|
||||
|
||||
struct LocalSpaceInfo {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "dConfig.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "BinaryPathFinder.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
|
||||
};
|
||||
}
|
||||
1614
dCommon/dEnums/MessageType/Game.h
Normal file
1614
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.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;
|
||||
};
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <set>
|
||||
#include "BitStream.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eClientMessageType.h"
|
||||
#include "MessageType/Client.h"
|
||||
#include "BitStreamUtils.h"
|
||||
|
||||
#pragma warning (disable:4251) //Disables SQL warnings
|
||||
@@ -33,9 +33,9 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
|
||||
#define CBITSTREAM RakNet::BitStream bitStream;
|
||||
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
|
||||
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
||||
#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
|
||||
#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GAME_MSG);
|
||||
#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false);
|
||||
#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
|
||||
//=========== TYPEDEFS ==========
|
||||
|
||||
|
||||
@@ -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
|
||||
VAULT_SIZE,
|
||||
// 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__
|
||||
|
||||
@@ -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,
|
||||
AUTH,
|
||||
CHAT,
|
||||
CHAT_INTERNAL,
|
||||
WORLD,
|
||||
WORLD = 4,
|
||||
CLIENT,
|
||||
MASTER
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
26
dCommon/dEnums/eHTTPMethod.h
Normal file
26
dCommon/dEnums/eHTTPMethod.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef __EHTTPMETHODS__H__
|
||||
#define __EHTTPMETHODS__H__
|
||||
|
||||
#ifdef DARKFLAME_PLATFORM_WIN32
|
||||
#pragma push_macro("DELETE")
|
||||
#undef DELETE
|
||||
#endif
|
||||
|
||||
enum class eHTTPMethod {
|
||||
GET,
|
||||
POST,
|
||||
PUT,
|
||||
DELETE,
|
||||
HEAD,
|
||||
CONNECT,
|
||||
OPTIONS,
|
||||
TRACE,
|
||||
PATCH,
|
||||
INVALID
|
||||
};
|
||||
|
||||
#ifdef DARKFLAME_PLATFORM_WIN32
|
||||
#pragma pop_macro("DELETE")
|
||||
#endif
|
||||
|
||||
#endif // __EHTTPMETHODS__H__
|
||||
72
dCommon/dEnums/eHTTPStatusCode.h
Normal file
72
dCommon/dEnums/eHTTPStatusCode.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef __EHTTPSTATUSCODE__H__
|
||||
#define __EHTTPSTATUSCODE__H__
|
||||
|
||||
#include <cstdint>
|
||||
// verbose list of http codes
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
||||
enum class eHTTPStatusCode : uint32_t {
|
||||
CONTINUE = 100,
|
||||
SWITCHING_PROTOCOLS = 101,
|
||||
PROCESSING = 102,
|
||||
EARLY_HINTS = 103,
|
||||
OK = 200,
|
||||
CREATED = 201,
|
||||
ACCEPTED = 202,
|
||||
NON_AUTHORITATIVE_INFORMATION = 203,
|
||||
NO_CONTENT = 204,
|
||||
RESET_CONTENT = 205,
|
||||
PARTIAL_CONTENT = 206,
|
||||
MULTI_STATUS = 207,
|
||||
ALREADY_REPORTED = 208,
|
||||
IM_USED = 226,
|
||||
MULTIPLE_CHOICES = 300,
|
||||
MOVED_PERMANENTLY = 301,
|
||||
FOUND = 302,
|
||||
SEE_OTHER = 303,
|
||||
NOT_MODIFIED = 304,
|
||||
USE_PROXY = 305,
|
||||
SWITCH_PROXY = 306,
|
||||
TEMPORARY_REDIRECT = 307,
|
||||
PERMANENT_REDIRECT = 308,
|
||||
BAD_REQUEST = 400,
|
||||
UNAUTHORIZED = 401,
|
||||
PAYMENT_REQUIRED = 402,
|
||||
FORBIDDEN = 403,
|
||||
NOT_FOUND = 404,
|
||||
METHOD_NOT_ALLOWED = 405,
|
||||
NOT_ACCEPTABLE = 406,
|
||||
PROXY_AUTHENTICATION_REQUIRED = 407,
|
||||
REQUEST_TIMEOUT = 408,
|
||||
CONFLICT = 409,
|
||||
GONE = 410,
|
||||
LENGTH_REQUIRED = 411,
|
||||
PRECONDITION_FAILED = 412,
|
||||
PAYLOAD_TOO_LARGE = 413,
|
||||
URI_TOO_LONG = 414,
|
||||
UNSUPPORTED_MEDIA_TYPE = 415,
|
||||
RANGE_NOT_SATISFIABLE = 416,
|
||||
EXPECTATION_FAILED = 417,
|
||||
I_AM_A_TEAPOT = 418,
|
||||
MISDIRECTED_REQUEST = 421,
|
||||
UNPROCESSABLE_ENTITY = 422,
|
||||
LOCKED = 423,
|
||||
FAILED_DEPENDENCY = 424,
|
||||
UPGRADE_REQUIRED = 426,
|
||||
PRECONDITION_REQUIRED = 428,
|
||||
TOO_MANY_REQUESTS = 429,
|
||||
REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
|
||||
UNAVAILABLE_FOR_LEGAL_REASONS = 451,
|
||||
INTERNAL_SERVER_ERROR = 500,
|
||||
NOT_IMPLEMENTED = 501,
|
||||
BAD_GATEWAY = 502,
|
||||
SERVICE_UNAVAILABLE = 503,
|
||||
GATEWAY_TIMEOUT = 504,
|
||||
HTTP_VERSION_NOT_SUPPORTED = 505,
|
||||
VARIANT_ALSO_NEGOTIATES = 506,
|
||||
INSUFFICIENT_STORAGE = 507,
|
||||
LOOP_DETECTED = 508,
|
||||
NOT_EXTENDED = 510,
|
||||
NETWORK_AUTHENTICATION_REQUIRED = 511
|
||||
};
|
||||
|
||||
#endif // !__EHTTPSTATUSCODE__H__
|
||||
@@ -4,6 +4,9 @@
|
||||
#define __EINVENTORYTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "magic_enum.hpp"
|
||||
|
||||
static const uint8_t NUMBER_OF_INVENTORIES = 17;
|
||||
/**
|
||||
* 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__
|
||||
|
||||
@@ -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
|
||||
@@ -106,7 +106,7 @@ enum class eReplicaComponentType : uint32_t {
|
||||
INTERACTION_MANAGER,
|
||||
DONATION_VENDOR,
|
||||
COMBAT_MEDIATOR,
|
||||
COMMENDATION_VENDOR,
|
||||
ACHIEVEMENT_VENDOR,
|
||||
GATE_RUSH_CONTROL,
|
||||
RAIL_ACTIVATOR,
|
||||
ROLLER,
|
||||
|
||||
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__
|
||||
15
dCommon/dEnums/eVendorTransactionResult.h
Normal file
15
dCommon/dEnums/eVendorTransactionResult.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef __EVENDORTRANSACTIONRESULT__
|
||||
#define __EVENDORTRANSACTIONRESULT__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eVendorTransactionResult : uint32_t {
|
||||
SELL_SUCCESS = 0,
|
||||
SELL_FAIL,
|
||||
PURCHASE_SUCCESS,
|
||||
PURCHASE_FAIL,
|
||||
DONATION_FAIL,
|
||||
DONATION_FULL
|
||||
};
|
||||
|
||||
#endif // !__EVENDORTRANSACTIONRESULT__
|
||||
59
dCommon/dEnums/eWaypointCommandType.h
Normal file
59
dCommon/dEnums/eWaypointCommandType.h
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
#ifndef __EWAYPOINTCOMMANDTYPES__H__
|
||||
#define __EWAYPOINTCOMMANDTYPES__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eWaypointCommandType : uint32_t {
|
||||
INVALID,
|
||||
BOUNCE,
|
||||
STOP,
|
||||
GROUP_EMOTE,
|
||||
SET_VARIABLE,
|
||||
CAST_SKILL,
|
||||
EQUIP_INVENTORY,
|
||||
UNEQUIP_INVENTORY,
|
||||
DELAY,
|
||||
EMOTE,
|
||||
TELEPORT,
|
||||
PATH_SPEED,
|
||||
REMOVE_NPC,
|
||||
CHANGE_WAYPOINT,
|
||||
DELETE_SELF,
|
||||
KILL_SELF,
|
||||
SPAWN_OBJECT,
|
||||
PLAY_SOUND,
|
||||
};
|
||||
|
||||
class WaypointCommandType {
|
||||
public:
|
||||
static eWaypointCommandType StringToWaypointCommandType(std::string commandString) {
|
||||
const std::map<std::string, eWaypointCommandType> WaypointCommandTypeMap = {
|
||||
{"bounce", eWaypointCommandType::BOUNCE},
|
||||
{"stop", eWaypointCommandType::STOP},
|
||||
{"groupemote", eWaypointCommandType::GROUP_EMOTE},
|
||||
{"setvar", eWaypointCommandType::SET_VARIABLE},
|
||||
{"castskill", eWaypointCommandType::CAST_SKILL},
|
||||
{"eqInvent", eWaypointCommandType::EQUIP_INVENTORY},
|
||||
{"unInvent", eWaypointCommandType::UNEQUIP_INVENTORY},
|
||||
{"delay", eWaypointCommandType::DELAY},
|
||||
{"femote", eWaypointCommandType::EMOTE},
|
||||
{"emote", eWaypointCommandType::EMOTE},
|
||||
{"teleport", eWaypointCommandType::TELEPORT},
|
||||
{"pathspeed", eWaypointCommandType::PATH_SPEED},
|
||||
{"removeNPC", eWaypointCommandType::REMOVE_NPC},
|
||||
{"changeWP", eWaypointCommandType::CHANGE_WAYPOINT},
|
||||
{"DeleteSelf", eWaypointCommandType::DELETE_SELF},
|
||||
{"killself", eWaypointCommandType::KILL_SELF},
|
||||
{"removeself", eWaypointCommandType::DELETE_SELF},
|
||||
{"spawnOBJ", eWaypointCommandType::SPAWN_OBJECT},
|
||||
{"playSound", eWaypointCommandType::PLAY_SOUND},
|
||||
};
|
||||
|
||||
auto intermed = WaypointCommandTypeMap.find(commandString);
|
||||
return (intermed != WaypointCommandTypeMap.end()) ? intermed->second : eWaypointCommandType::INVALID;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif //!__EWAYPOINTCOMMANDTYPES__H__
|
||||
@@ -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 "CDSkillBehaviorTable.h"
|
||||
#include "CDZoneTableTable.h"
|
||||
#include "CDTamingBuildPuzzleTable.h"
|
||||
#include "CDVendorComponentTable.h"
|
||||
#include "CDActivitiesTable.h"
|
||||
#include "CDPackageComponentTable.h"
|
||||
@@ -41,8 +42,6 @@
|
||||
#include "CDRewardCodesTable.h"
|
||||
#include "CDPetComponentTable.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
#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.
|
||||
// A vanilla CDClient takes about 46MB of memory + the regular world data.
|
||||
@@ -55,13 +54,6 @@
|
||||
#define CDCLIENT_DONT_CACHE_TABLE(x)
|
||||
#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.
|
||||
// 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(CDScriptComponentTable);
|
||||
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
|
||||
DEFINE_TABLE_STORAGE(CDTamingBuildPuzzleTable);
|
||||
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
|
||||
DEFINE_TABLE_STORAGE(CDZoneTableTable);
|
||||
|
||||
void CDClientManager::LoadValuesFromDatabase() {
|
||||
if (!CDClientDatabase::isConnected) throw CDClientConnectionException();
|
||||
if (!CDClientDatabase::isConnected) {
|
||||
throw std::runtime_error{ "CDClientDatabase is not connected!" };
|
||||
}
|
||||
|
||||
CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
|
||||
CDActivitiesTable::Instance().LoadValuesFromDatabase();
|
||||
@@ -152,6 +147,7 @@ void CDClientManager::LoadValuesFromDatabase() {
|
||||
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
||||
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
||||
CDTamingBuildPuzzleTable::Instance().LoadValuesFromDatabase();
|
||||
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDZoneTableTable::Instance().LoadValuesFromDatabase();
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ void CDLootTableTable::LoadValuesFromDatabase() {
|
||||
CDLootTable entry;
|
||||
uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1);
|
||||
|
||||
entries[lootTableIndex].push_back(ReadRow(tableData));
|
||||
entries[lootTableIndex].emplace_back(ReadRow(tableData));
|
||||
tableData.nextRow();
|
||||
}
|
||||
for (auto& [id, table] : entries) {
|
||||
@@ -66,7 +66,7 @@ void CDLootTableTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
}
|
||||
|
||||
const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
|
||||
const LootTableEntries& CDLootTableTable::GetTable(const uint32_t tableId) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
auto itr = entries.find(tableId);
|
||||
if (itr != entries.end()) {
|
||||
@@ -79,7 +79,7 @@ const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
|
||||
|
||||
while (!tableData.eof()) {
|
||||
CDLootTable entry;
|
||||
entries[tableId].push_back(ReadRow(tableData));
|
||||
entries[tableId].emplace_back(ReadRow(tableData));
|
||||
tableData.nextRow();
|
||||
}
|
||||
SortTable(entries[tableId]);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDLootTable {
|
||||
uint32_t itemid; //!< The LOT of the item
|
||||
uint32_t LootTableIndex; //!< The Loot Table Index
|
||||
@@ -20,6 +22,5 @@ private:
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
const LootTableEntries& GetTable(uint32_t tableId);
|
||||
const LootTableEntries& GetTable(const uint32_t tableId);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail");
|
||||
while (!tableData.eof()) {
|
||||
CDMissionEmail entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.ID = tableData.getIntField("ID", -1);
|
||||
entry.messageType = tableData.getIntField("messageType", -1);
|
||||
entry.notificationGroup = tableData.getIntField("notificationGroup", -1);
|
||||
@@ -30,11 +30,8 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
|
||||
entry.locStatus = tableData.getIntField("locStatus", -1);
|
||||
entry.gate_version = tableData.getStringField("gate_version", "");
|
||||
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDMissionEmail {
|
||||
uint32_t ID;
|
||||
uint32_t messageType;
|
||||
|
||||
@@ -20,18 +20,15 @@ void CDMissionNPCComponentTable::LoadValuesFromDatabase() {
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent");
|
||||
while (!tableData.eof()) {
|
||||
CDMissionNPCComponent entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.missionID = tableData.getIntField("missionID", -1);
|
||||
entry.offersMission = tableData.getIntField("offersMission", -1) == 1 ? true : false;
|
||||
entry.acceptsMission = tableData.getIntField("acceptsMission", -1) == 1 ? true : false;
|
||||
entry.gate_version = tableData.getStringField("gate_version", "");
|
||||
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDMissionNPCComponent {
|
||||
uint32_t id; //!< The ID
|
||||
uint32_t missionID; //!< The Mission ID
|
||||
@@ -17,4 +19,3 @@ public:
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDMissionNPCComponent> Query(std::function<bool(CDMissionNPCComponent)> predicate);
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ void CDMissionTasksTable::LoadValuesFromDatabase() {
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionTasks");
|
||||
while (!tableData.eof()) {
|
||||
CDMissionTasks entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1));
|
||||
entry.taskType = tableData.getIntField("taskType", -1);
|
||||
@@ -35,11 +35,8 @@ void CDMissionTasksTable::LoadValuesFromDatabase() {
|
||||
UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false);
|
||||
UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
|
||||
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
std::vector<CDMissionTasks> CDMissionTasksTable::Query(std::function<bool(CDMissionTasks)> predicate) {
|
||||
@@ -51,7 +48,7 @@ std::vector<CDMissionTasks> CDMissionTasksTable::Query(std::function<bool(CDMiss
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(uint32_t missionID) {
|
||||
std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(const uint32_t missionID) {
|
||||
std::vector<CDMissionTasks*> tasks;
|
||||
|
||||
// TODO: this should not be linear(?) and also shouldnt need to be a pointer
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDMissionTasks {
|
||||
uint32_t id; //!< The Mission ID that the task belongs to
|
||||
UNUSED(uint32_t locStatus); //!< ???
|
||||
@@ -25,7 +27,7 @@ public:
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDMissionTasks> Query(std::function<bool(CDMissionTasks)> predicate);
|
||||
|
||||
std::vector<CDMissionTasks*> GetByMissionID(uint32_t missionID);
|
||||
std::vector<CDMissionTasks*> GetByMissionID(const uint32_t missionID);
|
||||
|
||||
// TODO: Remove this and replace it with a proper lookup function.
|
||||
const CDTable::StorageType& GetEntries() const;
|
||||
|
||||
@@ -22,7 +22,7 @@ void CDMissionsTable::LoadValuesFromDatabase() {
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Missions");
|
||||
while (!tableData.eof()) {
|
||||
CDMissions entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.defined_type = tableData.getStringField("defined_type", "");
|
||||
entry.defined_subtype = tableData.getStringField("defined_subtype", "");
|
||||
@@ -76,10 +76,8 @@ void CDMissionsTable::LoadValuesFromDatabase() {
|
||||
UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1));
|
||||
entry.reward_bankinventory = tableData.getIntField("reward_bankinventory", -1);
|
||||
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
|
||||
Default.id = -1;
|
||||
@@ -118,3 +116,12 @@ const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& foun
|
||||
return Default;
|
||||
}
|
||||
|
||||
const std::set<int32_t> CDMissionsTable::GetMissionsForReward(LOT lot) {
|
||||
std::set<int32_t> toReturn {};
|
||||
for (const auto& entry : GetEntries()) {
|
||||
if (lot == entry.reward_item1 || lot == entry.reward_item2 || lot == entry.reward_item3 || lot == entry.reward_item4) {
|
||||
toReturn.insert(entry.id);
|
||||
}
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,8 @@ public:
|
||||
|
||||
const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const;
|
||||
|
||||
const std::set<int32_t> GetMissionsForReward(LOT lot);
|
||||
|
||||
|
||||
static CDMissions Default;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ void CDMovementAIComponentTable::LoadValuesFromDatabase() {
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MovementAIComponent");
|
||||
while (!tableData.eof()) {
|
||||
CDMovementAIComponent entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.MovementType = tableData.getStringField("MovementType", "");
|
||||
entry.WanderChance = tableData.getFloatField("WanderChance", -1.0f);
|
||||
@@ -30,11 +30,8 @@ void CDMovementAIComponentTable::LoadValuesFromDatabase() {
|
||||
entry.WanderRadius = tableData.getFloatField("WanderRadius", -1.0f);
|
||||
entry.attachedPath = tableData.getStringField("attachedPath", "");
|
||||
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
std::vector<CDMovementAIComponent> CDMovementAIComponentTable::Query(std::function<bool(CDMovementAIComponent)> predicate) {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDMovementAIComponent {
|
||||
uint32_t id;
|
||||
std::string MovementType;
|
||||
|
||||
@@ -20,17 +20,14 @@ void CDObjectSkillsTable::LoadValuesFromDatabase() {
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ObjectSkills");
|
||||
while (!tableData.eof()) {
|
||||
CDObjectSkills entry;
|
||||
auto &entry = entries.emplace_back();
|
||||
entry.objectTemplate = tableData.getIntField("objectTemplate", -1);
|
||||
entry.skillID = tableData.getIntField("skillID", -1);
|
||||
entry.castOnType = tableData.getIntField("castOnType", -1);
|
||||
entry.AICombatWeight = tableData.getIntField("AICombatWeight", -1);
|
||||
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
std::vector<CDObjectSkills> CDObjectSkillsTable::Query(std::function<bool(CDObjectSkills)> predicate) {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDObjectSkills {
|
||||
uint32_t objectTemplate; //!< The LOT of the item
|
||||
uint32_t skillID; //!< The Skill ID of the object
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "CDObjectsTable.h"
|
||||
|
||||
namespace {
|
||||
CDObjects m_default;
|
||||
CDObjects ObjDefault;
|
||||
};
|
||||
|
||||
void CDObjectsTable::LoadValuesFromDatabase() {
|
||||
@@ -20,8 +20,10 @@ void CDObjectsTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Objects");
|
||||
auto& entries = GetEntriesMutable();
|
||||
while (!tableData.eof()) {
|
||||
CDObjects entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
const uint32_t lot = tableData.getIntField("id", 0);
|
||||
|
||||
auto& entry = entries[lot];
|
||||
entry.id = lot;
|
||||
entry.name = tableData.getStringField("name", "");
|
||||
UNUSED_COLUMN(entry.placeable = tableData.getIntField("placeable", -1);)
|
||||
entry.type = tableData.getStringField("type", "");
|
||||
@@ -36,35 +38,34 @@ void CDObjectsTable::LoadValuesFromDatabase() {
|
||||
UNUSED_COLUMN(entry.gate_version = tableData.getStringField("gate_version", "");)
|
||||
UNUSED_COLUMN(entry.HQ_valid = tableData.getIntField("HQ_valid", -1);)
|
||||
|
||||
entries.insert(std::make_pair(entry.id, entry));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
|
||||
m_default.id = 0;
|
||||
ObjDefault.id = 0;
|
||||
}
|
||||
|
||||
const CDObjects& CDObjectsTable::GetByID(uint32_t LOT) {
|
||||
const CDObjects& CDObjectsTable::GetByID(const uint32_t lot) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
const auto& it = entries.find(LOT);
|
||||
const auto& it = entries.find(lot);
|
||||
if (it != entries.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Objects WHERE id = ?;");
|
||||
query.bind(1, static_cast<int32_t>(LOT));
|
||||
query.bind(1, static_cast<int32_t>(lot));
|
||||
|
||||
auto tableData = query.execQuery();
|
||||
if (tableData.eof()) {
|
||||
entries.insert(std::make_pair(LOT, m_default));
|
||||
return m_default;
|
||||
entries.emplace(lot, ObjDefault);
|
||||
return ObjDefault;
|
||||
}
|
||||
|
||||
// Now get the data
|
||||
while (!tableData.eof()) {
|
||||
CDObjects entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
const uint32_t lot = tableData.getIntField("id", 0);
|
||||
|
||||
auto& entry = entries[lot];
|
||||
entry.id = lot;
|
||||
entry.name = tableData.getStringField("name", "");
|
||||
UNUSED(entry.placeable = tableData.getIntField("placeable", -1));
|
||||
entry.type = tableData.getStringField("type", "");
|
||||
@@ -79,17 +80,15 @@ const CDObjects& CDObjectsTable::GetByID(uint32_t LOT) {
|
||||
UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
|
||||
UNUSED(entry.HQ_valid = tableData.getIntField("HQ_valid", -1));
|
||||
|
||||
entries.insert(std::make_pair(entry.id, entry));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
|
||||
const auto& it2 = entries.find(LOT);
|
||||
const auto& it2 = entries.find(lot);
|
||||
if (it2 != entries.end()) {
|
||||
return it2->second;
|
||||
}
|
||||
|
||||
return m_default;
|
||||
return ObjDefault;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDObjects {
|
||||
uint32_t id; //!< The LOT of the object
|
||||
std::string name; //!< The internal name of the object
|
||||
@@ -24,6 +26,6 @@ class CDObjectsTable : public CDTable<CDObjectsTable, std::map<uint32_t, CDObjec
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Gets an entry by ID
|
||||
const CDObjects& GetByID(uint32_t LOT);
|
||||
const CDObjects& GetByID(const uint32_t lot);
|
||||
};
|
||||
|
||||
|
||||
@@ -19,12 +19,11 @@ void CDPackageComponentTable::LoadValuesFromDatabase() {
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PackageComponent");
|
||||
while (!tableData.eof()) {
|
||||
CDPackageComponent entry;
|
||||
auto& entry = entries.emplace_back();
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
|
||||
entry.packageType = tableData.getIntField("packageType", -1);
|
||||
|
||||
entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct CDPackageComponent {
|
||||
uint32_t id;
|
||||
uint32_t LootMatrixIndex;
|
||||
|
||||
@@ -50,7 +50,7 @@ void CDPetComponentTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
void CDPetComponentTable::LoadValuesFromDefaults() {
|
||||
GetEntriesMutable().insert(std::make_pair(defaultEntry.id, defaultEntry));
|
||||
GetEntriesMutable().emplace(defaultEntry.id, defaultEntry);
|
||||
}
|
||||
|
||||
CDPetComponent& CDPetComponentTable::GetByID(const uint32_t componentID) {
|
||||
|
||||
@@ -4,32 +4,31 @@ void CDPhysicsComponentTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PhysicsComponent");
|
||||
auto& entries = GetEntriesMutable();
|
||||
while (!tableData.eof()) {
|
||||
CDPhysicsComponent entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
const uint32_t componentID = tableData.getIntField("id", -1);
|
||||
|
||||
auto& entry = entries[componentID];
|
||||
entry.id = componentID;
|
||||
entry.bStatic = tableData.getIntField("static", -1) != 0;
|
||||
entry.physicsAsset = tableData.getStringField("physics_asset", "");
|
||||
UNUSED(entry->jump = tableData.getIntField("jump", -1) != 0);
|
||||
UNUSED(entry->doublejump = tableData.getIntField("doublejump", -1) != 0);
|
||||
entry.speed = tableData.getFloatField("speed", -1);
|
||||
UNUSED(entry->rotSpeed = tableData.getFloatField("rotSpeed", -1));
|
||||
entry.playerHeight = tableData.getFloatField("playerHeight");
|
||||
entry.playerRadius = tableData.getFloatField("playerRadius");
|
||||
UNUSED_COLUMN(entry.jump = tableData.getIntField("jump", -1) != 0;)
|
||||
UNUSED_COLUMN(entry.doubleJump = tableData.getIntField("doublejump", -1) != 0;)
|
||||
entry.speed = static_cast<float>(tableData.getFloatField("speed", -1));
|
||||
UNUSED_COLUMN(entry.rotSpeed = tableData.getFloatField("rotSpeed", -1);)
|
||||
entry.playerHeight = static_cast<float>(tableData.getFloatField("playerHeight"));
|
||||
entry.playerRadius = static_cast<float>(tableData.getFloatField("playerRadius"));
|
||||
entry.pcShapeType = tableData.getIntField("pcShapeType");
|
||||
entry.collisionGroup = tableData.getIntField("collisionGroup");
|
||||
UNUSED(entry->airSpeed = tableData.getFloatField("airSpeed"));
|
||||
UNUSED(entry->boundaryAsset = tableData.getStringField("boundaryAsset"));
|
||||
UNUSED(entry->jumpAirSpeed = tableData.getFloatField("jumpAirSpeed"));
|
||||
UNUSED(entry->friction = tableData.getFloatField("friction"));
|
||||
UNUSED(entry->gravityVolumeAsset = tableData.getStringField("gravityVolumeAsset"));
|
||||
UNUSED_COLUMN(entry.airSpeed = tableData.getFloatField("airSpeed");)
|
||||
UNUSED_COLUMN(entry.boundaryAsset = tableData.getStringField("boundaryAsset");)
|
||||
UNUSED_COLUMN(entry.jumpAirSpeed = tableData.getFloatField("jumpAirSpeed");)
|
||||
UNUSED_COLUMN(entry.friction = tableData.getFloatField("friction");)
|
||||
UNUSED_COLUMN(entry.gravityVolumeAsset = tableData.getStringField("gravityVolumeAsset");)
|
||||
|
||||
entries.insert(std::make_pair(entry.id, entry));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
CDPhysicsComponent* CDPhysicsComponentTable::GetByID(uint32_t componentID) {
|
||||
CDPhysicsComponent* CDPhysicsComponentTable::GetByID(const uint32_t componentID) {
|
||||
auto& entries = GetEntriesMutable();
|
||||
auto itr = entries.find(componentID);
|
||||
return itr != entries.end() ? &itr->second : nullptr;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "CDTable.h"
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
struct CDPhysicsComponent {
|
||||
@@ -7,7 +8,7 @@ struct CDPhysicsComponent {
|
||||
bool bStatic;
|
||||
std::string physicsAsset;
|
||||
UNUSED(bool jump);
|
||||
UNUSED(bool doublejump);
|
||||
UNUSED(bool doubleJump);
|
||||
float speed;
|
||||
UNUSED(float rotSpeed);
|
||||
float playerHeight;
|
||||
@@ -26,5 +27,5 @@ public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
static const std::string GetTableName() { return "PhysicsComponent"; };
|
||||
CDPhysicsComponent* GetByID(uint32_t componentID);
|
||||
CDPhysicsComponent* GetByID(const uint32_t componentID);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "CDPlayerFlagsTable.h"
|
||||
|
||||
#include "CDClientDatabase.h"
|
||||
|
||||
namespace CDPlayerFlagsTable {
|
||||
Table entries;
|
||||
|
||||
void ReadEntry(CppSQLite3Query& table) {
|
||||
Entry entry;
|
||||
entry.sessionOnly = table.getIntField("SessionOnly") == 1;
|
||||
entry.onlySetByServer = table.getIntField("OnlySetByServer") == 1;
|
||||
entry.sessionZoneOnly = table.getIntField("SessionZoneOnly") == 1;
|
||||
entries[table.getIntField("id")] = entry;
|
||||
}
|
||||
|
||||
void LoadValuesFromDatabase() {
|
||||
auto table = CDClientDatabase::ExecuteQuery("SELECT * FROM PlayerFlags;");
|
||||
|
||||
if (!table.eof()) {
|
||||
do {
|
||||
ReadEntry(table);
|
||||
} while (!table.nextRow());
|
||||
}
|
||||
}
|
||||
|
||||
const std::optional<Entry> GetEntry(const FlagId flagId) {
|
||||
if (!entries.contains(flagId)) {
|
||||
auto table = CDClientDatabase::CreatePreppedStmt("SELECT * FROM PlayerFlags WHERE id = ?;");
|
||||
table.bind(1, static_cast<int>(flagId));
|
||||
auto result = table.execQuery();
|
||||
if (!result.eof()) {
|
||||
ReadEntry(result);
|
||||
}
|
||||
}
|
||||
|
||||
return entries[flagId];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef CDPLAYERFLAGSTABLE_H
|
||||
#define CDPLAYERFLAGSTABLE_H
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
|
||||
namespace CDPlayerFlagsTable {
|
||||
struct Entry {
|
||||
bool sessionOnly{};
|
||||
bool onlySetByServer{};
|
||||
bool sessionZoneOnly{};
|
||||
};
|
||||
|
||||
using FlagId = uint32_t;
|
||||
using Table = std::map<FlagId, std::optional<Entry>>;
|
||||
|
||||
void LoadValuesFromDatabase();
|
||||
const std::optional<Entry> GetEntry(const FlagId flagId);
|
||||
};
|
||||
|
||||
#endif //!CDPLAYERFLAGSTABLE_H
|
||||
@@ -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;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user