mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-17 03:37:08 -06:00
Compare commits
198 Commits
friction-v
...
item-compo
| Author | SHA1 | Date | |
|---|---|---|---|
| 15988afb4c | |||
| 5e9a956bed | |||
| c2d5be0e5d | |||
|
|
7671cc6865 | ||
|
|
bd79e9433c | ||
|
|
2bcf862f93 | ||
|
|
c3723371cf | ||
|
|
137a5e5c3d | ||
|
|
a532bc15d8 | ||
| ff0336793c | |||
|
|
49047a267b | ||
| 9d65d871d0 | |||
| e524b86e12 | |||
|
|
2837f68f44 | ||
|
|
a0c0a87956 | ||
|
|
3e482602d4 | ||
|
|
b6fc959433 | ||
| 6d989f37f1 | |||
|
|
d138b7b878 | ||
| 484488e47d | |||
|
|
72c93c8913 | ||
| 2ae9a92b55 | |||
| 50978620d8 | |||
| c168f6c970 | |||
| 3cd0d1ec3d | |||
| 91c0c1fcfb | |||
|
|
d17f51183e | ||
|
|
6aa69de4fd | ||
|
|
cdffd5ff30 | ||
| ac5f08f601 | |||
|
|
90d184ba93 | ||
| bff14fd391 | |||
| faf42d2f8c | |||
|
|
cff94b6c22 | ||
|
|
c8cd51ef63 | ||
| 6fd80e3117 | |||
|
|
14085d09bd | ||
|
|
7418e02365 | ||
|
|
fbaf1cbb25 | ||
| 872270704c | |||
|
|
7bca43ffc1 | ||
|
|
7aacfc1bf0 | ||
| 5557a98129 | |||
|
|
45d739499a | ||
|
|
5b30f4a5ae | ||
|
|
bfa4fbd5a9 | ||
|
|
e7bc4ef773 | ||
| ce39e3ad6b | |||
|
|
e67f310632 | ||
|
|
8920cd1063 | ||
|
|
a580e3a2f5 | ||
|
|
a28a2e60cf | ||
| 5374c555f5 | |||
| 80f8dd8003 | |||
|
|
1ac898ba00 | ||
|
|
fc75d6048f | ||
|
|
8bcb4bd36d | ||
|
|
bad3845d83 | ||
|
|
7fcc8a6e84 | ||
|
|
1a34f6f74a | ||
|
|
1789ec7f20 | ||
|
|
dc7d0ce142 | ||
|
|
203a150a56 | ||
|
|
19be0a61b2 | ||
|
|
09157506bf | ||
|
|
737eaba54d | ||
|
|
fab4414204 | ||
| 34b5f0f9d6 | |||
|
|
9adbb7aa86 | ||
|
|
bd28e4051f | ||
|
|
99c0ca253c | ||
|
|
0e9c0a8917 | ||
|
|
e41ed68447 | ||
| 5cc7d47074 | |||
|
|
1470af99c3 | ||
|
|
85ab573665 | ||
| 6ec921025d | |||
|
|
bbd5a49ea2 | ||
|
|
675cf1d2a4 | ||
| 9ebb06ba24 | |||
|
|
96313ecd69 | ||
|
|
015cbc06ea | ||
|
|
dff02773a0 | ||
|
|
d052ed6a63 | ||
|
|
fd9757d121 | ||
|
|
bd7f532a28 | ||
|
|
51dd56f0a0 | ||
|
|
38eb441ca1 | ||
|
|
559894024c | ||
|
|
0a31db9d44 | ||
|
|
f2fa81b5c3 | ||
|
|
2fdcf62ec6 | ||
|
|
d69f733772 | ||
| 157a05239e | |||
|
|
9f47b1f0bb | ||
|
|
f311685dda | ||
|
|
84c5d74450 | ||
|
|
b972acbacc | ||
|
|
f41dfaebdf | ||
|
|
12ab094082 | ||
|
|
e1bcde628f | ||
|
|
1da2db9db6 | ||
|
|
5d0de99390 | ||
|
|
2b56dfbc89 | ||
| 631365b7f7 | |||
| 32f8bda538 | |||
|
|
cd78a3dec7 | ||
|
|
a2ca273370 | ||
|
|
04ccd7ebe4 | ||
|
|
b33a3df012 | ||
|
|
0d460c0eb3 | ||
|
|
3f1b4339f5 | ||
|
|
e78dc0b874 | ||
|
|
b1d4153f00 | ||
|
|
1ed3af63b9 | ||
|
|
213c3c37b0 | ||
|
|
3c581fffbb | ||
|
|
4775dbf27f | ||
|
|
e1cc25759e | ||
|
|
b7341c8106 | ||
|
|
1afe717563 | ||
|
|
435761f64b | ||
|
|
9659000569 | ||
|
|
5292f36417 | ||
|
|
da910309a0 | ||
|
|
430c6da4a7 | ||
|
|
d5613b8034 | ||
| 8886bf6547 | |||
|
|
a14e16237b | ||
|
|
fde62a4777 | ||
|
|
46f085eb4b | ||
|
|
18a0ae599b | ||
|
|
0a616f891f | ||
|
|
2ba3103a0c | ||
|
|
e8ba3357e8 | ||
|
|
de3e53de6c | ||
|
|
ab5adea24c | ||
|
|
e1af528d9b | ||
| d8945e9067 | |||
| 2b9c014b86 | |||
|
|
63460ea00d | ||
|
|
09dfb6df3a | ||
|
|
56da3f8543 | ||
|
|
3222e78815 | ||
|
|
3939f19b08 | ||
|
|
1556f580d6 | ||
|
|
d382eb3bc2 | ||
|
|
f8f5b731f1 | ||
|
|
e40a597f18 | ||
|
|
af28d170fb | ||
|
|
e2616c5f11 | ||
| 36eecd693d | |||
|
|
4569f62100 | ||
|
|
afb97a81b5 | ||
|
|
b17ba56af1 | ||
|
|
9d62a8cd0b | ||
|
|
416021c208 | ||
| 3fa6ea4cea | |||
| 37524af549 | |||
|
|
53b559bef3 | ||
| 848c066924 | |||
| 7429902a64 | |||
| 22e5d02400 | |||
| cf7fa8e52d | |||
| 1eff3ae454 | |||
|
|
7c2437173b | ||
|
|
2570c74b71 | ||
|
|
2f48981801 | ||
|
|
1464762bcd | ||
| 9c58ea5c41 | |||
|
|
1d5c71eb9b | ||
| 162f84e285 | |||
|
|
8880486c8b | ||
|
|
8d37d9b681 | ||
|
|
b974eed8f5 | ||
|
|
8edade5f98 | ||
| 353c328485 | |||
|
|
4a6f3e44ee | ||
|
|
971e0fb3b6 | ||
|
|
62213cd701 | ||
|
|
d4af7d76a2 | ||
|
|
89fb66c4a9 | ||
|
|
906887bda9 | ||
|
|
a745cdb727 | ||
|
|
d8e73def9d | ||
|
|
2bdbf129cf | ||
|
|
c13937bd1f | ||
| 8d44f2f5da | |||
| 366c3db7fe | |||
|
|
f02e9c0f6a | ||
| 409d682c9d | |||
|
|
63af2c8da7 | ||
|
|
ce2e6f595b | ||
| c552f46780 | |||
| 14d4bf3cc5 | |||
| 26f2eb409f | |||
| 1af3e59348 | |||
|
|
e3077aa410 |
@@ -1,37 +0,0 @@
|
||||
---
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
BreakBeforeBraces: Attach
|
||||
ColumnLimit: 0
|
||||
IndentWidth: 4
|
||||
IndentCaseLabels: true
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '<[[:alnum:].]+\.h>'
|
||||
Priority: 1
|
||||
- Regex: '<[[:alnum:].]+>'
|
||||
Priority: 2
|
||||
- Regex: '.*/.*'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 4
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
...
|
||||
17
.clang-tidy
17
.clang-tidy
@@ -1,17 +0,0 @@
|
||||
Checks: '-*,readability-*,performance-*,modernize-*,-modernize-use-trailing-return-type,bugprone-*'
|
||||
WarningsAsErrors: true
|
||||
HeaderFilterRegex: ''
|
||||
FormatStyle: none
|
||||
CheckOptions:
|
||||
- key: readability-identifier-naming.ClassCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ClassMethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ClassMemberPrefix
|
||||
value: m_
|
||||
- key: readability-identifier-naming.ClassMemberCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ClassConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.FunctionCase
|
||||
value: CamelCase
|
||||
@@ -6,3 +6,6 @@
|
||||
|
||||
# convert to unix line endings
|
||||
72477e01e2711e0f61cdb192ee266e5e21b8846f
|
||||
|
||||
# enum cleanup
|
||||
faf42d2f8cf432df2993b031f079b0b8c6d7dbe7
|
||||
|
||||
5
.github/workflows/build-and-test.yml
vendored
5
.github/workflows/build-and-test.yml
vendored
@@ -10,12 +10,13 @@ jobs:
|
||||
build-and-test:
|
||||
name: Build & Test (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-2022, ubuntu-20.04, macos-11 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Add msbuild to PATH (Windows only)
|
||||
@@ -34,7 +35,7 @@ jobs:
|
||||
buildPreset: "ci-${{matrix.os}}"
|
||||
testPreset: "ci-${{matrix.os}}"
|
||||
- name: artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ github.ref == 'ref/head/main' }}
|
||||
with:
|
||||
name: build-${{matrix.os}}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -121,4 +121,4 @@ docker/__pycache__
|
||||
|
||||
docker-compose.override.yml
|
||||
|
||||
!/tests/TestBitStreams/*.bin
|
||||
!*Test.bin
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -14,12 +14,6 @@
|
||||
path = thirdparty/mariadb-connector-cpp
|
||||
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
|
||||
ignore = dirty
|
||||
[submodule "thirdparty/docker-utils"]
|
||||
path = thirdparty/docker-utils
|
||||
url = https://github.com/lcdr/utils.git
|
||||
[submodule "thirdparty/LUnpack"]
|
||||
path = thirdparty/LUnpack
|
||||
url = https://github.com/Xiphoseer/LUnpack.git
|
||||
[submodule "thirdparty/AccountManager"]
|
||||
path = thirdparty/AccountManager
|
||||
url = https://github.com/DarkflameUniverse/AccountManager
|
||||
|
||||
136
CMakeLists.txt
136
CMakeLists.txt
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
cmake_minimum_required(VERSION 3.18)
|
||||
project(Darkflame)
|
||||
include(CTest)
|
||||
|
||||
@@ -58,7 +58,7 @@ if(UNIX)
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC -lstdc++fs")
|
||||
endif()
|
||||
if (__dynamic AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
|
||||
@@ -76,21 +76,27 @@ endif()
|
||||
|
||||
# Our output dir
|
||||
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR})
|
||||
|
||||
# TODO make this not have to override the build type directories
|
||||
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})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Create a /res directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/res)
|
||||
|
||||
# Create a /locale directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/locale)
|
||||
# Create a /resServer directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/resServer)
|
||||
|
||||
# Create a /logs directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/logs)
|
||||
|
||||
# Copy resource files on first build
|
||||
set(RESOURCE_FILES "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
|
||||
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
|
||||
foreach(resource_file ${RESOURCE_FILES})
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
|
||||
configure_file(
|
||||
@@ -101,6 +107,17 @@ foreach(resource_file ${RESOURCE_FILES})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Copy navmesh data on first build and extract it
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/navmeshes.zip ${PROJECT_BINARY_DIR}/navmeshes.zip
|
||||
COPYONLY
|
||||
)
|
||||
|
||||
file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip)
|
||||
file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip)
|
||||
endif()
|
||||
|
||||
# Copy vanity files on first build
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
|
||||
foreach(file ${VANITY_FILES})
|
||||
@@ -108,13 +125,25 @@ foreach(file ${VANITY_FILES})
|
||||
endforeach()
|
||||
|
||||
# Move our migrations for MasterServer to run
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/)
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/dlu/)
|
||||
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql)
|
||||
foreach(file ${SQL_FILES})
|
||||
get_filename_component(file ${file} NAME)
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/${file})
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/dlu/${file})
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/${file}
|
||||
${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/dlu/${file}
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
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)
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file}
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
@@ -123,6 +152,8 @@ endforeach()
|
||||
# Create our list of include directories
|
||||
set(INCLUDED_DIRECTORIES
|
||||
"dCommon"
|
||||
"dCommon/dClient"
|
||||
"dCommon/dEnums"
|
||||
"dChatFilter"
|
||||
"dGame"
|
||||
"dGame/dBehaviors"
|
||||
@@ -131,6 +162,8 @@ set(INCLUDED_DIRECTORIES
|
||||
"dGame/dInventory"
|
||||
"dGame/dMission"
|
||||
"dGame/dEntity"
|
||||
"dGame/dPropertyBehaviors"
|
||||
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
|
||||
"dGame/dUtilities"
|
||||
"dPhysics"
|
||||
"dNavigation"
|
||||
@@ -140,12 +173,86 @@ set(INCLUDED_DIRECTORIES
|
||||
"dDatabase/Tables"
|
||||
"dNet"
|
||||
"dScripts"
|
||||
"dScripts/02_server"
|
||||
"dScripts/ai"
|
||||
"dScripts/client"
|
||||
"dScripts/EquipmentScripts"
|
||||
"dScripts/EquipmentTriggers"
|
||||
"dScripts/zone"
|
||||
"dScripts/02_server/DLU"
|
||||
"dScripts/02_server/Enemy"
|
||||
"dScripts/02_server/Equipment"
|
||||
"dScripts/02_server/Map"
|
||||
"dScripts/02_server/Minigame"
|
||||
"dScripts/02_server/Objects"
|
||||
"dScripts/02_server/Pets"
|
||||
"dScripts/02_server/Enemy/AG"
|
||||
"dScripts/02_server/Enemy/AM"
|
||||
"dScripts/02_server/Enemy/FV"
|
||||
"dScripts/02_server/Enemy/General"
|
||||
"dScripts/02_server/Enemy/Survival"
|
||||
"dScripts/02_server/Enemy/VE"
|
||||
"dScripts/02_server/Enemy/Waves"
|
||||
"dScripts/02_server/Map/AG"
|
||||
"dScripts/02_server/Map/AG_Spider_Queen"
|
||||
"dScripts/02_server/Map/AM"
|
||||
"dScripts/02_server/Map/FV"
|
||||
"dScripts/02_server/Map/General"
|
||||
"dScripts/02_server/Map/GF"
|
||||
"dScripts/02_server/Map/njhub"
|
||||
"dScripts/02_server/Map/NS"
|
||||
"dScripts/02_server/Map/NT"
|
||||
"dScripts/02_server/Map/PR"
|
||||
"dScripts/02_server/Map/Property"
|
||||
"dScripts/02_server/Map/SS"
|
||||
"dScripts/02_server/Map/VE"
|
||||
"dScripts/02_server/Map/FV/Racing"
|
||||
"dScripts/02_server/Map/General/Ninjago"
|
||||
"dScripts/02_server/Map/njhub/boss_instance"
|
||||
"dScripts/02_server/Map/NS/Waves"
|
||||
"dScripts/02_server/Map/Property/AG_Med"
|
||||
"dScripts/02_server/Map/Property/AG_Small"
|
||||
"dScripts/02_server/Map/Property/NS_Med"
|
||||
"dScripts/02_server/Minigame/General"
|
||||
"dScripts/ai/ACT"
|
||||
"dScripts/ai/AG"
|
||||
"dScripts/ai/FV"
|
||||
"dScripts/ai/GENERAL"
|
||||
"dScripts/ai/GF"
|
||||
"dScripts/ai/MINIGAME"
|
||||
"dScripts/ai/NP"
|
||||
"dScripts/ai/NS"
|
||||
"dScripts/ai/PETS"
|
||||
"dScripts/ai/PROPERTY"
|
||||
"dScripts/ai/RACING"
|
||||
"dScripts/ai/SPEC"
|
||||
"dScripts/ai/WILD"
|
||||
"dScripts/ai/ACT/FootRace"
|
||||
"dScripts/ai/MINIGAME/SG_GF"
|
||||
"dScripts/ai/MINIGAME/SG_GF/SERVER"
|
||||
"dScripts/ai/NS/NS_PP_01"
|
||||
"dScripts/ai/NS/WH"
|
||||
"dScripts/ai/PROPERTY/AG"
|
||||
"dScripts/ai/RACING/OBJECTS"
|
||||
"dScripts/client/ai"
|
||||
"dScripts/client/ai/PR"
|
||||
"dScripts/zone/AG"
|
||||
"dScripts/zone/LUPs"
|
||||
"dScripts/zone/PROPERTY"
|
||||
"dScripts/zone/PROPERTY/FV"
|
||||
"dScripts/zone/PROPERTY/GF"
|
||||
"dScripts/zone/PROPERTY/NS"
|
||||
|
||||
"thirdparty/raknet/Source"
|
||||
"thirdparty/tinyxml2"
|
||||
"thirdparty/recastnavigation"
|
||||
"thirdparty/SQLite"
|
||||
"thirdparty/cpplinq"
|
||||
|
||||
"tests"
|
||||
"tests/dCommonTests"
|
||||
"tests/dGameTests"
|
||||
"tests/dGameTests/dComponentsTests"
|
||||
)
|
||||
|
||||
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
||||
@@ -160,7 +267,6 @@ elseif (UNIX)
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt")
|
||||
endif()
|
||||
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
# Add binary directory as an include directory
|
||||
include_directories(${PROJECT_BINARY_DIR})
|
||||
|
||||
@@ -228,8 +334,6 @@ if (UNIX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests)
|
||||
|
||||
# Include all of our binary directories
|
||||
add_subdirectory(dWorldServer)
|
||||
add_subdirectory(dAuthServer)
|
||||
@@ -262,3 +366,7 @@ target_precompile_headers(
|
||||
tinyxml2 PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>"
|
||||
)
|
||||
|
||||
if (${__enable_testing__} MATCHES "1")
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -1,126 +1,128 @@
|
||||
{
|
||||
"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"
|
||||
"version": 3,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 14,
|
||||
"patch": 0
|
||||
},
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"displayName": "CI configure step for Ubuntu",
|
||||
"description": "Same as default, Used in GitHub actions workflow",
|
||||
"inherits": "default"
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"displayName": "CI configure step for MacOS",
|
||||
"description": "Same as default, Used in GitHub actions workflow",
|
||||
"inherits": "default",
|
||||
"cacheVariables": {
|
||||
"OPENSSL_ROOT_DIR": "/usr/local/Cellar/openssl@3/3.0.5/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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"
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "default",
|
||||
"displayName": "Default configure step",
|
||||
"description": "Use 'build' dir and Unix makefiles",
|
||||
"binaryDir": "${sourceDir}/build",
|
||||
"generator": "Unix Makefiles"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"displayName": "CI configure step for Ubuntu",
|
||||
"description": "Same as default, Used in GitHub actions workflow",
|
||||
"inherits": "default"
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"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-20.04",
|
||||
"configurePreset": "ci-ubuntu-20.04",
|
||||
"displayName": "Linux CI Build",
|
||||
"description": "This preset is used by the CI build on linux",
|
||||
"jobs": 2
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"displayName": "MacOS CI Build",
|
||||
"description": "This preset is used by the CI build on MacOS",
|
||||
"jobs": 2
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"configurePreset": "ci-ubuntu-20.04",
|
||||
"displayName": "CI Tests on Linux",
|
||||
"description": "Runs all tests on a linux configuration",
|
||||
"execution": {
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "default",
|
||||
"configurePreset": "default",
|
||||
"displayName": "Default Build",
|
||||
"description": "Default Build",
|
||||
"jobs": 2
|
||||
},
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"displayName": "CI Tests on MacOS",
|
||||
"description": "Runs all tests on a Mac configuration",
|
||||
"execution": {
|
||||
{
|
||||
"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
|
||||
},
|
||||
"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": {
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"configurePreset": "ci-ubuntu-20.04",
|
||||
"displayName": "Linux CI Build",
|
||||
"description": "This preset is used by the CI build on linux",
|
||||
"jobs": 2
|
||||
},
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"displayName": "MacOS CI Build",
|
||||
"description": "This preset is used by the CI build on MacOS",
|
||||
"jobs": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "ci-ubuntu-20.04",
|
||||
"configurePreset": "ci-ubuntu-20.04",
|
||||
"displayName": "CI Tests on Linux",
|
||||
"description": "Runs all tests on a linux configuration",
|
||||
"execution": {
|
||||
"jobs": 2
|
||||
},
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"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))+"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,13 +8,17 @@ LICENSE=AGPL-3.0
|
||||
# 171022 - Unmodded client
|
||||
NET_VERSION=171022
|
||||
# Debugging
|
||||
__dynamic=1
|
||||
# Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
||||
# __ggdb=1
|
||||
__dynamic=1
|
||||
# Set __ggdb to 1 to enable the -ggdb flag for the linker, including more debug info.
|
||||
# __include_backtrace__=1
|
||||
# __ggdb=1
|
||||
# Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs.
|
||||
# __include_backtrace__=1
|
||||
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
|
||||
# __compile_backtrace__=1
|
||||
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
|
||||
__maria_db_connector_compile_jobs__=1
|
||||
# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with.
|
||||
__maria_db_connector_compile_jobs__=1
|
||||
# When set to 1 and uncommented, compiling and linking testing folders and libraries will be done.
|
||||
__enable_testing__=1
|
||||
# The path to OpenSSL. Change this if your OpenSSL install path is different than the default.
|
||||
OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
- [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker)
|
||||
- [Docker Compose](https://docs.docker.com/compose/install/) (Included in Docker Desktop)
|
||||
- LEGO® Universe packed Client. Check the main [README](./README.md) for details on this.
|
||||
- LEGO® Universe Client. Check the main [README](./README.md) for details on this.
|
||||
|
||||
## Run server inside Docker
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
11. Once the command has completed (you can see you path again and can enter commands), close the window.
|
||||
12. Inside the downloaded folder, copy `.env.example` and name the copy `.env`
|
||||
13. Open `.env` with Notepad by right-clicking it and selecting _Open With_ -> _More apps_ -> _Notepad_.
|
||||
14. Change the text after `CLIENT_PATH=` to the location of your client. The folder you are pointing to must contain a folder called `client` which should contain the client files.
|
||||
14. Change the text after `CLIENT_PATH=` to the location of your client. This folder must contain either a folder `client` or `legouniverse.exe`.
|
||||
> If you need the extra performance, place the client files in `\\wsl$\<your linux OS>\...` to avoid working across file systems, see [Docker Best Practices](https://docs.docker.com/desktop/windows/wsl/#best-practices) and [WSL documentation](https://docs.microsoft.com/en-us/windows/wsl/filesystems#file-storage-and-performance-across-file-systems).
|
||||
|
||||
15. Optionally, you can change the number after `BUILD_THREADS=` to the number of cores / threads your processor has. If your computer crashes while building, you can try to reduce this value.
|
||||
|
||||
611
README.md
611
README.md
@@ -18,204 +18,192 @@ Darkflame Universe is licensed under AGPLv3, please read [LICENSE](LICENSE). Som
|
||||
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. DLU 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.
|
||||
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 in the resources tab below when checking if a client will work.
|
||||
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.
|
||||
|
||||
## Build
|
||||
Development of the latest iteration of Darkflame Universe has been done primarily in a Unix-like environment and is where it has been tested and designed for deployment. It is therefore highly recommended that Darkflame Universe be built and deployed using a Unix-like environment for the most streamlined experience.
|
||||
## Steps to setup server
|
||||
* [Clone this repository](#clone-the-repository)
|
||||
* [Install dependencies](#install-dependencies)
|
||||
* [Database setup](#database-setup)
|
||||
* [Build the server](#build-the-server)
|
||||
* [Configuring your server](#configuring-your-server)
|
||||
* [Required Configuration](#required-configuration)
|
||||
* [Optional Configuration](#optional-configuration)
|
||||
* [Verify your setup](#verify-your-setup)
|
||||
* [Running the server](#running-the-server)
|
||||
* [User Guide](#user-guide)
|
||||
|
||||
### Prerequisites
|
||||
#### Clone the repository
|
||||
## Clone the repository
|
||||
If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win)
|
||||
|
||||
Then run the following command
|
||||
```bash
|
||||
git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
||||
```
|
||||
#### Python
|
||||
|
||||
Some tools utilized to streamline the setup process require Python 3, make sure you have it installed.
|
||||
## Install dependencies
|
||||
|
||||
### 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!).
|
||||
|
||||
### Choosing the right version for your client
|
||||
DLU clients identify themselves using a higher version number than the regular live clients out there.
|
||||
This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client.
|
||||
### MacOS packages
|
||||
Ensure you have [brew](https://brew.sh) installed.
|
||||
You will need to install the following packages
|
||||
```bash
|
||||
brew install cmake gcc mariadb openssl zlib
|
||||
```
|
||||
|
||||
If you're using a DLU client you'll have to go into the "CMakeVariables.txt" file and change the NET_VERSION variable to 171023 to match the modified client's version number.
|
||||
### Linux packages
|
||||
Make sure packages like `gcc`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. You will also need a MySQL database solution to use. We recommend using `mariadb-server`.
|
||||
|
||||
### Using Docker
|
||||
Refer to [Docker.md](/Docker.md).
|
||||
For Ubuntu, you would run the following commands. On other systems, the package install command will differ.
|
||||
|
||||
For Windows, refer to [Docker_Windows.md](/Docker_Windows.md).
|
||||
```bash
|
||||
sudo apt update && sudo apt upgrade
|
||||
|
||||
### Linux builds
|
||||
Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`.
|
||||
# Install packages
|
||||
sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-server cmake
|
||||
```
|
||||
|
||||
CMake must be version 3.14 or higher!
|
||||
#### 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.
|
||||
You can check your CMake version by using the following command in a terminal.
|
||||
```bash
|
||||
cmake --version
|
||||
```
|
||||
|
||||
#### Build the repository
|
||||
If you are going to be using an Ubuntu environment to run the server, you may need to get a more recent version of `cmake` than the packages available may provide.
|
||||
|
||||
The general approach to do so would be to obtain a copy of the signing key and then add the CMake repository to your apt.
|
||||
You can do so with the following commands.
|
||||
|
||||
[Source of the below commands](https://askubuntu.com/questions/355565/how-do-i-install-the-latest-version-of-cmake-from-the-command-line)
|
||||
|
||||
```bash
|
||||
# Remove the old version of CMake
|
||||
sudo apt purge --auto-remove cmake
|
||||
|
||||
# Prepare for installation
|
||||
sudo apt update && sudo apt install -y software-properties-common lsb-release && sudo apt clean all
|
||||
|
||||
# Obtain a copy of the signing key
|
||||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
|
||||
|
||||
# Add the repository to your sources list.
|
||||
sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main"
|
||||
|
||||
# Next you'll want to ensure that Kitware's keyring stays up to date
|
||||
sudo apt update
|
||||
sudo apt install kitware-archive-keyring
|
||||
sudo rm /etc/apt/trusted.gpg.d/kitware.gpg
|
||||
|
||||
# If sudo apt update above returned an error, copy the public key at the end of the error message and run the following command
|
||||
# if the error message was "The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 6AF7F09730B3F0A4"
|
||||
# then the below command would be "sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6AF7F09730B3F0A4"
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys <TheCopiedPublicKey>
|
||||
|
||||
# Finally update and install
|
||||
sudo apt update
|
||||
sudo apt install cmake
|
||||
```
|
||||
|
||||
## Database setup
|
||||
First you'll need to start MariaDB.
|
||||
|
||||
For Windows the service is always running by default.
|
||||
|
||||
For MacOS, run the following command
|
||||
```bash
|
||||
brew services start mariadb
|
||||
```
|
||||
|
||||
For Linux, run the following command
|
||||
```bash
|
||||
sudo systemctl start mysql
|
||||
# If systemctl is not a known command on your distribution, try the following instead
|
||||
sudo service mysql start
|
||||
```
|
||||
|
||||
<font size="4">**You will need to run this command every time you restart your environment**</font>
|
||||
|
||||
If you are using Linux and `systemctl` and want the MariaDB instance to start on startup, run the following command
|
||||
```bash
|
||||
sudo systemctl enable --now mysql
|
||||
```
|
||||
|
||||
Once MariaDB is started, you'll need to create a user and an empty database for Darkflame Universe to use.
|
||||
|
||||
First, login to the MariaDB instance.
|
||||
|
||||
To do this on Ubuntu/Linux, MacOS, or another Unix like operating system, run the following command in a terminal
|
||||
```bash
|
||||
# Logs you into the MariaDB instance as root
|
||||
sudo mysql
|
||||
```
|
||||
|
||||
For Windows, run the following command in the `Command Prompt (MariaDB xx.xx)` terminal
|
||||
```bash
|
||||
# Logs you into the mysql instance
|
||||
mysql -u root -p
|
||||
# You will then be prompted for the password you set for root during installation of MariaDB
|
||||
```
|
||||
|
||||
Now that you are logged in, run the following commands.
|
||||
|
||||
```bash
|
||||
# Creates a user for this computer which uses a password and grant said user all privileges.
|
||||
# Change mydarkflameuser to a custom username and password to a custom password.
|
||||
GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION;
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
# Then create a database for Darkflame Universe to use.
|
||||
CREATE DATABASE darkflame;
|
||||
```
|
||||
|
||||
## Build the server
|
||||
You can either run `build.sh` when in the root folder of the repository:
|
||||
|
||||
```bash
|
||||
./build.sh
|
||||
```
|
||||
|
||||
Or manually run the commands used in `build.sh`:
|
||||
Or manually run the commands used in [build.sh](build.sh).
|
||||
|
||||
If you would like to build the server faster, append `-j<number>` where number is the number of simultaneous compile jobs to run at once. It is recommended that you have this number always be 1 less than your core count to prevent slowdowns. The command would look like this if you would build with 4 jobs at once:
|
||||
```bash
|
||||
# Create the build directory, preserving it if it already exists
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
# Run CMake to generate make files
|
||||
cmake ..
|
||||
|
||||
# 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
|
||||
./build.sh -j4
|
||||
```
|
||||
### 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.
|
||||
* If you are using a Darkflame Universe client, ensure NET_VERSION is changed to 171023.
|
||||
|
||||
### MacOS builds
|
||||
Ensure `cmake`, `zlib` and `open ssl` are installed as well as a compiler (e.g `clang` or `gcc`).
|
||||
## Configuring your server
|
||||
This server has a few steps that need to be taken to configure the server for your use case.
|
||||
|
||||
In the repository root folder run the following. Ensure -DOPENSSL_ROOT_DIR=/path/to/openssl points to your openssl install location
|
||||
```bash
|
||||
# Create the build directory, preserving it if it already exists
|
||||
mkdir -p build
|
||||
cd build
|
||||
### Required Configuration
|
||||
Darkflame Universe can run with either a packed or an unpacked client.
|
||||
Navigate to `build/sharedconfig.ini` and fill in the following fields:
|
||||
* `mysql_host` (This is the IP address or hostname of your MariaDB server. This is highly likely `localhost`)
|
||||
* If you setup your MariaDB instance on a port other than 3306, which can be done on a Windows install, you will need to make this value `tcp://localhost:portNum` where portNum is replaced with the port you chose to run MariaDB on.
|
||||
* `mysql_database` (This is the database you created for the server)
|
||||
* `mysql_username` (This is the user you created for the server)
|
||||
* `mysql_password` (This is the password for the user you created for the server)
|
||||
* `client_location` (This is the location of the client files. This should be the folder path of a packed or unpacked client)
|
||||
* Ideally the path to the client should not contain any spaces.
|
||||
|
||||
# Run CMake to generate build files
|
||||
cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl
|
||||
|
||||
# Get cmake to build the project. If make files are being used then using make and appending `-j` and the amount of cores to utilize may be preferable, for example `make -j8`
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### Windows builds (native)
|
||||
Ensure that you have either the [MSVC](https://visualstudio.microsoft.com/vs/) or the [Clang](https://github.com/llvm/llvm-project/releases/) (recommended) compiler installed. You will also need to install [CMake](https://cmake.org/download/). Currently on native Windows the server will only work in Release mode.
|
||||
|
||||
#### Build the repository
|
||||
```batch
|
||||
:: Create the build directory
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
:: Run CMake to generate make files
|
||||
cmake ..
|
||||
|
||||
:: Run CMake with build flag to build
|
||||
cmake --build . --config Release
|
||||
```
|
||||
#### Windows for ARM has not been tested but should build by doing the following
|
||||
```batch
|
||||
:: Create the build directory
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
:: Run CMake to generate make files
|
||||
cmake .. -DMARIADB_BUILD_SOURCE=ON
|
||||
|
||||
:: Run CMake with build flag to build
|
||||
cmake --build . --config Release
|
||||
```
|
||||
|
||||
### Windows builds (WSL)
|
||||
This section will go through how to install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and building in a Linux environment under Windows. WSL requires Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11.
|
||||
|
||||
#### Open the Command Prompt application with Administrator permissions and run the following:
|
||||
```bash
|
||||
# Installing Windows Subsystem for Linux
|
||||
wsl --install
|
||||
```
|
||||
|
||||
#### Open the Ubuntu application and run the following:
|
||||
```bash
|
||||
# Make sure the install is up to date
|
||||
apt update && apt upgrade
|
||||
|
||||
# Make sure the gcc, cmake, and build-essentials are installed
|
||||
sudo apt install gcc
|
||||
sudo apt install cmake
|
||||
sudo apt install build-essential
|
||||
```
|
||||
|
||||
[**Follow the Linux instructions**](#linux-builds)
|
||||
|
||||
### ARM builds
|
||||
AArch64 builds should work on linux and MacOS using their respective build steps. Windows ARM should build but it has not been tested
|
||||
|
||||
### Updating your build
|
||||
To update your server to the latest version navigate to your cloned directory
|
||||
```bash
|
||||
cd /path/to/DarkflameServer
|
||||
```
|
||||
run the following commands to update to the latest changes
|
||||
```bash
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
now follow the build section for your system
|
||||
|
||||
## Setting up the environment
|
||||
|
||||
### Resources
|
||||
|
||||
#### LEGO® Universe 1.10.64
|
||||
|
||||
This repository does not distribute any LEGO® Universe files. A full install of LEGO® Universe version 1.10.64 (latest) is required to finish setting up Darkflame Universe.
|
||||
|
||||
Known good SHA256 checksums of the client:
|
||||
- `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed)
|
||||
- `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed)
|
||||
- `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
|
||||
|
||||
Known good *SHA1* checksum of the DLU client:
|
||||
- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed)
|
||||
|
||||
How to generate a SHA256 checksum:
|
||||
```bash
|
||||
# Replace <file> with the file path to the client
|
||||
|
||||
# If on Linux or MacOS
|
||||
shasum -a 256 <file>
|
||||
|
||||
# If on Windows
|
||||
certutil -hashfile <file> SHA256
|
||||
```
|
||||
|
||||
#### Unpacking the client
|
||||
* Clone lcdr's utilities repository [here](https://github.com/lcdr/utils)
|
||||
* Use `pkextractor.pyw` to unpack the client files if they are not already unpacked
|
||||
|
||||
#### Setup resource directory
|
||||
* In the `build` directory create a `res` directory if it does not already exist.
|
||||
* Copy over or create symlinks from `macros`, `BrickModels`, `chatplus_en_us.txt`, `names`, and `maps` in your client `res` directory to the server `build/res` directory
|
||||
* Unzip the navmeshes [here](./resources/navmeshes.zip) and place them in `build/res/maps/navmeshes`
|
||||
|
||||
#### Setup locale
|
||||
* In the `build` directory create a `locale` directory if it does not already exist
|
||||
* Copy over or create symlinks from `locale.xml` in your client `locale` directory to the `build/locale` directory
|
||||
|
||||
#### Client database
|
||||
* Use `fdb_to_sqlite.py` in lcdr's utilities on `res/cdclient.fdb` in the unpacked client to convert the client database to `cdclient.sqlite`
|
||||
* Move and rename `cdclient.sqlite` into `build/res/CDServer.sqlite`
|
||||
* Run each SQL file in the order at which they appear [here](migrations/cdserver/) on the SQLite database
|
||||
|
||||
### Database
|
||||
Darkflame Universe utilizes a MySQL/MariaDB database for account and character information.
|
||||
|
||||
Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running.
|
||||
* Create a database for Darkflame Universe to use
|
||||
|
||||
#### Configuration
|
||||
|
||||
After the server has been built there should be four `ini` files in the build director: `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. Go through them and fill in the database credentials and configure other settings if necessary.
|
||||
|
||||
#### Setup and Migrations
|
||||
|
||||
Use the command `./MasterServer -m` to setup the tables in the database. The first time this command is run on a database, the tables will be up to date with the most recent version. To update your database tables, run this command again. Multiple invocations will not affect any functionality.
|
||||
|
||||
#### Verify
|
||||
### Optional Configuration
|
||||
* After the server has been built there should be five `ini` files in the build directory: `sharedconfig.ini`, `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`.
|
||||
* `authconfig.ini` contains an option to enable or disable play keys on your server. Do not change the default port for auth.
|
||||
* `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.
|
||||
|
||||
## Verify your setup
|
||||
Your build directory should now look like this:
|
||||
* AuthServer
|
||||
* ChatServer
|
||||
@@ -224,42 +212,35 @@ Your build directory should now look like this:
|
||||
* authconfig.ini
|
||||
* chatconfig.ini
|
||||
* masterconfig.ini
|
||||
* sharedconfig.ini
|
||||
* worldconfig.ini
|
||||
* **locale/**
|
||||
* locale.xml
|
||||
* **res/**
|
||||
* CDServer.sqlite
|
||||
* chatplus_en_us.txt
|
||||
* **macros/**
|
||||
* ...
|
||||
* **BrickModels/**
|
||||
* ...
|
||||
* **maps/**
|
||||
* **navmeshes/**
|
||||
* ...
|
||||
* ...
|
||||
* ...
|
||||
|
||||
## Running the server
|
||||
If everything has been configured correctly you should now be able to run the `MasterServer` binary. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the binary network permissions or run it under sudo.
|
||||
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
|
||||
```bash
|
||||
sudo setcap 'cap_net_bind_service=+ep' AuthServer
|
||||
```
|
||||
and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0.
|
||||
|
||||
### 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!
|
||||
|
||||
### Account Manager
|
||||
### Account management tool (Nexus Dashboard)
|
||||
**If you are just using this server for yourself, you can skip setting up Nexus Dashboard**
|
||||
|
||||
Follow the instructions [here](https://github.com/DarkflameUniverse/AccountManager) to setup the DLU account management Python web application. This is the intended way for users to create accounts.
|
||||
Follow the instructions [here](https://github.com/DarkflameUniverse/NexusDashboard) to setup the DLU Nexus Dashboard web application. This is the intended way for users to create accounts and the intended way for moderators to approve names/pets/properties and do other moderation actions.
|
||||
|
||||
### Admin levels
|
||||
The admin level, or Game Master level (hereafter referred to as gmlevel), is specified in the `accounts.gm_level` column in the MySQL database. Normal players should have this set to `0`, which comes with no special privileges. The system administrator will have this set to `9`, which comes will all privileges. gmlevel `8` should be used to give a player a majority of privileges without the safety critical once.
|
||||
|
||||
The admin level, or game master level, is specified in the `accounts.gm_level` column in the MySQL database. Normal players should have this set to `0`, which comes with no special privileges. The system administrator will have this set to `9`, which comes will all privileges. Admin level `8` should be used to give a player a majority of privileges without the safety critical once.
|
||||
While a character has a gmlevel of anything but `0`, some gameplay behavior will change. When testing gameplay, you should always use a character with a gmlevel of `0`.
|
||||
|
||||
While a character has a gmlevel of anything but 0, some gameplay behavior will change. When testing gameplay, you should always use a character with a gmlevel of 0.
|
||||
# User guide
|
||||
Some changes to the client `boot.cfg` file are needed to play on your server.
|
||||
|
||||
## User guide
|
||||
A few modifications have to be made to the client.
|
||||
|
||||
### Client configuration
|
||||
## Allowing a user to connect to your server
|
||||
To connect to a server follow these steps:
|
||||
* In the client directory, locate `boot.cfg`
|
||||
* Open it in a text editor and locate where it says `AUTHSERVERIP=0:`
|
||||
@@ -267,169 +248,88 @@ To connect to a server follow these steps:
|
||||
* 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.
|
||||
|
||||
### Survival
|
||||
## Brick-By-Brick building
|
||||
Should you choose to do any brick building, you will want to have some form of a http server that returns a 404 error since we are unable to emulate live User Generated Content at the moment. If you attempt to do any brick building without a 404 server running properly, you will be unable to load into your game. Python is the easiest way to do this, but any thing that returns a 404 should work fine.
|
||||
* Note: the client hard codes this request on port 80.
|
||||
|
||||
The client script for the survival minigame has a bug in it which can cause the minigame to not load. To fix this, follow these instructions:
|
||||
* Open `res/scripts/ai/minigame/survival/l_zone_survival_client.lua`
|
||||
* Navigate to line `617`
|
||||
* Change `PlayerReady(self)` to `onPlayerReady(self)`
|
||||
* Save the file, overriding readonly mode if required
|
||||
<font size="4">**If you do not plan on doing any Brick Building, then you can skip this step.**</font>
|
||||
|
||||
If you still experience the bug, try deleting/renaming `res/pack/scripts.pk`.
|
||||
The easiest way to do this is to install [python](https://www.python.org/downloads/).
|
||||
|
||||
### Brick-By-Brick building
|
||||
### Allowing a user to build in Brick-by-Brick mode
|
||||
Brick-By-Brick building requires `PATCHSERVERIP=0:` and `UGCSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be most easily achieved by pointing both of those variables to `localhost` while having running in the background.
|
||||
Each client must have their own 404 server running if they are using a locally hosted 404 server.
|
||||
```bash
|
||||
# If on linux run this command. Because this is run on a port below 1024, binary network permissions are needed.
|
||||
sudo python3 -m http.server 80
|
||||
|
||||
Brick-By-Brick building requires `PATCHSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be achieved by pointing it to `localhost` while having `sudo python -m http.server 80` running in the background.
|
||||
# If on windows one of the following will work when run through Powershell or Command Prompt assuming python is installed
|
||||
python3 -m http.server 80
|
||||
python http.server 80
|
||||
py -m http.server 80
|
||||
```
|
||||
|
||||
### In-game commands
|
||||
Here is a summary of the commands available in-game. All commands are prefixed by `/` and typed in the in-game chat window. Some commands requires admin privileges. Operands within `<>` are required, operands within `()` are not. For the full list of in-game commands, please checkout [the source file](./dGame/dUtilities/SlashCommandHandler.cpp).
|
||||
## Updating your server
|
||||
To update your server to the latest version navigate to your cloned directory
|
||||
```bash
|
||||
cd path/to/DarkflameServer
|
||||
```
|
||||
Run the following commands to update to the latest changes
|
||||
```bash
|
||||
git pull
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
Now follow the [build](#build-the-server) section for your system and your server is up to date.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<th>
|
||||
Command
|
||||
</th>
|
||||
<th>
|
||||
Usage
|
||||
</th>
|
||||
<th>
|
||||
Description
|
||||
</th>
|
||||
<th>
|
||||
Admin Level Requirement
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
info
|
||||
</td>
|
||||
<td>
|
||||
/info
|
||||
</td>
|
||||
<td>
|
||||
Displays server info to the user, including where to find the server's source code.
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
credits
|
||||
</td>
|
||||
<td>
|
||||
/credits
|
||||
</td>
|
||||
<td>
|
||||
Displays the names of the people behind Darkflame Universe.
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
instanceinfo
|
||||
</td>
|
||||
<td>
|
||||
/instanceinfo
|
||||
</td>
|
||||
<td>
|
||||
Displays in the chat the current zone, clone, and instance id.
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
gmlevel
|
||||
</td>
|
||||
<td>
|
||||
/gmlevel <level>
|
||||
</td>
|
||||
<td>
|
||||
Within the authorized range of levels for the current account, changes the character's game master level to the specified value. This is required to use certain commands.
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
testmap
|
||||
</td>
|
||||
<td>
|
||||
/testmap <zone> (clone-id)
|
||||
</td>
|
||||
<td>
|
||||
Transfers you to the given zone by id and clone id.
|
||||
</td>
|
||||
<td>
|
||||
1
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
ban
|
||||
</td>
|
||||
<td>
|
||||
/ban <username>
|
||||
</td>
|
||||
<td>
|
||||
Bans a user from the server.
|
||||
</td>
|
||||
<td>
|
||||
4
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
gmadditem
|
||||
</td>
|
||||
<td>
|
||||
/gmadditem <id> (count)
|
||||
</td>
|
||||
<td>
|
||||
Adds the given item to your inventory by id.
|
||||
</td>
|
||||
<td>
|
||||
8
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
spawn
|
||||
</td>
|
||||
<td>
|
||||
/spawn <id>
|
||||
</td>
|
||||
<td>
|
||||
Spawns an object at your location by id.
|
||||
</td>
|
||||
<td>
|
||||
8
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
metrics
|
||||
</td>
|
||||
<td>
|
||||
/metrics
|
||||
</td>
|
||||
<td>
|
||||
Prints some information about the server's performance.
|
||||
</td>
|
||||
<td>
|
||||
8
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
## In-game commands
|
||||
* A list of all in-game commands can be found [here](./docs/Commands.md).
|
||||
|
||||
## Verifying your client files
|
||||
|
||||
### LEGO® Universe 1.10.64
|
||||
To verify that you are indeed using a LEGO® Universe 1.10.64 client, make sure you have the full client compressed **in a rar file** and run the following command.
|
||||
```bash
|
||||
# Replace <file> with the file path to the zipped client
|
||||
|
||||
# If on Linux or MacOS
|
||||
shasum -a 256 <file>
|
||||
|
||||
# If on Windows using the Command Prompt
|
||||
certutil -hashfile <file> SHA256
|
||||
```
|
||||
|
||||
Below are known good SHA256 checksums of the client:
|
||||
* `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed)
|
||||
* `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed)
|
||||
* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
|
||||
|
||||
If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64.
|
||||
|
||||
### Darkflame Universe Client
|
||||
Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there.
|
||||
This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client.
|
||||
|
||||
To verify that you are indeed using a Darkflame Universe client, make sure you have the full client compressed **in a zip file** and run the following command.
|
||||
|
||||
```bash
|
||||
# Replace <file> with the file path to the zipped client
|
||||
|
||||
# If on Linux or MacOS
|
||||
shasum -a 1 <file>
|
||||
|
||||
# If on Windows using the Command Prompt
|
||||
certutil -hashfile <file> SHA1
|
||||
```
|
||||
|
||||
Known good *SHA1* checksum of the Darkflame Universe client:
|
||||
- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed)
|
||||
|
||||
# Development Documentation
|
||||
This is a Work in Progress, but below are some quick links to documentaion for systems and structs in the server
|
||||
[Networked message structs](https://lcdruniverse.org/lu_packets/lu_packets/index.html)
|
||||
[General system documentation](https://docs.lu-dev.net/en/latest/index.html)
|
||||
|
||||
# Credits
|
||||
## Active Contributors
|
||||
* [EmosewaMC](https://github.com/EmosewaMC)
|
||||
* [Jettford](https://github.com/Jettford)
|
||||
* [Aaron K.](https://github.com/aronwk-aaron)
|
||||
|
||||
## DLU Team
|
||||
* [DarwinAnim8or](https://github.com/DarwinAnim8or)
|
||||
@@ -438,25 +338,30 @@ Here is a summary of the commands available in-game. All commands are prefixed b
|
||||
* [averysumner](https://github.com/codeshaunted)
|
||||
* [Jon002](https://github.com/jaller200)
|
||||
* [Jonny](https://github.com/cuzitsjonny)
|
||||
* [Aaron K.](https://github.com/aronwk-aaron)
|
||||
|
||||
### Research and tools
|
||||
### Research and Tools
|
||||
* [lcdr](https://github.com/lcdr)
|
||||
* [Xiphoseer](https://github.com/Xiphoseer)
|
||||
|
||||
### Community management
|
||||
### Community Management
|
||||
* [Neal](https://github.com/NealSpellman)
|
||||
|
||||
### Former contributors
|
||||
### Logo
|
||||
* Cole Peterson (BlasterBuilder)
|
||||
|
||||
## Active Contributors
|
||||
* [EmosewaMC](https://github.com/EmosewaMC)
|
||||
* [Jettford](https://github.com/Jettford)
|
||||
|
||||
## Former Contributors
|
||||
* TheMachine
|
||||
* Matthew
|
||||
* [Raine](https://github.com/Rainebannister)
|
||||
* Bricknave
|
||||
|
||||
### Logo
|
||||
* Cole Peterson (BlasterBuilder)
|
||||
|
||||
## Special thanks
|
||||
## Special Thanks
|
||||
* humanoid24
|
||||
* pwjones1969
|
||||
* [Simon](https://github.com/SimonNitzsche)
|
||||
* ALL OF THE NETDEVIL AND LEGO TEAMS!
|
||||
* [ALL OF THE NETDEVIL AND LEGO TEAMS!](https://www.mobygames.com/game/macintosh/lego-universe/credits)
|
||||
|
||||
7
build.sh
7
build.sh
@@ -1,3 +1,6 @@
|
||||
# Error if any command fails
|
||||
set -e
|
||||
|
||||
# Create the build directory, preserving it if it already exists
|
||||
mkdir -p build
|
||||
cd build
|
||||
@@ -6,7 +9,5 @@ cd build
|
||||
cmake ..
|
||||
|
||||
# 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
|
||||
cmake --build . --config Release $1
|
||||
|
||||
# Run migrations
|
||||
./MasterServer -m
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "Database.h"
|
||||
#include "dConfig.h"
|
||||
#include "Diagnostics.h"
|
||||
#include "BinaryPathFinder.h"
|
||||
|
||||
//RakNet includes:
|
||||
#include "RakNetDefines.h"
|
||||
@@ -21,37 +22,40 @@
|
||||
|
||||
#include "Game.h"
|
||||
namespace Game {
|
||||
dLogger* logger;
|
||||
dServer* server;
|
||||
dConfig* config;
|
||||
dLogger* logger = nullptr;
|
||||
dServer* server = nullptr;
|
||||
dConfig* config = nullptr;
|
||||
bool shouldShutdown = false;
|
||||
}
|
||||
|
||||
dLogger* SetupLogger();
|
||||
void HandlePacket(Packet* packet);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
constexpr uint32_t authFramerate = mediumFramerate;
|
||||
constexpr uint32_t authFrameDelta = mediumFrameDelta;
|
||||
Diagnostics::SetProcessName("Auth");
|
||||
Diagnostics::SetProcessFileName(argv[0]);
|
||||
Diagnostics::Initialize();
|
||||
|
||||
//Create all the objects we need to run our service:
|
||||
Game::logger = SetupLogger();
|
||||
if (!Game::logger) return 0;
|
||||
if (!Game::logger) return EXIT_FAILURE;
|
||||
|
||||
//Read our config:
|
||||
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string());
|
||||
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
|
||||
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
|
||||
|
||||
Game::logger->Log("AuthServer", "Starting Auth server...");
|
||||
Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
||||
Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__);
|
||||
|
||||
//Read our config:
|
||||
dConfig config("authconfig.ini");
|
||||
Game::config = &config;
|
||||
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
|
||||
Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1");
|
||||
|
||||
//Connect to the MySQL Database
|
||||
std::string mysql_host = config.GetValue("mysql_host");
|
||||
std::string mysql_database = config.GetValue("mysql_database");
|
||||
std::string mysql_username = config.GetValue("mysql_username");
|
||||
std::string mysql_password = config.GetValue("mysql_password");
|
||||
std::string mysql_host = Game::config->GetValue("mysql_host");
|
||||
std::string mysql_database = Game::config->GetValue("mysql_database");
|
||||
std::string mysql_username = Game::config->GetValue("mysql_username");
|
||||
std::string mysql_password = Game::config->GetValue("mysql_password");
|
||||
|
||||
try {
|
||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||
@@ -60,12 +64,12 @@ int main(int argc, char** argv) {
|
||||
Database::Destroy("AuthServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
return 0;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
//Find out the master's IP:
|
||||
std::string masterIP;
|
||||
int masterPort = 1500;
|
||||
uint32_t masterPort = 1500;
|
||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
||||
auto res = stmt->executeQuery();
|
||||
while (res->next()) {
|
||||
@@ -77,26 +81,28 @@ int main(int argc, char** argv) {
|
||||
delete stmt;
|
||||
|
||||
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
||||
int maxClients = 50;
|
||||
int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
|
||||
if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients"));
|
||||
if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str());
|
||||
uint32_t maxClients = 50;
|
||||
uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
|
||||
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
|
||||
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
|
||||
|
||||
Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth);
|
||||
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown);
|
||||
|
||||
//Run it until server gets a kill message from Master:
|
||||
auto t = std::chrono::high_resolution_clock::now();
|
||||
Packet* packet = nullptr;
|
||||
int framesSinceLastFlush = 0;
|
||||
int framesSinceMasterDisconnect = 0;
|
||||
int framesSinceLastSQLPing = 0;
|
||||
constexpr uint32_t logFlushTime = 30 * authFramerate; // 30 seconds in frames
|
||||
constexpr uint32_t sqlPingTime = 10 * 60 * authFramerate; // 10 minutes in frames
|
||||
uint32_t framesSinceLastFlush = 0;
|
||||
uint32_t framesSinceMasterDisconnect = 0;
|
||||
uint32_t framesSinceLastSQLPing = 0;
|
||||
|
||||
while (true) {
|
||||
while (!Game::shouldShutdown) {
|
||||
//Check if we're still connected to master:
|
||||
if (!Game::server->GetIsConnectedToMaster()) {
|
||||
framesSinceMasterDisconnect++;
|
||||
|
||||
if (framesSinceMasterDisconnect >= 30)
|
||||
if (framesSinceMasterDisconnect >= authFramerate)
|
||||
break; //Exit our loop, shut down.
|
||||
} else framesSinceMasterDisconnect = 0;
|
||||
|
||||
@@ -112,16 +118,16 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//Push our log every 30s:
|
||||
if (framesSinceLastFlush >= 900) {
|
||||
if (framesSinceLastFlush >= logFlushTime) {
|
||||
Game::logger->Flush();
|
||||
framesSinceLastFlush = 0;
|
||||
} else framesSinceLastFlush++;
|
||||
|
||||
//Every 10 min we ping our sql server to keep it alive hopefully:
|
||||
if (framesSinceLastSQLPing >= 40000) {
|
||||
if (framesSinceLastSQLPing >= sqlPingTime) {
|
||||
//Find out the master's IP for absolutely no reason:
|
||||
std::string masterIP;
|
||||
int masterPort;
|
||||
uint32_t masterPort;
|
||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
||||
auto res = stmt->executeQuery();
|
||||
while (res->next()) {
|
||||
@@ -136,7 +142,7 @@ int main(int argc, char** argv) {
|
||||
} else framesSinceLastSQLPing++;
|
||||
|
||||
//Sleep our thread since auth can afford to.
|
||||
t += std::chrono::milliseconds(mediumFramerate); //Auth can run at a lower "fps"
|
||||
t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps"
|
||||
std::this_thread::sleep_until(t);
|
||||
}
|
||||
|
||||
@@ -144,13 +150,13 @@ int main(int argc, char** argv) {
|
||||
Database::Destroy("AuthServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
delete Game::config;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
dLogger* SetupLogger() {
|
||||
std::string logPath = "./logs/AuthServer_" + std::to_string(time(nullptr)) + ".log";
|
||||
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/AuthServer_" + std::to_string(time(nullptr)) + ".log")).string();
|
||||
bool logToConsole = false;
|
||||
bool logDebugStatements = false;
|
||||
#ifdef _DEBUG
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
set(DAUTHSERVER_SOURCES "AuthServer.cpp")
|
||||
|
||||
add_executable(AuthServer ${DAUTHSERVER_SOURCES})
|
||||
add_executable(AuthServer "AuthServer.cpp")
|
||||
target_link_libraries(AuthServer ${COMMON_LIBRARIES})
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
set(DCHATSERVER_SOURCES "ChatPacketHandler.cpp"
|
||||
"ChatServer.cpp"
|
||||
"PlayerContainer.cpp")
|
||||
|
||||
add_executable(ChatServer ${DCHATSERVER_SOURCES})
|
||||
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter)
|
||||
set(DCHATSERVER_SOURCES
|
||||
"ChatPacketHandler.cpp"
|
||||
"PlayerContainer.cpp"
|
||||
)
|
||||
|
||||
add_executable(ChatServer "ChatServer.cpp")
|
||||
add_library(dChatServer ${DCHATSERVER_SOURCES})
|
||||
|
||||
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
|
||||
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer)
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include "dServer.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "dLogger.h"
|
||||
#include "AddFriendResponseCode.h"
|
||||
#include "AddFriendResponseType.h"
|
||||
#include "eAddFriendResponseCode.h"
|
||||
#include "eAddFriendResponseType.h"
|
||||
#include "RakString.h"
|
||||
#include "dConfig.h"
|
||||
|
||||
@@ -33,9 +33,10 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
"WHEN friend_id = ? THEN player_id "
|
||||
"END AS requested_player, best_friend FROM friends) AS fr "
|
||||
"JOIN charinfo AS ci ON ci.id = fr.requested_player "
|
||||
"WHERE fr.requested_player IS NOT NULL;"));
|
||||
"WHERE fr.requested_player IS NOT NULL AND fr.requested_player != ?;"));
|
||||
stmt->setUInt(1, static_cast<uint32_t>(playerID));
|
||||
stmt->setUInt(2, static_cast<uint32_t>(playerID));
|
||||
stmt->setUInt(3, static_cast<uint32_t>(playerID));
|
||||
|
||||
std::vector<FriendData> friends;
|
||||
|
||||
@@ -113,6 +114,10 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
inStream.Read(isBestFriendRequest);
|
||||
|
||||
auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
|
||||
if (requestor->playerName == playerName) {
|
||||
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
|
||||
return;
|
||||
};
|
||||
std::unique_ptr<PlayerData> requestee(playerContainer.GetPlayerData(playerName));
|
||||
|
||||
// Check if player is online first
|
||||
@@ -148,7 +153,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
requestee.reset(new PlayerData());
|
||||
requestee->playerName = playerName;
|
||||
|
||||
SendFriendResponse(requestor, requestee.get(), result->next() ? AddFriendResponseType::NOTONLINE : AddFriendResponseType::INVALIDCHARACTER);
|
||||
SendFriendResponse(requestor, requestee.get(), result->next() ? eAddFriendResponseType::NOTONLINE : eAddFriendResponseType::INVALIDCHARACTER);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,10 +197,10 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
if (oldBestFriendStatus != bestFriendStatus) {
|
||||
if (requestee->countOfBestFriends >= maxNumberOfBestFriends || requestor->countOfBestFriends >= maxNumberOfBestFriends) {
|
||||
if (requestee->countOfBestFriends >= maxNumberOfBestFriends) {
|
||||
SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
||||
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
||||
}
|
||||
if (requestor->countOfBestFriends >= maxNumberOfBestFriends) {
|
||||
SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::YOURFRIENDSLISTFULL, false);
|
||||
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::YOURFRIENDSLISTFULL, false);
|
||||
}
|
||||
} else {
|
||||
// Then update the database with this new info.
|
||||
@@ -210,8 +215,8 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
if (bestFriendStatus == 3U) {
|
||||
requestee->countOfBestFriends += 1;
|
||||
requestor->countOfBestFriends += 1;
|
||||
if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, AddFriendResponseType::ACCEPTED, false, true);
|
||||
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::ACCEPTED, false, true);
|
||||
if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, eAddFriendResponseType::ACCEPTED, false, true);
|
||||
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::ACCEPTED, false, true);
|
||||
for (auto& friendData : requestor->friends) {
|
||||
if (friendData.friendID == requestee->playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
@@ -225,7 +230,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::WAITINGAPPROVAL, true, true);
|
||||
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::WAITINGAPPROVAL, true, true);
|
||||
}
|
||||
} else {
|
||||
// Do not send this if we are requesting to be a best friend.
|
||||
@@ -242,7 +247,7 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
inStream.Read(playerID);
|
||||
inStream.Read(playerID);
|
||||
|
||||
AddFriendResponseCode clientResponseCode = static_cast<AddFriendResponseCode>(packet->data[0x14]);
|
||||
eAddFriendResponseCode clientResponseCode = static_cast<eAddFriendResponseCode>(packet->data[0x14]);
|
||||
std::string friendName = PacketUtils::ReadString(0x15, packet, true);
|
||||
|
||||
//Now to try and find both of these:
|
||||
@@ -250,29 +255,29 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
auto requestee = playerContainer.GetPlayerData(friendName);
|
||||
if (!requestor || !requestee) return;
|
||||
|
||||
AddFriendResponseType serverResponseCode{};
|
||||
eAddFriendResponseType serverResponseCode{};
|
||||
uint8_t isAlreadyBestFriends = 0U;
|
||||
// We need to convert this response code to one we can actually send back to the client.
|
||||
switch (clientResponseCode) {
|
||||
case AddFriendResponseCode::ACCEPTED:
|
||||
serverResponseCode = AddFriendResponseType::ACCEPTED;
|
||||
case eAddFriendResponseCode::ACCEPTED:
|
||||
serverResponseCode = eAddFriendResponseType::ACCEPTED;
|
||||
break;
|
||||
case AddFriendResponseCode::BUSY:
|
||||
serverResponseCode = AddFriendResponseType::BUSY;
|
||||
case eAddFriendResponseCode::BUSY:
|
||||
serverResponseCode = eAddFriendResponseType::BUSY;
|
||||
break;
|
||||
case AddFriendResponseCode::CANCELLED:
|
||||
serverResponseCode = AddFriendResponseType::CANCELLED;
|
||||
case eAddFriendResponseCode::CANCELLED:
|
||||
serverResponseCode = eAddFriendResponseType::CANCELLED;
|
||||
break;
|
||||
case AddFriendResponseCode::REJECTED:
|
||||
serverResponseCode = AddFriendResponseType::DECLINED;
|
||||
case eAddFriendResponseCode::REJECTED:
|
||||
serverResponseCode = eAddFriendResponseType::DECLINED;
|
||||
break;
|
||||
}
|
||||
|
||||
// Now that we have handled the base cases, we need to check the other cases.
|
||||
if (serverResponseCode == AddFriendResponseType::ACCEPTED) {
|
||||
if (serverResponseCode == eAddFriendResponseType::ACCEPTED) {
|
||||
for (auto friendData : requestor->friends) {
|
||||
if (friendData.friendID == requestee->playerID) {
|
||||
serverResponseCode = AddFriendResponseType::ALREADYFRIEND;
|
||||
serverResponseCode = eAddFriendResponseType::ALREADYFRIEND;
|
||||
if (friendData.isBestFriend) {
|
||||
isAlreadyBestFriends = 1U;
|
||||
}
|
||||
@@ -281,7 +286,7 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
}
|
||||
|
||||
// This message is NOT sent for best friends and is handled differently for those requests.
|
||||
if (serverResponseCode == AddFriendResponseType::ACCEPTED) {
|
||||
if (serverResponseCode == eAddFriendResponseType::ACCEPTED) {
|
||||
// Add the each player to the others friend list.
|
||||
FriendData requestorData;
|
||||
requestorData.zoneID = requestor->zoneID;
|
||||
@@ -308,8 +313,8 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
statement->execute();
|
||||
}
|
||||
|
||||
if (serverResponseCode != AddFriendResponseType::DECLINED) SendFriendResponse(requestor, requestee, serverResponseCode, isAlreadyBestFriends);
|
||||
if (serverResponseCode != AddFriendResponseType::ALREADYFRIEND) SendFriendResponse(requestee, requestor, serverResponseCode, isAlreadyBestFriends);
|
||||
if (serverResponseCode != eAddFriendResponseType::DECLINED) SendFriendResponse(requestor, requestee, serverResponseCode, isAlreadyBestFriends);
|
||||
if (serverResponseCode != eAddFriendResponseType::ALREADYFRIEND) SendFriendResponse(requestee, requestor, serverResponseCode, isAlreadyBestFriends);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
@@ -389,7 +394,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
uint8_t channel = 0;
|
||||
inStream.Read(channel);
|
||||
|
||||
std::string message = PacketUtils::ReadString(0x66, packet, true);
|
||||
std::string message = PacketUtils::ReadString(0x66, packet, true, 512);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
|
||||
|
||||
@@ -431,7 +436,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
LWOOBJID senderID = PacketUtils::ReadPacketS64(0x08, packet);
|
||||
std::string receiverName = PacketUtils::ReadString(0x66, packet, true);
|
||||
std::string message = PacketUtils::ReadString(0xAA, packet, true);
|
||||
std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
|
||||
|
||||
//Get the bois:
|
||||
auto goonA = playerContainer.GetPlayerData(senderID);
|
||||
@@ -917,7 +922,7 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send
|
||||
//Make sure people aren't requesting people that they're already friends with:
|
||||
for (auto fr : receiver->friends) {
|
||||
if (fr.friendID == sender->playerID) {
|
||||
SendFriendResponse(sender, receiver, AddFriendResponseType::ALREADYFRIEND, fr.isBestFriend);
|
||||
SendFriendResponse(sender, receiver, eAddFriendResponseType::ALREADYFRIEND, fr.isBestFriend);
|
||||
return; //we have this player as a friend, yeet this function so it doesn't send another request.
|
||||
}
|
||||
}
|
||||
@@ -935,7 +940,7 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
|
||||
void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
|
||||
if (!receiver || !sender) return;
|
||||
|
||||
CBITSTREAM;
|
||||
@@ -946,11 +951,11 @@ void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sen
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_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 != AddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
|
||||
bitStream.Write<uint8_t>(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
|
||||
// Then write the player name
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
// Then if this is an acceptance code, write the following extra info.
|
||||
if (responseCode == AddFriendResponseType::ACCEPTED) {
|
||||
if (responseCode == eAddFriendResponseType::ACCEPTED) {
|
||||
bitStream.Write(sender->playerID);
|
||||
bitStream.Write(sender->zoneID);
|
||||
bitStream.Write(isBestFriendRequest); //isBFF
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "BitStream.h"
|
||||
|
||||
struct PlayerData;
|
||||
enum class AddFriendResponseType : uint8_t;
|
||||
enum class eAddFriendResponseType : uint8_t;
|
||||
|
||||
namespace ChatPacketHandler {
|
||||
void HandleFriendlistRequest(Packet* packet);
|
||||
@@ -35,6 +35,6 @@ namespace ChatPacketHandler {
|
||||
void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend);
|
||||
|
||||
void SendFriendRequest(PlayerData* receiver, PlayerData* sender);
|
||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
|
||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
|
||||
void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful);
|
||||
};
|
||||
|
||||
@@ -12,20 +12,25 @@
|
||||
#include "dMessageIdentifiers.h"
|
||||
#include "dChatFilter.h"
|
||||
#include "Diagnostics.h"
|
||||
#include "AssetManager.h"
|
||||
#include "BinaryPathFinder.h"
|
||||
|
||||
#include "PlayerContainer.h"
|
||||
#include "ChatPacketHandler.h"
|
||||
|
||||
#include "Game.h"
|
||||
namespace Game {
|
||||
dLogger* logger;
|
||||
dServer* server;
|
||||
dConfig* config;
|
||||
dChatFilter* chatFilter;
|
||||
}
|
||||
|
||||
//RakNet includes:
|
||||
#include "RakNetDefines.h"
|
||||
namespace Game {
|
||||
dLogger* logger = nullptr;
|
||||
dServer* server = nullptr;
|
||||
dConfig* config = nullptr;
|
||||
dChatFilter* chatFilter = nullptr;
|
||||
AssetManager* assetManager = nullptr;
|
||||
bool shouldShutdown = false;
|
||||
}
|
||||
|
||||
|
||||
dLogger* SetupLogger();
|
||||
void HandlePacket(Packet* packet);
|
||||
@@ -33,28 +38,45 @@ void HandlePacket(Packet* packet);
|
||||
PlayerContainer playerContainer;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
constexpr uint32_t chatFramerate = mediumFramerate;
|
||||
constexpr uint32_t chatFrameDelta = mediumFrameDelta;
|
||||
Diagnostics::SetProcessName("Chat");
|
||||
Diagnostics::SetProcessFileName(argv[0]);
|
||||
Diagnostics::Initialize();
|
||||
|
||||
//Create all the objects we need to run our service:
|
||||
Game::logger = SetupLogger();
|
||||
if (!Game::logger) return 0;
|
||||
if (!Game::logger) return EXIT_FAILURE;
|
||||
|
||||
//Read our config:
|
||||
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string());
|
||||
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
|
||||
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
|
||||
|
||||
Game::logger->Log("ChatServer", "Starting Chat server...");
|
||||
Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
||||
Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__);
|
||||
|
||||
//Read our config:
|
||||
dConfig config("chatconfig.ini");
|
||||
Game::config = &config;
|
||||
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
|
||||
Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1");
|
||||
try {
|
||||
std::string clientPathStr = Game::config->GetValue("client_location");
|
||||
if (clientPathStr.empty()) clientPathStr = "./res";
|
||||
std::filesystem::path clientPath = std::filesystem::path(clientPathStr);
|
||||
if (clientPath.is_relative()) {
|
||||
clientPath = BinaryPathFinder::GetBinaryDir() / clientPath;
|
||||
}
|
||||
|
||||
Game::assetManager = new AssetManager(clientPath);
|
||||
} catch (std::runtime_error& ex) {
|
||||
Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what());
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
//Connect to the MySQL Database
|
||||
std::string mysql_host = config.GetValue("mysql_host");
|
||||
std::string mysql_database = config.GetValue("mysql_database");
|
||||
std::string mysql_username = config.GetValue("mysql_username");
|
||||
std::string mysql_password = config.GetValue("mysql_password");
|
||||
std::string mysql_host = Game::config->GetValue("mysql_host");
|
||||
std::string mysql_database = Game::config->GetValue("mysql_database");
|
||||
std::string mysql_username = Game::config->GetValue("mysql_username");
|
||||
std::string mysql_password = Game::config->GetValue("mysql_password");
|
||||
|
||||
try {
|
||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||
@@ -63,12 +85,12 @@ int main(int argc, char** argv) {
|
||||
Database::Destroy("ChatServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
return 0;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
//Find out the master's IP:
|
||||
std::string masterIP;
|
||||
int masterPort = 1000;
|
||||
uint32_t masterPort = 1000;
|
||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
||||
auto res = stmt->executeQuery();
|
||||
while (res->next()) {
|
||||
@@ -80,28 +102,30 @@ int main(int argc, char** argv) {
|
||||
delete stmt;
|
||||
|
||||
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
||||
int maxClients = 50;
|
||||
int ourPort = 1501;
|
||||
if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients"));
|
||||
if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str());
|
||||
uint32_t maxClients = 50;
|
||||
uint32_t ourPort = 1501;
|
||||
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
|
||||
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str());
|
||||
|
||||
Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat);
|
||||
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
|
||||
|
||||
Game::chatFilter = new dChatFilter("./res/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf"))));
|
||||
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
|
||||
|
||||
//Run it until server gets a kill message from Master:
|
||||
auto t = std::chrono::high_resolution_clock::now();
|
||||
Packet* packet = nullptr;
|
||||
int framesSinceLastFlush = 0;
|
||||
int framesSinceMasterDisconnect = 0;
|
||||
int framesSinceLastSQLPing = 0;
|
||||
constexpr uint32_t logFlushTime = 30 * chatFramerate; // 30 seconds in frames
|
||||
constexpr uint32_t sqlPingTime = 10 * 60 * chatFramerate; // 10 minutes in frames
|
||||
uint32_t framesSinceLastFlush = 0;
|
||||
uint32_t framesSinceMasterDisconnect = 0;
|
||||
uint32_t framesSinceLastSQLPing = 0;
|
||||
|
||||
while (true) {
|
||||
while (!Game::shouldShutdown) {
|
||||
//Check if we're still connected to master:
|
||||
if (!Game::server->GetIsConnectedToMaster()) {
|
||||
framesSinceMasterDisconnect++;
|
||||
|
||||
if (framesSinceMasterDisconnect >= 30)
|
||||
if (framesSinceMasterDisconnect >= chatFramerate)
|
||||
break; //Exit our loop, shut down.
|
||||
} else framesSinceMasterDisconnect = 0;
|
||||
|
||||
@@ -117,16 +141,16 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
//Push our log every 30s:
|
||||
if (framesSinceLastFlush >= 900) {
|
||||
if (framesSinceLastFlush >= logFlushTime) {
|
||||
Game::logger->Flush();
|
||||
framesSinceLastFlush = 0;
|
||||
} else framesSinceLastFlush++;
|
||||
|
||||
//Every 10 min we ping our sql server to keep it alive hopefully:
|
||||
if (framesSinceLastSQLPing >= 40000) {
|
||||
if (framesSinceLastSQLPing >= sqlPingTime) {
|
||||
//Find out the master's IP for absolutely no reason:
|
||||
std::string masterIP;
|
||||
int masterPort;
|
||||
uint32_t masterPort;
|
||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
||||
auto res = stmt->executeQuery();
|
||||
while (res->next()) {
|
||||
@@ -141,7 +165,7 @@ int main(int argc, char** argv) {
|
||||
} else framesSinceLastSQLPing++;
|
||||
|
||||
//Sleep our thread since auth can afford to.
|
||||
t += std::chrono::milliseconds(mediumFramerate); //Chat can run at a lower "fps"
|
||||
t += std::chrono::milliseconds(chatFrameDelta); //Chat can run at a lower "fps"
|
||||
std::this_thread::sleep_until(t);
|
||||
}
|
||||
|
||||
@@ -149,13 +173,13 @@ int main(int argc, char** argv) {
|
||||
Database::Destroy("ChatServer");
|
||||
delete Game::server;
|
||||
delete Game::logger;
|
||||
delete Game::config;
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
dLogger* SetupLogger() {
|
||||
std::string logPath = "./logs/ChatServer_" + std::to_string(time(nullptr)) + ".log";
|
||||
std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/ChatServer_" + std::to_string(time(nullptr)) + ".log")).string();
|
||||
bool logToConsole = false;
|
||||
bool logDebugStatements = false;
|
||||
#ifdef _DEBUG
|
||||
|
||||
@@ -58,16 +58,6 @@ void AMFArrayValue::RemoveValue(const std::string& key) {
|
||||
}
|
||||
}
|
||||
|
||||
// AMFArray Find Value
|
||||
AMFValue* AMFArrayValue::FindValue(const std::string& key) {
|
||||
_AMFArrayMap_::iterator it = this->associative.find(key);
|
||||
if (it != this->associative.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// AMFArray Get Associative Iterator Begin
|
||||
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueBegin() {
|
||||
return this->associative.begin();
|
||||
@@ -93,11 +83,6 @@ uint32_t AMFArrayValue::GetDenseValueSize() {
|
||||
return (uint32_t)this->dense.size();
|
||||
}
|
||||
|
||||
// AMFArray Get value at index in Dense List
|
||||
AMFValue* AMFArrayValue::GetValueAt(uint32_t index) {
|
||||
return this->dense.at(index);
|
||||
}
|
||||
|
||||
// AMFArray Get Dense Iterator Begin
|
||||
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorBegin() {
|
||||
return this->dense.begin();
|
||||
|
||||
@@ -75,7 +75,9 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFUndefined; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFUndefined;
|
||||
};
|
||||
|
||||
//! The null value AMF type
|
||||
@@ -85,7 +87,9 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFNull; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFNull;
|
||||
};
|
||||
|
||||
//! The false value AMF type
|
||||
@@ -95,7 +99,9 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFFalse; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFFalse;
|
||||
};
|
||||
|
||||
//! The true value AMF type
|
||||
@@ -105,7 +111,9 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFTrue; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFTrue;
|
||||
};
|
||||
|
||||
//! The integer value AMF type
|
||||
@@ -117,9 +125,10 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFInteger; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFInteger;
|
||||
//! Sets the integer value
|
||||
/*!
|
||||
\param value The value to set
|
||||
@@ -142,9 +151,10 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFDouble; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFDouble;
|
||||
//! Sets the double value
|
||||
/*!
|
||||
\param value The value to set to
|
||||
@@ -167,9 +177,10 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFString; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFString;
|
||||
//! Sets the string value
|
||||
/*!
|
||||
\param value The string value to set to
|
||||
@@ -192,9 +203,10 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFXMLDoc; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFXMLDoc;
|
||||
//! Sets the XML Doc value
|
||||
/*!
|
||||
\param value The value to set to
|
||||
@@ -217,9 +229,10 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFDate; }
|
||||
AMFValueType GetValueType() { return ValueType; }
|
||||
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFDate;
|
||||
//! Sets the date time
|
||||
/*!
|
||||
\param value The value to set to
|
||||
@@ -244,9 +257,11 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFArray; }
|
||||
AMFValueType GetValueType() override { return ValueType; }
|
||||
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFArray;
|
||||
|
||||
~AMFArrayValue() override;
|
||||
//! Inserts an item into the array map for a specific key
|
||||
/*!
|
||||
@@ -265,7 +280,15 @@ public:
|
||||
/*!
|
||||
\return The AMF value if found, nullptr otherwise
|
||||
*/
|
||||
AMFValue* FindValue(const std::string& key);
|
||||
template <typename T>
|
||||
T* FindValue(const std::string& key) const {
|
||||
_AMFArrayMap_::const_iterator it = this->associative.find(key);
|
||||
if (it != this->associative.end() && T::ValueType == it->second->GetValueType()) {
|
||||
return dynamic_cast<T*>(it->second);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
//! Returns where the associative iterator begins
|
||||
/*!
|
||||
@@ -298,7 +321,12 @@ public:
|
||||
/*!
|
||||
\param index The index to get
|
||||
*/
|
||||
AMFValue* GetValueAt(uint32_t index);
|
||||
template <typename T>
|
||||
T* GetValueAt(uint32_t index) {
|
||||
if (index >= this->dense.size()) return nullptr;
|
||||
AMFValue* foundValue = this->dense.at(index);
|
||||
return T::ValueType == foundValue->GetValueType() ? dynamic_cast<T*>(foundValue) : nullptr;
|
||||
};
|
||||
|
||||
//! Returns where the dense iterator begins
|
||||
/*!
|
||||
@@ -334,10 +362,11 @@ private:
|
||||
/*!
|
||||
\return The AMF value type
|
||||
*/
|
||||
AMFValueType GetValueType() { return AMFObject; }
|
||||
AMFValueType GetValueType() override { return ValueType; }
|
||||
~AMFObjectValue() override;
|
||||
|
||||
public:
|
||||
static const AMFValueType ValueType = AMFObject;
|
||||
//! Constructor
|
||||
/*!
|
||||
\param traits The traits to set
|
||||
|
||||
@@ -10,7 +10,7 @@ void BinaryIO::WriteString(const std::string& stringToWrite, std::ofstream& outs
|
||||
}
|
||||
|
||||
//For reading null-terminated strings
|
||||
std::string BinaryIO::ReadString(std::ifstream& instream) {
|
||||
std::string BinaryIO::ReadString(std::istream& instream) {
|
||||
std::string toReturn;
|
||||
char buffer;
|
||||
|
||||
@@ -25,7 +25,7 @@ std::string BinaryIO::ReadString(std::ifstream& instream) {
|
||||
}
|
||||
|
||||
//For reading strings of a specific size
|
||||
std::string BinaryIO::ReadString(std::ifstream& instream, size_t size) {
|
||||
std::string BinaryIO::ReadString(std::istream& instream, size_t size) {
|
||||
std::string toReturn;
|
||||
char buffer;
|
||||
|
||||
@@ -37,7 +37,7 @@ std::string BinaryIO::ReadString(std::ifstream& instream, size_t size) {
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
std::string BinaryIO::ReadWString(std::ifstream& instream) {
|
||||
std::string BinaryIO::ReadWString(std::istream& instream) {
|
||||
size_t size;
|
||||
BinaryRead(instream, size);
|
||||
//toReturn.resize(size);
|
||||
|
||||
@@ -10,16 +10,15 @@ namespace BinaryIO {
|
||||
|
||||
template<typename T>
|
||||
std::istream& BinaryRead(std::istream& stream, T& value) {
|
||||
if (!stream.good())
|
||||
printf("bla");
|
||||
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
|
||||
|
||||
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
|
||||
std::string ReadString(std::ifstream& instream);
|
||||
std::string ReadString(std::ifstream& instream, size_t size);
|
||||
std::string ReadWString(std::ifstream& instream);
|
||||
std::string ReadString(std::istream& instream);
|
||||
std::string ReadString(std::istream& instream, size_t size);
|
||||
std::string ReadWString(std::istream& instream);
|
||||
|
||||
inline bool DoesFileExist(const std::string& name) {
|
||||
std::ifstream f(name.c_str());
|
||||
|
||||
71
dCommon/BinaryPathFinder.cpp
Normal file
71
dCommon/BinaryPathFinder.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include "BinaryPathFinder.h"
|
||||
#include "dPlatforms.h"
|
||||
|
||||
#if defined(DARKFLAME_PLATFORM_WIN32)
|
||||
#include <Windows.h>
|
||||
#elif defined(DARKFLAME_PLATFORM_MACOS) || defined(DARKFLAME_PLATFORM_IOS)
|
||||
#include <mach-o/dyld.h>
|
||||
#elif defined(DARKFLAME_PLATFORM_FREEBSD)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
std::filesystem::path BinaryPathFinder::binaryDir;
|
||||
|
||||
std::filesystem::path BinaryPathFinder::GetBinaryDir() {
|
||||
if (!binaryDir.empty()) {
|
||||
return binaryDir;
|
||||
}
|
||||
|
||||
std::string pathStr;
|
||||
|
||||
// Derived from boost::dll::program_location, licensed under the Boost Software License: http://www.boost.org/LICENSE_1_0.txt
|
||||
#if defined(DARKFLAME_PLATFORM_WIN32)
|
||||
char path[MAX_PATH];
|
||||
GetModuleFileName(NULL, path, MAX_PATH);
|
||||
pathStr = std::string(path);
|
||||
#elif defined(DARKFLAME_PLATFORM_MACOS) || defined(DARKFLAME_PLATFORM_IOS)
|
||||
char path[1024];
|
||||
uint32_t size = sizeof(path);
|
||||
if (_NSGetExecutablePath(path, &size) == 0) {
|
||||
pathStr = std::string(path);
|
||||
} else {
|
||||
// The filepath size is greater than our initial buffer size, so try again with the size
|
||||
// that _NSGetExecutablePath told us it actually is
|
||||
char *p = new char[size];
|
||||
if (_NSGetExecutablePath(p, &size) != 0) {
|
||||
throw std::runtime_error("Failed to get binary path from _NSGetExecutablePath");
|
||||
}
|
||||
|
||||
pathStr = std::string(p);
|
||||
delete[] p;
|
||||
}
|
||||
#elif defined(DARKFLAME_PLATFORM_FREEBSD)
|
||||
int mib[4];
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PATHNAME;
|
||||
mib[3] = -1;
|
||||
char buf[10240];
|
||||
size_t cb = sizeof(buf);
|
||||
sysctl(mib, 4, buf, &cb, NULL, 0);
|
||||
pathStr = std::string(buf);
|
||||
#else // DARKFLAME_PLATFORM_LINUX || DARKFLAME_PLATFORM_UNIX || DARKFLAME_PLATFORM_ANDROID
|
||||
pathStr = std::filesystem::read_symlink("/proc/self/exe");
|
||||
#endif
|
||||
|
||||
// Some methods like _NSGetExecutablePath could return a symlink
|
||||
// Either way, we need to get the parent path because we want the directory, not the binary itself
|
||||
// We also ensure that it is an absolute path so that it is valid if we need to construct a path
|
||||
// to exucute on unix systems (eg sudo BinaryPathFinder::GetBinaryDir() / WorldServer)
|
||||
if (std::filesystem::is_symlink(pathStr)) {
|
||||
binaryDir = std::filesystem::absolute(std::filesystem::read_symlink(pathStr).parent_path());
|
||||
} else {
|
||||
binaryDir = std::filesystem::absolute(std::filesystem::path(pathStr).parent_path());
|
||||
}
|
||||
|
||||
return binaryDir;
|
||||
}
|
||||
15
dCommon/BinaryPathFinder.h
Normal file
15
dCommon/BinaryPathFinder.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __BINARYPATHFINDER__H__
|
||||
#define __BINARYPATHFINDER__H__
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
class BinaryPathFinder {
|
||||
private:
|
||||
static std::filesystem::path binaryDir;
|
||||
public:
|
||||
static std::filesystem::path GetBinaryDir();
|
||||
};
|
||||
|
||||
#endif //!__BINARYPATHFINDER__H__
|
||||
180
dCommon/BrickByBrickFix.cpp
Normal file
180
dCommon/BrickByBrickFix.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
#include "BrickByBrickFix.h"
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "tinyxml2.h"
|
||||
|
||||
#include "Database.h"
|
||||
#include "Game.h"
|
||||
#include "ZCompression.h"
|
||||
#include "dLogger.h"
|
||||
|
||||
//! Forward declarations
|
||||
|
||||
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase();
|
||||
void WriteSd0Magic(char* input, uint32_t chunkSize);
|
||||
bool CheckSd0Magic(sql::Blob* streamToCheck);
|
||||
|
||||
/**
|
||||
* @brief Truncates all models with broken data from the database.
|
||||
*
|
||||
* @return The number of models deleted
|
||||
*/
|
||||
uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
|
||||
uint32_t modelsTruncated{};
|
||||
auto modelsToTruncate = GetModelsFromDatabase();
|
||||
bool previousCommitValue = Database::GetAutoCommit();
|
||||
Database::SetAutoCommit(false);
|
||||
while (modelsToTruncate->next()) {
|
||||
std::unique_ptr<sql::PreparedStatement> ugcModelToDelete(Database::CreatePreppedStmt("DELETE FROM ugc WHERE ugc.id = ?;"));
|
||||
std::unique_ptr<sql::PreparedStatement> pcModelToDelete(Database::CreatePreppedStmt("DELETE FROM properties_contents WHERE ugc_id = ?;"));
|
||||
std::string completeUncompressedModel{};
|
||||
uint32_t chunkCount{};
|
||||
uint64_t modelId = modelsToTruncate->getInt(1);
|
||||
std::unique_ptr<sql::Blob> modelAsSd0(modelsToTruncate->getBlob(2));
|
||||
// Check that header is sd0 by checking for the sd0 magic.
|
||||
if (CheckSd0Magic(modelAsSd0.get())) {
|
||||
while (true) {
|
||||
uint32_t chunkSize{};
|
||||
modelAsSd0->read(reinterpret_cast<char*>(&chunkSize), sizeof(uint32_t)); // Extract chunk size from istream
|
||||
|
||||
// Check if good here since if at the end of an sd0 file, this will have eof flagged.
|
||||
if (!modelAsSd0->good()) break;
|
||||
|
||||
std::unique_ptr<uint8_t[]> compressedChunk(new uint8_t[chunkSize]);
|
||||
for (uint32_t i = 0; i < chunkSize; i++) {
|
||||
compressedChunk[i] = modelAsSd0->get();
|
||||
}
|
||||
|
||||
// Ignore the valgrind warning about uninitialized values. These are discarded later when we know the actual uncompressed size.
|
||||
std::unique_ptr<uint8_t[]> uncompressedChunk(new uint8_t[ZCompression::MAX_SD0_CHUNK_SIZE]);
|
||||
int32_t err{};
|
||||
int32_t actualUncompressedSize = ZCompression::Decompress(
|
||||
compressedChunk.get(), chunkSize, uncompressedChunk.get(), ZCompression::MAX_SD0_CHUNK_SIZE, err);
|
||||
|
||||
if (actualUncompressedSize != -1) {
|
||||
uint32_t previousSize = completeUncompressedModel.size();
|
||||
completeUncompressedModel.append((char*)uncompressedChunk.get());
|
||||
completeUncompressedModel.resize(previousSize + actualUncompressedSize);
|
||||
} else {
|
||||
Game::logger->Log("BrickByBrickFix", "Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, modelId, err);
|
||||
break;
|
||||
}
|
||||
chunkCount++;
|
||||
}
|
||||
std::unique_ptr<tinyxml2::XMLDocument> document = std::make_unique<tinyxml2::XMLDocument>();
|
||||
if (!document) {
|
||||
Game::logger->Log("BrickByBrickFix", "Failed to initialize tinyxml document. Aborting.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(document->Parse(completeUncompressedModel.c_str(), completeUncompressedModel.size()) == tinyxml2::XML_SUCCESS)) {
|
||||
if (completeUncompressedModel.find(
|
||||
"</LXFML>",
|
||||
completeUncompressedModel.length() >= 15 ? completeUncompressedModel.length() - 15 : 0) == std::string::npos
|
||||
) {
|
||||
Game::logger->Log("BrickByBrickFix",
|
||||
"Brick-by-brick model %llu will be deleted!", modelId);
|
||||
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
|
||||
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
|
||||
ugcModelToDelete->execute();
|
||||
pcModelToDelete->execute();
|
||||
modelsTruncated++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Game::logger->Log("BrickByBrickFix",
|
||||
"Brick-by-brick model %llu will be deleted!", modelId);
|
||||
ugcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
|
||||
pcModelToDelete->setInt64(1, modelsToTruncate->getInt64(1));
|
||||
ugcModelToDelete->execute();
|
||||
pcModelToDelete->execute();
|
||||
modelsTruncated++;
|
||||
}
|
||||
}
|
||||
|
||||
Database::Commit();
|
||||
Database::SetAutoCommit(previousCommitValue);
|
||||
return modelsTruncated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates all current models in the database to have the Segmented Data 0 (SD0) format.
|
||||
* Any models that do not start with zlib and best compression magic will not be updated.
|
||||
*
|
||||
* @return The number of models updated to SD0
|
||||
*/
|
||||
uint32_t BrickByBrickFix::UpdateBrickByBrickModelsToSd0() {
|
||||
uint32_t updatedModels = 0;
|
||||
auto modelsToUpdate = GetModelsFromDatabase();
|
||||
auto previousAutoCommitState = Database::GetAutoCommit();
|
||||
Database::SetAutoCommit(false);
|
||||
std::unique_ptr<sql::PreparedStatement> insertionStatement(Database::CreatePreppedStmt("UPDATE ugc SET lxfml = ? WHERE id = ?;"));
|
||||
while (modelsToUpdate->next()) {
|
||||
int64_t modelId = modelsToUpdate->getInt64(1);
|
||||
std::unique_ptr<sql::Blob> oldLxfml(modelsToUpdate->getBlob(2));
|
||||
// Check if the stored blob starts with zlib magic (0x78 0xDA - best compression of zlib)
|
||||
// If it does, convert it to sd0.
|
||||
if (oldLxfml->get() == 0x78 && oldLxfml->get() == 0xDA) {
|
||||
|
||||
// Get and save size of zlib compressed chunk.
|
||||
oldLxfml->seekg(0, std::ios::end);
|
||||
uint32_t oldLxfmlSize = static_cast<uint32_t>(oldLxfml->tellg());
|
||||
oldLxfml->seekg(0);
|
||||
|
||||
// Allocate 9 extra bytes. 5 for sd0 magic, 4 for the only zlib compressed size.
|
||||
uint32_t oldLxfmlSizeWithHeader = oldLxfmlSize + 9;
|
||||
std::unique_ptr<char[]> sd0ConvertedModel(new char[oldLxfmlSizeWithHeader]);
|
||||
|
||||
WriteSd0Magic(sd0ConvertedModel.get(), oldLxfmlSize);
|
||||
for (uint32_t i = 9; i < oldLxfmlSizeWithHeader; i++) {
|
||||
sd0ConvertedModel.get()[i] = oldLxfml->get();
|
||||
}
|
||||
|
||||
std::string outputString(sd0ConvertedModel.get(), oldLxfmlSizeWithHeader);
|
||||
std::istringstream outputStringStream(outputString);
|
||||
|
||||
insertionStatement->setBlob(1, static_cast<std::istream*>(&outputStringStream));
|
||||
insertionStatement->setInt64(2, modelId);
|
||||
try {
|
||||
insertionStatement->executeUpdate();
|
||||
Game::logger->Log("BrickByBrickFix", "Updated model %i to sd0", modelId);
|
||||
updatedModels++;
|
||||
} catch (sql::SQLException exception) {
|
||||
Game::logger->Log(
|
||||
"BrickByBrickFix",
|
||||
"Failed to update model %i. This model should be inspected manually to see why."
|
||||
"The database error is %s", modelId, exception.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
Database::Commit();
|
||||
Database::SetAutoCommit(previousAutoCommitState);
|
||||
return updatedModels;
|
||||
}
|
||||
|
||||
std::unique_ptr<sql::ResultSet> GetModelsFromDatabase() {
|
||||
std::unique_ptr<sql::PreparedStatement> modelsRawDataQuery(Database::CreatePreppedStmt("SELECT id, lxfml FROM ugc;"));
|
||||
return std::unique_ptr<sql::ResultSet>(modelsRawDataQuery->executeQuery());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes sd0 magic at the front of a char*
|
||||
*
|
||||
* @param input the char* to write at the front of
|
||||
* @param chunkSize The size of the first chunk to write the size of
|
||||
*/
|
||||
void WriteSd0Magic(char* input, uint32_t chunkSize) {
|
||||
input[0] = 's';
|
||||
input[1] = 'd';
|
||||
input[2] = '0';
|
||||
input[3] = 0x01;
|
||||
input[4] = 0xFF;
|
||||
*reinterpret_cast<uint32_t*>(input + 5) = chunkSize; // Write the integer to the character array
|
||||
}
|
||||
|
||||
bool CheckSd0Magic(sql::Blob* streamToCheck) {
|
||||
return streamToCheck->get() == 's' && streamToCheck->get() == 'd' && streamToCheck->get() == '0' && streamToCheck->get() == 0x01 && streamToCheck->get() == 0xFF;
|
||||
}
|
||||
20
dCommon/BrickByBrickFix.h
Normal file
20
dCommon/BrickByBrickFix.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace BrickByBrickFix {
|
||||
/**
|
||||
* @brief Deletes all broken BrickByBrick models that have invalid XML
|
||||
*
|
||||
* @return The number of BrickByBrick models that were truncated
|
||||
*/
|
||||
uint32_t TruncateBrokenBrickByBrickXml();
|
||||
|
||||
/**
|
||||
* @brief Updates all BrickByBrick models in the database to be
|
||||
* in the sd0 format as opposed to a zlib compressed format.
|
||||
*
|
||||
* @return The number of BrickByBrick models that were updated
|
||||
*/
|
||||
uint32_t UpdateBrickByBrickModelsToSd0();
|
||||
};
|
||||
@@ -13,15 +13,51 @@ set(DCOMMON_SOURCES "AMFFormat.cpp"
|
||||
"NiQuaternion.cpp"
|
||||
"SHA512.cpp"
|
||||
"Type.cpp"
|
||||
"ZCompression.cpp")
|
||||
"ZCompression.cpp"
|
||||
"BrickByBrickFix.cpp"
|
||||
"BinaryPathFinder.cpp"
|
||||
"FdbToSqlite.cpp"
|
||||
)
|
||||
|
||||
add_subdirectory(dClient)
|
||||
|
||||
foreach(file ${DCOMMON_DCLIENT_SOURCES})
|
||||
set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}")
|
||||
endforeach()
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
|
||||
|
||||
add_library(dCommon STATIC ${DCOMMON_SOURCES})
|
||||
|
||||
target_link_libraries(dCommon bcrypt)
|
||||
target_link_libraries(dCommon bcrypt dDatabase tinyxml2)
|
||||
|
||||
if (UNIX)
|
||||
find_package(ZLIB REQUIRED)
|
||||
target_link_libraries(dCommon ZLIB::ZLIB)
|
||||
endif()
|
||||
elseif (WIN32)
|
||||
include(FetchContent)
|
||||
|
||||
# TODO Keep an eye on the zlib repository for an update to disable testing. Don't forget to update CMakePresets
|
||||
FetchContent_Declare(
|
||||
zlib
|
||||
URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip
|
||||
URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1
|
||||
)
|
||||
|
||||
# Disable warning about no project version.
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0048 NEW)
|
||||
# Disable warning about the minimum version of cmake used for bcrypt being deprecated in the future
|
||||
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "" FORCE)
|
||||
|
||||
FetchContent_MakeAvailable(zlib)
|
||||
|
||||
set(ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR})
|
||||
set_target_properties(zlib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIRS}")
|
||||
add_library(ZLIB::ZLIB ALIAS zlib)
|
||||
else ()
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"This platform does not have a way to use zlib.\nCreate an issue on GitHub with your build system so it can be configured."
|
||||
)
|
||||
endif ()
|
||||
|
||||
target_link_libraries(dCommon ZLIB::ZLIB)
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "Diagnostics.h"
|
||||
#include "Game.h"
|
||||
#include "dLogger.h"
|
||||
|
||||
// If we're on Win32, we'll include our minidump writer
|
||||
#ifdef _WIN32
|
||||
@@ -26,7 +28,7 @@ void make_minidump(EXCEPTION_POINTERS* e) {
|
||||
"_%4d%02d%02d_%02d%02d%02d.dmp",
|
||||
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
|
||||
}
|
||||
|
||||
Game::logger->Log("Diagnostics", "Creating crash dump %s", name);
|
||||
auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
@@ -81,6 +83,7 @@ struct bt_ctx {
|
||||
|
||||
static inline void Bt(struct backtrace_state* state) {
|
||||
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
||||
Game::logger->Log("Diagnostics", "backtrace is enabled, crash dump located at %s", fileName.c_str());
|
||||
FILE* file = fopen(fileName.c_str(), "w+");
|
||||
if (file != nullptr) {
|
||||
backtrace_print(state, 2, file);
|
||||
@@ -114,6 +117,8 @@ void GenerateDump() {
|
||||
void CatchUnhandled(int sig) {
|
||||
#ifndef __include_backtrace__
|
||||
|
||||
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
||||
Game::logger->Log("Diagnostics", "Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
|
||||
if (Diagnostics::GetProduceMemoryDump()) {
|
||||
GenerateDump();
|
||||
}
|
||||
@@ -124,7 +129,6 @@ void CatchUnhandled(int sig) {
|
||||
// get void*'s for all entries on the stack
|
||||
size = backtrace(array, 10);
|
||||
|
||||
printf("Fatal error %i\nStacktrace:\n", sig);
|
||||
#if defined(__GNUG__) and defined(__dynamic)
|
||||
|
||||
// Loop through the returned addresses, and get the symbols to be demangled
|
||||
@@ -142,19 +146,18 @@ void CatchUnhandled(int sig) {
|
||||
demangled = demangle(functionName.c_str());
|
||||
|
||||
if (demangled.empty()) {
|
||||
printf("[%02zu] %s\n", i, demangled.c_str());
|
||||
Game::logger->Log("Diagnostics", "[%02zu] %s", i, demangled.c_str());
|
||||
} else {
|
||||
printf("[%02zu] %s\n", i, functionName.c_str());
|
||||
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
|
||||
}
|
||||
} else {
|
||||
printf("[%02zu] %s\n", i, functionName.c_str());
|
||||
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
|
||||
}
|
||||
}
|
||||
#else
|
||||
backtrace_symbols_fd(array, size, STDOUT_FILENO);
|
||||
#endif
|
||||
|
||||
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
||||
FILE* file = fopen(fileName.c_str(), "w+");
|
||||
if (file != NULL) {
|
||||
// print out all the frames to stderr
|
||||
|
||||
247
dCommon/FdbToSqlite.cpp
Normal file
247
dCommon/FdbToSqlite.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#include "FdbToSqlite.h"
|
||||
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <cassert>
|
||||
#include <iomanip>
|
||||
|
||||
#include "BinaryIO.h"
|
||||
#include "CDClientDatabase.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "Game.h"
|
||||
#include "dLogger.h"
|
||||
#include "AssetManager.h"
|
||||
|
||||
#include "eSqliteDataType.h"
|
||||
|
||||
std::map<eSqliteDataType, std::string> FdbToSqlite::Convert::m_SqliteType = {
|
||||
{ eSqliteDataType::NONE, "none"},
|
||||
{ eSqliteDataType::INT32, "int32"},
|
||||
{ eSqliteDataType::REAL, "real"},
|
||||
{ eSqliteDataType::TEXT_4, "text_4"},
|
||||
{ eSqliteDataType::INT_BOOL, "int_bool"},
|
||||
{ eSqliteDataType::INT64, "int64"},
|
||||
{ eSqliteDataType::TEXT_8, "text_8"}
|
||||
};
|
||||
|
||||
FdbToSqlite::Convert::Convert(std::string binaryOutPath) {
|
||||
this->m_BinaryOutPath = binaryOutPath;
|
||||
}
|
||||
|
||||
bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
|
||||
if (m_ConversionStarted) return false;
|
||||
|
||||
std::istream cdClientBuffer(&buffer);
|
||||
|
||||
this->m_ConversionStarted = true;
|
||||
try {
|
||||
CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite");
|
||||
|
||||
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
|
||||
|
||||
int32_t numberOfTables = ReadInt32(cdClientBuffer);
|
||||
ReadTables(numberOfTables, cdClientBuffer);
|
||||
|
||||
CDClientDatabase::ExecuteQuery("COMMIT;");
|
||||
} catch (CppSQLite3Exception& e) {
|
||||
Game::logger->Log("FdbToSqlite", "Encountered error %s converting FDB to SQLite", e.errorMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t FdbToSqlite::Convert::ReadInt32(std::istream& cdClientBuffer) {
|
||||
int32_t nextInt{};
|
||||
BinaryIO::BinaryRead(cdClientBuffer, nextInt);
|
||||
return nextInt;
|
||||
}
|
||||
|
||||
int64_t FdbToSqlite::Convert::ReadInt64(std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
int64_t value{};
|
||||
BinaryIO::BinaryRead(cdClientBuffer, value);
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string FdbToSqlite::Convert::ReadString(std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
auto readString = BinaryIO::ReadString(cdClientBuffer);
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
return readString;
|
||||
}
|
||||
|
||||
int32_t FdbToSqlite::Convert::SeekPointer(std::istream& cdClientBuffer) {
|
||||
int32_t position{};
|
||||
BinaryIO::BinaryRead(cdClientBuffer, position);
|
||||
int32_t prevPosition = cdClientBuffer.tellg();
|
||||
cdClientBuffer.seekg(position);
|
||||
return prevPosition;
|
||||
}
|
||||
|
||||
std::string FdbToSqlite::Convert::ReadColumnHeader(std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
int32_t numberOfColumns = ReadInt32(cdClientBuffer);
|
||||
std::string tableName = ReadString(cdClientBuffer);
|
||||
|
||||
auto columns = ReadColumns(numberOfColumns, cdClientBuffer);
|
||||
std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");";
|
||||
CDClientDatabase::ExecuteDML(newTable);
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
|
||||
return tableName;
|
||||
}
|
||||
|
||||
void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
for (int32_t i = 0; i < numberOfTables; i++) {
|
||||
auto columnHeader = ReadColumnHeader(cdClientBuffer);
|
||||
ReadRowHeader(columnHeader, cdClientBuffer);
|
||||
}
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
}
|
||||
|
||||
std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer) {
|
||||
std::stringstream columnsToCreate;
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
std::string name{};
|
||||
eSqliteDataType dataType{};
|
||||
for (int32_t i = 0; i < numberOfColumns; i++) {
|
||||
if (i != 0) columnsToCreate << ", ";
|
||||
dataType = static_cast<eSqliteDataType>(ReadInt32(cdClientBuffer));
|
||||
name = ReadString(cdClientBuffer);
|
||||
columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType];
|
||||
}
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
return columnsToCreate.str();
|
||||
}
|
||||
|
||||
void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
int32_t numberOfAllocatedRows = ReadInt32(cdClientBuffer);
|
||||
if (numberOfAllocatedRows != 0) assert((numberOfAllocatedRows & (numberOfAllocatedRows - 1)) == 0); // assert power of 2 allocation size
|
||||
ReadRows(numberOfAllocatedRows, tableName, cdClientBuffer);
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
}
|
||||
|
||||
void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
int32_t rowid = 0;
|
||||
for (int32_t row = 0; row < numberOfAllocatedRows; row++) {
|
||||
int32_t rowPointer = ReadInt32(cdClientBuffer);
|
||||
if (rowPointer == -1) rowid++;
|
||||
else ReadRow(rowPointer, tableName, cdClientBuffer);
|
||||
}
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
}
|
||||
|
||||
void FdbToSqlite::Convert::ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = cdClientBuffer.tellg();
|
||||
cdClientBuffer.seekg(position);
|
||||
|
||||
while (true) {
|
||||
ReadRowInfo(tableName, cdClientBuffer);
|
||||
int32_t linked = ReadInt32(cdClientBuffer);
|
||||
if (linked == -1) break;
|
||||
cdClientBuffer.seekg(linked);
|
||||
}
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
}
|
||||
|
||||
void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
int32_t numberOfColumns = ReadInt32(cdClientBuffer);
|
||||
ReadRowValues(numberOfColumns, tableName, cdClientBuffer);
|
||||
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
}
|
||||
|
||||
void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer) {
|
||||
int32_t prevPosition = SeekPointer(cdClientBuffer);
|
||||
|
||||
int32_t emptyValue{};
|
||||
int32_t intValue{};
|
||||
float_t floatValue{};
|
||||
std::string stringValue{};
|
||||
int32_t boolValue{};
|
||||
int64_t int64Value{};
|
||||
bool insertedFirstEntry = false;
|
||||
std::stringstream insertedRow;
|
||||
insertedRow << "INSERT INTO " << tableName << " values (";
|
||||
|
||||
for (int32_t i = 0; i < numberOfColumns; i++) {
|
||||
if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row.
|
||||
switch (static_cast<eSqliteDataType>(ReadInt32(cdClientBuffer))) {
|
||||
case eSqliteDataType::NONE:
|
||||
BinaryIO::BinaryRead(cdClientBuffer, emptyValue);
|
||||
assert(emptyValue == 0);
|
||||
insertedRow << "NULL";
|
||||
break;
|
||||
|
||||
case eSqliteDataType::INT32:
|
||||
intValue = ReadInt32(cdClientBuffer);
|
||||
insertedRow << intValue;
|
||||
break;
|
||||
|
||||
case eSqliteDataType::REAL:
|
||||
BinaryIO::BinaryRead(cdClientBuffer, floatValue);
|
||||
insertedRow << std::fixed << std::setprecision(34) << floatValue; // maximum precision of floating point number
|
||||
break;
|
||||
|
||||
case eSqliteDataType::TEXT_4:
|
||||
case eSqliteDataType::TEXT_8: {
|
||||
stringValue = ReadString(cdClientBuffer);
|
||||
size_t position = 0;
|
||||
|
||||
// Need to escape quote with a double of ".
|
||||
while (position < stringValue.size()) {
|
||||
if (stringValue.at(position) == '\"') {
|
||||
stringValue.insert(position, "\"");
|
||||
position++;
|
||||
}
|
||||
position++;
|
||||
}
|
||||
insertedRow << "\"" << stringValue << "\"";
|
||||
break;
|
||||
}
|
||||
|
||||
case eSqliteDataType::INT_BOOL:
|
||||
BinaryIO::BinaryRead(cdClientBuffer, boolValue);
|
||||
insertedRow << static_cast<bool>(boolValue);
|
||||
break;
|
||||
|
||||
case eSqliteDataType::INT64:
|
||||
int64Value = ReadInt64(cdClientBuffer);
|
||||
insertedRow << std::to_string(int64Value);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::invalid_argument("Unsupported SQLite type encountered.");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
insertedRow << ");";
|
||||
|
||||
auto copiedString = insertedRow.str();
|
||||
CDClientDatabase::ExecuteDML(copiedString);
|
||||
cdClientBuffer.seekg(prevPosition);
|
||||
}
|
||||
145
dCommon/FdbToSqlite.h
Normal file
145
dCommon/FdbToSqlite.h
Normal file
@@ -0,0 +1,145 @@
|
||||
#ifndef __FDBTOSQLITE__H__
|
||||
#define __FDBTOSQLITE__H__
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
|
||||
class AssetMemoryBuffer;
|
||||
|
||||
enum class eSqliteDataType : int32_t;
|
||||
|
||||
namespace FdbToSqlite {
|
||||
class Convert {
|
||||
public:
|
||||
/**
|
||||
* Create a new convert object with an input .fdb file and an output binary path.
|
||||
*
|
||||
* @param inputFile The file which ends in .fdb to be converted
|
||||
* @param binaryPath The base path where the file will be saved
|
||||
*/
|
||||
Convert(std::string binaryOutPath);
|
||||
|
||||
/**
|
||||
* Converts the input file to sqlite. Calling multiple times is safe.
|
||||
*
|
||||
* @return true if the database was converted properly, false otherwise.
|
||||
*/
|
||||
bool ConvertDatabase(AssetMemoryBuffer& buffer);
|
||||
|
||||
/**
|
||||
* @brief Reads a 32 bit int from the fdb file.
|
||||
*
|
||||
* @return The read value
|
||||
*/
|
||||
int32_t ReadInt32(std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Reads a 64 bit integer from the fdb file.
|
||||
*
|
||||
* @return The read value
|
||||
*/
|
||||
int64_t ReadInt64(std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Reads a string from the fdb file.
|
||||
*
|
||||
* @return The read string
|
||||
*
|
||||
* TODO This needs to be translated to latin-1!
|
||||
*/
|
||||
std::string ReadString(std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Seeks to a pointer position.
|
||||
*
|
||||
* @return The previous position before the seek
|
||||
*/
|
||||
int32_t SeekPointer(std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Reads a column header from the fdb file and creates the table in the database
|
||||
*
|
||||
* @return The table name
|
||||
*/
|
||||
std::string ReadColumnHeader(std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Read the tables from the fdb file.
|
||||
*
|
||||
* @param numberOfTables The number of tables to read
|
||||
*/
|
||||
void ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Reads the columns from the fdb file.
|
||||
*
|
||||
* @param numberOfColumns The number of columns to read
|
||||
* @return All columns of the table formatted for a sql query
|
||||
*/
|
||||
std::string ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Reads the row header from the fdb file.
|
||||
*
|
||||
* @param tableName The tables name
|
||||
*/
|
||||
void ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Read the rows from the fdb file.,
|
||||
*
|
||||
* @param numberOfAllocatedRows The number of rows that were allocated. Always a power of 2!
|
||||
* @param tableName The tables name.
|
||||
*/
|
||||
void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Reads a row from the fdb file.
|
||||
*
|
||||
* @param position The position to seek in the fdb to
|
||||
* @param tableName The tables name
|
||||
*/
|
||||
void ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Reads the row info from the fdb file.
|
||||
*
|
||||
* @param tableName The tables name
|
||||
*/
|
||||
void ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer);
|
||||
|
||||
/**
|
||||
* @brief Reads each row and its values from the fdb file and inserts them into the database
|
||||
*
|
||||
* @param numberOfColumns The number of columns to read in
|
||||
* @param tableName The tables name
|
||||
*/
|
||||
void ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer);
|
||||
private:
|
||||
|
||||
/**
|
||||
* Maps each sqlite data type to its string equivalent.
|
||||
*/
|
||||
static std::map<eSqliteDataType, std::string> m_SqliteType;
|
||||
|
||||
/**
|
||||
* Base path of the folder containing the fdb file
|
||||
*/
|
||||
std::string m_BasePath{};
|
||||
|
||||
/**
|
||||
* Whether or not a conversion was started. If one was started, do not attempt to convert the file again.
|
||||
*/
|
||||
bool m_ConversionStarted{};
|
||||
|
||||
/**
|
||||
* The path where the CDServer will be stored
|
||||
*/
|
||||
std::string m_BinaryOutPath{};
|
||||
}; //! class FdbToSqlite
|
||||
}; //! namespace FdbToSqlite
|
||||
|
||||
#endif //!__FDBTOSQLITE__H__
|
||||
@@ -5,22 +5,21 @@
|
||||
class dServer;
|
||||
class dLogger;
|
||||
class InstanceManager;
|
||||
class dpWorld;
|
||||
class dChatFilter;
|
||||
class dConfig;
|
||||
class dLocale;
|
||||
class RakPeerInterface;
|
||||
class AssetManager;
|
||||
struct SystemAddress;
|
||||
|
||||
namespace Game {
|
||||
extern dLogger* logger;
|
||||
extern dServer* server;
|
||||
extern InstanceManager* im;
|
||||
extern dpWorld* physicsWorld;
|
||||
extern dChatFilter* chatFilter;
|
||||
extern dConfig* config;
|
||||
extern dLocale* locale;
|
||||
extern std::mt19937 randomEngine;
|
||||
extern RakPeerInterface* chatServer;
|
||||
extern AssetManager* assetManager;
|
||||
extern SystemAddress chatSysAddr;
|
||||
extern bool shouldShutdown;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
|
||||
template <typename T>
|
||||
inline size_t MinSize(size_t size, const std::basic_string_view<T>& string) {
|
||||
@@ -50,6 +52,7 @@ bool _IsSuffixChar(uint8_t c) {
|
||||
|
||||
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||
size_t rem = slice.length();
|
||||
if (slice.empty()) return false;
|
||||
const uint8_t* bytes = (const uint8_t*)&slice.front();
|
||||
if (rem > 0) {
|
||||
uint8_t first = bytes[0];
|
||||
@@ -289,51 +292,30 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) {
|
||||
return string;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
std::vector<std::string> GeneralUtils::GetFileNamesFromFolder(const std::string& folder) {
|
||||
std::vector<std::string> names;
|
||||
std::string search_path = folder + "/*.*";
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd);
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
names.push_back(fd.cFileName);
|
||||
}
|
||||
} while (::FindNextFile(hFind, &fd));
|
||||
::FindClose(hFind);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
std::vector<std::string> GeneralUtils::GetFileNamesFromFolder(const std::string& folder) {
|
||||
std::vector<std::string> names;
|
||||
struct dirent* entry;
|
||||
DIR* dir = opendir(folder.c_str());
|
||||
if (dir == NULL) {
|
||||
return names;
|
||||
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string& 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));
|
||||
}
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
std::string value(entry->d_name, strlen(entry->d_name));
|
||||
if (value == "." || value == "..") {
|
||||
continue;
|
||||
// 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;
|
||||
}
|
||||
names.push_back(value);
|
||||
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
||||
fileIterator++;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return names;
|
||||
return sortedFiles;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include <BitStream.h>
|
||||
|
||||
#include "Game.h"
|
||||
#include "dLogger.h"
|
||||
|
||||
enum eInventoryType : uint32_t;
|
||||
enum class eReplicaComponentType : uint32_t;
|
||||
|
||||
/*!
|
||||
\file GeneralUtils.hpp
|
||||
@@ -138,7 +142,7 @@ namespace GeneralUtils {
|
||||
|
||||
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
||||
|
||||
std::vector<std::string> GetFileNamesFromFolder(const std::string& folder);
|
||||
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
|
||||
|
||||
template <typename T>
|
||||
T Parse(const char* value);
|
||||
@@ -173,6 +177,16 @@ namespace GeneralUtils {
|
||||
return std::stoull(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline eInventoryType Parse(const char* value) {
|
||||
return static_cast<eInventoryType>(std::stoul(value));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline eReplicaComponentType Parse(const char* value) {
|
||||
return static_cast<eReplicaComponentType>(std::stoul(value));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool TryParse(const char* value, T& dst) {
|
||||
try {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* Bitmap of permissions and restrictions for characters.
|
||||
*/
|
||||
enum class PermissionMap : uint64_t
|
||||
{
|
||||
/**
|
||||
* Reserved for future use, bit 0-3.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The character has restricted trade acccess, bit 4.
|
||||
*/
|
||||
RestrictedTradeAccess = 0x1 << 4,
|
||||
|
||||
/**
|
||||
* The character has restricted mail access, bit 5.
|
||||
*/
|
||||
RestrictedMailAccess = 0x1 << 5,
|
||||
|
||||
/**
|
||||
* The character has restricted chat access, bit 6.
|
||||
*/
|
||||
RestrictedChatAccess = 0x1 << 6,
|
||||
|
||||
//
|
||||
// Combined permissions
|
||||
//
|
||||
|
||||
/**
|
||||
* The character is marked as 'old', restricted from trade and mail.
|
||||
*/
|
||||
Old = RestrictedTradeAccess | RestrictedMailAccess,
|
||||
|
||||
/**
|
||||
* The character is soft banned, restricted from trade, mail, and chat.
|
||||
*/
|
||||
SoftBanned = RestrictedTradeAccess | RestrictedMailAccess | RestrictedChatAccess,
|
||||
};
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "ZCompression.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
namespace ZCompression {
|
||||
@@ -27,7 +25,6 @@ namespace ZCompression {
|
||||
}
|
||||
deflateEnd(&zInfo); // zlib function
|
||||
return(nRet);
|
||||
|
||||
}
|
||||
|
||||
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr) {
|
||||
@@ -48,26 +45,6 @@ namespace ZCompression {
|
||||
}
|
||||
inflateEnd(&zInfo); // zlib function
|
||||
return(nRet);
|
||||
|
||||
/*
|
||||
z_stream zInfo = { 0 };
|
||||
zInfo.total_in = zInfo.avail_in = nLenSrc;
|
||||
zInfo.total_out = zInfo.avail_out = nLenDst;
|
||||
zInfo.next_in = const_cast<Bytef*>(abSrc);
|
||||
zInfo.next_out = const_cast<Bytef*>(abDst);
|
||||
|
||||
int nRet = -1;
|
||||
nErr = inflateInit(&zInfo); // zlib function
|
||||
if (nErr == Z_OK) {
|
||||
nErr = inflate(&zInfo, Z_FINISH); // zlib function
|
||||
if (nErr == Z_STREAM_END) {
|
||||
nRet = zInfo.total_out;
|
||||
}
|
||||
}
|
||||
inflateEnd(&zInfo); // zlib function
|
||||
return(nRet); // -1 or len of output
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "dPlatforms.h"
|
||||
|
||||
#ifndef DARKFLAME_PLATFORM_WIN32
|
||||
|
||||
namespace ZCompression {
|
||||
int32_t GetMaxCompressedLength(int32_t nLenSrc);
|
||||
|
||||
int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst);
|
||||
|
||||
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr);
|
||||
|
||||
/**
|
||||
* @brief Max size of an inflated sd0 zlib chunk
|
||||
*
|
||||
*/
|
||||
constexpr uint32_t MAX_SD0_CHUNK_SIZE = 1024 * 256;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
179
dCommon/dClient/AssetManager.cpp
Normal file
179
dCommon/dClient/AssetManager.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
#include <filesystem>
|
||||
|
||||
#include "AssetManager.h"
|
||||
#include "Game.h"
|
||||
#include "dLogger.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
AssetManager::AssetManager(const std::filesystem::path& path) {
|
||||
if (!std::filesystem::is_directory(path)) {
|
||||
throw std::runtime_error("Attempted to load asset bundle (" + path.string() + ") however it is not a valid directory.");
|
||||
}
|
||||
|
||||
m_Path = path;
|
||||
|
||||
if (std::filesystem::exists(m_Path / "client") && std::filesystem::exists(m_Path / "versions")) {
|
||||
m_AssetBundleType = eAssetBundleType::Packed;
|
||||
|
||||
m_RootPath = m_Path;
|
||||
m_ResPath = (m_Path / "client" / "res");
|
||||
} else if (std::filesystem::exists(m_Path / ".." / "versions") && std::filesystem::exists(m_Path / "res")) {
|
||||
m_AssetBundleType = eAssetBundleType::Packed;
|
||||
|
||||
m_RootPath = (m_Path / "..");
|
||||
m_ResPath = (m_Path / "res");
|
||||
} else if (std::filesystem::exists(m_Path / "pack") && std::filesystem::exists(m_Path / ".." / ".." / "versions")) {
|
||||
m_AssetBundleType = eAssetBundleType::Packed;
|
||||
|
||||
m_RootPath = (m_Path / ".." / "..");
|
||||
m_ResPath = m_Path;
|
||||
} else if ((std::filesystem::exists(m_Path / "res" / "cdclient.fdb") || std::filesystem::exists(m_Path / "res" / "CDServer.sqlite")) && !std::filesystem::exists(m_Path / "res" / "pack")) {
|
||||
m_AssetBundleType = eAssetBundleType::Unpacked;
|
||||
|
||||
m_ResPath = (m_Path / "res");
|
||||
} else if ((std::filesystem::exists(m_Path / "cdclient.fdb") || std::filesystem::exists(m_Path / "CDServer.sqlite")) && !std::filesystem::exists(m_Path / "pack")) {
|
||||
m_AssetBundleType = eAssetBundleType::Unpacked;
|
||||
|
||||
m_ResPath = m_Path;
|
||||
}
|
||||
|
||||
if (m_AssetBundleType == eAssetBundleType::None) {
|
||||
throw std::runtime_error("Failed to identify client type, cannot read client data.");
|
||||
}
|
||||
|
||||
switch (m_AssetBundleType) {
|
||||
case eAssetBundleType::Packed: {
|
||||
this->LoadPackIndex();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetManager::LoadPackIndex() {
|
||||
m_PackIndex = new PackIndex(m_RootPath);
|
||||
}
|
||||
|
||||
std::filesystem::path AssetManager::GetResPath() {
|
||||
return m_ResPath;
|
||||
}
|
||||
|
||||
eAssetBundleType AssetManager::GetAssetBundleType() {
|
||||
return m_AssetBundleType;
|
||||
}
|
||||
|
||||
bool AssetManager::HasFile(const char* name) {
|
||||
auto fixedName = std::string(name);
|
||||
std::transform(fixedName.begin(), fixedName.end(), fixedName.begin(), [](uint8_t c) { return std::tolower(c); });
|
||||
|
||||
// Special case for unpacked client have BrickModels in upper case
|
||||
if (this->m_AssetBundleType == eAssetBundleType::Unpacked) GeneralUtils::ReplaceInString(fixedName, "brickmodels", "BrickModels");
|
||||
|
||||
std::replace(fixedName.begin(), fixedName.end(), '\\', '/');
|
||||
if (std::filesystem::exists(m_ResPath / fixedName)) return true;
|
||||
|
||||
if (this->m_AssetBundleType == eAssetBundleType::Unpacked) return false;
|
||||
|
||||
std::replace(fixedName.begin(), fixedName.end(), '/', '\\');
|
||||
if (fixedName.rfind("client\\res\\", 0) != 0) fixedName = "client\\res\\" + fixedName;
|
||||
|
||||
uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size());
|
||||
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
|
||||
|
||||
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
|
||||
if (item.m_Crc == crc) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
|
||||
auto fixedName = std::string(name);
|
||||
std::transform(fixedName.begin(), fixedName.end(), fixedName.begin(), [](uint8_t c) { return std::tolower(c); });
|
||||
std::replace(fixedName.begin(), fixedName.end(), '\\', '/'); // On the off chance someone has the wrong slashes, force forward slashes
|
||||
|
||||
// Special case for unpacked client have BrickModels in upper case
|
||||
if (this->m_AssetBundleType == eAssetBundleType::Unpacked) GeneralUtils::ReplaceInString(fixedName, "brickmodels", "BrickModels");
|
||||
|
||||
if (std::filesystem::exists(m_ResPath / fixedName)) {
|
||||
FILE* file;
|
||||
#ifdef _WIN32
|
||||
fopen_s(&file, (m_ResPath / fixedName).string().c_str(), "rb");
|
||||
#elif __APPLE__
|
||||
// macOS has 64bit file IO by default
|
||||
file = fopen((m_ResPath / fixedName).string().c_str(), "rb");
|
||||
#else
|
||||
file = fopen64((m_ResPath / fixedName).string().c_str(), "rb");
|
||||
#endif
|
||||
fseek(file, 0, SEEK_END);
|
||||
*len = ftell(file);
|
||||
*data = (char*)malloc(*len);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
fread(*data, sizeof(uint8_t), *len, file);
|
||||
fclose(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->m_AssetBundleType == eAssetBundleType::Unpacked) return false;
|
||||
|
||||
// The crc in side of the pack always uses backslashes, so we need to convert them again...
|
||||
std::replace(fixedName.begin(), fixedName.end(), '/', '\\');
|
||||
if (fixedName.rfind("client\\res\\", 0) != 0) {
|
||||
fixedName = "client\\res\\" + fixedName;
|
||||
}
|
||||
int32_t packIndex = -1;
|
||||
uint32_t crc = crc32b(0xFFFFFFFF, (uint8_t*)fixedName.c_str(), fixedName.size());
|
||||
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
|
||||
|
||||
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
|
||||
if (item.m_Crc == crc) {
|
||||
packIndex = item.m_PackFileIndex;
|
||||
crc = item.m_Crc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (packIndex == -1 || !crc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto packs = this->m_PackIndex->GetPacks();
|
||||
auto* pack = packs.at(packIndex);
|
||||
|
||||
bool success = pack->ReadFileFromPack(crc, data, len);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) {
|
||||
char* buf;
|
||||
uint32_t len;
|
||||
|
||||
bool success = this->GetFile(name, &buf, &len);
|
||||
|
||||
return AssetMemoryBuffer(buf, len, success);
|
||||
}
|
||||
|
||||
uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {
|
||||
size_t i, j;
|
||||
uint32_t crc, msb;
|
||||
|
||||
crc = base;
|
||||
for (i = 0; i < l; i++) {
|
||||
// xor next byte to upper bits of crc
|
||||
crc ^= (((unsigned int)message[i]) << 24);
|
||||
for (j = 0; j < 8; j++) { // Do eight times.
|
||||
msb = crc >> 31;
|
||||
crc <<= 1;
|
||||
crc ^= (0 - msb) & 0x04C11DB7;
|
||||
}
|
||||
}
|
||||
return crc; // don't complement crc on output
|
||||
}
|
||||
|
||||
AssetManager::~AssetManager() {
|
||||
delete m_PackIndex;
|
||||
}
|
||||
77
dCommon/dClient/AssetManager.h
Normal file
77
dCommon/dClient/AssetManager.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <filesystem>
|
||||
|
||||
#include "Pack.h"
|
||||
#include "PackIndex.h"
|
||||
|
||||
enum class eAssetBundleType {
|
||||
None,
|
||||
Unpacked,
|
||||
Packed
|
||||
};
|
||||
|
||||
struct AssetMemoryBuffer : std::streambuf {
|
||||
char* m_Base;
|
||||
bool m_Success;
|
||||
|
||||
AssetMemoryBuffer(char* base, std::ptrdiff_t n, bool success) {
|
||||
m_Base = base;
|
||||
m_Success = success;
|
||||
if (!m_Success) return;
|
||||
this->setg(base, base, base + n);
|
||||
}
|
||||
|
||||
pos_type seekpos(pos_type sp, std::ios_base::openmode which) override {
|
||||
return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
|
||||
}
|
||||
|
||||
pos_type seekoff(off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which = std::ios_base::in) override {
|
||||
if (dir == std::ios_base::cur)
|
||||
gbump(off);
|
||||
else if (dir == std::ios_base::end)
|
||||
setg(eback(), egptr() + off, egptr());
|
||||
else if (dir == std::ios_base::beg)
|
||||
setg(eback(), eback() + off, egptr());
|
||||
return gptr() - eback();
|
||||
}
|
||||
|
||||
void close() {
|
||||
delete m_Base;
|
||||
}
|
||||
};
|
||||
|
||||
class AssetManager {
|
||||
public:
|
||||
AssetManager(const std::filesystem::path& path);
|
||||
~AssetManager();
|
||||
|
||||
std::filesystem::path GetResPath();
|
||||
eAssetBundleType GetAssetBundleType();
|
||||
|
||||
bool HasFile(const char* name);
|
||||
bool GetFile(const char* name, char** data, uint32_t* len);
|
||||
AssetMemoryBuffer GetFileAsBuffer(const char* name);
|
||||
|
||||
private:
|
||||
void LoadPackIndex();
|
||||
|
||||
// Modified crc algorithm (mpeg2)
|
||||
// Reference: https://stackoverflow.com/questions/54339800/how-to-modify-crc-32-to-crc-32-mpeg-2
|
||||
inline uint32_t crc32b(uint32_t base, uint8_t* message, size_t l);
|
||||
|
||||
bool m_SuccessfullyLoaded;
|
||||
|
||||
std::filesystem::path m_Path;
|
||||
std::filesystem::path m_RootPath;
|
||||
std::filesystem::path m_ResPath;
|
||||
|
||||
eAssetBundleType m_AssetBundleType = eAssetBundleType::None;
|
||||
|
||||
PackIndex* m_PackIndex;
|
||||
};
|
||||
6
dCommon/dClient/CMakeLists.txt
Normal file
6
dCommon/dClient/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
set(DCOMMON_DCLIENT_SOURCES
|
||||
"PackIndex.cpp"
|
||||
"Pack.cpp"
|
||||
"AssetManager.cpp"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
119
dCommon/dClient/Pack.cpp
Normal file
119
dCommon/dClient/Pack.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "Pack.h"
|
||||
|
||||
#include "BinaryIO.h"
|
||||
#include "ZCompression.h"
|
||||
|
||||
Pack::Pack(const std::filesystem::path& filePath) {
|
||||
m_FilePath = filePath;
|
||||
|
||||
if (!std::filesystem::exists(filePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_FileStream = std::ifstream(filePath, std::ios::in | std::ios::binary);
|
||||
|
||||
m_FileStream.read(m_Version, 7);
|
||||
|
||||
m_FileStream.seekg(-8, std::ios::end); // move file pointer to 8 bytes before the end (location of the address of the record count)
|
||||
|
||||
uint32_t recordCountPos = 0;
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, recordCountPos);
|
||||
|
||||
m_FileStream.seekg(recordCountPos, std::ios::beg);
|
||||
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_RecordCount);
|
||||
|
||||
for (int i = 0; i < m_RecordCount; i++) {
|
||||
PackRecord record;
|
||||
BinaryIO::BinaryRead<PackRecord>(m_FileStream, record);
|
||||
|
||||
m_Records.push_back(record);
|
||||
}
|
||||
|
||||
m_FileStream.close();
|
||||
}
|
||||
|
||||
bool Pack::HasFile(uint32_t crc) {
|
||||
for (const auto& record : m_Records) {
|
||||
if (record.m_Crc == crc) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
|
||||
// Time for some wacky C file reading for speed reasons
|
||||
|
||||
PackRecord pkRecord{};
|
||||
|
||||
for (const auto& record : m_Records) {
|
||||
if (record.m_Crc == crc) {
|
||||
pkRecord = record;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pkRecord.m_Crc == 0) return false;
|
||||
|
||||
size_t pos = 0;
|
||||
pos += pkRecord.m_FilePointer;
|
||||
|
||||
bool isCompressed = (pkRecord.m_IsCompressed & 0xff) > 0;
|
||||
auto inPackSize = isCompressed ? pkRecord.m_CompressedSize : pkRecord.m_UncompressedSize;
|
||||
|
||||
FILE* file;
|
||||
#ifdef _WIN32
|
||||
fopen_s(&file, m_FilePath.string().c_str(), "rb");
|
||||
#elif __APPLE__
|
||||
// macOS has 64bit file IO by default
|
||||
file = fopen(m_FilePath.string().c_str(), "rb");
|
||||
#else
|
||||
file = fopen64(m_FilePath.string().c_str(), "rb");
|
||||
#endif
|
||||
|
||||
fseek(file, pos, SEEK_SET);
|
||||
|
||||
if (!isCompressed) {
|
||||
char* tempData = (char*)malloc(pkRecord.m_UncompressedSize);
|
||||
fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file);
|
||||
|
||||
*data = tempData;
|
||||
*len = pkRecord.m_UncompressedSize;
|
||||
fclose(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pos += 5; // skip header
|
||||
|
||||
fseek(file, pos, SEEK_SET);
|
||||
|
||||
char* decompressedData = (char*)malloc(pkRecord.m_UncompressedSize);
|
||||
uint32_t currentReadPos = 0;
|
||||
|
||||
while (true) {
|
||||
if (currentReadPos >= pkRecord.m_UncompressedSize) break;
|
||||
|
||||
uint32_t size;
|
||||
fread(&size, sizeof(uint32_t), 1, file);
|
||||
pos += 4; // Move pointer position 4 to the right
|
||||
|
||||
char* chunk = (char*)malloc(size);
|
||||
fread(chunk, sizeof(int8_t), size, file);
|
||||
pos += size; // Move pointer position the amount of bytes read to the right
|
||||
|
||||
int32_t err;
|
||||
currentReadPos += ZCompression::Decompress((uint8_t*)chunk, size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
|
||||
|
||||
free(chunk);
|
||||
}
|
||||
|
||||
*data = decompressedData;
|
||||
*len = pkRecord.m_UncompressedSize;
|
||||
|
||||
fclose(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
38
dCommon/dClient/Pack.h
Normal file
38
dCommon/dClient/Pack.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct PackRecord {
|
||||
uint32_t m_Crc;
|
||||
int32_t m_LowerCrc;
|
||||
int32_t m_UpperCrc;
|
||||
uint32_t m_UncompressedSize;
|
||||
char m_UncompressedHash[32];
|
||||
uint32_t m_Padding1;
|
||||
uint32_t m_CompressedSize;
|
||||
char m_CompressedHash[32];
|
||||
uint32_t m_Padding2;
|
||||
uint32_t m_FilePointer;
|
||||
uint32_t m_IsCompressed; // u32 bool
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class Pack {
|
||||
public:
|
||||
Pack(const std::filesystem::path& filePath);
|
||||
~Pack() = default;
|
||||
|
||||
bool HasFile(uint32_t crc);
|
||||
bool ReadFileFromPack(uint32_t crc, char** data, uint32_t* len);
|
||||
private:
|
||||
std::ifstream m_FileStream;
|
||||
std::filesystem::path m_FilePath;
|
||||
|
||||
char m_Version[7];
|
||||
|
||||
uint32_t m_RecordCount;
|
||||
std::vector<PackRecord> m_Records;
|
||||
};
|
||||
54
dCommon/dClient/PackIndex.cpp
Normal file
54
dCommon/dClient/PackIndex.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "PackIndex.h"
|
||||
#include "BinaryIO.h"
|
||||
#include "Game.h"
|
||||
#include "dLogger.h"
|
||||
|
||||
PackIndex::PackIndex(const std::filesystem::path& filePath) {
|
||||
m_FileStream = std::ifstream(filePath / "versions" / "primary.pki", std::ios::in | std::ios::binary);
|
||||
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_Version);
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackPathCount);
|
||||
|
||||
for (int i = 0; i < m_PackPathCount; i++) {
|
||||
uint32_t stringLen = 0;
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, stringLen);
|
||||
|
||||
std::string path;
|
||||
|
||||
for (int j = 0; j < stringLen; j++) {
|
||||
char inChar;
|
||||
BinaryIO::BinaryRead<char>(m_FileStream, inChar);
|
||||
|
||||
path += inChar;
|
||||
}
|
||||
|
||||
m_PackPaths.push_back(path);
|
||||
}
|
||||
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackFileIndexCount);
|
||||
|
||||
for (int i = 0; i < m_PackFileIndexCount; i++) {
|
||||
PackFileIndex packFileIndex;
|
||||
BinaryIO::BinaryRead<PackFileIndex>(m_FileStream, packFileIndex);
|
||||
|
||||
m_PackFileIndices.push_back(packFileIndex);
|
||||
}
|
||||
|
||||
Game::logger->Log("PackIndex", "Loaded pack catalog with %i pack files and %i files", m_PackPaths.size(), m_PackFileIndices.size());
|
||||
|
||||
for (auto& item : m_PackPaths) {
|
||||
std::replace(item.begin(), item.end(), '\\', '/');
|
||||
|
||||
auto* pack = new Pack(filePath / item);
|
||||
|
||||
m_Packs.push_back(pack);
|
||||
}
|
||||
|
||||
m_FileStream.close();
|
||||
}
|
||||
|
||||
PackIndex::~PackIndex() {
|
||||
for (const auto* item : m_Packs) {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
40
dCommon/dClient/PackIndex.h
Normal file
40
dCommon/dClient/PackIndex.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
#include "Pack.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct PackFileIndex {
|
||||
uint32_t m_Crc;
|
||||
int32_t m_LowerCrc;
|
||||
int32_t m_UpperCrc;
|
||||
uint32_t m_PackFileIndex;
|
||||
uint32_t m_IsCompressed; // u32 bool?
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class PackIndex {
|
||||
public:
|
||||
PackIndex(const std::filesystem::path& filePath);
|
||||
~PackIndex();
|
||||
|
||||
const std::vector<std::string>& GetPackPaths() { return m_PackPaths; }
|
||||
const std::vector<PackFileIndex>& GetPackFileIndices() { return m_PackFileIndices; }
|
||||
const std::vector<Pack*>& GetPacks() { return m_Packs; }
|
||||
private:
|
||||
std::ifstream m_FileStream;
|
||||
|
||||
uint32_t m_Version;
|
||||
|
||||
uint32_t m_PackPathCount;
|
||||
std::vector<std::string> m_PackPaths;
|
||||
uint32_t m_PackFileIndexCount;
|
||||
std::vector<PackFileIndex> m_PackFileIndices;
|
||||
|
||||
std::vector<Pack*> m_Packs;
|
||||
};
|
||||
@@ -1,45 +1,53 @@
|
||||
#include "dConfig.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "BinaryPathFinder.h"
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
dConfig::dConfig(const std::string& filepath) {
|
||||
m_EmptyString = "";
|
||||
std::ifstream in(filepath);
|
||||
m_ConfigFilePath = filepath;
|
||||
LoadConfig();
|
||||
}
|
||||
|
||||
void dConfig::LoadConfig() {
|
||||
std::ifstream in(BinaryPathFinder::GetBinaryDir() / m_ConfigFilePath);
|
||||
if (!in.good()) return;
|
||||
|
||||
std::string line;
|
||||
std::string line{};
|
||||
while (std::getline(in, line)) {
|
||||
if (line.length() > 0) {
|
||||
if (line[0] != '#') ProcessLine(line);
|
||||
}
|
||||
if (!line.empty() && line.front() != '#') ProcessLine(line);
|
||||
}
|
||||
|
||||
std::ifstream sharedConfig(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini", std::ios::in);
|
||||
if (!sharedConfig.good()) return;
|
||||
|
||||
line.clear();
|
||||
while (std::getline(sharedConfig, line)) {
|
||||
if (!line.empty() && line.front() != '#') ProcessLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
dConfig::~dConfig(void) {
|
||||
void dConfig::ReloadConfig() {
|
||||
this->m_ConfigValues.clear();
|
||||
LoadConfig();
|
||||
}
|
||||
|
||||
const std::string& dConfig::GetValue(std::string key) {
|
||||
for (size_t i = 0; i < m_Keys.size(); ++i) {
|
||||
if (m_Keys[i] == key) return m_Values[i];
|
||||
}
|
||||
|
||||
return m_EmptyString;
|
||||
return this->m_ConfigValues[key];
|
||||
}
|
||||
|
||||
void dConfig::ProcessLine(const std::string& line) {
|
||||
std::stringstream ss(line);
|
||||
std::string segment;
|
||||
std::vector<std::string> seglist;
|
||||
auto splitLine = GeneralUtils::SplitString(line, '=');
|
||||
|
||||
while (std::getline(ss, segment, '=')) {
|
||||
seglist.push_back(segment);
|
||||
}
|
||||
|
||||
if (seglist.size() != 2) return;
|
||||
if (splitLine.size() != 2) return;
|
||||
|
||||
//Make sure that on Linux, we remove special characters:
|
||||
if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r')
|
||||
seglist[1].erase(seglist[1].size() - 1);
|
||||
auto& key = splitLine.at(0);
|
||||
auto& value = splitLine.at(1);
|
||||
if (!value.empty() && value.at(value.size() - 1) == '\r') value.erase(value.size() - 1);
|
||||
|
||||
m_Keys.push_back(seglist[0]);
|
||||
m_Values.push_back(seglist[1]);
|
||||
if (this->m_ConfigValues.find(key) != this->m_ConfigValues.end()) return;
|
||||
|
||||
this->m_ConfigValues.insert(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
@@ -1,20 +1,33 @@
|
||||
#pragma once
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class dConfig {
|
||||
public:
|
||||
dConfig(const std::string& filepath);
|
||||
~dConfig(void);
|
||||
|
||||
/**
|
||||
* Gets the specified key from the config. Returns an empty string if the value is not found.
|
||||
*
|
||||
* @param key Key to find
|
||||
* @return The keys value in the config
|
||||
*/
|
||||
const std::string& GetValue(std::string key);
|
||||
|
||||
/**
|
||||
* Loads the config from a file
|
||||
*/
|
||||
void LoadConfig();
|
||||
|
||||
/**
|
||||
* Reloads the config file to reset values
|
||||
*/
|
||||
void ReloadConfig();
|
||||
private:
|
||||
void ProcessLine(const std::string& line);
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_Keys;
|
||||
std::vector<std::string> m_Values;
|
||||
std::string m_EmptyString;
|
||||
std::map<std::string, std::string> m_ConfigValues;
|
||||
std::string m_ConfigFilePath;
|
||||
};
|
||||
|
||||
@@ -1,17 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __DCOMMONVARS__H__
|
||||
#define __DCOMMONVARS__H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "../thirdparty/raknet/Source/BitStream.h"
|
||||
#include "BitStream.h"
|
||||
|
||||
#pragma warning (disable:4251) //Disables SQL warnings
|
||||
|
||||
typedef int RESTICKET;
|
||||
|
||||
const int highFrameRate = 16; //60fps
|
||||
const int mediumFramerate = 33; //30fps
|
||||
const int lowFramerate = 66; //15fps
|
||||
// These are the same define, but they mean two different things in different contexts
|
||||
// so a different define to distinguish what calculation is happening will help clarity.
|
||||
#define FRAMES_TO_MS(x) 1000 / x
|
||||
#define MS_TO_FRAMES(x) 1000 / x
|
||||
|
||||
//=========== FRAME TIMINGS ===========
|
||||
constexpr uint32_t highFramerate = 60;
|
||||
constexpr uint32_t mediumFramerate = 30;
|
||||
constexpr uint32_t lowFramerate = 15;
|
||||
|
||||
constexpr uint32_t highFrameDelta = FRAMES_TO_MS(highFramerate);
|
||||
constexpr uint32_t mediumFrameDelta = FRAMES_TO_MS(mediumFramerate);
|
||||
constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
|
||||
|
||||
//========== MACROS ===========
|
||||
|
||||
@@ -30,6 +43,7 @@ typedef uint32_t LWOCLONEID; //!< Used for Clone IDs
|
||||
typedef uint16_t LWOMAPID; //!< Used for Map IDs
|
||||
typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs
|
||||
typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs
|
||||
typedef uint32_t StripId;
|
||||
|
||||
typedef int32_t PetTamingPiece; //!< Pet Taming Pieces
|
||||
|
||||
@@ -50,11 +64,6 @@ typedef std::set<LWOOBJID> TSetObjID;
|
||||
|
||||
const float PI = 3.14159f;
|
||||
|
||||
#if defined(__unix) || defined(__APPLE__)
|
||||
//For Linux:
|
||||
typedef __int64_t __int64;
|
||||
#endif
|
||||
|
||||
//============ STRUCTS ==============
|
||||
|
||||
struct LWOSCENEID {
|
||||
@@ -247,20 +256,6 @@ enum eReplicaPacketType {
|
||||
PACKET_TYPE_DESTRUCTION //!< A destruction packet
|
||||
};
|
||||
|
||||
enum ServerDisconnectIdentifiers {
|
||||
SERVER_DISCON_UNKNOWN_SERVER_ERROR = 0, //!< Unknown server error
|
||||
SERVER_DISCON_DUPLICATE_LOGIN = 4, //!< Used when another user with the same username is logged in (duplicate login)
|
||||
SERVER_DISCON_SERVER_SHUTDOWN = 5, //!< Used when the server is shutdown
|
||||
SERVER_DISCON_SERVER_MAP_LOAD_FAILURE = 6, //!< Used when the server cannot load a map
|
||||
SERVER_DISCON_INVALID_SESSION_KEY = 7, //!< Used if the session is invalid
|
||||
SERVER_DISCON_ACCOUNT_NOT_IN_PENDING_LIST = 8, //!< ???
|
||||
SERVER_DISCON_CHARACTER_NOT_FOUND = 9, //!< Used if a character that the server has is not found (i.e, corruption with user-player data)
|
||||
SERVER_DISCON_CHARACTER_CORRUPTED = 10, //!< Similar to abovce
|
||||
SERVER_DISCON_KICK = 11, //!< Used if the user is kicked from the server
|
||||
SERVER_DISCON_FREE_TRIAL_EXPIRED = 12, //!< Used if the user's free trial expired
|
||||
SERVER_DISCON_PLAY_SCHEDULE_TIME_DONE = 13 //!< Used if the user's play time is used up
|
||||
};
|
||||
|
||||
//! The Behavior Types for use with the AI system
|
||||
enum eCombatBehaviorTypes : uint32_t {
|
||||
PASSIVE = 0, //!< The object is passive
|
||||
@@ -351,7 +346,7 @@ enum eControlSceme {
|
||||
SCHEME_WEAR_A_ROBOT //== freecam?
|
||||
};
|
||||
|
||||
enum eStunState {
|
||||
enum class eStateChangeType : uint32_t {
|
||||
PUSH,
|
||||
POP
|
||||
};
|
||||
@@ -365,56 +360,6 @@ enum eNotifyType {
|
||||
NOTIFY_TYPE_NAMINGPET
|
||||
};
|
||||
|
||||
enum eReplicaComponentType : int32_t {
|
||||
COMPONENT_TYPE_CONTROLLABLE_PHYSICS = 1, //!< The ControllablePhysics Component
|
||||
COMPONENT_TYPE_RENDER = 2, //!< The Render Component
|
||||
COMPONENT_TYPE_SIMPLE_PHYSICS = 3, //!< The SimplePhysics Component
|
||||
COMPONENT_TYPE_CHARACTER = 4, //!< The Character Component
|
||||
COMPONENT_TYPE_SCRIPT = 5, //!< The Script Component
|
||||
COMPONENT_TYPE_BOUNCER = 6, //!< The Bouncer Component
|
||||
COMPONENT_TYPE_BUFF = 7, //!< The Buff Component
|
||||
COMPONENT_TYPE_SKILL = 9, //!< The Skill Component
|
||||
COMPONENT_TYPE_ITEM = 11, //!< The Item Component
|
||||
COMPONENT_TYPE_VENDOR = 16, //!< The Vendor Component
|
||||
COMPONENT_TYPE_INVENTORY = 17, //!< The Inventory Component
|
||||
COMPONENT_TYPE_SHOOTING_GALLERY = 19, //!< The Shooting Gallery Component
|
||||
COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS = 20, //!< The RigidBodyPhantomPhysics Component
|
||||
COMPONENT_TYPE_COLLECTIBLE = 23, //!< The Collectible Component
|
||||
COMPONENT_TYPE_MOVING_PLATFORM = 25, //!< The MovingPlatform Component
|
||||
COMPONENT_TYPE_PET = 26, //!< The Pet Component
|
||||
COMPONENT_TYPE_VEHICLE_PHYSICS = 30, //!< The VehiclePhysics Component
|
||||
COMPONENT_TYPE_MOVEMENT_AI = 31, //!< The MovementAI Component
|
||||
COMPONENT_TYPE_PROPERTY = 36, //!< The Property Component
|
||||
COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39, //!< The ScriptedActivity Component
|
||||
COMPONENT_TYPE_PHANTOM_PHYSICS = 40, //!< The PhantomPhysics Component
|
||||
COMPONENT_TYPE_MODEL = 42, //!< The Model Component
|
||||
COMPONENT_TYPE_PROPERTY_ENTRANCE = 43, //!< The PhantomPhysics Component
|
||||
COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45, //!< The PropertyManagement Component
|
||||
COMPONENT_TYPE_REBUILD = 48, //!< The Rebuild Component
|
||||
COMPONENT_TYPE_SWITCH = 49, //!< The Switch Component
|
||||
COMPONENT_TYPE_ZONE_CONTROL = 50, //!< The ZoneControl Component
|
||||
COMPONENT_TYPE_PACKAGE = 53, //!< The Package Component
|
||||
COMPONENT_TYPE_PLAYER_FLAG = 58, //!< The PlayerFlag Component
|
||||
COMPONENT_TYPE_BASE_COMBAT_AI = 60, //!< The BaseCombatAI Component
|
||||
COMPONENT_TYPE_MODULE_ASSEMBLY = 61, //!< The ModuleAssembly Component
|
||||
COMPONENT_TYPE_PROPERTY_VENDOR = 65, //!< The PropertyVendor Component
|
||||
COMPONENT_TYPE_ROCKET_LAUNCH = 67, //!< The RocketLaunch Component
|
||||
COMPONENT_TYPE_RACING_CONTROL = 71, //!< The RacingControl Component
|
||||
COMPONENT_TYPE_MISSION_OFFER = 73, //!< The MissionOffer Component
|
||||
COMPONENT_TYPE_EXHIBIT = 75, //!< The Exhibit Component
|
||||
COMPONENT_TYPE_RACING_STATS = 74, //!< The Racing Stats Component
|
||||
COMPONENT_TYPE_SOUND_TRIGGER = 77, //!< The Sound Trigger Component
|
||||
COMPONENT_TYPE_PROXIMITY_MONITOR = 78, //!< The Proximity Monitor Component
|
||||
COMPONENT_TYPE_MISSION = 84, //!< The Mission Component
|
||||
COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen
|
||||
COMPONENT_TYPE_RAIL_ACTIVATOR = 104, //!< The Rail Activator Component
|
||||
COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT = 106, //!< The Player Forced Movement Component
|
||||
COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component
|
||||
COMPONENT_TYPE_LEVEL_PROGRESSION = 109, //!< The Level Progression Component
|
||||
COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component
|
||||
COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component
|
||||
COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component
|
||||
};
|
||||
|
||||
enum class UseItemResponse : uint32_t {
|
||||
NoImaginationForPet = 1,
|
||||
@@ -422,25 +367,6 @@ enum class UseItemResponse : uint32_t {
|
||||
MountsNotAllowed
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents the different types of inventories an entity may have
|
||||
*/
|
||||
enum eInventoryType : uint32_t {
|
||||
ITEMS = 0,
|
||||
VAULT_ITEMS,
|
||||
BRICKS,
|
||||
TEMP_ITEMS = 4,
|
||||
MODELS,
|
||||
TEMP_MODELS,
|
||||
BEHAVIORS,
|
||||
PROPERTY_DEEDS,
|
||||
VENDOR_BUYBACK = 11,
|
||||
HIDDEN = 12, //Used for missional items
|
||||
VAULT_MODELS = 14,
|
||||
ITEM_SETS, //internal
|
||||
INVALID // made up, for internal use!!!
|
||||
};
|
||||
|
||||
enum eRebuildState : uint32_t {
|
||||
REBUILD_OPEN,
|
||||
REBUILD_COMPLETED = 2,
|
||||
@@ -554,6 +480,7 @@ enum ePlayerFlags {
|
||||
ENTER_BBB_FROM_PROPERTY_EDIT_CONFIRMATION_DIALOG = 64,
|
||||
AG_FIRST_COMBAT_COMPLETE = 65,
|
||||
AG_COMPLETE_BOB_MISSION = 66,
|
||||
IS_NEWS_SCREEN_VISIBLE = 114,
|
||||
NJ_GARMADON_CINEMATIC_SEEN = 125,
|
||||
ELEPHANT_PET_3050 = 801,
|
||||
CAT_PET_3054 = 802,
|
||||
@@ -648,3 +575,5 @@ inline T const& clamp(const T& val, const T& low, const T& high) {
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#endif //!__DCOMMONVARS__H__
|
||||
@@ -293,6 +293,7 @@ enum GAME_MSG : unsigned short {
|
||||
GAME_MSG_POP_EQUIPPED_ITEMS_STATE = 192,
|
||||
GAME_MSG_SET_GM_LEVEL = 193,
|
||||
GAME_MSG_SET_STUNNED = 198,
|
||||
GAME_MSG_SET_STUN_IMMUNITY = 200,
|
||||
GAME_MSG_KNOCKBACK = 202,
|
||||
GAME_MSG_REBUILD_CANCEL = 209,
|
||||
GAME_MSG_ENABLE_REBUILD = 213,
|
||||
@@ -373,6 +374,8 @@ enum GAME_MSG : unsigned short {
|
||||
GAME_MSG_PET_TAMING_TRY_BUILD_RESULT = 668,
|
||||
GAME_MSG_NOTIFY_TAMING_BUILD_SUCCESS = 673,
|
||||
GAME_MSG_NOTIFY_TAMING_MODEL_LOADED_ON_SERVER = 674,
|
||||
GAME_MSG_ACTIVATE_BUBBLE_BUFF = 678,
|
||||
GAME_MSG_DEACTIVATE_BUBBLE_BUFF = 679,
|
||||
GAME_MSG_ADD_PET_TO_PLAYER = 681,
|
||||
GAME_MSG_REQUEST_SET_PET_NAME = 683,
|
||||
GAME_MSG_SET_PET_NAME = 684,
|
||||
@@ -385,7 +388,10 @@ enum GAME_MSG : unsigned short {
|
||||
GAME_MSG_QUERY_PROPERTY_DATA = 717,
|
||||
GAME_MSG_PROPERTY_EDITOR_BEGIN = 724,
|
||||
GAME_MSG_PROPERTY_EDITOR_END = 725,
|
||||
GAME_MSG_START_PATHING = 735,
|
||||
GAME_MSG_IS_MINIFIG_IN_A_BUBBLE = 729,
|
||||
GAME_MSG_START_PATHING = 733,
|
||||
GAME_MSG_ACTIVATE_BUBBLE_BUFF_FROM_SERVER = 734,
|
||||
GAME_MSG_DEACTIVATE_BUBBLE_BUFF_FROM_SERVER = 735,
|
||||
GAME_MSG_NOTIFY_CLIENT_ZONE_OBJECT = 737,
|
||||
GAME_MSG_UPDATE_REPUTATION = 746,
|
||||
GAME_MSG_PROPERTY_RENTAL_RESPONSE = 750,
|
||||
@@ -433,6 +439,7 @@ enum GAME_MSG : unsigned short {
|
||||
GAME_MSG_ORIENT_TO_POSITION = 906,
|
||||
GAME_MSG_ORIENT_TO_ANGLE = 907,
|
||||
GAME_MSG_BOUNCER_ACTIVE_STATUS = 942,
|
||||
GAME_MSG_UN_USE_BBB_MODEL = 999,
|
||||
GAME_MSG_BBB_LOAD_ITEM_REQUEST = 1000,
|
||||
GAME_MSG_BBB_SAVE_REQUEST = 1001,
|
||||
GAME_MSG_BBB_SAVE_RESPONSE = 1006,
|
||||
@@ -487,6 +494,7 @@ enum GAME_MSG : unsigned short {
|
||||
GAME_MSG_MATCH_UPDATE = 1310,
|
||||
GAME_MSG_MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131,
|
||||
GAME_MSG_MODULE_ASSEMBLY_QUERY_DATA = 1132,
|
||||
GAME_MSG_CHANGE_IDLE_FLAGS = 1338,
|
||||
GAME_MSG_VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340,
|
||||
GAME_MSG_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341,
|
||||
GAME_MSG_VEHICLE_NOTIFY_SERVER_ADD_PASSIVE_BOOST_ACTION = 1342,
|
||||
@@ -510,6 +518,7 @@ enum GAME_MSG : unsigned short {
|
||||
GAME_MSG_UPDATE_CHAT_MODE = 1395,
|
||||
GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE = 1396,
|
||||
GAME_MSG_SET_CONSUMABLE_ITEM = 1409,
|
||||
GAME_MSG_SET_STATUS_IMMUNITY = 1435,
|
||||
GAME_MSG_SET_PET_NAME_MODERATED = 1448,
|
||||
GAME_MSG_MODIFY_LEGO_SCORE = 1459,
|
||||
GAME_MSG_RESTORE_TO_POST_LOAD_STATS = 1468,
|
||||
@@ -537,6 +546,9 @@ enum GAME_MSG : unsigned short {
|
||||
GAME_MSG_REMOVE_RUN_SPEED_MODIFIER = 1506,
|
||||
GAME_MSG_UPDATE_PROPERTY_PERFORMANCE_COST = 1547,
|
||||
GAME_MSG_PROPERTY_ENTRANCE_BEGIN = 1553,
|
||||
GAME_MSG_SET_RESURRECT_RESTORE_VALUES = 1591,
|
||||
GAME_MSG_VEHICLE_STOP_BOOST = 1617,
|
||||
GAME_MSG_REMOVE_BUFF = 1648,
|
||||
GAME_MSG_REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666,
|
||||
GAME_MSG_RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667,
|
||||
GAME_MSG_PLAYER_SET_CAMERA_CYCLING_MODE = 1676,
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __ADDFRIENDRESPONSECODE__H__
|
||||
#define __ADDFRIENDRESPONSECODE__H__
|
||||
#ifndef __EADDFRIENDRESPONSECODE__H__
|
||||
#define __EADDFRIENDRESPONSECODE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class AddFriendResponseCode : uint8_t {
|
||||
enum class eAddFriendResponseCode : uint8_t {
|
||||
ACCEPTED = 0,
|
||||
REJECTED,
|
||||
BUSY,
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __ADDFRIENDRESPONSETYPE__H__
|
||||
#define __ADDFRIENDRESPONSETYPE__H__
|
||||
#ifndef __EADDFRIENDRESPONSETYPE__H__
|
||||
#define __EADDFRIENDRESPONSETYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class AddFriendResponseType : uint8_t {
|
||||
enum class eAddFriendResponseType : uint8_t {
|
||||
ACCEPTED = 0,
|
||||
ALREADYFRIEND,
|
||||
INVALIDCHARACTER,
|
||||
@@ -21,4 +21,4 @@ enum class AddFriendResponseType : uint8_t {
|
||||
FRIENDISFREETRIAL
|
||||
};
|
||||
|
||||
#endif //!__ADDFRIENDRESPONSETYPE__H__
|
||||
#endif //!__EADDFRIENDRESPONSETYPE__H__
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
enum class eAnimationFlags : uint32_t {
|
||||
IDLE_INVALID = 0, // made up, for internal use!!!
|
||||
IDLE_NONE = 0,
|
||||
IDLE_BASIC,
|
||||
IDLE_SWIM,
|
||||
IDLE_CARRY,
|
||||
12
dCommon/dEnums/eBasicAttackSuccessTypes.h
Normal file
12
dCommon/dEnums/eBasicAttackSuccessTypes.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef __EBASICATTACKSUCCESSTYPES__H__
|
||||
#define __EBASICATTACKSUCCESSTYPES__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eBasicAttackSuccessTypes : uint8_t {
|
||||
SUCCESS = 1,
|
||||
FAILARMOR,
|
||||
FAILIMMUNE
|
||||
};
|
||||
|
||||
#endif //!__EBASICATTACKSUCCESSTYPES__H__
|
||||
26
dCommon/dEnums/eBlueprintSaveResponseType.h
Normal file
26
dCommon/dEnums/eBlueprintSaveResponseType.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EBLUEPRINTSAVERESPONSETYPE__H__
|
||||
#define __EBLUEPRINTSAVERESPONSETYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eBlueprintSaveResponseType : uint32_t {
|
||||
EverythingWorked = 0,
|
||||
SaveCancelled,
|
||||
CantBeginTransaction,
|
||||
SaveBlueprintFailed,
|
||||
SaveUgobjectFailed,
|
||||
CantEndTransaction,
|
||||
SaveFilesFailed,
|
||||
BadInput,
|
||||
NotEnoughBricks,
|
||||
InventoryFull,
|
||||
ModelGenerationFailed,
|
||||
PlacementFailed,
|
||||
GmLevelInsufficient,
|
||||
WaitForPreviousSave,
|
||||
FindMatchesFailed
|
||||
};
|
||||
|
||||
#endif //!__EBLUEPRINTSAVERESPONSETYPE__H__
|
||||
14
dCommon/dEnums/eBubbleType.h
Normal file
14
dCommon/dEnums/eBubbleType.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EBUBBLETYPE__H__
|
||||
#define __EBUBBLETYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eBubbleType : uint32_t {
|
||||
DEFAULT = 0,
|
||||
ENERGY,
|
||||
SKUNK
|
||||
};
|
||||
|
||||
#endif //!__EBUBBLETYPE__H__
|
||||
21
dCommon/dEnums/eCharacterVersion.h
Normal file
21
dCommon/dEnums/eCharacterVersion.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __ECHARACTERVERSION__H__
|
||||
#define __ECHARACTERVERSION__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eCharacterVersion : uint32_t {
|
||||
// Versions from the live game
|
||||
RELEASE = 0, // Initial release of the game
|
||||
LIVE, // Fixes for the 1.9 release bug fixes for missions leading up to joining a faction
|
||||
// New versions for DLU fixes
|
||||
// Fixes the "Joined a faction" player flag not being set properly
|
||||
PLAYER_FACTION_FLAGS,
|
||||
// Fixes vault size value
|
||||
VAULT_SIZE,
|
||||
// Fixes speed base value in level component
|
||||
UP_TO_DATE, // will become SPEED_BASE
|
||||
};
|
||||
|
||||
#endif //!__ECHARACTERVERSION__H__
|
||||
41
dCommon/dEnums/eHelpType.h
Normal file
41
dCommon/dEnums/eHelpType.h
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
#ifndef __EHELPTYPE__H__
|
||||
#define __EHELPTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eHelpType : int32_t {
|
||||
NONE = 0,
|
||||
UNLOCK_MINIMAP = 2,
|
||||
TOGGLETOOLTIP_OUTOFTIME_REBUILD = 3,
|
||||
TOGGLETOOLTIP_LEAVELOSE_REBUILD = 4,
|
||||
TOGGLECONTROLSTUTORIAL_WALKING = 6,
|
||||
DISPLAYTUTORIAL_PASSPORT_1ST_SMASH = 7,
|
||||
TOOLTIP_1ST_IMAGINATION_PICKUP = 8,
|
||||
UNKNOWN9 = 9,
|
||||
PETTAMINGMINIGAME_TUTORIAL_01 = 15,
|
||||
PR_BOUNCER_TUTORIAL_03 = 16,
|
||||
PR_TOOLTIP_1ST_PET_JUMPED_ON_SWITCH = 17,
|
||||
PR_DIG_TUTORIAL_01 = 18,
|
||||
PR_DIG_TUTORIAL_03 = 19,
|
||||
PR_BOUNCER_TUTORIAL_01 = 20,
|
||||
PR_NO_IMAGINATION_HIBERNATE = 21,
|
||||
UNKNOWN22 = 22,
|
||||
TOGGLECONTROLSTUTORIAL_JUMPING = 26,
|
||||
TOGGLECONTROLSTUTORIAL_DOUBLEJUMPING = 27,
|
||||
TOGGLECONTROLSTUTORIAL_CAMERA = 28,
|
||||
TOGGLECONTROLSTUTORIAL_SMASH = 30,
|
||||
UNKNOWN38 = 38,
|
||||
UI_MOD_BUILD_PUT_ON_HAT = 40,
|
||||
UI_MOD_BUILD_EQUIP_FIRST_MODULE = 41,
|
||||
UNKNOWN42 = 42,
|
||||
UNKNOWN43 = 43,
|
||||
UI_MOD_BUILD_GO_LAUNCH_ROCKET = 44,
|
||||
UI_MOD_BUILD_TALK_TO_SKYLANE = 45,
|
||||
UNKNOWN53 = 53,
|
||||
PET_DESPAWN_BY_OWNER_HIBERNATE = 69,
|
||||
PET_DESPAWN_TAMING_NEW_PET = 70,
|
||||
UI_INVENTORY_FULL_CANNOT_PICKUP_ITEM = 86
|
||||
};
|
||||
|
||||
#endif //!__EHELPTYPE__H__
|
||||
59
dCommon/dEnums/eInventoryType.h
Normal file
59
dCommon/dEnums/eInventoryType.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EINVENTORYTYPE__H__
|
||||
#define __EINVENTORYTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
static const uint8_t NUMBER_OF_INVENTORIES = 17;
|
||||
/**
|
||||
* Represents the different types of inventories an entity may have
|
||||
*/
|
||||
enum eInventoryType : uint32_t {
|
||||
ITEMS = 0,
|
||||
VAULT_ITEMS,
|
||||
BRICKS,
|
||||
MODELS_IN_BBB,
|
||||
TEMP_ITEMS,
|
||||
MODELS,
|
||||
TEMP_MODELS,
|
||||
BEHAVIORS,
|
||||
PROPERTY_DEEDS,
|
||||
BRICKS_IN_BBB,
|
||||
VENDOR,
|
||||
VENDOR_BUYBACK,
|
||||
QUEST, //Used for mission items
|
||||
DONATION,
|
||||
VAULT_MODELS,
|
||||
ITEM_SETS, //internal, technically this is BankBehaviors.
|
||||
INVALID // made up, for internal use!!!, Technically this called the ALL inventory.
|
||||
};
|
||||
|
||||
class InventoryType {
|
||||
public:
|
||||
static const char* InventoryTypeToString(eInventoryType inventory) {
|
||||
const char* eInventoryTypeTable[NUMBER_OF_INVENTORIES] = {
|
||||
"ITEMS",
|
||||
"VAULT_ITEMS",
|
||||
"BRICKS",
|
||||
"MODELS_IN_BBB",
|
||||
"TEMP_ITEMS",
|
||||
"MODELS",
|
||||
"TEMP_MODELS",
|
||||
"BEHAVIORS",
|
||||
"PROPERTY_DEEDS",
|
||||
"BRICKS_IN_BBB",
|
||||
"VENDOR",
|
||||
"VENDOR_BUYBACK",
|
||||
"QUEST", //Used for mission items
|
||||
"DONATION",
|
||||
"VAULT_MODELS",
|
||||
"ITEM_SETS", //internal, technically this is BankBehaviors.
|
||||
"INVALID" // made up, for internal use!!!, Technically this called the ALL inventory.
|
||||
};
|
||||
|
||||
if (inventory > NUMBER_OF_INVENTORIES - 1) return nullptr;
|
||||
return eInventoryTypeTable[inventory];
|
||||
};
|
||||
};
|
||||
|
||||
#endif //!__EINVENTORYTYPE__H__
|
||||
58
dCommon/dEnums/eItemSetPassiveAbilityID.h
Normal file
58
dCommon/dEnums/eItemSetPassiveAbilityID.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EITEMSETPASSIVEABILITYID__H__
|
||||
#define __EITEMSETPASSIVEABILITYID__H__
|
||||
|
||||
enum class eItemSetPassiveAbilityID {
|
||||
EngineerRank1 = 2,
|
||||
EngineerRank2 = 3,
|
||||
EngineerRank3 = 4,
|
||||
KnightRank1 = 7,
|
||||
KnightRank2 = 8,
|
||||
KnightRank3 = 9,
|
||||
SpaceRangerRank1 = 10,
|
||||
SpaceRangerRank2 = 11,
|
||||
SpaceRangerRank3 = 12,
|
||||
SamuraiRank1 = 13,
|
||||
SamuraiRank2 = 14,
|
||||
SamuraiRank3 = 15,
|
||||
SorcererRank1 = 16,
|
||||
SorcererRank2 = 17,
|
||||
SorcererRank3 = 18,
|
||||
SpaceMarauderRank1 = 19,
|
||||
SpaceMarauderRank2 = 20,
|
||||
SpaceMarauderRank3 = 21,
|
||||
ShinobiRank1 = 22,
|
||||
ShinobiRank2 = 23,
|
||||
ShinobiRank3 = 24,
|
||||
InventorRank1 = 25,
|
||||
InventorRank2 = 26,
|
||||
InventorRank3 = 27,
|
||||
SummonerRank1 = 28,
|
||||
SummonerRank2 = 29,
|
||||
SummonerRank3 = 30,
|
||||
AdventurerRank1 = 31,
|
||||
AdventurerRank2 = 32,
|
||||
AdventurerRank3 = 33,
|
||||
DaredevilRank1 = 34,
|
||||
DaredevilRank2 = 35,
|
||||
DaredevilRank3 = 36,
|
||||
BuccaneerRank1 = 37,
|
||||
BuccaneerRank2 = 38,
|
||||
BuccaneerRank3 = 39,
|
||||
BoneSuit = 40,
|
||||
ImaginationSpinjitzu = 41,
|
||||
BatLord = 42,
|
||||
MosaicJester = 43,
|
||||
ExplorienBot = 44,
|
||||
Unnamed1 = 45,
|
||||
Unnamed2 = 46,
|
||||
Unnamed3 = 47,
|
||||
EarthSpinjitzu = 48,
|
||||
Unnamed4 = 49,
|
||||
FireSpinjitzu = 50,
|
||||
IceSpinjitzu = 51,
|
||||
LightningSpinjitzu = 52
|
||||
};
|
||||
|
||||
#endif //!__EITEMSETPASSIVEABILITYID__H__
|
||||
36
dCommon/dEnums/eItemType.h
Normal file
36
dCommon/dEnums/eItemType.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EITEMTYPE__H__
|
||||
#define __EITEMTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eItemType : int32_t {
|
||||
UNKNOWN = -1,
|
||||
BRICK = 1,
|
||||
HAT,
|
||||
HAIR,
|
||||
NECK,
|
||||
LEFT_HAND,
|
||||
RIGHT_HAND,
|
||||
LEGS,
|
||||
LEFT_TRINKET,
|
||||
RIGHT_TRINKET,
|
||||
BEHAVIOR,
|
||||
PROPERTY,
|
||||
MODEL,
|
||||
COLLECTIBLE,
|
||||
CONSUMABLE,
|
||||
CHEST,
|
||||
EGG,
|
||||
PET_FOOD,
|
||||
QUEST_OBJECT,
|
||||
PET_INVENTORY_ITEM,
|
||||
PACKAGE,
|
||||
LOOT_MODEL,
|
||||
VEHICLE,
|
||||
LUP_MODEL,
|
||||
MOUNT
|
||||
};
|
||||
|
||||
#endif //!__EITEMTYPE__H__
|
||||
12
dCommon/dEnums/eMissionLockState.h
Normal file
12
dCommon/dEnums/eMissionLockState.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EMISSIONLOCKSTATE__H__
|
||||
#define __EMISSIONLOCKSTATE__H__
|
||||
|
||||
enum class eMissionLockState : int {
|
||||
LOCKED,
|
||||
NEW,
|
||||
UNLOCKED,
|
||||
};
|
||||
|
||||
#endif //!__EMISSIONLOCKSTATE__H__
|
||||
56
dCommon/dEnums/eMissionState.h
Normal file
56
dCommon/dEnums/eMissionState.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __MISSIONSTATE__H__
|
||||
#define __MISSIONSTATE__H__
|
||||
|
||||
/**
|
||||
* Represents the possible states a mission can be in
|
||||
*/
|
||||
enum class eMissionState : int {
|
||||
/**
|
||||
* The mission state is unknown
|
||||
*/
|
||||
UNKNOWN = -1,
|
||||
|
||||
/**
|
||||
* The mission is yielding rewards
|
||||
*/
|
||||
REWARDING = 0,
|
||||
|
||||
/**
|
||||
* The mission can be accepted
|
||||
*/
|
||||
AVAILABLE = 1,
|
||||
|
||||
/**
|
||||
* The mission has been accepted but not yet completed
|
||||
*/
|
||||
ACTIVE = 2,
|
||||
|
||||
/**
|
||||
* All the tasks for the mission have been completed and the entity can turn the mission in to complete it
|
||||
*/
|
||||
READY_TO_COMPLETE = 4, //!< The mission is ready to complete
|
||||
|
||||
/**
|
||||
* The mission has been completed
|
||||
*/
|
||||
COMPLETE = 8,
|
||||
|
||||
/**
|
||||
* The mission is available again and has been completed before. Used for daily missions.
|
||||
*/
|
||||
COMPLETE_AVAILABLE = 9,
|
||||
|
||||
/**
|
||||
* The mission is active and has been completed before. Used for daily missions.
|
||||
*/
|
||||
COMPLETE_ACTIVE = 10,
|
||||
|
||||
/**
|
||||
* The mission has been completed before and has now been completed again. Used for daily missions.
|
||||
*/
|
||||
COMPLETE_READY_TO_COMPLETE = 12
|
||||
};
|
||||
|
||||
#endif //!__MISSIONSTATE__H__
|
||||
43
dCommon/dEnums/eMissionTaskType.h
Normal file
43
dCommon/dEnums/eMissionTaskType.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EMISSIONTASKTYPE__H__
|
||||
#define __EMISSIONTASKTYPE__H__
|
||||
|
||||
enum class eMissionTaskType : int {
|
||||
UNKNOWN = -1,
|
||||
SMASH,
|
||||
SCRIPT,
|
||||
ACTIVITY,
|
||||
COLLECTION,
|
||||
TALK_TO_NPC,
|
||||
EMOTE,
|
||||
SHASH_CHAIN,
|
||||
BUY,
|
||||
SELL,
|
||||
USE_ITEM,
|
||||
USE_SKILL,
|
||||
GATHER,
|
||||
EXPLORE,
|
||||
DELIVERY,
|
||||
PERFORM_ACTIVITY,
|
||||
INTERACT,
|
||||
META,
|
||||
EARN_REPUTATION,
|
||||
VOTING,
|
||||
SHOWCASE_DELIVERY,
|
||||
REVIECE_CAST,
|
||||
POWERUP,
|
||||
PET_TAMING,
|
||||
RACING,
|
||||
PLAYER_FLAG,
|
||||
PLACE_MODEL,
|
||||
REMOVE_MODEL,
|
||||
ADD_BEHAVIOR,
|
||||
REMOVE_BEHAVIOR,
|
||||
CLAIM_PROPERTY,
|
||||
VISIT_PROPERTY,
|
||||
TIME_PLAYED,
|
||||
DONATION
|
||||
};
|
||||
|
||||
#endif //!__EMISSIONTASKTYPE__H__
|
||||
16
dCommon/dEnums/eMovementPlatformState.h
Normal file
16
dCommon/dEnums/eMovementPlatformState.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef __EMOVEMENTPLATFORMSTATE__H__
|
||||
#define __EMOVEMENTPLATFORMSTATE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* The different types of platform movement state, supposedly a bitmap
|
||||
*/
|
||||
enum class eMovementPlatformState : uint32_t
|
||||
{
|
||||
Moving = 0b00010,
|
||||
Stationary = 0b11001,
|
||||
Stopped = 0b01100
|
||||
};
|
||||
|
||||
#endif //!__EMOVEMENTPLATFORMSTATE__H__
|
||||
13
dCommon/dEnums/ePackageType.h
Normal file
13
dCommon/dEnums/ePackageType.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __EPACKAGETYPE__H__
|
||||
#define __EPACKAGETYPE__H__
|
||||
|
||||
enum class ePackageType {
|
||||
INVALID = -1,
|
||||
ITEM,
|
||||
BRICKS,
|
||||
MODELS,
|
||||
CAR_MODELS
|
||||
};
|
||||
|
||||
|
||||
#endif //!__EPACKAGETYPE__H__
|
||||
46
dCommon/dEnums/ePermissionMap.h
Normal file
46
dCommon/dEnums/ePermissionMap.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef __EPERMISSIONMAP__H__
|
||||
#define __EPERMISSIONMAP__H__
|
||||
|
||||
/**
|
||||
* Bitmap of permissions and restrictions for characters.
|
||||
*/
|
||||
enum class ePermissionMap : uint64_t {
|
||||
/**
|
||||
* Reserved for future use, bit 0-3.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The character has restricted trade acccess, bit 4.
|
||||
*/
|
||||
RestrictedTradeAccess = 0x1 << 4,
|
||||
|
||||
/**
|
||||
* The character has restricted mail access, bit 5.
|
||||
*/
|
||||
RestrictedMailAccess = 0x1 << 5,
|
||||
|
||||
/**
|
||||
* The character has restricted chat access, bit 6.
|
||||
*/
|
||||
RestrictedChatAccess = 0x1 << 6,
|
||||
|
||||
//
|
||||
// Combined permissions
|
||||
//
|
||||
|
||||
/**
|
||||
* The character is marked as 'old', restricted from trade and mail.
|
||||
*/
|
||||
Old = RestrictedTradeAccess | RestrictedMailAccess,
|
||||
|
||||
/**
|
||||
* The character is soft banned, restricted from trade, mail, and chat.
|
||||
*/
|
||||
SoftBanned = RestrictedTradeAccess | RestrictedMailAccess | RestrictedChatAccess,
|
||||
};
|
||||
|
||||
#endif //!__EPERMISSIONMAP__H__
|
||||
14
dCommon/dEnums/ePhysicsBehaviorType.h
Normal file
14
dCommon/dEnums/ePhysicsBehaviorType.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef __EPHYSICSBEHAVIORTYPE__H__
|
||||
#define __EPHYSICSBEHAVIORTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class ePhysicsBehaviorType : int32_t {
|
||||
INVALID = -1,
|
||||
GROUND,
|
||||
FLYING,
|
||||
STANDARD,
|
||||
DYNAMIC
|
||||
};
|
||||
|
||||
#endif //!__EPHYSICSBEHAVIORTYPE__H__
|
||||
25
dCommon/dEnums/eRacingTaskParam.h
Normal file
25
dCommon/dEnums/eRacingTaskParam.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __ERACINGTASKPARAM__H__
|
||||
#define __ERACINGTASKPARAM__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eRacingTaskParam : int32_t {
|
||||
FINISH_WITH_PLACEMENT = 1,
|
||||
LAP_TIME,
|
||||
TOTAL_TRACK_TIME,
|
||||
COMPLETE_ANY_RACING_TASK,
|
||||
COMPLETE_TRACK_TASKS,
|
||||
MODULAR_BUILDING,
|
||||
SAFE_DRIVER = 10,
|
||||
SMASHABLES,
|
||||
COLLECT_IMAGINATION,
|
||||
COMPETED_IN_RACE,
|
||||
WIN_RACE_IN_WORLD,
|
||||
FIRST_PLACE_MULTIPLE_TRACKS,
|
||||
LAST_PLACE_FINISH,
|
||||
SMASH_SPECIFIC_SMASHABLE
|
||||
};
|
||||
|
||||
#endif //!__ERACINGTASKPARAM__H__
|
||||
127
dCommon/dEnums/eReplicaComponentType.h
Normal file
127
dCommon/dEnums/eReplicaComponentType.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#ifndef __EREPLICACOMPONENTTYPE__H__
|
||||
#define __EREPLICACOMPONENTTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eReplicaComponentType : uint32_t {
|
||||
INVALID = 0,
|
||||
CONTROLLABLE_PHYSICS,
|
||||
RENDER,
|
||||
SIMPLE_PHYSICS,
|
||||
CHARACTER,
|
||||
SCRIPT,
|
||||
BOUNCER,
|
||||
BUFF, // buff is really 98, this is DESTROYABLE
|
||||
GHOST,
|
||||
SKILL,
|
||||
SPAWNER,
|
||||
ITEM,
|
||||
REBUILD,
|
||||
REBUILD_START,
|
||||
REBUILD_ACTIVATOR,
|
||||
ICON_ONLY,
|
||||
VENDOR,
|
||||
INVENTORY,
|
||||
PROJECTILE_PHYSICS,
|
||||
SHOOTING_GALLERY,
|
||||
RIGID_BODY_PHANTOM_PHYSICS,
|
||||
DROP_EFFECT,
|
||||
CHEST,
|
||||
COLLECTIBLE,
|
||||
BLUEPRINT,
|
||||
MOVING_PLATFORM,
|
||||
PET,
|
||||
PLATFORM_BOUNDARY,
|
||||
MODULE,
|
||||
ARCADE,
|
||||
VEHICLE_PHYSICS, // Havok demo based
|
||||
MOVEMENT_AI,
|
||||
EXHIBIT,
|
||||
OVERHEAD_ICON,
|
||||
PET_CONTROL,
|
||||
MINIFIG,
|
||||
PROPERTY,
|
||||
PET_CREATOR,
|
||||
MODEL_BUILDER,
|
||||
SCRIPTED_ACTIVITY,
|
||||
PHANTOM_PHYSICS,
|
||||
SPRINGPAD,
|
||||
MODEL,
|
||||
PROPERTY_ENTRANCE,
|
||||
FX,
|
||||
PROPERTY_MANAGEMENT,
|
||||
VEHICLE_PHYSICS_NEW, // internal physics based on havok
|
||||
PHYSICS_SYSTEM,
|
||||
QUICK_BUILD,
|
||||
SWITCH,
|
||||
ZONE_CONTROL, // Minigame
|
||||
CHANGLING,
|
||||
CHOICE_BUILD,
|
||||
PACKAGE,
|
||||
SOUND_REPEATER,
|
||||
SOUND_AMBIENT_2D,
|
||||
SOUND_AMBIENT_3D,
|
||||
PRECONDITION,
|
||||
PLAYER_FLAG,
|
||||
CUSTOM_BUILD_ASSEMBLY,
|
||||
BASE_COMBAT_AI,
|
||||
MODULE_ASSEMBLY,
|
||||
SHOWCASE_MODEL_HANDLER,
|
||||
RACING_MODULE,
|
||||
GENERIC_ACTIVATOR,
|
||||
PROPERTY_VENDOR,
|
||||
HF_LIGHT_DIRECTION_GADGET,
|
||||
ROCKET_LAUNCH,
|
||||
ROCKET_LANDING,
|
||||
TRIGGER,
|
||||
DROPPED_LOOT,
|
||||
RACING_CONTROL,
|
||||
FACTION_TRIGGER,
|
||||
MISSION_OFFER,
|
||||
RACING_STATS,
|
||||
LUP_EXHIBIT,
|
||||
BBB,
|
||||
SOUND_TRIGGER,
|
||||
PROXIMITY_MONITOR,
|
||||
RACING_SOUND_TRIGGER,
|
||||
CHAT,
|
||||
FRIENDS_LIST,
|
||||
GUILD,
|
||||
LOCAL_SYSTEM,
|
||||
MISSION,
|
||||
MUTABLE_MODEL_BEHAVIORS,
|
||||
PATHFINDING,
|
||||
PET_TAMING_CONTROL,
|
||||
PROPERTY_EDITOR,
|
||||
SKINNED_RENDER,
|
||||
SLASH_COMMAND,
|
||||
STATUS_EFFECT,
|
||||
TEAMS,
|
||||
TEXT_EFFECT,
|
||||
TRADE,
|
||||
USER_CONTROL,
|
||||
IGNORE_LIST,
|
||||
ROCKET_LAUNCH_LUP,
|
||||
BUFF_REAL, // the real buff component, should just be name BUFF
|
||||
INTERACTION_MANAGER,
|
||||
DONATION_VENDOR,
|
||||
COMBAT_MEDIATOR,
|
||||
COMMENDATION_VENDOR,
|
||||
UNKNOWN_103,
|
||||
RAIL_ACTIVATOR,
|
||||
ROLLER,
|
||||
PLAYER_FORCED_MOVEMENT,
|
||||
CRAFTING,
|
||||
POSSESSABLE,
|
||||
LEVEL_PROGRESSION,
|
||||
POSSESSOR,
|
||||
MOUNT_CONTROL,
|
||||
UNKNOWN_112,
|
||||
PROPERTY_PLAQUE,
|
||||
BUILD_BORDER,
|
||||
UNKOWN_115,
|
||||
CULLING_PLANE,
|
||||
DESTROYABLE = 1000 // Actually 7
|
||||
};
|
||||
|
||||
#endif //!__EREPLICACOMPONENTTYPE__H__
|
||||
24
dCommon/dEnums/eServerDisconnectIdentifiers.h
Normal file
24
dCommon/dEnums/eServerDisconnectIdentifiers.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef __ESERVERDISCONNECTIDENTIFIERS__H__
|
||||
#define __ESERVERDISCONNECTIDENTIFIERS__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eServerDisconnectIdentifiers : uint32_t {
|
||||
UNKNOWN_SERVER_ERROR = 0,
|
||||
WRONG_GAME_VERSION,
|
||||
WRONG_SERVER_VERSION,
|
||||
CONNECTION_ON_INVALID_PORT,
|
||||
DUPLICATE_LOGIN,
|
||||
SERVER_SHUTDOWN,
|
||||
SERVER_MAP_LOAD_FAILURE,
|
||||
INVALID_SESSION_KEY,
|
||||
ACCOUNT_NOT_IN_PENDING_LIST,
|
||||
CHARACTER_NOT_FOUND,
|
||||
CHARACTER_CORRUPTED,
|
||||
KICK,
|
||||
SAVE_FAILURE,
|
||||
FREE_TRIAL_EXPIRED,
|
||||
PLAY_SCHEDULE_TIME_DONE
|
||||
};
|
||||
|
||||
#endif //!__ESERVERDISCONNECTIDENTIFIERS__H__
|
||||
16
dCommon/dEnums/eSqliteDataType.h
Normal file
16
dCommon/dEnums/eSqliteDataType.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef __ESQLITEDATATYPE__H__
|
||||
#define __ESQLITEDATATYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eSqliteDataType : int32_t {
|
||||
NONE = 0,
|
||||
INT32,
|
||||
REAL = 3,
|
||||
TEXT_4,
|
||||
INT_BOOL,
|
||||
INT64,
|
||||
TEXT_8 = 8
|
||||
};
|
||||
|
||||
#endif //!__ESQLITEDATATYPE__H__
|
||||
119
dCommon/dEnums/eTriggerCommandType.h
Normal file
119
dCommon/dEnums/eTriggerCommandType.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#ifndef __ETRIGGERCOMMANDTYPE__H__
|
||||
#define __ETRIGGERCOMMANDTYPE__H__
|
||||
|
||||
// For info about Trigger Command see:
|
||||
// https://docs.lu-dev.net/en/latest/file-structures/lutriggers.html?highlight=trigger#possible-values-commands
|
||||
|
||||
enum class eTriggerCommandType {
|
||||
INVALID,
|
||||
ZONE_PLAYER,
|
||||
FIRE_EVENT,
|
||||
DESTROY_OBJ,
|
||||
TOGGLE_TRIGGER,
|
||||
RESET_REBUILD,
|
||||
SET_PATH,
|
||||
SET_PICK_TYPE,
|
||||
MOVE_OBJECT,
|
||||
ROTATE_OBJECT,
|
||||
PUSH_OBJECT,
|
||||
REPEL_OBJECT,
|
||||
SET_TIMER,
|
||||
CANCEL_TIMER,
|
||||
PLAY_CINEMATIC,
|
||||
TOGGLE_BBB,
|
||||
UPDATE_MISSION,
|
||||
SET_BOUNCER_STATE,
|
||||
BOUNCE_ALL_ON_BOUNCER,
|
||||
TURN_AROUND_ON_PATH,
|
||||
GO_FORWARD_ON_PATH,
|
||||
GO_BACKWARD_ON_PATH,
|
||||
STOP_PATHING,
|
||||
START_PATHING,
|
||||
LOCK_OR_UNLOCK_CONTROLS,
|
||||
PLAY_EFFECT,
|
||||
STOP_EFFECT,
|
||||
ACTIVATE_MUSIC_CUE,
|
||||
DEACTIVATE_MUSIC_CUE,
|
||||
FLASH_MUSIC_CUE,
|
||||
SET_MUSIC_PARAMETER,
|
||||
PLAY_2D_AMBIENT_SOUND,
|
||||
STOP_2D_AMBIENT_SOUND,
|
||||
PLAY_3D_AMBIENT_SOUND,
|
||||
STOP_3D_AMBIENT_SOUND,
|
||||
ACTIVATE_MIXER_PROGRAM,
|
||||
DEACTIVATE_MIXER_PROGRAM,
|
||||
CAST_SKILL,
|
||||
DISPLAY_ZONE_SUMMARY,
|
||||
SET_PHYSICS_VOLUME_EFFECT,
|
||||
SET_PHYSICS_VOLUME_STATUS,
|
||||
SET_MODEL_TO_BUILD,
|
||||
SPAWN_MODEL_BRICKS,
|
||||
ACTIVATE_SPAWNER_NETWORK,
|
||||
DEACTIVATE_SPAWNER_NETWORK,
|
||||
RESET_SPAWNER_NETWORK,
|
||||
DESTROY_SPAWNER_NETWORK_OBJECTS,
|
||||
GO_TO_WAYPOINT,
|
||||
ACTIVATE_PHYSICS
|
||||
};
|
||||
|
||||
|
||||
class TriggerCommandType {
|
||||
public:
|
||||
static eTriggerCommandType StringToTriggerCommandType(std::string commandString) {
|
||||
const std::map<std::string, eTriggerCommandType> TriggerCommandMap = {
|
||||
{ "zonePlayer", eTriggerCommandType::ZONE_PLAYER},
|
||||
{ "fireEvent", eTriggerCommandType::FIRE_EVENT},
|
||||
{ "destroyObj", eTriggerCommandType::DESTROY_OBJ},
|
||||
{ "toggleTrigger", eTriggerCommandType::TOGGLE_TRIGGER},
|
||||
{ "resetRebuild", eTriggerCommandType::RESET_REBUILD},
|
||||
{ "setPath", eTriggerCommandType::SET_PATH},
|
||||
{ "setPickType", eTriggerCommandType::SET_PICK_TYPE},
|
||||
{ "moveObject", eTriggerCommandType::MOVE_OBJECT},
|
||||
{ "rotateObject", eTriggerCommandType::ROTATE_OBJECT},
|
||||
{ "pushObject", eTriggerCommandType::PUSH_OBJECT},
|
||||
{ "repelObject", eTriggerCommandType::REPEL_OBJECT},
|
||||
{ "setTimer", eTriggerCommandType::SET_TIMER},
|
||||
{ "cancelTimer", eTriggerCommandType::CANCEL_TIMER},
|
||||
{ "playCinematic", eTriggerCommandType::PLAY_CINEMATIC},
|
||||
{ "toggleBBB", eTriggerCommandType::TOGGLE_BBB},
|
||||
{ "updateMission", eTriggerCommandType::UPDATE_MISSION},
|
||||
{ "setBouncerState", eTriggerCommandType::SET_BOUNCER_STATE},
|
||||
{ "bounceAllOnBouncer", eTriggerCommandType::BOUNCE_ALL_ON_BOUNCER},
|
||||
{ "turnAroundOnPath", eTriggerCommandType::TURN_AROUND_ON_PATH},
|
||||
{ "goForwardOnPath", eTriggerCommandType::GO_FORWARD_ON_PATH},
|
||||
{ "goBackwardOnPath", eTriggerCommandType::GO_BACKWARD_ON_PATH},
|
||||
{ "stopPathing", eTriggerCommandType::STOP_PATHING},
|
||||
{ "startPathing", eTriggerCommandType::START_PATHING},
|
||||
{ "LockOrUnlockControls", eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS},
|
||||
{ "PlayEffect", eTriggerCommandType::PLAY_EFFECT},
|
||||
{ "StopEffect", eTriggerCommandType::STOP_EFFECT},
|
||||
{ "activateMusicCue", eTriggerCommandType::ACTIVATE_MUSIC_CUE},
|
||||
{ "deactivateMusicCue", eTriggerCommandType::DEACTIVATE_MUSIC_CUE},
|
||||
{ "flashMusicCue", eTriggerCommandType::FLASH_MUSIC_CUE},
|
||||
{ "setMusicParameter", eTriggerCommandType::SET_MUSIC_PARAMETER},
|
||||
{ "play2DAmbientSound", eTriggerCommandType::PLAY_2D_AMBIENT_SOUND},
|
||||
{ "stop2DAmbientSound", eTriggerCommandType::STOP_2D_AMBIENT_SOUND},
|
||||
{ "play3DAmbientSound", eTriggerCommandType::PLAY_3D_AMBIENT_SOUND},
|
||||
{ "stop3DAmbientSound", eTriggerCommandType::STOP_3D_AMBIENT_SOUND},
|
||||
{ "activateMixerProgram", eTriggerCommandType::ACTIVATE_MIXER_PROGRAM},
|
||||
{ "deactivateMixerProgram", eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM},
|
||||
{ "CastSkill", eTriggerCommandType::CAST_SKILL},
|
||||
{ "displayZoneSummary", eTriggerCommandType::DISPLAY_ZONE_SUMMARY},
|
||||
{ "SetPhysicsVolumeEffect", eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT},
|
||||
{ "SetPhysicsVolumeStatus", eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS},
|
||||
{ "setModelToBuild", eTriggerCommandType::SET_MODEL_TO_BUILD},
|
||||
{ "spawnModelBricks", eTriggerCommandType::SPAWN_MODEL_BRICKS},
|
||||
{ "ActivateSpawnerNetwork", eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK},
|
||||
{ "DeactivateSpawnerNetwork", eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK},
|
||||
{ "ResetSpawnerNetwork", eTriggerCommandType::RESET_SPAWNER_NETWORK},
|
||||
{ "DestroySpawnerNetworkObjects", eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS},
|
||||
{ "Go_To_Waypoint", eTriggerCommandType::GO_TO_WAYPOINT},
|
||||
{ "ActivatePhysics", eTriggerCommandType::ACTIVATE_PHYSICS}
|
||||
};
|
||||
|
||||
auto intermed = TriggerCommandMap.find(commandString);
|
||||
return (intermed != TriggerCommandMap.end()) ? intermed->second : eTriggerCommandType::INVALID;
|
||||
};
|
||||
};
|
||||
|
||||
#endif //!__ETRIGGERCOMMANDTYPE__H__
|
||||
53
dCommon/dEnums/eTriggerEventType.h
Normal file
53
dCommon/dEnums/eTriggerEventType.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef __ETRIGGEREVENTTYPE__H__
|
||||
#define __ETRIGGEREVENTTYPE__H__
|
||||
|
||||
enum class eTriggerEventType {
|
||||
INVALID,
|
||||
DESTROY,
|
||||
CUSTOM_EVENT,
|
||||
ENTER,
|
||||
EXIT,
|
||||
CREATE,
|
||||
HIT,
|
||||
TIMER_DONE,
|
||||
REBUILD_COMPLETE,
|
||||
ACTIVATED,
|
||||
DEACTIVATED,
|
||||
ARRIVED,
|
||||
ARRIVED_AT_END_OF_PATH,
|
||||
ZONE_SUMMARY_DISMISSED,
|
||||
ARRIVED_AT_DESIRED_WAYPOINT,
|
||||
PET_ON_SWITCH,
|
||||
PET_OFF_SWITCH,
|
||||
INTERACT
|
||||
};
|
||||
|
||||
class TriggerEventType {
|
||||
public:
|
||||
static eTriggerEventType StringToTriggerEventType(std::string commandString) {
|
||||
const std::map<std::string, eTriggerEventType> TriggerEventMap = {
|
||||
{"OnDestroy", eTriggerEventType::DESTROY},
|
||||
{"OnCustomEvent", eTriggerEventType::CUSTOM_EVENT},
|
||||
{"OnEnter", eTriggerEventType::ENTER},
|
||||
{"OnExit", eTriggerEventType::EXIT},
|
||||
{"OnCreate", eTriggerEventType::CREATE},
|
||||
{"OnHit", eTriggerEventType::HIT},
|
||||
{"OnTimerDone", eTriggerEventType::TIMER_DONE},
|
||||
{"OnRebuildComplete", eTriggerEventType::REBUILD_COMPLETE},
|
||||
{"OnActivated", eTriggerEventType::ACTIVATED},
|
||||
{"OnDeactivated", eTriggerEventType::DEACTIVATED},
|
||||
{"OnArrived", eTriggerEventType::ARRIVED},
|
||||
{"OnArrivedAtEndOfPath", eTriggerEventType::ARRIVED_AT_END_OF_PATH},
|
||||
{"OnZoneSummaryDismissed", eTriggerEventType::ZONE_SUMMARY_DISMISSED},
|
||||
{"OnArrivedAtDesiredWaypoint", eTriggerEventType::ARRIVED_AT_DESIRED_WAYPOINT},
|
||||
{"OnPetOnSwitch", eTriggerEventType::PET_ON_SWITCH},
|
||||
{"OnPetOffSwitch", eTriggerEventType::PET_OFF_SWITCH},
|
||||
{"OnInteract", eTriggerEventType::INTERACT},
|
||||
};
|
||||
|
||||
auto intermed = TriggerEventMap.find(commandString);
|
||||
return (intermed != TriggerEventMap.end()) ? intermed->second : eTriggerEventType::INVALID;
|
||||
};
|
||||
};
|
||||
|
||||
#endif //!__ETRIGGEREVENTTYPE__H__
|
||||
13
dCommon/dEnums/eUgcModerationStatus.h
Normal file
13
dCommon/dEnums/eUgcModerationStatus.h
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
#ifndef __EUGCMODERATIONSTATUS__H__
|
||||
#define __EUGCMODERATIONSTATUS__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eUgcModerationStatus : uint32_t {
|
||||
NoStatus,
|
||||
Approved,
|
||||
Rejected,
|
||||
};
|
||||
|
||||
#endif //!__EUGCMODERATIONSTATUS__H__
|
||||
14
dCommon/dEnums/eUnequippableActiveType.h
Normal file
14
dCommon/dEnums/eUnequippableActiveType.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EUNEQUIPPABLEACTIVETYPE__H__
|
||||
#define __EUNEQUIPPABLEACTIVETYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eUnequippableActiveType : int32_t {
|
||||
INVALID = -1,
|
||||
PET = 0,
|
||||
MOUNT
|
||||
};
|
||||
|
||||
#endif //!__EUNEQUIPPABLEACTIVETYPE__H__
|
||||
@@ -89,7 +89,7 @@ void dLogger::Log(const std::string& className, const std::string& message) {
|
||||
void dLogger::LogDebug(const char* className, const char* format, ...) {
|
||||
if (!m_logDebugStatements) return;
|
||||
va_list args;
|
||||
std::string log = "[" + std::string(className) + "] " + std::string(format);
|
||||
std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n";
|
||||
va_start(args, format);
|
||||
vLog(log.c_str(), args);
|
||||
va_end(args);
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef __EITEMTYPE__H__
|
||||
#define __EITEMTYPE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eItemType : int32_t {
|
||||
ITEM_TYPE_UNKNOWN = -1, //!< An unknown item type
|
||||
ITEM_TYPE_BRICK = 1, //!< A brick
|
||||
ITEM_TYPE_HAT = 2, //!< A hat / head item
|
||||
ITEM_TYPE_HAIR = 3, //!< A hair item
|
||||
ITEM_TYPE_NECK = 4, //!< A neck item
|
||||
ITEM_TYPE_LEFT_HAND = 5, //!< A left handed item
|
||||
ITEM_TYPE_RIGHT_HAND = 6, //!< A right handed item
|
||||
ITEM_TYPE_LEGS = 7, //!< A pants item
|
||||
ITEM_TYPE_LEFT_TRINKET = 8, //!< A left handled trinket item
|
||||
ITEM_TYPE_RIGHT_TRINKET = 9, //!< A right handed trinket item
|
||||
ITEM_TYPE_BEHAVIOR = 10, //!< A behavior
|
||||
ITEM_TYPE_PROPERTY = 11, //!< A property
|
||||
ITEM_TYPE_MODEL = 12, //!< A model
|
||||
ITEM_TYPE_COLLECTIBLE = 13, //!< A collectible item
|
||||
ITEM_TYPE_CONSUMABLE = 14, //!< A consumable item
|
||||
ITEM_TYPE_CHEST = 15, //!< A chest item
|
||||
ITEM_TYPE_EGG = 16, //!< An egg
|
||||
ITEM_TYPE_PET_FOOD = 17, //!< A pet food item
|
||||
ITEM_TYPE_QUEST_OBJECT = 18, //!< A quest item
|
||||
ITEM_TYPE_PET_INVENTORY_ITEM = 19, //!< A pet inventory item
|
||||
ITEM_TYPE_PACKAGE = 20, //!< A package
|
||||
ITEM_TYPE_LOOT_MODEL = 21, //!< A loot model
|
||||
ITEM_TYPE_VEHICLE = 22, //!< A vehicle
|
||||
ITEM_TYPE_CURRENCY = 23, //!< Currency
|
||||
ITEM_TYPE_MOUNT = 24 //!< A Mount
|
||||
};
|
||||
|
||||
#endif //!__EITEMTYPE__H__
|
||||
@@ -14,6 +14,11 @@ CppSQLite3Query CDClientDatabase::ExecuteQuery(const std::string& query) {
|
||||
return conn->execQuery(query.c_str());
|
||||
}
|
||||
|
||||
//! Updates the CDClient file with Data Manipulation Language (DML) commands.
|
||||
int CDClientDatabase::ExecuteDML(const std::string& query) {
|
||||
return conn->execDML(query.c_str());
|
||||
}
|
||||
|
||||
//! Makes prepared statements
|
||||
CppSQLite3Statement CDClientDatabase::CreatePreppedStmt(const std::string& query) {
|
||||
return conn->compileStatement(query.c_str());
|
||||
|
||||
@@ -40,6 +40,14 @@ namespace CDClientDatabase {
|
||||
*/
|
||||
CppSQLite3Query ExecuteQuery(const std::string& query);
|
||||
|
||||
//! Updates the CDClient file with Data Manipulation Language (DML) commands.
|
||||
/*!
|
||||
\param query The DML command to run. DML command can be multiple queries in one string but only
|
||||
the last one will return its number of updated rows.
|
||||
\return The number of updated rows.
|
||||
*/
|
||||
int ExecuteDML(const std::string& query);
|
||||
|
||||
//! Queries the CDClient and parses arguments
|
||||
/*!
|
||||
\param query The query with formatted arguments
|
||||
|
||||
@@ -1,46 +1,80 @@
|
||||
#include "CDClientManager.h"
|
||||
#include "CDActivityRewardsTable.h"
|
||||
#include "CDAnimationsTable.h"
|
||||
#include "CDBehaviorParameterTable.h"
|
||||
#include "CDBehaviorTemplateTable.h"
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
#include "CDCurrencyTableTable.h"
|
||||
#include "CDDestructibleComponentTable.h"
|
||||
#include "CDEmoteTable.h"
|
||||
#include "CDInventoryComponentTable.h"
|
||||
#include "CDItemComponentTable.h"
|
||||
#include "CDItemSetsTable.h"
|
||||
#include "CDItemSetSkillsTable.h"
|
||||
#include "CDLevelProgressionLookupTable.h"
|
||||
#include "CDLootMatrixTable.h"
|
||||
#include "CDLootTableTable.h"
|
||||
#include "CDMissionNPCComponentTable.h"
|
||||
#include "CDMissionTasksTable.h"
|
||||
#include "CDMissionsTable.h"
|
||||
#include "CDObjectSkillsTable.h"
|
||||
#include "CDObjectsTable.h"
|
||||
#include "CDPhysicsComponentTable.h"
|
||||
#include "CDRebuildComponentTable.h"
|
||||
#include "CDScriptComponentTable.h"
|
||||
#include "CDSkillBehaviorTable.h"
|
||||
#include "CDZoneTableTable.h"
|
||||
#include "CDVendorComponentTable.h"
|
||||
#include "CDActivitiesTable.h"
|
||||
#include "CDPackageComponentTable.h"
|
||||
#include "CDProximityMonitorComponentTable.h"
|
||||
#include "CDMovementAIComponentTable.h"
|
||||
#include "CDBrickIDTableTable.h"
|
||||
#include "CDRarityTableTable.h"
|
||||
#include "CDMissionEmailTable.h"
|
||||
#include "CDRewardsTable.h"
|
||||
#include "CDPropertyEntranceComponentTable.h"
|
||||
#include "CDPropertyTemplateTable.h"
|
||||
#include "CDFeatureGatingTable.h"
|
||||
#include "CDRailActivatorComponent.h"
|
||||
|
||||
// Static Variables
|
||||
CDClientManager* CDClientManager::m_Address = nullptr;
|
||||
|
||||
//! Initializes the manager
|
||||
void CDClientManager::Initialize(void) {
|
||||
tables.insert(std::make_pair("ActivityRewards", new CDActivityRewardsTable()));
|
||||
UNUSED(tables.insert(std::make_pair("Animations", new CDAnimationsTable())));
|
||||
tables.insert(std::make_pair("BehaviorParameter", new CDBehaviorParameterTable()));
|
||||
tables.insert(std::make_pair("BehaviorTemplate", new CDBehaviorTemplateTable()));
|
||||
tables.insert(std::make_pair("ComponentsRegistry", new CDComponentsRegistryTable()));
|
||||
tables.insert(std::make_pair("CurrencyTable", new CDCurrencyTableTable()));
|
||||
tables.insert(std::make_pair("DestructibleComponent", new CDDestructibleComponentTable()));
|
||||
tables.insert(std::make_pair("EmoteTable", new CDEmoteTableTable()));
|
||||
tables.insert(std::make_pair("InventoryComponent", new CDInventoryComponentTable()));
|
||||
tables.insert(std::make_pair("ItemComponent", new CDItemComponentTable()));
|
||||
tables.insert(std::make_pair("ItemSets", new CDItemSetsTable()));
|
||||
tables.insert(std::make_pair("ItemSetSkills", new CDItemSetSkillsTable()));
|
||||
tables.insert(std::make_pair("LevelProgressionLookup", new CDLevelProgressionLookupTable()));
|
||||
tables.insert(std::make_pair("LootMatrix", new CDLootMatrixTable()));
|
||||
tables.insert(std::make_pair("LootTable", new CDLootTableTable()));
|
||||
tables.insert(std::make_pair("MissionNPCComponent", new CDMissionNPCComponentTable()));
|
||||
tables.insert(std::make_pair("MissionTasks", new CDMissionTasksTable()));
|
||||
tables.insert(std::make_pair("Missions", new CDMissionsTable()));
|
||||
tables.insert(std::make_pair("ObjectSkills", new CDObjectSkillsTable()));
|
||||
tables.insert(std::make_pair("Objects", new CDObjectsTable()));
|
||||
tables.insert(std::make_pair("PhysicsComponent", new CDPhysicsComponentTable()));
|
||||
tables.insert(std::make_pair("RebuildComponent", new CDRebuildComponentTable()));
|
||||
tables.insert(std::make_pair("ScriptComponent", new CDScriptComponentTable()));
|
||||
tables.insert(std::make_pair("SkillBehavior", new CDSkillBehaviorTable()));
|
||||
tables.insert(std::make_pair("ZoneTable", new CDZoneTableTable()));
|
||||
tables.insert(std::make_pair("VendorComponent", new CDVendorComponentTable()));
|
||||
tables.insert(std::make_pair("Activities", new CDActivitiesTable()));
|
||||
tables.insert(std::make_pair("PackageComponent", new CDPackageComponentTable()));
|
||||
tables.insert(std::make_pair("ProximityMonitorComponent", new CDProximityMonitorComponentTable()));
|
||||
tables.insert(std::make_pair("MovementAIComponent", new CDMovementAIComponentTable()));
|
||||
tables.insert(std::make_pair("BrickIDTable", new CDBrickIDTableTable()));
|
||||
tables.insert(std::make_pair("RarityTable", new CDRarityTableTable()));
|
||||
tables.insert(std::make_pair("MissionEmail", new CDMissionEmailTable()));
|
||||
tables.insert(std::make_pair("Rewards", new CDRewardsTable()));
|
||||
tables.insert(std::make_pair("PropertyEntranceComponent", new CDPropertyEntranceComponentTable()));
|
||||
tables.insert(std::make_pair("PropertyTemplate", new CDPropertyTemplateTable()));
|
||||
tables.insert(std::make_pair("FeatureGating", new CDFeatureGatingTable()));
|
||||
tables.insert(std::make_pair("RailActivatorComponent", new CDRailActivatorComponentTable()));
|
||||
CDClientManager::CDClientManager() {
|
||||
CDActivityRewardsTable::Instance();
|
||||
UNUSED(CDAnimationsTable::Instance());
|
||||
CDBehaviorParameterTable::Instance();
|
||||
CDBehaviorTemplateTable::Instance();
|
||||
CDComponentsRegistryTable::Instance();
|
||||
CDCurrencyTableTable::Instance();
|
||||
CDDestructibleComponentTable::Instance();
|
||||
CDEmoteTableTable::Instance();
|
||||
CDInventoryComponentTable::Instance();
|
||||
CDItemComponentTable::Instance();
|
||||
CDItemSetsTable::Instance();
|
||||
CDItemSetSkillsTable::Instance();
|
||||
CDLevelProgressionLookupTable::Instance();
|
||||
CDLootMatrixTable::Instance();
|
||||
CDLootTableTable::Instance();
|
||||
CDMissionNPCComponentTable::Instance();
|
||||
CDMissionTasksTable::Instance();
|
||||
CDMissionsTable::Instance();
|
||||
CDObjectSkillsTable::Instance();
|
||||
CDObjectsTable::Instance();
|
||||
CDPhysicsComponentTable::Instance();
|
||||
CDRebuildComponentTable::Instance();
|
||||
CDScriptComponentTable::Instance();
|
||||
CDSkillBehaviorTable::Instance();
|
||||
CDZoneTableTable::Instance();
|
||||
CDVendorComponentTable::Instance();
|
||||
CDActivitiesTable::Instance();
|
||||
CDPackageComponentTable::Instance();
|
||||
CDProximityMonitorComponentTable::Instance();
|
||||
CDMovementAIComponentTable::Instance();
|
||||
CDBrickIDTableTable::Instance();
|
||||
CDRarityTableTable::Instance();
|
||||
CDMissionEmailTable::Instance();
|
||||
CDRewardsTable::Instance();
|
||||
CDPropertyEntranceComponentTable::Instance();
|
||||
CDPropertyTemplateTable::Instance();
|
||||
CDFeatureGatingTable::Instance();
|
||||
CDRailActivatorComponentTable::Instance();
|
||||
}
|
||||
|
||||
@@ -1,96 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
// Tables
|
||||
#include "CDActivityRewardsTable.h"
|
||||
#include "CDAnimationsTable.h"
|
||||
#include "CDBehaviorParameterTable.h"
|
||||
#include "CDBehaviorTemplateTable.h"
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
#include "CDCurrencyTableTable.h"
|
||||
#include "CDDestructibleComponentTable.h"
|
||||
#include "CDEmoteTable.h"
|
||||
#include "CDInventoryComponentTable.h"
|
||||
#include "CDItemComponentTable.h"
|
||||
#include "CDItemSetsTable.h"
|
||||
#include "CDItemSetSkillsTable.h"
|
||||
#include "CDLevelProgressionLookupTable.h"
|
||||
#include "CDLootMatrixTable.h"
|
||||
#include "CDLootTableTable.h"
|
||||
#include "CDMissionNPCComponentTable.h"
|
||||
#include "CDMissionTasksTable.h"
|
||||
#include "CDMissionsTable.h"
|
||||
#include "CDObjectSkillsTable.h"
|
||||
#include "CDObjectsTable.h"
|
||||
#include "CDPhysicsComponentTable.h"
|
||||
#include "CDRebuildComponentTable.h"
|
||||
#include "CDScriptComponentTable.h"
|
||||
#include "CDSkillBehaviorTable.h"
|
||||
#include "CDZoneTableTable.h"
|
||||
#include "CDVendorComponentTable.h"
|
||||
#include "CDActivitiesTable.h"
|
||||
#include "CDPackageComponentTable.h"
|
||||
#include "CDProximityMonitorComponentTable.h"
|
||||
#include "CDMovementAIComponentTable.h"
|
||||
#include "CDBrickIDTableTable.h"
|
||||
#include "CDRarityTableTable.h"
|
||||
#include "CDMissionEmailTable.h"
|
||||
#include "CDRewardsTable.h"
|
||||
#include "CDPropertyEntranceComponentTable.h"
|
||||
#include "CDPropertyTemplateTable.h"
|
||||
#include "CDFeatureGatingTable.h"
|
||||
#include "CDRailActivatorComponent.h"
|
||||
#include "Singleton.h"
|
||||
|
||||
// C++
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
/*!
|
||||
\file CDClientManager.hpp
|
||||
\brief A manager for the CDClient tables
|
||||
/**
|
||||
* Initialize the CDClient tables so they are all loaded into memory.
|
||||
*/
|
||||
|
||||
//! Manages all data from the CDClient
|
||||
class CDClientManager {
|
||||
private:
|
||||
static CDClientManager* m_Address; //!< The singleton address
|
||||
|
||||
std::unordered_map<std::string, CDTable*> tables; //!< The tables
|
||||
|
||||
class CDClientManager : public Singleton<CDClientManager> {
|
||||
public:
|
||||
CDClientManager();
|
||||
|
||||
//! The singleton method
|
||||
static CDClientManager* Instance() {
|
||||
if (m_Address == 0) {
|
||||
m_Address = new CDClientManager;
|
||||
}
|
||||
|
||||
return m_Address;
|
||||
}
|
||||
|
||||
//! Initializes the manager
|
||||
void Initialize(void);
|
||||
|
||||
//! Fetches a CDClient table
|
||||
/*!
|
||||
This function uses typename T which must be a subclass of CDTable.
|
||||
It returns the class that conforms to the class name
|
||||
|
||||
\param tableName The table name
|
||||
\return The class or nullptr
|
||||
/**
|
||||
* Fetch a table from CDClient
|
||||
*
|
||||
* @tparam Table type to fetch
|
||||
* @return A pointer to the requested table.
|
||||
*/
|
||||
template<typename T>
|
||||
T* GetTable(const std::string& tableName) {
|
||||
static_assert(std::is_base_of<CDTable, T>::value, "T should inherit from CDTable!");
|
||||
|
||||
for (auto itr = this->tables.begin(); itr != this->tables.end(); ++itr) {
|
||||
if (itr->first == tableName) {
|
||||
return dynamic_cast<T*>(itr->second);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
T* GetTable() {
|
||||
return &T::Instance();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,8 +14,6 @@ std::string Database::database;
|
||||
void Database::Connect(const string& host, const string& database, const string& username, const string& password) {
|
||||
|
||||
//To bypass debug issues:
|
||||
std::string newHost = "tcp://" + host;
|
||||
const char* szHost = newHost.c_str();
|
||||
const char* szDatabase = database.c_str();
|
||||
const char* szUsername = username.c_str();
|
||||
const char* szPassword = password.c_str();
|
||||
@@ -23,7 +21,24 @@ void Database::Connect(const string& host, const string& database, const string&
|
||||
driver = sql::mariadb::get_driver_instance();
|
||||
|
||||
sql::Properties properties;
|
||||
properties["hostName"] = szHost;
|
||||
// The mariadb connector is *supposed* to handle unix:// and pipe:// prefixes to hostName, but there are bugs where
|
||||
// 1) it tries to parse a database from the connection string (like in tcp://localhost:3001/darkflame) based on the
|
||||
// presence of a /
|
||||
// 2) even avoiding that, the connector still assumes you're connecting with a tcp socket
|
||||
// So, what we do in the presence of a unix socket or pipe is to set the hostname to the protocol and localhost,
|
||||
// which avoids parsing errors while still ensuring the correct connection type is used, and then setting the appropriate
|
||||
// property manually (which the URL parsing fails to do)
|
||||
const std::string UNIX_PROTO = "unix://";
|
||||
const std::string PIPE_PROTO = "pipe://";
|
||||
if (host.find(UNIX_PROTO) == 0) {
|
||||
properties["hostName"] = "unix://localhost";
|
||||
properties["localSocket"] = host.substr(UNIX_PROTO.length()).c_str();
|
||||
} else if (host.find(PIPE_PROTO) == 0) {
|
||||
properties["hostName"] = "pipe://localhost";
|
||||
properties["pipe"] = host.substr(PIPE_PROTO.length()).c_str();
|
||||
} else {
|
||||
properties["hostName"] = host.c_str();
|
||||
}
|
||||
properties["user"] = szUsername;
|
||||
properties["password"] = szPassword;
|
||||
properties["autoReconnect"] = "true";
|
||||
@@ -35,8 +50,14 @@ void Database::Connect(const string& host, const string& database, const string&
|
||||
}
|
||||
|
||||
void Database::Connect() {
|
||||
con = driver->connect(Database::props);
|
||||
con->setSchema(Database::database);
|
||||
// `connect(const Properties& props)` segfaults in windows debug, but
|
||||
// `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly
|
||||
if (Database::props.find("localSocket") != Database::props.end() || Database::props.find("pipe") != Database::props.end()) {
|
||||
con = driver->connect(Database::props);
|
||||
} else {
|
||||
con = driver->connect(Database::props["hostName"].c_str(), Database::props["user"].c_str(), Database::props["password"].c_str());
|
||||
}
|
||||
con->setSchema(Database::database.c_str());
|
||||
}
|
||||
|
||||
void Database::Destroy(std::string source, bool log) {
|
||||
@@ -83,3 +104,15 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
|
||||
void Database::Commit() {
|
||||
Database::con->commit();
|
||||
}
|
||||
|
||||
bool Database::GetAutoCommit() {
|
||||
// TODO This should not just access a pointer. A future PR should update this
|
||||
// to check for null and throw an error if the connection is not valid.
|
||||
return con->getAutoCommit();
|
||||
}
|
||||
|
||||
void Database::SetAutoCommit(bool value) {
|
||||
// TODO This should not just access a pointer. A future PR should update this
|
||||
// to check for null and throw an error if the connection is not valid.
|
||||
Database::con->setAutoCommit(value);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ public:
|
||||
static sql::Statement* CreateStmt();
|
||||
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
|
||||
static void Commit();
|
||||
static bool GetAutoCommit();
|
||||
static void SetAutoCommit(bool value);
|
||||
|
||||
static std::string GetDatabase() { return database; }
|
||||
static sql::Properties GetProperties() { return props; }
|
||||
|
||||
@@ -1,65 +1,20 @@
|
||||
#include "MigrationRunner.h"
|
||||
|
||||
#include "BrickByBrickFix.h"
|
||||
#include "CDClientDatabase.h"
|
||||
#include "Database.h"
|
||||
#include "Game.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "dLogger.h"
|
||||
#include "BinaryPathFinder.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <istream>
|
||||
|
||||
void MigrationRunner::RunMigrations() {
|
||||
auto stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
|
||||
stmt->executeQuery();
|
||||
delete stmt;
|
||||
|
||||
sql::SQLString finalSQL = "";
|
||||
Migration checkMigration{};
|
||||
|
||||
for (const auto& entry : GeneralUtils::GetFileNamesFromFolder("./migrations/")) {
|
||||
auto migration = LoadMigration(entry);
|
||||
|
||||
if (migration.data.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
checkMigration = migration;
|
||||
|
||||
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
|
||||
stmt->setString(1, migration.name);
|
||||
auto res = stmt->executeQuery();
|
||||
bool doExit = res->next();
|
||||
delete res;
|
||||
delete stmt;
|
||||
if (doExit) continue;
|
||||
|
||||
Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str());
|
||||
|
||||
finalSQL.append(migration.data);
|
||||
finalSQL.append('\n');
|
||||
|
||||
stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
|
||||
stmt->setString(1, entry);
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
}
|
||||
|
||||
if (!finalSQL.empty()) {
|
||||
try {
|
||||
auto simpleStatement = Database::CreateStmt();
|
||||
simpleStatement->execute(finalSQL);
|
||||
delete simpleStatement;
|
||||
} catch (sql::SQLException e) {
|
||||
Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Migration MigrationRunner::LoadMigration(std::string path) {
|
||||
Migration LoadMigration(std::string path) {
|
||||
Migration migration{};
|
||||
std::ifstream file("./migrations/" + path);
|
||||
std::ifstream file(BinaryPathFinder::GetBinaryDir() / "migrations/" / path);
|
||||
|
||||
if (file.is_open()) {
|
||||
std::hash<std::string> hash;
|
||||
|
||||
std::string line;
|
||||
std::string total = "";
|
||||
|
||||
@@ -75,3 +30,129 @@ Migration MigrationRunner::LoadMigration(std::string path) {
|
||||
|
||||
return migration;
|
||||
}
|
||||
|
||||
void MigrationRunner::RunMigrations() {
|
||||
auto* stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
|
||||
sql::SQLString finalSQL = "";
|
||||
bool runSd0Migrations = false;
|
||||
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/").string())) {
|
||||
auto migration = LoadMigration("dlu/" + entry);
|
||||
|
||||
if (migration.data.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
|
||||
stmt->setString(1, migration.name.c_str());
|
||||
auto* res = stmt->executeQuery();
|
||||
bool doExit = res->next();
|
||||
delete res;
|
||||
delete stmt;
|
||||
if (doExit) continue;
|
||||
|
||||
Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str());
|
||||
if (migration.name == "dlu/5_brick_model_sd0.sql") {
|
||||
runSd0Migrations = true;
|
||||
} else {
|
||||
finalSQL.append(migration.data.c_str());
|
||||
}
|
||||
|
||||
stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
|
||||
stmt->setString(1, migration.name.c_str());
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
}
|
||||
|
||||
if (finalSQL.empty() && !runSd0Migrations) {
|
||||
Game::logger->Log("MigrationRunner", "Server database is up to date.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!finalSQL.empty()) {
|
||||
auto migration = GeneralUtils::SplitString(static_cast<std::string>(finalSQL), ';');
|
||||
std::unique_ptr<sql::Statement> simpleStatement(Database::CreateStmt());
|
||||
for (auto& query : migration) {
|
||||
try {
|
||||
if (query.empty()) continue;
|
||||
simpleStatement->execute(query.c_str());
|
||||
} catch (sql::SQLException& e) {
|
||||
Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Do this last on the off chance none of the other migrations have been run yet.
|
||||
if (runSd0Migrations) {
|
||||
uint32_t numberOfUpdatedModels = BrickByBrickFix::UpdateBrickByBrickModelsToSd0();
|
||||
Game::logger->Log("MasterServer", "%i models were updated from zlib to sd0.", numberOfUpdatedModels);
|
||||
uint32_t numberOfTruncatedModels = BrickByBrickFix::TruncateBrokenBrickByBrickXml();
|
||||
Game::logger->Log("MasterServer", "%i models were truncated from the database.", numberOfTruncatedModels);
|
||||
}
|
||||
}
|
||||
|
||||
void MigrationRunner::RunSQLiteMigrations() {
|
||||
auto cdstmt = CDClientDatabase::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);");
|
||||
cdstmt.execQuery().finalize();
|
||||
cdstmt.finalize();
|
||||
|
||||
auto* stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
|
||||
for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "migrations/cdserver/").string())) {
|
||||
auto migration = LoadMigration("cdserver/" + entry);
|
||||
|
||||
if (migration.data.empty()) continue;
|
||||
|
||||
// Check if there is an entry in the migration history table on the cdclient database.
|
||||
cdstmt = CDClientDatabase::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
|
||||
cdstmt.bind((int32_t) 1, migration.name.c_str());
|
||||
auto cdres = cdstmt.execQuery();
|
||||
bool doExit = !cdres.eof();
|
||||
cdres.finalize();
|
||||
cdstmt.finalize();
|
||||
|
||||
if (doExit) continue;
|
||||
|
||||
// Check first if there is entry in the migration history table on the main database.
|
||||
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
|
||||
stmt->setString(1, migration.name.c_str());
|
||||
auto* res = stmt->executeQuery();
|
||||
doExit = res->next();
|
||||
delete res;
|
||||
delete stmt;
|
||||
if (doExit) {
|
||||
// Insert into cdclient database if there is an entry in the main database but not the cdclient database.
|
||||
cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
|
||||
cdstmt.bind((int32_t) 1, migration.name.c_str());
|
||||
cdstmt.execQuery().finalize();
|
||||
cdstmt.finalize();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Doing these 1 migration at a time since one takes a long time and some may think it is crashing.
|
||||
// This will at the least guarentee that the full migration needs to be run in order to be counted as "migrated".
|
||||
Game::logger->Log("MigrationRunner", "Executing migration: %s. This may take a while. Do not shut down server.", migration.name.c_str());
|
||||
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
|
||||
for (const auto& dml : GeneralUtils::SplitString(migration.data, ';')) {
|
||||
if (dml.empty()) continue;
|
||||
try {
|
||||
CDClientDatabase::ExecuteDML(dml.c_str());
|
||||
} catch (CppSQLite3Exception& e) {
|
||||
Game::logger->Log("MigrationRunner", "Encountered error running DML command: (%i) : %s", e.errorCode(), e.errorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Insert into cdclient database.
|
||||
cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
|
||||
cdstmt.bind((int32_t) 1, migration.name.c_str());
|
||||
cdstmt.execQuery().finalize();
|
||||
cdstmt.finalize();
|
||||
CDClientDatabase::ExecuteQuery("COMMIT;");
|
||||
}
|
||||
|
||||
Game::logger->Log("MigrationRunner", "CDServer database is up to date.");
|
||||
}
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "Database.h"
|
||||
|
||||
#include "dCommonVars.h"
|
||||
#include "Game.h"
|
||||
#include "dCommonVars.h"
|
||||
#include "dLogger.h"
|
||||
#include <string>
|
||||
|
||||
struct Migration {
|
||||
std::string data;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class MigrationRunner {
|
||||
public:
|
||||
static void RunMigrations();
|
||||
static Migration LoadMigration(std::string path);
|
||||
namespace MigrationRunner {
|
||||
void RunMigrations();
|
||||
void RunSQLiteMigrations();
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "CDActivitiesTable.h"
|
||||
|
||||
//! Constructor
|
||||
CDActivitiesTable::CDActivitiesTable(void) {
|
||||
|
||||
// First, get the size of the table
|
||||
@@ -21,25 +20,25 @@ CDActivitiesTable::CDActivitiesTable(void) {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities");
|
||||
while (!tableData.eof()) {
|
||||
CDActivities entry;
|
||||
entry.ActivityID = tableData.getIntField(0, -1);
|
||||
entry.locStatus = tableData.getIntField(1, -1);
|
||||
entry.instanceMapID = tableData.getIntField(2, -1);
|
||||
entry.minTeams = tableData.getIntField(3, -1);
|
||||
entry.maxTeams = tableData.getIntField(4, -1);
|
||||
entry.minTeamSize = tableData.getIntField(5, -1);
|
||||
entry.maxTeamSize = tableData.getIntField(6, -1);
|
||||
entry.waitTime = tableData.getIntField(7, -1);
|
||||
entry.startDelay = tableData.getIntField(8, -1);
|
||||
entry.requiresUniqueData = tableData.getIntField(9, -1);
|
||||
entry.leaderboardType = tableData.getIntField(10, -1);
|
||||
entry.localize = tableData.getIntField(11, -1);
|
||||
entry.optionalCostLOT = tableData.getIntField(12, -1);
|
||||
entry.optionalCostCount = tableData.getIntField(13, -1);
|
||||
entry.showUIRewards = tableData.getIntField(14, -1);
|
||||
entry.CommunityActivityFlagID = tableData.getIntField(15, -1);
|
||||
entry.gate_version = tableData.getStringField(16, "");
|
||||
entry.noTeamLootOnDeath = tableData.getIntField(17, -1);
|
||||
entry.optionalPercentage = tableData.getFloatField(18, -1.0f);
|
||||
entry.ActivityID = tableData.getIntField("ActivityID", -1);
|
||||
entry.locStatus = tableData.getIntField("locStatus", -1);
|
||||
entry.instanceMapID = tableData.getIntField("instanceMapID", -1);
|
||||
entry.minTeams = tableData.getIntField("minTeams", -1);
|
||||
entry.maxTeams = tableData.getIntField("maxTeams", -1);
|
||||
entry.minTeamSize = tableData.getIntField("minTeamSize", -1);
|
||||
entry.maxTeamSize = tableData.getIntField("maxTeamSize", -1);
|
||||
entry.waitTime = tableData.getIntField("waitTime", -1);
|
||||
entry.startDelay = tableData.getIntField("startDelay", -1);
|
||||
entry.requiresUniqueData = tableData.getIntField("requiresUniqueData", -1);
|
||||
entry.leaderboardType = tableData.getIntField("leaderboardType", -1);
|
||||
entry.localize = tableData.getIntField("localize", -1);
|
||||
entry.optionalCostLOT = tableData.getIntField("optionalCostLOT", -1);
|
||||
entry.optionalCostCount = tableData.getIntField("optionalCostCount", -1);
|
||||
entry.showUIRewards = tableData.getIntField("showUIRewards", -1);
|
||||
entry.CommunityActivityFlagID = tableData.getIntField("CommunityActivityFlagID", -1);
|
||||
entry.gate_version = tableData.getStringField("gate_version", "");
|
||||
entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1);
|
||||
entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
@@ -48,15 +47,6 @@ CDActivitiesTable::CDActivitiesTable(void) {
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDActivitiesTable::~CDActivitiesTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDActivitiesTable::GetName(void) const {
|
||||
return "Activities";
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActivities)> predicate) {
|
||||
|
||||
std::vector<CDActivities> data = cpplinq::from(this->entries)
|
||||
@@ -66,7 +56,7 @@ std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActiviti
|
||||
return data;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
std::vector<CDActivities> CDActivitiesTable::GetEntries(void) const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
/*!
|
||||
\file CDActivitiesTable.hpp
|
||||
\brief Contains data for the Activities table
|
||||
*/
|
||||
|
||||
//! Activities Entry Struct
|
||||
struct CDActivities {
|
||||
unsigned int ActivityID;
|
||||
unsigned int locStatus;
|
||||
@@ -31,36 +25,14 @@ struct CDActivities {
|
||||
float optionalPercentage;
|
||||
};
|
||||
|
||||
|
||||
//! Activities table
|
||||
class CDActivitiesTable : public CDTable {
|
||||
class CDActivitiesTable : public CDTable<CDActivitiesTable> {
|
||||
private:
|
||||
std::vector<CDActivities> entries;
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CDActivitiesTable(void);
|
||||
|
||||
//! Destructor
|
||||
~CDActivitiesTable(void);
|
||||
|
||||
//! Returns the table's name
|
||||
/*!
|
||||
\return The table name
|
||||
*/
|
||||
std::string GetName(void) const override;
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
/*!
|
||||
\param predicate The predicate
|
||||
*/
|
||||
CDActivitiesTable();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDActivities> Query(std::function<bool(CDActivities)> predicate);
|
||||
|
||||
//! Gets all the entries in the table
|
||||
/*!
|
||||
\return The entries
|
||||
*/
|
||||
std::vector<CDActivities> GetEntries(void) const;
|
||||
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "CDActivityRewardsTable.h"
|
||||
|
||||
//! Constructor
|
||||
CDActivityRewardsTable::CDActivityRewardsTable(void) {
|
||||
|
||||
// First, get the size of the table
|
||||
@@ -21,13 +20,13 @@ CDActivityRewardsTable::CDActivityRewardsTable(void) {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards");
|
||||
while (!tableData.eof()) {
|
||||
CDActivityRewards entry;
|
||||
entry.objectTemplate = tableData.getIntField(0, -1);
|
||||
entry.ActivityRewardIndex = tableData.getIntField(1, -1);
|
||||
entry.activityRating = tableData.getIntField(2, -1);
|
||||
entry.LootMatrixIndex = tableData.getIntField(3, -1);
|
||||
entry.CurrencyIndex = tableData.getIntField(4, -1);
|
||||
entry.ChallengeRating = tableData.getIntField(5, -1);
|
||||
entry.description = tableData.getStringField(6, "");
|
||||
entry.objectTemplate = tableData.getIntField("objectTemplate", -1);
|
||||
entry.ActivityRewardIndex = tableData.getIntField("ActivityRewardIndex", -1);
|
||||
entry.activityRating = tableData.getIntField("activityRating", -1);
|
||||
entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
|
||||
entry.CurrencyIndex = tableData.getIntField("CurrencyIndex", -1);
|
||||
entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1);
|
||||
entry.description = tableData.getStringField("description", "");
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
@@ -36,15 +35,6 @@ CDActivityRewardsTable::CDActivityRewardsTable(void) {
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDActivityRewardsTable::~CDActivityRewardsTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDActivityRewardsTable::GetName(void) const {
|
||||
return "ActivityRewards";
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(CDActivityRewards)> predicate) {
|
||||
|
||||
std::vector<CDActivityRewards> data = cpplinq::from(this->entries)
|
||||
@@ -54,7 +44,7 @@ std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(
|
||||
return data;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
std::vector<CDActivityRewards> CDActivityRewardsTable::GetEntries(void) const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
/*!
|
||||
\file CDActivityRewardsTable.hpp
|
||||
\brief Contains data for the ActivityRewards table
|
||||
*/
|
||||
|
||||
//! ActivityRewards Entry Struct
|
||||
struct CDActivityRewards {
|
||||
unsigned int objectTemplate; //!< The object template (?)
|
||||
unsigned int ActivityRewardIndex; //!< The activity reward index
|
||||
@@ -19,36 +13,15 @@ struct CDActivityRewards {
|
||||
std::string description; //!< The description
|
||||
};
|
||||
|
||||
|
||||
//! ActivityRewards table
|
||||
class CDActivityRewardsTable : public CDTable {
|
||||
class CDActivityRewardsTable : public CDTable<CDActivityRewardsTable> {
|
||||
private:
|
||||
std::vector<CDActivityRewards> entries;
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CDActivityRewardsTable(void);
|
||||
|
||||
//! Destructor
|
||||
~CDActivityRewardsTable(void);
|
||||
|
||||
//! Returns the table's name
|
||||
/*!
|
||||
\return The table name
|
||||
*/
|
||||
std::string GetName(void) const override;
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
/*!
|
||||
\param predicate The predicate
|
||||
*/
|
||||
CDActivityRewardsTable();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDActivityRewards> Query(std::function<bool(CDActivityRewards)> predicate);
|
||||
|
||||
//! Gets all the entries in the table
|
||||
/*!
|
||||
\return The entries
|
||||
*/
|
||||
std::vector<CDActivityRewards> GetEntries(void) const;
|
||||
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "CDAnimationsTable.h"
|
||||
|
||||
//! Constructor
|
||||
CDAnimationsTable::CDAnimationsTable(void) {
|
||||
|
||||
// First, get the size of the table
|
||||
@@ -21,19 +20,19 @@ CDAnimationsTable::CDAnimationsTable(void) {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations");
|
||||
while (!tableData.eof()) {
|
||||
CDAnimations entry;
|
||||
entry.animationGroupID = tableData.getIntField(0, -1);
|
||||
entry.animation_type = tableData.getStringField(1, "");
|
||||
entry.animation_name = tableData.getStringField(2, "");
|
||||
entry.chance_to_play = tableData.getFloatField(3, -1.0f);
|
||||
entry.min_loops = tableData.getIntField(4, -1);
|
||||
entry.max_loops = tableData.getIntField(5, -1);
|
||||
entry.animation_length = tableData.getFloatField(6, -1.0f);
|
||||
entry.hideEquip = tableData.getIntField(7, -1) == 1 ? true : false;
|
||||
entry.ignoreUpperBody = tableData.getIntField(8, -1) == 1 ? true : false;
|
||||
entry.restartable = tableData.getIntField(9, -1) == 1 ? true : false;
|
||||
entry.face_animation_name = tableData.getStringField(10, "");
|
||||
entry.priority = tableData.getFloatField(11, -1.0f);
|
||||
entry.blendTime = tableData.getFloatField(12, -1.0f);
|
||||
entry.animationGroupID = tableData.getIntField("animationGroupID", -1);
|
||||
entry.animation_type = tableData.getStringField("animation_type", "");
|
||||
entry.animation_name = tableData.getStringField("animation_name", "");
|
||||
entry.chance_to_play = tableData.getFloatField("chance_to_play", -1.0f);
|
||||
entry.min_loops = tableData.getIntField("min_loops", -1);
|
||||
entry.max_loops = tableData.getIntField("max_loops", -1);
|
||||
entry.animation_length = tableData.getFloatField("animation_length", -1.0f);
|
||||
entry.hideEquip = tableData.getIntField("hideEquip", -1) == 1 ? true : false;
|
||||
entry.ignoreUpperBody = tableData.getIntField("ignoreUpperBody", -1) == 1 ? true : false;
|
||||
entry.restartable = tableData.getIntField("restartable", -1) == 1 ? true : false;
|
||||
entry.face_animation_name = tableData.getStringField("face_animation_name", "");
|
||||
entry.priority = tableData.getFloatField("priority", -1.0f);
|
||||
entry.blendTime = tableData.getFloatField("blendTime", -1.0f);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
@@ -42,15 +41,6 @@ CDAnimationsTable::CDAnimationsTable(void) {
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDAnimationsTable::~CDAnimationsTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDAnimationsTable::GetName(void) const {
|
||||
return "Animations";
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDAnimations> CDAnimationsTable::Query(std::function<bool(CDAnimations)> predicate) {
|
||||
|
||||
std::vector<CDAnimations> data = cpplinq::from(this->entries)
|
||||
@@ -60,7 +50,7 @@ std::vector<CDAnimations> CDAnimationsTable::Query(std::function<bool(CDAnimatio
|
||||
return data;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
std::vector<CDAnimations> CDAnimationsTable::GetEntries(void) const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
/*!
|
||||
\file CDAnimationsTable.hpp
|
||||
\brief Contains data for the Animations table
|
||||
*/
|
||||
|
||||
//! Animations Entry Struct
|
||||
struct CDAnimations {
|
||||
unsigned int animationGroupID; //!< The animation group ID
|
||||
std::string animation_type; //!< The animation type
|
||||
@@ -26,35 +20,14 @@ struct CDAnimations {
|
||||
};
|
||||
|
||||
|
||||
//! Animations table
|
||||
class CDAnimationsTable : public CDTable {
|
||||
class CDAnimationsTable : public CDTable<CDAnimationsTable> {
|
||||
private:
|
||||
std::vector<CDAnimations> entries;
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CDAnimationsTable(void);
|
||||
|
||||
//! Destructor
|
||||
~CDAnimationsTable(void);
|
||||
|
||||
//! Returns the table's name
|
||||
/*!
|
||||
\return The table name
|
||||
*/
|
||||
std::string GetName(void) const override;
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
/*!
|
||||
\param predicate The predicate
|
||||
*/
|
||||
CDAnimationsTable();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDAnimations> Query(std::function<bool(CDAnimations)> predicate);
|
||||
|
||||
//! Gets all the entries in the table
|
||||
/*!
|
||||
\return The entries
|
||||
*/
|
||||
std::vector<CDAnimations> GetEntries(void) const;
|
||||
|
||||
};
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
#include "CDBehaviorParameterTable.h"
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
//! Constructor
|
||||
CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
|
||||
size_t hash = 0;
|
||||
uint32_t uniqueParameterId = 0;
|
||||
uint64_t hash = 0;
|
||||
while (!tableData.eof()) {
|
||||
hash = 0;
|
||||
CDBehaviorParameter entry;
|
||||
entry.behaviorID = tableData.getIntField(0, -1);
|
||||
auto candidateStringToAdd = std::string(tableData.getStringField(1, ""));
|
||||
entry.behaviorID = tableData.getIntField("behaviorID", -1);
|
||||
auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", ""));
|
||||
auto parameter = m_ParametersList.find(candidateStringToAdd);
|
||||
if (parameter != m_ParametersList.end()) {
|
||||
entry.parameterID = parameter;
|
||||
} else {
|
||||
entry.parameterID = m_ParametersList.insert(candidateStringToAdd).first;
|
||||
entry.parameterID = m_ParametersList.insert(std::make_pair(candidateStringToAdd, uniqueParameterId)).first;
|
||||
uniqueParameterId++;
|
||||
}
|
||||
entry.value = tableData.getFloatField(2, -1.0f);
|
||||
hash = entry.behaviorID;
|
||||
hash = (hash << 31U) | entry.parameterID->second;
|
||||
entry.value = tableData.getFloatField("value", -1.0f);
|
||||
|
||||
GeneralUtils::hash_combine(hash, entry.behaviorID);
|
||||
GeneralUtils::hash_combine(hash, *entry.parameterID);
|
||||
|
||||
auto it = m_Entries.find(entry.behaviorID);
|
||||
m_ParametersList.insert(*entry.parameterID);
|
||||
m_Entries.insert(std::make_pair(hash, entry));
|
||||
|
||||
tableData.nextRow();
|
||||
@@ -30,40 +27,30 @@ CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDBehaviorParameterTable::~CDBehaviorParameterTable(void) {}
|
||||
float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
|
||||
auto parameterID = this->m_ParametersList.find(name);
|
||||
if (parameterID == this->m_ParametersList.end()) return defaultValue;
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDBehaviorParameterTable::GetName(void) const {
|
||||
return "BehaviorParameter";
|
||||
}
|
||||
uint64_t hash = behaviorID;
|
||||
|
||||
CDBehaviorParameter CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
|
||||
CDBehaviorParameter returnValue;
|
||||
returnValue.behaviorID = 0;
|
||||
returnValue.parameterID = m_ParametersList.end();
|
||||
returnValue.value = defaultValue;
|
||||
|
||||
size_t hash = 0;
|
||||
GeneralUtils::hash_combine(hash, behaviorID);
|
||||
GeneralUtils::hash_combine(hash, name);
|
||||
hash = (hash << 31U) | parameterID->second;
|
||||
|
||||
// Search for specific parameter
|
||||
const auto& it = m_Entries.find(hash);
|
||||
return it != m_Entries.end() ? it->second : returnValue;
|
||||
return it != m_Entries.end() ? it->second.value : defaultValue;
|
||||
}
|
||||
|
||||
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
|
||||
size_t hash;
|
||||
uint64_t hashBase = behaviorID;
|
||||
std::map<std::string, float> returnInfo;
|
||||
for (auto parameterCandidate : m_ParametersList) {
|
||||
hash = 0;
|
||||
GeneralUtils::hash_combine(hash, behaviorID);
|
||||
GeneralUtils::hash_combine(hash, parameterCandidate);
|
||||
uint64_t hash;
|
||||
for (auto& parameterCandidate : m_ParametersList) {
|
||||
hash = (hashBase << 31U) | parameterCandidate.second;
|
||||
auto infoCandidate = m_Entries.find(hash);
|
||||
if (infoCandidate != m_Entries.end()) {
|
||||
returnInfo.insert(std::make_pair(*(infoCandidate->second.parameterID), infoCandidate->second.value));
|
||||
returnInfo.insert(std::make_pair(infoCandidate->second.parameterID->first, infoCandidate->second.value));
|
||||
}
|
||||
}
|
||||
return returnInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,38 +5,19 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
/*!
|
||||
\file CDBehaviorParameterTable.hpp
|
||||
\brief Contains data for the BehaviorParameter table
|
||||
*/
|
||||
|
||||
//! BehaviorParameter Entry Struct
|
||||
struct CDBehaviorParameter {
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
std::unordered_set<std::string>::iterator parameterID; //!< The Parameter ID
|
||||
float value; //!< The value of the behavior template
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
std::unordered_map<std::string, uint32_t>::iterator parameterID; //!< The Parameter ID
|
||||
float value; //!< The value of the behavior template
|
||||
};
|
||||
|
||||
//! BehaviorParameter table
|
||||
class CDBehaviorParameterTable : public CDTable {
|
||||
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable> {
|
||||
private:
|
||||
std::unordered_map<size_t, CDBehaviorParameter> m_Entries;
|
||||
std::unordered_set<std::string> m_ParametersList;
|
||||
std::unordered_map<uint64_t, CDBehaviorParameter> m_Entries;
|
||||
std::unordered_map<std::string, uint32_t> m_ParametersList;
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CDBehaviorParameterTable(void);
|
||||
|
||||
//! Destructor
|
||||
~CDBehaviorParameterTable(void);
|
||||
|
||||
//! Returns the table's name
|
||||
/*!
|
||||
\return The table name
|
||||
*/
|
||||
std::string GetName(void) const override;
|
||||
|
||||
CDBehaviorParameter GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0);
|
||||
CDBehaviorParameterTable();
|
||||
float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0);
|
||||
|
||||
std::map<std::string, float> GetParametersByBehaviorID(uint32_t behaviorID);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "CDBehaviorTemplateTable.h"
|
||||
|
||||
//! Constructor
|
||||
CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
|
||||
|
||||
// First, get the size of the table
|
||||
@@ -21,9 +20,9 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
|
||||
while (!tableData.eof()) {
|
||||
CDBehaviorTemplate entry;
|
||||
entry.behaviorID = tableData.getIntField(0, -1);
|
||||
entry.templateID = tableData.getIntField(1, -1);
|
||||
entry.effectID = tableData.getIntField(2, -1);
|
||||
entry.behaviorID = tableData.getIntField("behaviorID", -1);
|
||||
entry.templateID = tableData.getIntField("templateID", -1);
|
||||
entry.effectID = tableData.getIntField("effectID", -1);
|
||||
auto candidateToAdd = tableData.getStringField(3, "");
|
||||
auto parameter = m_EffectHandles.find(candidateToAdd);
|
||||
if (parameter != m_EffectHandles.end()) {
|
||||
@@ -40,15 +39,6 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDBehaviorTemplateTable::~CDBehaviorTemplateTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDBehaviorTemplateTable::GetName(void) const {
|
||||
return "BehaviorTemplate";
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<bool(CDBehaviorTemplate)> predicate) {
|
||||
|
||||
std::vector<CDBehaviorTemplate> data = cpplinq::from(this->entries)
|
||||
@@ -58,7 +48,6 @@ std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<boo
|
||||
return data;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
|
||||
return this->entries;
|
||||
}
|
||||
@@ -75,3 +64,4 @@ const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behav
|
||||
return entry->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,6 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
/*!
|
||||
\file CDBehaviorTemplateTable.hpp
|
||||
\brief Contains data for the BehaviorTemplate table
|
||||
*/
|
||||
|
||||
//! BehaviorTemplate Entry Struct
|
||||
struct CDBehaviorTemplate {
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
unsigned int templateID; //!< The Template ID (LOT)
|
||||
@@ -19,36 +13,16 @@ struct CDBehaviorTemplate {
|
||||
};
|
||||
|
||||
|
||||
//! BehaviorTemplate table
|
||||
class CDBehaviorTemplateTable : public CDTable {
|
||||
class CDBehaviorTemplateTable : public CDTable<CDBehaviorTemplateTable> {
|
||||
private:
|
||||
std::vector<CDBehaviorTemplate> entries;
|
||||
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
|
||||
std::unordered_set<std::string> m_EffectHandles;
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CDBehaviorTemplateTable(void);
|
||||
|
||||
//! Destructor
|
||||
~CDBehaviorTemplateTable(void);
|
||||
|
||||
//! Returns the table's name
|
||||
/*!
|
||||
\return The table name
|
||||
*/
|
||||
std::string GetName(void) const override;
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
/*!
|
||||
\param predicate The predicate
|
||||
*/
|
||||
CDBehaviorTemplateTable();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
|
||||
|
||||
//! Gets all the entries in the table
|
||||
/*!
|
||||
\return The entries
|
||||
*/
|
||||
std::vector<CDBehaviorTemplate> GetEntries(void) const;
|
||||
|
||||
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "CDBrickIDTableTable.h"
|
||||
|
||||
//! Constructor
|
||||
CDBrickIDTableTable::CDBrickIDTableTable(void) {
|
||||
|
||||
// First, get the size of the table
|
||||
@@ -21,8 +20,8 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable");
|
||||
while (!tableData.eof()) {
|
||||
CDBrickIDTable entry;
|
||||
entry.NDObjectID = tableData.getIntField(0, -1);
|
||||
entry.LEGOBrickID = tableData.getIntField(1, -1);
|
||||
entry.NDObjectID = tableData.getIntField("NDObjectID", -1);
|
||||
entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
@@ -31,15 +30,6 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) {
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Destructor
|
||||
CDBrickIDTableTable::~CDBrickIDTableTable(void) {}
|
||||
|
||||
//! Returns the table's name
|
||||
std::string CDBrickIDTableTable::GetName(void) const {
|
||||
return "BrickIDTable";
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBrickIDTable)> predicate) {
|
||||
|
||||
std::vector<CDBrickIDTable> data = cpplinq::from(this->entries)
|
||||
@@ -49,7 +39,7 @@ std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBric
|
||||
return data;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
std::vector<CDBrickIDTable> CDBrickIDTableTable::GetEntries(void) const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,34 +16,14 @@ struct CDBrickIDTable {
|
||||
|
||||
|
||||
//! BrickIDTable table
|
||||
class CDBrickIDTableTable : public CDTable {
|
||||
class CDBrickIDTableTable : public CDTable<CDBrickIDTableTable> {
|
||||
private:
|
||||
std::vector<CDBrickIDTable> entries;
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
CDBrickIDTableTable(void);
|
||||
|
||||
//! Destructor
|
||||
~CDBrickIDTableTable(void);
|
||||
|
||||
//! Returns the table's name
|
||||
/*!
|
||||
\return The table name
|
||||
*/
|
||||
std::string GetName(void) const override;
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
/*!
|
||||
\param predicate The predicate
|
||||
*/
|
||||
CDBrickIDTableTable();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDBrickIDTable> Query(std::function<bool(CDBrickIDTable)> predicate);
|
||||
|
||||
//! Gets all the entries in the table
|
||||
/*!
|
||||
\return The entries
|
||||
*/
|
||||
std::vector<CDBrickIDTable> GetEntries(void) const;
|
||||
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user