mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-24 06:27:24 +00:00
Merge branch 'main' into FallSpeedBehavior
This commit is contained in:
commit
565b23227e
@ -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
|
|
76
.editorconfig
Normal file
76
.editorconfig
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
# top-most EditorConfig file
|
||||||
|
root=true
|
||||||
|
|
||||||
|
# Unix-style newlines with a newline ending every file
|
||||||
|
[*]
|
||||||
|
indent_style=tab
|
||||||
|
tab_width=4
|
||||||
|
charset=utf-8
|
||||||
|
trim_trailing_whitespace=true
|
||||||
|
end_of_line=lf
|
||||||
|
insert_final_newline=true
|
||||||
|
|
||||||
|
[*.{c++,cc,cpp,cxx,h,h++,hh,hpp,hxx,inl,ipp,tlh,tli}]
|
||||||
|
|
||||||
|
vc_generate_documentation_comments=doxygen_slash_star
|
||||||
|
|
||||||
|
cpp_indent_braces=false
|
||||||
|
cpp_alignment_tab_fill_style=use_spaces
|
||||||
|
cpp_indent_multi_line_relative_to=innermost_parenthesis
|
||||||
|
cpp_indent_within_parentheses=indent
|
||||||
|
cpp_indent_preserve_within_parentheses=false
|
||||||
|
cpp_indent_case_labels=false
|
||||||
|
cpp_indent_case_contents=true
|
||||||
|
cpp_indent_case_contents_when_block=false
|
||||||
|
cpp_indent_lambda_braces_when_parameter=true
|
||||||
|
cpp_indent_goto_labels=one_left
|
||||||
|
cpp_indent_preprocessor=leftmost_column
|
||||||
|
cpp_indent_access_specifiers=false
|
||||||
|
cpp_indent_namespace_contents=true
|
||||||
|
cpp_indent_preserve_comments=false
|
||||||
|
cpp_new_line_before_open_brace_namespace=same_line
|
||||||
|
cpp_new_line_before_open_brace_type=same_line
|
||||||
|
cpp_new_line_before_open_brace_function=same_line
|
||||||
|
cpp_new_line_before_open_brace_block=same_line
|
||||||
|
cpp_new_line_before_open_brace_lambda=same_line
|
||||||
|
cpp_new_line_scope_braces_on_separate_lines=false
|
||||||
|
cpp_new_line_close_brace_same_line_empty_type=false
|
||||||
|
cpp_new_line_close_brace_same_line_empty_function=false
|
||||||
|
cpp_new_line_before_catch=false
|
||||||
|
cpp_new_line_before_else=false
|
||||||
|
cpp_new_line_before_while_in_do_while=false
|
||||||
|
cpp_space_before_function_open_parenthesis=remove
|
||||||
|
cpp_space_within_parameter_list_parentheses=false
|
||||||
|
cpp_space_between_empty_parameter_list_parentheses=false
|
||||||
|
cpp_space_after_keywords_in_control_flow_statements=true
|
||||||
|
cpp_space_within_control_flow_statement_parentheses=false
|
||||||
|
cpp_space_before_lambda_open_parenthesis=false
|
||||||
|
cpp_space_within_cast_parentheses=false
|
||||||
|
cpp_space_after_cast_close_parenthesis=false
|
||||||
|
cpp_space_within_expression_parentheses=false
|
||||||
|
cpp_space_before_block_open_brace=true
|
||||||
|
cpp_space_between_empty_braces=false
|
||||||
|
cpp_space_before_initializer_list_open_brace=false
|
||||||
|
cpp_space_within_initializer_list_braces=true
|
||||||
|
cpp_space_preserve_in_initializer_list=true
|
||||||
|
cpp_space_before_open_square_bracket=false
|
||||||
|
cpp_space_within_square_brackets=false
|
||||||
|
cpp_space_before_empty_square_brackets=false
|
||||||
|
cpp_space_between_empty_square_brackets=false
|
||||||
|
cpp_space_group_square_brackets=true
|
||||||
|
cpp_space_within_lambda_brackets=false
|
||||||
|
cpp_space_between_empty_lambda_brackets=false
|
||||||
|
cpp_space_before_comma=false
|
||||||
|
cpp_space_after_comma=true
|
||||||
|
cpp_space_remove_around_member_operators=true
|
||||||
|
cpp_space_before_inheritance_colon=true
|
||||||
|
cpp_space_before_constructor_colon=true
|
||||||
|
cpp_space_remove_before_semicolon=true
|
||||||
|
cpp_space_after_semicolon=false
|
||||||
|
cpp_space_remove_around_unary_operator=true
|
||||||
|
cpp_space_around_binary_operator=insert
|
||||||
|
cpp_space_around_assignment_operator=insert
|
||||||
|
cpp_space_pointer_reference_alignment=left
|
||||||
|
cpp_space_around_ternary_operator=insert
|
||||||
|
cpp_wrap_preserve_blocks=one_liners
|
||||||
|
cpp_indent_comment=fasle
|
11
.git-blame-ignore-revs
Normal file
11
.git-blame-ignore-revs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# format codebase
|
||||||
|
19e77a38d837ce781ba0ca6ea8e78b67a6e3b5a5
|
||||||
|
|
||||||
|
# add semi-colons to macros consistently
|
||||||
|
9e4ce24fd2851e65df776dd9c57bcb0d45f4453a
|
||||||
|
|
||||||
|
# convert to unix line endings
|
||||||
|
72477e01e2711e0f61cdb192ee266e5e21b8846f
|
||||||
|
|
||||||
|
# enum cleanup
|
||||||
|
faf42d2f8cf432df2993b031f079b0b8c6d7dbe7
|
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -1 +1 @@
|
|||||||
*.sh eol=lf
|
* text=auto eol=lf
|
||||||
|
12
.github/workflows/build-and-test.yml
vendored
12
.github/workflows/build-and-test.yml
vendored
@ -10,20 +10,24 @@ jobs:
|
|||||||
build-and-test:
|
build-and-test:
|
||||||
name: Build & Test (${{ matrix.os }})
|
name: Build & Test (${{ matrix.os }})
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ windows-2022, ubuntu-20.04 ]
|
os: [ windows-2022, ubuntu-20.04, macos-11 ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Add msbuild to PATH (windows only)
|
- name: Add msbuild to PATH (Windows only)
|
||||||
if: ${{ matrix.os == 'windows-2022' }}
|
if: ${{ matrix.os == 'windows-2022' }}
|
||||||
uses: microsoft/setup-msbuild@v1.1
|
uses: microsoft/setup-msbuild@v1.1
|
||||||
with:
|
with:
|
||||||
vs-version: '[17,18)'
|
vs-version: '[17,18)'
|
||||||
msbuild-architecture: x64
|
msbuild-architecture: x64
|
||||||
|
- name: Install libssl (Mac Only)
|
||||||
|
if: ${{ matrix.os == 'macos-11' }}
|
||||||
|
run: brew install openssl@3
|
||||||
- name: cmake
|
- name: cmake
|
||||||
uses: lukka/run-cmake@v10
|
uses: lukka/run-cmake@v10
|
||||||
with:
|
with:
|
||||||
@ -31,7 +35,7 @@ jobs:
|
|||||||
buildPreset: "ci-${{matrix.os}}"
|
buildPreset: "ci-${{matrix.os}}"
|
||||||
testPreset: "ci-${{matrix.os}}"
|
testPreset: "ci-${{matrix.os}}"
|
||||||
- name: artifacts
|
- name: artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
if: ${{ github.ref == 'ref/head/main' }}
|
if: ${{ github.ref == 'ref/head/main' }}
|
||||||
with:
|
with:
|
||||||
name: build-${{matrix.os}}
|
name: build-${{matrix.os}}
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -120,3 +120,5 @@ thirdparty/zlib-1.2.11/
|
|||||||
docker/__pycache__
|
docker/__pycache__
|
||||||
|
|
||||||
docker-compose.override.yml
|
docker-compose.override.yml
|
||||||
|
|
||||||
|
!*Test.bin
|
||||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -14,12 +14,6 @@
|
|||||||
path = thirdparty/mariadb-connector-cpp
|
path = thirdparty/mariadb-connector-cpp
|
||||||
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
|
url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git
|
||||||
ignore = dirty
|
ignore = dirty
|
||||||
[submodule "thirdparty/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"]
|
[submodule "thirdparty/AccountManager"]
|
||||||
path = thirdparty/AccountManager
|
path = thirdparty/AccountManager
|
||||||
url = https://github.com/DarkflameUniverse/AccountManager
|
url = https://github.com/DarkflameUniverse/AccountManager
|
||||||
|
754
CMakeLists.txt
754
CMakeLists.txt
@ -1,7 +1,9 @@
|
|||||||
cmake_minimum_required(VERSION 3.14)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
project(Darkflame)
|
project(Darkflame)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
|
set (CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
# Read variables from file
|
# Read variables from file
|
||||||
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
|
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
|
||||||
|
|
||||||
@ -10,447 +12,361 @@ string(REPLACE "\n" ";" variables ${variables})
|
|||||||
|
|
||||||
# Set the cmake variables, formatted as "VARIABLE #" in variables
|
# Set the cmake variables, formatted as "VARIABLE #" in variables
|
||||||
foreach(variable ${variables})
|
foreach(variable ${variables})
|
||||||
# If the string contains a #, skip it
|
# If the string contains a #, skip it
|
||||||
if(NOT "${variable}" MATCHES "#")
|
if(NOT "${variable}" MATCHES "#")
|
||||||
|
|
||||||
# Split the variable into name and value
|
# Split the variable into name and value
|
||||||
string(REPLACE "=" ";" variable ${variable})
|
string(REPLACE "=" ";" variable ${variable})
|
||||||
|
|
||||||
# Check that the length of the variable is 2 (name and value)
|
# Check that the length of the variable is 2 (name and value)
|
||||||
list(LENGTH variable length)
|
list(LENGTH variable length)
|
||||||
if(${length} EQUAL 2)
|
if(${length} EQUAL 2)
|
||||||
|
|
||||||
list(GET variable 0 variable_name)
|
list(GET variable 0 variable_name)
|
||||||
list(GET variable 1 variable_value)
|
list(GET variable 1 variable_value)
|
||||||
|
|
||||||
# Set the variable
|
# Set the variable
|
||||||
set(${variable_name} ${variable_value})
|
set(${variable_name} ${variable_value})
|
||||||
|
|
||||||
# Add compiler definition
|
# Add compiler definition
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}")
|
||||||
|
|
||||||
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# On windows it's better to build this from source, as there's no way FindZLIB is gonna find it
|
|
||||||
if(NOT WIN32)
|
|
||||||
find_package(ZLIB REQUIRED)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Fetch External (Non-Submodule) Libraries
|
|
||||||
if(WIN32)
|
|
||||||
include(FetchContent)
|
|
||||||
|
|
||||||
FetchContent_Declare(
|
|
||||||
zlib
|
|
||||||
URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip
|
|
||||||
URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1
|
|
||||||
)
|
|
||||||
|
|
||||||
FetchContent_MakeAvailable(zlib)
|
|
||||||
|
|
||||||
set(ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR})
|
|
||||||
set_target_properties(zlib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIRS}") # Why?
|
|
||||||
add_library(ZLIB::ZLIB ALIAS zlib) # You're welcome
|
|
||||||
|
|
||||||
endif(WIN32)
|
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE)
|
|
||||||
include(FetchContent)
|
|
||||||
if (__include_backtrace__ AND __compile_backtrace__)
|
|
||||||
FetchContent_Declare(
|
|
||||||
backtrace
|
|
||||||
GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git
|
|
||||||
)
|
|
||||||
|
|
||||||
FetchContent_MakeAvailable(backtrace)
|
|
||||||
|
|
||||||
if (NOT EXISTS ${backtrace_SOURCE_DIR}/.libs)
|
|
||||||
set(backtrace_make_cmd "${backtrace_SOURCE_DIR}/configure --prefix=\"/usr\" --enable-shared --with-system-libunwind")
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND bash -c "cd ${backtrace_SOURCE_DIR} && ${backtrace_make_cmd} && make && cd ${CMAKE_SOURCE_DIR}"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
link_directories(${backtrace_SOURCE_DIR}/.libs/)
|
|
||||||
include_directories(${backtrace_SOURCE_DIR})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Set the version
|
# Set the version
|
||||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}")
|
|
||||||
|
|
||||||
# Echo the version
|
# Echo the version
|
||||||
message(STATUS "Version: ${PROJECT_VERSION}")
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
# Disable demo, tests and examples for recastNavigation. Turn these to ON if you want to use them
|
||||||
|
# This has to be done here to prevent a rare build error due to missing dependencies on the initial generations.
|
||||||
if(WIN32)
|
set(RECASTNAVIGATION_DEMO OFF CACHE BOOL "" FORCE)
|
||||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
set(RECASTNAVIGATION_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
endif(WIN32)
|
set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
# Our output dir
|
|
||||||
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR})
|
|
||||||
|
|
||||||
# Create a /res directory
|
|
||||||
make_directory(${CMAKE_BINARY_DIR}/res)
|
|
||||||
|
|
||||||
# Create a /locale directory
|
|
||||||
make_directory(${CMAKE_BINARY_DIR}/locale)
|
|
||||||
|
|
||||||
# Create a /logs directory
|
|
||||||
make_directory(${CMAKE_BINARY_DIR}/logs)
|
|
||||||
|
|
||||||
# Copy ini files on first build
|
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/authconfig.ini)
|
|
||||||
configure_file(
|
|
||||||
${CMAKE_SOURCE_DIR}/resources/authconfig.ini ${PROJECT_BINARY_DIR}/authconfig.ini
|
|
||||||
COPYONLY
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/chatconfig.ini)
|
|
||||||
configure_file(
|
|
||||||
${CMAKE_SOURCE_DIR}/resources/chatconfig.ini ${PROJECT_BINARY_DIR}/chatconfig.ini
|
|
||||||
COPYONLY
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/worldconfig.ini)
|
|
||||||
configure_file(
|
|
||||||
${CMAKE_SOURCE_DIR}/resources/worldconfig.ini ${PROJECT_BINARY_DIR}/worldconfig.ini
|
|
||||||
COPYONLY
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/masterconfig.ini)
|
|
||||||
configure_file(
|
|
||||||
${CMAKE_SOURCE_DIR}/resources/masterconfig.ini ${PROJECT_BINARY_DIR}/masterconfig.ini
|
|
||||||
COPYONLY
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Copy files to output
|
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/CREDITS.md" "${CMAKE_BINARY_DIR}/vanity/CREDITS.md" COPYONLY)
|
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/INFO.md" "${CMAKE_BINARY_DIR}/vanity/INFO.md" COPYONLY)
|
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/TESTAMENT.md" "${CMAKE_BINARY_DIR}/vanity/TESTAMENT.md" COPYONLY)
|
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/NPC.xml" "${CMAKE_BINARY_DIR}/vanity/NPC.xml" COPYONLY)
|
|
||||||
|
|
||||||
# 3rdparty includes
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/raknet/Source/)
|
|
||||||
if(APPLE)
|
|
||||||
include_directories(/usr/local/include/)
|
|
||||||
endif(APPLE)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Include)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Include)
|
|
||||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
# Bcrypt
|
|
||||||
if (NOT WIN32)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt)
|
|
||||||
else ()
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Our includes
|
|
||||||
include_directories(${PROJECT_BINARY_DIR})
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dChatFilter/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dBehaviors)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dComponents)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dGameMessages)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dInventory)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dMission)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dEntity)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dUtilities)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dPhysics/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dZoneManager/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dDatabase/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dDatabase/Tables/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/SQLite/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/cpplinq/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dNet/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dScripts/)
|
|
||||||
|
|
||||||
# Lib folders:
|
|
||||||
link_directories(${PROJECT_BINARY_DIR})
|
|
||||||
|
|
||||||
# Third-Party libraries
|
|
||||||
add_subdirectory(thirdparty)
|
|
||||||
|
|
||||||
# Source Code
|
|
||||||
file(
|
|
||||||
GLOB SOURCES
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dWorldServer/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for AuthServer
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_AUTH
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dAuthServer/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for MasterServer
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_MASTER
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dMasterServer/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for ChatServer
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_CHAT
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dChatServer/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for dCommon
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_DCOMMON
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dCommon/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for dChatFilter
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_DCHATFILTER
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dChatFilter/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for dDatabase
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_DDATABASE
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dDatabase/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
file(
|
|
||||||
GLOB HEADERS_DDATABASE
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
${PROJECT_SOURCE_DIR}/dDatabase/*.h
|
|
||||||
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h
|
|
||||||
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
|
||||||
)
|
|
||||||
|
|
||||||
file(
|
|
||||||
GLOB HEADERS_DZONEMANAGER
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
${PROJECT_SOURCE_DIR}/dZoneManager/*.h
|
|
||||||
)
|
|
||||||
|
|
||||||
file(
|
|
||||||
GLOB HEADERS_DCOMMON
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
${PROJECT_SOURCE_DIR}/dCommon/*.h
|
|
||||||
)
|
|
||||||
|
|
||||||
file(
|
|
||||||
GLOB HEADERS_DGAME
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/Entity.h
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/EntityManager.h
|
|
||||||
${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for dNet
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_DNET
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dNet/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for dGame
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_DGAME
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/dBehaviors/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/dComponents/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/dInventory/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/dMission/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/dEntity/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dGame/dUtilities/*.cpp
|
|
||||||
${PROJECT_SOURCE_DIR}/dScripts/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for dZoneManager
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_DZM
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dZoneManager/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
# Source Code for dPhysics
|
|
||||||
file(
|
|
||||||
GLOB SOURCES_DPHYSICS
|
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dPhysics/*.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
|
||||||
add_compile_options("/wd4267")
|
|
||||||
endif(MSVC)
|
|
||||||
|
|
||||||
# Our static libraries:
|
|
||||||
add_library(dCommon ${SOURCES_DCOMMON})
|
|
||||||
add_library(dChatFilter ${SOURCES_DCHATFILTER})
|
|
||||||
add_library(dDatabase ${SOURCES_DDATABASE})
|
|
||||||
add_library(dNet ${SOURCES_DNET})
|
|
||||||
add_library(dGame ${SOURCES_DGAME})
|
|
||||||
add_library(dZoneManager ${SOURCES_DZM})
|
|
||||||
add_library(dPhysics ${SOURCES_DPHYSICS})
|
|
||||||
target_link_libraries(dDatabase sqlite3)
|
|
||||||
target_link_libraries(dNet dCommon) #Needed because otherwise linker errors occur.
|
|
||||||
target_link_libraries(dCommon ZLIB::ZLIB)
|
|
||||||
target_link_libraries(dCommon libbcrypt)
|
|
||||||
target_link_libraries(dDatabase mariadbConnCpp)
|
|
||||||
target_link_libraries(dNet dDatabase)
|
|
||||||
target_link_libraries(dGame dDatabase)
|
|
||||||
target_link_libraries(dChatFilter dDatabase)
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
target_link_libraries(raknet ws2_32)
|
|
||||||
endif(WIN32)
|
|
||||||
|
|
||||||
# Our executables:
|
|
||||||
add_executable(WorldServer ${SOURCES})
|
|
||||||
add_executable(AuthServer ${SOURCES_AUTH})
|
|
||||||
add_executable(MasterServer ${SOURCES_MASTER})
|
|
||||||
add_executable(ChatServer ${SOURCES_CHAT})
|
|
||||||
|
|
||||||
# Add out precompiled headers
|
|
||||||
target_precompile_headers(
|
|
||||||
dGame PRIVATE
|
|
||||||
${HEADERS_DGAME}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_precompile_headers(
|
|
||||||
dZoneManager PRIVATE
|
|
||||||
${HEADERS_DZONEMANAGER}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Need to specify to use the CXX compiler language here or else we get errors including <string>.
|
|
||||||
target_precompile_headers(
|
|
||||||
dDatabase PRIVATE
|
|
||||||
"$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
|
|
||||||
)
|
|
||||||
|
|
||||||
target_precompile_headers(
|
|
||||||
dCommon PRIVATE
|
|
||||||
${HEADERS_DCOMMON}
|
|
||||||
)
|
|
||||||
|
|
||||||
target_precompile_headers(
|
|
||||||
tinyxml2 PRIVATE
|
|
||||||
"$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Target libraries to link to:
|
|
||||||
target_link_libraries(WorldServer dCommon)
|
|
||||||
target_link_libraries(WorldServer dChatFilter)
|
|
||||||
target_link_libraries(WorldServer dDatabase)
|
|
||||||
target_link_libraries(WorldServer dNet)
|
|
||||||
target_link_libraries(WorldServer dGame)
|
|
||||||
target_link_libraries(WorldServer dZoneManager)
|
|
||||||
target_link_libraries(WorldServer dPhysics)
|
|
||||||
target_link_libraries(WorldServer detour)
|
|
||||||
target_link_libraries(WorldServer recast)
|
|
||||||
target_link_libraries(WorldServer raknet)
|
|
||||||
target_link_libraries(WorldServer mariadbConnCpp)
|
|
||||||
if(UNIX)
|
|
||||||
if(NOT APPLE AND __include_backtrace__)
|
|
||||||
target_link_libraries(WorldServer backtrace)
|
|
||||||
target_link_libraries(MasterServer backtrace)
|
|
||||||
target_link_libraries(AuthServer backtrace)
|
|
||||||
target_link_libraries(ChatServer backtrace)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endif(UNIX)
|
|
||||||
target_link_libraries(WorldServer tinyxml2)
|
|
||||||
|
|
||||||
# Target libraries for Auth:
|
|
||||||
target_link_libraries(AuthServer dCommon)
|
|
||||||
target_link_libraries(AuthServer dDatabase)
|
|
||||||
target_link_libraries(AuthServer dNet)
|
|
||||||
target_link_libraries(AuthServer raknet)
|
|
||||||
target_link_libraries(AuthServer mariadbConnCpp)
|
|
||||||
if(UNIX)
|
|
||||||
target_link_libraries(AuthServer pthread)
|
|
||||||
target_link_libraries(AuthServer dl)
|
|
||||||
endif(UNIX)
|
|
||||||
|
|
||||||
# Target libraries for Master:
|
|
||||||
target_link_libraries(MasterServer dCommon)
|
|
||||||
target_link_libraries(MasterServer dDatabase)
|
|
||||||
target_link_libraries(MasterServer dNet)
|
|
||||||
target_link_libraries(MasterServer raknet)
|
|
||||||
target_link_libraries(MasterServer mariadbConnCpp)
|
|
||||||
if(UNIX)
|
|
||||||
target_link_libraries(MasterServer pthread)
|
|
||||||
target_link_libraries(MasterServer dl)
|
|
||||||
endif(UNIX)
|
|
||||||
|
|
||||||
# Target libraries for Chat:
|
|
||||||
target_link_libraries(ChatServer dCommon)
|
|
||||||
target_link_libraries(ChatServer dChatFilter)
|
|
||||||
target_link_libraries(ChatServer dDatabase)
|
|
||||||
target_link_libraries(ChatServer dNet)
|
|
||||||
target_link_libraries(ChatServer raknet)
|
|
||||||
target_link_libraries(ChatServer mariadbConnCpp)
|
|
||||||
if(UNIX)
|
|
||||||
target_link_libraries(ChatServer pthread)
|
|
||||||
target_link_libraries(ChatServer dl)
|
|
||||||
endif(UNIX)
|
|
||||||
|
|
||||||
# Compiler flags:
|
# Compiler flags:
|
||||||
# Disabled deprecated warnings as the MySQL includes have deprecated code in them.
|
# Disabled deprecated warnings as the MySQL includes have deprecated code in them.
|
||||||
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
|
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
|
||||||
# Disabled no-register
|
# Disabled no-register
|
||||||
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}")
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
if(APPLE)
|
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")
|
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()
|
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()
|
endif()
|
||||||
if (__dynamic)
|
if (__dynamic AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
|
||||||
endif()
|
endif()
|
||||||
if (__ggdb)
|
if (__ggdb)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
|
||||||
endif()
|
endif()
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
||||||
endif(UNIX)
|
elseif(MSVC)
|
||||||
|
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
||||||
if(WIN32)
|
add_compile_options("/wd4267" "/utf-8")
|
||||||
add_dependencies(MasterServer WorldServer)
|
elseif(WIN32)
|
||||||
add_dependencies(MasterServer AuthServer)
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
add_dependencies(MasterServer ChatServer)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Finally, add the tests
|
# Our output dir
|
||||||
add_subdirectory(tests)
|
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 /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 "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(
|
||||||
|
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
|
||||||
|
COPYONLY
|
||||||
|
)
|
||||||
|
message("Moved ${resource_file} to project binary directory")
|
||||||
|
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})
|
||||||
|
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Move our migrations for MasterServer to run
|
||||||
|
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/dlu/)
|
||||||
|
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql)
|
||||||
|
foreach(file ${SQL_FILES})
|
||||||
|
get_filename_component(file ${file} NAME)
|
||||||
|
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/dlu/${file})
|
||||||
|
configure_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()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Create our list of include directories
|
||||||
|
set(INCLUDED_DIRECTORIES
|
||||||
|
"dCommon"
|
||||||
|
"dCommon/dClient"
|
||||||
|
"dCommon/dEnums"
|
||||||
|
"dChatFilter"
|
||||||
|
"dGame"
|
||||||
|
"dGame/dBehaviors"
|
||||||
|
"dGame/dComponents"
|
||||||
|
"dGame/dGameMessages"
|
||||||
|
"dGame/dInventory"
|
||||||
|
"dGame/dMission"
|
||||||
|
"dGame/dEntity"
|
||||||
|
"dGame/dPropertyBehaviors"
|
||||||
|
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
|
||||||
|
"dGame/dUtilities"
|
||||||
|
"dPhysics"
|
||||||
|
"dNavigation"
|
||||||
|
"dNavigation/dTerrain"
|
||||||
|
"dZoneManager"
|
||||||
|
"dDatabase"
|
||||||
|
"dDatabase/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)
|
||||||
|
if (APPLE)
|
||||||
|
include_directories("/usr/local/include/")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include")
|
||||||
|
elseif (UNIX)
|
||||||
|
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt")
|
||||||
|
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add binary directory as an include directory
|
||||||
|
include_directories(${PROJECT_BINARY_DIR})
|
||||||
|
|
||||||
|
# Actually include the directories from our list
|
||||||
|
foreach (dir ${INCLUDED_DIRECTORIES})
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/${dir})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Add linking directories:
|
||||||
|
link_directories(${PROJECT_BINARY_DIR})
|
||||||
|
|
||||||
|
# Load all of our third party directories
|
||||||
|
add_subdirectory(thirdparty)
|
||||||
|
|
||||||
|
# Glob together all headers that need to be precompiled
|
||||||
|
file(
|
||||||
|
GLOB HEADERS_DDATABASE
|
||||||
|
LIST_DIRECTORIES false
|
||||||
|
${PROJECT_SOURCE_DIR}/dDatabase/*.h
|
||||||
|
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h
|
||||||
|
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
||||||
|
)
|
||||||
|
|
||||||
|
file(
|
||||||
|
GLOB HEADERS_DZONEMANAGER
|
||||||
|
LIST_DIRECTORIES false
|
||||||
|
${PROJECT_SOURCE_DIR}/dZoneManager/*.h
|
||||||
|
)
|
||||||
|
|
||||||
|
file(
|
||||||
|
GLOB HEADERS_DCOMMON
|
||||||
|
LIST_DIRECTORIES false
|
||||||
|
${PROJECT_SOURCE_DIR}/dCommon/*.h
|
||||||
|
)
|
||||||
|
|
||||||
|
file(
|
||||||
|
GLOB HEADERS_DGAME
|
||||||
|
LIST_DIRECTORIES false
|
||||||
|
${PROJECT_SOURCE_DIR}/dGame/Entity.h
|
||||||
|
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h
|
||||||
|
${PROJECT_SOURCE_DIR}/dGame/EntityManager.h
|
||||||
|
${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add our library subdirectories for creation of the library object
|
||||||
|
add_subdirectory(dCommon)
|
||||||
|
add_subdirectory(dDatabase)
|
||||||
|
add_subdirectory(dChatFilter)
|
||||||
|
add_subdirectory(dNet)
|
||||||
|
add_subdirectory(dScripts) # Add for dGame to use
|
||||||
|
add_subdirectory(dGame)
|
||||||
|
add_subdirectory(dZoneManager)
|
||||||
|
add_subdirectory(dNavigation)
|
||||||
|
add_subdirectory(dPhysics)
|
||||||
|
|
||||||
|
# Create a list of common libraries shared between all binaries
|
||||||
|
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp")
|
||||||
|
|
||||||
|
# Add platform specific common libraries
|
||||||
|
if (UNIX)
|
||||||
|
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "dl" "pthread")
|
||||||
|
|
||||||
|
if (NOT APPLE AND __include_backtrace__)
|
||||||
|
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "backtrace")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Include all of our binary directories
|
||||||
|
add_subdirectory(dWorldServer)
|
||||||
|
add_subdirectory(dAuthServer)
|
||||||
|
add_subdirectory(dChatServer)
|
||||||
|
add_subdirectory(dMasterServer) # Add MasterServer last so it can rely on the other binaries
|
||||||
|
|
||||||
|
# Add our precompiled headers
|
||||||
|
target_precompile_headers(
|
||||||
|
dGame PRIVATE
|
||||||
|
${HEADERS_DGAME}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_precompile_headers(
|
||||||
|
dZoneManager PRIVATE
|
||||||
|
${HEADERS_DZONEMANAGER}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Need to specify to use the CXX compiler language here or else we get errors including <string>.
|
||||||
|
target_precompile_headers(
|
||||||
|
dDatabase PRIVATE
|
||||||
|
"$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_precompile_headers(
|
||||||
|
dCommon PRIVATE
|
||||||
|
${HEADERS_DCOMMON}
|
||||||
|
)
|
||||||
|
|
||||||
|
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,98 +1,128 @@
|
|||||||
{
|
{
|
||||||
"version": 3,
|
"version": 3,
|
||||||
"cmakeMinimumRequired": {
|
"cmakeMinimumRequired": {
|
||||||
"major": 3,
|
"major": 3,
|
||||||
"minor": 14,
|
"minor": 14,
|
||||||
"patch": 0
|
"patch": 0
|
||||||
},
|
|
||||||
"configurePresets": [
|
|
||||||
{
|
|
||||||
"name": "default",
|
|
||||||
"displayName": "Default configure step",
|
|
||||||
"description": "Use 'build' dir and Unix makefiles",
|
|
||||||
"binaryDir": "${sourceDir}/build",
|
|
||||||
"generator": "Unix Makefiles"
|
|
||||||
},
|
},
|
||||||
{
|
"configurePresets": [
|
||||||
"name": "ci-ubuntu-20.04",
|
{
|
||||||
"displayName": "CI configure step for Ubuntu",
|
"name": "default",
|
||||||
"description": "Same as default, Used in GitHub actions workflow",
|
"displayName": "Default configure step",
|
||||||
"inherits": "default"
|
"description": "Use 'build' dir and Unix makefiles",
|
||||||
},
|
"binaryDir": "${sourceDir}/build",
|
||||||
{
|
"generator": "Unix Makefiles"
|
||||||
"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": "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"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
],
|
||||||
{
|
"buildPresets": [
|
||||||
"name": "windows-default",
|
{
|
||||||
"inherits": "ci-windows-2022",
|
"name": "default",
|
||||||
"displayName": "Windows only Configure Settings",
|
"configurePreset": "default",
|
||||||
"description": "Sets build and install directories",
|
"displayName": "Default Build",
|
||||||
"generator": "Ninja",
|
"description": "Default Build",
|
||||||
"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
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"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
|
"jobs": 2
|
||||||
},
|
},
|
||||||
"output": {
|
{
|
||||||
"outputOnFailure": true
|
"name": "ci-windows-2022",
|
||||||
}
|
"configurePreset": "ci-windows-2022",
|
||||||
},
|
"displayName": "Windows CI Build",
|
||||||
{
|
"description": "This preset is used by the CI build on windows",
|
||||||
"name": "ci-windows-2022",
|
"configuration": "RelWithDebInfo",
|
||||||
"configurePreset": "ci-windows-2022",
|
|
||||||
"displayName": "CI Tests on windows",
|
|
||||||
"description": "Runs all tests on a windows configuration",
|
|
||||||
"configuration": "RelWithDebInfo",
|
|
||||||
"execution": {
|
|
||||||
"jobs": 2
|
"jobs": 2
|
||||||
},
|
},
|
||||||
"output": {
|
{
|
||||||
"outputOnFailure": true
|
"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": {
|
||||||
|
"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))+"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
PROJECT_VERSION_MAJOR=1
|
PROJECT_VERSION_MAJOR=1
|
||||||
PROJECT_VERSION_MINOR=0
|
PROJECT_VERSION_MINOR=0
|
||||||
PROJECT_VERSION_PATCH=2
|
PROJECT_VERSION_PATCH=4
|
||||||
# LICENSE
|
# LICENSE
|
||||||
LICENSE=AGPL-3.0
|
LICENSE=AGPL-3.0
|
||||||
# The network version.
|
# The network version.
|
||||||
@ -8,13 +8,17 @@ LICENSE=AGPL-3.0
|
|||||||
# 171022 - Unmodded client
|
# 171022 - Unmodded client
|
||||||
NET_VERSION=171022
|
NET_VERSION=171022
|
||||||
# Debugging
|
# Debugging
|
||||||
# __dynamic=1
|
|
||||||
# Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
# Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
||||||
# __ggdb=1
|
__dynamic=1
|
||||||
# Set __ggdb to 1 to enable the -ggdb flag for the linker, including more debug info.
|
# 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.
|
# Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs.
|
||||||
# __compile_backtrace__=1
|
# __include_backtrace__=1
|
||||||
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
|
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
|
||||||
__maria_db_connector_compile_jobs__=1
|
# __compile_backtrace__=1
|
||||||
# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with.
|
# 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/
|
||||||
|
@ -123,6 +123,15 @@ added, which produced InvalidScript errors.
|
|||||||
|
|
||||||
Check out a compiled list of development resources and tools [here](https://lu-dev.net/).
|
Check out a compiled list of development resources and tools [here](https://lu-dev.net/).
|
||||||
|
|
||||||
|
|
||||||
|
Please use [.editorconfig](https://editorconfig.org/#pre-installed) with your preferred IDE.
|
||||||
|
|
||||||
|
And run:
|
||||||
|
```bash
|
||||||
|
git config blame.ignoreRevsFile .git-blame-ignore-revs
|
||||||
|
```
|
||||||
|
to ignore the gitblame of mass formatting commits
|
||||||
|
|
||||||
## Coding Style
|
## Coding Style
|
||||||
|
|
||||||
This project has gone through multiple iterations of coding style. In the code you'll find a number of different coding styles in use. What follows is the preferred style for this project.
|
This project has gone through multiple iterations of coding style. In the code you'll find a number of different coding styles in use. What follows is the preferred style for this project.
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
- [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker)
|
- [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)
|
- [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
|
## Run server inside Docker
|
||||||
|
|
||||||
@ -25,8 +25,7 @@
|
|||||||
|
|
||||||
**NOTE #4**: Make sure to run the following in the repo root directory after cloning so submodules are also downloaded.
|
**NOTE #4**: Make sure to run the following in the repo root directory after cloning so submodules are also downloaded.
|
||||||
```
|
```
|
||||||
git submodule init
|
git submodule update --init --recursive
|
||||||
git submodule update
|
|
||||||
```
|
```
|
||||||
**NOTE #5**: If DarkflameSetup fails due to not having cdclient.fdb, rename CDClient.fdb (in the same folder) to cdclient.fdb
|
**NOTE #5**: If DarkflameSetup fails due to not having cdclient.fdb, rename CDClient.fdb (in the same folder) to cdclient.fdb
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
11. Once the command has completed (you can see you path again and can enter commands), close the window.
|
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`
|
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_.
|
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).
|
> 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.
|
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.
|
||||||
|
604
README.md
604
README.md
@ -18,196 +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.
|
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
|
### 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
|
### 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
|
## Steps to setup server
|
||||||
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.
|
* [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
|
```bash
|
||||||
git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
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
|
### MacOS packages
|
||||||
DLU clients identify themselves using a higher version number than the regular live clients out there.
|
Ensure you have [brew](https://brew.sh) installed.
|
||||||
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.
|
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`.
|
||||||
|
|
||||||
### Linux builds
|
For Ubuntu, you would run the following commands. On other systems, the package install command will differ.
|
||||||
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`.
|
|
||||||
|
|
||||||
CMake must be version 3.14 or higher!
|
```bash
|
||||||
|
sudo apt update && sudo apt upgrade
|
||||||
|
|
||||||
**Build the repository**
|
# Install packages
|
||||||
|
sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-server cmake
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
```
|
||||||
|
|
||||||
|
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:
|
You can either run `build.sh` when in the root folder of the repository:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./build.sh
|
./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
|
```bash
|
||||||
# Create the build directory, preserving it if it already exists
|
./build.sh -j4
|
||||||
mkdir -p build
|
|
||||||
cd build
|
|
||||||
|
|
||||||
# Run CMake to generate make files
|
|
||||||
cmake ..
|
|
||||||
|
|
||||||
# Run make to build the project. To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `make -j8`
|
|
||||||
make
|
|
||||||
```
|
```
|
||||||
|
### 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
|
## Configuring your server
|
||||||
Ensure `cmake`, `zlib` and `open ssl` are installed as well as a compiler (e.g `clang` or `gcc`).
|
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
|
### Required Configuration
|
||||||
```bash
|
Darkflame Universe can run with either a packed or an unpacked client.
|
||||||
# Create the build directory, preserving it if it already exists
|
Navigate to `build/sharedconfig.ini` and fill in the following fields:
|
||||||
mkdir -p build
|
* `mysql_host` (This is the IP address or hostname of your MariaDB server. This is highly likely `localhost`)
|
||||||
cd build
|
* 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
|
### Optional Configuration
|
||||||
cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl
|
* 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.
|
||||||
# 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`
|
* `chatconfig.ini` contains a port option.
|
||||||
cmake --build . --config Release
|
* `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.
|
||||||
### 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
|
|
||||||
|
|
||||||
### 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
|
|
||||||
* Run each SQL file in the order at which they appear [here](migrations/dlu/) on the database
|
|
||||||
|
|
||||||
### 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
|
|
||||||
|
|
||||||
**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.
|
|
||||||
|
|
||||||
**Verify**
|
|
||||||
|
|
||||||
|
## Verify your setup
|
||||||
Your build directory should now look like this:
|
Your build directory should now look like this:
|
||||||
* AuthServer
|
* AuthServer
|
||||||
* ChatServer
|
* ChatServer
|
||||||
@ -216,211 +212,105 @@ Your build directory should now look like this:
|
|||||||
* authconfig.ini
|
* authconfig.ini
|
||||||
* chatconfig.ini
|
* chatconfig.ini
|
||||||
* masterconfig.ini
|
* masterconfig.ini
|
||||||
|
* sharedconfig.ini
|
||||||
* worldconfig.ini
|
* worldconfig.ini
|
||||||
* **locale/**
|
|
||||||
* locale.xml
|
|
||||||
* **res/**
|
|
||||||
* CDServer.sqlite
|
|
||||||
* chatplus_en_us.txt
|
|
||||||
* **macros/**
|
|
||||||
* ...
|
|
||||||
* **BrickModels/**
|
|
||||||
* ...
|
|
||||||
* **maps/**
|
|
||||||
* **navmeshes/**
|
|
||||||
* ...
|
|
||||||
* ...
|
|
||||||
* ...
|
* ...
|
||||||
|
|
||||||
## Running the server
|
## 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
|
### 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!
|
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
|
### 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
|
## Allowing a user to connect to your server
|
||||||
A few modifications have to be made to the client.
|
|
||||||
|
|
||||||
### Client configuration
|
|
||||||
To connect to a server follow these steps:
|
To connect to a server follow these steps:
|
||||||
* In the client directory, locate `boot.cfg`
|
* In the client directory, locate `boot.cfg`
|
||||||
* Open it in a text editor and locate where it says `AUTHSERVERIP=0:`
|
* Open it in a text editor and locate where it says `AUTHSERVERIP=0:`
|
||||||
* Replace the contents after to `:` and the following `,` with what you configured as the server's public facing IP. For example `AUTHSERVERIP=0:localhost` for locally hosted servers
|
* Replace the contents after to `:` and the following `,` with what you configured as the server's public facing IP. For example `AUTHSERVERIP=0:localhost` for locally hosted servers
|
||||||
|
* Next locate the line `UGCUSE3DSERVICES=7:`
|
||||||
|
* Ensure the number after the 7 is a `0`
|
||||||
* Launch `legouniverse.exe`, through `wine` if on a Unix-like operating system
|
* 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.
|
* 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
|
## 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.
|
||||||
|
|
||||||
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:
|
## In-game commands
|
||||||
* Open `res/scripts/ai/minigame/survival/l_zone_survival_client.lua`
|
* A list of all in-game commands can be found [here](./docs/Commands.md).
|
||||||
* Navigate to line `617`
|
|
||||||
* Change `PlayerReady(self)` to `onPlayerReady(self)`
|
|
||||||
* Save the file, overriding readonly mode if required
|
|
||||||
|
|
||||||
If you still experience the bug, try deleting/renaming `res/pack/scripts.pk`.
|
## Verifying your client files
|
||||||
|
|
||||||
### Brick-By-Brick building
|
### 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
|
||||||
|
|
||||||
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 Linux or MacOS
|
||||||
|
shasum -a 256 <file>
|
||||||
|
|
||||||
### In-game commands
|
# If on Windows using the Command Prompt
|
||||||
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).
|
certutil -hashfile <file> SHA256
|
||||||
|
```
|
||||||
|
|
||||||
<table>
|
Below are known good SHA256 checksums of the client:
|
||||||
<thead>
|
* `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed)
|
||||||
<th>
|
* `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed)
|
||||||
Command
|
* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
|
||||||
</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>
|
|
||||||
|
|
||||||
## Credits
|
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.
|
||||||
## Active Contributors
|
|
||||||
* [EmosewaMC](https://github.com/EmosewaMC)
|
### Darkflame Universe Client
|
||||||
* [Jettford](https://github.com/Jettford)
|
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
|
||||||
|
|
||||||
## DLU Team
|
## DLU Team
|
||||||
* [DarwinAnim8or](https://github.com/DarwinAnim8or)
|
* [DarwinAnim8or](https://github.com/DarwinAnim8or)
|
||||||
@ -429,26 +319,30 @@ Here is a summary of the commands available in-game. All commands are prefixed b
|
|||||||
* [averysumner](https://github.com/codeshaunted)
|
* [averysumner](https://github.com/codeshaunted)
|
||||||
* [Jon002](https://github.com/jaller200)
|
* [Jon002](https://github.com/jaller200)
|
||||||
* [Jonny](https://github.com/cuzitsjonny)
|
* [Jonny](https://github.com/cuzitsjonny)
|
||||||
|
* [Aaron K.](https://github.com/aronwk-aaron)
|
||||||
|
|
||||||
|
### Research and Tools
|
||||||
|
* [lcdr](https://github.com/lcdr)
|
||||||
|
* [Xiphoseer](https://github.com/Xiphoseer)
|
||||||
|
|
||||||
|
### Community Management
|
||||||
|
* [Neal](https://github.com/NealSpellman)
|
||||||
|
|
||||||
|
### Logo
|
||||||
|
* Cole Peterson (BlasterBuilder)
|
||||||
|
|
||||||
|
## Active Contributors
|
||||||
|
* [EmosewaMC](https://github.com/EmosewaMC)
|
||||||
|
* [Jettford](https://github.com/Jettford)
|
||||||
|
|
||||||
|
## Former Contributors
|
||||||
* TheMachine
|
* TheMachine
|
||||||
* Matthew
|
* Matthew
|
||||||
* [Raine](https://github.com/Rainebannister)
|
* [Raine](https://github.com/Rainebannister)
|
||||||
* Bricknave
|
* Bricknave
|
||||||
|
|
||||||
### Research and tools
|
## Special Thanks
|
||||||
* [lcdr](https://github.com/lcdr)
|
|
||||||
* [Xiphoseer](https://github.com/Xiphoseer)
|
|
||||||
|
|
||||||
### Community management
|
|
||||||
* [Neal](https://github.com/NealSpellman)
|
|
||||||
|
|
||||||
### Former contributors
|
|
||||||
* TheMachine
|
|
||||||
* Matthew
|
|
||||||
* Raine
|
|
||||||
* Bricknave
|
|
||||||
|
|
||||||
### Special thanks
|
|
||||||
* humanoid24
|
* humanoid24
|
||||||
* pwjones1969
|
* pwjones1969
|
||||||
* BlasterBuilder for the logo
|
* [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)
|
||||||
|
51
SECURITY.md
Normal file
51
SECURITY.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
At the moment, only the latest commit on the `main` branch will be supported for security vulnerabilities. Private server operators
|
||||||
|
should keep their instances up to date and forks should regularily rebase on `main`.
|
||||||
|
|
||||||
|
| Branch | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| `main` | :white_check_mark: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you found a security vulnerability in DLU, please send a message to [darkflame-security@googlegroups.com][darkflame-security]. You should get a
|
||||||
|
reply within *72 hours* that we have received your report and a tentative [CVSS score](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator).
|
||||||
|
We will do a preliminary analysis to confirm that the vulnerability is a plausible claim and decline the report otherwise.
|
||||||
|
|
||||||
|
If possible, please include
|
||||||
|
|
||||||
|
1. reproducible steps on how to trigger the vulnerability
|
||||||
|
2. a description on why you are convinced that it exists.
|
||||||
|
3. any information you may have on active exploitation of the vulnerability (zero-day).
|
||||||
|
|
||||||
|
## Security Advisories
|
||||||
|
|
||||||
|
The project will release advisories on resolved vulnerabilities at <https://github.com/DarkflameUniverse/DarkflameServer/security/advisories>
|
||||||
|
|
||||||
|
## Receiving Security Updates
|
||||||
|
|
||||||
|
We set up [darkflame-security-announce@googlegroups.com][darkflame-security-announce] for private server operators to receive updates on vulnerabilities
|
||||||
|
such as the release of [Security Advisories](#security-advisories) or early workarounds and recommendations to mitigate ongoing
|
||||||
|
vulnerabilities.
|
||||||
|
|
||||||
|
Unfortunately, we cannot guarantee that announcements will be sent for every vulnerability.
|
||||||
|
|
||||||
|
## Embargo
|
||||||
|
|
||||||
|
We propose a 90 day (approx. 3 months) embargo on security vulnerabilities. That is, we ask everyone not to disclose the vulnerabilty
|
||||||
|
publicly until either:
|
||||||
|
|
||||||
|
1. 90 days have passed from the time the first related email is sent to `darkflame-security@`
|
||||||
|
2. a security advisory related to the vulnerability has been published by the project.
|
||||||
|
|
||||||
|
If you fail to comply with this embargo, you might be exluded from [receiving security updates](#receiving-security-updates).
|
||||||
|
|
||||||
|
## Bug Bounty
|
||||||
|
|
||||||
|
Unfortunately we cannot provide bug bounties at this time.
|
||||||
|
|
||||||
|
[darkflame-security]: mailto:darkflame-security@googlegroups.com
|
||||||
|
[darkflame-security-announce]: https://groups.google.com/g/darkflame-security-announce
|
8
build.sh
8
build.sh
@ -1,3 +1,6 @@
|
|||||||
|
# Error if any command fails
|
||||||
|
set -e
|
||||||
|
|
||||||
# Create the build directory, preserving it if it already exists
|
# Create the build directory, preserving it if it already exists
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
@ -5,5 +8,6 @@ cd build
|
|||||||
# Run cmake to generate make files
|
# Run cmake to generate make files
|
||||||
cmake ..
|
cmake ..
|
||||||
|
|
||||||
# Run make to build the project. To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `make -j8`
|
# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8'
|
||||||
make
|
cmake --build . --config Release $1
|
||||||
|
|
||||||
|
@ -11,61 +11,68 @@
|
|||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
#include "Diagnostics.h"
|
#include "Diagnostics.h"
|
||||||
|
#include "BinaryPathFinder.h"
|
||||||
|
|
||||||
//RakNet includes:
|
//RakNet includes:
|
||||||
#include "RakNetDefines.h"
|
#include "RakNetDefines.h"
|
||||||
|
#include <MessageIdentifiers.h>
|
||||||
|
|
||||||
//Auth includes:
|
//Auth includes:
|
||||||
#include "AuthPackets.h"
|
#include "AuthPackets.h"
|
||||||
#include "dMessageIdentifiers.h"
|
#include "eConnectionType.h"
|
||||||
|
#include "eServerMessageType.h"
|
||||||
|
#include "eAuthMessageType.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
namespace Game {
|
namespace Game {
|
||||||
dLogger* logger;
|
dLogger* logger = nullptr;
|
||||||
dServer* server;
|
dServer* server = nullptr;
|
||||||
dConfig* config;
|
dConfig* config = nullptr;
|
||||||
|
bool shouldShutdown = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dLogger* SetupLogger();
|
dLogger* SetupLogger();
|
||||||
void HandlePacket(Packet* packet);
|
void HandlePacket(Packet* packet);
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
constexpr uint32_t authFramerate = mediumFramerate;
|
||||||
|
constexpr uint32_t authFrameDelta = mediumFrameDelta;
|
||||||
Diagnostics::SetProcessName("Auth");
|
Diagnostics::SetProcessName("Auth");
|
||||||
Diagnostics::SetProcessFileName(argv[0]);
|
Diagnostics::SetProcessFileName(argv[0]);
|
||||||
Diagnostics::Initialize();
|
Diagnostics::Initialize();
|
||||||
|
|
||||||
//Create all the objects we need to run our service:
|
//Create all the objects we need to run our service:
|
||||||
Game::logger = SetupLogger();
|
Game::logger = SetupLogger();
|
||||||
if (!Game::logger) return 0;
|
if (!Game::logger) return EXIT_FAILURE;
|
||||||
Game::logger->Log("AuthServer", "Starting Auth server...\n");
|
|
||||||
Game::logger->Log("AuthServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
|
||||||
Game::logger->Log("AuthServer", "Compiled on: %s\n", __TIMESTAMP__);
|
|
||||||
|
|
||||||
//Read our config:
|
//Read our config:
|
||||||
dConfig config("authconfig.ini");
|
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string());
|
||||||
Game::config = &config;
|
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
|
||||||
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
|
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
|
||||||
Game::logger->SetLogDebugStatements(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__);
|
||||||
|
|
||||||
//Connect to the MySQL Database
|
//Connect to the MySQL Database
|
||||||
std::string mysql_host = config.GetValue("mysql_host");
|
std::string mysql_host = Game::config->GetValue("mysql_host");
|
||||||
std::string mysql_database = config.GetValue("mysql_database");
|
std::string mysql_database = Game::config->GetValue("mysql_database");
|
||||||
std::string mysql_username = config.GetValue("mysql_username");
|
std::string mysql_username = Game::config->GetValue("mysql_username");
|
||||||
std::string mysql_password = config.GetValue("mysql_password");
|
std::string mysql_password = Game::config->GetValue("mysql_password");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||||
} catch (sql::SQLException& ex) {
|
} catch (sql::SQLException& ex) {
|
||||||
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s\n", ex.what());
|
Game::logger->Log("AuthServer", "Got an error while connecting to the database: %s", ex.what());
|
||||||
Database::Destroy("AuthServer");
|
Database::Destroy("AuthServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
return 0;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Find out the master's IP:
|
//Find out the master's IP:
|
||||||
std::string masterIP;
|
std::string masterIP;
|
||||||
int masterPort = 1500;
|
uint32_t masterPort = 1500;
|
||||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
||||||
auto res = stmt->executeQuery();
|
auto res = stmt->executeQuery();
|
||||||
while (res->next()) {
|
while (res->next()) {
|
||||||
@ -77,29 +84,30 @@ int main(int argc, char** argv) {
|
|||||||
delete stmt;
|
delete stmt;
|
||||||
|
|
||||||
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
||||||
int maxClients = 50;
|
uint32_t maxClients = 50;
|
||||||
int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
|
uint32_t 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 (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
|
||||||
if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str());
|
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:
|
//Run it until server gets a kill message from Master:
|
||||||
auto t = std::chrono::high_resolution_clock::now();
|
auto t = std::chrono::high_resolution_clock::now();
|
||||||
Packet* packet = nullptr;
|
Packet* packet = nullptr;
|
||||||
int framesSinceLastFlush = 0;
|
constexpr uint32_t logFlushTime = 30 * authFramerate; // 30 seconds in frames
|
||||||
int framesSinceMasterDisconnect = 0;
|
constexpr uint32_t sqlPingTime = 10 * 60 * authFramerate; // 10 minutes in frames
|
||||||
int framesSinceLastSQLPing = 0;
|
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:
|
//Check if we're still connected to master:
|
||||||
if (!Game::server->GetIsConnectedToMaster()) {
|
if (!Game::server->GetIsConnectedToMaster()) {
|
||||||
framesSinceMasterDisconnect++;
|
framesSinceMasterDisconnect++;
|
||||||
|
|
||||||
if (framesSinceMasterDisconnect >= 30)
|
if (framesSinceMasterDisconnect >= authFramerate)
|
||||||
break; //Exit our loop, shut down.
|
break; //Exit our loop, shut down.
|
||||||
}
|
} else framesSinceMasterDisconnect = 0;
|
||||||
else framesSinceMasterDisconnect = 0;
|
|
||||||
|
|
||||||
//In world we'd update our other systems here.
|
//In world we'd update our other systems here.
|
||||||
|
|
||||||
@ -113,16 +121,16 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Push our log every 30s:
|
//Push our log every 30s:
|
||||||
if (framesSinceLastFlush >= 900) {
|
if (framesSinceLastFlush >= logFlushTime) {
|
||||||
Game::logger->Flush();
|
Game::logger->Flush();
|
||||||
framesSinceLastFlush = 0;
|
framesSinceLastFlush = 0;
|
||||||
} else framesSinceLastFlush++;
|
} else framesSinceLastFlush++;
|
||||||
|
|
||||||
//Every 10 min we ping our sql server to keep it alive hopefully:
|
//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:
|
//Find out the master's IP for absolutely no reason:
|
||||||
std::string masterIP;
|
std::string masterIP;
|
||||||
int masterPort;
|
uint32_t masterPort;
|
||||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
||||||
auto res = stmt->executeQuery();
|
auto res = stmt->executeQuery();
|
||||||
while (res->next()) {
|
while (res->next()) {
|
||||||
@ -134,11 +142,10 @@ int main(int argc, char** argv) {
|
|||||||
delete stmt;
|
delete stmt;
|
||||||
|
|
||||||
framesSinceLastSQLPing = 0;
|
framesSinceLastSQLPing = 0;
|
||||||
}
|
} else framesSinceLastSQLPing++;
|
||||||
else framesSinceLastSQLPing++;
|
|
||||||
|
|
||||||
//Sleep our thread since auth can afford to.
|
//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);
|
std::this_thread::sleep_until(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,13 +153,13 @@ int main(int argc, char** argv) {
|
|||||||
Database::Destroy("AuthServer");
|
Database::Destroy("AuthServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
|
delete Game::config;
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
dLogger * SetupLogger() {
|
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 logToConsole = false;
|
||||||
bool logDebugStatements = false;
|
bool logDebugStatements = false;
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@ -164,13 +171,15 @@ dLogger * SetupLogger() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HandlePacket(Packet* packet) {
|
void HandlePacket(Packet* packet) {
|
||||||
|
if (packet->length < 4) return;
|
||||||
|
|
||||||
if (packet->data[0] == ID_USER_PACKET_ENUM) {
|
if (packet->data[0] == ID_USER_PACKET_ENUM) {
|
||||||
if (packet->data[1] == SERVER) {
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) {
|
||||||
if (packet->data[3] == MSG_SERVER_VERSION_CONFIRM) {
|
if (static_cast<eServerMessageType>(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) {
|
||||||
AuthPackets::HandleHandshake(Game::server, packet);
|
AuthPackets::HandleHandshake(Game::server, packet);
|
||||||
}
|
}
|
||||||
} else if (packet->data[1] == AUTH) {
|
} else if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::AUTH) {
|
||||||
if (packet->data[3] == MSG_AUTH_LOGIN_REQUEST) {
|
if (static_cast<eAuthMessageType>(packet->data[3]) == eAuthMessageType::LOGIN_REQUEST) {
|
||||||
AuthPackets::HandleLoginRequest(Game::server, packet);
|
AuthPackets::HandleLoginRequest(Game::server, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
dAuthServer/CMakeLists.txt
Normal file
2
dAuthServer/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
add_executable(AuthServer "AuthServer.cpp")
|
||||||
|
target_link_libraries(AuthServer ${COMMON_LIBRARIES})
|
4
dChatFilter/CMakeLists.txt
Normal file
4
dChatFilter/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(DCHATFILTER_SOURCES "dChatFilter.cpp")
|
||||||
|
|
||||||
|
add_library(dChatFilter STATIC ${DCHATFILTER_SOURCES})
|
||||||
|
target_link_libraries(dChatFilter dDatabase)
|
@ -8,9 +8,11 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
#include "Database.h"
|
|
||||||
#include "dLogger.h"
|
#include "dLogger.h"
|
||||||
|
#include "dConfig.h"
|
||||||
|
#include "Database.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
#include "eGameMasterLevel.h"
|
||||||
|
|
||||||
using namespace dChatFilterDCF;
|
using namespace dChatFilterDCF;
|
||||||
|
|
||||||
@ -18,12 +20,15 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
|
|||||||
m_DontGenerateDCF = dontGenerateDCF;
|
m_DontGenerateDCF = dontGenerateDCF;
|
||||||
|
|
||||||
if (!BinaryIO::DoesFileExist(filepath + ".dcf") || m_DontGenerateDCF) {
|
if (!BinaryIO::DoesFileExist(filepath + ".dcf") || m_DontGenerateDCF) {
|
||||||
ReadWordlistPlaintext(filepath + ".txt");
|
ReadWordlistPlaintext(filepath + ".txt", true);
|
||||||
if (!m_DontGenerateDCF) ExportWordlistToDCF(filepath + ".dcf");
|
if (!m_DontGenerateDCF) ExportWordlistToDCF(filepath + ".dcf", true);
|
||||||
|
} else if (!ReadWordlistDCF(filepath + ".dcf", true)) {
|
||||||
|
ReadWordlistPlaintext(filepath + ".txt", true);
|
||||||
|
ExportWordlistToDCF(filepath + ".dcf", true);
|
||||||
}
|
}
|
||||||
else if (!ReadWordlistDCF(filepath + ".dcf")) {
|
|
||||||
ReadWordlistPlaintext(filepath + ".txt");
|
if (BinaryIO::DoesFileExist("blacklist.dcf")) {
|
||||||
ExportWordlistToDCF(filepath + ".dcf");
|
ReadWordlistDCF("blacklist.dcf", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read player names that are ok as well:
|
//Read player names that are ok as well:
|
||||||
@ -32,29 +37,31 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) {
|
|||||||
while (res->next()) {
|
while (res->next()) {
|
||||||
std::string line = res->getString(1).c_str();
|
std::string line = res->getString(1).c_str();
|
||||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
||||||
m_Words.push_back(CalculateHash(line));
|
m_ApprovedWords.push_back(CalculateHash(line));
|
||||||
}
|
}
|
||||||
delete res;
|
delete res;
|
||||||
delete stmt;
|
delete stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
dChatFilter::~dChatFilter() {
|
dChatFilter::~dChatFilter() {
|
||||||
m_Words.clear();
|
m_ApprovedWords.clear();
|
||||||
|
m_DeniedWords.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath) {
|
void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) {
|
||||||
std::ifstream file(filepath);
|
std::ifstream file(filepath);
|
||||||
if (file) {
|
if (file) {
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(file, line)) {
|
||||||
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
line.erase(std::remove(line.begin(), line.end(), '\r'), line.end());
|
||||||
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase
|
||||||
m_Words.push_back(CalculateHash(line));
|
if (whiteList) m_ApprovedWords.push_back(CalculateHash(line));
|
||||||
|
else m_DeniedWords.push_back(CalculateHash(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dChatFilter::ReadWordlistDCF(const std::string& filepath) {
|
bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) {
|
||||||
std::ifstream file(filepath, std::ios::binary);
|
std::ifstream file(filepath, std::ios::binary);
|
||||||
if (file) {
|
if (file) {
|
||||||
fileHeader hdr;
|
fileHeader hdr;
|
||||||
@ -67,17 +74,18 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath) {
|
|||||||
if (hdr.formatVersion == formatVersion) {
|
if (hdr.formatVersion == formatVersion) {
|
||||||
size_t wordsToRead = 0;
|
size_t wordsToRead = 0;
|
||||||
BinaryIO::BinaryRead(file, wordsToRead);
|
BinaryIO::BinaryRead(file, wordsToRead);
|
||||||
m_Words.reserve(wordsToRead);
|
if (whiteList) m_ApprovedWords.reserve(wordsToRead);
|
||||||
|
else m_DeniedWords.reserve(wordsToRead);
|
||||||
|
|
||||||
size_t word = 0;
|
size_t word = 0;
|
||||||
for (size_t i = 0; i < wordsToRead; ++i) {
|
for (size_t i = 0; i < wordsToRead; ++i) {
|
||||||
BinaryIO::BinaryRead(file, word);
|
BinaryIO::BinaryRead(file, word);
|
||||||
m_Words.push_back(word);
|
if (whiteList) m_ApprovedWords.push_back(word);
|
||||||
|
else m_DeniedWords.push_back(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
file.close();
|
file.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -86,14 +94,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dChatFilter::ExportWordlistToDCF(const std::string& filepath) {
|
void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) {
|
||||||
std::ofstream file(filepath, std::ios::binary | std::ios_base::out);
|
std::ofstream file(filepath, std::ios::binary | std::ios_base::out);
|
||||||
if (file) {
|
if (file) {
|
||||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
|
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header));
|
||||||
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
|
BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion));
|
||||||
BinaryIO::BinaryWrite(file, size_t(m_Words.size()));
|
BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size()));
|
||||||
|
|
||||||
for (size_t word : m_Words) {
|
for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) {
|
||||||
BinaryIO::BinaryWrite(file, word);
|
BinaryIO::BinaryWrite(file, word);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,31 +109,45 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel) {
|
std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) {
|
||||||
if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return true; //If anything but a forum mod, return true.
|
if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true.
|
||||||
if (message.empty()) return true;
|
if (message.empty()) return { };
|
||||||
|
if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } };
|
||||||
|
|
||||||
std::stringstream sMessage(message);
|
std::stringstream sMessage(message);
|
||||||
std::string segment;
|
std::string segment;
|
||||||
std::regex reg("(!*|\\?*|\\;*|\\.*|\\,*)");
|
std::regex reg("(!*|\\?*|\\;*|\\.*|\\,*)");
|
||||||
|
|
||||||
|
std::vector<std::pair<uint8_t, uint8_t>> listOfBadSegments = std::vector<std::pair<uint8_t, uint8_t>>();
|
||||||
|
|
||||||
|
uint32_t position = 0;
|
||||||
|
|
||||||
while (std::getline(sMessage, segment, ' ')) {
|
while (std::getline(sMessage, segment, ' ')) {
|
||||||
|
std::string originalSegment = segment;
|
||||||
|
|
||||||
std::transform(segment.begin(), segment.end(), segment.begin(), ::tolower); //Transform to lowercase
|
std::transform(segment.begin(), segment.end(), segment.begin(), ::tolower); //Transform to lowercase
|
||||||
segment = std::regex_replace(segment, reg, "");
|
segment = std::regex_replace(segment, reg, "");
|
||||||
|
|
||||||
size_t hash = CalculateHash(segment);
|
size_t hash = CalculateHash(segment);
|
||||||
|
|
||||||
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end()) {
|
if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) {
|
||||||
return false;
|
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsInWordlist(hash)) {
|
if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) {
|
||||||
m_UserUnapprovedWordCache.push_back(hash);
|
m_UserUnapprovedWordCache.push_back(hash);
|
||||||
return false;
|
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) {
|
||||||
|
m_UserUnapprovedWordCache.push_back(hash);
|
||||||
|
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
position += segment.length() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return listOfBadSegments;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t dChatFilter::CalculateHash(const std::string& word) {
|
size_t dChatFilter::CalculateHash(const std::string& word) {
|
||||||
@ -135,7 +157,3 @@ size_t dChatFilter::CalculateHash(const std::string& word) {
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dChatFilter::IsInWordlist(size_t word) {
|
|
||||||
return std::find(m_Words.begin(), m_Words.end(), word) != m_Words.end();
|
|
||||||
}
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
|
|
||||||
|
enum class eGameMasterLevel : uint8_t;
|
||||||
namespace dChatFilterDCF {
|
namespace dChatFilterDCF {
|
||||||
static const uint32_t header = ('D' + ('C' << 8) + ('F' << 16) + ('B' << 24));
|
static const uint32_t header = ('D' + ('C' << 8) + ('F' << 16) + ('B' << 24));
|
||||||
static const uint32_t formatVersion = 2;
|
static const uint32_t formatVersion = 2;
|
||||||
@ -20,17 +21,17 @@ public:
|
|||||||
dChatFilter(const std::string& filepath, bool dontGenerateDCF);
|
dChatFilter(const std::string& filepath, bool dontGenerateDCF);
|
||||||
~dChatFilter();
|
~dChatFilter();
|
||||||
|
|
||||||
void ReadWordlistPlaintext(const std::string & filepath);
|
void ReadWordlistPlaintext(const std::string& filepath, bool whiteList);
|
||||||
bool ReadWordlistDCF(const std::string & filepath);
|
bool ReadWordlistDCF(const std::string& filepath, bool whiteList);
|
||||||
void ExportWordlistToDCF(const std::string & filepath);
|
void ExportWordlistToDCF(const std::string& filepath, bool whiteList);
|
||||||
bool IsSentenceOkay(const std::string& message, int gmLevel);
|
std::vector<std::pair<uint8_t, uint8_t>> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_DontGenerateDCF;
|
bool m_DontGenerateDCF;
|
||||||
std::vector<size_t> m_Words;
|
std::vector<size_t> m_DeniedWords;
|
||||||
|
std::vector<size_t> m_ApprovedWords;
|
||||||
std::vector<size_t> m_UserUnapprovedWordCache;
|
std::vector<size_t> m_UserUnapprovedWordCache;
|
||||||
|
|
||||||
//Private functions:
|
//Private functions:
|
||||||
size_t CalculateHash(const std::string& word);
|
size_t CalculateHash(const std::string& word);
|
||||||
bool IsInWordlist(size_t word);
|
|
||||||
};
|
};
|
||||||
|
10
dChatServer/CMakeLists.txt
Normal file
10
dChatServer/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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)
|
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@
|
|||||||
#include "BitStream.h"
|
#include "BitStream.h"
|
||||||
|
|
||||||
struct PlayerData;
|
struct PlayerData;
|
||||||
|
enum class eAddFriendResponseType : uint8_t;
|
||||||
|
|
||||||
namespace ChatPacketHandler {
|
namespace ChatPacketHandler {
|
||||||
void HandleFriendlistRequest(Packet* packet);
|
void HandleFriendlistRequest(Packet* packet);
|
||||||
@ -31,10 +32,9 @@ namespace ChatPacketHandler {
|
|||||||
void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
|
void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
|
||||||
|
|
||||||
//FriendData is the player we're SENDING this stuff to. Player is the friend that changed state.
|
//FriendData is the player we're SENDING this stuff to. Player is the friend that changed state.
|
||||||
void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType);
|
void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend);
|
||||||
|
|
||||||
void SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq = false);
|
void SendFriendRequest(PlayerData* receiver, PlayerData* sender);
|
||||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode = 3);
|
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);
|
void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,23 +9,32 @@
|
|||||||
#include "dLogger.h"
|
#include "dLogger.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
#include "dMessageIdentifiers.h"
|
|
||||||
#include "dChatFilter.h"
|
#include "dChatFilter.h"
|
||||||
#include "Diagnostics.h"
|
#include "Diagnostics.h"
|
||||||
|
#include "AssetManager.h"
|
||||||
|
#include "BinaryPathFinder.h"
|
||||||
|
#include "eConnectionType.h"
|
||||||
#include "PlayerContainer.h"
|
#include "PlayerContainer.h"
|
||||||
#include "ChatPacketHandler.h"
|
#include "ChatPacketHandler.h"
|
||||||
|
#include "eChatMessageType.h"
|
||||||
|
#include "eChatInternalMessageType.h"
|
||||||
|
#include "eWorldMessageType.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
namespace Game {
|
|
||||||
dLogger* logger;
|
|
||||||
dServer* server;
|
|
||||||
dConfig* config;
|
|
||||||
dChatFilter* chatFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
//RakNet includes:
|
//RakNet includes:
|
||||||
#include "RakNetDefines.h"
|
#include "RakNetDefines.h"
|
||||||
|
#include <MessageIdentifiers.h>
|
||||||
|
|
||||||
|
namespace Game {
|
||||||
|
dLogger* logger = nullptr;
|
||||||
|
dServer* server = nullptr;
|
||||||
|
dConfig* config = nullptr;
|
||||||
|
dChatFilter* chatFilter = nullptr;
|
||||||
|
AssetManager* assetManager = nullptr;
|
||||||
|
bool shouldShutdown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dLogger* SetupLogger();
|
dLogger* SetupLogger();
|
||||||
void HandlePacket(Packet* packet);
|
void HandlePacket(Packet* packet);
|
||||||
@ -33,43 +42,59 @@ void HandlePacket(Packet* packet);
|
|||||||
PlayerContainer playerContainer;
|
PlayerContainer playerContainer;
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
constexpr uint32_t chatFramerate = mediumFramerate;
|
||||||
|
constexpr uint32_t chatFrameDelta = mediumFrameDelta;
|
||||||
Diagnostics::SetProcessName("Chat");
|
Diagnostics::SetProcessName("Chat");
|
||||||
Diagnostics::SetProcessFileName(argv[0]);
|
Diagnostics::SetProcessFileName(argv[0]);
|
||||||
Diagnostics::Initialize();
|
Diagnostics::Initialize();
|
||||||
|
|
||||||
//Create all the objects we need to run our service:
|
//Create all the objects we need to run our service:
|
||||||
Game::logger = SetupLogger();
|
Game::logger = SetupLogger();
|
||||||
if (!Game::logger) return 0;
|
if (!Game::logger) return EXIT_FAILURE;
|
||||||
Game::logger->Log("ChatServer", "Starting Chat server...\n");
|
|
||||||
Game::logger->Log("ChatServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
|
||||||
Game::logger->Log("ChatServer", "Compiled on: %s\n", __TIMESTAMP__);
|
|
||||||
|
|
||||||
//Read our config:
|
//Read our config:
|
||||||
dConfig config("chatconfig.ini");
|
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string());
|
||||||
Game::config = &config;
|
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
|
||||||
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
|
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
|
||||||
Game::logger->SetLogDebugStatements(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__);
|
||||||
|
|
||||||
|
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
|
//Connect to the MySQL Database
|
||||||
std::string mysql_host = config.GetValue("mysql_host");
|
std::string mysql_host = Game::config->GetValue("mysql_host");
|
||||||
std::string mysql_database = config.GetValue("mysql_database");
|
std::string mysql_database = Game::config->GetValue("mysql_database");
|
||||||
std::string mysql_username = config.GetValue("mysql_username");
|
std::string mysql_username = Game::config->GetValue("mysql_username");
|
||||||
std::string mysql_password = config.GetValue("mysql_password");
|
std::string mysql_password = Game::config->GetValue("mysql_password");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||||
}
|
} catch (sql::SQLException& ex) {
|
||||||
catch (sql::SQLException& ex) {
|
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s", ex.what());
|
||||||
Game::logger->Log("ChatServer", "Got an error while connecting to the database: %s\n", ex.what());
|
|
||||||
Database::Destroy("ChatServer");
|
Database::Destroy("ChatServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
return 0;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Find out the master's IP:
|
//Find out the master's IP:
|
||||||
std::string masterIP;
|
std::string masterIP;
|
||||||
int masterPort = 1000;
|
uint32_t masterPort = 1000;
|
||||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
||||||
auto res = stmt->executeQuery();
|
auto res = stmt->executeQuery();
|
||||||
while (res->next()) {
|
while (res->next()) {
|
||||||
@ -81,31 +106,32 @@ int main(int argc, char** argv) {
|
|||||||
delete stmt;
|
delete stmt;
|
||||||
|
|
||||||
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
||||||
int maxClients = 50;
|
uint32_t maxClients = 50;
|
||||||
int ourPort = 1501;
|
uint32_t ourPort = 1501;
|
||||||
if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients"));
|
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients"));
|
||||||
if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str());
|
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:
|
//Run it until server gets a kill message from Master:
|
||||||
auto t = std::chrono::high_resolution_clock::now();
|
auto t = std::chrono::high_resolution_clock::now();
|
||||||
Packet* packet = nullptr;
|
Packet* packet = nullptr;
|
||||||
int framesSinceLastFlush = 0;
|
constexpr uint32_t logFlushTime = 30 * chatFramerate; // 30 seconds in frames
|
||||||
int framesSinceMasterDisconnect = 0;
|
constexpr uint32_t sqlPingTime = 10 * 60 * chatFramerate; // 10 minutes in frames
|
||||||
int framesSinceLastSQLPing = 0;
|
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:
|
//Check if we're still connected to master:
|
||||||
if (!Game::server->GetIsConnectedToMaster()) {
|
if (!Game::server->GetIsConnectedToMaster()) {
|
||||||
framesSinceMasterDisconnect++;
|
framesSinceMasterDisconnect++;
|
||||||
|
|
||||||
if (framesSinceMasterDisconnect >= 30)
|
if (framesSinceMasterDisconnect >= chatFramerate)
|
||||||
break; //Exit our loop, shut down.
|
break; //Exit our loop, shut down.
|
||||||
}
|
} else framesSinceMasterDisconnect = 0;
|
||||||
else framesSinceMasterDisconnect = 0;
|
|
||||||
|
|
||||||
//In world we'd update our other systems here.
|
//In world we'd update our other systems here.
|
||||||
|
|
||||||
@ -119,17 +145,16 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Push our log every 30s:
|
//Push our log every 30s:
|
||||||
if (framesSinceLastFlush >= 900) {
|
if (framesSinceLastFlush >= logFlushTime) {
|
||||||
Game::logger->Flush();
|
Game::logger->Flush();
|
||||||
framesSinceLastFlush = 0;
|
framesSinceLastFlush = 0;
|
||||||
}
|
} else framesSinceLastFlush++;
|
||||||
else framesSinceLastFlush++;
|
|
||||||
|
|
||||||
//Every 10 min we ping our sql server to keep it alive hopefully:
|
//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:
|
//Find out the master's IP for absolutely no reason:
|
||||||
std::string masterIP;
|
std::string masterIP;
|
||||||
int masterPort;
|
uint32_t masterPort;
|
||||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';");
|
||||||
auto res = stmt->executeQuery();
|
auto res = stmt->executeQuery();
|
||||||
while (res->next()) {
|
while (res->next()) {
|
||||||
@ -141,11 +166,10 @@ int main(int argc, char** argv) {
|
|||||||
delete stmt;
|
delete stmt;
|
||||||
|
|
||||||
framesSinceLastSQLPing = 0;
|
framesSinceLastSQLPing = 0;
|
||||||
}
|
} else framesSinceLastSQLPing++;
|
||||||
else framesSinceLastSQLPing++;
|
|
||||||
|
|
||||||
//Sleep our thread since auth can afford to.
|
//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);
|
std::this_thread::sleep_until(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,13 +177,13 @@ int main(int argc, char** argv) {
|
|||||||
Database::Destroy("ChatServer");
|
Database::Destroy("ChatServer");
|
||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
|
delete Game::config;
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
dLogger * SetupLogger() {
|
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 logToConsole = false;
|
||||||
bool logDebugStatements = false;
|
bool logDebugStatements = false;
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@ -172,32 +196,34 @@ dLogger * SetupLogger() {
|
|||||||
|
|
||||||
void HandlePacket(Packet* packet) {
|
void HandlePacket(Packet* packet) {
|
||||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||||
Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.\n");
|
Game::logger->Log("ChatServer", "A server has disconnected, erasing their connected players from the list.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) {
|
||||||
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.\n");
|
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->data[1] == CHAT_INTERNAL) {
|
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
|
||||||
switch (packet->data[3]) {
|
|
||||||
case MSG_CHAT_INTERNAL_PLAYER_ADDED_NOTIFICATION:
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
|
||||||
|
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
||||||
|
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
||||||
playerContainer.InsertPlayer(packet);
|
playerContainer.InsertPlayer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION:
|
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
||||||
playerContainer.RemovePlayer(packet);
|
playerContainer.RemovePlayer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_INTERNAL_MUTE_UPDATE:
|
case eChatInternalMessageType::MUTE_UPDATE:
|
||||||
playerContainer.MuteUpdate(packet);
|
playerContainer.MuteUpdate(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_INTERNAL_CREATE_TEAM:
|
case eChatInternalMessageType::CREATE_TEAM:
|
||||||
playerContainer.CreateTeamServer(packet);
|
playerContainer.CreateTeamServer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_INTERNAL_ANNOUNCEMENT: {
|
case eChatInternalMessageType::ANNOUNCEMENT: {
|
||||||
//we just forward this packet to every connected server
|
//we just forward this packet to every connected server
|
||||||
CINSTREAM;
|
CINSTREAM;
|
||||||
Game::server->Send(&inStream, packet->systemAddress, true); //send to everyone except origin
|
Game::server->Send(&inStream, packet->systemAddress, true); //send to everyone except origin
|
||||||
@ -205,88 +231,88 @@ void HandlePacket(Packet* packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i\n", int(packet->data[3]));
|
Game::logger->Log("ChatServer", "Unknown CHAT_INTERNAL id: %i", int(packet->data[3]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->data[1] == CHAT) {
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) {
|
||||||
switch (packet->data[3]) {
|
switch (static_cast<eChatMessageType>(packet->data[3])) {
|
||||||
case MSG_CHAT_GET_FRIENDS_LIST:
|
case eChatMessageType::GET_FRIENDS_LIST:
|
||||||
ChatPacketHandler::HandleFriendlistRequest(packet);
|
ChatPacketHandler::HandleFriendlistRequest(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_GET_IGNORE_LIST:
|
case eChatMessageType::GET_IGNORE_LIST:
|
||||||
Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.\n");
|
Game::logger->Log("ChatServer", "Asked for ignore list, but is unimplemented right now.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_TEAM_GET_STATUS:
|
case eChatMessageType::TEAM_GET_STATUS:
|
||||||
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_ADD_FRIEND_REQUEST:
|
case eChatMessageType::ADD_FRIEND_REQUEST:
|
||||||
//this involves someone sending the initial request, the response is below, response as in from the other player.
|
//this involves someone sending the initial request, the response is below, response as in from the other player.
|
||||||
//We basically just check to see if this player is online or not and route the packet.
|
//We basically just check to see if this player is online or not and route the packet.
|
||||||
ChatPacketHandler::HandleFriendRequest(packet);
|
ChatPacketHandler::HandleFriendRequest(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_ADD_FRIEND_RESPONSE:
|
case eChatMessageType::ADD_FRIEND_RESPONSE:
|
||||||
//This isn't the response a server sent, rather it is a player's response to a received request.
|
//This isn't the response a server sent, rather it is a player's response to a received request.
|
||||||
//Here, we'll actually have to add them to eachother's friend lists depending on the response code.
|
//Here, we'll actually have to add them to eachother's friend lists depending on the response code.
|
||||||
ChatPacketHandler::HandleFriendResponse(packet);
|
ChatPacketHandler::HandleFriendResponse(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_REMOVE_FRIEND:
|
case eChatMessageType::REMOVE_FRIEND:
|
||||||
ChatPacketHandler::HandleRemoveFriend(packet);
|
ChatPacketHandler::HandleRemoveFriend(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_GENERAL_CHAT_MESSAGE:
|
case eChatMessageType::GENERAL_CHAT_MESSAGE:
|
||||||
ChatPacketHandler::HandleChatMessage(packet);
|
ChatPacketHandler::HandleChatMessage(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_PRIVATE_CHAT_MESSAGE:
|
case eChatMessageType::PRIVATE_CHAT_MESSAGE:
|
||||||
//This message is supposed to be echo'd to both the sender and the receiver
|
//This message is supposed to be echo'd to both the sender and the receiver
|
||||||
//BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up.
|
//BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up.
|
||||||
ChatPacketHandler::HandlePrivateChatMessage(packet);
|
ChatPacketHandler::HandlePrivateChatMessage(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_TEAM_INVITE:
|
case eChatMessageType::TEAM_INVITE:
|
||||||
ChatPacketHandler::HandleTeamInvite(packet);
|
ChatPacketHandler::HandleTeamInvite(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_TEAM_INVITE_RESPONSE:
|
case eChatMessageType::TEAM_INVITE_RESPONSE:
|
||||||
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_TEAM_LEAVE:
|
case eChatMessageType::TEAM_LEAVE:
|
||||||
ChatPacketHandler::HandleTeamLeave(packet);
|
ChatPacketHandler::HandleTeamLeave(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_TEAM_SET_LEADER:
|
case eChatMessageType::TEAM_SET_LEADER:
|
||||||
ChatPacketHandler::HandleTeamPromote(packet);
|
ChatPacketHandler::HandleTeamPromote(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_TEAM_KICK:
|
case eChatMessageType::TEAM_KICK:
|
||||||
ChatPacketHandler::HandleTeamKick(packet);
|
ChatPacketHandler::HandleTeamKick(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_CHAT_TEAM_SET_LOOT:
|
case eChatMessageType::TEAM_SET_LOOT:
|
||||||
ChatPacketHandler::HandleTeamLootOption(packet);
|
ChatPacketHandler::HandleTeamLootOption(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Game::logger->Log("ChatServer", "Unknown CHAT id: %i\n", int(packet->data[3]));
|
Game::logger->Log("ChatServer", "Unknown CHAT id: %i", int(packet->data[3]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packet->data[1] == WORLD) {
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::WORLD) {
|
||||||
switch (packet->data[3]) {
|
switch (static_cast<eWorldMessageType>(packet->data[3])) {
|
||||||
case MSG_WORLD_CLIENT_ROUTE_PACKET: {
|
case eWorldMessageType::ROUTE_PACKET: {
|
||||||
printf("routing packet from world\n");
|
Game::logger->Log("ChatServer", "Routing packet from world");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Game::logger->Log("ChatServer", "Unknown World id: %i\n", int(packet->data[3]));
|
Game::logger->Log("ChatServer", "Unknown World id: %i", int(packet->data[3]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,10 @@
|
|||||||
#include "dLogger.h"
|
#include "dLogger.h"
|
||||||
#include "ChatPacketHandler.h"
|
#include "ChatPacketHandler.h"
|
||||||
#include "GeneralUtils.h"
|
#include "GeneralUtils.h"
|
||||||
#include "dMessageIdentifiers.h"
|
|
||||||
#include "PacketUtils.h"
|
#include "PacketUtils.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
|
#include "eConnectionType.h"
|
||||||
|
#include "eChatInternalMessageType.h"
|
||||||
|
|
||||||
PlayerContainer::PlayerContainer() {
|
PlayerContainer::PlayerContainer() {
|
||||||
}
|
}
|
||||||
@ -18,19 +19,26 @@ PlayerContainer::~PlayerContainer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::InsertPlayer(Packet* packet) {
|
void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||||
CINSTREAM;
|
CINSTREAM_SKIP_HEADER;
|
||||||
PlayerData* data = new PlayerData();
|
PlayerData* data = new PlayerData();
|
||||||
inStream.Read(data->playerID);
|
inStream.Read(data->playerID);
|
||||||
inStream.Read(data->playerID);
|
|
||||||
inStream.Read(data->playerName);
|
uint32_t len;
|
||||||
|
inStream.Read<uint32_t>(len);
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char character; inStream.Read<char>(character);
|
||||||
|
data->playerName += character;
|
||||||
|
}
|
||||||
|
|
||||||
inStream.Read(data->zoneID);
|
inStream.Read(data->zoneID);
|
||||||
inStream.Read(data->muteExpire);
|
inStream.Read(data->muteExpire);
|
||||||
data->sysAddr = packet->systemAddress;
|
data->sysAddr = packet->systemAddress;
|
||||||
|
|
||||||
mNames[data->playerID] = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String()));
|
mNames[data->playerID] = GeneralUtils::UTF8ToUTF16(data->playerName);
|
||||||
|
|
||||||
mPlayers.insert(std::make_pair(data->playerID, data));
|
mPlayers.insert(std::make_pair(data->playerID, data));
|
||||||
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i\n", data->playerName.C_String(), data->playerID, data->zoneID.GetMapID());
|
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
|
||||||
|
|
||||||
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
||||||
|
|
||||||
@ -43,45 +51,37 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::RemovePlayer(Packet* packet) {
|
void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||||
CINSTREAM;
|
CINSTREAM_SKIP_HEADER;
|
||||||
LWOOBJID playerID;
|
LWOOBJID playerID;
|
||||||
inStream.Read(playerID); //skip header
|
|
||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
|
|
||||||
//Before they get kicked, we need to also send a message to their friends saying that they disconnected.
|
//Before they get kicked, we need to also send a message to their friends saying that they disconnected.
|
||||||
auto player = this->GetPlayerData(playerID);
|
std::unique_ptr<PlayerData> player(this->GetPlayerData(playerID));
|
||||||
|
|
||||||
if (player == nullptr) {
|
if (player == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& fr : player->friends) {
|
for (auto& fr : player->friends) {
|
||||||
//if (!fr.isOnline) continue;
|
|
||||||
|
|
||||||
auto fd = this->GetPlayerData(fr.friendID);
|
auto fd = this->GetPlayerData(fr.friendID);
|
||||||
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0);
|
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player.get(), 0, fr.isBestFriend);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* team = GetTeam(playerID);
|
auto* team = GetTeam(playerID);
|
||||||
|
|
||||||
if (team != nullptr)
|
if (team != nullptr) {
|
||||||
{
|
const auto memberName = GeneralUtils::UTF8ToUTF16(std::string(player->playerName.c_str()));
|
||||||
//TeamStatusUpdate(team);
|
|
||||||
|
|
||||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.C_String()));
|
for (const auto memberId : team->memberIDs) {
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs)
|
|
||||||
{
|
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
auto* otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (otherMember == nullptr) continue;
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, {0, 0, 0});
|
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, { 0, 0, 0 });
|
||||||
//ChatPacketHandler::SendTeamRemovePlayer(otherMember, false, false, true, false, team->leaderID, player->playerID, memberName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Game::logger->Log("PlayerContainer", "Removed user: %llu\n", playerID);
|
Game::logger->Log("PlayerContainer", "Removed user: %llu", playerID);
|
||||||
mPlayers.erase(playerID);
|
mPlayers.erase(playerID);
|
||||||
|
|
||||||
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
||||||
@ -94,20 +94,17 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
|||||||
insertLog->executeUpdate();
|
insertLog->executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::MuteUpdate(Packet* packet)
|
void PlayerContainer::MuteUpdate(Packet* packet) {
|
||||||
{
|
CINSTREAM_SKIP_HEADER;
|
||||||
CINSTREAM;
|
|
||||||
LWOOBJID playerID;
|
LWOOBJID playerID;
|
||||||
inStream.Read(playerID); //skip header
|
|
||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
time_t expire = 0;
|
time_t expire = 0;
|
||||||
inStream.Read(expire);
|
inStream.Read(expire);
|
||||||
|
|
||||||
auto* player = this->GetPlayerData(playerID);
|
auto* player = this->GetPlayerData(playerID);
|
||||||
|
|
||||||
if (player == nullptr)
|
if (player == nullptr) {
|
||||||
{
|
Game::logger->Log("PlayerContainer", "Failed to find user: %llu", playerID);
|
||||||
Game::logger->Log("PlayerContainer", "Failed to find user: %llu\n", playerID);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -117,11 +114,9 @@ void PlayerContainer::MuteUpdate(Packet* packet)
|
|||||||
BroadcastMuteUpdate(playerID, expire);
|
BroadcastMuteUpdate(playerID, expire);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::CreateTeamServer(Packet* packet)
|
void PlayerContainer::CreateTeamServer(Packet* packet) {
|
||||||
{
|
CINSTREAM_SKIP_HEADER;
|
||||||
CINSTREAM;
|
|
||||||
LWOOBJID playerID;
|
LWOOBJID playerID;
|
||||||
inStream.Read(playerID); //skip header
|
|
||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
size_t membersSize = 0;
|
size_t membersSize = 0;
|
||||||
inStream.Read(membersSize);
|
inStream.Read(membersSize);
|
||||||
@ -130,8 +125,7 @@ void PlayerContainer::CreateTeamServer(Packet* packet)
|
|||||||
|
|
||||||
members.reserve(membersSize);
|
members.reserve(membersSize);
|
||||||
|
|
||||||
for (size_t i = 0; i < membersSize; i++)
|
for (size_t i = 0; i < membersSize; i++) {
|
||||||
{
|
|
||||||
LWOOBJID member;
|
LWOOBJID member;
|
||||||
inStream.Read(member);
|
inStream.Read(member);
|
||||||
members.push_back(member);
|
members.push_back(member);
|
||||||
@ -143,18 +137,16 @@ void PlayerContainer::CreateTeamServer(Packet* packet)
|
|||||||
|
|
||||||
auto* team = CreateLocalTeam(members);
|
auto* team = CreateLocalTeam(members);
|
||||||
|
|
||||||
if (team != nullptr)
|
if (team != nullptr) {
|
||||||
{
|
|
||||||
team->zoneId = zoneId;
|
team->zoneId = zoneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTeamsOnWorld(team, false);
|
UpdateTeamsOnWorld(team, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time)
|
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
||||||
{
|
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_MUTE_UPDATE);
|
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
|
||||||
|
|
||||||
bitStream.Write(player);
|
bitStream.Write(player);
|
||||||
bitStream.Write(time);
|
bitStream.Write(time);
|
||||||
@ -162,30 +154,23 @@ void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time)
|
|||||||
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members)
|
TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members) {
|
||||||
{
|
if (members.empty()) {
|
||||||
if (members.empty())
|
|
||||||
{
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TeamData* newTeam = nullptr;
|
TeamData* newTeam = nullptr;
|
||||||
|
|
||||||
for (const auto member : members)
|
for (const auto member : members) {
|
||||||
{
|
|
||||||
auto* team = GetTeam(member);
|
auto* team = GetTeam(member);
|
||||||
|
|
||||||
if (team != nullptr)
|
if (team != nullptr) {
|
||||||
{
|
|
||||||
RemoveMember(team, member, false, false, true);
|
RemoveMember(team, member, false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newTeam == nullptr)
|
if (newTeam == nullptr) {
|
||||||
{
|
|
||||||
newTeam = CreateTeam(member, true);
|
newTeam = CreateTeam(member, true);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
AddMember(newTeam, member);
|
AddMember(newTeam, member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,8 +182,7 @@ TeamData* PlayerContainer::CreateLocalTeam(std::vector<LWOOBJID> members)
|
|||||||
return newTeam;
|
return newTeam;
|
||||||
}
|
}
|
||||||
|
|
||||||
TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local)
|
TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local) {
|
||||||
{
|
|
||||||
auto* team = new TeamData();
|
auto* team = new TeamData();
|
||||||
|
|
||||||
team->teamID = ++mTeamIDCounter;
|
team->teamID = ++mTeamIDCounter;
|
||||||
@ -212,10 +196,8 @@ TeamData* PlayerContainer::CreateTeam(LWOOBJID leader, bool local)
|
|||||||
return team;
|
return team;
|
||||||
}
|
}
|
||||||
|
|
||||||
TeamData* PlayerContainer::GetTeam(LWOOBJID playerID)
|
TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
|
||||||
{
|
for (auto* team : mTeams) {
|
||||||
for (auto* team : mTeams)
|
|
||||||
{
|
|
||||||
if (std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID) == team->memberIDs.end()) continue;
|
if (std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID) == team->memberIDs.end()) continue;
|
||||||
|
|
||||||
return team;
|
return team;
|
||||||
@ -224,8 +206,7 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID)
|
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
|
||||||
{
|
|
||||||
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
|
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
|
||||||
|
|
||||||
if (index != team->memberIDs.end()) return;
|
if (index != team->memberIDs.end()) return;
|
||||||
@ -237,30 +218,20 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID)
|
|||||||
|
|
||||||
if (leader == nullptr || member == nullptr) return;
|
if (leader == nullptr || member == nullptr) return;
|
||||||
|
|
||||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String()));
|
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName);
|
||||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.C_String()));
|
const auto memberName = GeneralUtils::UTF8ToUTF16(member->playerName);
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamInviteConfirm(member, false, leader->playerID, leader->zoneID, team->lootFlag, 0, 0, leaderName);
|
ChatPacketHandler::SendTeamInviteConfirm(member, false, leader->playerID, leader->zoneID, team->lootFlag, 0, 0, leaderName);
|
||||||
|
|
||||||
/*
|
if (!team->local) {
|
||||||
ChatPacketHandler::SendTeamAddPlayer(member, false, false, false, leader->playerID, leaderName, leader->zoneID);
|
|
||||||
|
|
||||||
Game::logger->Log("PlayerContainer", "Team invite successfully accepted, leader: %s, member: %s\n", leader->playerName.C_String(), member->playerName.C_String());
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!team->local)
|
|
||||||
{
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(member, leader->playerID);
|
ChatPacketHandler::SendTeamSetLeader(member, leader->playerID);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTeamsOnWorld(team, false);
|
UpdateTeamsOnWorld(team, false);
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs)
|
for (const auto memberId : team->memberIDs) {
|
||||||
{
|
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
auto* otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == member) continue;
|
if (otherMember == member) continue;
|
||||||
@ -269,32 +240,27 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID)
|
|||||||
|
|
||||||
ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
|
ChatPacketHandler::SendTeamAddPlayer(member, false, team->local, false, memberId, otherMemberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
|
||||||
|
|
||||||
if (otherMember != nullptr)
|
if (otherMember != nullptr) {
|
||||||
{
|
|
||||||
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member->playerID, memberName, member->zoneID);
|
ChatPacketHandler::SendTeamAddPlayer(otherMember, false, team->local, false, member->playerID, memberName, member->zoneID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disband, bool kicked, bool leaving, bool silent)
|
void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disband, bool kicked, bool leaving, bool silent) {
|
||||||
{
|
|
||||||
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
|
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
|
||||||
|
|
||||||
if (index == team->memberIDs.end()) return;
|
if (index == team->memberIDs.end()) return;
|
||||||
|
|
||||||
auto* member = GetPlayerData(playerID);
|
auto* member = GetPlayerData(playerID);
|
||||||
|
|
||||||
if (member != nullptr && !silent)
|
if (member != nullptr && !silent) {
|
||||||
{
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
ChatPacketHandler::SendTeamSetLeader(member, LWOOBJID_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto memberName = GetName(playerID);
|
const auto memberName = GetName(playerID);
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs)
|
for (const auto memberId : team->memberIDs) {
|
||||||
{
|
if (silent && memberId == playerID) {
|
||||||
if (silent && memberId == playerID)
|
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,25 +275,19 @@ void PlayerContainer::RemoveMember(TeamData* team, LWOOBJID playerID, bool disba
|
|||||||
|
|
||||||
UpdateTeamsOnWorld(team, false);
|
UpdateTeamsOnWorld(team, false);
|
||||||
|
|
||||||
if (team->memberIDs.size() <= 1)
|
if (team->memberIDs.size() <= 1) {
|
||||||
{
|
|
||||||
DisbandTeam(team);
|
DisbandTeam(team);
|
||||||
}
|
} else {
|
||||||
else
|
if (playerID == team->leaderID) {
|
||||||
{
|
|
||||||
if (playerID == team->leaderID)
|
|
||||||
{
|
|
||||||
PromoteMember(team, team->memberIDs[0]);
|
PromoteMember(team, team->memberIDs[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader)
|
void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader) {
|
||||||
{
|
|
||||||
team->leaderID = newLeader;
|
team->leaderID = newLeader;
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs)
|
for (const auto memberId : team->memberIDs) {
|
||||||
{
|
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
auto* otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (otherMember == nullptr) continue;
|
||||||
@ -336,19 +296,17 @@ void PlayerContainer::PromoteMember(TeamData* team, LWOOBJID newLeader)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::DisbandTeam(TeamData* team)
|
void PlayerContainer::DisbandTeam(TeamData* team) {
|
||||||
{
|
|
||||||
const auto index = std::find(mTeams.begin(), mTeams.end(), team);
|
const auto index = std::find(mTeams.begin(), mTeams.end(), team);
|
||||||
|
|
||||||
if (index == mTeams.end()) return;
|
if (index == mTeams.end()) return;
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs)
|
for (const auto memberId : team->memberIDs) {
|
||||||
{
|
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
auto* otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (otherMember == nullptr) continue;
|
||||||
|
|
||||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(otherMember->playerName.C_String()));
|
const auto memberName = GeneralUtils::UTF8ToUTF16(otherMember->playerName);
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
|
ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
|
||||||
ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember->playerID, memberName);
|
ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember->playerID, memberName);
|
||||||
@ -361,8 +319,7 @@ void PlayerContainer::DisbandTeam(TeamData* team)
|
|||||||
delete team;
|
delete team;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::TeamStatusUpdate(TeamData* team)
|
void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
||||||
{
|
|
||||||
const auto index = std::find(mTeams.begin(), mTeams.end(), team);
|
const auto index = std::find(mTeams.begin(), mTeams.end(), team);
|
||||||
|
|
||||||
if (index == mTeams.end()) return;
|
if (index == mTeams.end()) return;
|
||||||
@ -371,41 +328,32 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team)
|
|||||||
|
|
||||||
if (leader == nullptr) return;
|
if (leader == nullptr) return;
|
||||||
|
|
||||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String()));
|
const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName);
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs)
|
for (const auto memberId : team->memberIDs) {
|
||||||
{
|
|
||||||
auto* otherMember = GetPlayerData(memberId);
|
auto* otherMember = GetPlayerData(memberId);
|
||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
if (otherMember == nullptr) continue;
|
||||||
|
|
||||||
if (!team->local)
|
if (!team->local) {
|
||||||
{
|
|
||||||
ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader->zoneID, team->lootFlag, 0, leaderName);
|
ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader->zoneID, team->lootFlag, 0, leaderName);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
//ChatPacketHandler::SendTeamStatus(otherMember, LWOOBJID_EMPTY, LWOZONEID(0, 0, 0), 1, 0, u"");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateTeamsOnWorld(team, false);
|
UpdateTeamsOnWorld(team, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam)
|
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
||||||
{
|
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_TEAM_UPDATE);
|
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
|
||||||
|
|
||||||
bitStream.Write(team->teamID);
|
bitStream.Write(team->teamID);
|
||||||
bitStream.Write(deleteTeam);
|
bitStream.Write(deleteTeam);
|
||||||
|
|
||||||
if (!deleteTeam)
|
if (!deleteTeam) {
|
||||||
{
|
|
||||||
bitStream.Write(team->lootFlag);
|
bitStream.Write(team->lootFlag);
|
||||||
bitStream.Write(static_cast<char>(team->memberIDs.size()));
|
bitStream.Write(static_cast<char>(team->memberIDs.size()));
|
||||||
for (const auto memberID : team->memberIDs)
|
for (const auto memberID : team->memberIDs) {
|
||||||
{
|
|
||||||
bitStream.Write(memberID);
|
bitStream.Write(memberID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,8 +361,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam)
|
|||||||
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u16string PlayerContainer::GetName(LWOOBJID playerID)
|
std::u16string PlayerContainer::GetName(LWOOBJID playerID) {
|
||||||
{
|
|
||||||
const auto& pair = mNames.find(playerID);
|
const auto& pair = mNames.find(playerID);
|
||||||
|
|
||||||
if (pair == mNames.end()) return u"";
|
if (pair == mNames.end()) return u"";
|
||||||
@ -422,12 +369,9 @@ std::u16string PlayerContainer::GetName(LWOOBJID playerID)
|
|||||||
return pair->second;
|
return pair->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
LWOOBJID PlayerContainer::GetId(const std::u16string& playerName)
|
LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) {
|
||||||
{
|
for (const auto& pair : mNames) {
|
||||||
for (const auto& pair : mNames)
|
if (pair.second == playerName) {
|
||||||
{
|
|
||||||
if (pair.second == playerName)
|
|
||||||
{
|
|
||||||
return pair.first;
|
return pair.first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,7 +379,6 @@ LWOOBJID PlayerContainer::GetId(const std::u16string& playerName)
|
|||||||
return LWOOBJID_EMPTY;
|
return LWOOBJID_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerContainer::GetIsMuted(PlayerData* data)
|
bool PlayerContainer::GetIsMuted(PlayerData* data) {
|
||||||
{
|
|
||||||
return data->muteExpire == 1 || data->muteExpire > time(NULL);
|
return data->muteExpire == 1 || data->muteExpire > time(NULL);
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,18 @@
|
|||||||
|
|
||||||
struct PlayerData {
|
struct PlayerData {
|
||||||
LWOOBJID playerID;
|
LWOOBJID playerID;
|
||||||
RakNet::RakString playerName;
|
std::string playerName;
|
||||||
SystemAddress sysAddr;
|
SystemAddress sysAddr;
|
||||||
LWOZONEID zoneID;
|
LWOZONEID zoneID;
|
||||||
std::vector<FriendData> friends;
|
std::vector<FriendData> friends;
|
||||||
time_t muteExpire;
|
time_t muteExpire;
|
||||||
|
uint8_t countOfBestFriends = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TeamData {
|
struct TeamData {
|
||||||
LWOOBJID teamID = LWOOBJID_EMPTY; // Internal use
|
LWOOBJID teamID = LWOOBJID_EMPTY; // Internal use
|
||||||
LWOOBJID leaderID = LWOOBJID_EMPTY;
|
LWOOBJID leaderID = LWOOBJID_EMPTY;
|
||||||
std::vector<LWOOBJID> memberIDs {};
|
std::vector<LWOOBJID> memberIDs{};
|
||||||
uint8_t lootFlag = 0;
|
uint8_t lootFlag = 0;
|
||||||
bool local = false;
|
bool local = false;
|
||||||
LWOZONEID zoneId = {};
|
LWOZONEID zoneId = {};
|
||||||
@ -45,7 +46,7 @@ public:
|
|||||||
PlayerData* GetPlayerData(const std::string& playerName) {
|
PlayerData* GetPlayerData(const std::string& playerName) {
|
||||||
for (auto player : mPlayers) {
|
for (auto player : mPlayers) {
|
||||||
if (player.second) {
|
if (player.second) {
|
||||||
std::string pn = player.second->playerName.C_String();
|
std::string pn = player.second->playerName.c_str();
|
||||||
if (pn == playerName) return player.second;
|
if (pn == playerName) return player.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
160
dCommon/AMFDeserialize.cpp
Normal file
160
dCommon/AMFDeserialize.cpp
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#include "AMFDeserialize.h"
|
||||||
|
|
||||||
|
#include "AMFFormat.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AMF3 Reference document https://rtmp.veriskope.com/pdf/amf3-file-format-spec.pdf
|
||||||
|
* AMF3 Deserializer written by EmosewaMC
|
||||||
|
*/
|
||||||
|
|
||||||
|
AMFValue* AMFDeserialize::Read(RakNet::BitStream* inStream) {
|
||||||
|
if (!inStream) return nullptr;
|
||||||
|
AMFValue* returnValue = nullptr;
|
||||||
|
// Read in the value type from the bitStream
|
||||||
|
int8_t marker;
|
||||||
|
inStream->Read(marker);
|
||||||
|
// Based on the typing, create the value associated with that and return the base value class
|
||||||
|
switch (marker) {
|
||||||
|
case AMFValueType::AMFUndefined: {
|
||||||
|
returnValue = new AMFUndefinedValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AMFValueType::AMFNull: {
|
||||||
|
returnValue = new AMFNullValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AMFValueType::AMFFalse: {
|
||||||
|
returnValue = new AMFFalseValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AMFValueType::AMFTrue: {
|
||||||
|
returnValue = new AMFTrueValue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AMFValueType::AMFInteger: {
|
||||||
|
returnValue = ReadAmfInteger(inStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AMFValueType::AMFDouble: {
|
||||||
|
returnValue = ReadAmfDouble(inStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AMFValueType::AMFString: {
|
||||||
|
returnValue = ReadAmfString(inStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case AMFValueType::AMFArray: {
|
||||||
|
returnValue = ReadAmfArray(inStream);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO We do not need these values, but if someone wants to implement them
|
||||||
|
// then please do so and add the corresponding unit tests.
|
||||||
|
case AMFValueType::AMFXMLDoc:
|
||||||
|
case AMFValueType::AMFDate:
|
||||||
|
case AMFValueType::AMFObject:
|
||||||
|
case AMFValueType::AMFXML:
|
||||||
|
case AMFValueType::AMFByteArray:
|
||||||
|
case AMFValueType::AMFVectorInt:
|
||||||
|
case AMFValueType::AMFVectorUInt:
|
||||||
|
case AMFValueType::AMFVectorDouble:
|
||||||
|
case AMFValueType::AMFVectorObject:
|
||||||
|
case AMFValueType::AMFDictionary: {
|
||||||
|
throw static_cast<AMFValueType>(marker);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw static_cast<AMFValueType>(marker);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) {
|
||||||
|
bool byteFlag = true;
|
||||||
|
uint32_t actualNumber{};
|
||||||
|
uint8_t numberOfBytesRead{};
|
||||||
|
while (byteFlag && numberOfBytesRead < 4) {
|
||||||
|
uint8_t byte{};
|
||||||
|
inStream->Read(byte);
|
||||||
|
// Parse the byte
|
||||||
|
if (numberOfBytesRead < 3) {
|
||||||
|
byteFlag = byte & static_cast<uint8_t>(1 << 7);
|
||||||
|
byte = byte << 1UL;
|
||||||
|
}
|
||||||
|
// Combine the read byte with our current read in number
|
||||||
|
actualNumber <<= 8UL;
|
||||||
|
actualNumber |= static_cast<uint32_t>(byte);
|
||||||
|
// If we are not done reading in bytes, shift right 1 bit
|
||||||
|
if (numberOfBytesRead < 3) actualNumber = actualNumber >> 1UL;
|
||||||
|
numberOfBytesRead++;
|
||||||
|
}
|
||||||
|
return actualNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) {
|
||||||
|
auto length = ReadU29(inStream);
|
||||||
|
// Check if this is a reference
|
||||||
|
bool isReference = length % 2 == 1;
|
||||||
|
// Right shift by 1 bit to get index if reference or size of next string if value
|
||||||
|
length = length >> 1;
|
||||||
|
if (isReference) {
|
||||||
|
std::string value(length, 0);
|
||||||
|
inStream->Read(&value[0], length);
|
||||||
|
// Empty strings are never sent by reference
|
||||||
|
if (!value.empty()) accessedElements.push_back(value);
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
// Length is a reference to a previous index - use that as the read in value
|
||||||
|
return accessedElements[length];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AMFValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) {
|
||||||
|
auto doubleValue = new AMFDoubleValue();
|
||||||
|
double value;
|
||||||
|
inStream->Read<double>(value);
|
||||||
|
doubleValue->SetDoubleValue(value);
|
||||||
|
return doubleValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AMFValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) {
|
||||||
|
auto arrayValue = new AMFArrayValue();
|
||||||
|
|
||||||
|
// Read size of dense array
|
||||||
|
auto sizeOfDenseArray = (ReadU29(inStream) >> 1);
|
||||||
|
|
||||||
|
// Then read Key'd portion
|
||||||
|
while (true) {
|
||||||
|
auto key = ReadString(inStream);
|
||||||
|
// No more values when we encounter an empty string
|
||||||
|
if (key.size() == 0) break;
|
||||||
|
arrayValue->InsertValue(key, Read(inStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally read dense portion
|
||||||
|
for (uint32_t i = 0; i < sizeOfDenseArray; i++) {
|
||||||
|
arrayValue->PushBackValue(Read(inStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
return arrayValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AMFValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) {
|
||||||
|
auto stringValue = new AMFStringValue();
|
||||||
|
stringValue->SetStringValue(ReadString(inStream));
|
||||||
|
return stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AMFValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) {
|
||||||
|
auto integerValue = new AMFIntegerValue();
|
||||||
|
integerValue->SetIntegerValue(ReadU29(inStream));
|
||||||
|
return integerValue;
|
||||||
|
}
|
71
dCommon/AMFDeserialize.h
Normal file
71
dCommon/AMFDeserialize.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BitStream.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class AMFValue;
|
||||||
|
class AMFDeserialize {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Read an AMF3 value from a bitstream.
|
||||||
|
*
|
||||||
|
* @param inStream inStream to read value from.
|
||||||
|
* @return Returns an AMFValue with all the information from the bitStream in it.
|
||||||
|
*/
|
||||||
|
AMFValue* Read(RakNet::BitStream* inStream);
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Private method to read a U29 integer from a bitstream
|
||||||
|
*
|
||||||
|
* @param inStream bitstream to read data from
|
||||||
|
* @return The number as an unsigned 29 bit integer
|
||||||
|
*/
|
||||||
|
uint32_t ReadU29(RakNet::BitStream* inStream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads a string from a bitstream
|
||||||
|
*
|
||||||
|
* @param inStream bitStream to read data from
|
||||||
|
* @return The read string
|
||||||
|
*/
|
||||||
|
std::string ReadString(RakNet::BitStream* inStream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an AMFDouble value from a bitStream
|
||||||
|
*
|
||||||
|
* @param inStream bitStream to read data from
|
||||||
|
* @return Double value represented as an AMFValue
|
||||||
|
*/
|
||||||
|
AMFValue* ReadAmfDouble(RakNet::BitStream* inStream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an AMFArray from a bitStream
|
||||||
|
*
|
||||||
|
* @param inStream bitStream to read data from
|
||||||
|
* @return Array value represented as an AMFValue
|
||||||
|
*/
|
||||||
|
AMFValue* ReadAmfArray(RakNet::BitStream* inStream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an AMFString from a bitStream
|
||||||
|
*
|
||||||
|
* @param inStream bitStream to read data from
|
||||||
|
* @return String value represented as an AMFValue
|
||||||
|
*/
|
||||||
|
AMFValue* ReadAmfString(RakNet::BitStream* inStream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read an AMFInteger from a bitStream
|
||||||
|
*
|
||||||
|
* @param inStream bitStream to read data from
|
||||||
|
* @return Integer value represented as an AMFValue
|
||||||
|
*/
|
||||||
|
AMFValue* ReadAmfInteger(RakNet::BitStream* inStream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of strings read so far saved to be read by reference.
|
||||||
|
*/
|
||||||
|
std::vector<std::string> accessedElements;
|
||||||
|
};
|
@ -2,156 +2,155 @@
|
|||||||
|
|
||||||
// AMFInteger
|
// AMFInteger
|
||||||
void AMFIntegerValue::SetIntegerValue(uint32_t value) {
|
void AMFIntegerValue::SetIntegerValue(uint32_t value) {
|
||||||
this->value = value;
|
this->value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AMFIntegerValue::GetIntegerValue() {
|
uint32_t AMFIntegerValue::GetIntegerValue() {
|
||||||
return this->value;
|
return this->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFDouble
|
// AMFDouble
|
||||||
void AMFDoubleValue::SetDoubleValue(double value) {
|
void AMFDoubleValue::SetDoubleValue(double value) {
|
||||||
this->value = value;
|
this->value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AMFDoubleValue::GetDoubleValue() {
|
double AMFDoubleValue::GetDoubleValue() {
|
||||||
return this->value;
|
return this->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFString
|
// AMFString
|
||||||
void AMFStringValue::SetStringValue(const std::string& value) {
|
void AMFStringValue::SetStringValue(const std::string& value) {
|
||||||
this->value = value;
|
this->value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AMFStringValue::GetStringValue() {
|
std::string AMFStringValue::GetStringValue() {
|
||||||
return this->value;
|
return this->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFXMLDoc
|
// AMFXMLDoc
|
||||||
void AMFXMLDocValue::SetXMLDocValue(const std::string& value) {
|
void AMFXMLDocValue::SetXMLDocValue(const std::string& value) {
|
||||||
this->xmlData = value;
|
this->xmlData = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AMFXMLDocValue::GetXMLDocValue() {
|
std::string AMFXMLDocValue::GetXMLDocValue() {
|
||||||
return this->xmlData;
|
return this->xmlData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFDate
|
// AMFDate
|
||||||
void AMFDateValue::SetDateValue(uint64_t value) {
|
void AMFDateValue::SetDateValue(uint64_t value) {
|
||||||
this->millisecondTimestamp = value;
|
this->millisecondTimestamp = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t AMFDateValue::GetDateValue() {
|
uint64_t AMFDateValue::GetDateValue() {
|
||||||
return this->millisecondTimestamp;
|
return this->millisecondTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFArray Insert Value
|
// AMFArray Insert Value
|
||||||
void AMFArrayValue::InsertValue(const std::string& key, AMFValue* value) {
|
void AMFArrayValue::InsertValue(const std::string& key, AMFValue* value) {
|
||||||
this->associative.insert(std::make_pair(key, value));
|
this->associative.insert(std::make_pair(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFArray Remove Value
|
// AMFArray Remove Value
|
||||||
void AMFArrayValue::RemoveValue(const std::string& key) {
|
void AMFArrayValue::RemoveValue(const std::string& key) {
|
||||||
_AMFArrayMap_::iterator it = this->associative.find(key);
|
_AMFArrayMap_::iterator it = this->associative.find(key);
|
||||||
if (it != this->associative.end()) {
|
if (it != this->associative.end()) {
|
||||||
this->associative.erase(it);
|
this->associative.erase(it);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
// AMFArray Get Associative Iterator Begin
|
||||||
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueBegin() {
|
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueBegin() {
|
||||||
return this->associative.begin();
|
return this->associative.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFArray Get Associative Iterator End
|
// AMFArray Get Associative Iterator End
|
||||||
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueEnd() {
|
_AMFArrayMap_::iterator AMFArrayValue::GetAssociativeIteratorValueEnd() {
|
||||||
return this->associative.end();
|
return this->associative.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFArray Push Back Value
|
// AMFArray Push Back Value
|
||||||
void AMFArrayValue::PushBackValue(AMFValue* value) {
|
void AMFArrayValue::PushBackValue(AMFValue* value) {
|
||||||
this->dense.push_back(value);
|
this->dense.push_back(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFArray Pop Back Value
|
// AMFArray Pop Back Value
|
||||||
void AMFArrayValue::PopBackValue() {
|
void AMFArrayValue::PopBackValue() {
|
||||||
this->dense.pop_back();
|
this->dense.pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFArray Get Dense List Size
|
// AMFArray Get Dense List Size
|
||||||
uint32_t AMFArrayValue::GetDenseValueSize() {
|
uint32_t AMFArrayValue::GetDenseValueSize() {
|
||||||
return (uint32_t)this->dense.size();
|
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
|
// AMFArray Get Dense Iterator Begin
|
||||||
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorBegin() {
|
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorBegin() {
|
||||||
return this->dense.begin();
|
return this->dense.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFArray Get Dense Iterator End
|
// AMFArray Get Dense Iterator End
|
||||||
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorEnd() {
|
_AMFArrayList_::iterator AMFArrayValue::GetDenseIteratorEnd() {
|
||||||
return this->dense.end();
|
return this->dense.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AMFArrayValue::~AMFArrayValue() {
|
||||||
|
for (auto valueToDelete : GetDenseArray()) {
|
||||||
|
if (valueToDelete) delete valueToDelete;
|
||||||
|
}
|
||||||
|
for (auto valueToDelete : GetAssociativeMap()) {
|
||||||
|
if (valueToDelete.second) delete valueToDelete.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AMFObject Constructor
|
// AMFObject Constructor
|
||||||
AMFObjectValue::AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits) {
|
AMFObjectValue::AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits) {
|
||||||
this->traits.reserve(traits.size());
|
this->traits.reserve(traits.size());
|
||||||
std::vector<std::pair<std::string, AMFValueType>>::iterator it = traits.begin();
|
std::vector<std::pair<std::string, AMFValueType>>::iterator it = traits.begin();
|
||||||
while (it != traits.end()) {
|
while (it != traits.end()) {
|
||||||
this->traits.insert(std::make_pair(it->first, std::make_pair(it->second, new AMFNullValue())));
|
this->traits.insert(std::make_pair(it->first, std::make_pair(it->second, new AMFNullValue())));
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFObject Set Value
|
// AMFObject Set Value
|
||||||
void AMFObjectValue::SetTraitValue(const std::string& trait, AMFValue* value) {
|
void AMFObjectValue::SetTraitValue(const std::string& trait, AMFValue* value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
_AMFObjectTraits_::iterator it = this->traits.find(trait);
|
_AMFObjectTraits_::iterator it = this->traits.find(trait);
|
||||||
if (it != this->traits.end()) {
|
if (it != this->traits.end()) {
|
||||||
if (it->second.first == value->GetValueType()) {
|
if (it->second.first == value->GetValueType()) {
|
||||||
it->second.second = value;
|
it->second.second = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFObject Get Value
|
// AMFObject Get Value
|
||||||
AMFValue* AMFObjectValue::GetTraitValue(const std::string& trait) {
|
AMFValue* AMFObjectValue::GetTraitValue(const std::string& trait) {
|
||||||
_AMFObjectTraits_::iterator it = this->traits.find(trait);
|
_AMFObjectTraits_::iterator it = this->traits.find(trait);
|
||||||
if (it != this->traits.end()) {
|
if (it != this->traits.end()) {
|
||||||
return it->second.second;
|
return it->second.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFObject Get Trait Iterator Begin
|
// AMFObject Get Trait Iterator Begin
|
||||||
_AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorBegin() {
|
_AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorBegin() {
|
||||||
return this->traits.begin();
|
return this->traits.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFObject Get Trait Iterator End
|
// AMFObject Get Trait Iterator End
|
||||||
_AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorEnd() {
|
_AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorEnd() {
|
||||||
return this->traits.end();
|
return this->traits.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// AMFObject Get Trait Size
|
// AMFObject Get Trait Size
|
||||||
uint32_t AMFObjectValue::GetTraitArrayCount() {
|
uint32_t AMFObjectValue::GetTraitArrayCount() {
|
||||||
return (uint32_t)this->traits.size();
|
return (uint32_t)this->traits.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
AMFObjectValue::~AMFObjectValue() {
|
||||||
|
for (auto valueToDelete = GetTraitsIteratorBegin(); valueToDelete != GetTraitsIteratorEnd(); valueToDelete++) {
|
||||||
|
if (valueToDelete->second.second) delete valueToDelete->second.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,42 +23,43 @@ class AMFValue; // Forward declaration
|
|||||||
|
|
||||||
//! An enum for each AMF value type
|
//! An enum for each AMF value type
|
||||||
enum AMFValueType : unsigned char {
|
enum AMFValueType : unsigned char {
|
||||||
AMFUndefined = 0x00, //!< An undefined AMF Value
|
AMFUndefined = 0x00, //!< An undefined AMF Value
|
||||||
AMFNull = 0x01, //!< A null AMF value
|
AMFNull = 0x01, //!< A null AMF value
|
||||||
AMFFalse = 0x02, //!< A false AMF value
|
AMFFalse = 0x02, //!< A false AMF value
|
||||||
AMFTrue = 0x03, //!< A true AMF value
|
AMFTrue = 0x03, //!< A true AMF value
|
||||||
AMFInteger = 0x04, //!< An integer AMF value
|
AMFInteger = 0x04, //!< An integer AMF value
|
||||||
AMFDouble = 0x05, //!< A double AMF value
|
AMFDouble = 0x05, //!< A double AMF value
|
||||||
AMFString = 0x06, //!< A string AMF value
|
AMFString = 0x06, //!< A string AMF value
|
||||||
AMFXMLDoc = 0x07, //!< An XML Doc AMF value
|
AMFXMLDoc = 0x07, //!< An XML Doc AMF value
|
||||||
AMFDate = 0x08, //!< A date AMF value
|
AMFDate = 0x08, //!< A date AMF value
|
||||||
AMFArray = 0x09, //!< An array AMF value
|
AMFArray = 0x09, //!< An array AMF value
|
||||||
AMFObject = 0x0A, //!< An object AMF value
|
AMFObject = 0x0A, //!< An object AMF value
|
||||||
AMFXML = 0x0B, //!< An XML AMF value
|
AMFXML = 0x0B, //!< An XML AMF value
|
||||||
AMFByteArray = 0x0C, //!< A byte array AMF value
|
AMFByteArray = 0x0C, //!< A byte array AMF value
|
||||||
AMFVectorInt = 0x0D, //!< An integer vector AMF value
|
AMFVectorInt = 0x0D, //!< An integer vector AMF value
|
||||||
AMFVectorUInt = 0x0E, //!< An unsigned integer AMF value
|
AMFVectorUInt = 0x0E, //!< An unsigned integer AMF value
|
||||||
AMFVectorDouble = 0x0F, //!< A double vector AMF value
|
AMFVectorDouble = 0x0F, //!< A double vector AMF value
|
||||||
AMFVectorObject = 0x10, //!< An object vector AMF value
|
AMFVectorObject = 0x10, //!< An object vector AMF value
|
||||||
AMFDictionary = 0x11 //!< A dictionary AMF value
|
AMFDictionary = 0x11 //!< A dictionary AMF value
|
||||||
};
|
};
|
||||||
|
|
||||||
//! An enum for the object value types
|
//! An enum for the object value types
|
||||||
enum AMFObjectValueType : unsigned char {
|
enum AMFObjectValueType : unsigned char {
|
||||||
AMFObjectAnonymous = 0x01,
|
AMFObjectAnonymous = 0x01,
|
||||||
AMFObjectTyped = 0x02,
|
AMFObjectTyped = 0x02,
|
||||||
AMFObjectDynamic = 0x03,
|
AMFObjectDynamic = 0x03,
|
||||||
AMFObjectExternalizable = 0x04
|
AMFObjectExternalizable = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The base AMF value class
|
//! The base AMF value class
|
||||||
class AMFValue {
|
class AMFValue {
|
||||||
public:
|
public:
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
virtual AMFValueType GetValueType() = 0;
|
virtual AMFValueType GetValueType() = 0;
|
||||||
|
virtual ~AMFValue() {};
|
||||||
};
|
};
|
||||||
|
|
||||||
//! A typedef for a pointer to an AMF value
|
//! A typedef for a pointer to an AMF value
|
||||||
@ -70,299 +71,343 @@ typedef AMFValue* NDGFxValue;
|
|||||||
//! The undefined value AMF type
|
//! The undefined value AMF type
|
||||||
class AMFUndefinedValue : public AMFValue {
|
class AMFUndefinedValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFUndefined; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
public:
|
||||||
|
static const AMFValueType ValueType = AMFUndefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The null value AMF type
|
//! The null value AMF type
|
||||||
class AMFNullValue : public AMFValue {
|
class AMFNullValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFNull; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
public:
|
||||||
|
static const AMFValueType ValueType = AMFNull;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The false value AMF type
|
//! The false value AMF type
|
||||||
class AMFFalseValue : public AMFValue {
|
class AMFFalseValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFFalse; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
public:
|
||||||
|
static const AMFValueType ValueType = AMFFalse;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The true value AMF type
|
//! The true value AMF type
|
||||||
class AMFTrueValue : public AMFValue {
|
class AMFTrueValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFTrue; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
public:
|
||||||
|
static const AMFValueType ValueType = AMFTrue;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The integer value AMF type
|
//! The integer value AMF type
|
||||||
class AMFIntegerValue : public AMFValue {
|
class AMFIntegerValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
uint32_t value; //!< The value of the AMF type
|
uint32_t value; //!< The value of the AMF type
|
||||||
|
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFInteger; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! Sets the integer value
|
static const AMFValueType ValueType = AMFInteger;
|
||||||
/*!
|
//! Sets the integer value
|
||||||
\param value The value to set
|
/*!
|
||||||
*/
|
\param value The value to set
|
||||||
void SetIntegerValue(uint32_t value);
|
*/
|
||||||
|
void SetIntegerValue(uint32_t value);
|
||||||
|
|
||||||
//! Gets the integer value
|
//! Gets the integer value
|
||||||
/*!
|
/*!
|
||||||
\return The integer value
|
\return The integer value
|
||||||
*/
|
*/
|
||||||
uint32_t GetIntegerValue();
|
uint32_t GetIntegerValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The double value AMF type
|
//! The double value AMF type
|
||||||
class AMFDoubleValue : public AMFValue {
|
class AMFDoubleValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
double value; //!< The value of the AMF type
|
double value; //!< The value of the AMF type
|
||||||
|
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFDouble; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! Sets the double value
|
static const AMFValueType ValueType = AMFDouble;
|
||||||
/*!
|
//! Sets the double value
|
||||||
\param value The value to set to
|
/*!
|
||||||
*/
|
\param value The value to set to
|
||||||
void SetDoubleValue(double value);
|
*/
|
||||||
|
void SetDoubleValue(double value);
|
||||||
|
|
||||||
//! Gets the double value
|
//! Gets the double value
|
||||||
/*!
|
/*!
|
||||||
\return The double value
|
\return The double value
|
||||||
*/
|
*/
|
||||||
double GetDoubleValue();
|
double GetDoubleValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The string value AMF type
|
//! The string value AMF type
|
||||||
class AMFStringValue : public AMFValue {
|
class AMFStringValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
std::string value; //!< The value of the AMF type
|
std::string value; //!< The value of the AMF type
|
||||||
|
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFString; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! Sets the string value
|
static const AMFValueType ValueType = AMFString;
|
||||||
/*!
|
//! Sets the string value
|
||||||
\param value The string value to set to
|
/*!
|
||||||
*/
|
\param value The string value to set to
|
||||||
void SetStringValue(const std::string& value);
|
*/
|
||||||
|
void SetStringValue(const std::string& value);
|
||||||
|
|
||||||
//! Gets the string value
|
//! Gets the string value
|
||||||
/*!
|
/*!
|
||||||
\return The string value
|
\return The string value
|
||||||
*/
|
*/
|
||||||
std::string GetStringValue();
|
std::string GetStringValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The XML doc value AMF type
|
//! The XML doc value AMF type
|
||||||
class AMFXMLDocValue : public AMFValue {
|
class AMFXMLDocValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
std::string xmlData; //!< The value of the AMF type
|
std::string xmlData; //!< The value of the AMF type
|
||||||
|
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFXMLDoc; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! Sets the XML Doc value
|
static const AMFValueType ValueType = AMFXMLDoc;
|
||||||
/*!
|
//! Sets the XML Doc value
|
||||||
\param value The value to set to
|
/*!
|
||||||
*/
|
\param value The value to set to
|
||||||
void SetXMLDocValue(const std::string& value);
|
*/
|
||||||
|
void SetXMLDocValue(const std::string& value);
|
||||||
|
|
||||||
//! Gets the XML Doc value
|
//! Gets the XML Doc value
|
||||||
/*!
|
/*!
|
||||||
\return The XML Doc value
|
\return The XML Doc value
|
||||||
*/
|
*/
|
||||||
std::string GetXMLDocValue();
|
std::string GetXMLDocValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The date value AMF type
|
//! The date value AMF type
|
||||||
class AMFDateValue : public AMFValue {
|
class AMFDateValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
uint64_t millisecondTimestamp; //!< The time in milliseconds since the ephoch
|
uint64_t millisecondTimestamp; //!< The time in milliseconds since the ephoch
|
||||||
|
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFDate; }
|
AMFValueType GetValueType() { return ValueType; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! Sets the date time
|
static const AMFValueType ValueType = AMFDate;
|
||||||
/*!
|
//! Sets the date time
|
||||||
\param value The value to set to
|
/*!
|
||||||
*/
|
\param value The value to set to
|
||||||
void SetDateValue(uint64_t value);
|
*/
|
||||||
|
void SetDateValue(uint64_t value);
|
||||||
|
|
||||||
//! Gets the date value
|
//! Gets the date value
|
||||||
/*!
|
/*!
|
||||||
\return The date value in milliseconds since the epoch
|
\return The date value in milliseconds since the epoch
|
||||||
*/
|
*/
|
||||||
uint64_t GetDateValue();
|
uint64_t GetDateValue();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The array value AMF type
|
//! The array value AMF type
|
||||||
|
// This object will manage it's own memory map and list. Do not delete its values.
|
||||||
class AMFArrayValue : public AMFValue {
|
class AMFArrayValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
_AMFArrayMap_ associative; //!< The array map (associative part)
|
_AMFArrayMap_ associative; //!< The array map (associative part)
|
||||||
_AMFArrayList_ dense; //!< The array list (dense part)
|
_AMFArrayList_ dense; //!< The array list (dense part)
|
||||||
|
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFArray; }
|
AMFValueType GetValueType() override { return ValueType; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! Inserts an item into the array map for a specific key
|
static const AMFValueType ValueType = AMFArray;
|
||||||
/*!
|
|
||||||
\param key The key to set
|
|
||||||
\param value The value to add
|
|
||||||
*/
|
|
||||||
void InsertValue(const std::string& key, AMFValue* value);
|
|
||||||
|
|
||||||
//! Removes an item for a specific key
|
~AMFArrayValue() override;
|
||||||
/*!
|
//! Inserts an item into the array map for a specific key
|
||||||
\param key The key to remove
|
/*!
|
||||||
*/
|
\param key The key to set
|
||||||
void RemoveValue(const std::string& key);
|
\param value The value to add
|
||||||
|
*/
|
||||||
|
void InsertValue(const std::string& key, AMFValue* value);
|
||||||
|
|
||||||
//! Finds an AMF value
|
//! Removes an item for a specific key
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value if found, nullptr otherwise
|
\param key The key to remove
|
||||||
*/
|
*/
|
||||||
AMFValue* FindValue(const std::string& key);
|
void RemoveValue(const std::string& key);
|
||||||
|
|
||||||
//! Returns where the associative iterator begins
|
//! Finds an AMF value
|
||||||
/*!
|
/*!
|
||||||
\return Where the array map iterator begins
|
\return The AMF value if found, nullptr otherwise
|
||||||
*/
|
*/
|
||||||
_AMFArrayMap_::iterator GetAssociativeIteratorValueBegin();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
//! Returns where the associative iterator ends
|
return nullptr;
|
||||||
/*!
|
};
|
||||||
\return Where the array map iterator ends
|
|
||||||
*/
|
|
||||||
_AMFArrayMap_::iterator GetAssociativeIteratorValueEnd();
|
|
||||||
|
|
||||||
//! Pushes back a value into the array list
|
//! Returns where the associative iterator begins
|
||||||
/*!
|
/*!
|
||||||
\param value The value to push back
|
\return Where the array map iterator begins
|
||||||
*/
|
*/
|
||||||
void PushBackValue(AMFValue* value);
|
_AMFArrayMap_::iterator GetAssociativeIteratorValueBegin();
|
||||||
|
|
||||||
//! Pops back the last value in the array list
|
//! Returns where the associative iterator ends
|
||||||
void PopBackValue();
|
/*!
|
||||||
|
\return Where the array map iterator ends
|
||||||
|
*/
|
||||||
|
_AMFArrayMap_::iterator GetAssociativeIteratorValueEnd();
|
||||||
|
|
||||||
//! Gets the count of the dense list
|
//! Pushes back a value into the array list
|
||||||
/*!
|
/*!
|
||||||
\return The dense list size
|
\param value The value to push back
|
||||||
*/
|
*/
|
||||||
uint32_t GetDenseValueSize();
|
void PushBackValue(AMFValue* value);
|
||||||
|
|
||||||
//! Gets a specific value from the list for the specified index
|
//! Pops back the last value in the array list
|
||||||
/*!
|
void PopBackValue();
|
||||||
\param index The index to get
|
|
||||||
*/
|
|
||||||
AMFValue* GetValueAt(uint32_t index);
|
|
||||||
|
|
||||||
//! Returns where the dense iterator begins
|
//! Gets the count of the dense list
|
||||||
/*!
|
/*!
|
||||||
\return Where the iterator begins
|
\return The dense list size
|
||||||
*/
|
*/
|
||||||
_AMFArrayList_::iterator GetDenseIteratorBegin();
|
uint32_t GetDenseValueSize();
|
||||||
|
|
||||||
//! Returns where the dense iterator ends
|
//! Gets a specific value from the list for the specified index
|
||||||
/*!
|
/*!
|
||||||
\return Where the iterator ends
|
\param index The index to get
|
||||||
*/
|
*/
|
||||||
_AMFArrayList_::iterator GetDenseIteratorEnd();
|
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
|
||||||
|
/*!
|
||||||
|
\return Where the iterator begins
|
||||||
|
*/
|
||||||
|
_AMFArrayList_::iterator GetDenseIteratorBegin();
|
||||||
|
|
||||||
|
//! Returns where the dense iterator ends
|
||||||
|
/*!
|
||||||
|
\return Where the iterator ends
|
||||||
|
*/
|
||||||
|
_AMFArrayList_::iterator GetDenseIteratorEnd();
|
||||||
|
|
||||||
|
//! Returns the associative map
|
||||||
|
/*!
|
||||||
|
\return The associative map
|
||||||
|
*/
|
||||||
|
_AMFArrayMap_ GetAssociativeMap() { return this->associative; };
|
||||||
|
|
||||||
|
//! Returns the dense array
|
||||||
|
/*!
|
||||||
|
\return The dense array
|
||||||
|
*/
|
||||||
|
_AMFArrayList_ GetDenseArray() { return this->dense; };
|
||||||
};
|
};
|
||||||
|
|
||||||
//! The anonymous object value AMF type
|
//! The anonymous object value AMF type
|
||||||
class AMFObjectValue : public AMFValue {
|
class AMFObjectValue : public AMFValue {
|
||||||
private:
|
private:
|
||||||
_AMFObjectTraits_ traits; //!< The object traits
|
_AMFObjectTraits_ traits; //!< The object traits
|
||||||
|
|
||||||
//! Returns the AMF value type
|
//! Returns the AMF value type
|
||||||
/*!
|
/*!
|
||||||
\return The AMF value type
|
\return The AMF value type
|
||||||
*/
|
*/
|
||||||
AMFValueType GetValueType() { return AMFObject; }
|
AMFValueType GetValueType() override { return ValueType; }
|
||||||
|
~AMFObjectValue() override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//! Constructor
|
static const AMFValueType ValueType = AMFObject;
|
||||||
/*!
|
//! Constructor
|
||||||
\param traits The traits to set
|
/*!
|
||||||
*/
|
\param traits The traits to set
|
||||||
AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits);
|
*/
|
||||||
|
AMFObjectValue(std::vector<std::pair<std::string, AMFValueType>> traits);
|
||||||
|
|
||||||
//! Gets the object value type
|
//! Gets the object value type
|
||||||
/*!
|
/*!
|
||||||
\return The object value type
|
\return The object value type
|
||||||
*/
|
*/
|
||||||
virtual AMFObjectValueType GetObjectValueType() { return AMFObjectAnonymous; }
|
virtual AMFObjectValueType GetObjectValueType() { return AMFObjectAnonymous; }
|
||||||
|
|
||||||
//! Sets the value of a trait
|
//! Sets the value of a trait
|
||||||
/*!
|
/*!
|
||||||
\param trait The trait to set the value for
|
\param trait The trait to set the value for
|
||||||
\param value The AMF value to set
|
\param value The AMF value to set
|
||||||
*/
|
*/
|
||||||
void SetTraitValue(const std::string& trait, AMFValue* value);
|
void SetTraitValue(const std::string& trait, AMFValue* value);
|
||||||
|
|
||||||
//! Gets a trait value
|
//! Gets a trait value
|
||||||
/*!
|
/*!
|
||||||
\param trait The trait to get the value for
|
\param trait The trait to get the value for
|
||||||
\return The trait value
|
\return The trait value
|
||||||
*/
|
*/
|
||||||
AMFValue* GetTraitValue(const std::string& trait);
|
AMFValue* GetTraitValue(const std::string& trait);
|
||||||
|
|
||||||
//! Gets the beginning of the object traits iterator
|
//! Gets the beginning of the object traits iterator
|
||||||
/*!
|
/*!
|
||||||
\return The AMF trait array iterator begin
|
\return The AMF trait array iterator begin
|
||||||
*/
|
*/
|
||||||
_AMFObjectTraits_::iterator GetTraitsIteratorBegin();
|
_AMFObjectTraits_::iterator GetTraitsIteratorBegin();
|
||||||
|
|
||||||
//! Gets the end of the object traits iterator
|
//! Gets the end of the object traits iterator
|
||||||
/*!
|
/*!
|
||||||
\return The AMF trait array iterator begin
|
\return The AMF trait array iterator begin
|
||||||
*/
|
*/
|
||||||
_AMFObjectTraits_::iterator GetTraitsIteratorEnd();
|
_AMFObjectTraits_::iterator GetTraitsIteratorEnd();
|
||||||
|
|
||||||
//! Gets the amount of traits
|
//! Gets the amount of traits
|
||||||
/*!
|
/*!
|
||||||
\return The amount of traits
|
\return The amount of traits
|
||||||
*/
|
*/
|
||||||
uint32_t GetTraitArrayCount();
|
uint32_t GetTraitArrayCount();
|
||||||
};
|
};
|
||||||
|
@ -3,269 +3,257 @@
|
|||||||
// Writes an AMFValue pointer to a RakNet::BitStream
|
// Writes an AMFValue pointer to a RakNet::BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
|
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
|
||||||
if (value != nullptr) {
|
if (value != nullptr) {
|
||||||
AMFValueType type = value->GetValueType();
|
AMFValueType type = value->GetValueType();
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AMFUndefined: {
|
case AMFUndefined: {
|
||||||
AMFUndefinedValue* v = (AMFUndefinedValue*)value;
|
AMFUndefinedValue* v = (AMFUndefinedValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AMFNull: {
|
case AMFNull: {
|
||||||
AMFNullValue* v = (AMFNullValue*)value;
|
AMFNullValue* v = (AMFNullValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AMFFalse: {
|
case AMFFalse: {
|
||||||
AMFFalseValue* v = (AMFFalseValue*)value;
|
AMFFalseValue* v = (AMFFalseValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AMFTrue: {
|
case AMFTrue: {
|
||||||
AMFTrueValue* v = (AMFTrueValue*)value;
|
AMFTrueValue* v = (AMFTrueValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AMFInteger: {
|
case AMFInteger: {
|
||||||
AMFIntegerValue* v = (AMFIntegerValue*)value;
|
AMFIntegerValue* v = (AMFIntegerValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AMFString: {
|
case AMFDouble: {
|
||||||
AMFStringValue* v = (AMFStringValue*)value;
|
AMFDoubleValue* v = (AMFDoubleValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AMFXMLDoc: {
|
case AMFString: {
|
||||||
AMFXMLDocValue* v = (AMFXMLDocValue*)value;
|
AMFStringValue* v = (AMFStringValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AMFDate: {
|
case AMFXMLDoc: {
|
||||||
AMFDateValue* v = (AMFDateValue*)value;
|
AMFXMLDocValue* v = (AMFXMLDocValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AMFArray: {
|
case AMFDate: {
|
||||||
AMFArrayValue* v = (AMFArrayValue*)value;
|
AMFDateValue* v = (AMFDateValue*)value;
|
||||||
this->Write(*v);
|
this->Write(*v);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
case AMFArray: {
|
||||||
|
this->Write((AMFArrayValue*)value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AMFObject:
|
||||||
|
case AMFXML:
|
||||||
|
case AMFByteArray:
|
||||||
|
case AMFVectorInt:
|
||||||
|
case AMFVectorUInt:
|
||||||
|
case AMFVectorDouble:
|
||||||
|
case AMFVectorObject:
|
||||||
|
case AMFDictionary:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A private function to write an value to a RakNet::BitStream
|
/**
|
||||||
|
* A private function to write an value to a RakNet::BitStream
|
||||||
|
* RakNet writes in the correct byte order - do not reverse this.
|
||||||
|
*/
|
||||||
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||||
unsigned char b4 = (unsigned char)v;
|
unsigned char b4 = (unsigned char)v;
|
||||||
if (v < 0x00200000) {
|
if (v < 0x00200000) {
|
||||||
b4 = b4 & 0x7F;
|
b4 = b4 & 0x7F;
|
||||||
if (v > 0x7F) {
|
if (v > 0x7F) {
|
||||||
unsigned char b3;
|
unsigned char b3;
|
||||||
v = v >> 7;
|
v = v >> 7;
|
||||||
b3 = ((unsigned char)(v)) | 0x80;
|
b3 = ((unsigned char)(v)) | 0x80;
|
||||||
if (v > 0x7F) {
|
if (v > 0x7F) {
|
||||||
unsigned char b2;
|
unsigned char b2;
|
||||||
v = v >> 7;
|
v = v >> 7;
|
||||||
b2 = ((unsigned char)(v)) | 0x80;
|
b2 = ((unsigned char)(v)) | 0x80;
|
||||||
bs->Write(b2);
|
bs->Write(b2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->Write(b3);
|
bs->Write(b3);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned char b1;
|
unsigned char b1;
|
||||||
unsigned char b2;
|
unsigned char b2;
|
||||||
unsigned char b3;
|
unsigned char b3;
|
||||||
|
|
||||||
v = v >> 8;
|
v = v >> 8;
|
||||||
b3 = ((unsigned char)(v)) | 0x80;
|
b3 = ((unsigned char)(v)) | 0x80;
|
||||||
v = v >> 7;
|
v = v >> 7;
|
||||||
b2 = ((unsigned char)(v)) | 0x80;
|
b2 = ((unsigned char)(v)) | 0x80;
|
||||||
v = v >> 7;
|
v = v >> 7;
|
||||||
b1 = ((unsigned char)(v)) | 0x80;
|
b1 = ((unsigned char)(v)) | 0x80;
|
||||||
|
|
||||||
bs->Write(b1);
|
bs->Write(b1);
|
||||||
bs->Write(b2);
|
bs->Write(b2);
|
||||||
bs->Write(b3);
|
bs->Write(b3);
|
||||||
}
|
}
|
||||||
|
|
||||||
bs->Write(b4);
|
bs->Write(b4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes a flag number to a RakNet::BitStream
|
/**
|
||||||
|
* Writes a flag number to a RakNet::BitStream
|
||||||
|
* RakNet writes in the correct byte order - do not reverse this.
|
||||||
|
*/
|
||||||
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
|
void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
|
||||||
v = (v << 1) | 0x01;
|
v = (v << 1) | 0x01;
|
||||||
WriteUInt29(bs, v);
|
WriteUInt29(bs, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFString to a RakNet::BitStream
|
/**
|
||||||
|
* Writes an AMFString to a RakNet::BitStream
|
||||||
|
*
|
||||||
|
* RakNet writes in the correct byte order - do not reverse this.
|
||||||
|
*/
|
||||||
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
|
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
|
||||||
WriteFlagNumber(bs, (uint32_t)str.size());
|
WriteFlagNumber(bs, (uint32_t)str.size());
|
||||||
bs->Write(str.c_str(), (uint32_t)str.size());
|
bs->Write(str.c_str(), (uint32_t)str.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMF U16 to a RakNet::BitStream
|
/**
|
||||||
|
* Writes an U16 to a bitstream
|
||||||
|
*
|
||||||
|
* RakNet writes in the correct byte order - do not reverse this.
|
||||||
|
*/
|
||||||
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
|
void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) {
|
||||||
unsigned char b2;
|
bs->Write(value);
|
||||||
b2 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
bs->Write((unsigned char)value);
|
|
||||||
bs->Write(b2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMF U32 to RakNet::BitStream
|
/**
|
||||||
|
* Writes an U32 to a bitstream
|
||||||
|
*
|
||||||
|
* RakNet writes in the correct byte order - do not reverse this.
|
||||||
|
*/
|
||||||
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
|
void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) {
|
||||||
unsigned char b2;
|
bs->Write(value);
|
||||||
unsigned char b3;
|
|
||||||
unsigned char b4;
|
|
||||||
|
|
||||||
b4 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
b3 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
b2 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
|
|
||||||
bs->Write((unsigned char)value);
|
|
||||||
bs->Write(b2);
|
|
||||||
bs->Write(b3);
|
|
||||||
bs->Write(b4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMF U64 to RakNet::BitStream
|
/**
|
||||||
|
* Writes an U64 to a bitstream
|
||||||
|
*
|
||||||
|
* RakNet writes in the correct byte order - do not reverse this.
|
||||||
|
*/
|
||||||
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
|
void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) {
|
||||||
unsigned char b2;
|
bs->Write(value);
|
||||||
unsigned char b3;
|
|
||||||
unsigned char b4;
|
|
||||||
unsigned char b5;
|
|
||||||
unsigned char b6;
|
|
||||||
unsigned char b7;
|
|
||||||
unsigned char b8;
|
|
||||||
|
|
||||||
b8 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
b7 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
b6 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
b5 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
b4 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
b3 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
b2 = (unsigned char)value;
|
|
||||||
value = value >> 8;
|
|
||||||
|
|
||||||
bs->Write((unsigned char)value);
|
|
||||||
bs->Write(b2);
|
|
||||||
bs->Write(b3);
|
|
||||||
bs->Write(b4);
|
|
||||||
bs->Write(b5);
|
|
||||||
bs->Write(b6);
|
|
||||||
bs->Write(b7);
|
|
||||||
bs->Write(b8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Writes an AMFUndefinedValue to BitStream
|
// Writes an AMFUndefinedValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value) {
|
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value) {
|
||||||
this->Write(AMFUndefined);
|
this->Write(AMFUndefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFNullValue to BitStream
|
// Writes an AMFNullValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value) {
|
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value) {
|
||||||
this->Write(AMFNull);
|
this->Write(AMFNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFFalseValue to BitStream
|
// Writes an AMFFalseValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value) {
|
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value) {
|
||||||
this->Write(AMFFalse);
|
this->Write(AMFFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFTrueValue to BitStream
|
// Writes an AMFTrueValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value) {
|
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value) {
|
||||||
this->Write(AMFTrue);
|
this->Write(AMFTrue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFIntegerValue to BitStream
|
// Writes an AMFIntegerValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value) {
|
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value) {
|
||||||
this->Write(AMFInteger);
|
this->Write(AMFInteger);
|
||||||
WriteUInt29(this, value.GetIntegerValue());
|
WriteUInt29(this, value.GetIntegerValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFDoubleValue to BitStream
|
// Writes an AMFDoubleValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value) {
|
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value) {
|
||||||
this->Write(AMFDouble);
|
this->Write(AMFDouble);
|
||||||
double d = value.GetDoubleValue();
|
double d = value.GetDoubleValue();
|
||||||
WriteAMFU64(this, *((unsigned long long*)&d));
|
WriteAMFU64(this, *((unsigned long long*) & d));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFStringValue to BitStream
|
// Writes an AMFStringValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value) {
|
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value) {
|
||||||
this->Write(AMFString);
|
this->Write(AMFString);
|
||||||
std::string v = value.GetStringValue();
|
std::string v = value.GetStringValue();
|
||||||
WriteAMFString(this, v);
|
WriteAMFString(this, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFXMLDocValue to BitStream
|
// Writes an AMFXMLDocValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value) {
|
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value) {
|
||||||
this->Write(AMFXMLDoc);
|
this->Write(AMFXMLDoc);
|
||||||
std::string v = value.GetXMLDocValue();
|
std::string v = value.GetXMLDocValue();
|
||||||
WriteAMFString(this, v);
|
WriteAMFString(this, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFDateValue to BitStream
|
// Writes an AMFDateValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value) {
|
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value) {
|
||||||
this->Write(AMFDate);
|
this->Write(AMFDate);
|
||||||
uint64_t date = value.GetDateValue();
|
uint64_t date = value.GetDateValue();
|
||||||
WriteAMFU64(this, date);
|
WriteAMFU64(this, date);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFArrayValue to BitStream
|
// Writes an AMFArrayValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value) {
|
void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value) {
|
||||||
this->Write(AMFArray);
|
this->Write(AMFArray);
|
||||||
uint32_t denseSize = value.GetDenseValueSize();
|
uint32_t denseSize = value->GetDenseValueSize();
|
||||||
WriteFlagNumber(this, denseSize);
|
WriteFlagNumber(this, denseSize);
|
||||||
|
|
||||||
_AMFArrayMap_::iterator it = value.GetAssociativeIteratorValueBegin();
|
_AMFArrayMap_::iterator it = value->GetAssociativeIteratorValueBegin();
|
||||||
_AMFArrayMap_::iterator end = value.GetAssociativeIteratorValueEnd();
|
_AMFArrayMap_::iterator end = value->GetAssociativeIteratorValueEnd();
|
||||||
|
|
||||||
while (it != end) {
|
while (it != end) {
|
||||||
WriteAMFString(this, it->first);
|
WriteAMFString(this, it->first);
|
||||||
this->Write(it->second);
|
this->Write(it->second);
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->Write(AMFNull);
|
this->Write(AMFNull);
|
||||||
|
|
||||||
if (denseSize > 0) {
|
if (denseSize > 0) {
|
||||||
_AMFArrayList_::iterator it2 = value.GetDenseIteratorBegin();
|
_AMFArrayList_::iterator it2 = value->GetDenseIteratorBegin();
|
||||||
_AMFArrayList_::iterator end2 = value.GetDenseIteratorEnd();
|
_AMFArrayList_::iterator end2 = value->GetDenseIteratorEnd();
|
||||||
|
|
||||||
while (it2 != end2) {
|
while (it2 != end2) {
|
||||||
this->Write(*it2);
|
this->Write(*it2);
|
||||||
it2++;
|
it2++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,86 +7,86 @@
|
|||||||
#include <BitStream.h>
|
#include <BitStream.h>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\file AMFBitStream.hpp
|
\file AMFFormat_BitStream.h
|
||||||
\brief A class that implements native writing of AMF values to RakNet::BitStream
|
\brief A class that implements native writing of AMF values to RakNet::BitStream
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// We are using the RakNet namespace
|
// We are using the RakNet namespace
|
||||||
namespace RakNet {
|
namespace RakNet {
|
||||||
//! Writes an AMFValue pointer to a RakNet::BitStream
|
//! Writes an AMFValue pointer to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value);
|
void RakNet::BitStream::Write<AMFValue*>(AMFValue* value);
|
||||||
|
|
||||||
//! Writes an AMFUndefinedValue to a RakNet::BitStream
|
//! Writes an AMFUndefinedValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value);
|
void RakNet::BitStream::Write<AMFUndefinedValue>(AMFUndefinedValue value);
|
||||||
|
|
||||||
//! Writes an AMFNullValue to a RakNet::BitStream
|
//! Writes an AMFNullValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value);
|
void RakNet::BitStream::Write<AMFNullValue>(AMFNullValue value);
|
||||||
|
|
||||||
//! Writes an AMFFalseValue to a RakNet::BitStream
|
//! Writes an AMFFalseValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value);
|
void RakNet::BitStream::Write<AMFFalseValue>(AMFFalseValue value);
|
||||||
|
|
||||||
//! Writes an AMFTrueValue to a RakNet::BitStream
|
//! Writes an AMFTrueValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value);
|
void RakNet::BitStream::Write<AMFTrueValue>(AMFTrueValue value);
|
||||||
|
|
||||||
//! Writes an AMFIntegerValue to a RakNet::BitStream
|
//! Writes an AMFIntegerValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value);
|
void RakNet::BitStream::Write<AMFIntegerValue>(AMFIntegerValue value);
|
||||||
|
|
||||||
//! Writes an AMFDoubleValue to a RakNet::BitStream
|
//! Writes an AMFDoubleValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value);
|
void RakNet::BitStream::Write<AMFDoubleValue>(AMFDoubleValue value);
|
||||||
|
|
||||||
//! Writes an AMFStringValue to a RakNet::BitStream
|
//! Writes an AMFStringValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value);
|
void RakNet::BitStream::Write<AMFStringValue>(AMFStringValue value);
|
||||||
|
|
||||||
//! Writes an AMFXMLDocValue to a RakNet::BitStream
|
//! Writes an AMFXMLDocValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value);
|
void RakNet::BitStream::Write<AMFXMLDocValue>(AMFXMLDocValue value);
|
||||||
|
|
||||||
//! Writes an AMFDateValue to a RakNet::BitStream
|
//! Writes an AMFDateValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value);
|
void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value);
|
||||||
|
|
||||||
//! Writes an AMFArrayValue to a RakNet::BitStream
|
//! Writes an AMFArrayValue to a RakNet::BitStream
|
||||||
/*!
|
/*!
|
||||||
\param value The value to write
|
\param value The value to write
|
||||||
*/
|
*/
|
||||||
template<>
|
template <>
|
||||||
void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value);
|
void RakNet::BitStream::Write<AMFArrayValue*>(AMFArrayValue* value);
|
||||||
}
|
} // namespace RakNet
|
||||||
|
@ -10,7 +10,7 @@ void BinaryIO::WriteString(const std::string& stringToWrite, std::ofstream& outs
|
|||||||
}
|
}
|
||||||
|
|
||||||
//For reading null-terminated strings
|
//For reading null-terminated strings
|
||||||
std::string BinaryIO::ReadString(std::ifstream & instream) {
|
std::string BinaryIO::ReadString(std::istream& instream) {
|
||||||
std::string toReturn;
|
std::string toReturn;
|
||||||
char buffer;
|
char buffer;
|
||||||
|
|
||||||
@ -25,7 +25,7 @@ std::string BinaryIO::ReadString(std::ifstream & instream) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//For reading strings of a specific size
|
//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;
|
std::string toReturn;
|
||||||
char buffer;
|
char buffer;
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ std::string BinaryIO::ReadString(std::ifstream& instream, size_t size) {
|
|||||||
return toReturn;
|
return toReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string BinaryIO::ReadWString(std::ifstream & instream) {
|
std::string BinaryIO::ReadWString(std::istream& instream) {
|
||||||
size_t size;
|
size_t size;
|
||||||
BinaryRead(instream, size);
|
BinaryRead(instream, size);
|
||||||
//toReturn.resize(size);
|
//toReturn.resize(size);
|
||||||
|
@ -9,17 +9,16 @@ namespace BinaryIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::istream & BinaryRead(std::istream& stream, T& value) {
|
std::istream& BinaryRead(std::istream& stream, T& value) {
|
||||||
if (!stream.good())
|
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
|
||||||
printf("bla");
|
|
||||||
|
|
||||||
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
|
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
|
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
|
||||||
std::string ReadString(std::ifstream & instream);
|
std::string ReadString(std::istream& instream);
|
||||||
std::string ReadString(std::ifstream& instream, size_t size);
|
std::string ReadString(std::istream& instream, size_t size);
|
||||||
std::string ReadWString(std::ifstream& instream);
|
std::string ReadWString(std::istream& instream);
|
||||||
|
|
||||||
inline bool DoesFileExist(const std::string& name) {
|
inline bool DoesFileExist(const std::string& name) {
|
||||||
std::ifstream f(name.c_str());
|
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__
|
11
dCommon/Brick.h
Normal file
11
dCommon/Brick.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __BRICK__H__
|
||||||
|
#define __BRICK__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
struct Brick {
|
||||||
|
uint32_t designerID;
|
||||||
|
uint32_t materialID;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__BRICK__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();
|
||||||
|
};
|
63
dCommon/CMakeLists.txt
Normal file
63
dCommon/CMakeLists.txt
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
set(DCOMMON_SOURCES "AMFFormat.cpp"
|
||||||
|
"AMFDeserialize.cpp"
|
||||||
|
"AMFFormat_BitStream.cpp"
|
||||||
|
"BinaryIO.cpp"
|
||||||
|
"dConfig.cpp"
|
||||||
|
"Diagnostics.cpp"
|
||||||
|
"dLogger.cpp"
|
||||||
|
"GeneralUtils.cpp"
|
||||||
|
"LDFFormat.cpp"
|
||||||
|
"MD5.cpp"
|
||||||
|
"Metrics.cpp"
|
||||||
|
"NiPoint3.cpp"
|
||||||
|
"NiQuaternion.cpp"
|
||||||
|
"SHA512.cpp"
|
||||||
|
"Type.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 dDatabase tinyxml2)
|
||||||
|
|
||||||
|
if (UNIX)
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
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 "Diagnostics.h"
|
||||||
|
#include "Game.h"
|
||||||
|
#include "dLogger.h"
|
||||||
|
|
||||||
// If we're on Win32, we'll include our minidump writer
|
// If we're on Win32, we'll include our minidump writer
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -10,51 +12,51 @@
|
|||||||
#include "dLogger.h"
|
#include "dLogger.h"
|
||||||
|
|
||||||
void make_minidump(EXCEPTION_POINTERS* e) {
|
void make_minidump(EXCEPTION_POINTERS* e) {
|
||||||
auto hDbgHelp = LoadLibraryA("dbghelp");
|
auto hDbgHelp = LoadLibraryA("dbghelp");
|
||||||
if (hDbgHelp == nullptr)
|
if (hDbgHelp == nullptr)
|
||||||
return;
|
return;
|
||||||
auto pMiniDumpWriteDump = (decltype(&MiniDumpWriteDump))GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
|
auto pMiniDumpWriteDump = (decltype(&MiniDumpWriteDump))GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
|
||||||
if (pMiniDumpWriteDump == nullptr)
|
if (pMiniDumpWriteDump == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
char name[MAX_PATH];
|
char name[MAX_PATH];
|
||||||
{
|
{
|
||||||
auto nameEnd = name + GetModuleFileNameA(GetModuleHandleA(0), name, MAX_PATH);
|
auto nameEnd = name + GetModuleFileNameA(GetModuleHandleA(0), name, MAX_PATH);
|
||||||
SYSTEMTIME t;
|
SYSTEMTIME t;
|
||||||
GetSystemTime(&t);
|
GetSystemTime(&t);
|
||||||
wsprintfA(nameEnd - strlen(".exe"),
|
wsprintfA(nameEnd - strlen(".exe"),
|
||||||
"_%4d%02d%02d_%02d%02d%02d.dmp",
|
"_%4d%02d%02d_%02d%02d%02d.dmp",
|
||||||
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
|
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;
|
||||||
|
|
||||||
auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
|
||||||
if (hFile == INVALID_HANDLE_VALUE)
|
exceptionInfo.ThreadId = GetCurrentThreadId();
|
||||||
return;
|
exceptionInfo.ExceptionPointers = e;
|
||||||
|
exceptionInfo.ClientPointers = FALSE;
|
||||||
|
|
||||||
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
|
auto dumped = pMiniDumpWriteDump(
|
||||||
exceptionInfo.ThreadId = GetCurrentThreadId();
|
GetCurrentProcess(),
|
||||||
exceptionInfo.ExceptionPointers = e;
|
GetCurrentProcessId(),
|
||||||
exceptionInfo.ClientPointers = FALSE;
|
hFile,
|
||||||
|
MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory),
|
||||||
|
e ? &exceptionInfo : nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
auto dumped = pMiniDumpWriteDump(
|
CloseHandle(hFile);
|
||||||
GetCurrentProcess(),
|
|
||||||
GetCurrentProcessId(),
|
|
||||||
hFile,
|
|
||||||
MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory),
|
|
||||||
e ? &exceptionInfo : nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr);
|
|
||||||
|
|
||||||
CloseHandle(hFile);
|
return;
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e) {
|
LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e) {
|
||||||
make_minidump(e);
|
make_minidump(e);
|
||||||
if (Game::logger)
|
if (Game::logger)
|
||||||
Game::logger->Flush(); // Flush our log if we have one, before exiting.
|
Game::logger->Flush(); // Flush our log if we have one, before exiting.
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -75,146 +77,147 @@ LONG CALLBACK unhandled_handler(EXCEPTION_POINTERS* e) {
|
|||||||
#include <backtrace-supported.h>
|
#include <backtrace-supported.h>
|
||||||
|
|
||||||
struct bt_ctx {
|
struct bt_ctx {
|
||||||
struct backtrace_state* state;
|
struct backtrace_state* state;
|
||||||
int error;
|
int error;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void Bt(struct backtrace_state* state) {
|
static inline void Bt(struct backtrace_state* state) {
|
||||||
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
||||||
FILE* file = fopen(fileName.c_str(), "w+");
|
Game::logger->Log("Diagnostics", "backtrace is enabled, crash dump located at %s", fileName.c_str());
|
||||||
if (file != nullptr) {
|
FILE* file = fopen(fileName.c_str(), "w+");
|
||||||
backtrace_print(state, 2, file);
|
if (file != nullptr) {
|
||||||
fclose(file);
|
backtrace_print(state, 2, file);
|
||||||
}
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
backtrace_print(state, 2, stdout);
|
backtrace_print(state, 2, stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ErrorCallback(void* data, const char* msg, int errnum) {
|
static void ErrorCallback(void* data, const char* msg, int errnum) {
|
||||||
auto* ctx = (struct bt_ctx*)data;
|
auto* ctx = (struct bt_ctx*)data;
|
||||||
fprintf(stderr, "ERROR: %s (%d)", msg, errnum);
|
fprintf(stderr, "ERROR: %s (%d)", msg, errnum);
|
||||||
ctx->error = 1;
|
ctx->error = 1;
|
||||||
|
|
||||||
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
||||||
FILE* file = fopen(fileName.c_str(), "w+");
|
FILE* file = fopen(fileName.c_str(), "w+");
|
||||||
if (file != nullptr) {
|
if (file != nullptr) {
|
||||||
fprintf(file, "ERROR: %s (%d)", msg, errnum);
|
fprintf(file, "ERROR: %s (%d)", msg, errnum);
|
||||||
fclose(file);
|
fclose(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "Type.h"
|
#include "Type.h"
|
||||||
|
|
||||||
void GenerateDump() {
|
void GenerateDump() {
|
||||||
std::string cmd = "sudo gcore " + std::to_string(getpid());
|
std::string cmd = "sudo gcore " + std::to_string(getpid());
|
||||||
system(cmd.c_str());
|
int ret = system(cmd.c_str()); // Saving a return just to prevent warning
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatchUnhandled(int sig) {
|
void CatchUnhandled(int sig) {
|
||||||
#ifndef __include_backtrace__
|
#ifndef __include_backtrace__
|
||||||
|
|
||||||
if (Diagnostics::GetProduceMemoryDump()) {
|
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
||||||
GenerateDump();
|
Game::logger->Log("Diagnostics", "Encountered signal %i, creating crash dump %s", sig, fileName.c_str());
|
||||||
}
|
if (Diagnostics::GetProduceMemoryDump()) {
|
||||||
|
GenerateDump();
|
||||||
|
}
|
||||||
|
|
||||||
void* array[10];
|
void* array[10];
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
// get void*'s for all entries on the stack
|
// get void*'s for all entries on the stack
|
||||||
size = backtrace(array, 10);
|
size = backtrace(array, 10);
|
||||||
|
|
||||||
printf("Fatal error %i\nStacktrace:\n", sig);
|
|
||||||
#if defined(__GNUG__) and defined(__dynamic)
|
#if defined(__GNUG__) and defined(__dynamic)
|
||||||
|
|
||||||
// Loop through the returned addresses, and get the symbols to be demangled
|
// Loop through the returned addresses, and get the symbols to be demangled
|
||||||
char** strings = backtrace_symbols(array, size);
|
char** strings = backtrace_symbols(array, size);
|
||||||
|
|
||||||
// Print the stack trace
|
// Print the stack trace
|
||||||
for (size_t i = 0; i < size; i++) {
|
for (size_t i = 0; i < size; i++) {
|
||||||
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]' and extract the function name
|
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]' and extract the function name
|
||||||
std::string functionName = strings[i];
|
std::string functionName = strings[i];
|
||||||
std::string::size_type start = functionName.find('(');
|
std::string::size_type start = functionName.find('(');
|
||||||
std::string::size_type end = functionName.find('+');
|
std::string::size_type end = functionName.find('+');
|
||||||
if (start != std::string::npos && end != std::string::npos) {
|
if (start != std::string::npos && end != std::string::npos) {
|
||||||
std::string demangled = functionName.substr(start + 1, end - start - 1);
|
std::string demangled = functionName.substr(start + 1, end - start - 1);
|
||||||
|
|
||||||
demangled = demangle(functionName.c_str());
|
demangled = demangle(functionName.c_str());
|
||||||
|
|
||||||
if (demangled.empty()) {
|
if (demangled.empty()) {
|
||||||
printf("[%02d] %s\n", i, demangled.c_str());
|
Game::logger->Log("Diagnostics", "[%02zu] %s", i, demangled.c_str());
|
||||||
} else {
|
} else {
|
||||||
printf("[%02d] %s\n", i, functionName.c_str());
|
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf("[%02d] %s\n", i, functionName.c_str());
|
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
backtrace_symbols_fd(array, size, STDOUT_FILENO);
|
backtrace_symbols_fd(array, size, STDOUT_FILENO);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log";
|
FILE* file = fopen(fileName.c_str(), "w+");
|
||||||
FILE* file = fopen(fileName.c_str(), "w+");
|
if (file != NULL) {
|
||||||
if (file != NULL) {
|
// print out all the frames to stderr
|
||||||
// print out all the frames to stderr
|
fprintf(file, "Error: signal %d:\n", sig);
|
||||||
fprintf(file, "Error: signal %d:\n", sig);
|
backtrace_symbols_fd(array, size, fileno(file));
|
||||||
backtrace_symbols_fd(array, size, fileno(file));
|
fclose(file);
|
||||||
fclose(file);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
struct backtrace_state* state = backtrace_create_state(
|
struct backtrace_state* state = backtrace_create_state(
|
||||||
Diagnostics::GetProcessFileName().c_str(),
|
Diagnostics::GetProcessFileName().c_str(),
|
||||||
BACKTRACE_SUPPORTS_THREADS,
|
BACKTRACE_SUPPORTS_THREADS,
|
||||||
ErrorCallback,
|
ErrorCallback,
|
||||||
nullptr);
|
nullptr);
|
||||||
|
|
||||||
struct bt_ctx ctx = {state, 0};
|
struct bt_ctx ctx = { state, 0 };
|
||||||
Bt(state);
|
Bt(state);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CritErrHdlr(int sig_num, siginfo_t* info, void* ucontext) {
|
void CritErrHdlr(int sig_num, siginfo_t* info, void* ucontext) {
|
||||||
CatchUnhandled(sig_num);
|
CatchUnhandled(sig_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnTerminate() {
|
void OnTerminate() {
|
||||||
CatchUnhandled(-1);
|
CatchUnhandled(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MakeBacktrace() {
|
void MakeBacktrace() {
|
||||||
struct sigaction sigact;
|
struct sigaction sigact;
|
||||||
|
|
||||||
sigact.sa_sigaction = CritErrHdlr;
|
sigact.sa_sigaction = CritErrHdlr;
|
||||||
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||||
|
|
||||||
if (sigaction(SIGSEGV, &sigact, (struct sigaction*)nullptr) != 0 ||
|
if (sigaction(SIGSEGV, &sigact, (struct sigaction*)nullptr) != 0 ||
|
||||||
sigaction(SIGFPE, &sigact, (struct sigaction*)nullptr) != 0 ||
|
sigaction(SIGFPE, &sigact, (struct sigaction*)nullptr) != 0 ||
|
||||||
sigaction(SIGABRT, &sigact, (struct sigaction*)nullptr) != 0 ||
|
sigaction(SIGABRT, &sigact, (struct sigaction*)nullptr) != 0 ||
|
||||||
sigaction(SIGILL, &sigact, (struct sigaction*)nullptr) != 0) {
|
sigaction(SIGILL, &sigact, (struct sigaction*)nullptr) != 0) {
|
||||||
fprintf(stderr, "error setting signal handler for %d (%s)\n",
|
fprintf(stderr, "error setting signal handler for %d (%s)\n",
|
||||||
SIGSEGV,
|
SIGSEGV,
|
||||||
strsignal(SIGSEGV));
|
strsignal(SIGSEGV));
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set_terminate(OnTerminate);
|
std::set_terminate(OnTerminate);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Diagnostics::Initialize() {
|
void Diagnostics::Initialize() {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetUnhandledExceptionFilter(unhandled_handler);
|
SetUnhandledExceptionFilter(unhandled_handler);
|
||||||
#elif defined(__linux__) //&& !defined(__clang__)
|
#elif defined(__linux__) //&& !defined(__clang__)
|
||||||
MakeBacktrace();
|
MakeBacktrace();
|
||||||
#else
|
#else
|
||||||
fprintf(stderr, "Diagnostics not supported on this platform.\n");
|
fprintf(stderr, "Diagnostics not supported on this platform.\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,33 +227,33 @@ std::string Diagnostics::m_OutDirectory{};
|
|||||||
bool Diagnostics::m_ProduceMemoryDump{};
|
bool Diagnostics::m_ProduceMemoryDump{};
|
||||||
|
|
||||||
void Diagnostics::SetProcessName(const std::string& name) {
|
void Diagnostics::SetProcessName(const std::string& name) {
|
||||||
m_ProcessName = name;
|
m_ProcessName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Diagnostics::SetProcessFileName(const std::string& name) {
|
void Diagnostics::SetProcessFileName(const std::string& name) {
|
||||||
m_ProcessFileName = name;
|
m_ProcessFileName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Diagnostics::SetOutDirectory(const std::string& path) {
|
void Diagnostics::SetOutDirectory(const std::string& path) {
|
||||||
m_OutDirectory = path;
|
m_OutDirectory = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Diagnostics::SetProduceMemoryDump(bool value) {
|
void Diagnostics::SetProduceMemoryDump(bool value) {
|
||||||
m_ProduceMemoryDump = value;
|
m_ProduceMemoryDump = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Diagnostics::GetProcessName() {
|
const std::string& Diagnostics::GetProcessName() {
|
||||||
return m_ProcessName;
|
return m_ProcessName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Diagnostics::GetProcessFileName() {
|
const std::string& Diagnostics::GetProcessFileName() {
|
||||||
return m_ProcessFileName;
|
return m_ProcessFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Diagnostics::GetOutDirectory() {
|
const std::string& Diagnostics::GetOutDirectory() {
|
||||||
return m_OutDirectory;
|
return m_OutDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Diagnostics::GetProduceMemoryDump() {
|
bool Diagnostics::GetProduceMemoryDump() {
|
||||||
return m_ProduceMemoryDump;
|
return m_ProduceMemoryDump;
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,27 @@
|
|||||||
class Diagnostics
|
class Diagnostics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
|
|
||||||
static void SetProcessName(const std::string& name);
|
static void SetProcessName(const std::string& name);
|
||||||
|
|
||||||
static void SetProcessFileName(const std::string& name);
|
static void SetProcessFileName(const std::string& name);
|
||||||
|
|
||||||
static void SetOutDirectory(const std::string& path);
|
static void SetOutDirectory(const std::string& path);
|
||||||
|
|
||||||
static void SetProduceMemoryDump(bool value);
|
static void SetProduceMemoryDump(bool value);
|
||||||
|
|
||||||
static const std::string& GetProcessName();
|
static const std::string& GetProcessName();
|
||||||
|
|
||||||
static const std::string& GetProcessFileName();
|
static const std::string& GetProcessFileName();
|
||||||
|
|
||||||
static const std::string& GetOutDirectory();
|
static const std::string& GetOutDirectory();
|
||||||
|
|
||||||
static bool GetProduceMemoryDump();
|
static bool GetProduceMemoryDump();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::string m_ProcessName;
|
static std::string m_ProcessName;
|
||||||
static std::string m_ProcessFileName;
|
static std::string m_ProcessFileName;
|
||||||
static std::string m_OutDirectory;
|
static std::string m_OutDirectory;
|
||||||
static bool m_ProduceMemoryDump;
|
static bool m_ProduceMemoryDump;
|
||||||
};
|
};
|
||||||
|
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 dServer;
|
||||||
class dLogger;
|
class dLogger;
|
||||||
class InstanceManager;
|
class InstanceManager;
|
||||||
class dpWorld;
|
|
||||||
class dChatFilter;
|
class dChatFilter;
|
||||||
class dConfig;
|
class dConfig;
|
||||||
class dLocale;
|
|
||||||
class RakPeerInterface;
|
class RakPeerInterface;
|
||||||
|
class AssetManager;
|
||||||
struct SystemAddress;
|
struct SystemAddress;
|
||||||
|
|
||||||
namespace Game {
|
namespace Game {
|
||||||
extern dLogger* logger;
|
extern dLogger* logger;
|
||||||
extern dServer* server;
|
extern dServer* server;
|
||||||
extern InstanceManager* im;
|
extern InstanceManager* im;
|
||||||
extern dpWorld* physicsWorld;
|
|
||||||
extern dChatFilter* chatFilter;
|
extern dChatFilter* chatFilter;
|
||||||
extern dConfig* config;
|
extern dConfig* config;
|
||||||
extern dLocale* locale;
|
|
||||||
extern std::mt19937 randomEngine;
|
extern std::mt19937 randomEngine;
|
||||||
extern RakPeerInterface* chatServer;
|
extern RakPeerInterface* chatServer;
|
||||||
|
extern AssetManager* assetManager;
|
||||||
extern SystemAddress chatSysAddr;
|
extern SystemAddress chatSysAddr;
|
||||||
|
extern bool shouldShutdown;
|
||||||
}
|
}
|
@ -4,168 +4,271 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline size_t MinSize(size_t size, const std::basic_string<T>& string) {
|
inline size_t MinSize(size_t size, const std::basic_string_view<T>& string) {
|
||||||
if (size == size_t(-1) || size > string.size()) {
|
if (size == size_t(-1) || size > string.size()) {
|
||||||
return string.size();
|
return string.size();
|
||||||
} else {
|
} else {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsLeadSurrogate(char16_t c) {
|
inline bool IsLeadSurrogate(char16_t c) {
|
||||||
return (0xD800 <= c) && (c <= 0xDBFF);
|
return (0xD800 <= c) && (c <= 0xDBFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsTrailSurrogate(char16_t c) {
|
inline bool IsTrailSurrogate(char16_t c) {
|
||||||
return (0xDC00 <= c) && (c <= 0xDFFF);
|
return (0xDC00 <= c) && (c <= 0xDFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
||||||
if (cp <= 0x007F) {
|
if (cp <= 0x007F) {
|
||||||
ret.push_back(cp);
|
ret.push_back(static_cast<uint8_t>(cp));
|
||||||
} else if (cp <= 0x07FF) {
|
} else if (cp <= 0x07FF) {
|
||||||
ret.push_back(0xC0 | (cp >> 6));
|
ret.push_back(0xC0 | (cp >> 6));
|
||||||
ret.push_back(0x80 | (cp & 0x3F));
|
ret.push_back(0x80 | (cp & 0x3F));
|
||||||
} else if (cp <= 0xFFFF) {
|
} else if (cp <= 0xFFFF) {
|
||||||
ret.push_back(0xE0 | (cp >> 12));
|
ret.push_back(0xE0 | (cp >> 12));
|
||||||
ret.push_back(0x80 | ((cp >> 6) & 0x3F));
|
ret.push_back(0x80 | ((cp >> 6) & 0x3F));
|
||||||
ret.push_back(0x80 | (cp & 0x3F));
|
ret.push_back(0x80 | (cp & 0x3F));
|
||||||
} else if (cp <= 0x10FFFF) {
|
} else if (cp <= 0x10FFFF) {
|
||||||
ret.push_back(0xF0 | (cp >> 18));
|
ret.push_back(0xF0 | (cp >> 18));
|
||||||
ret.push_back(0x80 | ((cp >> 12) & 0x3F));
|
ret.push_back(0x80 | ((cp >> 12) & 0x3F));
|
||||||
ret.push_back(0x80 | ((cp >> 6) & 0x3F));
|
ret.push_back(0x80 | ((cp >> 6) & 0x3F));
|
||||||
ret.push_back(0x80 | (cp & 0x3F));
|
ret.push_back(0x80 | (cp & 0x3F));
|
||||||
} else {
|
} else {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
||||||
|
|
||||||
|
bool _IsSuffixChar(uint8_t c) {
|
||||||
|
return (c & 0xC0) == 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
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];
|
||||||
|
if (first < 0x80) { // 1 byte character
|
||||||
|
out = static_cast<uint32_t>(first & 0x7F);
|
||||||
|
slice.remove_prefix(1);
|
||||||
|
return true;
|
||||||
|
} else if (first < 0xC0) {
|
||||||
|
// middle byte, not valid at start, fall through
|
||||||
|
} else if (first < 0xE0) { // two byte character
|
||||||
|
if (rem > 1) {
|
||||||
|
uint8_t second = bytes[1];
|
||||||
|
if (_IsSuffixChar(second)) {
|
||||||
|
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
||||||
|
+ static_cast<uint32_t>(second & 0x3F);
|
||||||
|
slice.remove_prefix(2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (first < 0xF0) { // three byte character
|
||||||
|
if (rem > 2) {
|
||||||
|
uint8_t second = bytes[1];
|
||||||
|
uint8_t third = bytes[2];
|
||||||
|
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
||||||
|
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
||||||
|
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
||||||
|
+ static_cast<uint32_t>(third & 0x3F);
|
||||||
|
slice.remove_prefix(3);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (first < 0xF8) { // four byte character
|
||||||
|
if (rem > 3) {
|
||||||
|
uint8_t second = bytes[1];
|
||||||
|
uint8_t third = bytes[2];
|
||||||
|
uint8_t fourth = bytes[3];
|
||||||
|
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
||||||
|
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
||||||
|
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
||||||
|
+ (static_cast<uint32_t>(third & 0x3F) << 6)
|
||||||
|
+ static_cast<uint32_t>(fourth & 0x3F);
|
||||||
|
slice.remove_prefix(4);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out = static_cast<uint32_t>(REPLACEMENT_CHARACTER);
|
||||||
|
slice.remove_prefix(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See <https://www.ietf.org/rfc/rfc2781.html#section-2.1>
|
||||||
|
bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
||||||
|
if (output.length() >= size) return false;
|
||||||
|
if (U < 0x10000) {
|
||||||
|
// If U < 0x10000, encode U as a 16-bit unsigned integer and terminate.
|
||||||
|
output.push_back(static_cast<uint16_t>(U));
|
||||||
|
return true;
|
||||||
|
} else if (U > 0x10FFFF) {
|
||||||
|
output.push_back(REPLACEMENT_CHARACTER);
|
||||||
|
return true;
|
||||||
|
} else if (output.length() + 1 < size) {
|
||||||
|
// Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
|
||||||
|
// U' must be less than or equal to 0xFFFFF. That is, U' can be
|
||||||
|
// represented in 20 bits.
|
||||||
|
uint32_t Ut = U - 0x10000;
|
||||||
|
|
||||||
|
// Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
|
||||||
|
// 0xDC00, respectively. These integers each have 10 bits free to
|
||||||
|
// encode the character value, for a total of 20 bits.
|
||||||
|
uint16_t W1 = 0xD800;
|
||||||
|
uint16_t W2 = 0xDC00;
|
||||||
|
|
||||||
|
// Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
|
||||||
|
// bits of W1 and the 10 low-order bits of U' to the 10 low-order
|
||||||
|
// bits of W2.
|
||||||
|
W1 += static_cast<uint16_t>((Ut & 0x3FC00) >> 10);
|
||||||
|
W2 += static_cast<uint16_t>((Ut & 0x3FF) >> 0);
|
||||||
|
|
||||||
|
// Terminate.
|
||||||
|
output.push_back(W1); // high surrogate
|
||||||
|
output.push_back(W2); // low surrogate
|
||||||
|
return true;
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) {
|
||||||
|
size_t newSize = MinSize(size, string);
|
||||||
|
std::u16string output;
|
||||||
|
output.reserve(newSize);
|
||||||
|
std::string_view iterator = string;
|
||||||
|
|
||||||
|
uint32_t c;
|
||||||
|
while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
||||||
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
||||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string& string, size_t size) {
|
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) {
|
||||||
size_t newSize = MinSize(size, string);
|
size_t newSize = MinSize(size, string);
|
||||||
std::u16string ret;
|
std::u16string ret;
|
||||||
ret.reserve(newSize);
|
ret.reserve(newSize);
|
||||||
|
|
||||||
for (size_t i = 0; i < newSize; i++) {
|
for (size_t i = 0; i < newSize; i++) {
|
||||||
char c = string[i];
|
char c = string[i];
|
||||||
assert(c > 0 && c <= 127);
|
// Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t
|
||||||
ret.push_back(static_cast<char16_t>(c));
|
ret.push_back((c > 0 && c <= 127) ? static_cast<char16_t>(c) : REPLACEMENT_CHARACTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
|
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
|
||||||
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
||||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string& string, size_t size) {
|
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) {
|
||||||
size_t newSize = MinSize(size, string);
|
size_t newSize = MinSize(size, string);
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret.reserve(newSize);
|
ret.reserve(newSize);
|
||||||
|
|
||||||
for (size_t i = 0; i < newSize; i++) {
|
for (size_t i = 0; i < newSize; i++) {
|
||||||
char16_t u = string[i];
|
char16_t u = string[i];
|
||||||
if (IsLeadSurrogate(u) && (i + 1) < newSize) {
|
if (IsLeadSurrogate(u) && (i + 1) < newSize) {
|
||||||
char16_t next = string[i + 1];
|
char16_t next = string[i + 1];
|
||||||
if (IsTrailSurrogate(next)) {
|
if (IsTrailSurrogate(next)) {
|
||||||
i += 1;
|
i += 1;
|
||||||
char32_t cp = 0x10000
|
char32_t cp = 0x10000
|
||||||
+ ((static_cast<char32_t>(u) - 0xD800) << 10)
|
+ ((static_cast<char32_t>(u) - 0xD800) << 10)
|
||||||
+ (static_cast<char32_t>(next) - 0xDC00);
|
+ (static_cast<char32_t>(next) - 0xDC00);
|
||||||
PushUTF8CodePoint(ret, cp);
|
PushUTF8CodePoint(ret, cp);
|
||||||
} else {
|
} else {
|
||||||
PushUTF8CodePoint(ret, u);
|
PushUTF8CodePoint(ret, u);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PushUTF8CodePoint(ret, u);
|
PushUTF8CodePoint(ret, u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) {
|
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) {
|
||||||
return std::equal(a.begin(), a.end (), b.begin(), b.end(),[](char a, char b) { return tolower(a) == tolower(b); });
|
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Bits
|
// MARK: Bits
|
||||||
|
|
||||||
//! Sets a specific bit in a signed 64-bit integer
|
//! Sets a specific bit in a signed 64-bit integer
|
||||||
int64_t GeneralUtils::SetBit(int64_t value, uint32_t index) {
|
int64_t GeneralUtils::SetBit(int64_t value, uint32_t index) {
|
||||||
return value |= 1ULL << index;
|
return value |= 1ULL << index;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Clears a specific bit in a signed 64-bit integer
|
//! Clears a specific bit in a signed 64-bit integer
|
||||||
int64_t GeneralUtils::ClearBit(int64_t value, uint32_t index) {
|
int64_t GeneralUtils::ClearBit(int64_t value, uint32_t index) {
|
||||||
return value &= ~(1ULL << index);
|
return value &= ~(1ULL << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Checks a specific bit in a signed 64-bit integer
|
//! Checks a specific bit in a signed 64-bit integer
|
||||||
bool GeneralUtils::CheckBit(int64_t value, uint32_t index) {
|
bool GeneralUtils::CheckBit(int64_t value, uint32_t index) {
|
||||||
return value & (1ULL << index);
|
return value & (1ULL << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) {
|
bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) {
|
||||||
size_t start_pos = str.find(from);
|
size_t start_pos = str.find(from);
|
||||||
if(start_pos == std::string::npos)
|
if (start_pos == std::string::npos)
|
||||||
return false;
|
return false;
|
||||||
str.replace(start_pos, from.length(), to);
|
str.replace(start_pos, from.length(), to);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter)
|
std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) {
|
||||||
{
|
std::vector<std::wstring> vector = std::vector<std::wstring>();
|
||||||
std::vector<std::wstring> vector = std::vector<std::wstring>();
|
std::wstring current;
|
||||||
std::wstring current;
|
|
||||||
|
|
||||||
for (const auto& c : str) {
|
for (const auto& c : str) {
|
||||||
if (c == delimiter) {
|
if (c == delimiter) {
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = L"";
|
current = L"";
|
||||||
} else {
|
} else {
|
||||||
current += c;
|
current += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::u16string> GeneralUtils::SplitString(std::u16string& str, char16_t delimiter)
|
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) {
|
||||||
{
|
std::vector<std::u16string> vector = std::vector<std::u16string>();
|
||||||
std::vector<std::u16string> vector = std::vector<std::u16string>();
|
std::u16string current;
|
||||||
std::u16string current;
|
|
||||||
|
|
||||||
for (const auto& c : str) {
|
for (const auto& c : str) {
|
||||||
if (c == delimiter) {
|
if (c == delimiter) {
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = u"";
|
current = u"";
|
||||||
} else {
|
} else {
|
||||||
current += c;
|
current += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char delimiter)
|
std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char delimiter) {
|
||||||
{
|
|
||||||
std::vector<std::string> vector = std::vector<std::string>();
|
std::vector<std::string> vector = std::vector<std::string>();
|
||||||
std::string current = "";
|
std::string current = "";
|
||||||
|
|
||||||
for (size_t i = 0; i < str.length(); i++)
|
for (size_t i = 0; i < str.length(); i++) {
|
||||||
{
|
|
||||||
char c = str[i];
|
char c = str[i];
|
||||||
|
|
||||||
if (c == delimiter)
|
if (c == delimiter) {
|
||||||
{
|
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = "";
|
current = "";
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
current += c;
|
current += c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,16 +278,48 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
|
|||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u16string GeneralUtils::ReadWString(RakNet::BitStream *inStream) {
|
std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) {
|
||||||
uint32_t length;
|
uint32_t length;
|
||||||
inStream->Read<uint32_t>(length);
|
inStream->Read<uint32_t>(length);
|
||||||
|
|
||||||
std::u16string string;
|
std::u16string string;
|
||||||
for (auto i = 0; i < length; i++) {
|
for (auto i = 0; i < length; i++) {
|
||||||
uint16_t c;
|
uint16_t c;
|
||||||
inStream->Read(c);
|
inStream->Read(c);
|
||||||
string.push_back(c);
|
string.push_back(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
return string;
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
||||||
|
fileIterator++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) {
|
||||||
|
return TryParse<float>(x.c_str(), dst.x) && TryParse<float>(y.c_str(), dst.y) && TryParse<float>(z.c_str(), dst.z);
|
||||||
}
|
}
|
||||||
|
@ -10,201 +10,217 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <BitStream.h>
|
#include <BitStream.h>
|
||||||
|
#include "NiPoint3.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
#include "dLogger.h"
|
||||||
|
|
||||||
|
enum eInventoryType : uint32_t;
|
||||||
|
enum class eObjectBits : size_t;
|
||||||
|
enum class eReplicaComponentType : uint32_t;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\file GeneralUtils.hpp
|
\file GeneralUtils.hpp
|
||||||
\brief A namespace containing general utility functions
|
\brief A namespace containing general utility functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//! The general utils namespace
|
//! The general utils namespace
|
||||||
namespace GeneralUtils {
|
namespace GeneralUtils {
|
||||||
//! Converts a plain ASCII string to a UTF-16 string
|
//! Converts a plain ASCII string to a UTF-16 string
|
||||||
/*!
|
/*!
|
||||||
\param string The string to convert
|
\param string The string to convert
|
||||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||||
\return An UTF-16 representation of the string
|
\return An UTF-16 representation of the string
|
||||||
*/
|
*/
|
||||||
std::u16string ASCIIToUTF16(const std::string& string, size_t size = -1);
|
std::u16string ASCIIToUTF16(const std::string_view& string, size_t size = -1);
|
||||||
|
|
||||||
//! Converts a UTF-16 string to a UTF-8 string
|
//! Converts a UTF-8 String to a UTF-16 string
|
||||||
/*!
|
/*!
|
||||||
\param string The string to convert
|
\param string The string to convert
|
||||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||||
\return An UTF-8 representation of the string
|
\return An UTF-16 representation of the string
|
||||||
*/
|
*/
|
||||||
std::string UTF16ToWTF8(const std::u16string& string, size_t size = -1);
|
std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1);
|
||||||
|
|
||||||
/**
|
//! Internal, do not use
|
||||||
* Compares two basic strings but does so ignoring case sensitivity
|
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
||||||
* \param a the first string to compare against the second string
|
|
||||||
* \param b the second string to compare against the first string
|
|
||||||
* @return if the two strings are equal
|
|
||||||
*/
|
|
||||||
bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b);
|
|
||||||
|
|
||||||
// MARK: Bits
|
//! Converts a UTF-16 string to a UTF-8 string
|
||||||
|
/*!
|
||||||
|
\param string The string to convert
|
||||||
|
\param size A size to trim the string to. Default is -1 (No trimming)
|
||||||
|
\return An UTF-8 representation of the string
|
||||||
|
*/
|
||||||
|
std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1);
|
||||||
|
|
||||||
// MARK: Bits
|
/**
|
||||||
|
* Compares two basic strings but does so ignoring case sensitivity
|
||||||
|
* \param a the first string to compare against the second string
|
||||||
|
* \param b the second string to compare against the first string
|
||||||
|
* @return if the two strings are equal
|
||||||
|
*/
|
||||||
|
bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b);
|
||||||
|
|
||||||
//! Sets a bit on a numerical value
|
// MARK: Bits
|
||||||
template <typename T>
|
|
||||||
void SetBit(T& value, size_t index) {
|
|
||||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
|
||||||
|
|
||||||
if (index > (sizeof(T) * 8) - 1) {
|
// MARK: Bits
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
value |= static_cast<T>(1) << index;
|
//! Sets a bit on a numerical value
|
||||||
}
|
template <typename T>
|
||||||
|
inline void SetBit(T& value, eObjectBits bits) {
|
||||||
|
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||||
|
auto index = static_cast<size_t>(bits);
|
||||||
|
if (index > (sizeof(T) * 8) - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//! Clears a bit on a numerical value
|
value |= static_cast<T>(1) << index;
|
||||||
template <typename T>
|
}
|
||||||
void ClearBit(T& value, size_t index) {
|
|
||||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
|
||||||
|
|
||||||
if (index > (sizeof(T) * 8 - 1)) {
|
//! Clears a bit on a numerical value
|
||||||
return;
|
template <typename T>
|
||||||
}
|
inline void ClearBit(T& value, eObjectBits bits) {
|
||||||
|
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||||
|
auto index = static_cast<size_t>(bits);
|
||||||
|
if (index > (sizeof(T) * 8 - 1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
value &= ~(static_cast<T>(1) << index);
|
value &= ~(static_cast<T>(1) << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets a specific bit in a signed 64-bit integer
|
//! Sets a specific bit in a signed 64-bit integer
|
||||||
/*!
|
/*!
|
||||||
\param value The value to set the bit for
|
\param value The value to set the bit for
|
||||||
\param index The index of the bit
|
\param index The index of the bit
|
||||||
*/
|
*/
|
||||||
int64_t SetBit(int64_t value, uint32_t index);
|
int64_t SetBit(int64_t value, uint32_t index);
|
||||||
|
|
||||||
//! Clears a specific bit in a signed 64-bit integer
|
//! Clears a specific bit in a signed 64-bit integer
|
||||||
/*!
|
/*!
|
||||||
\param value The value to clear the bit from
|
\param value The value to clear the bit from
|
||||||
\param index The index of the bit
|
\param index The index of the bit
|
||||||
*/
|
*/
|
||||||
int64_t ClearBit(int64_t value, uint32_t index);
|
int64_t ClearBit(int64_t value, uint32_t index);
|
||||||
|
|
||||||
//! Checks a specific bit in a signed 64-bit integer
|
//! Checks a specific bit in a signed 64-bit integer
|
||||||
/*!
|
/*!
|
||||||
\parma value The value to check the bit in
|
\parma value The value to check the bit in
|
||||||
\param index The index of the bit
|
\param index The index of the bit
|
||||||
\return Whether or not the bit is set
|
\return Whether or not the bit is set
|
||||||
*/
|
*/
|
||||||
bool CheckBit(int64_t value, uint32_t index);
|
bool CheckBit(int64_t value, uint32_t index);
|
||||||
|
|
||||||
// MARK: Random Number Generation
|
// MARK: Random Number Generation
|
||||||
|
|
||||||
//! Generates a random number
|
//! Generates a random number
|
||||||
/*!
|
/*!
|
||||||
\param min The minimum the generate from
|
\param min The minimum the generate from
|
||||||
\param max The maximum to generate to
|
\param max The maximum to generate to
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
|
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
|
||||||
// Make sure it is a numeric type
|
// Make sure it is a numeric type
|
||||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||||
|
|
||||||
if constexpr (std::is_integral_v<T>) { // constexpr only necessary on first statement
|
if constexpr (std::is_integral_v<T>) { // constexpr only necessary on first statement
|
||||||
std::uniform_int_distribution<T> distribution(min, max);
|
std::uniform_int_distribution<T> distribution(min, max);
|
||||||
return distribution(Game::randomEngine);
|
return distribution(Game::randomEngine);
|
||||||
}
|
} else if (std::is_floating_point_v<T>) {
|
||||||
else if (std::is_floating_point_v<T>) {
|
std::uniform_real_distribution<T> distribution(min, max);
|
||||||
std::uniform_real_distribution<T> distribution(min, max);
|
return distribution(Game::randomEngine);
|
||||||
return distribution(Game::randomEngine);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return T();
|
return T();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
|
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
|
||||||
|
|
||||||
std::u16string ReadWString(RakNet::BitStream *inStream);
|
std::u16string ReadWString(RakNet::BitStream* inStream);
|
||||||
|
|
||||||
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
|
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
|
||||||
|
|
||||||
std::vector<std::u16string> SplitString(std::u16string& str, char16_t delimiter);
|
std::vector<std::u16string> SplitString(const std::u16string& str, char16_t delimiter);
|
||||||
|
|
||||||
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
||||||
|
|
||||||
template <typename T>
|
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
|
||||||
T Parse(const char* value);
|
|
||||||
|
template <typename T>
|
||||||
|
T Parse(const char* value);
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline int32_t Parse(const char* value)
|
inline int32_t Parse(const char* value) {
|
||||||
{
|
return std::stoi(value);
|
||||||
return std::stoi(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline int64_t Parse(const char* value)
|
inline int64_t Parse(const char* value) {
|
||||||
{
|
return std::stoll(value);
|
||||||
return std::stoll(value);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline float Parse(const char* value)
|
inline float Parse(const char* value) {
|
||||||
{
|
return std::stof(value);
|
||||||
return std::stof(value);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline double Parse(const char* value)
|
inline double Parse(const char* value) {
|
||||||
{
|
return std::stod(value);
|
||||||
return std::stod(value);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline uint32_t Parse(const char* value)
|
inline uint32_t Parse(const char* value) {
|
||||||
{
|
return std::stoul(value);
|
||||||
return std::stoul(value);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline uint64_t Parse(const char* value)
|
inline uint64_t Parse(const char* value) {
|
||||||
{
|
return std::stoull(value);
|
||||||
return std::stoull(value);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <>
|
||||||
bool TryParse(const char* value, T& dst)
|
inline eInventoryType Parse(const char* value) {
|
||||||
{
|
return static_cast<eInventoryType>(std::stoul(value));
|
||||||
try
|
}
|
||||||
{
|
|
||||||
dst = Parse<T>(value);
|
|
||||||
|
|
||||||
return true;
|
template <>
|
||||||
}
|
inline eReplicaComponentType Parse(const char* value) {
|
||||||
catch (...)
|
return static_cast<eReplicaComponentType>(std::stoul(value));
|
||||||
{
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Parse(const std::string& value)
|
bool TryParse(const char* value, T& dst) {
|
||||||
{
|
try {
|
||||||
return Parse<T>(value.c_str());
|
dst = Parse<T>(value);
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
return true;
|
||||||
bool TryParse(const std::string& value, T& dst)
|
} catch (...) {
|
||||||
{
|
return false;
|
||||||
return TryParse<T>(value.c_str(), dst);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
std::u16string to_u16string(T value)
|
T Parse(const std::string& value) {
|
||||||
{
|
return Parse<T>(value.c_str());
|
||||||
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// From boost::hash_combine
|
template <typename T>
|
||||||
template <class T>
|
bool TryParse(const std::string& value, T& dst) {
|
||||||
void hash_combine(std::size_t& s, const T& v)
|
return TryParse<T>(value.c_str(), dst);
|
||||||
{
|
}
|
||||||
std::hash<T> h;
|
|
||||||
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
|
bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst);
|
||||||
}
|
|
||||||
|
template<typename T>
|
||||||
|
std::u16string to_u16string(T value) {
|
||||||
|
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// From boost::hash_combine
|
||||||
|
template <class T>
|
||||||
|
void hash_combine(std::size_t& s, const T& v) {
|
||||||
|
std::hash<T> h;
|
||||||
|
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,132 +3,174 @@
|
|||||||
// Custom Classes
|
// Custom Classes
|
||||||
#include "GeneralUtils.h"
|
#include "GeneralUtils.h"
|
||||||
|
|
||||||
|
#include "Game.h"
|
||||||
|
#include "dLogger.h"
|
||||||
|
|
||||||
// C++
|
// C++
|
||||||
#include <sstream>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
using LDFKey = std::string_view;
|
||||||
|
using LDFTypeAndValue = std::string_view;
|
||||||
|
|
||||||
|
using LDFType = std::string_view;
|
||||||
|
using LDFValue = std::string_view;
|
||||||
|
|
||||||
//! Returns a pointer to a LDFData value based on string format
|
//! Returns a pointer to a LDFData value based on string format
|
||||||
LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
|
LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||||
|
// A valid LDF must be at least 3 characters long (=0:) is the shortest valid LDF (empty UTF-16 key with no initial value)
|
||||||
|
if (format.empty() || format.length() <= 2) return nullptr;
|
||||||
|
auto equalsPosition = format.find('=');
|
||||||
|
// You can have an empty key, just make sure the type and value might exist
|
||||||
|
if (equalsPosition == std::string::npos || equalsPosition == (format.size() - 1)) return nullptr;
|
||||||
|
|
||||||
// First, check the format
|
std::pair<LDFKey, LDFTypeAndValue> keyValue;
|
||||||
std::istringstream ssFormat(format);
|
keyValue.first = format.substr(0, equalsPosition);
|
||||||
std::string token;
|
keyValue.second = format.substr(equalsPosition + 1, format.size());
|
||||||
|
|
||||||
std::vector<std::string> keyValueArray;
|
std::u16string key = GeneralUtils::ASCIIToUTF16(keyValue.first);
|
||||||
while (std::getline(ssFormat, token, '=')) {
|
|
||||||
keyValueArray.push_back(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyValueArray.size() == 2) {
|
auto colonPosition = keyValue.second.find(':');
|
||||||
std::u16string key = GeneralUtils::ASCIIToUTF16(keyValueArray[0]);
|
|
||||||
|
|
||||||
std::vector<std::string> dataArray;
|
// If : is the first thing after an =, then this is an invalid LDF since
|
||||||
std::istringstream ssData(keyValueArray[1]);
|
// we dont have a type to use.
|
||||||
while (std::getline(ssData, token, ':')) {
|
if (colonPosition == std::string::npos || colonPosition == 0) return nullptr;
|
||||||
dataArray.push_back(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dataArray.size() > 2) { // hacky fix for strings with colons in them
|
std::pair<LDFType, LDFValue> ldfTypeAndValue;
|
||||||
std::vector<std::string> newDataArray;
|
ldfTypeAndValue.first = keyValue.second.substr(0, colonPosition);
|
||||||
newDataArray.push_back(dataArray[0]);
|
ldfTypeAndValue.second = keyValue.second.substr(colonPosition + 1, keyValue.second.size());
|
||||||
std::string value = "";
|
|
||||||
for (size_t i = 1; i < dataArray.size(); ++i) {
|
// Only allow empty values for string values.
|
||||||
value += dataArray[i] + ':';
|
if (ldfTypeAndValue.second.size() == 0 && !(ldfTypeAndValue.first == "0" || ldfTypeAndValue.first == "13")) return nullptr;
|
||||||
|
|
||||||
|
eLDFType type;
|
||||||
|
char* storage;
|
||||||
|
try {
|
||||||
|
type = static_cast<eLDFType>(strtol(ldfTypeAndValue.first.data(), &storage, 10));
|
||||||
|
} catch (std::exception) {
|
||||||
|
Game::logger->Log("LDFFormat", "Attempted to process invalid ldf type (%s) from string (%s)", ldfTypeAndValue.first.data(), format.data());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LDFBaseData* returnValue = nullptr;
|
||||||
|
switch (type) {
|
||||||
|
case LDF_TYPE_UTF_16: {
|
||||||
|
std::u16string data = GeneralUtils::UTF8ToUTF16(ldfTypeAndValue.second);
|
||||||
|
returnValue = new LDFData<std::u16string>(key, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LDF_TYPE_S32: {
|
||||||
|
try {
|
||||||
|
int32_t data = static_cast<int32_t>(strtoul(ldfTypeAndValue.second.data(), &storage, 10));
|
||||||
|
returnValue = new LDFData<int32_t>(key, data);
|
||||||
|
} catch (std::exception) {
|
||||||
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LDF_TYPE_FLOAT: {
|
||||||
|
try {
|
||||||
|
float data = strtof(ldfTypeAndValue.second.data(), &storage);
|
||||||
|
returnValue = new LDFData<float>(key, data);
|
||||||
|
} catch (std::exception) {
|
||||||
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LDF_TYPE_DOUBLE: {
|
||||||
|
try {
|
||||||
|
double data = strtod(ldfTypeAndValue.second.data(), &storage);
|
||||||
|
returnValue = new LDFData<double>(key, data);
|
||||||
|
} catch (std::exception) {
|
||||||
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LDF_TYPE_U32:
|
||||||
|
{
|
||||||
|
uint32_t data;
|
||||||
|
|
||||||
|
if (ldfTypeAndValue.second == "true") {
|
||||||
|
data = 1;
|
||||||
|
} else if (ldfTypeAndValue.second == "false") {
|
||||||
|
data = 0;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
data = static_cast<uint32_t>(strtoul(ldfTypeAndValue.second.data(), &storage, 10));
|
||||||
|
} catch (std::exception) {
|
||||||
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
value.pop_back(); // remove last colon
|
|
||||||
newDataArray.push_back(value);
|
|
||||||
dataArray = newDataArray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dataArray[0] == "0" || dataArray[0] == "13") && dataArray.size() == 1) {
|
returnValue = new LDFData<uint32_t>(key, data);
|
||||||
dataArray.push_back("");
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataArray.size() == 2) {
|
case LDF_TYPE_BOOLEAN: {
|
||||||
eLDFType type = static_cast<eLDFType>(stoi(dataArray[0]));
|
bool data;
|
||||||
|
|
||||||
switch (type) {
|
if (ldfTypeAndValue.second == "true") {
|
||||||
case LDF_TYPE_UTF_16: {
|
data = true;
|
||||||
std::u16string data = GeneralUtils::ASCIIToUTF16(dataArray[1]);
|
} else if (ldfTypeAndValue.second == "false") {
|
||||||
return new LDFData<std::u16string>(key, data);
|
data = false;
|
||||||
}
|
} else {
|
||||||
|
try {
|
||||||
|
data = static_cast<bool>(strtol(ldfTypeAndValue.second.data(), &storage, 10));
|
||||||
|
} catch (std::exception) {
|
||||||
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case LDF_TYPE_S32: {
|
returnValue = new LDFData<bool>(key, data);
|
||||||
int32_t data = static_cast<int32_t>(stoull(dataArray[1]));
|
break;
|
||||||
return new LDFData<int32_t>(key, data);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
case LDF_TYPE_FLOAT: {
|
case LDF_TYPE_U64: {
|
||||||
float data = static_cast<float>(stof(dataArray[1]));
|
try {
|
||||||
return new LDFData<float>(key, data);
|
uint64_t data = static_cast<uint64_t>(strtoull(ldfTypeAndValue.second.data(), &storage, 10));
|
||||||
}
|
returnValue = new LDFData<uint64_t>(key, data);
|
||||||
|
} catch (std::exception) {
|
||||||
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case LDF_TYPE_DOUBLE: {
|
case LDF_TYPE_OBJID: {
|
||||||
double data = static_cast<float>(stod(dataArray[1]));
|
try {
|
||||||
return new LDFData<double>(key, data);
|
LWOOBJID data = static_cast<LWOOBJID>(strtoll(ldfTypeAndValue.second.data(), &storage, 10));
|
||||||
}
|
returnValue = new LDFData<LWOOBJID>(key, data);
|
||||||
|
} catch (std::exception) {
|
||||||
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case LDF_TYPE_U32:
|
case LDF_TYPE_UTF_8: {
|
||||||
{
|
std::string data = ldfTypeAndValue.second.data();
|
||||||
uint32_t data;
|
returnValue = new LDFData<std::string>(key, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (dataArray[1] == "true")
|
case LDF_TYPE_UNKNOWN: {
|
||||||
{
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid unknown value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||||
data = 1;
|
break;
|
||||||
}
|
}
|
||||||
else if (dataArray[1] == "false")
|
|
||||||
{
|
|
||||||
data = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
data = static_cast<uint32_t>(stoul(dataArray[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LDFData<uint32_t>(key, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
case LDF_TYPE_BOOLEAN: {
|
|
||||||
bool data;
|
|
||||||
|
|
||||||
if (dataArray[1] == "true")
|
|
||||||
{
|
|
||||||
data = true;
|
|
||||||
}
|
|
||||||
else if (dataArray[1] == "false")
|
|
||||||
{
|
|
||||||
data = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
data = static_cast<bool>(stoi(dataArray[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new LDFData<bool>(key, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
case LDF_TYPE_U64: {
|
|
||||||
uint64_t data = static_cast<uint64_t>(stoull(dataArray[1]));
|
|
||||||
return new LDFData<uint64_t>(key, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
case LDF_TYPE_OBJID: {
|
|
||||||
LWOOBJID data = static_cast<LWOOBJID>(stoll(dataArray[1]));
|
|
||||||
return new LDFData<LWOOBJID>(key, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
case LDF_TYPE_UTF_8: {
|
|
||||||
std::string data = dataArray[1];
|
|
||||||
return new LDFData<std::string>(key, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
case LDF_TYPE_UNKNOWN: {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
|
default: {
|
||||||
|
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LDF type (%d) from string (%s)", type, format.data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef __LDFFORMAT__H__
|
||||||
|
#define __LDFFORMAT__H__
|
||||||
|
|
||||||
// Custom Classes
|
// Custom Classes
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
@ -6,191 +7,162 @@
|
|||||||
|
|
||||||
// C++
|
// C++
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
// RakNet
|
// RakNet
|
||||||
|
#include "BitStream.h"
|
||||||
|
|
||||||
#include "../thirdparty/raknet/Source/BitStream.h"
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\file LDFFormat.hpp
|
|
||||||
\brief A collection of LDF format classes
|
|
||||||
*/
|
|
||||||
|
|
||||||
//! An enum for LDF Data Types
|
|
||||||
enum eLDFType {
|
enum eLDFType {
|
||||||
LDF_TYPE_UNKNOWN = -1, //!< Unknown data type
|
LDF_TYPE_UNKNOWN = -1, //!< Unknown data type
|
||||||
LDF_TYPE_UTF_16 = 0, //!< UTF-16 wstring data type
|
LDF_TYPE_UTF_16 = 0, //!< UTF-16 wstring data type
|
||||||
LDF_TYPE_S32 = 1, //!< Signed 32-bit data type
|
LDF_TYPE_S32 = 1, //!< Signed 32-bit data type
|
||||||
LDF_TYPE_FLOAT = 3, //!< Float data type
|
LDF_TYPE_FLOAT = 3, //!< Float data type
|
||||||
LDF_TYPE_DOUBLE = 4, //!< Double data type
|
LDF_TYPE_DOUBLE = 4, //!< Double data type
|
||||||
LDF_TYPE_U32 = 5, //!< Unsigned 32-bit data type
|
LDF_TYPE_U32 = 5, //!< Unsigned 32-bit data type
|
||||||
LDF_TYPE_BOOLEAN = 7, //!< Boolean data type
|
LDF_TYPE_BOOLEAN = 7, //!< Boolean data type
|
||||||
LDF_TYPE_U64 = 8, //!< Unsigned 64-bit data type (originally signed, templates won't work with both S64 & OBJID
|
LDF_TYPE_U64 = 8, //!< Unsigned 64-bit data type (originally signed, templates won't work with both S64 & OBJID
|
||||||
LDF_TYPE_OBJID = 9, //!< Signed 64-bit data type (reserved for object IDs)
|
LDF_TYPE_OBJID = 9, //!< Signed 64-bit data type (reserved for object IDs)
|
||||||
LDF_TYPE_UTF_8 = 13, //!< UTF-8 string data type
|
LDF_TYPE_UTF_8 = 13, //!< UTF-8 string data type
|
||||||
};
|
};
|
||||||
|
|
||||||
//! A base class for the LDF data
|
|
||||||
class LDFBaseData {
|
class LDFBaseData {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Destructor
|
virtual ~LDFBaseData() {}
|
||||||
virtual ~LDFBaseData(void) { }
|
|
||||||
|
|
||||||
//! Writes the data to a packet
|
virtual void WriteToPacket(RakNet::BitStream* packet) = 0;
|
||||||
/*!
|
|
||||||
\param packet The packet
|
|
||||||
*/
|
|
||||||
virtual void WriteToPacket(RakNet::BitStream * packet) = 0;
|
|
||||||
|
|
||||||
//! Gets the key
|
virtual const std::u16string& GetKey() = 0;
|
||||||
/*!
|
|
||||||
\return The key
|
|
||||||
*/
|
|
||||||
virtual const std::u16string& GetKey(void) = 0;
|
|
||||||
|
|
||||||
//! Gets the value type
|
virtual eLDFType GetValueType() = 0;
|
||||||
/*!
|
|
||||||
\return The value type
|
|
||||||
*/
|
|
||||||
virtual eLDFType GetValueType(void) = 0;
|
|
||||||
|
|
||||||
//! Gets a string from the key/value pair
|
/** Gets a string from the key/value pair
|
||||||
/*!
|
* @param includeKey Whether or not to include the key in the data
|
||||||
\param includeKey Whether or not to include the key in the data
|
* @param includeTypeId Whether or not to include the type id in the data
|
||||||
\param includeTypeId Whether or not to include the type id in the data
|
* @return The string representation of the data
|
||||||
\return The string representation of the data
|
*/
|
||||||
*/
|
virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0;
|
||||||
virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0;
|
|
||||||
|
|
||||||
virtual std::string GetValueAsString() = 0;
|
virtual std::string GetValueAsString() = 0;
|
||||||
|
|
||||||
virtual LDFBaseData * Copy() = 0;
|
virtual LDFBaseData* Copy() = 0;
|
||||||
|
|
||||||
// MARK: Functions
|
/**
|
||||||
|
* Given an input string, return the data as a LDF key.
|
||||||
//! Returns a pointer to a LDFData value based on string format
|
*/
|
||||||
/*!
|
static LDFBaseData* DataFromString(const std::string_view& format);
|
||||||
\param format The format
|
|
||||||
*/
|
|
||||||
static LDFBaseData * DataFromString(const std::string& format);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! A structure for an LDF key-value pair
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class LDFData : public LDFBaseData {
|
class LDFData: public LDFBaseData {
|
||||||
private:
|
private:
|
||||||
std::u16string key;
|
std::u16string key;
|
||||||
T value;
|
T value;
|
||||||
|
|
||||||
//! Writes the key to the packet
|
//! Writes the key to the packet
|
||||||
void WriteKey(RakNet::BitStream * packet) {
|
void WriteKey(RakNet::BitStream* packet) {
|
||||||
packet->Write(static_cast<uint8_t>(this->key.length() * sizeof(uint16_t)));
|
packet->Write(static_cast<uint8_t>(this->key.length() * sizeof(uint16_t)));
|
||||||
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
||||||
packet->Write(static_cast<uint16_t>(this->key[i]));
|
packet->Write(static_cast<uint16_t>(this->key[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Writes the value to the packet
|
//! Writes the value to the packet
|
||||||
void WriteValue(RakNet::BitStream * packet) {
|
void WriteValue(RakNet::BitStream* packet) {
|
||||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||||
packet->Write(this->value);
|
packet->Write(this->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Initializer
|
//! Initializer
|
||||||
LDFData(const std::u16string& key, const T& value) {
|
LDFData(const std::u16string& key, const T& value) {
|
||||||
this->key = key;
|
this->key = key;
|
||||||
this->value = value;
|
this->value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Destructor
|
//! Destructor
|
||||||
~LDFData(void) override { }
|
~LDFData(void) override {}
|
||||||
|
|
||||||
//! Gets the value
|
//! Gets the value
|
||||||
/*!
|
/*!
|
||||||
\return The value
|
\return The value
|
||||||
*/
|
*/
|
||||||
const T& GetValue(void) { return this->value; }
|
const T& GetValue(void) { return this->value; }
|
||||||
|
|
||||||
//! Sets the value
|
//! Sets the value
|
||||||
/*!
|
/*!
|
||||||
\param value The value to set to
|
\param value The value to set to
|
||||||
*/
|
*/
|
||||||
void SetValue(T value) { this->value = value; };
|
void SetValue(T value) { this->value = value; };
|
||||||
|
|
||||||
//! Gets the value string
|
//! Gets the value string
|
||||||
/*!
|
/*!
|
||||||
\return The value string
|
\return The value string
|
||||||
*/
|
*/
|
||||||
std::string GetValueString(void) { return ""; }
|
std::string GetValueString(void) { return ""; }
|
||||||
|
|
||||||
//! Writes the data to a packet
|
//! Writes the data to a packet
|
||||||
/*!
|
/*!
|
||||||
\param packet The packet
|
\param packet The packet
|
||||||
*/
|
*/
|
||||||
void WriteToPacket(RakNet::BitStream * packet) override {
|
void WriteToPacket(RakNet::BitStream* packet) override {
|
||||||
this->WriteKey(packet);
|
this->WriteKey(packet);
|
||||||
this->WriteValue(packet);
|
this->WriteValue(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the key
|
//! Gets the key
|
||||||
/*!
|
/*!
|
||||||
\return The key
|
\return The key
|
||||||
*/
|
*/
|
||||||
const std::u16string& GetKey(void) override { return this->key; }
|
const std::u16string& GetKey(void) override { return this->key; }
|
||||||
|
|
||||||
//! Gets the LDF Type
|
//! Gets the LDF Type
|
||||||
/*!
|
/*!
|
||||||
\return The LDF value type
|
\return The LDF value type
|
||||||
*/
|
*/
|
||||||
eLDFType GetValueType(void) override { return LDF_TYPE_UNKNOWN; }
|
eLDFType GetValueType(void) override { return LDF_TYPE_UNKNOWN; }
|
||||||
|
|
||||||
//! Gets the string data
|
//! Gets the string data
|
||||||
/*!
|
/*!
|
||||||
\param includeKey Whether or not to include the key in the data
|
\param includeKey Whether or not to include the key in the data
|
||||||
\param includeTypeId Whether or not to include the type id in the data
|
\param includeTypeId Whether or not to include the type id in the data
|
||||||
\return The string representation of the data
|
\return The string representation of the data
|
||||||
*/
|
*/
|
||||||
std::string GetString(const bool includeKey = true, const bool includeTypeId = true) override {
|
std::string GetString(const bool includeKey = true, const bool includeTypeId = true) override {
|
||||||
if (GetValueType() == -1) {
|
if (GetValueType() == -1) {
|
||||||
return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>";
|
return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:<server variable>";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
|
|
||||||
if (includeKey) {
|
if (includeKey) {
|
||||||
const std::string& sKey = GeneralUtils::UTF16ToWTF8(this->key, this->key.size());
|
const std::string& sKey = GeneralUtils::UTF16ToWTF8(this->key, this->key.size());
|
||||||
|
stream << sKey << '=';
|
||||||
|
}
|
||||||
|
|
||||||
stream << sKey << "=";
|
if (includeTypeId) {
|
||||||
}
|
stream << this->GetValueType() << ':';
|
||||||
|
}
|
||||||
|
|
||||||
if (includeTypeId) {
|
const std::string& sData = this->GetValueString();
|
||||||
const std::string& sType = std::to_string(this->GetValueType());
|
|
||||||
|
|
||||||
|
stream << sData;
|
||||||
|
|
||||||
stream << sType << ":";
|
return stream.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& sData = this->GetValueString();
|
std::string GetValueAsString() override {
|
||||||
|
return this->GetValueString();
|
||||||
|
}
|
||||||
|
|
||||||
stream << sData;
|
LDFBaseData* Copy() override {
|
||||||
|
return new LDFData<T>(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
return stream.str();
|
inline static T Default = {};
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetValueAsString() override {
|
|
||||||
return this->GetValueString();
|
|
||||||
}
|
|
||||||
|
|
||||||
LDFBaseData * Copy() override {
|
|
||||||
return new LDFData<T>(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static T Default = {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// LDF Types
|
// LDF Types
|
||||||
@ -206,48 +178,46 @@ template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF
|
|||||||
|
|
||||||
// The specialized version for std::u16string (UTF-16)
|
// The specialized version for std::u16string (UTF-16)
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream * packet) {
|
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) {
|
||||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||||
|
|
||||||
packet->Write(static_cast<uint32_t>(this->value.length()));
|
packet->Write(static_cast<uint32_t>(this->value.length()));
|
||||||
for (uint32_t i = 0; i < this->value.length(); ++i) {
|
for (uint32_t i = 0; i < this->value.length(); ++i) {
|
||||||
packet->Write(static_cast<uint16_t>(this->value[i]));
|
packet->Write(static_cast<uint16_t>(this->value[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The specialized version for bool
|
// The specialized version for bool
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream * packet) {
|
inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
|
||||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||||
|
|
||||||
packet->Write(static_cast<uint8_t>(this->value));
|
packet->Write(static_cast<uint8_t>(this->value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The specialized version for std::string (UTF-8)
|
// The specialized version for std::string (UTF-8)
|
||||||
template<>
|
template<>
|
||||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream * packet) {
|
inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
|
||||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||||
|
|
||||||
packet->Write(static_cast<uint32_t>(this->value.length()));
|
packet->Write(static_cast<uint32_t>(this->value.length()));
|
||||||
for (uint32_t i = 0; i < this->value.length(); ++i) {
|
for (uint32_t i = 0; i < this->value.length(); ++i) {
|
||||||
packet->Write(static_cast<uint8_t>(this->value[i]));
|
packet->Write(static_cast<uint8_t>(this->value[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: String Data
|
template<> inline std::string LDFData<std::u16string>::GetValueString() {
|
||||||
template<> inline std::string LDFData<std::u16string>::GetValueString(void) {
|
|
||||||
//std::string toReturn(this->value.begin(), this->value.end());
|
|
||||||
//return toReturn;
|
|
||||||
|
|
||||||
return GeneralUtils::UTF16ToWTF8(this->value, this->value.size());
|
return GeneralUtils::UTF16ToWTF8(this->value, this->value.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline std::string LDFData<int32_t>::GetValueString(void) { return std::to_string(this->value); }
|
template<> inline std::string LDFData<int32_t>::GetValueString() { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<float>::GetValueString(void) { return std::to_string(this->value); }
|
template<> inline std::string LDFData<float>::GetValueString() { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<double>::GetValueString(void) { return std::to_string(this->value); }
|
template<> inline std::string LDFData<double>::GetValueString() { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<uint32_t>::GetValueString(void) { return std::to_string(this->value); }
|
template<> inline std::string LDFData<uint32_t>::GetValueString() { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<bool>::GetValueString(void) { return std::to_string(this->value); }
|
template<> inline std::string LDFData<bool>::GetValueString() { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<uint64_t>::GetValueString(void) { return std::to_string(this->value); }
|
template<> inline std::string LDFData<uint64_t>::GetValueString() { return std::to_string(this->value); }
|
||||||
template<> inline std::string LDFData<LWOOBJID>::GetValueString(void) { return std::to_string(this->value); }
|
template<> inline std::string LDFData<LWOOBJID>::GetValueString() { return std::to_string(this->value); }
|
||||||
|
|
||||||
template<> inline std::string LDFData<std::string>::GetValueString(void) { return this->value; }
|
template<> inline std::string LDFData<std::string>::GetValueString() { return this->value; }
|
||||||
|
|
||||||
|
#endif //!__LDFFORMAT__H__
|
||||||
|
372
dCommon/MD5.cpp
372
dCommon/MD5.cpp
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* interface header */
|
/* interface header */
|
||||||
#include "MD5.h"
|
#include "MD5.h"
|
||||||
|
|
||||||
/* system implementation headers */
|
/* system implementation headers */
|
||||||
@ -59,304 +59,290 @@
|
|||||||
|
|
||||||
// F, G, H and I are basic MD5 functions.
|
// F, G, H and I are basic MD5 functions.
|
||||||
inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
|
inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
|
||||||
return x&y | ~x&z;
|
return x & y | ~x & z;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
|
inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
|
||||||
return x&z | y&~z;
|
return x & z | y & ~z;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
|
inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
|
||||||
return x^y^z;
|
return x ^ y ^ z;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
|
inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
|
||||||
return y ^ (x | ~z);
|
return y ^ (x | ~z);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rotate_left rotates x left n bits.
|
// rotate_left rotates x left n bits.
|
||||||
inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
|
inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
|
||||||
return (x << n) | (x >> (32 - n));
|
return (x << n) | (x >> (32 - n));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||||
// Rotation is separate from addition to prevent recomputation.
|
// Rotation is separate from addition to prevent recomputation.
|
||||||
inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||||
a = rotate_left(a + F(b, c, d) + x + ac, s) + b;
|
a = rotate_left(a + F(b, c, d) + x + ac, s) + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||||
a = rotate_left(a + G(b, c, d) + x + ac, s) + b;
|
a = rotate_left(a + G(b, c, d) + x + ac, s) + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||||
a = rotate_left(a + H(b, c, d) + x + ac, s) + b;
|
a = rotate_left(a + H(b, c, d) + x + ac, s) + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
|
||||||
a = rotate_left(a + I(b, c, d) + x + ac, s) + b;
|
a = rotate_left(a + I(b, c, d) + x + ac, s) + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
|
|
||||||
// default ctor, just initailize
|
// default ctor, just initailize
|
||||||
MD5::MD5()
|
MD5::MD5() {
|
||||||
{
|
init();
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
|
|
||||||
// nifty shortcut ctor, compute MD5 for string and finalize it right away
|
// nifty shortcut ctor, compute MD5 for string and finalize it right away
|
||||||
MD5::MD5(const std::string &text)
|
MD5::MD5(const std::string& text) {
|
||||||
{
|
init();
|
||||||
init();
|
update(text.c_str(), text.length());
|
||||||
update(text.c_str(), text.length());
|
finalize();
|
||||||
finalize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
void MD5::init()
|
void MD5::init() {
|
||||||
{
|
finalized = false;
|
||||||
finalized = false;
|
|
||||||
|
|
||||||
count[0] = 0;
|
count[0] = 0;
|
||||||
count[1] = 0;
|
count[1] = 0;
|
||||||
|
|
||||||
// load magic initialization constants.
|
// load magic initialization constants.
|
||||||
state[0] = 0x67452301;
|
state[0] = 0x67452301;
|
||||||
state[1] = 0xefcdab89;
|
state[1] = 0xefcdab89;
|
||||||
state[2] = 0x98badcfe;
|
state[2] = 0x98badcfe;
|
||||||
state[3] = 0x10325476;
|
state[3] = 0x10325476;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
|
// decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
|
||||||
void MD5::decode(uint4 output[], const uint1 input[], size_type len)
|
void MD5::decode(uint4 output[], const uint1 input[], size_type len) {
|
||||||
{
|
for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
|
||||||
for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
|
output[i] = ((uint4)input[j]) | (((uint4)input[j + 1]) << 8) |
|
||||||
output[i] = ((uint4)input[j]) | (((uint4)input[j + 1]) << 8) |
|
(((uint4)input[j + 2]) << 16) | (((uint4)input[j + 3]) << 24);
|
||||||
(((uint4)input[j + 2]) << 16) | (((uint4)input[j + 3]) << 24);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
// encodes input (uint4) into output (unsigned char). Assumes len is
|
// encodes input (uint4) into output (unsigned char). Assumes len is
|
||||||
// a multiple of 4.
|
// a multiple of 4.
|
||||||
void MD5::encode(uint1 output[], const uint4 input[], size_type len)
|
void MD5::encode(uint1 output[], const uint4 input[], size_type len) {
|
||||||
{
|
for (size_type i = 0, j = 0; j < len; i++, j += 4) {
|
||||||
for (size_type i = 0, j = 0; j < len; i++, j += 4) {
|
output[j] = input[i] & 0xff;
|
||||||
output[j] = input[i] & 0xff;
|
output[j + 1] = (input[i] >> 8) & 0xff;
|
||||||
output[j + 1] = (input[i] >> 8) & 0xff;
|
output[j + 2] = (input[i] >> 16) & 0xff;
|
||||||
output[j + 2] = (input[i] >> 16) & 0xff;
|
output[j + 3] = (input[i] >> 24) & 0xff;
|
||||||
output[j + 3] = (input[i] >> 24) & 0xff;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
// apply MD5 algo on a block
|
// apply MD5 algo on a block
|
||||||
void MD5::transform(const uint1 block[blocksize])
|
void MD5::transform(const uint1 block[blocksize]) {
|
||||||
{
|
uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||||
uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
decode(x, block, blocksize);
|
||||||
decode(x, block, blocksize);
|
|
||||||
|
|
||||||
/* Round 1 */
|
/* Round 1 */
|
||||||
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
|
FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
|
||||||
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
|
FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
|
||||||
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
|
FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
|
||||||
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
|
FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
|
||||||
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
|
FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
|
||||||
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
|
FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
|
||||||
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
|
FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
|
||||||
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
|
FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
|
||||||
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
|
FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
|
||||||
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
|
FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
|
||||||
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||||
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||||
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||||
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||||
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||||
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||||
|
|
||||||
/* Round 2 */
|
/* Round 2 */
|
||||||
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
|
GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
|
||||||
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
|
GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
|
||||||
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||||
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
|
GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
|
||||||
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
|
GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
|
||||||
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||||
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||||
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
|
GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
|
||||||
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
|
GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
|
||||||
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||||
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
|
GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
|
||||||
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
|
GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
|
||||||
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||||
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
|
GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
|
||||||
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
|
GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
|
||||||
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||||
|
|
||||||
/* Round 3 */
|
/* Round 3 */
|
||||||
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
|
HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
|
||||||
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
|
HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
|
||||||
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||||
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||||
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
|
HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
|
||||||
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
|
HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
|
||||||
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
|
HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
|
||||||
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||||
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||||
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
|
HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
|
||||||
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
|
HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
|
||||||
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
|
HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
|
||||||
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
|
HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
|
||||||
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||||
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||||
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
|
HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
|
||||||
|
|
||||||
/* Round 4 */
|
/* Round 4 */
|
||||||
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
|
II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
|
||||||
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
|
II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
|
||||||
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||||
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
|
II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
|
||||||
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||||
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
|
II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
|
||||||
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||||
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
|
II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
|
||||||
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
|
II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
|
||||||
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||||
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
|
II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
|
||||||
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||||
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
|
II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
|
||||||
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||||
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
|
II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
|
||||||
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
|
II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
|
||||||
|
|
||||||
state[0] += a;
|
state[0] += a;
|
||||||
state[1] += b;
|
state[1] += b;
|
||||||
state[2] += c;
|
state[2] += c;
|
||||||
state[3] += d;
|
state[3] += d;
|
||||||
|
|
||||||
// Zeroize sensitive information.
|
// Zeroize sensitive information.
|
||||||
memset(x, 0, sizeof x);
|
memset(x, 0, sizeof x);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
// MD5 block update operation. Continues an MD5 message-digest
|
// MD5 block update operation. Continues an MD5 message-digest
|
||||||
// operation, processing another message block
|
// operation, processing another message block
|
||||||
void MD5::update(const unsigned char input[], size_type length)
|
void MD5::update(const unsigned char input[], size_type length) {
|
||||||
{
|
// compute number of bytes mod 64
|
||||||
// compute number of bytes mod 64
|
size_type index = count[0] / 8 % blocksize;
|
||||||
size_type index = count[0] / 8 % blocksize;
|
|
||||||
|
|
||||||
// Update number of bits
|
// Update number of bits
|
||||||
if ((count[0] += (length << 3)) < (length << 3))
|
if ((count[0] += (length << 3)) < (length << 3))
|
||||||
count[1]++;
|
count[1]++;
|
||||||
count[1] += (length >> 29);
|
count[1] += (length >> 29);
|
||||||
|
|
||||||
// number of bytes we need to fill in buffer
|
// number of bytes we need to fill in buffer
|
||||||
size_type firstpart = 64 - index;
|
size_type firstpart = 64 - index;
|
||||||
|
|
||||||
size_type i;
|
size_type i;
|
||||||
|
|
||||||
// transform as many times as possible.
|
// transform as many times as possible.
|
||||||
if (length >= firstpart)
|
if (length >= firstpart) {
|
||||||
{
|
// fill buffer first, transform
|
||||||
// fill buffer first, transform
|
memcpy(&buffer[index], input, firstpart);
|
||||||
memcpy(&buffer[index], input, firstpart);
|
transform(buffer);
|
||||||
transform(buffer);
|
|
||||||
|
|
||||||
// transform chunks of blocksize (64 bytes)
|
// transform chunks of blocksize (64 bytes)
|
||||||
for (i = firstpart; i + blocksize <= length; i += blocksize)
|
for (i = firstpart; i + blocksize <= length; i += blocksize)
|
||||||
transform(&input[i]);
|
transform(&input[i]);
|
||||||
|
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
} else
|
||||||
else
|
i = 0;
|
||||||
i = 0;
|
|
||||||
|
|
||||||
// buffer remaining input
|
// buffer remaining input
|
||||||
memcpy(&buffer[index], &input[i], length - i);
|
memcpy(&buffer[index], &input[i], length - i);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
// for convenience provide a verson with signed char
|
// for convenience provide a verson with signed char
|
||||||
void MD5::update(const char input[], size_type length)
|
void MD5::update(const char input[], size_type length) {
|
||||||
{
|
update((const unsigned char*)input, length);
|
||||||
update((const unsigned char*)input, length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
// MD5 finalization. Ends an MD5 message-digest operation, writing the
|
// MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||||
// the message digest and zeroizing the context.
|
// the message digest and zeroizing the context.
|
||||||
MD5& MD5::finalize()
|
MD5& MD5::finalize() {
|
||||||
{
|
static unsigned char padding[64] = {
|
||||||
static unsigned char padding[64] = {
|
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
};
|
||||||
};
|
|
||||||
|
|
||||||
if (!finalized) {
|
if (!finalized) {
|
||||||
// Save number of bits
|
// Save number of bits
|
||||||
unsigned char bits[8];
|
unsigned char bits[8];
|
||||||
encode(bits, count, 8);
|
encode(bits, count, 8);
|
||||||
|
|
||||||
// pad out to 56 mod 64.
|
// pad out to 56 mod 64.
|
||||||
size_type index = count[0] / 8 % 64;
|
size_type index = count[0] / 8 % 64;
|
||||||
size_type padLen = (index < 56) ? (56 - index) : (120 - index);
|
size_type padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||||
update(padding, padLen);
|
update(padding, padLen);
|
||||||
|
|
||||||
// Append length (before padding)
|
// Append length (before padding)
|
||||||
update(bits, 8);
|
update(bits, 8);
|
||||||
|
|
||||||
// Store state in digest
|
// Store state in digest
|
||||||
encode(digest, state, 16);
|
encode(digest, state, 16);
|
||||||
|
|
||||||
// Zeroize sensitive information.
|
// Zeroize sensitive information.
|
||||||
memset(buffer, 0, sizeof buffer);
|
memset(buffer, 0, sizeof buffer);
|
||||||
memset(count, 0, sizeof count);
|
memset(count, 0, sizeof count);
|
||||||
|
|
||||||
finalized = true;
|
finalized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
// return hex representation of digest as string
|
// return hex representation of digest as string
|
||||||
std::string MD5::hexdigest() const
|
std::string MD5::hexdigest() const {
|
||||||
{
|
if (!finalized)
|
||||||
if (!finalized)
|
return "";
|
||||||
return "";
|
|
||||||
|
|
||||||
char buf[33];
|
char buf[33];
|
||||||
for (int i = 0; i<16; i++)
|
for (int i = 0; i < 16; i++)
|
||||||
sprintf(buf + i * 2, "%02x", digest[i]);
|
sprintf(buf + i * 2, "%02x", digest[i]);
|
||||||
buf[32] = 0;
|
buf[32] = 0;
|
||||||
|
|
||||||
return std::string(buf);
|
return std::string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, MD5 md5)
|
std::ostream& operator<<(std::ostream& out, MD5 md5) {
|
||||||
{
|
return out << md5.hexdigest();
|
||||||
return out << md5.hexdigest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|
||||||
std::string md5(const std::string str)
|
std::string md5(const std::string str) {
|
||||||
{
|
MD5 md5 = MD5(str);
|
||||||
MD5 md5 = MD5(str);
|
|
||||||
|
|
||||||
return md5.hexdigest();
|
return md5.hexdigest();
|
||||||
}
|
}
|
||||||
|
@ -37,55 +37,55 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
// a small class for calculating MD5 hashes of strings or byte arrays
|
// a small class for calculating MD5 hashes of strings or byte arrays
|
||||||
// it is not meant to be fast or secure
|
// it is not meant to be fast or secure
|
||||||
//
|
//
|
||||||
// usage: 1) feed it blocks of uchars with update()
|
// usage: 1) feed it blocks of uchars with update()
|
||||||
// 2) finalize()
|
// 2) finalize()
|
||||||
// 3) get hexdigest() string
|
// 3) get hexdigest() string
|
||||||
// or
|
// or
|
||||||
// MD5(std::string).hexdigest()
|
// MD5(std::string).hexdigest()
|
||||||
//
|
//
|
||||||
// assumes that char is 8 bit and int is 32 bit
|
// assumes that char is 8 bit and int is 32 bit
|
||||||
class MD5
|
class MD5
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef unsigned int size_type; // must be 32bit
|
typedef unsigned int size_type; // must be 32bit
|
||||||
|
|
||||||
MD5();
|
MD5();
|
||||||
MD5(const std::string& text);
|
MD5(const std::string& text);
|
||||||
void update(const unsigned char *buf, size_type length);
|
void update(const unsigned char* buf, size_type length);
|
||||||
void update(const char *buf, size_type length);
|
void update(const char* buf, size_type length);
|
||||||
MD5& finalize();
|
MD5& finalize();
|
||||||
std::string hexdigest() const;
|
std::string hexdigest() const;
|
||||||
friend std::ostream& operator<<(std::ostream&, MD5 md5);
|
friend std::ostream& operator<<(std::ostream&, MD5 md5);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
typedef unsigned char uint1; // 8bit
|
typedef unsigned char uint1; // 8bit
|
||||||
typedef unsigned int uint4; // 32bit
|
typedef unsigned int uint4; // 32bit
|
||||||
enum { blocksize = 64 }; // VC6 won't eat a const static int here
|
enum { blocksize = 64 }; // VC6 won't eat a const static int here
|
||||||
|
|
||||||
void transform(const uint1 block[blocksize]);
|
void transform(const uint1 block[blocksize]);
|
||||||
static void decode(uint4 output[], const uint1 input[], size_type len);
|
static void decode(uint4 output[], const uint1 input[], size_type len);
|
||||||
static void encode(uint1 output[], const uint4 input[], size_type len);
|
static void encode(uint1 output[], const uint4 input[], size_type len);
|
||||||
|
|
||||||
bool finalized;
|
bool finalized;
|
||||||
uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
|
uint1 buffer[blocksize]; // bytes that didn't fit in last 64 byte chunk
|
||||||
uint4 count[2]; // 64bit counter for number of bits (lo, hi)
|
uint4 count[2]; // 64bit counter for number of bits (lo, hi)
|
||||||
uint4 state[4]; // digest so far
|
uint4 state[4]; // digest so far
|
||||||
uint1 digest[16]; // the result
|
uint1 digest[16]; // the result
|
||||||
|
|
||||||
// low level logic operations
|
// low level logic operations
|
||||||
static inline uint4 F(uint4 x, uint4 y, uint4 z);
|
static inline uint4 F(uint4 x, uint4 y, uint4 z);
|
||||||
static inline uint4 G(uint4 x, uint4 y, uint4 z);
|
static inline uint4 G(uint4 x, uint4 y, uint4 z);
|
||||||
static inline uint4 H(uint4 x, uint4 y, uint4 z);
|
static inline uint4 H(uint4 x, uint4 y, uint4 z);
|
||||||
static inline uint4 I(uint4 x, uint4 y, uint4 z);
|
static inline uint4 I(uint4 x, uint4 y, uint4 z);
|
||||||
static inline uint4 rotate_left(uint4 x, int n);
|
static inline uint4 rotate_left(uint4 x, int n);
|
||||||
static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
static inline void FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||||
static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
static inline void GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||||
static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
static inline void HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||||
static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
static inline void II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string md5(const std::string str);
|
std::string md5(const std::string str);
|
||||||
|
@ -4,174 +4,150 @@
|
|||||||
|
|
||||||
std::unordered_map<MetricVariable, Metric*> Metrics::m_Metrics = {};
|
std::unordered_map<MetricVariable, Metric*> Metrics::m_Metrics = {};
|
||||||
std::vector<MetricVariable> Metrics::m_Variables = {
|
std::vector<MetricVariable> Metrics::m_Variables = {
|
||||||
MetricVariable::GameLoop,
|
MetricVariable::GameLoop,
|
||||||
MetricVariable::PacketHandling,
|
MetricVariable::PacketHandling,
|
||||||
MetricVariable::UpdateEntities,
|
MetricVariable::UpdateEntities,
|
||||||
MetricVariable::UpdateSpawners,
|
MetricVariable::UpdateSpawners,
|
||||||
MetricVariable::Physics,
|
MetricVariable::Physics,
|
||||||
MetricVariable::UpdateReplica,
|
MetricVariable::UpdateReplica,
|
||||||
MetricVariable::Ghosting,
|
MetricVariable::Ghosting,
|
||||||
MetricVariable::CPUTime,
|
MetricVariable::CPUTime,
|
||||||
MetricVariable::Sleep,
|
MetricVariable::Sleep,
|
||||||
MetricVariable::Frame,
|
MetricVariable::Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
void Metrics::AddMeasurement(MetricVariable variable, int64_t value)
|
void Metrics::AddMeasurement(MetricVariable variable, int64_t value) {
|
||||||
{
|
const auto& iter = m_Metrics.find(variable);
|
||||||
const auto& iter = m_Metrics.find(variable);
|
|
||||||
|
|
||||||
Metric* metric;
|
Metric* metric;
|
||||||
|
|
||||||
if (iter == m_Metrics.end())
|
if (iter == m_Metrics.end()) {
|
||||||
{
|
metric = new Metric();
|
||||||
metric = new Metric();
|
|
||||||
|
|
||||||
m_Metrics[variable] = metric;
|
m_Metrics[variable] = metric;
|
||||||
}
|
} else {
|
||||||
else
|
metric = iter->second;
|
||||||
{
|
}
|
||||||
metric = iter->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddMeasurement(metric, value);
|
AddMeasurement(metric, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metrics::AddMeasurement(Metric* metric, int64_t value)
|
void Metrics::AddMeasurement(Metric* metric, int64_t value) {
|
||||||
{
|
const auto index = metric->measurementIndex;
|
||||||
const auto index = metric->measurementIndex;
|
|
||||||
|
|
||||||
metric->measurements[index] = value;
|
metric->measurements[index] = value;
|
||||||
|
|
||||||
if (metric->max == -1 || value > metric->max)
|
if (metric->max == -1 || value > metric->max) {
|
||||||
{
|
metric->max = value;
|
||||||
metric->max = value;
|
} else if (metric->min == -1 || metric->min > value) {
|
||||||
}
|
metric->min = value;
|
||||||
else if (metric->min == -1 || metric->min > value)
|
}
|
||||||
{
|
|
||||||
metric->min = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metric->measurementSize < MAX_MEASURMENT_POINTS)
|
if (metric->measurementSize < MAX_MEASURMENT_POINTS) {
|
||||||
{
|
metric->measurementSize++;
|
||||||
metric->measurementSize++;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
metric->measurementIndex = (index + 1) % MAX_MEASURMENT_POINTS;
|
metric->measurementIndex = (index + 1) % MAX_MEASURMENT_POINTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Metric* Metrics::GetMetric(MetricVariable variable)
|
const Metric* Metrics::GetMetric(MetricVariable variable) {
|
||||||
{
|
const auto& iter = m_Metrics.find(variable);
|
||||||
const auto& iter = m_Metrics.find(variable);
|
|
||||||
|
|
||||||
if (iter == m_Metrics.end())
|
if (iter == m_Metrics.end()) {
|
||||||
{
|
return nullptr;
|
||||||
return nullptr;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Metric* metric = iter->second;
|
Metric* metric = iter->second;
|
||||||
|
|
||||||
int64_t average = 0;
|
int64_t average = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < metric->measurementSize; i++)
|
for (size_t i = 0; i < metric->measurementSize; i++) {
|
||||||
{
|
average += metric->measurements[i];
|
||||||
average += metric->measurements[i];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
average /= metric->measurementSize;
|
average /= metric->measurementSize;
|
||||||
|
|
||||||
metric->average = average;
|
metric->average = average;
|
||||||
|
|
||||||
return metric;
|
return metric;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metrics::StartMeasurement(MetricVariable variable)
|
void Metrics::StartMeasurement(MetricVariable variable) {
|
||||||
{
|
const auto& iter = m_Metrics.find(variable);
|
||||||
const auto& iter = m_Metrics.find(variable);
|
|
||||||
|
|
||||||
Metric* metric;
|
Metric* metric;
|
||||||
|
|
||||||
if (iter == m_Metrics.end())
|
if (iter == m_Metrics.end()) {
|
||||||
{
|
metric = new Metric();
|
||||||
metric = new Metric();
|
|
||||||
|
|
||||||
m_Metrics[variable] = metric;
|
m_Metrics[variable] = metric;
|
||||||
}
|
} else {
|
||||||
else
|
metric = iter->second;
|
||||||
{
|
}
|
||||||
metric = iter->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
metric->activeMeasurement = std::chrono::high_resolution_clock::now();
|
metric->activeMeasurement = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metrics::EndMeasurement(MetricVariable variable)
|
void Metrics::EndMeasurement(MetricVariable variable) {
|
||||||
{
|
const auto end = std::chrono::high_resolution_clock::now();
|
||||||
const auto end = std::chrono::high_resolution_clock::now();
|
|
||||||
|
|
||||||
const auto& iter = m_Metrics.find(variable);
|
const auto& iter = m_Metrics.find(variable);
|
||||||
|
|
||||||
if (iter == m_Metrics.end())
|
if (iter == m_Metrics.end()) {
|
||||||
{
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Metric* metric = iter->second;
|
Metric* metric = iter->second;
|
||||||
|
|
||||||
const auto elapsed = end - metric->activeMeasurement;
|
const auto elapsed = end - metric->activeMeasurement;
|
||||||
|
|
||||||
const auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count();
|
const auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count();
|
||||||
|
|
||||||
AddMeasurement(metric, nanoseconds);
|
AddMeasurement(metric, nanoseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Metrics::ToMiliseconds(int64_t nanoseconds)
|
float Metrics::ToMiliseconds(int64_t nanoseconds) {
|
||||||
{
|
return (float)nanoseconds / 1e6;
|
||||||
return (float) nanoseconds / 1e6;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Metrics::MetricVariableToString(MetricVariable variable)
|
std::string Metrics::MetricVariableToString(MetricVariable variable) {
|
||||||
{
|
switch (variable) {
|
||||||
switch (variable)
|
case MetricVariable::GameLoop:
|
||||||
{
|
return "GameLoop";
|
||||||
case MetricVariable::GameLoop:
|
case MetricVariable::PacketHandling:
|
||||||
return "GameLoop";
|
return "PacketHandling";
|
||||||
case MetricVariable::PacketHandling:
|
case MetricVariable::UpdateEntities:
|
||||||
return "PacketHandling";
|
return "UpdateEntities";
|
||||||
case MetricVariable::UpdateEntities:
|
case MetricVariable::UpdateSpawners:
|
||||||
return "UpdateEntities";
|
return "UpdateSpawners";
|
||||||
case MetricVariable::UpdateSpawners:
|
case MetricVariable::Physics:
|
||||||
return "UpdateSpawners";
|
return "Physics";
|
||||||
case MetricVariable::Physics:
|
case MetricVariable::UpdateReplica:
|
||||||
return "Physics";
|
return "UpdateReplica";
|
||||||
case MetricVariable::UpdateReplica:
|
case MetricVariable::Sleep:
|
||||||
return "UpdateReplica";
|
return "Sleep";
|
||||||
case MetricVariable::Sleep:
|
case MetricVariable::CPUTime:
|
||||||
return "Sleep";
|
return "CPUTime";
|
||||||
case MetricVariable::CPUTime:
|
case MetricVariable::Frame:
|
||||||
return "CPUTime";
|
return "Frame";
|
||||||
case MetricVariable::Frame:
|
case MetricVariable::Ghosting:
|
||||||
return "Frame";
|
return "Ghosting";
|
||||||
case MetricVariable::Ghosting:
|
|
||||||
return "Ghosting";
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return "Invalid";
|
return "Invalid";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<MetricVariable>& Metrics::GetAllMetrics()
|
const std::vector<MetricVariable>& Metrics::GetAllMetrics() {
|
||||||
{
|
return m_Variables;
|
||||||
return m_Variables;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metrics::Clear()
|
void Metrics::Clear() {
|
||||||
{
|
for (const auto& pair : m_Metrics) {
|
||||||
for (const auto& pair : m_Metrics)
|
delete pair.second;
|
||||||
{
|
}
|
||||||
delete pair.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Metrics.clear();
|
m_Metrics.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RSS Memory utilities
|
/* RSS Memory utilities
|
||||||
@ -207,46 +183,44 @@ void Metrics::Clear()
|
|||||||
#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
|
#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the peak (maximum so far) resident set size (physical
|
* Returns the peak (maximum so far) resident set size (physical
|
||||||
* memory use) measured in bytes, or zero if the value cannot be
|
* memory use) measured in bytes, or zero if the value cannot be
|
||||||
* determined on this OS.
|
* determined on this OS.
|
||||||
*/
|
*/
|
||||||
size_t Metrics::GetPeakRSS()
|
size_t Metrics::GetPeakRSS() {
|
||||||
{
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
/* Windows -------------------------------------------------- */
|
/* Windows -------------------------------------------------- */
|
||||||
PROCESS_MEMORY_COUNTERS info;
|
PROCESS_MEMORY_COUNTERS info;
|
||||||
GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
|
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
||||||
return (size_t)info.PeakWorkingSetSize;
|
return (size_t)info.PeakWorkingSetSize;
|
||||||
|
|
||||||
#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
|
#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
|
||||||
/* AIX and Solaris ------------------------------------------ */
|
/* AIX and Solaris ------------------------------------------ */
|
||||||
struct psinfo psinfo;
|
struct psinfo psinfo;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
if ( (fd = open( "/proc/self/psinfo", O_RDONLY )) == -1 )
|
if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1)
|
||||||
return (size_t)0L; /* Can't open? */
|
return (size_t)0L; /* Can't open? */
|
||||||
if ( read( fd, &psinfo, sizeof(psinfo) ) != sizeof(psinfo) )
|
if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
|
||||||
{
|
close(fd);
|
||||||
close( fd );
|
return (size_t)0L; /* Can't read? */
|
||||||
return (size_t)0L; /* Can't read? */
|
}
|
||||||
}
|
close(fd);
|
||||||
close( fd );
|
return (size_t)(psinfo.pr_rssize * 1024L);
|
||||||
return (size_t)(psinfo.pr_rssize * 1024L);
|
|
||||||
|
|
||||||
#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
|
#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
/* BSD, Linux, and OSX -------------------------------------- */
|
/* BSD, Linux, and OSX -------------------------------------- */
|
||||||
struct rusage rusage;
|
struct rusage rusage;
|
||||||
getrusage( RUSAGE_SELF, &rusage );
|
getrusage(RUSAGE_SELF, &rusage);
|
||||||
#if defined(__APPLE__) && defined(__MACH__)
|
#if defined(__APPLE__) && defined(__MACH__)
|
||||||
return (size_t)rusage.ru_maxrss;
|
return (size_t)rusage.ru_maxrss;
|
||||||
#else
|
#else
|
||||||
return (size_t)(rusage.ru_maxrss * 1024L);
|
return (size_t)(rusage.ru_maxrss * 1024L);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Unknown OS ----------------------------------------------- */
|
/* Unknown OS ----------------------------------------------- */
|
||||||
return (size_t)0L; /* Unsupported. */
|
return (size_t)0L; /* Unsupported. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -255,49 +229,46 @@ size_t Metrics::GetPeakRSS()
|
|||||||
* Returns the current resident set size (physical memory use) measured
|
* Returns the current resident set size (physical memory use) measured
|
||||||
* in bytes, or zero if the value cannot be determined on this OS.
|
* in bytes, or zero if the value cannot be determined on this OS.
|
||||||
*/
|
*/
|
||||||
size_t Metrics::GetCurrentRSS()
|
size_t Metrics::GetCurrentRSS() {
|
||||||
{
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
/* Windows -------------------------------------------------- */
|
/* Windows -------------------------------------------------- */
|
||||||
PROCESS_MEMORY_COUNTERS info;
|
PROCESS_MEMORY_COUNTERS info;
|
||||||
GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
|
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
||||||
return (size_t)info.WorkingSetSize;
|
return (size_t)info.WorkingSetSize;
|
||||||
|
|
||||||
#elif defined(__APPLE__) && defined(__MACH__)
|
#elif defined(__APPLE__) && defined(__MACH__)
|
||||||
/* OSX ------------------------------------------------------ */
|
/* OSX ------------------------------------------------------ */
|
||||||
struct mach_task_basic_info info;
|
struct mach_task_basic_info info;
|
||||||
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
|
mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT;
|
||||||
if ( task_info( mach_task_self( ), MACH_TASK_BASIC_INFO,
|
if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
|
||||||
(task_info_t)&info, &infoCount ) != KERN_SUCCESS )
|
(task_info_t)&info, &infoCount) != KERN_SUCCESS)
|
||||||
return (size_t)0L; /* Can't access? */
|
return (size_t)0L; /* Can't access? */
|
||||||
return (size_t)info.resident_size;
|
return (size_t)info.resident_size;
|
||||||
|
|
||||||
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
|
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
|
||||||
/* Linux ---------------------------------------------------- */
|
/* Linux ---------------------------------------------------- */
|
||||||
long rss = 0L;
|
long rss = 0L;
|
||||||
FILE* fp = NULL;
|
FILE* fp = NULL;
|
||||||
if ( (fp = fopen( "/proc/self/statm", "r" )) == NULL )
|
if ((fp = fopen("/proc/self/statm", "r")) == NULL)
|
||||||
return (size_t)0L; /* Can't open? */
|
return (size_t)0L; /* Can't open? */
|
||||||
if ( fscanf( fp, "%*s%ld", &rss ) != 1 )
|
if (fscanf(fp, "%*s%ld", &rss) != 1) {
|
||||||
{
|
fclose(fp);
|
||||||
fclose( fp );
|
return (size_t)0L; /* Can't read? */
|
||||||
return (size_t)0L; /* Can't read? */
|
}
|
||||||
}
|
fclose(fp);
|
||||||
fclose( fp );
|
return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE);
|
||||||
return (size_t)rss * (size_t)sysconf( _SC_PAGESIZE);
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* AIX, BSD, Solaris, and Unknown OS ------------------------ */
|
/* AIX, BSD, Solaris, and Unknown OS ------------------------ */
|
||||||
return (size_t)0L; /* Unsupported. */
|
return (size_t)0L; /* Unsupported. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Metrics::GetProcessID()
|
size_t Metrics::GetProcessID() {
|
||||||
{
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
return GetCurrentProcessId();
|
return GetCurrentProcessId();
|
||||||
#else
|
#else
|
||||||
return getpid();
|
return getpid();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -10,52 +10,52 @@
|
|||||||
|
|
||||||
enum class MetricVariable : int32_t
|
enum class MetricVariable : int32_t
|
||||||
{
|
{
|
||||||
GameLoop,
|
GameLoop,
|
||||||
PacketHandling,
|
PacketHandling,
|
||||||
UpdateEntities,
|
UpdateEntities,
|
||||||
UpdateSpawners,
|
UpdateSpawners,
|
||||||
Physics,
|
Physics,
|
||||||
UpdateReplica,
|
UpdateReplica,
|
||||||
Ghosting,
|
Ghosting,
|
||||||
CPUTime,
|
CPUTime,
|
||||||
Sleep,
|
Sleep,
|
||||||
Frame,
|
Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Metric
|
struct Metric
|
||||||
{
|
{
|
||||||
int64_t measurements[MAX_MEASURMENT_POINTS] = {};
|
int64_t measurements[MAX_MEASURMENT_POINTS] = {};
|
||||||
size_t measurementIndex = 0;
|
size_t measurementIndex = 0;
|
||||||
size_t measurementSize = 0;
|
size_t measurementSize = 0;
|
||||||
int64_t max = -1;
|
int64_t max = -1;
|
||||||
int64_t min = -1;
|
int64_t min = -1;
|
||||||
int64_t average = 0;
|
int64_t average = 0;
|
||||||
std::chrono::time_point<std::chrono::high_resolution_clock> activeMeasurement;
|
std::chrono::time_point<std::chrono::high_resolution_clock> activeMeasurement;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Metrics
|
class Metrics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
~Metrics();
|
~Metrics();
|
||||||
|
|
||||||
static void AddMeasurement(MetricVariable variable, int64_t value);
|
static void AddMeasurement(MetricVariable variable, int64_t value);
|
||||||
static void AddMeasurement(Metric* metric, int64_t value);
|
static void AddMeasurement(Metric* metric, int64_t value);
|
||||||
static const Metric* GetMetric(MetricVariable variable);
|
static const Metric* GetMetric(MetricVariable variable);
|
||||||
static void StartMeasurement(MetricVariable variable);
|
static void StartMeasurement(MetricVariable variable);
|
||||||
static void EndMeasurement(MetricVariable variable);
|
static void EndMeasurement(MetricVariable variable);
|
||||||
static float ToMiliseconds(int64_t nanoseconds);
|
static float ToMiliseconds(int64_t nanoseconds);
|
||||||
static std::string MetricVariableToString(MetricVariable variable);
|
static std::string MetricVariableToString(MetricVariable variable);
|
||||||
static const std::vector<MetricVariable>& GetAllMetrics();
|
static const std::vector<MetricVariable>& GetAllMetrics();
|
||||||
|
|
||||||
static size_t GetPeakRSS();
|
static size_t GetPeakRSS();
|
||||||
static size_t GetCurrentRSS();
|
static size_t GetCurrentRSS();
|
||||||
static size_t GetProcessID();
|
static size_t GetProcessID();
|
||||||
|
|
||||||
static void Clear();
|
static void Clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Metrics();
|
Metrics();
|
||||||
|
|
||||||
static std::unordered_map<MetricVariable, Metric*> m_Metrics;
|
static std::unordered_map<MetricVariable, Metric*> m_Metrics;
|
||||||
static std::vector<MetricVariable> m_Variables;
|
static std::vector<MetricVariable> m_Variables;
|
||||||
};
|
};
|
||||||
|
@ -13,23 +13,23 @@ const NiPoint3 NiPoint3::UNIT_ALL(1.0f, 1.0f, 1.0f);
|
|||||||
|
|
||||||
//! Initializer
|
//! Initializer
|
||||||
NiPoint3::NiPoint3(void) {
|
NiPoint3::NiPoint3(void) {
|
||||||
this->x = 0;
|
this->x = 0;
|
||||||
this->y = 0;
|
this->y = 0;
|
||||||
this->z = 0;
|
this->z = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Initializer
|
//! Initializer
|
||||||
NiPoint3::NiPoint3(float x, float y, float z) {
|
NiPoint3::NiPoint3(float x, float y, float z) {
|
||||||
this->x = x;
|
this->x = x;
|
||||||
this->y = y;
|
this->y = y;
|
||||||
this->z = z;
|
this->z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Copy Constructor
|
//! Copy Constructor
|
||||||
NiPoint3::NiPoint3(const NiPoint3& point) {
|
NiPoint3::NiPoint3(const NiPoint3& point) {
|
||||||
this->x = point.x;
|
this->x = point.x;
|
||||||
this->y = point.y;
|
this->y = point.y;
|
||||||
this->z = point.z;
|
this->z = point.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Destructor
|
//! Destructor
|
||||||
@ -39,63 +39,63 @@ NiPoint3::~NiPoint3(void) {}
|
|||||||
|
|
||||||
//! Gets the X coordinate
|
//! Gets the X coordinate
|
||||||
float NiPoint3::GetX(void) const {
|
float NiPoint3::GetX(void) const {
|
||||||
return this->x;
|
return this->x;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the X coordinate
|
//! Sets the X coordinate
|
||||||
void NiPoint3::SetX(float x) {
|
void NiPoint3::SetX(float x) {
|
||||||
this->x = x;
|
this->x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the Y coordinate
|
//! Gets the Y coordinate
|
||||||
float NiPoint3::GetY(void) const {
|
float NiPoint3::GetY(void) const {
|
||||||
return this->y;
|
return this->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the Y coordinate
|
//! Sets the Y coordinate
|
||||||
void NiPoint3::SetY(float y) {
|
void NiPoint3::SetY(float y) {
|
||||||
this->y = y;
|
this->y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the Z coordinate
|
//! Gets the Z coordinate
|
||||||
float NiPoint3::GetZ(void) const {
|
float NiPoint3::GetZ(void) const {
|
||||||
return this->z;
|
return this->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the Z coordinate
|
//! Sets the Z coordinate
|
||||||
void NiPoint3::SetZ(float z) {
|
void NiPoint3::SetZ(float z) {
|
||||||
this->z = z;
|
this->z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
//! Gets the length of the vector
|
//! Gets the length of the vector
|
||||||
float NiPoint3::Length(void) const {
|
float NiPoint3::Length(void) const {
|
||||||
return sqrt(x*x + y*y + z*z);
|
return sqrt(x * x + y * y + z * z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the squared length of a vector
|
//! Gets the squared length of a vector
|
||||||
float NiPoint3::SquaredLength(void) const {
|
float NiPoint3::SquaredLength(void) const {
|
||||||
return (x*x + y*y + z*z);
|
return (x * x + y * y + z * z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the dot product of the vector dotted with another vector
|
//! Returns the dot product of the vector dotted with another vector
|
||||||
float NiPoint3::DotProduct(const Vector3& vec) const {
|
float NiPoint3::DotProduct(const Vector3& vec) const {
|
||||||
return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z));
|
return ((this->x * vec.x) + (this->y * vec.y) + (this->z * vec.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the cross product of the vector crossed with another vector
|
//! Returns the cross product of the vector crossed with another vector
|
||||||
Vector3 NiPoint3::CrossProduct(const Vector3& vec) const {
|
Vector3 NiPoint3::CrossProduct(const Vector3& vec) const {
|
||||||
return Vector3(((this->y * vec.z) - (this->z * vec.y)),
|
return Vector3(((this->y * vec.z) - (this->z * vec.y)),
|
||||||
((this->z * vec.x) - (this->x * vec.z)),
|
((this->z * vec.x) - (this->x * vec.z)),
|
||||||
((this->x * vec.y) - (this->y * vec.x)));
|
((this->x * vec.y) - (this->y * vec.x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Unitize the vector
|
//! Unitize the vector
|
||||||
NiPoint3 NiPoint3::Unitize(void) const {
|
NiPoint3 NiPoint3::Unitize(void) const {
|
||||||
float length = this->Length();
|
float length = this->Length();
|
||||||
|
|
||||||
return length != 0 ? *this / length : NiPoint3::ZERO;
|
return length != 0 ? *this / length : NiPoint3::ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -103,57 +103,63 @@ NiPoint3 NiPoint3::Unitize(void) const {
|
|||||||
|
|
||||||
//! Operator to check for equality
|
//! Operator to check for equality
|
||||||
bool NiPoint3::operator==(const NiPoint3& point) const {
|
bool NiPoint3::operator==(const NiPoint3& point) const {
|
||||||
return point.x == this->x && point.y == this->y && point.z == this->z;
|
return point.x == this->x && point.y == this->y && point.z == this->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator to check for inequality
|
//! Operator to check for inequality
|
||||||
bool NiPoint3::operator!=(const NiPoint3& point) const {
|
bool NiPoint3::operator!=(const NiPoint3& point) const {
|
||||||
return !(*this == point);
|
return !(*this == point);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for subscripting
|
//! Operator for subscripting
|
||||||
float& NiPoint3::operator[](int i) {
|
float& NiPoint3::operator[](int i) {
|
||||||
float * base = &x;
|
float* base = &x;
|
||||||
return (float&)base[i];
|
return (float&)base[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for subscripting
|
//! Operator for subscripting
|
||||||
const float& NiPoint3::operator[](int i) const {
|
const float& NiPoint3::operator[](int i) const {
|
||||||
const float * base = &x;
|
const float* base = &x;
|
||||||
return (float&)base[i];
|
return (float&)base[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for addition of vectors
|
//! Operator for addition of vectors
|
||||||
NiPoint3 NiPoint3::operator+(const NiPoint3& point) const {
|
NiPoint3 NiPoint3::operator+(const NiPoint3& point) const {
|
||||||
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
|
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Operator for addition of vectors
|
||||||
|
NiPoint3 NiPoint3::operator+=(const NiPoint3& point) const {
|
||||||
|
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! Operator for subtraction of vectors
|
//! Operator for subtraction of vectors
|
||||||
NiPoint3 NiPoint3::operator-(const NiPoint3& point) const {
|
NiPoint3 NiPoint3::operator-(const NiPoint3& point) const {
|
||||||
return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z);
|
return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for addition of a scalar on all vector components
|
//! Operator for addition of a scalar on all vector components
|
||||||
NiPoint3 NiPoint3::operator+(float fScalar) const {
|
NiPoint3 NiPoint3::operator+(float fScalar) const {
|
||||||
return NiPoint3(this->x + fScalar, this->y + fScalar, this->z + fScalar);
|
return NiPoint3(this->x + fScalar, this->y + fScalar, this->z + fScalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for subtraction of a scalar on all vector components
|
//! Operator for subtraction of a scalar on all vector components
|
||||||
NiPoint3 NiPoint3::operator-(float fScalar) const {
|
NiPoint3 NiPoint3::operator-(float fScalar) const {
|
||||||
return NiPoint3(this->x - fScalar, this->y - fScalar, this->z - fScalar);
|
return NiPoint3(this->x - fScalar, this->y - fScalar, this->z - fScalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for scalar multiplication of a vector
|
//! Operator for scalar multiplication of a vector
|
||||||
NiPoint3 NiPoint3::operator*(float fScalar) const {
|
NiPoint3 NiPoint3::operator*(float fScalar) const {
|
||||||
return NiPoint3(this->x * fScalar, this->y * fScalar, this->z * fScalar);
|
return NiPoint3(this->x * fScalar, this->y * fScalar, this->z * fScalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator for scalar division of a vector
|
//! Operator for scalar division of a vector
|
||||||
NiPoint3 NiPoint3::operator/(float fScalar) const {
|
NiPoint3 NiPoint3::operator/(float fScalar) const {
|
||||||
float retX = this->x != 0 ? this->x / fScalar : 0;
|
float retX = this->x != 0 ? this->x / fScalar : 0;
|
||||||
float retY = this->y != 0 ? this->y / fScalar : 0;
|
float retY = this->y != 0 ? this->y / fScalar : 0;
|
||||||
float retZ = this->z != 0 ? this->z / fScalar : 0;
|
float retZ = this->z != 0 ? this->z / fScalar : 0;
|
||||||
return NiPoint3(retX, retY, retZ);
|
return NiPoint3(retX, retY, retZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -161,96 +167,91 @@ NiPoint3 NiPoint3::operator/(float fScalar) const {
|
|||||||
|
|
||||||
//! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box
|
//! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box
|
||||||
bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) {
|
bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint) {
|
||||||
if (this->x < minPoint.x) return false;
|
if (this->x < minPoint.x) return false;
|
||||||
if (this->x > maxPoint.x) return false;
|
if (this->x > maxPoint.x) return false;
|
||||||
if (this->y < minPoint.y) return false;
|
if (this->y < minPoint.y) return false;
|
||||||
if (this->y > maxPoint.y) return false;
|
if (this->y > maxPoint.y) return false;
|
||||||
|
|
||||||
return (this->z < maxPoint.z && this->z > minPoint.z);
|
return (this->z < maxPoint.z&& this->z > minPoint.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Checks to see if the point (or vector) is within a sphere
|
//! Checks to see if the point (or vector) is within a sphere
|
||||||
bool NiPoint3::IsWithinSpehere(const NiPoint3& sphereCenter, float radius) {
|
bool NiPoint3::IsWithinSpehere(const NiPoint3& sphereCenter, float radius) {
|
||||||
Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ());
|
Vector3 diffVec = Vector3(x - sphereCenter.GetX(), y - sphereCenter.GetY(), z - sphereCenter.GetZ());
|
||||||
return (diffVec.SquaredLength() <= (radius * radius));
|
return (diffVec.SquaredLength() <= (radius * radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p)
|
NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p) {
|
||||||
{
|
if (a == b) return a;
|
||||||
if (a == b) return a;
|
|
||||||
|
|
||||||
const auto pa = p - a;
|
const auto pa = p - a;
|
||||||
const auto ab = b - a;
|
const auto ab = b - a;
|
||||||
|
|
||||||
const auto t = pa.DotProduct(ab) / ab.SquaredLength();
|
const auto t = pa.DotProduct(ab) / ab.SquaredLength();
|
||||||
|
|
||||||
if (t <= 0.0f) return a;
|
if (t <= 0.0f) return a;
|
||||||
|
|
||||||
if (t >= 1.0f) return b;
|
if (t >= 1.0f) return b;
|
||||||
|
|
||||||
return a + ab * t;
|
return a + ab * t;
|
||||||
}
|
}
|
||||||
|
|
||||||
float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b)
|
float NiPoint3::Angle(const NiPoint3& a, const NiPoint3& b) {
|
||||||
{
|
const auto dot = a.DotProduct(b);
|
||||||
const auto dot = a.DotProduct(b);
|
const auto lenA = a.SquaredLength();
|
||||||
const auto lenA = a.SquaredLength();
|
const auto lenB = a.SquaredLength();
|
||||||
const auto lenB = a.SquaredLength();
|
return acos(dot / sqrt(lenA * lenB));
|
||||||
return acos(dot / sqrt(lenA * lenB));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b)
|
float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b) {
|
||||||
{
|
const auto dx = a.x - b.x;
|
||||||
const auto dx = a.x - b.x;
|
const auto dy = a.y - b.y;
|
||||||
const auto dy = a.y - b.y;
|
const auto dz = a.z - b.z;
|
||||||
const auto dz = a.z - b.z;
|
|
||||||
|
|
||||||
return std::sqrt(dx * dx + dy * dy + dz * dz);
|
return std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
}
|
}
|
||||||
|
|
||||||
float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b)
|
float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b) {
|
||||||
{
|
const auto dx = a.x - b.x;
|
||||||
const auto dx = a.x - b.x;
|
const auto dy = a.y - b.y;
|
||||||
const auto dy = a.y - b.y;
|
const auto dz = a.z - b.z;
|
||||||
const auto dz = a.z - b.z;
|
|
||||||
|
|
||||||
return dx * dx + dy * dy + dz * dz;
|
return dx * dx + dy * dy + dz * dz;
|
||||||
}
|
}
|
||||||
|
|
||||||
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta)
|
NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta) {
|
||||||
{
|
float dx = target.x - current.x;
|
||||||
float dx = target.x - current.x;
|
float dy = target.y - current.y;
|
||||||
float dy = target.y - current.y;
|
float dz = target.z - current.z;
|
||||||
float dz = target.z - current.z;
|
float lengthSquared = (float)((double)dx * (double)dx + (double)dy * (double)dy + (double)dz * (double)dz);
|
||||||
float lengthSquared = (float) ((double) dx * (double) dx + (double) dy * (double) dy + (double) dz * (double) dz);
|
if ((double)lengthSquared == 0.0 || (double)maxDistanceDelta >= 0.0 && (double)lengthSquared <= (double)maxDistanceDelta * (double)maxDistanceDelta)
|
||||||
if ((double) lengthSquared == 0.0 || (double) maxDistanceDelta >= 0.0 && (double) lengthSquared <= (double) maxDistanceDelta * (double) maxDistanceDelta)
|
return target;
|
||||||
return target;
|
float length = (float)std::sqrt((double)lengthSquared);
|
||||||
float length = (float) std::sqrt((double) lengthSquared);
|
return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta);
|
||||||
return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible.
|
//This code is yoinked from the MS XNA code, so it should be right, even if it's horrible.
|
||||||
NiPoint3 NiPoint3::RotateByQuaternion(const NiQuaternion& rotation) {
|
NiPoint3 NiPoint3::RotateByQuaternion(const NiQuaternion& rotation) {
|
||||||
Vector3 vector;
|
Vector3 vector;
|
||||||
float num12 = rotation.x + rotation.x;
|
float num12 = rotation.x + rotation.x;
|
||||||
float num2 = rotation.y + rotation.y;
|
float num2 = rotation.y + rotation.y;
|
||||||
float num = rotation.z + rotation.z;
|
float num = rotation.z + rotation.z;
|
||||||
float num11 = rotation.w * num12;
|
float num11 = rotation.w * num12;
|
||||||
float num10 = rotation.w * num2;
|
float num10 = rotation.w * num2;
|
||||||
float num9 = rotation.w * num;
|
float num9 = rotation.w * num;
|
||||||
float num8 = rotation.x * num12;
|
float num8 = rotation.x * num12;
|
||||||
float num7 = rotation.x * num2;
|
float num7 = rotation.x * num2;
|
||||||
float num6 = rotation.x * num;
|
float num6 = rotation.x * num;
|
||||||
float num5 = rotation.y * num2;
|
float num5 = rotation.y * num2;
|
||||||
float num4 = rotation.y * num;
|
float num4 = rotation.y * num;
|
||||||
float num3 = rotation.z * num;
|
float num3 = rotation.z * num;
|
||||||
|
|
||||||
NiPoint3 value = *this;
|
NiPoint3 value = *this;
|
||||||
float num15 = ((value.x * ((1.0f - num5) - num3)) + (value.y * (num7 - num9))) + (value.z * (num6 + num10));
|
float num15 = ((value.x * ((1.0f - num5) - num3)) + (value.y * (num7 - num9))) + (value.z * (num6 + num10));
|
||||||
float num14 = ((value.x * (num7 + num9)) + (value.y * ((1.0f - num8) - num3))) + (value.z * (num4 - num11));
|
float num14 = ((value.x * (num7 + num9)) + (value.y * ((1.0f - num8) - num3))) + (value.z * (num4 - num11));
|
||||||
float num13 = ((value.x * (num6 - num10)) + (value.y * (num4 + num11))) + (value.z * ((1.0f - num8) - num5));
|
float num13 = ((value.x * (num6 - num10)) + (value.y * (num4 + num11))) + (value.z * ((1.0f - num8) - num5));
|
||||||
vector.x = num15;
|
vector.x = num15;
|
||||||
vector.y = num14;
|
vector.y = num14;
|
||||||
vector.z = num13;
|
vector.z = num13;
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
@ -12,177 +12,180 @@ typedef NiPoint3 Vector3; //!< The Vector3 class is technically the NiPoin
|
|||||||
//! A custom class the defines a point in space
|
//! A custom class the defines a point in space
|
||||||
class NiPoint3 {
|
class NiPoint3 {
|
||||||
public:
|
public:
|
||||||
float x; //!< The x position
|
float x; //!< The x position
|
||||||
float y; //!< The y position
|
float y; //!< The y position
|
||||||
float z; //!< The z position
|
float z; //!< The z position
|
||||||
|
|
||||||
|
|
||||||
//! Initializer
|
//! Initializer
|
||||||
NiPoint3(void);
|
NiPoint3(void);
|
||||||
|
|
||||||
//! Initializer
|
//! Initializer
|
||||||
/*!
|
/*!
|
||||||
\param x The x coordinate
|
\param x The x coordinate
|
||||||
\param y The y coordinate
|
\param y The y coordinate
|
||||||
\param z The z coordinate
|
\param z The z coordinate
|
||||||
*/
|
*/
|
||||||
NiPoint3(float x, float y, float z);
|
NiPoint3(float x, float y, float z);
|
||||||
|
|
||||||
//! Copy Constructor
|
//! Copy Constructor
|
||||||
/*!
|
/*!
|
||||||
\param point The point to copy
|
\param point The point to copy
|
||||||
*/
|
*/
|
||||||
NiPoint3(const NiPoint3& point);
|
NiPoint3(const NiPoint3& point);
|
||||||
|
|
||||||
//! Destructor
|
//! Destructor
|
||||||
~NiPoint3(void);
|
~NiPoint3(void);
|
||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
static const NiPoint3 ZERO; //!< Point(0, 0, 0)
|
static const NiPoint3 ZERO; //!< Point(0, 0, 0)
|
||||||
static const NiPoint3 UNIT_X; //!< Point(1, 0, 0)
|
static const NiPoint3 UNIT_X; //!< Point(1, 0, 0)
|
||||||
static const NiPoint3 UNIT_Y; //!< Point(0, 1, 0)
|
static const NiPoint3 UNIT_Y; //!< Point(0, 1, 0)
|
||||||
static const NiPoint3 UNIT_Z; //!< Point(0, 0, 1)
|
static const NiPoint3 UNIT_Z; //!< Point(0, 0, 1)
|
||||||
static const NiPoint3 UNIT_ALL; //!< Point(1, 1, 1)
|
static const NiPoint3 UNIT_ALL; //!< Point(1, 1, 1)
|
||||||
|
|
||||||
// MARK: Getters / Setters
|
// MARK: Getters / Setters
|
||||||
|
|
||||||
//! Gets the X coordinate
|
//! Gets the X coordinate
|
||||||
/*!
|
/*!
|
||||||
\return The x coordinate
|
\return The x coordinate
|
||||||
*/
|
*/
|
||||||
float GetX(void) const;
|
float GetX(void) const;
|
||||||
|
|
||||||
//! Sets the X coordinate
|
//! Sets the X coordinate
|
||||||
/*!
|
/*!
|
||||||
\param x The x coordinate
|
\param x The x coordinate
|
||||||
*/
|
*/
|
||||||
void SetX(float x);
|
void SetX(float x);
|
||||||
|
|
||||||
//! Gets the Y coordinate
|
//! Gets the Y coordinate
|
||||||
/*!
|
/*!
|
||||||
\return The y coordinate
|
\return The y coordinate
|
||||||
*/
|
*/
|
||||||
float GetY(void) const;
|
float GetY(void) const;
|
||||||
|
|
||||||
//! Sets the Y coordinate
|
//! Sets the Y coordinate
|
||||||
/*!
|
/*!
|
||||||
\param y The y coordinate
|
\param y The y coordinate
|
||||||
*/
|
*/
|
||||||
void SetY(float y);
|
void SetY(float y);
|
||||||
|
|
||||||
//! Gets the Z coordinate
|
//! Gets the Z coordinate
|
||||||
/*!
|
/*!
|
||||||
\return The z coordinate
|
\return The z coordinate
|
||||||
*/
|
*/
|
||||||
float GetZ(void) const;
|
float GetZ(void) const;
|
||||||
|
|
||||||
//! Sets the Z coordinate
|
//! Sets the Z coordinate
|
||||||
/*!
|
/*!
|
||||||
\param z The z coordinate
|
\param z The z coordinate
|
||||||
*/
|
*/
|
||||||
void SetZ(float z);
|
void SetZ(float z);
|
||||||
|
|
||||||
|
|
||||||
// MARK: Member Functions
|
// MARK: Member Functions
|
||||||
|
|
||||||
//! Gets the length of the vector
|
//! Gets the length of the vector
|
||||||
/*!
|
/*!
|
||||||
\return The scalar length of the vector
|
\return The scalar length of the vector
|
||||||
*/
|
*/
|
||||||
float Length(void) const;
|
float Length(void) const;
|
||||||
|
|
||||||
//! Gets the squared length of a vector
|
//! Gets the squared length of a vector
|
||||||
/*!
|
/*!
|
||||||
\return The squared length of a vector
|
\return The squared length of a vector
|
||||||
*/
|
*/
|
||||||
float SquaredLength(void) const;
|
float SquaredLength(void) const;
|
||||||
|
|
||||||
//! Returns the dot product of the vector dotted with another vector
|
//! Returns the dot product of the vector dotted with another vector
|
||||||
/*!
|
/*!
|
||||||
\param vec The second vector
|
\param vec The second vector
|
||||||
\return The dot product of the two vectors
|
\return The dot product of the two vectors
|
||||||
*/
|
*/
|
||||||
float DotProduct(const Vector3& vec) const;
|
float DotProduct(const Vector3& vec) const;
|
||||||
|
|
||||||
//! Returns the cross product of the vector crossed with another vector
|
//! Returns the cross product of the vector crossed with another vector
|
||||||
/*!
|
/*!
|
||||||
\param vec The second vector
|
\param vec The second vector
|
||||||
\return The cross product of the two vectors
|
\return The cross product of the two vectors
|
||||||
*/
|
*/
|
||||||
Vector3 CrossProduct(const Vector3& vec) const;
|
Vector3 CrossProduct(const Vector3& vec) const;
|
||||||
|
|
||||||
//! Unitize the vector
|
//! Unitize the vector
|
||||||
/*!
|
/*!
|
||||||
\returns The current vector
|
\returns The current vector
|
||||||
*/
|
*/
|
||||||
NiPoint3 Unitize(void) const;
|
NiPoint3 Unitize(void) const;
|
||||||
|
|
||||||
|
|
||||||
// MARK: Operators
|
// MARK: Operators
|
||||||
|
|
||||||
//! Operator to check for equality
|
//! Operator to check for equality
|
||||||
bool operator==(const NiPoint3& point) const;
|
bool operator==(const NiPoint3& point) const;
|
||||||
|
|
||||||
//! Operator to check for inequality
|
//! Operator to check for inequality
|
||||||
bool operator!=(const NiPoint3& point) const;
|
bool operator!=(const NiPoint3& point) const;
|
||||||
|
|
||||||
//! Operator for subscripting
|
//! Operator for subscripting
|
||||||
float& operator[](int i);
|
float& operator[](int i);
|
||||||
|
|
||||||
//! Operator for subscripting
|
//! Operator for subscripting
|
||||||
const float& operator[](int i) const;
|
const float& operator[](int i) const;
|
||||||
|
|
||||||
//! Operator for addition of vectors
|
//! Operator for addition of vectors
|
||||||
NiPoint3 operator+(const NiPoint3& point) const;
|
NiPoint3 operator+(const NiPoint3& point) const;
|
||||||
|
|
||||||
//! Operator for subtraction of vectors
|
//! Operator for addition of vectors
|
||||||
NiPoint3 operator-(const NiPoint3& point) const;
|
NiPoint3 operator+=(const NiPoint3& point) const;
|
||||||
|
|
||||||
//! Operator for addition of a scalar on all vector components
|
//! Operator for subtraction of vectors
|
||||||
NiPoint3 operator+(float fScalar) const;
|
NiPoint3 operator-(const NiPoint3& point) const;
|
||||||
|
|
||||||
//! Operator for subtraction of a scalar on all vector components
|
//! Operator for addition of a scalar on all vector components
|
||||||
NiPoint3 operator-(float fScalar) const;
|
NiPoint3 operator+(float fScalar) const;
|
||||||
|
|
||||||
//! Operator for scalar multiplication of a vector
|
//! Operator for subtraction of a scalar on all vector components
|
||||||
NiPoint3 operator*(float fScalar) const;
|
NiPoint3 operator-(float fScalar) const;
|
||||||
|
|
||||||
//! Operator for scalar division of a vector
|
//! Operator for scalar multiplication of a vector
|
||||||
NiPoint3 operator/(float fScalar) const;
|
NiPoint3 operator*(float fScalar) const;
|
||||||
|
|
||||||
|
//! Operator for scalar division of a vector
|
||||||
|
NiPoint3 operator/(float fScalar) const;
|
||||||
|
|
||||||
|
|
||||||
// MARK: Helper Functions
|
// MARK: Helper Functions
|
||||||
|
|
||||||
//! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box
|
//! Checks to see if the point (or vector) is with an Axis-Aligned Bounding Box
|
||||||
/*!
|
/*!
|
||||||
\param minPoint The minimum point of the bounding box
|
\param minPoint The minimum point of the bounding box
|
||||||
\param maxPoint The maximum point of the bounding box
|
\param maxPoint The maximum point of the bounding box
|
||||||
\return Whether or not this point lies within the box
|
\return Whether or not this point lies within the box
|
||||||
*/
|
*/
|
||||||
bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint);
|
bool IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3& maxPoint);
|
||||||
|
|
||||||
//! Checks to see if the point (or vector) is within a sphere
|
//! Checks to see if the point (or vector) is within a sphere
|
||||||
/*!
|
/*!
|
||||||
\param sphereCenter The sphere center
|
\param sphereCenter The sphere center
|
||||||
\param radius The radius
|
\param radius The radius
|
||||||
*/
|
*/
|
||||||
bool IsWithinSpehere(const NiPoint3& sphereCenter, float radius);
|
bool IsWithinSpehere(const NiPoint3& sphereCenter, float radius);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\param a Start of line
|
\param a Start of line
|
||||||
\param b End of line
|
\param b End of line
|
||||||
\param p Refrence point
|
\param p Refrence point
|
||||||
\return The point of line AB which is closest to P
|
\return The point of line AB which is closest to P
|
||||||
*/
|
*/
|
||||||
static NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p);
|
static NiPoint3 ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, const NiPoint3& p);
|
||||||
|
|
||||||
static float Angle(const NiPoint3& a, const NiPoint3& b);
|
static float Angle(const NiPoint3& a, const NiPoint3& b);
|
||||||
|
|
||||||
static float Distance(const NiPoint3& a, const NiPoint3& b);
|
static float Distance(const NiPoint3& a, const NiPoint3& b);
|
||||||
|
|
||||||
static float DistanceSquared(const NiPoint3& a, const NiPoint3& b);
|
static float DistanceSquared(const NiPoint3& a, const NiPoint3& b);
|
||||||
|
|
||||||
static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta);
|
static NiPoint3 MoveTowards(const NiPoint3& current, const NiPoint3& target, float maxDistanceDelta);
|
||||||
|
|
||||||
NiPoint3 RotateByQuaternion(const NiQuaternion& rotation);
|
NiPoint3 RotateByQuaternion(const NiQuaternion& rotation);
|
||||||
};
|
};
|
||||||
|
@ -8,18 +8,18 @@ const NiQuaternion NiQuaternion::IDENTITY(1, 0, 0, 0);
|
|||||||
|
|
||||||
//! The initializer
|
//! The initializer
|
||||||
NiQuaternion::NiQuaternion(void) {
|
NiQuaternion::NiQuaternion(void) {
|
||||||
this->w = 1;
|
this->w = 1;
|
||||||
this->x = 0;
|
this->x = 0;
|
||||||
this->y = 0;
|
this->y = 0;
|
||||||
this->z = 0;
|
this->z = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! The initializer
|
//! The initializer
|
||||||
NiQuaternion::NiQuaternion(float w, float x, float y, float z) {
|
NiQuaternion::NiQuaternion(float w, float x, float y, float z) {
|
||||||
this->w = w;
|
this->w = w;
|
||||||
this->x = x;
|
this->x = x;
|
||||||
this->y = y;
|
this->y = y;
|
||||||
this->z = z;
|
this->z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Destructor
|
//! Destructor
|
||||||
@ -30,42 +30,42 @@ NiQuaternion::~NiQuaternion(void) {}
|
|||||||
|
|
||||||
//! Gets the W coordinate
|
//! Gets the W coordinate
|
||||||
float NiQuaternion::GetW(void) const {
|
float NiQuaternion::GetW(void) const {
|
||||||
return this->w;
|
return this->w;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the W coordinate
|
//! Sets the W coordinate
|
||||||
void NiQuaternion::SetW(float w) {
|
void NiQuaternion::SetW(float w) {
|
||||||
this->w = w;
|
this->w = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the X coordinate
|
//! Gets the X coordinate
|
||||||
float NiQuaternion::GetX(void) const {
|
float NiQuaternion::GetX(void) const {
|
||||||
return this->x;
|
return this->x;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the X coordinate
|
//! Sets the X coordinate
|
||||||
void NiQuaternion::SetX(float x) {
|
void NiQuaternion::SetX(float x) {
|
||||||
this->x = x;
|
this->x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the Y coordinate
|
//! Gets the Y coordinate
|
||||||
float NiQuaternion::GetY(void) const {
|
float NiQuaternion::GetY(void) const {
|
||||||
return this->y;
|
return this->y;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the Y coordinate
|
//! Sets the Y coordinate
|
||||||
void NiQuaternion::SetY(float y) {
|
void NiQuaternion::SetY(float y) {
|
||||||
this->y = y;
|
this->y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Gets the Z coordinate
|
//! Gets the Z coordinate
|
||||||
float NiQuaternion::GetZ(void) const {
|
float NiQuaternion::GetZ(void) const {
|
||||||
return this->z;
|
return this->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the Z coordinate
|
//! Sets the Z coordinate
|
||||||
void NiQuaternion::SetZ(float z) {
|
void NiQuaternion::SetZ(float z) {
|
||||||
this->z = z;
|
this->z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,55 +73,54 @@ void NiQuaternion::SetZ(float z) {
|
|||||||
|
|
||||||
//! Returns the forward vector from the quaternion
|
//! Returns the forward vector from the quaternion
|
||||||
Vector3 NiQuaternion::GetForwardVector(void) const {
|
Vector3 NiQuaternion::GetForwardVector(void) const {
|
||||||
return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
|
return Vector3(2 * (x * z + w * y), 2 * (y * z - w * x), 1 - 2 * (x * x + y * y));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the up vector from the quaternion
|
//! Returns the up vector from the quaternion
|
||||||
Vector3 NiQuaternion::GetUpVector(void) const {
|
Vector3 NiQuaternion::GetUpVector(void) const {
|
||||||
return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
|
return Vector3(2 * (x * y - w * z), 1 - 2 * (x * x + z * z), 2 * (y * z + w * x));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the right vector from the quaternion
|
//! Returns the right vector from the quaternion
|
||||||
Vector3 NiQuaternion::GetRightVector(void) const {
|
Vector3 NiQuaternion::GetRightVector(void) const {
|
||||||
return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
|
return Vector3(1 - 2 * (y * y + z * z), 2 * (x * y + w * z), 2 * (x * z - w * y));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 NiQuaternion::GetEulerAngles() const {
|
Vector3 NiQuaternion::GetEulerAngles() const {
|
||||||
Vector3 angles;
|
Vector3 angles;
|
||||||
|
|
||||||
// roll (x-axis rotation)
|
// roll (x-axis rotation)
|
||||||
const float sinr_cosp = 2 * (w * x + y * z);
|
const float sinr_cosp = 2 * (w * x + y * z);
|
||||||
const float cosr_cosp = 1 - 2 * (x * x + y * y);
|
const float cosr_cosp = 1 - 2 * (x * x + y * y);
|
||||||
angles.x = std::atan2(sinr_cosp, cosr_cosp);
|
angles.x = std::atan2(sinr_cosp, cosr_cosp);
|
||||||
|
|
||||||
// pitch (y-axis rotation)
|
// pitch (y-axis rotation)
|
||||||
const float sinp = 2 * (w * y - z * x);
|
const float sinp = 2 * (w * y - z * x);
|
||||||
|
|
||||||
if (std::abs(sinp) >= 1) {
|
if (std::abs(sinp) >= 1) {
|
||||||
angles.y = std::copysign(3.14 / 2, sinp); // use 90 degrees if out of range
|
angles.y = std::copysign(3.14 / 2, sinp); // use 90 degrees if out of range
|
||||||
}
|
} else {
|
||||||
else {
|
angles.y = std::asin(sinp);
|
||||||
angles.y = std::asin(sinp);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// yaw (z-axis rotation)
|
// yaw (z-axis rotation)
|
||||||
const float siny_cosp = 2 * (w * z + x * y);
|
const float siny_cosp = 2 * (w * z + x * y);
|
||||||
const float cosy_cosp = 1 - 2 * (y * y + z * z);
|
const float cosy_cosp = 1 - 2 * (y * y + z * z);
|
||||||
angles.z = std::atan2(siny_cosp, cosy_cosp);
|
angles.z = std::atan2(siny_cosp, cosy_cosp);
|
||||||
|
|
||||||
return angles;
|
return angles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Operators
|
// MARK: Operators
|
||||||
|
|
||||||
//! Operator to check for equality
|
//! Operator to check for equality
|
||||||
bool NiQuaternion::operator==(const NiQuaternion& rot) const {
|
bool NiQuaternion::operator==(const NiQuaternion& rot) const {
|
||||||
return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w;
|
return rot.x == this->x && rot.y == this->y && rot.z == this->z && rot.w == this->w;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Operator to check for inequality
|
//! Operator to check for inequality
|
||||||
bool NiQuaternion::operator!=(const NiQuaternion& rot) const {
|
bool NiQuaternion::operator!=(const NiQuaternion& rot) const {
|
||||||
return !(*this == rot);
|
return !(*this == rot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -135,65 +134,63 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
|
|||||||
source.y = 0.0f;
|
source.y = 0.0f;
|
||||||
dest.y = 0.0f;
|
dest.y = 0.0f;
|
||||||
|
|
||||||
NiPoint3 forwardVector = NiPoint3(dest - source).Unitize();
|
NiPoint3 forwardVector = NiPoint3(dest - source).Unitize();
|
||||||
|
|
||||||
NiPoint3 posZ = NiPoint3::UNIT_Z;
|
NiPoint3 posZ = NiPoint3::UNIT_Z;
|
||||||
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
|
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
|
||||||
|
|
||||||
float dot = posZ.DotProduct(forwardVector);
|
float dot = posZ.DotProduct(forwardVector);
|
||||||
float rotAngle = static_cast<float>(acos(dot));
|
float rotAngle = static_cast<float>(acos(dot));
|
||||||
|
|
||||||
NiPoint3 vecB = vecA.CrossProduct(posZ);
|
NiPoint3 vecB = vecA.CrossProduct(posZ);
|
||||||
|
|
||||||
if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle;
|
if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle;
|
||||||
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
|
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint)
|
NiQuaternion NiQuaternion::LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint) {
|
||||||
{
|
NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize();
|
||||||
NiPoint3 forwardVector = NiPoint3(destPoint - sourcePoint).Unitize();
|
|
||||||
|
|
||||||
NiPoint3 posZ = NiPoint3::UNIT_Z;
|
NiPoint3 posZ = NiPoint3::UNIT_Z;
|
||||||
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
|
NiPoint3 vecA = posZ.CrossProduct(forwardVector).Unitize();
|
||||||
|
|
||||||
float dot = posZ.DotProduct(forwardVector);
|
float dot = posZ.DotProduct(forwardVector);
|
||||||
float rotAngle = static_cast<float>(acos(dot));
|
float rotAngle = static_cast<float>(acos(dot));
|
||||||
|
|
||||||
NiPoint3 vecB = vecA.CrossProduct(posZ);
|
NiPoint3 vecB = vecA.CrossProduct(posZ);
|
||||||
|
|
||||||
if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle;
|
if (vecB.DotProduct(forwardVector) < 0) rotAngle = -rotAngle;
|
||||||
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
|
return NiQuaternion::CreateFromAxisAngle(vecA, rotAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Creates a Quaternion from a specific axis and angle relative to that axis
|
//! Creates a Quaternion from a specific axis and angle relative to that axis
|
||||||
NiQuaternion NiQuaternion::CreateFromAxisAngle(const Vector3& axis, float angle) {
|
NiQuaternion NiQuaternion::CreateFromAxisAngle(const Vector3& axis, float angle) {
|
||||||
float halfAngle = angle * 0.5f;
|
float halfAngle = angle * 0.5f;
|
||||||
float s = static_cast<float>(sin(halfAngle));
|
float s = static_cast<float>(sin(halfAngle));
|
||||||
|
|
||||||
NiQuaternion q;
|
NiQuaternion q;
|
||||||
q.x = axis.GetX() * s;
|
q.x = axis.GetX() * s;
|
||||||
q.y = axis.GetY() * s;
|
q.y = axis.GetY() * s;
|
||||||
q.z = axis.GetZ() * s;
|
q.z = axis.GetZ() * s;
|
||||||
q.w = static_cast<float>(cos(halfAngle));
|
q.w = static_cast<float>(cos(halfAngle));
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
NiQuaternion NiQuaternion::FromEulerAngles(const NiPoint3& eulerAngles)
|
NiQuaternion NiQuaternion::FromEulerAngles(const NiPoint3& eulerAngles) {
|
||||||
{
|
// Abbreviations for the various angular functions
|
||||||
// Abbreviations for the various angular functions
|
float cy = cos(eulerAngles.z * 0.5);
|
||||||
float cy = cos(eulerAngles.z * 0.5);
|
float sy = sin(eulerAngles.z * 0.5);
|
||||||
float sy = sin(eulerAngles.z * 0.5);
|
float cp = cos(eulerAngles.y * 0.5);
|
||||||
float cp = cos(eulerAngles.y * 0.5);
|
float sp = sin(eulerAngles.y * 0.5);
|
||||||
float sp = sin(eulerAngles.y * 0.5);
|
float cr = cos(eulerAngles.x * 0.5);
|
||||||
float cr = cos(eulerAngles.x * 0.5);
|
float sr = sin(eulerAngles.x * 0.5);
|
||||||
float sr = sin(eulerAngles.x * 0.5);
|
|
||||||
|
|
||||||
NiQuaternion q;
|
NiQuaternion q;
|
||||||
q.w = cr * cp * cy + sr * sp * sy;
|
q.w = cr * cp * cy + sr * sp * sy;
|
||||||
q.x = sr * cp * cy - cr * sp * sy;
|
q.x = sr * cp * cy - cr * sp * sy;
|
||||||
q.y = cr * sp * cy + sr * cp * sy;
|
q.y = cr * sp * cy + sr * cp * sy;
|
||||||
q.z = cr * cp * sy - sr * sp * cy;
|
q.z = cr * cp * sy - sr * sp * cy;
|
||||||
|
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
@ -14,138 +14,138 @@ typedef NiQuaternion Quaternion; //!< A typedef for a shorthand version o
|
|||||||
//! A class that defines a rotation in space
|
//! A class that defines a rotation in space
|
||||||
class NiQuaternion {
|
class NiQuaternion {
|
||||||
public:
|
public:
|
||||||
float w; //!< The w coordinate
|
float w; //!< The w coordinate
|
||||||
float x; //!< The x coordinate
|
float x; //!< The x coordinate
|
||||||
float y; //!< The y coordinate
|
float y; //!< The y coordinate
|
||||||
float z; //!< The z coordinate
|
float z; //!< The z coordinate
|
||||||
|
|
||||||
|
|
||||||
//! The initializer
|
//! The initializer
|
||||||
NiQuaternion(void);
|
NiQuaternion(void);
|
||||||
|
|
||||||
//! The initializer
|
//! The initializer
|
||||||
/*!
|
/*!
|
||||||
\param w The w coordinate
|
\param w The w coordinate
|
||||||
\param x The x coordinate
|
\param x The x coordinate
|
||||||
\param y The y coordinate
|
\param y The y coordinate
|
||||||
\param z The z coordinate
|
\param z The z coordinate
|
||||||
*/
|
*/
|
||||||
NiQuaternion(float w, float x, float y, float z);
|
NiQuaternion(float w, float x, float y, float z);
|
||||||
|
|
||||||
//! Destructor
|
//! Destructor
|
||||||
~NiQuaternion(void);
|
~NiQuaternion(void);
|
||||||
|
|
||||||
// MARK: Constants
|
// MARK: Constants
|
||||||
static const NiQuaternion IDENTITY; //!< Quaternion(1, 0, 0, 0)
|
static const NiQuaternion IDENTITY; //!< Quaternion(1, 0, 0, 0)
|
||||||
|
|
||||||
// MARK: Setters / Getters
|
// MARK: Setters / Getters
|
||||||
|
|
||||||
//! Gets the W coordinate
|
//! Gets the W coordinate
|
||||||
/*!
|
/*!
|
||||||
\return The w coordinate
|
\return The w coordinate
|
||||||
*/
|
*/
|
||||||
float GetW(void) const;
|
float GetW(void) const;
|
||||||
|
|
||||||
//! Sets the W coordinate
|
//! Sets the W coordinate
|
||||||
/*!
|
/*!
|
||||||
\param w The w coordinate
|
\param w The w coordinate
|
||||||
*/
|
*/
|
||||||
void SetW(float w);
|
void SetW(float w);
|
||||||
|
|
||||||
//! Gets the X coordinate
|
//! Gets the X coordinate
|
||||||
/*!
|
/*!
|
||||||
\return The x coordinate
|
\return The x coordinate
|
||||||
*/
|
*/
|
||||||
float GetX(void) const;
|
float GetX(void) const;
|
||||||
|
|
||||||
//! Sets the X coordinate
|
//! Sets the X coordinate
|
||||||
/*!
|
/*!
|
||||||
\param x The x coordinate
|
\param x The x coordinate
|
||||||
*/
|
*/
|
||||||
void SetX(float x);
|
void SetX(float x);
|
||||||
|
|
||||||
//! Gets the Y coordinate
|
//! Gets the Y coordinate
|
||||||
/*!
|
/*!
|
||||||
\return The y coordinate
|
\return The y coordinate
|
||||||
*/
|
*/
|
||||||
float GetY(void) const;
|
float GetY(void) const;
|
||||||
|
|
||||||
//! Sets the Y coordinate
|
//! Sets the Y coordinate
|
||||||
/*!
|
/*!
|
||||||
\param y The y coordinate
|
\param y The y coordinate
|
||||||
*/
|
*/
|
||||||
void SetY(float y);
|
void SetY(float y);
|
||||||
|
|
||||||
//! Gets the Z coordinate
|
//! Gets the Z coordinate
|
||||||
/*!
|
/*!
|
||||||
\return The z coordinate
|
\return The z coordinate
|
||||||
*/
|
*/
|
||||||
float GetZ(void) const;
|
float GetZ(void) const;
|
||||||
|
|
||||||
//! Sets the Z coordinate
|
//! Sets the Z coordinate
|
||||||
/*!
|
/*!
|
||||||
\param z The z coordinate
|
\param z The z coordinate
|
||||||
*/
|
*/
|
||||||
void SetZ(float z);
|
void SetZ(float z);
|
||||||
|
|
||||||
|
|
||||||
// MARK: Member Functions
|
// MARK: Member Functions
|
||||||
|
|
||||||
//! Returns the forward vector from the quaternion
|
//! Returns the forward vector from the quaternion
|
||||||
/*!
|
/*!
|
||||||
\return The forward vector of the quaternion
|
\return The forward vector of the quaternion
|
||||||
*/
|
*/
|
||||||
Vector3 GetForwardVector(void) const;
|
Vector3 GetForwardVector(void) const;
|
||||||
|
|
||||||
//! Returns the up vector from the quaternion
|
//! Returns the up vector from the quaternion
|
||||||
/*!
|
/*!
|
||||||
\return The up vector fo the quaternion
|
\return The up vector fo the quaternion
|
||||||
*/
|
*/
|
||||||
Vector3 GetUpVector(void) const;
|
Vector3 GetUpVector(void) const;
|
||||||
|
|
||||||
//! Returns the right vector from the quaternion
|
//! Returns the right vector from the quaternion
|
||||||
/*!
|
/*!
|
||||||
\return The right vector of the quaternion
|
\return The right vector of the quaternion
|
||||||
*/
|
*/
|
||||||
Vector3 GetRightVector(void) const;
|
Vector3 GetRightVector(void) const;
|
||||||
|
|
||||||
Vector3 GetEulerAngles() const;
|
Vector3 GetEulerAngles() const;
|
||||||
|
|
||||||
|
|
||||||
// MARK: Operators
|
// MARK: Operators
|
||||||
|
|
||||||
//! Operator to check for equality
|
//! Operator to check for equality
|
||||||
bool operator==(const NiQuaternion& rot) const;
|
bool operator==(const NiQuaternion& rot) const;
|
||||||
|
|
||||||
//! Operator to check for inequality
|
//! Operator to check for inequality
|
||||||
bool operator!=(const NiQuaternion& rot) const;
|
bool operator!=(const NiQuaternion& rot) const;
|
||||||
|
|
||||||
|
|
||||||
// MARK: Helper Functions
|
// MARK: Helper Functions
|
||||||
|
|
||||||
//! Look from a specific point in space to another point in space (Y-locked)
|
//! Look from a specific point in space to another point in space (Y-locked)
|
||||||
/*!
|
/*!
|
||||||
\param sourcePoint The source location
|
\param sourcePoint The source location
|
||||||
\param destPoint The destination location
|
\param destPoint The destination location
|
||||||
\return The Quaternion with the rotation towards the destination
|
\return The Quaternion with the rotation towards the destination
|
||||||
*/
|
*/
|
||||||
static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
|
static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
|
||||||
|
|
||||||
//! Look from a specific point in space to another point in space
|
//! Look from a specific point in space to another point in space
|
||||||
/*!
|
/*!
|
||||||
\param sourcePoint The source location
|
\param sourcePoint The source location
|
||||||
\param destPoint The destination location
|
\param destPoint The destination location
|
||||||
\return The Quaternion with the rotation towards the destination
|
\return The Quaternion with the rotation towards the destination
|
||||||
*/
|
*/
|
||||||
static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
|
static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint);
|
||||||
|
|
||||||
//! Creates a Quaternion from a specific axis and angle relative to that axis
|
//! Creates a Quaternion from a specific axis and angle relative to that axis
|
||||||
/*!
|
/*!
|
||||||
\param axis The axis that is used
|
\param axis The axis that is used
|
||||||
\param angle The angle relative to this axis
|
\param angle The angle relative to this axis
|
||||||
\return A quaternion created from the axis and angle
|
\return A quaternion created from the axis and angle
|
||||||
*/
|
*/
|
||||||
static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);
|
static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);
|
||||||
|
|
||||||
static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles);
|
static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles);
|
||||||
};
|
};
|
||||||
|
@ -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,
|
|
||||||
};
|
|
@ -5,153 +5,148 @@
|
|||||||
|
|
||||||
const unsigned long long SHA512::sha512_k[80] = //ULL = uint64
|
const unsigned long long SHA512::sha512_k[80] = //ULL = uint64
|
||||||
{ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
|
{ 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL,
|
||||||
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
|
0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
|
||||||
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
|
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
|
||||||
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
|
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
|
||||||
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
|
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
|
||||||
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
|
0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
|
||||||
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
|
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL,
|
||||||
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
|
0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
|
||||||
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
|
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
|
||||||
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
|
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
|
||||||
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
|
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL,
|
||||||
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
|
0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
|
||||||
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
|
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL,
|
||||||
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
|
0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
|
||||||
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
|
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
|
||||||
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
|
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
|
||||||
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
|
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL,
|
||||||
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
|
0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
|
||||||
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
|
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL,
|
||||||
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
|
0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
|
||||||
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
|
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
|
||||||
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
|
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
|
||||||
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
|
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL,
|
||||||
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
|
0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
|
||||||
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
|
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
|
||||||
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
|
0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
|
||||||
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
|
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
|
||||||
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
|
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
|
||||||
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
|
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL,
|
||||||
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
|
0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
|
||||||
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
|
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL,
|
||||||
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
|
0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
|
||||||
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
|
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
|
||||||
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
|
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
|
||||||
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
|
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
|
||||||
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
|
0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
|
||||||
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
|
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL,
|
||||||
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
|
0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
|
||||||
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
|
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
|
||||||
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
|
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL };
|
||||||
|
|
||||||
void SHA512::transform(const unsigned char *message, unsigned int block_nb)
|
void SHA512::transform(const unsigned char* message, unsigned int block_nb) {
|
||||||
{
|
uint64 w[80];
|
||||||
uint64 w[80];
|
uint64 wv[8];
|
||||||
uint64 wv[8];
|
uint64 t1, t2;
|
||||||
uint64 t1, t2;
|
const unsigned char* sub_block;
|
||||||
const unsigned char *sub_block;
|
int i, j;
|
||||||
int i, j;
|
for (i = 0; i < (int)block_nb; i++) {
|
||||||
for (i = 0; i < (int)block_nb; i++) {
|
sub_block = message + (i << 7);
|
||||||
sub_block = message + (i << 7);
|
for (j = 0; j < 16; j++) {
|
||||||
for (j = 0; j < 16; j++) {
|
SHA2_PACK64(&sub_block[j << 3], &w[j]);
|
||||||
SHA2_PACK64(&sub_block[j << 3], &w[j]);
|
}
|
||||||
}
|
for (j = 16; j < 80; j++) {
|
||||||
for (j = 16; j < 80; j++) {
|
w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16];
|
||||||
w[j] = SHA512_F4(w[j - 2]) + w[j - 7] + SHA512_F3(w[j - 15]) + w[j - 16];
|
}
|
||||||
}
|
for (j = 0; j < 8; j++) {
|
||||||
for (j = 0; j < 8; j++) {
|
wv[j] = m_h[j];
|
||||||
wv[j] = m_h[j];
|
}
|
||||||
}
|
for (j = 0; j < 80; j++) {
|
||||||
for (j = 0; j < 80; j++) {
|
t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6])
|
||||||
t1 = wv[7] + SHA512_F2(wv[4]) + SHA2_CH(wv[4], wv[5], wv[6])
|
+ sha512_k[j] + w[j];
|
||||||
+ sha512_k[j] + w[j];
|
t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]);
|
||||||
t2 = SHA512_F1(wv[0]) + SHA2_MAJ(wv[0], wv[1], wv[2]);
|
wv[7] = wv[6];
|
||||||
wv[7] = wv[6];
|
wv[6] = wv[5];
|
||||||
wv[6] = wv[5];
|
wv[5] = wv[4];
|
||||||
wv[5] = wv[4];
|
wv[4] = wv[3] + t1;
|
||||||
wv[4] = wv[3] + t1;
|
wv[3] = wv[2];
|
||||||
wv[3] = wv[2];
|
wv[2] = wv[1];
|
||||||
wv[2] = wv[1];
|
wv[1] = wv[0];
|
||||||
wv[1] = wv[0];
|
wv[0] = t1 + t2;
|
||||||
wv[0] = t1 + t2;
|
}
|
||||||
}
|
for (j = 0; j < 8; j++) {
|
||||||
for (j = 0; j < 8; j++) {
|
m_h[j] += wv[j];
|
||||||
m_h[j] += wv[j];
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHA512::init()
|
void SHA512::init() {
|
||||||
{
|
m_h[0] = 0x6a09e667f3bcc908ULL;
|
||||||
m_h[0] = 0x6a09e667f3bcc908ULL;
|
m_h[1] = 0xbb67ae8584caa73bULL;
|
||||||
m_h[1] = 0xbb67ae8584caa73bULL;
|
m_h[2] = 0x3c6ef372fe94f82bULL;
|
||||||
m_h[2] = 0x3c6ef372fe94f82bULL;
|
m_h[3] = 0xa54ff53a5f1d36f1ULL;
|
||||||
m_h[3] = 0xa54ff53a5f1d36f1ULL;
|
m_h[4] = 0x510e527fade682d1ULL;
|
||||||
m_h[4] = 0x510e527fade682d1ULL;
|
m_h[5] = 0x9b05688c2b3e6c1fULL;
|
||||||
m_h[5] = 0x9b05688c2b3e6c1fULL;
|
m_h[6] = 0x1f83d9abfb41bd6bULL;
|
||||||
m_h[6] = 0x1f83d9abfb41bd6bULL;
|
m_h[7] = 0x5be0cd19137e2179ULL;
|
||||||
m_h[7] = 0x5be0cd19137e2179ULL;
|
m_len = 0;
|
||||||
m_len = 0;
|
m_tot_len = 0;
|
||||||
m_tot_len = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHA512::update(const unsigned char *message, unsigned int len)
|
void SHA512::update(const unsigned char* message, unsigned int len) {
|
||||||
{
|
unsigned int block_nb;
|
||||||
unsigned int block_nb;
|
unsigned int new_len, rem_len, tmp_len;
|
||||||
unsigned int new_len, rem_len, tmp_len;
|
const unsigned char* shifted_message;
|
||||||
const unsigned char *shifted_message;
|
tmp_len = SHA384_512_BLOCK_SIZE - m_len;
|
||||||
tmp_len = SHA384_512_BLOCK_SIZE - m_len;
|
rem_len = len < tmp_len ? len : tmp_len;
|
||||||
rem_len = len < tmp_len ? len : tmp_len;
|
memcpy(&m_block[m_len], message, rem_len);
|
||||||
memcpy(&m_block[m_len], message, rem_len);
|
if (m_len + len < SHA384_512_BLOCK_SIZE) {
|
||||||
if (m_len + len < SHA384_512_BLOCK_SIZE) {
|
m_len += len;
|
||||||
m_len += len;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
new_len = len - rem_len;
|
||||||
new_len = len - rem_len;
|
block_nb = new_len / SHA384_512_BLOCK_SIZE;
|
||||||
block_nb = new_len / SHA384_512_BLOCK_SIZE;
|
shifted_message = message + rem_len;
|
||||||
shifted_message = message + rem_len;
|
transform(m_block, 1);
|
||||||
transform(m_block, 1);
|
transform(shifted_message, block_nb);
|
||||||
transform(shifted_message, block_nb);
|
rem_len = new_len % SHA384_512_BLOCK_SIZE;
|
||||||
rem_len = new_len % SHA384_512_BLOCK_SIZE;
|
memcpy(m_block, &shifted_message[block_nb << 7], rem_len);
|
||||||
memcpy(m_block, &shifted_message[block_nb << 7], rem_len);
|
m_len = rem_len;
|
||||||
m_len = rem_len;
|
m_tot_len += (block_nb + 1) << 7;
|
||||||
m_tot_len += (block_nb + 1) << 7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SHA512::final(unsigned char *digest)
|
void SHA512::final(unsigned char* digest) {
|
||||||
{
|
unsigned int block_nb;
|
||||||
unsigned int block_nb;
|
unsigned int pm_len;
|
||||||
unsigned int pm_len;
|
unsigned int len_b;
|
||||||
unsigned int len_b;
|
int i;
|
||||||
int i;
|
block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17)
|
||||||
block_nb = 1 + ((SHA384_512_BLOCK_SIZE - 17)
|
< (m_len % SHA384_512_BLOCK_SIZE));
|
||||||
< (m_len % SHA384_512_BLOCK_SIZE));
|
len_b = (m_tot_len + m_len) << 3;
|
||||||
len_b = (m_tot_len + m_len) << 3;
|
pm_len = block_nb << 7;
|
||||||
pm_len = block_nb << 7;
|
memset(m_block + m_len, 0, pm_len - m_len);
|
||||||
memset(m_block + m_len, 0, pm_len - m_len);
|
m_block[m_len] = 0x80;
|
||||||
m_block[m_len] = 0x80;
|
SHA2_UNPACK32(len_b, m_block + pm_len - 4);
|
||||||
SHA2_UNPACK32(len_b, m_block + pm_len - 4);
|
transform(m_block, block_nb);
|
||||||
transform(m_block, block_nb);
|
for (i = 0; i < 8; i++) {
|
||||||
for (i = 0; i < 8; i++) {
|
SHA2_UNPACK64(m_h[i], &digest[i << 3]);
|
||||||
SHA2_UNPACK64(m_h[i], &digest[i << 3]);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sha512(std::string input)
|
std::string sha512(std::string input) {
|
||||||
{
|
unsigned char digest[SHA512::DIGEST_SIZE];
|
||||||
unsigned char digest[SHA512::DIGEST_SIZE];
|
memset(digest, 0, SHA512::DIGEST_SIZE);
|
||||||
memset(digest, 0, SHA512::DIGEST_SIZE);
|
class SHA512 ctx;
|
||||||
class SHA512 ctx;
|
ctx.init();
|
||||||
ctx.init();
|
ctx.update((unsigned char*)input.c_str(), input.length());
|
||||||
ctx.update((unsigned char*)input.c_str(), input.length());
|
ctx.final(digest);
|
||||||
ctx.final(digest);
|
|
||||||
|
|
||||||
char buf[2 * SHA512::DIGEST_SIZE + 1];
|
char buf[2 * SHA512::DIGEST_SIZE + 1];
|
||||||
buf[2 * SHA512::DIGEST_SIZE] = 0;
|
buf[2 * SHA512::DIGEST_SIZE] = 0;
|
||||||
for (int i = 0; i < SHA512::DIGEST_SIZE; i++)
|
for (int i = 0; i < SHA512::DIGEST_SIZE; i++)
|
||||||
sprintf(buf + i * 2, "%02x", digest[i]);
|
sprintf(buf + i * 2, "%02x", digest[i]);
|
||||||
|
|
||||||
return std::string(buf);
|
return std::string(buf);
|
||||||
}
|
}
|
||||||
|
@ -5,25 +5,25 @@
|
|||||||
|
|
||||||
class SHA512 {
|
class SHA512 {
|
||||||
protected:
|
protected:
|
||||||
typedef unsigned char uint8;
|
typedef unsigned char uint8;
|
||||||
typedef unsigned int uint32;
|
typedef unsigned int uint32;
|
||||||
typedef unsigned long long uint64;
|
typedef unsigned long long uint64;
|
||||||
|
|
||||||
const static uint64 sha512_k[];
|
const static uint64 sha512_k[];
|
||||||
static const unsigned int SHA384_512_BLOCK_SIZE = (1024 / 8);
|
static const unsigned int SHA384_512_BLOCK_SIZE = (1024 / 8);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
void update(const unsigned char *message, unsigned int len);
|
void update(const unsigned char* message, unsigned int len);
|
||||||
void final(unsigned char *digest);
|
void final(unsigned char* digest);
|
||||||
static const unsigned int DIGEST_SIZE = (512 / 8);
|
static const unsigned int DIGEST_SIZE = (512 / 8);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void transform(const unsigned char *message, unsigned int block_nb);
|
void transform(const unsigned char* message, unsigned int block_nb);
|
||||||
unsigned int m_tot_len;
|
unsigned int m_tot_len;
|
||||||
unsigned int m_len;
|
unsigned int m_len;
|
||||||
unsigned char m_block[2 * SHA384_512_BLOCK_SIZE];
|
unsigned char m_block[2 * SHA384_512_BLOCK_SIZE];
|
||||||
uint64 m_h[8];
|
uint64 m_h[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string sha512(std::string input);
|
std::string sha512(std::string input);
|
||||||
|
@ -6,22 +6,22 @@
|
|||||||
|
|
||||||
std::string demangle(const char* name) {
|
std::string demangle(const char* name) {
|
||||||
|
|
||||||
int status = -4; // some arbitrary value to eliminate the compiler warning
|
int status = -4; // some arbitrary value to eliminate the compiler warning
|
||||||
|
|
||||||
// enable c++11 by passing the flag -std=c++11 to g++
|
// enable c++11 by passing the flag -std=c++11 to g++
|
||||||
std::unique_ptr<char, void(*)(void*)> res {
|
std::unique_ptr<char, void(*)(void*)> res{
|
||||||
abi::__cxa_demangle(name, NULL, NULL, &status),
|
abi::__cxa_demangle(name, NULL, NULL, &status),
|
||||||
std::free
|
std::free
|
||||||
};
|
};
|
||||||
|
|
||||||
return (status==0) ? res.get() : name ;
|
return (status == 0) ? res.get() : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// does nothing if not g++
|
// does nothing if not g++
|
||||||
std::string demangle(const char* name) {
|
std::string demangle(const char* name) {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,5 +8,5 @@ std::string demangle(const char* name);
|
|||||||
template <class T>
|
template <class T>
|
||||||
std::string type(const T& t) {
|
std::string type(const T& t) {
|
||||||
|
|
||||||
return demangle(typeid(t).name());
|
return demangle(typeid(t).name());
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,50 @@
|
|||||||
#include "ZCompression.h"
|
#include "ZCompression.h"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
namespace ZCompression
|
namespace ZCompression {
|
||||||
{
|
int32_t GetMaxCompressedLength(int32_t nLenSrc) {
|
||||||
int32_t GetMaxCompressedLength(int32_t nLenSrc)
|
int32_t n16kBlocks = (nLenSrc + 16383) / 16384; // round up any fraction of a block
|
||||||
{
|
return (nLenSrc + 6 + (n16kBlocks * 5));
|
||||||
int32_t n16kBlocks = (nLenSrc + 16383) / 16384; // round up any fraction of a block
|
}
|
||||||
return (nLenSrc + 6 + (n16kBlocks * 5));
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst)
|
int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst) {
|
||||||
{
|
z_stream zInfo = { 0 };
|
||||||
z_stream zInfo = { 0 };
|
zInfo.total_in = zInfo.avail_in = nLenSrc;
|
||||||
zInfo.total_in = zInfo.avail_in = nLenSrc;
|
zInfo.total_out = zInfo.avail_out = nLenDst;
|
||||||
zInfo.total_out = zInfo.avail_out = nLenDst;
|
zInfo.next_in = const_cast<Bytef*>(abSrc);
|
||||||
zInfo.next_in = const_cast<Bytef*>(abSrc);
|
zInfo.next_out = abDst;
|
||||||
zInfo.next_out = abDst;
|
|
||||||
|
|
||||||
int nErr, nRet = -1;
|
int nErr, nRet = -1;
|
||||||
nErr = deflateInit(&zInfo, Z_DEFAULT_COMPRESSION); // zlib function
|
nErr = deflateInit(&zInfo, Z_DEFAULT_COMPRESSION); // zlib function
|
||||||
if (nErr == Z_OK) {
|
if (nErr == Z_OK) {
|
||||||
nErr = deflate(&zInfo, Z_FINISH); // zlib function
|
nErr = deflate(&zInfo, Z_FINISH); // zlib function
|
||||||
if (nErr == Z_STREAM_END) {
|
if (nErr == Z_STREAM_END) {
|
||||||
nRet = zInfo.total_out;
|
nRet = zInfo.total_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deflateEnd(&zInfo); // zlib function
|
deflateEnd(&zInfo); // zlib function
|
||||||
return(nRet);
|
return(nRet);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr) {
|
||||||
|
// Get the size of the decompressed data
|
||||||
|
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 = abDst;
|
||||||
|
|
||||||
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr)
|
int nRet = -1;
|
||||||
{
|
nErr = inflateInit(&zInfo); // zlib function
|
||||||
// Get the size of the decompressed data
|
if (nErr == Z_OK) {
|
||||||
z_stream zInfo = { 0 };
|
nErr = inflate(&zInfo, Z_FINISH); // zlib function
|
||||||
zInfo.total_in = zInfo.avail_in = nLenSrc;
|
if (nErr == Z_STREAM_END) {
|
||||||
zInfo.total_out = zInfo.avail_out = nLenDst;
|
nRet = zInfo.total_out;
|
||||||
zInfo.next_in = const_cast<Bytef*>(abSrc);
|
}
|
||||||
zInfo.next_out = abDst;
|
}
|
||||||
|
inflateEnd(&zInfo); // zlib function
|
||||||
int nRet = -1;
|
return(nRet);
|
||||||
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);
|
|
||||||
|
|
||||||
/*
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace ZCompression
|
namespace ZCompression {
|
||||||
{
|
|
||||||
int32_t GetMaxCompressedLength(int32_t nLenSrc);
|
int32_t GetMaxCompressedLength(int32_t nLenSrc);
|
||||||
|
|
||||||
int32_t Compress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst);
|
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);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
183
dCommon/dClient/AssetManager.cpp
Normal file
183
dCommon/dClient/AssetManager.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
case eAssetBundleType::None:
|
||||||
|
case eAssetBundleType::Unpacked: {
|
||||||
|
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);
|
||||||
|
int32_t readInData = 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);
|
||||||
|
int32_t readInData = 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;
|
||||||
|
int32_t readInData = fread(&size, sizeof(uint32_t), 1, file);
|
||||||
|
pos += 4; // Move pointer position 4 to the right
|
||||||
|
|
||||||
|
char* chunk = (char*)malloc(size);
|
||||||
|
int32_t readInData2 = 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,676 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <set>
|
|
||||||
#include "../thirdparty/raknet/Source/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
|
|
||||||
|
|
||||||
//========== MACROS ===========
|
|
||||||
|
|
||||||
#define CBITSTREAM RakNet::BitStream bitStream;
|
|
||||||
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
|
|
||||||
#define CMSGHEADER PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_GAME_MSG);
|
|
||||||
#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
|
|
||||||
#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
|
||||||
|
|
||||||
//=========== TYPEDEFS ==========
|
|
||||||
|
|
||||||
typedef int32_t LOT; //!< A LOT
|
|
||||||
typedef int64_t LWOOBJID; //!< An object ID (should be unsigned actually but ok)
|
|
||||||
typedef int32_t TSkillID; //!< A skill ID
|
|
||||||
typedef uint32_t LWOCLONEID; //!< Used for Clone IDs
|
|
||||||
typedef uint16_t LWOMAPID; //!< Used for Map IDs
|
|
||||||
typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs
|
|
||||||
typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs
|
|
||||||
|
|
||||||
typedef int32_t PetTamingPiece; //!< Pet Taming Pieces
|
|
||||||
|
|
||||||
const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID
|
|
||||||
const LOT LOT_NULL = -1; //!< A null LOT
|
|
||||||
const int32_t LOOTTYPE_NONE = 0; //!< No loot type available
|
|
||||||
const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority
|
|
||||||
const uint32_t INVENTORY_INVALID = -1; //!< Invalid Inventory
|
|
||||||
const uint32_t INVENTORY_DEFAULT = -1; //!< Default Inventory
|
|
||||||
const uint32_t StatusChangeInfo = 0; //!< Status Change Info (???)
|
|
||||||
const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size
|
|
||||||
const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
|
|
||||||
const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
|
|
||||||
const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
|
|
||||||
const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
|
|
||||||
|
|
||||||
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 {
|
|
||||||
public:
|
|
||||||
LWOSCENEID() { m_sceneID = -1; m_layerID = 0; }
|
|
||||||
LWOSCENEID(int sceneID) { m_sceneID = sceneID; m_layerID = 0; }
|
|
||||||
LWOSCENEID(int sceneID, unsigned int layerID) { m_sceneID = sceneID; m_layerID = layerID; }
|
|
||||||
|
|
||||||
LWOSCENEID& operator=(const LWOSCENEID& rhs) { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; }
|
|
||||||
LWOSCENEID& operator=(const int rhs) { m_sceneID = rhs; m_layerID = 0; return *this; }
|
|
||||||
|
|
||||||
bool operator<(const LWOSCENEID& rhs) const { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); }
|
|
||||||
bool operator<(const int rhs) const { return m_sceneID < rhs; }
|
|
||||||
|
|
||||||
bool operator==(const LWOSCENEID& rhs) const { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); }
|
|
||||||
bool operator==(const int rhs) const { return m_sceneID == rhs; }
|
|
||||||
|
|
||||||
const int GetSceneID() const { return m_sceneID; }
|
|
||||||
const unsigned int GetLayerID() const { return m_layerID; }
|
|
||||||
|
|
||||||
void SetSceneID(const int sceneID) { m_sceneID = sceneID; }
|
|
||||||
void SetLayerID(const unsigned int layerID) { m_layerID = layerID; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_sceneID;
|
|
||||||
unsigned int m_layerID;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LWOZONEID {
|
|
||||||
public:
|
|
||||||
const LWOMAPID& GetMapID() const { return m_MapID; }
|
|
||||||
const LWOINSTANCEID& GetInstanceID() const { return m_InstanceID; }
|
|
||||||
const LWOCLONEID& GetCloneID() const { return m_CloneID; }
|
|
||||||
|
|
||||||
//In order: def constr, constr, assign op
|
|
||||||
LWOZONEID() { m_MapID = LWOMAPID_INVALID; m_InstanceID = LWOINSTANCEID_INVALID; m_CloneID = LWOCLONEID_INVALID; }
|
|
||||||
LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; }
|
|
||||||
LWOZONEID(const LWOZONEID& replacement) { *this = replacement; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
LWOMAPID m_MapID; //1000 for VE, 1100 for AG, etc...
|
|
||||||
LWOINSTANCEID m_InstanceID; //Instances host the same world, but on a different dWorld process.
|
|
||||||
LWOCLONEID m_CloneID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds.
|
|
||||||
};
|
|
||||||
|
|
||||||
const LWOSCENEID LWOSCENEID_INVALID = -1;
|
|
||||||
|
|
||||||
struct LWONameValue {
|
|
||||||
uint32_t length = 0; //!< The length of the name
|
|
||||||
std::u16string name; //!< The name
|
|
||||||
|
|
||||||
LWONameValue(void) {}
|
|
||||||
|
|
||||||
LWONameValue(const std::u16string& name) {
|
|
||||||
this->name = name;
|
|
||||||
this->length = static_cast<uint32_t>(name.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
~LWONameValue(void) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FriendData {
|
|
||||||
public:
|
|
||||||
bool isOnline = false;
|
|
||||||
bool isBestFriend = false;
|
|
||||||
bool isFTP = false;
|
|
||||||
LWOZONEID zoneID;
|
|
||||||
LWOOBJID friendID;
|
|
||||||
std::string friendName;
|
|
||||||
|
|
||||||
void Serialize(RakNet::BitStream& bitStream) {
|
|
||||||
bitStream.Write<uint8_t>(isOnline);
|
|
||||||
bitStream.Write<uint8_t>(isBestFriend);
|
|
||||||
bitStream.Write<uint8_t>(isFTP);
|
|
||||||
bitStream.Write<uint32_t>(0); //???
|
|
||||||
bitStream.Write<uint8_t>(0); //???
|
|
||||||
bitStream.Write(zoneID.GetMapID());
|
|
||||||
bitStream.Write(zoneID.GetInstanceID());
|
|
||||||
bitStream.Write(zoneID.GetCloneID());
|
|
||||||
bitStream.Write(friendID);
|
|
||||||
|
|
||||||
uint32_t maxSize = 33;
|
|
||||||
uint32_t size = static_cast<uint32_t>(friendName.length());
|
|
||||||
uint32_t remSize = static_cast<uint32_t>(maxSize - size);
|
|
||||||
|
|
||||||
if (size > maxSize) size = maxSize;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < size; ++i) {
|
|
||||||
bitStream.Write(static_cast<uint16_t>(friendName[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t j = 0; j < remSize; ++j) {
|
|
||||||
bitStream.Write(static_cast<uint16_t>(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
bitStream.Write<uint32_t>(0); //???
|
|
||||||
bitStream.Write<uint16_t>(0); //???
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Brick {
|
|
||||||
uint32_t designerID;
|
|
||||||
uint32_t materialID;
|
|
||||||
};
|
|
||||||
|
|
||||||
//This union is used by the behavior system
|
|
||||||
union suchar {
|
|
||||||
unsigned char usigned;
|
|
||||||
char svalue;
|
|
||||||
};
|
|
||||||
|
|
||||||
//=========== DLU ENUMS ============
|
|
||||||
|
|
||||||
enum eGameMasterLevel : int32_t {
|
|
||||||
GAME_MASTER_LEVEL_CIVILIAN = 0, // Normal player.
|
|
||||||
GAME_MASTER_LEVEL_FORUM_MODERATOR = 1, // No permissions on live servers.
|
|
||||||
GAME_MASTER_LEVEL_JUNIOR_MODERATOR = 2, // Can kick/mute and pull chat logs.
|
|
||||||
GAME_MASTER_LEVEL_MODERATOR = 3, // Can return lost items.
|
|
||||||
GAME_MASTER_LEVEL_SENIOR_MODERATOR = 4, // Can ban.
|
|
||||||
GAME_MASTER_LEVEL_LEAD_MODERATOR = 5, // Can approve properties.
|
|
||||||
GAME_MASTER_LEVEL_JUNIOR_DEVELOPER = 6, // Junior developer & future content team. Civilan on live.
|
|
||||||
GAME_MASTER_LEVEL_INACTIVE_DEVELOPER = 7, // Inactive developer, limited permissions.
|
|
||||||
GAME_MASTER_LEVEL_DEVELOPER = 8, // Active developer, full permissions on live.
|
|
||||||
GAME_MASTER_LEVEL_OPERATOR = 9 // Can shutdown server for restarts & updates.
|
|
||||||
};
|
|
||||||
|
|
||||||
//=========== LU ENUMS ============
|
|
||||||
|
|
||||||
//! An enum for object ID bits
|
|
||||||
enum eObjectBits : int32_t {
|
|
||||||
OBJECT_BIT_PERSISTENT = 32, //!< The 32 bit index
|
|
||||||
OBJECT_BIT_CLIENT = 46, //!< The 46 bit index
|
|
||||||
OBJECT_BIT_SPAWNED = 58, //!< The 58 bit index
|
|
||||||
OBJECT_BIT_CHARACTER = 60 //!< The 60 bit index
|
|
||||||
};
|
|
||||||
|
|
||||||
//! An enum for MatchUpdate types
|
|
||||||
enum eMatchUpdate : int {
|
|
||||||
MATCH_UPDATE_PLAYER_JOINED = 0,
|
|
||||||
MATCH_UPDATE_PLAYER_LEFT = 1,
|
|
||||||
MATCH_UPDATE_TIME = 3,
|
|
||||||
MATCH_UPDATE_TIME_START_DELAY = 4,
|
|
||||||
MATCH_UPDATE_PLAYER_READY = 5,
|
|
||||||
MATCH_UPDATE_PLAYER_UNREADY = 6
|
|
||||||
};
|
|
||||||
|
|
||||||
//! An enum for camera cycling modes
|
|
||||||
enum eCyclingMode : uint32_t {
|
|
||||||
ALLOW_CYCLE_TEAMMATES,
|
|
||||||
DISALLOW_CYCLING
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eCinematicEvent : uint32_t {
|
|
||||||
STARTED,
|
|
||||||
WAYPOINT,
|
|
||||||
ENDED,
|
|
||||||
};
|
|
||||||
|
|
||||||
//! An enum for character creation responses
|
|
||||||
enum eCreationResponse : uint8_t {
|
|
||||||
CREATION_RESPONSE_SUCCESS = 0, //!< The creation was successful
|
|
||||||
CREATION_RESPONSE_OBJECT_ID_UNAVAILABLE, //!< The Object ID can't be used
|
|
||||||
CREATION_RESPONSE_NAME_NOT_ALLOWED, //!< The name is not allowed
|
|
||||||
CREATION_RESPONSE_PREDEFINED_NAME_IN_USE, //!< The predefined name is already in use
|
|
||||||
CREATION_RESPONSE_CUSTOM_NAME_IN_USE //!< The custom name is already in use
|
|
||||||
};
|
|
||||||
|
|
||||||
//! An enum for login responses
|
|
||||||
enum eLoginResponse : uint8_t {
|
|
||||||
LOGIN_RESPONSE_GENERAL_FAILED = 0,
|
|
||||||
LOGIN_RESPONSE_SUCCESS = 1,
|
|
||||||
LOGIN_RESPONSE_BANNED = 2,
|
|
||||||
LOGIN_RESPONSE_PERMISSIONS_NOT_HIGH_ENOUGH = 5,
|
|
||||||
LOGIN_RESPONSE_WRONG_PASS_OR_USER = 6,
|
|
||||||
LOGIN_RESPONSE_ACCOUNT_LOCKED = 7
|
|
||||||
};
|
|
||||||
|
|
||||||
//! An enum for character rename responses
|
|
||||||
enum eRenameResponse : uint8_t {
|
|
||||||
RENAME_RESPONSE_SUCCESS = 0, //!< The renaming was successful
|
|
||||||
RENAME_RESPONSE_UNKNOWN_ERROR, //!< There was an unknown error
|
|
||||||
RENAME_RESPONSE_NAME_UNAVAILABLE, //!< The name is unavailable
|
|
||||||
RENAME_RESPONSE_NAME_IN_USE //!< The name is already in use
|
|
||||||
};
|
|
||||||
|
|
||||||
//! A replica packet type
|
|
||||||
enum eReplicaPacketType {
|
|
||||||
PACKET_TYPE_CONSTRUCTION, //!< A construction packet
|
|
||||||
PACKET_TYPE_SERIALIZATION, //!< A serialization packet
|
|
||||||
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
|
|
||||||
AGGRESSIVE = 1, //!< The object is aggressive
|
|
||||||
PASSIVE_TURRET = 2, //!< The object is a passive turret
|
|
||||||
AGGRESSIVE_TURRET = 3 //!< The object is an aggressive turret
|
|
||||||
};
|
|
||||||
|
|
||||||
//! The Combat Role Type for use with the AI system
|
|
||||||
enum eCombatRoleType : uint32_t {
|
|
||||||
MELEE = 0, //!< Used for melee attacks
|
|
||||||
RANGED = 1, //!< Used for range attacks
|
|
||||||
SUPPORT = 2 //!< Used for support
|
|
||||||
};
|
|
||||||
|
|
||||||
//! The kill types for the Die packet
|
|
||||||
enum eKillType : uint32_t {
|
|
||||||
VIOLENT,
|
|
||||||
SILENT
|
|
||||||
};
|
|
||||||
|
|
||||||
//! The various world states used throughout the server
|
|
||||||
enum eObjectWorldState {
|
|
||||||
WORLDSTATE_INWORLD, //!< Probably used when the object is in the world
|
|
||||||
WORLDSTATE_ATTACHED, //!< Probably used when the object is attached to another object
|
|
||||||
WORLDSTATE_INVENTORY //!< Probably used when the object is in an inventory
|
|
||||||
};
|
|
||||||
|
|
||||||
//! The trigger stats (???)
|
|
||||||
enum eTriggerStat {
|
|
||||||
INVALID_STAT, //!< ???
|
|
||||||
HEALTH, //!< Probably used for health
|
|
||||||
ARMOR, //!< Probably used for armor
|
|
||||||
IMAGINATION //!< Probably used for imagination
|
|
||||||
};
|
|
||||||
|
|
||||||
//! The trigger operations (???)
|
|
||||||
enum eTriggerOperator {
|
|
||||||
INVALID_OPER, //!< ???
|
|
||||||
EQUAL, //!< ???
|
|
||||||
NOT_EQUAL, //!< ???
|
|
||||||
GREATER, //!< ???
|
|
||||||
GREATER_EQUAL, //!< ???
|
|
||||||
LESS, //!< ???
|
|
||||||
LESS_EQUAL //!< ???
|
|
||||||
};
|
|
||||||
|
|
||||||
//! The various build types
|
|
||||||
enum eBuildType {
|
|
||||||
BUILD_NOWHERE, //!< Used if something can't be built anywhere
|
|
||||||
BUILD_IN_WORLD, //!< Used if something can be built in the world
|
|
||||||
BUILD_ON_PROPERTY //!< Used if something can be build on a property
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Quickbuild fail reasons
|
|
||||||
enum eFailReason : uint32_t {
|
|
||||||
REASON_NOT_GIVEN,
|
|
||||||
REASON_OUT_OF_IMAGINATION,
|
|
||||||
REASON_CANCELED_EARLY,
|
|
||||||
REASON_BUILD_ENDED
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Terminate interaction type
|
|
||||||
enum eTerminateType : uint32_t {
|
|
||||||
RANGE,
|
|
||||||
USER,
|
|
||||||
FROM_INTERACTION
|
|
||||||
};
|
|
||||||
|
|
||||||
//! The combat state
|
|
||||||
enum eCombatState {
|
|
||||||
IDLE, //!< The AI is in an idle state
|
|
||||||
AGGRO, //!< The AI is in an aggressive state
|
|
||||||
TETHER, //!< The AI is being redrawn back to tether point
|
|
||||||
SPAWN, //!< The AI is spawning
|
|
||||||
DEAD //!< The AI is dead
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eControlSceme {
|
|
||||||
SCHEME_A,
|
|
||||||
SCHEME_D,
|
|
||||||
SCHEME_GAMEPAD,
|
|
||||||
SCHEME_E,
|
|
||||||
SCHEME_FPS,
|
|
||||||
SCHEME_DRIVING,
|
|
||||||
SCHEME_TAMING,
|
|
||||||
SCHEME_MODULAR_BUILD,
|
|
||||||
SCHEME_WEAR_A_ROBOT //== freecam?
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eStunState {
|
|
||||||
PUSH,
|
|
||||||
POP
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eNotifyType {
|
|
||||||
NOTIFY_TYPE_SUCCESS,
|
|
||||||
NOTIFY_TYPE_QUIT,
|
|
||||||
NOTIFY_TYPE_FAILED,
|
|
||||||
NOTIFY_TYPE_BEGIN,
|
|
||||||
NOTIFY_TYPE_READY,
|
|
||||||
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_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 Exhibit 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,
|
|
||||||
COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component
|
|
||||||
COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component
|
|
||||||
COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component
|
|
||||||
COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component
|
|
||||||
|
|
||||||
COMPONENT_TYPE_MODEL = 5398484 //look man idk
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class UseItemResponse : uint32_t {
|
|
||||||
NoImaginationForPet = 1,
|
|
||||||
FailedPrecondition,
|
|
||||||
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 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
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eRebuildState : uint32_t {
|
|
||||||
REBUILD_OPEN,
|
|
||||||
REBUILD_COMPLETED = 2,
|
|
||||||
REBUILD_RESETTING = 4,
|
|
||||||
REBUILD_BUILDING,
|
|
||||||
REBUILD_INCOMPLETE
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The loot source's type.
|
|
||||||
*/
|
|
||||||
enum eLootSourceType : int32_t {
|
|
||||||
LOOT_SOURCE_NONE = 0,
|
|
||||||
LOOT_SOURCE_CHEST,
|
|
||||||
LOOT_SOURCE_MISSION,
|
|
||||||
LOOT_SOURCE_MAIL,
|
|
||||||
LOOT_SOURCE_CURRENCY,
|
|
||||||
LOOT_SOURCE_ACHIEVEMENT,
|
|
||||||
LOOT_SOURCE_TRADE,
|
|
||||||
LOOT_SOURCE_QUICKBUILD,
|
|
||||||
LOOT_SOURCE_DELETION,
|
|
||||||
LOOT_SOURCE_VENDOR,
|
|
||||||
LOOT_SOURCE_ACTIVITY,
|
|
||||||
LOOT_SOURCE_PICKUP,
|
|
||||||
LOOT_SOURCE_BRICK,
|
|
||||||
LOOT_SOURCE_PROPERTY,
|
|
||||||
LOOT_SOURCE_MODERATION,
|
|
||||||
LOOT_SOURCE_EXHIBIT,
|
|
||||||
LOOT_SOURCE_INVENTORY,
|
|
||||||
LOOT_SOURCE_CLAIMCODE,
|
|
||||||
LOOT_SOURCE_CONSUMPTION,
|
|
||||||
LOOT_SOURCE_CRAFTING,
|
|
||||||
LOOT_SOURCE_LEVEL_REWARD,
|
|
||||||
LOOT_SOURCE_RELOCATE
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eGameActivities : uint32_t {
|
|
||||||
ACTIVITY_NONE,
|
|
||||||
ACTIVITY_QUICKBUILDING,
|
|
||||||
ACTIVITY_SHOOTING_GALLERY,
|
|
||||||
ACTIVITY_RACING,
|
|
||||||
ACTIVITY_PINBALL,
|
|
||||||
ACTIVITY_PET_TAMING
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ePlayerFlags {
|
|
||||||
BTARR_TESTING = 0,
|
|
||||||
PLAYER_HAS_ENTERED_PET_RANCH = 1,
|
|
||||||
MINIMAP_UNLOCKED = 2,
|
|
||||||
ACTIVITY_REBUILDING_FAIL_TIME = 3,
|
|
||||||
ACTIVITY_REBUILDING_FAIL_RANGE = 4,
|
|
||||||
ACTIVITY_SHOOTING_GALLERY_HELP = 5,
|
|
||||||
HELP_WALKING_CONTROLS = 6,
|
|
||||||
FIRST_SMASHABLE = 7,
|
|
||||||
FIRST_IMAGINATION_PICKUP = 8,
|
|
||||||
FIRST_DAMAGE = 9,
|
|
||||||
FIRST_ITEM = 10,
|
|
||||||
FIRST_BRICK = 11,
|
|
||||||
FIRST_CONSUMABLE = 12,
|
|
||||||
FIRST_EQUIPPABLE = 13,
|
|
||||||
CHAT_HELP = 14,
|
|
||||||
FIRST_PET_TAMING_MINIGAME = 15,
|
|
||||||
FIRST_PET_ON_SWITCH = 16,
|
|
||||||
FIRST_PET_JUMPED_ON_SWITCH = 17,
|
|
||||||
FIRST_PET_FOUND_TREASURE = 18,
|
|
||||||
FIRST_PET_DUG_TREASURE = 19,
|
|
||||||
FIRST_PET_OWNER_ON_PET_BOUNCER = 20,
|
|
||||||
FIRST_PET_DESPAWN_NO_IMAGINATION = 21,
|
|
||||||
FIRST_PET_SELECTED_ENOUGH_BRICKS = 22,
|
|
||||||
FIRST_EMOTE_UNLOCKED = 23,
|
|
||||||
GF_PIRATE_REP = 24,
|
|
||||||
AG_BOB_CINEMATIC_EVENT = 25,
|
|
||||||
HELP_JUMPING_CONTROLS = 26,
|
|
||||||
HELP_DOUBLE_JUMP_CONTROLS = 27,
|
|
||||||
HELP_CAMERA_CONTROLS = 28,
|
|
||||||
HELP_ROTATE_CONTROLS = 29,
|
|
||||||
HELP_SMASH = 30,
|
|
||||||
MONUMENT_INTRO_MUSIC_PLAYED = 31,
|
|
||||||
BEGINNING_ZONE_SUMMARY_DISPLAYED = 32,
|
|
||||||
AG_FINISH_LINE_BUILT = 33,
|
|
||||||
AG_BOSS_AREA_FOUND = 34,
|
|
||||||
AG_LANDED_IN_BATTLEFIELD = 35,
|
|
||||||
GF_PLAYER_HAS_BEEN_TO_THE_RAVINE = 36,
|
|
||||||
MODULAR_BUILD_STARTED = 37,
|
|
||||||
MODULAR_BUILD_FINISHED_CLICK_BUTTON = 38,
|
|
||||||
THINKING_HAT_RECEIVED_GO_TO_MODULAR_BUILD_AREA = 39,
|
|
||||||
BUILD_AREA_ENTERED_MOD_NOT_ACTIVATED_PUT_ON_HAT = 40,
|
|
||||||
HAT_ON_INSIDE_OF_MOD_BUILD_EQUIP_A_MODULE_FROM_LEG = 41,
|
|
||||||
MODULE_EQUIPPED_PLACE_ON_GLOWING_BLUE_SPOT = 42,
|
|
||||||
FIRST_MODULE_PLACED_CORRECTLY_NOW_DO_THE_REST = 43,
|
|
||||||
ROCKET_COMPLETE_NOW_LAUNCH_FROM_PAD = 44,
|
|
||||||
JOINED_A_FACTION = 45,
|
|
||||||
VENTURE_FACTION = 46,
|
|
||||||
ASSEMBLY_FACTION = 47,
|
|
||||||
PARADOX_FACTION = 48,
|
|
||||||
SENTINEL_FACTION = 49,
|
|
||||||
LUP_WORLD_ACCESS = 50,
|
|
||||||
AG_FIRST_FLAG_COLLECTED = 51,
|
|
||||||
TOOLTIP_TALK_TO_SKYLAND_TO_GET_HAT = 52,
|
|
||||||
MODULAR_BUILD_PLAYER_PLACES_FIRST_MODEL_IN_SCRATCH = 53,
|
|
||||||
MODULAR_BUILD_FIRST_ARROW_DISPLAY_FOR_MODULE = 54,
|
|
||||||
AG_BEACON_QB,_SO_THE_PLAYER_CAN_ALWAYS_BUILD_THEM = 55,
|
|
||||||
GF_PET_DIG_FLAG_1 = 56,
|
|
||||||
GF_PET_DIG_FLAG_2 = 57,
|
|
||||||
GF_PET_DIG_FLAG_3 = 58,
|
|
||||||
SUPPRESS_SPACESHIP_CINEMATIC_FLYTHROUGH = 59,
|
|
||||||
GF_PLAYER_FALL_DEATH = 60,
|
|
||||||
GF_PLAYER_CAN_GET_FLAG_1 = 61,
|
|
||||||
GF_PLAYER_CAN_GET_FLAG_2 = 62,
|
|
||||||
GF_PLAYER_CAN_GET_FLAG_3 = 63,
|
|
||||||
ENTER_BBB_FROM_PROPERTY_EDIT_CONFIRMATION_DIALOG = 64,
|
|
||||||
AG_FIRST_COMBAT_COMPLETE = 65,
|
|
||||||
AG_COMPLETE_BOB_MISSION = 66,
|
|
||||||
NJ_GARMADON_CINEMATIC_SEEN = 125,
|
|
||||||
ELEPHANT_PET_3050 = 801,
|
|
||||||
CAT_PET_3054 = 802,
|
|
||||||
TRICERATOPS_PET_3195 = 803,
|
|
||||||
TERRIER_PET_3254 = 804,
|
|
||||||
SKUNK_PET_3261 = 805,
|
|
||||||
LION_PET_3520 = 806,
|
|
||||||
BUNNY_PET_3672 = 807,
|
|
||||||
CROCODILE_PET_3994 = 808,
|
|
||||||
DOBERMAN_PET_5635 = 809,
|
|
||||||
BUFFALO_PET_5636 = 810,
|
|
||||||
ROBOT_DOG_PET_5637 = 811,
|
|
||||||
EUROPEAN_DRAGON_PET_5639 = 812,
|
|
||||||
TORTOISE_PET_5640 = 813,
|
|
||||||
ASIAN_DRAGON_PET_5641 = 814,
|
|
||||||
MANTIS_PET_5642 = 815,
|
|
||||||
PANDA_PET_5643 = 816,
|
|
||||||
WARTHOG_PET_6720 = 817,
|
|
||||||
GOAT_PET_7638 = 818,
|
|
||||||
CRAB_PET_7694 = 819,
|
|
||||||
AG_SPACE_SHIP_BINOC_AT_LAUNCH = 1001,
|
|
||||||
AG_SPACE_SHIP_BINOC_AT_LAUNCH_PLATFORM = 1002,
|
|
||||||
AG_SPACE_SHIP_BINOC_ON_PLATFORM_TO_LEFT_OF_START = 1003,
|
|
||||||
AG_SPACE_SHIP_BINOC_ON_PLATFORM_TO_RIGHT_OF_START = 1004,
|
|
||||||
AG_SPACE_SHIP_BINOC_AT_BOB = 1005,
|
|
||||||
AG_BATTLE_BINOC_FOR_TRICERETOPS = 1101,
|
|
||||||
AG_BATTLE_BINOC_AT_PARADOX = 1102,
|
|
||||||
AG_BATTLE_BINOC_AT_MISSION_GIVER = 1103,
|
|
||||||
AG_BATTLE_BINOC_AT_BECK = 1104,
|
|
||||||
AG_MONUMENT_BINOC_INTRO = 1105,
|
|
||||||
AG_MONUMENT_BINOC_OUTRO = 1106,
|
|
||||||
AG_LAUNCH_BINOC_INTRO = 1107,
|
|
||||||
AG_LAUNCH_BINOC_BISON = 1108,
|
|
||||||
AG_LAUNCH_BINOC_SHARK = 1109,
|
|
||||||
NS_BINOC_CONCERT_TRANSITION = 1201,
|
|
||||||
NS_BINOC_RACE_PLACE_TRANSITION = 1202,
|
|
||||||
NS_BINOC_BRICK_ANNEX_TRANSITION = 1203,
|
|
||||||
NS_BINOC_GF_LAUNCH = 1204,
|
|
||||||
NS_BINOC_FV_LAUNCH = 1205,
|
|
||||||
NS_BINOC_BRICK_ANNEX_WATER = 1206,
|
|
||||||
NS_BINOC_AG_LAUNCH_AT_RACE_PLACE = 1207,
|
|
||||||
NS_BINOC_AG_LAUNCH_AT_BRICK_ANNEX = 1208,
|
|
||||||
NS_BINOC_AG_LAUNCH_AT_PLAZA = 1209,
|
|
||||||
NS_BINOC_TBA = 1210,
|
|
||||||
NS_FLAG_COLLECTABLE_1_BY_JONNY_THUNDER = 1211,
|
|
||||||
NS_FLAG_COLLECTABLE_2_UNDER_CONCERT_BRIDGE = 1212,
|
|
||||||
NS_FLAG_COLLECTABLE_3_BY_FV_LAUNCH = 1213,
|
|
||||||
NS_FLAG_COLLECTABLE_4_IN_PLAZA_BEHIND_BUILDING = 1214,
|
|
||||||
NS_FLAG_COLLECTABLE_5_BY_GF_LAUNCH = 1215,
|
|
||||||
NS_FLAG_COLLECTABLE_6_BY_DUCK_SG = 1216,
|
|
||||||
NS_FLAG_COLLECTABLE_7_BY_LUP_LAUNCH = 1217,
|
|
||||||
NS_FLAG_COLLECTABLE_8_BY_NT_LUANCH = 1218,
|
|
||||||
NS_FLAG_COLLECTABLE_9_BY_RACE_BUILD = 1219,
|
|
||||||
NS_FLAG_COLLECTABLE_10_ON_AG_LAUNCH_PATH = 1220,
|
|
||||||
PR_BINOC_AT_LAUNCH_PAD = 1251,
|
|
||||||
PR_BINOC_AT_BEGINNING_OF_ISLAND_B = 1252,
|
|
||||||
PR_BINOC_AT_FIRST_PET_BOUNCER = 1253,
|
|
||||||
PR_BINOC_ON_BY_CROWS_NEST = 1254,
|
|
||||||
PR_PET_DIG_AT_BEGINNING_OF_ISLAND_B = 1261,
|
|
||||||
PR_PET_DIG_AT_THE_LOCATION_OF_OLD_BOUNCE_BACK = 1262,
|
|
||||||
PR_PET_DIG_UNDER_QB_BRIDGE = 1263,
|
|
||||||
PR_PET_DIG_BACK_SIDE_BY_PARTNER_BOUNCE = 1264,
|
|
||||||
PR_PET_DIG_BY_LAUNCH_PAD = 1265,
|
|
||||||
PR_PET_DIG_BY_FIRST_PET_BOUNCER = 1266,
|
|
||||||
GF_BINOC_ON_LANDING_PAD = 1301,
|
|
||||||
GF_BINOC_AT_RAVINE_START = 1302,
|
|
||||||
GF_BINOC_ON_TOP_OF_RAVINE_HEAD = 1303,
|
|
||||||
GF_BINOC_AT_TURTLE_AREA = 1304,
|
|
||||||
GF_BINOC_IN_TUNNEL_TO_ELEPHANTS = 1305,
|
|
||||||
GF_BINOC_IN_ELEPHANTS_AREA = 1306,
|
|
||||||
GF_BINOC_IN_RACING_AREA = 1307,
|
|
||||||
GF_BINOC_IN_CROC_AREA = 1308,
|
|
||||||
GF_BINOC_IN_JAIL_AREA = 1309,
|
|
||||||
GF_BINOC_TELESCOPE_NEXT_TO_CAPTAIN_JACK = 1310,
|
|
||||||
NT_FACTION_SPY_DUKE = 1974,
|
|
||||||
NT_FACTION_SPY_OVERBUILD = 1976,
|
|
||||||
NT_FACTION_SPY_HAEL = 1977,
|
|
||||||
NJ_EARTH_SPINJITZU = 2030,
|
|
||||||
NJ_LIGHTNING_SPINJITZU = 2031,
|
|
||||||
NJ_ICE_SPINJITZU = 2032,
|
|
||||||
NJ_FIRE_SPINJITZU = 2033,
|
|
||||||
NJ_WU_SHOW_DAILY_CHEST = 2099
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//======== FUNC ===========
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline T const& clamp(const T& val, const T& low, const T& high) {
|
|
||||||
if (val < low) return low;
|
|
||||||
else if (val > high) return high;
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
@ -1,45 +1,53 @@
|
|||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "BinaryPathFinder.h"
|
||||||
|
#include "GeneralUtils.h"
|
||||||
|
|
||||||
dConfig::dConfig(const std::string& filepath) {
|
dConfig::dConfig(const std::string& filepath) {
|
||||||
m_EmptyString = "";
|
m_ConfigFilePath = filepath;
|
||||||
std::ifstream in(filepath);
|
LoadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dConfig::LoadConfig() {
|
||||||
|
std::ifstream in(BinaryPathFinder::GetBinaryDir() / m_ConfigFilePath);
|
||||||
if (!in.good()) return;
|
if (!in.good()) return;
|
||||||
|
|
||||||
std::string line;
|
std::string line{};
|
||||||
while (std::getline(in, line)) {
|
while (std::getline(in, line)) {
|
||||||
if (line.length() > 0) {
|
if (!line.empty() && line.front() != '#') ProcessLine(line);
|
||||||
if (line[0] != '#') 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) {
|
const std::string& dConfig::GetValue(std::string key) {
|
||||||
for (size_t i = 0; i < m_Keys.size(); ++i) {
|
return this->m_ConfigValues[key];
|
||||||
if (m_Keys[i] == key) return m_Values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_EmptyString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dConfig::ProcessLine(const std::string& line) {
|
void dConfig::ProcessLine(const std::string& line) {
|
||||||
std::stringstream ss(line);
|
auto splitLine = GeneralUtils::SplitString(line, '=');
|
||||||
std::string segment;
|
|
||||||
std::vector<std::string> seglist;
|
|
||||||
|
|
||||||
while (std::getline(ss, segment, '=')) {
|
if (splitLine.size() != 2) return;
|
||||||
seglist.push_back(segment);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seglist.size() != 2) return;
|
|
||||||
|
|
||||||
//Make sure that on Linux, we remove special characters:
|
//Make sure that on Linux, we remove special characters:
|
||||||
if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r')
|
auto& key = splitLine.at(0);
|
||||||
seglist[1].erase(seglist[1].size() - 1);
|
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]);
|
if (this->m_ConfigValues.find(key) != this->m_ConfigValues.end()) return;
|
||||||
m_Values.push_back(seglist[1]);
|
|
||||||
|
this->m_ConfigValues.insert(std::make_pair(key, value));
|
||||||
}
|
}
|
@ -1,20 +1,33 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
class dConfig {
|
class dConfig {
|
||||||
public:
|
public:
|
||||||
dConfig(const std::string& filepath);
|
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);
|
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:
|
private:
|
||||||
void ProcessLine(const std::string& line);
|
void ProcessLine(const std::string& line);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> m_Keys;
|
std::map<std::string, std::string> m_ConfigValues;
|
||||||
std::vector<std::string> m_Values;
|
std::string m_ConfigFilePath;
|
||||||
std::string m_EmptyString;
|
|
||||||
};
|
};
|
162
dCommon/dEnums/dCommonVars.h
Normal file
162
dCommon/dEnums/dCommonVars.h
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __DCOMMONVARS__H__
|
||||||
|
#define __DCOMMONVARS__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include "BitStream.h"
|
||||||
|
#include "eConnectionType.h"
|
||||||
|
#include "eClientMessageType.h"
|
||||||
|
|
||||||
|
#pragma warning (disable:4251) //Disables SQL warnings
|
||||||
|
|
||||||
|
// 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 ===========
|
||||||
|
|
||||||
|
#define HEADER_SIZE 8
|
||||||
|
#define CBITSTREAM RakNet::BitStream bitStream;
|
||||||
|
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||||
|
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
|
||||||
|
#define CMSGHEADER PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
||||||
|
#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
|
||||||
|
#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||||
|
|
||||||
|
//=========== TYPEDEFS ==========
|
||||||
|
|
||||||
|
typedef int32_t LOT; //!< A LOT
|
||||||
|
typedef int64_t LWOOBJID; //!< An object ID (should be unsigned actually but ok)
|
||||||
|
typedef int32_t TSkillID; //!< A skill ID
|
||||||
|
typedef uint32_t LWOCLONEID; //!< Used for Clone IDs
|
||||||
|
typedef uint16_t LWOMAPID; //!< Used for Map IDs
|
||||||
|
typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs
|
||||||
|
typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs
|
||||||
|
typedef uint32_t StripId;
|
||||||
|
|
||||||
|
const LWOOBJID LWOOBJID_EMPTY = 0; //!< An empty object ID
|
||||||
|
const LOT LOT_NULL = -1; //!< A null LOT
|
||||||
|
const int32_t LOOTTYPE_NONE = 0; //!< No loot type available
|
||||||
|
const float SECONDARY_PRIORITY = 1.0f; //!< Secondary Priority
|
||||||
|
const uint32_t INVENTORY_MAX = 9999999; //!< The Maximum Inventory Size
|
||||||
|
const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
|
||||||
|
const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
|
||||||
|
const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
|
||||||
|
const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
|
||||||
|
|
||||||
|
const float PI = 3.14159f;
|
||||||
|
|
||||||
|
//============ STRUCTS ==============
|
||||||
|
|
||||||
|
struct LWOSCENEID {
|
||||||
|
public:
|
||||||
|
LWOSCENEID() { m_sceneID = -1; m_layerID = 0; }
|
||||||
|
LWOSCENEID(int sceneID) { m_sceneID = sceneID; m_layerID = 0; }
|
||||||
|
LWOSCENEID(int sceneID, unsigned int layerID) { m_sceneID = sceneID; m_layerID = layerID; }
|
||||||
|
|
||||||
|
LWOSCENEID& operator=(const LWOSCENEID& rhs) { m_sceneID = rhs.m_sceneID; m_layerID = rhs.m_layerID; return *this; }
|
||||||
|
LWOSCENEID& operator=(const int rhs) { m_sceneID = rhs; m_layerID = 0; return *this; }
|
||||||
|
|
||||||
|
bool operator<(const LWOSCENEID& rhs) const { return (m_sceneID < rhs.m_sceneID || (m_sceneID == rhs.m_sceneID && m_layerID < rhs.m_layerID)); }
|
||||||
|
bool operator<(const int rhs) const { return m_sceneID < rhs; }
|
||||||
|
|
||||||
|
bool operator==(const LWOSCENEID& rhs) const { return (m_sceneID == rhs.m_sceneID && m_layerID == rhs.m_layerID); }
|
||||||
|
bool operator==(const int rhs) const { return m_sceneID == rhs; }
|
||||||
|
|
||||||
|
const int GetSceneID() const { return m_sceneID; }
|
||||||
|
const unsigned int GetLayerID() const { return m_layerID; }
|
||||||
|
|
||||||
|
void SetSceneID(const int sceneID) { m_sceneID = sceneID; }
|
||||||
|
void SetLayerID(const unsigned int layerID) { m_layerID = layerID; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_sceneID;
|
||||||
|
unsigned int m_layerID;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LWOZONEID {
|
||||||
|
public:
|
||||||
|
const LWOMAPID& GetMapID() const { return m_MapID; }
|
||||||
|
const LWOINSTANCEID& GetInstanceID() const { return m_InstanceID; }
|
||||||
|
const LWOCLONEID& GetCloneID() const { return m_CloneID; }
|
||||||
|
|
||||||
|
//In order: def constr, constr, assign op
|
||||||
|
LWOZONEID() { m_MapID = LWOMAPID_INVALID; m_InstanceID = LWOINSTANCEID_INVALID; m_CloneID = LWOCLONEID_INVALID; }
|
||||||
|
LWOZONEID(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) { m_MapID = mapID; m_InstanceID = instanceID; m_CloneID = cloneID; }
|
||||||
|
LWOZONEID(const LWOZONEID& replacement) { *this = replacement; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
LWOMAPID m_MapID; //1000 for VE, 1100 for AG, etc...
|
||||||
|
LWOINSTANCEID m_InstanceID; //Instances host the same world, but on a different dWorld process.
|
||||||
|
LWOCLONEID m_CloneID; //To differentiate between "your property" and "my property". Always 0 for non-prop worlds.
|
||||||
|
};
|
||||||
|
|
||||||
|
const LWOSCENEID LWOSCENEID_INVALID = -1;
|
||||||
|
|
||||||
|
struct LWONameValue {
|
||||||
|
uint32_t length = 0; //!< The length of the name
|
||||||
|
std::u16string name; //!< The name
|
||||||
|
|
||||||
|
LWONameValue(void) {}
|
||||||
|
|
||||||
|
LWONameValue(const std::u16string& name) {
|
||||||
|
this->name = name;
|
||||||
|
this->length = static_cast<uint32_t>(name.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
~LWONameValue(void) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FriendData {
|
||||||
|
public:
|
||||||
|
bool isOnline = false;
|
||||||
|
bool isBestFriend = false;
|
||||||
|
bool isFTP = false;
|
||||||
|
LWOZONEID zoneID;
|
||||||
|
LWOOBJID friendID;
|
||||||
|
std::string friendName;
|
||||||
|
|
||||||
|
void Serialize(RakNet::BitStream& bitStream) {
|
||||||
|
bitStream.Write<uint8_t>(isOnline);
|
||||||
|
bitStream.Write<uint8_t>(isBestFriend);
|
||||||
|
bitStream.Write<uint8_t>(isFTP);
|
||||||
|
bitStream.Write<uint32_t>(0); //???
|
||||||
|
bitStream.Write<uint8_t>(0); //???
|
||||||
|
bitStream.Write(zoneID.GetMapID());
|
||||||
|
bitStream.Write(zoneID.GetInstanceID());
|
||||||
|
bitStream.Write(zoneID.GetCloneID());
|
||||||
|
bitStream.Write(friendID);
|
||||||
|
|
||||||
|
uint32_t maxSize = 33;
|
||||||
|
uint32_t size = static_cast<uint32_t>(friendName.length());
|
||||||
|
uint32_t remSize = static_cast<uint32_t>(maxSize - size);
|
||||||
|
|
||||||
|
if (size > maxSize) size = maxSize;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < size; ++i) {
|
||||||
|
bitStream.Write(static_cast<uint16_t>(friendName[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < remSize; ++j) {
|
||||||
|
bitStream.Write(static_cast<uint16_t>(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
bitStream.Write<uint32_t>(0); //???
|
||||||
|
bitStream.Write<uint16_t>(0); //???
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__DCOMMONVARS__H__
|
29
dCommon/dEnums/dPlatforms.h
Normal file
29
dCommon/dEnums/dPlatforms.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define DARKFLAME_PLATFORM_WIN32
|
||||||
|
#elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
|
||||||
|
#define DARKFLAME_PLATFORM_IOS
|
||||||
|
#elif TARGET_OS_MAC
|
||||||
|
#define DARKFLAME_PLATFORM_MACOS
|
||||||
|
#else
|
||||||
|
#error unknown Apple operating system
|
||||||
|
#endif
|
||||||
|
#elif defined(__unix__)
|
||||||
|
#define DARKFLAME_PLATFORM_UNIX
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#define DARKFLAME_PLATFORM_ANDROID
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#define DARKFLAME_PLATFORM_LINUX
|
||||||
|
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
|
#define DARKFLAME_PLATFORM_FREEBSD
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
#define DARKFLAME_PLATFORM_CYGWIN
|
||||||
|
#else
|
||||||
|
#error unknown unix operating system
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error unknown operating system
|
||||||
|
#endif
|
16
dCommon/dEnums/dpCollisionGroups.h
Normal file
16
dCommon/dEnums/dpCollisionGroups.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Collision Groups
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum eCollisionGroup : uint8_t
|
||||||
|
{
|
||||||
|
COLLISION_GROUP_ALL = 0 << 0,
|
||||||
|
COLLISION_GROUP_NEUTRAL = 1 << 0,
|
||||||
|
COLLISION_GROUP_FRIENDLY = 1 << 1,
|
||||||
|
COLLISION_GROUP_ENEMY = 1 << 2,
|
||||||
|
COLLISION_GROUP_DYNAMIC = 1 << 3,
|
||||||
|
};
|
15
dCommon/dEnums/eAddFriendResponseCode.h
Normal file
15
dCommon/dEnums/eAddFriendResponseCode.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __EADDFRIENDRESPONSECODE__H__
|
||||||
|
#define __EADDFRIENDRESPONSECODE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eAddFriendResponseCode : uint8_t {
|
||||||
|
ACCEPTED = 0,
|
||||||
|
REJECTED,
|
||||||
|
BUSY,
|
||||||
|
CANCELLED
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ADDFRIENDRESPONSECODE__H__
|
24
dCommon/dEnums/eAddFriendResponseType.h
Normal file
24
dCommon/dEnums/eAddFriendResponseType.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __EADDFRIENDRESPONSETYPE__H__
|
||||||
|
#define __EADDFRIENDRESPONSETYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eAddFriendResponseType : uint8_t {
|
||||||
|
ACCEPTED = 0,
|
||||||
|
ALREADYFRIEND,
|
||||||
|
INVALIDCHARACTER,
|
||||||
|
GENERALERROR,
|
||||||
|
YOURFRIENDSLISTFULL,
|
||||||
|
THEIRFRIENDLISTFULL,
|
||||||
|
DECLINED,
|
||||||
|
BUSY,
|
||||||
|
NOTONLINE,
|
||||||
|
WAITINGAPPROVAL,
|
||||||
|
MYTHRAN,
|
||||||
|
CANCELLED,
|
||||||
|
FRIENDISFREETRIAL
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EADDFRIENDRESPONSETYPE__H__
|
44
dCommon/dEnums/eAninmationFlags.h
Normal file
44
dCommon/dEnums/eAninmationFlags.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __EANINMATIONFLAGS__H__
|
||||||
|
#define __EANINMATIONFLAGS__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eAnimationFlags : uint32_t {
|
||||||
|
IDLE_NONE = 0,
|
||||||
|
IDLE_BASIC,
|
||||||
|
IDLE_SWIM,
|
||||||
|
IDLE_CARRY,
|
||||||
|
IDLE_SWORD,
|
||||||
|
IDLE_HAMMER,
|
||||||
|
IDLE_SPEAR,
|
||||||
|
IDLE_PISTOL,
|
||||||
|
IDLE_BOW,
|
||||||
|
IDLE_COMBAT,
|
||||||
|
IDLE_JETPACK,
|
||||||
|
IDLE_HORSE,
|
||||||
|
IDLE_SG,
|
||||||
|
IDLE_ORGAN,
|
||||||
|
IDLE_SKATEBOARD,
|
||||||
|
IDLE_DAREDEVIL,
|
||||||
|
IDLE_SAMURAI,
|
||||||
|
IDLE_SUMMONER,
|
||||||
|
IDLE_BUCCANEER,
|
||||||
|
IDLE_MISC,
|
||||||
|
IDLE_NINJA,
|
||||||
|
IDLE_MISC1,
|
||||||
|
IDLE_MISC2,
|
||||||
|
IDLE_MISC3,
|
||||||
|
IDLE_MISC4,
|
||||||
|
IDLE_MISC5,
|
||||||
|
IDLE_MISC6,
|
||||||
|
IDLE_MISC7,
|
||||||
|
IDLE_MISC8,
|
||||||
|
IDLE_MISC9,
|
||||||
|
IDLE_MISC10,
|
||||||
|
IDLE_MISC11,
|
||||||
|
IDLE_MISC12
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EANINMATIONFLAGS__H__
|
15
dCommon/dEnums/eAuthMessageType.h
Normal file
15
dCommon/dEnums/eAuthMessageType.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __EAUTHMESSAGETYPE__H__
|
||||||
|
#define __EAUTHMESSAGETYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eAuthMessageType : uint32_t {
|
||||||
|
LOGIN_REQUEST = 0,
|
||||||
|
LOGOUT_REQUEST,
|
||||||
|
CREATE_NEW_ACCOUNT_REQUEST,
|
||||||
|
LEGOINTERFACE_AUTH_RESPONSE,
|
||||||
|
SESSIONKEY_RECEIVED_CONFIRM,
|
||||||
|
RUNTIME_CONFIG
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EAUTHMESSAGETYPE__H__
|
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__
|
12
dCommon/dEnums/eBuildType.h
Normal file
12
dCommon/dEnums/eBuildType.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __EBUILDTYPE__H__
|
||||||
|
#define __EBUILDTYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eBuildType :uint32_t {
|
||||||
|
NOWHERE,
|
||||||
|
IN_WORLD,
|
||||||
|
ON_PROPERTY
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EBUILDTYPE__H__
|
14
dCommon/dEnums/eCharacterCreationResponse.h
Normal file
14
dCommon/dEnums/eCharacterCreationResponse.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __ECHARACTERCREATIONRESPONSE__H__
|
||||||
|
#define __ECHARACTERCREATIONRESPONSE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eCharacterCreationResponse : uint8_t {
|
||||||
|
SUCCESS = 0,
|
||||||
|
OBJECT_ID_UNAVAILABLE,
|
||||||
|
NAME_NOT_ALLOWED,
|
||||||
|
PREDEFINED_NAME_IN_USE,
|
||||||
|
CUSTOM_NAME_IN_USE
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ECHARACTERCREATIONRESPONSE__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__
|
31
dCommon/dEnums/eChatInternalMessageType.h
Normal file
31
dCommon/dEnums/eChatInternalMessageType.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef __ECHATINTERNALMESSAGETYPE__H__
|
||||||
|
#define __ECHATINTERNALMESSAGETYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum eChatInternalMessageType : uint32_t {
|
||||||
|
PLAYER_ADDED_NOTIFICATION = 0,
|
||||||
|
PLAYER_REMOVED_NOTIFICATION,
|
||||||
|
ADD_FRIEND,
|
||||||
|
ADD_BEST_FRIEND,
|
||||||
|
ADD_TO_TEAM,
|
||||||
|
ADD_BLOCK,
|
||||||
|
REMOVE_FRIEND,
|
||||||
|
REMOVE_BLOCK,
|
||||||
|
REMOVE_FROM_TEAM,
|
||||||
|
DELETE_TEAM,
|
||||||
|
REPORT,
|
||||||
|
PRIVATE_CHAT,
|
||||||
|
PRIVATE_CHAT_RESPONSE,
|
||||||
|
ANNOUNCEMENT,
|
||||||
|
MAIL_COUNT_UPDATE,
|
||||||
|
MAIL_SEND_NOTIFY,
|
||||||
|
REQUEST_USER_LIST,
|
||||||
|
FRIEND_LIST,
|
||||||
|
ROUTE_TO_PLAYER,
|
||||||
|
TEAM_UPDATE,
|
||||||
|
MUTE_UPDATE,
|
||||||
|
CREATE_TEAM,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ECHATINTERNALMESSAGETYPE__H__
|
78
dCommon/dEnums/eChatMessageType.h
Normal file
78
dCommon/dEnums/eChatMessageType.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef __ECHATMESSAGETYPE__H__
|
||||||
|
#define __ECHATMESSAGETYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
//! The Internal Chat Packet Identifiers
|
||||||
|
enum class eChatMessageType :uint32_t {
|
||||||
|
LOGIN_SESSION_NOTIFY = 0,
|
||||||
|
GENERAL_CHAT_MESSAGE,
|
||||||
|
PRIVATE_CHAT_MESSAGE,
|
||||||
|
USER_CHANNEL_CHAT_MESSAGE,
|
||||||
|
WORLD_DISCONNECT_REQUEST,
|
||||||
|
WORLD_PROXIMITY_RESPONSE,
|
||||||
|
WORLD_PARCEL_RESPONSE,
|
||||||
|
ADD_FRIEND_REQUEST,
|
||||||
|
ADD_FRIEND_RESPONSE,
|
||||||
|
REMOVE_FRIEND,
|
||||||
|
GET_FRIENDS_LIST,
|
||||||
|
ADD_IGNORE,
|
||||||
|
REMOVE_IGNORE,
|
||||||
|
GET_IGNORE_LIST,
|
||||||
|
TEAM_MISSED_INVITE_CHECK,
|
||||||
|
TEAM_INVITE,
|
||||||
|
TEAM_INVITE_RESPONSE,
|
||||||
|
TEAM_KICK,
|
||||||
|
TEAM_LEAVE,
|
||||||
|
TEAM_SET_LOOT,
|
||||||
|
TEAM_SET_LEADER,
|
||||||
|
TEAM_GET_STATUS,
|
||||||
|
GUILD_CREATE,
|
||||||
|
GUILD_INVITE,
|
||||||
|
GUILD_INVITE_RESPONSE,
|
||||||
|
GUILD_LEAVE,
|
||||||
|
GUILD_KICK,
|
||||||
|
GUILD_GET_STATUS,
|
||||||
|
GUILD_GET_ALL,
|
||||||
|
SHOW_ALL,
|
||||||
|
BLUEPRINT_MODERATED,
|
||||||
|
BLUEPRINT_MODEL_READY,
|
||||||
|
PROPERTY_READY_FOR_APPROVAL,
|
||||||
|
PROPERTY_MODERATION_CHANGED,
|
||||||
|
PROPERTY_BUILDMODE_CHANGED,
|
||||||
|
PROPERTY_BUILDMODE_CHANGED_REPORT,
|
||||||
|
MAIL,
|
||||||
|
WORLD_INSTANCE_LOCATION_REQUEST,
|
||||||
|
REPUTATION_UPDATE,
|
||||||
|
SEND_CANNED_TEXT,
|
||||||
|
GMLEVEL_UPDATE,
|
||||||
|
CHARACTER_NAME_CHANGE_REQUEST,
|
||||||
|
CSR_REQUEST,
|
||||||
|
CSR_REPLY,
|
||||||
|
GM_KICK,
|
||||||
|
GM_ANNOUNCE,
|
||||||
|
GM_MUTE,
|
||||||
|
ACTIVITY_UPDATE,
|
||||||
|
WORLD_ROUTE_PACKET,
|
||||||
|
GET_ZONE_POPULATIONS,
|
||||||
|
REQUEST_MINIMUM_CHAT_MODE,
|
||||||
|
REQUEST_MINIMUM_CHAT_MODE_PRIVATE,
|
||||||
|
MATCH_REQUEST,
|
||||||
|
UGCMANIFEST_REPORT_MISSING_FILE,
|
||||||
|
UGCMANIFEST_REPORT_DONE_FILE,
|
||||||
|
UGCMANIFEST_REPORT_DONE_BLUEPRINT,
|
||||||
|
UGCC_REQUEST,
|
||||||
|
WHO,
|
||||||
|
WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE,
|
||||||
|
ACHIEVEMENT_NOTIFY,
|
||||||
|
GM_CLOSE_PRIVATE_CHAT_WINDOW,
|
||||||
|
UNEXPECTED_DISCONNECT,
|
||||||
|
PLAYER_READY,
|
||||||
|
GET_DONATION_TOTAL,
|
||||||
|
UPDATE_DONATION,
|
||||||
|
PRG_CSR_COMMAND,
|
||||||
|
HEARTBEAT_REQUEST_FROM_WORLD,
|
||||||
|
UPDATE_FREE_TRIAL_STATUS
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ECHATMESSAGETYPE__H__
|
12
dCommon/dEnums/eCinematicEvent.h
Normal file
12
dCommon/dEnums/eCinematicEvent.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __ECINEMATICEVENT__H__
|
||||||
|
#define __ECINEMATICEVENT__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eCinematicEvent : uint32_t {
|
||||||
|
STARTED,
|
||||||
|
WAYPOINT,
|
||||||
|
ENDED,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ECINEMATICEVENT__H__
|
76
dCommon/dEnums/eClientMessageType.h
Normal file
76
dCommon/dEnums/eClientMessageType.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#ifndef __ECLIENTMESSAGETYPE__H__
|
||||||
|
#define __ECLIENTMESSAGETYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eClientMessageType : uint32_t {
|
||||||
|
LOGIN_RESPONSE = 0,
|
||||||
|
LOGOUT_RESPONSE,
|
||||||
|
LOAD_STATIC_ZONE,
|
||||||
|
CREATE_OBJECT,
|
||||||
|
CREATE_CHARACTER,
|
||||||
|
CREATE_CHARACTER_EXTENDED,
|
||||||
|
CHARACTER_LIST_RESPONSE,
|
||||||
|
CHARACTER_CREATE_RESPONSE,
|
||||||
|
CHARACTER_RENAME_RESPONSE,
|
||||||
|
CHAT_CONNECT_RESPONSE,
|
||||||
|
AUTH_ACCOUNT_CREATE_RESPONSE,
|
||||||
|
DELETE_CHARACTER_RESPONSE,
|
||||||
|
GAME_MSG,
|
||||||
|
CONNECT_CHAT,
|
||||||
|
TRANSFER_TO_WORLD,
|
||||||
|
IMPENDING_RELOAD_NOTIFY,
|
||||||
|
MAKE_GM_RESPONSE,
|
||||||
|
HTTP_MONITOR_INFO_RESPONSE,
|
||||||
|
SLASH_PUSH_MAP_RESPONSE,
|
||||||
|
SLASH_PULL_MAP_RESPONSE,
|
||||||
|
SLASH_LOCK_MAP_RESPONSE,
|
||||||
|
BLUEPRINT_SAVE_RESPONSE,
|
||||||
|
BLUEPRINT_LUP_SAVE_RESPONSE,
|
||||||
|
BLUEPRINT_LOAD_RESPONSE_ITEMID,
|
||||||
|
BLUEPRINT_GET_ALL_DATA_RESPONSE,
|
||||||
|
MODEL_INSTANTIATE_RESPONSE,
|
||||||
|
DEBUG_OUTPUT,
|
||||||
|
ADD_FRIEND_REQUEST,
|
||||||
|
ADD_FRIEND_RESPONSE,
|
||||||
|
REMOVE_FRIEND_RESPONSE,
|
||||||
|
GET_FRIENDS_LIST_RESPONSE,
|
||||||
|
UPDATE_FRIEND_NOTIFY,
|
||||||
|
ADD_IGNORE_RESPONSE,
|
||||||
|
REMOVE_IGNORE_RESPONSE,
|
||||||
|
GET_IGNORE_LIST_RESPONSE,
|
||||||
|
TEAM_INVITE,
|
||||||
|
TEAM_INVITE_INITIAL_RESPONSE,
|
||||||
|
GUILD_CREATE_RESPONSE,
|
||||||
|
GUILD_GET_STATUS_RESPONSE,
|
||||||
|
GUILD_INVITE,
|
||||||
|
GUILD_INVITE_INITIAL_RESPONSE,
|
||||||
|
GUILD_INVITE_FINAL_RESPONSE,
|
||||||
|
GUILD_INVITE_CONFIRM,
|
||||||
|
GUILD_ADD_PLAYER,
|
||||||
|
GUILD_REMOVE_PLAYER,
|
||||||
|
GUILD_LOGIN_LOGOUT,
|
||||||
|
GUILD_RANK_CHANGE,
|
||||||
|
GUILD_DATA,
|
||||||
|
GUILD_STATUS,
|
||||||
|
MAIL,
|
||||||
|
DB_PROXY_RESULT,
|
||||||
|
SHOW_ALL_RESPONSE,
|
||||||
|
WHO_RESPONSE,
|
||||||
|
SEND_CANNED_TEXT,
|
||||||
|
UPDATE_CHARACTER_NAME,
|
||||||
|
SET_NETWORK_SIMULATOR,
|
||||||
|
INVALID_CHAT_MESSAGE,
|
||||||
|
MINIMUM_CHAT_MODE_RESPONSE,
|
||||||
|
MINIMUM_CHAT_MODE_RESPONSE_PRIVATE,
|
||||||
|
CHAT_MODERATION_STRING,
|
||||||
|
UGC_MANIFEST_RESPONSE,
|
||||||
|
IN_LOGIN_QUEUE,
|
||||||
|
SERVER_STATES,
|
||||||
|
GM_CLOSE_TARGET_CHAT_WINDOW,
|
||||||
|
GENERAL_TEXT_FOR_LOCALIZATION,
|
||||||
|
UPDATE_FREE_TRIAL_STATUS,
|
||||||
|
UGC_DOWNLOAD_FAILED = 120
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ECLIENTMESSAGETYPE__H__
|
14
dCommon/dEnums/eConnectionType.h
Normal file
14
dCommon/dEnums/eConnectionType.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __ECONNECTIONTYPE__H__
|
||||||
|
#define __ECONNECTIONTYPE__H__
|
||||||
|
|
||||||
|
enum class eConnectionType : uint16_t {
|
||||||
|
SERVER = 0,
|
||||||
|
AUTH,
|
||||||
|
CHAT,
|
||||||
|
CHAT_INTERNAL,
|
||||||
|
WORLD,
|
||||||
|
CLIENT,
|
||||||
|
MASTER
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ECONNECTIONTYPE__H__
|
18
dCommon/dEnums/eControlScheme.h
Normal file
18
dCommon/dEnums/eControlScheme.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef __ECONTROLSCHEME__H__
|
||||||
|
#define __ECONTROLSCHEME__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eControlScheme : uint32_t {
|
||||||
|
SCHEME_A,
|
||||||
|
SCHEME_D,
|
||||||
|
SCHEME_GAMEPAD,
|
||||||
|
SCHEME_E,
|
||||||
|
SCHEME_FPS,
|
||||||
|
SCHEME_DRIVING,
|
||||||
|
SCHEME_TAMING,
|
||||||
|
SCHEME_MODULAR_BUILD,
|
||||||
|
SCHEME_WEAR_A_ROBOT //== freecam?
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ECONTROLSCHEME__H__
|
11
dCommon/dEnums/eCyclingMode.h
Normal file
11
dCommon/dEnums/eCyclingMode.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __ECYCLINGMODE__H__
|
||||||
|
#define __ECYCLINGMODE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eCyclingMode : uint32_t {
|
||||||
|
ALLOW_CYCLE_TEAMMATES,
|
||||||
|
DISALLOW_CYCLING
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ECYCLINGMODE__H__
|
11
dCommon/dEnums/eEndBehavior.h
Normal file
11
dCommon/dEnums/eEndBehavior.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __EENDBEHAVIOR__H__
|
||||||
|
#define __EENDBEHAVIOR__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eEndBehavior : uint32_t {
|
||||||
|
RETURN,
|
||||||
|
WAIT
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EENDBEHAVIOR__H__
|
15
dCommon/dEnums/eGameActivity.h
Normal file
15
dCommon/dEnums/eGameActivity.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __EGAMEACTIVITY__H__
|
||||||
|
#define __EGAMEACTIVITY__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class eGameActivity : uint32_t {
|
||||||
|
NONE,
|
||||||
|
QUICKBUILDING,
|
||||||
|
SHOOTING_GALLERY,
|
||||||
|
RACING,
|
||||||
|
PINBALL,
|
||||||
|
PET_TAMING
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__EGAMEACTIVITY__H__
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user