Merge branch 'main' into cdclient-rework

This commit is contained in:
Wincent Holm 2022-10-29 21:52:08 +02:00
commit 633b87a5e7
963 changed files with 39754 additions and 41072 deletions

76
.editorconfig Normal file
View 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

8
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,8 @@
# format codebase
19e77a38d837ce781ba0ca6ea8e78b67a6e3b5a5
# add semi-colons to macros consistently
9e4ce24fd2851e65df776dd9c57bcb0d45f4453a
# convert to unix line endings
72477e01e2711e0f61cdb192ee266e5e21b8846f

2
.gitattributes vendored
View File

@ -1 +1 @@
*.sh eol=lf * text=auto eol=lf

2
.gitignore vendored
View File

@ -120,3 +120,5 @@ thirdparty/zlib-1.2.11/
docker/__pycache__ docker/__pycache__
docker-compose.override.yml docker-compose.override.yml
!/tests/TestBitStreams/*.bin

View File

@ -42,6 +42,12 @@ set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT
# Echo the version # Echo the version
message(STATUS "Version: ${PROJECT_VERSION}") message(STATUS "Version: ${PROJECT_VERSION}")
# 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.
set(RECASTNAVIGATION_DEMO OFF CACHE BOOL "" FORCE)
set(RECASTNAVIGATION_TESTS OFF CACHE BOOL "" FORCE)
set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE)
# 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.
@ -54,7 +60,7 @@ if(UNIX)
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")
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)
@ -63,7 +69,7 @@ if(UNIX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
elseif(MSVC) elseif(MSVC)
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now # Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
add_compile_options("/wd4267") add_compile_options("/wd4267" "/utf-8")
elseif(WIN32) elseif(WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS) add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif() endif()
@ -83,14 +89,15 @@ make_directory(${CMAKE_BINARY_DIR}/locale)
# Create a /logs directory # Create a /logs directory
make_directory(${CMAKE_BINARY_DIR}/logs) make_directory(${CMAKE_BINARY_DIR}/logs)
# Copy ini files on first build # Copy resource files on first build
set(INI_FILES "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini") set(RESOURCE_FILES "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
foreach(ini ${INI_FILES}) foreach(resource_file ${RESOURCE_FILES})
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${ini}) if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
configure_file( configure_file(
${CMAKE_SOURCE_DIR}/resources/${ini} ${PROJECT_BINARY_DIR}/${ini} ${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
COPYONLY COPYONLY
) )
message("Moved ${resource_file} to project binary directory")
endif() endif()
endforeach() endforeach()
@ -126,6 +133,8 @@ set(INCLUDED_DIRECTORIES
"dGame/dEntity" "dGame/dEntity"
"dGame/dUtilities" "dGame/dUtilities"
"dPhysics" "dPhysics"
"dNavigation"
"dNavigation/dTerrain"
"dZoneManager" "dZoneManager"
"dDatabase" "dDatabase"
"dDatabase/Tables" "dDatabase/Tables"
@ -134,8 +143,7 @@ set(INCLUDED_DIRECTORIES
"thirdparty/raknet/Source" "thirdparty/raknet/Source"
"thirdparty/tinyxml2" "thirdparty/tinyxml2"
"thirdparty/recastnavigation/Recast/Include" "thirdparty/recastnavigation"
"thirdparty/recastnavigation/Detour/Include"
"thirdparty/SQLite" "thirdparty/SQLite"
"thirdparty/cpplinq" "thirdparty/cpplinq"
) )
@ -152,7 +160,6 @@ elseif (UNIX)
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt") set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt")
endif() endif()
include_directories(${ZLIB_INCLUDE_DIRS})
# Add binary directory as an include directory # Add binary directory as an include directory
include_directories(${PROJECT_BINARY_DIR}) include_directories(${PROJECT_BINARY_DIR})
@ -205,6 +212,7 @@ add_subdirectory(dNet)
add_subdirectory(dScripts) # Add for dGame to use add_subdirectory(dScripts) # Add for dGame to use
add_subdirectory(dGame) add_subdirectory(dGame)
add_subdirectory(dZoneManager) add_subdirectory(dZoneManager)
add_subdirectory(dNavigation)
add_subdirectory(dPhysics) add_subdirectory(dPhysics)
# Create a list of common libraries shared between all binaries # Create a list of common libraries shared between all binaries

View File

@ -118,6 +118,11 @@
"execution": { "execution": {
"jobs": 2 "jobs": 2
}, },
"filter": {
"exclude": {
"name": "((example)|(minigzip))+"
}
},
"output": { "output": {
"outputOnFailure": true "outputOnFailure": true
} }

View File

@ -1,6 +1,6 @@
PROJECT_VERSION_MAJOR=1 PROJECT_VERSION_MAJOR=1
PROJECT_VERSION_MINOR=0 PROJECT_VERSION_MINOR=0
PROJECT_VERSION_PATCH=3 PROJECT_VERSION_PATCH=4
# LICENSE # LICENSE
LICENSE=AGPL-3.0 LICENSE=AGPL-3.0
# The network version. # The network version.
@ -8,7 +8,7 @@ LICENSE=AGPL-3.0
# 171022 - Unmodded client # 171022 - Unmodded client
NET_VERSION=171022 NET_VERSION=171022
# Debugging # Debugging
# __dynamic=1 __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 # __ggdb=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.

View File

@ -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.

View File

@ -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

View File

@ -27,11 +27,11 @@ Darkflame Universe is a server emulator and does not distribute any LEGO® Unive
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. 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.
### Prerequisites ### Prerequisites
**Clone the repository** #### Clone the repository
```bash ```bash
git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
``` ```
**Python** #### Python
Some tools utilized to streamline the setup process require Python 3, make sure you have it installed. Some tools utilized to streamline the setup process require Python 3, make sure you have it installed.
@ -42,12 +42,17 @@ This was done make sure that older and incomplete clients wouldn't produce false
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. 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.
### Using Docker
Refer to [Docker.md](/Docker.md).
For Windows, refer to [Docker_Windows.md](/Docker_Windows.md).
### Linux builds ### Linux builds
Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. 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! CMake must be version 3.14 or higher!
**Build the repository** #### Build the repository
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:
@ -65,8 +70,8 @@ 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
``` ```
### MacOS builds ### MacOS builds
@ -88,7 +93,7 @@ cmake --build . --config Release
### Windows builds (native) ### 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. 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** #### Build the repository
```batch ```batch
:: Create the build directory :: Create the build directory
mkdir build mkdir build
@ -100,7 +105,7 @@ cmake ..
:: Run CMake with build flag to build :: Run CMake with build flag to build
cmake --build . --config Release cmake --build . --config Release
``` ```
**Windows for ARM** has not been tested but should build by doing the following #### Windows for ARM has not been tested but should build by doing the following
```batch ```batch
:: Create the build directory :: Create the build directory
mkdir build mkdir build
@ -116,13 +121,13 @@ cmake --build . --config Release
### Windows builds (WSL) ### 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. 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:** #### Open the Command Prompt application with Administrator permissions and run the following:
```bash ```bash
# Installing Windows Subsystem for Linux # Installing Windows Subsystem for Linux
wsl --install wsl --install
``` ```
**Open the Ubuntu application and run the following:** #### Open the Ubuntu application and run the following:
```bash ```bash
# Make sure the install is up to date # Make sure the install is up to date
apt update && apt upgrade apt update && apt upgrade
@ -154,7 +159,7 @@ now follow the build section for your system
### Resources ### Resources
**LEGO® Universe 1.10.64** #### 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. 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.
@ -177,20 +182,20 @@ shasum -a 256 <file>
certutil -hashfile <file> SHA256 certutil -hashfile <file> SHA256
``` ```
**Unpacking the client** #### Unpacking the client
* Clone lcdr's utilities repository [here](https://github.com/lcdr/utils) * 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 * Use `pkextractor.pyw` to unpack the client files if they are not already unpacked
**Setup resource directory** #### Setup resource directory
* In the `build` directory create a `res` directory if it does not already exist. * 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 * 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` * Unzip the navmeshes [here](./resources/navmeshes.zip) and place them in `build/res/maps/navmeshes`
**Setup locale** #### Setup locale
* In the `build` directory create a `locale` directory if it does not already exist * 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 * Copy over or create symlinks from `locale.xml` in your client `locale` directory to the `build/locale` directory
**Client database** #### 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` * 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` * 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 * Run each SQL file in the order at which they appear [here](migrations/cdserver/) on the SQLite database
@ -199,14 +204,18 @@ certutil -hashfile <file> SHA256
Darkflame Universe utilizes a MySQL/MariaDB database for account and character information. 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. 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
* Use the command `./MasterServer -m` to automatically run them.
**Configuration** * All that you need to do is create a database to connect to. As long as the server can connect to the database, the schema will always be kept up to date when you start the server.
#### 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. 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** #### Migrations
The database is automatically setup and migrated to what it should look like for the latest commit whenever you start the server.
#### Verify
Your build directory should now look like this: Your build directory should now look like this:
* AuthServer * AuthServer
@ -417,10 +426,11 @@ Here is a summary of the commands available in-game. All commands are prefixed b
</tbody> </tbody>
</table> </table>
## Credits # Credits
## Active Contributors ## Active Contributors
* [EmosewaMC](https://github.com/EmosewaMC) * [EmosewaMC](https://github.com/EmosewaMC)
* [Jettford](https://github.com/Jettford) * [Jettford](https://github.com/Jettford)
* [Aaron K.](https://github.com/aronwk-aaron)
## DLU Team ## DLU Team
* [DarwinAnim8or](https://github.com/DarwinAnim8or) * [DarwinAnim8or](https://github.com/DarwinAnim8or)
@ -429,10 +439,6 @@ 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)
* TheMachine
* Matthew
* [Raine](https://github.com/Rainebannister)
* Bricknave
### Research and tools ### Research and tools
* [lcdr](https://github.com/lcdr) * [lcdr](https://github.com/lcdr)
@ -444,11 +450,14 @@ Here is a summary of the commands available in-game. All commands are prefixed b
### Former contributors ### Former contributors
* TheMachine * TheMachine
* Matthew * Matthew
* Raine * [Raine](https://github.com/Rainebannister)
* Bricknave * Bricknave
### Special thanks ### Logo
* Cole Peterson (BlasterBuilder)
## 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!

51
SECURITY.md Normal file
View 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

View File

@ -5,5 +5,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

View File

@ -37,9 +37,9 @@ int main(int argc, char** argv) {
//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 0;
Game::logger->Log("AuthServer", "Starting Auth server...\n"); Game::logger->Log("AuthServer", "Starting Auth server...");
Game::logger->Log("AuthServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("AuthServer", "Compiled on: %s\n", __TIMESTAMP__); Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__);
//Read our config: //Read our config:
dConfig config("authconfig.ini"); dConfig config("authconfig.ini");
@ -56,7 +56,7 @@ int main(int argc, char** argv) {
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;
@ -98,8 +98,7 @@ int main(int argc, char** argv) {
if (framesSinceMasterDisconnect >= 30) if (framesSinceMasterDisconnect >= 30)
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.
@ -134,8 +133,7 @@ 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(mediumFramerate); //Auth can run at a lower "fps"
@ -151,7 +149,7 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
dLogger * SetupLogger() { dLogger* SetupLogger() {
std::string logPath = "./logs/AuthServer_" + std::to_string(time(nullptr)) + ".log"; std::string logPath = "./logs/AuthServer_" + std::to_string(time(nullptr)) + ".log";
bool logToConsole = false; bool logToConsole = false;
bool logDebugStatements = false; bool logDebugStatements = false;

View File

@ -8,8 +8,9 @@
#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"
using namespace dChatFilterDCF; using namespace dChatFilterDCF;
@ -18,12 +19,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 +36,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 +73,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 +93,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 +108,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, int gmLevel, bool whiteList) {
if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return true; //If anything but a forum mod, return true. if (gmLevel > GAME_MASTER_LEVEL_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());
}
} }
return true; 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 listOfBadSegments;
} }
size_t dChatFilter::CalculateHash(const std::string& word) { size_t dChatFilter::CalculateHash(const std::string& word) {
@ -135,7 +156,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();
}

View File

@ -20,17 +20,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, int 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);
}; };

View File

@ -33,9 +33,10 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
"WHEN friend_id = ? THEN player_id " "WHEN friend_id = ? THEN player_id "
"END AS requested_player, best_friend FROM friends) AS fr " "END AS requested_player, best_friend FROM friends) AS fr "
"JOIN charinfo AS ci ON ci.id = fr.requested_player " "JOIN charinfo AS ci ON ci.id = fr.requested_player "
"WHERE fr.requested_player IS NOT NULL;")); "WHERE fr.requested_player IS NOT NULL AND fr.requested_player != ?;"));
stmt->setUInt(1, static_cast<uint32_t>(playerID)); stmt->setUInt(1, static_cast<uint32_t>(playerID));
stmt->setUInt(2, static_cast<uint32_t>(playerID)); stmt->setUInt(2, static_cast<uint32_t>(playerID));
stmt->setUInt(3, static_cast<uint32_t>(playerID));
std::vector<FriendData> friends; std::vector<FriendData> friends;
@ -48,7 +49,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
GeneralUtils::SetBit(fd.friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER)); GeneralUtils::SetBit(fd.friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
fd.isBestFriend = res->getInt(2) == 3; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs fd.isBestFriend = res->getInt(2) == 3; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs
if (fd.isBestFriend) player->countOfBestFriends+=1; if (fd.isBestFriend) player->countOfBestFriends += 1;
fd.friendName = res->getString(3); fd.friendName = res->getString(3);
//Now check if they're online: //Now check if they're online:
@ -60,8 +61,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Since this friend is online, we need to update them on the fact that we've just logged in: //Since this friend is online, we need to update them on the fact that we've just logged in:
SendFriendUpdate(fr, player, 1, fd.isBestFriend); SendFriendUpdate(fr, player, 1, fd.isBestFriend);
} } else {
else {
fd.isOnline = false; fd.isOnline = false;
fd.zoneID = LWOZONEID(); fd.zoneID = LWOZONEID();
} }
@ -114,6 +114,10 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
inStream.Read(isBestFriendRequest); inStream.Read(isBestFriendRequest);
auto requestor = playerContainer.GetPlayerData(requestorPlayerID); auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
if (requestor->playerName == playerName) {
SendFriendResponse(requestor, requestor, AddFriendResponseType::MYTHRAN);
return;
};
std::unique_ptr<PlayerData> requestee(playerContainer.GetPlayerData(playerName)); std::unique_ptr<PlayerData> requestee(playerContainer.GetPlayerData(playerName));
// Check if player is online first // Check if player is online first
@ -209,8 +213,8 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
updateQuery->executeUpdate(); updateQuery->executeUpdate();
// Sent the best friend update here if the value is 3 // Sent the best friend update here if the value is 3
if (bestFriendStatus == 3U) { if (bestFriendStatus == 3U) {
requestee->countOfBestFriends+=1; requestee->countOfBestFriends += 1;
requestor->countOfBestFriends+=1; requestor->countOfBestFriends += 1;
if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, AddFriendResponseType::ACCEPTED, false, true); if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, AddFriendResponseType::ACCEPTED, false, true);
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::ACCEPTED, false, true); if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::ACCEPTED, false, true);
for (auto& friendData : requestor->friends) { for (auto& friendData : requestor->friends) {
@ -371,8 +375,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
SendRemoveFriend(goonB, goonAName, true); SendRemoveFriend(goonB, goonAName, true);
} }
void ChatPacketHandler::HandleChatMessage(Packet* packet) void ChatPacketHandler::HandleChatMessage(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
@ -393,7 +396,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
std::string message = PacketUtils::ReadString(0x66, packet, true); std::string message = PacketUtils::ReadString(0x66, packet, true);
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s\n", senderName.c_str(), channel, message.c_str()); Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s", senderName.c_str(), channel, message.c_str());
if (channel != 8) return; if (channel != 8) return;
@ -401,8 +404,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
if (team == nullptr) return; if (team == nullptr) return;
for (const auto memberId : team->memberIDs) for (const auto memberId : team->memberIDs) {
{
auto* otherMember = playerContainer.GetPlayerData(memberId); auto* otherMember = playerContainer.GetPlayerData(memberId);
if (otherMember == nullptr) return; if (otherMember == nullptr) return;
@ -493,8 +495,7 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
} }
} }
void ChatPacketHandler::HandleTeamInvite(Packet* packet) void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); inStream.Read(playerID);
@ -503,44 +504,39 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet)
auto* player = playerContainer.GetPlayerData(playerID); auto* player = playerContainer.GetPlayerData(playerID);
if (player == nullptr) if (player == nullptr) {
{
return; return;
} }
auto* team = playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
if (team == nullptr) if (team == nullptr) {
{
team = playerContainer.CreateTeam(playerID); team = playerContainer.CreateTeam(playerID);
} }
auto* other = playerContainer.GetPlayerData(invitedPlayer); auto* other = playerContainer.GetPlayerData(invitedPlayer);
if (other == nullptr) if (other == nullptr) {
{
return; return;
} }
if (playerContainer.GetTeam(other->playerID) != nullptr) if (playerContainer.GetTeam(other->playerID) != nullptr) {
{
return; return;
} }
if (team->memberIDs.size() > 3) { if (team->memberIDs.size() > 3) {
// no more teams greater than 4 // no more teams greater than 4
Game::logger->Log("ChatPacketHandler", "Someone tried to invite a 5th player to a team\n"); Game::logger->Log("ChatPacketHandler", "Someone tried to invite a 5th player to a team");
return; return;
} }
SendTeamInvite(other, player); SendTeamInvite(other, player);
Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s\n", playerID, invitedPlayer.c_str()); Game::logger->Log("ChatPacketHandler", "Got team invite: %llu -> %s", playerID, invitedPlayer.c_str());
} }
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
@ -552,33 +548,29 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet)
LWOOBJID leaderID = LWOOBJID_EMPTY; LWOOBJID leaderID = LWOOBJID_EMPTY;
inStream.Read(leaderID); inStream.Read(leaderID);
Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)\n", playerID, leaderID, declined); Game::logger->Log("ChatPacketHandler", "Accepted invite: %llu -> %llu (%d)", playerID, leaderID, declined);
if (declined) if (declined) {
{
return; return;
} }
auto* team = playerContainer.GetTeam(leaderID); auto* team = playerContainer.GetTeam(leaderID);
if (team == nullptr) if (team == nullptr) {
{ Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)", leaderID);
Game::logger->Log("ChatPacketHandler", "Failed to find team for leader (%llu)\n", leaderID);
team = playerContainer.GetTeam(playerID); team = playerContainer.GetTeam(playerID);
} }
if (team == nullptr) if (team == nullptr) {
{ Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)", playerID);
Game::logger->Log("ChatPacketHandler", "Failed to find team for player (%llu)\n", playerID);
return; return;
} }
playerContainer.AddMember(team, playerID); playerContainer.AddMember(team, playerID);
} }
void ChatPacketHandler::HandleTeamLeave(Packet* packet) void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
@ -588,16 +580,14 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet)
auto* team = playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
Game::logger->Log("ChatPacketHandler", "(%llu) leaving team\n", playerID); Game::logger->Log("ChatPacketHandler", "(%llu) leaving team", playerID);
if (team != nullptr) if (team != nullptr) {
{
playerContainer.RemoveMember(team, playerID, false, false, true); playerContainer.RemoveMember(team, playerID, false, false, true);
} }
} }
void ChatPacketHandler::HandleTeamKick(Packet* packet) void ChatPacketHandler::HandleTeamKick(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
@ -605,35 +595,30 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet)
std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true); std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true);
Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team\n", playerID, kickedPlayer.c_str()); Game::logger->Log("ChatPacketHandler", "(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
auto* kicked = playerContainer.GetPlayerData(kickedPlayer); auto* kicked = playerContainer.GetPlayerData(kickedPlayer);
LWOOBJID kickedId = LWOOBJID_EMPTY; LWOOBJID kickedId = LWOOBJID_EMPTY;
if (kicked != nullptr) if (kicked != nullptr) {
{
kickedId = kicked->playerID; kickedId = kicked->playerID;
} } else {
else kickedId = playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
{
kickedId = playerContainer.GetId(GeneralUtils::ASCIIToUTF16(kickedPlayer));
} }
if (kickedId == LWOOBJID_EMPTY) return; if (kickedId == LWOOBJID_EMPTY) return;
auto* team = playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
if (team != nullptr) if (team != nullptr) {
{
if (team->leaderID != playerID || team->leaderID == kickedId) return; if (team->leaderID != playerID || team->leaderID == kickedId) return;
playerContainer.RemoveMember(team, kickedId, false, true, false); playerContainer.RemoveMember(team, kickedId, false, true, false);
} }
} }
void ChatPacketHandler::HandleTeamPromote(Packet* packet) void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
@ -641,7 +626,7 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet)
std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true); std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true);
Game::logger->Log("ChatPacketHandler", "(%llu) promoting (%s) to team leader\n", playerID, promotedPlayer.c_str()); Game::logger->Log("ChatPacketHandler", "(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
auto* promoted = playerContainer.GetPlayerData(promotedPlayer); auto* promoted = playerContainer.GetPlayerData(promotedPlayer);
@ -649,16 +634,14 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet)
auto* team = playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
if (team != nullptr) if (team != nullptr) {
{
if (team->leaderID != playerID) return; if (team->leaderID != playerID) return;
playerContainer.PromoteMember(team, promoted->playerID); playerContainer.PromoteMember(team, promoted->playerID);
} }
} }
void ChatPacketHandler::HandleTeamLootOption(Packet* packet) void ChatPacketHandler::HandleTeamLootOption(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
@ -671,8 +654,7 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
auto* team = playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
if (team != nullptr) if (team != nullptr) {
{
if (team->leaderID != playerID) return; if (team->leaderID != playerID) return;
team->lootFlag = option; team->lootFlag = option;
@ -683,8 +665,7 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
} }
} }
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
@ -693,45 +674,37 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
auto* team = playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
auto* data = playerContainer.GetPlayerData(playerID); auto* data = playerContainer.GetPlayerData(playerID);
if (team != nullptr && data != nullptr) if (team != nullptr && data != nullptr) {
{ if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) {
if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID())
{
playerContainer.RemoveMember(team, playerID, false, false, true, true); playerContainer.RemoveMember(team, playerID, false, false, true, true);
return; return;
} }
if (team->memberIDs.size() <= 1 && !team->local) if (team->memberIDs.size() <= 1 && !team->local) {
{
playerContainer.DisbandTeam(team); playerContainer.DisbandTeam(team);
return; return;
} }
if (!team->local) if (!team->local) {
{
ChatPacketHandler::SendTeamSetLeader(data, team->leaderID); ChatPacketHandler::SendTeamSetLeader(data, team->leaderID);
} } else {
else
{
ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY); ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY);
} }
playerContainer.TeamStatusUpdate(team); playerContainer.TeamStatusUpdate(team);
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.c_str())); const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName);
for (const auto memberId : team->memberIDs) for (const auto memberId : team->memberIDs) {
{
auto* otherMember = playerContainer.GetPlayerData(memberId); auto* otherMember = playerContainer.GetPlayerData(memberId);
if (memberId == playerID) continue; if (memberId == playerID) continue;
const auto memberName = playerContainer.GetName(memberId); const auto memberName = playerContainer.GetName(memberId);
if (otherMember != nullptr) if (otherMember != nullptr) {
{
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID); ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
} }
ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0)); ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
@ -741,8 +714,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
} }
} }
void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) {
{
CBITSTREAM; CBITSTREAM;
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
@ -757,14 +729,13 @@ void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender)
SEND_PACKET; SEND_PACKET;
} }
void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
{
CBITSTREAM; CBITSTREAM;
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER CMSGHEADER;
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_INVITE_CONFIRM); bitStream.Write(GAME_MSG::GAME_MSG_TEAM_INVITE_CONFIRM);
@ -777,8 +748,7 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader
bitStream.Write(ucNumOfOtherPlayers); bitStream.Write(ucNumOfOtherPlayers);
bitStream.Write(ucResponseCode); bitStream.Write(ucResponseCode);
bitStream.Write(static_cast<uint32_t>(wsLeaderName.size())); bitStream.Write(static_cast<uint32_t>(wsLeaderName.size()));
for (const auto character : wsLeaderName) for (const auto character : wsLeaderName) {
{
bitStream.Write(character); bitStream.Write(character);
} }
@ -786,14 +756,13 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader
SEND_PACKET; SEND_PACKET;
} }
void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
{
CBITSTREAM; CBITSTREAM;
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER CMSGHEADER;
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_GET_STATUS_RESPONSE); bitStream.Write(GAME_MSG::GAME_MSG_TEAM_GET_STATUS_RESPONSE);
@ -804,8 +773,7 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI
bitStream.Write(ucLootFlag); bitStream.Write(ucLootFlag);
bitStream.Write(ucNumOfOtherPlayers); bitStream.Write(ucNumOfOtherPlayers);
bitStream.Write(static_cast<uint32_t>(wsLeaderName.size())); bitStream.Write(static_cast<uint32_t>(wsLeaderName.size()));
for (const auto character : wsLeaderName) for (const auto character : wsLeaderName) {
{
bitStream.Write(character); bitStream.Write(character);
} }
@ -813,14 +781,13 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI
SEND_PACKET; SEND_PACKET;
} }
void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID) void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID) {
{
CBITSTREAM; CBITSTREAM;
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER CMSGHEADER;
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_SET_LEADER); bitStream.Write(GAME_MSG::GAME_MSG_TEAM_SET_LEADER);
@ -831,14 +798,13 @@ void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64Play
SEND_PACKET; SEND_PACKET;
} }
void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
{
CBITSTREAM; CBITSTREAM;
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER CMSGHEADER;
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_ADD_PLAYER); bitStream.Write(GAME_MSG::GAME_MSG_TEAM_ADD_PLAYER);
@ -848,13 +814,11 @@ void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTria
bitStream.Write(bNoLootOnDeath); bitStream.Write(bNoLootOnDeath);
bitStream.Write(i64PlayerID); bitStream.Write(i64PlayerID);
bitStream.Write(static_cast<uint32_t>(wsPlayerName.size())); bitStream.Write(static_cast<uint32_t>(wsPlayerName.size()));
for (const auto character : wsPlayerName) for (const auto character : wsPlayerName) {
{
bitStream.Write(character); bitStream.Write(character);
} }
bitStream.Write1(); bitStream.Write1();
if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) {
{
zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0); zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0);
} }
bitStream.Write(zoneID); bitStream.Write(zoneID);
@ -863,14 +827,13 @@ void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTria
SEND_PACKET; SEND_PACKET;
} }
void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
{
CBITSTREAM; CBITSTREAM;
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER CMSGHEADER;
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_REMOVE_PLAYER); bitStream.Write(GAME_MSG::GAME_MSG_TEAM_REMOVE_PLAYER);
@ -882,8 +845,7 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband
bitStream.Write(i64LeaderID); bitStream.Write(i64LeaderID);
bitStream.Write(i64PlayerID); bitStream.Write(i64PlayerID);
bitStream.Write(static_cast<uint32_t>(wsPlayerName.size())); bitStream.Write(static_cast<uint32_t>(wsPlayerName.size()));
for (const auto character : wsPlayerName) for (const auto character : wsPlayerName) {
{
bitStream.Write(character); bitStream.Write(character);
} }
@ -891,21 +853,19 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband
SEND_PACKET; SEND_PACKET;
} }
void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
{
CBITSTREAM; CBITSTREAM;
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
//portion that will get routed: //portion that will get routed:
CMSGHEADER CMSGHEADER;
bitStream.Write(receiver->playerID); bitStream.Write(receiver->playerID);
bitStream.Write(GAME_MSG::GAME_MSG_TEAM_SET_OFF_WORLD_FLAG); bitStream.Write(GAME_MSG::GAME_MSG_TEAM_SET_OFF_WORLD_FLAG);
bitStream.Write(i64PlayerID); bitStream.Write(i64PlayerID);
if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) if (receiver->zoneID.GetCloneID() == zoneID.GetCloneID()) {
{
zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0); zoneID = LWOZONEID(zoneID.GetMapID(), zoneID.GetInstanceID(), 0);
} }
bitStream.Write(zoneID); bitStream.Write(zoneID);
@ -943,12 +903,9 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla
bitStream.Write(playerData->zoneID.GetMapID()); bitStream.Write(playerData->zoneID.GetMapID());
bitStream.Write(playerData->zoneID.GetInstanceID()); bitStream.Write(playerData->zoneID.GetInstanceID());
if (playerData->zoneID.GetCloneID() == friendData->zoneID.GetCloneID()) if (playerData->zoneID.GetCloneID() == friendData->zoneID.GetCloneID()) {
{
bitStream.Write(0); bitStream.Write(0);
} } else {
else
{
bitStream.Write(playerData->zoneID.GetCloneID()); bitStream.Write(playerData->zoneID.GetCloneID());
} }

View File

@ -40,9 +40,9 @@ int main(int argc, char** argv) {
//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 0;
Game::logger->Log("ChatServer", "Starting Chat server...\n"); Game::logger->Log("ChatServer", "Starting Chat server...");
Game::logger->Log("ChatServer", "Version: %i.%i\n", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("ChatServer", "Compiled on: %s\n", __TIMESTAMP__); Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__);
//Read our config: //Read our config:
dConfig config("chatconfig.ini"); dConfig config("chatconfig.ini");
@ -58,9 +58,8 @@ int main(int argc, char** argv) {
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;
@ -104,8 +103,7 @@ int main(int argc, char** argv) {
if (framesSinceMasterDisconnect >= 30) if (framesSinceMasterDisconnect >= 30)
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.
@ -122,8 +120,7 @@ int main(int argc, char** argv) {
if (framesSinceLastFlush >= 900) { if (framesSinceLastFlush >= 900) {
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 >= 40000) {
@ -141,8 +138,7 @@ 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(mediumFramerate); //Chat can run at a lower "fps"
@ -158,7 +154,7 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
dLogger * SetupLogger() { dLogger* SetupLogger() {
std::string logPath = "./logs/ChatServer_" + std::to_string(time(nullptr)) + ".log"; std::string logPath = "./logs/ChatServer_" + std::to_string(time(nullptr)) + ".log";
bool logToConsole = false; bool logToConsole = false;
bool logDebugStatements = false; bool logDebugStatements = false;
@ -172,11 +168,11 @@ 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->data[1] == CHAT_INTERNAL) {
@ -205,7 +201,7 @@ 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]));
} }
} }
@ -216,7 +212,7 @@ void HandlePacket(Packet* packet) {
break; break;
case MSG_CHAT_GET_IGNORE_LIST: case MSG_CHAT_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 MSG_CHAT_TEAM_GET_STATUS:
@ -274,19 +270,19 @@ void HandlePacket(Packet* 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 (packet->data[1] == WORLD) {
switch (packet->data[3]) { switch (packet->data[3]) {
case MSG_WORLD_CLIENT_ROUTE_PACKET: { case MSG_WORLD_CLIENT_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]));
} }
} }
} }

View File

@ -35,10 +35,10 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
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_str())); 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_str(), 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 (?, ?, ?, ?);");
@ -70,21 +70,19 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
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()));
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.c_str()));
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 });
} }
} }
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 (?, ?, ?, ?);");
@ -97,8 +95,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
insertLog->executeUpdate(); insertLog->executeUpdate();
} }
void PlayerContainer::MuteUpdate(Packet* packet) void PlayerContainer::MuteUpdate(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); //skip header inStream.Read(playerID); //skip header
@ -108,9 +105,8 @@ void PlayerContainer::MuteUpdate(Packet* packet)
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;
} }
@ -120,8 +116,7 @@ void PlayerContainer::MuteUpdate(Packet* packet)
BroadcastMuteUpdate(playerID, expire); BroadcastMuteUpdate(playerID, expire);
} }
void PlayerContainer::CreateTeamServer(Packet* packet) void PlayerContainer::CreateTeamServer(Packet* packet) {
{
CINSTREAM; CINSTREAM;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); //skip header inStream.Read(playerID); //skip header
@ -133,8 +128,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);
@ -146,16 +140,14 @@ 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, CHAT_INTERNAL, MSG_CHAT_INTERNAL_MUTE_UPDATE);
@ -165,30 +157,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);
} }
} }
@ -200,8 +185,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;
@ -215,10 +199,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;
@ -227,8 +209,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;
@ -240,24 +221,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_str())); const auto leaderName = GeneralUtils::UTF8ToUTF16(leader->playerName);
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.c_str())); 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) 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;
@ -266,32 +243,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;
} }
@ -306,25 +278,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;
@ -333,19 +299,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_str())); 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);
@ -358,8 +322,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;
@ -368,16 +331,14 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team)
if (leader == nullptr) return; if (leader == nullptr) return;
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.c_str())); 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);
} }
} }
@ -385,20 +346,17 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team)
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, CHAT_INTERNAL, MSG_CHAT_INTERNAL_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);
} }
} }
@ -406,8 +364,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"";
@ -415,12 +372,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;
} }
} }
@ -428,7 +382,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);
} }

View File

@ -20,7 +20,7 @@ struct PlayerData {
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 = {};

160
dCommon/AMFDeserialize.cpp Normal file
View 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
View 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;
};

View File

@ -108,6 +108,14 @@ _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) {
@ -155,3 +163,9 @@ _AMFObjectTraits_::iterator AMFObjectValue::GetTraitsIteratorEnd() {
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;
}
}

View File

@ -59,6 +59,7 @@ public:
\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
@ -233,6 +234,7 @@ public:
}; };
//! 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)
@ -245,6 +247,7 @@ private:
AMFValueType GetValueType() { return AMFArray; } AMFValueType GetValueType() { return AMFArray; }
public: public:
~AMFArrayValue() override;
//! Inserts an item into the array map for a specific key //! Inserts an item into the array map for a specific key
/*! /*!
\param key The key to set \param key The key to set
@ -308,6 +311,18 @@ public:
\return Where the iterator ends \return Where the iterator ends
*/ */
_AMFArrayList_::iterator GetDenseIteratorEnd(); _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
@ -320,6 +335,7 @@ private:
\return The AMF value type \return The AMF value type
*/ */
AMFValueType GetValueType() { return AMFObject; } AMFValueType GetValueType() { return AMFObject; }
~AMFObjectValue() override;
public: public:
//! Constructor //! Constructor

View File

@ -37,6 +37,12 @@ void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
break; break;
} }
case AMFDouble: {
AMFDoubleValue* v = (AMFDoubleValue*)value;
this->Write(*v);
break;
}
case AMFString: { case AMFString: {
AMFStringValue* v = (AMFStringValue*)value; AMFStringValue* v = (AMFStringValue*)value;
this->Write(*v); this->Write(*v);
@ -56,15 +62,17 @@ void RakNet::BitStream::Write<AMFValue*>(AMFValue* value) {
} }
case AMFArray: { case AMFArray: {
AMFArrayValue* v = (AMFArrayValue*)value; this->Write((AMFArrayValue*)value);
this->Write(*v);
break; 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) {
@ -102,79 +110,50 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
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);
} }
@ -214,7 +193,7 @@ 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
@ -243,13 +222,13 @@ void RakNet::BitStream::Write<AMFDateValue>(AMFDateValue value) {
// 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);
@ -260,8 +239,8 @@ void RakNet::BitStream::Write<AMFArrayValue>(AMFArrayValue value) {
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);

View File

@ -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

View File

@ -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::ifstream& instream) {
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::ifstream& instream) {
size_t size; size_t size;
BinaryRead(instream, size); BinaryRead(instream, size);
//toReturn.resize(size); //toReturn.resize(size);

View File

@ -9,7 +9,7 @@ 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())
printf("bla"); printf("bla");
@ -17,7 +17,7 @@ namespace BinaryIO {
} }
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::ifstream& instream);
std::string ReadString(std::ifstream& instream, size_t size); std::string ReadString(std::ifstream& instream, size_t size);
std::string ReadWString(std::ifstream& instream); std::string ReadWString(std::ifstream& instream);

180
dCommon/BrickByBrickFix.cpp Normal file
View 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[MAX_SD0_CHUNK_SIZE]);
int32_t err{};
int32_t actualUncompressedSize = ZCompression::Decompress(
compressedChunk.get(), chunkSize, uncompressedChunk.get(), 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;
}

26
dCommon/BrickByBrickFix.h Normal file
View File

@ -0,0 +1,26 @@
#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();
/**
* @brief Max size of an inflated sd0 zlib chunk
*
*/
constexpr uint32_t MAX_SD0_CHUNK_SIZE = 1024 * 256;
};

View File

@ -1,4 +1,5 @@
set(DCOMMON_SOURCES "AMFFormat.cpp" set(DCOMMON_SOURCES "AMFFormat.cpp"
"AMFDeserialize.cpp"
"AMFFormat_BitStream.cpp" "AMFFormat_BitStream.cpp"
"BinaryIO.cpp" "BinaryIO.cpp"
"dConfig.cpp" "dConfig.cpp"
@ -12,15 +13,43 @@ set(DCOMMON_SOURCES "AMFFormat.cpp"
"NiQuaternion.cpp" "NiQuaternion.cpp"
"SHA512.cpp" "SHA512.cpp"
"Type.cpp" "Type.cpp"
"ZCompression.cpp") "ZCompression.cpp"
"BrickByBrickFix.cpp"
)
include_directories(${PROJECT_SOURCE_DIR}/dCommon/) include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
add_library(dCommon STATIC ${DCOMMON_SOURCES}) add_library(dCommon STATIC ${DCOMMON_SOURCES})
target_link_libraries(dCommon libbcrypt) target_link_libraries(dCommon bcrypt dDatabase tinyxml2)
if (UNIX) if (UNIX)
find_package(ZLIB REQUIRED) find_package(ZLIB REQUIRED)
target_link_libraries(dCommon ZLIB::ZLIB) elseif (WIN32)
endif() 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)

View File

@ -142,12 +142,12 @@ void CatchUnhandled(int sig) {
demangled = demangle(functionName.c_str()); demangled = demangle(functionName.c_str());
if (demangled.empty()) { if (demangled.empty()) {
printf("[%02d] %s\n", i, demangled.c_str()); printf("[%02zu] %s\n", i, demangled.c_str());
} else { } else {
printf("[%02d] %s\n", i, functionName.c_str()); printf("[%02zu] %s\n", i, functionName.c_str());
} }
} else { } else {
printf("[%02d] %s\n", i, functionName.c_str()); printf("[%02zu] %s\n", i, functionName.c_str());
} }
} }
#else #else
@ -171,10 +171,7 @@ void CatchUnhandled(int sig) {
ErrorCallback, ErrorCallback,
nullptr); nullptr);
// Print error code struct bt_ctx ctx = { state, 0 };
printf("Error code: %d\n", sig);
struct bt_ctx ctx = {state, 0};
Bt(state); Bt(state);
#endif #endif

View File

@ -6,7 +6,7 @@
#include <algorithm> #include <algorithm>
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 {
@ -24,7 +24,7 @@ inline bool IsTrailSurrogate(char16_t c) {
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));
@ -42,16 +42,123 @@ inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
} }
} }
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();
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;
@ -59,7 +166,7 @@ std::u16string GeneralUtils::ASCIIToUTF16(const std::string& string, size_t size
//! 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);
@ -86,7 +193,7 @@ std::string GeneralUtils::UTF16ToWTF8(const std::u16string& string, size_t size)
} }
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
@ -108,14 +215,13 @@ bool GeneralUtils::CheckBit(int64_t value, uint32_t 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;
@ -132,8 +238,7 @@ std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t d
return vector; return vector;
} }
std::vector<std::u16string> GeneralUtils::SplitString(std::u16string& str, char16_t delimiter) std::vector<std::u16string> GeneralUtils::SplitString(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;
@ -150,22 +255,17 @@ std::vector<std::u16string> GeneralUtils::SplitString(std::u16string& str, char1
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,7 +275,7 @@ 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);
@ -193,8 +293,7 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream *inStream) {
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
std::vector<std::string> GeneralUtils::GetFileNamesFromFolder(const std::string& folder) std::vector<std::string> GeneralUtils::GetFileNamesFromFolder(const std::string& folder) {
{
std::vector<std::string> names; std::vector<std::string> names;
std::string search_path = folder + "/*.*"; std::string search_path = folder + "/*.*";
WIN32_FIND_DATA fd; WIN32_FIND_DATA fd;

View File

@ -18,7 +18,7 @@
\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
/*! /*!
@ -26,7 +26,18 @@ namespace GeneralUtils {
\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-8 String to a UTF-16 string
/*!
\param string The string to convert
\param size A size to trim the string to. Default is -1 (No trimming)
\return An UTF-16 representation of the string
*/
std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1);
//! Internal, do not use
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
//! Converts a UTF-16 string to a UTF-8 string //! Converts a UTF-16 string to a UTF-8 string
/*! /*!
@ -34,7 +45,7 @@ namespace GeneralUtils {
\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-8 representation of the string
*/ */
std::string UTF16ToWTF8(const std::u16string& string, size_t size = -1); std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1);
/** /**
* Compares two basic strings but does so ignoring case sensitivity * Compares two basic strings but does so ignoring case sensitivity
@ -109,8 +120,7 @@ namespace GeneralUtils {
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);
} }
@ -120,7 +130,7 @@ namespace GeneralUtils {
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);
@ -134,78 +144,64 @@ namespace GeneralUtils {
T Parse(const char* value); 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 <typename T>
bool TryParse(const char* value, T& dst) bool TryParse(const char* value, T& dst) {
{ try {
try
{
dst = Parse<T>(value); dst = Parse<T>(value);
return true; return true;
} } catch (...) {
catch (...)
{
return false; return false;
} }
} }
template <typename T> template <typename T>
T Parse(const std::string& value) T Parse(const std::string& value) {
{
return Parse<T>(value.c_str()); return Parse<T>(value.c_str());
} }
template <typename T> template <typename T>
bool TryParse(const std::string& value, T& dst) bool TryParse(const std::string& value, T& dst) {
{
return TryParse<T>(value.c_str(), dst); return TryParse<T>(value.c_str(), dst);
} }
template<typename T> template<typename T>
std::u16string to_u16string(T value) std::u16string to_u16string(T value) {
{
return GeneralUtils::ASCIIToUTF16(std::to_string(value)); return GeneralUtils::ASCIIToUTF16(std::to_string(value));
} }
// From boost::hash_combine // From boost::hash_combine
template <class T> template <class T>
void hash_combine(std::size_t& s, const T& v) void hash_combine(std::size_t& s, const T& v) {
{
std::hash<T> h; std::hash<T> h;
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
} }

View File

@ -8,7 +8,7 @@
#include <vector> #include <vector>
//! 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& format) {
// First, check the format // First, check the format
std::istringstream ssFormat(format); std::istringstream ssFormat(format);
@ -49,7 +49,7 @@ LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
switch (type) { switch (type) {
case LDF_TYPE_UTF_16: { case LDF_TYPE_UTF_16: {
std::u16string data = GeneralUtils::ASCIIToUTF16(dataArray[1]); std::u16string data = GeneralUtils::UTF8ToUTF16(dataArray[1]);
return new LDFData<std::u16string>(key, data); return new LDFData<std::u16string>(key, data);
} }
@ -72,16 +72,11 @@ LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
{ {
uint32_t data; uint32_t data;
if (dataArray[1] == "true") if (dataArray[1] == "true") {
{
data = 1; data = 1;
} } else if (dataArray[1] == "false") {
else if (dataArray[1] == "false")
{
data = 0; data = 0;
} } else {
else
{
data = static_cast<uint32_t>(stoul(dataArray[1])); data = static_cast<uint32_t>(stoul(dataArray[1]));
} }
@ -91,16 +86,11 @@ LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
case LDF_TYPE_BOOLEAN: { case LDF_TYPE_BOOLEAN: {
bool data; bool data;
if (dataArray[1] == "true") if (dataArray[1] == "true") {
{
data = true; data = true;
} } else if (dataArray[1] == "false") {
else if (dataArray[1] == "false")
{
data = false; data = false;
} } else {
else
{
data = static_cast<bool>(stoi(dataArray[1])); data = static_cast<bool>(stoi(dataArray[1]));
} }

View File

@ -17,7 +17,7 @@
\brief A collection of LDF format classes \brief A collection of LDF format classes
*/ */
//! An enum for LDF Data Types //! 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
@ -36,13 +36,13 @@ class LDFBaseData {
public: public:
//! Destructor //! Destructor
virtual ~LDFBaseData(void) { } virtual ~LDFBaseData(void) {}
//! Writes the data to a packet //! Writes the data to a packet
/*! /*!
\param packet The packet \param packet The packet
*/ */
virtual void WriteToPacket(RakNet::BitStream * packet) = 0; virtual void WriteToPacket(RakNet::BitStream* packet) = 0;
//! Gets the key //! Gets the key
/*! /*!
@ -66,7 +66,7 @@ public:
virtual std::string GetValueAsString() = 0; virtual std::string GetValueAsString() = 0;
virtual LDFBaseData * Copy() = 0; virtual LDFBaseData* Copy() = 0;
// MARK: Functions // MARK: Functions
@ -74,7 +74,7 @@ public:
/*! /*!
\param format The format \param format The format
*/ */
static LDFBaseData * DataFromString(const std::string& format); static LDFBaseData* DataFromString(const std::string& format);
}; };
@ -86,7 +86,7 @@ private:
T value; T value;
//! Writes the key to the packet //! Writes the key to the packet
void WriteKey(RakNet::BitStream * packet) { void WriteKey(RakNet::BitStream* packet) {
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]));
@ -94,7 +94,7 @@ private:
} }
//! 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);
} }
@ -108,7 +108,7 @@ public:
} }
//! Destructor //! Destructor
~LDFData(void) override { } ~LDFData(void) override {}
//! Gets the value //! Gets the value
/*! /*!
@ -132,7 +132,7 @@ public:
/*! /*!
\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);
} }
@ -186,7 +186,7 @@ public:
return this->GetValueString(); return this->GetValueString();
} }
LDFBaseData * Copy() override { LDFBaseData* Copy() override {
return new LDFData<T>(key, value); return new LDFData<T>(key, value);
} }
@ -206,7 +206,7 @@ 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()));
@ -217,7 +217,7 @@ inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream * packet) {
// The specialized version for bool // The specialized version for bool
template<> template<>
inline void LDFData<bool>::WriteValue(RakNet::BitStream * packet) { inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
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));
@ -225,7 +225,7 @@ inline void LDFData<bool>::WriteValue(RakNet::BitStream * packet) {
// The specialized version for std::string (UTF-8) // The specialized version for std::string (UTF-8)
template<> template<>
inline void LDFData<std::string>::WriteValue(RakNet::BitStream * packet) { inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
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()));

View File

@ -30,7 +30,7 @@
*/ */
/* interface header */ /* interface header */
#include "MD5.h" #include "MD5.h"
/* system implementation headers */ /* system implementation headers */
@ -59,15 +59,15 @@
// 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) {
@ -81,35 +81,33 @@ inline MD5::uint4 MD5::rotate_left(uint4 x, int 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();
@ -117,8 +115,7 @@ MD5::MD5(const std::string &text)
////////////////////////////// //////////////////////////////
void MD5::init() void MD5::init() {
{
finalized = false; finalized = false;
count[0] = 0; count[0] = 0;
@ -134,8 +131,7 @@ void MD5::init()
////////////////////////////// //////////////////////////////
// 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);
@ -145,8 +141,7 @@ void MD5::decode(uint4 output[], const uint1 input[], size_type len)
// 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;
@ -158,8 +153,7 @@ void MD5::encode(uint1 output[], const uint4 input[], size_type len)
////////////////////////////// //////////////////////////////
// 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);
@ -248,8 +242,7 @@ void MD5::transform(const uint1 block[blocksize])
// 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;
@ -264,8 +257,7 @@ void MD5::update(const unsigned char input[], size_type length)
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);
@ -275,8 +267,7 @@ void MD5::update(const unsigned char input[], size_type length)
transform(&input[i]); transform(&input[i]);
index = 0; index = 0;
} } else
else
i = 0; i = 0;
// buffer remaining input // buffer remaining input
@ -286,8 +277,7 @@ void MD5::update(const unsigned char input[], size_type length)
////////////////////////////// //////////////////////////////
// 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);
} }
@ -295,8 +285,7 @@ void MD5::update(const char input[], size_type 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,
@ -332,13 +321,12 @@ MD5& MD5::finalize()
////////////////////////////// //////////////////////////////
// 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;
@ -347,15 +335,13 @@ std::string MD5::hexdigest() const
////////////////////////////// //////////////////////////////
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();

View File

@ -37,16 +37,16 @@
#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:
@ -54,8 +54,8 @@ public:
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);
@ -82,10 +82,10 @@ private:
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);

View File

@ -16,55 +16,44 @@ std::vector<MetricVariable> Metrics::m_Variables = {
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) {
else if (metric->min == -1 || metric->min > value)
{
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;
} }
@ -72,8 +61,7 @@ const Metric* Metrics::GetMetric(MetricVariable variable)
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];
} }
@ -84,34 +72,28 @@ const Metric* Metrics::GetMetric(MetricVariable variable)
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;
} }
@ -124,15 +106,12 @@ void Metrics::EndMeasurement(MetricVariable variable)
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: case MetricVariable::GameLoop:
return "GameLoop"; return "GameLoop";
case MetricVariable::PacketHandling: case MetricVariable::PacketHandling:
@ -159,15 +138,12 @@ std::string Metrics::MetricVariableToString(MetricVariable variable)
} }
} }
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;
} }
@ -207,37 +183,35 @@ 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
@ -255,20 +229,19 @@ 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;
@ -276,15 +249,14 @@ size_t Metrics::GetCurrentRSS()
/* 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 ------------------------ */
@ -293,8 +265,7 @@ size_t Metrics::GetCurrentRSS()
} }
size_t Metrics::GetProcessID() size_t Metrics::GetProcessID() {
{
#if defined(_WIN32) #if defined(_WIN32)
return GetCurrentProcessId(); return GetCurrentProcessId();
#else #else

View File

@ -71,12 +71,12 @@ void NiPoint3::SetZ(float z) {
//! 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
@ -113,13 +113,13 @@ bool NiPoint3::operator!=(const NiPoint3& point) const {
//! 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];
} }
@ -166,7 +166,7 @@ bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3&
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
@ -175,8 +175,7 @@ bool NiPoint3::IsWithinSpehere(const NiPoint3& sphereCenter, float radius) {
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;
@ -191,16 +190,14 @@ NiPoint3 NiPoint3::ClosestPointOnLine(const NiPoint3& a, const NiPoint3& b, cons
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;
@ -208,8 +205,7 @@ float NiPoint3::Distance(const NiPoint3& a, const NiPoint3& b)
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;
@ -217,15 +213,14 @@ float NiPoint3::DistanceSquared(const NiPoint3& a, const NiPoint3& b)
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);
} }

View File

@ -99,8 +99,7 @@ Vector3 NiQuaternion::GetEulerAngles() const {
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);
} }
@ -149,8 +148,7 @@ NiQuaternion NiQuaternion::LookAt(const NiPoint3& sourcePoint, const NiPoint3& d
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;
@ -179,8 +177,7 @@ NiQuaternion NiQuaternion::CreateFromAxisAngle(const Vector3& axis, float angle)
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);

View File

@ -45,12 +45,11 @@ const unsigned long long SHA512::sha512_k[80] = //ULL = uint64
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);
@ -83,8 +82,7 @@ void SHA512::transform(const unsigned char *message, unsigned int block_nb)
} }
} }
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;
@ -97,11 +95,10 @@ void SHA512::init()
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);
@ -120,8 +117,7 @@ void SHA512::update(const unsigned char *message, unsigned int 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;
@ -139,8 +135,7 @@ void SHA512::final(unsigned char *digest)
} }
} }
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;

View File

@ -14,12 +14,12 @@ protected:
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];

View File

@ -9,12 +9,12 @@ 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

View File

@ -1,19 +1,14 @@
#include "ZCompression.h" #include "ZCompression.h"
#ifndef _WIN32
#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 int32_t n16kBlocks = (nLenSrc + 16383) / 16384; // round up any fraction of a block
return (nLenSrc + 6 + (n16kBlocks * 5)); 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;
@ -30,11 +25,9 @@ namespace ZCompression
} }
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) 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 // Get the size of the decompressed data
z_stream zInfo = { 0 }; z_stream zInfo = { 0 };
zInfo.total_in = zInfo.avail_in = nLenSrc; zInfo.total_in = zInfo.avail_in = nLenSrc;
@ -52,26 +45,6 @@ namespace ZCompression
} }
inflateEnd(&zInfo); // zlib function inflateEnd(&zInfo); // zlib function
return(nRet); return(nRet);
/*
z_stream zInfo = { 0 };
zInfo.total_in = zInfo.avail_in = nLenSrc;
zInfo.total_out = zInfo.avail_out = nLenDst;
zInfo.next_in = const_cast<Bytef*>(abSrc);
zInfo.next_out = const_cast<Bytef*>(abDst);
int nRet = -1;
nErr = inflateInit(&zInfo); // zlib function
if (nErr == Z_OK) {
nErr = inflate(&zInfo, Z_FINISH); // zlib function
if (nErr == Z_STREAM_END) {
nRet = zInfo.total_out;
}
}
inflateEnd(&zInfo); // zlib function
return(nRet); // -1 or len of output
*/
} }
} }
#endif

View File

@ -1,13 +1,8 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include "dPlatforms.h" namespace ZCompression {
#ifndef DARKFLAME_PLATFORM_WIN32
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);
@ -15,4 +10,3 @@ namespace ZCompression
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);
} }
#endif

View File

@ -387,6 +387,7 @@ enum eReplicaComponentType : int32_t {
COMPONENT_TYPE_PROPERTY = 36, //!< The Property Component COMPONENT_TYPE_PROPERTY = 36, //!< The Property Component
COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39, //!< The ScriptedActivity Component COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39, //!< The ScriptedActivity Component
COMPONENT_TYPE_PHANTOM_PHYSICS = 40, //!< The PhantomPhysics Component COMPONENT_TYPE_PHANTOM_PHYSICS = 40, //!< The PhantomPhysics Component
COMPONENT_TYPE_MODEL = 42, //!< The Model Component
COMPONENT_TYPE_PROPERTY_ENTRANCE = 43, //!< The PhantomPhysics Component COMPONENT_TYPE_PROPERTY_ENTRANCE = 43, //!< The PhantomPhysics Component
COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45, //!< The PropertyManagement Component COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45, //!< The PropertyManagement Component
COMPONENT_TYPE_REBUILD = 48, //!< The Rebuild Component COMPONENT_TYPE_REBUILD = 48, //!< The Rebuild Component
@ -401,18 +402,18 @@ enum eReplicaComponentType : int32_t {
COMPONENT_TYPE_RACING_CONTROL = 71, //!< The RacingControl Component COMPONENT_TYPE_RACING_CONTROL = 71, //!< The RacingControl Component
COMPONENT_TYPE_MISSION_OFFER = 73, //!< The MissionOffer Component COMPONENT_TYPE_MISSION_OFFER = 73, //!< The MissionOffer Component
COMPONENT_TYPE_EXHIBIT = 75, //!< The Exhibit Component COMPONENT_TYPE_EXHIBIT = 75, //!< The Exhibit Component
COMPONENT_TYPE_RACING_STATS = 74, //!< The Exhibit Component COMPONENT_TYPE_RACING_STATS = 74, //!< The Racing Stats Component
COMPONENT_TYPE_SOUND_TRIGGER = 77, //!< The Sound Trigger Component COMPONENT_TYPE_SOUND_TRIGGER = 77, //!< The Sound Trigger Component
COMPONENT_TYPE_PROXIMITY_MONITOR = 78, //!< The Proximity Monitor Component COMPONENT_TYPE_PROXIMITY_MONITOR = 78, //!< The Proximity Monitor Component
COMPONENT_TYPE_MISSION = 84, //!< The Mission Component COMPONENT_TYPE_MISSION = 84, //!< The Mission Component
COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen
COMPONENT_TYPE_RAIL_ACTIVATOR = 104, COMPONENT_TYPE_RAIL_ACTIVATOR = 104, //!< The Rail Activator Component
COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT = 106, //!< The Player Forced Movement Component
COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component
COMPONENT_TYPE_LEVEL_PROGRESSION = 109, //!< The Level Progression Component
COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component
COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component
COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component
COMPONENT_TYPE_MODEL = 5398484 //look man idk
}; };
enum class UseItemResponse : uint32_t { enum class UseItemResponse : uint32_t {
@ -541,7 +542,7 @@ enum ePlayerFlags {
TOOLTIP_TALK_TO_SKYLAND_TO_GET_HAT = 52, TOOLTIP_TALK_TO_SKYLAND_TO_GET_HAT = 52,
MODULAR_BUILD_PLAYER_PLACES_FIRST_MODEL_IN_SCRATCH = 53, MODULAR_BUILD_PLAYER_PLACES_FIRST_MODEL_IN_SCRATCH = 53,
MODULAR_BUILD_FIRST_ARROW_DISPLAY_FOR_MODULE = 54, MODULAR_BUILD_FIRST_ARROW_DISPLAY_FOR_MODULE = 54,
AG_BEACON_QB,_SO_THE_PLAYER_CAN_ALWAYS_BUILD_THEM = 55, AG_BEACON_QB_SO_THE_PLAYER_CAN_ALWAYS_BUILD_THEM = 55,
GF_PET_DIG_FLAG_1 = 56, GF_PET_DIG_FLAG_1 = 56,
GF_PET_DIG_FLAG_2 = 57, GF_PET_DIG_FLAG_2 = 57,
GF_PET_DIG_FLAG_3 = 58, GF_PET_DIG_FLAG_3 = 58,
@ -627,6 +628,7 @@ enum ePlayerFlags {
GF_BINOC_IN_CROC_AREA = 1308, GF_BINOC_IN_CROC_AREA = 1308,
GF_BINOC_IN_JAIL_AREA = 1309, GF_BINOC_IN_JAIL_AREA = 1309,
GF_BINOC_TELESCOPE_NEXT_TO_CAPTAIN_JACK = 1310, GF_BINOC_TELESCOPE_NEXT_TO_CAPTAIN_JACK = 1310,
NT_PLINTH_REBUILD = 1919,
NT_FACTION_SPY_DUKE = 1974, NT_FACTION_SPY_DUKE = 1974,
NT_FACTION_SPY_OVERBUILD = 1976, NT_FACTION_SPY_OVERBUILD = 1976,
NT_FACTION_SPY_HAEL = 1977, NT_FACTION_SPY_HAEL = 1977,

View File

@ -33,17 +33,17 @@ void dLogger::vLog(const char* format, va_list args) {
char timeStr[70]; char timeStr[70];
strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", &time); strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", &time);
char message[2048]; char message[2048];
vsprintf_s(message, format, args); vsnprintf(message, 2048, format, args);
if (m_logToConsole) std::cout << "[" << timeStr << "] " << message; if (m_logToConsole) std::cout << "[" << timeStr << "] " << message;
mFile << "[" << timeStr << "] " << message; mFile << "[" << timeStr << "] " << message;
#else #else
time_t t = time(NULL); time_t t = time(NULL);
struct tm * time = localtime(&t); struct tm* time = localtime(&t);
char timeStr[70]; char timeStr[70];
strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", time); strftime(timeStr, sizeof(timeStr), "%d-%m-%y %H:%M:%S", time);
char message[2048]; char message[2048];
vsprintf(message, format, args); vsnprintf(message, 2048, format, args);
if (m_logToConsole) { if (m_logToConsole) {
fputs("[", stdout); fputs("[", stdout);
@ -63,30 +63,30 @@ void dLogger::vLog(const char* format, va_list args) {
#endif #endif
} }
void dLogger::LogBasic(const char * format, ...) { void dLogger::LogBasic(const char* format, ...) {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
vLog(format, args); vLog(format, args);
va_end(args); va_end(args);
} }
void dLogger::LogBasic(const std::string & message) { void dLogger::LogBasic(const std::string& message) {
LogBasic(message.c_str()); LogBasic(message.c_str());
} }
void dLogger::Log(const char * className, const char * format, ...) { void dLogger::Log(const char* className, const char* format, ...) {
va_list args; va_list args;
std::string log = "[" + std::string(className) + "] " + std::string(format); std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n";
va_start(args, format); va_start(args, format);
vLog(log.c_str(), args); vLog(log.c_str(), args);
va_end(args); va_end(args);
} }
void dLogger::Log(const std::string & className, const std::string & message) { void dLogger::Log(const std::string& className, const std::string& message) {
Log(className.c_str(), message.c_str()); Log(className.c_str(), message.c_str());
} }
void dLogger::LogDebug(const char * className, const char * format, ...) { void dLogger::LogDebug(const char* className, const char* format, ...) {
if (!m_logDebugStatements) return; if (!m_logDebugStatements) return;
va_list args; va_list args;
std::string log = "[" + std::string(className) + "] " + std::string(format); std::string log = "[" + std::string(className) + "] " + std::string(format);
@ -95,7 +95,7 @@ void dLogger::LogDebug(const char * className, const char * format, ...) {
va_end(args); va_end(args);
} }
void dLogger::LogDebug(const std::string & className, const std::string & message) { void dLogger::LogDebug(const std::string& className, const std::string& message) {
LogDebug(className.c_str(), message.c_str()); LogDebug(className.c_str(), message.c_str());
} }

View File

@ -31,8 +31,8 @@ private:
std::string m_outpath; std::string m_outpath;
std::ofstream mFile; std::ofstream mFile;
#ifndef _WIN32 #ifndef _WIN32
//Glorious linux can run with SPEED: //Glorious linux can run with SPEED:
FILE* fp = nullptr; FILE* fp = nullptr;
#endif #endif
}; };

View File

@ -1,29 +1,29 @@
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
#define DARKFLAME_PLATFORM_WIN32 #define DARKFLAME_PLATFORM_WIN32
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
#include <TargetConditionals.h> #include <TargetConditionals.h>
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
#define DARKFLAME_PLATFORM_IOS #define DARKFLAME_PLATFORM_IOS
#elif TARGET_OS_MAC #elif TARGET_OS_MAC
#define DARKFLAME_PLATFORM_MACOS #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 #else
#error unknown operating system #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 #endif

View File

@ -0,0 +1,14 @@
#pragma once
#ifndef __EUNEQUIPPABLEACTIVETYPE__H__
#define __EUNEQUIPPABLEACTIVETYPE__H__
#include <cstdint>
enum class eUnequippableActiveType : int32_t {
INVALID = -1,
PET = 0,
MOUNT
};
#endif //!__EUNEQUIPPABLEACTIVETYPE__H__

View File

@ -2,7 +2,7 @@
#include "CDComponentsRegistryTable.h" #include "CDComponentsRegistryTable.h"
// Static Variables // Static Variables
static CppSQLite3DB * conn = new CppSQLite3DB(); static CppSQLite3DB* conn = new CppSQLite3DB();
//! Opens a connection with the CDClient //! Opens a connection with the CDClient
void CDClientDatabase::Connect(const std::string& filename) { void CDClientDatabase::Connect(const std::string& filename) {

View File

@ -13,10 +13,10 @@
#include <sstream> #include <sstream>
#include <iostream> #include <iostream>
// Enable this to cache all entries in each table for fast access, comes with more memory cost // Enable this to cache all entries in each table for fast access, comes with more memory cost
//#define CDCLIENT_CACHE_ALL //#define CDCLIENT_CACHE_ALL
// Enable this to skip some unused columns in some tables // Enable this to skip some unused columns in some tables
#define UNUSED(v) #define UNUSED(v)
/*! /*!
@ -24,7 +24,7 @@
\brief An interface between the CDClient.sqlite file and the server \brief An interface between the CDClient.sqlite file and the server
*/ */
//! The CDClient Database namespace //! The CDClient Database namespace
namespace CDClientDatabase { namespace CDClientDatabase {
//! Opens a connection with the CDClient //! Opens a connection with the CDClient

View File

@ -1,7 +1,7 @@
#include "CDClientManager.h" #include "CDClientManager.h"
// Static Variables // Static Variables
CDClientManager * CDClientManager::m_Address = nullptr; CDClientManager* CDClientManager::m_Address = nullptr;
//! Initializes the manager //! Initializes the manager
void CDClientManager::Initialize(void) { void CDClientManager::Initialize(void) {

View File

@ -52,17 +52,17 @@
\brief A manager for the CDClient tables \brief A manager for the CDClient tables
*/ */
//! Manages all data from the CDClient //! Manages all data from the CDClient
class CDClientManager { class CDClientManager {
private: private:
static CDClientManager * m_Address; //!< The singleton address static CDClientManager* m_Address; //!< The singleton address
std::unordered_map<std::string, CDTable*> tables; //!< The tables std::unordered_map<std::string, CDTable*> tables; //!< The tables
public: public:
//! The singleton method //! The singleton method
static CDClientManager * Instance() { static CDClientManager* Instance() {
if (m_Address == 0) { if (m_Address == 0) {
m_Address = new CDClientManager; m_Address = new CDClientManager;
} }
@ -82,7 +82,7 @@ public:
\return The class or nullptr \return The class or nullptr
*/ */
template<typename T> template<typename T>
T * GetTable(const std::string& tableName) { T* GetTable(const std::string& tableName) {
static_assert(std::is_base_of<CDTable, T>::value, "T should inherit from CDTable!"); static_assert(std::is_base_of<CDTable, T>::value, "T should inherit from CDTable!");
for (auto itr = this->tables.begin(); itr != this->tables.end(); ++itr) { for (auto itr = this->tables.begin(); itr != this->tables.end(); ++itr) {
@ -93,6 +93,4 @@ public:
return nullptr; return nullptr;
} }
void LoadHost();
}; };

View File

@ -6,8 +6,8 @@ using namespace std;
#pragma warning (disable:4251) //Disables SQL warnings #pragma warning (disable:4251) //Disables SQL warnings
sql::Driver * Database::driver; sql::Driver* Database::driver;
sql::Connection * Database::con; sql::Connection* Database::con;
sql::Properties Database::props; sql::Properties Database::props;
std::string Database::database; std::string Database::database;
@ -43,8 +43,8 @@ void Database::Destroy(std::string source, bool log) {
if (!con) return; if (!con) return;
if (log) { if (log) {
if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!\n", source.c_str()); if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!", source.c_str());
else Game::logger->Log("Database", "Destroying MySQL connection!\n"); else Game::logger->Log("Database", "Destroying MySQL connection!");
} }
con->close(); con->close();
@ -63,17 +63,16 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
if (!con) { if (!con) {
Connect(); Connect();
Game::logger->Log("Database", "Trying to reconnect to MySQL\n"); Game::logger->Log("Database", "Trying to reconnect to MySQL");
} }
if (!con->isValid() || con->isClosed()) if (!con->isValid() || con->isClosed()) {
{
delete con; delete con;
con = nullptr; con = nullptr;
Connect(); Connect();
Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection\n"); Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection");
} }
auto* stmt = con->prepareStatement(str); auto* stmt = con->prepareStatement(str);
@ -84,3 +83,15 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
void Database::Commit() { void Database::Commit() {
Database::con->commit(); Database::con->commit();
} }
bool Database::GetAutoCommit() {
// TODO This should not just access a pointer. A future PR should update this
// to check for null and throw an error if the connection is not valid.
return con->getAutoCommit();
}
void Database::SetAutoCommit(bool value) {
// TODO This should not just access a pointer. A future PR should update this
// to check for null and throw an error if the connection is not valid.
Database::con->setAutoCommit(value);
}

View File

@ -11,8 +11,8 @@ public:
class Database { class Database {
private: private:
static sql::Driver *driver; static sql::Driver* driver;
static sql::Connection *con; static sql::Connection* con;
static sql::Properties props; static sql::Properties props;
static std::string database; static std::string database;
public: public:
@ -23,6 +23,8 @@ public:
static sql::Statement* CreateStmt(); static sql::Statement* CreateStmt();
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query); static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
static void Commit(); static void Commit();
static bool GetAutoCommit();
static void SetAutoCommit(bool value);
static std::string GetDatabase() { return database; } static std::string GetDatabase() { return database; }
static sql::Properties GetProperties() { return props; } static sql::Properties GetProperties() { return props; }

View File

@ -1,5 +1,6 @@
#include "MigrationRunner.h" #include "MigrationRunner.h"
#include "BrickByBrickFix.h"
#include "GeneralUtils.h" #include "GeneralUtils.h"
#include <fstream> #include <fstream>
@ -7,13 +8,13 @@
#include <thread> #include <thread>
void MigrationRunner::RunMigrations() { void MigrationRunner::RunMigrations() {
auto stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());"); auto* stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());");
stmt->executeQuery(); stmt->execute();
delete stmt; delete stmt;
sql::SQLString finalSQL = ""; sql::SQLString finalSQL = "";
Migration checkMigration{}; Migration checkMigration{};
bool runSd0Migrations = false;
for (const auto& entry : GeneralUtils::GetFileNamesFromFolder("./migrations/")) { for (const auto& entry : GeneralUtils::GetFileNamesFromFolder("./migrations/")) {
auto migration = LoadMigration(entry); auto migration = LoadMigration(entry);
@ -25,16 +26,18 @@ void MigrationRunner::RunMigrations() {
stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;"); stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
stmt->setString(1, migration.name); stmt->setString(1, migration.name);
auto res = stmt->executeQuery(); auto* res = stmt->executeQuery();
bool doExit = res->next(); bool doExit = res->next();
delete res; delete res;
delete stmt; delete stmt;
if (doExit) continue; if (doExit) continue;
Game::logger->Log("MigrationRunner", "Running migration: " + migration.name + "\n"); Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str());
if (migration.name == "5_brick_model_sd0.sql") {
runSd0Migrations = true;
} else {
finalSQL.append(migration.data); finalSQL.append(migration.data);
finalSQL.append('\n'); }
stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
stmt->setString(1, entry); stmt->setString(1, entry);
@ -42,16 +45,31 @@ void MigrationRunner::RunMigrations() {
delete stmt; delete stmt;
} }
if (finalSQL.empty() && !runSd0Migrations) {
Game::logger->Log("MigrationRunner", "Server database is up to date.");
return;
}
if (!finalSQL.empty()) { if (!finalSQL.empty()) {
auto migration = GeneralUtils::SplitString(static_cast<std::string>(finalSQL), ';');
std::unique_ptr<sql::Statement> simpleStatement(Database::CreateStmt());
for (auto& query : migration) {
try { try {
auto simpleStatement = Database::CreateStmt(); if (query.empty()) continue;
simpleStatement->execute(finalSQL); simpleStatement->execute(query);
delete simpleStatement; } catch (sql::SQLException& e) {
Game::logger->Log("MigrationRunner", "Encountered error running migration: %s", e.what());
} }
catch (sql::SQLException e) {
Game::logger->Log("MigrationRunner", std::string("Encountered error running migration: ") + e.what() + "\n");
} }
} }
// Do this last on the off chance none of the other migrations have been run yet.
if (runSd0Migrations) {
uint32_t numberOfUpdatedModels = BrickByBrickFix::UpdateBrickByBrickModelsToSd0();
Game::logger->Log("MasterServer", "%i models were updated from zlib to sd0.", numberOfUpdatedModels);
uint32_t numberOfTruncatedModels = BrickByBrickFix::TruncateBrokenBrickByBrickXml();
Game::logger->Log("MasterServer", "%i models were truncated from the database.", numberOfTruncatedModels);
}
} }
Migration MigrationRunner::LoadMigration(std::string path) { Migration MigrationRunner::LoadMigration(std::string path) {
@ -59,8 +77,6 @@ Migration MigrationRunner::LoadMigration(std::string path) {
std::ifstream file("./migrations/" + path); std::ifstream file("./migrations/" + path);
if (file.is_open()) { if (file.is_open()) {
std::hash<std::string> hash;
std::string line; std::string line;
std::string total = ""; std::string total = "";

View File

@ -49,7 +49,7 @@ CDActivitiesTable::CDActivitiesTable(void) {
} }
//! Destructor //! Destructor
CDActivitiesTable::~CDActivitiesTable(void) { } CDActivitiesTable::~CDActivitiesTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDActivitiesTable::GetName(void) const { std::string CDActivitiesTable::GetName(void) const {

View File

@ -37,7 +37,7 @@ CDActivityRewardsTable::CDActivityRewardsTable(void) {
} }
//! Destructor //! Destructor
CDActivityRewardsTable::~CDActivityRewardsTable(void) { } CDActivityRewardsTable::~CDActivityRewardsTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDActivityRewardsTable::GetName(void) const { std::string CDActivityRewardsTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the ActivityRewards table \brief Contains data for the ActivityRewards table
*/ */
//! ActivityRewards Entry Struct //! ActivityRewards Entry Struct
struct CDActivityRewards { struct CDActivityRewards {
unsigned int objectTemplate; //!< The object template (?) unsigned int objectTemplate; //!< The object template (?)
unsigned int ActivityRewardIndex; //!< The activity reward index unsigned int ActivityRewardIndex; //!< The activity reward index

View File

@ -43,7 +43,7 @@ CDAnimationsTable::CDAnimationsTable(void) {
} }
//! Destructor //! Destructor
CDAnimationsTable::~CDAnimationsTable(void) { } CDAnimationsTable::~CDAnimationsTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDAnimationsTable::GetName(void) const { std::string CDAnimationsTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the Animations table \brief Contains data for the Animations table
*/ */
//! Animations Entry Struct //! Animations Entry Struct
struct CDAnimations { struct CDAnimations {
unsigned int animationGroupID; //!< The animation group ID unsigned int animationGroupID; //!< The animation group ID
std::string animation_type; //!< The animation type std::string animation_type; //!< The animation type

View File

@ -29,7 +29,7 @@ CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
} }
//! Destructor //! Destructor
CDBehaviorParameterTable::~CDBehaviorParameterTable(void) { } CDBehaviorParameterTable::~CDBehaviorParameterTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDBehaviorParameterTable::GetName(void) const { std::string CDBehaviorParameterTable::GetName(void) const {

View File

@ -10,7 +10,7 @@
\brief Contains data for the BehaviorParameter table \brief Contains data for the BehaviorParameter table
*/ */
//! BehaviorParameter Entry Struct //! BehaviorParameter Entry Struct
struct CDBehaviorParameter { struct CDBehaviorParameter {
int32_t behaviorID; //!< The Behavior ID int32_t behaviorID; //!< The Behavior ID
int32_t parameterID; //!< The Parameter ID int32_t parameterID; //!< The Parameter ID

View File

@ -23,7 +23,7 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
} }
//! Destructor //! Destructor
CDBehaviorTemplateTable::~CDBehaviorTemplateTable(void) { } CDBehaviorTemplateTable::~CDBehaviorTemplateTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDBehaviorTemplateTable::GetName(void) const { std::string CDBehaviorTemplateTable::GetName(void) const {

View File

@ -10,7 +10,7 @@
\brief Contains data for the BehaviorTemplate table \brief Contains data for the BehaviorTemplate table
*/ */
//! BehaviorTemplate Entry Struct //! BehaviorTemplate Entry Struct
struct CDBehaviorTemplate { struct CDBehaviorTemplate {
unsigned int behaviorID; //!< The Behavior ID unsigned int behaviorID; //!< The Behavior ID
unsigned int templateID; //!< The Template ID (LOT) unsigned int templateID; //!< The Template ID (LOT)

View File

@ -32,7 +32,7 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) {
} }
//! Destructor //! Destructor
CDBrickIDTableTable::~CDBrickIDTableTable(void) { } CDBrickIDTableTable::~CDBrickIDTableTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDBrickIDTableTable::GetName(void) const { std::string CDBrickIDTableTable::GetName(void) const {

View File

@ -28,7 +28,7 @@ CDComponentsRegistryTable::CDComponentsRegistryTable(void) {
} }
//! Destructor //! Destructor
CDComponentsRegistryTable::~CDComponentsRegistryTable(void) { } CDComponentsRegistryTable::~CDComponentsRegistryTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDComponentsRegistryTable::GetName(void) const { std::string CDComponentsRegistryTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the ComponentsRegistry table \brief Contains data for the ComponentsRegistry table
*/ */
//! ComponentsRegistry Entry Struct //! ComponentsRegistry Entry Struct
struct CDComponentsRegistry { struct CDComponentsRegistry {
unsigned int id; //!< The LOT is used as the ID unsigned int id; //!< The LOT is used as the ID
unsigned int component_type; //!< See ComponentTypes enum for values unsigned int component_type; //!< See ComponentTypes enum for values
@ -31,6 +31,18 @@ public:
//! Destructor //! Destructor
~CDComponentsRegistryTable(void); ~CDComponentsRegistryTable(void);
//! Returns the table's name
/*!
\return The table name
*/
std::string GetName(void) const override;
//! Constructor
CDComponentsRegistryTable(void);
//! Destructor
~CDComponentsRegistryTable(void);
//! Returns the table's name //! Returns the table's name
/*! /*!
\return The table name \return The table name

View File

@ -35,7 +35,7 @@ CDCurrencyTableTable::CDCurrencyTableTable(void) {
} }
//! Destructor //! Destructor
CDCurrencyTableTable::~CDCurrencyTableTable(void) { } CDCurrencyTableTable::~CDCurrencyTableTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDCurrencyTableTable::GetName(void) const { std::string CDCurrencyTableTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the CurrencyTable table \brief Contains data for the CurrencyTable table
*/ */
//! CurrencyTable Struct //! CurrencyTable Struct
struct CDCurrencyTable { struct CDCurrencyTable {
unsigned int currencyIndex; //!< The Currency Index unsigned int currencyIndex; //!< The Currency Index
unsigned int npcminlevel; //!< The minimum level of the npc unsigned int npcminlevel; //!< The minimum level of the npc

View File

@ -44,7 +44,7 @@ CDDestructibleComponentTable::CDDestructibleComponentTable(void) {
} }
//! Destructor //! Destructor
CDDestructibleComponentTable::~CDDestructibleComponentTable(void) { } CDDestructibleComponentTable::~CDDestructibleComponentTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDDestructibleComponentTable::GetName(void) const { std::string CDDestructibleComponentTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the DestructibleComponent table \brief Contains data for the DestructibleComponent table
*/ */
//! ItemComponent Struct //! ItemComponent Struct
struct CDDestructibleComponent { struct CDDestructibleComponent {
unsigned int id; //!< The component ID from the ComponentsRegistry Table unsigned int id; //!< The component ID from the ComponentsRegistry Table
int faction; //!< The Faction ID of the object int faction; //!< The Faction ID of the object

View File

@ -35,7 +35,7 @@ std::string CDEmoteTableTable::GetName(void) const {
return "Emotes"; return "Emotes";
} }
CDEmoteTable * CDEmoteTableTable::GetEmote(int id) { CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
for (auto e : entries) { for (auto e : entries) {
if (e.first == id) return e.second; if (e.first == id) return e.second;
} }

View File

@ -9,7 +9,7 @@
\brief Contains data for the CDEmoteTable table \brief Contains data for the CDEmoteTable table
*/ */
//! CDEmoteEntry Struct //! CDEmoteEntry Struct
struct CDEmoteTable { struct CDEmoteTable {
CDEmoteTable() { CDEmoteTable() {
ID = -1; ID = -1;

View File

@ -35,7 +35,7 @@ CDFeatureGatingTable::CDFeatureGatingTable(void) {
} }
//! Destructor //! Destructor
CDFeatureGatingTable::~CDFeatureGatingTable(void) { } CDFeatureGatingTable::~CDFeatureGatingTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDFeatureGatingTable::GetName(void) const { std::string CDFeatureGatingTable::GetName(void) const {
@ -52,12 +52,9 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
return data; return data;
} }
bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const {
{ for (const auto& entry : entries) {
for (const auto& entry : entries) if (entry.featureName == feature) {
{
if (entry.featureName == feature)
{
return true; return true;
} }
} }

View File

@ -7,7 +7,7 @@
\file CDFeatureGatingTable.hpp \file CDFeatureGatingTable.hpp
*/ */
//! ItemComponent Struct //! ItemComponent Struct
struct CDFeatureGating { struct CDFeatureGating {
std::string featureName; std::string featureName;
int32_t major; int32_t major;

View File

@ -34,7 +34,7 @@ CDInventoryComponentTable::CDInventoryComponentTable(void) {
} }
//! Destructor //! Destructor
CDInventoryComponentTable::~CDInventoryComponentTable(void) { } CDInventoryComponentTable::~CDInventoryComponentTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDInventoryComponentTable::GetName(void) const { std::string CDInventoryComponentTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the InventoryComponent table \brief Contains data for the InventoryComponent table
*/ */
//! ItemComponent Struct //! ItemComponent Struct
struct CDInventoryComponent { struct CDInventoryComponent {
unsigned int id; //!< The component ID for this object unsigned int id; //!< The component ID for this object
unsigned int itemid; //!< The LOT of the object unsigned int itemid; //!< The LOT of the object

View File

@ -45,7 +45,7 @@ CDItemComponentTable::CDItemComponentTable(void) {
entry.offsetGroupID = tableData.getIntField(19, -1); entry.offsetGroupID = tableData.getIntField(19, -1);
entry.buildTypes = tableData.getIntField(20, -1); entry.buildTypes = tableData.getIntField(20, -1);
entry.reqPrecondition = tableData.getStringField(21, ""); entry.reqPrecondition = tableData.getStringField(21, "");
entry.animationFlag = tableData.getIntField(22, -1); entry.animationFlag = tableData.getIntField(22, 0);
entry.equipEffects = tableData.getIntField(23, -1); entry.equipEffects = tableData.getIntField(23, -1);
entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false; entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false;
entry.itemRating = tableData.getIntField(25, -1); entry.itemRating = tableData.getIntField(25, -1);
@ -75,14 +75,14 @@ CDItemComponentTable::CDItemComponentTable(void) {
} }
//! Destructor //! Destructor
CDItemComponentTable::~CDItemComponentTable(void) { } CDItemComponentTable::~CDItemComponentTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDItemComponentTable::GetName(void) const { std::string CDItemComponentTable::GetName(void) const {
return "ItemComponent"; return "ItemComponent";
} }
const CDItemComponent & CDItemComponentTable::GetItemComponentByID(unsigned int skillID) { const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int skillID) {
const auto& it = this->entries.find(skillID); const auto& it = this->entries.find(skillID);
if (it != this->entries.end()) { if (it != this->entries.end()) {
return it->second; return it->second;
@ -123,7 +123,7 @@ const CDItemComponent & CDItemComponentTable::GetItemComponentByID(unsigned int
entry.offsetGroupID = tableData.getIntField(19, -1); entry.offsetGroupID = tableData.getIntField(19, -1);
entry.buildTypes = tableData.getIntField(20, -1); entry.buildTypes = tableData.getIntField(20, -1);
entry.reqPrecondition = tableData.getStringField(21, ""); entry.reqPrecondition = tableData.getStringField(21, "");
entry.animationFlag = tableData.getIntField(22, -1); entry.animationFlag = tableData.getIntField(22, 0);
entry.equipEffects = tableData.getIntField(23, -1); entry.equipEffects = tableData.getIntField(23, -1);
entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false; entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false;
entry.itemRating = tableData.getIntField(25, -1); entry.itemRating = tableData.getIntField(25, -1);

View File

@ -9,7 +9,7 @@
\brief Contains data for the ItemComponent table \brief Contains data for the ItemComponent table
*/ */
//! ItemComponent Struct //! ItemComponent Struct
struct CDItemComponent { struct CDItemComponent {
unsigned int id; //!< The Component ID unsigned int id; //!< The Component ID
std::string equipLocation; //!< The equip location std::string equipLocation; //!< The equip location

View File

@ -33,7 +33,7 @@ CDItemSetSkillsTable::CDItemSetSkillsTable(void) {
} }
//! Destructor //! Destructor
CDItemSetSkillsTable::~CDItemSetSkillsTable(void) { } CDItemSetSkillsTable::~CDItemSetSkillsTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDItemSetSkillsTable::GetName(void) const { std::string CDItemSetSkillsTable::GetName(void) const {
@ -55,8 +55,7 @@ std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetEntries(void) const {
return this->entries; return this->entries;
} }
std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(unsigned int SkillSetID) std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(unsigned int SkillSetID) {
{
std::vector<CDItemSetSkills> toReturn; std::vector<CDItemSetSkills> toReturn;
for (CDItemSetSkills entry : this->entries) { for (CDItemSetSkills entry : this->entries) {

View File

@ -8,7 +8,7 @@
\brief Contains data for the ItemSetSkills table \brief Contains data for the ItemSetSkills table
*/ */
//! ZoneTable Struct //! ZoneTable Struct
struct CDItemSetSkills { struct CDItemSetSkills {
unsigned int SkillSetID; //!< The skill set ID unsigned int SkillSetID; //!< The skill set ID
unsigned int SkillID; //!< The skill ID unsigned int SkillID; //!< The skill ID

View File

@ -45,7 +45,7 @@ CDItemSetsTable::CDItemSetsTable(void) {
} }
//! Destructor //! Destructor
CDItemSetsTable::~CDItemSetsTable(void) { } CDItemSetsTable::~CDItemSetsTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDItemSetsTable::GetName(void) const { std::string CDItemSetsTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the ItemSets table \brief Contains data for the ItemSets table
*/ */
//! ZoneTable Struct //! ZoneTable Struct
struct CDItemSets { struct CDItemSets {
unsigned int setID; //!< The item set ID unsigned int setID; //!< The item set ID
unsigned int locStatus; //!< The loc status unsigned int locStatus; //!< The loc status

View File

@ -33,7 +33,7 @@ CDLevelProgressionLookupTable::CDLevelProgressionLookupTable(void) {
} }
//! Destructor //! Destructor
CDLevelProgressionLookupTable::~CDLevelProgressionLookupTable(void) { } CDLevelProgressionLookupTable::~CDLevelProgressionLookupTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDLevelProgressionLookupTable::GetName(void) const { std::string CDLevelProgressionLookupTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the LevelProgressionLookup table \brief Contains data for the LevelProgressionLookup table
*/ */
//! LevelProgressionLookup Entry Struct //! LevelProgressionLookup Entry Struct
struct CDLevelProgressionLookup { struct CDLevelProgressionLookup {
unsigned int id; //!< The Level ID unsigned int id; //!< The Level ID
unsigned int requiredUScore; //!< The required LEGO Score unsigned int requiredUScore; //!< The required LEGO Score

View File

@ -39,7 +39,7 @@ CDLootMatrixTable::CDLootMatrixTable(void) {
} }
//! Destructor //! Destructor
CDLootMatrixTable::~CDLootMatrixTable(void) { } CDLootMatrixTable::~CDLootMatrixTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDLootMatrixTable::GetName(void) const { std::string CDLootMatrixTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the ObjectSkills table \brief Contains data for the ObjectSkills table
*/ */
//! LootMatrix Struct //! LootMatrix Struct
struct CDLootMatrix { struct CDLootMatrix {
unsigned int LootMatrixIndex; //!< The Loot Matrix Index unsigned int LootMatrixIndex; //!< The Loot Matrix Index
unsigned int LootTableIndex; //!< The Loot Table Index unsigned int LootTableIndex; //!< The Loot Table Index

View File

@ -36,7 +36,7 @@ CDLootTableTable::CDLootTableTable(void) {
} }
//! Destructor //! Destructor
CDLootTableTable::~CDLootTableTable(void) { } CDLootTableTable::~CDLootTableTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDLootTableTable::GetName(void) const { std::string CDLootTableTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the LootTable table \brief Contains data for the LootTable table
*/ */
//! LootTable Struct //! LootTable Struct
struct CDLootTable { struct CDLootTable {
unsigned int itemid; //!< The LOT of the item unsigned int itemid; //!< The LOT of the item
unsigned int LootTableIndex; //!< The Loot Table Index unsigned int LootTableIndex; //!< The Loot Table Index

View File

@ -38,7 +38,7 @@ CDMissionEmailTable::CDMissionEmailTable(void) {
} }
//! Destructor //! Destructor
CDMissionEmailTable::~CDMissionEmailTable(void) { } CDMissionEmailTable::~CDMissionEmailTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDMissionEmailTable::GetName(void) const { std::string CDMissionEmailTable::GetName(void) const {

View File

@ -35,7 +35,7 @@ CDMissionNPCComponentTable::CDMissionNPCComponentTable(void) {
} }
//! Destructor //! Destructor
CDMissionNPCComponentTable::~CDMissionNPCComponentTable(void) { } CDMissionNPCComponentTable::~CDMissionNPCComponentTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDMissionNPCComponentTable::GetName(void) const { std::string CDMissionNPCComponentTable::GetName(void) const {

View File

@ -8,7 +8,7 @@
\brief Contains data for the ObjectSkills table \brief Contains data for the ObjectSkills table
*/ */
//! MissionNPCComponent Struct //! MissionNPCComponent Struct
struct CDMissionNPCComponent { struct CDMissionNPCComponent {
unsigned int id; //!< The ID unsigned int id; //!< The ID
unsigned int missionID; //!< The Mission ID unsigned int missionID; //!< The Mission ID

View File

@ -43,7 +43,7 @@ CDMissionTasksTable::CDMissionTasksTable(void) {
} }
//! Destructor //! Destructor
CDMissionTasksTable::~CDMissionTasksTable(void) { } CDMissionTasksTable::~CDMissionTasksTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDMissionTasksTable::GetName(void) const { std::string CDMissionTasksTable::GetName(void) const {
@ -60,14 +60,11 @@ std::vector<CDMissionTasks> CDMissionTasksTable::Query(std::function<bool(CDMiss
return data; return data;
} }
std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(uint32_t missionID) std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(uint32_t missionID) {
{
std::vector<CDMissionTasks*> tasks; std::vector<CDMissionTasks*> tasks;
for (auto& entry : this->entries) for (auto& entry : this->entries) {
{ if (entry.id == missionID) {
if (entry.id == missionID)
{
CDMissionTasks* task = const_cast<CDMissionTasks*>(&entry); CDMissionTasks* task = const_cast<CDMissionTasks*>(&entry);
tasks.push_back(task); tasks.push_back(task);

View File

@ -8,7 +8,7 @@
\brief Contains data for the MissionTasks table \brief Contains data for the MissionTasks table
*/ */
//! ObjectSkills Struct //! ObjectSkills Struct
struct CDMissionTasks { struct CDMissionTasks {
unsigned int id; //!< The Mission ID that the task belongs to unsigned int id; //!< The Mission ID that the task belongs to
UNUSED(unsigned int locStatus); //!< ??? UNUSED(unsigned int locStatus); //!< ???

View File

@ -86,7 +86,7 @@ CDMissionsTable::CDMissionsTable(void) {
} }
//! Destructor //! Destructor
CDMissionsTable::~CDMissionsTable(void) { } CDMissionsTable::~CDMissionsTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDMissionsTable::GetName(void) const { std::string CDMissionsTable::GetName(void) const {
@ -108,12 +108,9 @@ const std::vector<CDMissions>& CDMissionsTable::GetEntries(void) const {
return this->entries; return this->entries;
} }
const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const {
{ for (const auto& entry : entries) {
for (const auto& entry : entries) if (entry.id == missionID) {
{
if (entry.id == missionID)
{
return const_cast<CDMissions*>(&entry); return const_cast<CDMissions*>(&entry);
} }
} }
@ -121,12 +118,9 @@ const CDMissions* CDMissionsTable::GetPtrByMissionID(uint32_t missionID) const
return &Default; return &Default;
} }
const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& found) const const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& found) const {
{ for (const auto& entry : entries) {
for (const auto& entry : entries) if (entry.id == missionID) {
{
if (entry.id == missionID)
{
found = true; found = true;
return entry; return entry;

View File

@ -10,7 +10,7 @@
\brief Contains data for the Missions table \brief Contains data for the Missions table
*/ */
//! Missions Struct //! Missions Struct
struct CDMissions { struct CDMissions {
int id; //!< The Mission ID int id; //!< The Mission ID
std::string defined_type; //!< The type of mission std::string defined_type; //!< The type of mission

View File

@ -38,7 +38,7 @@ CDMovementAIComponentTable::CDMovementAIComponentTable(void) {
} }
//! Destructor //! Destructor
CDMovementAIComponentTable::~CDMovementAIComponentTable(void) { } CDMovementAIComponentTable::~CDMovementAIComponentTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDMovementAIComponentTable::GetName(void) const { std::string CDMovementAIComponentTable::GetName(void) const {

View File

@ -34,7 +34,7 @@ CDObjectSkillsTable::CDObjectSkillsTable(void) {
} }
//! Destructor //! Destructor
CDObjectSkillsTable::~CDObjectSkillsTable(void) { } CDObjectSkillsTable::~CDObjectSkillsTable(void) {}
//! Returns the table's name //! Returns the table's name
std::string CDObjectSkillsTable::GetName(void) const { std::string CDObjectSkillsTable::GetName(void) const {

Some files were not shown because too many files have changed in this diff Show More