diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 5af12d3a..00000000 --- a/.clang-format +++ /dev/null @@ -1,37 +0,0 @@ ---- -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: false - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - AfterExternBlock: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: false - SplitEmptyNamespace: false - BeforeLambdaBody: false - BeforeWhile: false -BreakBeforeBraces: Attach -ColumnLimit: 0 -IndentWidth: 4 -IndentCaseLabels: true -IncludeBlocks: Regroup -IncludeCategories: - - Regex: '<[[:alnum:].]+\.h>' - Priority: 1 - - Regex: '<[[:alnum:].]+>' - Priority: 2 - - Regex: '.*/.*' - Priority: 3 - - Regex: '.*' - Priority: 4 -DerivePointerAlignment: false -PointerAlignment: Left -... diff --git a/.clang-tidy b/.clang-tidy deleted file mode 100644 index ea50801d..00000000 --- a/.clang-tidy +++ /dev/null @@ -1,17 +0,0 @@ -Checks: '-*,readability-*,performance-*,modernize-*,-modernize-use-trailing-return-type,bugprone-*' -WarningsAsErrors: true -HeaderFilterRegex: '' -FormatStyle: none -CheckOptions: - - key: readability-identifier-naming.ClassCase - value: CamelCase - - key: readability-identifier-naming.ClassMethodCase - value: CamelCase - - key: readability-identifier-naming.ClassMemberPrefix - value: m_ - - key: readability-identifier-naming.ClassMemberCase - value: CamelCase - - key: readability-identifier-naming.ClassConstantCase - value: UPPER_CASE - - key: readability-identifier-naming.FunctionCase - value: CamelCase \ No newline at end of file diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 37567a02..14e48fbe 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,6 @@ # convert to unix line endings 72477e01e2711e0f61cdb192ee266e5e21b8846f + +# enum cleanup +faf42d2f8cf432df2993b031f079b0b8c6d7dbe7 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8f65fd8e..ab3917c1 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -16,7 +16,7 @@ jobs: os: [ windows-2022, ubuntu-20.04, macos-11 ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: true - name: Add msbuild to PATH (Windows only) @@ -35,7 +35,7 @@ jobs: buildPreset: "ci-${{matrix.os}}" testPreset: "ci-${{matrix.os}}" - name: artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: ${{ github.ref == 'ref/head/main' }} with: name: build-${{matrix.os}} diff --git a/.gitignore b/.gitignore index 3777608d..e093ba4b 100644 --- a/.gitignore +++ b/.gitignore @@ -121,4 +121,4 @@ docker/__pycache__ docker-compose.override.yml -!/tests/TestBitStreams/*.bin +!*Test.bin diff --git a/.gitmodules b/.gitmodules index 6fb56bde..33193447 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,12 +14,6 @@ path = thirdparty/mariadb-connector-cpp url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git ignore = dirty -[submodule "thirdparty/docker-utils"] - path = thirdparty/docker-utils - url = https://github.com/lcdr/utils.git -[submodule "thirdparty/LUnpack"] - path = thirdparty/LUnpack - url = https://github.com/Xiphoseer/LUnpack.git [submodule "thirdparty/AccountManager"] path = thirdparty/AccountManager url = https://github.com/DarkflameUniverse/AccountManager diff --git a/CMakeLists.txt b/CMakeLists.txt index 34a6cd27..41d4219f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,15 +76,21 @@ endif() # Our output dir set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR}) + +# TODO make this not have to override the build type directories +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -# Create a /res directory -make_directory(${CMAKE_BINARY_DIR}/res) - -# Create a /locale directory -make_directory(${CMAKE_BINARY_DIR}/locale) +# Create a /resServer directory +make_directory(${CMAKE_BINARY_DIR}/resServer) # Create a /logs directory make_directory(${CMAKE_BINARY_DIR}/logs) @@ -146,6 +152,8 @@ endforeach() # Create our list of include directories set(INCLUDED_DIRECTORIES "dCommon" + "dCommon/dClient" + "dCommon/dEnums" "dChatFilter" "dGame" "dGame/dBehaviors" @@ -155,8 +163,8 @@ set(INCLUDED_DIRECTORIES "dGame/dMission" "dGame/dEntity" "dGame/dPropertyBehaviors" + "dGame/dPropertyBehaviors/ControlBehaviorMessages" "dGame/dUtilities" - "dCommon/dClient" "dPhysics" "dNavigation" "dNavigation/dTerrain" @@ -169,6 +177,7 @@ set(INCLUDED_DIRECTORIES "dScripts/ai" "dScripts/client" "dScripts/EquipmentScripts" + "dScripts/EquipmentTriggers" "dScripts/zone" "dScripts/02_server/DLU" "dScripts/02_server/Enemy" @@ -239,6 +248,11 @@ set(INCLUDED_DIRECTORIES "thirdparty/recastnavigation" "thirdparty/SQLite" "thirdparty/cpplinq" + + "tests" + "tests/dCommonTests" + "tests/dGameTests" + "tests/dGameTests/dComponentsTests" ) # Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux) @@ -320,8 +334,6 @@ if (UNIX) endif() endif() -add_subdirectory(tests) - # Include all of our binary directories add_subdirectory(dWorldServer) add_subdirectory(dAuthServer) @@ -354,3 +366,7 @@ target_precompile_headers( tinyxml2 PRIVATE "$<$:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>" ) + +if (${__enable_testing__} MATCHES "1") + add_subdirectory(tests) +endif() diff --git a/CMakePresets.json b/CMakePresets.json index badb161d..f8170755 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,131 +1,128 @@ { - "version": 3, - "cmakeMinimumRequired": { - "major": 3, - "minor": 14, - "patch": 0 - }, - "configurePresets": [ - { - "name": "default", - "displayName": "Default configure step", - "description": "Use 'build' dir and Unix makefiles", - "binaryDir": "${sourceDir}/build", - "generator": "Unix Makefiles" + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 14, + "patch": 0 }, - { - "name": "ci-ubuntu-20.04", - "displayName": "CI configure step for Ubuntu", - "description": "Same as default, Used in GitHub actions workflow", - "inherits": "default" - }, - { - "name": "ci-macos-11", - "displayName": "CI configure step for MacOS", - "description": "Same as default, Used in GitHub actions workflow", - "inherits": "default", - "cacheVariables": { - "OPENSSL_ROOT_DIR": "/usr/local/Cellar/openssl@3/3.0.5/" - } - }, - { - "name": "ci-windows-2022", - "displayName": "CI configure step for Windows", - "description": "Set architecture to 64-bit (b/c RakNet)", - "inherits": "default", - "generator": "Visual Studio 17 2022", - "architecture": { - "value": "x64" + "configurePresets": [ + { + "name": "default", + "displayName": "Default configure step", + "description": "Use 'build' dir and Unix makefiles", + "binaryDir": "${sourceDir}/build", + "generator": "Unix Makefiles" }, - "cacheVariables": { - "CMAKE_BUILD_TYPE": "RelWithDebInfo" + { + "name": "ci-ubuntu-20.04", + "displayName": "CI configure step for Ubuntu", + "description": "Same as default, Used in GitHub actions workflow", + "inherits": "default" + }, + { + "name": "ci-macos-11", + "displayName": "CI configure step for MacOS", + "description": "Same as default, Used in GitHub actions workflow", + "inherits": "default" + }, + { + "name": "ci-windows-2022", + "displayName": "CI configure step for Windows", + "description": "Set architecture to 64-bit (b/c RakNet)", + "inherits": "default", + "generator": "Visual Studio 17 2022", + "architecture": { + "value": "x64" + }, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "windows-default", + "inherits": "ci-windows-2022", + "displayName": "Windows only Configure Settings", + "description": "Sets build and install directories", + "generator": "Ninja", + "architecture": { + "value": "x64", + "strategy": "external" + } } - }, - { - "name": "windows-default", - "inherits": "ci-windows-2022", - "displayName": "Windows only Configure Settings", - "description": "Sets build and install directories", - "generator": "Ninja", - "architecture": { - "value": "x64", - "strategy": "external" - } - } - ], - "buildPresets": [ - { - "name": "default", - "configurePreset": "default", - "displayName": "Default Build", - "description": "Default Build", - "jobs": 2 - }, - { - "name": "ci-windows-2022", - "configurePreset": "ci-windows-2022", - "displayName": "Windows CI Build", - "description": "This preset is used by the CI build on windows", - "configuration": "RelWithDebInfo", - "jobs": 2 - }, - { - "name": "ci-ubuntu-20.04", - "configurePreset": "ci-ubuntu-20.04", - "displayName": "Linux CI Build", - "description": "This preset is used by the CI build on linux", - "jobs": 2 - }, - { - "name": "ci-macos-11", - "configurePreset": "ci-macos-11", - "displayName": "MacOS CI Build", - "description": "This preset is used by the CI build on MacOS", - "jobs": 2 - } - ], - "testPresets": [ - { - "name": "ci-ubuntu-20.04", - "configurePreset": "ci-ubuntu-20.04", - "displayName": "CI Tests on Linux", - "description": "Runs all tests on a linux configuration", - "execution": { + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default", + "displayName": "Default Build", + "description": "Default Build", "jobs": 2 }, - "output": { - "outputOnFailure": true - } - }, - { - "name": "ci-macos-11", - "configurePreset": "ci-macos-11", - "displayName": "CI Tests on MacOS", - "description": "Runs all tests on a Mac configuration", - "execution": { + { + "name": "ci-windows-2022", + "configurePreset": "ci-windows-2022", + "displayName": "Windows CI Build", + "description": "This preset is used by the CI build on windows", + "configuration": "RelWithDebInfo", "jobs": 2 }, - "output": { - "outputOnFailure": true + { + "name": "ci-ubuntu-20.04", + "configurePreset": "ci-ubuntu-20.04", + "displayName": "Linux CI Build", + "description": "This preset is used by the CI build on linux", + "jobs": 2 + }, + { + "name": "ci-macos-11", + "configurePreset": "ci-macos-11", + "displayName": "MacOS CI Build", + "description": "This preset is used by the CI build on MacOS", + "jobs": 2 } - }, - { - "name": "ci-windows-2022", - "configurePreset": "ci-windows-2022", - "displayName": "CI Tests on windows", - "description": "Runs all tests on a windows configuration", - "configuration": "RelWithDebInfo", + ], + "testPresets": [ + { + "name": "ci-ubuntu-20.04", + "configurePreset": "ci-ubuntu-20.04", + "displayName": "CI Tests on Linux", + "description": "Runs all tests on a linux configuration", "execution": { "jobs": 2 }, + "output": { + "outputOnFailure": true + } + }, + { + "name": "ci-macos-11", + "configurePreset": "ci-macos-11", + "displayName": "CI Tests on MacOS", + "description": "Runs all tests on a Mac configuration", + "execution": { + "jobs": 2 + }, + "output": { + "outputOnFailure": true + } + }, + { + "name": "ci-windows-2022", + "configurePreset": "ci-windows-2022", + "displayName": "CI Tests on windows", + "description": "Runs all tests on a windows configuration", + "configuration": "RelWithDebInfo", + "execution": { + "jobs": 2 + }, + "output": { + "outputOnFailure": true + }, "filter": { "exclude": { "name": "((example)|(minigzip))+" } - }, - "output": { - "outputOnFailure": true + } } - } - ] -} + ] + } diff --git a/CMakeVariables.txt b/CMakeVariables.txt index e68e826e..d3c8b36f 100644 --- a/CMakeVariables.txt +++ b/CMakeVariables.txt @@ -8,13 +8,17 @@ LICENSE=AGPL-3.0 # 171022 - Unmodded client NET_VERSION=171022 # Debugging -__dynamic=1 # Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs. -# __ggdb=1 +__dynamic=1 # Set __ggdb to 1 to enable the -ggdb flag for the linker, including more debug info. -# __include_backtrace__=1 +# __ggdb=1 # Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs. -# __compile_backtrace__=1 +# __include_backtrace__=1 # Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries. -__maria_db_connector_compile_jobs__=1 +# __compile_backtrace__=1 # Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with. +__maria_db_connector_compile_jobs__=1 +# When set to 1 and uncommented, compiling and linking testing folders and libraries will be done. +__enable_testing__=1 +# The path to OpenSSL. Change this if your OpenSSL install path is different than the default. +OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/ diff --git a/Docker.md b/Docker.md index 54d0ce19..b06bd0fe 100644 --- a/Docker.md +++ b/Docker.md @@ -4,7 +4,7 @@ - [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker) - [Docker Compose](https://docs.docker.com/compose/install/) (Included in Docker Desktop) -- LEGO® Universe packed Client. Check the main [README](./README.md) for details on this. +- LEGO® Universe Client. Check the main [README](./README.md) for details on this. ## Run server inside Docker diff --git a/Docker_Windows.md b/Docker_Windows.md index 1cc633cc..984bbe57 100644 --- a/Docker_Windows.md +++ b/Docker_Windows.md @@ -25,7 +25,7 @@ 11. Once the command has completed (you can see you path again and can enter commands), close the window. 12. Inside the downloaded folder, copy `.env.example` and name the copy `.env` 13. Open `.env` with Notepad by right-clicking it and selecting _Open With_ -> _More apps_ -> _Notepad_. -14. Change the text after `CLIENT_PATH=` to the location of your client. The folder you are pointing to must contain a folder called `client` which should contain the client files. +14. Change the text after `CLIENT_PATH=` to the location of your client. This folder must contain either a folder `client` or `legouniverse.exe`. > If you need the extra performance, place the client files in `\\wsl$\\...` to avoid working across file systems, see [Docker Best Practices](https://docs.docker.com/desktop/windows/wsl/#best-practices) and [WSL documentation](https://docs.microsoft.com/en-us/windows/wsl/filesystems#file-storage-and-performance-across-file-systems). 15. Optionally, you can change the number after `BUILD_THREADS=` to the number of cores / threads your processor has. If your computer crashes while building, you can try to reduce this value. diff --git a/README.md b/README.md index 8f9eaf8d..df782a32 100644 --- a/README.md +++ b/README.md @@ -18,206 +18,192 @@ Darkflame Universe is licensed under AGPLv3, please read [LICENSE](LICENSE). Som Throughout the entire build and setup process a level of familiarity with the command line and preferably a Unix-like development environment is greatly advantageous. ### Hosting a server -We do not recommend hosting public servers. DLU is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks. +We do not recommend hosting public servers. Darkflame Universe is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks. ### Supply of resource files -Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed in the resources tab below when checking if a client will work. +Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed [here](#verifying-your-client-files) to see if a client will work. -## Build -Development of the latest iteration of Darkflame Universe has been done primarily in a Unix-like environment and is where it has been tested and designed for deployment. It is therefore highly recommended that Darkflame Universe be built and deployed using a Unix-like environment for the most streamlined experience. +## Steps to setup server +* [Clone this repository](#clone-the-repository) +* [Install dependencies](#install-dependencies) +* [Database setup](#database-setup) +* [Build the server](#build-the-server) +* [Configuring your server](#configuring-your-server) + * [Required Configuration](#required-configuration) + * [Optional Configuration](#optional-configuration) +* [Verify your setup](#verify-your-setup) +* [Running the server](#running-the-server) +* [User Guide](#user-guide) -### Prerequisites -#### Clone the repository +## Clone the repository +If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win) + +Then run the following command ```bash git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer ``` -#### Python -Some tools utilized to streamline the setup process require Python 3, make sure you have it installed. +## Install dependencies +### Windows packages +Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed. +You'll also need to download and install [CMake](https://cmake.org/download/) (version **CMake version 3.18** or later!). -### Choosing the right version for your client -DLU clients identify themselves using a higher version number than the regular live clients out there. -This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client. +### MacOS packages +Ensure you have [brew](https://brew.sh) installed. +You will need to install the following packages +```bash +brew install cmake gcc mariadb openssl zlib +``` -If you're using a DLU client you'll have to go into the "CMakeVariables.txt" file and change the NET_VERSION variable to 171023 to match the modified client's version number. +### Linux packages +Make sure packages like `gcc`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. You will also need a MySQL database solution to use. We recommend using `mariadb-server`. -### Using Docker -Refer to [Docker.md](/Docker.md). +For Ubuntu, you would run the following commands. On other systems, the package install command will differ. -For Windows, refer to [Docker_Windows.md](/Docker_Windows.md). +```bash +sudo apt update && sudo apt upgrade -### Linux builds -Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. +# Install packages +sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-server cmake +``` -CMake must be version 3.14 or higher! +#### Required CMake version +This project uses **CMake version 3.18** or higher and as such you will need to ensure you have this version installed. +You can check your CMake version by using the following command in a terminal. +```bash +cmake --version +``` -#### Build the repository +If you are going to be using an Ubuntu environment to run the server, you may need to get a more recent version of `cmake` than the packages available may provide. +The general approach to do so would be to obtain a copy of the signing key and then add the CMake repository to your apt. +You can do so with the following commands. + +[Source of the below commands](https://askubuntu.com/questions/355565/how-do-i-install-the-latest-version-of-cmake-from-the-command-line) + +```bash +# Remove the old version of CMake +sudo apt purge --auto-remove cmake + +# Prepare for installation +sudo apt update && sudo apt install -y software-properties-common lsb-release && sudo apt clean all + +# Obtain a copy of the signing key +wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null + +# Add the repository to your sources list. +sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" + +# Next you'll want to ensure that Kitware's keyring stays up to date +sudo apt update +sudo apt install kitware-archive-keyring +sudo rm /etc/apt/trusted.gpg.d/kitware.gpg + +# If sudo apt update above returned an error, copy the public key at the end of the error message and run the following command +# if the error message was "The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 6AF7F09730B3F0A4" +# then the below command would be "sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6AF7F09730B3F0A4" +sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys + +# Finally update and install +sudo apt update +sudo apt install cmake +``` + +## Database setup +First you'll need to start MariaDB. + +For Windows the service is always running by default. + +For MacOS, run the following command +```bash +brew services start mariadb +``` + +For Linux, run the following command +```bash +sudo systemctl start mysql +# If systemctl is not a known command on your distribution, try the following instead +sudo service mysql start +``` + +**You will need to run this command every time you restart your environment** + +If you are using Linux and `systemctl` and want the MariaDB instance to start on startup, run the following command +```bash +sudo systemctl enable --now mysql +``` + +Once MariaDB is started, you'll need to create a user and an empty database for Darkflame Universe to use. + +First, login to the MariaDB instance. + +To do this on Ubuntu/Linux, MacOS, or another Unix like operating system, run the following command in a terminal +```bash +# Logs you into the MariaDB instance as root +sudo mysql +``` + +For Windows, run the following command in the `Command Prompt (MariaDB xx.xx)` terminal +```bash +# Logs you into the mysql instance +mysql -u root -p +# You will then be prompted for the password you set for root during installation of MariaDB +``` + +Now that you are logged in, run the following commands. + +```bash +# Creates a user for this computer which uses a password and grant said user all privileges. +# Change mydarkflameuser to a custom username and password to a custom password. +GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION; +FLUSH PRIVILEGES; + +# Then create a database for Darkflame Universe to use. +CREATE DATABASE darkflame; +``` + +## Build the server You can either run `build.sh` when in the root folder of the repository: ```bash ./build.sh ``` -Or manually run the commands used in `build.sh`: +Or manually run the commands used in [build.sh](build.sh). +If you would like to build the server faster, append `-j` where number is the number of simultaneous compile jobs to run at once. It is recommended that you have this number always be 1 less than your core count to prevent slowdowns. The command would look like this if you would build with 4 jobs at once: ```bash -# Create the build directory, preserving it if it already exists -mkdir -p build -cd build - -# Run CMake to generate make files -cmake .. - -# To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8' -cmake --build . --config Release +./build.sh -j4 ``` +### Notes +Depending on your operating system, you may need to adjust some pre-processor defines in [CMakeVariables.txt](./CMakeVariables.txt) before building: +* If you are on MacOS, ensure OPENSSL_ROOT_DIR is pointing to the openssl root directory. +* If you are using a Darkflame Universe client, ensure NET_VERSION is changed to 171023. -### MacOS builds -Ensure `cmake`, `zlib` and `open ssl` are installed as well as a compiler (e.g `clang` or `gcc`). +## Configuring your server +This server has a few steps that need to be taken to configure the server for your use case. -In the repository root folder run the following. Ensure -DOPENSSL_ROOT_DIR=/path/to/openssl points to your openssl install location -```bash -# Create the build directory, preserving it if it already exists -mkdir -p build -cd build +### Required Configuration +Darkflame Universe can run with either a packed or an unpacked client. +Navigate to `build/sharedconfig.ini` and fill in the following fields: +* `mysql_host` (This is the IP address or hostname of your MariaDB server. This is highly likely `localhost`) + * If you setup your MariaDB instance on a port other than 3306, which can be done on a Windows install, you will need to make this value `tcp://localhost:portNum` where portNum is replaced with the port you chose to run MariaDB on. +* `mysql_database` (This is the database you created for the server) +* `mysql_username` (This is the user you created for the server) +* `mysql_password` (This is the password for the user you created for the server) +* `client_location` (This is the location of the client files. This should be the folder path of a packed or unpacked client) + * Ideally the path to the client should not contain any spaces. -# Run CMake to generate build files -cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl - -# Get cmake to build the project. If make files are being used then using make and appending `-j` and the amount of cores to utilize may be preferable, for example `make -j8` -cmake --build . --config Release -``` - -### Windows builds (native) -Ensure that you have either the [MSVC](https://visualstudio.microsoft.com/vs/) or the [Clang](https://github.com/llvm/llvm-project/releases/) (recommended) compiler installed. You will also need to install [CMake](https://cmake.org/download/). Currently on native Windows the server will only work in Release mode. - -#### Build the repository -```batch -:: Create the build directory -mkdir build -cd build - -:: Run CMake to generate make files -cmake .. - -:: Run CMake with build flag to build -cmake --build . --config Release -``` -#### Windows for ARM has not been tested but should build by doing the following -```batch -:: Create the build directory -mkdir build -cd build - -:: Run CMake to generate make files -cmake .. -DMARIADB_BUILD_SOURCE=ON - -:: Run CMake with build flag to build -cmake --build . --config Release -``` - -### Windows builds (WSL) -This section will go through how to install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and building in a Linux environment under Windows. WSL requires Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11. - -#### Open the Command Prompt application with Administrator permissions and run the following: -```bash -# Installing Windows Subsystem for Linux -wsl --install -``` - -#### Open the Ubuntu application and run the following: -```bash -# Make sure the install is up to date -apt update && apt upgrade - -# Make sure the gcc, cmake, and build-essentials are installed -sudo apt install gcc -sudo apt install cmake -sudo apt install build-essential -``` - -[**Follow the Linux instructions**](#linux-builds) - -### ARM builds -AArch64 builds should work on linux and MacOS using their respective build steps. Windows ARM should build but it has not been tested - -### Updating your build -To update your server to the latest version navigate to your cloned directory -```bash -cd /path/to/DarkflameServer -``` -run the following commands to update to the latest changes -```bash -git pull -git submodule update --init --recursive -``` -now follow the build section for your system - -## Setting up the environment - -### Resources - -#### LEGO® Universe 1.10.64 - -This repository does not distribute any LEGO® Universe files. A full install of LEGO® Universe version 1.10.64 (latest) is required to finish setting up Darkflame Universe. - -Known good SHA256 checksums of the client: -- `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed) -- `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed) -- `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed) - -Known good *SHA1* checksum of the DLU client: -- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed) - -How to generate a SHA256 checksum: -```bash -# Replace with the file path to the client - -# If on Linux or MacOS -shasum -a 256 - -# If on Windows -certutil -hashfile SHA256 -``` - -#### Unpacking the client -* Clone lcdr's utilities repository [here](https://github.com/lcdr/utils) -* Use `pkextractor.pyw` to unpack the client files if they are not already unpacked - -#### Setup resource directory -* In the `build` directory create a `res` directory if it does not already exist. -* Copy over or create symlinks from `macros`, `BrickModels`, `chatplus_en_us.txt`, `names`, and `maps` in your client `res` directory to the server `build/res` directory -* Unzip the navmeshes [here](./resources/navmeshes.zip) and place them in `build/res/maps/navmeshes` - -#### Setup locale -* In the `build` directory create a `locale` directory if it does not already exist -* Copy over or create symlinks from `locale.xml` in your client `locale` directory to the `build/locale` directory - -#### Client database -* Move the file `res/cdclient.fdb` from the unpacked client to the `build/res` folder on the server. -* The server will automatically copy and convert the file from fdb to sqlite should `CDServer.sqlite` not already exist. -* You can also convert the database manually using `fdb_to_sqlite.py` using lcdr's utilities. Just make sure to rename the file to `CDServer.sqlite` instead of `cdclient.sqlite`. -* Migrations to the database are automatically run on server start. When migrations are needed to be ran, the server may take a bit longer to start. - -### Database -Darkflame Universe utilizes a MySQL/MariaDB database for account and character information. - -Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running. - -* 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: `sharedconfig.ini`, `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. Go through them and fill in the database credentials and configure other settings if necessary. - -#### Migrations - -The database is automatically setup and migrated to what it should look like for the latest commit whenever you start the server. - -#### Verify +### Optional Configuration +* After the server has been built there should be five `ini` files in the build directory: `sharedconfig.ini`, `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. +* `authconfig.ini` contains an option to enable or disable play keys on your server. Do not change the default port for auth. +* `chatconfig.ini` contains a port option. +* `masterconfig.ini` contains options related to permissions you want to run your servers with. +* `sharedconfig.ini` contains several options that are shared across all servers +* `worldconfig.ini` contains several options to turn on QOL improvements should you want them. If you would like the most vanilla experience possible, you will need to turn some of these settings off. +## Verify your setup Your build directory should now look like this: * AuthServer * ChatServer @@ -226,42 +212,35 @@ Your build directory should now look like this: * authconfig.ini * chatconfig.ini * masterconfig.ini +* sharedconfig.ini * worldconfig.ini -* **locale/** - * locale.xml -* **res/** - * cdclient.fdb - * chatplus_en_us.txt - * **macros/** - * ... - * **BrickModels/** - * ... - * **maps/** - * **navmeshes/** - * ... - * ... * ... ## Running the server -If everything has been configured correctly you should now be able to run the `MasterServer` binary. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the binary network permissions or run it under sudo. +If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the `AuthServer` binary network permissions or run it under sudo. +To give `AuthServer` network permissions and not require sudo, run the following command +```bash +sudo setcap 'cap_net_bind_service=+ep' AuthServer +``` +and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0. ### First admin user Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users! -### Account Manager +### Account management tool (Nexus Dashboard) +**If you are just using this server for yourself, you can skip setting up Nexus Dashboard** -Follow the instructions [here](https://github.com/DarkflameUniverse/AccountManager) to setup the DLU account management Python web application. This is the intended way for users to create accounts. +Follow the instructions [here](https://github.com/DarkflameUniverse/NexusDashboard) to setup the DLU Nexus Dashboard web application. This is the intended way for users to create accounts and the intended way for moderators to approve names/pets/properties and do other moderation actions. ### Admin levels +The admin level, or Game Master level (hereafter referred to as gmlevel), is specified in the `accounts.gm_level` column in the MySQL database. Normal players should have this set to `0`, which comes with no special privileges. The system administrator will have this set to `9`, which comes will all privileges. gmlevel `8` should be used to give a player a majority of privileges without the safety critical once. -The admin level, or game master level, is specified in the `accounts.gm_level` column in the MySQL database. Normal players should have this set to `0`, which comes with no special privileges. The system administrator will have this set to `9`, which comes will all privileges. Admin level `8` should be used to give a player a majority of privileges without the safety critical once. +While a character has a gmlevel of anything but `0`, some gameplay behavior will change. When testing gameplay, you should always use a character with a gmlevel of `0`. -While a character has a gmlevel of anything but 0, some gameplay behavior will change. When testing gameplay, you should always use a character with a gmlevel of 0. +# User guide +Some changes to the client `boot.cfg` file are needed to play on your server. -## User guide -A few modifications have to be made to the client. - -### Client configuration +## Allowing a user to connect to your server To connect to a server follow these steps: * In the client directory, locate `boot.cfg` * Open it in a text editor and locate where it says `AUTHSERVERIP=0:` @@ -269,169 +248,88 @@ To connect to a server follow these steps: * Launch `legouniverse.exe`, through `wine` if on a Unix-like operating system * Note that if you are on WSL2, you will need to configure the public IP in the server and client to be the IP of the WSL2 instance and not localhost, which can be found by running `ifconfig` in the terminal. Windows defaults to WSL1, so this will not apply to most users. -### Survival +## Brick-By-Brick building +Should you choose to do any brick building, you will want to have some form of a http server that returns a 404 error since we are unable to emulate live User Generated Content at the moment. If you attempt to do any brick building without a 404 server running properly, you will be unable to load into your game. Python is the easiest way to do this, but any thing that returns a 404 should work fine. +* Note: the client hard codes this request on port 80. -The client script for the survival minigame has a bug in it which can cause the minigame to not load. To fix this, follow these instructions: -* Open `res/scripts/ai/minigame/survival/l_zone_survival_client.lua` -* Navigate to line `617` -* Change `PlayerReady(self)` to `onPlayerReady(self)` -* Save the file, overriding readonly mode if required +**If you do not plan on doing any Brick Building, then you can skip this step.** -If you still experience the bug, try deleting/renaming `res/pack/scripts.pk`. +The easiest way to do this is to install [python](https://www.python.org/downloads/). -### Brick-By-Brick building +### Allowing a user to build in Brick-by-Brick mode +Brick-By-Brick building requires `PATCHSERVERIP=0:` and `UGCSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be most easily achieved by pointing both of those variables to `localhost` while having running in the background. +Each client must have their own 404 server running if they are using a locally hosted 404 server. +```bash +# If on linux run this command. Because this is run on a port below 1024, binary network permissions are needed. +sudo python3 -m http.server 80 -Brick-By-Brick building requires `PATCHSERVERIP=0:` in the `boot.cfg` to point to a HTTP server which always returns `HTTP 404 - Not Found` for all requests. This can be achieved by pointing it to `localhost` while having `sudo python -m http.server 80` running in the background. +# If on windows one of the following will work when run through Powershell or Command Prompt assuming python is installed +python3 -m http.server 80 +python http.server 80 +py -m http.server 80 +``` -### In-game commands -Here is a summary of the commands available in-game. All commands are prefixed by `/` and typed in the in-game chat window. Some commands requires admin privileges. Operands within `<>` are required, operands within `()` are not. For the full list of in-game commands, please checkout [the source file](./dGame/dUtilities/SlashCommandHandler.cpp). +## Updating your server +To update your server to the latest version navigate to your cloned directory +```bash +cd path/to/DarkflameServer +``` +Run the following commands to update to the latest changes +```bash +git pull +git submodule update --init --recursive +``` +Now follow the [build](#build-the-server) section for your system and your server is up to date. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Command - - Usage - - Description - - Admin Level Requirement -
- info - - /info - - Displays server info to the user, including where to find the server's source code. - -
- credits - - /credits - - Displays the names of the people behind Darkflame Universe. - -
- instanceinfo - - /instanceinfo - - Displays in the chat the current zone, clone, and instance id. - -
- gmlevel - - /gmlevel <level> - - Within the authorized range of levels for the current account, changes the character's game master level to the specified value. This is required to use certain commands. - -
- testmap - - /testmap <zone> (clone-id) - - Transfers you to the given zone by id and clone id. - - 1 -
- ban - - /ban <username> - - Bans a user from the server. - - 4 -
- gmadditem - - /gmadditem <id> (count) - - Adds the given item to your inventory by id. - - 8 -
- spawn - - /spawn <id> - - Spawns an object at your location by id. - - 8 -
- metrics - - /metrics - - Prints some information about the server's performance. - - 8 -
+## In-game commands +* A list of all in-game commands can be found [here](./docs/Commands.md). + +## Verifying your client files + +### LEGO® Universe 1.10.64 +To verify that you are indeed using a LEGO® Universe 1.10.64 client, make sure you have the full client compressed **in a rar file** and run the following command. +```bash +# Replace with the file path to the zipped client + +# If on Linux or MacOS +shasum -a 256 + +# If on Windows using the Command Prompt +certutil -hashfile SHA256 +``` + +Below are known good SHA256 checksums of the client: +* `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed) +* `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed) +* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed) + +If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64. + +### Darkflame Universe Client +Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there. +This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client. + +To verify that you are indeed using a Darkflame Universe client, make sure you have the full client compressed **in a zip file** and run the following command. + +```bash +# Replace with the file path to the zipped client + +# If on Linux or MacOS +shasum -a 1 + +# If on Windows using the Command Prompt +certutil -hashfile SHA1 +``` + +Known good *SHA1* checksum of the Darkflame Universe client: +- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed) + +# Development Documentation +This is a Work in Progress, but below are some quick links to documentaion for systems and structs in the server +[Networked message structs](https://lcdruniverse.org/lu_packets/lu_packets/index.html) +[General system documentation](https://docs.lu-dev.net/en/latest/index.html) # Credits -## Active Contributors -* [EmosewaMC](https://github.com/EmosewaMC) -* [Jettford](https://github.com/Jettford) -* [Aaron K.](https://github.com/aronwk-aaron) ## DLU Team * [DarwinAnim8or](https://github.com/DarwinAnim8or) @@ -440,25 +338,30 @@ Here is a summary of the commands available in-game. All commands are prefixed b * [averysumner](https://github.com/codeshaunted) * [Jon002](https://github.com/jaller200) * [Jonny](https://github.com/cuzitsjonny) +* [Aaron K.](https://github.com/aronwk-aaron) -### Research and tools +### Research and Tools * [lcdr](https://github.com/lcdr) * [Xiphoseer](https://github.com/Xiphoseer) -### Community management +### Community Management * [Neal](https://github.com/NealSpellman) -### Former contributors +### Logo +* Cole Peterson (BlasterBuilder) + +## Active Contributors +* [EmosewaMC](https://github.com/EmosewaMC) +* [Jettford](https://github.com/Jettford) + +## Former Contributors * TheMachine * Matthew * [Raine](https://github.com/Rainebannister) * Bricknave -### Logo -* Cole Peterson (BlasterBuilder) - -## Special thanks +## Special Thanks * humanoid24 * pwjones1969 * [Simon](https://github.com/SimonNitzsche) -* ALL OF THE NETDEVIL AND LEGO TEAMS! +* [ALL OF THE NETDEVIL AND LEGO TEAMS!](https://www.mobygames.com/game/macintosh/lego-universe/credits) diff --git a/build.sh b/build.sh index 4a476cc1..b8d33492 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,6 @@ +# Error if any command fails +set -e + # Create the build directory, preserving it if it already exists mkdir -p build cd build @@ -6,5 +9,5 @@ cd build cmake .. # To build utilizing multiple cores, append `-j` and the amount of cores to utilize, for example `cmake --build . --config Release -j8' -cmake --build . --config Release +cmake --build . --config Release $1 diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 73cb4212..f5090495 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -11,6 +11,7 @@ #include "Database.h" #include "dConfig.h" #include "Diagnostics.h" +#include "BinaryPathFinder.h" //RakNet includes: #include "RakNetDefines.h" @@ -21,37 +22,40 @@ #include "Game.h" namespace Game { - dLogger* logger; - dServer* server; - dConfig* config; + dLogger* logger = nullptr; + dServer* server = nullptr; + dConfig* config = nullptr; + bool shouldShutdown = false; } dLogger* SetupLogger(); void HandlePacket(Packet* packet); int main(int argc, char** argv) { + constexpr uint32_t authFramerate = mediumFramerate; + constexpr uint32_t authFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Auth"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("AuthServer", "Starting Auth server..."); Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__); - //Read our config: - dConfig config("authconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -60,12 +64,12 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; - return 0; + return EXIT_FAILURE; } //Find out the master's IP: std::string masterIP; - int masterPort = 1500; + uint32_t masterPort = 1500; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -77,26 +81,28 @@ int main(int argc, char** argv) { delete stmt; //It's safe to pass 'localhost' here, as the IP is only used as the external IP. - int maxClients = 50; - int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); + uint32_t maxClients = 50; + uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceLastSQLPing = 0; + constexpr uint32_t logFlushTime = 30 * authFramerate; // 30 seconds in frames + constexpr uint32_t sqlPingTime = 10 * 60 * authFramerate; // 10 minutes in frames + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceLastSQLPing = 0; - while (true) { + while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - if (framesSinceMasterDisconnect >= 30) + if (framesSinceMasterDisconnect >= authFramerate) break; //Exit our loop, shut down. } else framesSinceMasterDisconnect = 0; @@ -112,16 +118,16 @@ int main(int argc, char** argv) { } //Push our log every 30s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -136,7 +142,7 @@ int main(int argc, char** argv) { } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFramerate); //Auth can run at a lower "fps" + t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps" std::this_thread::sleep_until(t); } @@ -144,13 +150,13 @@ int main(int argc, char** argv) { Database::Destroy("AuthServer"); delete Game::server; delete Game::logger; + delete Game::config; - exit(EXIT_SUCCESS); return EXIT_SUCCESS; } dLogger* SetupLogger() { - std::string logPath = "./logs/AuthServer_" + std::to_string(time(nullptr)) + ".log"; + std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/AuthServer_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; #ifdef _DEBUG diff --git a/dAuthServer/CMakeLists.txt b/dAuthServer/CMakeLists.txt index 353f2a54..00fa6e7a 100644 --- a/dAuthServer/CMakeLists.txt +++ b/dAuthServer/CMakeLists.txt @@ -1,4 +1,2 @@ -set(DAUTHSERVER_SOURCES "AuthServer.cpp") - -add_executable(AuthServer ${DAUTHSERVER_SOURCES}) +add_executable(AuthServer "AuthServer.cpp") target_link_libraries(AuthServer ${COMMON_LIBRARIES}) diff --git a/dChatFilter/dChatFilter.cpp b/dChatFilter/dChatFilter.cpp index ea38f8cd..92da9556 100644 --- a/dChatFilter/dChatFilter.cpp +++ b/dChatFilter/dChatFilter.cpp @@ -12,6 +12,7 @@ #include "dConfig.h" #include "Database.h" #include "Game.h" +#include "eGameMasterLevel.h" using namespace dChatFilterDCF; @@ -108,8 +109,8 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis } } -std::vector> dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList) { - if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. +std::vector> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) { + if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. if (message.empty()) return { }; if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } }; diff --git a/dChatFilter/dChatFilter.h b/dChatFilter/dChatFilter.h index 7e7dd859..d00525ce 100644 --- a/dChatFilter/dChatFilter.h +++ b/dChatFilter/dChatFilter.h @@ -4,6 +4,7 @@ #include "dCommonVars.h" +enum class eGameMasterLevel : uint8_t; namespace dChatFilterDCF { static const uint32_t header = ('D' + ('C' << 8) + ('F' << 16) + ('B' << 24)); static const uint32_t formatVersion = 2; @@ -23,7 +24,7 @@ public: void ReadWordlistPlaintext(const std::string& filepath, bool whiteList); bool ReadWordlistDCF(const std::string& filepath, bool whiteList); void ExportWordlistToDCF(const std::string& filepath, bool whiteList); - std::vector> IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList = true); + std::vector> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true); private: bool m_DontGenerateDCF; diff --git a/dChatServer/CMakeLists.txt b/dChatServer/CMakeLists.txt index 948593fb..9a47803d 100644 --- a/dChatServer/CMakeLists.txt +++ b/dChatServer/CMakeLists.txt @@ -1,6 +1,10 @@ -set(DCHATSERVER_SOURCES "ChatPacketHandler.cpp" - "ChatServer.cpp" - "PlayerContainer.cpp") - -add_executable(ChatServer ${DCHATSERVER_SOURCES}) -target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter) +set(DCHATSERVER_SOURCES + "ChatPacketHandler.cpp" + "PlayerContainer.cpp" +) + +add_executable(ChatServer "ChatServer.cpp") +add_library(dChatServer ${DCHATSERVER_SOURCES}) + +target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter) +target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer) diff --git a/dChatServer/ChatPacketHandler.cpp b/dChatServer/ChatPacketHandler.cpp index 119083ee..592c3870 100644 --- a/dChatServer/ChatPacketHandler.cpp +++ b/dChatServer/ChatPacketHandler.cpp @@ -8,8 +8,8 @@ #include "dServer.h" #include "GeneralUtils.h" #include "dLogger.h" -#include "AddFriendResponseCode.h" -#include "AddFriendResponseType.h" +#include "eAddFriendResponseCode.h" +#include "eAddFriendResponseType.h" #include "RakString.h" #include "dConfig.h" @@ -115,7 +115,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) { auto requestor = playerContainer.GetPlayerData(requestorPlayerID); if (requestor->playerName == playerName) { - SendFriendResponse(requestor, requestor, AddFriendResponseType::MYTHRAN); + SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN); return; }; std::unique_ptr requestee(playerContainer.GetPlayerData(playerName)); @@ -153,7 +153,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) { requestee.reset(new PlayerData()); requestee->playerName = playerName; - SendFriendResponse(requestor, requestee.get(), result->next() ? AddFriendResponseType::NOTONLINE : AddFriendResponseType::INVALIDCHARACTER); + SendFriendResponse(requestor, requestee.get(), result->next() ? eAddFriendResponseType::NOTONLINE : eAddFriendResponseType::INVALIDCHARACTER); return; } @@ -197,10 +197,10 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) { if (oldBestFriendStatus != bestFriendStatus) { if (requestee->countOfBestFriends >= maxNumberOfBestFriends || requestor->countOfBestFriends >= maxNumberOfBestFriends) { if (requestee->countOfBestFriends >= maxNumberOfBestFriends) { - SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::THEIRFRIENDLISTFULL, false); + SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false); } if (requestor->countOfBestFriends >= maxNumberOfBestFriends) { - SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::YOURFRIENDSLISTFULL, false); + SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::YOURFRIENDSLISTFULL, false); } } else { // Then update the database with this new info. @@ -215,8 +215,8 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) { if (bestFriendStatus == 3U) { requestee->countOfBestFriends += 1; requestor->countOfBestFriends += 1; - if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, AddFriendResponseType::ACCEPTED, false, true); - if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::ACCEPTED, false, true); + if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, eAddFriendResponseType::ACCEPTED, false, true); + if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::ACCEPTED, false, true); for (auto& friendData : requestor->friends) { if (friendData.friendID == requestee->playerID) { friendData.isBestFriend = true; @@ -230,7 +230,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) { } } } else { - if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::WAITINGAPPROVAL, true, true); + if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::WAITINGAPPROVAL, true, true); } } else { // Do not send this if we are requesting to be a best friend. @@ -247,7 +247,7 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) { inStream.Read(playerID); inStream.Read(playerID); - AddFriendResponseCode clientResponseCode = static_cast(packet->data[0x14]); + eAddFriendResponseCode clientResponseCode = static_cast(packet->data[0x14]); std::string friendName = PacketUtils::ReadString(0x15, packet, true); //Now to try and find both of these: @@ -255,29 +255,29 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) { auto requestee = playerContainer.GetPlayerData(friendName); if (!requestor || !requestee) return; - AddFriendResponseType serverResponseCode{}; + eAddFriendResponseType serverResponseCode{}; uint8_t isAlreadyBestFriends = 0U; // We need to convert this response code to one we can actually send back to the client. switch (clientResponseCode) { - case AddFriendResponseCode::ACCEPTED: - serverResponseCode = AddFriendResponseType::ACCEPTED; + case eAddFriendResponseCode::ACCEPTED: + serverResponseCode = eAddFriendResponseType::ACCEPTED; break; - case AddFriendResponseCode::BUSY: - serverResponseCode = AddFriendResponseType::BUSY; + case eAddFriendResponseCode::BUSY: + serverResponseCode = eAddFriendResponseType::BUSY; break; - case AddFriendResponseCode::CANCELLED: - serverResponseCode = AddFriendResponseType::CANCELLED; + case eAddFriendResponseCode::CANCELLED: + serverResponseCode = eAddFriendResponseType::CANCELLED; break; - case AddFriendResponseCode::REJECTED: - serverResponseCode = AddFriendResponseType::DECLINED; + case eAddFriendResponseCode::REJECTED: + serverResponseCode = eAddFriendResponseType::DECLINED; break; } // Now that we have handled the base cases, we need to check the other cases. - if (serverResponseCode == AddFriendResponseType::ACCEPTED) { + if (serverResponseCode == eAddFriendResponseType::ACCEPTED) { for (auto friendData : requestor->friends) { if (friendData.friendID == requestee->playerID) { - serverResponseCode = AddFriendResponseType::ALREADYFRIEND; + serverResponseCode = eAddFriendResponseType::ALREADYFRIEND; if (friendData.isBestFriend) { isAlreadyBestFriends = 1U; } @@ -286,7 +286,7 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) { } // This message is NOT sent for best friends and is handled differently for those requests. - if (serverResponseCode == AddFriendResponseType::ACCEPTED) { + if (serverResponseCode == eAddFriendResponseType::ACCEPTED) { // Add the each player to the others friend list. FriendData requestorData; requestorData.zoneID = requestor->zoneID; @@ -313,8 +313,8 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) { statement->execute(); } - if (serverResponseCode != AddFriendResponseType::DECLINED) SendFriendResponse(requestor, requestee, serverResponseCode, isAlreadyBestFriends); - if (serverResponseCode != AddFriendResponseType::ALREADYFRIEND) SendFriendResponse(requestee, requestor, serverResponseCode, isAlreadyBestFriends); + if (serverResponseCode != eAddFriendResponseType::DECLINED) SendFriendResponse(requestor, requestee, serverResponseCode, isAlreadyBestFriends); + if (serverResponseCode != eAddFriendResponseType::ALREADYFRIEND) SendFriendResponse(requestee, requestor, serverResponseCode, isAlreadyBestFriends); } void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { @@ -922,7 +922,7 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send //Make sure people aren't requesting people that they're already friends with: for (auto fr : receiver->friends) { if (fr.friendID == sender->playerID) { - SendFriendResponse(sender, receiver, AddFriendResponseType::ALREADYFRIEND, fr.isBestFriend); + SendFriendResponse(sender, receiver, eAddFriendResponseType::ALREADYFRIEND, fr.isBestFriend); return; //we have this player as a friend, yeet this function so it doesn't send another request. } } @@ -940,7 +940,7 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send SEND_PACKET; } -void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) { +void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) { if (!receiver || !sender) return; CBITSTREAM; @@ -951,11 +951,11 @@ void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sen PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_RESPONSE); bitStream.Write(responseCode); // For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver. - bitStream.Write(responseCode != AddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS); + bitStream.Write(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS); // Then write the player name PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream); // Then if this is an acceptance code, write the following extra info. - if (responseCode == AddFriendResponseType::ACCEPTED) { + if (responseCode == eAddFriendResponseType::ACCEPTED) { bitStream.Write(sender->playerID); bitStream.Write(sender->zoneID); bitStream.Write(isBestFriendRequest); //isBFF diff --git a/dChatServer/ChatPacketHandler.h b/dChatServer/ChatPacketHandler.h index fffd1ca4..f2d83502 100644 --- a/dChatServer/ChatPacketHandler.h +++ b/dChatServer/ChatPacketHandler.h @@ -4,7 +4,7 @@ #include "BitStream.h" struct PlayerData; -enum class AddFriendResponseType : uint8_t; +enum class eAddFriendResponseType : uint8_t; namespace ChatPacketHandler { void HandleFriendlistRequest(Packet* packet); @@ -35,6 +35,6 @@ namespace ChatPacketHandler { void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend); void SendFriendRequest(PlayerData* receiver, PlayerData* sender); - void SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U); + void SendFriendResponse(PlayerData* receiver, PlayerData* sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U); void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful); }; diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index fc8bdd5b..a75c4d51 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -13,21 +13,24 @@ #include "dChatFilter.h" #include "Diagnostics.h" #include "AssetManager.h" +#include "BinaryPathFinder.h" #include "PlayerContainer.h" #include "ChatPacketHandler.h" #include "Game.h" -namespace Game { - dLogger* logger; - dServer* server; - dConfig* config; - dChatFilter* chatFilter; - AssetManager* assetManager; -} //RakNet includes: #include "RakNetDefines.h" +namespace Game { + dLogger* logger = nullptr; + dServer* server = nullptr; + dConfig* config = nullptr; + dChatFilter* chatFilter = nullptr; + AssetManager* assetManager = nullptr; + bool shouldShutdown = false; +} + dLogger* SetupLogger(); void HandlePacket(Packet* packet); @@ -35,38 +38,45 @@ void HandlePacket(Packet* packet); PlayerContainer playerContainer; int main(int argc, char** argv) { + constexpr uint32_t chatFramerate = mediumFramerate; + constexpr uint32_t chatFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Chat"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); //Create all the objects we need to run our service: Game::logger = SetupLogger(); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("ChatServer", "Starting Chat server..."); Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__); - //Read our config: - dConfig config("chatconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - try { - std::string client_path = config.GetValue("client_location"); - if (client_path.empty()) client_path = "./res"; - Game::assetManager = new AssetManager(client_path); + std::string clientPathStr = Game::config->GetValue("client_location"); + if (clientPathStr.empty()) clientPathStr = "./res"; + std::filesystem::path clientPath = std::filesystem::path(clientPathStr); + if (clientPath.is_relative()) { + clientPath = BinaryPathFinder::GetBinaryDir() / clientPath; + } + + Game::assetManager = new AssetManager(clientPath); } catch (std::runtime_error& ex) { Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what()); - + return EXIT_FAILURE; } //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -75,12 +85,12 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; - return 0; + return EXIT_FAILURE; } //Find out the master's IP: std::string masterIP; - int masterPort = 1000; + uint32_t masterPort = 1000; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -92,28 +102,30 @@ int main(int argc, char** argv) { delete stmt; //It's safe to pass 'localhost' here, as the IP is only used as the external IP. - int maxClients = 50; - int ourPort = 1501; - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str()); + uint32_t maxClients = 50; + uint32_t ourPort = 1501; + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown); - Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceLastSQLPing = 0; + constexpr uint32_t logFlushTime = 30 * chatFramerate; // 30 seconds in frames + constexpr uint32_t sqlPingTime = 10 * 60 * chatFramerate; // 10 minutes in frames + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceLastSQLPing = 0; - while (true) { + while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - if (framesSinceMasterDisconnect >= 30) + if (framesSinceMasterDisconnect >= chatFramerate) break; //Exit our loop, shut down. } else framesSinceMasterDisconnect = 0; @@ -129,16 +141,16 @@ int main(int argc, char** argv) { } //Push our log every 30s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -153,7 +165,7 @@ int main(int argc, char** argv) { } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFramerate); //Chat can run at a lower "fps" + t += std::chrono::milliseconds(chatFrameDelta); //Chat can run at a lower "fps" std::this_thread::sleep_until(t); } @@ -161,13 +173,13 @@ int main(int argc, char** argv) { Database::Destroy("ChatServer"); delete Game::server; delete Game::logger; + delete Game::config; - exit(EXIT_SUCCESS); return EXIT_SUCCESS; } dLogger* SetupLogger() { - std::string logPath = "./logs/ChatServer_" + std::to_string(time(nullptr)) + ".log"; + std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/ChatServer_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; #ifdef _DEBUG diff --git a/dCommon/AMFFormat.h b/dCommon/AMFFormat.h index 2b423abd..6e479ef6 100644 --- a/dCommon/AMFFormat.h +++ b/dCommon/AMFFormat.h @@ -257,7 +257,7 @@ private: /*! \return The AMF value type */ - AMFValueType GetValueType() { return ValueType; } + AMFValueType GetValueType() override { return ValueType; } public: static const AMFValueType ValueType = AMFArray; @@ -362,7 +362,7 @@ private: /*! \return The AMF value type */ - AMFValueType GetValueType() { return ValueType; } + AMFValueType GetValueType() override { return ValueType; } ~AMFObjectValue() override; public: diff --git a/dCommon/BinaryPathFinder.cpp b/dCommon/BinaryPathFinder.cpp new file mode 100644 index 00000000..b1c2afef --- /dev/null +++ b/dCommon/BinaryPathFinder.cpp @@ -0,0 +1,71 @@ +#include +#include +#include "BinaryPathFinder.h" +#include "dPlatforms.h" + +#if defined(DARKFLAME_PLATFORM_WIN32) +#include +#elif defined(DARKFLAME_PLATFORM_MACOS) || defined(DARKFLAME_PLATFORM_IOS) +#include +#elif defined(DARKFLAME_PLATFORM_FREEBSD) +#include +#include +#include +#endif + +std::filesystem::path BinaryPathFinder::binaryDir; + +std::filesystem::path BinaryPathFinder::GetBinaryDir() { + if (!binaryDir.empty()) { + return binaryDir; + } + + std::string pathStr; + + // Derived from boost::dll::program_location, licensed under the Boost Software License: http://www.boost.org/LICENSE_1_0.txt +#if defined(DARKFLAME_PLATFORM_WIN32) + char path[MAX_PATH]; + GetModuleFileName(NULL, path, MAX_PATH); + pathStr = std::string(path); +#elif defined(DARKFLAME_PLATFORM_MACOS) || defined(DARKFLAME_PLATFORM_IOS) + char path[1024]; + uint32_t size = sizeof(path); + if (_NSGetExecutablePath(path, &size) == 0) { + pathStr = std::string(path); + } else { + // The filepath size is greater than our initial buffer size, so try again with the size + // that _NSGetExecutablePath told us it actually is + char *p = new char[size]; + if (_NSGetExecutablePath(p, &size) != 0) { + throw std::runtime_error("Failed to get binary path from _NSGetExecutablePath"); + } + + pathStr = std::string(p); + delete[] p; + } +#elif defined(DARKFLAME_PLATFORM_FREEBSD) + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + char buf[10240]; + size_t cb = sizeof(buf); + sysctl(mib, 4, buf, &cb, NULL, 0); + pathStr = std::string(buf); +#else // DARKFLAME_PLATFORM_LINUX || DARKFLAME_PLATFORM_UNIX || DARKFLAME_PLATFORM_ANDROID + pathStr = std::filesystem::read_symlink("/proc/self/exe"); +#endif + + // Some methods like _NSGetExecutablePath could return a symlink + // Either way, we need to get the parent path because we want the directory, not the binary itself + // We also ensure that it is an absolute path so that it is valid if we need to construct a path + // to exucute on unix systems (eg sudo BinaryPathFinder::GetBinaryDir() / WorldServer) + if (std::filesystem::is_symlink(pathStr)) { + binaryDir = std::filesystem::absolute(std::filesystem::read_symlink(pathStr).parent_path()); + } else { + binaryDir = std::filesystem::absolute(std::filesystem::path(pathStr).parent_path()); + } + + return binaryDir; +} diff --git a/dCommon/BinaryPathFinder.h b/dCommon/BinaryPathFinder.h new file mode 100644 index 00000000..c4ca6da2 --- /dev/null +++ b/dCommon/BinaryPathFinder.h @@ -0,0 +1,15 @@ +#pragma once + +#ifndef __BINARYPATHFINDER__H__ +#define __BINARYPATHFINDER__H__ + +#include + +class BinaryPathFinder { +private: + static std::filesystem::path binaryDir; +public: + static std::filesystem::path GetBinaryDir(); +}; + +#endif //!__BINARYPATHFINDER__H__ diff --git a/dCommon/CMakeLists.txt b/dCommon/CMakeLists.txt index 46102b74..549acfb2 100644 --- a/dCommon/CMakeLists.txt +++ b/dCommon/CMakeLists.txt @@ -15,6 +15,8 @@ set(DCOMMON_SOURCES "AMFFormat.cpp" "Type.cpp" "ZCompression.cpp" "BrickByBrickFix.cpp" + "BinaryPathFinder.cpp" + "FdbToSqlite.cpp" ) add_subdirectory(dClient) diff --git a/dCommon/Diagnostics.cpp b/dCommon/Diagnostics.cpp index 4c2c8beb..3025f083 100644 --- a/dCommon/Diagnostics.cpp +++ b/dCommon/Diagnostics.cpp @@ -1,4 +1,6 @@ #include "Diagnostics.h" +#include "Game.h" +#include "dLogger.h" // If we're on Win32, we'll include our minidump writer #ifdef _WIN32 @@ -26,7 +28,7 @@ void make_minidump(EXCEPTION_POINTERS* e) { "_%4d%02d%02d_%02d%02d%02d.dmp", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); } - + Game::logger->Log("Diagnostics", "Creating crash dump %s", name); auto hFile = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (hFile == INVALID_HANDLE_VALUE) return; @@ -81,6 +83,7 @@ struct bt_ctx { static inline void Bt(struct backtrace_state* state) { std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; + Game::logger->Log("Diagnostics", "backtrace is enabled, crash dump located at %s", fileName.c_str()); FILE* file = fopen(fileName.c_str(), "w+"); if (file != nullptr) { backtrace_print(state, 2, file); @@ -114,6 +117,8 @@ void GenerateDump() { void CatchUnhandled(int sig) { #ifndef __include_backtrace__ + std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; + Game::logger->Log("Diagnostics", "Encountered signal %i, creating crash dump %s", sig, fileName.c_str()); if (Diagnostics::GetProduceMemoryDump()) { GenerateDump(); } @@ -124,7 +129,6 @@ void CatchUnhandled(int sig) { // get void*'s for all entries on the stack size = backtrace(array, 10); - printf("Fatal error %i\nStacktrace:\n", sig); #if defined(__GNUG__) and defined(__dynamic) // Loop through the returned addresses, and get the symbols to be demangled @@ -142,19 +146,18 @@ void CatchUnhandled(int sig) { demangled = demangle(functionName.c_str()); if (demangled.empty()) { - printf("[%02zu] %s\n", i, demangled.c_str()); + Game::logger->Log("Diagnostics", "[%02zu] %s", i, demangled.c_str()); } else { - printf("[%02zu] %s\n", i, functionName.c_str()); + Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str()); } } else { - printf("[%02zu] %s\n", i, functionName.c_str()); + Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str()); } } #else backtrace_symbols_fd(array, size, STDOUT_FILENO); #endif - std::string fileName = Diagnostics::GetOutDirectory() + "crash_" + Diagnostics::GetProcessName() + "_" + std::to_string(getpid()) + ".log"; FILE* file = fopen(fileName.c_str(), "w+"); if (file != NULL) { // print out all the frames to stderr diff --git a/dCommon/FdbToSqlite.cpp b/dCommon/FdbToSqlite.cpp new file mode 100644 index 00000000..e05286a9 --- /dev/null +++ b/dCommon/FdbToSqlite.cpp @@ -0,0 +1,247 @@ +#include "FdbToSqlite.h" + +#include +#include +#include +#include + +#include "BinaryIO.h" +#include "CDClientDatabase.h" +#include "GeneralUtils.h" +#include "Game.h" +#include "dLogger.h" +#include "AssetManager.h" + +#include "eSqliteDataType.h" + +std::map FdbToSqlite::Convert::m_SqliteType = { + { eSqliteDataType::NONE, "none"}, + { eSqliteDataType::INT32, "int32"}, + { eSqliteDataType::REAL, "real"}, + { eSqliteDataType::TEXT_4, "text_4"}, + { eSqliteDataType::INT_BOOL, "int_bool"}, + { eSqliteDataType::INT64, "int64"}, + { eSqliteDataType::TEXT_8, "text_8"} +}; + +FdbToSqlite::Convert::Convert(std::string binaryOutPath) { + this->m_BinaryOutPath = binaryOutPath; +} + +bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) { + if (m_ConversionStarted) return false; + + std::istream cdClientBuffer(&buffer); + + this->m_ConversionStarted = true; + try { + CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite"); + + CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); + + int32_t numberOfTables = ReadInt32(cdClientBuffer); + ReadTables(numberOfTables, cdClientBuffer); + + CDClientDatabase::ExecuteQuery("COMMIT;"); + } catch (CppSQLite3Exception& e) { + Game::logger->Log("FdbToSqlite", "Encountered error %s converting FDB to SQLite", e.errorMessage()); + return false; + } + + return true; +} + +int32_t FdbToSqlite::Convert::ReadInt32(std::istream& cdClientBuffer) { + int32_t nextInt{}; + BinaryIO::BinaryRead(cdClientBuffer, nextInt); + return nextInt; +} + +int64_t FdbToSqlite::Convert::ReadInt64(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int64_t value{}; + BinaryIO::BinaryRead(cdClientBuffer, value); + + cdClientBuffer.seekg(prevPosition); + return value; +} + +std::string FdbToSqlite::Convert::ReadString(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + auto readString = BinaryIO::ReadString(cdClientBuffer); + + cdClientBuffer.seekg(prevPosition); + return readString; +} + +int32_t FdbToSqlite::Convert::SeekPointer(std::istream& cdClientBuffer) { + int32_t position{}; + BinaryIO::BinaryRead(cdClientBuffer, position); + int32_t prevPosition = cdClientBuffer.tellg(); + cdClientBuffer.seekg(position); + return prevPosition; +} + +std::string FdbToSqlite::Convert::ReadColumnHeader(std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t numberOfColumns = ReadInt32(cdClientBuffer); + std::string tableName = ReadString(cdClientBuffer); + + auto columns = ReadColumns(numberOfColumns, cdClientBuffer); + std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");"; + CDClientDatabase::ExecuteDML(newTable); + + cdClientBuffer.seekg(prevPosition); + + return tableName; +} + +void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + for (int32_t i = 0; i < numberOfTables; i++) { + auto columnHeader = ReadColumnHeader(cdClientBuffer); + ReadRowHeader(columnHeader, cdClientBuffer); + } + + cdClientBuffer.seekg(prevPosition); +} + +std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer) { + std::stringstream columnsToCreate; + int32_t prevPosition = SeekPointer(cdClientBuffer); + + std::string name{}; + eSqliteDataType dataType{}; + for (int32_t i = 0; i < numberOfColumns; i++) { + if (i != 0) columnsToCreate << ", "; + dataType = static_cast(ReadInt32(cdClientBuffer)); + name = ReadString(cdClientBuffer); + columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType]; + } + + cdClientBuffer.seekg(prevPosition); + return columnsToCreate.str(); +} + +void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t numberOfAllocatedRows = ReadInt32(cdClientBuffer); + if (numberOfAllocatedRows != 0) assert((numberOfAllocatedRows & (numberOfAllocatedRows - 1)) == 0); // assert power of 2 allocation size + ReadRows(numberOfAllocatedRows, tableName, cdClientBuffer); + + cdClientBuffer.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t rowid = 0; + for (int32_t row = 0; row < numberOfAllocatedRows; row++) { + int32_t rowPointer = ReadInt32(cdClientBuffer); + if (rowPointer == -1) rowid++; + else ReadRow(rowPointer, tableName, cdClientBuffer); + } + + cdClientBuffer.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = cdClientBuffer.tellg(); + cdClientBuffer.seekg(position); + + while (true) { + ReadRowInfo(tableName, cdClientBuffer); + int32_t linked = ReadInt32(cdClientBuffer); + if (linked == -1) break; + cdClientBuffer.seekg(linked); + } + + cdClientBuffer.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t numberOfColumns = ReadInt32(cdClientBuffer); + ReadRowValues(numberOfColumns, tableName, cdClientBuffer); + + cdClientBuffer.seekg(prevPosition); +} + +void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer) { + int32_t prevPosition = SeekPointer(cdClientBuffer); + + int32_t emptyValue{}; + int32_t intValue{}; + float_t floatValue{}; + std::string stringValue{}; + int32_t boolValue{}; + int64_t int64Value{}; + bool insertedFirstEntry = false; + std::stringstream insertedRow; + insertedRow << "INSERT INTO " << tableName << " values ("; + + for (int32_t i = 0; i < numberOfColumns; i++) { + if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row. + switch (static_cast(ReadInt32(cdClientBuffer))) { + case eSqliteDataType::NONE: + BinaryIO::BinaryRead(cdClientBuffer, emptyValue); + assert(emptyValue == 0); + insertedRow << "NULL"; + break; + + case eSqliteDataType::INT32: + intValue = ReadInt32(cdClientBuffer); + insertedRow << intValue; + break; + + case eSqliteDataType::REAL: + BinaryIO::BinaryRead(cdClientBuffer, floatValue); + insertedRow << std::fixed << std::setprecision(34) << floatValue; // maximum precision of floating point number + break; + + case eSqliteDataType::TEXT_4: + case eSqliteDataType::TEXT_8: { + stringValue = ReadString(cdClientBuffer); + size_t position = 0; + + // Need to escape quote with a double of ". + while (position < stringValue.size()) { + if (stringValue.at(position) == '\"') { + stringValue.insert(position, "\""); + position++; + } + position++; + } + insertedRow << "\"" << stringValue << "\""; + break; + } + + case eSqliteDataType::INT_BOOL: + BinaryIO::BinaryRead(cdClientBuffer, boolValue); + insertedRow << static_cast(boolValue); + break; + + case eSqliteDataType::INT64: + int64Value = ReadInt64(cdClientBuffer); + insertedRow << std::to_string(int64Value); + break; + + default: + throw std::invalid_argument("Unsupported SQLite type encountered."); + break; + + } + } + + insertedRow << ");"; + + auto copiedString = insertedRow.str(); + CDClientDatabase::ExecuteDML(copiedString); + cdClientBuffer.seekg(prevPosition); +} diff --git a/dCommon/FdbToSqlite.h b/dCommon/FdbToSqlite.h new file mode 100644 index 00000000..7aad2703 --- /dev/null +++ b/dCommon/FdbToSqlite.h @@ -0,0 +1,145 @@ +#ifndef __FDBTOSQLITE__H__ +#define __FDBTOSQLITE__H__ + +#pragma once + +#include +#include +#include + +class AssetMemoryBuffer; + +enum class eSqliteDataType : int32_t; + +namespace FdbToSqlite { + class Convert { + public: + /** + * Create a new convert object with an input .fdb file and an output binary path. + * + * @param inputFile The file which ends in .fdb to be converted + * @param binaryPath The base path where the file will be saved + */ + Convert(std::string binaryOutPath); + + /** + * Converts the input file to sqlite. Calling multiple times is safe. + * + * @return true if the database was converted properly, false otherwise. + */ + bool ConvertDatabase(AssetMemoryBuffer& buffer); + + /** + * @brief Reads a 32 bit int from the fdb file. + * + * @return The read value + */ + int32_t ReadInt32(std::istream& cdClientBuffer); + + /** + * @brief Reads a 64 bit integer from the fdb file. + * + * @return The read value + */ + int64_t ReadInt64(std::istream& cdClientBuffer); + + /** + * @brief Reads a string from the fdb file. + * + * @return The read string + * + * TODO This needs to be translated to latin-1! + */ + std::string ReadString(std::istream& cdClientBuffer); + + /** + * @brief Seeks to a pointer position. + * + * @return The previous position before the seek + */ + int32_t SeekPointer(std::istream& cdClientBuffer); + + /** + * @brief Reads a column header from the fdb file and creates the table in the database + * + * @return The table name + */ + std::string ReadColumnHeader(std::istream& cdClientBuffer); + + /** + * @brief Read the tables from the fdb file. + * + * @param numberOfTables The number of tables to read + */ + void ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer); + + /** + * @brief Reads the columns from the fdb file. + * + * @param numberOfColumns The number of columns to read + * @return All columns of the table formatted for a sql query + */ + std::string ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer); + + /** + * @brief Reads the row header from the fdb file. + * + * @param tableName The tables name + */ + void ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer); + + /** + * @brief Read the rows from the fdb file., + * + * @param numberOfAllocatedRows The number of rows that were allocated. Always a power of 2! + * @param tableName The tables name. + */ + void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName, std::istream& cdClientBuffer); + + /** + * @brief Reads a row from the fdb file. + * + * @param position The position to seek in the fdb to + * @param tableName The tables name + */ + void ReadRow(int32_t& position, std::string& tableName, std::istream& cdClientBuffer); + + /** + * @brief Reads the row info from the fdb file. + * + * @param tableName The tables name + */ + void ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer); + + /** + * @brief Reads each row and its values from the fdb file and inserts them into the database + * + * @param numberOfColumns The number of columns to read in + * @param tableName The tables name + */ + void ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer); + private: + + /** + * Maps each sqlite data type to its string equivalent. + */ + static std::map m_SqliteType; + + /** + * Base path of the folder containing the fdb file + */ + std::string m_BasePath{}; + + /** + * Whether or not a conversion was started. If one was started, do not attempt to convert the file again. + */ + bool m_ConversionStarted{}; + + /** + * The path where the CDServer will be stored + */ + std::string m_BinaryOutPath{}; + }; //! class FdbToSqlite +}; //! namespace FdbToSqlite + +#endif //!__FDBTOSQLITE__H__ diff --git a/dCommon/Game.h b/dCommon/Game.h index 616c7fbf..66f3f6b7 100644 --- a/dCommon/Game.h +++ b/dCommon/Game.h @@ -5,10 +5,8 @@ class dServer; class dLogger; class InstanceManager; -class dpWorld; class dChatFilter; class dConfig; -class dLocale; class RakPeerInterface; class AssetManager; struct SystemAddress; @@ -17,12 +15,11 @@ namespace Game { extern dLogger* logger; extern dServer* server; extern InstanceManager* im; - extern dpWorld* physicsWorld; extern dChatFilter* chatFilter; extern dConfig* config; - extern dLocale* locale; extern std::mt19937 randomEngine; extern RakPeerInterface* chatServer; extern AssetManager* assetManager; extern SystemAddress chatSysAddr; + extern bool shouldShutdown; } diff --git a/dCommon/GeneralUtils.cpp b/dCommon/GeneralUtils.cpp index 24ea72a0..99ca687a 100644 --- a/dCommon/GeneralUtils.cpp +++ b/dCommon/GeneralUtils.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include template inline size_t MinSize(size_t size, const std::basic_string_view& string) { @@ -239,7 +241,7 @@ std::vector GeneralUtils::SplitString(std::wstring& str, wchar_t d return vector; } -std::vector GeneralUtils::SplitString(std::u16string& str, char16_t delimiter) { +std::vector GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) { std::vector vector = std::vector(); std::u16string current; @@ -290,51 +292,34 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) { return string; } -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include - -std::vector GeneralUtils::GetFileNamesFromFolder(const std::string& folder) { - std::vector names; - std::string search_path = folder + "/*.*"; - WIN32_FIND_DATA fd; - HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - names.push_back(fd.cFileName); - } - } while (::FindNextFile(hFind, &fd)); - ::FindClose(hFind); - } - return names; -} -#else -#include -#include -#include -#include -#include -#include - -std::vector GeneralUtils::GetFileNamesFromFolder(const std::string& folder) { - std::vector names; - struct dirent* entry; - DIR* dir = opendir(folder.c_str()); - if (dir == NULL) { - return names; +std::vector GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) { + // Because we dont know how large the initial number before the first _ is we need to make it a map like so. + std::map filenames{}; + for (auto& t : std::filesystem::directory_iterator(folder)) { + auto filename = t.path().filename().string(); + auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0)); + filenames.insert(std::make_pair(index, filename)); } - while ((entry = readdir(dir)) != NULL) { - std::string value(entry->d_name, strlen(entry->d_name)); - if (value == "." || value == "..") { - continue; + // Now sort the map by the oldest migration. + std::vector sortedFiles{}; + auto fileIterator = filenames.begin(); + std::map::iterator oldest = filenames.begin(); + while (!filenames.empty()) { + if (fileIterator == filenames.end()) { + sortedFiles.push_back(oldest->second); + filenames.erase(oldest); + fileIterator = filenames.begin(); + oldest = filenames.begin(); + continue; } - names.push_back(value); + if (oldest->first > fileIterator->first) oldest = fileIterator; + fileIterator++; } - closedir(dir); - - return names; + return sortedFiles; +} + +bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) { + return TryParse(x.c_str(), dst.x) && TryParse(y.c_str(), dst.y) && TryParse(z.c_str(), dst.z); } -#endif diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index 898616d2..0555a45e 100644 --- a/dCommon/GeneralUtils.h +++ b/dCommon/GeneralUtils.h @@ -10,8 +10,13 @@ #include #include #include +#include "NiPoint3.h" #include "Game.h" +#include "dLogger.h" + +enum eInventoryType : uint32_t; +enum class eReplicaComponentType : uint32_t; /*! \file GeneralUtils.hpp @@ -134,11 +139,11 @@ namespace GeneralUtils { std::vector SplitString(std::wstring& str, wchar_t delimiter); - std::vector SplitString(std::u16string& str, char16_t delimiter); + std::vector SplitString(const std::u16string& str, char16_t delimiter); std::vector SplitString(const std::string& str, char delimiter); - std::vector GetFileNamesFromFolder(const std::string& folder); + std::vector GetSqlFileNamesFromFolder(const std::string& folder); template T Parse(const char* value); @@ -173,6 +178,16 @@ namespace GeneralUtils { return std::stoull(value); } + template <> + inline eInventoryType Parse(const char* value) { + return static_cast(std::stoul(value)); + } + + template <> + inline eReplicaComponentType Parse(const char* value) { + return static_cast(std::stoul(value)); + } + template bool TryParse(const char* value, T& dst) { try { @@ -194,6 +209,8 @@ namespace GeneralUtils { return TryParse(value.c_str(), dst); } + bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst); + template std::u16string to_u16string(T value) { return GeneralUtils::ASCIIToUTF16(std::to_string(value)); diff --git a/dCommon/NiPoint3.cpp b/dCommon/NiPoint3.cpp index a539c4df..b2ffa0d1 100644 --- a/dCommon/NiPoint3.cpp +++ b/dCommon/NiPoint3.cpp @@ -128,6 +128,12 @@ NiPoint3 NiPoint3::operator+(const NiPoint3& point) const { return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z); } +//! Operator for addition of vectors +NiPoint3 NiPoint3::operator+=(const NiPoint3& point) const { + return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z); +} + + //! Operator for subtraction of vectors NiPoint3 NiPoint3::operator-(const NiPoint3& point) const { return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z); diff --git a/dCommon/NiPoint3.h b/dCommon/NiPoint3.h index 6c0b9d3d..f76b9269 100644 --- a/dCommon/NiPoint3.h +++ b/dCommon/NiPoint3.h @@ -135,6 +135,9 @@ public: //! Operator for addition of vectors NiPoint3 operator+(const NiPoint3& point) const; + //! Operator for addition of vectors + NiPoint3 operator+=(const NiPoint3& point) const; + //! Operator for subtraction of vectors NiPoint3 operator-(const NiPoint3& point) const; diff --git a/dCommon/PermissionMap.h b/dCommon/PermissionMap.h deleted file mode 100644 index 8c271f17..00000000 --- a/dCommon/PermissionMap.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include - -/** - * Bitmap of permissions and restrictions for characters. - */ -enum class PermissionMap : uint64_t -{ - /** - * Reserved for future use, bit 0-3. - */ - - /** - * The character has restricted trade acccess, bit 4. - */ - RestrictedTradeAccess = 0x1 << 4, - - /** - * The character has restricted mail access, bit 5. - */ - RestrictedMailAccess = 0x1 << 5, - - /** - * The character has restricted chat access, bit 6. - */ - RestrictedChatAccess = 0x1 << 6, - - // - // Combined permissions - // - - /** - * The character is marked as 'old', restricted from trade and mail. - */ - Old = RestrictedTradeAccess | RestrictedMailAccess, - - /** - * The character is soft banned, restricted from trade, mail, and chat. - */ - SoftBanned = RestrictedTradeAccess | RestrictedMailAccess | RestrictedChatAccess, -}; diff --git a/dPhysics/Singleton.h b/dCommon/Singleton.h similarity index 100% rename from dPhysics/Singleton.h rename to dCommon/Singleton.h diff --git a/dCommon/dClient/AssetManager.cpp b/dCommon/dClient/AssetManager.cpp index 0cb2db31..ed86d719 100644 --- a/dCommon/dClient/AssetManager.cpp +++ b/dCommon/dClient/AssetManager.cpp @@ -1,15 +1,17 @@ +#include + #include "AssetManager.h" #include "Game.h" #include "dLogger.h" #include -AssetManager::AssetManager(const std::string& path) { +AssetManager::AssetManager(const std::filesystem::path& path) { if (!std::filesystem::is_directory(path)) { - throw std::runtime_error("Attempted to load asset bundle (" + path + ") however it is not a valid directory."); + throw std::runtime_error("Attempted to load asset bundle (" + path.string() + ") however it is not a valid directory."); } - m_Path = std::filesystem::path(path); + m_Path = path; if (std::filesystem::exists(m_Path / "client") && std::filesystem::exists(m_Path / "versions")) { m_AssetBundleType = eAssetBundleType::Packed; @@ -26,11 +28,11 @@ AssetManager::AssetManager(const std::string& path) { m_RootPath = (m_Path / ".." / ".."); m_ResPath = m_Path; - } else if (std::filesystem::exists(m_Path / "res" / "cdclient.fdb") && !std::filesystem::exists(m_Path / "res" / "pack")) { + } else if ((std::filesystem::exists(m_Path / "res" / "cdclient.fdb") || std::filesystem::exists(m_Path / "res" / "CDServer.sqlite")) && !std::filesystem::exists(m_Path / "res" / "pack")) { m_AssetBundleType = eAssetBundleType::Unpacked; m_ResPath = (m_Path / "res"); - } else if (std::filesystem::exists(m_Path / "cdclient.fdb") && !std::filesystem::exists(m_Path / "pack")) { + } else if ((std::filesystem::exists(m_Path / "cdclient.fdb") || std::filesystem::exists(m_Path / "CDServer.sqlite")) && !std::filesystem::exists(m_Path / "pack")) { m_AssetBundleType = eAssetBundleType::Unpacked; m_ResPath = m_Path; @@ -43,9 +45,6 @@ AssetManager::AssetManager(const std::string& path) { switch (m_AssetBundleType) { case eAssetBundleType::Packed: { this->LoadPackIndex(); - - this->UnpackRequiredAssets(); - break; } } @@ -158,31 +157,6 @@ AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) { return AssetMemoryBuffer(buf, len, success); } -void AssetManager::UnpackRequiredAssets() { - if (std::filesystem::exists(m_ResPath / "cdclient.fdb")) return; - - char* data; - uint32_t size; - - bool success = this->GetFile("cdclient.fdb", &data, &size); - - if (!success) { - Game::logger->Log("AssetManager", "Failed to extract required files from the packs."); - - delete data; - - return; - } - - std::ofstream cdclientOutput(m_ResPath / "cdclient.fdb", std::ios::out | std::ios::binary); - cdclientOutput.write(data, size); - cdclientOutput.close(); - - delete data; - - return; -} - uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) { size_t i, j; uint32_t crc, msb; diff --git a/dCommon/dClient/AssetManager.h b/dCommon/dClient/AssetManager.h index 87653845..bc7e5ff7 100644 --- a/dCommon/dClient/AssetManager.h +++ b/dCommon/dClient/AssetManager.h @@ -48,7 +48,7 @@ struct AssetMemoryBuffer : std::streambuf { class AssetManager { public: - AssetManager(const std::string& path); + AssetManager(const std::filesystem::path& path); ~AssetManager(); std::filesystem::path GetResPath(); @@ -60,7 +60,6 @@ public: private: void LoadPackIndex(); - void UnpackRequiredAssets(); // Modified crc algorithm (mpeg2) // Reference: https://stackoverflow.com/questions/54339800/how-to-modify-crc-32-to-crc-32-mpeg-2 diff --git a/dCommon/dConfig.cpp b/dCommon/dConfig.cpp index c22c91cc..f09a44c1 100644 --- a/dCommon/dConfig.cpp +++ b/dCommon/dConfig.cpp @@ -1,60 +1,53 @@ #include "dConfig.h" + #include +#include "BinaryPathFinder.h" +#include "GeneralUtils.h" + dConfig::dConfig(const std::string& filepath) { - m_EmptyString = ""; - std::ifstream in(filepath); + m_ConfigFilePath = filepath; + LoadConfig(); +} + +void dConfig::LoadConfig() { + std::ifstream in(BinaryPathFinder::GetBinaryDir() / m_ConfigFilePath); if (!in.good()) return; - std::string line; + std::string line{}; while (std::getline(in, line)) { - if (line.length() > 0) { - if (line[0] != '#') ProcessLine(line); - } + if (!line.empty() && line.front() != '#') ProcessLine(line); } - std::ifstream sharedConfig("sharedconfig.ini", std::ios::in); + std::ifstream sharedConfig(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini", std::ios::in); if (!sharedConfig.good()) return; + line.clear(); while (std::getline(sharedConfig, line)) { - if (line.length() > 0) { - if (line[0] != '#') ProcessLine(line); - } + if (!line.empty() && line.front() != '#') ProcessLine(line); } } -dConfig::~dConfig(void) { +void dConfig::ReloadConfig() { + this->m_ConfigValues.clear(); + LoadConfig(); } const std::string& dConfig::GetValue(std::string key) { - for (size_t i = 0; i < m_Keys.size(); ++i) { - if (m_Keys[i] == key) return m_Values[i]; - } - - return m_EmptyString; + return this->m_ConfigValues[key]; } void dConfig::ProcessLine(const std::string& line) { - std::stringstream ss(line); - std::string segment; - std::vector seglist; + auto splitLine = GeneralUtils::SplitString(line, '='); - while (std::getline(ss, segment, '=')) { - seglist.push_back(segment); - } - - if (seglist.size() != 2) return; + if (splitLine.size() != 2) return; //Make sure that on Linux, we remove special characters: - if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r') - seglist[1].erase(seglist[1].size() - 1); + auto& key = splitLine.at(0); + auto& value = splitLine.at(1); + if (!value.empty() && value.at(value.size() - 1) == '\r') value.erase(value.size() - 1); - for (const auto& key : m_Keys) { - if (seglist[0] == key) { - return; // first loaded key is preferred due to loading shared config secondarily - } - } + if (this->m_ConfigValues.find(key) != this->m_ConfigValues.end()) return; - m_Keys.push_back(seglist[0]); - m_Values.push_back(seglist[1]); + this->m_ConfigValues.insert(std::make_pair(key, value)); } diff --git a/dCommon/dConfig.h b/dCommon/dConfig.h index 7764fa54..562c1ce9 100644 --- a/dCommon/dConfig.h +++ b/dCommon/dConfig.h @@ -1,20 +1,33 @@ #pragma once #include +#include #include -#include class dConfig { public: dConfig(const std::string& filepath); - ~dConfig(void); + /** + * Gets the specified key from the config. Returns an empty string if the value is not found. + * + * @param key Key to find + * @return The keys value in the config + */ const std::string& GetValue(std::string key); + /** + * Loads the config from a file + */ + void LoadConfig(); + + /** + * Reloads the config file to reset values + */ + void ReloadConfig(); private: void ProcessLine(const std::string& line); private: - std::vector m_Keys; - std::vector m_Values; - std::string m_EmptyString; + std::map m_ConfigValues; + std::string m_ConfigFilePath; }; diff --git a/dCommon/dCommonVars.h b/dCommon/dEnums/dCommonVars.h similarity index 74% rename from dCommon/dCommonVars.h rename to dCommon/dEnums/dCommonVars.h index 4c0e15fa..16cae3c9 100644 --- a/dCommon/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -1,17 +1,30 @@ #pragma once +#ifndef __DCOMMONVARS__H__ +#define __DCOMMONVARS__H__ + #include #include #include -#include "../thirdparty/raknet/Source/BitStream.h" +#include "BitStream.h" #pragma warning (disable:4251) //Disables SQL warnings typedef int RESTICKET; -const int highFrameRate = 16; //60fps -const int mediumFramerate = 33; //30fps -const int lowFramerate = 66; //15fps +// These are the same define, but they mean two different things in different contexts +// so a different define to distinguish what calculation is happening will help clarity. +#define FRAMES_TO_MS(x) 1000 / x +#define MS_TO_FRAMES(x) 1000 / x + +//=========== FRAME TIMINGS =========== +constexpr uint32_t highFramerate = 60; +constexpr uint32_t mediumFramerate = 30; +constexpr uint32_t lowFramerate = 15; + +constexpr uint32_t highFrameDelta = FRAMES_TO_MS(highFramerate); +constexpr uint32_t mediumFrameDelta = FRAMES_TO_MS(mediumFramerate); +constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate); //========== MACROS =========== @@ -30,6 +43,7 @@ typedef uint32_t LWOCLONEID; //!< Used for Clone IDs typedef uint16_t LWOMAPID; //!< Used for Map IDs typedef uint16_t LWOINSTANCEID; //!< Used for Instance IDs typedef uint32_t PROPERTYCLONELIST; //!< Used for Property Clone IDs +typedef uint32_t StripId; typedef int32_t PetTamingPiece; //!< Pet Taming Pieces @@ -50,11 +64,6 @@ typedef std::set TSetObjID; const float PI = 3.14159f; -#if defined(__unix) || defined(__APPLE__) -//For Linux: -typedef __int64_t __int64; -#endif - //============ STRUCTS ============== struct LWOSCENEID { @@ -166,21 +175,6 @@ union suchar { char svalue; }; -//=========== DLU ENUMS ============ - -enum eGameMasterLevel : int32_t { - GAME_MASTER_LEVEL_CIVILIAN = 0, // Normal player. - GAME_MASTER_LEVEL_FORUM_MODERATOR = 1, // No permissions on live servers. - GAME_MASTER_LEVEL_JUNIOR_MODERATOR = 2, // Can kick/mute and pull chat logs. - GAME_MASTER_LEVEL_MODERATOR = 3, // Can return lost items. - GAME_MASTER_LEVEL_SENIOR_MODERATOR = 4, // Can ban. - GAME_MASTER_LEVEL_LEAD_MODERATOR = 5, // Can approve properties. - GAME_MASTER_LEVEL_JUNIOR_DEVELOPER = 6, // Junior developer & future content team. Civilan on live. - GAME_MASTER_LEVEL_INACTIVE_DEVELOPER = 7, // Inactive developer, limited permissions. - GAME_MASTER_LEVEL_DEVELOPER = 8, // Active developer, full permissions on live. - GAME_MASTER_LEVEL_OPERATOR = 9 // Can shutdown server for restarts & updates. -}; - //=========== LU ENUMS ============ //! An enum for object ID bits @@ -247,20 +241,6 @@ enum eReplicaPacketType { PACKET_TYPE_DESTRUCTION //!< A destruction packet }; -enum ServerDisconnectIdentifiers { - SERVER_DISCON_UNKNOWN_SERVER_ERROR = 0, //!< Unknown server error - SERVER_DISCON_DUPLICATE_LOGIN = 4, //!< Used when another user with the same username is logged in (duplicate login) - SERVER_DISCON_SERVER_SHUTDOWN = 5, //!< Used when the server is shutdown - SERVER_DISCON_SERVER_MAP_LOAD_FAILURE = 6, //!< Used when the server cannot load a map - SERVER_DISCON_INVALID_SESSION_KEY = 7, //!< Used if the session is invalid - SERVER_DISCON_ACCOUNT_NOT_IN_PENDING_LIST = 8, //!< ??? - SERVER_DISCON_CHARACTER_NOT_FOUND = 9, //!< Used if a character that the server has is not found (i.e, corruption with user-player data) - SERVER_DISCON_CHARACTER_CORRUPTED = 10, //!< Similar to abovce - SERVER_DISCON_KICK = 11, //!< Used if the user is kicked from the server - SERVER_DISCON_FREE_TRIAL_EXPIRED = 12, //!< Used if the user's free trial expired - SERVER_DISCON_PLAY_SCHEDULE_TIME_DONE = 13 //!< Used if the user's play time is used up -}; - //! The Behavior Types for use with the AI system enum eCombatBehaviorTypes : uint32_t { PASSIVE = 0, //!< The object is passive @@ -351,7 +331,7 @@ enum eControlSceme { SCHEME_WEAR_A_ROBOT //== freecam? }; -enum eStunState { +enum class eStateChangeType : uint32_t { PUSH, POP }; @@ -365,56 +345,6 @@ enum eNotifyType { NOTIFY_TYPE_NAMINGPET }; -enum eReplicaComponentType : int32_t { - COMPONENT_TYPE_CONTROLLABLE_PHYSICS = 1, //!< The ControllablePhysics Component - COMPONENT_TYPE_RENDER = 2, //!< The Render Component - COMPONENT_TYPE_SIMPLE_PHYSICS = 3, //!< The SimplePhysics Component - COMPONENT_TYPE_CHARACTER = 4, //!< The Character Component - COMPONENT_TYPE_SCRIPT = 5, //!< The Script Component - COMPONENT_TYPE_BOUNCER = 6, //!< The Bouncer Component - COMPONENT_TYPE_BUFF = 7, //!< The Buff Component - COMPONENT_TYPE_SKILL = 9, //!< The Skill Component - COMPONENT_TYPE_ITEM = 11, //!< The Item Component - COMPONENT_TYPE_VENDOR = 16, //!< The Vendor Component - COMPONENT_TYPE_INVENTORY = 17, //!< The Inventory Component - COMPONENT_TYPE_SHOOTING_GALLERY = 19, //!< The Shooting Gallery Component - COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS = 20, //!< The RigidBodyPhantomPhysics Component - COMPONENT_TYPE_COLLECTIBLE = 23, //!< The Collectible Component - COMPONENT_TYPE_MOVING_PLATFORM = 25, //!< The MovingPlatform Component - COMPONENT_TYPE_PET = 26, //!< The Pet Component - COMPONENT_TYPE_VEHICLE_PHYSICS = 30, //!< The VehiclePhysics Component - COMPONENT_TYPE_MOVEMENT_AI = 31, //!< The MovementAI Component - COMPONENT_TYPE_PROPERTY = 36, //!< The Property Component - COMPONENT_TYPE_SCRIPTED_ACTIVITY = 39, //!< The ScriptedActivity Component - COMPONENT_TYPE_PHANTOM_PHYSICS = 40, //!< The PhantomPhysics Component - COMPONENT_TYPE_MODEL = 42, //!< The Model Component - COMPONENT_TYPE_PROPERTY_ENTRANCE = 43, //!< The PhantomPhysics Component - COMPONENT_TYPE_PROPERTY_MANAGEMENT = 45, //!< The PropertyManagement Component - COMPONENT_TYPE_REBUILD = 48, //!< The Rebuild Component - COMPONENT_TYPE_SWITCH = 49, //!< The Switch Component - COMPONENT_TYPE_ZONE_CONTROL = 50, //!< The ZoneControl Component - COMPONENT_TYPE_PACKAGE = 53, //!< The Package Component - COMPONENT_TYPE_PLAYER_FLAG = 58, //!< The PlayerFlag Component - COMPONENT_TYPE_BASE_COMBAT_AI = 60, //!< The BaseCombatAI Component - COMPONENT_TYPE_MODULE_ASSEMBLY = 61, //!< The ModuleAssembly Component - COMPONENT_TYPE_PROPERTY_VENDOR = 65, //!< The PropertyVendor Component - COMPONENT_TYPE_ROCKET_LAUNCH = 67, //!< The RocketLaunch Component - COMPONENT_TYPE_RACING_CONTROL = 71, //!< The RacingControl Component - COMPONENT_TYPE_MISSION_OFFER = 73, //!< The MissionOffer Component - COMPONENT_TYPE_EXHIBIT = 75, //!< The Exhibit Component - COMPONENT_TYPE_RACING_STATS = 74, //!< The Racing Stats Component - COMPONENT_TYPE_SOUND_TRIGGER = 77, //!< The Sound Trigger Component - COMPONENT_TYPE_PROXIMITY_MONITOR = 78, //!< The Proximity Monitor Component - COMPONENT_TYPE_MISSION = 84, //!< The Mission Component - COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen - COMPONENT_TYPE_RAIL_ACTIVATOR = 104, //!< The Rail Activator Component - COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT = 106, //!< The Player Forced Movement Component - COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component - COMPONENT_TYPE_LEVEL_PROGRESSION = 109, //!< The Level Progression Component - COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component - COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component - COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component -}; enum class UseItemResponse : uint32_t { NoImaginationForPet = 1, @@ -422,25 +352,6 @@ enum class UseItemResponse : uint32_t { MountsNotAllowed }; -/** - * Represents the different types of inventories an entity may have - */ -enum eInventoryType : uint32_t { - ITEMS = 0, - VAULT_ITEMS, - BRICKS, - TEMP_ITEMS = 4, - MODELS, - TEMP_MODELS, - BEHAVIORS, - PROPERTY_DEEDS, - VENDOR_BUYBACK = 11, - HIDDEN = 12, //Used for missional items - VAULT_MODELS = 14, - ITEM_SETS, //internal - INVALID // made up, for internal use!!! -}; - enum eRebuildState : uint32_t { REBUILD_OPEN, REBUILD_COMPLETED = 2, @@ -554,6 +465,7 @@ enum ePlayerFlags { ENTER_BBB_FROM_PROPERTY_EDIT_CONFIRMATION_DIALOG = 64, AG_FIRST_COMBAT_COMPLETE = 65, AG_COMPLETE_BOB_MISSION = 66, + IS_NEWS_SCREEN_VISIBLE = 114, NJ_GARMADON_CINEMATIC_SEEN = 125, ELEPHANT_PET_3050 = 801, CAT_PET_3054 = 802, @@ -648,3 +560,5 @@ inline T const& clamp(const T& val, const T& low, const T& high) { return val; } + +#endif //!__DCOMMONVARS__H__ diff --git a/dNet/dMessageIdentifiers.h b/dCommon/dEnums/dMessageIdentifiers.h similarity index 97% rename from dNet/dMessageIdentifiers.h rename to dCommon/dEnums/dMessageIdentifiers.h index 7dc08711..7c810a2d 100644 --- a/dNet/dMessageIdentifiers.h +++ b/dCommon/dEnums/dMessageIdentifiers.h @@ -293,6 +293,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_POP_EQUIPPED_ITEMS_STATE = 192, GAME_MSG_SET_GM_LEVEL = 193, GAME_MSG_SET_STUNNED = 198, + GAME_MSG_SET_STUN_IMMUNITY = 200, GAME_MSG_KNOCKBACK = 202, GAME_MSG_REBUILD_CANCEL = 209, GAME_MSG_ENABLE_REBUILD = 213, @@ -373,6 +374,8 @@ enum GAME_MSG : unsigned short { GAME_MSG_PET_TAMING_TRY_BUILD_RESULT = 668, GAME_MSG_NOTIFY_TAMING_BUILD_SUCCESS = 673, GAME_MSG_NOTIFY_TAMING_MODEL_LOADED_ON_SERVER = 674, + GAME_MSG_ACTIVATE_BUBBLE_BUFF = 678, + GAME_MSG_DEACTIVATE_BUBBLE_BUFF = 679, GAME_MSG_ADD_PET_TO_PLAYER = 681, GAME_MSG_REQUEST_SET_PET_NAME = 683, GAME_MSG_SET_PET_NAME = 684, @@ -385,7 +388,10 @@ enum GAME_MSG : unsigned short { GAME_MSG_QUERY_PROPERTY_DATA = 717, GAME_MSG_PROPERTY_EDITOR_BEGIN = 724, GAME_MSG_PROPERTY_EDITOR_END = 725, - GAME_MSG_START_PATHING = 735, + GAME_MSG_IS_MINIFIG_IN_A_BUBBLE = 729, + GAME_MSG_START_PATHING = 733, + GAME_MSG_ACTIVATE_BUBBLE_BUFF_FROM_SERVER = 734, + GAME_MSG_DEACTIVATE_BUBBLE_BUFF_FROM_SERVER = 735, GAME_MSG_NOTIFY_CLIENT_ZONE_OBJECT = 737, GAME_MSG_UPDATE_REPUTATION = 746, GAME_MSG_PROPERTY_RENTAL_RESPONSE = 750, @@ -433,11 +439,13 @@ enum GAME_MSG : unsigned short { GAME_MSG_ORIENT_TO_POSITION = 906, GAME_MSG_ORIENT_TO_ANGLE = 907, GAME_MSG_BOUNCER_ACTIVE_STATUS = 942, + GAME_MSG_UN_USE_BBB_MODEL = 999, GAME_MSG_BBB_LOAD_ITEM_REQUEST = 1000, GAME_MSG_BBB_SAVE_REQUEST = 1001, GAME_MSG_BBB_SAVE_RESPONSE = 1006, GAME_MSG_NOTIFY_CLIENT_OBJECT = 1042, GAME_MSG_DISPLAY_ZONE_SUMMARY = 1043, + GAME_MSG_ZONE_SUMMARY_DISMISSED = 1044, GAME_MSG_ACTIVITY_STATE_CHANGE_REQUEST = 1053, GAME_MSG_MODIFY_PLAYER_ZONE_STATISTIC = 1046, GAME_MSG_START_BUILDING_WITH_ITEM = 1057, @@ -477,6 +485,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_LOCK_NODE_ROTATION = 1260, GAME_MSG_VEHICLE_SET_WHEEL_LOCK_STATE = 1273, GAME_MSG_NOTIFY_VEHICLE_OF_RACING_OBJECT = 1276, + GAME_MSG_SET_NAME_BILLBOARD_STATE = 1284, GAME_MSG_PLAYER_REACHED_RESPAWN_CHECKPOINT = 1296, GAME_MSG_HANDLE_UGC_EQUIP_POST_DELETE_BASED_ON_EDIT_MODE = 1300, GAME_MSG_HANDLE_UGC_EQUIP_PRE_CREATE_BASED_ON_EDIT_MODE = 1301, @@ -487,6 +496,8 @@ enum GAME_MSG : unsigned short { GAME_MSG_MATCH_UPDATE = 1310, GAME_MSG_MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131, GAME_MSG_MODULE_ASSEMBLY_QUERY_DATA = 1132, + GAME_MSG_SHOW_BILLBOARD_INTERACT_ICON = 1337, + GAME_MSG_CHANGE_IDLE_FLAGS = 1338, GAME_MSG_VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340, GAME_MSG_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341, GAME_MSG_VEHICLE_NOTIFY_SERVER_ADD_PASSIVE_BOOST_ACTION = 1342, @@ -510,6 +521,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_UPDATE_CHAT_MODE = 1395, GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE = 1396, GAME_MSG_SET_CONSUMABLE_ITEM = 1409, + GAME_MSG_SET_STATUS_IMMUNITY = 1435, GAME_MSG_SET_PET_NAME_MODERATED = 1448, GAME_MSG_MODIFY_LEGO_SCORE = 1459, GAME_MSG_RESTORE_TO_POST_LOAD_STATS = 1468, @@ -537,6 +549,9 @@ enum GAME_MSG : unsigned short { GAME_MSG_REMOVE_RUN_SPEED_MODIFIER = 1506, GAME_MSG_UPDATE_PROPERTY_PERFORMANCE_COST = 1547, GAME_MSG_PROPERTY_ENTRANCE_BEGIN = 1553, + GAME_MSG_SET_RESURRECT_RESTORE_VALUES = 1591, + GAME_MSG_VEHICLE_STOP_BOOST = 1617, + GAME_MSG_REMOVE_BUFF = 1648, GAME_MSG_REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666, GAME_MSG_RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667, GAME_MSG_PLAYER_SET_CAMERA_CYCLING_MODE = 1676, diff --git a/dCommon/dPlatforms.h b/dCommon/dEnums/dPlatforms.h similarity index 100% rename from dCommon/dPlatforms.h rename to dCommon/dEnums/dPlatforms.h diff --git a/dPhysics/dpCollisionGroups.h b/dCommon/dEnums/dpCollisionGroups.h similarity index 100% rename from dPhysics/dpCollisionGroups.h rename to dCommon/dEnums/dpCollisionGroups.h diff --git a/dPhysics/dpCommon.h b/dCommon/dEnums/dpCommon.h similarity index 100% rename from dPhysics/dpCommon.h rename to dCommon/dEnums/dpCommon.h diff --git a/dCommon/AddFriendResponseCode.h b/dCommon/dEnums/eAddFriendResponseCode.h similarity index 50% rename from dCommon/AddFriendResponseCode.h rename to dCommon/dEnums/eAddFriendResponseCode.h index bb2faff7..56304c82 100644 --- a/dCommon/AddFriendResponseCode.h +++ b/dCommon/dEnums/eAddFriendResponseCode.h @@ -1,11 +1,11 @@ #pragma once -#ifndef __ADDFRIENDRESPONSECODE__H__ -#define __ADDFRIENDRESPONSECODE__H__ +#ifndef __EADDFRIENDRESPONSECODE__H__ +#define __EADDFRIENDRESPONSECODE__H__ #include -enum class AddFriendResponseCode : uint8_t { +enum class eAddFriendResponseCode : uint8_t { ACCEPTED = 0, REJECTED, BUSY, diff --git a/dCommon/AddFriendResponseType.h b/dCommon/dEnums/eAddFriendResponseType.h similarity index 59% rename from dCommon/AddFriendResponseType.h rename to dCommon/dEnums/eAddFriendResponseType.h index 305796e8..5568aafb 100644 --- a/dCommon/AddFriendResponseType.h +++ b/dCommon/dEnums/eAddFriendResponseType.h @@ -1,11 +1,11 @@ #pragma once -#ifndef __ADDFRIENDRESPONSETYPE__H__ -#define __ADDFRIENDRESPONSETYPE__H__ +#ifndef __EADDFRIENDRESPONSETYPE__H__ +#define __EADDFRIENDRESPONSETYPE__H__ #include -enum class AddFriendResponseType : uint8_t { +enum class eAddFriendResponseType : uint8_t { ACCEPTED = 0, ALREADYFRIEND, INVALIDCHARACTER, @@ -21,4 +21,4 @@ enum class AddFriendResponseType : uint8_t { FRIENDISFREETRIAL }; -#endif //!__ADDFRIENDRESPONSETYPE__H__ +#endif //!__EADDFRIENDRESPONSETYPE__H__ diff --git a/dCommon/eAninmationFlags.h b/dCommon/dEnums/eAninmationFlags.h similarity index 92% rename from dCommon/eAninmationFlags.h rename to dCommon/dEnums/eAninmationFlags.h index 9b2ea3fb..ce235ae9 100644 --- a/dCommon/eAninmationFlags.h +++ b/dCommon/dEnums/eAninmationFlags.h @@ -6,7 +6,7 @@ #include enum class eAnimationFlags : uint32_t { - IDLE_INVALID = 0, // made up, for internal use!!! + IDLE_NONE = 0, IDLE_BASIC, IDLE_SWIM, IDLE_CARRY, diff --git a/dCommon/dEnums/eBasicAttackSuccessTypes.h b/dCommon/dEnums/eBasicAttackSuccessTypes.h new file mode 100644 index 00000000..8c06da8a --- /dev/null +++ b/dCommon/dEnums/eBasicAttackSuccessTypes.h @@ -0,0 +1,12 @@ +#ifndef __EBASICATTACKSUCCESSTYPES__H__ +#define __EBASICATTACKSUCCESSTYPES__H__ + +#include + +enum class eBasicAttackSuccessTypes : uint8_t { + SUCCESS = 1, + FAILARMOR, + FAILIMMUNE +}; + +#endif //!__EBASICATTACKSUCCESSTYPES__H__ diff --git a/dCommon/dEnums/eBlueprintSaveResponseType.h b/dCommon/dEnums/eBlueprintSaveResponseType.h new file mode 100644 index 00000000..29d15695 --- /dev/null +++ b/dCommon/dEnums/eBlueprintSaveResponseType.h @@ -0,0 +1,26 @@ +#pragma once + +#ifndef __EBLUEPRINTSAVERESPONSETYPE__H__ +#define __EBLUEPRINTSAVERESPONSETYPE__H__ + +#include + +enum class eBlueprintSaveResponseType : uint32_t { + EverythingWorked = 0, + SaveCancelled, + CantBeginTransaction, + SaveBlueprintFailed, + SaveUgobjectFailed, + CantEndTransaction, + SaveFilesFailed, + BadInput, + NotEnoughBricks, + InventoryFull, + ModelGenerationFailed, + PlacementFailed, + GmLevelInsufficient, + WaitForPreviousSave, + FindMatchesFailed +}; + +#endif //!__EBLUEPRINTSAVERESPONSETYPE__H__ diff --git a/dCommon/dEnums/eBubbleType.h b/dCommon/dEnums/eBubbleType.h new file mode 100644 index 00000000..9ceef4b5 --- /dev/null +++ b/dCommon/dEnums/eBubbleType.h @@ -0,0 +1,14 @@ +#pragma once + +#ifndef __EBUBBLETYPE__H__ +#define __EBUBBLETYPE__H__ + +#include + +enum class eBubbleType : uint32_t { + DEFAULT = 0, + ENERGY, + SKUNK +}; + +#endif //!__EBUBBLETYPE__H__ diff --git a/dCommon/dEnums/eCharacterVersion.h b/dCommon/dEnums/eCharacterVersion.h new file mode 100644 index 00000000..0fab4498 --- /dev/null +++ b/dCommon/dEnums/eCharacterVersion.h @@ -0,0 +1,21 @@ +#pragma once + +#ifndef __ECHARACTERVERSION__H__ +#define __ECHARACTERVERSION__H__ + +#include + +enum class eCharacterVersion : uint32_t { +// Versions from the live game + RELEASE = 0, // Initial release of the game + LIVE, // Fixes for the 1.9 release bug fixes for missions leading up to joining a faction +// New versions for DLU fixes + // Fixes the "Joined a faction" player flag not being set properly + PLAYER_FACTION_FLAGS, + // Fixes vault size value + VAULT_SIZE, + // Fixes speed base value in level component + UP_TO_DATE, // will become SPEED_BASE +}; + +#endif //!__ECHARACTERVERSION__H__ diff --git a/dCommon/dEnums/eEndBehavior.h b/dCommon/dEnums/eEndBehavior.h new file mode 100644 index 00000000..77afaab4 --- /dev/null +++ b/dCommon/dEnums/eEndBehavior.h @@ -0,0 +1,11 @@ +#ifndef __EENDBEHAVIOR__H__ +#define __EENDBEHAVIOR__H__ + +#include + +enum class eEndBehavior : uint32_t { + RETURN, + WAIT +}; + +#endif //!__EENDBEHAVIOR__H__ diff --git a/dCommon/dEnums/eGameMasterLevel.h b/dCommon/dEnums/eGameMasterLevel.h new file mode 100644 index 00000000..a63c1caf --- /dev/null +++ b/dCommon/dEnums/eGameMasterLevel.h @@ -0,0 +1,20 @@ +#ifndef __EGAMEMASTERLEVEL__H__ +#define __EGAMEMASTERLEVEL__H__ + +#include + +enum class eGameMasterLevel : uint8_t { + CIVILIAN = 0, // Normal player. + FORUM_MODERATOR = 1, // No permissions on live servers. + JUNIOR_MODERATOR = 2, // Can kick/mute and pull chat logs. + MODERATOR = 3, // Can return lost items. + SENIOR_MODERATOR = 4, // Can ban. + LEAD_MODERATOR = 5, // Can approve properties. + JUNIOR_DEVELOPER = 6, // Junior developer & future content team. Civilan on live. + INACTIVE_DEVELOPER = 7, // Inactive developer, limited permissions. + DEVELOPER = 8, // Active developer, full permissions on live. + OPERATOR = 9 // Can shutdown server for restarts & updates. +}; + + +#endif //!__EGAMEMASTERLEVEL__H__ diff --git a/dCommon/dEnums/eHelpType.h b/dCommon/dEnums/eHelpType.h new file mode 100644 index 00000000..d1838cc6 --- /dev/null +++ b/dCommon/dEnums/eHelpType.h @@ -0,0 +1,41 @@ + +#ifndef __EHELPTYPE__H__ +#define __EHELPTYPE__H__ + +#include + +enum class eHelpType : int32_t { + NONE = 0, + UNLOCK_MINIMAP = 2, + TOGGLETOOLTIP_OUTOFTIME_REBUILD = 3, + TOGGLETOOLTIP_LEAVELOSE_REBUILD = 4, + TOGGLECONTROLSTUTORIAL_WALKING = 6, + DISPLAYTUTORIAL_PASSPORT_1ST_SMASH = 7, + TOOLTIP_1ST_IMAGINATION_PICKUP = 8, + UNKNOWN9 = 9, + PETTAMINGMINIGAME_TUTORIAL_01 = 15, + PR_BOUNCER_TUTORIAL_03 = 16, + PR_TOOLTIP_1ST_PET_JUMPED_ON_SWITCH = 17, + PR_DIG_TUTORIAL_01 = 18, + PR_DIG_TUTORIAL_03 = 19, + PR_BOUNCER_TUTORIAL_01 = 20, + PR_NO_IMAGINATION_HIBERNATE = 21, + UNKNOWN22 = 22, + TOGGLECONTROLSTUTORIAL_JUMPING = 26, + TOGGLECONTROLSTUTORIAL_DOUBLEJUMPING = 27, + TOGGLECONTROLSTUTORIAL_CAMERA = 28, + TOGGLECONTROLSTUTORIAL_SMASH = 30, + UNKNOWN38 = 38, + UI_MOD_BUILD_PUT_ON_HAT = 40, + UI_MOD_BUILD_EQUIP_FIRST_MODULE = 41, + UNKNOWN42 = 42, + UNKNOWN43 = 43, + UI_MOD_BUILD_GO_LAUNCH_ROCKET = 44, + UI_MOD_BUILD_TALK_TO_SKYLANE = 45, + UNKNOWN53 = 53, + PET_DESPAWN_BY_OWNER_HIBERNATE = 69, + PET_DESPAWN_TAMING_NEW_PET = 70, + UI_INVENTORY_FULL_CANNOT_PICKUP_ITEM = 86 +}; + +#endif //!__EHELPTYPE__H__ diff --git a/dCommon/dEnums/eInventoryType.h b/dCommon/dEnums/eInventoryType.h new file mode 100644 index 00000000..12573aa4 --- /dev/null +++ b/dCommon/dEnums/eInventoryType.h @@ -0,0 +1,59 @@ +#pragma once + +#ifndef __EINVENTORYTYPE__H__ +#define __EINVENTORYTYPE__H__ + +#include +static const uint8_t NUMBER_OF_INVENTORIES = 17; +/** + * Represents the different types of inventories an entity may have + */ +enum eInventoryType : uint32_t { + ITEMS = 0, + VAULT_ITEMS, + BRICKS, + MODELS_IN_BBB, + TEMP_ITEMS, + MODELS, + TEMP_MODELS, + BEHAVIORS, + PROPERTY_DEEDS, + BRICKS_IN_BBB, + VENDOR, + VENDOR_BUYBACK, + QUEST, //Used for mission items + DONATION, + VAULT_MODELS, + ITEM_SETS, //internal, technically this is BankBehaviors. + INVALID // made up, for internal use!!!, Technically this called the ALL inventory. +}; + +class InventoryType { +public: + static const char* InventoryTypeToString(eInventoryType inventory) { + const char* eInventoryTypeTable[NUMBER_OF_INVENTORIES] = { + "ITEMS", + "VAULT_ITEMS", + "BRICKS", + "MODELS_IN_BBB", + "TEMP_ITEMS", + "MODELS", + "TEMP_MODELS", + "BEHAVIORS", + "PROPERTY_DEEDS", + "BRICKS_IN_BBB", + "VENDOR", + "VENDOR_BUYBACK", + "QUEST", //Used for mission items + "DONATION", + "VAULT_MODELS", + "ITEM_SETS", //internal, technically this is BankBehaviors. + "INVALID" // made up, for internal use!!!, Technically this called the ALL inventory. + }; + + if (inventory > NUMBER_OF_INVENTORIES - 1) return nullptr; + return eInventoryTypeTable[inventory]; + }; +}; + +#endif //!__EINVENTORYTYPE__H__ diff --git a/dCommon/dEnums/eItemSetPassiveAbilityID.h b/dCommon/dEnums/eItemSetPassiveAbilityID.h new file mode 100644 index 00000000..8641d0f2 --- /dev/null +++ b/dCommon/dEnums/eItemSetPassiveAbilityID.h @@ -0,0 +1,58 @@ +#pragma once + +#ifndef __EITEMSETPASSIVEABILITYID__H__ +#define __EITEMSETPASSIVEABILITYID__H__ + +enum class eItemSetPassiveAbilityID { + EngineerRank1 = 2, + EngineerRank2 = 3, + EngineerRank3 = 4, + KnightRank1 = 7, + KnightRank2 = 8, + KnightRank3 = 9, + SpaceRangerRank1 = 10, + SpaceRangerRank2 = 11, + SpaceRangerRank3 = 12, + SamuraiRank1 = 13, + SamuraiRank2 = 14, + SamuraiRank3 = 15, + SorcererRank1 = 16, + SorcererRank2 = 17, + SorcererRank3 = 18, + SpaceMarauderRank1 = 19, + SpaceMarauderRank2 = 20, + SpaceMarauderRank3 = 21, + ShinobiRank1 = 22, + ShinobiRank2 = 23, + ShinobiRank3 = 24, + InventorRank1 = 25, + InventorRank2 = 26, + InventorRank3 = 27, + SummonerRank1 = 28, + SummonerRank2 = 29, + SummonerRank3 = 30, + AdventurerRank1 = 31, + AdventurerRank2 = 32, + AdventurerRank3 = 33, + DaredevilRank1 = 34, + DaredevilRank2 = 35, + DaredevilRank3 = 36, + BuccaneerRank1 = 37, + BuccaneerRank2 = 38, + BuccaneerRank3 = 39, + BoneSuit = 40, + ImaginationSpinjitzu = 41, + BatLord = 42, + MosaicJester = 43, + ExplorienBot = 44, + Unnamed1 = 45, + Unnamed2 = 46, + Unnamed3 = 47, + EarthSpinjitzu = 48, + Unnamed4 = 49, + FireSpinjitzu = 50, + IceSpinjitzu = 51, + LightningSpinjitzu = 52 +}; + +#endif //!__EITEMSETPASSIVEABILITYID__H__ diff --git a/dCommon/dEnums/eItemType.h b/dCommon/dEnums/eItemType.h new file mode 100644 index 00000000..41c7765b --- /dev/null +++ b/dCommon/dEnums/eItemType.h @@ -0,0 +1,36 @@ +#pragma once + +#ifndef __EITEMTYPE__H__ +#define __EITEMTYPE__H__ + +#include + +enum class eItemType : int32_t { + UNKNOWN = -1, + BRICK = 1, + HAT, + HAIR, + NECK, + LEFT_HAND, + RIGHT_HAND, + LEGS, + LEFT_TRINKET, + RIGHT_TRINKET, + BEHAVIOR, + PROPERTY, + MODEL, + COLLECTIBLE, + CONSUMABLE, + CHEST, + EGG, + PET_FOOD, + QUEST_OBJECT, + PET_INVENTORY_ITEM, + PACKAGE, + LOOT_MODEL, + VEHICLE, + LUP_MODEL, + MOUNT +}; + +#endif //!__EITEMTYPE__H__ diff --git a/dCommon/dEnums/eMissionLockState.h b/dCommon/dEnums/eMissionLockState.h new file mode 100644 index 00000000..52752767 --- /dev/null +++ b/dCommon/dEnums/eMissionLockState.h @@ -0,0 +1,12 @@ +#pragma once + +#ifndef __EMISSIONLOCKSTATE__H__ +#define __EMISSIONLOCKSTATE__H__ + +enum class eMissionLockState : int { + LOCKED, + NEW, + UNLOCKED, +}; + +#endif //!__EMISSIONLOCKSTATE__H__ diff --git a/dCommon/dEnums/eMissionState.h b/dCommon/dEnums/eMissionState.h new file mode 100644 index 00000000..e080f455 --- /dev/null +++ b/dCommon/dEnums/eMissionState.h @@ -0,0 +1,56 @@ +#pragma once + +#ifndef __MISSIONSTATE__H__ +#define __MISSIONSTATE__H__ + +/** + * Represents the possible states a mission can be in + */ +enum class eMissionState : int { + /** + * The mission state is unknown + */ + UNKNOWN = -1, + + /** + * The mission is yielding rewards + */ + REWARDING = 0, + + /** + * The mission can be accepted + */ + AVAILABLE = 1, + + /** + * The mission has been accepted but not yet completed + */ + ACTIVE = 2, + + /** + * All the tasks for the mission have been completed and the entity can turn the mission in to complete it + */ + READY_TO_COMPLETE = 4, //!< The mission is ready to complete + + /** + * The mission has been completed + */ + COMPLETE = 8, + + /** + * The mission is available again and has been completed before. Used for daily missions. + */ + COMPLETE_AVAILABLE = 9, + + /** + * The mission is active and has been completed before. Used for daily missions. + */ + COMPLETE_ACTIVE = 10, + + /** + * The mission has been completed before and has now been completed again. Used for daily missions. + */ + COMPLETE_READY_TO_COMPLETE = 12 +}; + +#endif //!__MISSIONSTATE__H__ diff --git a/dCommon/dEnums/eMissionTaskType.h b/dCommon/dEnums/eMissionTaskType.h new file mode 100644 index 00000000..2636f88c --- /dev/null +++ b/dCommon/dEnums/eMissionTaskType.h @@ -0,0 +1,43 @@ +#pragma once + +#ifndef __EMISSIONTASKTYPE__H__ +#define __EMISSIONTASKTYPE__H__ + +enum class eMissionTaskType : int { + UNKNOWN = -1, + SMASH, + SCRIPT, + ACTIVITY, + COLLECTION, + TALK_TO_NPC, + EMOTE, + SHASH_CHAIN, + BUY, + SELL, + USE_ITEM, + USE_SKILL, + GATHER, + EXPLORE, + DELIVERY, + PERFORM_ACTIVITY, + INTERACT, + META, + EARN_REPUTATION, + VOTING, + SHOWCASE_DELIVERY, + REVIECE_CAST, + POWERUP, + PET_TAMING, + RACING, + PLAYER_FLAG, + PLACE_MODEL, + REMOVE_MODEL, + ADD_BEHAVIOR, + REMOVE_BEHAVIOR, + CLAIM_PROPERTY, + VISIT_PROPERTY, + TIME_PLAYED, + DONATION +}; + +#endif //!__EMISSIONTASKTYPE__H__ diff --git a/dCommon/dEnums/eMovementPlatformState.h b/dCommon/dEnums/eMovementPlatformState.h new file mode 100644 index 00000000..1df437d8 --- /dev/null +++ b/dCommon/dEnums/eMovementPlatformState.h @@ -0,0 +1,16 @@ +#ifndef __EMOVEMENTPLATFORMSTATE__H__ +#define __EMOVEMENTPLATFORMSTATE__H__ + +#include + +/** + * The different types of platform movement state, supposedly a bitmap + */ +enum class eMovementPlatformState : uint32_t +{ + Moving = 0b00010, + Stationary = 0b11001, + Stopped = 0b01100 +}; + +#endif //!__EMOVEMENTPLATFORMSTATE__H__ diff --git a/dCommon/dEnums/ePackageType.h b/dCommon/dEnums/ePackageType.h new file mode 100644 index 00000000..2c1c9977 --- /dev/null +++ b/dCommon/dEnums/ePackageType.h @@ -0,0 +1,13 @@ +#ifndef __EPACKAGETYPE__H__ +#define __EPACKAGETYPE__H__ + +enum class ePackageType { + INVALID = -1, + ITEM, + BRICKS, + MODELS, + CAR_MODELS +}; + + +#endif //!__EPACKAGETYPE__H__ diff --git a/dCommon/dEnums/ePermissionMap.h b/dCommon/dEnums/ePermissionMap.h new file mode 100644 index 00000000..d15c9fd3 --- /dev/null +++ b/dCommon/dEnums/ePermissionMap.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +#ifndef __EPERMISSIONMAP__H__ +#define __EPERMISSIONMAP__H__ + +/** + * Bitmap of permissions and restrictions for characters. + */ +enum class ePermissionMap : uint64_t { + /** + * Reserved for future use, bit 0-3. + */ + + /** + * The character has restricted trade acccess, bit 4. + */ + RestrictedTradeAccess = 0x1 << 4, + + /** + * The character has restricted mail access, bit 5. + */ + RestrictedMailAccess = 0x1 << 5, + + /** + * The character has restricted chat access, bit 6. + */ + RestrictedChatAccess = 0x1 << 6, + + // + // Combined permissions + // + + /** + * The character is marked as 'old', restricted from trade and mail. + */ + Old = RestrictedTradeAccess | RestrictedMailAccess, + + /** + * The character is soft banned, restricted from trade, mail, and chat. + */ + SoftBanned = RestrictedTradeAccess | RestrictedMailAccess | RestrictedChatAccess, +}; + +#endif //!__EPERMISSIONMAP__H__ diff --git a/dCommon/dEnums/ePhysicsEffectType.h b/dCommon/dEnums/ePhysicsEffectType.h new file mode 100644 index 00000000..1aa68b34 --- /dev/null +++ b/dCommon/dEnums/ePhysicsEffectType.h @@ -0,0 +1,15 @@ +#ifndef __EPHYSICSEFFECTTYPE__H__ +#define __EPHYSICSEFFECTTYPE__H__ + + +#include + +enum class ePhysicsEffectType : uint32_t { + PUSH, + ATTRACT, + REPULSE, + GRAVITY_SCALE, + FRICTION +}; + +#endif //!__EPHYSICSEFFECTTYPE__H__ diff --git a/dCommon/dEnums/eRacingTaskParam.h b/dCommon/dEnums/eRacingTaskParam.h new file mode 100644 index 00000000..df50e382 --- /dev/null +++ b/dCommon/dEnums/eRacingTaskParam.h @@ -0,0 +1,25 @@ +#pragma once + +#ifndef __ERACINGTASKPARAM__H__ +#define __ERACINGTASKPARAM__H__ + +#include + +enum class eRacingTaskParam : int32_t { + FINISH_WITH_PLACEMENT = 1, + LAP_TIME, + TOTAL_TRACK_TIME, + COMPLETE_ANY_RACING_TASK, + COMPLETE_TRACK_TASKS, + MODULAR_BUILDING, + SAFE_DRIVER = 10, + SMASHABLES, + COLLECT_IMAGINATION, + COMPETED_IN_RACE, + WIN_RACE_IN_WORLD, + FIRST_PLACE_MULTIPLE_TRACKS, + LAST_PLACE_FINISH, + SMASH_SPECIFIC_SMASHABLE +}; + +#endif //!__ERACINGTASKPARAM__H__ diff --git a/dCommon/dEnums/eReplicaComponentType.h b/dCommon/dEnums/eReplicaComponentType.h new file mode 100644 index 00000000..3eee16f3 --- /dev/null +++ b/dCommon/dEnums/eReplicaComponentType.h @@ -0,0 +1,127 @@ +#ifndef __EREPLICACOMPONENTTYPE__H__ +#define __EREPLICACOMPONENTTYPE__H__ + +#include + +enum class eReplicaComponentType : uint32_t { + INVALID = 0, + CONTROLLABLE_PHYSICS, + RENDER, + SIMPLE_PHYSICS, + CHARACTER, + SCRIPT, + BOUNCER, + BUFF, // buff is really 98, this is DESTROYABLE + GHOST, + SKILL, + SPAWNER, + ITEM, + REBUILD, + REBUILD_START, + REBUILD_ACTIVATOR, + ICON_ONLY, + VENDOR, + INVENTORY, + PROJECTILE_PHYSICS, + SHOOTING_GALLERY, + RIGID_BODY_PHANTOM_PHYSICS, + DROP_EFFECT, + CHEST, + COLLECTIBLE, + BLUEPRINT, + MOVING_PLATFORM, + PET, + PLATFORM_BOUNDARY, + MODULE, + ARCADE, + VEHICLE_PHYSICS, // Havok demo based + MOVEMENT_AI, + EXHIBIT, + OVERHEAD_ICON, + PET_CONTROL, + MINIFIG, + PROPERTY, + PET_CREATOR, + MODEL_BUILDER, + SCRIPTED_ACTIVITY, + PHANTOM_PHYSICS, + SPRINGPAD, + MODEL, + PROPERTY_ENTRANCE, + FX, + PROPERTY_MANAGEMENT, + VEHICLE_PHYSICS_NEW, // internal physics based on havok + PHYSICS_SYSTEM, + QUICK_BUILD, + SWITCH, + ZONE_CONTROL, // Minigame + CHANGLING, + CHOICE_BUILD, + PACKAGE, + SOUND_REPEATER, + SOUND_AMBIENT_2D, + SOUND_AMBIENT_3D, + PRECONDITION, + PLAYER_FLAG, + CUSTOM_BUILD_ASSEMBLY, + BASE_COMBAT_AI, + MODULE_ASSEMBLY, + SHOWCASE_MODEL_HANDLER, + RACING_MODULE, + GENERIC_ACTIVATOR, + PROPERTY_VENDOR, + HF_LIGHT_DIRECTION_GADGET, + ROCKET_LAUNCH, + ROCKET_LANDING, + TRIGGER, + DROPPED_LOOT, + RACING_CONTROL, + FACTION_TRIGGER, + MISSION_OFFER, + RACING_STATS, + LUP_EXHIBIT, + BBB, + SOUND_TRIGGER, + PROXIMITY_MONITOR, + RACING_SOUND_TRIGGER, + CHAT, + FRIENDS_LIST, + GUILD, + LOCAL_SYSTEM, + MISSION, + MUTABLE_MODEL_BEHAVIORS, + PATHFINDING, + PET_TAMING_CONTROL, + PROPERTY_EDITOR, + SKINNED_RENDER, + SLASH_COMMAND, + STATUS_EFFECT, + TEAMS, + TEXT_EFFECT, + TRADE, + USER_CONTROL, + IGNORE_LIST, + ROCKET_LAUNCH_LUP, + BUFF_REAL, // the real buff component, should just be name BUFF + INTERACTION_MANAGER, + DONATION_VENDOR, + COMBAT_MEDIATOR, + COMMENDATION_VENDOR, + UNKNOWN_103, + RAIL_ACTIVATOR, + ROLLER, + PLAYER_FORCED_MOVEMENT, + CRAFTING, + POSSESSABLE, + LEVEL_PROGRESSION, + POSSESSOR, + MOUNT_CONTROL, + UNKNOWN_112, + PROPERTY_PLAQUE, + BUILD_BORDER, + UNKOWN_115, + CULLING_PLANE, + DESTROYABLE = 1000 // Actually 7 +}; + +#endif //!__EREPLICACOMPONENTTYPE__H__ diff --git a/dCommon/dEnums/eServerDisconnectIdentifiers.h b/dCommon/dEnums/eServerDisconnectIdentifiers.h new file mode 100644 index 00000000..99d2cd44 --- /dev/null +++ b/dCommon/dEnums/eServerDisconnectIdentifiers.h @@ -0,0 +1,24 @@ +#ifndef __ESERVERDISCONNECTIDENTIFIERS__H__ +#define __ESERVERDISCONNECTIDENTIFIERS__H__ + +#include + +enum class eServerDisconnectIdentifiers : uint32_t { + UNKNOWN_SERVER_ERROR = 0, + WRONG_GAME_VERSION, + WRONG_SERVER_VERSION, + CONNECTION_ON_INVALID_PORT, + DUPLICATE_LOGIN, + SERVER_SHUTDOWN, + SERVER_MAP_LOAD_FAILURE, + INVALID_SESSION_KEY, + ACCOUNT_NOT_IN_PENDING_LIST, + CHARACTER_NOT_FOUND, + CHARACTER_CORRUPTED, + KICK, + SAVE_FAILURE, + FREE_TRIAL_EXPIRED, + PLAY_SCHEDULE_TIME_DONE +}; + +#endif //!__ESERVERDISCONNECTIDENTIFIERS__H__ diff --git a/dCommon/dEnums/eSqliteDataType.h b/dCommon/dEnums/eSqliteDataType.h new file mode 100644 index 00000000..26e1233b --- /dev/null +++ b/dCommon/dEnums/eSqliteDataType.h @@ -0,0 +1,16 @@ +#ifndef __ESQLITEDATATYPE__H__ +#define __ESQLITEDATATYPE__H__ + +#include + +enum class eSqliteDataType : int32_t { + NONE = 0, + INT32, + REAL = 3, + TEXT_4, + INT_BOOL, + INT64, + TEXT_8 = 8 +}; + +#endif //!__ESQLITEDATATYPE__H__ diff --git a/dCommon/dEnums/eTriggerCommandType.h b/dCommon/dEnums/eTriggerCommandType.h new file mode 100644 index 00000000..fadfafb8 --- /dev/null +++ b/dCommon/dEnums/eTriggerCommandType.h @@ -0,0 +1,119 @@ +#ifndef __ETRIGGERCOMMANDTYPE__H__ +#define __ETRIGGERCOMMANDTYPE__H__ + +// For info about Trigger Command see: +// https://docs.lu-dev.net/en/latest/file-structures/lutriggers.html?highlight=trigger#possible-values-commands + +enum class eTriggerCommandType { + INVALID, + ZONE_PLAYER, + FIRE_EVENT, + DESTROY_OBJ, + TOGGLE_TRIGGER, + RESET_REBUILD, + SET_PATH, + SET_PICK_TYPE, + MOVE_OBJECT, + ROTATE_OBJECT, + PUSH_OBJECT, + REPEL_OBJECT, + SET_TIMER, + CANCEL_TIMER, + PLAY_CINEMATIC, + TOGGLE_BBB, + UPDATE_MISSION, + SET_BOUNCER_STATE, + BOUNCE_ALL_ON_BOUNCER, + TURN_AROUND_ON_PATH, + GO_FORWARD_ON_PATH, + GO_BACKWARD_ON_PATH, + STOP_PATHING, + START_PATHING, + LOCK_OR_UNLOCK_CONTROLS, + PLAY_EFFECT, + STOP_EFFECT, + ACTIVATE_MUSIC_CUE, + DEACTIVATE_MUSIC_CUE, + FLASH_MUSIC_CUE, + SET_MUSIC_PARAMETER, + PLAY_2D_AMBIENT_SOUND, + STOP_2D_AMBIENT_SOUND, + PLAY_3D_AMBIENT_SOUND, + STOP_3D_AMBIENT_SOUND, + ACTIVATE_MIXER_PROGRAM, + DEACTIVATE_MIXER_PROGRAM, + CAST_SKILL, + DISPLAY_ZONE_SUMMARY, + SET_PHYSICS_VOLUME_EFFECT, + SET_PHYSICS_VOLUME_STATUS, + SET_MODEL_TO_BUILD, + SPAWN_MODEL_BRICKS, + ACTIVATE_SPAWNER_NETWORK, + DEACTIVATE_SPAWNER_NETWORK, + RESET_SPAWNER_NETWORK, + DESTROY_SPAWNER_NETWORK_OBJECTS, + GO_TO_WAYPOINT, + ACTIVATE_PHYSICS +}; + + +class TriggerCommandType { +public: + static eTriggerCommandType StringToTriggerCommandType(std::string commandString) { + const std::map TriggerCommandMap = { + { "zonePlayer", eTriggerCommandType::ZONE_PLAYER}, + { "fireEvent", eTriggerCommandType::FIRE_EVENT}, + { "destroyObj", eTriggerCommandType::DESTROY_OBJ}, + { "toggleTrigger", eTriggerCommandType::TOGGLE_TRIGGER}, + { "resetRebuild", eTriggerCommandType::RESET_REBUILD}, + { "setPath", eTriggerCommandType::SET_PATH}, + { "setPickType", eTriggerCommandType::SET_PICK_TYPE}, + { "moveObject", eTriggerCommandType::MOVE_OBJECT}, + { "rotateObject", eTriggerCommandType::ROTATE_OBJECT}, + { "pushObject", eTriggerCommandType::PUSH_OBJECT}, + { "repelObject", eTriggerCommandType::REPEL_OBJECT}, + { "setTimer", eTriggerCommandType::SET_TIMER}, + { "cancelTimer", eTriggerCommandType::CANCEL_TIMER}, + { "playCinematic", eTriggerCommandType::PLAY_CINEMATIC}, + { "toggleBBB", eTriggerCommandType::TOGGLE_BBB}, + { "updateMission", eTriggerCommandType::UPDATE_MISSION}, + { "setBouncerState", eTriggerCommandType::SET_BOUNCER_STATE}, + { "bounceAllOnBouncer", eTriggerCommandType::BOUNCE_ALL_ON_BOUNCER}, + { "turnAroundOnPath", eTriggerCommandType::TURN_AROUND_ON_PATH}, + { "goForwardOnPath", eTriggerCommandType::GO_FORWARD_ON_PATH}, + { "goBackwardOnPath", eTriggerCommandType::GO_BACKWARD_ON_PATH}, + { "stopPathing", eTriggerCommandType::STOP_PATHING}, + { "startPathing", eTriggerCommandType::START_PATHING}, + { "LockOrUnlockControls", eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS}, + { "PlayEffect", eTriggerCommandType::PLAY_EFFECT}, + { "StopEffect", eTriggerCommandType::STOP_EFFECT}, + { "activateMusicCue", eTriggerCommandType::ACTIVATE_MUSIC_CUE}, + { "deactivateMusicCue", eTriggerCommandType::DEACTIVATE_MUSIC_CUE}, + { "flashMusicCue", eTriggerCommandType::FLASH_MUSIC_CUE}, + { "setMusicParameter", eTriggerCommandType::SET_MUSIC_PARAMETER}, + { "play2DAmbientSound", eTriggerCommandType::PLAY_2D_AMBIENT_SOUND}, + { "stop2DAmbientSound", eTriggerCommandType::STOP_2D_AMBIENT_SOUND}, + { "play3DAmbientSound", eTriggerCommandType::PLAY_3D_AMBIENT_SOUND}, + { "stop3DAmbientSound", eTriggerCommandType::STOP_3D_AMBIENT_SOUND}, + { "activateMixerProgram", eTriggerCommandType::ACTIVATE_MIXER_PROGRAM}, + { "deactivateMixerProgram", eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM}, + { "CastSkill", eTriggerCommandType::CAST_SKILL}, + { "displayZoneSummary", eTriggerCommandType::DISPLAY_ZONE_SUMMARY}, + { "SetPhysicsVolumeEffect", eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT}, + { "SetPhysicsVolumeStatus", eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS}, + { "setModelToBuild", eTriggerCommandType::SET_MODEL_TO_BUILD}, + { "spawnModelBricks", eTriggerCommandType::SPAWN_MODEL_BRICKS}, + { "ActivateSpawnerNetwork", eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK}, + { "DeactivateSpawnerNetwork", eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK}, + { "ResetSpawnerNetwork", eTriggerCommandType::RESET_SPAWNER_NETWORK}, + { "DestroySpawnerNetworkObjects", eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS}, + { "Go_To_Waypoint", eTriggerCommandType::GO_TO_WAYPOINT}, + { "ActivatePhysics", eTriggerCommandType::ACTIVATE_PHYSICS} + }; + + auto intermed = TriggerCommandMap.find(commandString); + return (intermed != TriggerCommandMap.end()) ? intermed->second : eTriggerCommandType::INVALID; + }; +}; + +#endif //!__ETRIGGERCOMMANDTYPE__H__ diff --git a/dCommon/dEnums/eTriggerEventType.h b/dCommon/dEnums/eTriggerEventType.h new file mode 100644 index 00000000..a2daa256 --- /dev/null +++ b/dCommon/dEnums/eTriggerEventType.h @@ -0,0 +1,53 @@ +#ifndef __ETRIGGEREVENTTYPE__H__ +#define __ETRIGGEREVENTTYPE__H__ + +enum class eTriggerEventType { + INVALID, + DESTROY, + CUSTOM_EVENT, + ENTER, + EXIT, + CREATE, + HIT, + TIMER_DONE, + REBUILD_COMPLETE, + ACTIVATED, + DEACTIVATED, + ARRIVED, + ARRIVED_AT_END_OF_PATH, + ZONE_SUMMARY_DISMISSED, + ARRIVED_AT_DESIRED_WAYPOINT, + PET_ON_SWITCH, + PET_OFF_SWITCH, + INTERACT +}; + +class TriggerEventType { +public: + static eTriggerEventType StringToTriggerEventType(std::string commandString) { + const std::map TriggerEventMap = { + {"OnDestroy", eTriggerEventType::DESTROY}, + {"OnCustomEvent", eTriggerEventType::CUSTOM_EVENT}, + {"OnEnter", eTriggerEventType::ENTER}, + {"OnExit", eTriggerEventType::EXIT}, + {"OnCreate", eTriggerEventType::CREATE}, + {"OnHit", eTriggerEventType::HIT}, + {"OnTimerDone", eTriggerEventType::TIMER_DONE}, + {"OnRebuildComplete", eTriggerEventType::REBUILD_COMPLETE}, + {"OnActivated", eTriggerEventType::ACTIVATED}, + {"OnDectivated", eTriggerEventType::DEACTIVATED}, // Dectivated vs Deactivated + {"OnArrived", eTriggerEventType::ARRIVED}, + {"OnArrivedAtEndOfPath", eTriggerEventType::ARRIVED_AT_END_OF_PATH}, + {"OnZoneSummaryDismissed", eTriggerEventType::ZONE_SUMMARY_DISMISSED}, + {"OnArrivedAtDesiredWaypoint", eTriggerEventType::ARRIVED_AT_DESIRED_WAYPOINT}, + {"OnPetOnSwitch", eTriggerEventType::PET_ON_SWITCH}, + {"OnPetOffSwitch", eTriggerEventType::PET_OFF_SWITCH}, + {"OnInteract", eTriggerEventType::INTERACT}, + }; + + auto intermed = TriggerEventMap.find(commandString); + return (intermed != TriggerEventMap.end()) ? intermed->second : eTriggerEventType::INVALID; + }; +}; + +#endif //!__ETRIGGEREVENTTYPE__H__ diff --git a/dCommon/eUnequippableActiveType.h b/dCommon/dEnums/eUnequippableActiveType.h similarity index 100% rename from dCommon/eUnequippableActiveType.h rename to dCommon/dEnums/eUnequippableActiveType.h diff --git a/dCommon/dLogger.cpp b/dCommon/dLogger.cpp index d4e6a96e..7785a070 100644 --- a/dCommon/dLogger.cpp +++ b/dCommon/dLogger.cpp @@ -89,7 +89,7 @@ void dLogger::Log(const std::string& className, const std::string& message) { void dLogger::LogDebug(const char* className, const char* format, ...) { if (!m_logDebugStatements) return; va_list args; - std::string log = "[" + std::string(className) + "] " + std::string(format); + std::string log = "[" + std::string(className) + "] " + std::string(format) + "\n"; va_start(args, format); vLog(log.c_str(), args); va_end(args); diff --git a/dCommon/eItemType.h b/dCommon/eItemType.h deleted file mode 100644 index e68ce695..00000000 --- a/dCommon/eItemType.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#ifndef __EITEMTYPE__H__ -#define __EITEMTYPE__H__ - -#include - -enum class eItemType : int32_t { - ITEM_TYPE_UNKNOWN = -1, //!< An unknown item type - ITEM_TYPE_BRICK = 1, //!< A brick - ITEM_TYPE_HAT = 2, //!< A hat / head item - ITEM_TYPE_HAIR = 3, //!< A hair item - ITEM_TYPE_NECK = 4, //!< A neck item - ITEM_TYPE_LEFT_HAND = 5, //!< A left handed item - ITEM_TYPE_RIGHT_HAND = 6, //!< A right handed item - ITEM_TYPE_LEGS = 7, //!< A pants item - ITEM_TYPE_LEFT_TRINKET = 8, //!< A left handled trinket item - ITEM_TYPE_RIGHT_TRINKET = 9, //!< A right handed trinket item - ITEM_TYPE_BEHAVIOR = 10, //!< A behavior - ITEM_TYPE_PROPERTY = 11, //!< A property - ITEM_TYPE_MODEL = 12, //!< A model - ITEM_TYPE_COLLECTIBLE = 13, //!< A collectible item - ITEM_TYPE_CONSUMABLE = 14, //!< A consumable item - ITEM_TYPE_CHEST = 15, //!< A chest item - ITEM_TYPE_EGG = 16, //!< An egg - ITEM_TYPE_PET_FOOD = 17, //!< A pet food item - ITEM_TYPE_QUEST_OBJECT = 18, //!< A quest item - ITEM_TYPE_PET_INVENTORY_ITEM = 19, //!< A pet inventory item - ITEM_TYPE_PACKAGE = 20, //!< A package - ITEM_TYPE_LOOT_MODEL = 21, //!< A loot model - ITEM_TYPE_VEHICLE = 22, //!< A vehicle - ITEM_TYPE_CURRENCY = 23, //!< Currency - ITEM_TYPE_MOUNT = 24 //!< A Mount -}; - -#endif //!__EITEMTYPE__H__ diff --git a/dDatabase/CDClientManager.cpp b/dDatabase/CDClientManager.cpp index 4b32e749..eeea686f 100644 --- a/dDatabase/CDClientManager.cpp +++ b/dDatabase/CDClientManager.cpp @@ -1,46 +1,80 @@ #include "CDClientManager.h" +#include "CDActivityRewardsTable.h" +#include "CDAnimationsTable.h" +#include "CDBehaviorParameterTable.h" +#include "CDBehaviorTemplateTable.h" +#include "CDComponentsRegistryTable.h" +#include "CDCurrencyTableTable.h" +#include "CDDestructibleComponentTable.h" +#include "CDEmoteTable.h" +#include "CDInventoryComponentTable.h" +#include "CDItemComponentTable.h" +#include "CDItemSetsTable.h" +#include "CDItemSetSkillsTable.h" +#include "CDLevelProgressionLookupTable.h" +#include "CDLootMatrixTable.h" +#include "CDLootTableTable.h" +#include "CDMissionNPCComponentTable.h" +#include "CDMissionTasksTable.h" +#include "CDMissionsTable.h" +#include "CDObjectSkillsTable.h" +#include "CDObjectsTable.h" +#include "CDPhysicsComponentTable.h" +#include "CDRebuildComponentTable.h" +#include "CDScriptComponentTable.h" +#include "CDSkillBehaviorTable.h" +#include "CDZoneTableTable.h" +#include "CDVendorComponentTable.h" +#include "CDActivitiesTable.h" +#include "CDPackageComponentTable.h" +#include "CDProximityMonitorComponentTable.h" +#include "CDMovementAIComponentTable.h" +#include "CDBrickIDTableTable.h" +#include "CDRarityTableTable.h" +#include "CDMissionEmailTable.h" +#include "CDRewardsTable.h" +#include "CDPropertyEntranceComponentTable.h" +#include "CDPropertyTemplateTable.h" +#include "CDFeatureGatingTable.h" +#include "CDRailActivatorComponent.h" -// Static Variables -CDClientManager* CDClientManager::m_Address = nullptr; - -//! Initializes the manager -void CDClientManager::Initialize(void) { - tables.insert(std::make_pair("ActivityRewards", new CDActivityRewardsTable())); - UNUSED(tables.insert(std::make_pair("Animations", new CDAnimationsTable()))); - tables.insert(std::make_pair("BehaviorParameter", new CDBehaviorParameterTable())); - tables.insert(std::make_pair("BehaviorTemplate", new CDBehaviorTemplateTable())); - tables.insert(std::make_pair("ComponentsRegistry", new CDComponentsRegistryTable())); - tables.insert(std::make_pair("CurrencyTable", new CDCurrencyTableTable())); - tables.insert(std::make_pair("DestructibleComponent", new CDDestructibleComponentTable())); - tables.insert(std::make_pair("EmoteTable", new CDEmoteTableTable())); - tables.insert(std::make_pair("InventoryComponent", new CDInventoryComponentTable())); - tables.insert(std::make_pair("ItemComponent", new CDItemComponentTable())); - tables.insert(std::make_pair("ItemSets", new CDItemSetsTable())); - tables.insert(std::make_pair("ItemSetSkills", new CDItemSetSkillsTable())); - tables.insert(std::make_pair("LevelProgressionLookup", new CDLevelProgressionLookupTable())); - tables.insert(std::make_pair("LootMatrix", new CDLootMatrixTable())); - tables.insert(std::make_pair("LootTable", new CDLootTableTable())); - tables.insert(std::make_pair("MissionNPCComponent", new CDMissionNPCComponentTable())); - tables.insert(std::make_pair("MissionTasks", new CDMissionTasksTable())); - tables.insert(std::make_pair("Missions", new CDMissionsTable())); - tables.insert(std::make_pair("ObjectSkills", new CDObjectSkillsTable())); - tables.insert(std::make_pair("Objects", new CDObjectsTable())); - tables.insert(std::make_pair("PhysicsComponent", new CDPhysicsComponentTable())); - tables.insert(std::make_pair("RebuildComponent", new CDRebuildComponentTable())); - tables.insert(std::make_pair("ScriptComponent", new CDScriptComponentTable())); - tables.insert(std::make_pair("SkillBehavior", new CDSkillBehaviorTable())); - tables.insert(std::make_pair("ZoneTable", new CDZoneTableTable())); - tables.insert(std::make_pair("VendorComponent", new CDVendorComponentTable())); - tables.insert(std::make_pair("Activities", new CDActivitiesTable())); - tables.insert(std::make_pair("PackageComponent", new CDPackageComponentTable())); - tables.insert(std::make_pair("ProximityMonitorComponent", new CDProximityMonitorComponentTable())); - tables.insert(std::make_pair("MovementAIComponent", new CDMovementAIComponentTable())); - tables.insert(std::make_pair("BrickIDTable", new CDBrickIDTableTable())); - tables.insert(std::make_pair("RarityTable", new CDRarityTableTable())); - tables.insert(std::make_pair("MissionEmail", new CDMissionEmailTable())); - tables.insert(std::make_pair("Rewards", new CDRewardsTable())); - tables.insert(std::make_pair("PropertyEntranceComponent", new CDPropertyEntranceComponentTable())); - tables.insert(std::make_pair("PropertyTemplate", new CDPropertyTemplateTable())); - tables.insert(std::make_pair("FeatureGating", new CDFeatureGatingTable())); - tables.insert(std::make_pair("RailActivatorComponent", new CDRailActivatorComponentTable())); +CDClientManager::CDClientManager() { + CDActivityRewardsTable::Instance(); + UNUSED(CDAnimationsTable::Instance()); + CDBehaviorParameterTable::Instance(); + CDBehaviorTemplateTable::Instance(); + CDComponentsRegistryTable::Instance(); + CDCurrencyTableTable::Instance(); + CDDestructibleComponentTable::Instance(); + CDEmoteTableTable::Instance(); + CDInventoryComponentTable::Instance(); + CDItemComponentTable::Instance(); + CDItemSetsTable::Instance(); + CDItemSetSkillsTable::Instance(); + CDLevelProgressionLookupTable::Instance(); + CDLootMatrixTable::Instance(); + CDLootTableTable::Instance(); + CDMissionNPCComponentTable::Instance(); + CDMissionTasksTable::Instance(); + CDMissionsTable::Instance(); + CDObjectSkillsTable::Instance(); + CDObjectsTable::Instance(); + CDPhysicsComponentTable::Instance(); + CDRebuildComponentTable::Instance(); + CDScriptComponentTable::Instance(); + CDSkillBehaviorTable::Instance(); + CDZoneTableTable::Instance(); + CDVendorComponentTable::Instance(); + CDActivitiesTable::Instance(); + CDPackageComponentTable::Instance(); + CDProximityMonitorComponentTable::Instance(); + CDMovementAIComponentTable::Instance(); + CDBrickIDTableTable::Instance(); + CDRarityTableTable::Instance(); + CDMissionEmailTable::Instance(); + CDRewardsTable::Instance(); + CDPropertyEntranceComponentTable::Instance(); + CDPropertyTemplateTable::Instance(); + CDFeatureGatingTable::Instance(); + CDRailActivatorComponentTable::Instance(); } diff --git a/dDatabase/CDClientManager.h b/dDatabase/CDClientManager.h index ea24a373..1754fe99 100644 --- a/dDatabase/CDClientManager.h +++ b/dDatabase/CDClientManager.h @@ -1,96 +1,24 @@ #pragma once -// Custom Classes #include "CDTable.h" -// Tables -#include "CDActivityRewardsTable.h" -#include "CDAnimationsTable.h" -#include "CDBehaviorParameterTable.h" -#include "CDBehaviorTemplateTable.h" -#include "CDComponentsRegistryTable.h" -#include "CDCurrencyTableTable.h" -#include "CDDestructibleComponentTable.h" -#include "CDEmoteTable.h" -#include "CDInventoryComponentTable.h" -#include "CDItemComponentTable.h" -#include "CDItemSetsTable.h" -#include "CDItemSetSkillsTable.h" -#include "CDLevelProgressionLookupTable.h" -#include "CDLootMatrixTable.h" -#include "CDLootTableTable.h" -#include "CDMissionNPCComponentTable.h" -#include "CDMissionTasksTable.h" -#include "CDMissionsTable.h" -#include "CDObjectSkillsTable.h" -#include "CDObjectsTable.h" -#include "CDPhysicsComponentTable.h" -#include "CDRebuildComponentTable.h" -#include "CDScriptComponentTable.h" -#include "CDSkillBehaviorTable.h" -#include "CDZoneTableTable.h" -#include "CDVendorComponentTable.h" -#include "CDActivitiesTable.h" -#include "CDPackageComponentTable.h" -#include "CDProximityMonitorComponentTable.h" -#include "CDMovementAIComponentTable.h" -#include "CDBrickIDTableTable.h" -#include "CDRarityTableTable.h" -#include "CDMissionEmailTable.h" -#include "CDRewardsTable.h" -#include "CDPropertyEntranceComponentTable.h" -#include "CDPropertyTemplateTable.h" -#include "CDFeatureGatingTable.h" -#include "CDRailActivatorComponent.h" +#include "Singleton.h" -// C++ -#include -#include - -/*! - \file CDClientManager.hpp - \brief A manager for the CDClient tables +/** + * Initialize the CDClient tables so they are all loaded into memory. */ - - //! Manages all data from the CDClient -class CDClientManager { -private: - static CDClientManager* m_Address; //!< The singleton address - - std::unordered_map tables; //!< The tables - +class CDClientManager : public Singleton { public: + CDClientManager(); - //! The singleton method - static CDClientManager* Instance() { - if (m_Address == 0) { - m_Address = new CDClientManager; - } - - return m_Address; - } - - //! Initializes the manager - void Initialize(void); - - //! Fetches a CDClient table - /*! - This function uses typename T which must be a subclass of CDTable. - It returns the class that conforms to the class name - - \param tableName The table name - \return The class or nullptr + /** + * Fetch a table from CDClient + * + * @tparam Table type to fetch + * @return A pointer to the requested table. */ template - T* GetTable(const std::string& tableName) { - static_assert(std::is_base_of::value, "T should inherit from CDTable!"); - - for (auto itr = this->tables.begin(); itr != this->tables.end(); ++itr) { - if (itr->first == tableName) { - return dynamic_cast(itr->second); - } - } - - return nullptr; + T* GetTable() { + return &T::Instance(); } }; diff --git a/dDatabase/Database.cpp b/dDatabase/Database.cpp index 91589377..1ce6966f 100644 --- a/dDatabase/Database.cpp +++ b/dDatabase/Database.cpp @@ -14,8 +14,6 @@ std::string Database::database; void Database::Connect(const string& host, const string& database, const string& username, const string& password) { //To bypass debug issues: - std::string newHost = "tcp://" + host; - const char* szHost = newHost.c_str(); const char* szDatabase = database.c_str(); const char* szUsername = username.c_str(); const char* szPassword = password.c_str(); @@ -23,7 +21,24 @@ void Database::Connect(const string& host, const string& database, const string& driver = sql::mariadb::get_driver_instance(); sql::Properties properties; - properties["hostName"] = szHost; + // The mariadb connector is *supposed* to handle unix:// and pipe:// prefixes to hostName, but there are bugs where + // 1) it tries to parse a database from the connection string (like in tcp://localhost:3001/darkflame) based on the + // presence of a / + // 2) even avoiding that, the connector still assumes you're connecting with a tcp socket + // So, what we do in the presence of a unix socket or pipe is to set the hostname to the protocol and localhost, + // which avoids parsing errors while still ensuring the correct connection type is used, and then setting the appropriate + // property manually (which the URL parsing fails to do) + const std::string UNIX_PROTO = "unix://"; + const std::string PIPE_PROTO = "pipe://"; + if (host.find(UNIX_PROTO) == 0) { + properties["hostName"] = "unix://localhost"; + properties["localSocket"] = host.substr(UNIX_PROTO.length()).c_str(); + } else if (host.find(PIPE_PROTO) == 0) { + properties["hostName"] = "pipe://localhost"; + properties["pipe"] = host.substr(PIPE_PROTO.length()).c_str(); + } else { + properties["hostName"] = host.c_str(); + } properties["user"] = szUsername; properties["password"] = szPassword; properties["autoReconnect"] = "true"; @@ -35,7 +50,13 @@ void Database::Connect(const string& host, const string& database, const string& } void Database::Connect() { - con = driver->connect(Database::props["hostName"].c_str(), Database::props["user"].c_str(), Database::props["password"].c_str()); + // `connect(const Properties& props)` segfaults in windows debug, but + // `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly + if (Database::props.find("localSocket") != Database::props.end() || Database::props.find("pipe") != Database::props.end()) { + con = driver->connect(Database::props); + } else { + con = driver->connect(Database::props["hostName"].c_str(), Database::props["user"].c_str(), Database::props["password"].c_str()); + } con->setSchema(Database::database.c_str()); } diff --git a/dDatabase/MigrationRunner.cpp b/dDatabase/MigrationRunner.cpp index 25312608..5e70c401 100644 --- a/dDatabase/MigrationRunner.cpp +++ b/dDatabase/MigrationRunner.cpp @@ -6,12 +6,13 @@ #include "Game.h" #include "GeneralUtils.h" #include "dLogger.h" +#include "BinaryPathFinder.h" #include Migration LoadMigration(std::string path) { Migration migration{}; - std::ifstream file("./migrations/" + path); + std::ifstream file(BinaryPathFinder::GetBinaryDir() / "migrations/" / path); if (file.is_open()) { std::string line; @@ -37,7 +38,7 @@ void MigrationRunner::RunMigrations() { sql::SQLString finalSQL = ""; bool runSd0Migrations = false; - for (const auto& entry : GeneralUtils::GetFileNamesFromFolder("./migrations/dlu/")) { + for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "./migrations/dlu/").string())) { auto migration = LoadMigration("dlu/" + entry); if (migration.data.empty()) { @@ -53,7 +54,7 @@ void MigrationRunner::RunMigrations() { if (doExit) continue; Game::logger->Log("MigrationRunner", "Running migration: %s", migration.name.c_str()); - if (migration.name == "5_brick_model_sd0.sql") { + if (migration.name == "dlu/5_brick_model_sd0.sql") { runSd0Migrations = true; } else { finalSQL.append(migration.data.c_str()); @@ -93,26 +94,49 @@ void MigrationRunner::RunMigrations() { } void MigrationRunner::RunSQLiteMigrations() { + auto cdstmt = CDClientDatabase::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP);"); + cdstmt.execQuery().finalize(); + cdstmt.finalize(); + auto* stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());"); stmt->execute(); delete stmt; - for (const auto& entry : GeneralUtils::GetFileNamesFromFolder("./migrations/cdserver/")) { + for (const auto& entry : GeneralUtils::GetSqlFileNamesFromFolder((BinaryPathFinder::GetBinaryDir() / "migrations/cdserver/").string())) { auto migration = LoadMigration("cdserver/" + entry); if (migration.data.empty()) continue; + // Check if there is an entry in the migration history table on the cdclient database. + cdstmt = CDClientDatabase::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;"); + cdstmt.bind((int32_t) 1, migration.name.c_str()); + auto cdres = cdstmt.execQuery(); + bool doExit = !cdres.eof(); + cdres.finalize(); + cdstmt.finalize(); + + if (doExit) continue; + + // Check first if there is entry in the migration history table on the main database. stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;"); stmt->setString(1, migration.name.c_str()); auto* res = stmt->executeQuery(); - bool doExit = res->next(); + doExit = res->next(); delete res; delete stmt; - if (doExit) continue; + if (doExit) { + // Insert into cdclient database if there is an entry in the main database but not the cdclient database. + cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); + cdstmt.bind((int32_t) 1, migration.name.c_str()); + cdstmt.execQuery().finalize(); + cdstmt.finalize(); + continue; + } // Doing these 1 migration at a time since one takes a long time and some may think it is crashing. // This will at the least guarentee that the full migration needs to be run in order to be counted as "migrated". Game::logger->Log("MigrationRunner", "Executing migration: %s. This may take a while. Do not shut down server.", migration.name.c_str()); + CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;"); for (const auto& dml : GeneralUtils::SplitString(migration.data, ';')) { if (dml.empty()) continue; try { @@ -121,10 +145,14 @@ void MigrationRunner::RunSQLiteMigrations() { Game::logger->Log("MigrationRunner", "Encountered error running DML command: (%i) : %s", e.errorCode(), e.errorMessage()); } } - stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); - stmt->setString(1, migration.name); - stmt->execute(); - delete stmt; + + // Insert into cdclient database. + cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); + cdstmt.bind((int32_t) 1, migration.name.c_str()); + cdstmt.execQuery().finalize(); + cdstmt.finalize(); + CDClientDatabase::ExecuteQuery("COMMIT;"); } + Game::logger->Log("MigrationRunner", "CDServer database is up to date."); } diff --git a/dDatabase/Tables/CDActivitiesTable.cpp b/dDatabase/Tables/CDActivitiesTable.cpp index 835ca3d2..e1660d66 100644 --- a/dDatabase/Tables/CDActivitiesTable.cpp +++ b/dDatabase/Tables/CDActivitiesTable.cpp @@ -1,6 +1,5 @@ #include "CDActivitiesTable.h" -//! Constructor CDActivitiesTable::CDActivitiesTable(void) { // First, get the size of the table @@ -21,25 +20,25 @@ CDActivitiesTable::CDActivitiesTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Activities"); while (!tableData.eof()) { CDActivities entry; - entry.ActivityID = tableData.getIntField(0, -1); - entry.locStatus = tableData.getIntField(1, -1); - entry.instanceMapID = tableData.getIntField(2, -1); - entry.minTeams = tableData.getIntField(3, -1); - entry.maxTeams = tableData.getIntField(4, -1); - entry.minTeamSize = tableData.getIntField(5, -1); - entry.maxTeamSize = tableData.getIntField(6, -1); - entry.waitTime = tableData.getIntField(7, -1); - entry.startDelay = tableData.getIntField(8, -1); - entry.requiresUniqueData = tableData.getIntField(9, -1); - entry.leaderboardType = tableData.getIntField(10, -1); - entry.localize = tableData.getIntField(11, -1); - entry.optionalCostLOT = tableData.getIntField(12, -1); - entry.optionalCostCount = tableData.getIntField(13, -1); - entry.showUIRewards = tableData.getIntField(14, -1); - entry.CommunityActivityFlagID = tableData.getIntField(15, -1); - entry.gate_version = tableData.getStringField(16, ""); - entry.noTeamLootOnDeath = tableData.getIntField(17, -1); - entry.optionalPercentage = tableData.getFloatField(18, -1.0f); + entry.ActivityID = tableData.getIntField("ActivityID", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.instanceMapID = tableData.getIntField("instanceMapID", -1); + entry.minTeams = tableData.getIntField("minTeams", -1); + entry.maxTeams = tableData.getIntField("maxTeams", -1); + entry.minTeamSize = tableData.getIntField("minTeamSize", -1); + entry.maxTeamSize = tableData.getIntField("maxTeamSize", -1); + entry.waitTime = tableData.getIntField("waitTime", -1); + entry.startDelay = tableData.getIntField("startDelay", -1); + entry.requiresUniqueData = tableData.getIntField("requiresUniqueData", -1); + entry.leaderboardType = tableData.getIntField("leaderboardType", -1); + entry.localize = tableData.getIntField("localize", -1); + entry.optionalCostLOT = tableData.getIntField("optionalCostLOT", -1); + entry.optionalCostCount = tableData.getIntField("optionalCostCount", -1); + entry.showUIRewards = tableData.getIntField("showUIRewards", -1); + entry.CommunityActivityFlagID = tableData.getIntField("CommunityActivityFlagID", -1); + entry.gate_version = tableData.getStringField("gate_version", ""); + entry.noTeamLootOnDeath = tableData.getIntField("noTeamLootOnDeath", -1); + entry.optionalPercentage = tableData.getFloatField("optionalPercentage", -1.0f); this->entries.push_back(entry); tableData.nextRow(); @@ -48,15 +47,6 @@ CDActivitiesTable::CDActivitiesTable(void) { tableData.finalize(); } -//! Destructor -CDActivitiesTable::~CDActivitiesTable(void) {} - -//! Returns the table's name -std::string CDActivitiesTable::GetName(void) const { - return "Activities"; -} - -//! Queries the table with a custom "where" clause std::vector CDActivitiesTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -66,7 +56,7 @@ std::vector CDActivitiesTable::Query(std::function CDActivitiesTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDActivitiesTable.h b/dDatabase/Tables/CDActivitiesTable.h index 51c560cf..4b60afbd 100644 --- a/dDatabase/Tables/CDActivitiesTable.h +++ b/dDatabase/Tables/CDActivitiesTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDActivitiesTable.hpp - \brief Contains data for the Activities table - */ - - //! Activities Entry Struct struct CDActivities { unsigned int ActivityID; unsigned int locStatus; @@ -31,36 +25,14 @@ struct CDActivities { float optionalPercentage; }; - -//! Activities table -class CDActivitiesTable : public CDTable { +class CDActivitiesTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDActivitiesTable(void); - - //! Destructor - ~CDActivitiesTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDActivitiesTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDActivityRewardsTable.cpp b/dDatabase/Tables/CDActivityRewardsTable.cpp index f1719204..65ef1101 100644 --- a/dDatabase/Tables/CDActivityRewardsTable.cpp +++ b/dDatabase/Tables/CDActivityRewardsTable.cpp @@ -1,6 +1,5 @@ #include "CDActivityRewardsTable.h" -//! Constructor CDActivityRewardsTable::CDActivityRewardsTable(void) { // First, get the size of the table @@ -21,13 +20,13 @@ CDActivityRewardsTable::CDActivityRewardsTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ActivityRewards"); while (!tableData.eof()) { CDActivityRewards entry; - entry.objectTemplate = tableData.getIntField(0, -1); - entry.ActivityRewardIndex = tableData.getIntField(1, -1); - entry.activityRating = tableData.getIntField(2, -1); - entry.LootMatrixIndex = tableData.getIntField(3, -1); - entry.CurrencyIndex = tableData.getIntField(4, -1); - entry.ChallengeRating = tableData.getIntField(5, -1); - entry.description = tableData.getStringField(6, ""); + entry.objectTemplate = tableData.getIntField("objectTemplate", -1); + entry.ActivityRewardIndex = tableData.getIntField("ActivityRewardIndex", -1); + entry.activityRating = tableData.getIntField("activityRating", -1); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); + entry.CurrencyIndex = tableData.getIntField("CurrencyIndex", -1); + entry.ChallengeRating = tableData.getIntField("ChallengeRating", -1); + entry.description = tableData.getStringField("description", ""); this->entries.push_back(entry); tableData.nextRow(); @@ -36,15 +35,6 @@ CDActivityRewardsTable::CDActivityRewardsTable(void) { tableData.finalize(); } -//! Destructor -CDActivityRewardsTable::~CDActivityRewardsTable(void) {} - -//! Returns the table's name -std::string CDActivityRewardsTable::GetName(void) const { - return "ActivityRewards"; -} - -//! Queries the table with a custom "where" clause std::vector CDActivityRewardsTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -54,7 +44,7 @@ std::vector CDActivityRewardsTable::Query(std::function CDActivityRewardsTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDActivityRewardsTable.h b/dDatabase/Tables/CDActivityRewardsTable.h index 7f1e81a0..b5503fb6 100644 --- a/dDatabase/Tables/CDActivityRewardsTable.h +++ b/dDatabase/Tables/CDActivityRewardsTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDActivityRewardsTable.hpp - \brief Contains data for the ActivityRewards table - */ - - //! ActivityRewards Entry Struct struct CDActivityRewards { unsigned int objectTemplate; //!< The object template (?) unsigned int ActivityRewardIndex; //!< The activity reward index @@ -19,36 +13,15 @@ struct CDActivityRewards { std::string description; //!< The description }; - -//! ActivityRewards table -class CDActivityRewardsTable : public CDTable { +class CDActivityRewardsTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDActivityRewardsTable(void); - - //! Destructor - ~CDActivityRewardsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDActivityRewardsTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDAnimationsTable.cpp b/dDatabase/Tables/CDAnimationsTable.cpp index 399804f8..e1227f39 100644 --- a/dDatabase/Tables/CDAnimationsTable.cpp +++ b/dDatabase/Tables/CDAnimationsTable.cpp @@ -1,6 +1,5 @@ #include "CDAnimationsTable.h" -//! Constructor CDAnimationsTable::CDAnimationsTable(void) { // First, get the size of the table @@ -21,19 +20,19 @@ CDAnimationsTable::CDAnimationsTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations"); while (!tableData.eof()) { CDAnimations entry; - entry.animationGroupID = tableData.getIntField(0, -1); - entry.animation_type = tableData.getStringField(1, ""); - entry.animation_name = tableData.getStringField(2, ""); - entry.chance_to_play = tableData.getFloatField(3, -1.0f); - entry.min_loops = tableData.getIntField(4, -1); - entry.max_loops = tableData.getIntField(5, -1); - entry.animation_length = tableData.getFloatField(6, -1.0f); - entry.hideEquip = tableData.getIntField(7, -1) == 1 ? true : false; - entry.ignoreUpperBody = tableData.getIntField(8, -1) == 1 ? true : false; - entry.restartable = tableData.getIntField(9, -1) == 1 ? true : false; - entry.face_animation_name = tableData.getStringField(10, ""); - entry.priority = tableData.getFloatField(11, -1.0f); - entry.blendTime = tableData.getFloatField(12, -1.0f); + entry.animationGroupID = tableData.getIntField("animationGroupID", -1); + entry.animation_type = tableData.getStringField("animation_type", ""); + entry.animation_name = tableData.getStringField("animation_name", ""); + entry.chance_to_play = tableData.getFloatField("chance_to_play", -1.0f); + entry.min_loops = tableData.getIntField("min_loops", -1); + entry.max_loops = tableData.getIntField("max_loops", -1); + entry.animation_length = tableData.getFloatField("animation_length", -1.0f); + entry.hideEquip = tableData.getIntField("hideEquip", -1) == 1 ? true : false; + entry.ignoreUpperBody = tableData.getIntField("ignoreUpperBody", -1) == 1 ? true : false; + entry.restartable = tableData.getIntField("restartable", -1) == 1 ? true : false; + entry.face_animation_name = tableData.getStringField("face_animation_name", ""); + entry.priority = tableData.getFloatField("priority", -1.0f); + entry.blendTime = tableData.getFloatField("blendTime", -1.0f); this->entries.push_back(entry); tableData.nextRow(); @@ -42,15 +41,6 @@ CDAnimationsTable::CDAnimationsTable(void) { tableData.finalize(); } -//! Destructor -CDAnimationsTable::~CDAnimationsTable(void) {} - -//! Returns the table's name -std::string CDAnimationsTable::GetName(void) const { - return "Animations"; -} - -//! Queries the table with a custom "where" clause std::vector CDAnimationsTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -60,7 +50,7 @@ std::vector CDAnimationsTable::Query(std::function CDAnimationsTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDAnimationsTable.h b/dDatabase/Tables/CDAnimationsTable.h index 24112985..43400abf 100644 --- a/dDatabase/Tables/CDAnimationsTable.h +++ b/dDatabase/Tables/CDAnimationsTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDAnimationsTable.hpp - \brief Contains data for the Animations table - */ - - //! Animations Entry Struct struct CDAnimations { unsigned int animationGroupID; //!< The animation group ID std::string animation_type; //!< The animation type @@ -26,35 +20,14 @@ struct CDAnimations { }; -//! Animations table -class CDAnimationsTable : public CDTable { +class CDAnimationsTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDAnimationsTable(void); - - //! Destructor - ~CDAnimationsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDAnimationsTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDBehaviorParameterTable.cpp b/dDatabase/Tables/CDBehaviorParameterTable.cpp index 96015896..0713e740 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.cpp +++ b/dDatabase/Tables/CDBehaviorParameterTable.cpp @@ -1,28 +1,25 @@ #include "CDBehaviorParameterTable.h" #include "GeneralUtils.h" -//! Constructor CDBehaviorParameterTable::CDBehaviorParameterTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); - size_t hash = 0; + uint32_t uniqueParameterId = 0; + uint64_t hash = 0; while (!tableData.eof()) { - hash = 0; CDBehaviorParameter entry; - entry.behaviorID = tableData.getIntField(0, -1); - auto candidateStringToAdd = std::string(tableData.getStringField(1, "")); + entry.behaviorID = tableData.getIntField("behaviorID", -1); + auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", "")); auto parameter = m_ParametersList.find(candidateStringToAdd); if (parameter != m_ParametersList.end()) { entry.parameterID = parameter; } else { - entry.parameterID = m_ParametersList.insert(candidateStringToAdd).first; + entry.parameterID = m_ParametersList.insert(std::make_pair(candidateStringToAdd, uniqueParameterId)).first; + uniqueParameterId++; } - entry.value = tableData.getFloatField(2, -1.0f); + hash = entry.behaviorID; + hash = (hash << 31U) | entry.parameterID->second; + entry.value = tableData.getFloatField("value", -1.0f); - GeneralUtils::hash_combine(hash, entry.behaviorID); - GeneralUtils::hash_combine(hash, *entry.parameterID); - - auto it = m_Entries.find(entry.behaviorID); - m_ParametersList.insert(*entry.parameterID); m_Entries.insert(std::make_pair(hash, entry)); tableData.nextRow(); @@ -30,40 +27,30 @@ CDBehaviorParameterTable::CDBehaviorParameterTable(void) { tableData.finalize(); } -//! Destructor -CDBehaviorParameterTable::~CDBehaviorParameterTable(void) {} +float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) { + auto parameterID = this->m_ParametersList.find(name); + if (parameterID == this->m_ParametersList.end()) return defaultValue; -//! Returns the table's name -std::string CDBehaviorParameterTable::GetName(void) const { - return "BehaviorParameter"; -} + uint64_t hash = behaviorID; -CDBehaviorParameter CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) { - CDBehaviorParameter returnValue; - returnValue.behaviorID = 0; - returnValue.parameterID = m_ParametersList.end(); - returnValue.value = defaultValue; - - size_t hash = 0; - GeneralUtils::hash_combine(hash, behaviorID); - GeneralUtils::hash_combine(hash, name); + hash = (hash << 31U) | parameterID->second; // Search for specific parameter const auto& it = m_Entries.find(hash); - return it != m_Entries.end() ? it->second : returnValue; + return it != m_Entries.end() ? it->second.value : defaultValue; } std::map CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { - size_t hash; + uint64_t hashBase = behaviorID; std::map returnInfo; - for (auto parameterCandidate : m_ParametersList) { - hash = 0; - GeneralUtils::hash_combine(hash, behaviorID); - GeneralUtils::hash_combine(hash, parameterCandidate); + uint64_t hash; + for (auto& parameterCandidate : m_ParametersList) { + hash = (hashBase << 31U) | parameterCandidate.second; auto infoCandidate = m_Entries.find(hash); if (infoCandidate != m_Entries.end()) { - returnInfo.insert(std::make_pair(*(infoCandidate->second.parameterID), infoCandidate->second.value)); + returnInfo.insert(std::make_pair(infoCandidate->second.parameterID->first, infoCandidate->second.value)); } } return returnInfo; } + diff --git a/dDatabase/Tables/CDBehaviorParameterTable.h b/dDatabase/Tables/CDBehaviorParameterTable.h index f067e7d2..b0715684 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.h +++ b/dDatabase/Tables/CDBehaviorParameterTable.h @@ -5,38 +5,19 @@ #include #include -/*! - \file CDBehaviorParameterTable.hpp - \brief Contains data for the BehaviorParameter table - */ - - //! BehaviorParameter Entry Struct struct CDBehaviorParameter { - unsigned int behaviorID; //!< The Behavior ID - std::unordered_set::iterator parameterID; //!< The Parameter ID - float value; //!< The value of the behavior template + unsigned int behaviorID; //!< The Behavior ID + std::unordered_map::iterator parameterID; //!< The Parameter ID + float value; //!< The value of the behavior template }; -//! BehaviorParameter table -class CDBehaviorParameterTable : public CDTable { +class CDBehaviorParameterTable : public CDTable { private: - std::unordered_map m_Entries; - std::unordered_set m_ParametersList; + std::unordered_map m_Entries; + std::unordered_map m_ParametersList; public: - - //! Constructor - CDBehaviorParameterTable(void); - - //! Destructor - ~CDBehaviorParameterTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - CDBehaviorParameter GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); + CDBehaviorParameterTable(); + float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); std::map GetParametersByBehaviorID(uint32_t behaviorID); }; diff --git a/dDatabase/Tables/CDBehaviorTemplateTable.cpp b/dDatabase/Tables/CDBehaviorTemplateTable.cpp index 1628756f..08bc86d1 100644 --- a/dDatabase/Tables/CDBehaviorTemplateTable.cpp +++ b/dDatabase/Tables/CDBehaviorTemplateTable.cpp @@ -1,6 +1,5 @@ #include "CDBehaviorTemplateTable.h" -//! Constructor CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) { // First, get the size of the table @@ -21,9 +20,9 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate"); while (!tableData.eof()) { CDBehaviorTemplate entry; - entry.behaviorID = tableData.getIntField(0, -1); - entry.templateID = tableData.getIntField(1, -1); - entry.effectID = tableData.getIntField(2, -1); + entry.behaviorID = tableData.getIntField("behaviorID", -1); + entry.templateID = tableData.getIntField("templateID", -1); + entry.effectID = tableData.getIntField("effectID", -1); auto candidateToAdd = tableData.getStringField(3, ""); auto parameter = m_EffectHandles.find(candidateToAdd); if (parameter != m_EffectHandles.end()) { @@ -40,15 +39,6 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) { tableData.finalize(); } -//! Destructor -CDBehaviorTemplateTable::~CDBehaviorTemplateTable(void) {} - -//! Returns the table's name -std::string CDBehaviorTemplateTable::GetName(void) const { - return "BehaviorTemplate"; -} - -//! Queries the table with a custom "where" clause std::vector CDBehaviorTemplateTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -58,7 +48,6 @@ std::vector CDBehaviorTemplateTable::Query(std::function CDBehaviorTemplateTable::GetEntries(void) const { return this->entries; } @@ -75,3 +64,4 @@ const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behav return entry->second; } } + diff --git a/dDatabase/Tables/CDBehaviorTemplateTable.h b/dDatabase/Tables/CDBehaviorTemplateTable.h index b2bd2521..f9ac9a09 100644 --- a/dDatabase/Tables/CDBehaviorTemplateTable.h +++ b/dDatabase/Tables/CDBehaviorTemplateTable.h @@ -5,12 +5,6 @@ #include #include -/*! - \file CDBehaviorTemplateTable.hpp - \brief Contains data for the BehaviorTemplate table - */ - - //! BehaviorTemplate Entry Struct struct CDBehaviorTemplate { unsigned int behaviorID; //!< The Behavior ID unsigned int templateID; //!< The Template ID (LOT) @@ -19,36 +13,16 @@ struct CDBehaviorTemplate { }; -//! BehaviorTemplate table -class CDBehaviorTemplateTable : public CDTable { +class CDBehaviorTemplateTable : public CDTable { private: std::vector entries; std::unordered_map entriesMappedByBehaviorID; std::unordered_set m_EffectHandles; public: - - //! Constructor - CDBehaviorTemplateTable(void); - - //! Destructor - ~CDBehaviorTemplateTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDBehaviorTemplateTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID); diff --git a/dDatabase/Tables/CDBrickIDTableTable.cpp b/dDatabase/Tables/CDBrickIDTableTable.cpp index 9dbdf2c0..9ad24d39 100644 --- a/dDatabase/Tables/CDBrickIDTableTable.cpp +++ b/dDatabase/Tables/CDBrickIDTableTable.cpp @@ -1,6 +1,5 @@ #include "CDBrickIDTableTable.h" -//! Constructor CDBrickIDTableTable::CDBrickIDTableTable(void) { // First, get the size of the table @@ -21,8 +20,8 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BrickIDTable"); while (!tableData.eof()) { CDBrickIDTable entry; - entry.NDObjectID = tableData.getIntField(0, -1); - entry.LEGOBrickID = tableData.getIntField(1, -1); + entry.NDObjectID = tableData.getIntField("NDObjectID", -1); + entry.LEGOBrickID = tableData.getIntField("LEGOBrickID", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -31,15 +30,6 @@ CDBrickIDTableTable::CDBrickIDTableTable(void) { tableData.finalize(); } -//! Destructor -CDBrickIDTableTable::~CDBrickIDTableTable(void) {} - -//! Returns the table's name -std::string CDBrickIDTableTable::GetName(void) const { - return "BrickIDTable"; -} - -//! Queries the table with a custom "where" clause std::vector CDBrickIDTableTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -49,7 +39,7 @@ std::vector CDBrickIDTableTable::Query(std::function CDBrickIDTableTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDBrickIDTableTable.h b/dDatabase/Tables/CDBrickIDTableTable.h index aefe332c..e2084caf 100644 --- a/dDatabase/Tables/CDBrickIDTableTable.h +++ b/dDatabase/Tables/CDBrickIDTableTable.h @@ -16,34 +16,14 @@ struct CDBrickIDTable { //! BrickIDTable table -class CDBrickIDTableTable : public CDTable { +class CDBrickIDTableTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDBrickIDTableTable(void); - - //! Destructor - ~CDBrickIDTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDBrickIDTableTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDComponentsRegistryTable.cpp b/dDatabase/Tables/CDComponentsRegistryTable.cpp index 8e5ae108..32012f6c 100644 --- a/dDatabase/Tables/CDComponentsRegistryTable.cpp +++ b/dDatabase/Tables/CDComponentsRegistryTable.cpp @@ -1,8 +1,8 @@ #include "CDComponentsRegistryTable.h" +#include "eReplicaComponentType.h" #define CDCLIENT_CACHE_ALL -//! Constructor CDComponentsRegistryTable::CDComponentsRegistryTable(void) { #ifdef CDCLIENT_CACHE_ALL @@ -24,30 +24,12 @@ CDComponentsRegistryTable::CDComponentsRegistryTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry"); while (!tableData.eof()) { CDComponentsRegistry entry; - entry.id = tableData.getIntField(0, -1); - entry.component_type = tableData.getIntField(1, -1); - entry.component_id = tableData.getIntField(2, -1); + entry.id = tableData.getIntField("id", -1); + entry.component_type = static_cast(tableData.getIntField("component_type", 0)); + entry.component_id = tableData.getIntField("component_id", -1); this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((uint64_t)entry.id), entry.component_id); - //this->entries.push_back(entry); - - /* - //Darwin's stuff: - const auto& it = this->mappedEntries.find(entry.id); - if (it != mappedEntries.end()) { - const auto& iter = it->second.find(entry.component_type); - if (iter == it->second.end()) { - it->second.insert(std::make_pair(entry.component_type, entry.component_id)); - } - } - else { - std::map map; - map.insert(std::make_pair(entry.component_type, entry.component_id)); - this->mappedEntries.insert(std::make_pair(entry.id, map)); - } - */ - tableData.nextRow(); } @@ -55,15 +37,7 @@ CDComponentsRegistryTable::CDComponentsRegistryTable(void) { #endif } -//! Destructor -CDComponentsRegistryTable::~CDComponentsRegistryTable(void) {} - -//! Returns the table's name -std::string CDComponentsRegistryTable::GetName(void) const { - return "ComponentsRegistry"; -} - -int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue) { +int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) { const auto& iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id)); if (iter == this->mappedEntries.end()) { @@ -72,16 +46,6 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componen return iter->second; - /* - const auto& it = this->mappedEntries.find(id); - if (it != mappedEntries.end()) { - const auto& iter = it->second.find(componentType); - if (iter != it->second.end()) { - return iter->second; - } - } - */ - #ifndef CDCLIENT_CACHE_ALL // Now get the data std::stringstream query; @@ -91,9 +55,9 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componen auto tableData = CDClientDatabase::ExecuteQuery(query.str()); while (!tableData.eof()) { CDComponentsRegistry entry; - entry.id = tableData.getIntField(0, -1); - entry.component_type = tableData.getIntField(1, -1); - entry.component_id = tableData.getIntField(2, -1); + entry.id = tableData.getIntField("id", -1); + entry.component_type = tableData.getIntField("component_type", -1); + entry.component_id = tableData.getIntField("component_id", -1); //this->entries.push_back(entry); @@ -126,3 +90,4 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componen return defaultValue; #endif } + diff --git a/dDatabase/Tables/CDComponentsRegistryTable.h b/dDatabase/Tables/CDComponentsRegistryTable.h index c3eb0ed2..990072c9 100644 --- a/dDatabase/Tables/CDComponentsRegistryTable.h +++ b/dDatabase/Tables/CDComponentsRegistryTable.h @@ -3,38 +3,19 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDComponentsRegistryTable.hpp - \brief Contains data for the ComponentsRegistry table - */ - - //! ComponentsRegistry Entry Struct +enum class eReplicaComponentType : uint32_t; struct CDComponentsRegistry { unsigned int id; //!< The LOT is used as the ID - unsigned int component_type; //!< See ComponentTypes enum for values + eReplicaComponentType component_type; //!< See ComponentTypes enum for values unsigned int component_id; //!< The ID used within the component's table (0 may either mean it's non-networked, or that the ID is actually 0 }; -//! ComponentsRegistry table -class CDComponentsRegistryTable : public CDTable { +class CDComponentsRegistryTable : public CDTable { private: - //std::vector entries; std::map mappedEntries; //id, component_type, component_id public: - - //! Constructor - CDComponentsRegistryTable(void); - - //! Destructor - ~CDComponentsRegistryTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - int32_t GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue = 0); + CDComponentsRegistryTable(); + int32_t GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue = 0); }; diff --git a/dDatabase/Tables/CDCurrencyTableTable.cpp b/dDatabase/Tables/CDCurrencyTableTable.cpp index a1923a73..78a716f9 100644 --- a/dDatabase/Tables/CDCurrencyTableTable.cpp +++ b/dDatabase/Tables/CDCurrencyTableTable.cpp @@ -21,11 +21,11 @@ CDCurrencyTableTable::CDCurrencyTableTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM CurrencyTable"); while (!tableData.eof()) { CDCurrencyTable entry; - entry.currencyIndex = tableData.getIntField(0, -1); - entry.npcminlevel = tableData.getIntField(1, -1); - entry.minvalue = tableData.getIntField(2, -1); - entry.maxvalue = tableData.getIntField(3, -1); - entry.id = tableData.getIntField(4, -1); + entry.currencyIndex = tableData.getIntField("currencyIndex", -1); + entry.npcminlevel = tableData.getIntField("npcminlevel", -1); + entry.minvalue = tableData.getIntField("minvalue", -1); + entry.maxvalue = tableData.getIntField("maxvalue", -1); + entry.id = tableData.getIntField("id", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -34,15 +34,6 @@ CDCurrencyTableTable::CDCurrencyTableTable(void) { tableData.finalize(); } -//! Destructor -CDCurrencyTableTable::~CDCurrencyTableTable(void) {} - -//! Returns the table's name -std::string CDCurrencyTableTable::GetName(void) const { - return "CurrencyTable"; -} - -//! Queries the table with a custom "where" clause std::vector CDCurrencyTableTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -52,7 +43,7 @@ std::vector CDCurrencyTableTable::Query(std::function CDCurrencyTableTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDCurrencyTableTable.h b/dDatabase/Tables/CDCurrencyTableTable.h index 5a856395..ec700320 100644 --- a/dDatabase/Tables/CDCurrencyTableTable.h +++ b/dDatabase/Tables/CDCurrencyTableTable.h @@ -18,34 +18,14 @@ struct CDCurrencyTable { }; //! CurrencyTable table -class CDCurrencyTableTable : public CDTable { +class CDCurrencyTableTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDCurrencyTableTable(void); - - //! Destructor - ~CDCurrencyTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDCurrencyTableTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDDestructibleComponentTable.cpp b/dDatabase/Tables/CDDestructibleComponentTable.cpp index d7438fc7..4bbc8242 100644 --- a/dDatabase/Tables/CDDestructibleComponentTable.cpp +++ b/dDatabase/Tables/CDDestructibleComponentTable.cpp @@ -21,20 +21,20 @@ CDDestructibleComponentTable::CDDestructibleComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM DestructibleComponent"); while (!tableData.eof()) { CDDestructibleComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.faction = tableData.getIntField(1, -1); - entry.factionList = tableData.getStringField(2, ""); - entry.life = tableData.getIntField(3, -1); - entry.imagination = tableData.getIntField(4, -1); - entry.LootMatrixIndex = tableData.getIntField(5, -1); - entry.CurrencyIndex = tableData.getIntField(6, -1); - entry.level = tableData.getIntField(7, -1); - entry.armor = tableData.getFloatField(8, -1.0f); - entry.death_behavior = tableData.getIntField(9, -1); - entry.isnpc = tableData.getIntField(10, -1) == 1 ? true : false; - entry.attack_priority = tableData.getIntField(11, -1); - entry.isSmashable = tableData.getIntField(12, -1) == 1 ? true : false; - entry.difficultyLevel = tableData.getIntField(13, -1); + entry.id = tableData.getIntField("id", -1); + entry.faction = tableData.getIntField("faction", -1); + entry.factionList = tableData.getStringField("factionList", ""); + entry.life = tableData.getIntField("life", -1); + entry.imagination = tableData.getIntField("imagination", -1); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); + entry.CurrencyIndex = tableData.getIntField("CurrencyIndex", -1); + entry.level = tableData.getIntField("level", -1); + entry.armor = tableData.getFloatField("armor", -1.0f); + entry.death_behavior = tableData.getIntField("death_behavior", -1); + entry.isnpc = tableData.getIntField("isnpc", -1) == 1 ? true : false; + entry.attack_priority = tableData.getIntField("attack_priority", -1); + entry.isSmashable = tableData.getIntField("isSmashable", -1) == 1 ? true : false; + entry.difficultyLevel = tableData.getIntField("difficultyLevel", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -43,15 +43,6 @@ CDDestructibleComponentTable::CDDestructibleComponentTable(void) { tableData.finalize(); } -//! Destructor -CDDestructibleComponentTable::~CDDestructibleComponentTable(void) {} - -//! Returns the table's name -std::string CDDestructibleComponentTable::GetName(void) const { - return "DestructibleComponent"; -} - -//! Queries the table with a custom "where" clause std::vector CDDestructibleComponentTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -61,7 +52,7 @@ std::vector CDDestructibleComponentTable::Query(std::fu return data; } -//! Gets all the entries in the table std::vector CDDestructibleComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDDestructibleComponentTable.h b/dDatabase/Tables/CDDestructibleComponentTable.h index e89bbff8..e42cf486 100644 --- a/dDatabase/Tables/CDDestructibleComponentTable.h +++ b/dDatabase/Tables/CDDestructibleComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDDestructibleComponentTable.hpp - \brief Contains data for the DestructibleComponent table - */ - - //! ItemComponent Struct struct CDDestructibleComponent { unsigned int id; //!< The component ID from the ComponentsRegistry Table int faction; //!< The Faction ID of the object @@ -26,35 +20,14 @@ struct CDDestructibleComponent { int difficultyLevel; //!< ??? }; -//! ItemComponent table -class CDDestructibleComponentTable : public CDTable { +class CDDestructibleComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDDestructibleComponentTable(void); - - //! Destructor - ~CDDestructibleComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDDestructibleComponentTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDEmoteTable.cpp b/dDatabase/Tables/CDEmoteTable.cpp index e3898422..aacbdd55 100644 --- a/dDatabase/Tables/CDEmoteTable.cpp +++ b/dDatabase/Tables/CDEmoteTable.cpp @@ -5,14 +5,14 @@ CDEmoteTableTable::CDEmoteTableTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Emotes"); while (!tableData.eof()) { CDEmoteTable* entry = new CDEmoteTable(); - entry->ID = tableData.getIntField(0, -1); - entry->animationName = tableData.getStringField(1, ""); - entry->iconFilename = tableData.getStringField(2, ""); - entry->channel = tableData.getIntField(3, -1); - entry->locked = tableData.getIntField(5, -1) != 0; - entry->localize = tableData.getIntField(6, -1) != 0; - entry->locState = tableData.getIntField(7, -1); - entry->gateVersion = tableData.getIntField(8, -1); + entry->ID = tableData.getIntField("id", -1); + entry->animationName = tableData.getStringField("animationName", ""); + entry->iconFilename = tableData.getStringField("iconFilename", ""); + entry->channel = tableData.getIntField("channel", -1); + entry->locked = tableData.getIntField("locked", -1) != 0; + entry->localize = tableData.getIntField("localize", -1) != 0; + entry->locState = tableData.getIntField("locStatus", -1); + entry->gateVersion = tableData.getStringField("gate_version", ""); entries.insert(std::make_pair(entry->ID, entry)); tableData.nextRow(); @@ -30,11 +30,6 @@ CDEmoteTableTable::~CDEmoteTableTable(void) { entries.clear(); } -//! Returns the table's name -std::string CDEmoteTableTable::GetName(void) const { - return "Emotes"; -} - CDEmoteTable* CDEmoteTableTable::GetEmote(int id) { for (auto e : entries) { if (e.first == id) return e.second; @@ -42,3 +37,4 @@ CDEmoteTable* CDEmoteTableTable::GetEmote(int id) { return nullptr; } + diff --git a/dDatabase/Tables/CDEmoteTable.h b/dDatabase/Tables/CDEmoteTable.h index a22ae23e..be40c86f 100644 --- a/dDatabase/Tables/CDEmoteTable.h +++ b/dDatabase/Tables/CDEmoteTable.h @@ -4,12 +4,6 @@ #include "CDTable.h" #include -/*! - \file CDEmoteTable.hpp - \brief Contains data for the CDEmoteTable table - */ - - //! CDEmoteEntry Struct struct CDEmoteTable { CDEmoteTable() { ID = -1; @@ -19,7 +13,7 @@ struct CDEmoteTable { channel = -1; locked = false; localize = false; - gateVersion = -1; + gateVersion = ""; } int ID; @@ -29,28 +23,16 @@ struct CDEmoteTable { int channel; bool locked; bool localize; - int gateVersion; + std::string gateVersion; }; -//! CDEmoteTable table -class CDEmoteTableTable : public CDTable { +class CDEmoteTableTable : public CDTable { private: std::map entries; public: - - //! Constructor - CDEmoteTableTable(void); - - //! Destructor - ~CDEmoteTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Returns an emote by ID + CDEmoteTableTable(); + ~CDEmoteTableTable(); + // Returns an emote by ID CDEmoteTable* GetEmote(int id); }; diff --git a/dDatabase/Tables/CDFeatureGatingTable.cpp b/dDatabase/Tables/CDFeatureGatingTable.cpp index dfc65387..05fe69bf 100644 --- a/dDatabase/Tables/CDFeatureGatingTable.cpp +++ b/dDatabase/Tables/CDFeatureGatingTable.cpp @@ -21,11 +21,11 @@ CDFeatureGatingTable::CDFeatureGatingTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM FeatureGating"); while (!tableData.eof()) { CDFeatureGating entry; - entry.featureName = tableData.getStringField(0, ""); - entry.major = tableData.getIntField(1, -1); - entry.current = tableData.getIntField(2, -1); - entry.minor = tableData.getIntField(3, -1); - entry.description = tableData.getStringField(4, ""); + entry.featureName = tableData.getStringField("featureName", ""); + entry.major = tableData.getIntField("major", -1); + entry.current = tableData.getIntField("current", -1); + entry.minor = tableData.getIntField("minor", -1); + entry.description = tableData.getStringField("description", ""); this->entries.push_back(entry); tableData.nextRow(); @@ -34,15 +34,6 @@ CDFeatureGatingTable::CDFeatureGatingTable(void) { tableData.finalize(); } -//! Destructor -CDFeatureGatingTable::~CDFeatureGatingTable(void) {} - -//! Returns the table's name -std::string CDFeatureGatingTable::GetName(void) const { - return "FeatureGating"; -} - -//! Queries the table with a custom "where" clause std::vector CDFeatureGatingTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -62,7 +53,7 @@ bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const { return false; } -//! Gets all the entries in the table std::vector CDFeatureGatingTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDFeatureGatingTable.h b/dDatabase/Tables/CDFeatureGatingTable.h index 54e6d21b..7f536db5 100644 --- a/dDatabase/Tables/CDFeatureGatingTable.h +++ b/dDatabase/Tables/CDFeatureGatingTable.h @@ -3,11 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDFeatureGatingTable.hpp - */ - - //! ItemComponent Struct struct CDFeatureGating { std::string featureName; int32_t major; @@ -16,37 +11,16 @@ struct CDFeatureGating { std::string description; }; -//! ItemComponent table -class CDFeatureGatingTable : public CDTable { +class CDFeatureGatingTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDFeatureGatingTable(void); - - //! Destructor - ~CDFeatureGatingTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDFeatureGatingTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); bool FeatureUnlocked(const std::string& feature) const; - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDInventoryComponentTable.cpp b/dDatabase/Tables/CDInventoryComponentTable.cpp index 65f09c9b..2dc375ab 100644 --- a/dDatabase/Tables/CDInventoryComponentTable.cpp +++ b/dDatabase/Tables/CDInventoryComponentTable.cpp @@ -21,10 +21,10 @@ CDInventoryComponentTable::CDInventoryComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM InventoryComponent"); while (!tableData.eof()) { CDInventoryComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.itemid = tableData.getIntField(1, -1); - entry.count = tableData.getIntField(2, -1); - entry.equip = tableData.getIntField(3, -1) == 1 ? true : false; + entry.id = tableData.getIntField("id", -1); + entry.itemid = tableData.getIntField("itemid", -1); + entry.count = tableData.getIntField("count", -1); + entry.equip = tableData.getIntField("equip", -1) == 1 ? true : false; this->entries.push_back(entry); tableData.nextRow(); @@ -33,15 +33,6 @@ CDInventoryComponentTable::CDInventoryComponentTable(void) { tableData.finalize(); } -//! Destructor -CDInventoryComponentTable::~CDInventoryComponentTable(void) {} - -//! Returns the table's name -std::string CDInventoryComponentTable::GetName(void) const { - return "InventoryComponent"; -} - -//! Queries the table with a custom "where" clause std::vector CDInventoryComponentTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -51,7 +42,7 @@ std::vector CDInventoryComponentTable::Query(std::function return data; } -//! Gets all the entries in the table std::vector CDInventoryComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDInventoryComponentTable.h b/dDatabase/Tables/CDInventoryComponentTable.h index c6117907..cbc04d99 100644 --- a/dDatabase/Tables/CDInventoryComponentTable.h +++ b/dDatabase/Tables/CDInventoryComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDInventoryComponentTable.hpp - \brief Contains data for the InventoryComponent table - */ - - //! ItemComponent Struct struct CDInventoryComponent { unsigned int id; //!< The component ID for this object unsigned int itemid; //!< The LOT of the object @@ -16,35 +10,14 @@ struct CDInventoryComponent { bool equip; //!< Whether or not to equip the item }; -//! ItemComponent table -class CDInventoryComponentTable : public CDTable { +class CDInventoryComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDInventoryComponentTable(void); - - //! Destructor - ~CDInventoryComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDInventoryComponentTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDItemComponentTable.cpp b/dDatabase/Tables/CDItemComponentTable.cpp index 6ff192fd..54afc417 100644 --- a/dDatabase/Tables/CDItemComponentTable.cpp +++ b/dDatabase/Tables/CDItemComponentTable.cpp @@ -23,48 +23,48 @@ CDItemComponentTable::CDItemComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemComponent"); while (!tableData.eof()) { CDItemComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.equipLocation = tableData.getStringField(1, ""); - entry.baseValue = tableData.getIntField(2, -1); - entry.isKitPiece = tableData.getIntField(3, -1) == 1 ? true : false; - entry.rarity = tableData.getIntField(4, 0); - entry.itemType = tableData.getIntField(5, -1); - entry.itemInfo = tableData.getInt64Field(6, -1); - entry.inLootTable = tableData.getIntField(7, -1) == 1 ? true : false; - entry.inVendor = tableData.getIntField(8, -1) == 1 ? true : false; - entry.isUnique = tableData.getIntField(9, -1) == 1 ? true : false; - entry.isBOP = tableData.getIntField(10, -1) == 1 ? true : false; - entry.isBOE = tableData.getIntField(11, -1) == 1 ? true : false; - entry.reqFlagID = tableData.getIntField(12, -1); - entry.reqSpecialtyID = tableData.getIntField(13, -1); - entry.reqSpecRank = tableData.getIntField(14, -1); - entry.reqAchievementID = tableData.getIntField(15, -1); - entry.stackSize = tableData.getIntField(16, -1); - entry.color1 = tableData.getIntField(17, -1); - entry.decal = tableData.getIntField(18, -1); - entry.offsetGroupID = tableData.getIntField(19, -1); - entry.buildTypes = tableData.getIntField(20, -1); - entry.reqPrecondition = tableData.getStringField(21, ""); - entry.animationFlag = tableData.getIntField(22, 0); - entry.equipEffects = tableData.getIntField(23, -1); - entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false; - entry.itemRating = tableData.getIntField(25, -1); - entry.isTwoHanded = tableData.getIntField(26, -1) == 1 ? true : false; - entry.minNumRequired = tableData.getIntField(27, -1); - entry.delResIndex = tableData.getIntField(28, -1); - entry.currencyLOT = tableData.getIntField(29, -1); - entry.altCurrencyCost = tableData.getIntField(30, -1); - entry.subItems = tableData.getStringField(31, ""); - entry.audioEventUse = tableData.getStringField(32, ""); - entry.noEquipAnimation = tableData.getIntField(33, -1) == 1 ? true : false; - entry.commendationLOT = tableData.getIntField(34, -1); - entry.commendationCost = tableData.getIntField(35, -1); - entry.audioEquipMetaEventSet = tableData.getStringField(36, ""); - entry.currencyCosts = tableData.getStringField(37, ""); - entry.ingredientInfo = tableData.getStringField(38, ""); - entry.locStatus = tableData.getIntField(39, -1); - entry.forgeType = tableData.getIntField(40, -1); - entry.SellMultiplier = tableData.getFloatField(41, -1.0f); + entry.id = tableData.getIntField("id", -1); + entry.equipLocation = tableData.getStringField("equipLocation", ""); + entry.baseValue = tableData.getIntField("baseValue", -1); + entry.isKitPiece = tableData.getIntField("isKitPiece", -1) == 1 ? true : false; + entry.rarity = tableData.getIntField("rarity", 0); + entry.itemType = tableData.getIntField("itemType", -1); + entry.itemInfo = tableData.getInt64Field("itemInfo", -1); + entry.inLootTable = tableData.getIntField("inLootTable", -1) == 1 ? true : false; + entry.inVendor = tableData.getIntField("inVendor", -1) == 1 ? true : false; + entry.isUnique = tableData.getIntField("isUnique", -1) == 1 ? true : false; + entry.isBOP = tableData.getIntField("isBOP", -1) == 1 ? true : false; + entry.isBOE = tableData.getIntField("isBOE", -1) == 1 ? true : false; + entry.reqFlagID = tableData.getIntField("reqFlagID", -1); + entry.reqSpecialtyID = tableData.getIntField("reqSpecialtyID", -1); + entry.reqSpecRank = tableData.getIntField("reqSpecRank", -1); + entry.reqAchievementID = tableData.getIntField("reqAchievementID", -1); + entry.stackSize = tableData.getIntField("stackSize", -1); + entry.color1 = tableData.getIntField("color1", -1); + entry.decal = tableData.getIntField("decal", -1); + entry.offsetGroupID = tableData.getIntField("offsetGroupID", -1); + entry.buildTypes = tableData.getIntField("buildTypes", -1); + entry.reqPrecondition = tableData.getStringField("reqPrecondition", ""); + entry.animationFlag = tableData.getIntField("animationFlag", 0); + entry.equipEffects = tableData.getIntField("equipEffects", -1); + entry.readyForQA = tableData.getIntField("readyForQA", -1) == 1 ? true : false; + entry.itemRating = tableData.getIntField("itemRating", -1); + entry.isTwoHanded = tableData.getIntField("isTwoHanded", -1) == 1 ? true : false; + entry.minNumRequired = tableData.getIntField("minNumRequired", -1); + entry.delResIndex = tableData.getIntField("delResIndex", -1); + entry.currencyLOT = tableData.getIntField("currencyLOT", -1); + entry.altCurrencyCost = tableData.getIntField("altCurrencyCost", -1); + entry.subItems = tableData.getStringField("subItems", ""); + entry.audioEventUse = tableData.getStringField("audioEventUse", ""); + entry.noEquipAnimation = tableData.getIntField("noEquipAnimation", -1) == 1 ? true : false; + entry.commendationLOT = tableData.getIntField("commendationLOT", -1); + entry.commendationCost = tableData.getIntField("commendationCost", -1); + entry.audioEquipMetaEventSet = tableData.getStringField("audioEquipMetaEventSet", ""); + entry.currencyCosts = tableData.getStringField("currencyCosts", ""); + entry.ingredientInfo = tableData.getStringField("ingredientInfo", ""); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.forgeType = tableData.getIntField("forgeType", -1); + entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); this->entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); @@ -74,14 +74,6 @@ CDItemComponentTable::CDItemComponentTable(void) { #endif } -//! Destructor -CDItemComponentTable::~CDItemComponentTable(void) {} - -//! Returns the table's name -std::string CDItemComponentTable::GetName(void) const { - return "ItemComponent"; -} - const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int skillID) { const auto& it = this->entries.find(skillID); if (it != this->entries.end()) { @@ -101,48 +93,48 @@ const CDItemComponent& CDItemComponentTable::GetItemComponentByID(unsigned int s while (!tableData.eof()) { CDItemComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.equipLocation = tableData.getStringField(1, ""); - entry.baseValue = tableData.getIntField(2, -1); - entry.isKitPiece = tableData.getIntField(3, -1) == 1 ? true : false; - entry.rarity = tableData.getIntField(4, 0); - entry.itemType = tableData.getIntField(5, -1); - entry.itemInfo = tableData.getInt64Field(6, -1); - entry.inLootTable = tableData.getIntField(7, -1) == 1 ? true : false; - entry.inVendor = tableData.getIntField(8, -1) == 1 ? true : false; - entry.isUnique = tableData.getIntField(9, -1) == 1 ? true : false; - entry.isBOP = tableData.getIntField(10, -1) == 1 ? true : false; - entry.isBOE = tableData.getIntField(11, -1) == 1 ? true : false; - entry.reqFlagID = tableData.getIntField(12, -1); - entry.reqSpecialtyID = tableData.getIntField(13, -1); - entry.reqSpecRank = tableData.getIntField(14, -1); - entry.reqAchievementID = tableData.getIntField(15, -1); - entry.stackSize = tableData.getIntField(16, -1); - entry.color1 = tableData.getIntField(17, -1); - entry.decal = tableData.getIntField(18, -1); - entry.offsetGroupID = tableData.getIntField(19, -1); - entry.buildTypes = tableData.getIntField(20, -1); - entry.reqPrecondition = tableData.getStringField(21, ""); - entry.animationFlag = tableData.getIntField(22, 0); - entry.equipEffects = tableData.getIntField(23, -1); - entry.readyForQA = tableData.getIntField(24, -1) == 1 ? true : false; - entry.itemRating = tableData.getIntField(25, -1); - entry.isTwoHanded = tableData.getIntField(26, -1) == 1 ? true : false; - entry.minNumRequired = tableData.getIntField(27, -1); - entry.delResIndex = tableData.getIntField(28, -1); - entry.currencyLOT = tableData.getIntField(29, -1); - entry.altCurrencyCost = tableData.getIntField(30, -1); - entry.subItems = tableData.getStringField(31, ""); - UNUSED(entry.audioEventUse = tableData.getStringField(32, "")); - entry.noEquipAnimation = tableData.getIntField(33, -1) == 1 ? true : false; - entry.commendationLOT = tableData.getIntField(34, -1); - entry.commendationCost = tableData.getIntField(35, -1); - UNUSED(entry.audioEquipMetaEventSet = tableData.getStringField(36, "")); - entry.currencyCosts = tableData.getStringField(37, ""); - UNUSED(entry.ingredientInfo = tableData.getStringField(38, "")); - entry.locStatus = tableData.getIntField(39, -1); - entry.forgeType = tableData.getIntField(40, -1); - entry.SellMultiplier = tableData.getFloatField(41, -1.0f); + entry.id = tableData.getIntField("id", -1); + entry.equipLocation = tableData.getStringField("equipLocation", ""); + entry.baseValue = tableData.getIntField("baseValue", -1); + entry.isKitPiece = tableData.getIntField("isKitPiece", -1) == 1 ? true : false; + entry.rarity = tableData.getIntField("rarity", 0); + entry.itemType = tableData.getIntField("itemType", -1); + entry.itemInfo = tableData.getInt64Field("itemInfo", -1); + entry.inLootTable = tableData.getIntField("inLootTable", -1) == 1 ? true : false; + entry.inVendor = tableData.getIntField("inVendor", -1) == 1 ? true : false; + entry.isUnique = tableData.getIntField("isUnique", -1) == 1 ? true : false; + entry.isBOP = tableData.getIntField("isBOP", -1) == 1 ? true : false; + entry.isBOE = tableData.getIntField("isBOE", -1) == 1 ? true : false; + entry.reqFlagID = tableData.getIntField("reqFlagID", -1); + entry.reqSpecialtyID = tableData.getIntField("reqSpecialtyID", -1); + entry.reqSpecRank = tableData.getIntField("reqSpecRank", -1); + entry.reqAchievementID = tableData.getIntField("reqAchievementID", -1); + entry.stackSize = tableData.getIntField("stackSize", -1); + entry.color1 = tableData.getIntField("color1", -1); + entry.decal = tableData.getIntField("decal", -1); + entry.offsetGroupID = tableData.getIntField("offsetGroupID", -1); + entry.buildTypes = tableData.getIntField("buildTypes", -1); + entry.reqPrecondition = tableData.getStringField("reqPrecondition", ""); + entry.animationFlag = tableData.getIntField("animationFlag", 0); + entry.equipEffects = tableData.getIntField("equipEffects", -1); + entry.readyForQA = tableData.getIntField("readyForQA", -1) == 1 ? true : false; + entry.itemRating = tableData.getIntField("itemRating", -1); + entry.isTwoHanded = tableData.getIntField("isTwoHanded", -1) == 1 ? true : false; + entry.minNumRequired = tableData.getIntField("minNumRequired", -1); + entry.delResIndex = tableData.getIntField("delResIndex", -1); + entry.currencyLOT = tableData.getIntField("currencyLOT", -1); + entry.altCurrencyCost = tableData.getIntField("altCurrencyCost", -1); + entry.subItems = tableData.getStringField("subItems", ""); + UNUSED(entry.audioEventUse = tableData.getStringField("audioEventUse", "")); + entry.noEquipAnimation = tableData.getIntField("noEquipAnimation", -1) == 1 ? true : false; + entry.commendationLOT = tableData.getIntField("commendationLOT", -1); + entry.commendationCost = tableData.getIntField("commendationCost", -1); + UNUSED(entry.audioEquipMetaEventSet = tableData.getStringField("audioEquipMetaEventSet", "")); + entry.currencyCosts = tableData.getStringField("currencyCosts", ""); + UNUSED(entry.ingredientInfo = tableData.getStringField("ingredientInfo", "")); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.forgeType = tableData.getIntField("forgeType", -1); + entry.SellMultiplier = tableData.getFloatField("SellMultiplier", -1.0f); this->entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); @@ -177,3 +169,4 @@ std::map CDItemComponentTable::ParseCraftingCurrencies(const CDIt return currencies; } + diff --git a/dDatabase/Tables/CDItemComponentTable.h b/dDatabase/Tables/CDItemComponentTable.h index b3a2a5f4..11c34dd6 100644 --- a/dDatabase/Tables/CDItemComponentTable.h +++ b/dDatabase/Tables/CDItemComponentTable.h @@ -4,12 +4,6 @@ #include "CDTable.h" #include "dCommonVars.h" -/*! - \file CDItemComponentTable.hpp - \brief Contains data for the ItemComponent table - */ - - //! ItemComponent Struct struct CDItemComponent { unsigned int id; //!< The Component ID std::string equipLocation; //!< The equip location @@ -55,28 +49,15 @@ struct CDItemComponent { float SellMultiplier; //!< Something to do with early vendors perhaps (but replaced) }; -//! ItemComponent table -class CDItemComponentTable : public CDTable { +class CDItemComponentTable : public CDTable { private: std::map entries; public: - - //! Constructor - CDItemComponentTable(void); - - //! Destructor - ~CDItemComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - + CDItemComponentTable(); static std::map ParseCraftingCurrencies(const CDItemComponent& itemComponent); - //! Gets an entry by ID + // Gets an entry by ID const CDItemComponent& GetItemComponentByID(unsigned int skillID); static CDItemComponent Default; diff --git a/dDatabase/Tables/CDItemSetSkillsTable.cpp b/dDatabase/Tables/CDItemSetSkillsTable.cpp index e94cf527..f6b412ff 100644 --- a/dDatabase/Tables/CDItemSetSkillsTable.cpp +++ b/dDatabase/Tables/CDItemSetSkillsTable.cpp @@ -21,9 +21,9 @@ CDItemSetSkillsTable::CDItemSetSkillsTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSetSkills"); while (!tableData.eof()) { CDItemSetSkills entry; - entry.SkillSetID = tableData.getIntField(0, -1); - entry.SkillID = tableData.getIntField(1, -1); - entry.SkillCastType = tableData.getIntField(2, -1); + entry.SkillSetID = tableData.getIntField("SkillSetID", -1); + entry.SkillID = tableData.getIntField("SkillID", -1); + entry.SkillCastType = tableData.getIntField("SkillCastType", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -32,15 +32,6 @@ CDItemSetSkillsTable::CDItemSetSkillsTable(void) { tableData.finalize(); } -//! Destructor -CDItemSetSkillsTable::~CDItemSetSkillsTable(void) {} - -//! Returns the table's name -std::string CDItemSetSkillsTable::GetName(void) const { - return "ItemSetSkills"; -} - -//! Queries the table with a custom "where" clause std::vector CDItemSetSkillsTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -50,7 +41,6 @@ std::vector CDItemSetSkillsTable::Query(std::function CDItemSetSkillsTable::GetEntries(void) const { return this->entries; } diff --git a/dDatabase/Tables/CDItemSetSkillsTable.h b/dDatabase/Tables/CDItemSetSkillsTable.h index bf05eea9..8328c66b 100644 --- a/dDatabase/Tables/CDItemSetSkillsTable.h +++ b/dDatabase/Tables/CDItemSetSkillsTable.h @@ -3,50 +3,22 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDItemSetSkillsTable.hpp - \brief Contains data for the ItemSetSkills table - */ - - //! ZoneTable Struct struct CDItemSetSkills { unsigned int SkillSetID; //!< The skill set ID unsigned int SkillID; //!< The skill ID unsigned int SkillCastType; //!< The skill cast type }; -//! ItemSets table -class CDItemSetSkillsTable : public CDTable { +class CDItemSetSkillsTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDItemSetSkillsTable(void); - - //! Destructor - ~CDItemSetSkillsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDItemSetSkillsTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; std::vector GetBySkillID(unsigned int SkillSetID); - }; - diff --git a/dDatabase/Tables/CDItemSetsTable.cpp b/dDatabase/Tables/CDItemSetsTable.cpp index 606e0cf9..0632ef13 100644 --- a/dDatabase/Tables/CDItemSetsTable.cpp +++ b/dDatabase/Tables/CDItemSetsTable.cpp @@ -21,21 +21,21 @@ CDItemSetsTable::CDItemSetsTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ItemSets"); while (!tableData.eof()) { CDItemSets entry; - entry.setID = tableData.getIntField(0, -1); - entry.locStatus = tableData.getIntField(1, -1); - entry.itemIDs = tableData.getStringField(2, ""); - entry.kitType = tableData.getIntField(3, -1); - entry.kitRank = tableData.getIntField(4, -1); - entry.kitImage = tableData.getIntField(5, -1); - entry.skillSetWith2 = tableData.getIntField(6, -1); - entry.skillSetWith3 = tableData.getIntField(7, -1); - entry.skillSetWith4 = tableData.getIntField(8, -1); - entry.skillSetWith5 = tableData.getIntField(9, -1); - entry.skillSetWith6 = tableData.getIntField(10, -1); - entry.localize = tableData.getIntField(11, -1) == 1 ? true : false; - entry.gate_version = tableData.getStringField(12, ""); - entry.kitID = tableData.getIntField(13, -1); - entry.priority = tableData.getFloatField(14, -1.0f); + entry.setID = tableData.getIntField("setID", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.itemIDs = tableData.getStringField("itemIDs", ""); + entry.kitType = tableData.getIntField("kitType", -1); + entry.kitRank = tableData.getIntField("kitRank", -1); + entry.kitImage = tableData.getIntField("kitImage", -1); + entry.skillSetWith2 = tableData.getIntField("skillSetWith2", -1); + entry.skillSetWith3 = tableData.getIntField("skillSetWith3", -1); + entry.skillSetWith4 = tableData.getIntField("skillSetWith4", -1); + entry.skillSetWith5 = tableData.getIntField("skillSetWith5", -1); + entry.skillSetWith6 = tableData.getIntField("skillSetWith6", -1); + entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false; + entry.gate_version = tableData.getStringField("gate_version", ""); + entry.kitID = tableData.getIntField("kitID", -1); + entry.priority = tableData.getFloatField("priority", -1.0f); this->entries.push_back(entry); tableData.nextRow(); @@ -44,15 +44,6 @@ CDItemSetsTable::CDItemSetsTable(void) { tableData.finalize(); } -//! Destructor -CDItemSetsTable::~CDItemSetsTable(void) {} - -//! Returns the table's name -std::string CDItemSetsTable::GetName(void) const { - return "ItemSets"; -} - -//! Queries the table with a custom "where" clause std::vector CDItemSetsTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -62,7 +53,7 @@ std::vector CDItemSetsTable::Query(std::function p return data; } -//! Gets all the entries in the table std::vector CDItemSetsTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDItemSetsTable.h b/dDatabase/Tables/CDItemSetsTable.h index ef12c7b4..6756e7fa 100644 --- a/dDatabase/Tables/CDItemSetsTable.h +++ b/dDatabase/Tables/CDItemSetsTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDItemSetsTable.hpp - \brief Contains data for the ItemSets table - */ - - //! ZoneTable Struct struct CDItemSets { unsigned int setID; //!< The item set ID unsigned int locStatus; //!< The loc status @@ -27,36 +21,15 @@ struct CDItemSets { float priority; //!< The priority }; -//! ItemSets table -class CDItemSetsTable : public CDTable { +class CDItemSetsTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDItemSetsTable(void); - - //! Destructor - ~CDItemSetsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDItemSetsTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDLevelProgressionLookupTable.cpp b/dDatabase/Tables/CDLevelProgressionLookupTable.cpp index 121c9f62..47a8fc0e 100644 --- a/dDatabase/Tables/CDLevelProgressionLookupTable.cpp +++ b/dDatabase/Tables/CDLevelProgressionLookupTable.cpp @@ -21,9 +21,9 @@ CDLevelProgressionLookupTable::CDLevelProgressionLookupTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LevelProgressionLookup"); while (!tableData.eof()) { CDLevelProgressionLookup entry; - entry.id = tableData.getIntField(0, -1); - entry.requiredUScore = tableData.getIntField(1, -1); - entry.BehaviorEffect = tableData.getStringField(2, ""); + entry.id = tableData.getIntField("id", -1); + entry.requiredUScore = tableData.getIntField("requiredUScore", -1); + entry.BehaviorEffect = tableData.getStringField("BehaviorEffect", ""); this->entries.push_back(entry); tableData.nextRow(); @@ -32,14 +32,6 @@ CDLevelProgressionLookupTable::CDLevelProgressionLookupTable(void) { tableData.finalize(); } -//! Destructor -CDLevelProgressionLookupTable::~CDLevelProgressionLookupTable(void) {} - -//! Returns the table's name -std::string CDLevelProgressionLookupTable::GetName(void) const { - return "LevelProgressionLookup"; -} - //! Queries the table with a custom "where" clause std::vector CDLevelProgressionLookupTable::Query(std::function predicate) { @@ -54,3 +46,4 @@ std::vector CDLevelProgressionLookupTable::Query(std:: std::vector CDLevelProgressionLookupTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDLevelProgressionLookupTable.h b/dDatabase/Tables/CDLevelProgressionLookupTable.h index 391c9b37..070b2e0c 100644 --- a/dDatabase/Tables/CDLevelProgressionLookupTable.h +++ b/dDatabase/Tables/CDLevelProgressionLookupTable.h @@ -3,47 +3,21 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDLevelProgressionLookupTable.hpp - \brief Contains data for the LevelProgressionLookup table - */ - - //! LevelProgressionLookup Entry Struct struct CDLevelProgressionLookup { unsigned int id; //!< The Level ID unsigned int requiredUScore; //!< The required LEGO Score std::string BehaviorEffect; //!< The behavior effect attached to this }; -//! LevelProgressionLookup table -class CDLevelProgressionLookupTable : public CDTable { +class CDLevelProgressionLookupTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDLevelProgressionLookupTable(void); - - //! Destructor - ~CDLevelProgressionLookupTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDLevelProgressionLookupTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ + // Gets all the entries in the table std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDLootMatrixTable.cpp b/dDatabase/Tables/CDLootMatrixTable.cpp index d47c081b..8f25e8a3 100644 --- a/dDatabase/Tables/CDLootMatrixTable.cpp +++ b/dDatabase/Tables/CDLootMatrixTable.cpp @@ -21,15 +21,15 @@ CDLootMatrixTable::CDLootMatrixTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix"); while (!tableData.eof()) { CDLootMatrix entry; - entry.LootMatrixIndex = tableData.getIntField(0, -1); - entry.LootTableIndex = tableData.getIntField(1, -1); - entry.RarityTableIndex = tableData.getIntField(2, -1); - entry.percent = tableData.getFloatField(3, -1.0f); - entry.minToDrop = tableData.getIntField(4, -1); - entry.maxToDrop = tableData.getIntField(5, -1); - entry.id = tableData.getIntField(6, -1); - entry.flagID = tableData.getIntField(7, -1); - UNUSED(entry.gate_version = tableData.getStringField(8, "")); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); + entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1); + entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1); + entry.percent = tableData.getFloatField("percent", -1.0f); + entry.minToDrop = tableData.getIntField("minToDrop", -1); + entry.maxToDrop = tableData.getIntField("maxToDrop", -1); + entry.id = tableData.getIntField("id", -1); + entry.flagID = tableData.getIntField("flagID", -1); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); this->entries.push_back(entry); tableData.nextRow(); @@ -38,15 +38,6 @@ CDLootMatrixTable::CDLootMatrixTable(void) { tableData.finalize(); } -//! Destructor -CDLootMatrixTable::~CDLootMatrixTable(void) {} - -//! Returns the table's name -std::string CDLootMatrixTable::GetName(void) const { - return "LootMatrix"; -} - -//! Queries the table with a custom "where" clause std::vector CDLootMatrixTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -56,7 +47,7 @@ std::vector CDLootMatrixTable::Query(std::function& CDLootMatrixTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDLootMatrixTable.h b/dDatabase/Tables/CDLootMatrixTable.h index 7d311b3b..c6035841 100644 --- a/dDatabase/Tables/CDLootMatrixTable.h +++ b/dDatabase/Tables/CDLootMatrixTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDLootMatrixTable.hpp - \brief Contains data for the ObjectSkills table - */ - - //! LootMatrix Struct struct CDLootMatrix { unsigned int LootMatrixIndex; //!< The Loot Matrix Index unsigned int LootTableIndex; //!< The Loot Table Index @@ -21,36 +15,15 @@ struct CDLootMatrix { UNUSED(std::string gate_version); //!< The Gate Version }; -//! MissionNPCComponent table -class CDLootMatrixTable : public CDTable { +class CDLootMatrixTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDLootMatrixTable(void); - - //! Destructor - ~CDLootMatrixTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDLootMatrixTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ const std::vector& GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDLootTableTable.cpp b/dDatabase/Tables/CDLootTableTable.cpp index da8c824b..0a46784a 100644 --- a/dDatabase/Tables/CDLootTableTable.cpp +++ b/dDatabase/Tables/CDLootTableTable.cpp @@ -21,12 +21,12 @@ CDLootTableTable::CDLootTableTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable"); while (!tableData.eof()) { CDLootTable entry; - entry.id = tableData.getIntField(0, -1); - entry.itemid = tableData.getIntField(0, -1); - entry.LootTableIndex = tableData.getIntField(1, -1); - entry.id = tableData.getIntField(2, -1); - entry.MissionDrop = tableData.getIntField(3, -1) == 1 ? true : false; - entry.sortPriority = tableData.getIntField(4, -1); + entry.id = tableData.getIntField("id", -1); + entry.itemid = tableData.getIntField("itemid", -1); + entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1); + entry.id = tableData.getIntField("id", -1); + entry.MissionDrop = tableData.getIntField("MissionDrop", -1) == 1 ? true : false; + entry.sortPriority = tableData.getIntField("sortPriority", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -35,14 +35,6 @@ CDLootTableTable::CDLootTableTable(void) { tableData.finalize(); } -//! Destructor -CDLootTableTable::~CDLootTableTable(void) {} - -//! Returns the table's name -std::string CDLootTableTable::GetName(void) const { - return "LootTable"; -} - //! Queries the table with a custom "where" clause std::vector CDLootTableTable::Query(std::function predicate) { @@ -57,3 +49,4 @@ std::vector CDLootTableTable::Query(std::function& CDLootTableTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDLootTableTable.h b/dDatabase/Tables/CDLootTableTable.h index 3f1baf60..ba6f207e 100644 --- a/dDatabase/Tables/CDLootTableTable.h +++ b/dDatabase/Tables/CDLootTableTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDLootTableTable.hpp - \brief Contains data for the LootTable table - */ - - //! LootTable Struct struct CDLootTable { unsigned int itemid; //!< The LOT of the item unsigned int LootTableIndex; //!< The Loot Table Index @@ -17,36 +11,15 @@ struct CDLootTable { unsigned int sortPriority; //!< The sorting priority }; -//! LootTable table -class CDLootTableTable : public CDTable { +class CDLootTableTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDLootTableTable(void); - - //! Destructor - ~CDLootTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDLootTableTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ const std::vector& GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDMissionEmailTable.cpp b/dDatabase/Tables/CDMissionEmailTable.cpp index a8beb95b..ed855d8a 100644 --- a/dDatabase/Tables/CDMissionEmailTable.cpp +++ b/dDatabase/Tables/CDMissionEmailTable.cpp @@ -21,14 +21,14 @@ CDMissionEmailTable::CDMissionEmailTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionEmail"); while (!tableData.eof()) { CDMissionEmail entry; - entry.ID = tableData.getIntField(0, -1); - entry.messageType = tableData.getIntField(1, -1); - entry.notificationGroup = tableData.getIntField(2, -1); - entry.missionID = tableData.getIntField(3, -1); - entry.attachmentLOT = tableData.getIntField(4, 0); - entry.localize = (bool)tableData.getIntField(5, -1); - entry.locStatus = tableData.getIntField(6, -1); - entry.gate_version = tableData.getStringField(7, ""); + entry.ID = tableData.getIntField("ID", -1); + entry.messageType = tableData.getIntField("messageType", -1); + entry.notificationGroup = tableData.getIntField("notificationGroup", -1); + entry.missionID = tableData.getIntField("missionID", -1); + entry.attachmentLOT = tableData.getIntField("attachmentLOT", 0); + entry.localize = (bool)tableData.getIntField("localize", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.gate_version = tableData.getStringField("gate_version", ""); this->entries.push_back(entry); tableData.nextRow(); @@ -37,14 +37,6 @@ CDMissionEmailTable::CDMissionEmailTable(void) { tableData.finalize(); } -//! Destructor -CDMissionEmailTable::~CDMissionEmailTable(void) {} - -//! Returns the table's name -std::string CDMissionEmailTable::GetName(void) const { - return "MissionEmail"; -} - //! Queries the table with a custom "where" clause std::vector CDMissionEmailTable::Query(std::function predicate) { @@ -59,3 +51,4 @@ std::vector CDMissionEmailTable::Query(std::function CDMissionEmailTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDMissionEmailTable.h b/dDatabase/Tables/CDMissionEmailTable.h index 81a7a793..db2310d4 100644 --- a/dDatabase/Tables/CDMissionEmailTable.h +++ b/dDatabase/Tables/CDMissionEmailTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDMissionEmailTable.hpp - \brief Contains data for the MissionEmail table - */ - - //! MissionEmail Entry Struct struct CDMissionEmail { unsigned int ID; unsigned int messageType; @@ -21,35 +15,14 @@ struct CDMissionEmail { }; -//! MissionEmail table -class CDMissionEmailTable : public CDTable { +class CDMissionEmailTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDMissionEmailTable(void); - - //! Destructor - ~CDMissionEmailTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDMissionEmailTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDMissionNPCComponentTable.cpp b/dDatabase/Tables/CDMissionNPCComponentTable.cpp index e2589890..5672ed67 100644 --- a/dDatabase/Tables/CDMissionNPCComponentTable.cpp +++ b/dDatabase/Tables/CDMissionNPCComponentTable.cpp @@ -21,11 +21,11 @@ CDMissionNPCComponentTable::CDMissionNPCComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent"); while (!tableData.eof()) { CDMissionNPCComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.missionID = tableData.getIntField(1, -1); - entry.offersMission = tableData.getIntField(2, -1) == 1 ? true : false; - entry.acceptsMission = tableData.getIntField(3, -1) == 1 ? true : false; - entry.gate_version = tableData.getStringField(4, ""); + entry.id = tableData.getIntField("id", -1); + entry.missionID = tableData.getIntField("missionID", -1); + entry.offersMission = tableData.getIntField("offersMission", -1) == 1 ? true : false; + entry.acceptsMission = tableData.getIntField("acceptsMission", -1) == 1 ? true : false; + entry.gate_version = tableData.getStringField("gate_version", ""); this->entries.push_back(entry); tableData.nextRow(); @@ -34,14 +34,6 @@ CDMissionNPCComponentTable::CDMissionNPCComponentTable(void) { tableData.finalize(); } -//! Destructor -CDMissionNPCComponentTable::~CDMissionNPCComponentTable(void) {} - -//! Returns the table's name -std::string CDMissionNPCComponentTable::GetName(void) const { - return "MissionNPCComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDMissionNPCComponentTable::Query(std::function predicate) { @@ -56,3 +48,4 @@ std::vector CDMissionNPCComponentTable::Query(std::functi std::vector CDMissionNPCComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDMissionNPCComponentTable.h b/dDatabase/Tables/CDMissionNPCComponentTable.h index 68c94ef0..a7aeb145 100644 --- a/dDatabase/Tables/CDMissionNPCComponentTable.h +++ b/dDatabase/Tables/CDMissionNPCComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDMissionNPCComponentTable.hpp - \brief Contains data for the ObjectSkills table - */ - - //! MissionNPCComponent Struct struct CDMissionNPCComponent { unsigned int id; //!< The ID unsigned int missionID; //!< The Mission ID @@ -17,35 +11,16 @@ struct CDMissionNPCComponent { std::string gate_version; //!< The gate version }; -//! MissionNPCComponent table -class CDMissionNPCComponentTable : public CDTable { +class CDMissionNPCComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDMissionNPCComponentTable(void); - - //! Destructor - ~CDMissionNPCComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDMissionNPCComponentTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ + // Gets all the entries in the table std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDMissionTasksTable.cpp b/dDatabase/Tables/CDMissionTasksTable.cpp index 81de2088..f32dca1b 100644 --- a/dDatabase/Tables/CDMissionTasksTable.cpp +++ b/dDatabase/Tables/CDMissionTasksTable.cpp @@ -21,19 +21,19 @@ CDMissionTasksTable::CDMissionTasksTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionTasks"); while (!tableData.eof()) { CDMissionTasks entry; - entry.id = tableData.getIntField(0, -1); - UNUSED(entry.locStatus = tableData.getIntField(1, -1)); - entry.taskType = tableData.getIntField(2, -1); - entry.target = tableData.getIntField(3, -1); - entry.targetGroup = tableData.getStringField(4, ""); - entry.targetValue = tableData.getIntField(5, -1); - entry.taskParam1 = tableData.getStringField(6, ""); - UNUSED(entry.largeTaskIcon = tableData.getStringField(7, "")); - UNUSED(entry.IconID = tableData.getIntField(8, -1)); - entry.uid = tableData.getIntField(9, -1); - UNUSED(entry.largeTaskIconID = tableData.getIntField(10, -1)); - UNUSED(entry.localize = tableData.getIntField(11, -1) == 1 ? true : false); - UNUSED(entry.gate_version = tableData.getStringField(12, "")); + entry.id = tableData.getIntField("id", -1); + UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); + entry.taskType = tableData.getIntField("taskType", -1); + entry.target = tableData.getIntField("target", -1); + entry.targetGroup = tableData.getStringField("targetGroup", ""); + entry.targetValue = tableData.getIntField("targetValue", -1); + entry.taskParam1 = tableData.getStringField("taskParam1", ""); + UNUSED(entry.largeTaskIcon = tableData.getStringField("largeTaskIcon", "")); + UNUSED(entry.IconID = tableData.getIntField("IconID", -1)); + entry.uid = tableData.getIntField("uid", -1); + UNUSED(entry.largeTaskIconID = tableData.getIntField("largeTaskIconID", -1)); + UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); this->entries.push_back(entry); tableData.nextRow(); @@ -42,15 +42,6 @@ CDMissionTasksTable::CDMissionTasksTable(void) { tableData.finalize(); } -//! Destructor -CDMissionTasksTable::~CDMissionTasksTable(void) {} - -//! Returns the table's name -std::string CDMissionTasksTable::GetName(void) const { - return "MissionTasks"; -} - -//! Queries the table with a custom "where" clause std::vector CDMissionTasksTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -74,7 +65,7 @@ std::vector CDMissionTasksTable::GetByMissionID(uint32_t missio return tasks; } -//! Gets all the entries in the table const std::vector& CDMissionTasksTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDMissionTasksTable.h b/dDatabase/Tables/CDMissionTasksTable.h index 1a4bd361..fa213faf 100644 --- a/dDatabase/Tables/CDMissionTasksTable.h +++ b/dDatabase/Tables/CDMissionTasksTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDMissionTasksTable.hpp - \brief Contains data for the MissionTasks table - */ - - //! ObjectSkills Struct struct CDMissionTasks { unsigned int id; //!< The Mission ID that the task belongs to UNUSED(unsigned int locStatus); //!< ??? @@ -25,37 +19,17 @@ struct CDMissionTasks { UNUSED(std::string gate_version); //!< ??? }; -//! ObjectSkills table -class CDMissionTasksTable : public CDTable { +class CDMissionTasksTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDMissionTasksTable(void); - - //! Destructor - ~CDMissionTasksTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDMissionTasksTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); std::vector GetByMissionID(uint32_t missionID); - //! Gets all the entries in the table - /*! - \return The entries - */ const std::vector& GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDMissionsTable.cpp b/dDatabase/Tables/CDMissionsTable.cpp index 7e59657d..d4ee40ae 100644 --- a/dDatabase/Tables/CDMissionsTable.cpp +++ b/dDatabase/Tables/CDMissionsTable.cpp @@ -23,58 +23,58 @@ CDMissionsTable::CDMissionsTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Missions"); while (!tableData.eof()) { CDMissions entry; - entry.id = tableData.getIntField(0, -1); - entry.defined_type = tableData.getStringField(1, ""); - entry.defined_subtype = tableData.getStringField(2, ""); - entry.UISortOrder = tableData.getIntField(3, -1); - entry.offer_objectID = tableData.getIntField(4, -1); - entry.target_objectID = tableData.getIntField(5, -1); - entry.reward_currency = tableData.getInt64Field(6, -1); - entry.LegoScore = tableData.getIntField(7, -1); - entry.reward_reputation = tableData.getIntField(8, -1); - entry.isChoiceReward = tableData.getIntField(9, -1) == 1 ? true : false; - entry.reward_item1 = tableData.getIntField(10, 0); - entry.reward_item1_count = tableData.getIntField(11, 0); - entry.reward_item2 = tableData.getIntField(12, 0); - entry.reward_item2_count = tableData.getIntField(13, 0); - entry.reward_item3 = tableData.getIntField(14, 0); - entry.reward_item3_count = tableData.getIntField(15, 0); - entry.reward_item4 = tableData.getIntField(16, 0); - entry.reward_item4_count = tableData.getIntField(17, 0); - entry.reward_emote = tableData.getIntField(18, -1); - entry.reward_emote2 = tableData.getIntField(19, -1); - entry.reward_emote3 = tableData.getIntField(20, -1); - entry.reward_emote4 = tableData.getIntField(21, -1); - entry.reward_maximagination = tableData.getIntField(22, -1); - entry.reward_maxhealth = tableData.getIntField(23, -1); - entry.reward_maxinventory = tableData.getIntField(24, -1); - entry.reward_maxmodel = tableData.getIntField(25, -1); - entry.reward_maxwidget = tableData.getIntField(26, -1); - entry.reward_maxwallet = tableData.getIntField(27, -1); - entry.repeatable = tableData.getIntField(28, -1) == 1 ? true : false; - entry.reward_currency_repeatable = tableData.getIntField(29, -1); - entry.reward_item1_repeatable = tableData.getIntField(30, -1); - entry.reward_item1_repeat_count = tableData.getIntField(31, -1); - entry.reward_item2_repeatable = tableData.getIntField(32, -1); - entry.reward_item2_repeat_count = tableData.getIntField(33, -1); - entry.reward_item3_repeatable = tableData.getIntField(34, -1); - entry.reward_item3_repeat_count = tableData.getIntField(35, -1); - entry.reward_item4_repeatable = tableData.getIntField(36, -1); - entry.reward_item4_repeat_count = tableData.getIntField(37, -1); - entry.time_limit = tableData.getIntField(38, -1); - entry.isMission = tableData.getIntField(39, -1) ? true : false; - entry.missionIconID = tableData.getIntField(40, -1); - entry.prereqMissionID = tableData.getStringField(41, ""); - entry.localize = tableData.getIntField(42, -1) == 1 ? true : false; - entry.inMOTD = tableData.getIntField(43, -1) == 1 ? true : false; - entry.cooldownTime = tableData.getInt64Field(44, -1); - entry.isRandom = tableData.getIntField(45, -1) == 1 ? true : false; - entry.randomPool = tableData.getStringField(46, ""); - entry.UIPrereqID = tableData.getIntField(47, -1); - UNUSED(entry.gate_version = tableData.getStringField(48, "")); - UNUSED(entry.HUDStates = tableData.getStringField(49, "")); - UNUSED(entry.locStatus = tableData.getIntField(50, -1)); - entry.reward_bankinventory = tableData.getIntField(51, -1); + entry.id = tableData.getIntField("id", -1); + entry.defined_type = tableData.getStringField("defined_type", ""); + entry.defined_subtype = tableData.getStringField("defined_subtype", ""); + entry.UISortOrder = tableData.getIntField("UISortOrder", -1); + entry.offer_objectID = tableData.getIntField("offer_objectID", -1); + entry.target_objectID = tableData.getIntField("target_objectID", -1); + entry.reward_currency = tableData.getInt64Field("reward_currency", -1); + entry.LegoScore = tableData.getIntField("LegoScore", -1); + entry.reward_reputation = tableData.getIntField("reward_reputation", -1); + entry.isChoiceReward = tableData.getIntField("isChoiceReward", -1) == 1 ? true : false; + entry.reward_item1 = tableData.getIntField("reward_item1", 0); + entry.reward_item1_count = tableData.getIntField("reward_item1_count", 0); + entry.reward_item2 = tableData.getIntField("reward_item2", 0); + entry.reward_item2_count = tableData.getIntField("reward_item2_count", 0); + entry.reward_item3 = tableData.getIntField("reward_item3", 0); + entry.reward_item3_count = tableData.getIntField("reward_item3_count", 0); + entry.reward_item4 = tableData.getIntField("reward_item4", 0); + entry.reward_item4_count = tableData.getIntField("reward_item4_count", 0); + entry.reward_emote = tableData.getIntField("reward_emote", -1); + entry.reward_emote2 = tableData.getIntField("reward_emote2", -1); + entry.reward_emote3 = tableData.getIntField("reward_emote3", -1); + entry.reward_emote4 = tableData.getIntField("reward_emote4", -1); + entry.reward_maximagination = tableData.getIntField("reward_maximagination", -1); + entry.reward_maxhealth = tableData.getIntField("reward_maxhealth", -1); + entry.reward_maxinventory = tableData.getIntField("reward_maxinventory", -1); + entry.reward_maxmodel = tableData.getIntField("reward_maxmodel", -1); + entry.reward_maxwidget = tableData.getIntField("reward_maxwidget", -1); + entry.reward_maxwallet = tableData.getIntField("reward_maxwallet", -1); + entry.repeatable = tableData.getIntField("repeatable", -1) == 1 ? true : false; + entry.reward_currency_repeatable = tableData.getIntField("reward_currency_repeatable", -1); + entry.reward_item1_repeatable = tableData.getIntField("reward_item1_repeatable", -1); + entry.reward_item1_repeat_count = tableData.getIntField("reward_item1_repeat_count", -1); + entry.reward_item2_repeatable = tableData.getIntField("reward_item2_repeatable", -1); + entry.reward_item2_repeat_count = tableData.getIntField("reward_item2_repeat_count", -1); + entry.reward_item3_repeatable = tableData.getIntField("reward_item3_repeatable", -1); + entry.reward_item3_repeat_count = tableData.getIntField("reward_item3_repeat_count", -1); + entry.reward_item4_repeatable = tableData.getIntField("reward_item4_repeatable", -1); + entry.reward_item4_repeat_count = tableData.getIntField("reward_item4_repeat_count", -1); + entry.time_limit = tableData.getIntField("time_limit", -1); + entry.isMission = tableData.getIntField("isMission", -1) ? true : false; + entry.missionIconID = tableData.getIntField("missionIconID", -1); + entry.prereqMissionID = tableData.getStringField("prereqMissionID", ""); + entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false; + entry.inMOTD = tableData.getIntField("inMOTD", -1) == 1 ? true : false; + entry.cooldownTime = tableData.getInt64Field("cooldownTime", -1); + entry.isRandom = tableData.getIntField("isRandom", -1) == 1 ? true : false; + entry.randomPool = tableData.getStringField("randomPool", ""); + entry.UIPrereqID = tableData.getIntField("UIPrereqID", -1); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + UNUSED(entry.HUDStates = tableData.getStringField("HUDStates", "")); + UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); + entry.reward_bankinventory = tableData.getIntField("reward_bankinventory", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -85,15 +85,6 @@ CDMissionsTable::CDMissionsTable(void) { Default.id = -1; } -//! Destructor -CDMissionsTable::~CDMissionsTable(void) {} - -//! Returns the table's name -std::string CDMissionsTable::GetName(void) const { - return "Missions"; -} - -//! Queries the table with a custom "where" clause std::vector CDMissionsTable::Query(std::function predicate) { std::vector data = cpplinq::from(this->entries) @@ -103,7 +94,6 @@ std::vector CDMissionsTable::Query(std::function p return data; } -//! Gets all the entries in the table const std::vector& CDMissionsTable::GetEntries(void) const { return this->entries; } @@ -131,3 +121,4 @@ const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& foun return Default; } + diff --git a/dDatabase/Tables/CDMissionsTable.h b/dDatabase/Tables/CDMissionsTable.h index 6d1c4a8f..e6a44b02 100644 --- a/dDatabase/Tables/CDMissionsTable.h +++ b/dDatabase/Tables/CDMissionsTable.h @@ -5,12 +5,6 @@ #include #include -/*! - \file CDMissionsTable.hpp - \brief Contains data for the Missions table - */ - - //! Missions Struct struct CDMissions { int id; //!< The Mission ID std::string defined_type; //!< The type of mission @@ -66,35 +60,16 @@ struct CDMissions { int reward_bankinventory; //!< The amount of bank space this mission rewards }; -//! Missions table -class CDMissionsTable : public CDTable { +class CDMissionsTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDMissionsTable(void); - - //! Destructor - ~CDMissionsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDMissionsTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ + // Gets all the entries in the table const std::vector& GetEntries(void) const; const CDMissions* GetPtrByMissionID(uint32_t missionID) const; diff --git a/dDatabase/Tables/CDMovementAIComponentTable.cpp b/dDatabase/Tables/CDMovementAIComponentTable.cpp index a98be8ba..3b9cc4f4 100644 --- a/dDatabase/Tables/CDMovementAIComponentTable.cpp +++ b/dDatabase/Tables/CDMovementAIComponentTable.cpp @@ -21,14 +21,14 @@ CDMovementAIComponentTable::CDMovementAIComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MovementAIComponent"); while (!tableData.eof()) { CDMovementAIComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.MovementType = tableData.getStringField(1, ""); - entry.WanderChance = tableData.getFloatField(2, -1.0f); - entry.WanderDelayMin = tableData.getFloatField(3, -1.0f); - entry.WanderDelayMax = tableData.getFloatField(4, -1.0f); - entry.WanderSpeed = tableData.getFloatField(5, -1.0f); - entry.WanderRadius = tableData.getFloatField(6, -1.0f); - entry.attachedPath = tableData.getStringField(7, ""); + entry.id = tableData.getIntField("id", -1); + entry.MovementType = tableData.getStringField("MovementType", ""); + entry.WanderChance = tableData.getFloatField("WanderChance", -1.0f); + entry.WanderDelayMin = tableData.getFloatField("WanderDelayMin", -1.0f); + entry.WanderDelayMax = tableData.getFloatField("WanderDelayMax", -1.0f); + entry.WanderSpeed = tableData.getFloatField("WanderSpeed", -1.0f); + entry.WanderRadius = tableData.getFloatField("WanderRadius", -1.0f); + entry.attachedPath = tableData.getStringField("attachedPath", ""); this->entries.push_back(entry); tableData.nextRow(); @@ -37,14 +37,6 @@ CDMovementAIComponentTable::CDMovementAIComponentTable(void) { tableData.finalize(); } -//! Destructor -CDMovementAIComponentTable::~CDMovementAIComponentTable(void) {} - -//! Returns the table's name -std::string CDMovementAIComponentTable::GetName(void) const { - return "MovementAIComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDMovementAIComponentTable::Query(std::function predicate) { @@ -59,3 +51,4 @@ std::vector CDMovementAIComponentTable::Query(std::functi std::vector CDMovementAIComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDMovementAIComponentTable.h b/dDatabase/Tables/CDMovementAIComponentTable.h index 0064a98b..84896e2c 100644 --- a/dDatabase/Tables/CDMovementAIComponentTable.h +++ b/dDatabase/Tables/CDMovementAIComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDMovementAIComponentTable.hpp - \brief Contains data for the MovementAIComponent table - */ - - //! MovementAIComponent Struct struct CDMovementAIComponent { unsigned int id; std::string MovementType; @@ -20,36 +14,15 @@ struct CDMovementAIComponent { std::string attachedPath; }; -//! MovementAIComponent table -class CDMovementAIComponentTable : public CDTable { +class CDMovementAIComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDMovementAIComponentTable(void); - - //! Destructor - ~CDMovementAIComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDMovementAIComponentTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ + // Gets all the entries in the table std::vector GetEntries(void) const; - }; - diff --git a/dDatabase/Tables/CDObjectSkillsTable.cpp b/dDatabase/Tables/CDObjectSkillsTable.cpp index 1a5c4790..2e8b3fb2 100644 --- a/dDatabase/Tables/CDObjectSkillsTable.cpp +++ b/dDatabase/Tables/CDObjectSkillsTable.cpp @@ -21,10 +21,10 @@ CDObjectSkillsTable::CDObjectSkillsTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ObjectSkills"); while (!tableData.eof()) { CDObjectSkills entry; - entry.objectTemplate = tableData.getIntField(0, -1); - entry.skillID = tableData.getIntField(1, -1); - entry.castOnType = tableData.getIntField(2, -1); - entry.AICombatWeight = tableData.getIntField(3, -1); + entry.objectTemplate = tableData.getIntField("objectTemplate", -1); + entry.skillID = tableData.getIntField("skillID", -1); + entry.castOnType = tableData.getIntField("castOnType", -1); + entry.AICombatWeight = tableData.getIntField("AICombatWeight", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -33,14 +33,6 @@ CDObjectSkillsTable::CDObjectSkillsTable(void) { tableData.finalize(); } -//! Destructor -CDObjectSkillsTable::~CDObjectSkillsTable(void) {} - -//! Returns the table's name -std::string CDObjectSkillsTable::GetName(void) const { - return "ObjectSkills"; -} - //! Queries the table with a custom "where" clause std::vector CDObjectSkillsTable::Query(std::function predicate) { diff --git a/dDatabase/Tables/CDObjectSkillsTable.h b/dDatabase/Tables/CDObjectSkillsTable.h index c2caf71b..4ceaa447 100644 --- a/dDatabase/Tables/CDObjectSkillsTable.h +++ b/dDatabase/Tables/CDObjectSkillsTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDObjectSkillsTable.hpp - \brief Contains data for the ObjectSkills table - */ - - //! ObjectSkills Struct struct CDObjectSkills { unsigned int objectTemplate; //!< The LOT of the item unsigned int skillID; //!< The Skill ID of the object @@ -16,35 +10,16 @@ struct CDObjectSkills { unsigned int AICombatWeight; //!< ??? }; -//! ObjectSkills table -class CDObjectSkillsTable : public CDTable { +class CDObjectSkillsTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDObjectSkillsTable(void); - - //! Destructor - ~CDObjectSkillsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDObjectSkillsTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ + // Gets all the entries in the table std::vector GetEntries(void) const; }; diff --git a/dDatabase/Tables/CDObjectsTable.cpp b/dDatabase/Tables/CDObjectsTable.cpp index 03979af2..c68c3e6a 100644 --- a/dDatabase/Tables/CDObjectsTable.cpp +++ b/dDatabase/Tables/CDObjectsTable.cpp @@ -18,20 +18,20 @@ CDObjectsTable::CDObjectsTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Objects"); while (!tableData.eof()) { CDObjects entry; - entry.id = tableData.getIntField(0, -1); - entry.name = tableData.getStringField(1, ""); - entry.placeable = tableData.getIntField(2, -1); - entry.type = tableData.getStringField(3, ""); - entry.description = tableData.getStringField(4, ""); - entry.localize = tableData.getIntField(5, -1); - entry.npcTemplateID = tableData.getIntField(6, -1); - entry.displayName = tableData.getStringField(7, ""); - entry.interactionDistance = tableData.getFloatField(8, -1.0f); - entry.nametag = tableData.getIntField(9, -1); - entry._internalNotes = tableData.getStringField(10, ""); - entry.locStatus = tableData.getIntField(11, -1); - entry.gate_version = tableData.getStringField(12, ""); - entry.HQ_valid = tableData.getIntField(13, -1); + entry.id = tableData.getIntField("id", -1); + entry.name = tableData.getStringField("name", ""); + entry.placeable = tableData.getIntField("placeable", -1); + entry.type = tableData.getStringField("type", ""); + entry.description = tableData.getStringField("description", ""); + entry.localize = tableData.getIntField("localize", -1); + entry.npcTemplateID = tableData.getIntField("npcTemplateID", -1); + entry.displayName = tableData.getStringField("displayName", ""); + entry.interactionDistance = tableData.getFloatField("interactionDistance", -1.0f); + entry.nametag = tableData.getIntField("nametag", -1); + entry._internalNotes = tableData.getStringField("_internalNotes", ""); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.gate_version = tableData.getStringField("gate_version", ""); + entry.HQ_valid = tableData.getIntField("HQ_valid", -1); this->entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); @@ -43,14 +43,6 @@ CDObjectsTable::CDObjectsTable(void) { m_default.id = 0; } -//! Destructor -CDObjectsTable::~CDObjectsTable(void) {} - -//! Returns the table's name -std::string CDObjectsTable::GetName(void) const { - return "Objects"; -} - const CDObjects& CDObjectsTable::GetByID(unsigned int LOT) { const auto& it = this->entries.find(LOT); if (it != this->entries.end()) { @@ -71,20 +63,20 @@ const CDObjects& CDObjectsTable::GetByID(unsigned int LOT) { // Now get the data while (!tableData.eof()) { CDObjects entry; - entry.id = tableData.getIntField(0, -1); - entry.name = tableData.getStringField(1, ""); - UNUSED(entry.placeable = tableData.getIntField(2, -1)); - entry.type = tableData.getStringField(3, ""); + entry.id = tableData.getIntField("id", -1); + entry.name = tableData.getStringField("name", ""); + UNUSED(entry.placeable = tableData.getIntField("placeable", -1)); + entry.type = tableData.getStringField("type", ""); UNUSED(ntry.description = tableData.getStringField(4, "")); - UNUSED(entry.localize = tableData.getIntField(5, -1)); - UNUSED(entry.npcTemplateID = tableData.getIntField(6, -1)); - UNUSED(entry.displayName = tableData.getStringField(7, "")); - entry.interactionDistance = tableData.getFloatField(8, -1.0f); - UNUSED(entry.nametag = tableData.getIntField(9, -1)); - UNUSED(entry._internalNotes = tableData.getStringField(10, "")); - UNUSED(entry.locStatus = tableData.getIntField(11, -1)); - UNUSED(entry.gate_version = tableData.getStringField(12, "")); - UNUSED(entry.HQ_valid = tableData.getIntField(13, -1)); + UNUSED(entry.localize = tableData.getIntField("localize", -1)); + UNUSED(entry.npcTemplateID = tableData.getIntField("npcTemplateID", -1)); + UNUSED(entry.displayName = tableData.getStringField("displayName", "")); + entry.interactionDistance = tableData.getFloatField("interactionDistance", -1.0f); + UNUSED(entry.nametag = tableData.getIntField("nametag", -1)); + UNUSED(entry._internalNotes = tableData.getStringField("_internalNotes", "")); + UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + UNUSED(entry.HQ_valid = tableData.getIntField("HQ_valid", -1)); this->entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); @@ -100,3 +92,4 @@ const CDObjects& CDObjectsTable::GetByID(unsigned int LOT) { return m_default; } + diff --git a/dDatabase/Tables/CDObjectsTable.h b/dDatabase/Tables/CDObjectsTable.h index 333477bd..171eddef 100644 --- a/dDatabase/Tables/CDObjectsTable.h +++ b/dDatabase/Tables/CDObjectsTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDObjectsTable.hpp - \brief Contains data for the Objects table - */ - - //! RebuildComponent Struct struct CDObjects { unsigned int id; //!< The LOT of the object std::string name; //!< The internal name of the object @@ -26,29 +20,14 @@ struct CDObjects { UNUSED(unsigned int HQ_valid); //!< Probably used for the Nexus HQ database on LEGOUniverse.com }; -//! ObjectSkills table -class CDObjectsTable : public CDTable { +class CDObjectsTable : public CDTable { private: - //std::vector entries; std::map entries; CDObjects m_default; public: - - //! Constructor - CDObjectsTable(void); - - //! Destructor - ~CDObjectsTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Gets an entry by ID + CDObjectsTable(); + // Gets an entry by ID const CDObjects& GetByID(unsigned int LOT); - }; diff --git a/dDatabase/Tables/CDPackageComponentTable.cpp b/dDatabase/Tables/CDPackageComponentTable.cpp index 83673c6f..efb85eeb 100644 --- a/dDatabase/Tables/CDPackageComponentTable.cpp +++ b/dDatabase/Tables/CDPackageComponentTable.cpp @@ -21,9 +21,9 @@ CDPackageComponentTable::CDPackageComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PackageComponent"); while (!tableData.eof()) { CDPackageComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.LootMatrixIndex = tableData.getIntField(1, -1); - entry.packageType = tableData.getIntField(2, -1); + entry.id = tableData.getIntField("id", -1); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); + entry.packageType = tableData.getIntField("packageType", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -32,14 +32,6 @@ CDPackageComponentTable::CDPackageComponentTable(void) { tableData.finalize(); } -//! Destructor -CDPackageComponentTable::~CDPackageComponentTable(void) {} - -//! Returns the table's name -std::string CDPackageComponentTable::GetName(void) const { - return "PackageComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDPackageComponentTable::Query(std::function predicate) { @@ -54,3 +46,4 @@ std::vector CDPackageComponentTable::Query(std::function CDPackageComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDPackageComponentTable.h b/dDatabase/Tables/CDPackageComponentTable.h index 763acf8c..6c11ab39 100644 --- a/dDatabase/Tables/CDPackageComponentTable.h +++ b/dDatabase/Tables/CDPackageComponentTable.h @@ -3,48 +3,20 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDPackageComponentTable.hpp - \brief Contains data for the PackageComponent table - */ - - //! PackageComponent Entry Struct struct CDPackageComponent { unsigned int id; unsigned int LootMatrixIndex; unsigned int packageType; }; - -//! PackageComponent table -class CDPackageComponentTable : public CDTable { +class CDPackageComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor CDPackageComponentTable(void); - - //! Destructor - ~CDPackageComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDPhysicsComponentTable.cpp b/dDatabase/Tables/CDPhysicsComponentTable.cpp index 8cb7a3b0..bb21ed7f 100644 --- a/dDatabase/Tables/CDPhysicsComponentTable.cpp +++ b/dDatabase/Tables/CDPhysicsComponentTable.cpp @@ -4,22 +4,22 @@ CDPhysicsComponentTable::CDPhysicsComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PhysicsComponent"); while (!tableData.eof()) { CDPhysicsComponent* entry = new CDPhysicsComponent(); - entry->id = tableData.getIntField(0, -1); - entry->bStatic = tableData.getIntField(1, -1) != 0; - entry->physicsAsset = tableData.getStringField(2, ""); - UNUSED(entry->jump = tableData.getIntField(3, -1) != 0); - UNUSED(entry->doublejump = tableData.getIntField(4, -1) != 0); - entry->speed = tableData.getFloatField(5, -1); - UNUSED(entry->rotSpeed = tableData.getFloatField(6, -1)); - entry->playerHeight = tableData.getFloatField(7); - entry->playerRadius = tableData.getFloatField(8); - entry->pcShapeType = tableData.getIntField(9); - entry->collisionGroup = tableData.getIntField(10); - UNUSED(entry->airSpeed = tableData.getFloatField(11)); - UNUSED(entry->boundaryAsset = tableData.getStringField(12)); - UNUSED(entry->jumpAirSpeed = tableData.getFloatField(13)); - UNUSED(entry->friction = tableData.getFloatField(14)); - UNUSED(entry->gravityVolumeAsset = tableData.getStringField(15)); + entry->id = tableData.getIntField("id", -1); + entry->bStatic = tableData.getIntField("static", -1) != 0; + entry->physicsAsset = tableData.getStringField("physics_asset", ""); + UNUSED(entry->jump = tableData.getIntField("jump", -1) != 0); + UNUSED(entry->doublejump = tableData.getIntField("doublejump", -1) != 0); + entry->speed = tableData.getFloatField("speed", -1); + UNUSED(entry->rotSpeed = tableData.getFloatField("rotSpeed", -1)); + entry->playerHeight = tableData.getFloatField("playerHeight"); + entry->playerRadius = tableData.getFloatField("playerRadius"); + entry->pcShapeType = tableData.getIntField("pcShapeType"); + entry->collisionGroup = tableData.getIntField("collisionGroup"); + UNUSED(entry->airSpeed = tableData.getFloatField("airSpeed")); + UNUSED(entry->boundaryAsset = tableData.getStringField("boundaryAsset")); + UNUSED(entry->jumpAirSpeed = tableData.getFloatField("jumpAirSpeed")); + UNUSED(entry->friction = tableData.getFloatField("friction")); + UNUSED(entry->gravityVolumeAsset = tableData.getStringField("gravityVolumeAsset")); m_entries.insert(std::make_pair(entry->id, entry)); tableData.nextRow(); @@ -28,7 +28,7 @@ CDPhysicsComponentTable::CDPhysicsComponentTable(void) { tableData.finalize(); } -CDPhysicsComponentTable::~CDPhysicsComponentTable(void) { +CDPhysicsComponentTable::~CDPhysicsComponentTable() { for (auto e : m_entries) { if (e.second) delete e.second; } @@ -36,10 +36,6 @@ CDPhysicsComponentTable::~CDPhysicsComponentTable(void) { m_entries.clear(); } -std::string CDPhysicsComponentTable::GetName(void) const { - return "PhysicsComponent"; -} - CDPhysicsComponent* CDPhysicsComponentTable::GetByID(unsigned int componentID) { for (auto e : m_entries) { if (e.first == componentID) return e.second; @@ -47,3 +43,4 @@ CDPhysicsComponent* CDPhysicsComponentTable::GetByID(unsigned int componentID) { return nullptr; } + diff --git a/dDatabase/Tables/CDPhysicsComponentTable.h b/dDatabase/Tables/CDPhysicsComponentTable.h index c5805da3..e63d337d 100644 --- a/dDatabase/Tables/CDPhysicsComponentTable.h +++ b/dDatabase/Tables/CDPhysicsComponentTable.h @@ -21,12 +21,12 @@ struct CDPhysicsComponent { UNUSED(std::string gravityVolumeAsset); }; -class CDPhysicsComponentTable : public CDTable { +class CDPhysicsComponentTable : public CDTable { public: - CDPhysicsComponentTable(void); - ~CDPhysicsComponentTable(void); + CDPhysicsComponentTable(); + ~CDPhysicsComponentTable(); - std::string GetName(void) const override; + static const std::string GetTableName() { return "PhysicsComponent"; }; CDPhysicsComponent* GetByID(unsigned int componentID); private: diff --git a/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp b/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp index 01a2ae37..1fead45e 100644 --- a/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp +++ b/dDatabase/Tables/CDPropertyEntranceComponentTable.cpp @@ -18,11 +18,11 @@ CDPropertyEntranceComponentTable::CDPropertyEntranceComponentTable() { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PropertyEntranceComponent;"); while (!tableData.eof()) { auto entry = CDPropertyEntranceComponent{ - static_cast(tableData.getIntField(0, -1)), - static_cast(tableData.getIntField(1, -1)), - tableData.getStringField(2, ""), - static_cast(tableData.getIntField(3, false)), - tableData.getStringField(4, "") + static_cast(tableData.getIntField("id", -1)), + static_cast(tableData.getIntField("mapID", -1)), + tableData.getStringField("propertyName", ""), + static_cast(tableData.getIntField("isOnProperty", false)), + tableData.getStringField("groupType", "") }; this->entries.push_back(entry); @@ -32,12 +32,6 @@ CDPropertyEntranceComponentTable::CDPropertyEntranceComponentTable() { tableData.finalize(); } -CDPropertyEntranceComponentTable::~CDPropertyEntranceComponentTable(void) = default; - -std::string CDPropertyEntranceComponentTable::GetName() const { - return "PropertyEntranceComponent"; -} - CDPropertyEntranceComponent CDPropertyEntranceComponentTable::GetByID(uint32_t id) { for (const auto& entry : entries) { if (entry.id == id) @@ -46,3 +40,4 @@ CDPropertyEntranceComponent CDPropertyEntranceComponentTable::GetByID(uint32_t i return defaultEntry; } + diff --git a/dDatabase/Tables/CDPropertyEntranceComponentTable.h b/dDatabase/Tables/CDPropertyEntranceComponentTable.h index fa0603c0..925fd1be 100644 --- a/dDatabase/Tables/CDPropertyEntranceComponentTable.h +++ b/dDatabase/Tables/CDPropertyEntranceComponentTable.h @@ -9,31 +9,13 @@ struct CDPropertyEntranceComponent { std::string groupType; }; -class CDPropertyEntranceComponentTable : public CDTable { +class CDPropertyEntranceComponentTable : public CDTable { public: - //! Constructor CDPropertyEntranceComponentTable(); - - //! Destructor - ~CDPropertyEntranceComponentTable(); - - //! Returns the table's name - /*! - \return The table name - */ - [[nodiscard]] std::string GetName() const override; - - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + // Queries the table with a custom "where" clause CDPropertyEntranceComponent GetByID(uint32_t id); - //! Gets all the entries in the table - /*! - \return The entries - */ + // Gets all the entries in the table [[nodiscard]] std::vector GetEntries() const { return entries; } private: std::vector entries{}; diff --git a/dDatabase/Tables/CDPropertyTemplateTable.cpp b/dDatabase/Tables/CDPropertyTemplateTable.cpp index 7dd118eb..4caa6dc5 100644 --- a/dDatabase/Tables/CDPropertyTemplateTable.cpp +++ b/dDatabase/Tables/CDPropertyTemplateTable.cpp @@ -17,10 +17,10 @@ CDPropertyTemplateTable::CDPropertyTemplateTable() { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PropertyTemplate;"); while (!tableData.eof()) { auto entry = CDPropertyTemplate{ - static_cast(tableData.getIntField(0, -1)), - static_cast(tableData.getIntField(1, -1)), - static_cast(tableData.getIntField(2, -1)), - tableData.getStringField(3, "") + static_cast(tableData.getIntField("id", -1)), + static_cast(tableData.getIntField("mapID", -1)), + static_cast(tableData.getIntField("vendorMapID", -1)), + tableData.getStringField("spawnName", "") }; this->entries.push_back(entry); @@ -30,12 +30,6 @@ CDPropertyTemplateTable::CDPropertyTemplateTable() { tableData.finalize(); } -CDPropertyTemplateTable::~CDPropertyTemplateTable() = default; - -std::string CDPropertyTemplateTable::GetName() const { - return "PropertyTemplate"; -} - CDPropertyTemplate CDPropertyTemplateTable::GetByMapID(uint32_t mapID) { for (const auto& entry : entries) { if (entry.mapID == mapID) @@ -44,3 +38,4 @@ CDPropertyTemplate CDPropertyTemplateTable::GetByMapID(uint32_t mapID) { return defaultEntry; } + diff --git a/dDatabase/Tables/CDPropertyTemplateTable.h b/dDatabase/Tables/CDPropertyTemplateTable.h index a266932b..cb075dbf 100644 --- a/dDatabase/Tables/CDPropertyTemplateTable.h +++ b/dDatabase/Tables/CDPropertyTemplateTable.h @@ -8,12 +8,11 @@ struct CDPropertyTemplate { std::string spawnName; }; -class CDPropertyTemplateTable : public CDTable { +class CDPropertyTemplateTable : public CDTable { public: CDPropertyTemplateTable(); - ~CDPropertyTemplateTable(); - [[nodiscard]] std::string GetName() const override; + static const std::string GetTableName() { return "PropertyTemplate"; }; CDPropertyTemplate GetByMapID(uint32_t mapID); private: std::vector entries{}; diff --git a/dDatabase/Tables/CDProximityMonitorComponentTable.cpp b/dDatabase/Tables/CDProximityMonitorComponentTable.cpp index 092f3ca1..688de056 100644 --- a/dDatabase/Tables/CDProximityMonitorComponentTable.cpp +++ b/dDatabase/Tables/CDProximityMonitorComponentTable.cpp @@ -21,10 +21,10 @@ CDProximityMonitorComponentTable::CDProximityMonitorComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ProximityMonitorComponent"); while (!tableData.eof()) { CDProximityMonitorComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.Proximities = tableData.getStringField(1, ""); - entry.LoadOnClient = tableData.getIntField(2, -1); - entry.LoadOnServer = tableData.getIntField(3, -1); + entry.id = tableData.getIntField("id", -1); + entry.Proximities = tableData.getStringField("Proximities", ""); + entry.LoadOnClient = tableData.getIntField("LoadOnClient", -1); + entry.LoadOnServer = tableData.getIntField("LoadOnServer", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -33,14 +33,6 @@ CDProximityMonitorComponentTable::CDProximityMonitorComponentTable(void) { tableData.finalize(); } -//! Destructor -CDProximityMonitorComponentTable::~CDProximityMonitorComponentTable(void) {} - -//! Returns the table's name -std::string CDProximityMonitorComponentTable::GetName(void) const { - return "ProximityMonitorComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDProximityMonitorComponentTable::Query(std::function predicate) { @@ -55,3 +47,4 @@ std::vector CDProximityMonitorComponentTable::Query std::vector CDProximityMonitorComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDProximityMonitorComponentTable.h b/dDatabase/Tables/CDProximityMonitorComponentTable.h index 007bb916..38b7d43b 100644 --- a/dDatabase/Tables/CDProximityMonitorComponentTable.h +++ b/dDatabase/Tables/CDProximityMonitorComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDProximityMonitorComponentTable.hpp - \brief Contains data for the ProximityMonitorComponent table - */ - - //! ProximityMonitorComponent Entry Struct struct CDProximityMonitorComponent { unsigned int id; std::string Proximities; @@ -16,36 +10,14 @@ struct CDProximityMonitorComponent { bool LoadOnServer; }; - -//! ProximityMonitorComponent table -class CDProximityMonitorComponentTable : public CDTable { +class CDProximityMonitorComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor CDProximityMonitorComponentTable(void); - - //! Destructor - ~CDProximityMonitorComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDRailActivatorComponent.cpp b/dDatabase/Tables/CDRailActivatorComponent.cpp index 4c141256..2ff8990d 100644 --- a/dDatabase/Tables/CDRailActivatorComponent.cpp +++ b/dDatabase/Tables/CDRailActivatorComponent.cpp @@ -6,35 +6,35 @@ CDRailActivatorComponentTable::CDRailActivatorComponentTable() { while (!tableData.eof()) { CDRailActivatorComponent entry; - entry.id = tableData.getIntField(0); + entry.id = tableData.getIntField("id", 0); - entry.startAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField(1, "")); - entry.loopAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField(2, "")); - entry.stopAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField(3, "")); - entry.startSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField(4, "")); - entry.loopSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField(5, "")); - entry.stopSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField(6, "")); + entry.startAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField("startAnim", "")); + entry.loopAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField("loopAnim", "")); + entry.stopAnimation = GeneralUtils::ASCIIToUTF16(tableData.getStringField("stopAnim", "")); + entry.startSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField("startSound", "")); + entry.loopSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField("loopSound", "")); + entry.stopSound = GeneralUtils::ASCIIToUTF16(tableData.getStringField("stopSound", "")); - std::string loopEffectString(tableData.getStringField(7, "")); + std::string loopEffectString(tableData.getStringField("effectIDs", "")); entry.loopEffectID = EffectPairFromString(loopEffectString); - entry.preconditions = tableData.getStringField(8, "-1"); + entry.preconditions = tableData.getStringField("preconditions", "-1"); - entry.playerCollision = tableData.getIntField(9, 0); + entry.playerCollision = tableData.getIntField("playerCollision", 0); - entry.cameraLocked = tableData.getIntField(10, 0); + entry.cameraLocked = tableData.getIntField("cameraLocked", 0); - std::string startEffectString(tableData.getStringField(11, "")); + std::string startEffectString(tableData.getStringField("StartEffectID", "")); entry.startEffectID = EffectPairFromString(startEffectString); - std::string stopEffectString(tableData.getStringField(12, "")); + std::string stopEffectString(tableData.getStringField("StopEffectID", "")); entry.stopEffectID = EffectPairFromString(stopEffectString); - entry.damageImmune = tableData.getIntField(13, 0); + entry.damageImmune = tableData.getIntField("DamageImmune", 0); - entry.noAggro = tableData.getIntField(14, 0); + entry.noAggro = tableData.getIntField("NoAggro", 0); - entry.showNameBillboard = tableData.getIntField(15, 0); + entry.showNameBillboard = tableData.getIntField("ShowNameBillboard", 0); m_Entries.push_back(entry); tableData.nextRow(); @@ -43,12 +43,6 @@ CDRailActivatorComponentTable::CDRailActivatorComponentTable() { tableData.finalize(); } -CDRailActivatorComponentTable::~CDRailActivatorComponentTable() = default; - -std::string CDRailActivatorComponentTable::GetName() const { - return "RailActivatorComponent"; -} - CDRailActivatorComponent CDRailActivatorComponentTable::GetEntryByID(int32_t id) const { for (const auto& entry : m_Entries) { if (entry.id == id) @@ -70,3 +64,4 @@ std::pair CDRailActivatorComponentTable::EffectPairFro return {}; } + diff --git a/dDatabase/Tables/CDRailActivatorComponent.h b/dDatabase/Tables/CDRailActivatorComponent.h index b8313e96..03dd0525 100644 --- a/dDatabase/Tables/CDRailActivatorComponent.h +++ b/dDatabase/Tables/CDRailActivatorComponent.h @@ -20,12 +20,10 @@ struct CDRailActivatorComponent { bool showNameBillboard; }; -class CDRailActivatorComponentTable : public CDTable { +class CDRailActivatorComponentTable : public CDTable { public: CDRailActivatorComponentTable(); - ~CDRailActivatorComponentTable(); - - std::string GetName() const override; + static const std::string GetTableName() { return "RailActivatorComponent"; }; [[nodiscard]] CDRailActivatorComponent GetEntryByID(int32_t id) const; [[nodiscard]] std::vector GetEntries() const; private: diff --git a/dDatabase/Tables/CDRarityTableTable.cpp b/dDatabase/Tables/CDRarityTableTable.cpp index 67878cd2..0b1212c0 100644 --- a/dDatabase/Tables/CDRarityTableTable.cpp +++ b/dDatabase/Tables/CDRarityTableTable.cpp @@ -21,10 +21,10 @@ CDRarityTableTable::CDRarityTableTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RarityTable"); while (!tableData.eof()) { CDRarityTable entry; - entry.id = tableData.getIntField(0, -1); - entry.randmax = tableData.getFloatField(1, -1); - entry.rarity = tableData.getIntField(2, -1); - entry.RarityTableIndex = tableData.getIntField(3, -1); + entry.id = tableData.getIntField("id", -1); + entry.randmax = tableData.getFloatField("randmax", -1); + entry.rarity = tableData.getIntField("rarity", -1); + entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -33,14 +33,6 @@ CDRarityTableTable::CDRarityTableTable(void) { tableData.finalize(); } -//! Destructor -CDRarityTableTable::~CDRarityTableTable(void) {} - -//! Returns the table's name -std::string CDRarityTableTable::GetName(void) const { - return "RarityTable"; -} - //! Queries the table with a custom "where" clause std::vector CDRarityTableTable::Query(std::function predicate) { @@ -55,3 +47,4 @@ std::vector CDRarityTableTable::Query(std::function& CDRarityTableTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDRarityTableTable.h b/dDatabase/Tables/CDRarityTableTable.h index 55cfec4b..592346ed 100644 --- a/dDatabase/Tables/CDRarityTableTable.h +++ b/dDatabase/Tables/CDRarityTableTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDRarityTableTable.hpp - \brief Contains data for the RarityTable table - */ - - //! RarityTable Entry Struct struct CDRarityTable { unsigned int id; float randmax; @@ -32,37 +26,15 @@ struct CDRarityTable { } }; - -//! RarityTable table -class CDRarityTableTable : public CDTable { +class CDRarityTableTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDRarityTableTable(void); - - //! Destructor - ~CDRarityTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDRarityTableTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ - const std::vector& GetEntries(void) const; - + const std::vector& GetEntries() const; }; diff --git a/dDatabase/Tables/CDRebuildComponentTable.cpp b/dDatabase/Tables/CDRebuildComponentTable.cpp index c4299b98..d5c386d1 100644 --- a/dDatabase/Tables/CDRebuildComponentTable.cpp +++ b/dDatabase/Tables/CDRebuildComponentTable.cpp @@ -21,16 +21,16 @@ CDRebuildComponentTable::CDRebuildComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RebuildComponent"); while (!tableData.eof()) { CDRebuildComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.reset_time = tableData.getFloatField(1, -1.0f); - entry.complete_time = tableData.getFloatField(2, -1.0f); - entry.take_imagination = tableData.getIntField(3, -1); - entry.interruptible = tableData.getIntField(4, -1) == 1 ? true : false; - entry.self_activator = tableData.getIntField(5, -1) == 1 ? true : false; - entry.custom_modules = tableData.getStringField(6, ""); - entry.activityID = tableData.getIntField(7, -1); - entry.post_imagination_cost = tableData.getIntField(8, -1); - entry.time_before_smash = tableData.getFloatField(9, -1.0f); + entry.id = tableData.getIntField("id", -1); + entry.reset_time = tableData.getFloatField("reset_time", -1.0f); + entry.complete_time = tableData.getFloatField("complete_time", -1.0f); + entry.take_imagination = tableData.getIntField("take_imagination", -1); + entry.interruptible = tableData.getIntField("interruptible", -1) == 1 ? true : false; + entry.self_activator = tableData.getIntField("self_activator", -1) == 1 ? true : false; + entry.custom_modules = tableData.getStringField("custom_modules", ""); + entry.activityID = tableData.getIntField("activityID", -1); + entry.post_imagination_cost = tableData.getIntField("post_imagination_cost", -1); + entry.time_before_smash = tableData.getFloatField("time_before_smash", -1.0f); this->entries.push_back(entry); tableData.nextRow(); @@ -39,14 +39,6 @@ CDRebuildComponentTable::CDRebuildComponentTable(void) { tableData.finalize(); } -//! Destructor -CDRebuildComponentTable::~CDRebuildComponentTable(void) {} - -//! Returns the table's name -std::string CDRebuildComponentTable::GetName(void) const { - return "RebuildComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDRebuildComponentTable::Query(std::function predicate) { @@ -61,3 +53,4 @@ std::vector CDRebuildComponentTable::Query(std::function CDRebuildComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDRebuildComponentTable.h b/dDatabase/Tables/CDRebuildComponentTable.h index bdc2da8a..db70a47d 100644 --- a/dDatabase/Tables/CDRebuildComponentTable.h +++ b/dDatabase/Tables/CDRebuildComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDRebuildComponentTable.hpp - \brief Contains data for the RebuildComponent table - */ - - //! RebuildComponent Struct struct CDRebuildComponent { unsigned int id; //!< The component Id float reset_time; //!< The reset time @@ -22,36 +16,15 @@ struct CDRebuildComponent { float time_before_smash; //!< The time before smash }; -//! ObjectSkills table -class CDRebuildComponentTable : public CDTable { +class CDRebuildComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDRebuildComponentTable(void); - - //! Destructor - ~CDRebuildComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDRebuildComponentTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ - std::vector GetEntries(void) const; - + std::vector GetEntries() const; }; diff --git a/dDatabase/Tables/CDRewardsTable.cpp b/dDatabase/Tables/CDRewardsTable.cpp index 99d56f26..55672add 100644 --- a/dDatabase/Tables/CDRewardsTable.cpp +++ b/dDatabase/Tables/CDRewardsTable.cpp @@ -4,12 +4,12 @@ CDRewardsTable::CDRewardsTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Rewards"); while (!tableData.eof()) { CDRewards* entry = new CDRewards(); - entry->id = tableData.getIntField(0, -1); - entry->levelID = tableData.getIntField(1, -1); - entry->missionID = tableData.getIntField(2, -1); - entry->rewardType = tableData.getIntField(3, -1); - entry->value = tableData.getIntField(4, -1); - entry->count = tableData.getIntField(5, -1); + entry->id = tableData.getIntField("id", -1); + entry->levelID = tableData.getIntField("LevelID", -1); + entry->missionID = tableData.getIntField("MissionID", -1); + entry->rewardType = tableData.getIntField("RewardType", -1); + entry->value = tableData.getIntField("value", -1); + entry->count = tableData.getIntField("count", -1); m_entries.insert(std::make_pair(entry->id, entry)); tableData.nextRow(); @@ -26,10 +26,6 @@ CDRewardsTable::~CDRewardsTable(void) { m_entries.clear(); } -std::string CDRewardsTable::GetName(void) const { - return "Rewards"; -} - std::vector CDRewardsTable::GetByLevelID(uint32_t levelID) { std::vector result{}; for (const auto& e : m_entries) { @@ -38,3 +34,4 @@ std::vector CDRewardsTable::GetByLevelID(uint32_t levelID) { return result; } + diff --git a/dDatabase/Tables/CDRewardsTable.h b/dDatabase/Tables/CDRewardsTable.h index 2edfd2b3..2e079a83 100644 --- a/dDatabase/Tables/CDRewardsTable.h +++ b/dDatabase/Tables/CDRewardsTable.h @@ -11,12 +11,12 @@ struct CDRewards { int32_t count; }; -class CDRewardsTable : public CDTable { +class CDRewardsTable : public CDTable { public: - CDRewardsTable(void); - ~CDRewardsTable(void); + CDRewardsTable(); + ~CDRewardsTable(); - std::string GetName(void) const override; + static const std::string GetTableName() { return "Rewards"; }; std::vector GetByLevelID(uint32_t levelID); private: diff --git a/dDatabase/Tables/CDScriptComponentTable.cpp b/dDatabase/Tables/CDScriptComponentTable.cpp index b34f96f1..8050c139 100644 --- a/dDatabase/Tables/CDScriptComponentTable.cpp +++ b/dDatabase/Tables/CDScriptComponentTable.cpp @@ -18,9 +18,9 @@ CDScriptComponentTable::CDScriptComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ScriptComponent"); while (!tableData.eof()) { CDScriptComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.script_name = tableData.getStringField(1, ""); - entry.client_script_name = tableData.getStringField(2, ""); + entry.id = tableData.getIntField("id", -1); + entry.script_name = tableData.getStringField("script_name", ""); + entry.client_script_name = tableData.getStringField("client_script_name", ""); this->entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); @@ -29,14 +29,6 @@ CDScriptComponentTable::CDScriptComponentTable(void) { tableData.finalize(); } -//! Destructor -CDScriptComponentTable::~CDScriptComponentTable(void) {} - -//! Returns the table's name -std::string CDScriptComponentTable::GetName(void) const { - return "ScriptComponent"; -} - const CDScriptComponent& CDScriptComponentTable::GetByID(unsigned int id) { std::map::iterator it = this->entries.find(id); if (it != this->entries.end()) { @@ -45,3 +37,4 @@ const CDScriptComponent& CDScriptComponentTable::GetByID(unsigned int id) { return m_ToReturnWhenNoneFound; } + diff --git a/dDatabase/Tables/CDScriptComponentTable.h b/dDatabase/Tables/CDScriptComponentTable.h index 92534cc0..77453939 100644 --- a/dDatabase/Tables/CDScriptComponentTable.h +++ b/dDatabase/Tables/CDScriptComponentTable.h @@ -3,44 +3,20 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDScriptComponentTable.hpp - \brief Contains data for the ScriptComponent table - */ - - //! ScriptComponent Struct struct CDScriptComponent { unsigned int id; //!< The component ID std::string script_name; //!< The script name std::string client_script_name; //!< The client script name }; -//! ObjectSkills table -class CDScriptComponentTable : public CDTable { +class CDScriptComponentTable : public CDTable { private: std::map entries; CDScriptComponent m_ToReturnWhenNoneFound; public: - //! Gets an entry by ID + CDScriptComponentTable(); + // Gets an entry by scriptID const CDScriptComponent& GetByID(unsigned int id); - - //! Constructor - CDScriptComponentTable(void); - - //! Destructor - ~CDScriptComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ - }; diff --git a/dDatabase/Tables/CDSkillBehaviorTable.cpp b/dDatabase/Tables/CDSkillBehaviorTable.cpp index e3986578..c5df78ef 100644 --- a/dDatabase/Tables/CDSkillBehaviorTable.cpp +++ b/dDatabase/Tables/CDSkillBehaviorTable.cpp @@ -23,25 +23,25 @@ CDSkillBehaviorTable::CDSkillBehaviorTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM SkillBehavior"); while (!tableData.eof()) { CDSkillBehavior entry; - entry.skillID = tableData.getIntField(0, -1); - UNUSED(entry.locStatus = tableData.getIntField(1, -1)); - entry.behaviorID = tableData.getIntField(2, -1); - entry.imaginationcost = tableData.getIntField(3, -1); - entry.cooldowngroup = tableData.getIntField(4, -1); - entry.cooldown = tableData.getFloatField(5, -1.0f); - UNUSED(entry.isNpcEditor = tableData.getIntField(6, -1) == 1 ? true : false); - UNUSED(entry.skillIcon = tableData.getIntField(7, -1)); - UNUSED(entry.oomSkillID = tableData.getStringField(8, "")); - UNUSED(entry.oomBehaviorEffectID = tableData.getIntField(9, -1)); - UNUSED(entry.castTypeDesc = tableData.getIntField(10, -1)); - UNUSED(entry.imBonusUI = tableData.getIntField(11, -1)); - UNUSED(entry.lifeBonusUI = tableData.getIntField(12, -1)); - UNUSED(entry.armorBonusUI = tableData.getIntField(13, -1)); - UNUSED(entry.damageUI = tableData.getIntField(14, -1)); - UNUSED(entry.hideIcon = tableData.getIntField(15, -1) == 1 ? true : false); - UNUSED(entry.localize = tableData.getIntField(16, -1) == 1 ? true : false); - UNUSED(entry.gate_version = tableData.getStringField(17, "")); - UNUSED(entry.cancelType = tableData.getIntField(18, -1)); + entry.skillID = tableData.getIntField("skillID", -1); + UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); + entry.behaviorID = tableData.getIntField("behaviorID", -1); + entry.imaginationcost = tableData.getIntField("imaginationcost", -1); + entry.cooldowngroup = tableData.getIntField("cooldowngroup", -1); + entry.cooldown = tableData.getFloatField("cooldown", -1.0f); + UNUSED(entry.isNpcEditor = tableData.getIntField("isNpcEditor", -1) == 1 ? true : false); + UNUSED(entry.skillIcon = tableData.getIntField("skillIcon", -1)); + UNUSED(entry.oomSkillID = tableData.getStringField("oomSkillID", "")); + UNUSED(entry.oomBehaviorEffectID = tableData.getIntField("oomBehaviorEffectID", -1)); + UNUSED(entry.castTypeDesc = tableData.getIntField("castTypeDesc", -1)); + UNUSED(entry.imBonusUI = tableData.getIntField("imBonusUI", -1)); + UNUSED(entry.lifeBonusUI = tableData.getIntField("lifeBonusUI", -1)); + UNUSED(entry.armorBonusUI = tableData.getIntField("armorBonusUI", -1)); + UNUSED(entry.damageUI = tableData.getIntField("damageUI", -1)); + UNUSED(entry.hideIcon = tableData.getIntField("hideIcon", -1) == 1 ? true : false); + UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + UNUSED(entry.cancelType = tableData.getIntField("cancelType", -1)); this->entries.insert(std::make_pair(entry.skillID, entry)); //this->entries.push_back(entry); @@ -51,24 +51,8 @@ CDSkillBehaviorTable::CDSkillBehaviorTable(void) { tableData.finalize(); } -//! Destructor -CDSkillBehaviorTable::~CDSkillBehaviorTable(void) {} - -//! Returns the table's name -std::string CDSkillBehaviorTable::GetName(void) const { - return "SkillBehavior"; -} - //! Queries the table with a custom "where" clause std::vector CDSkillBehaviorTable::Query(std::function predicate) { - - /*std::vector data = cpplinq::from(this->entries) - >> cpplinq::where(predicate) - >> cpplinq::to_vector(); - - return data;*/ - - //Logger::LogDebug("CDSkillBehaviorTable", "The 'Query' function is no longer working! Please use GetSkillByID instead!"); std::vector data; //So MSVC shuts up return data; } @@ -82,3 +66,4 @@ const CDSkillBehavior& CDSkillBehaviorTable::GetSkillByID(unsigned int skillID) return m_empty; } + diff --git a/dDatabase/Tables/CDSkillBehaviorTable.h b/dDatabase/Tables/CDSkillBehaviorTable.h index da8676db..eb3094e0 100644 --- a/dDatabase/Tables/CDSkillBehaviorTable.h +++ b/dDatabase/Tables/CDSkillBehaviorTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDSkillBehaviorTable.hpp - \brief Contains data for the SkillBehavior table - */ - - //! ZoneTable Struct struct CDSkillBehavior { unsigned int skillID; //!< The Skill ID of the skill UNUSED(unsigned int locStatus); //!< ?? @@ -31,33 +25,17 @@ struct CDSkillBehavior { UNUSED(unsigned int cancelType); //!< The cancel type (?) }; -//! SkillBehavior table -class CDSkillBehaviorTable : public CDTable { +class CDSkillBehaviorTable : public CDTable { private: std::map entries; CDSkillBehavior m_empty; public: - - //! Constructor - CDSkillBehaviorTable(void); - - //! Destructor - ~CDSkillBehaviorTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDSkillBehaviorTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets an entry by ID + // Gets an entry by skillID const CDSkillBehavior& GetSkillByID(unsigned int skillID); }; diff --git a/dDatabase/Tables/CDTable.h b/dDatabase/Tables/CDTable.h index cd05782d..fca16eb8 100644 --- a/dDatabase/Tables/CDTable.h +++ b/dDatabase/Tables/CDTable.h @@ -1,9 +1,8 @@ #pragma once -// Custom Classes -#include "../CDClientDatabase.h" +#include "CDClientDatabase.h" +#include "Singleton.h" -// C++ #include #include #include @@ -19,23 +18,8 @@ #pragma warning (disable : 4244) //Disable double to float conversion warnings #pragma warning (disable : 4715) //Disable "not all control paths return a value" -#if defined(__unix) || defined(__APPLE__) -//For Linux: -typedef __int64_t __int64; -#endif - -/*! - \file CDTable.hpp - \brief A virtual class for CDClient Tables - */ - - //! The base class for all CD tables -class CDTable { -public: - - //! Returns the table's name - /*! - \return The table name - */ - virtual std::string GetName() const = 0; +template +class CDTable : public Singleton { +protected: + virtual ~CDTable() = default; }; diff --git a/dDatabase/Tables/CDVendorComponentTable.cpp b/dDatabase/Tables/CDVendorComponentTable.cpp index f1dd96db..dfff2e20 100644 --- a/dDatabase/Tables/CDVendorComponentTable.cpp +++ b/dDatabase/Tables/CDVendorComponentTable.cpp @@ -21,11 +21,11 @@ CDVendorComponentTable::CDVendorComponentTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM VendorComponent"); while (!tableData.eof()) { CDVendorComponent entry; - entry.id = tableData.getIntField(0, -1); - entry.buyScalar = tableData.getFloatField(1, -1.0f); - entry.sellScalar = tableData.getFloatField(2, -1.0f); - entry.refreshTimeSeconds = tableData.getFloatField(3, -1.0f); - entry.LootMatrixIndex = tableData.getIntField(4, -1); + entry.id = tableData.getIntField("id", -1); + entry.buyScalar = tableData.getFloatField("buyScalar", -1.0f); + entry.sellScalar = tableData.getFloatField("sellScalar", -1.0f); + entry.refreshTimeSeconds = tableData.getFloatField("refreshTimeSeconds", -1.0f); + entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1); this->entries.push_back(entry); tableData.nextRow(); @@ -34,14 +34,6 @@ CDVendorComponentTable::CDVendorComponentTable(void) { tableData.finalize(); } -//! Destructor -CDVendorComponentTable::~CDVendorComponentTable(void) {} - -//! Returns the table's name -std::string CDVendorComponentTable::GetName(void) const { - return "VendorComponent"; -} - //! Queries the table with a custom "where" clause std::vector CDVendorComponentTable::Query(std::function predicate) { @@ -56,3 +48,4 @@ std::vector CDVendorComponentTable::Query(std::function CDVendorComponentTable::GetEntries(void) const { return this->entries; } + diff --git a/dDatabase/Tables/CDVendorComponentTable.h b/dDatabase/Tables/CDVendorComponentTable.h index 2e0fb9e4..f2666d7e 100644 --- a/dDatabase/Tables/CDVendorComponentTable.h +++ b/dDatabase/Tables/CDVendorComponentTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDVendorComponentTable.hpp - \brief Contains data for the VendorComponent table - */ - - //! VendorComponent Struct struct CDVendorComponent { unsigned int id; //!< The Component ID float buyScalar; //!< Buy Scalar (what does that mean?) @@ -17,36 +11,15 @@ struct CDVendorComponent { unsigned int LootMatrixIndex; //!< LootMatrixIndex of the vendor's items }; -//! VendorComponent table -class CDVendorComponentTable : public CDTable { +class CDVendorComponentTable : public CDTable { private: std::vector entries; public: - - //! Constructor - CDVendorComponentTable(void); - - //! Destructor - ~CDVendorComponentTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a custom "where" clause - /*! - \param predicate The predicate - */ + CDVendorComponentTable(); + // Queries the table with a custom "where" clause std::vector Query(std::function predicate); - //! Gets all the entries in the table - /*! - \return The entries - */ std::vector GetEntries(void) const; - }; diff --git a/dDatabase/Tables/CDZoneTableTable.cpp b/dDatabase/Tables/CDZoneTableTable.cpp index e172f79a..bafbf8fe 100644 --- a/dDatabase/Tables/CDZoneTableTable.cpp +++ b/dDatabase/Tables/CDZoneTableTable.cpp @@ -18,33 +18,33 @@ CDZoneTableTable::CDZoneTableTable(void) { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ZoneTable"); while (!tableData.eof()) { CDZoneTable entry; - entry.zoneID = tableData.getIntField(0, -1); - entry.locStatus = tableData.getIntField(1, -1); - entry.zoneName = tableData.getStringField(2, ""); - entry.scriptID = tableData.getIntField(3, -1); - entry.ghostdistance_min = tableData.getFloatField(4, -1.0f); - entry.ghostdistance = tableData.getFloatField(5, -1.0f); - entry.population_soft_cap = tableData.getIntField(6, -1); - entry.population_hard_cap = tableData.getIntField(7, -1); - UNUSED(entry.DisplayDescription = tableData.getStringField(8, "")); - UNUSED(entry.mapFolder = tableData.getStringField(9, "")); - entry.smashableMinDistance = tableData.getFloatField(10, -1.0f); - entry.smashableMaxDistance = tableData.getFloatField(11, -1.0f); - UNUSED(entry.mixerProgram = tableData.getStringField(12, "")); - UNUSED(entry.clientPhysicsFramerate = tableData.getStringField(13, "")); - UNUSED(entry.serverPhysicsFramerate = tableData.getStringField(14, "")); - entry.zoneControlTemplate = tableData.getIntField(15, -1); - entry.widthInChunks = tableData.getIntField(16, -1); - entry.heightInChunks = tableData.getIntField(17, -1); - entry.petsAllowed = tableData.getIntField(18, -1) == 1 ? true : false; - entry.localize = tableData.getIntField(19, -1) == 1 ? true : false; - entry.fZoneWeight = tableData.getFloatField(20, -1.0f); - UNUSED(entry.thumbnail = tableData.getStringField(21, "")); - entry.PlayerLoseCoinsOnDeath = tableData.getIntField(22, -1) == 1 ? true : false; - UNUSED(entry.disableSaveLoc = tableData.getIntField(23, -1) == 1 ? true : false); - entry.teamRadius = tableData.getFloatField(24, -1.0f); - UNUSED(entry.gate_version = tableData.getStringField(25, "")); - UNUSED(entry.mountsAllowed = tableData.getIntField(26, -1) == 1 ? true : false); + entry.zoneID = tableData.getIntField("zoneID", -1); + entry.locStatus = tableData.getIntField("locStatus", -1); + entry.zoneName = tableData.getStringField("zoneName", ""); + entry.scriptID = tableData.getIntField("scriptID", -1); + entry.ghostdistance_min = tableData.getFloatField("ghostdistance_min", -1.0f); + entry.ghostdistance = tableData.getFloatField("ghostdistance", -1.0f); + entry.population_soft_cap = tableData.getIntField("population_soft_cap", -1); + entry.population_hard_cap = tableData.getIntField("population_hard_cap", -1); + UNUSED(entry.DisplayDescription = tableData.getStringField("DisplayDescription", "")); + UNUSED(entry.mapFolder = tableData.getStringField("mapFolder", "")); + entry.smashableMinDistance = tableData.getFloatField("smashableMinDistance", -1.0f); + entry.smashableMaxDistance = tableData.getFloatField("smashableMaxDistance", -1.0f); + UNUSED(entry.mixerProgram = tableData.getStringField("mixerProgram", "")); + UNUSED(entry.clientPhysicsFramerate = tableData.getStringField("clientPhysicsFramerate", "")); + UNUSED(entry.serverPhysicsFramerate = tableData.getStringField("serverPhysicsFramerate", "")); + entry.zoneControlTemplate = tableData.getIntField("zoneControlTemplate", -1); + entry.widthInChunks = tableData.getIntField("widthInChunks", -1); + entry.heightInChunks = tableData.getIntField("heightInChunks", -1); + entry.petsAllowed = tableData.getIntField("petsAllowed", -1) == 1 ? true : false; + entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false; + entry.fZoneWeight = tableData.getFloatField("fZoneWeight", -1.0f); + UNUSED(entry.thumbnail = tableData.getStringField("thumbnail", "")); + entry.PlayerLoseCoinsOnDeath = tableData.getIntField("PlayerLoseCoinsOnDeath", -1) == 1 ? true : false; + UNUSED(entry.disableSaveLoc = tableData.getIntField("disableSaveLoc", -1) == 1 ? true : false); + entry.teamRadius = tableData.getFloatField("teamRadius", -1.0f); + UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); + UNUSED(entry.mountsAllowed = tableData.getIntField("mountsAllowed", -1) == 1 ? true : false); this->m_Entries.insert(std::make_pair(entry.zoneID, entry)); tableData.nextRow(); @@ -53,14 +53,6 @@ CDZoneTableTable::CDZoneTableTable(void) { tableData.finalize(); } -//! Destructor -CDZoneTableTable::~CDZoneTableTable(void) {} - -//! Returns the table's name -std::string CDZoneTableTable::GetName(void) const { - return "ZoneTable"; -} - //! Queries the table with a zoneID to find. const CDZoneTable* CDZoneTableTable::Query(unsigned int zoneID) { const auto& iter = m_Entries.find(zoneID); @@ -71,3 +63,4 @@ const CDZoneTable* CDZoneTableTable::Query(unsigned int zoneID) { return nullptr; } + diff --git a/dDatabase/Tables/CDZoneTableTable.h b/dDatabase/Tables/CDZoneTableTable.h index c115a38a..f844fd25 100644 --- a/dDatabase/Tables/CDZoneTableTable.h +++ b/dDatabase/Tables/CDZoneTableTable.h @@ -3,12 +3,6 @@ // Custom Classes #include "CDTable.h" -/*! - \file CDZoneTableTable.hpp - \brief Contains data for the ZoneTable table - */ - - //! ZoneTable Struct struct CDZoneTable { unsigned int zoneID; //!< The Zone ID of the object unsigned int locStatus; //!< The Locale Status(?) @@ -39,28 +33,13 @@ struct CDZoneTable { UNUSED(bool mountsAllowed); //!< Whether or not mounts are allowed }; -//! ZoneTable table -class CDZoneTableTable : public CDTable { +class CDZoneTableTable : public CDTable { private: std::map m_Entries; public: + CDZoneTableTable(); - //! Constructor - CDZoneTableTable(void); - - //! Destructor - ~CDZoneTableTable(void); - - //! Returns the table's name - /*! - \return The table name - */ - std::string GetName(void) const override; - - //! Queries the table with a zoneID to find. - /*! - \param id The zoneID - */ + // Queries the table with a zoneID to find. const CDZoneTable* Query(unsigned int zoneID); }; diff --git a/dGame/Character.cpp b/dGame/Character.cpp index 440c30c1..b8d08854 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -15,6 +15,10 @@ #include "Zone.h" #include "ChatPackets.h" #include "Inventory.h" +#include "InventoryComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "eGameMasterLevel.h" Character::Character(uint32_t id, User* parentUser) { //First load the name, etc: @@ -33,7 +37,7 @@ Character::Character(uint32_t id, User* parentUser) { m_UnapprovedName = res->getString(2).c_str(); m_NameRejected = res->getBoolean(3); m_PropertyCloneID = res->getUInt(4); - m_PermissionMap = static_cast(res->getUInt64(5)); + m_PermissionMap = static_cast(res->getUInt64(5)); } delete res; @@ -92,7 +96,7 @@ void Character::UpdateFromDatabase() { m_UnapprovedName = res->getString(2).c_str(); m_NameRejected = res->getBoolean(3); m_PropertyCloneID = res->getUInt(4); - m_PermissionMap = static_cast(res->getUInt64(5)); + m_PermissionMap = static_cast(res->getUInt64(5)); } delete res; @@ -201,7 +205,9 @@ void Character::DoQuickXMLDataParse() { tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); if (character) { character->QueryAttribute("cc", &m_Coins); - character->QueryAttribute("gm", &m_GMLevel); + int32_t gm_level = 0; + character->QueryAttribute("gm", &gm_level); + m_GMLevel = static_cast(gm_level); uint64_t lzidConcat = 0; if (character->FindAttribute("lzid")) { @@ -264,14 +270,17 @@ void Character::DoQuickXMLDataParse() { if (flags) { auto* currentChild = flags->FirstChildElement(); while (currentChild) { - uint32_t index = 0; - uint64_t value = 0; const auto* temp = currentChild->Attribute("v"); + const auto* id = currentChild->Attribute("id"); + if (temp && id) { + uint32_t index = 0; + uint64_t value = 0; - index = std::stoul(currentChild->Attribute("id")); - value = std::stoull(temp); + index = std::stoul(id); + value = std::stoull(temp); - m_PlayerFlags.insert(std::make_pair(index, value)); + m_PlayerFlags.insert(std::make_pair(index, value)); + } currentChild = currentChild->NextSiblingElement(); } } @@ -298,7 +307,7 @@ void Character::SaveXMLToDatabase() { tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); if (character) { - character->SetAttribute("gm", m_GMLevel); + character->SetAttribute("gm", static_cast(m_GMLevel)); character->SetAttribute("cc", m_Coins); auto zoneInfo = dZoneManager::Instance()->GetZone()->GetZoneID(); @@ -351,6 +360,13 @@ void Character::SaveXMLToDatabase() { flags->LinkEndChild(f); } + // Prevents the news feed from showing up on world transfers + if (GetPlayerFlag(ePlayerFlags::IS_NEWS_SCREEN_VISIBLE)) { + auto* s = m_Doc->NewElement("s"); + s->SetAttribute("si", ePlayerFlags::IS_NEWS_SCREEN_VISIBLE); + flags->LinkEndChild(s); + } + SaveXmlRespawnCheckpoints(); //Call upon the entity to update our xmlDoc: @@ -361,6 +377,31 @@ void Character::SaveXMLToDatabase() { m_OurEntity->UpdateXMLDoc(m_Doc); + WriteToDatabase(); + + //For metrics, log the time it took to save: + auto end = std::chrono::system_clock::now(); + std::chrono::duration elapsed = end - start; + Game::logger->Log("Character", "Saved character to Database in: %fs", elapsed.count()); +} + +void Character::SetIsNewLogin() { + // If we dont have a flag element, then we cannot have a s element as a child of flag. + auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + if (!flags) return; + + auto* currentChild = flags->FirstChildElement(); + while (currentChild) { + if (currentChild->Attribute("si")) { + flags->DeleteChild(currentChild); + Game::logger->Log("Character", "Removed isLoggedIn flag from character %i, saving character to database", GetID()); + WriteToDatabase(); + } + currentChild = currentChild->NextSiblingElement(); + } +} + +void Character::WriteToDatabase() { //Dump our xml into m_XMLData: auto* printer = new tinyxml2::XMLPrinter(0, true, 0); m_Doc->Print(printer); @@ -372,12 +413,6 @@ void Character::SaveXMLToDatabase() { stmt->setUInt(2, m_ID); stmt->execute(); delete stmt; - - //For metrics, log the time it took to save: - auto end = std::chrono::system_clock::now(); - std::chrono::duration elapsed = end - start; - Game::logger->Log("Character", "Saved character to Database in: %fs", elapsed.count()); - delete printer; } @@ -393,7 +428,7 @@ void Character::SetPlayerFlag(const uint32_t flagId, const bool value) { auto* missionComponent = player->GetComponent(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PLAYER_FLAG, flagId); + missionComponent->Progress(eMissionTaskType::PLAYER_FLAG, flagId); } } } @@ -505,7 +540,7 @@ void Character::OnZoneLoad() { if (missionComponent != nullptr) { // Fix the monument race flag - if (missionComponent->GetMissionState(319) >= MissionState::MISSION_STATE_READY_TO_COMPLETE) { + if (missionComponent->GetMissionState(319) >= eMissionState::READY_TO_COMPLETE) { SetPlayerFlag(33, true); } } @@ -513,14 +548,14 @@ void Character::OnZoneLoad() { const auto maxGMLevel = m_ParentUser->GetMaxGMLevel(); // This does not apply to the GMs - if (maxGMLevel > GAME_MASTER_LEVEL_CIVILIAN) { + if (maxGMLevel > eGameMasterLevel::CIVILIAN) { return; } /** * Restrict old character to 1 million coins */ - if (HasPermission(PermissionMap::Old)) { + if (HasPermission(ePermissionMap::Old)) { if (GetCoins() > 1000000) { SetCoins(1000000, eLootSourceType::LOOT_SOURCE_NONE); } @@ -538,11 +573,11 @@ void Character::OnZoneLoad() { } } -PermissionMap Character::GetPermissionMap() const { +ePermissionMap Character::GetPermissionMap() const { return m_PermissionMap; } -bool Character::HasPermission(PermissionMap permission) const { +bool Character::HasPermission(ePermissionMap permission) const { return (static_cast(m_PermissionMap) & static_cast(permission)) != 0; } @@ -589,3 +624,21 @@ void Character::SendMuteNotice() const { ChatPackets::SendSystemMessage(GetEntity()->GetSystemAddress(), u"You are muted until " + timeStr); } + +void Character::SetBillboardVisible(bool visible) { + if (m_BillboardVisible == visible) return; + m_BillboardVisible = visible; + + GameMessages::SendSetNamebillboardState(UNASSIGNED_SYSTEM_ADDRESS, m_OurEntity->GetObjectID()); + + if (!visible) return; + + // The GameMessage we send for turning the nameplate off just deletes the BillboardSubcomponent from the parent component. + // Because that same message does not allow for custom parameters, we need to create the BillboardSubcomponent a different way + // This workaround involves sending an unrelated GameMessage that does not apply to player entites, + // but forces the client to create the necessary SubComponent that controls the billboard. + GameMessages::SendShowBillboardInteractIcon(UNASSIGNED_SYSTEM_ADDRESS, m_OurEntity->GetObjectID()); + + // Now turn off the billboard for the owner. + GameMessages::SendSetNamebillboardState(m_OurEntity->GetSystemAddress(), m_OurEntity->GetObjectID()); +} diff --git a/dGame/Character.h b/dGame/Character.h index 52bff83d..2f0abba5 100644 --- a/dGame/Character.h +++ b/dGame/Character.h @@ -9,11 +9,13 @@ #include "NiPoint3.h" #include "NiQuaternion.h" -#include "PermissionMap.h" +#include "ePermissionMap.h" class User; struct Packet; class Entity; +enum class ePermissionMap : uint64_t; +enum class eGameMasterLevel : uint8_t; /** * Meta information about a character, like their name and style @@ -23,6 +25,10 @@ public: Character(uint32_t id, User* parentUser); ~Character(); + /** + * Write the current m_Doc to the database for saving. + */ + void WriteToDatabase(); void SaveXMLToDatabase(); void UpdateFromDatabase(); @@ -32,6 +38,15 @@ public: const std::string& GetXMLData() const { return m_XMLData; } tinyxml2::XMLDocument* GetXMLDoc() const { return m_Doc; } + /** + * Out of abundance of safety and clarity of what this saves, this is its own function. + * + * Clears the s element from the flag element and saves the xml to the database. Used to prevent the news + * feed from showing up on world transfers. + * + */ + void SetIsNewLogin(); + /** * Gets the database ID of the character * @return the database ID of the character @@ -294,13 +309,13 @@ public: * Gets the GM level of the character * @return the GM level */ - int32_t GetGMLevel() const { return m_GMLevel; } + eGameMasterLevel GetGMLevel() const { return m_GMLevel; } /** * Sets the GM level of the character * @param value the GM level to set */ - void SetGMLevel(uint8_t value) { m_GMLevel = value; } + void SetGMLevel(eGameMasterLevel value) { m_GMLevel = value; } /** * Gets the current amount of coins of the character @@ -372,14 +387,14 @@ public: * Gets the permissions of the character, determining what actions a character may do * @return the permissions for this character */ - PermissionMap GetPermissionMap() const; + ePermissionMap GetPermissionMap() const; /** * Check if this character has a certain permission * @param permission the ID of the permission to check for * @return whether the character has the specified permission */ - bool HasPermission(PermissionMap permission) const; + bool HasPermission(ePermissionMap permission) const; /** * Gets all the emotes this character has unlocked so far @@ -427,7 +442,7 @@ public: /** * @brief Get the flying state - * @return value of the flying state + * @return value of the flying state */ bool GetIsFlying() { return m_IsFlying; } @@ -437,6 +452,10 @@ public: */ void SetIsFlying(bool isFlying) { m_IsFlying = isFlying; } + bool GetBillboardVisible() { return m_BillboardVisible; } + + void SetBillboardVisible(bool visible); + private: /** * The ID of this character. First 32 bits of the ObjectID. @@ -463,12 +482,12 @@ private: * * @see eGameMasterLevel */ - int32_t m_GMLevel; + eGameMasterLevel m_GMLevel; /** * Bitmap of permission attributes this character has. */ - PermissionMap m_PermissionMap; + ePermissionMap m_PermissionMap; /** * The default name of this character @@ -638,6 +657,11 @@ private: */ bool m_IsFlying = false; + /** + * True if billboard (referred to as nameplate for end users) is visible, false otherwise + */ + bool m_BillboardVisible = true; + /** * Queries the character XML and updates all the fields of this object * NOTE: quick as there's no DB lookups diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 82cc3c33..95a550a6 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -17,6 +17,13 @@ #include "UserManager.h" #include "dpWorld.h" #include "Player.h" +#include "LUTriggers.h" +#include "User.h" +#include "EntityTimer.h" +#include "EntityCallbackTimer.h" +#include "Loot.h" +#include "eMissionTaskType.h" +#include "eTriggerEventType.h" //Component includes: #include "Component.h" @@ -62,15 +69,29 @@ #include "ShootingGalleryComponent.h" #include "RailActivatorComponent.h" #include "LUPExhibitComponent.h" +#include "TriggerComponent.h" +#include "eGameMasterLevel.h" +#include "eReplicaComponentType.h" + +// Table includes +#include "CDComponentsRegistryTable.h" +#include "CDCurrencyTableTable.h" +#include "CDMovementAIComponentTable.h" +#include "CDProximityMonitorComponentTable.h" +#include "CDRebuildComponentTable.h" +#include "CDObjectSkillsTable.h" +#include "CDObjectsTable.h" +#include "CDScriptComponentTable.h" +#include "CDSkillBehaviorTable.h" +#include "CDZoneTableTable.h" Entity::Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity) { m_ObjectID = objectID; m_TemplateID = info.lot; m_ParentEntity = parentEntity; m_Character = nullptr; - m_GMLevel = 0; + m_GMLevel = eGameMasterLevel::CIVILIAN; m_CollectibleID = 0; - m_Trigger = nullptr; //new LUTriggers::Trigger(); m_NetworkID = 0; m_Groups = {}; m_OwnerOverride = LWOOBJID_EMPTY; @@ -126,30 +147,9 @@ void Entity::Initialize() { * Setup trigger */ - const auto triggerName = GetVarAsString(u"trigger_id"); + const auto triggerInfo = GetVarAsString(u"trigger_id"); - if (!triggerName.empty()) { - std::stringstream ss(triggerName); - std::vector tokens; - std::string token; - while (std::getline(ss, token, ':')) { - tokens.push_back(token); - } - - uint32_t sceneID = std::stoi(tokens[0]); - uint32_t triggerID = std::stoi(tokens[1]); - - if (m_Trigger != nullptr) { - delete m_Trigger; - m_Trigger = nullptr; - } - - m_Trigger = dZoneManager::Instance()->GetZone()->GetTrigger(sceneID, triggerID); - - if (m_Trigger == nullptr) { - m_Trigger = new LUTriggers::Trigger(); - } - } + if (!triggerInfo.empty()) m_Components.emplace(eReplicaComponentType::TRIGGER, new TriggerComponent(this, triggerInfo)); /** * Setup groups @@ -171,30 +171,30 @@ void Entity::Initialize() { } // Get the registry table - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); /** * Special case for BBB models. They have components not corresponding to the registry. */ if (m_TemplateID == 14) { - const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SIMPLE_PHYSICS); + const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS); SimplePhysicsComponent* comp = new SimplePhysicsComponent(simplePhysicsComponentID, this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SIMPLE_PHYSICS, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SIMPLE_PHYSICS, comp)); ModelComponent* modelcomp = new ModelComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_MODEL, modelcomp)); + m_Components.insert(std::make_pair(eReplicaComponentType::MODEL, modelcomp)); RenderComponent* render = new RenderComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_RENDER, render)); + m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render)); auto destroyableComponent = new DestroyableComponent(this); destroyableComponent->SetHealth(1); destroyableComponent->SetMaxHealth(1.0f); destroyableComponent->SetFaction(-1, true); destroyableComponent->SetIsSmashable(true); - m_Components.insert(std::make_pair(COMPONENT_TYPE_DESTROYABLE, destroyableComponent)); + m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, destroyableComponent)); // We have all our components. return; } @@ -207,47 +207,47 @@ void Entity::Initialize() { if (GetParentUser()) { auto missions = new MissionComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_MISSION, missions)); + m_Components.insert(std::make_pair(eReplicaComponentType::MISSION, missions)); missions->LoadFromXml(m_Character->GetXMLDoc()); } - uint32_t petComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PET); + uint32_t petComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PET); if (petComponentId > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_PET, new PetComponent(this, petComponentId))); + m_Components.insert(std::make_pair(eReplicaComponentType::PET, new PetComponent(this, petComponentId))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ZONE_CONTROL) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_ZONE_CONTROL, nullptr)); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ZONE_CONTROL) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::ZONE_CONTROL, nullptr)); } - uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_POSSESSABLE); + uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE); if (possessableComponentId > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSABLE, new PossessableComponent(this, possessableComponentId))); + m_Components.insert(std::make_pair(eReplicaComponentType::POSSESSABLE, new PossessableComponent(this, possessableComponentId))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MODULE_ASSEMBLY) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_MODULE_ASSEMBLY, new ModuleAssemblyComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODULE_ASSEMBLY) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::MODULE_ASSEMBLY, new ModuleAssemblyComponent(this))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RACING_STATS) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_RACING_STATS, nullptr)); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_STATS) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::RACING_STATS, nullptr)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_EXHIBIT, -1) >= 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_EXHIBIT, new LUPExhibitComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::LUP_EXHIBIT, -1) >= 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::LUP_EXHIBIT, new LUPExhibitComponent(this))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RACING_CONTROL) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_RACING_CONTROL, new RacingControlComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_CONTROL) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::RACING_CONTROL, new RacingControlComponent(this))); } - const auto propertyEntranceComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROPERTY_ENTRANCE); + const auto propertyEntranceComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_ENTRANCE); if (propertyEntranceComponentID > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_PROPERTY_ENTRANCE, + m_Components.insert(std::make_pair(eReplicaComponentType::PROPERTY_ENTRANCE, new PropertyEntranceComponent(propertyEntranceComponentID, this))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_CONTROLLABLE_PHYSICS) > 0) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS) > 0) { ControllablePhysicsComponent* controllablePhysics = new ControllablePhysicsComponent(this); if (m_Character) { @@ -282,68 +282,68 @@ void Entity::Initialize() { controllablePhysics->SetRotation(m_DefaultRotation); } - m_Components.insert(std::make_pair(COMPONENT_TYPE_CONTROLLABLE_PHYSICS, controllablePhysics)); + m_Components.insert(std::make_pair(eReplicaComponentType::CONTROLLABLE_PHYSICS, controllablePhysics)); } // If an entity is marked a phantom, simple physics is made into phantom phyics. bool markedAsPhantom = GetVar(u"markedAsPhantom"); - const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SIMPLE_PHYSICS); + const auto simplePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SIMPLE_PHYSICS); if (!markedAsPhantom && simplePhysicsComponentID > 0) { SimplePhysicsComponent* comp = new SimplePhysicsComponent(simplePhysicsComponentID, this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SIMPLE_PHYSICS, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SIMPLE_PHYSICS, comp)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS) > 0) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS) > 0) { RigidbodyPhantomPhysicsComponent* comp = new RigidbodyPhantomPhysicsComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS, comp)); } - if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PHANTOM_PHYSICS) > 0) { + if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS) > 0) { PhantomPhysicsComponent* phantomPhysics = new PhantomPhysicsComponent(this); phantomPhysics->SetPhysicsEffectActive(false); - m_Components.insert(std::make_pair(COMPONENT_TYPE_PHANTOM_PHYSICS, phantomPhysics)); + m_Components.insert(std::make_pair(eReplicaComponentType::PHANTOM_PHYSICS, phantomPhysics)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_VEHICLE_PHYSICS) > 0) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VEHICLE_PHYSICS) > 0) { VehiclePhysicsComponent* vehiclePhysicsComponent = new VehiclePhysicsComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_VEHICLE_PHYSICS, vehiclePhysicsComponent)); + m_Components.insert(std::make_pair(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent)); vehiclePhysicsComponent->SetPosition(m_DefaultPosition); vehiclePhysicsComponent->SetRotation(m_DefaultRotation); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SOUND_TRIGGER, -1) != -1) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) { auto* comp = new SoundTriggerComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SOUND_TRIGGER, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SOUND_TRIGGER, comp)); } //Also check for the collectible id: m_CollectibleID = GetVarAs(u"collectible_id"); - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BUFF) > 0) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF) > 0) { BuffComponent* comp = new BuffComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_BUFF, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::BUFF, comp)); } - int collectibleComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_COLLECTIBLE); + int collectibleComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::COLLECTIBLE); if (collectibleComponentID > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_COLLECTIBLE, nullptr)); + m_Components.insert(std::make_pair(eReplicaComponentType::COLLECTIBLE, nullptr)); } /** * Multiple components require the destructible component. */ - int buffComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BUFF); - int rebuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_REBUILD); + int buffComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF); + int rebuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD); int componentID = 0; if (collectibleComponentID > 0) componentID = collectibleComponentID; if (rebuildComponentID > 0) componentID = rebuildComponentID; if (buffComponentID > 0) componentID = buffComponentID; - CDDestructibleComponentTable* destCompTable = CDClientManager::Instance()->GetTable("DestructibleComponent"); + CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable(); std::vector destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); }); if (buffComponentID > 0 || collectibleComponentID > 0) { @@ -355,7 +355,7 @@ void Entity::Initialize() { std::vector destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); }); if (destCompData.size() > 0) { - if (HasComponent(COMPONENT_TYPE_RACING_STATS)) { + if (HasComponent(eReplicaComponentType::RACING_STATS)) { destCompData[0].imagination = 60; } @@ -375,7 +375,7 @@ void Entity::Initialize() { uint32_t npcMinLevel = destCompData[0].level; uint32_t currencyIndex = destCompData[0].CurrencyIndex; - CDCurrencyTableTable* currencyTable = CDClientManager::Instance()->GetTable("CurrencyTable"); + CDCurrencyTableTable* currencyTable = CDClientManager::Instance().GetTable(); std::vector currencyValues = currencyTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == currencyIndex && entry.npcminlevel == npcMinLevel); }); if (currencyValues.size() > 0) { @@ -399,8 +399,8 @@ void Entity::Initialize() { comp->AddFaction(6); //Smashables // A race car has 60 imagination, other entities defaults to 0. - comp->SetImagination(HasComponent(COMPONENT_TYPE_RACING_STATS) ? 60 : 0); - comp->SetMaxImagination(HasComponent(COMPONENT_TYPE_RACING_STATS) ? 60 : 0); + comp->SetImagination(HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0); + comp->SetMaxImagination(HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0); } } @@ -418,43 +418,43 @@ void Entity::Initialize() { } } - m_Components.insert(std::make_pair(COMPONENT_TYPE_DESTROYABLE, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, comp)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_CHARACTER) > 0 || m_Character) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CHARACTER) > 0 || m_Character) { // Character Component always has a possessor, level, and forced movement components - m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSOR, new PossessorComponent(this))); + m_Components.insert(std::make_pair(eReplicaComponentType::POSSESSOR, new PossessorComponent(this))); // load in the xml for the level auto* levelComp = new LevelProgressionComponent(this); levelComp->LoadFromXml(m_Character->GetXMLDoc()); - m_Components.insert(std::make_pair(COMPONENT_TYPE_LEVEL_PROGRESSION, levelComp)); + m_Components.insert(std::make_pair(eReplicaComponentType::LEVEL_PROGRESSION, levelComp)); - m_Components.insert(std::make_pair(COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT, new PlayerForcedMovementComponent(this))); + m_Components.insert(std::make_pair(eReplicaComponentType::PLAYER_FORCED_MOVEMENT, new PlayerForcedMovementComponent(this))); CharacterComponent* charComp = new CharacterComponent(this, m_Character); charComp->LoadFromXml(m_Character->GetXMLDoc()); - m_Components.insert(std::make_pair(COMPONENT_TYPE_CHARACTER, charComp)); + m_Components.insert(std::make_pair(eReplicaComponentType::CHARACTER, charComp)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_INVENTORY) > 0 || m_Character) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) { InventoryComponent* comp = nullptr; if (m_Character) comp = new InventoryComponent(this, m_Character->GetXMLDoc()); else comp = new InventoryComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_INVENTORY, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::INVENTORY, comp)); } // if this component exists, then we initialize it. it's value is always 0 - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ROCKET_LAUNCH_LUP, -1) != -1) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH_LUP, -1) != -1) { auto comp = new RocketLaunchLupComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_ROCKET_LAUNCH_LUP, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::ROCKET_LAUNCH_LUP, comp)); } /** * This is a bit of a mess */ - CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable("ScriptComponent"); - int scriptComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SCRIPT); + CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable(); + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPT, -1); std::string scriptName = ""; bool client = false; @@ -496,13 +496,13 @@ void Entity::Initialize() { scriptName = customScriptServer; } - if (!scriptName.empty() || client || m_Character) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_SCRIPT, new ScriptComponent(this, scriptName, true, client && scriptName.empty()))); + if (!scriptName.empty() || client || m_Character || scriptComponentID >= 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, new ScriptComponent(this, scriptName, true, client && scriptName.empty()))); } // ZoneControl script if (m_TemplateID == 2365) { - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable(); const auto zoneID = dZoneManager::Instance()->GetZoneID(); const CDZoneTable* zoneData = zoneTable->Query(zoneID.GetMapID()); @@ -511,26 +511,26 @@ void Entity::Initialize() { CDScriptComponent zoneScriptData = scriptCompTable->GetByID(zoneScriptID); ScriptComponent* comp = new ScriptComponent(this, zoneScriptData.script_name, true); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SCRIPT, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, comp)); } } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SKILL, -1) != -1 || m_Character) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SKILL, -1) != -1 || m_Character) { SkillComponent* comp = new SkillComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SKILL, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SKILL, comp)); } - const auto combatAiId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BASE_COMBAT_AI); + const auto combatAiId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BASE_COMBAT_AI); if (combatAiId > 0) { BaseCombatAIComponent* comp = new BaseCombatAIComponent(this, combatAiId); - m_Components.insert(std::make_pair(COMPONENT_TYPE_BASE_COMBAT_AI, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::BASE_COMBAT_AI, comp)); } - if (int componentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_REBUILD) > 0) { + if (int componentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD) > 0) { RebuildComponent* comp = new RebuildComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_REBUILD, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::QUICK_BUILD, comp)); - CDRebuildComponentTable* rebCompTable = CDClientManager::Instance()->GetTable("RebuildComponent"); + CDRebuildComponentTable* rebCompTable = CDClientManager::Instance().GetTable(); std::vector rebCompData = rebCompTable->Query([=](CDRebuildComponent entry) { return (entry.id == rebuildComponentID); }); if (rebCompData.size() > 0) { @@ -568,89 +568,89 @@ void Entity::Initialize() { } } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SWITCH, -1) != -1) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SWITCH, -1) != -1) { SwitchComponent* comp = new SwitchComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_SWITCH, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::SWITCH, comp)); } - if ((compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_VENDOR) > 0)) { + if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VENDOR) > 0)) { VendorComponent* comp = new VendorComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_VENDOR, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::VENDOR, comp)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROPERTY_VENDOR, -1) != -1) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) { auto* component = new PropertyVendorComponent(this); - m_Components.insert_or_assign(COMPONENT_TYPE_PROPERTY_VENDOR, component); + m_Components.insert_or_assign(eReplicaComponentType::PROPERTY_VENDOR, component); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROPERTY_MANAGEMENT, -1) != -1) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_MANAGEMENT, -1) != -1) { auto* component = new PropertyManagementComponent(this); - m_Components.insert_or_assign(COMPONENT_TYPE_PROPERTY_MANAGEMENT, component); + m_Components.insert_or_assign(eReplicaComponentType::PROPERTY_MANAGEMENT, component); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BOUNCER, -1) != -1) { // you have to determine it like this because all bouncers have a componentID of 0 + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BOUNCER, -1) != -1) { // you have to determine it like this because all bouncers have a componentID of 0 BouncerComponent* comp = new BouncerComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_BOUNCER, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::BOUNCER, comp)); } - if ((compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RENDER) > 0 && m_TemplateID != 2365) || m_Character) { + if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER) > 0 && m_TemplateID != 2365) || m_Character) { RenderComponent* render = new RenderComponent(this); - m_Components.insert(std::make_pair(COMPONENT_TYPE_RENDER, render)); + m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render)); } - if ((compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MISSION_OFFER) > 0) || m_Character) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_MISSION_OFFER, new MissionOfferComponent(this, m_TemplateID))); + if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MISSION_OFFER) > 0) || m_Character) { + m_Components.insert(std::make_pair(eReplicaComponentType::MISSION_OFFER, new MissionOfferComponent(this, m_TemplateID))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_BUILD_BORDER, -1) != -1) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_BUILD_BORDER, new BuildBorderComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUILD_BORDER, -1) != -1) { + m_Components.insert(std::make_pair(eReplicaComponentType::BUILD_BORDER, new BuildBorderComponent(this))); } // Scripted activity component - int scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SCRIPTED_ACTIVITY); + int scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPTED_ACTIVITY); if ((scriptedActivityID > 0)) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_SCRIPTED_ACTIVITY, new ScriptedActivityComponent(this, scriptedActivityID))); + m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPTED_ACTIVITY, new ScriptedActivityComponent(this, scriptedActivityID))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MODEL, -1) != -1 && !GetComponent()) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_MODEL, new ModelComponent(this))); - if (m_Components.find(COMPONENT_TYPE_DESTROYABLE) == m_Components.end()) { + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent()) { + m_Components.insert(std::make_pair(eReplicaComponentType::MODEL, new ModelComponent(this))); + if (m_Components.find(eReplicaComponentType::DESTROYABLE) == m_Components.end()) { auto destroyableComponent = new DestroyableComponent(this); destroyableComponent->SetHealth(1); destroyableComponent->SetMaxHealth(1.0f); destroyableComponent->SetFaction(-1, true); destroyableComponent->SetIsSmashable(true); - m_Components.insert(std::make_pair(COMPONENT_TYPE_DESTROYABLE, destroyableComponent)); + m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, destroyableComponent)); } } PetComponent* petComponent; - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ITEM) > 0 && !TryGetComponent(COMPONENT_TYPE_PET, petComponent) && !HasComponent(COMPONENT_TYPE_MODEL)) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_ITEM, nullptr)); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ITEM) > 0 && !TryGetComponent(eReplicaComponentType::PET, petComponent) && !HasComponent(eReplicaComponentType::MODEL)) { + m_Components.insert(std::make_pair(eReplicaComponentType::ITEM, nullptr)); } // Shooting gallery component - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_SHOOTING_GALLERY) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_SHOOTING_GALLERY, new ShootingGalleryComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SHOOTING_GALLERY) > 0) { + m_Components.insert(std::make_pair(eReplicaComponentType::SHOOTING_GALLERY, new ShootingGalleryComponent(this))); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROPERTY, -1) != -1) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_PROPERTY, new PropertyComponent(this))); + if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY, -1) != -1) { + m_Components.insert(std::make_pair(eReplicaComponentType::PROPERTY, new PropertyComponent(this))); } - const int rocketId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_ROCKET_LAUNCH); + const int rocketId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH); if ((rocketId > 0)) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_ROCKET_LAUNCH, new RocketLaunchpadControlComponent(this, rocketId))); + m_Components.insert(std::make_pair(eReplicaComponentType::ROCKET_LAUNCH, new RocketLaunchpadControlComponent(this, rocketId))); } - const int32_t railComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_RAIL_ACTIVATOR); + const int32_t railComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RAIL_ACTIVATOR); if (railComponentID > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_RAIL_ACTIVATOR, new RailActivatorComponent(this, railComponentID))); + m_Components.insert(std::make_pair(eReplicaComponentType::RAIL_ACTIVATOR, new RailActivatorComponent(this, railComponentID))); } - int movementAIID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MOVEMENT_AI); + int movementAIID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVEMENT_AI); if (movementAIID > 0) { - CDMovementAIComponentTable* moveAITable = CDClientManager::Instance()->GetTable("MovementAIComponent"); + CDMovementAIComponentTable* moveAITable = CDClientManager::Instance().GetTable(); std::vector moveAIComp = moveAITable->Query([=](CDMovementAIComponent entry) {return (entry.id == movementAIID); }); if (moveAIComp.size() > 0) { @@ -673,7 +673,7 @@ void Entity::Initialize() { } } - m_Components.insert(std::make_pair(COMPONENT_TYPE_MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); + m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); } } else if (petComponentId > 0 || combatAiId > 0 && GetComponent()->GetTetherSpeed() > 0) { MovementAIInfo moveInfo = MovementAIInfo(); @@ -684,49 +684,37 @@ void Entity::Initialize() { moveInfo.wanderDelayMax = 5; moveInfo.wanderDelayMin = 2; - m_Components.insert(std::make_pair(COMPONENT_TYPE_MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); + m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); } - std::string attachedPath = GetVarAsString(u"attached_path"); - Path* path = nullptr; - if ((!attachedPath.empty())){ - path = const_cast(dZoneManager::Instance()->GetZone()->GetPath(attachedPath)); - } + std::string pathName = GetVarAsString(u"attached_path"); + const Path* path = dZoneManager::Instance()->GetZone()->GetPath(pathName); + //Check to see if we have an attached path and add the appropiate component to handle it: if (path){ - if (path->pathType == PathType::MovingPlatform || compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MOVING_PLATFORM, -1) != -1) { - MovingPlatformComponent* plat = new MovingPlatformComponent(this, attachedPath); - m_Components.insert(std::make_pair(COMPONENT_TYPE_MOVING_PLATFORM, plat)); - } else if (path->pathType == PathType::Movement && !HasComponent(COMPONENT_TYPE_MOVEMENT_AI)){ - MovementAIInfo moveInfo = MovementAIInfo(); - - // no wandering for you - moveInfo.movementType = ""; - moveInfo.wanderChance = 0; - moveInfo.wanderRadius = 0; - moveInfo.wanderSpeed = 0.0f; - moveInfo.wanderDelayMax = 0; - moveInfo.wanderDelayMin = 0; - - auto* movementAIcomp = new MovementAIComponent(this, moveInfo); - if (movementAIcomp) movementAIcomp->SetPath(path); - - m_Components.insert(std::make_pair(COMPONENT_TYPE_MOVEMENT_AI, movementAIcomp)); - } else if (path->pathType == PathType::Movement && HasComponent(COMPONENT_TYPE_MOVEMENT_AI)){ - auto* movementAIcomp = this->GetComponent(); - if (movementAIcomp) movementAIcomp->SetPath(path); - } + // if we have a moving platform path, then we need a moving platform component + if (path->pathType == PathType::MovingPlatform) { + MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName); + m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat)); + // else if we are a movement path + } /*else if (path->pathType == PathType::Movement) { + auto movementAIcomp = GetComponent(); + if (movementAIcomp){ + // TODO: set path in existing movementAIComp + } else { + // TODO: create movementAIcomp and set path + } + }*/ } - - int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_PROXIMITY_MONITOR); + int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR); if (proximityMonitorID > 0) { - CDProximityMonitorComponentTable* proxCompTable = CDClientManager::Instance()->GetTable("ProximityMonitorComponent"); + CDProximityMonitorComponentTable* proxCompTable = CDClientManager::Instance().GetTable(); std::vector proxCompData = proxCompTable->Query([=](CDProximityMonitorComponent entry) { return (entry.id == proximityMonitorID); }); if (proxCompData.size() > 0) { std::vector proximityStr = GeneralUtils::SplitString(proxCompData[0].Proximities, ','); ProximityMonitorComponent* comp = new ProximityMonitorComponent(this, std::stoi(proximityStr[0]), std::stoi(proximityStr[1])); - m_Components.insert(std::make_pair(COMPONENT_TYPE_PROXIMITY_MONITOR, comp)); + m_Components.insert(std::make_pair(eReplicaComponentType::PROXIMITY_MONITOR, comp)); } } @@ -739,7 +727,7 @@ void Entity::Initialize() { if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) { // Don't ghost what is likely large scene elements - if (m_Components.size() == 2 && HasComponent(COMPONENT_TYPE_SIMPLE_PHYSICS) && HasComponent(COMPONENT_TYPE_RENDER)) { + if (m_Components.size() == 2 && HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER)) { goto no_ghosting; } @@ -751,14 +739,14 @@ void Entity::Initialize() { */ if ( !EntityManager::IsExcludedFromGhosting(GetLOT()) && - !HasComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY) && - !HasComponent(COMPONENT_TYPE_MOVING_PLATFORM) && - !HasComponent(COMPONENT_TYPE_PHANTOM_PHYSICS) && - !HasComponent(COMPONENT_TYPE_PROPERTY) && - !HasComponent(COMPONENT_TYPE_RACING_CONTROL) && - !HasComponent(COMPONENT_TYPE_VEHICLE_PHYSICS) + !HasComponent(eReplicaComponentType::SCRIPTED_ACTIVITY) && + !HasComponent(eReplicaComponentType::MOVING_PLATFORM) && + !HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && + !HasComponent(eReplicaComponentType::PROPERTY) && + !HasComponent(eReplicaComponentType::RACING_CONTROL) && + !HasComponent(eReplicaComponentType::VEHICLE_PHYSICS) ) - //if (HasComponent(COMPONENT_TYPE_BASE_COMBAT_AI)) + //if (HasComponent(eReplicaComponentType::BASE_COMBAT_AI)) { m_IsGhostingCandidate = true; } @@ -768,21 +756,21 @@ void Entity::Initialize() { } // Special case for collectibles in Ninjago - if (HasComponent(COMPONENT_TYPE_COLLECTIBLE) && Game::server->GetZoneID() == 2000) { + if (HasComponent(eReplicaComponentType::COLLECTIBLE) && Game::server->GetZoneID() == 2000) { m_IsGhostingCandidate = true; } } no_ghosting: - TriggerEvent("OnCreate"); + TriggerEvent(eTriggerEventType::CREATE, this); if (m_Character) { auto* controllablePhysicsComponent = GetComponent(); auto* levelComponent = GetComponent(); - if (controllablePhysicsComponent != nullptr && levelComponent->GetLevel() >= 20) { - controllablePhysicsComponent->SetSpeedMultiplier(525.0f / 500.0f); + if (controllablePhysicsComponent && levelComponent) { + controllablePhysicsComponent->SetSpeedMultiplier(levelComponent->GetSpeedBase() / 500.0f); } } } @@ -803,7 +791,7 @@ User* Entity::GetParentUser() const { return static_cast(this)->GetParentUser(); } -Component* Entity::GetComponent(int32_t componentID) const { +Component* Entity::GetComponent(eReplicaComponentType componentID) const { const auto& index = m_Components.find(componentID); if (index == m_Components.end()) { @@ -813,11 +801,11 @@ Component* Entity::GetComponent(int32_t componentID) const { return index->second; } -bool Entity::HasComponent(const int32_t componentId) const { +bool Entity::HasComponent(const eReplicaComponentType componentId) const { return m_Components.find(componentId) != m_Components.end(); } -void Entity::AddComponent(const int32_t componentId, Component* component) { +void Entity::AddComponent(const eReplicaComponentType componentId, Component* component) { if (HasComponent(componentId)) { return; } @@ -827,8 +815,8 @@ void Entity::AddComponent(const int32_t componentId, Component* component) { std::vector Entity::GetScriptComponents() { std::vector comps; - for (std::pair p : m_Components) { - if (p.first == COMPONENT_TYPE_SCRIPT) { + for (std::pair p : m_Components) { + if (p.first == eReplicaComponentType::SCRIPT) { comps.push_back(static_cast(p.second)); } } @@ -836,11 +824,27 @@ std::vector Entity::GetScriptComponents() { return comps; } +void Entity::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName) { + if (notificationName == "HitOrHealResult" || notificationName == "Hit") { + auto* destroyableComponent = GetComponent(); + if (!destroyableComponent) return; + destroyableComponent->Subscribe(scriptObjId, scriptToAdd); + } +} + +void Entity::Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName) { + if (notificationName == "HitOrHealResult" || notificationName == "Hit") { + auto* destroyableComponent = GetComponent(); + if (!destroyableComponent) return; + destroyableComponent->Unsubscribe(scriptObjId); + } +} + void Entity::SetProximityRadius(float proxRadius, std::string name) { ProximityMonitorComponent* proxMon = GetComponent(); if (!proxMon) { proxMon = new ProximityMonitorComponent(this); - m_Components.insert_or_assign(COMPONENT_TYPE_PROXIMITY_MONITOR, proxMon); + m_Components.insert_or_assign(eReplicaComponentType::PROXIMITY_MONITOR, proxMon); } proxMon->SetProximityRadius(proxRadius, name); } @@ -849,12 +853,12 @@ void Entity::SetProximityRadius(dpEntity* entity, std::string name) { ProximityMonitorComponent* proxMon = GetComponent(); if (!proxMon) { proxMon = new ProximityMonitorComponent(this); - m_Components.insert_or_assign(COMPONENT_TYPE_PROXIMITY_MONITOR, proxMon); + m_Components.insert_or_assign(eReplicaComponentType::PROXIMITY_MONITOR, proxMon); } proxMon->SetProximityRadius(entity, name); } -void Entity::SetGMLevel(uint8_t value) { +void Entity::SetGMLevel(eGameMasterLevel value) { m_GMLevel = value; if (GetParentUser()) { Character* character = GetParentUser()->GetLastUsedChar(); @@ -936,12 +940,16 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke outBitStream->Write0(); //No ldf data } - if (m_Trigger != nullptr && m_Trigger->events.size() > 0) { - outBitStream->Write1(); - } else { + TriggerComponent* triggerComponent; + if (TryGetComponent(eReplicaComponentType::TRIGGER, triggerComponent)) { + // has trigger component, check to see if we have events to handle + auto* trigger = triggerComponent->GetTrigger(); + outBitStream->Write(trigger && trigger->events.size() > 0); + } else { // no trigger componenet, so definitely no triggers outBitStream->Write0(); } + if (m_ParentEntity != nullptr || m_SpawnerID != 0) { outBitStream->Write1(); if (m_ParentEntity != nullptr) outBitStream->Write(GeneralUtils::SetBit(m_ParentEntity->GetObjectID(), OBJECT_BIT_CLIENT)); @@ -962,7 +970,7 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke outBitStream->Write0(); //ObjectWorldState - if (m_GMLevel != 0) { + if (m_GMLevel != eGameMasterLevel::CIVILIAN) { outBitStream->Write1(); outBitStream->Write(m_GMLevel); } else outBitStream->Write0(); //No GM Level @@ -999,59 +1007,59 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType unsigned int flags = 0; PossessableComponent* possessableComponent; - if (TryGetComponent(COMPONENT_TYPE_POSSESSABLE, possessableComponent)) { + if (TryGetComponent(eReplicaComponentType::POSSESSABLE, possessableComponent)) { possessableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ModuleAssemblyComponent* moduleAssemblyComponent; - if (TryGetComponent(COMPONENT_TYPE_MODULE_ASSEMBLY, moduleAssemblyComponent)) { + if (TryGetComponent(eReplicaComponentType::MODULE_ASSEMBLY, moduleAssemblyComponent)) { moduleAssemblyComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ControllablePhysicsComponent* controllablePhysicsComponent; - if (TryGetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS, controllablePhysicsComponent)) { + if (TryGetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS, controllablePhysicsComponent)) { controllablePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } SimplePhysicsComponent* simplePhysicsComponent; - if (TryGetComponent(COMPONENT_TYPE_SIMPLE_PHYSICS, simplePhysicsComponent)) { + if (TryGetComponent(eReplicaComponentType::SIMPLE_PHYSICS, simplePhysicsComponent)) { simplePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } RigidbodyPhantomPhysicsComponent* rigidbodyPhantomPhysics; - if (TryGetComponent(COMPONENT_TYPE_RIGID_BODY_PHANTOM_PHYSICS, rigidbodyPhantomPhysics)) { + if (TryGetComponent(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS, rigidbodyPhantomPhysics)) { rigidbodyPhantomPhysics->Serialize(outBitStream, bIsInitialUpdate, flags); } VehiclePhysicsComponent* vehiclePhysicsComponent; - if (TryGetComponent(COMPONENT_TYPE_VEHICLE_PHYSICS, vehiclePhysicsComponent)) { + if (TryGetComponent(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent)) { vehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } PhantomPhysicsComponent* phantomPhysicsComponent; - if (TryGetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS, phantomPhysicsComponent)) { + if (TryGetComponent(eReplicaComponentType::PHANTOM_PHYSICS, phantomPhysicsComponent)) { phantomPhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } SoundTriggerComponent* soundTriggerComponent; - if (TryGetComponent(COMPONENT_TYPE_SOUND_TRIGGER, soundTriggerComponent)) { + if (TryGetComponent(eReplicaComponentType::SOUND_TRIGGER, soundTriggerComponent)) { soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } BuffComponent* buffComponent; - if (TryGetComponent(COMPONENT_TYPE_BUFF, buffComponent)) { + if (TryGetComponent(eReplicaComponentType::BUFF, buffComponent)) { buffComponent->Serialize(outBitStream, bIsInitialUpdate, flags); DestroyableComponent* destroyableComponent; - if (TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent)) { + if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) { destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } destroyableSerialized = true; } - if (HasComponent(COMPONENT_TYPE_COLLECTIBLE)) { + if (HasComponent(eReplicaComponentType::COLLECTIBLE)) { DestroyableComponent* destroyableComponent; - if (TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent) && !destroyableSerialized) { + if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) { destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } destroyableSerialized = true; @@ -1059,15 +1067,15 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType } PetComponent* petComponent; - if (TryGetComponent(COMPONENT_TYPE_PET, petComponent)) { + if (TryGetComponent(eReplicaComponentType::PET, petComponent)) { petComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } CharacterComponent* characterComponent; - if (TryGetComponent(COMPONENT_TYPE_CHARACTER, characterComponent)) { + if (TryGetComponent(eReplicaComponentType::CHARACTER, characterComponent)) { PossessorComponent* possessorComponent; - if (TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) { + if (TryGetComponent(eReplicaComponentType::POSSESSOR, possessorComponent)) { possessorComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } else { // Should never happen, but just to be safe @@ -1075,7 +1083,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType } LevelProgressionComponent* levelProgressionComponent; - if (TryGetComponent(COMPONENT_TYPE_LEVEL_PROGRESSION, levelProgressionComponent)) { + if (TryGetComponent(eReplicaComponentType::LEVEL_PROGRESSION, levelProgressionComponent)) { levelProgressionComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } else { // Should never happen, but just to be safe @@ -1083,7 +1091,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType } PlayerForcedMovementComponent* playerForcedMovementComponent; - if (TryGetComponent(COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT, playerForcedMovementComponent)) { + if (TryGetComponent(eReplicaComponentType::PLAYER_FORCED_MOVEMENT, playerForcedMovementComponent)) { playerForcedMovementComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } else { // Should never happen, but just to be safe @@ -1093,34 +1101,34 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType characterComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } - if (HasComponent(COMPONENT_TYPE_ITEM)) { + if (HasComponent(eReplicaComponentType::ITEM)) { outBitStream->Write0(); } InventoryComponent* inventoryComponent; - if (TryGetComponent(COMPONENT_TYPE_INVENTORY, inventoryComponent)) { + if (TryGetComponent(eReplicaComponentType::INVENTORY, inventoryComponent)) { inventoryComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ScriptComponent* scriptComponent; - if (TryGetComponent(COMPONENT_TYPE_SCRIPT, scriptComponent)) { + if (TryGetComponent(eReplicaComponentType::SCRIPT, scriptComponent)) { scriptComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } SkillComponent* skillComponent; - if (TryGetComponent(COMPONENT_TYPE_SKILL, skillComponent)) { + if (TryGetComponent(eReplicaComponentType::SKILL, skillComponent)) { skillComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } BaseCombatAIComponent* baseCombatAiComponent; - if (TryGetComponent(COMPONENT_TYPE_BASE_COMBAT_AI, baseCombatAiComponent)) { + if (TryGetComponent(eReplicaComponentType::BASE_COMBAT_AI, baseCombatAiComponent)) { baseCombatAiComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } RebuildComponent* rebuildComponent; - if (TryGetComponent(COMPONENT_TYPE_REBUILD, rebuildComponent)) { + if (TryGetComponent(eReplicaComponentType::QUICK_BUILD, rebuildComponent)) { DestroyableComponent* destroyableComponent; - if (TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent) && !destroyableSerialized) { + if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) { destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } destroyableSerialized = true; @@ -1128,64 +1136,64 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType } MovingPlatformComponent* movingPlatformComponent; - if (TryGetComponent(COMPONENT_TYPE_MOVING_PLATFORM, movingPlatformComponent)) { + if (TryGetComponent(eReplicaComponentType::MOVING_PLATFORM, movingPlatformComponent)) { movingPlatformComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } SwitchComponent* switchComponent; - if (TryGetComponent(COMPONENT_TYPE_SWITCH, switchComponent)) { + if (TryGetComponent(eReplicaComponentType::SWITCH, switchComponent)) { switchComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } VendorComponent* vendorComponent; - if (TryGetComponent(COMPONENT_TYPE_VENDOR, vendorComponent)) { + if (TryGetComponent(eReplicaComponentType::VENDOR, vendorComponent)) { vendorComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } BouncerComponent* bouncerComponent; - if (TryGetComponent(COMPONENT_TYPE_BOUNCER, bouncerComponent)) { + if (TryGetComponent(eReplicaComponentType::BOUNCER, bouncerComponent)) { bouncerComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ScriptedActivityComponent* scriptedActivityComponent; - if (TryGetComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY, scriptedActivityComponent)) { + if (TryGetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY, scriptedActivityComponent)) { scriptedActivityComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ShootingGalleryComponent* shootingGalleryComponent; - if (TryGetComponent(COMPONENT_TYPE_SHOOTING_GALLERY, shootingGalleryComponent)) { + if (TryGetComponent(eReplicaComponentType::SHOOTING_GALLERY, shootingGalleryComponent)) { shootingGalleryComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } RacingControlComponent* racingControlComponent; - if (TryGetComponent(COMPONENT_TYPE_RACING_CONTROL, racingControlComponent)) { + if (TryGetComponent(eReplicaComponentType::RACING_CONTROL, racingControlComponent)) { racingControlComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } LUPExhibitComponent* lupExhibitComponent; - if (TryGetComponent(COMPONENT_TYPE_EXHIBIT, lupExhibitComponent)) { + if (TryGetComponent(eReplicaComponentType::LUP_EXHIBIT, lupExhibitComponent)) { lupExhibitComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } ModelComponent* modelComponent; - if (TryGetComponent(COMPONENT_TYPE_MODEL, modelComponent)) { + if (TryGetComponent(eReplicaComponentType::MODEL, modelComponent)) { modelComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } RenderComponent* renderComponent; - if (TryGetComponent(COMPONENT_TYPE_RENDER, renderComponent)) { + if (TryGetComponent(eReplicaComponentType::RENDER, renderComponent)) { renderComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } if (modelComponent) { DestroyableComponent* destroyableComponent; - if (TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent) && !destroyableSerialized) { + if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) { destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags); destroyableSerialized = true; } } - if (HasComponent(COMPONENT_TYPE_ZONE_CONTROL)) { + if (HasComponent(eReplicaComponentType::ZONE_CONTROL)) { outBitStream->Write(0x40000000); } @@ -1300,7 +1308,7 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) { switchComp->EntityEnter(other); } - TriggerEvent("OnEnter", other); + TriggerEvent(eTriggerEventType::ENTER, other); // POI system const auto& poi = GetVar(u"POI"); @@ -1309,7 +1317,7 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) { auto* missionComponent = other->GetComponent(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_LOCATION, 0, 0, GeneralUtils::UTF16ToWTF8(poi)); + missionComponent->Progress(eMissionTaskType::EXPLORE, 0, 0, GeneralUtils::UTF16ToWTF8(poi)); } } @@ -1334,7 +1342,7 @@ void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) { auto* other = EntityManager::Instance()->GetEntity(otherEntity); if (!other) return; - TriggerEvent("OnLeave", other); + TriggerEvent(eTriggerEventType::EXIT, other); SwitchComponent* switchComp = GetComponent(); if (switchComp) { @@ -1382,7 +1390,7 @@ void Entity::OnEmoteReceived(const int32_t emote, Entity* target) { } void Entity::OnUse(Entity* originator) { - TriggerEvent("OnInteract"); + TriggerEvent(eTriggerEventType::INTERACT, originator); for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnUse(this, originator); @@ -1404,6 +1412,7 @@ void Entity::OnHitOrHealResult(Entity* attacker, int32_t damage) { } void Entity::OnHit(Entity* attacker) { + TriggerEvent(eTriggerEventType::HIT, attacker); for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnHit(this, attacker); } @@ -1581,7 +1590,7 @@ void Entity::PickupItem(const LWOOBJID& objectID) { InventoryComponent* inv = GetComponent(); if (!inv) return; - CDObjectsTable* objectsTable = CDClientManager::Instance()->GetTable("Objects"); + CDObjectsTable* objectsTable = CDClientManager::Instance().GetTable(); auto& droppedLoot = static_cast(this)->GetDroppedLoot(); @@ -1594,10 +1603,10 @@ void Entity::PickupItem(const LWOOBJID& objectID) { const CDObjects& object = objectsTable->GetByID(p.second.lot); if (object.id != 0 && object.type == "Powerup") { - CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable("ObjectSkills"); + CDObjectSkillsTable* skillsTable = CDClientManager::Instance().GetTable(); std::vector skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == p.second.lot); }); for (CDObjectSkills skill : skills) { - CDSkillBehaviorTable* skillBehTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + CDSkillBehaviorTable* skillBehTable = CDClientManager::Instance().GetTable(); CDSkillBehavior behaviorData = skillBehTable->GetSkillByID(skill.skillID); SkillComponent::HandleUnmanaged(behaviorData.behaviorID, GetObjectID()); @@ -1605,7 +1614,7 @@ void Entity::PickupItem(const LWOOBJID& objectID) { auto* missionComponent = GetComponent(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_POWERUP, skill.skillID); + missionComponent->Progress(eMissionTaskType::POWERUP, skill.skillID); } } } else { @@ -1726,94 +1735,9 @@ bool Entity::IsPlayer() const { return m_TemplateID == 1 && GetSystemAddress() != UNASSIGNED_SYSTEM_ADDRESS; } -void Entity::TriggerEvent(std::string eventID, Entity* optionalTarget) { - if (m_Trigger != nullptr && m_Trigger->enabled) { - for (LUTriggers::Event* triggerEvent : m_Trigger->events) { - if (triggerEvent->eventID == eventID) { - for (LUTriggers::Command* cmd : triggerEvent->commands) { - HandleTriggerCommand(cmd->id, cmd->target, cmd->targetName, cmd->args, optionalTarget); - } - } - } - } -} - -// This should probably get it's own triggers class at some point... -void Entity::HandleTriggerCommand(std::string id, std::string target, std::string targetName, std::string args, Entity* optionalTarget) { - std::vector argArray; - // Parse args - std::stringstream ssData(args); - std::string token; - char deliminator = ','; - - while (std::getline(ssData, token, deliminator)) { - std::string lowerToken; - for (char character : token) { - lowerToken.push_back(std::tolower(character)); // make lowercase to ensure it works - } - argArray.push_back(lowerToken); - } - - std::vector targetEntities; - if (target == "self") targetEntities.push_back(this); - if (target == "objGroup") targetEntities = EntityManager::Instance()->GetEntitiesInGroup(targetName); - if (optionalTarget) targetEntities.push_back(optionalTarget); - if (targetEntities.size() == 0) return; - for (Entity* targetEntity : targetEntities) { - if (!targetEntity) continue; - - if (id == "SetPhysicsVolumeEffect") { - PhantomPhysicsComponent* phanPhys = GetComponent(); - if (!phanPhys) return; - - phanPhys->SetPhysicsEffectActive(true); - uint32_t effectType = 0; - if (argArray[0] == "push") effectType = 0; - else if (argArray[0] == "attract") effectType = 1; - else if (argArray[0] == "repulse") effectType = 2; - else if (argArray[0] == "gravity") effectType = 3; - else if (argArray[0] == "friction") effectType = 4; - - phanPhys->SetEffectType(effectType); - phanPhys->SetDirectionalMultiplier(std::stof(argArray[1])); - if (argArray.size() > 4) { - NiPoint3 direction = NiPoint3::ZERO; - GeneralUtils::TryParse(argArray[2], direction.x); - GeneralUtils::TryParse(argArray[3], direction.y); - GeneralUtils::TryParse(argArray[4], direction.z); - phanPhys->SetDirection(direction); - } - if (argArray.size() > 5) { - phanPhys->SetMin(std::stoi(argArray[6])); - phanPhys->SetMax(std::stoi(argArray[7])); - } - - if (target == "self") { - EntityManager::Instance()->ConstructEntity(this); - } - } else if (id == "updateMission") { - CDMissionTasksTable* missionTasksTable = CDClientManager::Instance()->GetTable("MissionTasks"); - std::vector missionTasks = missionTasksTable->Query([=](CDMissionTasks entry) { - std::string lowerTargetGroup; - for (char character : entry.targetGroup) { - lowerTargetGroup.push_back(std::tolower(character)); // make lowercase to ensure it works - } - - return (lowerTargetGroup == argArray[4]); - }); - - for (const CDMissionTasks& task : missionTasks) { - MissionComponent* missionComponent = targetEntity->GetComponent(); - if (!missionComponent) continue; - - missionComponent->ForceProgress(task.id, task.uid, std::stoi(argArray[2])); - } - } else if (id == "fireEvent") { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(targetEntity)) { - script->OnFireEventServerSide(targetEntity, this, args, 0, 0, 0); - } - } - } +void Entity::TriggerEvent(eTriggerEventType event, Entity* optionalTarget) { + auto* triggerComponent = GetComponent(); + if (triggerComponent) triggerComponent->TriggerEvent(event, optionalTarget); } Entity* Entity::GetOwner() const { diff --git a/dGame/Entity.h b/dGame/Entity.h index 6c0968f8..f8abff31 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -4,29 +4,39 @@ #include #include #include +#include #include -#include "../thirdparty/raknet/Source/Replica.h" -#include "../thirdparty/raknet/Source/ReplicaManager.h" - -#include "dCommonVars.h" -#include "User.h" #include "NiPoint3.h" #include "NiQuaternion.h" #include "LDFFormat.h" -#include "Loot.h" -#include "Zone.h" -#include "EntityTimer.h" -#include "EntityCallbackTimer.h" -#include "EntityInfo.h" +namespace Loot { + class Info; +}; + +namespace tinyxml2 { + class XMLDocument; +}; class Player; +class EntityInfo; +class User; class Spawner; class ScriptComponent; class dpEntity; +class EntityTimer; class Component; +class Item; class Character; +class EntityCallbackTimer; +enum class eTriggerEventType; +enum class eGameMasterLevel : uint8_t; +enum class eReplicaComponentType : uint32_t; + +namespace CppScripts { + class Script; +}; /** * An entity in the world. Has multiple components. @@ -51,14 +61,12 @@ public: Character* GetCharacter() const { return m_Character; } - uint8_t GetGMLevel() const { return m_GMLevel; } + eGameMasterLevel GetGMLevel() const { return m_GMLevel; } uint8_t GetCollectibleID() const { return uint8_t(m_CollectibleID); } Entity* GetParentEntity() const { return m_ParentEntity; } - LUTriggers::Trigger* GetTrigger() const { return m_Trigger; } - std::vector& GetGroups() { return m_Groups; }; Spawner* GetSpawner() const { return m_Spawner; } @@ -101,7 +109,7 @@ public: void SetCharacter(Character* value) { m_Character = value; } - void SetGMLevel(uint8_t value); + void SetGMLevel(eGameMasterLevel value); void SetOwnerOverride(LWOOBJID value); @@ -125,20 +133,23 @@ public: * Component management */ - Component* GetComponent(int32_t componentID) const; + Component* GetComponent(eReplicaComponentType componentID) const; template T* GetComponent() const; template - bool TryGetComponent(int32_t componentId, T*& component) const; + bool TryGetComponent(eReplicaComponentType componentId, T*& component) const; - bool HasComponent(int32_t componentId) const; + bool HasComponent(eReplicaComponentType componentId) const; - void AddComponent(int32_t componentId, Component* component); + void AddComponent(eReplicaComponentType componentId, Component* component); std::vector GetScriptComponents(); + void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName); + void Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName); + void SetProximityRadius(float proxRadius, std::string name); void SetProximityRadius(dpEntity* entity, std::string name); @@ -155,7 +166,7 @@ public: void AddToGroup(const std::string& group); bool IsPlayer() const; - std::unordered_map& GetComponents() { return m_Components; } // TODO: Remove + std::unordered_map& GetComponents() { return m_Components; } // TODO: Remove void WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType); void WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType packetType); @@ -208,9 +219,8 @@ public: void RegisterCoinDrop(uint64_t count); void ScheduleKillAfterUpdate(Entity* murderer = nullptr); - void TriggerEvent(std::string eveneventtID, Entity* optionalTarget = nullptr); + void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr); void ScheduleDestructionAfterUpdate() { m_ShouldDestroyAfterUpdate = true; } - void HandleTriggerCommand(std::string id, std::string target, std::string targetName, std::string args, Entity* optionalTarget); virtual NiPoint3 GetRespawnPosition() const { return NiPoint3::ZERO; } virtual NiQuaternion GetRespawnRotation() const { return NiQuaternion::IDENTITY; } @@ -295,20 +305,18 @@ protected: bool m_HasSpawnerNodeID; uint32_t m_SpawnerNodeID; - LUTriggers::Trigger* m_Trigger; - Character* m_Character; Entity* m_ParentEntity; //For spawners and the like std::vector m_ChildEntities; - uint8_t m_GMLevel; + eGameMasterLevel m_GMLevel; uint16_t m_CollectibleID; std::vector m_Groups; uint16_t m_NetworkID; std::vector> m_DieCallbacks; std::vector> m_PhantomCollisionCallbacks; - std::unordered_map m_Components; //The int is the ID of the component + std::unordered_map m_Components; std::vector m_Timers; std::vector m_PendingTimers; std::vector m_CallbackTimers; @@ -338,7 +346,7 @@ protected: */ template -bool Entity::TryGetComponent(const int32_t componentId, T*& component) const { +bool Entity::TryGetComponent(const eReplicaComponentType componentId, T*& component) const { const auto& index = m_Components.find(componentId); if (index == m_Components.end()) { diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 02b8b59e..d547cdb1 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -17,6 +17,11 @@ #include "MissionComponent.h" #include "Game.h" #include "dLogger.h" +#include "MessageIdentifiers.h" +#include "dConfig.h" +#include "eTriggerEventType.h" +#include "eGameMasterLevel.h" +#include "eReplicaComponentType.h" EntityManager* EntityManager::m_Address = nullptr; @@ -57,6 +62,20 @@ void EntityManager::Initialize() { m_GhostingExcludedZones.end(), dZoneManager::Instance()->GetZoneID().GetMapID() ) == m_GhostingExcludedZones.end(); + + // grab hardcore mode settings and load them with sane defaults + auto hcmode = Game::config->GetValue("hardcore_mode"); + m_HardcoreMode = hcmode.empty() ? false : (hcmode == "1"); + auto hcUscorePercent = Game::config->GetValue("hardcore_lose_uscore_on_death_percent"); + m_HardcoreLoseUscoreOnDeathPercent = hcUscorePercent.empty() ? 10 : std::stoi(hcUscorePercent); + auto hcUscoreMult = Game::config->GetValue("hardcore_uscore_enemies_multiplier"); + m_HardcoreUscoreEnemiesMultiplier = hcUscoreMult.empty() ? 2 : std::stoi(hcUscoreMult); + auto hcDropInv = Game::config->GetValue("hardcore_dropinventory_on_death"); + m_HardcoreDropinventoryOnDeath = hcDropInv.empty() ? false : (hcDropInv == "1"); + + // If cloneID is not zero, then hardcore mode is disabled + // aka minigames and props + if (dZoneManager::Instance()->GetZoneID().GetCloneID() != 0) m_HardcoreMode = false; } EntityManager::~EntityManager() { @@ -144,6 +163,8 @@ void EntityManager::DestroyEntity(Entity* entity) { return; } + entity->TriggerEvent(eTriggerEventType::DESTROY, entity); + const auto id = entity->GetObjectID(); if (std::count(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), id)) { @@ -251,10 +272,10 @@ std::vector EntityManager::GetEntitiesInGroup(const std::string& group) return entitiesInGroup; } -std::vector EntityManager::GetEntitiesByComponent(const int componentType) const { +std::vector EntityManager::GetEntitiesByComponent(const eReplicaComponentType componentType) const { std::vector withComp; for (const auto& entity : m_Entities) { - if (componentType != -1 && !entity.second->HasComponent(componentType)) continue; + if (componentType != eReplicaComponentType::INVALID && !entity.second->HasComponent(componentType)) continue; withComp.push_back(entity.second); } @@ -352,7 +373,7 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr // PacketUtils::SavePacket("[24]_"+std::to_string(entity->GetObjectID()) + "_" + std::to_string(m_SerializationCounter) + ".bin", (char*)stream.GetData(), stream.GetNumberOfBytesUsed()); if (entity->IsPlayer()) { - if (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN) { + if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, sysAddr); } } @@ -569,7 +590,7 @@ void EntityManager::ScheduleForKill(Entity* entity) { SwitchComponent* switchComp = entity->GetComponent(); if (switchComp) { - entity->TriggerEvent("OnDectivated"); + entity->TriggerEvent(eTriggerEventType::DEACTIVATED, entity); } const auto objectId = entity->GetObjectID(); diff --git a/dGame/EntityManager.h b/dGame/EntityManager.h index 40a98076..0314cc09 100644 --- a/dGame/EntityManager.h +++ b/dGame/EntityManager.h @@ -2,15 +2,18 @@ #define ENTITYMANAGER_H #include "dCommonVars.h" -#include "../thirdparty/raknet/Source/Replica.h" #include #include - -#include "Entity.h" #include +#include + +class Entity; +class EntityInfo; +class Player; +class User; +enum class eReplicaComponentType : uint32_t; struct SystemAddress; -class User; class EntityManager { public: @@ -33,7 +36,7 @@ public: void DestroyEntity(Entity* entity); Entity* GetEntity(const LWOOBJID& objectId) const; std::vector GetEntitiesInGroup(const std::string& group); - std::vector GetEntitiesByComponent(int componentType) const; + std::vector GetEntitiesByComponent(eReplicaComponentType componentType) const; std::vector GetEntitiesByLOT(const LOT& lot) const; Entity* GetZoneControlEntity() const; @@ -76,6 +79,11 @@ public: static bool IsExcludedFromGhosting(LOT lot); + const bool GetHardcoreMode() { return m_HardcoreMode; }; + const uint32_t GetHardcoreLoseUscoreOnDeathPercent() { return m_HardcoreLoseUscoreOnDeathPercent; }; + const bool GetHardcoreDropinventoryOnDeath() { return m_HardcoreDropinventoryOnDeath; }; + const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; }; + private: static EntityManager* m_Address; //For singleton method static std::vector m_GhostingExcludedZones; @@ -100,6 +108,12 @@ private: // Map of spawnname to entity object ID std::unordered_map m_SpawnPoints; + + // hardcore mode vars + bool m_HardcoreMode; + uint32_t m_HardcoreLoseUscoreOnDeathPercent; + bool m_HardcoreDropinventoryOnDeath; + uint32_t m_HardcoreUscoreEnemiesMultiplier; }; #endif // ENTITYMANAGER_H diff --git a/dGame/LeaderboardManager.cpp b/dGame/LeaderboardManager.cpp index b069e761..d85a95d4 100644 --- a/dGame/LeaderboardManager.cpp +++ b/dGame/LeaderboardManager.cpp @@ -7,6 +7,11 @@ #include "GameMessages.h" #include "dLogger.h" #include "dConfig.h" +#include "CDClientManager.h" +#include "GeneralUtils.h" +#include "Entity.h" + +#include "CDActivitiesTable.h" Leaderboard::Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector entries, LWOOBJID relatedPlayer, LeaderboardType leaderboardType) { @@ -272,7 +277,7 @@ void LeaderboardManager::SendLeaderboard(uint32_t gameID, InfoType infoType, boo } LeaderboardType LeaderboardManager::GetLeaderboardType(uint32_t gameID) { - auto* activitiesTable = CDClientManager::Instance()->GetTable("Activities"); + auto* activitiesTable = CDClientManager::Instance().GetTable(); std::vector activities = activitiesTable->Query([=](const CDActivities& entry) { return (entry.ActivityID == gameID); }); diff --git a/dGame/Player.cpp b/dGame/Player.cpp index 5306584e..2e194e6a 100644 --- a/dGame/Player.cpp +++ b/dGame/Player.cpp @@ -13,7 +13,10 @@ #include "dZoneManager.h" #include "CharacterComponent.h" #include "Mail.h" +#include "User.h" #include "CppScripts.h" +#include "Loot.h" +#include "eReplicaComponentType.h" std::vector Player::m_Players = {}; @@ -221,7 +224,7 @@ Player* Player::GetPlayer(const SystemAddress& sysAddr) { } Player* Player::GetPlayer(const std::string& name) { - const auto characters = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CHARACTER); + const auto characters = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); for (auto* character : characters) { if (!character->IsPlayer()) continue; @@ -287,7 +290,7 @@ Player::~Player() { script->OnPlayerExit(zoneControl, this); } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { diff --git a/dGame/TradingManager.cpp b/dGame/TradingManager.cpp index e49cca70..e1eac422 100644 --- a/dGame/TradingManager.cpp +++ b/dGame/TradingManager.cpp @@ -9,6 +9,7 @@ #include "Character.h" #include "CharacterComponent.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" TradingManager* TradingManager::m_Address = nullptr; @@ -103,6 +104,7 @@ void Trade::SetAccepted(LWOOBJID participant, bool value) { } Complete(); + TradingManager::Instance()->CancelTrade(m_TradeId); } } @@ -121,33 +123,59 @@ void Trade::Complete() { if (inventoryA == nullptr || inventoryB == nullptr || characterA == nullptr || characterB == nullptr || missionsA == nullptr || missionsB == nullptr) return; + // First verify both players have the coins and items requested for the trade. + if (characterA->GetCoins() < m_CoinsA || characterB->GetCoins() < m_CoinsB) { + Game::logger->Log("TradingManager", "Possible coin trade cheating attempt! Aborting trade."); + return; + } + + for (const auto& tradeItem : m_ItemsA) { + auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId); + if (itemToRemove) { + if (itemToRemove->GetCount() < tradeItem.itemCount) { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterA->GetName().c_str()); + return; + } + } else { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!!", characterA->GetName().c_str()); + return; + } + } + + for (const auto& tradeItem : m_ItemsB) { + auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId); + if (itemToRemove) { + if (itemToRemove->GetCount() < tradeItem.itemCount) { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading!!! Aborting trade", characterB->GetName().c_str()); + return; + } + } else { + Game::logger->Log("TradingManager", "Possible cheating attempt from %s in trading due to item not being available!!! Aborting trade", characterB->GetName().c_str()); + return; + } + } + + // Now actually do the trade. characterA->SetCoins(characterA->GetCoins() - m_CoinsA + m_CoinsB, eLootSourceType::LOOT_SOURCE_TRADE); characterB->SetCoins(characterB->GetCoins() - m_CoinsB + m_CoinsA, eLootSourceType::LOOT_SOURCE_TRADE); for (const auto& tradeItem : m_ItemsA) { - inventoryA->RemoveItem(tradeItem.itemLot, tradeItem.itemCount, INVALID, true); - - missionsA->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); - } - - for (const auto& tradeItem : m_ItemsB) { - inventoryB->RemoveItem(tradeItem.itemLot, tradeItem.itemCount, INVALID, true); - - missionsB->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); - } - - for (const auto& tradeItem : m_ItemsA) { + auto* itemToRemove = inventoryA->FindItemById(tradeItem.itemId); + if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount); + missionsA->Progress(eMissionTaskType::GATHER, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); inventoryB->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::LOOT_SOURCE_TRADE); } for (const auto& tradeItem : m_ItemsB) { + auto* itemToRemove = inventoryB->FindItemById(tradeItem.itemId); + if (itemToRemove) itemToRemove->SetCount(itemToRemove->GetCount() - tradeItem.itemCount); + missionsB->Progress(eMissionTaskType::GATHER, tradeItem.itemLot, LWOOBJID_EMPTY, "", -tradeItem.itemCount); inventoryA->AddItem(tradeItem.itemLot, tradeItem.itemCount, eLootSourceType::LOOT_SOURCE_TRADE); } - TradingManager::Instance()->CancelTrade(m_TradeId); - characterA->SaveXMLToDatabase(); characterB->SaveXMLToDatabase(); + return; } void Trade::Cancel() { diff --git a/dGame/User.cpp b/dGame/User.cpp index 20cc3ab4..55bbcc09 100644 --- a/dGame/User.cpp +++ b/dGame/User.cpp @@ -5,13 +5,15 @@ #include "dLogger.h" #include "Game.h" #include "dZoneManager.h" +#include "eServerDisconnectIdentifiers.h" +#include "eGameMasterLevel.h" User::User(const SystemAddress& sysAddr, const std::string& username, const std::string& sessionKey) { m_AccountID = 0; m_Username = ""; m_SessionKey = ""; - m_MaxGMLevel = 0; //The max GM level this account can assign to it's characters + m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters m_LastCharID = 0; m_SessionKey = sessionKey; @@ -32,7 +34,7 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std: sql::ResultSet* res = stmt->executeQuery(); while (res->next()) { m_AccountID = res->getUInt(1); - m_MaxGMLevel = res->getInt(2); + m_MaxGMLevel = static_cast(res->getInt(2)); m_MuteExpire = 0; //res->getUInt64(3); } @@ -126,6 +128,6 @@ void User::UserOutOfSync() { if (m_AmountOfTimesOutOfSync > m_MaxDesyncAllowed) { //YEET Game::logger->Log("User", "User %s was out of sync %i times out of %i, disconnecting for suspected speedhacking.", m_Username.c_str(), m_AmountOfTimesOutOfSync, m_MaxDesyncAllowed); - Game::server->Disconnect(this->m_SystemAddress, SERVER_DISCON_KICK); + Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE); } } diff --git a/dGame/User.h b/dGame/User.h index 59416c4c..3201538e 100644 --- a/dGame/User.h +++ b/dGame/User.h @@ -9,6 +9,7 @@ #include class Character; +enum class eGameMasterLevel : uint8_t; struct BehaviorParams { uint32_t behavior; @@ -29,7 +30,7 @@ public: std::string& GetSessionKey() { return m_SessionKey; } SystemAddress& GetSystemAddress() { return m_SystemAddress; } - uint32_t GetMaxGMLevel() { return m_MaxGMLevel; } + eGameMasterLevel GetMaxGMLevel() { return m_MaxGMLevel; } uint32_t GetLastCharID() { return m_LastCharID; } void SetLastCharID(uint32_t newCharID) { m_LastCharID = newCharID; } @@ -61,7 +62,7 @@ private: std::string m_SessionKey; SystemAddress m_SystemAddress; - uint32_t m_MaxGMLevel; //The max GM level this account can assign to it's characters + eGameMasterLevel m_MaxGMLevel; //The max GM level this account can assign to it's characters uint32_t m_LastCharID; std::vector m_Characters; LWOOBJID m_LoggedInCharID; diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 7da26b9a..4f0c456d 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -20,6 +20,10 @@ #include "Entity.h" #include "EntityManager.h" #include "SkillComponent.h" +#include "AssetManager.h" +#include "CDClientDatabase.h" +#include "dMessageIdentifiers.h" +#include "eGameMasterLevel.h" UserManager* UserManager::m_Address = nullptr; @@ -32,43 +36,59 @@ inline void StripCR(std::string& str) { } void UserManager::Initialize() { - std::string firstNamePath = "./res/names/minifigname_first.txt"; - std::string middleNamePath = "./res/names/minifigname_middle.txt"; - std::string lastNamePath = "./res/names/minifigname_last.txt"; std::string line; - std::fstream fnFile(firstNamePath, std::ios::in); - std::fstream mnFile(middleNamePath, std::ios::in); - std::fstream lnFile(lastNamePath, std::ios::in); - - while (std::getline(fnFile, line, '\n')) { + AssetMemoryBuffer fnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_first.txt"); + if (!fnBuff.m_Success) { + Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_first.txt").string().c_str()); + throw std::runtime_error("Aborting initialization due to missing minifigure name file."); + } + std::istream fnStream = std::istream(&fnBuff); + while (std::getline(fnStream, line, '\n')) { std::string name = line; StripCR(name); m_FirstNames.push_back(name); } + fnBuff.close(); - while (std::getline(mnFile, line, '\n')) { + AssetMemoryBuffer mnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_middle.txt"); + if (!mnBuff.m_Success) { + Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_middle.txt").string().c_str()); + throw std::runtime_error("Aborting initialization due to missing minifigure name file."); + } + std::istream mnStream = std::istream(&mnBuff); + while (std::getline(mnStream, line, '\n')) { std::string name = line; StripCR(name); m_MiddleNames.push_back(name); } + mnBuff.close(); - while (std::getline(lnFile, line, '\n')) { + AssetMemoryBuffer lnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_last.txt"); + if (!lnBuff.m_Success) { + Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_last.txt").string().c_str()); + throw std::runtime_error("Aborting initialization due to missing minifigure name file."); + } + std::istream lnStream = std::istream(&lnBuff); + while (std::getline(lnStream, line, '\n')) { std::string name = line; StripCR(name); m_LastNames.push_back(name); } - - fnFile.close(); - mnFile.close(); - lnFile.close(); + lnBuff.close(); //Load our pre-approved names: - std::fstream chatList("./res/chatplus_en_us.txt", std::ios::in); - while (std::getline(chatList, line, '\n')) { + AssetMemoryBuffer chatListBuff = Game::assetManager->GetFileAsBuffer("chatplus_en_us.txt"); + if (!chatListBuff.m_Success) { + Game::logger->Log("UserManager", "Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str()); + throw std::runtime_error("Aborting initialization due to missing chat whitelist file."); + } + std::istream chatListStream = std::istream(&chatListBuff); + while (std::getline(chatListStream, line, '\n')) { StripCR(line); m_PreapprovedNames.push_back(line); } + chatListBuff.close(); } UserManager::~UserManager() { @@ -210,6 +230,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) { while (res->next()) { LWOOBJID objID = res->getUInt64(1); Character* character = new Character(uint32_t(objID), u); + character->SetIsNewLogin(); chars.push_back(character); } } @@ -310,7 +331,7 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) //Check to see if our name was pre-approved: bool nameOk = IsNamePreapproved(name); - if (!nameOk && u->GetMaxGMLevel() > 1) nameOk = true; + if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true; if (name != "") { sql::PreparedStatement* stmt = Database::CreatePreppedStmt("INSERT INTO `charinfo`(`id`, `account_id`, `name`, `pending_name`, `needs_rename`, `last_login`) VALUES (?,?,?,?,?,?)"); diff --git a/dGame/dBehaviors/AirMovementBehavior.cpp b/dGame/dBehaviors/AirMovementBehavior.cpp index 469ac6e4..dbfde465 100644 --- a/dGame/dBehaviors/AirMovementBehavior.cpp +++ b/dGame/dBehaviors/AirMovementBehavior.cpp @@ -2,13 +2,18 @@ #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "EntityManager.h" +#include "Game.h" +#include "dLogger.h" void AirMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - uint32_t handle; + uint32_t handle{}; - bitStream->Read(handle); + if (!bitStream->Read(handle)) { + Game::logger->Log("AirMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - context->RegisterSyncBehavior(handle, this, branch); + context->RegisterSyncBehavior(handle, this, branch, this->m_Timeout); } void AirMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { @@ -17,14 +22,20 @@ void AirMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream->Write(handle); } -void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { - uint32_t behaviorId; +void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + uint32_t behaviorId{}; - bit_stream->Read(behaviorId); + if (!bitStream->Read(behaviorId)) { + Game::logger->Log("AirMovementBehavior", "Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - LWOOBJID target; + LWOOBJID target{}; - bit_stream->Read(target); + if (!bitStream->Read(target)) { + Game::logger->Log("AirMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } auto* behavior = CreateBehavior(behaviorId); @@ -32,8 +43,9 @@ void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bit_ branch.target = target; } - behavior->Handle(context, bit_stream, branch); + behavior->Handle(context, bitStream, branch); } void AirMovementBehavior::Load() { + this->m_Timeout = (GetFloat("timeout_ms") / 1000.0f); } diff --git a/dGame/dBehaviors/AirMovementBehavior.h b/dGame/dBehaviors/AirMovementBehavior.h index 323edf37..9d51ef03 100644 --- a/dGame/dBehaviors/AirMovementBehavior.h +++ b/dGame/dBehaviors/AirMovementBehavior.h @@ -4,19 +4,15 @@ class AirMovementBehavior final : public Behavior { public: - - /* - * Inherited - */ - - explicit AirMovementBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { - } + explicit AirMovementBehavior(const uint32_t behavior_id) : Behavior(behavior_id) {} void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Sync(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; +private: + float m_Timeout; }; diff --git a/dGame/dBehaviors/AreaOfEffectBehavior.cpp b/dGame/dBehaviors/AreaOfEffectBehavior.cpp index 898d1f99..dedede2a 100644 --- a/dGame/dBehaviors/AreaOfEffectBehavior.cpp +++ b/dGame/dBehaviors/AreaOfEffectBehavior.cpp @@ -9,11 +9,16 @@ #include "BehaviorContext.h" #include "RebuildComponent.h" #include "DestroyableComponent.h" +#include "Game.h" +#include "dLogger.h" void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - uint32_t targetCount; + uint32_t targetCount{}; - bitStream->Read(targetCount); + if (!bitStream->Read(targetCount)) { + Game::logger->Log("AreaOfEffectBehavior", "Unable to read targetCount from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } if (targetCount > this->m_maxTargets) { return; @@ -24,9 +29,12 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b targets.reserve(targetCount); for (auto i = 0u; i < targetCount; ++i) { - LWOOBJID target; + LWOOBJID target{}; - bitStream->Read(target); + if (!bitStream->Read(target)) { + Game::logger->Log("AreaOfEffectBehavior", "failed to read in target %i from bitStream, aborting target Handle!", i); + return; + }; targets.push_back(target); } @@ -40,9 +48,8 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* self = EntityManager::Instance()->GetEntity(context->caster); - if (self == nullptr) { - Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!", context->originator); + Game::logger->Log("AreaOfEffectBehavior", "Invalid self for (%llu)!", context->originator); return; } @@ -71,7 +78,7 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream auto* entity = EntityManager::Instance()->GetEntity(validTarget); if (entity == nullptr) { - Game::logger->Log("TacArcBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator); + Game::logger->Log("AreaOfEffectBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator); continue; } diff --git a/dGame/dBehaviors/AttackDelayBehavior.cpp b/dGame/dBehaviors/AttackDelayBehavior.cpp index 450741ec..af33aadd 100644 --- a/dGame/dBehaviors/AttackDelayBehavior.cpp +++ b/dGame/dBehaviors/AttackDelayBehavior.cpp @@ -5,12 +5,15 @@ #include "dLogger.h" void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - uint32_t handle; + uint32_t handle{}; - bitStream->Read(handle); + if (!bitStream->Read(handle)) { + Game::logger->Log("AttackDelayBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; for (auto i = 0u; i < this->m_numIntervals; ++i) { - context->RegisterSyncBehavior(handle, this, branch); + context->RegisterSyncBehavior(handle, this, branch, m_ignoreInterrupts, this->m_delay * i); } } diff --git a/dGame/dBehaviors/BasicAttackBehavior.cpp b/dGame/dBehaviors/BasicAttackBehavior.cpp index fe773f36..f8693795 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.cpp +++ b/dGame/dBehaviors/BasicAttackBehavior.cpp @@ -5,7 +5,7 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "BehaviorContext.h" - +#include "eBasicAttackSuccessTypes.h" void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { if (context->unmanaged) { @@ -14,137 +14,242 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi auto* destroyableComponent = entity->GetComponent(); if (destroyableComponent != nullptr) { PlayFx(u"onhit", entity->GetObjectID()); - destroyableComponent->Damage(this->m_maxDamage, context->originator, context->skillID); + destroyableComponent->Damage(this->m_MaxDamage, context->originator, context->skillID); } - this->m_onSuccess->Handle(context, bitStream, branch); + this->m_OnSuccess->Handle(context, bitStream, branch); return; } bitStream->AlignReadToByteBoundary(); - uint16_t allocatedBits; - bitStream->Read(allocatedBits); - + uint16_t allocatedBits{}; + if (!bitStream->Read(allocatedBits) || allocatedBits == 0) { + Game::logger->LogDebug("BasicAttackBehavior", "No allocated bits"); + return; + } + Game::logger->LogDebug("BasicAttackBehavior", "Number of allocated bits %i", allocatedBits); const auto baseAddress = bitStream->GetReadOffset(); - if (bitStream->ReadBit()) { // Blocked - return; - } - if (bitStream->ReadBit()) { // Immune - return; - } - - if (bitStream->ReadBit()) { // Success - uint32_t unknown; - bitStream->Read(unknown); - - uint32_t damageDealt; - bitStream->Read(damageDealt); - - // A value that's too large may be a cheating attempt, so we set it to MIN too - if (damageDealt > this->m_maxDamage || damageDealt < this->m_minDamage) { - damageDealt = this->m_minDamage; - } - - auto* entity = EntityManager::Instance()->GetEntity(branch.target); - bool died; - bitStream->Read(died); - - if (entity != nullptr) { - auto* destroyableComponent = entity->GetComponent(); - if (destroyableComponent != nullptr) { - PlayFx(u"onhit", entity->GetObjectID()); - destroyableComponent->Damage(damageDealt, context->originator, context->skillID); - } - } - } - - uint8_t successState; - bitStream->Read(successState); - - switch (successState) { - case 1: - this->m_onSuccess->Handle(context, bitStream, branch); - break; - default: - Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); - break; - } + DoHandleBehavior(context, bitStream, branch); bitStream->SetReadOffset(baseAddress + allocatedBits); } -void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - auto* self = EntityManager::Instance()->GetEntity(context->originator); - if (self == nullptr) { - Game::logger->Log("BasicAttackBehavior", "Invalid self entity (%llu)!", context->originator); +void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); + if (!targetEntity) { + Game::logger->Log("BasicAttackBehavior", "Target targetEntity %llu not found.", branch.target); return; } + auto* destroyableComponent = targetEntity->GetComponent(); + if (!destroyableComponent) { + Game::logger->Log("BasicAttackBehavior", "No destroyable found on the obj/lot %llu/%i", branch.target, targetEntity->GetLOT()); + return; + } + + bool isBlocked{}; + bool isImmune{}; + bool isSuccess{}; + + if (!bitStream->Read(isBlocked)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read isBlocked"); + return; + } + + if (isBlocked) { + destroyableComponent->SetAttacksToBlock(std::min(destroyableComponent->GetAttacksToBlock() - 1, 0U)); + EntityManager::Instance()->SerializeEntity(targetEntity); + this->m_OnFailBlocked->Handle(context, bitStream, branch); + return; + } + + if (!bitStream->Read(isImmune)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read isImmune"); + return; + } + + if (isImmune) { + this->m_OnFailImmune->Handle(context, bitStream, branch); + return; + } + + if (!bitStream->Read(isSuccess)) { + Game::logger->Log("BasicAttackBehavior", "failed to read success from bitstream"); + return; + } + + if (isSuccess) { + uint32_t armorDamageDealt{}; + if (!bitStream->Read(armorDamageDealt)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read armorDamageDealt"); + return; + } + + uint32_t healthDamageDealt{}; + if (!bitStream->Read(healthDamageDealt)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read healthDamageDealt"); + return; + } + + uint32_t totalDamageDealt = armorDamageDealt + healthDamageDealt; + + // A value that's too large may be a cheating attempt, so we set it to MIN + if (totalDamageDealt > this->m_MaxDamage) { + totalDamageDealt = this->m_MinDamage; + } + + bool died{}; + if (!bitStream->Read(died)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read died"); + return; + } + auto previousArmor = destroyableComponent->GetArmor(); + auto previousHealth = destroyableComponent->GetHealth(); + PlayFx(u"onhit", targetEntity->GetObjectID()); + destroyableComponent->Damage(totalDamageDealt, context->originator, context->skillID); + } + + uint8_t successState{}; + if (!bitStream->Read(successState)) { + Game::logger->Log("BasicAttackBehavior", "Unable to read success state"); + return; + } + + switch (static_cast(successState)) { + case eBasicAttackSuccessTypes::SUCCESS: + this->m_OnSuccess->Handle(context, bitStream, branch); + break; + case eBasicAttackSuccessTypes::FAILARMOR: + this->m_OnFailArmor->Handle(context, bitStream, branch); + break; + default: + if (static_cast(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) { + Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); + return; + } + this->m_OnFailImmune->Handle(context, bitStream, branch); + break; + } +} + +void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { bitStream->AlignWriteToByteBoundary(); const auto allocatedAddress = bitStream->GetWriteOffset(); - bitStream->Write(uint16_t(0)); + bitStream->Write(0); const auto startAddress = bitStream->GetWriteOffset(); - bitStream->Write0(); // Blocked - bitStream->Write0(); // Immune - bitStream->Write1(); // Success - - if (true) { - uint32_t unknown3 = 0; - bitStream->Write(unknown3); - - auto damage = this->m_minDamage; - auto* entity = EntityManager::Instance()->GetEntity(branch.target); - - if (entity == nullptr) { - damage = 0; - bitStream->Write(damage); - bitStream->Write(false); - } else { - bitStream->Write(damage); - bitStream->Write(true); - - auto* destroyableComponent = entity->GetComponent(); - if (damage != 0 && destroyableComponent != nullptr) { - PlayFx(u"onhit", entity->GetObjectID(), 1); - destroyableComponent->Damage(damage, context->originator, context->skillID, false); - context->ScheduleUpdate(branch.target); - } - } - } - - uint8_t successState = 1; - bitStream->Write(successState); - - switch (successState) { - case 1: - this->m_onSuccess->Calculate(context, bitStream, branch); - break; - default: - Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); - break; - } + DoBehaviorCalculation(context, bitStream, branch); const auto endAddress = bitStream->GetWriteOffset(); - const uint16_t allocate = endAddress - startAddress + 1; + const uint16_t allocate = endAddress - startAddress; bitStream->SetWriteOffset(allocatedAddress); bitStream->Write(allocate); bitStream->SetWriteOffset(startAddress + allocate); } -void BasicAttackBehavior::Load() { - this->m_minDamage = GetInt("min damage"); - if (this->m_minDamage == 0) this->m_minDamage = 1; +void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); + if (!targetEntity) { + Game::logger->Log("BasicAttackBehavior", "Target entity %llu is null!", branch.target); + return; + } - this->m_maxDamage = GetInt("max damage"); - if (this->m_maxDamage == 0) this->m_maxDamage = 1; + auto* destroyableComponent = targetEntity->GetComponent(); + if (!destroyableComponent || !destroyableComponent->GetParent()) { + Game::logger->Log("BasicAttackBehavior", "No destroyable component on %llu", branch.target); + return; + } - this->m_onSuccess = GetAction("on_success"); + const bool isBlocking = destroyableComponent->GetAttacksToBlock() > 0; + + bitStream->Write(isBlocking); + + if (isBlocking) { + destroyableComponent->SetAttacksToBlock(destroyableComponent->GetAttacksToBlock() - 1); + EntityManager::Instance()->SerializeEntity(targetEntity); + this->m_OnFailBlocked->Calculate(context, bitStream, branch); + return; + } + + const bool isImmune = destroyableComponent->IsImmune(); + + bitStream->Write(isImmune); + + if (isImmune) { + this->m_OnFailImmune->Calculate(context, bitStream, branch); + return; + } + + bool isSuccess = false; + const uint32_t previousHealth = destroyableComponent->GetHealth(); + const uint32_t previousArmor = destroyableComponent->GetArmor(); + + const auto damage = this->m_MinDamage; + + PlayFx(u"onhit", targetEntity->GetObjectID(), 1); + destroyableComponent->Damage(damage, context->originator, context->skillID, false); + context->ScheduleUpdate(branch.target); + + const uint32_t armorDamageDealt = previousArmor - destroyableComponent->GetArmor(); + const uint32_t healthDamageDealt = previousHealth - destroyableComponent->GetHealth(); + isSuccess = armorDamageDealt > 0 || healthDamageDealt > 0 || (armorDamageDealt + healthDamageDealt) > 0; + + bitStream->Write(isSuccess); + + eBasicAttackSuccessTypes successState = eBasicAttackSuccessTypes::FAILIMMUNE; + if (isSuccess) { + if (healthDamageDealt >= 1) { + successState = eBasicAttackSuccessTypes::SUCCESS; + } else if (armorDamageDealt >= 1) { + successState = this->m_OnFailArmor->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY ? eBasicAttackSuccessTypes::FAILIMMUNE : eBasicAttackSuccessTypes::FAILARMOR; + } + + bitStream->Write(armorDamageDealt); + bitStream->Write(healthDamageDealt); + bitStream->Write(targetEntity->GetIsDead()); + } + + bitStream->Write(successState); + + switch (static_cast(successState)) { + case eBasicAttackSuccessTypes::SUCCESS: + this->m_OnSuccess->Calculate(context, bitStream, branch); + break; + case eBasicAttackSuccessTypes::FAILARMOR: + this->m_OnFailArmor->Calculate(context, bitStream, branch); + break; + default: + if (static_cast(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) { + Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState); + break; + } + this->m_OnFailImmune->Calculate(context, bitStream, branch); + break; + } +} + +void BasicAttackBehavior::Load() { + this->m_MinDamage = GetInt("min damage"); + if (this->m_MinDamage == 0) this->m_MinDamage = 1; + + this->m_MaxDamage = GetInt("max damage"); + if (this->m_MaxDamage == 0) this->m_MaxDamage = 1; + + // The client sets the minimum damage to maximum, so we'll do the same. These are usually the same value anyways. + if (this->m_MinDamage < this->m_MaxDamage) this->m_MinDamage = this->m_MaxDamage; + + this->m_OnSuccess = GetAction("on_success"); + + this->m_OnFailArmor = GetAction("on_fail_armor"); + + this->m_OnFailImmune = GetAction("on_fail_immune"); + + this->m_OnFailBlocked = GetAction("on_fail_blocked"); } diff --git a/dGame/dBehaviors/BasicAttackBehavior.h b/dGame/dBehaviors/BasicAttackBehavior.h index 8e23d443..f6e3fa28 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.h +++ b/dGame/dBehaviors/BasicAttackBehavior.h @@ -4,18 +4,59 @@ class BasicAttackBehavior final : public Behavior { public: - uint32_t m_minDamage; - - uint32_t m_maxDamage; - - Behavior* m_onSuccess; - explicit BasicAttackBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } + /** + * @brief Reads a 16bit short from the bitStream and when the actual behavior handling finishes with all of its branches, the bitStream + * is then offset to after the allocated bits for this stream. + * + */ + void DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + + /** + * @brief Handles a client initialized Basic Attack Behavior cast to be deserialized and verified on the server. + * + * @param context The Skill's Behavior context. All behaviors in the same tree share the same context + * @param bitStream The bitStream to deserialize. BitStreams will always check their bounds before reading in a behavior + * and will fail gracefully if an overread is detected. + * @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down. + */ void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + /** + * @brief Writes a 16bit short to the bitStream and when the actual behavior calculation finishes with all of its branches, the number + * of bits used is then written to where the 16bit short initially was. + * + */ void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + /** + * @brief Calculates a server initialized Basic Attack Behavior cast to be serialized to the client + * + * @param context The Skill's Behavior context. All behaviors in the same tree share the same context + * @param bitStream The bitStream to serialize to. + * @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down. + */ + void DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + + /** + * @brief Loads this Behaviors parameters from the database. For this behavior specifically: + * max and min damage will always be the same. If min is less than max, they are both set to max. + * If an action is not in the database, then no action is taken for that result. + * + */ void Load() override; +private: + uint32_t m_MinDamage; + + uint32_t m_MaxDamage; + + Behavior* m_OnSuccess; + + Behavior* m_OnFailArmor; + + Behavior* m_OnFailImmune; + + Behavior* m_OnFailBlocked; }; diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index 046df117..2a269ddc 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -42,11 +42,13 @@ #include "SkillCastFailedBehavior.h" #include "SpawnBehavior.h" #include "ForceMovementBehavior.h" +#include "RemoveBuffBehavior.h" #include "ImmunityBehavior.h" #include "InterruptBehavior.h" #include "PlayEffectBehavior.h" #include "DamageAbsorptionBehavior.h" #include "VentureVisionBehavior.h" +#include "PropertyTeleportBehavior.h" #include "BlockBehavior.h" #include "ClearTargetBehavior.h" #include "PullToPointBehavior.h" @@ -59,6 +61,8 @@ #include "SpeedBehavior.h" #include "DamageReductionBehavior.h" #include "JetPackBehavior.h" +#include "ChangeIdleFlagsBehavior.h" +#include "DarkInspirationBehavior.h" //CDClient includes #include "CDBehaviorParameterTable.h" @@ -69,13 +73,14 @@ #include "EntityManager.h" #include "RenderComponent.h" #include "DestroyableComponent.h" +#include "CDBehaviorTemplateTable.h" std::unordered_map Behavior::Cache = {}; CDBehaviorParameterTable* Behavior::BehaviorParameterTable = nullptr; Behavior* Behavior::GetBehavior(const uint32_t behaviorId) { if (BehaviorParameterTable == nullptr) { - BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); + BehaviorParameterTable = CDClientManager::Instance().GetTable(); } const auto pair = Cache.find(behaviorId); @@ -167,7 +172,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { case BehaviorTemplates::BEHAVIOR_SPEED: behavior = new SpeedBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: break; + case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: + behavior = new DarkInspirationBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_LOOT_BUFF: behavior = new LootBuffBehavior(behaviorId); break; @@ -195,7 +202,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { behavior = new SkillCastFailedBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_IMITATION_SKUNK_STINK: break; - case BehaviorTemplates::BEHAVIOR_CHANGE_IDLE_FLAGS: break; + case BehaviorTemplates::BEHAVIOR_CHANGE_IDLE_FLAGS: + behavior = new ChangeIdleFlagsBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_APPLY_BUFF: behavior = new ApplyBuffBehavior(behaviorId); break; @@ -226,7 +235,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { break; case BehaviorTemplates::BEHAVIOR_ALTER_CHAIN_DELAY: break; case BehaviorTemplates::BEHAVIOR_CAMERA: break; - case BehaviorTemplates::BEHAVIOR_REMOVE_BUFF: break; + case BehaviorTemplates::BEHAVIOR_REMOVE_BUFF: + behavior = new RemoveBuffBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_GRAB: break; case BehaviorTemplates::BEHAVIOR_MODULAR_BUILD: break; case BehaviorTemplates::BEHAVIOR_NPC_COMBAT_SKILL: @@ -254,7 +265,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { case BehaviorTemplates::BEHAVIOR_DAMAGE_REDUCTION: behavior = new DamageReductionBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PROPERTY_TELEPORT: break; + case BehaviorTemplates::BEHAVIOR_PROPERTY_TELEPORT: + behavior = new PropertyTeleportBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_PROPERTY_CLEAR_TARGET: behavior = new ClearTargetBehavior(behaviorId); break; @@ -278,7 +291,7 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { } BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) { - auto behaviorTemplateTable = CDClientManager::Instance()->GetTable("BehaviorTemplate"); + auto behaviorTemplateTable = CDClientManager::Instance().GetTable(); BehaviorTemplates templateID = BehaviorTemplates::BEHAVIOR_EMPTY; // Find behavior template by its behavior id. Default to 0. @@ -386,7 +399,7 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID } Behavior::Behavior(const uint32_t behaviorId) { - auto behaviorTemplateTable = CDClientManager::Instance()->GetTable("BehaviorTemplate"); + auto behaviorTemplateTable = CDClientManager::Instance().GetTable(); CDBehaviorTemplate templateInDatabase{}; @@ -429,8 +442,8 @@ Behavior::Behavior(const uint32_t behaviorId) { float Behavior::GetFloat(const std::string& name, const float defaultValue) const { // Get the behavior parameter entry and return its value. - if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); - return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue).value; + if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance().GetTable(); + return BehaviorParameterTable->GetValue(this->m_behaviorId, name, defaultValue); } @@ -457,7 +470,7 @@ Behavior* Behavior::GetAction(float value) const { std::map Behavior::GetParameterNames() const { std::map templatesInDatabase; // Find behavior template by its behavior id. - if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); + if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance().GetTable(); if (BehaviorParameterTable) { templatesInDatabase = BehaviorParameterTable->GetParametersByBehaviorID(this->m_behaviorId); } diff --git a/dGame/dBehaviors/BehaviorBranchContext.h b/dGame/dBehaviors/BehaviorBranchContext.h index 5b2ec595..2e56cd35 100644 --- a/dGame/dBehaviors/BehaviorBranchContext.h +++ b/dGame/dBehaviors/BehaviorBranchContext.h @@ -15,6 +15,8 @@ struct BehaviorBranchContext uint32_t start = 0; + bool isSync = false; + BehaviorBranchContext(); BehaviorBranchContext(LWOOBJID target, float duration = 0, const NiPoint3& referencePosition = NiPoint3(0, 0, 0)); diff --git a/dGame/dBehaviors/BehaviorContext.cpp b/dGame/dBehaviors/BehaviorContext.cpp index 4cd9e415..d0cb68e4 100644 --- a/dGame/dBehaviors/BehaviorContext.cpp +++ b/dGame/dBehaviors/BehaviorContext.cpp @@ -10,10 +10,12 @@ #include - +#include "dMessageIdentifiers.h" #include "DestroyableComponent.h" +#include "EchoSyncSkill.h" #include "PhantomPhysicsComponent.h" #include "RebuildComponent.h" +#include "eReplicaComponentType.h" BehaviorSyncEntry::BehaviorSyncEntry() { } @@ -45,12 +47,17 @@ uint32_t BehaviorContext::GetUniqueSkillId() const { } -void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext) { +void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext, const float duration, bool ignoreInterrupts) { auto entry = BehaviorSyncEntry(); entry.handle = syncId; entry.behavior = behavior; entry.branchContext = branchContext; + entry.branchContext.isSync = true; + entry.ignoreInterrupts = ignoreInterrupts; + // Add 10 seconds + duration time to account for lag and give clients time to send their syncs to the server. + constexpr float lagTime = 10.0f; + entry.time = lagTime + duration; this->syncEntries.push_back(entry); } @@ -179,6 +186,21 @@ void BehaviorContext::SyncCalculation(const uint32_t syncId, const float time, B this->syncEntries.push_back(entry); } +void BehaviorContext::UpdatePlayerSyncs(float deltaTime) { + uint32_t i = 0; + while (i < this->syncEntries.size()) { + auto& entry = this->syncEntries.at(i); + + entry.time -= deltaTime; + + if (entry.time >= 0.0f) { + i++; + continue; + } + this->syncEntries.erase(this->syncEntries.begin() + i); + } +} + void BehaviorContext::InvokeEnd(const uint32_t id) { std::vector entries; @@ -214,7 +236,7 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) { } // Echo sync - GameMessages::EchoSyncSkill echo; + EchoSyncSkill echo; echo.bDone = true; echo.uiBehaviorHandle = entry.handle; @@ -308,13 +330,13 @@ std::vector BehaviorContext::GetValidTargets(int32_t ignoreFaction, in } } - if (ignoreFaction || includeFaction || (!entity->HasComponent(COMPONENT_TYPE_PHANTOM_PHYSICS) && targets.empty())) { + if (ignoreFaction || includeFaction || (!entity->HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && targets.empty())) { DestroyableComponent* destroyableComponent; - if (!entity->TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent)) { + if (!entity->TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) { return targets; } - auto entities = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS); + auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS); for (auto* candidate : entities) { const auto id = candidate->GetObjectID(); diff --git a/dGame/dBehaviors/BehaviorContext.h b/dGame/dBehaviors/BehaviorContext.h index 0462d97f..117f328d 100644 --- a/dGame/dBehaviors/BehaviorContext.h +++ b/dGame/dBehaviors/BehaviorContext.h @@ -80,7 +80,9 @@ struct BehaviorContext uint32_t GetUniqueSkillId() const; - void RegisterSyncBehavior(uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext); + void UpdatePlayerSyncs(float deltaTime); + + void RegisterSyncBehavior(uint32_t syncId, Behavior* behavior, const BehaviorBranchContext& branchContext, const float duration, bool ignoreInterrupts = false); void RegisterTimerBehavior(Behavior* behavior, const BehaviorBranchContext& branchContext, LWOOBJID second = LWOOBJID_EMPTY); diff --git a/dGame/dBehaviors/CMakeLists.txt b/dGame/dBehaviors/CMakeLists.txt index fe8e89b8..7b331fe0 100644 --- a/dGame/dBehaviors/CMakeLists.txt +++ b/dGame/dBehaviors/CMakeLists.txt @@ -12,11 +12,13 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" "BuffBehavior.cpp" "CarBoostBehavior.cpp" "ChainBehavior.cpp" + "ChangeIdleFlagsBehavior.cpp" "ChangeOrientationBehavior.cpp" "ChargeUpBehavior.cpp" "ClearTargetBehavior.cpp" "DamageAbsorptionBehavior.cpp" "DamageReductionBehavior.cpp" + "DarkInspirationBehavior.cpp" "DurationBehavior.cpp" "EmptyBehavior.cpp" "EndBehavior.cpp" @@ -33,7 +35,9 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" "OverTimeBehavior.cpp" "PlayEffectBehavior.cpp" "ProjectileAttackBehavior.cpp" + "PropertyTeleportBehavior.cpp" "PullToPointBehavior.cpp" + "RemoveBuffBehavior.cpp" "RepairBehavior.cpp" "SkillCastFailedBehavior.cpp" "SkillEventBehavior.cpp" diff --git a/dGame/dBehaviors/ChainBehavior.cpp b/dGame/dBehaviors/ChainBehavior.cpp index 3ef8c15b..ec0f8969 100644 --- a/dGame/dBehaviors/ChainBehavior.cpp +++ b/dGame/dBehaviors/ChainBehavior.cpp @@ -4,14 +4,19 @@ #include "dLogger.h" void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - uint32_t chain_index; + uint32_t chainIndex{}; - bitStream->Read(chain_index); + if (!bitStream->Read(chainIndex)) { + Game::logger->Log("ChainBehavior", "Unable to read chainIndex from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - chain_index--; + chainIndex--; - if (chain_index < this->m_behaviors.size()) { - this->m_behaviors.at(chain_index)->Handle(context, bitStream, branch); + if (chainIndex < this->m_behaviors.size()) { + this->m_behaviors.at(chainIndex)->Handle(context, bitStream, branch); + } else { + Game::logger->Log("ChainBehavior", "chainIndex out of bounds, aborting handle of chain %i bits unread %i", chainIndex, bitStream->GetNumberOfUnreadBits()); } } diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp new file mode 100644 index 00000000..06a79fa7 --- /dev/null +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp @@ -0,0 +1,37 @@ + +#include "ChangeIdleFlagsBehavior.h" +#include "BehaviorContext.h" +#include "BehaviorBranchContext.h" + +void ChangeIdleFlagsBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; + if (!target) return; + + GameMessages::SendChangeIdleFlags(target, m_FlagsOn, m_FlagsOff, UNASSIGNED_SYSTEM_ADDRESS); + + if (branch.duration > 0.0f) { + context->RegisterTimerBehavior(this, branch); + } else if (branch.start > 0) { + context->RegisterEndBehavior(this, branch); + } +} + +void ChangeIdleFlagsBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Handle(context, bitStream, branch); +} + +void ChangeIdleFlagsBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; + if (!target) return; + // flip on and off to end behavior + GameMessages::SendChangeIdleFlags(target, m_FlagsOff, m_FlagsOn, UNASSIGNED_SYSTEM_ADDRESS); +} + +void ChangeIdleFlagsBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + End(context, branch, second); +} + +void ChangeIdleFlagsBehavior::Load() { + m_FlagsOff = static_cast(GetInt("flags_off", 0)); + m_FlagsOn = static_cast(GetInt("flags_on", 0)); +} diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.h b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h new file mode 100644 index 00000000..91f802f4 --- /dev/null +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h @@ -0,0 +1,23 @@ + +#pragma once +#include "Behavior.h" +#include "eAninmationFlags.h" + +class ChangeIdleFlagsBehavior final : public Behavior { +public: + + /* + * Inherited + */ + explicit ChangeIdleFlagsBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} + + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + void Load() override; + +private: + eAnimationFlags m_FlagsOff; + eAnimationFlags m_FlagsOn; +}; diff --git a/dGame/dBehaviors/ChangeOrientationBehavior.cpp b/dGame/dBehaviors/ChangeOrientationBehavior.cpp index a60be62f..36a2e6a8 100644 --- a/dGame/dBehaviors/ChangeOrientationBehavior.cpp +++ b/dGame/dBehaviors/ChangeOrientationBehavior.cpp @@ -2,43 +2,35 @@ #include "BehaviorBranchContext.h" #include "BehaviorContext.h" #include "EntityManager.h" -#include "BaseCombatAIComponent.h" - -void ChangeOrientationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { -} void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - if (!m_ToTarget) return; // TODO: Add the other arguments to this behavior + Entity* sourceEntity; + if (this->m_orientCaster) sourceEntity = EntityManager::Instance()->GetEntity(context->originator); + else sourceEntity = EntityManager::Instance()->GetEntity(branch.target); + if (!sourceEntity) return; - auto* self = EntityManager::Instance()->GetEntity(context->originator); - auto* other = EntityManager::Instance()->GetEntity(branch.target); + if (this->m_toTarget) { + Entity* destinationEntity; + if (this->m_orientCaster) destinationEntity = EntityManager::Instance()->GetEntity(branch.target); + else destinationEntity = EntityManager::Instance()->GetEntity(context->originator); + if (!destinationEntity) return; - if (self == nullptr || other == nullptr) return; - - const auto source = self->GetPosition(); - const auto destination = self->GetPosition(); - - if (m_OrientCaster) { - auto* baseCombatAIComponent = self->GetComponent(); - - /*if (baseCombatAIComponent != nullptr) - { - baseCombatAIComponent->LookAt(destination); - } - else*/ - { - self->SetRotation(NiQuaternion::LookAt(source, destination)); - } - - EntityManager::Instance()->SerializeEntity(self); - } else { - other->SetRotation(NiQuaternion::LookAt(destination, source)); - - EntityManager::Instance()->SerializeEntity(other); - } + sourceEntity->SetRotation( + NiQuaternion::LookAt(sourceEntity->GetPosition(), destinationEntity->GetPosition()) + ); + } else if (this->m_toAngle){ + auto baseAngle = NiPoint3(0, 0, this->m_angle); + if (this->m_relative) baseAngle += sourceEntity->GetRotation().GetForwardVector(); + sourceEntity->SetRotation(NiQuaternion::FromEulerAngles(baseAngle)); + } else return; + EntityManager::Instance()->SerializeEntity(sourceEntity); + return; } void ChangeOrientationBehavior::Load() { - m_OrientCaster = GetBoolean("orient_caster"); - m_ToTarget = GetBoolean("to_target"); + this->m_orientCaster = GetBoolean("orient_caster", true); + this->m_toTarget = GetBoolean("to_target", false); + this->m_toAngle = GetBoolean("to_angle", false); + this->m_angle = GetFloat("angle", 0.0f); + this->m_relative = GetBoolean("relative", false); } diff --git a/dGame/dBehaviors/ChangeOrientationBehavior.h b/dGame/dBehaviors/ChangeOrientationBehavior.h index eb038ffb..22c92bb8 100644 --- a/dGame/dBehaviors/ChangeOrientationBehavior.h +++ b/dGame/dBehaviors/ChangeOrientationBehavior.h @@ -2,24 +2,15 @@ #include "Behavior.h" -#include - -class ChangeOrientationBehavior final : public Behavior -{ +class ChangeOrientationBehavior final : public Behavior { public: - bool m_OrientCaster; - bool m_ToTarget; - - /* - * Inherited - */ - - explicit ChangeOrientationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { - } - - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - + explicit ChangeOrientationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Load() override; +private: + bool m_orientCaster; + bool m_toTarget; + bool m_toAngle; + float m_angle; + bool m_relative; }; diff --git a/dGame/dBehaviors/ChargeUpBehavior.cpp b/dGame/dBehaviors/ChargeUpBehavior.cpp index fa9fa34b..4c7c3dac 100644 --- a/dGame/dBehaviors/ChargeUpBehavior.cpp +++ b/dGame/dBehaviors/ChargeUpBehavior.cpp @@ -1,14 +1,18 @@ #include "ChargeUpBehavior.h" #include "BehaviorBranchContext.h" #include "BehaviorContext.h" +#include "Game.h" #include "dLogger.h" void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - uint32_t handle; + uint32_t handle{}; - bitStream->Read(handle); + if (!bitStream->Read(handle)) { + Game::logger->Log("ChargeUpBehavior", "Unable to read handle from bitStream, aborting Handle! variable_type"); + return; + }; - context->RegisterSyncBehavior(handle, this, branch); + context->RegisterSyncBehavior(handle, this, branch, this->m_MaxDuration); } void ChargeUpBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { @@ -20,4 +24,5 @@ void ChargeUpBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStre void ChargeUpBehavior::Load() { this->m_action = GetAction("action"); + this->m_MaxDuration = GetFloat("max_duration"); } diff --git a/dGame/dBehaviors/ChargeUpBehavior.h b/dGame/dBehaviors/ChargeUpBehavior.h index d753895e..ceb40f6c 100644 --- a/dGame/dBehaviors/ChargeUpBehavior.h +++ b/dGame/dBehaviors/ChargeUpBehavior.h @@ -4,14 +4,7 @@ class ChargeUpBehavior final : public Behavior { public: - Behavior* m_action; - - /* - * Inherited - */ - - explicit ChargeUpBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { - } + explicit ChargeUpBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; @@ -20,4 +13,7 @@ public: void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Load() override; +private: + Behavior* m_action; + float m_MaxDuration; }; diff --git a/dGame/dBehaviors/DarkInspirationBehavior.cpp b/dGame/dBehaviors/DarkInspirationBehavior.cpp new file mode 100644 index 00000000..ea80cbba --- /dev/null +++ b/dGame/dBehaviors/DarkInspirationBehavior.cpp @@ -0,0 +1,52 @@ +#include "DarkInspirationBehavior.h" + +#include "BehaviorBranchContext.h" +#include "Entity.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "BehaviorContext.h" + +void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + + if (target == nullptr) { + Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target); + return; + } + + auto* destroyableComponent = target->GetComponent(); + + if (destroyableComponent == nullptr) { + return; + } + + if (destroyableComponent->HasFaction(m_FactionList)) { + this->m_ActionIfFactionMatches->Handle(context, bitStream, branch); + } +} + +void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* target = EntityManager::Instance()->GetEntity(branch.target); + + if (target == nullptr) { + Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target); + + return; + } + + auto* destroyableComponent = target->GetComponent(); + + if (destroyableComponent == nullptr) { + return; + } + + if (destroyableComponent->HasFaction(m_FactionList)) { + this->m_ActionIfFactionMatches->Calculate(context, bitStream, branch); + } +} + +void DarkInspirationBehavior::Load() { + this->m_ActionIfFactionMatches = GetAction("action"); + + this->m_FactionList = GetInt("faction_list"); +} diff --git a/dGame/dBehaviors/DarkInspirationBehavior.h b/dGame/dBehaviors/DarkInspirationBehavior.h new file mode 100644 index 00000000..f8298742 --- /dev/null +++ b/dGame/dBehaviors/DarkInspirationBehavior.h @@ -0,0 +1,22 @@ +#pragma once +#include "Behavior.h" + +class DarkInspirationBehavior final : public Behavior +{ +public: + /* + * Inherited + */ + + explicit DarkInspirationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Load() override; +private: + Behavior* m_ActionIfFactionMatches; + uint32_t m_FactionList; +}; diff --git a/dGame/dBehaviors/ForceMovementBehavior.cpp b/dGame/dBehaviors/ForceMovementBehavior.cpp index 55cda622..52359cf7 100644 --- a/dGame/dBehaviors/ForceMovementBehavior.cpp +++ b/dGame/dBehaviors/ForceMovementBehavior.cpp @@ -3,23 +3,34 @@ #include "BehaviorContext.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" +#include "Game.h" +#include "dLogger.h" void ForceMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { return; } - uint32_t handle; - bitStream->Read(handle); - context->RegisterSyncBehavior(handle, this, branch); + uint32_t handle{}; + if (!bitStream->Read(handle)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + } + context->RegisterSyncBehavior(handle, this, branch, this->m_Duration); } void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - uint32_t next; - bitStream->Read(next); + uint32_t next{}; + if (!bitStream->Read(next)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } - LWOOBJID target; - bitStream->Read(target); + LWOOBJID target{}; + if (!bitStream->Read(target)) { + Game::logger->Log("ForceMovementBehavior", "Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + return; + } branch.target = target; auto* behavior = CreateBehavior(next); @@ -75,5 +86,5 @@ void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::Bi this->m_hitAction->Calculate(context, bitStream, branch); this->m_hitEnemyAction->Calculate(context, bitStream, branch); - this->m_hitEnemyAction->Calculate(context, bitStream, branch); + this->m_hitFactionAction->Calculate(context, bitStream, branch); } diff --git a/dGame/dBehaviors/HealBehavior.cpp b/dGame/dBehaviors/HealBehavior.cpp index 2799d2e2..66fe2c79 100644 --- a/dGame/dBehaviors/HealBehavior.cpp +++ b/dGame/dBehaviors/HealBehavior.cpp @@ -4,6 +4,7 @@ #include "dLogger.h" #include "EntityManager.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { @@ -15,7 +16,7 @@ void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_strea return; } - auto* destroyable = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto* destroyable = static_cast(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (destroyable == nullptr) { Game::logger->Log("HealBehavior", "Failed to find destroyable component for %(llu)!", branch.target); diff --git a/dGame/dBehaviors/ImmunityBehavior.cpp b/dGame/dBehaviors/ImmunityBehavior.cpp index 69c652f9..f4a41c52 100644 --- a/dGame/dBehaviors/ImmunityBehavior.cpp +++ b/dGame/dBehaviors/ImmunityBehavior.cpp @@ -6,28 +6,47 @@ #include "Game.h" #include "dLogger.h" #include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - if (target == nullptr) { + if (!target) { Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); - return; } - auto* destroyable = static_cast(target->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - - if (destroyable == nullptr) { - return; + auto* destroyableComponent = target->GetComponent(); + if (destroyableComponent) { + destroyableComponent->SetStatusImmunity( + eStateChangeType::PUSH, + this->m_ImmuneToBasicAttack, + this->m_ImmuneToDamageOverTime, + this->m_ImmuneToKnockback, + this->m_ImmuneToInterrupt, + this->m_ImmuneToSpeed, + this->m_ImmuneToImaginationGain, + this->m_ImmuneToImaginationLoss, + this->m_ImmuneToQuickbuildInterrupt, + this->m_ImmuneToPullToPoint + ); } - if (!this->m_immuneBasicAttack) { - return; + auto* controllablePhysicsComponent = target->GetComponent(); + if (controllablePhysicsComponent) { + controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::PUSH, + context->caster, + this->m_ImmuneToStunAttack, + this->m_ImmuneToStunEquip, + this->m_ImmuneToStunInteract, + this->m_ImmuneToStunJump, + this->m_ImmuneToStunMove, + this->m_ImmuneToStunTurn, + this->m_ImmuneToStunUseItem + ); } - destroyable->PushImmunity(); - context->RegisterTimerBehavior(this, branch, target->GetObjectID()); } @@ -38,21 +57,60 @@ void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bi void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(second); - if (target == nullptr) { + if (!target) { Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second); - return; } - auto* destroyable = static_cast(target->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - - if (destroyable == nullptr) { - return; + auto* destroyableComponent = target->GetComponent(); + if (destroyableComponent) { + destroyableComponent->SetStatusImmunity( + eStateChangeType::POP, + this->m_ImmuneToBasicAttack, + this->m_ImmuneToDamageOverTime, + this->m_ImmuneToKnockback, + this->m_ImmuneToInterrupt, + this->m_ImmuneToSpeed, + this->m_ImmuneToImaginationGain, + this->m_ImmuneToImaginationLoss, + this->m_ImmuneToQuickbuildInterrupt, + this->m_ImmuneToPullToPoint + ); + } + + auto* controllablePhysicsComponent = target->GetComponent(); + if (controllablePhysicsComponent) { + controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::POP, + context->caster, + this->m_ImmuneToStunAttack, + this->m_ImmuneToStunEquip, + this->m_ImmuneToStunInteract, + this->m_ImmuneToStunJump, + this->m_ImmuneToStunMove, + this->m_ImmuneToStunTurn, + this->m_ImmuneToStunUseItem + ); } - destroyable->PopImmunity(); } void ImmunityBehavior::Load() { - this->m_immuneBasicAttack = GetBoolean("immune_basic_attack"); + //Stun + this->m_ImmuneToStunAttack = GetBoolean("immune_stun_attack", false); + this->m_ImmuneToStunEquip = GetBoolean("immune_stun_equip", false); + this->m_ImmuneToStunInteract = GetBoolean("immune_stun_interact", false); + this->m_ImmuneToStunMove = GetBoolean("immune_stun_move", false); + this->m_ImmuneToStunTurn = GetBoolean("immune_stun_rotate", false); + + // Status + this->m_ImmuneToBasicAttack = GetBoolean("immune_basic_attack", false); + this->m_ImmuneToDamageOverTime = GetBoolean("immune_damage_over_time", false); + this->m_ImmuneToKnockback = GetBoolean("immune_knockback", false); + this->m_ImmuneToInterrupt = GetBoolean("immune_interrupt", false); + this->m_ImmuneToSpeed = GetBoolean("immune_speed", false); + this->m_ImmuneToImaginationGain = GetBoolean("immune_imagination_gain", false); + this->m_ImmuneToImaginationLoss = GetBoolean("immune_imagination_loss", false); + this->m_ImmuneToQuickbuildInterrupt = GetBoolean("immune_quickbuild_interrupts", false); + this->m_ImmuneToPullToPoint = GetBoolean("immune_pulltopoint", false); } diff --git a/dGame/dBehaviors/ImmunityBehavior.h b/dGame/dBehaviors/ImmunityBehavior.h index f9409e4c..02cc0fae 100644 --- a/dGame/dBehaviors/ImmunityBehavior.h +++ b/dGame/dBehaviors/ImmunityBehavior.h @@ -4,8 +4,6 @@ class ImmunityBehavior final : public Behavior { public: - uint32_t m_immuneBasicAttack; - /* * Inherited */ @@ -20,4 +18,25 @@ public: void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void Load() override; + +private: + // stuns + bool m_ImmuneToStunAttack = false; + bool m_ImmuneToStunEquip = false; + bool m_ImmuneToStunInteract = false; + bool m_ImmuneToStunJump = false; // Unused + bool m_ImmuneToStunMove = false; + bool m_ImmuneToStunTurn = false; + bool m_ImmuneToStunUseItem = false; // Unused + + //status + bool m_ImmuneToBasicAttack = false; + bool m_ImmuneToDamageOverTime = false; + bool m_ImmuneToKnockback = false; + bool m_ImmuneToInterrupt = false; + bool m_ImmuneToSpeed = false; + bool m_ImmuneToImaginationGain = false; + bool m_ImmuneToImaginationLoss = false; + bool m_ImmuneToQuickbuildInterrupt = false; + bool m_ImmuneToPullToPoint = false; // Unused in cdclient, but used in client }; diff --git a/dGame/dBehaviors/InterruptBehavior.cpp b/dGame/dBehaviors/InterruptBehavior.cpp index b42eadb0..9035c092 100644 --- a/dGame/dBehaviors/InterruptBehavior.cpp +++ b/dGame/dBehaviors/InterruptBehavior.cpp @@ -11,7 +11,10 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS if (branch.target != context->originator) { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown1 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (unknown) return; } @@ -19,7 +22,10 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS if (!this->m_interruptBlock) { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown2 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (unknown) return; } @@ -28,7 +34,10 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS { bool unknown = false; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("InterruptBehavior", "Unable to read unknown3 from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } if (branch.target == context->originator) return; diff --git a/dGame/dBehaviors/KnockbackBehavior.cpp b/dGame/dBehaviors/KnockbackBehavior.cpp index 83c82010..1b878ed0 100644 --- a/dGame/dBehaviors/KnockbackBehavior.cpp +++ b/dGame/dBehaviors/KnockbackBehavior.cpp @@ -6,11 +6,16 @@ #include "EntityManager.h" #include "GameMessages.h" #include "DestroyableComponent.h" +#include "Game.h" +#include "dLogger.h" void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - bool unknown; + bool unknown{}; - bitStream->Read(unknown); + if (!bitStream->Read(unknown)) { + Game::logger->Log("KnockbackBehavior", "Unable to read unknown from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { diff --git a/dGame/dBehaviors/MovementSwitchBehavior.cpp b/dGame/dBehaviors/MovementSwitchBehavior.cpp index 17ed5c40..0c11380f 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.cpp +++ b/dGame/dBehaviors/MovementSwitchBehavior.cpp @@ -4,18 +4,20 @@ #include "dLogger.h" void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - if (this->m_groundAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_jumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_fallingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_doubleJumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_airAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && - this->m_jetpackAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + uint32_t movementType{}; + if (!bitStream->Read(movementType)) { + if (this->m_groundAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_jumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_fallingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_doubleJumpAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_airAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_jetpackAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && + this->m_movingAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + return; + } + Game::logger->Log("MovementSwitchBehavior", "Unable to read movementType from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); return; - } - - uint32_t movementType; - - bitStream->Read(movementType); + }; switch (movementType) { case 1: @@ -25,34 +27,40 @@ void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* this->m_jumpAction->Handle(context, bitStream, branch); break; case 3: - this->m_fallingAction->Handle(context, bitStream, branch); + this->m_airAction->Handle(context, bitStream, branch); break; case 4: this->m_doubleJumpAction->Handle(context, bitStream, branch); break; case 5: - this->m_airAction->Handle(context, bitStream, branch); + this->m_fallingAction->Handle(context, bitStream, branch); break; case 6: this->m_jetpackAction->Handle(context, bitStream, branch); break; default: - Game::logger->Log("MovementSwitchBehavior", "Invalid movement behavior type (%i)!", movementType); + this->m_groundAction->Handle(context, bitStream, branch); break; } } -void MovementSwitchBehavior::Load() { - this->m_airAction = GetAction("air_action"); - - this->m_doubleJumpAction = GetAction("double_jump_action"); - - this->m_fallingAction = GetAction("falling_action"); - - this->m_groundAction = GetAction("ground_action"); - - this->m_jetpackAction = GetAction("jetpack_action"); - - this->m_jumpAction = GetAction("jump_action"); +Behavior* MovementSwitchBehavior::LoadMovementType(std::string movementType) { + float actionValue = GetFloat(movementType, -1.0f); + auto loadedBehavior = GetAction(actionValue != -1.0f ? actionValue : 0.0f); + if (actionValue == -1.0f && loadedBehavior->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + loadedBehavior = this->m_groundAction; + } + return loadedBehavior; } +void MovementSwitchBehavior::Load() { + float groundActionValue = GetFloat("ground_action", -1.0f); + this->m_groundAction = GetAction(groundActionValue != -1.0f ? groundActionValue : 0.0f); + + this->m_airAction = LoadMovementType("air_action"); + this->m_doubleJumpAction = LoadMovementType("double_jump_action"); + this->m_fallingAction = LoadMovementType("falling_action"); + this->m_jetpackAction = LoadMovementType("jetpack_action"); + this->m_jumpAction = LoadMovementType("jump_action"); + this->m_movingAction = LoadMovementType("moving_action"); +} diff --git a/dGame/dBehaviors/MovementSwitchBehavior.h b/dGame/dBehaviors/MovementSwitchBehavior.h index 82e1a9e9..e6ff96f6 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.h +++ b/dGame/dBehaviors/MovementSwitchBehavior.h @@ -3,7 +3,7 @@ class MovementSwitchBehavior final : public Behavior { -public: +private: /* * Members */ @@ -19,6 +19,17 @@ public: Behavior* m_jumpAction; + Behavior* m_movingAction; + + /** + * @brief Loads a movement type from the database into a behavior + * + * @param movementType The movement type to lookup in the database + * @param behaviorToLoad The Behavior where the result will be stored + */ + Behavior* LoadMovementType(std::string movementType); + +public: /* * Inherited */ diff --git a/dGame/dBehaviors/OverTimeBehavior.cpp b/dGame/dBehaviors/OverTimeBehavior.cpp index 43ac9bc2..5afbbd26 100644 --- a/dGame/dBehaviors/OverTimeBehavior.cpp +++ b/dGame/dBehaviors/OverTimeBehavior.cpp @@ -6,6 +6,10 @@ #include "EntityManager.h" #include "SkillComponent.h" #include "DestroyableComponent.h" +#include "CDClientDatabase.h" +#include "CDClientManager.h" + +#include "CDSkillBehaviorTable.h" void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { const auto originator = context->originator; @@ -37,7 +41,7 @@ void OverTimeBehavior::Load() { m_Action = GetInt("action"); // Since m_Action is a skillID and not a behavior, get is correlated behaviorID. - CDSkillBehaviorTable* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + CDSkillBehaviorTable* skillTable = CDClientManager::Instance().GetTable(); m_ActionBehaviorId = skillTable->GetSkillByID(m_Action).behaviorID; m_Delay = GetFloat("delay"); diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.cpp b/dGame/dBehaviors/ProjectileAttackBehavior.cpp index 350234e2..3ce6c415 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.cpp +++ b/dGame/dBehaviors/ProjectileAttackBehavior.cpp @@ -8,9 +8,12 @@ #include "../dWorldServer/ObjectIDManager.h" void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - LWOOBJID target; + LWOOBJID target{}; - bitStream->Read(target); + if (!bitStream->Read(target)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; auto* entity = EntityManager::Instance()->GetEntity(context->originator); @@ -28,17 +31,23 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea return; } - if (m_useMouseposit) { + if (m_useMouseposit && !branch.isSync) { NiPoint3 targetPosition = NiPoint3::ZERO; - bitStream->Read(targetPosition); + if (!bitStream->Read(targetPosition)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } auto* targetEntity = EntityManager::Instance()->GetEntity(target); for (auto i = 0u; i < this->m_projectileCount; ++i) { - LWOOBJID projectileId; + LWOOBJID projectileId{}; - bitStream->Read(projectileId); + if (!bitStream->Read(projectileId)) { + Game::logger->Log("ProjectileAttackBehavior", "Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; branch.target = target; branch.isProjectile = true; @@ -98,7 +107,7 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt for (auto i = 0u; i < this->m_projectileCount; ++i) { auto id = static_cast(ObjectIDManager::Instance()->GenerateObjectID()); - id = GeneralUtils::SetBit(id, OBJECT_BIT_CLIENT); + id = GeneralUtils::SetBit(id, OBJECT_BIT_SPAWNED); bitStream->Write(id); @@ -148,4 +157,6 @@ void ProjectileAttackBehavior::Load() { this->m_trackRadius = GetFloat("track_radius"); this->m_useMouseposit = GetBoolean("use_mouseposit"); + + this->m_ProjectileType = GetInt("projectile_type"); } diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.h b/dGame/dBehaviors/ProjectileAttackBehavior.h index 17353a2a..b307e66c 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.h +++ b/dGame/dBehaviors/ProjectileAttackBehavior.h @@ -23,6 +23,8 @@ public: bool m_useMouseposit; + int32_t m_ProjectileType; + /* * Inherited */ diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.cpp b/dGame/dBehaviors/PropertyTeleportBehavior.cpp new file mode 100644 index 00000000..447b085b --- /dev/null +++ b/dGame/dBehaviors/PropertyTeleportBehavior.cpp @@ -0,0 +1,61 @@ +#include "PropertyTeleportBehavior.h" + +#include "BehaviorBranchContext.h" +#include "BehaviorContext.h" +#include "Character.h" +#include "CharacterComponent.h" +#include "ChatPackets.h" +#include "WorldPackets.h" +#include "EntityManager.h" +#include "Game.h" +#include "ZoneInstanceManager.h" +#include "dZoneManager.h" + +void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* caster = EntityManager::Instance()->GetEntity(context->caster); + if (!caster) return; + + auto* character = caster->GetCharacter(); + if (!character) return; + + LWOOBJID objId = caster->GetObjectID(); + + LWOMAPID targetMapId = m_MapId; + LWOCLONEID targetCloneId = character->GetPropertyCloneID(); + + if (dZoneManager::Instance()->GetZoneID().GetCloneID() == character->GetPropertyCloneID()) { + targetMapId = character->GetLastNonInstanceZoneID(); + targetCloneId = 0; + } else { + character->SetLastNonInstanceZoneID(dZoneManager::Instance()->GetZoneID().GetMapID()); + } + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, targetMapId, targetCloneId, false, [objId](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + + auto* entity = EntityManager::Instance()->GetEntity(objId); + if (!entity) return; + + const auto sysAddr = entity->GetSystemAddress(); + + if (zoneClone != 0) ChatPackets::SendSystemMessage(sysAddr, u"Transfering to your property!"); + else ChatPackets::SendSystemMessage(sysAddr, u"Transfering back to previous world!"); + + Game::logger->Log("PropertyTeleportBehavior", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + entity->GetComponent()->SetLastRocketConfig(u""); + } + + entity->GetCharacter()->SaveXMLToDatabase(); + + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + return; + }); +} + +void PropertyTeleportBehavior::Load() { + this->m_CancelIfInteracting = GetBoolean("cancel_if_interacting"); // TODO unused + this->m_MapId = LWOMAPID(GetInt("mapID")); +} diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.h b/dGame/dBehaviors/PropertyTeleportBehavior.h new file mode 100644 index 00000000..74eed03b --- /dev/null +++ b/dGame/dBehaviors/PropertyTeleportBehavior.h @@ -0,0 +1,21 @@ +#pragma once +#include "Behavior.h" + +class PropertyTeleportBehavior final : public Behavior +{ +public: + /* + * Inherited + */ + + explicit PropertyTeleportBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Load() override; + +private: + LWOMAPID m_MapId; + bool m_CancelIfInteracting; +}; diff --git a/dGame/dBehaviors/RemoveBuffBehavior.cpp b/dGame/dBehaviors/RemoveBuffBehavior.cpp new file mode 100644 index 00000000..be3066ac --- /dev/null +++ b/dGame/dBehaviors/RemoveBuffBehavior.cpp @@ -0,0 +1,21 @@ +#include "RemoveBuffBehavior.h" + +#include "BehaviorBranchContext.h" +#include "BehaviorContext.h" +#include "EntityManager.h" +#include "BuffComponent.h" + +void RemoveBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + auto* entity = EntityManager::Instance()->GetEntity(context->caster); + if (!entity) return; + + auto* buffComponent = entity->GetComponent(); + if (!buffComponent) return; + + buffComponent->RemoveBuff(m_BuffId, false, m_RemoveImmunity); +} + +void RemoveBuffBehavior::Load() { + this->m_RemoveImmunity = GetBoolean("remove_immunity"); + this->m_BuffId = GetInt("buff_id"); +} diff --git a/dGame/dBehaviors/RemoveBuffBehavior.h b/dGame/dBehaviors/RemoveBuffBehavior.h new file mode 100644 index 00000000..f2d8547b --- /dev/null +++ b/dGame/dBehaviors/RemoveBuffBehavior.h @@ -0,0 +1,22 @@ +#pragma once +#include "Behavior.h" + +class RemoveBuffBehavior final : public Behavior +{ +public: + + /* + * Inherited + */ + + explicit RemoveBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void Load() override; + +private: + bool m_RemoveImmunity; + uint32_t m_BuffId; +}; diff --git a/dGame/dBehaviors/RepairBehavior.cpp b/dGame/dBehaviors/RepairBehavior.cpp index a48141d3..ce2e5fd2 100644 --- a/dGame/dBehaviors/RepairBehavior.cpp +++ b/dGame/dBehaviors/RepairBehavior.cpp @@ -5,6 +5,7 @@ #include "EntityManager.h" #include "dLogger.h" #include "Game.h" +#include "eReplicaComponentType.h" void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { auto* entity = EntityManager::Instance()->GetEntity(branch.target); @@ -15,7 +16,7 @@ void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_str return; } - auto* destroyable = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto* destroyable = static_cast(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (destroyable == nullptr) { Game::logger->Log("RepairBehavior", "Failed to find destroyable component for %(llu)!", branch.target); diff --git a/dGame/dBehaviors/SpawnBehavior.cpp b/dGame/dBehaviors/SpawnBehavior.cpp index ac7bb797..75c84f6c 100644 --- a/dGame/dBehaviors/SpawnBehavior.cpp +++ b/dGame/dBehaviors/SpawnBehavior.cpp @@ -7,6 +7,9 @@ #include "dLogger.h" #include "DestroyableComponent.h" #include "RebuildComponent.h" +#include "Entity.h" +#include "EntityInfo.h" +#include "eReplicaComponentType.h" void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { auto* origin = EntityManager::Instance()->GetEntity(context->originator); @@ -84,7 +87,7 @@ void SpawnBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext return; } - auto* destroyable = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto* destroyable = static_cast(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (destroyable == nullptr) { entity->Smash(context->originator); diff --git a/dGame/dBehaviors/SpeedBehavior.cpp b/dGame/dBehaviors/SpeedBehavior.cpp index c7855557..d326aa45 100644 --- a/dGame/dBehaviors/SpeedBehavior.cpp +++ b/dGame/dBehaviors/SpeedBehavior.cpp @@ -7,85 +7,48 @@ void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - if (m_AffectsCaster) { - branch.target = context->caster; - } + if (m_AffectsCaster) branch.target = context->caster; auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } + if (!target) return; auto* controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current + ((m_RunSpeed - 500.0f) / 500.0f)); - + controllablePhysicsComponent->AddSpeedboost(m_RunSpeed); EntityManager::Instance()->SerializeEntity(target); if (branch.duration > 0.0f) { context->RegisterTimerBehavior(this, branch); } else if (branch.start > 0) { - controllablePhysicsComponent->SetIgnoreMultipliers(true); - context->RegisterEndBehavior(this, branch); } } +void SpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + Handle(context, bitStream, branch); +} + +void SpeedBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { + End(context, branch, LWOOBJID_EMPTY); +} + void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { - auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } - - auto* controllablePhysicsComponent = target->GetComponent(); - - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((m_RunSpeed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(target); + End(context, branch, second); } void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { auto* target = EntityManager::Instance()->GetEntity(branch.target); - - if (target == nullptr) { - return; - } + if (!target) return; auto* controllablePhysicsComponent = target->GetComponent(); + if (!controllablePhysicsComponent) return; - if (controllablePhysicsComponent == nullptr) { - return; - } - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetIgnoreMultipliers(false); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((m_RunSpeed - 500.0f) / 500.0f)); - + controllablePhysicsComponent->RemoveSpeedboost(m_RunSpeed); EntityManager::Instance()->SerializeEntity(target); } void SpeedBehavior::Load() { m_RunSpeed = GetFloat("run_speed"); - - if (m_RunSpeed < 500.0f) { - m_RunSpeed = 500.0f; - } - m_AffectsCaster = GetBoolean("affects_caster"); } diff --git a/dGame/dBehaviors/SpeedBehavior.h b/dGame/dBehaviors/SpeedBehavior.h index 04c0090f..88b85820 100644 --- a/dGame/dBehaviors/SpeedBehavior.h +++ b/dGame/dBehaviors/SpeedBehavior.h @@ -13,6 +13,10 @@ public: void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; diff --git a/dGame/dBehaviors/StunBehavior.cpp b/dGame/dBehaviors/StunBehavior.cpp index 59a81440..4e34d3a2 100644 --- a/dGame/dBehaviors/StunBehavior.cpp +++ b/dGame/dBehaviors/StunBehavior.cpp @@ -7,6 +7,7 @@ #include "Game.h" #include "dLogger.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { @@ -14,8 +15,11 @@ void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream return; } - bool blocked; - bitStream->Read(blocked); + bool blocked{}; + if (!bitStream->Read(blocked)) { + Game::logger->Log("StunBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; auto* target = EntityManager::Instance()->GetEntity(branch.target); @@ -29,7 +33,7 @@ void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream * If our target is an enemy we can go ahead and stun it. */ - auto* combatAiComponent = static_cast(target->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); + auto* combatAiComponent = static_cast(target->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); if (combatAiComponent == nullptr) { return; @@ -52,7 +56,7 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr * See if we can stun ourselves */ - auto* combatAiComponent = static_cast(self->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); + auto* combatAiComponent = static_cast(self->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); if (combatAiComponent == nullptr) { return; @@ -87,7 +91,7 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr * If our target is an enemy we can go ahead and stun it. */ - auto* combatAiComponent = static_cast(target->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); + auto* combatAiComponent = static_cast(target->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); if (combatAiComponent == nullptr) { return; diff --git a/dGame/dBehaviors/SwitchBehavior.cpp b/dGame/dBehaviors/SwitchBehavior.cpp index 78271b99..c010f31b 100644 --- a/dGame/dBehaviors/SwitchBehavior.cpp +++ b/dGame/dBehaviors/SwitchBehavior.cpp @@ -10,7 +10,10 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre auto state = true; if (this->m_imagination > 0 || !this->m_isEnemyFaction) { - bitStream->Read(state); + if (!bitStream->Read(state)) { + Game::logger->Log("SwitchBehavior", "Unable to read state from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; } auto* entity = EntityManager::Instance()->GetEntity(context->originator); @@ -25,7 +28,7 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre return; } - Game::logger->Log("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); + Game::logger->LogDebug("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); if (state || (entity->GetLOT() == 8092 && destroyableComponent->GetImagination() >= m_imagination)) { this->m_actionTrue->Handle(context, bitStream, branch); diff --git a/dGame/dBehaviors/SwitchMultipleBehavior.cpp b/dGame/dBehaviors/SwitchMultipleBehavior.cpp index 946e5e0f..23411429 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.cpp +++ b/dGame/dBehaviors/SwitchMultipleBehavior.cpp @@ -9,31 +9,30 @@ #include "EntityManager.h" -void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { - float value; +void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { + float value{}; - bit_stream->Read(value); + if (!bitStream->Read(value)) { + Game::logger->Log("SwitchMultipleBehavior", "Unable to read value from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; uint32_t trigger = 0; for (unsigned int i = 0; i < this->m_behaviors.size(); i++) { const double data = this->m_behaviors.at(i).first; + trigger = i; - if (value <= data) { - - trigger = i; - - break; - } + if (value <= data) break; } auto* behavior = this->m_behaviors.at(trigger).second; - behavior->Handle(context, bit_stream, branch); + behavior->Handle(context, bitStream, branch); } -void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { +void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { // TODO } diff --git a/dGame/dBehaviors/TacArcBehavior.cpp b/dGame/dBehaviors/TacArcBehavior.cpp index 8789f9b6..91df3879 100644 --- a/dGame/dBehaviors/TacArcBehavior.cpp +++ b/dGame/dBehaviors/TacArcBehavior.cpp @@ -20,12 +20,18 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre bool hit = false; - bitStream->Read(hit); + if (!bitStream->Read(hit)) { + Game::logger->Log("TacArcBehavior", "Unable to read hit from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (this->m_checkEnv) { bool blocked = false; - bitStream->Read(blocked); + if (!bitStream->Read(blocked)) { + Game::logger->Log("TacArcBehavior", "Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (blocked) { this->m_blockedAction->Handle(context, bitStream, branch); @@ -37,7 +43,10 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre if (hit) { uint32_t count = 0; - bitStream->Read(count); + if (!bitStream->Read(count)) { + Game::logger->Log("TacArcBehavior", "Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; if (count > m_maxTargets && m_maxTargets > 0) { count = m_maxTargets; @@ -46,9 +55,12 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre std::vector targets; for (auto i = 0u; i < count; ++i) { - LWOOBJID id; + LWOOBJID id{}; - bitStream->Read(id); + if (!bitStream->Read(id)) { + Game::logger->Log("TacArcBehavior", "Unable to read id from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + return; + }; targets.push_back(id); } diff --git a/dGame/dComponents/AchievementCacheKey.h b/dGame/dComponents/AchievementCacheKey.h new file mode 100644 index 00000000..398e0231 --- /dev/null +++ b/dGame/dComponents/AchievementCacheKey.h @@ -0,0 +1,45 @@ +#include "eMissionTaskType.h" + +#ifndef __ACHIEVEMENTCACHEKEY__H__ +#define __ACHIEVEMENTCACHEKEY__H__ + +class AchievementCacheKey { +public: + AchievementCacheKey() { + targets = ""; + value = 0; + type = eMissionTaskType::UNKNOWN; + }; + + bool operator==(const AchievementCacheKey& point) const { + return this->targets == point.targets && this->value == point.value && this->type == point.type; + }; + void SetTargets(const std::string value) { this->targets = value; }; + void SetValue(uint32_t value) { this->value = value; }; + void SetType(eMissionTaskType value) { this->type = value; }; + + std::string GetTargets() const { return this->targets; }; + uint32_t GetValue() const { return this->value; }; + eMissionTaskType GetType() const { return this->type; }; +private: + std::string targets; + uint32_t value; + eMissionTaskType type; + +}; + +// Specialization of hash for the above class +namespace std { + template<> + struct hash { + size_t operator()(const AchievementCacheKey& key) const { + size_t hash = 0; + GeneralUtils::hash_combine(hash, key.GetType()); + GeneralUtils::hash_combine(hash, key.GetValue()); + GeneralUtils::hash_combine(hash, key.GetTargets()); + return hash; + }; + }; +}; + +#endif //!__ACHIEVEMENTCACHEKEY__H__ diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index c035a807..64c739f5 100644 --- a/dGame/dComponents/BaseCombatAIComponent.cpp +++ b/dGame/dComponents/BaseCombatAIComponent.cpp @@ -22,10 +22,13 @@ #include "SkillComponent.h" #include "RebuildComponent.h" #include "DestroyableComponent.h" +#include "Metrics.hpp" +#include "CDComponentsRegistryTable.h" +#include "CDPhysicsComponentTable.h" -BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) : Component(parent) { +BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): Component(parent) { m_Target = LWOOBJID_EMPTY; - m_State = AiState::spawn; + SetAiState(AiState::spawn); m_Timer = 1.0f; m_StartPosition = parent->GetPosition(); m_MovementAI = nullptr; @@ -104,10 +107,10 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) int32_t collisionGroup = (COLLISION_GROUP_DYNAMIC | COLLISION_GROUP_ENEMY); - CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - auto componentID = componentRegistryTable->GetByIDAndType(parent->GetLOT(), COMPONENT_TYPE_CONTROLLABLE_PHYSICS); + CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance().GetTable(); + auto componentID = componentRegistryTable->GetByIDAndType(parent->GetLOT(), eReplicaComponentType::CONTROLLABLE_PHYSICS); - CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance()->GetTable("PhysicsComponent"); + CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance().GetTable(); if (physicsComponentTable != nullptr) { auto* info = physicsComponentTable->GetByID(componentID); @@ -179,7 +182,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { if (m_Disabled || m_Parent->GetIsDead()) return; - + bool stunnedThisFrame = m_Stunned; CalculateCombat(deltaTime); // Putting this here for now if (m_StartPosition == NiPoint3::ZERO) { @@ -192,7 +195,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { return; } - if (m_Stunned) { + if (stunnedThisFrame) { m_MovementAI->Stop(); return; @@ -206,7 +209,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) { switch (m_State) { case AiState::spawn: Stun(2.0f); - m_State = AiState::idle; + SetAiState(AiState::idle); break; case AiState::idle: @@ -228,6 +231,18 @@ void BaseCombatAIComponent::Update(const float deltaTime) { void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { + bool hasSkillToCast = false; + for (auto& entry : m_SkillEntries) { + if (entry.cooldown > 0.0f) { + entry.cooldown -= deltaTime; + } else { + hasSkillToCast = true; + } + } + + bool hadRemainingDowntime = m_SkillTime > 0.0f; + if (m_SkillTime > 0.0f) m_SkillTime -= deltaTime; + auto* rebuild = m_Parent->GetComponent(); if (rebuild != nullptr) { @@ -248,19 +263,17 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { if (m_Disabled) return; - if (m_StunTime > 0.0f) { + if (m_Stunned) { m_StunTime -= deltaTime; if (m_StunTime > 0.0f) { return; } - + m_StunTime = 0.0f; m_Stunned = false; } - if (m_Stunned) { - return; - } + if (m_Stunned || hadRemainingDowntime) return; auto newTarget = FindTarget(); @@ -320,41 +333,19 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { m_Timer = 0; } - m_State = AiState::aggro; + SetAiState(AiState::aggro); } else { - m_State = AiState::idle; + SetAiState(AiState::idle); } - for (auto i = 0; i < m_SkillEntries.size(); ++i) { - auto entry = m_SkillEntries.at(i); - - if (entry.cooldown > 0) { - entry.cooldown -= deltaTime; - - m_SkillEntries[i] = entry; - } - } - - if (m_SkillTime > 0) { - m_SkillTime -= deltaTime; - - return; - } - - if (m_Downtime > 0) { - m_Downtime -= deltaTime; - - return; - } + if (!hasSkillToCast) return; if (m_Target == LWOOBJID_EMPTY) { - m_State = AiState::idle; + SetAiState(AiState::idle); return; } - m_Downtime = 0.5f; - auto* target = GetTargetEntity(); if (target != nullptr) { @@ -375,7 +366,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { m_MovementAI->Stop(); } - m_State = AiState::aggro; + SetAiState(AiState::aggro); m_Timer = 0; @@ -532,11 +523,20 @@ bool BaseCombatAIComponent::IsMech() { void BaseCombatAIComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write1(); - outBitStream->Write(uint32_t(m_State)); - outBitStream->Write(m_Target); + outBitStream->Write(m_DirtyStateOrTarget || bIsInitialUpdate); + if (m_DirtyStateOrTarget || bIsInitialUpdate) { + outBitStream->Write(uint32_t(m_State)); + outBitStream->Write(m_Target); + m_DirtyStateOrTarget = false; + } } +void BaseCombatAIComponent::SetAiState(AiState newState) { + if (newState == this->m_State) return; + this->m_State = newState; + m_DirtyStateOrTarget = true; + EntityManager::Instance()->SerializeEntity(m_Parent); +} bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const { auto* entity = EntityManager::Instance()->GetEntity(target); @@ -585,7 +585,10 @@ bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const { } void BaseCombatAIComponent::SetTarget(const LWOOBJID target) { + if (this->m_Target == target) return; m_Target = target; + m_DirtyStateOrTarget = true; + EntityManager::Instance()->SerializeEntity(m_Parent); } Entity* BaseCombatAIComponent::GetTargetEntity() const { @@ -700,7 +703,7 @@ void BaseCombatAIComponent::OnAggro() { m_MovementAI->SetDestination(targetPos); - m_State = AiState::tether; + SetAiState(AiState::tether); } m_Timer += 0.5f; @@ -726,7 +729,7 @@ void BaseCombatAIComponent::OnTether() { m_MovementAI->SetDestination(m_StartPosition); - m_State = AiState::aggro; + SetAiState(AiState::aggro); } else { if (IsMech() && Vector3::DistanceSquared(targetPos, currentPos) > m_AttackRadius * m_AttackRadius * 3 * 3) return; diff --git a/dGame/dComponents/BaseCombatAIComponent.h b/dGame/dComponents/BaseCombatAIComponent.h index 70a88a42..8bf6140a 100644 --- a/dGame/dComponents/BaseCombatAIComponent.h +++ b/dGame/dComponents/BaseCombatAIComponent.h @@ -8,6 +8,7 @@ #include "dpWorld.h" #include "dpEntity.h" #include "Component.h" +#include "eReplicaComponentType.h" #include #include @@ -46,7 +47,7 @@ struct AiSkillEntry */ class BaseCombatAIComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_BASE_COMBAT_AI; + static const eReplicaComponentType ComponentType = eReplicaComponentType::BASE_COMBAT_AI; BaseCombatAIComponent(Entity* parentEntity, uint32_t id); ~BaseCombatAIComponent() override; @@ -243,6 +244,12 @@ private: */ std::vector GetTargetWithinAggroRange() const; + /** + * @brief Sets the AiState and prepares the entity for serialization next frame. + * + */ + void SetAiState(AiState newState); + /** * The current state of the AI */ @@ -334,11 +341,6 @@ private: */ bool m_StunImmune = false; - /** - * Time taken between actions - */ - float m_Downtime = 0; - /** * How long this entity needs to execute its skill */ @@ -374,6 +376,12 @@ private: */ bool m_DirtyThreat = false; + /** + * Whether or not the Component has dirty information and should update next frame + * + */ + bool m_DirtyStateOrTarget = false; + /** * Whether the current entity is a mech enemy, needed as mechs tether radius works differently * @return whether this entity is a mech diff --git a/dGame/dComponents/BouncerComponent.cpp b/dGame/dComponents/BouncerComponent.cpp index 1f32d6e5..f6a53261 100644 --- a/dGame/dComponents/BouncerComponent.cpp +++ b/dGame/dComponents/BouncerComponent.cpp @@ -7,6 +7,7 @@ #include "dLogger.h" #include "GameMessages.h" #include +#include "eTriggerEventType.h" BouncerComponent::BouncerComponent(Entity* parent) : Component(parent) { m_PetEnabled = false; @@ -46,8 +47,10 @@ void BouncerComponent::SetPetBouncerEnabled(bool value) { EntityManager::Instance()->SerializeEntity(m_Parent); if (value) { + m_Parent->TriggerEvent(eTriggerEventType::PET_ON_SWITCH, m_Parent); GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 1513, u"create", "PetOnSwitch", LWOOBJID_EMPTY, 1, 1, true); } else { + m_Parent->TriggerEvent(eTriggerEventType::PET_OFF_SWITCH, m_Parent); GameMessages::SendStopFXEffect(m_Parent, true, "PetOnSwitch"); } diff --git a/dGame/dComponents/BouncerComponent.h b/dGame/dComponents/BouncerComponent.h index f179998b..15665cc1 100644 --- a/dGame/dComponents/BouncerComponent.h +++ b/dGame/dComponents/BouncerComponent.h @@ -5,13 +5,14 @@ #include "RakNetTypes.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Attached to bouncer entities, allowing other entities to bounce off of it */ class BouncerComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_BOUNCER; + static const eReplicaComponentType ComponentType = eReplicaComponentType::BOUNCER; BouncerComponent(Entity* parentEntity); ~BouncerComponent() override; diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index ecb10017..68b5182c 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -9,6 +9,8 @@ #include "SkillComponent.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" +#include "CDClientManager.h" +#include "CDSkillBehaviorTable.h" std::unordered_map> BuffComponent::m_Cache{}; @@ -100,7 +102,7 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO const auto& parameters = GetBuffParameters(id); for (const auto& parameter : parameters) { if (parameter.name == "overtime") { - auto* behaviorTemplateTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + auto* behaviorTemplateTable = CDClientManager::Instance().GetTable(); behaviorID = behaviorTemplateTable->GetSkillByID(parameter.values[0]).behaviorID; stacks = static_cast(parameter.values[1]); @@ -123,13 +125,15 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO m_Buffs.emplace(id, buff); } -void BuffComponent::RemoveBuff(int32_t id) { +void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) { const auto& iter = m_Buffs.find(id); if (iter == m_Buffs.end()) { return; } + GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id); + m_Buffs.erase(iter); RemoveBuffEffect(id); @@ -167,17 +171,10 @@ void BuffComponent::ApplyBuffEffect(int32_t id) { destroyable->SetMaxImagination(destroyable->GetMaxImagination() + maxImagination); } else if (parameter.name == "speed") { - const auto speed = parameter.value; - auto* controllablePhysicsComponent = this->GetParent()->GetComponent(); - - if (controllablePhysicsComponent == nullptr) return; - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current + ((speed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(this->GetParent()); + if (!controllablePhysicsComponent) return; + const auto speed = parameter.value; + controllablePhysicsComponent->AddSpeedboost(speed); } } } @@ -210,17 +207,10 @@ void BuffComponent::RemoveBuffEffect(int32_t id) { destroyable->SetMaxImagination(destroyable->GetMaxImagination() - maxImagination); } else if (parameter.name == "speed") { - const auto speed = parameter.value; - auto* controllablePhysicsComponent = this->GetParent()->GetComponent(); - - if (controllablePhysicsComponent == nullptr) return; - - const auto current = controllablePhysicsComponent->GetSpeedMultiplier(); - - controllablePhysicsComponent->SetSpeedMultiplier(current - ((speed - 500.0f) / 500.0f)); - - EntityManager::Instance()->SerializeEntity(this->GetParent()); + if (!controllablePhysicsComponent) return; + const auto speed = parameter.value; + controllablePhysicsComponent->RemoveSpeedboost(speed); } } } diff --git a/dGame/dComponents/BuffComponent.h b/dGame/dComponents/BuffComponent.h index aa669b13..d9175883 100644 --- a/dGame/dComponents/BuffComponent.h +++ b/dGame/dComponents/BuffComponent.h @@ -7,6 +7,7 @@ #include #include #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -41,7 +42,7 @@ struct Buff */ class BuffComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_BUFF; + static const eReplicaComponentType ComponentType = eReplicaComponentType::BUFF; explicit BuffComponent(Entity* parent); @@ -78,8 +79,9 @@ public: /** * Removes a buff from the parent entity, reversing its effects * @param id the id of the buff to remove + * @param removeImmunity whether or not to remove immunity on removing the buff */ - void RemoveBuff(int32_t id); + void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false); /** * Returns whether or not the entity has a buff identified by `id` diff --git a/dGame/dComponents/BuildBorderComponent.h b/dGame/dComponents/BuildBorderComponent.h index ba677e37..dc5afc8a 100644 --- a/dGame/dComponents/BuildBorderComponent.h +++ b/dGame/dComponents/BuildBorderComponent.h @@ -9,13 +9,14 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component for the build border, allowing the user to start building when interacting with it */ class BuildBorderComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_BUILD_BORDER; + static const eReplicaComponentType ComponentType = eReplicaComponentType::BUILD_BORDER; BuildBorderComponent(Entity* parent); ~BuildBorderComponent() override; diff --git a/dGame/dComponents/CMakeLists.txt b/dGame/dComponents/CMakeLists.txt index 0995428b..b396829a 100644 --- a/dGame/dComponents/CMakeLists.txt +++ b/dGame/dComponents/CMakeLists.txt @@ -38,5 +38,6 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp" "SkillComponent.cpp" "SoundTriggerComponent.cpp" "SwitchComponent.cpp" + "TriggerComponent.cpp" "VehiclePhysicsComponent.cpp" "VendorComponent.cpp" PARENT_SCOPE) diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index 424be0ac..6394cc32 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -13,6 +13,8 @@ #include "VehiclePhysicsComponent.h" #include "GameMessages.h" #include "Item.h" +#include "AMFFormat.h" +#include "eGameMasterLevel.h" CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) { m_Character = character; @@ -42,7 +44,6 @@ bool CharacterComponent::LandingAnimDisabled(int zoneID) { switch (zoneID) { case 0: case 556: - case 1001: case 1101: case 1202: case 1203: @@ -165,9 +166,9 @@ void CharacterComponent::SetPvpEnabled(const bool value) { m_PvpEnabled = value; } -void CharacterComponent::SetGMLevel(int gmlevel) { +void CharacterComponent::SetGMLevel(eGameMasterLevel gmlevel) { m_DirtyGMInfo = true; - if (gmlevel > 0) m_IsGM = true; + if (gmlevel > eGameMasterLevel::CIVILIAN) m_IsGM = true; else m_IsGM = false; m_GMLevel = gmlevel; } @@ -239,7 +240,7 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { // End custom attributes // - if (m_GMLevel > 0) { + if (m_GMLevel > eGameMasterLevel::CIVILIAN) { m_IsGM = true; m_DirtyGMInfo = true; m_EditorLevel = m_GMLevel; diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index 196dfa01..0e047494 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -9,6 +9,7 @@ #include #include "CDMissionsTable.h" #include "tinyxml2.h" +#include "eReplicaComponentType.h" /** * The statistics that can be achieved per zone @@ -59,7 +60,7 @@ enum StatisticID { */ class CharacterComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_CHARACTER; + static const eReplicaComponentType ComponentType = eReplicaComponentType::CHARACTER; CharacterComponent(Entity* parent, Character* character); ~CharacterComponent() override; @@ -177,7 +178,7 @@ public: * Sets the GM level of the character, should be called in the entity. Here it's set for serialization * @param gmlevel the gm level to set */ - void SetGMLevel(int gmlevel); + void SetGMLevel(eGameMasterLevel gmlevel); /** * Initializes the player statistics from the string stored in the XML @@ -332,7 +333,7 @@ private: /** * The current GM level of this character (anything > 0 counts as a GM) */ - unsigned char m_GMLevel; + eGameMasterLevel m_GMLevel; /** * Whether the character has HF enabled @@ -342,7 +343,7 @@ private: /** * The level of the character in HF */ - unsigned char m_EditorLevel; + eGameMasterLevel m_EditorLevel; /** * Whether the currently active activity has been changed diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index d7caf6a9..6a6d69ce 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -12,6 +12,7 @@ #include "EntityManager.h" #include "Character.h" #include "dZoneManager.h" +#include "LevelProgressionComponent.h" ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Component(entity) { m_Position = {}; @@ -30,10 +31,25 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Com m_GravityScale = 1; m_DirtyCheats = false; m_IgnoreMultipliers = false; + + m_DirtyEquippedItemInfo = true; m_PickupRadius = 0.0f; - m_DirtyPickupRadiusScale = true; + + m_DirtyBubble = false; + m_IsInBubble = false; + m_SpecialAnims = false; + m_BubbleType = eBubbleType::DEFAULT; + m_IsTeleporting = false; + m_ImmuneToStunAttackCount = 0; + m_ImmuneToStunEquipCount = 0; + m_ImmuneToStunInteractCount = 0; + m_ImmuneToStunJumpCount = 0; + m_ImmuneToStunMoveCount = 0; + m_ImmuneToStunTurnCount = 0; + m_ImmuneToStunUseItemCount = 0; + if (entity->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI return; @@ -70,16 +86,17 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo outBitStream->Write(m_JetpackBypassChecks); } - outBitStream->Write0(); //This contains info about immunities, but for now I'm leaving it out. + outBitStream->Write1(); // always write these on construction + outBitStream->Write(m_ImmuneToStunMoveCount); + outBitStream->Write(m_ImmuneToStunJumpCount); + outBitStream->Write(m_ImmuneToStunTurnCount); + outBitStream->Write(m_ImmuneToStunAttackCount); + outBitStream->Write(m_ImmuneToStunUseItemCount); + outBitStream->Write(m_ImmuneToStunEquipCount); + outBitStream->Write(m_ImmuneToStunInteractCount); } - if (m_SpeedMultiplier < 1.0f) { - m_DirtyCheats = false; - } - - if (m_IgnoreMultipliers) { - m_DirtyCheats = false; - } + if (m_IgnoreMultipliers) m_DirtyCheats = false; outBitStream->Write(m_DirtyCheats); if (m_DirtyCheats) { @@ -89,14 +106,22 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo m_DirtyCheats = false; } - outBitStream->Write(m_DirtyPickupRadiusScale); - if (m_DirtyPickupRadiusScale) { + outBitStream->Write(m_DirtyEquippedItemInfo); + if (m_DirtyEquippedItemInfo) { outBitStream->Write(m_PickupRadius); - outBitStream->Write0(); //No clue what this is so im leaving it false. - m_DirtyPickupRadiusScale = false; + outBitStream->Write(m_InJetpackMode); + m_DirtyEquippedItemInfo = false; } - outBitStream->Write0(); + outBitStream->Write(m_DirtyBubble); + if (m_DirtyBubble) { + outBitStream->Write(m_IsInBubble); + if (m_IsInBubble) { + outBitStream->Write(m_BubbleType); + outBitStream->Write(m_SpecialAnims); + } + m_DirtyBubble = false; + } outBitStream->Write(m_DirtyPosition || bIsInitialUpdate); if (m_DirtyPosition || bIsInitialUpdate) { @@ -253,7 +278,7 @@ void ControllablePhysicsComponent::AddPickupRadiusScale(float value) { m_ActivePickupRadiusScales.push_back(value); if (value > m_PickupRadius) { m_PickupRadius = value; - m_DirtyPickupRadiusScale = true; + m_DirtyEquippedItemInfo = true; } } @@ -263,16 +288,102 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) { if (pos != m_ActivePickupRadiusScales.end()) { m_ActivePickupRadiusScales.erase(pos); } else { - Game::logger->Log("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size()); + Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find pickup radius %f in list of active radii. List has %i active radii.", value, m_ActivePickupRadiusScales.size()); return; } // Recalculate pickup radius since we removed one by now m_PickupRadius = 0.0f; - m_DirtyPickupRadiusScale = true; + m_DirtyEquippedItemInfo = true; for (uint32_t i = 0; i < m_ActivePickupRadiusScales.size(); i++) { auto candidateRadius = m_ActivePickupRadiusScales[i]; if (m_PickupRadius < candidateRadius) m_PickupRadius = candidateRadius; } EntityManager::Instance()->SerializeEntity(m_Parent); } + +void ControllablePhysicsComponent::AddSpeedboost(float value) { + m_ActiveSpeedBoosts.push_back(value); + m_SpeedBoost = value; + SetSpeedMultiplier(value / 500.0f); // 500 being the base speed +} + +void ControllablePhysicsComponent::RemoveSpeedboost(float value) { + const auto pos = std::find(m_ActiveSpeedBoosts.begin(), m_ActiveSpeedBoosts.end(), value); + if (pos != m_ActiveSpeedBoosts.end()) { + m_ActiveSpeedBoosts.erase(pos); + } else { + Game::logger->LogDebug("ControllablePhysicsComponent", "Warning: Could not find speedboost %f in list of active speedboosts. List has %i active speedboosts.", value, m_ActiveSpeedBoosts.size()); + return; + } + + // Recalculate speedboost since we removed one + m_SpeedBoost = 0.0f; + if (m_ActiveSpeedBoosts.size() == 0) { // no active speed boosts left, so return to base speed + auto* levelProgressionComponent = m_Parent->GetComponent(); + if (levelProgressionComponent) m_SpeedBoost = levelProgressionComponent->GetSpeedBase(); + } else { // Used the last applied speedboost + m_SpeedBoost = m_ActiveSpeedBoosts.back(); + } + SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed + EntityManager::Instance()->SerializeEntity(m_Parent); +} + +void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims){ + if (m_IsInBubble) { + Game::logger->Log("ControllablePhysicsComponent", "Already in bubble"); + return; + } + m_BubbleType = bubbleType; + m_IsInBubble = true; + m_DirtyBubble = true; + m_SpecialAnims = specialAnims; + EntityManager::Instance()->SerializeEntity(m_Parent); +} + +void ControllablePhysicsComponent::DeactivateBubbleBuff(){ + m_DirtyBubble = true; + m_IsInBubble = false; + EntityManager::Instance()->SerializeEntity(m_Parent); +}; + +void ControllablePhysicsComponent::SetStunImmunity( + const eStateChangeType state, + const LWOOBJID originator, + const bool bImmuneToStunAttack, + const bool bImmuneToStunEquip, + const bool bImmuneToStunInteract, + const bool bImmuneToStunJump, + const bool bImmuneToStunMove, + const bool bImmuneToStunTurn, + const bool bImmuneToStunUseItem){ + + if (state == eStateChangeType::POP){ + if (bImmuneToStunAttack && m_ImmuneToStunAttackCount > 0) m_ImmuneToStunAttackCount -= 1; + if (bImmuneToStunEquip && m_ImmuneToStunEquipCount > 0) m_ImmuneToStunEquipCount -= 1; + if (bImmuneToStunInteract && m_ImmuneToStunInteractCount > 0) m_ImmuneToStunInteractCount -= 1; + if (bImmuneToStunJump && m_ImmuneToStunJumpCount > 0) m_ImmuneToStunJumpCount -= 1; + if (bImmuneToStunMove && m_ImmuneToStunMoveCount > 0) m_ImmuneToStunMoveCount -= 1; + if (bImmuneToStunTurn && m_ImmuneToStunTurnCount > 0) m_ImmuneToStunTurnCount -= 1; + if (bImmuneToStunUseItem && m_ImmuneToStunUseItemCount > 0) m_ImmuneToStunUseItemCount -= 1; + } else if (state == eStateChangeType::PUSH) { + if (bImmuneToStunAttack) m_ImmuneToStunAttackCount += 1; + if (bImmuneToStunEquip) m_ImmuneToStunEquipCount += 1; + if (bImmuneToStunInteract) m_ImmuneToStunInteractCount += 1; + if (bImmuneToStunJump) m_ImmuneToStunJumpCount += 1; + if (bImmuneToStunMove) m_ImmuneToStunMoveCount += 1; + if (bImmuneToStunTurn) m_ImmuneToStunTurnCount += 1; + if (bImmuneToStunUseItem) m_ImmuneToStunUseItemCount += 1; + } + + GameMessages::SendSetStunImmunity( + m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(), originator, + bImmuneToStunAttack, + bImmuneToStunEquip, + bImmuneToStunInteract, + bImmuneToStunJump, + bImmuneToStunMove, + bImmuneToStunTurn, + bImmuneToStunUseItem + ); +} diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index ac481b9f..a7359a26 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -9,6 +9,8 @@ #include "Component.h" #include "dpCollisionChecks.h" #include "PhantomPhysicsComponent.h" +#include "eBubbleType.h" +#include "eReplicaComponentType.h" class Entity; class dpEntity; @@ -18,7 +20,7 @@ class dpEntity; */ class ControllablePhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_CONTROLLABLE_PHYSICS; + static const eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS; ControllablePhysicsComponent(Entity* entity); ~ControllablePhysicsComponent() override; @@ -257,6 +259,63 @@ public: */ std::vector GetActivePickupRadiusScales() { return m_ActivePickupRadiusScales; }; + /** + * Add a Speed boost to the entity + * This will recalculate the speed boost based on what is being added + */ + void AddSpeedboost(float value); + + /** + * Remove speed boost from entity + * This will recalculate the speed boost based on what is the last one in te vector + */ + void RemoveSpeedboost(float value); + + /** + * The speed boosts of this component. + * @return All active Speed boosts for this component. + */ + std::vector GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; }; + + /** + * Activates the Bubble Buff + */ + void ActivateBubbleBuff(eBubbleType bubbleType = eBubbleType::DEFAULT, bool specialAnims = true); + + /** + * Deactivates the Bubble Buff + */ + void DeactivateBubbleBuff(); + + /** + * Gets if the Entity is in a bubble + */ + bool GetIsInBubble(){ return m_IsInBubble; }; + + /** + * Push or Pop a layer of stun immunity to this entity + */ + void SetStunImmunity( + const eStateChangeType state, + const LWOOBJID originator = LWOOBJID_EMPTY, + const bool bImmuneToStunAttack = false, + const bool bImmuneToStunEquip = false, + const bool bImmuneToStunInteract = false, + const bool bImmuneToStunJump = false, + const bool bImmuneToStunMove = false, + const bool bImmuneToStunTurn = false, + const bool bImmuneToStunUseItem = false + ); + + // getters for stun immunities + const bool GetImmuneToStunAttack() { return m_ImmuneToStunAttackCount > 0;}; + const bool GetImmuneToStunEquip() { return m_ImmuneToStunEquipCount > 0;}; + const bool GetImmuneToStunInteract() { return m_ImmuneToStunInteractCount > 0;}; + const bool GetImmuneToStunJump() { return m_ImmuneToStunJumpCount > 0;}; + const bool GetImmuneToStunMove() { return m_ImmuneToStunMoveCount > 0;}; + const bool GetImmuneToStunTurn() { return m_ImmuneToStunTurnCount > 0;}; + const bool GetImmuneToStunUseItem() { return m_ImmuneToStunUseItemCount > 0;}; + private: /** * The entity that owns this component @@ -356,7 +415,7 @@ private: /** * Whether the pickup scale is dirty. */ - bool m_DirtyPickupRadiusScale; + bool m_DirtyEquippedItemInfo; /** * The list of pickup radius scales for this entity @@ -372,6 +431,47 @@ private: * If the entity is teleporting */ bool m_IsTeleporting; + + /** + * The list of speed boosts for this entity + */ + std::vector m_ActiveSpeedBoosts; + + /** + * The active speed boost for this entity + */ + float m_SpeedBoost; + + /* + * If Bubble info is dirty + */ + bool m_DirtyBubble; + + /* + * If the entity is in a bubble + */ + bool m_IsInBubble; + + /* + * The type of bubble the entity has + */ + eBubbleType m_BubbleType; + + /* + * If the entity should be using the special animations + */ + bool m_SpecialAnims; + + /** + * stun immunity counters + */ + int32_t m_ImmuneToStunAttackCount; + int32_t m_ImmuneToStunEquipCount; + int32_t m_ImmuneToStunInteractCount; + int32_t m_ImmuneToStunJumpCount; + int32_t m_ImmuneToStunMoveCount; + int32_t m_ImmuneToStunTurnCount; + int32_t m_ImmuneToStunUseItemCount; }; #endif // CONTROLLABLEPHYSICSCOMPONENT_H diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 8b9ae42d..c2d72941 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -2,6 +2,7 @@ #include #include "dLogger.h" #include "Game.h" +#include "dConfig.h" #include "AMFFormat.h" #include "AMFFormat_BitStream.h" @@ -28,7 +29,12 @@ #include "CharacterComponent.h" #include "PossessableComponent.h" #include "PossessorComponent.h" +#include "InventoryComponent.h" #include "dZoneManager.h" +#include "WorldConfig.h" +#include "eMissionTaskType.h" + +#include "CDComponentsRegistryTable.h" DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { m_iArmor = 0; @@ -53,26 +59,35 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { m_LootMatrixID = 0; m_MinCoins = 0; m_MaxCoins = 0; - m_ImmuneStacks = 0; m_DamageReduction = 0; + + m_ImmuneToBasicAttackCount = 0; + m_ImmuneToDamageOverTimeCount = 0; + m_ImmuneToKnockbackCount = 0; + m_ImmuneToInterruptCount = 0; + m_ImmuneToSpeedCount = 0; + m_ImmuneToImaginationGainCount = 0; + m_ImmuneToImaginationLossCount = 0; + m_ImmuneToQuickbuildInterruptCount = 0; + m_ImmuneToPullToPointCount = 0; } DestroyableComponent::~DestroyableComponent() { } void DestroyableComponent::Reinitialize(LOT templateID) { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); - int32_t buffComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_BUFF); - int32_t collectibleComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_COLLECTIBLE); - int32_t rebuildComponentID = compRegistryTable->GetByIDAndType(templateID, COMPONENT_TYPE_REBUILD); + int32_t buffComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::BUFF); + int32_t collectibleComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::COLLECTIBLE); + int32_t rebuildComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::QUICK_BUILD); int32_t componentID = 0; if (collectibleComponentID > 0) componentID = collectibleComponentID; if (rebuildComponentID > 0) componentID = rebuildComponentID; if (buffComponentID > 0) componentID = buffComponentID; - CDDestructibleComponentTable* destCompTable = CDClientManager::Instance()->GetTable("DestructibleComponent"); + CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable(); std::vector destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); }); if (componentID > 0) { @@ -104,7 +119,16 @@ void DestroyableComponent::Reinitialize(LOT templateID) { void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) { if (bIsInitialUpdate) { - outBitStream->Write0(); //Contains info about immunities this object has, but it's left out for now. + outBitStream->Write1(); // always write these on construction + outBitStream->Write(m_ImmuneToBasicAttackCount); + outBitStream->Write(m_ImmuneToDamageOverTimeCount); + outBitStream->Write(m_ImmuneToKnockbackCount); + outBitStream->Write(m_ImmuneToInterruptCount); + outBitStream->Write(m_ImmuneToSpeedCount); + outBitStream->Write(m_ImmuneToImaginationGainCount); + outBitStream->Write(m_ImmuneToImaginationLossCount); + outBitStream->Write(m_ImmuneToQuickbuildInterruptCount); + outBitStream->Write(m_ImmuneToPullToPointCount); } outBitStream->Write(m_DirtyHealth || bIsInitialUpdate); @@ -138,25 +162,17 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn if (m_IsSmashable) { outBitStream->Write(m_HasBricks); - - if (m_ExplodeFactor != 1.0f) { - outBitStream->Write1(); - outBitStream->Write(m_ExplodeFactor); - } else { - outBitStream->Write0(); - } + outBitStream->Write(m_ExplodeFactor != 1.0f); + if (m_ExplodeFactor != 1.0f) outBitStream->Write(m_ExplodeFactor); } } - m_DirtyHealth = false; } + outBitStream->Write(m_DirtyThreatList || bIsInitialUpdate); if (m_DirtyThreatList || bIsInitialUpdate) { - outBitStream->Write1(); outBitStream->Write(m_HasThreats); m_DirtyThreatList = false; - } else { - outBitStream->Write0(); } } @@ -342,7 +358,7 @@ void DestroyableComponent::SetDamageReduction(int32_t value) { void DestroyableComponent::SetIsImmune(bool value) { m_DirtyHealth = true; - m_ImmuneStacks = value ? 1 : 0; + m_ImmuneToBasicAttackCount = value ? 1 : 0; } void DestroyableComponent::SetIsGMImmune(bool value) { @@ -438,7 +454,6 @@ void DestroyableComponent::AddEnemyFaction(int32_t factionID) { void DestroyableComponent::SetIsSmashable(bool value) { m_DirtyHealth = true; m_IsSmashable = value; - //m_HasBricks = value; } void DestroyableComponent::SetAttacksToBlock(const uint32_t value) { @@ -446,7 +461,7 @@ void DestroyableComponent::SetAttacksToBlock(const uint32_t value) { } bool DestroyableComponent::IsImmune() const { - return m_ImmuneStacks > 0 || m_IsGMImmune; + return m_IsGMImmune || m_ImmuneToBasicAttackCount > 0; } bool DestroyableComponent::IsKnockbackImmune() const { @@ -455,9 +470,9 @@ bool DestroyableComponent::IsKnockbackImmune() const { if (characterComponent != nullptr && inventoryComponent != nullptr && characterComponent->GetCurrentActivity() == eGameActivities::ACTIVITY_QUICKBUILDING) { const auto hasPassive = inventoryComponent->HasAnyPassive({ - ItemSetPassiveAbilityID::EngineerRank2, ItemSetPassiveAbilityID::EngineerRank3, - ItemSetPassiveAbilityID::SummonerRank2, ItemSetPassiveAbilityID::SummonerRank3, - ItemSetPassiveAbilityID::InventorRank2, ItemSetPassiveAbilityID::InventorRank3, + eItemSetPassiveAbilityID::EngineerRank2, eItemSetPassiveAbilityID::EngineerRank3, + eItemSetPassiveAbilityID::SummonerRank2, eItemSetPassiveAbilityID::SummonerRank3, + eItemSetPassiveAbilityID::InventorRank2, eItemSetPassiveAbilityID::InventorRank3, }, 5); if (hasPassive) { @@ -639,6 +654,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 auto* attacker = EntityManager::Instance()->GetEntity(source); m_Parent->OnHit(attacker); m_Parent->OnHitOrHealResult(attacker, sourceDamage); + NotifySubscribers(attacker, sourceDamage); for (const auto& cb : m_OnHitCallbacks) { cb(attacker); @@ -653,9 +669,38 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 return; } + + //check if hardcore mode is enabled + if (EntityManager::Instance()->GetHardcoreMode()) { + DoHardcoreModeDrops(source); + } + Smash(source, eKillType::VIOLENT, u"", skillID); } +void DestroyableComponent::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd) { + m_SubscribedScripts.insert(std::make_pair(scriptObjId, scriptToAdd)); + Game::logger->LogDebug("DestroyableComponent", "Added script %llu to entity %llu", scriptObjId, m_Parent->GetObjectID()); + Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size()); +} + +void DestroyableComponent::Unsubscribe(LWOOBJID scriptObjId) { + auto foundScript = m_SubscribedScripts.find(scriptObjId); + if (foundScript != m_SubscribedScripts.end()) { + m_SubscribedScripts.erase(foundScript); + Game::logger->LogDebug("DestroyableComponent", "Removed script %llu from entity %llu", scriptObjId, m_Parent->GetObjectID()); + } else { + Game::logger->LogDebug("DestroyableComponent", "Tried to remove a script for Entity %llu but script %llu didnt exist", m_Parent->GetObjectID(), scriptObjId); + } + Game::logger->LogDebug("DestroyableComponent", "Number of subscribed scripts %i", m_SubscribedScripts.size()); +} + +void DestroyableComponent::NotifySubscribers(Entity* attacker, uint32_t damage) { + for (auto script : m_SubscribedScripts) { + script.second->NotifyHitOrHealResult(m_Parent, attacker, damage); + } +} + void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType, uint32_t skillID) { if (m_iHealth > 0) { SetArmor(0); @@ -678,13 +723,13 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType auto* inventoryComponent = owner->GetComponent(); if (inventoryComponent != nullptr && isEnemy) { - inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed); + inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed, m_Parent); } auto* missions = owner->GetComponent(); if (missions != nullptr) { - if (team != nullptr && isEnemy) { + if (team != nullptr) { for (const auto memberId : team->members) { auto* member = EntityManager::Instance()->GetEntity(memberId); @@ -694,12 +739,12 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType if (memberMissions == nullptr) continue; - memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT()); - memberMissions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, m_Parent->GetLOT(), skillID); + memberMissions->Progress(eMissionTaskType::SMASH, m_Parent->GetLOT()); + memberMissions->Progress(eMissionTaskType::USE_SKILL, m_Parent->GetLOT(), skillID); } } else { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, m_Parent->GetLOT()); - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, m_Parent->GetLOT(), skillID); + missions->Progress(eMissionTaskType::SMASH, m_Parent->GetLOT()); + missions->Progress(eMissionTaskType::USE_SKILL, m_Parent->GetLOT(), skillID); } } } @@ -747,22 +792,17 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType if (dZoneManager::Instance()->GetPlayerLoseCoinOnDeath()) { auto* character = m_Parent->GetCharacter(); uint64_t coinsTotal = character->GetCoins(); + const uint64_t minCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMin; + if (coinsTotal >= minCoinsToLose) { + const uint64_t maxCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMax; + const float coinPercentageToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathPercent; - if (coinsTotal > 0) { - uint64_t coinsToLoose = 1; + uint64_t coinsToLose = std::max(static_cast(coinsTotal * coinPercentageToLose), minCoinsToLose); + coinsToLose = std::min(maxCoinsToLose, coinsToLose); - if (coinsTotal >= 200) { - float hundreth = (coinsTotal / 100.0f); - coinsToLoose = static_cast(hundreth); - } + coinsTotal -= coinsToLose; - if (coinsToLoose > 10000) { - coinsToLoose = 10000; - } - - coinsTotal -= coinsToLoose; - - LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLoose, coinsToLoose); + LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLose, coinsToLose); character->SetCoins(coinsTotal, eLootSourceType::LOOT_SOURCE_PICKUP); } } @@ -772,7 +812,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType script->OnPlayerDied(zoneControl, m_Parent); } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { @@ -792,12 +832,53 @@ void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) { AddFaction(factionID, ignoreChecks); } -void DestroyableComponent::PushImmunity(int32_t stacks) { - m_ImmuneStacks += stacks; -} +void DestroyableComponent::SetStatusImmunity( + const eStateChangeType state, + const bool bImmuneToBasicAttack, + const bool bImmuneToDamageOverTime, + const bool bImmuneToKnockback, + const bool bImmuneToInterrupt, + const bool bImmuneToSpeed, + const bool bImmuneToImaginationGain, + const bool bImmuneToImaginationLoss, + const bool bImmuneToQuickbuildInterrupt, + const bool bImmuneToPullToPoint) { -void DestroyableComponent::PopImmunity(int32_t stacks) { - m_ImmuneStacks -= stacks; + if (state == eStateChangeType::POP) { + if (bImmuneToBasicAttack && m_ImmuneToBasicAttackCount > 0) m_ImmuneToBasicAttackCount -= 1; + if (bImmuneToDamageOverTime && m_ImmuneToDamageOverTimeCount > 0) m_ImmuneToDamageOverTimeCount -= 1; + if (bImmuneToKnockback && m_ImmuneToKnockbackCount > 0) m_ImmuneToKnockbackCount -= 1; + if (bImmuneToInterrupt && m_ImmuneToInterruptCount > 0) m_ImmuneToInterruptCount -= 1; + if (bImmuneToSpeed && m_ImmuneToSpeedCount > 0) m_ImmuneToSpeedCount -= 1; + if (bImmuneToImaginationGain && m_ImmuneToImaginationGainCount > 0) m_ImmuneToImaginationGainCount -= 1; + if (bImmuneToImaginationLoss && m_ImmuneToImaginationLossCount > 0) m_ImmuneToImaginationLossCount -= 1; + if (bImmuneToQuickbuildInterrupt && m_ImmuneToQuickbuildInterruptCount > 0) m_ImmuneToQuickbuildInterruptCount -= 1; + if (bImmuneToPullToPoint && m_ImmuneToPullToPointCount > 0) m_ImmuneToPullToPointCount -= 1; + + } else if (state == eStateChangeType::PUSH){ + if (bImmuneToBasicAttack) m_ImmuneToBasicAttackCount += 1; + if (bImmuneToDamageOverTime) m_ImmuneToDamageOverTimeCount += 1; + if (bImmuneToKnockback) m_ImmuneToKnockbackCount += 1; + if (bImmuneToInterrupt) m_ImmuneToInterruptCount += 1; + if (bImmuneToSpeed) m_ImmuneToSpeedCount += 1; + if (bImmuneToImaginationGain) m_ImmuneToImaginationGainCount += 1; + if (bImmuneToImaginationLoss) m_ImmuneToImaginationLossCount += 1; + if (bImmuneToQuickbuildInterrupt) m_ImmuneToQuickbuildInterruptCount += 1; + if (bImmuneToPullToPoint) m_ImmuneToPullToPointCount += 1; + } + + GameMessages::SendSetStatusImmunity( + m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(), + bImmuneToBasicAttack, + bImmuneToDamageOverTime, + bImmuneToKnockback, + bImmuneToInterrupt, + bImmuneToSpeed, + bImmuneToImaginationGain, + bImmuneToImaginationLoss, + bImmuneToQuickbuildInterrupt, + bImmuneToPullToPoint + ); } void DestroyableComponent::FixStats() { @@ -900,3 +981,75 @@ void DestroyableComponent::FixStats() { void DestroyableComponent::AddOnHitCallback(const std::function& callback) { m_OnHitCallbacks.push_back(callback); } + +void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){ + //check if this is a player: + if (m_Parent->IsPlayer()) { + //remove hardcore_lose_uscore_on_death_percent from the player's uscore: + auto* character = m_Parent->GetComponent(); + auto uscore = character->GetUScore(); + + auto uscoreToLose = uscore * (EntityManager::Instance()->GetHardcoreLoseUscoreOnDeathPercent() / 100); + character->SetUScore(uscore - uscoreToLose); + + GameMessages::SendModifyLEGOScore(m_Parent, m_Parent->GetSystemAddress(), -uscoreToLose, eLootSourceType::LOOT_SOURCE_MISSION); + + if (EntityManager::Instance()->GetHardcoreDropinventoryOnDeath()) { + //drop all items from inventory: + auto* inventory = m_Parent->GetComponent(); + if (inventory) { + //get the items inventory: + auto items = inventory->GetInventory(eInventoryType::ITEMS); + if (items){ + auto itemMap = items->GetItems(); + if (!itemMap.empty()){ + for (const auto& item : itemMap) { + //drop the item: + if (!item.second) continue; + // don't drop the thinkng cap + if (item.second->GetLot() == 6086) continue; + GameMessages::SendDropClientLoot(m_Parent, source, item.second->GetLot(), 0, m_Parent->GetPosition(), item.second->GetCount()); + item.second->SetCount(0, false, false); + } + EntityManager::Instance()->SerializeEntity(m_Parent); + } + } + } + } + + //get character: + auto* chars = m_Parent->GetCharacter(); + if (chars) { + auto coins = chars->GetCoins(); + + //lose all coins: + chars->SetCoins(0, eLootSourceType::LOOT_SOURCE_NONE); + + //drop all coins: + GameMessages::SendDropClientLoot(m_Parent, source, LOT_NULL, coins, m_Parent->GetPosition()); + } + + // Reload the player since we can't normally reduce uscore from the server and we want the UI to update + // do this last so we don't get killed.... again + EntityManager::Instance()->DestructEntity(m_Parent); + EntityManager::Instance()->ConstructEntity(m_Parent); + return; + } + + //award the player some u-score: + auto* player = EntityManager::Instance()->GetEntity(source); + if (player && player->IsPlayer()) { + auto* playerStats = player->GetComponent(); + if (playerStats) { + //get the maximum health from this enemy: + auto maxHealth = GetMaxHealth(); + + int uscore = maxHealth * EntityManager::Instance()->GetHardcoreUscoreEnemiesMultiplier(); + + playerStats->SetUScore(playerStats->GetUScore() + uscore); + GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::LOOT_SOURCE_MISSION); + + EntityManager::Instance()->SerializeEntity(m_Parent); + } + } +} diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index a403717b..47be96a0 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -6,6 +6,11 @@ #include "tinyxml2.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" + +namespace CppScripts { + class Script; +}; //! namespace CppScripts /** * Represents the stats of an entity, for example its health, imagination and armor. Also handles factions, which @@ -13,7 +18,7 @@ */ class DestroyableComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_DESTROYABLE; + static const eReplicaComponentType ComponentType = eReplicaComponentType::DESTROYABLE; DestroyableComponent(Entity* parentEntity); ~DestroyableComponent() override; @@ -239,7 +244,7 @@ public: * Sets the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed * @param value the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed */ - void SetExplodeFactor(float value); + void SetExplodeFactor(float value) { m_ExplodeFactor = value; }; /** * Returns the current multiplier for explosions @@ -392,16 +397,31 @@ public: void Smash(LWOOBJID source, eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"", uint32_t skillID = 0); /** - * Pushes a layer of immunity to this entity, making it immune for longer - * @param stacks the amount of immunity to add + * Push or Pop a layer of status immunity to this entity */ - void PushImmunity(int32_t stacks = 1); + void SetStatusImmunity( + const eStateChangeType state, + const bool bImmuneToBasicAttack = false, + const bool bImmuneToDamageOverTime = false, + const bool bImmuneToKnockback = false, + const bool bImmuneToInterrupt = false, + const bool bImmuneToSpeed = false, + const bool bImmuneToImaginationGain = false, + const bool bImmuneToImaginationLoss = false, + const bool bImmuneToQuickbuildInterrupt = false, + const bool bImmuneToPullToPoint = false + ); - /** - * Pops layers of immunity, making it immune for less longer - * @param stacks the number of layers of immunity to remove - */ - void PopImmunity(int32_t stacks = 1); + // Getters for status immunities + const bool GetImmuneToBasicAttack() {return m_ImmuneToBasicAttackCount > 0;}; + const bool GetImmuneToDamageOverTime() {return m_ImmuneToDamageOverTimeCount > 0;}; + const bool GetImmuneToKnockback() {return m_ImmuneToKnockbackCount > 0;}; + const bool GetImmuneToInterrupt() {return m_ImmuneToInterruptCount > 0;}; + const bool GetImmuneToSpeed() {return m_ImmuneToSpeedCount > 0;}; + const bool GetImmuneToImaginationGain() {return m_ImmuneToImaginationGainCount > 0;}; + const bool GetImmuneToImaginationLoss() {return m_ImmuneToImaginationLossCount > 0;}; + const bool GetImmuneToQuickbuildInterrupt() {return m_ImmuneToQuickbuildInterruptCount > 0;}; + const bool GetImmuneToPullToPoint() {return m_ImmuneToPullToPointCount > 0;}; /** * Utility to reset all stats to the default stats based on items and completed missions @@ -414,6 +434,28 @@ public: */ void AddOnHitCallback(const std::function& callback); + /** + * Pushes a faction back to the list of factions. + * @param value Faction to add to list. + * + * This method should only be used for testing. Use AddFaction(int32_t, bool) for adding a faction properly. + */ + void AddFactionNoLookup(int32_t faction) { m_FactionIDs.push_back(faction); }; + + /** + * Notify subscribed scripts of Damage actions. + * + * @param attacker The attacking Entity + * @param damage The amount of damage that was done + */ + void NotifySubscribers(Entity* attacker, uint32_t damage); + + void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd); + void Unsubscribe(LWOOBJID scriptObjId); + + // handle hardcode mode drops + void DoHardcoreModeDrops(const LWOOBJID source); + private: /** * Whether or not the health should be serialized @@ -470,11 +512,6 @@ private: */ uint32_t m_AttacksToBlock; - /** - * The layers of immunity this entity has left - */ - int32_t m_ImmuneStacks; - /** * The amount of damage that should be reduced from every attack */ @@ -549,6 +586,24 @@ private: * The list of callbacks that will be called when this entity gets hit */ std::vector> m_OnHitCallbacks; + + /** + * The list of scripts subscribed to this components actions + */ + std::map m_SubscribedScripts; + + /** + * status immunity counters + */ + uint32_t m_ImmuneToBasicAttackCount; + uint32_t m_ImmuneToDamageOverTimeCount; + uint32_t m_ImmuneToKnockbackCount; + uint32_t m_ImmuneToInterruptCount; + uint32_t m_ImmuneToSpeedCount; + uint32_t m_ImmuneToImaginationGainCount; + uint32_t m_ImmuneToImaginationLossCount; + uint32_t m_ImmuneToQuickbuildInterruptCount; + uint32_t m_ImmuneToPullToPointCount; }; #endif // DESTROYABLECOMPONENT_H diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 930ace8d..dc8fdbdc 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -27,8 +27,16 @@ #include "dConfig.h" #include "eItemType.h" #include "eUnequippableActiveType.h" +#include "CppScripts.h" +#include "eMissionTaskType.h" -InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) { +#include "CDComponentsRegistryTable.h" +#include "CDInventoryComponentTable.h" +#include "CDScriptComponentTable.h" +#include "CDObjectSkillsTable.h" +#include "CDSkillBehaviorTable.h" + +InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document): Component(parent) { this->m_Dirty = true; this->m_Equipped = {}; this->m_Pushed = {}; @@ -45,10 +53,10 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do return; } - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - const auto componentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_INVENTORY); + auto* compRegistryTable = CDClientManager::Instance().GetTable(); + const auto componentId = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::INVENTORY); - auto* inventoryComponentTable = CDClientManager::Instance()->GetTable("InventoryComponent"); + auto* inventoryComponentTable = CDClientManager::Instance().GetTable(); auto items = inventoryComponentTable->Query([=](const CDInventoryComponent entry) { return entry.id == componentId; }); auto slot = 0u; @@ -179,7 +187,7 @@ void InventoryComponent::AddItem( inventoryType = Inventory::FindInventoryTypeForLot(lot); } - auto* missions = static_cast(this->m_Parent->GetComponent(COMPONENT_TYPE_MISSION)); + auto* missions = static_cast(this->m_Parent->GetComponent(eReplicaComponentType::MISSION)); auto* inventory = GetInventory(inventoryType); @@ -195,7 +203,7 @@ void InventoryComponent::AddItem( auto* item = new Item(lot, inventory, slot, count, config, parent, showFlyingLoot, isModMoveAndEquip, subKey, bound, lootSourceType); if (missions != nullptr && !IsTransferInventory(inventoryType)) { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", count, IsTransferInventory(inventorySourceType)); + missions->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count, IsTransferInventory(inventorySourceType)); } return; @@ -209,9 +217,11 @@ void InventoryComponent::AddItem( auto stack = static_cast(info.stackSize); + bool isBrick = inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == 1); + // info.itemType of 1 is item type brick - if (inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == 1)) { - stack = 999; + if (isBrick) { + stack = UINT32_MAX; } else if (stack == 0) { stack = 1; } @@ -232,7 +242,8 @@ void InventoryComponent::AddItem( } } - while (left > 0) { + // If we have some leftover and we aren't bricks, make a new stack + while (left > 0 && (!isBrick || (isBrick && !existing))) { const auto size = std::min(left, stack); left -= size; @@ -280,7 +291,7 @@ void InventoryComponent::AddItem( } if (missions != nullptr && !IsTransferInventory(inventoryType)) { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", count - outOfSpace, IsTransferInventory(inventorySourceType)); + missions->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", count - outOfSpace, IsTransferInventory(inventorySourceType)); } } @@ -327,7 +338,9 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in const auto lot = item->GetLot(); - if (item->GetConfig().empty() && !item->GetBound() || (item->GetBound() && item->GetInfo().isBOP)) { + const auto subkey = item->GetSubKey(); + + if (subkey == LWOOBJID_EMPTY && item->GetConfig().empty() && (!item->GetBound() || (item->GetBound() && item->GetInfo().isBOP))) { auto left = std::min(count, origin->GetLotCount(lot)); while (left > 0) { @@ -358,7 +371,7 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in const auto delta = std::min(item->GetCount(), count); - AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, LWOOBJID_EMPTY, origin->GetType(), 0, item->GetBound(), preferredSlot); + AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, subkey, origin->GetType(), 0, item->GetBound(), preferredSlot); item->SetCount(item->GetCount() - delta, false, false); } @@ -367,7 +380,7 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in if (missionComponent != nullptr) { if (IsTransferInventory(inventory)) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, LWOOBJID_EMPTY, "", -static_cast(count)); + missionComponent->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", -static_cast(count)); } } } @@ -605,16 +618,17 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { return; } - std::vector inventories; + std::vector inventoriesToSave; + // Need to prevent some transfer inventories from being saved for (const auto& pair : this->m_Inventories) { auto* inventory = pair.second; - if (inventory->GetType() == VENDOR_BUYBACK) { + if (inventory->GetType() == VENDOR_BUYBACK || inventory->GetType() == eInventoryType::MODELS_IN_BBB) { continue; } - inventories.push_back(inventory); + inventoriesToSave.push_back(inventory); } inventoryElement->SetAttribute("csl", m_Consumable); @@ -629,7 +643,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { bags->DeleteChildren(); - for (const auto* inventory : inventories) { + for (const auto* inventory : inventoriesToSave) { auto* bag = document->NewElement("b"); bag->SetAttribute("t", inventory->GetType()); @@ -648,7 +662,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { items->DeleteChildren(); - for (auto* inventory : inventories) { + for (auto* inventory : inventoriesToSave) { if (inventory->GetSize() == 0) { continue; } @@ -810,7 +824,7 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { if (character != nullptr && !skipChecks) { // Hacky proximity rocket if (item->GetLot() == 6416) { - const auto rocketLauchPads = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_ROCKET_LAUNCH); + const auto rocketLauchPads = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::ROCKET_LAUNCH); const auto position = m_Parent->GetPosition(); @@ -834,9 +848,9 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { const auto type = static_cast(item->GetInfo().itemType); - if (!building && (item->GetLot() == 6086 || type == eItemType::ITEM_TYPE_LOOT_MODEL || type == eItemType::ITEM_TYPE_VEHICLE)) return; + if (!building && (item->GetLot() == 6086 || type == eItemType::LOOT_MODEL || type == eItemType::VEHICLE)) return; - if (type != eItemType::ITEM_TYPE_LOOT_MODEL && type != eItemType::ITEM_TYPE_MODEL) { + if (type != eItemType::LOOT_MODEL && type != eItemType::MODEL) { if (!item->GetBound() && !item->GetPreconditionExpression()->Check(m_Parent)) { return; } @@ -861,6 +875,8 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { AddItemSkills(item->GetLot()); + EquipScripts(item); + EntityManager::Instance()->SerializeEntity(m_Parent); } @@ -889,6 +905,8 @@ void InventoryComponent::UnEquipItem(Item* item) { PurgeProxies(item); + UnequipScripts(item); + EntityManager::Instance()->SerializeEntity(m_Parent); // Trigger property event @@ -898,6 +916,37 @@ void InventoryComponent::UnEquipItem(Item* item) { } } + +void InventoryComponent::EquipScripts(Item* equippedItem) { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + if (!compRegistryTable) return; + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1); + if (scriptComponentID > -1) { + CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable(); + CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); + auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name); + if (!itemScript) { + Game::logger->Log("InventoryComponent", "null script?"); + } + itemScript->OnFactionTriggerItemEquipped(m_Parent, equippedItem->GetId()); + } +} + +void InventoryComponent::UnequipScripts(Item* unequippedItem) { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + if (!compRegistryTable) return; + int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1); + if (scriptComponentID > -1) { + CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable(); + CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID); + auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name); + if (!itemScript) { + Game::logger->Log("InventoryComponent", "null script?"); + } + itemScript->OnFactionTriggerItemUnequipped(m_Parent, unequippedItem->GetId()); + } +} + void InventoryComponent::HandlePossession(Item* item) { auto* characterComponent = m_Parent->GetComponent(); if (!characterComponent) return; @@ -917,7 +966,7 @@ void InventoryComponent::HandlePossession(Item* item) { return; } - GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); // Set the mount Item ID so that we know what were handling possessorComponent->SetMountItemID(item->GetId()); @@ -985,6 +1034,7 @@ void InventoryComponent::ApplyBuff(Item* item) const { } } +// TODO Something needs to send the remove buff GameMessage as well when it is unequipping items that would remove buffs. void InventoryComponent::RemoveBuff(Item* item) const { const auto buffs = FindBuffs(item, false); @@ -1153,20 +1203,20 @@ void InventoryComponent::RemoveItemSkills(const LOT lot) { } } -void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger) { +void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) { for (auto* set : m_Itemsets) { - set->TriggerPassiveAbility(trigger); + set->TriggerPassiveAbility(trigger, target); } } -bool InventoryComponent::HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const { +bool InventoryComponent::HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const { for (auto* set : m_Itemsets) { if (set->GetEquippedCount() < equipmentRequirement) { continue; } // Check if the set has any of the passive abilities - if (std::find(passiveIDs.begin(), passiveIDs.end(), static_cast(set->GetID())) != passiveIDs.end()) { + if (std::find(passiveIDs.begin(), passiveIDs.end(), static_cast(set->GetID())) != passiveIDs.end()) { return true; } } @@ -1242,15 +1292,15 @@ void InventoryComponent::RemoveDatabasePet(LWOOBJID id) { BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type) { switch (type) { - case eItemType::ITEM_TYPE_HAT: + case eItemType::HAT: return BehaviorSlot::Head; - case eItemType::ITEM_TYPE_NECK: + case eItemType::NECK: return BehaviorSlot::Neck; - case eItemType::ITEM_TYPE_LEFT_HAND: + case eItemType::LEFT_HAND: return BehaviorSlot::Offhand; - case eItemType::ITEM_TYPE_RIGHT_HAND: + case eItemType::RIGHT_HAND: return BehaviorSlot::Primary; - case eItemType::ITEM_TYPE_CONSUMABLE: + case eItemType::CONSUMABLE: return BehaviorSlot::Consumable; default: return BehaviorSlot::Invalid; @@ -1258,11 +1308,11 @@ BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type) { } bool InventoryComponent::IsTransferInventory(eInventoryType type) { - return type == VENDOR_BUYBACK || type == VAULT_ITEMS || type == VAULT_MODELS || type == TEMP_ITEMS || type == TEMP_MODELS; + return type == VENDOR_BUYBACK || type == VAULT_ITEMS || type == VAULT_MODELS || type == TEMP_ITEMS || type == TEMP_MODELS || type == MODELS_IN_BBB; } uint32_t InventoryComponent::FindSkill(const LOT lot) { - auto* table = CDClientManager::Instance()->GetTable("ObjectSkills"); + auto* table = CDClientManager::Instance().GetTable(); const auto results = table->Query([=](const CDObjectSkills& entry) { return entry.objectTemplate == static_cast(lot); @@ -1280,14 +1330,14 @@ uint32_t InventoryComponent::FindSkill(const LOT lot) { std::vector InventoryComponent::FindBuffs(Item* item, bool castOnEquip) const { std::vector buffs; if (item == nullptr) return buffs; - auto* table = CDClientManager::Instance()->GetTable("ObjectSkills"); - auto* behaviors = CDClientManager::Instance()->GetTable("SkillBehavior"); + auto* table = CDClientManager::Instance().GetTable(); + auto* behaviors = CDClientManager::Instance().GetTable(); const auto results = table->Query([=](const CDObjectSkills& entry) { return entry.objectTemplate == static_cast(item->GetLot()); }); - auto* missions = static_cast(m_Parent->GetComponent(COMPONENT_TYPE_MISSION)); + auto* missions = static_cast(m_Parent->GetComponent(eReplicaComponentType::MISSION)); for (const auto& result : results) { if (result.castOnType == 1) { @@ -1300,7 +1350,7 @@ std::vector InventoryComponent::FindBuffs(Item* item, bool castOnEquip } if (missions != nullptr && castOnEquip) { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, result.skillID); + missions->Progress(eMissionTaskType::USE_SKILL, result.skillID); } // If item is not a proxy, add its buff to the added buffs. diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 394cb801..d695737c 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -17,8 +17,10 @@ #include "DatabasePet.h" #include "Component.h" #include "ItemSetPassiveAbility.h" -#include "ItemSetPassiveAbilityID.h" +#include "eItemSetPassiveAbilityID.h" #include "PossessorComponent.h" +#include "eInventoryType.h" +#include "eReplicaComponentType.h" class Entity; class ItemSet; @@ -35,7 +37,7 @@ enum class eItemType : int32_t; class InventoryComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_INVENTORY; + static const eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY; explicit InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document = nullptr); void Update(float deltaTime) override; @@ -282,7 +284,7 @@ public: * Triggers one of the passive abilities from the equipped item set * @param trigger the trigger to fire */ - void TriggerPassiveAbility(PassiveAbilityTrigger trigger); + void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr); /** * Returns if the entity has any of the passed passive abilities equipped @@ -290,7 +292,7 @@ public: * @param equipmentRequirement the number of equipment required to be allowed to have the ability * @return if the entity has any of the passed passive abilities equipped */ - bool HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const; + bool HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const; /** * Despawns the currently active pet, if any @@ -351,6 +353,20 @@ public: */ static uint32_t FindSkill(LOT lot); + /** + * Call this when you equip an item. This calls OnFactionTriggerItemEquipped for any scripts found on the items. + * + * @param equippedItem The item script to lookup and call equip on + */ + void EquipScripts(Item* equippedItem); + + /** + * Call this when you unequip an item. This calls OnFactionTriggerItemUnequipped for any scripts found on the items. + * + * @param unequippedItem The item script to lookup and call unequip on + */ + void UnequipScripts(Item* unequippedItem); + ~InventoryComponent() override; private: diff --git a/dGame/dComponents/LUPExhibitComponent.h b/dGame/dComponents/LUPExhibitComponent.h index 2d128f6c..587d1b2f 100644 --- a/dGame/dComponents/LUPExhibitComponent.h +++ b/dGame/dComponents/LUPExhibitComponent.h @@ -2,6 +2,7 @@ #include "Component.h" #include "Entity.h" +#include "eReplicaComponentType.h" /** * Component that handles the LOT that is shown in the LUP exhibit in the LUP world. Works by setting a timer and @@ -10,7 +11,7 @@ class LUPExhibitComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_EXHIBIT; + static const eReplicaComponentType ComponentType = eReplicaComponentType::EXHIBIT; LUPExhibitComponent(Entity* parent); ~LUPExhibitComponent(); diff --git a/dGame/dComponents/LevelProgressionComponent.cpp b/dGame/dComponents/LevelProgressionComponent.cpp index ee3cfc6b..814a7a86 100644 --- a/dGame/dComponents/LevelProgressionComponent.cpp +++ b/dGame/dComponents/LevelProgressionComponent.cpp @@ -4,9 +4,13 @@ #include "CharacterComponent.h" #include "tinyxml2.h" +#include "CDRewardsTable.h" + LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component(parent) { m_Parent = parent; m_Level = 1; + m_SpeedBase = 500.0f; + m_CharacterVersion = eCharacterVersion::LIVE; } void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { @@ -16,7 +20,8 @@ void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { return; } level->SetAttribute("l", m_Level); - + level->SetAttribute("sb", m_SpeedBase); + level->SetAttribute("cv", static_cast(m_CharacterVersion)); } void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { @@ -26,7 +31,10 @@ void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { return; } level->QueryAttribute("l", &m_Level); - + level->QueryAttribute("sb", &m_SpeedBase); + uint32_t characterVersion; + level->QueryAttribute("cv", &characterVersion); + m_CharacterVersion = static_cast(characterVersion); } void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { @@ -36,7 +44,7 @@ void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool } void LevelProgressionComponent::HandleLevelUp() { - auto* rewardsTable = CDClientManager::Instance()->GetTable("Rewards"); + auto* rewardsTable = CDClientManager::Instance().GetTable(); const auto& rewards = rewardsTable->GetByLevelID(m_Level); bool rewardingItem = rewards.size() > 0; @@ -60,7 +68,8 @@ void LevelProgressionComponent::HandleLevelUp() { } break; case 9: - controllablePhysicsComponent->SetSpeedMultiplier(static_cast(reward->value) / 500.0f); + SetSpeedBase(static_cast(reward->value) ); + controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f); break; case 11: case 12: @@ -72,3 +81,9 @@ void LevelProgressionComponent::HandleLevelUp() { // Tell the client we have finished sending level rewards. if (rewardingItem) GameMessages::NotifyLevelRewards(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), m_Level, !rewardingItem); } + +void LevelProgressionComponent::SetRetroactiveBaseSpeed(){ + if (m_Level >= 20) m_SpeedBase = 525.0f; + auto* controllablePhysicsComponent = m_Parent->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetSpeedMultiplier(m_SpeedBase / 500.0f); +} diff --git a/dGame/dComponents/LevelProgressionComponent.h b/dGame/dComponents/LevelProgressionComponent.h index 53f6693e..06908a81 100644 --- a/dGame/dComponents/LevelProgressionComponent.h +++ b/dGame/dComponents/LevelProgressionComponent.h @@ -3,14 +3,17 @@ #include "Entity.h" #include "GameMessages.h" #include "Component.h" +#include "eCharacterVersion.h" +#include "eReplicaComponentType.h" /** * Component that handles level progression and serilization. * */ + class LevelProgressionComponent : public Component { public: - static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_LEVEL_PROGRESSION; + static const eReplicaComponentType ComponentType = eReplicaComponentType::LEVEL_PROGRESSION; /** * Constructor for this component @@ -44,11 +47,40 @@ public: */ void SetLevel(uint32_t level) { m_Level = level; m_DirtyLevelInfo = true; } + /** + * Gets the current Speed Base of the entity + * @return the current Speed Base of the entity + */ + const uint32_t GetSpeedBase() const { return m_SpeedBase; } + + /** + * Sets the Speed Base of the entity + * @param SpeedBase the Speed Base to set + */ + void SetSpeedBase(uint32_t SpeedBase) { m_SpeedBase = SpeedBase; } + /** * Gives the player rewards for the last level that they leveled up from */ void HandleLevelUp(); + /** + * Gets the current Character Version of the entity + * @return the current Character Version of the entity + */ + const eCharacterVersion GetCharacterVersion() const { return m_CharacterVersion; } + + /** + * Sets the Character Version of the entity + * @param CharacterVersion the Character Version to set + */ + void SetCharacterVersion(eCharacterVersion CharacterVersion) { m_CharacterVersion = CharacterVersion; } + + /** + * Set the Base Speed retroactively of the entity + */ + void SetRetroactiveBaseSpeed(); + private: /** * whether the level is dirty @@ -59,4 +91,15 @@ private: * Level of the entity */ uint32_t m_Level; + + /** + * The base speed of the entity + */ + float m_SpeedBase; + + /** + * The Character format version + */ + eCharacterVersion m_CharacterVersion; + }; diff --git a/dGame/dComponents/MissionComponent.cpp b/dGame/dComponents/MissionComponent.cpp index 96f213e5..0ae0f07e 100644 --- a/dGame/dComponents/MissionComponent.cpp +++ b/dGame/dComponents/MissionComponent.cpp @@ -17,10 +17,12 @@ #include "dZoneManager.h" #include "Mail.h" #include "MissionPrerequisites.h" +#include "AchievementCacheKey.h" +#include "eMissionState.h" // MARK: Mission Component -std::unordered_map> MissionComponent::m_AchievementCache = {}; +std::unordered_map> MissionComponent::m_AchievementCache = {}; //! Initializer MissionComponent::MissionComponent(Entity* parent) : Component(parent) { @@ -52,11 +54,11 @@ Mission* MissionComponent::GetMission(const uint32_t missionId) const { } -MissionState MissionComponent::GetMissionState(const uint32_t missionId) const { +eMissionState MissionComponent::GetMissionState(const uint32_t missionId) const { auto* mission = GetMission(missionId); if (mission == nullptr) { - return CanAccept(missionId) ? MissionState::MISSION_STATE_AVAILABLE : MissionState::MISSION_STATE_UNKNOWN; + return CanAccept(missionId) ? eMissionState::AVAILABLE : eMissionState::UNKNOWN; } return mission->GetMissionState(); @@ -142,7 +144,7 @@ void MissionComponent::RemoveMission(uint32_t missionId) { m_Missions.erase(missionId); } -void MissionComponent::Progress(MissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count, bool ignoreAchievements) { +void MissionComponent::Progress(eMissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count, bool ignoreAchievements) { for (const auto& pair : m_Missions) { auto* mission = pair.second; @@ -214,7 +216,7 @@ void MissionComponent::ForceProgressTaskType(const uint32_t missionId, const uin } for (auto* element : mission->GetTasks()) { - if (element->GetType() != static_cast(taskType)) continue; + if (element->GetType() != static_cast(taskType)) continue; element->AddProgress(value); } @@ -252,7 +254,7 @@ void MissionComponent::ForceProgressValue(uint32_t missionId, uint32_t taskType, } for (auto* element : mission->GetTasks()) { - if (element->GetType() != static_cast(taskType) || !element->InAllTargets(value)) continue; + if (element->GetType() != static_cast(taskType) || !element->InAllTargets(value)) continue; element->AddProgress(1); } @@ -263,7 +265,7 @@ void MissionComponent::ForceProgressValue(uint32_t missionId, uint32_t taskType, } bool MissionComponent::GetMissionInfo(uint32_t missionId, CDMissions& result) { - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + auto* missionsTable = CDClientManager::Instance().GetTable(); const auto missions = missionsTable->Query([=](const CDMissions& entry) { return entry.id == static_cast(missionId); @@ -280,7 +282,7 @@ bool MissionComponent::GetMissionInfo(uint32_t missionId, CDMissions& result) { #define MISSION_NEW_METHOD -bool MissionComponent::LookForAchievements(MissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) { +bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) { #ifdef MISSION_NEW_METHOD // Query for achievments, using the cache const auto& result = QueryAchievements(type, value, targets); @@ -317,8 +319,8 @@ bool MissionComponent::LookForAchievements(MissionTaskType type, int32_t value, return any; #else - auto* missionTasksTable = CDClientManager::Instance()->GetTable("MissionTasks"); - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + auto* missionTasksTable = CDClientManager::Instance().GetTable(); + auto* missionsTable = CDClientManager::Instance().GetTable(); auto tasks = missionTasksTable->Query([=](const CDMissionTasks& entry) { return entry.taskType == static_cast(type); @@ -389,14 +391,14 @@ bool MissionComponent::LookForAchievements(MissionTaskType type, int32_t value, #endif } -const std::vector& MissionComponent::QueryAchievements(MissionTaskType type, int32_t value, const std::string targets) { +const std::vector& MissionComponent::QueryAchievements(eMissionTaskType type, int32_t value, const std::string targets) { // Create a hash which represent this query for achievements - size_t hash = 0; - GeneralUtils::hash_combine(hash, type); - GeneralUtils::hash_combine(hash, value); - GeneralUtils::hash_combine(hash, targets); + AchievementCacheKey toFind; + toFind.SetType(type); + toFind.SetValue(value); + toFind.SetTargets(targets); - const std::unordered_map>::iterator& iter = m_AchievementCache.find(hash); + const auto& iter = m_AchievementCache.find(toFind); // Check if this query is cached if (iter != m_AchievementCache.end()) { @@ -404,8 +406,8 @@ const std::vector& MissionComponent::QueryAchievements(MissionTaskType } // Find relevent tables - auto* missionTasksTable = CDClientManager::Instance()->GetTable("MissionTasks"); - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + auto* missionTasksTable = CDClientManager::Instance().GetTable(); + auto* missionsTable = CDClientManager::Instance().GetTable(); std::vector result; @@ -447,11 +449,9 @@ const std::vector& MissionComponent::QueryAchievements(MissionTaskType } } } - // Insert into cache - m_AchievementCache.insert_or_assign(hash, result); - - return m_AchievementCache.find(hash)->second; + m_AchievementCache.insert_or_assign(toFind, result); + return m_AchievementCache.find(toFind)->second; } bool MissionComponent::RequiresItem(const LOT lot) { @@ -485,7 +485,7 @@ bool MissionComponent::RequiresItem(const LOT lot) { } for (auto* task : mission->GetTasks()) { - if (task->IsComplete() || task->GetType() != MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION) { + if (task->IsComplete() || task->GetType() != eMissionTaskType::GATHER) { continue; } @@ -497,7 +497,7 @@ bool MissionComponent::RequiresItem(const LOT lot) { } } - const auto required = LookForAchievements(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, lot, false); + const auto required = LookForAchievements(eMissionTaskType::GATHER, lot, false); return required; } diff --git a/dGame/dComponents/MissionComponent.h b/dGame/dComponents/MissionComponent.h index 58185a68..eeaaa726 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -16,15 +16,18 @@ #include "CDClientManager.h" #include "CDMissionsTable.h" #include "Component.h" +#include "eReplicaComponentType.h" + +class AchievementCacheKey; /** * The mission inventory of an entity. Tracks mission state for each mission that can be accepted and allows for - * progression of each of the mission task types (see MissionTaskType). + * progression of each of the mission task types (see eMissionTaskType). */ class MissionComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MISSION; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION; explicit MissionComponent(Entity* parent); ~MissionComponent() override; @@ -50,7 +53,7 @@ public: * @param missionId the ID of the mission to get the mission state for * @return the mission state of the mission specified by the ID */ - MissionState GetMissionState(uint32_t missionId) const; + eMissionState GetMissionState(uint32_t missionId) const; /** * Checks if the entity has all the requirements for accepting the mission specified by the ID. @@ -91,7 +94,7 @@ public: * @param count the number to progress by, for example the number of items * @param ignoreAchievements do not progress achievements */ - void Progress(MissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1, bool ignoreAchievements = false); + void Progress(eMissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1, bool ignoreAchievements = false); /** * Forces progression for a mission and task, ignoring checks @@ -138,7 +141,7 @@ public: * @param count the number of values to progress by (differs by task type) * @return true if a achievement was accepted, false otherwise */ - bool LookForAchievements(MissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1); + bool LookForAchievements(eMissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1); /** * Checks if there's a mission active that requires the collection of the specified LOT @@ -186,13 +189,13 @@ private: * @param targets optional targets to progress with * @return list of mission IDs (achievements) that can be progressed for the given parameters */ - static const std::vector& QueryAchievements(MissionTaskType type, int32_t value, const std::string targets); + static const std::vector& QueryAchievements(eMissionTaskType type, int32_t value, const std::string targets); /** * As achievements can be hard to query, we here store a list of all the mission IDs that can be unlocked for a * combination of tasks and values, so that they can be easily re-queried later */ - static std::unordered_map> m_AchievementCache; + static std::unordered_map> m_AchievementCache; /** * Order of missions in the UI. This value is incremented by 1 diff --git a/dGame/dComponents/MissionOfferComponent.cpp b/dGame/dComponents/MissionOfferComponent.cpp index 2f2ed0f0..e4c94ebd 100644 --- a/dGame/dComponents/MissionOfferComponent.cpp +++ b/dGame/dComponents/MissionOfferComponent.cpp @@ -14,6 +14,9 @@ #include "dLogger.h" #include "Game.h" #include "MissionPrerequisites.h" +#include "eMissionState.h" + +#include "CDComponentsRegistryTable.h" OfferedMission::OfferedMission(const uint32_t missionId, const bool offersMission, const bool acceptsMission) { this->missionId = missionId; @@ -37,15 +40,15 @@ bool OfferedMission::GetAcceptMission() const { //------------------------ MissionOfferComponent below ------------------------ MissionOfferComponent::MissionOfferComponent(Entity* parent, const LOT parentLot) : Component(parent) { - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + auto* compRegistryTable = CDClientManager::Instance().GetTable(); - auto value = compRegistryTable->GetByIDAndType(parentLot, COMPONENT_TYPE_MISSION_OFFER, -1); + auto value = compRegistryTable->GetByIDAndType(parentLot, eReplicaComponentType::MISSION_OFFER, -1); if (value != -1) { const uint32_t componentId = value; // Now lookup the missions in the MissionNPCComponent table - auto* missionNpcComponentTable = CDClientManager::Instance()->GetTable("MissionNPCComponent"); + auto* missionNpcComponentTable = CDClientManager::Instance().GetTable(); auto missions = missionNpcComponentTable->Query([=](const CDMissionNPCComponent& entry) { return entry.id == static_cast(componentId); @@ -76,7 +79,7 @@ void MissionOfferComponent::OnUse(Entity* originator) { void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifiedMissionId) { // First, get the entity's MissionComponent. If there is not one, then we cannot offer missions to this entity. - auto* missionComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto* missionComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (!missionComponent) { Game::logger->Log("MissionOfferComponent", "Unable to get mission component for Entity %llu", entity->GetObjectID()); @@ -170,10 +173,10 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi for (const auto sample : randomMissionPool) { const auto state = missionComponent->GetMissionState(sample); - if (state == MissionState::MISSION_STATE_ACTIVE || - state == MissionState::MISSION_STATE_COMPLETE_ACTIVE || - state == MissionState::MISSION_STATE_READY_TO_COMPLETE || - state == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE || + if (state == eMissionState::ACTIVE || + state == eMissionState::COMPLETE_ACTIVE || + state == eMissionState::READY_TO_COMPLETE || + state == eMissionState::COMPLETE_READY_TO_COMPLETE || sample == specifiedMissionId) { mission = missionComponent->GetMission(sample); diff --git a/dGame/dComponents/MissionOfferComponent.h b/dGame/dComponents/MissionOfferComponent.h index 42aad3c4..6e22ca05 100644 --- a/dGame/dComponents/MissionOfferComponent.h +++ b/dGame/dComponents/MissionOfferComponent.h @@ -10,6 +10,7 @@ #include "Component.h" #include #include +#include "eReplicaComponentType.h" class Entity; @@ -60,7 +61,7 @@ private: */ class MissionOfferComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MISSION_OFFER; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MISSION_OFFER; MissionOfferComponent(Entity* parent, LOT parentLot); ~MissionOfferComponent() override; diff --git a/dGame/dComponents/ModelComponent.cpp b/dGame/dComponents/ModelComponent.cpp index 8fa085f2..74f614d1 100644 --- a/dGame/dComponents/ModelComponent.cpp +++ b/dGame/dComponents/ModelComponent.cpp @@ -10,7 +10,7 @@ ModelComponent::ModelComponent(Entity* parent) : Component(parent) { void ModelComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { // ItemComponent Serialization. Pets do not get this serialization. - if (!m_Parent->HasComponent(COMPONENT_TYPE_PET)) { + if (!m_Parent->HasComponent(eReplicaComponentType::PET)) { outBitStream->Write1(); outBitStream->Write(m_userModelID != LWOOBJID_EMPTY ? m_userModelID : m_Parent->GetObjectID()); outBitStream->Write(0); diff --git a/dGame/dComponents/ModelComponent.h b/dGame/dComponents/ModelComponent.h index 81342059..b5224869 100644 --- a/dGame/dComponents/ModelComponent.h +++ b/dGame/dComponents/ModelComponent.h @@ -4,6 +4,7 @@ #include "NiPoint3.h" #include "NiQuaternion.h" #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -12,7 +13,7 @@ class Entity; */ class ModelComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MODEL; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MODEL; ModelComponent(Entity* parent); diff --git a/dGame/dComponents/ModuleAssemblyComponent.h b/dGame/dComponents/ModuleAssemblyComponent.h index 24e1c1ee..c6e217ed 100644 --- a/dGame/dComponents/ModuleAssemblyComponent.h +++ b/dGame/dComponents/ModuleAssemblyComponent.h @@ -3,6 +3,7 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component that belongs to an object that may be modularly built, like cars and rockets. Note that this is not the @@ -11,7 +12,7 @@ */ class ModuleAssemblyComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MODULE_ASSEMBLY; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MODULE_ASSEMBLY; ModuleAssemblyComponent(Entity* MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION); ~ModuleAssemblyComponent() override; diff --git a/dGame/dComponents/MovementAIComponent.cpp b/dGame/dComponents/MovementAIComponent.cpp index 18dac63a..2a0155a6 100644 --- a/dGame/dComponents/MovementAIComponent.cpp +++ b/dGame/dComponents/MovementAIComponent.cpp @@ -10,6 +10,10 @@ #include "EntityManager.h" #include "SimplePhysicsComponent.h" #include "dZoneManager.h" +#include "CDClientManager.h" + +#include "CDComponentsRegistryTable.h" +#include "CDPhysicsComponentTable.h" std::map MovementAIComponent::m_PhysicsSpeedCache = {}; @@ -19,7 +23,7 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) : m_BaseCombatAI = nullptr; - m_BaseCombatAI = reinterpret_cast(m_Parent->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); + m_BaseCombatAI = reinterpret_cast(m_Parent->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); //Try and fix the insane values: if (m_Info.wanderRadius > 5.0f) m_Info.wanderRadius = m_Info.wanderRadius * 0.5f; @@ -132,7 +136,6 @@ void MovementAIComponent::Update(const float deltaTime) { } else if (m_CurrentPath->pathWaypoints.size() > m_WaypointPathIndex) ArrivedAtPathWaypoint(); } } - } // if (m_HaltDistance > 0) { @@ -421,13 +424,13 @@ float MovementAIComponent::GetBaseSpeed(LOT lot) { return it->second; } - CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance()->GetTable("PhysicsComponent"); + CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance().GetTable(); + CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance().GetTable(); int32_t componentID; CDPhysicsComponent* physicsComponent = nullptr; - componentID = componentRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_CONTROLLABLE_PHYSICS, -1); + componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::CONTROLLABLE_PHYSICS, -1); if (componentID != -1) { physicsComponent = physicsComponentTable->GetByID(componentID); @@ -435,7 +438,7 @@ float MovementAIComponent::GetBaseSpeed(LOT lot) { goto foundComponent; } - componentID = componentRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_SIMPLE_PHYSICS, -1); + componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::SIMPLE_PHYSICS, -1); if (componentID != -1) { physicsComponent = physicsComponentTable->GetByID(componentID); diff --git a/dGame/dComponents/MovementAIComponent.h b/dGame/dComponents/MovementAIComponent.h index 3c2e7110..67d75800 100644 --- a/dGame/dComponents/MovementAIComponent.h +++ b/dGame/dComponents/MovementAIComponent.h @@ -13,6 +13,7 @@ #include "Game.h" #include "dLogger.h" #include "Component.h" +#include "eReplicaComponentType.h" #include class ControllablePhysicsComponent; @@ -56,7 +57,7 @@ struct MovementAIInfo { */ class MovementAIComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MOVEMENT_AI; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVEMENT_AI; MovementAIComponent(Entity* parentEntity, MovementAIInfo info); ~MovementAIComponent() override; diff --git a/dGame/dComponents/MovingPlatformComponent.cpp b/dGame/dComponents/MovingPlatformComponent.cpp index 42699672..2666c60c 100644 --- a/dGame/dComponents/MovingPlatformComponent.cpp +++ b/dGame/dComponents/MovingPlatformComponent.cpp @@ -12,11 +12,12 @@ #include "GameMessages.h" #include "CppScripts.h" #include "SimplePhysicsComponent.h" +#include "Zone.h" MoverSubComponent::MoverSubComponent(const NiPoint3& startPos) { mPosition = {}; - mState = MovementPlatformState::Stopped; + mState = eMovementPlatformState::Stopped; mDesiredWaypointIndex = 0; // -1; mInReverse = false; mShouldStopAtDesiredWaypoint = false; @@ -127,7 +128,7 @@ void MovingPlatformComponent::OnCompleteRebuild() { StartPathing(); } -void MovingPlatformComponent::SetMovementState(MovementPlatformState value) { +void MovingPlatformComponent::SetMovementState(eMovementPlatformState value) { auto* subComponent = static_cast(m_MoverSubComponent); subComponent->mState = value; @@ -152,7 +153,7 @@ void MovingPlatformComponent::StartPathing() { auto* subComponent = static_cast(m_MoverSubComponent); subComponent->mShouldStopAtDesiredWaypoint = true; - subComponent->mState = MovementPlatformState::Stationary; + subComponent->mState = eMovementPlatformState::Stationary; NiPoint3 targetPosition; @@ -174,7 +175,7 @@ void MovingPlatformComponent::StartPathing() { } m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] { - SetMovementState(MovementPlatformState::Moving); + SetMovementState(eMovementPlatformState::Moving); }); const auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5f; @@ -199,7 +200,7 @@ void MovingPlatformComponent::StartPathing() { void MovingPlatformComponent::ContinuePathing() { auto* subComponent = static_cast(m_MoverSubComponent); - subComponent->mState = MovementPlatformState::Stationary; + subComponent->mState = eMovementPlatformState::Stationary; subComponent->mCurrentWaypointIndex = subComponent->mNextWaypointIndex; @@ -282,7 +283,7 @@ void MovingPlatformComponent::ContinuePathing() { m_Parent->CancelCallbackTimers(); m_Parent->AddCallbackTimer(subComponent->mWaitTime, [this] { - SetMovementState(MovementPlatformState::Moving); + SetMovementState(eMovementPlatformState::Moving); }); auto travelTime = Vector3::Distance(targetPosition, subComponent->mPosition) / subComponent->mSpeed + 1.5; @@ -313,7 +314,7 @@ void MovingPlatformComponent::StopPathing() { m_PathingStopped = true; - subComponent->mState = MovementPlatformState::Stopped; + subComponent->mState = eMovementPlatformState::Stopped; subComponent->mDesiredWaypointIndex = -1; subComponent->mShouldStopAtDesiredWaypoint = false; diff --git a/dGame/dComponents/MovingPlatformComponent.h b/dGame/dComponents/MovingPlatformComponent.h index efa3a4cf..9e4c1ecf 100644 --- a/dGame/dComponents/MovingPlatformComponent.h +++ b/dGame/dComponents/MovingPlatformComponent.h @@ -13,6 +13,10 @@ #include "dCommonVars.h" #include "EntityManager.h" #include "Component.h" +#include "eMovementPlatformState.h" +#include "eReplicaComponentType.h" + +class Path; /** * Different types of available platforms @@ -26,16 +30,6 @@ enum class eMoverSubComponentType : uint32_t { simpleMover = 5, }; -/** - * The different types of platform movement state, supposedly a bitmap - */ -enum class MovementPlatformState : uint32_t -{ - Moving = 0b00010, - Stationary = 0b11001, - Stopped = 0b01100 -}; - /** * Sub component for moving platforms that determine the actual current movement state */ @@ -49,7 +43,7 @@ public: /** * The state the platform is currently in */ - MovementPlatformState mState = MovementPlatformState::Stationary; + eMovementPlatformState mState = eMovementPlatformState::Stationary; /** * The waypoint this platform currently wants to traverse to @@ -112,7 +106,7 @@ public: */ class MovingPlatformComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_MOVING_PLATFORM; + static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVING_PLATFORM; MovingPlatformComponent(Entity* parent, const std::string& pathName); ~MovingPlatformComponent() override; @@ -133,7 +127,7 @@ public: * Updates the movement state for the moving platform * @param value the movement state to set */ - void SetMovementState(MovementPlatformState value); + void SetMovementState(eMovementPlatformState value); /** * Instructs the moving platform to go to some waypoint diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 0b136a5c..090e5791 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -20,6 +20,9 @@ #include "dConfig.h" #include "dChatFilter.h" #include "Database.h" +#include "EntityInfo.h" +#include "eMissionTaskType.h" +#include "eGameMasterLevel.h" std::unordered_map PetComponent::buildCache{}; std::unordered_map PetComponent::currentActivities{}; @@ -59,7 +62,7 @@ std::map PetComponent::petFlags = { { 13067, 838 }, // Skeleton dragon }; -PetComponent::PetComponent(Entity* parent, uint32_t componentId) : Component(parent) { +PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(parent) { m_ComponentId = componentId; m_Interaction = LWOOBJID_EMPTY; @@ -118,21 +121,23 @@ void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpd outBitStream->Write(m_Owner); } - outBitStream->Write(tamed); - if (tamed) { - outBitStream->Write(m_ModerationStatus); + if (bIsInitialUpdate) { + outBitStream->Write(tamed); + if (tamed) { + outBitStream->Write(m_ModerationStatus); - const auto nameData = GeneralUtils::UTF8ToUTF16(m_Name); - const auto ownerNameData = GeneralUtils::UTF8ToUTF16(m_OwnerName); + const auto nameData = GeneralUtils::UTF8ToUTF16(m_Name); + const auto ownerNameData = GeneralUtils::UTF8ToUTF16(m_OwnerName); - outBitStream->Write(static_cast(nameData.size())); - for (const auto c : nameData) { - outBitStream->Write(c); - } + outBitStream->Write(static_cast(nameData.size())); + for (const auto c : nameData) { + outBitStream->Write(c); + } - outBitStream->Write(static_cast(ownerNameData.size())); - for (const auto c : ownerNameData) { - outBitStream->Write(c); + outBitStream->Write(static_cast(ownerNameData.size())); + for (const auto c : ownerNameData) { + outBitStream->Write(c); + } } } } @@ -599,7 +604,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { auto* missionComponent = tamer->GetComponent(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PET_TAMING, m_Parent->GetLOT()); + missionComponent->Progress(eMissionTaskType::PET_TAMING, m_Parent->GetLOT()); } SetStatus(1); @@ -916,16 +921,16 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { return; } - // If we are out of imagination despawn the pet. - if (playerDestroyableComponent->GetImagination() == 0) { - this->Deactivate(); - auto playerEntity = playerDestroyableComponent->GetParent(); - if (!playerEntity) return; + // If we are out of imagination despawn the pet. + if (playerDestroyableComponent->GetImagination() == 0) { + this->Deactivate(); + auto playerEntity = playerDestroyableComponent->GetParent(); + if (!playerEntity) return; - GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet); - } + GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet); + } - this->AddDrainImaginationTimer(item); + this->AddDrainImaginationTimer(item); }); } @@ -983,7 +988,7 @@ void PetComponent::Command(NiPoint3 position, LWOOBJID source, int32_t commandTy // TODO: Go to player } - if (owner->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (owner->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { ChatPackets::SendSystemMessage(owner->GetSystemAddress(), u"Commmand Type: " + (GeneralUtils::to_u16string(commandType)) + u" - Type Id: " + (GeneralUtils::to_u16string(typeId))); } } @@ -1075,7 +1080,7 @@ void PetComponent::SetPetNameForModeration(const std::string& petName) { int approved = 1; //default, in mod //Make sure that the name isn't already auto-approved: - if (Game::chatFilter->IsSentenceOkay(petName, 0).empty()) { + if (Game::chatFilter->IsSentenceOkay(petName, eGameMasterLevel::CIVILIAN).empty()) { approved = 2; //approved } diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index efde0e8a..e3c1556b 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -4,6 +4,7 @@ #include "MovementAIComponent.h" #include "Component.h" #include "Preconditions.h" +#include "eReplicaComponentType.h" enum class PetAbilityType { @@ -20,7 +21,7 @@ enum class PetAbilityType class PetComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PET; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PET; explicit PetComponent(Entity* parentEntity, uint32_t componentId); ~PetComponent() override; diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index cef9cc36..ce205826 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -14,11 +14,13 @@ #include "EntityManager.h" #include "ControllablePhysicsComponent.h" #include "GameMessages.h" +#include "ePhysicsEffectType.h" #include "CDClientManager.h" #include "CDComponentsRegistryTable.h" #include "CDPhysicsComponentTable.h" #include "dServer.h" +#include "EntityInfo.h" #include "dpWorld.h" #include "dpEntity.h" @@ -35,7 +37,7 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par m_PositionInfoDirty = false; m_IsPhysicsEffectActive = false; - m_EffectType = 0; + m_EffectType = ePhysicsEffectType::PUSH; m_DirectionalMultiplier = 0.0f; m_MinMax = false; @@ -142,10 +144,10 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par */ if (!m_HasCreatedPhysics) { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_PHANTOM_PHYSICS); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS); - CDPhysicsComponentTable* physComp = CDClientManager::Instance()->GetTable("PhysicsComponent"); + CDPhysicsComponentTable* physComp = CDClientManager::Instance().GetTable(); if (physComp == nullptr) return; @@ -252,10 +254,10 @@ void PhantomPhysicsComponent::CreatePhysics() { y = m_Parent->GetVar(u"primitiveModelValueY"); z = m_Parent->GetVar(u"primitiveModelValueZ"); } else { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_PHANTOM_PHYSICS); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS); - CDPhysicsComponentTable* physComp = CDClientManager::Instance()->GetTable("PhysicsComponent"); + CDPhysicsComponentTable* physComp = CDClientManager::Instance().GetTable(); if (physComp == nullptr) return; @@ -404,7 +406,7 @@ void PhantomPhysicsComponent::SetDirectionalMultiplier(float mul) { m_EffectInfoDirty = true; } -void PhantomPhysicsComponent::SetEffectType(uint32_t type) { +void PhantomPhysicsComponent::SetEffectType(ePhysicsEffectType type) { m_EffectType = type; m_EffectInfoDirty = true; } diff --git a/dGame/dComponents/PhantomPhysicsComponent.h b/dGame/dComponents/PhantomPhysicsComponent.h index 1e9a7b60..cc0d1844 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.h +++ b/dGame/dComponents/PhantomPhysicsComponent.h @@ -12,10 +12,12 @@ #include "CppScripts.h" #include "InvalidScript.h" #include "Component.h" +#include "eReplicaComponentType.h" class LDFBaseData; class Entity; class dpEntity; +enum class ePhysicsEffectType : uint32_t ; /** * Allows the creation of phantom physics for an entity: a physics object that is generally invisible but can be @@ -25,7 +27,7 @@ class dpEntity; */ class PhantomPhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PHANTOM_PHYSICS; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS; PhantomPhysicsComponent(Entity* parent); ~PhantomPhysicsComponent() override; @@ -102,13 +104,13 @@ public: * Returns the effect that's currently active, defaults to 0 * @return the effect that's currently active */ - uint32_t GetEffectType() const { return m_EffectType; } + ePhysicsEffectType GetEffectType() const { return m_EffectType; } /** * Sets the effect that's currently active * @param type the effect to set */ - void SetEffectType(uint32_t type); + void SetEffectType(ePhysicsEffectType type); /** * Returns the Physics entity for the component @@ -167,7 +169,7 @@ private: /** * The physics effect that's currently active, defaults to 0 */ - uint32_t m_EffectType; + ePhysicsEffectType m_EffectType; /** * A scaling multiplier to add to the directional vector diff --git a/dGame/dComponents/PlayerForcedMovementComponent.cpp b/dGame/dComponents/PlayerForcedMovementComponent.cpp index 3bcad677..76993507 100644 --- a/dGame/dComponents/PlayerForcedMovementComponent.cpp +++ b/dGame/dComponents/PlayerForcedMovementComponent.cpp @@ -7,8 +7,8 @@ PlayerForcedMovementComponent::PlayerForcedMovementComponent(Entity* parent) : C PlayerForcedMovementComponent::~PlayerForcedMovementComponent() {} void PlayerForcedMovementComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write(m_DirtyInfo); - if (m_DirtyInfo) { + outBitStream->Write(m_DirtyInfo || bIsInitialUpdate); + if (m_DirtyInfo || bIsInitialUpdate) { outBitStream->Write(m_PlayerOnRail); outBitStream->Write(m_ShowBillboard); } diff --git a/dGame/dComponents/PlayerForcedMovementComponent.h b/dGame/dComponents/PlayerForcedMovementComponent.h index 43b99997..90708c9a 100644 --- a/dGame/dComponents/PlayerForcedMovementComponent.h +++ b/dGame/dComponents/PlayerForcedMovementComponent.h @@ -2,6 +2,7 @@ #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component that handles player forced movement @@ -9,7 +10,7 @@ */ class PlayerForcedMovementComponent : public Component { public: - static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_PLAYER_FORCED_MOVEMENT; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PLAYER_FORCED_MOVEMENT; /** * Constructor for this component diff --git a/dGame/dComponents/PossessableComponent.cpp b/dGame/dComponents/PossessableComponent.cpp index 37591532..5c45a6c1 100644 --- a/dGame/dComponents/PossessableComponent.cpp +++ b/dGame/dComponents/PossessableComponent.cpp @@ -34,8 +34,8 @@ void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn outBitStream->Write(m_Possessor != LWOOBJID_EMPTY); if (m_Possessor != LWOOBJID_EMPTY) outBitStream->Write(m_Possessor); - outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_INVALID); - if (m_AnimationFlag != eAnimationFlags::IDLE_INVALID) outBitStream->Write(m_AnimationFlag); + outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_NONE); + if (m_AnimationFlag != eAnimationFlags::IDLE_NONE) outBitStream->Write(m_AnimationFlag); outBitStream->Write(m_ImmediatelyDepossess); m_ImmediatelyDepossess = false; // reset flag diff --git a/dGame/dComponents/PossessableComponent.h b/dGame/dComponents/PossessableComponent.h index 43ce8610..2026c11e 100644 --- a/dGame/dComponents/PossessableComponent.h +++ b/dGame/dComponents/PossessableComponent.h @@ -6,6 +6,7 @@ #include "Item.h" #include "PossessorComponent.h" #include "eAninmationFlags.h" +#include "eReplicaComponentType.h" /** * Represents an entity that can be controlled by some other entity, generally used by cars to indicate that some @@ -13,7 +14,7 @@ */ class PossessableComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSABLE; + static const eReplicaComponentType ComponentType = eReplicaComponentType::POSSESSABLE; PossessableComponent(Entity* parentEntity, uint32_t componentId); @@ -109,7 +110,7 @@ private: * @brief What animaiton flag to use * */ - eAnimationFlags m_AnimationFlag = eAnimationFlags::IDLE_INVALID; + eAnimationFlags m_AnimationFlag = eAnimationFlags::IDLE_NONE; /** * @brief Should this be immediately depossessed diff --git a/dGame/dComponents/PossessorComponent.cpp b/dGame/dComponents/PossessorComponent.cpp index f0cad5ca..69046c3b 100644 --- a/dGame/dComponents/PossessorComponent.cpp +++ b/dGame/dComponents/PossessorComponent.cpp @@ -54,7 +54,7 @@ void PossessorComponent::Mount(Entity* mount) { // GM's to send GameMessages::SendSetJetPackMode(m_Parent, false); GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress()); - GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); EntityManager::Instance()->SerializeEntity(m_Parent); EntityManager::Instance()->SerializeEntity(mount); diff --git a/dGame/dComponents/PossessorComponent.h b/dGame/dComponents/PossessorComponent.h index 00b24445..4456af27 100644 --- a/dGame/dComponents/PossessorComponent.h +++ b/dGame/dComponents/PossessorComponent.h @@ -3,6 +3,7 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" // possession types enum class ePossessionType : uint8_t { @@ -17,7 +18,7 @@ enum class ePossessionType : uint8_t { */ class PossessorComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSOR; + static const eReplicaComponentType ComponentType = eReplicaComponentType::POSSESSOR; PossessorComponent(Entity* parent); ~PossessorComponent() override; diff --git a/dGame/dComponents/PropertyComponent.h b/dGame/dComponents/PropertyComponent.h index 2096a475..41f93677 100644 --- a/dGame/dComponents/PropertyComponent.h +++ b/dGame/dComponents/PropertyComponent.h @@ -9,6 +9,7 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" struct PropertyState { LWOOBJID ownerID; @@ -21,7 +22,7 @@ struct PropertyState { */ class PropertyComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY; explicit PropertyComponent(Entity* parentEntity); ~PropertyComponent() override; [[nodiscard]] PropertyState* GetPropertyState() const { return m_PropertyState; }; diff --git a/dGame/dComponents/PropertyEntranceComponent.cpp b/dGame/dComponents/PropertyEntranceComponent.cpp index e6540417..c251dc96 100644 --- a/dGame/dComponents/PropertyEntranceComponent.cpp +++ b/dGame/dComponents/PropertyEntranceComponent.cpp @@ -11,11 +11,13 @@ #include "CharacterComponent.h" #include "UserManager.h" #include "dLogger.h" +#include "AMFFormat.h" +#include "eGameMasterLevel.h" PropertyEntranceComponent::PropertyEntranceComponent(uint32_t componentID, Entity* parent) : Component(parent) { this->propertyQueries = {}; - auto table = CDClientManager::Instance()->GetTable("PropertyEntranceComponent"); + auto table = CDClientManager::Instance().GetTable(); const auto& entry = table->GetByID(componentID); this->m_MapID = entry.mapID; @@ -270,7 +272,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl bool isModeratorApproved = propertyEntry->getBoolean(10); - if (!isModeratorApproved && entity->GetGMLevel() >= GAME_MASTER_LEVEL_LEAD_MODERATOR) { + if (!isModeratorApproved && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { propertyName = "[AWAITING APPROVAL]"; propertyDescription = "[AWAITING APPROVAL]"; isModeratorApproved = true; diff --git a/dGame/dComponents/PropertyEntranceComponent.h b/dGame/dComponents/PropertyEntranceComponent.h index 4110e7d9..e37d1daa 100644 --- a/dGame/dComponents/PropertyEntranceComponent.h +++ b/dGame/dComponents/PropertyEntranceComponent.h @@ -6,13 +6,14 @@ #include "Entity.h" #include "EntityManager.h" #include "GameMessages.h" +#include "eReplicaComponentType.h" /** * Represents the launch pad that's used to select and browse properties */ class PropertyEntranceComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_ENTRANCE; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_ENTRANCE; explicit PropertyEntranceComponent(uint32_t componentID, Entity* parent); /** diff --git a/dGame/dComponents/PropertyManagementComponent.cpp b/dGame/dComponents/PropertyManagementComponent.cpp index 1e90e8db..0b05b10e 100644 --- a/dGame/dComponents/PropertyManagementComponent.cpp +++ b/dGame/dComponents/PropertyManagementComponent.cpp @@ -17,6 +17,8 @@ #include "Player.h" #include "RocketLaunchpadControlComponent.h" #include "PropertyEntranceComponent.h" +#include "InventoryComponent.h" +#include "eMissionTaskType.h" #include #include "CppScripts.h" @@ -200,6 +202,16 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) { // If we are not on our clone do not allow us to claim the property if (propertyCloneId != playerCloneId) return false; + std::string name = zone->GetZoneName(); + std::string description = ""; + + auto prop_path = zone->GetPath(m_Parent->GetVarAsString(u"propertyName")); + + if (prop_path){ + if (!prop_path->property.displayName.empty()) name = prop_path->property.displayName; + description = prop_path->property.displayDesc; + } + SetOwnerId(playerId); propertyId = ObjectIDManager::GenerateRandomObjectID(); @@ -207,14 +219,15 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) { auto* insertion = Database::CreatePreppedStmt( "INSERT INTO properties" "(id, owner_id, template_id, clone_id, name, description, rent_amount, rent_due, privacy_option, last_updated, time_claimed, rejection_reason, reputation, zone_id, performance_cost)" - "VALUES (?, ?, ?, ?, ?, '', 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, ?, 0.0)" + "VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '', 0, ?, 0.0)" ); insertion->setUInt64(1, propertyId); insertion->setUInt64(2, (uint32_t)playerId); insertion->setUInt(3, templateId); insertion->setUInt64(4, playerCloneId); - insertion->setString(5, zone->GetZoneName().c_str()); - insertion->setInt(6, propertyZoneId); + insertion->setString(5, name.c_str()); + insertion->setString(6, description.c_str()); + insertion->setInt(7, propertyZoneId); // Try and execute the query, print an error if it fails. try { @@ -242,7 +255,7 @@ void PropertyManagementComponent::OnStartBuilding() { LWOMAPID zoneId = 1100; - const auto entrance = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROPERTY_ENTRANCE); + const auto entrance = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_ENTRANCE); originalPrivacyOption = privacyOption; @@ -392,7 +405,7 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N }); // Progress place model missions auto missionComponent = entity->GetComponent(); - if (missionComponent != nullptr) missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_PLACE_MODEL, 0); + if (missionComponent != nullptr) missionComponent->Progress(eMissionTaskType::PLACE_MODEL, 0); } void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int deleteReason) { @@ -463,7 +476,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet settings.push_back(propertyObjectID); settings.push_back(modelType); - inventoryComponent->AddItem(6662, 1, eLootSourceType::LOOT_SOURCE_DELETION, eInventoryType::HIDDEN, settings, LWOOBJID_EMPTY, false, false, spawnerId); + inventoryComponent->AddItem(6662, 1, eLootSourceType::LOOT_SOURCE_DELETION, eInventoryType::MODELS_IN_BBB, settings, LWOOBJID_EMPTY, false, false, spawnerId); auto* item = inventoryComponent->FindItemBySubKey(spawnerId); if (item == nullptr) { @@ -706,7 +719,7 @@ void PropertyManagementComponent::Save() { insertion->setDouble(9, rotation.y); insertion->setDouble(10, rotation.z); insertion->setDouble(11, rotation.w); - insertion->setString(12, "Objects_" + std::to_string(entity->GetLOT()) + "_name"); // Model name. TODO make this customizable + insertion->setString(12, ("Objects_" + std::to_string(entity->GetLOT()) + "_name").c_str()); // Model name. TODO make this customizable insertion->setString(13, ""); // Model description. TODO implement this. insertion->setDouble(14, 0); // behavior 1. TODO implement this. insertion->setDouble(15, 0); // behavior 2. TODO implement this. diff --git a/dGame/dComponents/PropertyManagementComponent.h b/dGame/dComponents/PropertyManagementComponent.h index d9526015..2ee010a8 100644 --- a/dGame/dComponents/PropertyManagementComponent.h +++ b/dGame/dComponents/PropertyManagementComponent.h @@ -3,6 +3,7 @@ #include #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Information regarding which players may visit this property @@ -31,7 +32,7 @@ enum class PropertyPrivacyOption class PropertyManagementComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_MANAGEMENT; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_MANAGEMENT; PropertyManagementComponent(Entity* parent); static PropertyManagementComponent* Instance(); diff --git a/dGame/dComponents/PropertyVendorComponent.h b/dGame/dComponents/PropertyVendorComponent.h index f947d745..5055b445 100644 --- a/dGame/dComponents/PropertyVendorComponent.h +++ b/dGame/dComponents/PropertyVendorComponent.h @@ -2,6 +2,7 @@ #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * The property guard that stands on a property before it's claimed, allows entities to attempt claiming this property. @@ -9,7 +10,7 @@ class PropertyVendorComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROPERTY_VENDOR; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_VENDOR; explicit PropertyVendorComponent(Entity* parent); /** diff --git a/dGame/dComponents/ProximityMonitorComponent.h b/dGame/dComponents/ProximityMonitorComponent.h index a98397a2..2f51917d 100644 --- a/dGame/dComponents/ProximityMonitorComponent.h +++ b/dGame/dComponents/ProximityMonitorComponent.h @@ -11,6 +11,7 @@ #include "dpWorld.h" #include "dpEntity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Utility component for detecting how close entities are to named proximities for this entity. Allows you to store @@ -18,7 +19,7 @@ */ class ProximityMonitorComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PROXIMITY_MONITOR; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PROXIMITY_MONITOR; ProximityMonitorComponent(Entity* parentEntity, int smallRadius = -1, int largeRadius = -1); ~ProximityMonitorComponent() override; diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index 75465669..fe4f1faf 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -15,12 +15,14 @@ #include "Player.h" #include "PossessableComponent.h" #include "PossessorComponent.h" -#include "RacingTaskParam.h" +#include "eRacingTaskParam.h" #include "Spawner.h" #include "VehiclePhysicsComponent.h" #include "dServer.h" #include "dZoneManager.h" #include "dConfig.h" +#include "Loot.h" +#include "eMissionTaskType.h" #ifndef M_PI #define M_PI 3.14159265358979323846264338327950288 @@ -98,7 +100,7 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) { } void RacingControlComponent::LoadPlayerVehicle(Entity* player, - bool initialLoad) { + uint32_t positionNumber, bool initialLoad) { // Load the player's vehicle. if (player == nullptr) { @@ -126,33 +128,18 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player, auto* path = dZoneManager::Instance()->GetZone()->GetPath( GeneralUtils::UTF16ToWTF8(m_PathName)); - auto startPosition = path->pathWaypoints[0].position + NiPoint3::UNIT_Y * 3; - - const auto spacing = 15; - - // This sometimes spawns the vehicle out of the map if there are lots of - // players loaded. - - const auto range = m_LoadedPlayers * spacing; - - startPosition = - startPosition + NiPoint3::UNIT_Z * ((m_LeadingPlayer / 2) + - m_RacingPlayers.size() * spacing); - - auto startRotation = - NiQuaternion::LookAt(startPosition, startPosition + NiPoint3::UNIT_X); - - auto angles = startRotation.GetEulerAngles(); - - angles.y -= M_PI; - - startRotation = NiQuaternion::FromEulerAngles(angles); - - Game::logger->Log("RacingControlComponent", - "Start position <%f, %f, %f>, <%f, %f, %f>", - startPosition.x, startPosition.y, startPosition.z, - angles.x * (180.0f / M_PI), angles.y * (180.0f / M_PI), - angles.z * (180.0f / M_PI)); + auto spawnPointEntities = EntityManager::Instance()->GetEntitiesByLOT(4843); + auto startPosition = NiPoint3::ZERO; + auto startRotation = NiQuaternion::IDENTITY; + const std::string placementAsString = std::to_string(positionNumber); + for (auto entity : spawnPointEntities) { + if (!entity) continue; + if (entity->GetVarAsString(u"placement") == placementAsString) { + startPosition = entity->GetPosition(); + startRotation = entity->GetRotation(); + break; + } + } // Make sure the player is at the correct position. @@ -319,30 +306,58 @@ void RacingControlComponent::OnRequestDie(Entity* player) { auto* vehicle = EntityManager::Instance()->GetEntity(racingPlayer.vehicleID); - if (vehicle == nullptr) { - return; - } + if (!vehicle) return; if (!racingPlayer.noSmashOnReload) { racingPlayer.smashedTimes++; + GameMessages::SendDie(vehicle, vehicle->GetObjectID(), LWOOBJID_EMPTY, true, + VIOLENT, u"", 0, 0, 90.0f, false, true, 0); + + auto* destroyableComponent = vehicle->GetComponent(); + uint32_t respawnImagination = 0; + // Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live. + // Do not actually change the value yet. Do that on respawn. + if (destroyableComponent) { + respawnImagination = static_cast(ceil(destroyableComponent->GetImagination() / 2.0f / 10.0f)) * 10.0f; + GameMessages::SendSetResurrectRestoreValues(vehicle, -1, -1, respawnImagination); + } + + // Respawn the player in 2 seconds, as was done in live. Not sure if this value is in a setting somewhere else... + vehicle->AddCallbackTimer(2.0f, [=]() { + if (!vehicle || !this->m_Parent) return; + GameMessages::SendRacingResetPlayerToLastReset( + m_Parent->GetObjectID(), racingPlayer.playerID, + UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendVehicleStopBoost(vehicle, player->GetSystemAddress(), true); + + GameMessages::SendRacingSetPlayerResetInfo( + m_Parent->GetObjectID(), racingPlayer.lap, + racingPlayer.respawnIndex, player->GetObjectID(), + racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, + UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendResurrect(vehicle); + auto* destroyableComponent = vehicle->GetComponent(); + // Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live. + if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination); + EntityManager::Instance()->SerializeEntity(vehicle); + }); + + auto* characterComponent = player->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(RacingTimesWrecked); + } + } else { + GameMessages::SendRacingSetPlayerResetInfo( + m_Parent->GetObjectID(), racingPlayer.lap, + racingPlayer.respawnIndex, player->GetObjectID(), + racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, + UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendRacingResetPlayerToLastReset( + m_Parent->GetObjectID(), racingPlayer.playerID, + UNASSIGNED_SYSTEM_ADDRESS); } - - // Reset player to last checkpoint - GameMessages::SendRacingSetPlayerResetInfo( - m_Parent->GetObjectID(), racingPlayer.lap, - racingPlayer.respawnIndex, player->GetObjectID(), - racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, - UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendRacingResetPlayerToLastReset( - m_Parent->GetObjectID(), racingPlayer.playerID, - UNASSIGNED_SYSTEM_ADDRESS); - - auto* characterComponent = player->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(RacingTimesWrecked); - } - - return; } } @@ -361,19 +376,6 @@ void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity* player) { return; } - if (!racingPlayer.noSmashOnReload) { - GameMessages::SendDie(vehicle, LWOOBJID_EMPTY, LWOOBJID_EMPTY, true, - VIOLENT, u"", 0, 0, 0, true, false, 0); - - GameMessages::SendVehicleUnlockInput(racingPlayer.vehicleID, false, - UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendVehicleSetWheelLockState( - racingPlayer.vehicleID, false, false, - UNASSIGNED_SYSTEM_ADDRESS); - - GameMessages::SendResurrect(vehicle); - } - racingPlayer.noSmashOnReload = false; return; @@ -409,18 +411,18 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COMPETED_IN_RACE); // Progress task for competing in a race - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, data->smashedTimes, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SAFE_DRIVER); // Finish a race without being smashed. + missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::COMPETED_IN_RACE); // Progress task for competing in a race + missionComponent->Progress(eMissionTaskType::RACING, data->smashedTimes, (LWOOBJID)eRacingTaskParam::SAFE_DRIVER); // Finish a race without being smashed. // If solo racing is enabled OR if there are 3 players in the race, progress placement tasks. if (m_SoloRacing || m_LoadedPlayers > 2) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, data->finished, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_FINISH_WITH_PLACEMENT); // Finish in 1st place on a race + missionComponent->Progress(eMissionTaskType::RACING, data->finished, (LWOOBJID)eRacingTaskParam::FINISH_WITH_PLACEMENT); // Finish in 1st place on a race if (data->finished == 1) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_FIRST_PLACE_MULTIPLE_TRACKS); // Finish in 1st place on multiple tracks. - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_WIN_RACE_IN_WORLD); // Finished first place in specific world. + missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::FIRST_PLACE_MULTIPLE_TRACKS); // Finish in 1st place on multiple tracks. + missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::WIN_RACE_IN_WORLD); // Finished first place in specific world. } if (data->finished == m_LoadedPlayers) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_LAST_PLACE_FINISH); // Finished first place in specific world. + missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::LAST_PLACE_FINISH); // Finished first place in specific world. } } } else if (id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") { @@ -567,12 +569,12 @@ void RacingControlComponent::Update(float deltaTime) { Game::logger->Log("RacingControlComponent", "Loading all players..."); - for (size_t i = 0; i < m_LobbyPlayers.size(); i++) { + for (size_t positionNumber = 0; positionNumber < m_LobbyPlayers.size(); positionNumber++) { Game::logger->Log("RacingControlComponent", "Loading player now!"); auto* player = - EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]); + EntityManager::Instance()->GetEntity(m_LobbyPlayers[positionNumber]); if (player == nullptr) { return; @@ -581,7 +583,7 @@ void RacingControlComponent::Update(float deltaTime) { Game::logger->Log("RacingControlComponent", "Loading player now NOW!"); - LoadPlayerVehicle(player, true); + LoadPlayerVehicle(player, positionNumber + 1, true); m_Loaded = true; } @@ -842,7 +844,7 @@ void RacingControlComponent::Update(float deltaTime) { if (missionComponent != nullptr) { // Progress lap time tasks - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, (lapTime) * 1000, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_LAP_TIME); + missionComponent->Progress(eMissionTaskType::RACING, (lapTime) * 1000, (LWOOBJID)eRacingTaskParam::LAP_TIME); if (player.lap == 3) { m_Finished++; @@ -858,7 +860,7 @@ void RacingControlComponent::Update(float deltaTime) { raceTime, raceTime * 1000); // Entire race time - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, (raceTime) * 1000, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_TOTAL_TRACK_TIME); + missionComponent->Progress(eMissionTaskType::RACING, (raceTime) * 1000, (LWOOBJID)eRacingTaskParam::TOTAL_TRACK_TIME); auto* characterComponent = playerEntity->GetComponent(); if (characterComponent != nullptr) { diff --git a/dGame/dComponents/RacingControlComponent.h b/dGame/dComponents/RacingControlComponent.h index dac60962..91ab2fd4 100644 --- a/dGame/dComponents/RacingControlComponent.h +++ b/dGame/dComponents/RacingControlComponent.h @@ -7,6 +7,7 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Information for each player in the race @@ -104,7 +105,7 @@ struct RacingPlayerInfo { */ class RacingControlComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_RACING_CONTROL; + static const eReplicaComponentType ComponentType = eReplicaComponentType::RACING_CONTROL; RacingControlComponent(Entity* parentEntity); ~RacingControlComponent(); @@ -123,7 +124,7 @@ public: * @param player The player who's vehicle to initialize. * @param initialLoad Is this the first time the player is loading in this race? */ - void LoadPlayerVehicle(Entity* player, bool initialLoad = false); + void LoadPlayerVehicle(Entity* player, uint32_t positionNumber, bool initialLoad = false); /** * Invoked when the client says it has loaded in. diff --git a/dGame/dComponents/RailActivatorComponent.cpp b/dGame/dComponents/RailActivatorComponent.cpp index 1b94fc4a..49fc105d 100644 --- a/dGame/dComponents/RailActivatorComponent.cpp +++ b/dGame/dComponents/RailActivatorComponent.cpp @@ -10,8 +10,7 @@ RailActivatorComponent::RailActivatorComponent(Entity* parent, int32_t componentID) : Component(parent) { m_ComponentID = componentID; - const auto tableData = CDClientManager::Instance() - ->GetTable("RailActivatorComponent")->GetEntryByID(componentID); + const auto tableData = CDClientManager::Instance().GetTable()->GetEntryByID(componentID);; m_Path = parent->GetVar(u"rail_path"); m_PathDirection = parent->GetVar(u"rail_path_direction"); @@ -95,7 +94,7 @@ void RailActivatorComponent::OnUse(Entity* originator) { void RailActivatorComponent::OnRailMovementReady(Entity* originator) const { // Stun the originator - GameMessages::SendSetStunned(originator->GetObjectID(), PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); @@ -123,7 +122,7 @@ void RailActivatorComponent::OnRailMovementReady(Entity* originator) const { void RailActivatorComponent::OnCancelRailMovement(Entity* originator) { // Remove the stun from the originator - GameMessages::SendSetStunned(originator->GetObjectID(), POP, originator->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::POP, originator->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); diff --git a/dGame/dComponents/RailActivatorComponent.h b/dGame/dComponents/RailActivatorComponent.h index 8f67e7e3..5d625d2a 100644 --- a/dGame/dComponents/RailActivatorComponent.h +++ b/dGame/dComponents/RailActivatorComponent.h @@ -4,6 +4,7 @@ #include #include "dCommonVars.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component that handles the traveling using rails, e.g. the ninjago posts that can be used to travel using Spinjitzu. @@ -14,7 +15,7 @@ public: explicit RailActivatorComponent(Entity* parent, int32_t componentID); ~RailActivatorComponent() override; - static const uint32_t ComponentType = COMPONENT_TYPE_RAIL_ACTIVATOR; + static const eReplicaComponentType ComponentType = eReplicaComponentType::RAIL_ACTIVATOR; /** * Handles the OnUse event from some entity, initiates the rail movement diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index 6ec9b964..2562b313 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -7,13 +7,16 @@ #include "dLogger.h" #include "CharacterComponent.h" #include "MissionComponent.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" +#include "eTriggerEventType.h" #include "dServer.h" #include "PacketUtils.h" #include "Spawner.h" #include "MovingPlatformComponent.h" #include "Preconditions.h" +#include "Loot.h" +#include "TeamManager.h" #include "CppScripts.h" @@ -51,7 +54,7 @@ RebuildComponent::~RebuildComponent() { } void RebuildComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - if (m_Parent->GetComponent(COMPONENT_TYPE_DESTROYABLE) == nullptr) { + if (m_Parent->GetComponent(eReplicaComponentType::DESTROYABLE) == nullptr) { if (bIsInitialUpdate) { outBitStream->Write(false); } @@ -464,12 +467,20 @@ void RebuildComponent::CompleteRebuild(Entity* user) { auto* builder = GetBuilder(); - if (builder != nullptr) { - auto* missionComponent = builder->GetComponent(); - if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityId); + if (builder) { + auto* team = TeamManager::Instance()->GetTeam(builder->GetObjectID()); + if (team) { + for (const auto memberId : team->members) { // progress missions for all team members + auto* member = EntityManager::Instance()->GetEntity(memberId); + if (member) { + auto* missionComponent = member->GetComponent(); + if (missionComponent) missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityId); + } + } + } else{ + auto* missionComponent = builder->GetComponent(); + if (missionComponent) missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityId); } - LootGenerator::Instance().DropActivityLoot(builder, m_Parent, m_ActivityId, 1); } @@ -485,6 +496,8 @@ void RebuildComponent::CompleteRebuild(Entity* user) { for (const auto& callback : m_RebuildCompleteCallbacks) callback(user); + m_Parent->TriggerEvent(eTriggerEventType::REBUILD_COMPLETE, user); + auto* movingPlatform = m_Parent->GetComponent(); if (movingPlatform != nullptr) { movingPlatform->OnCompleteRebuild(); diff --git a/dGame/dComponents/RebuildComponent.h b/dGame/dComponents/RebuildComponent.h index bd3edd7d..a8e11e4c 100644 --- a/dGame/dComponents/RebuildComponent.h +++ b/dGame/dComponents/RebuildComponent.h @@ -9,6 +9,7 @@ #include "ScriptedActivityComponent.h" #include "Preconditions.h" #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -19,7 +20,7 @@ class Entity; */ class RebuildComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_REBUILD; + static const eReplicaComponentType ComponentType = eReplicaComponentType::QUICK_BUILD; RebuildComponent(Entity* entity); ~RebuildComponent() override; diff --git a/dGame/dComponents/RenderComponent.cpp b/dGame/dComponents/RenderComponent.cpp index 3002ae33..ee42acba 100644 --- a/dGame/dComponents/RenderComponent.cpp +++ b/dGame/dComponents/RenderComponent.cpp @@ -20,9 +20,9 @@ RenderComponent::RenderComponent(Entity* parent) : Component(parent) { return; /* - auto* table = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + auto* table = CDClientManager::Instance().GetTable(); - const auto entry = table->GetByIDAndType(parent->GetLOT(), COMPONENT_TYPE_RENDER); + const auto entry = table->GetByIDAndType(parent->GetLOT(), eReplicaComponentType::RENDER); std::stringstream query; diff --git a/dGame/dComponents/RenderComponent.h b/dGame/dComponents/RenderComponent.h index e6184564..de8b2907 100644 --- a/dGame/dComponents/RenderComponent.h +++ b/dGame/dComponents/RenderComponent.h @@ -8,6 +8,7 @@ #include "AMFFormat.h" #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -55,7 +56,7 @@ struct Effect { */ class RenderComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_RENDER; + static const eReplicaComponentType ComponentType = eReplicaComponentType::RENDER; RenderComponent(Entity* entity); ~RenderComponent() override; diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h index c8faa930..480f9b81 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h @@ -11,6 +11,7 @@ #include "NiPoint3.h" #include "NiQuaternion.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the @@ -18,7 +19,7 @@ */ class RigidbodyPhantomPhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_PHANTOM_PHYSICS; + static const eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS; RigidbodyPhantomPhysicsComponent(Entity* parent); ~RigidbodyPhantomPhysicsComponent() override; diff --git a/dGame/dComponents/RocketLaunchLupComponent.h b/dGame/dComponents/RocketLaunchLupComponent.h index 3fc0b444..226fa1b2 100644 --- a/dGame/dComponents/RocketLaunchLupComponent.h +++ b/dGame/dComponents/RocketLaunchLupComponent.h @@ -3,6 +3,7 @@ #include "Entity.h" #include "GameMessages.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Component that handles the LUP/WBL rocket launchpad that can be interacted with to travel to WBL worlds. @@ -10,7 +11,7 @@ */ class RocketLaunchLupComponent : public Component { public: - static const uint32_t ComponentType = eReplicaComponentType::COMPONENT_TYPE_ROCKET_LAUNCH_LUP; + static const eReplicaComponentType ComponentType = eReplicaComponentType::ROCKET_LAUNCH_LUP; /** * Constructor for this component, builds the m_LUPWorlds vector diff --git a/dGame/dComponents/RocketLaunchpadControlComponent.h b/dGame/dComponents/RocketLaunchpadControlComponent.h index 8a10f0f7..84cff22d 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.h +++ b/dGame/dComponents/RocketLaunchpadControlComponent.h @@ -9,6 +9,7 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" class PreconditionExpression; @@ -17,7 +18,7 @@ class PreconditionExpression; */ class RocketLaunchpadControlComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_ROCKET_LAUNCH; + static const eReplicaComponentType ComponentType = eReplicaComponentType::ROCKET_LAUNCH; RocketLaunchpadControlComponent(Entity* parent, int rocketId); ~RocketLaunchpadControlComponent() override; diff --git a/dGame/dComponents/ScriptedActivityComponent.cpp b/dGame/dComponents/ScriptedActivityComponent.cpp index 4b5ec41d..1bc8c01f 100644 --- a/dGame/dComponents/ScriptedActivityComponent.cpp +++ b/dGame/dComponents/ScriptedActivityComponent.cpp @@ -16,11 +16,20 @@ #include "GeneralUtils.h" #include "dZoneManager.h" #include "dConfig.h" +#include "InventoryComponent.h" #include "DestroyableComponent.h" +#include "dMessageIdentifiers.h" +#include "Loot.h" +#include "eMissionTaskType.h" + +#include "CDCurrencyTableTable.h" +#include "CDActivityRewardsTable.h" +#include "CDActivitiesTable.h" ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activityID) : Component(parent) { - CDActivitiesTable* activitiesTable = CDClientManager::Instance()->GetTable("Activities"); - std::vector activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == activityID); }); + m_ActivityID = activityID; + CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable(); + std::vector activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); }); for (CDActivities activity : activities) { m_ActivityInfo = activity; @@ -48,7 +57,7 @@ ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activit if (destroyableComponent) { // check for LMIs and set the loot LMIs - CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable("ActivityRewards"); + CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable(); std::vector activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) {return (entry.LootMatrixIndex == destroyableComponent->GetLootMatrixID()); }); uint32_t startingLMI = 0; @@ -88,6 +97,21 @@ void ScriptedActivityComponent::Serialize(RakNet::BitStream* outBitStream, bool } } +void ScriptedActivityComponent::ReloadConfig() { + CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable(); + std::vector activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); }); + for (auto activity : activities) { + auto mapID = m_ActivityInfo.instanceMapID; + if ((mapID == 1203 || mapID == 1261 || mapID == 1303 || mapID == 1403) && Game::config->GetValue("solo_racing") == "1") { + m_ActivityInfo.minTeamSize = 1; + m_ActivityInfo.minTeams = 1; + } else { + m_ActivityInfo.minTeamSize = activity.minTeamSize; + m_ActivityInfo.minTeams = activity.minTeams; + } + } +} + void ScriptedActivityComponent::HandleMessageBoxResponse(Entity* player, const std::string& id) { if (m_ActivityInfo.ActivityID == 103) { return; @@ -117,7 +141,7 @@ void ScriptedActivityComponent::PlayerJoin(Entity* player) { } void ScriptedActivityComponent::PlayerJoinLobby(Entity* player) { - if (!m_Parent->HasComponent(COMPONENT_TYPE_REBUILD)) + if (!m_Parent->HasComponent(eReplicaComponentType::QUICK_BUILD)) GameMessages::SendMatchResponse(player, player->GetSystemAddress(), 0); // tell the client they joined a lobby LobbyPlayer* newLobbyPlayer = new LobbyPlayer(); newLobbyPlayer->entityID = player->GetObjectID(); @@ -191,7 +215,7 @@ void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) { } void ScriptedActivityComponent::Update(float deltaTime) { - + std::vector lobbiesToRemove{}; // Ticks all the lobbies, not applicable for non-instance activities for (Lobby* lobby : m_Queue) { for (LobbyPlayer* player : lobby->players) { @@ -202,6 +226,11 @@ void ScriptedActivityComponent::Update(float deltaTime) { } } + if (lobby->players.empty()) { + lobbiesToRemove.push_back(lobby); + continue; + } + // Update the match time for all players if (m_ActivityInfo.maxTeamSize != 1 && lobby->players.size() >= m_ActivityInfo.minTeamSize || m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() >= m_ActivityInfo.minTeams) { @@ -245,13 +274,17 @@ void ScriptedActivityComponent::Update(float deltaTime) { // The timer has elapsed, start the instance if (lobby->timer <= 0.0f) { Game::logger->Log("ScriptedActivityComponent", "Setting up instance."); - ActivityInstance* instance = NewInstance(); LoadPlayersIntoInstance(instance, lobby->players); - RemoveLobby(lobby); instance->StartZone(); + lobbiesToRemove.push_back(lobby); } } + + while (!lobbiesToRemove.empty()) { + RemoveLobby(lobbiesToRemove.front()); + lobbiesToRemove.erase(lobbiesToRemove.begin()); + } } void ScriptedActivityComponent::RemoveLobby(Lobby* lobby) { @@ -270,7 +303,7 @@ bool ScriptedActivityComponent::HasLobby() const { bool ScriptedActivityComponent::IsValidActivity(Entity* player) { // Makes it so that scripted activities with an unimplemented map cannot be joined - /*if (player->GetGMLevel() < GAME_MASTER_LEVEL_DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) { + /*if (player->GetGMLevel() < eGameMasterLevel::DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) { if (m_Parent->GetLOT() == 4860) { auto* missionComponent = player->GetComponent(); missionComponent->CompleteMission(229); @@ -524,18 +557,18 @@ void ActivityInstance::StartZone() { void ActivityInstance::RewardParticipant(Entity* participant) { auto* missionComponent = participant->GetComponent(); if (missionComponent) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_ActivityInfo.ActivityID); + missionComponent->Progress(eMissionTaskType::ACTIVITY, m_ActivityInfo.ActivityID); } // First, get the activity data - auto* activityRewardsTable = CDClientManager::Instance()->GetTable("ActivityRewards"); + auto* activityRewardsTable = CDClientManager::Instance().GetTable(); std::vector activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) { return (entry.objectTemplate == m_ActivityInfo.ActivityID); }); if (!activityRewards.empty()) { uint32_t minCoins = 0; uint32_t maxCoins = 0; - auto* currencyTableTable = CDClientManager::Instance()->GetTable("CurrencyTable"); + auto* currencyTableTable = CDClientManager::Instance().GetTable(); std::vector currencyTable = currencyTableTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == activityRewards[0].CurrencyIndex && entry.npcminlevel == 1); }); if (!currencyTable.empty()) { diff --git a/dGame/dComponents/ScriptedActivityComponent.h b/dGame/dComponents/ScriptedActivityComponent.h index 66ca799f..1d49a62d 100644 --- a/dGame/dComponents/ScriptedActivityComponent.h +++ b/dGame/dComponents/ScriptedActivityComponent.h @@ -11,6 +11,9 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" + +#include "CDActivitiesTable.h" /** * Represents an instance of an activity, having participants and score @@ -153,7 +156,7 @@ struct ActivityPlayer { */ class ScriptedActivityComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SCRIPTED_ACTIVITY; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SCRIPTED_ACTIVITY; ScriptedActivityComponent(Entity* parent, int activityID); ~ScriptedActivityComponent() override; @@ -276,6 +279,12 @@ public: */ ActivityInstance* GetInstance(const LWOOBJID playerID); + /** + * @brief Reloads the config settings for this component + * + */ + void ReloadConfig(); + /** * Removes all the instances */ @@ -361,6 +370,12 @@ private: * LMIs for team sizes */ std::unordered_map m_ActivityLootMatrices; + + /** + * The activity id + * + */ + int32_t m_ActivityID; }; #endif // SCRIPTEDACTIVITYCOMPONENT_H diff --git a/dGame/dComponents/ShootingGalleryComponent.h b/dGame/dComponents/ShootingGalleryComponent.h index c43f20c2..c31575f1 100644 --- a/dGame/dComponents/ShootingGalleryComponent.h +++ b/dGame/dComponents/ShootingGalleryComponent.h @@ -3,6 +3,7 @@ #include "NiPoint3.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Parameters for the shooting gallery that change during playtime @@ -72,7 +73,7 @@ struct StaticShootingGalleryParams { */ class ShootingGalleryComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SHOOTING_GALLERY; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SHOOTING_GALLERY; explicit ShootingGalleryComponent(Entity* parent); ~ShootingGalleryComponent(); diff --git a/dGame/dComponents/SimplePhysicsComponent.h b/dGame/dComponents/SimplePhysicsComponent.h index ebb8b124..51356710 100644 --- a/dGame/dComponents/SimplePhysicsComponent.h +++ b/dGame/dComponents/SimplePhysicsComponent.h @@ -11,6 +11,7 @@ #include "NiPoint3.h" #include "NiQuaternion.h" #include "Component.h" +#include "eReplicaComponentType.h" class Entity; @@ -27,7 +28,7 @@ enum class eClimbableType : int32_t { */ class SimplePhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SIMPLE_PHYSICS; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SIMPLE_PHYSICS; SimplePhysicsComponent(uint32_t componentID, Entity* parent); ~SimplePhysicsComponent() override; diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index f7e8e7d9..ae0e82f0 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -19,11 +19,18 @@ #include "BaseCombatAIComponent.h" #include "ScriptComponent.h" #include "BuffComponent.h" +#include "EchoStartSkill.h" +#include "dMessageIdentifiers.h" +#include "DoClientProjectileImpact.h" +#include "CDClientManager.h" +#include "CDSkillBehaviorTable.h" ProjectileSyncEntry::ProjectileSyncEntry() { } +std::unordered_map SkillComponent::m_skillBehaviorCache = {}; + bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t skillUid, RakNet::BitStream* bitStream, const LWOOBJID target, uint32_t skillID) { auto* context = new BehaviorContext(this->m_Parent->GetObjectID()); @@ -123,10 +130,14 @@ void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, Behav } void SkillComponent::Update(const float deltaTime) { - if (!m_Parent->HasComponent(COMPONENT_TYPE_BASE_COMBAT_AI) && m_Parent->GetLOT() != 1) { + if (!m_Parent->HasComponent(eReplicaComponentType::BASE_COMBAT_AI) && m_Parent->GetLOT() != 1) { CalculateUpdate(deltaTime); } + if (m_Parent->IsPlayer()) { + for (const auto& pair : this->m_managedBehaviors) pair.second->UpdatePlayerSyncs(deltaTime); + } + std::map keep{}; for (const auto& pair : this->m_managedBehaviors) { @@ -181,17 +192,19 @@ void SkillComponent::Reset() { } void SkillComponent::Interrupt() { - if (m_Parent->IsPlayer()) return; - + // TODO: need to check immunities on the destroyable component, but they aren't implemented auto* combat = m_Parent->GetComponent(); - - if (combat != nullptr && combat->GetStunImmune()) { - return; - } + if (combat != nullptr && combat->GetStunImmune()) return; for (const auto& behavior : this->m_managedBehaviors) { + for (const auto& behaviorEndEntry : behavior.second->endEntries) { + behaviorEndEntry.behavior->End(behavior.second, behaviorEndEntry.branchContext, behaviorEndEntry.second); + } + behavior.second->endEntries.clear(); + if (m_Parent->IsPlayer()) continue; behavior.second->Interrupt(); } + } void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot, const float maxTime, @@ -214,6 +227,29 @@ void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, B this->m_managedProjectiles.push_back(entry); } +bool SkillComponent::CastSkill(const uint32_t skillId, LWOOBJID target, const LWOOBJID optionalOriginatorID) { + uint32_t behaviorId = -1; + // try to find it via the cache + const auto& pair = m_skillBehaviorCache.find(skillId); + + // if it's not in the cache look it up and cache it + if (pair == m_skillBehaviorCache.end()) { + auto skillTable = CDClientManager::Instance().GetTable(); + behaviorId = skillTable->GetSkillByID(skillId).behaviorID; + m_skillBehaviorCache.insert_or_assign(skillId, behaviorId); + } else { + behaviorId = pair->second; + } + + // check to see if we got back a valid behavior + if (behaviorId == -1) { + Game::logger->LogDebug("SkillComponent", "Tried to cast skill %i but found no behavior", skillId); + return false; + } + + return CalculateBehavior(skillId, behaviorId, target, false, false, optionalOriginatorID).success; +} + SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, const uint32_t behaviorId, const LWOOBJID target, const bool ignoreTarget, const bool clientInitalized, const LWOOBJID originatorOverride) { auto* bitStream = new RakNet::BitStream(); @@ -246,12 +282,13 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c if (!clientInitalized) { // Echo start skill - GameMessages::EchoStartSkill start; + EchoStartSkill start; start.iCastType = 0; start.skillID = skillId; start.uiSkillHandle = context->skillUId; start.optionalOriginatorID = context->originator; + start.optionalTargetID = target; auto* originator = EntityManager::Instance()->GetEntity(context->originator); @@ -319,34 +356,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime) { const auto distance = Vector3::DistanceSquared(targetPosition, closestPoint); if (distance > 3 * 3) { - /* - if (entry.TrackTarget && distance <= entry.TrackRadius) - { - const auto rotation = NiQuaternion::LookAtUnlocked(position, targetPosition); - - const auto speed = entry.Velocity.Length(); - - const auto homingTarget = rotation.GetForwardVector() * speed; - - Vector3 homing; - - // Move towards - - const auto difference = homingTarget - entry.Velocity; - const auto mag = difference.Length(); - if (mag <= speed || mag == 0) - { - homing = homingTarget; - } - else - { - entry.Velocity + homingTarget / mag * speed; - } - - entry.Velocity = homing; - } - */ - + // TODO There is supposed to be an implementation for homing projectiles here continue; } @@ -416,7 +426,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) behavior->Calculate(entry.context, bitStream, entry.branchContext); - GameMessages::DoClientProjectileImpact projectileImpact; + DoClientProjectileImpact projectileImpact; projectileImpact.sBitStream.assign((char*)bitStream->GetData(), bitStream->GetNumberOfBytesUsed()); projectileImpact.i64OwnerID = this->m_Parent->GetObjectID(); @@ -465,7 +475,7 @@ void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID targ delete context; } -SkillComponent::SkillComponent(Entity* parent) : Component(parent) { +SkillComponent::SkillComponent(Entity* parent): Component(parent) { this->m_skillUid = 0; } diff --git a/dGame/dComponents/SkillComponent.h b/dGame/dComponents/SkillComponent.h index f43276f1..034e65ce 100644 --- a/dGame/dComponents/SkillComponent.h +++ b/dGame/dComponents/SkillComponent.h @@ -13,6 +13,7 @@ #include "Component.h" #include "Entity.h" #include "dLogger.h" +#include "eReplicaComponentType.h" struct ProjectileSyncEntry { LWOOBJID id = LWOOBJID_EMPTY; @@ -58,7 +59,7 @@ struct SkillExecutionResult { */ class SkillComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SKILL; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SKILL; explicit SkillComponent(Entity* parent); ~SkillComponent() override; @@ -119,6 +120,15 @@ public: */ void RegisterPlayerProjectile(LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, LOT lot); + /** + * Wrapper for CalculateBehavior that mimics the call structure in scripts and helps reduce magic numbers + * @param skillId the skill to cast + * @param target the target of the skill + * @param optionalOriginatorID change the originator of the skill + * @return if the case succeeded + */ + bool CastSkill(const uint32_t skillId, LWOOBJID target = LWOOBJID_EMPTY, const LWOOBJID optionalOriginatorID = LWOOBJID_EMPTY); + /** * Initializes a server-side skill calculation. * @param skillId the skill ID @@ -190,6 +200,11 @@ private: */ uint32_t m_skillUid; + /** + * Cache for looking up a behavior id via a skill ID + */ + static std::unordered_map m_skillBehaviorCache; + /** * Sync a server-side projectile calculation. * @param entry the projectile information diff --git a/dGame/dComponents/SoundTriggerComponent.h b/dGame/dComponents/SoundTriggerComponent.h index e1178150..954d8495 100644 --- a/dGame/dComponents/SoundTriggerComponent.h +++ b/dGame/dComponents/SoundTriggerComponent.h @@ -3,6 +3,7 @@ #include "Entity.h" #include "GUID.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Music that should be played by the client @@ -19,7 +20,7 @@ struct MusicCue { */ class SoundTriggerComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SOUND_TRIGGER; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SOUND_TRIGGER; explicit SoundTriggerComponent(Entity* parent); ~SoundTriggerComponent() override; diff --git a/dGame/dComponents/SwitchComponent.cpp b/dGame/dComponents/SwitchComponent.cpp index 2263a866..392d885a 100644 --- a/dGame/dComponents/SwitchComponent.cpp +++ b/dGame/dComponents/SwitchComponent.cpp @@ -1,5 +1,6 @@ #include "SwitchComponent.h" #include "EntityManager.h" +#include "eTriggerEventType.h" std::vector SwitchComponent::petSwitches; @@ -42,7 +43,7 @@ void SwitchComponent::EntityEnter(Entity* entity) { } m_Active = true; if (!m_Parent) return; - m_Parent->TriggerEvent("OnActivated"); + m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED, entity); const auto grpName = m_Parent->GetVarAsString(u"grp_name"); @@ -78,7 +79,7 @@ void SwitchComponent::Update(float deltaTime) { if (m_Timer <= 0.0f) { m_Active = false; if (!m_Parent) return; - m_Parent->TriggerEvent("OnDectivated"); + m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED, m_Parent); const auto grpName = m_Parent->GetVarAsString(u"grp_name"); diff --git a/dGame/dComponents/SwitchComponent.h b/dGame/dComponents/SwitchComponent.h index ea5955d8..fde3cfc0 100644 --- a/dGame/dComponents/SwitchComponent.h +++ b/dGame/dComponents/SwitchComponent.h @@ -9,13 +9,14 @@ #include "BouncerComponent.h" #include #include "Component.h" +#include "eReplicaComponentType.h" /** * A component for switches in game, including pet triggered switches. */ class SwitchComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SWITCH; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SWITCH; SwitchComponent(Entity* parent); ~SwitchComponent() override; diff --git a/dGame/dComponents/TriggerComponent.cpp b/dGame/dComponents/TriggerComponent.cpp new file mode 100644 index 00000000..0f241116 --- /dev/null +++ b/dGame/dComponents/TriggerComponent.cpp @@ -0,0 +1,423 @@ +#include "TriggerComponent.h" +#include "dZoneManager.h" +#include "TeamManager.h" +#include "eTriggerCommandType.h" +#include "eMissionTaskType.h" +#include "ePhysicsEffectType.h" + +#include "CharacterComponent.h" +#include "ControllablePhysicsComponent.h" +#include "MissionComponent.h" +#include "PhantomPhysicsComponent.h" +#include "Player.h" +#include "RebuildComponent.h" +#include "SkillComponent.h" +#include "eEndBehavior.h" + + +TriggerComponent::TriggerComponent(Entity* parent, const std::string triggerInfo): Component(parent) { + m_Parent = parent; + m_Trigger = nullptr; + + std::vector tokens = GeneralUtils::SplitString(triggerInfo, ':'); + + uint32_t sceneID; + GeneralUtils::TryParse(tokens.at(0), sceneID); + uint32_t triggerID; + GeneralUtils::TryParse(tokens.at(1), triggerID); + + m_Trigger = dZoneManager::Instance()->GetZone()->GetTrigger(sceneID, triggerID); + + if (!m_Trigger) m_Trigger = new LUTriggers::Trigger(); +} + +void TriggerComponent::TriggerEvent(eTriggerEventType event, Entity* optionalTarget) { + if (m_Trigger && m_Trigger->enabled) { + for (LUTriggers::Event* triggerEvent : m_Trigger->events) { + if (triggerEvent->id == event) { + for (LUTriggers::Command* command : triggerEvent->commands) { + HandleTriggerCommand(command, optionalTarget); + } + } + } + } +} + +void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget) { + auto argArray = GeneralUtils::SplitString(command->args, ','); + + // determine targets + std::vector targetEntities = GatherTargets(command, optionalTarget); + + // if we have no targets, then we are done + if (targetEntities.empty()) return; + + for (Entity* targetEntity : targetEntities) { + if (!targetEntity) continue; + + switch (command->id) { + case eTriggerCommandType::ZONE_PLAYER: break; + case eTriggerCommandType::FIRE_EVENT: + HandleFireEvent(targetEntity, command->args); + break; + case eTriggerCommandType::DESTROY_OBJ: + HandleDestroyObject(targetEntity, command->args); + break; + case eTriggerCommandType::TOGGLE_TRIGGER: + HandleToggleTrigger(targetEntity, command->args); + break; + case eTriggerCommandType::RESET_REBUILD: + HandleResetRebuild(targetEntity, command->args); + break; + case eTriggerCommandType::SET_PATH: break; + case eTriggerCommandType::SET_PICK_TYPE: break; + case eTriggerCommandType::MOVE_OBJECT: + HandleMoveObject(targetEntity, argArray); + break; + case eTriggerCommandType::ROTATE_OBJECT: + HandleRotateObject(targetEntity, argArray); + break; + case eTriggerCommandType::PUSH_OBJECT: + HandlePushObject(targetEntity, argArray); + break; + case eTriggerCommandType::REPEL_OBJECT: + HandleRepelObject(targetEntity, command->args); + break; + case eTriggerCommandType::SET_TIMER: break; + case eTriggerCommandType::CANCEL_TIMER: break; + case eTriggerCommandType::PLAY_CINEMATIC: + HandlePlayCinematic(targetEntity, argArray); + break; + case eTriggerCommandType::TOGGLE_BBB: + HandleToggleBBB(targetEntity, command->args); + break; + case eTriggerCommandType::UPDATE_MISSION: + HandleUpdateMission(targetEntity, argArray); + break; + case eTriggerCommandType::SET_BOUNCER_STATE: break; + case eTriggerCommandType::BOUNCE_ALL_ON_BOUNCER: break; + case eTriggerCommandType::TURN_AROUND_ON_PATH: break; + case eTriggerCommandType::GO_FORWARD_ON_PATH: break; + case eTriggerCommandType::GO_BACKWARD_ON_PATH: break; + case eTriggerCommandType::STOP_PATHING: break; + case eTriggerCommandType::START_PATHING: break; + case eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS: break; + case eTriggerCommandType::PLAY_EFFECT: + HandlePlayEffect(targetEntity, argArray); + break; + case eTriggerCommandType::STOP_EFFECT: + GameMessages::SendStopFXEffect(targetEntity, true, command->args); + break; + case eTriggerCommandType::CAST_SKILL: + HandleCastSkill(targetEntity, command->args); + break; + case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: + GameMessages::SendDisplayZoneSummary(targetEntity->GetObjectID(), targetEntity->GetSystemAddress(), false, command->args == "1", m_Parent->GetObjectID()); + break; + case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT: + HandleSetPhysicsVolumeEffect(targetEntity, argArray); + break; + case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS: + HandleSetPhysicsVolumeStatus(targetEntity, command->args); + break; + case eTriggerCommandType::SET_MODEL_TO_BUILD: break; + case eTriggerCommandType::SPAWN_MODEL_BRICKS: break; + case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK: + HandleActivateSpawnerNetwork(command->args); + break; + case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK: + HandleDeactivateSpawnerNetwork(command->args); + break; + case eTriggerCommandType::RESET_SPAWNER_NETWORK: + HandleResetSpawnerNetwork(command->args); + break; + case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS: + HandleDestroySpawnerNetworkObjects(command->args); + break; + case eTriggerCommandType::GO_TO_WAYPOINT: break; + case eTriggerCommandType::ACTIVATE_PHYSICS: + HandleActivatePhysics(targetEntity, command->args); + break; + // DEPRECATED BLOCK START + case eTriggerCommandType::ACTIVATE_MUSIC_CUE: break; + case eTriggerCommandType::DEACTIVATE_MUSIC_CUE: break; + case eTriggerCommandType::FLASH_MUSIC_CUE: break; + case eTriggerCommandType::SET_MUSIC_PARAMETER: break; + case eTriggerCommandType::PLAY_2D_AMBIENT_SOUND: break; + case eTriggerCommandType::STOP_2D_AMBIENT_SOUND: break; + case eTriggerCommandType::PLAY_3D_AMBIENT_SOUND: break; + case eTriggerCommandType::STOP_3D_AMBIENT_SOUND: break; + case eTriggerCommandType::ACTIVATE_MIXER_PROGRAM: break; + case eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM: break; + // DEPRECATED BLOCK END + default: + Game::logger->LogDebug("TriggerComponent", "Event %i was not handled!", command->id); + break; + } + } +} + +std::vector TriggerComponent::GatherTargets(LUTriggers::Command* command, Entity* optionalTarget) { + std::vector entities = {}; + + if (command->target == "self") entities.push_back(m_Parent); + else if (command->target == "zone") { /*TODO*/ } + else if (command->target == "target" && optionalTarget) entities.push_back(optionalTarget); + else if (command->target == "targetTeam" && optionalTarget) { + auto* team = TeamManager::Instance()->GetTeam(optionalTarget->GetObjectID()); + for (const auto memberId : team->members) { + auto* member = EntityManager::Instance()->GetEntity(memberId); + if (member) entities.push_back(member); + } + } else if (command->target == "objGroup") entities = EntityManager::Instance()->GetEntitiesInGroup(command->targetName); + else if (command->target == "allPlayers") { + for (auto* player : Player::GetAllPlayers()) { + entities.push_back(player); + } + } else if (command->target == "allNPCs") { /*UNUSED*/ } + + return entities; +} + +void TriggerComponent::HandleFireEvent(Entity* targetEntity, std::string args) { + for (CppScripts::Script* script : CppScripts::GetEntityScripts(targetEntity)) { + script->OnFireEventServerSide(targetEntity, m_Parent, args, 0, 0, 0); + } +} + +void TriggerComponent::HandleDestroyObject(Entity* targetEntity, std::string args){ + uint32_t killType; + GeneralUtils::TryParse(args, killType); + targetEntity->Smash(m_Parent->GetObjectID(), static_cast(killType)); +} + +void TriggerComponent::HandleToggleTrigger(Entity* targetEntity, std::string args){ + auto* triggerComponent = targetEntity->GetComponent(); + if (!triggerComponent) { + Game::logger->Log("TriggerComponent::HandleToggleTrigger", "Trigger component not found!"); + return; + } + triggerComponent->SetTriggerEnabled(args == "1"); +} + +void TriggerComponent::HandleResetRebuild(Entity* targetEntity, std::string args){ + auto* rebuildComponent = targetEntity->GetComponent(); + if (!rebuildComponent) { + Game::logger->Log("TriggerComponent::HandleResetRebuild", "Rebuild component not found!"); + return; + } + rebuildComponent->ResetRebuild(args == "1"); +} + +void TriggerComponent::HandleMoveObject(Entity* targetEntity, std::vector argArray){ + if (argArray.size() <= 2) return; + + auto position = targetEntity->GetPosition(); + NiPoint3 offset = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), offset); + + position += offset; + targetEntity->SetPosition(position); +} + +void TriggerComponent::HandleRotateObject(Entity* targetEntity, std::vector argArray){ + if (argArray.size() <= 2) return; + + NiPoint3 vector = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), vector); + + NiQuaternion rotation = NiQuaternion::FromEulerAngles(vector); + targetEntity->SetRotation(rotation); +} + +void TriggerComponent::HandlePushObject(Entity* targetEntity, std::vector argArray){ + auto* phantomPhysicsComponent = m_Parent->GetComponent(); + if (!phantomPhysicsComponent) { + Game::logger->Log("TriggerComponent::HandlePushObject", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(true); + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); + phantomPhysicsComponent->SetDirectionalMultiplier(1); + NiPoint3 direction = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), direction); + phantomPhysicsComponent->SetDirection(direction); + + EntityManager::Instance()->SerializeEntity(m_Parent); +} + + +void TriggerComponent::HandleRepelObject(Entity* targetEntity, std::string args){ + auto* phantomPhysicsComponent = m_Parent->GetComponent(); + if (!phantomPhysicsComponent) { + Game::logger->Log("TriggerComponent::HandleRepelObject", "Phantom Physics component not found!"); + return; + } + float forceMultiplier; + GeneralUtils::TryParse(args, forceMultiplier); + phantomPhysicsComponent->SetPhysicsEffectActive(true); + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::REPULSE); + phantomPhysicsComponent->SetDirectionalMultiplier(forceMultiplier); + + auto triggerPos = m_Parent->GetPosition(); + auto targetPos = targetEntity->GetPosition(); + + // normalize the vectors to get the direction + auto delta = targetPos - triggerPos; + auto length = delta.Length(); + NiPoint3 direction = delta / length; + phantomPhysicsComponent->SetDirection(direction); + + EntityManager::Instance()->SerializeEntity(m_Parent); +} + +void TriggerComponent::HandlePlayCinematic(Entity* targetEntity, std::vector argArray) { + float leadIn = -1.0; + auto wait = eEndBehavior::RETURN; + bool unlock = true; + bool leaveLocked = false; + bool hidePlayer = false; + + if (argArray.size() >= 2) { + GeneralUtils::TryParse(argArray.at(1), leadIn); + if (argArray.size() >= 3 && argArray.at(2) == "wait") { + wait = eEndBehavior::WAIT; + if (argArray.size() >= 4 && argArray.at(3) == "unlock") { + unlock = false; + if (argArray.size() >= 5 && argArray.at(4) == "leavelocked") { + leaveLocked = true; + if (argArray.size() >= 6 && argArray.at(5) == "hideplayer") { + hidePlayer = true; + } + } + } + } + } + + GameMessages::SendPlayCinematic(targetEntity->GetObjectID(), GeneralUtils::UTF8ToUTF16(argArray.at(0)), targetEntity->GetSystemAddress(), true, true, false, false, wait, hidePlayer, leadIn, leaveLocked, unlock); +} + +void TriggerComponent::HandleToggleBBB(Entity* targetEntity, std::string args) { + auto* character = targetEntity->GetCharacter(); + if (!character) { + Game::logger->Log("TriggerComponent::HandleToggleBBB", "Character was not found!"); + return; + } + bool buildMode = !(character->GetBuildMode()); + if (args == "enter") buildMode = true; + else if (args == "exit") buildMode = false; + character->SetBuildMode(buildMode); +} + +void TriggerComponent::HandleUpdateMission(Entity* targetEntity, std::vector argArray) { + // there are only explore tasks used + // If others need to be implemented for modding + // then we need a good way to convert this from a string to that enum + if (argArray.at(0) != "exploretask") return; + MissionComponent* missionComponent = targetEntity->GetComponent(); + if (!missionComponent){ + Game::logger->Log("TriggerComponent::HandleUpdateMission", "Mission component not found!"); + return; + } + missionComponent->Progress(eMissionTaskType::EXPLORE, 0, 0, argArray.at(4)); +} + +void TriggerComponent::HandlePlayEffect(Entity* targetEntity, std::vector argArray) { + if (argArray.size() < 3) return; + int32_t effectID = 0; + if (!GeneralUtils::TryParse(argArray.at(1), effectID)) return; + std::u16string effectType = GeneralUtils::UTF8ToUTF16(argArray.at(2)); + float priority = 1; + if (argArray.size() == 4) GeneralUtils::TryParse(argArray.at(3), priority); + GameMessages::SendPlayFXEffect(targetEntity, effectID, effectType, argArray.at(0), LWOOBJID_EMPTY, priority); +} + +void TriggerComponent::HandleCastSkill(Entity* targetEntity, std::string args){ + auto* skillComponent = targetEntity->GetComponent(); + if (!skillComponent) { + Game::logger->Log("TriggerComponent::HandleCastSkill", "Skill component not found!"); + return; + } + uint32_t skillId; + GeneralUtils::TryParse(args, skillId); + skillComponent->CastSkill(skillId, targetEntity->GetObjectID()); +} + +void TriggerComponent::HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector argArray) { + auto* phantomPhysicsComponent = targetEntity->GetComponent(); + if (!phantomPhysicsComponent) { + Game::logger->Log("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(true); + ePhysicsEffectType effectType = ePhysicsEffectType::PUSH; + std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase + if (argArray.at(0) == "push") effectType = ePhysicsEffectType::PUSH; + else if (argArray.at(0) == "attract") effectType = ePhysicsEffectType::ATTRACT; + else if (argArray.at(0) == "repulse") effectType = ePhysicsEffectType::REPULSE; + else if (argArray.at(0) == "gravity") effectType = ePhysicsEffectType::GRAVITY_SCALE; + else if (argArray.at(0) == "friction") effectType = ePhysicsEffectType::FRICTION; + + phantomPhysicsComponent->SetEffectType(effectType); + phantomPhysicsComponent->SetDirectionalMultiplier(std::stof(argArray.at(1))); + if (argArray.size() > 4) { + NiPoint3 direction = NiPoint3::ZERO; + GeneralUtils::TryParse(argArray.at(2), argArray.at(3), argArray.at(4), direction); + phantomPhysicsComponent->SetDirection(direction); + } + if (argArray.size() > 5) { + uint32_t min; + GeneralUtils::TryParse(argArray.at(6), min); + phantomPhysicsComponent->SetMin(min); + + uint32_t max; + GeneralUtils::TryParse(argArray.at(7), max); + phantomPhysicsComponent->SetMax(max); + } + + EntityManager::Instance()->SerializeEntity(targetEntity); +} + +void TriggerComponent::HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args) { + auto* phantomPhysicsComponent = targetEntity->GetComponent(); + if (!phantomPhysicsComponent) { + Game::logger->Log("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!"); + return; + } + phantomPhysicsComponent->SetPhysicsEffectActive(args == "On"); + EntityManager::Instance()->SerializeEntity(targetEntity); +} + +void TriggerComponent::HandleActivateSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Activate(); + } +} + +void TriggerComponent::HandleDeactivateSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Deactivate(); + } +} + +void TriggerComponent::HandleResetSpawnerNetwork(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->Reset(); + } +} + +void TriggerComponent::HandleDestroySpawnerNetworkObjects(std::string args){ + for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) { + if (spawner) spawner->DestroyAllEntities(); + } +} + +void TriggerComponent::HandleActivatePhysics(Entity* targetEntity, std::string args) { + if (args == "true") { + // TODO add physics entity if there isn't one + } else if (args == "false"){ + // TODO remove Phsyics entity if there is one + } else { + Game::logger->LogDebug("TriggerComponent", "Invalid argument for ActivatePhysics Trigger: %s", args.c_str()); + } +} diff --git a/dGame/dComponents/TriggerComponent.h b/dGame/dComponents/TriggerComponent.h new file mode 100644 index 00000000..317da00e --- /dev/null +++ b/dGame/dComponents/TriggerComponent.h @@ -0,0 +1,48 @@ +#ifndef __TRIGGERCOMPONENT__H__ +#define __TRIGGERCOMPONENT__H__ + +#include "Component.h" +#include "LUTriggers.h" +#include "eReplicaComponentType.h" + +class TriggerComponent : public Component { +public: + static const eReplicaComponentType ComponentType = eReplicaComponentType::TRIGGER; + + explicit TriggerComponent(Entity* parent, const std::string triggerInfo); + + void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr); + LUTriggers::Trigger* GetTrigger() const { return m_Trigger; } + void SetTriggerEnabled(bool enabled){ m_Trigger->enabled = enabled; }; + + +private: + + void HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget); + std::vector GatherTargets(LUTriggers::Command* command, Entity* optionalTarget); + + // Trigger Event Handlers + void HandleFireEvent(Entity* targetEntity, std::string args); + void HandleDestroyObject(Entity* targetEntity, std::string args); + void HandleToggleTrigger(Entity* targetEntity, std::string args); + void HandleResetRebuild(Entity* targetEntity, std::string args); + void HandleMoveObject(Entity* targetEntity, std::vector argArray); + void HandleRotateObject(Entity* targetEntity, std::vector argArray); + void HandlePushObject(Entity* targetEntity, std::vector argArray); + void HandleRepelObject(Entity* targetEntity, std::string args); + void HandlePlayCinematic(Entity* targetEntity, std::vector argArray); + void HandleToggleBBB(Entity* targetEntity, std::string args); + void HandleUpdateMission(Entity* targetEntity, std::vector argArray); + void HandlePlayEffect(Entity* targetEntity, std::vector argArray); + void HandleCastSkill(Entity* targetEntity, std::string args); + void HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector argArray); + void HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args); + void HandleActivateSpawnerNetwork(std::string args); + void HandleDeactivateSpawnerNetwork(std::string args); + void HandleResetSpawnerNetwork(std::string args); + void HandleDestroySpawnerNetworkObjects(std::string args); + void HandleActivatePhysics(Entity* targetEntity, std::string args); + + LUTriggers::Trigger* m_Trigger; +}; +#endif //!__TRIGGERCOMPONENT__H__ diff --git a/dGame/dComponents/VehiclePhysicsComponent.h b/dGame/dComponents/VehiclePhysicsComponent.h index f5ab1917..551cce42 100644 --- a/dGame/dComponents/VehiclePhysicsComponent.h +++ b/dGame/dComponents/VehiclePhysicsComponent.h @@ -3,13 +3,14 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "eReplicaComponentType.h" /** * Physics component for vehicles. */ class VehiclePhysicsComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_VEHICLE_PHYSICS; + static const eReplicaComponentType ComponentType = eReplicaComponentType::VEHICLE_PHYSICS; VehiclePhysicsComponent(Entity* parentEntity); ~VehiclePhysicsComponent() override; diff --git a/dGame/dComponents/VendorComponent.cpp b/dGame/dComponents/VendorComponent.cpp index 96dfb2c0..c9178785 100644 --- a/dGame/dComponents/VendorComponent.cpp +++ b/dGame/dComponents/VendorComponent.cpp @@ -5,6 +5,11 @@ #include "Game.h" #include "dServer.h" +#include "CDComponentsRegistryTable.h" +#include "CDVendorComponentTable.h" +#include "CDLootMatrixTable.h" +#include "CDLootTableTable.h" + VendorComponent::VendorComponent(Entity* parent) : Component(parent) { SetupConstants(); RefreshInventory(true); @@ -59,13 +64,13 @@ void VendorComponent::RefreshInventory(bool isCreation) { return; } m_Inventory.clear(); - auto* lootMatrixTable = CDClientManager::Instance()->GetTable("LootMatrix"); + auto* lootMatrixTable = CDClientManager::Instance().GetTable(); std::vector lootMatrices = lootMatrixTable->Query([=](CDLootMatrix entry) { return (entry.LootMatrixIndex == m_LootMatrixID); }); if (lootMatrices.empty()) return; // Done with lootMatrix table - auto* lootTableTable = CDClientManager::Instance()->GetTable("LootTable"); + auto* lootTableTable = CDClientManager::Instance().GetTable(); for (const auto& lootMatrix : lootMatrices) { int lootTableID = lootMatrix.LootTableIndex; @@ -118,10 +123,10 @@ void VendorComponent::RefreshInventory(bool isCreation) { } void VendorComponent::SetupConstants() { - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), COMPONENT_TYPE_VENDOR); + auto* compRegistryTable = CDClientManager::Instance().GetTable(); + int componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::VENDOR); - auto* vendorComponentTable = CDClientManager::Instance()->GetTable("VendorComponent"); + auto* vendorComponentTable = CDClientManager::Instance().GetTable(); std::vector vendorComps = vendorComponentTable->Query([=](CDVendorComponent entry) { return (entry.id == componentID); }); if (vendorComps.empty()) return; m_BuyScalar = vendorComps[0].buyScalar; diff --git a/dGame/dComponents/VendorComponent.h b/dGame/dComponents/VendorComponent.h index 72a5816d..bf372bf2 100644 --- a/dGame/dComponents/VendorComponent.h +++ b/dGame/dComponents/VendorComponent.h @@ -7,13 +7,14 @@ #include "Entity.h" #include "GameMessages.h" #include "RakNetTypes.h" +#include "eReplicaComponentType.h" /** * A component for vendor NPCs. A vendor sells items to the player. */ class VendorComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_VENDOR; + static const eReplicaComponentType ComponentType = eReplicaComponentType::VENDOR; VendorComponent(Entity* parent); ~VendorComponent() override; diff --git a/dGame/dGameMessages/DoClientProjectileImpact.h b/dGame/dGameMessages/DoClientProjectileImpact.h new file mode 100644 index 00000000..436e3dd2 --- /dev/null +++ b/dGame/dGameMessages/DoClientProjectileImpact.h @@ -0,0 +1,83 @@ +#ifndef __DOCLIENTPROJECTILEIMPACT__H__ +#define __DOCLIENTPROJECTILEIMPACT__H__ + +#include "dMessageIdentifiers.h" +#include "dCommonVars.h" + +/* Tell a client local projectile to impact */ +class DoClientProjectileImpact { + static const GAME_MSG MsgID = GAME_MSG_DO_CLIENT_PROJECTILE_IMPACT; + +public: + DoClientProjectileImpact() { + i64OrgID = LWOOBJID_EMPTY; + i64OwnerID = LWOOBJID_EMPTY; + i64TargetID = LWOOBJID_EMPTY; + } + + DoClientProjectileImpact(std::string _sBitStream, LWOOBJID _i64OrgID = LWOOBJID_EMPTY, LWOOBJID _i64OwnerID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { + i64OrgID = _i64OrgID; + i64OwnerID = _i64OwnerID; + i64TargetID = _i64TargetID; + sBitStream = _sBitStream; + } + + DoClientProjectileImpact(RakNet::BitStream* stream) : DoClientProjectileImpact() { + Deserialize(stream); + } + + ~DoClientProjectileImpact() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(i64OrgID != LWOOBJID_EMPTY); + if (i64OrgID != LWOOBJID_EMPTY) stream->Write(i64OrgID); + + stream->Write(i64OwnerID != LWOOBJID_EMPTY); + if (i64OwnerID != LWOOBJID_EMPTY) stream->Write(i64OwnerID); + + stream->Write(i64TargetID != LWOOBJID_EMPTY); + if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + } + + bool Deserialize(RakNet::BitStream* stream) { + bool i64OrgIDIsDefault{}; + stream->Read(i64OrgIDIsDefault); + if (i64OrgIDIsDefault != 0) stream->Read(i64OrgID); + + bool i64OwnerIDIsDefault{}; + stream->Read(i64OwnerIDIsDefault); + if (i64OwnerIDIsDefault != 0) stream->Read(i64OwnerID); + + bool i64TargetIDIsDefault{}; + stream->Read(i64TargetIDIsDefault); + if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + + return true; + } + + LWOOBJID i64OrgID; + LWOOBJID i64OwnerID; + LWOOBJID i64TargetID; + std::string sBitStream; +}; + +#endif //!__DOCLIENTPROJECTILEIMPACT__H__ diff --git a/dGame/dGameMessages/EchoStartSkill.h b/dGame/dGameMessages/EchoStartSkill.h new file mode 100644 index 00000000..6d912798 --- /dev/null +++ b/dGame/dGameMessages/EchoStartSkill.h @@ -0,0 +1,132 @@ +#ifndef __ECHOSTARTSKILL__H__ +#define __ECHOSTARTSKILL__H__ + +#include "dCommonVars.h" +#include "dMessageIdentifiers.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" + +/* Same as start skill but with different network options. An echo down to other clients that need to play the skill. */ +class EchoStartSkill { + static const GAME_MSG MsgID = GAME_MSG_ECHO_START_SKILL; + +public: + EchoStartSkill() { + bUsedMouse = false; + fCasterLatency = 0.0f; + iCastType = 0; + lastClickedPosit = NiPoint3::ZERO; + optionalTargetID = LWOOBJID_EMPTY; + originatorRot = NiQuaternion::IDENTITY; + uiSkillHandle = 0; + } + + EchoStartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, float _fCasterLatency = 0.0f, int32_t _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, uint32_t _uiSkillHandle = 0) { + bUsedMouse = _bUsedMouse; + fCasterLatency = _fCasterLatency; + iCastType = _iCastType; + lastClickedPosit = _lastClickedPosit; + optionalOriginatorID = _optionalOriginatorID; + optionalTargetID = _optionalTargetID; + originatorRot = _originatorRot; + sBitStream = _sBitStream; + skillID = _skillID; + uiSkillHandle = _uiSkillHandle; + } + + EchoStartSkill(RakNet::BitStream* stream) : EchoStartSkill() { + Deserialize(stream); + } + + ~EchoStartSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(bUsedMouse); + + stream->Write(fCasterLatency != 0.0f); + if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); + + stream->Write(iCastType != 0); + if (iCastType != 0) stream->Write(iCastType); + + stream->Write(lastClickedPosit != NiPoint3::ZERO); + if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); + + stream->Write(optionalOriginatorID); + + stream->Write(optionalTargetID != LWOOBJID_EMPTY); + if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); + + stream->Write(originatorRot != NiQuaternion::IDENTITY); + if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(skillID); + + stream->Write(uiSkillHandle != 0); + if (uiSkillHandle != 0) stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bUsedMouse); + + bool fCasterLatencyIsDefault{}; + stream->Read(fCasterLatencyIsDefault); + if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); + + bool iCastTypeIsDefault{}; + stream->Read(iCastTypeIsDefault); + if (iCastTypeIsDefault != 0) stream->Read(iCastType); + + bool lastClickedPositIsDefault{}; + stream->Read(lastClickedPositIsDefault); + if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); + + stream->Read(optionalOriginatorID); + + bool optionalTargetIDIsDefault{}; + stream->Read(optionalTargetIDIsDefault); + if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); + + bool originatorRotIsDefault{}; + stream->Read(originatorRotIsDefault); + if (originatorRotIsDefault != 0) stream->Read(originatorRot); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(skillID); + + bool uiSkillHandleIsDefault{}; + stream->Read(uiSkillHandleIsDefault); + if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); + + return true; + } + + bool bUsedMouse; + float fCasterLatency; + int32_t iCastType; + NiPoint3 lastClickedPosit; + LWOOBJID optionalOriginatorID; + LWOOBJID optionalTargetID; + NiQuaternion originatorRot; + std::string sBitStream; + TSkillID skillID; + uint32_t uiSkillHandle; +}; + +#endif //!__ECHOSTARTSKILL__H__ diff --git a/dGame/dGameMessages/EchoSyncSkill.h b/dGame/dGameMessages/EchoSyncSkill.h new file mode 100644 index 00000000..b56beae8 --- /dev/null +++ b/dGame/dGameMessages/EchoSyncSkill.h @@ -0,0 +1,70 @@ +#ifndef __ECHOSYNCSKILL__H__ +#define __ECHOSYNCSKILL__H__ + +#include + +#include "BitStream.h" + +#include "dMessageIdentifiers.h" + +/* Message to synchronize a skill cast */ +class EchoSyncSkill { + static const GAME_MSG MsgID = GAME_MSG_ECHO_SYNC_SKILL; + +public: + EchoSyncSkill() { + bDone = false; + } + + EchoSyncSkill(std::string _sBitStream, uint32_t _uiBehaviorHandle, uint32_t _uiSkillHandle, bool _bDone = false) { + bDone = _bDone; + sBitStream = _sBitStream; + uiBehaviorHandle = _uiBehaviorHandle; + uiSkillHandle = _uiSkillHandle; + } + + EchoSyncSkill(RakNet::BitStream* stream) : EchoSyncSkill() { + Deserialize(stream); + } + + ~EchoSyncSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(bDone); + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(uiBehaviorHandle); + stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bDone); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (unsigned int k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(uiBehaviorHandle); + stream->Read(uiSkillHandle); + + return true; + } + + bool bDone{}; + std::string sBitStream{}; + uint32_t uiBehaviorHandle{}; + uint32_t uiSkillHandle{}; +}; + +#endif //!__ECHOSYNCSKILL__H__ diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index 9cf09bbc..c0893a09 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -26,6 +26,13 @@ #include "CDSkillBehaviorTable.h" #include "SkillComponent.h" #include "RacingControlComponent.h" +#include "RequestServerProjectileImpact.h" +#include "SyncSkill.h" +#include "StartSkill.h" +#include "EchoStartSkill.h" +#include "EchoSyncSkill.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" using namespace std; @@ -46,6 +53,10 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System switch (messageID) { + case GAME_MSG_UN_USE_BBB_MODEL: { + GameMessages::HandleUnUseModel(inStream, entity, sysAddr); + break; + } case GAME_MSG_PLAY_EMOTE: { GameMessages::HandlePlayEmote(inStream, entity); break; @@ -112,7 +123,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System destroyable->SetImagination(destroyable->GetImagination()); EntityManager::Instance()->SerializeEntity(entity); - std::vector racingControllers = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_RACING_CONTROL); + std::vector racingControllers = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); for (Entity* racingController : racingControllers) { auto* racingComponent = racingController->GetComponent(); if (racingComponent != nullptr) { @@ -125,7 +136,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System script->OnPlayerLoaded(zoneControl, player); } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPT); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { @@ -157,8 +168,8 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System Game::logger->Log("GameMessageHandler", "Player %s (%llu) loaded.", entity->GetCharacter()->GetName().c_str(), entity->GetObjectID()); // After we've done our thing, tell the client they're ready - GameMessages::SendPlayerReady(dZoneManager::Instance()->GetZoneControlObject(), sysAddr); GameMessages::SendPlayerReady(entity, sysAddr); + GameMessages::SendPlayerReady(dZoneManager::Instance()->GetZoneControlObject(), sysAddr); break; } @@ -231,7 +242,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System case GAME_MSG_REQUEST_RESURRECT: { GameMessages::SendResurrect(entity); - /*auto* dest = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + /*auto* dest = static_cast(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth(4); dest->SetArmor(0); @@ -247,7 +258,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System case GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT: { - auto message = GameMessages::RequestServerProjectileImpact(); + auto message = RequestServerProjectileImpact(); message.Deserialize(inStream); @@ -265,17 +276,17 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System } case GAME_MSG_START_SKILL: { - GameMessages::StartSkill startSkill = GameMessages::StartSkill(); + StartSkill startSkill = StartSkill(); startSkill.Deserialize(inStream); // inStream replaces &bitStream if (startSkill.skillID == 1561 || startSkill.skillID == 1562 || startSkill.skillID == 1541) return; MissionComponent* comp = entity->GetComponent(); if (comp) { - comp->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, startSkill.skillID); + comp->Progress(eMissionTaskType::USE_SKILL, startSkill.skillID); } - CDSkillBehaviorTable* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + CDSkillBehaviorTable* skillTable = CDClientManager::Instance().GetTable(); unsigned int behaviorId = skillTable->GetSkillByID(startSkill.skillID).behaviorID; bool success = false; @@ -305,7 +316,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System PacketUtils::WriteHeader(bitStreamLocal, CLIENT, MSG_CLIENT_GAME_MSG); bitStreamLocal.Write(entity->GetObjectID()); - GameMessages::EchoStartSkill echoStartSkill; + EchoStartSkill echoStartSkill; echoStartSkill.bUsedMouse = startSkill.bUsedMouse; echoStartSkill.fCasterLatency = startSkill.fCasterLatency; echoStartSkill.iCastType = startSkill.iCastType; @@ -329,7 +340,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System //bitStreamLocal.Write((unsigned short)GAME_MSG_ECHO_SYNC_SKILL); //bitStreamLocal.Write(inStream); - GameMessages::SyncSkill sync = GameMessages::SyncSkill(inStream); // inStream replaced &bitStream + SyncSkill sync = SyncSkill(inStream); // inStream replaced &bitStream //sync.Serialize(&bitStreamLocal); ostringstream buffer; @@ -352,7 +363,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System delete bs; } - GameMessages::EchoSyncSkill echo = GameMessages::EchoSyncSkill(); + EchoSyncSkill echo = EchoSyncSkill(); echo.bDone = sync.bDone; echo.sBitStream = sync.sBitStream; echo.uiBehaviorHandle = sync.uiBehaviorHandle; @@ -656,9 +667,17 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System case GAME_MSG_DISMOUNT_COMPLETE: GameMessages::HandleDismountComplete(inStream, entity, sysAddr); break; - + case GAME_MSG_DEACTIVATE_BUBBLE_BUFF: + GameMessages::HandleDeactivateBubbleBuff(inStream, entity); + break; + case GAME_MSG_ACTIVATE_BUBBLE_BUFF: + GameMessages::HandleActivateBubbleBuff(inStream, entity); + break; + case GAME_MSG_ZONE_SUMMARY_DISMISSED: + GameMessages::HandleZoneSummaryDismissed(inStream, entity); + break; default: - //Game::logger->Log("GameMessageHandler", "Unknown game message ID: %X", messageID); + // Game::logger->Log("GameMessageHandler", "Unknown game message ID: %i", messageID); break; } } diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 18d7e0f6..bf7476e9 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -25,9 +25,16 @@ #include "dConfig.h" #include "TeamManager.h" #include "ChatPackets.h" -#include "GameConfig.h" #include "RocketLaunchLupComponent.h" #include "eUnequippableActiveType.h" +#include "eMovementPlatformState.h" +#include "LeaderboardManager.h" +#include "AMFFormat.h" +#include "Loot.h" +#include "eRacingTaskParam.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "eTriggerEventType.h" #include #include @@ -49,6 +56,7 @@ #include "ScriptComponent.h" #include "RebuildComponent.h" #include "VendorComponent.h" +#include "InventoryComponent.h" #include "RocketLaunchpadControlComponent.h" #include "PropertyEntranceComponent.h" #include "MovingPlatformComponent.h" @@ -70,6 +78,13 @@ #include "TradingManager.h" #include "ControlBehaviors.h" #include "AMFDeserialize.h" +#include "eBlueprintSaveResponseType.h" +#include "eAninmationFlags.h" +#include "AMFFormat_BitStream.h" +#include "eReplicaComponentType.h" + +#include "CDComponentsRegistryTable.h" +#include "CDObjectsTable.h" void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) { CBITSTREAM; @@ -327,7 +342,7 @@ void GameMessages::SendStartPathing(Entity* entity) { void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint, int iIndex, int iDesiredWaypointIndex, int nextIndex, - MovementPlatformState movementState) { + eMovementPlatformState movementState) { CBITSTREAM; CMSGHEADER; @@ -338,7 +353,7 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd iIndex = 0; nextIndex = 0; bStopAtDesiredWaypoint = true; - movementState = MovementPlatformState::Stationary; + movementState = eMovementPlatformState::Stationary; } bitStream.Write(entity->GetObjectID()); @@ -395,7 +410,7 @@ void GameMessages::SendServerDoneLoadingAllObjects(Entity* entity, const SystemA SEND_PACKET; } -void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, uint8_t level) { +void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); @@ -404,7 +419,7 @@ void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, uint8_t level) { SEND_PACKET_BROADCAST; } -void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, uint8_t level) { +void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); @@ -572,7 +587,7 @@ void GameMessages::SendModifyLEGOScore(Entity* entity, const SystemAddress& sysA SEND_PACKET; } -void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, NDGFxValue args) { +void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFValue* args) { CBITSTREAM; CMSGHEADER; @@ -590,7 +605,7 @@ void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const Syste SEND_PACKET; } -void GameMessages::SendUIMessageServerToAllClients(const std::string& message, NDGFxValue args) { +void GameMessages::SendUIMessageServerToAllClients(const std::string& message, AMFValue* args) { CBITSTREAM; CMSGHEADER; @@ -904,17 +919,25 @@ void GameMessages::SendSetJetPackMode(Entity* entity, bool use, bool bypassCheck } void GameMessages::SendResurrect(Entity* entity) { - DestroyableComponent* dest = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + // Restore the players health after the animation for respawning has finished. + // This is when the health appered back in live, not immediately upon requesting respawn + // Add a half second in case someone decides to cheat and move during the death animation + // and just make sure the client has time to be ready. + constexpr float respawnTime = 3.66700005531311f + 0.5f; + entity->AddCallbackTimer(respawnTime, [=]() { + auto* destroyableComponent = entity->GetComponent(); - if (dest != nullptr && entity->GetLOT() == 1) { - auto* levelComponent = entity->GetComponent(); - if (levelComponent) { - dest->SetHealth(levelComponent->GetLevel() >= 45 ? 8 : 4); - dest->SetImagination(levelComponent->GetLevel() >= 45 ? 20 : 6); + if (destroyableComponent != nullptr && entity->GetLOT() == 1) { + auto* levelComponent = entity->GetComponent(); + if (levelComponent) { + destroyableComponent->SetHealth(levelComponent->GetLevel() >= 45 ? 8 : 4); + destroyableComponent->SetImagination(levelComponent->GetLevel() >= 45 ? 20 : 6); + } } - } + }); - auto cont = static_cast(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + + auto cont = static_cast(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (cont && entity->GetLOT() == 1) { cont->SetPosition(entity->GetRespawnPosition()); cont->SetRotation(entity->GetRespawnRotation()); @@ -997,7 +1020,7 @@ void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress& } void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, LOT item, int currency, NiPoint3 spawnPos, int count) { - if (GameConfig::GetValue("no_drops") == 1) { + if (Game::config->GetValue("disable_drops") == "1") { return; } @@ -1058,7 +1081,7 @@ void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, // Currency and powerups should not sync if (team != nullptr && currency == 0) { - CDObjectsTable* objectsTable = CDClientManager::Instance()->GetTable("Objects"); + CDObjectsTable* objectsTable = CDClientManager::Instance().GetTable(); const CDObjects& object = objectsTable->GetByID(item); @@ -1111,7 +1134,7 @@ void GameMessages::SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPo bitStream.Write(position.y); bitStream.Write(position.z); - auto con = static_cast(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + auto con = static_cast(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (con) { auto rot = con->GetRotation(); bitStream.Write(rot.x); @@ -1246,7 +1269,7 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s CBITSTREAM; CMSGHEADER; - VendorComponent* vendor = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); + VendorComponent* vendor = static_cast(entity->GetComponent(eReplicaComponentType::VENDOR)); if (!vendor) return; std::map vendorItems = vendor->GetInventory(); @@ -1368,7 +1391,7 @@ void GameMessages::SendMoveInventoryBatch(Entity* entity, uint32_t stackCount, i CBITSTREAM; CMSGHEADER; - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; Item* itemStack = inv->FindItemById(iObjID); @@ -1672,7 +1695,7 @@ void GameMessages::HandleActivityStateChangeRequest(RakNet::BitStream* inStream, Game::logger->Log("Activity State Change", "%s [%i, %i] from %i to %i", GeneralUtils::UTF16ToWTF8(stringValue).c_str(), value1, value2, entity->GetLOT(), assosiate != nullptr ? assosiate->GetLOT() : 0); - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SHOOTING_GALLERY); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SHOOTING_GALLERY); for (Entity* scriptEntity : scriptedActs) { scriptEntity->OnActivityStateChangeRequest(objectID, value1, value2, stringValue); } @@ -2139,6 +2162,32 @@ void GameMessages::HandleSetPropertyAccess(RakNet::BitStream* inStream, Entity* PropertyManagementComponent::Instance()->SetPrivacyOption(static_cast(accessType)); } +void GameMessages::HandleUnUseModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + bool unknown{}; + LWOOBJID objIdToAddToInventory{}; + inStream->Read(unknown); + inStream->Read(objIdToAddToInventory); + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) { + auto* inventory = inventoryComponent->GetInventory(eInventoryType::MODELS_IN_BBB); + auto* item = inventory->FindItemById(objIdToAddToInventory); + if (item) { + inventoryComponent->MoveItemToInventory(item, eInventoryType::MODELS, 1); + } else { + Game::logger->Log("GameMessages", "item id %llu not found in MODELS_IN_BBB inventory, likely because it does not exist", objIdToAddToInventory); + } + } + + if (unknown) { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE); + bitStream.Write(LWOOBJID_EMPTY); //always zero so that a check on the client passes + bitStream.Write(eBlueprintSaveResponseType::PlacementFailed); // Sending a non-zero error code here prevents the client from deleting its in progress build for some reason? + bitStream.Write(0); + SEND_PACKET; + } +} + void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool isProperty{}; LWOOBJID objectId{}; @@ -2175,24 +2224,24 @@ void GameMessages::HandleQueryPropertyData(RakNet::BitStream* inStream, Entity* Game::logger->Log("HandleQueryPropertyData", "Entity (%i) requesting data", entity->GetLOT()); /* - auto entites = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROPERTY_VENDOR); + auto entites = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_VENDOR); entity = entites[0]; */ - auto* propertyVendorComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_PROPERTY_VENDOR)); + auto* propertyVendorComponent = static_cast(entity->GetComponent(eReplicaComponentType::PROPERTY_VENDOR)); if (propertyVendorComponent != nullptr) { propertyVendorComponent->OnQueryPropertyData(entity, sysAddr); } /* - entites = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROPERTY_MANAGEMENT); + entites = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_MANAGEMENT); entity = entites[0]; */ - auto* propertyManagerComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_PROPERTY_MANAGEMENT)); + auto* propertyManagerComponent = static_cast(entity->GetComponent(eReplicaComponentType::PROPERTY_MANAGEMENT)); if (propertyManagerComponent != nullptr) { propertyManagerComponent->OnQueryPropertyData(entity, sysAddr); @@ -2236,7 +2285,7 @@ void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entit } void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - if (!entity->HasComponent(COMPONENT_TYPE_PROPERTY_MANAGEMENT)) { + if (!entity->HasComponent(eReplicaComponentType::PROPERTY_MANAGEMENT)) { return; } @@ -2353,16 +2402,40 @@ void GameMessages::HandleDeletePropertyModel(RakNet::BitStream* inStream, Entity } void GameMessages::HandleBBBLoadItemRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - LWOOBJID itemID = LWOOBJID_EMPTY; - inStream->Read(itemID); + LWOOBJID previousItemID = LWOOBJID_EMPTY; + inStream->Read(previousItemID); - Game::logger->Log("BBB", "Load item request for: %lld", itemID); + Game::logger->Log("BBB", "Load item request for: %lld", previousItemID); + LWOOBJID newId = previousItemID; + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) { + auto* inventory = inventoryComponent->GetInventory(eInventoryType::MODELS); + auto* itemToMove = inventory->FindItemById(previousItemID); + if (itemToMove) { + LOT previousLot = itemToMove->GetLot(); + inventoryComponent->MoveItemToInventory(itemToMove, eInventoryType::MODELS_IN_BBB, 1, false); + + auto* destinationInventory = inventoryComponent->GetInventory(eInventoryType::MODELS_IN_BBB); + if (destinationInventory) { + auto* movedItem = destinationInventory->FindItemByLot(previousLot); + if (movedItem) newId = movedItem->GetId(); + } + } else { + Game::logger->Log("GameMessages", "item id %llu not found in MODELS inventory, likely because it does not exist", previousItemID); + } + } + + // Second argument always true (successful) for now + SendBlueprintLoadItemResponse(sysAddr, true, previousItemID, newId); +} + +void GameMessages::SendBlueprintLoadItemResponse(const SystemAddress& sysAddr, bool success, LWOOBJID oldItemId, LWOOBJID newItemId) { CBITSTREAM; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_BLUEPRINT_LOAD_RESPONSE_ITEMID); - bitStream.Write(static_cast(1)); - bitStream.Write(itemID); - bitStream.Write(itemID); + bitStream.Write(static_cast(success)); + bitStream.Write(oldItemId); + bitStream.Write(newItemId); SEND_PACKET; } @@ -2413,9 +2486,9 @@ void GameMessages::HandleControlBehaviors(RakNet::BitStream* inStream, Entity* e } auto owner = PropertyManagementComponent::Instance()->GetOwner(); - if (!owner) return; + if (!owner) return; - ControlBehaviors::ProcessCommand(entity, sysAddr, static_cast(amfArguments.get()), command, owner); + ControlBehaviors::Instance().ProcessCommand(entity, sysAddr, static_cast(amfArguments.get()), command, owner); } void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { @@ -2609,8 +2682,8 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent CBITSTREAM; PacketUtils::WriteHeader(bitStream, CLIENT, CLIENT::MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE); bitStream.Write(localId); - bitStream.Write(0); - bitStream.Write(1); + bitStream.Write(eBlueprintSaveResponseType::EverythingWorked); + bitStream.Write(1); bitStream.Write(blueprintID); bitStream.Write(sd0Size); @@ -2620,7 +2693,6 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent } SEND_PACKET; - // PacketUtils::SavePacket("MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE.bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); //Now we have to construct this object: @@ -2742,7 +2814,7 @@ void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener, - int endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, + eEndBehavior endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) { CBITSTREAM; CMSGHEADER; @@ -2755,8 +2827,8 @@ void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, bitStream.Write(bSendServerNotify); bitStream.Write(bUseControlledObjectForAudioListener); - bitStream.Write(endBehavior != 0); - if (endBehavior != 0) bitStream.Write(endBehavior); + bitStream.Write(endBehavior != eEndBehavior::RETURN); + if (endBehavior != eEndBehavior::RETURN) bitStream.Write(endBehavior); bitStream.Write(hidePlayerDuringCine); @@ -2842,13 +2914,13 @@ void GameMessages::HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* en inStream->Read(waypoint); } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPT); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); for (Entity* scriptEntity : scriptedActs) { scriptEntity->OnCinematicUpdate(scriptEntity, entity, event, pathName, pathTime, overallTime, waypoint); } } -void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, const SystemAddress& sysAddr, +void GameMessages::SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, LWOOBJID originator, bool bCantAttack, bool bCantEquip, bool bCantInteract, bool bCantJump, bool bCantMove, bool bCantTurn, bool bCantUseItem, bool bDontTerminateInteract, bool bIgnoreImmunity, @@ -2896,6 +2968,69 @@ void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, SEND_PACKET; } +void GameMessages::SendSetStunImmunity(LWOOBJID target, eStateChangeType state, const SystemAddress& sysAddr, + LWOOBJID originator, + bool bImmuneToStunAttack, + bool bImmuneToStunEquip, + bool bImmuneToStunInteract, + bool bImmuneToStunJump, + bool bImmuneToStunMove, + bool bImmuneToStunTurn, + bool bImmuneToStunUseItem) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(target); + bitStream.Write(GAME_MSG::GAME_MSG_SET_STUN_IMMUNITY); + + bitStream.Write(originator != LWOOBJID_EMPTY); + if (originator != LWOOBJID_EMPTY) bitStream.Write(originator); + + bitStream.Write(state); + + bitStream.Write(bImmuneToStunAttack); + bitStream.Write(bImmuneToStunEquip); + bitStream.Write(bImmuneToStunInteract); + bitStream.Write(bImmuneToStunJump); + bitStream.Write(bImmuneToStunMove); + bitStream.Write(bImmuneToStunTurn); + bitStream.Write(bImmuneToStunUseItem); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::SendSetStatusImmunity(LWOOBJID objectId, eStateChangeType state, const SystemAddress& sysAddr, + bool bImmuneToBasicAttack, + bool bImmuneToDamageOverTime, + bool bImmuneToKnockback, + bool bImmuneToInterrupt, + bool bImmuneToSpeed, + bool bImmuneToImaginationGain, + bool bImmuneToImaginationLoss, + bool bImmuneToQuickbuildInterrupt, + bool bImmuneToPullToPoint) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_SET_STATUS_IMMUNITY); + + bitStream.Write(state); + + bitStream.Write(bImmuneToBasicAttack); + bitStream.Write(bImmuneToDamageOverTime); + bitStream.Write(bImmuneToKnockback); + bitStream.Write(bImmuneToInterrupt); + bitStream.Write(bImmuneToSpeed); + bitStream.Write(bImmuneToImaginationGain); + bitStream.Write(bImmuneToImaginationLoss); + bitStream.Write(bImmuneToQuickbuildInterrupt); + bitStream.Write(bImmuneToPullToPoint); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) { CBITSTREAM; @@ -3144,7 +3279,7 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* // Check if the player has restricted trade access auto* character = entity->GetCharacter(); - if (character->HasPermission(PermissionMap::RestrictedTradeAccess)) { + if (character->HasPermission(ePermissionMap::RestrictedTradeAccess)) { // Send a message to the player ChatPackets::SendSystemMessage( sysAddr, @@ -3164,7 +3299,7 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* if (invitee != nullptr && invitee->IsPlayer()) { character = invitee->GetCharacter(); - if (character->HasPermission(PermissionMap::RestrictedTradeAccess)) { + if (character->HasPermission(ePermissionMap::RestrictedTradeAccess)) { // Send a message to the player ChatPackets::SendSystemMessage( sysAddr, @@ -3476,6 +3611,20 @@ void GameMessages::SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID ta SEND_PACKET; } +void GameMessages::SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(GAME_MSG::GAME_MSG_REMOVE_BUFF); + + bitStream.Write(false); // bFromRemoveBehavior but setting this to true makes the GM not do anything on the client? + bitStream.Write(fromUnEquip); + bitStream.Write(removeImmunity); + bitStream.Write(buffId); + + SEND_PACKET_BROADCAST; +} void GameMessages::SendBouncerActiveStatus(LWOOBJID objectId, bool bActive, const SystemAddress& sysAddr) { CBITSTREAM; @@ -3732,7 +3881,7 @@ void GameMessages::HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* racingControlComponent->HandleMessageBoxResponse(userEntity, GeneralUtils::UTF16ToWTF8(identifier)); } - for (auto* shootingGallery : EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SHOOTING_GALLERY)) { + for (auto* shootingGallery : EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SHOOTING_GALLERY)) { shootingGallery->OnMessageBoxResponse(userEntity, iButton, identifier, userData); } } @@ -3858,6 +4007,20 @@ void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string SEND_PACKET; } + +void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags flagsOn, eAnimationFlags flagsOff, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_CHANGE_IDLE_FLAGS); + bitStream.Write(flagsOff != eAnimationFlags::IDLE_NONE); + if (flagsOff != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOff); + bitStream.Write(flagsOn != eAnimationFlags::IDLE_NONE); + if (flagsOn != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOn); + + SEND_PACKET_BROADCAST; +} // Mounts void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr) { @@ -3907,7 +4070,7 @@ void GameMessages::HandleDismountComplete(RakNet::BitStream* inStream, Entity* e EntityManager::Instance()->SerializeEntity(entity); // We aren't mounted so remove the stun - GameMessages::SendSetStunned(entity->GetObjectID(), eStunState::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + GameMessages::SendSetStunned(entity->GetObjectID(), eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); } } } @@ -4245,6 +4408,36 @@ void GameMessages::SendRacingResetPlayerToLastReset(LWOOBJID objectId, LWOOBJID SEND_PACKET; } +void GameMessages::SendVehicleStopBoost(Entity* targetEntity, const SystemAddress& playerSysAddr, bool affectPassive) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(targetEntity->GetObjectID()); + bitStream.Write(GAME_MSG::GAME_MSG_VEHICLE_STOP_BOOST); + + bitStream.Write(affectPassive); + + SEND_PACKET_BROADCAST; +} + +void GameMessages::SendSetResurrectRestoreValues(Entity* targetEntity, int32_t armorRestore, int32_t healthRestore, int32_t imaginationRestore) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(targetEntity->GetObjectID()); + bitStream.Write(GAME_MSG::GAME_MSG_SET_RESURRECT_RESTORE_VALUES); + + bitStream.Write(armorRestore != -1); + if (armorRestore != -1) bitStream.Write(armorRestore); + + bitStream.Write(healthRestore != -1); + if (healthRestore != -1) bitStream.Write(healthRestore); + + bitStream.Write(imaginationRestore != -1); + if (imaginationRestore != -1) bitStream.Write(imaginationRestore); + + SEND_PACKET_BROADCAST; +} void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, int32_t param1, LWOOBJID paramObj, std::u16string paramStr, LWOOBJID singleClient, const SystemAddress& sysAddr) { CBITSTREAM; @@ -4398,13 +4591,13 @@ void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uin // NT void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - bool bAllowPartial; + bool bAllowPartial{}; int32_t destSlot = -1; int32_t iStackCount = 1; eInventoryType invTypeDst = ITEMS; eInventoryType invTypeSrc = ITEMS; LWOOBJID itemID = LWOOBJID_EMPTY; - bool showFlyingLoot; + bool showFlyingLoot{}; LWOOBJID subkey = LWOOBJID_EMPTY; LOT itemLOT = 0; @@ -4428,12 +4621,12 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* if (itemID != LWOOBJID_EMPTY) { auto* item = inventoryComponent->FindItemById(itemID); - if (item == nullptr) { - return; - } + if (!item) return; - if (inventoryComponent->IsPet(item->GetSubKey()) || !item->GetConfig().empty()) { - return; + // Despawn the pet if we are moving that pet to the vault. + auto* petComponent = PetComponent::GetActivePet(entity->GetObjectID()); + if (petComponent && petComponent->GetDatabaseId() == item->GetSubKey()) { + inventoryComponent->DespawnPet(); } inventoryComponent->MoveItemToInventory(item, invTypeDst, iStackCount, showFlyingLoot, false, false, destSlot); @@ -4515,7 +4708,7 @@ void GameMessages::HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* enti Entity* player = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!player) return; - auto* propertyVendorComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_PROPERTY_VENDOR)); + auto* propertyVendorComponent = static_cast(entity->GetComponent(eReplicaComponentType::PROPERTY_VENDOR)); if (propertyVendorComponent != nullptr) { propertyVendorComponent->OnBuyFromVendor(player, bConfirmed, item, count); @@ -4525,16 +4718,16 @@ void GameMessages::HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* enti const auto isCommendationVendor = entity->GetLOT() == 13806; - VendorComponent* vend = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); + VendorComponent* vend = static_cast(entity->GetComponent(eReplicaComponentType::VENDOR)); if (!vend && !isCommendationVendor) return; - InventoryComponent* inv = static_cast(player->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable("ItemComponent"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable(); - int itemCompID = compRegistryTable->GetByIDAndType(item, COMPONENT_TYPE_ITEM); + int itemCompID = compRegistryTable->GetByIDAndType(item, eReplicaComponentType::ITEM); CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); Character* character = player->GetCharacter(); @@ -4559,25 +4752,10 @@ void GameMessages::HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* enti LOT tokenId = -1; - if (missionComponent->GetMissionState(545) == MissionState::MISSION_STATE_COMPLETE) // "Join Assembly!" - { - tokenId = 8318; // "Assembly Token" - } - - if (missionComponent->GetMissionState(556) == MissionState::MISSION_STATE_COMPLETE) // "Join Venture League!" - { - tokenId = 8321; // "Venture League Token" - } - - if (missionComponent->GetMissionState(567) == MissionState::MISSION_STATE_COMPLETE) // "Join The Sentinels!" - { - tokenId = 8319; // "Sentinels Token" - } - - if (missionComponent->GetMissionState(578) == MissionState::MISSION_STATE_COMPLETE) // "Join Paradox!" - { - tokenId = 8320; // "Paradox Token" - } + if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) tokenId = 8318; // "Assembly Token" + if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) tokenId = 8321; // "Venture League Token" + if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) tokenId = 8319; // "Sentinels Token" + if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) tokenId = 8320; // "Paradox Token" const uint32_t altCurrencyCost = itemComp.commendationCost * count; @@ -4629,19 +4807,19 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit if (!player) return; Character* character = player->GetCharacter(); if (!character) return; - InventoryComponent* inv = static_cast(player->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; - VendorComponent* vend = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); + VendorComponent* vend = static_cast(entity->GetComponent(eReplicaComponentType::VENDOR)); if (!vend) return; Item* item = inv->FindItemById(iObjID); if (!item) return; - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable("ItemComponent"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable(); - int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), COMPONENT_TYPE_ITEM); + int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), eReplicaComponentType::ITEM); CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); // Items with a base value of 0 or max int are special items that should not be sold if they're not sub items @@ -4649,13 +4827,13 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit float sellScalar = vend->GetSellScalar(); if (Inventory::IsValidItem(itemComp.currencyLOT)) { - const auto altCurrency = (itemComp.altCurrencyCost * sellScalar) * count; + const auto altCurrency = static_cast(itemComp.altCurrencyCost * sellScalar) * count; inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::LOOT_SOURCE_VENDOR); // Return alt currencies like faction tokens. } //inv->RemoveItem(count, -1, iObjID); inv->MoveItemToInventory(item, eInventoryType::VENDOR_BUYBACK, count, true, false, true); - character->SetCoins(std::floor(character->GetCoins() + ((itemComp.baseValue * sellScalar) * count)), eLootSourceType::LOOT_SOURCE_VENDOR); + character->SetCoins(std::floor(character->GetCoins() + (static_cast(itemComp.baseValue * sellScalar) * count)), eLootSourceType::LOOT_SOURCE_VENDOR); //EntityManager::Instance()->SerializeEntity(player); // so inventory updates GameMessages::SendVendorTransactionResult(entity, sysAddr); } @@ -4679,19 +4857,19 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* if (!player) return; Character* character = player->GetCharacter(); if (!character) return; - InventoryComponent* inv = static_cast(player->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; - VendorComponent* vend = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); + VendorComponent* vend = static_cast(entity->GetComponent(eReplicaComponentType::VENDOR)); if (!vend) return; Item* item = inv->FindItemById(iObjID); if (!item) return; - CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable("ItemComponent"); + CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable(); - int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), COMPONENT_TYPE_ITEM); + int itemCompID = compRegistryTable->GetByIDAndType(item->GetLot(), eReplicaComponentType::ITEM); CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); float sellScalar = vend->GetSellScalar(); @@ -4833,7 +5011,7 @@ void GameMessages::HandleRebuildCancel(RakNet::BitStream* inStream, Entity* enti inStream->Read(bEarlyRelease); inStream->Read(userID); - RebuildComponent* rebComp = static_cast(entity->GetComponent(COMPONENT_TYPE_REBUILD)); + RebuildComponent* rebComp = static_cast(entity->GetComponent(eReplicaComponentType::QUICK_BUILD)); if (!rebComp) return; rebComp->CancelRebuild(EntityManager::Instance()->GetEntity(userID), eFailReason::REASON_CANCELED_EARLY); @@ -4866,7 +5044,7 @@ void GameMessages::HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, if (bIsMultiInteractUse) { if (multiInteractType == 0) { - auto* missionOfferComponent = static_cast(interactedObject->GetComponent(COMPONENT_TYPE_MISSION_OFFER)); + auto* missionOfferComponent = static_cast(interactedObject->GetComponent(eReplicaComponentType::MISSION_OFFER)); if (missionOfferComponent != nullptr) { missionOfferComponent->OfferMissions(entity, multiInteractID); @@ -4879,12 +5057,12 @@ void GameMessages::HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, } //Perform use task if possible: - auto missionComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto missionComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MISSION_INTERACTION, interactedObject->GetLOT(), interactedObject->GetObjectID()); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_NON_MISSION_INTERACTION, interactedObject->GetLOT(), interactedObject->GetObjectID()); + missionComponent->Progress(eMissionTaskType::TALK_TO_NPC, interactedObject->GetLOT(), interactedObject->GetObjectID()); + missionComponent->Progress(eMissionTaskType::INTERACT, interactedObject->GetLOT(), interactedObject->GetObjectID()); } void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) { @@ -4894,28 +5072,28 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) inStream->Read(emoteID); inStream->Read(targetID); - Game::logger->Log("GameMessages", "Emote (%i) (%llu)", emoteID, targetID); + Game::logger->LogDebug("GameMessages", "Emote (%i) (%llu)", emoteID, targetID); //TODO: If targetID != 0, and we have one of the "perform emote" missions, complete them. if (emoteID == 0) return; std::string sAnimationName = "deaded"; //Default name in case we fail to get the emote - MissionComponent* mission = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); - if (mission) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_EMOTE, emoteID, targetID); - } + MissionComponent* missionComponent = entity->GetComponent(); + if (!missionComponent) return; if (targetID != LWOOBJID_EMPTY) { auto* targetEntity = EntityManager::Instance()->GetEntity(targetID); - Game::logger->Log("GameMessages", "Emote target found (%d)", targetEntity != nullptr); + Game::logger->LogDebug("GameMessages", "Emote target found (%d)", targetEntity != nullptr); if (targetEntity != nullptr) { targetEntity->OnEmoteReceived(emoteID, entity); + missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, targetID); } } else { - const auto scriptedEntities = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPT); + Game::logger->LogDebug("GameMessages", "Target ID is empty, using backup"); + const auto scriptedEntities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); const auto& referencePoint = entity->GetPosition(); @@ -4923,10 +5101,11 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) if (Vector3::DistanceSquared(scripted->GetPosition(), referencePoint) > 5.0f * 5.0f) continue; scripted->OnEmoteReceived(emoteID, entity); + missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, scripted->GetObjectID()); } } - CDEmoteTableTable* emotes = CDClientManager::Instance()->GetTable("EmoteTable"); + CDEmoteTableTable* emotes = CDClientManager::Instance().GetTable(); if (emotes) { CDEmoteTable* emote = emotes->GetEmote(emoteID); if (emote) sAnimationName = emote->animationName; @@ -4944,7 +5123,7 @@ void GameMessages::HandleModularBuildConvertModel(RakNet::BitStream* inStream, E if (!user) return; Entity* character = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!character) return; - InventoryComponent* inv = static_cast(character->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(modelID); @@ -4987,7 +5166,7 @@ void GameMessages::HandleRespondToMission(RakNet::BitStream* inStream, Entity* e inStream->Read(isDefaultReward); if (isDefaultReward) inStream->Read(reward); - MissionComponent* missionComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* missionComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (!missionComponent) { Game::logger->Log("GameMessages", "Unable to get mission component for entity %llu to handle RespondToMission", playerID); return; @@ -5014,7 +5193,7 @@ void GameMessages::HandleRespondToMission(RakNet::BitStream* inStream, Entity* e void GameMessages::HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* entity) { bool bIsComplete{}; - MissionState iMissionState{}; + eMissionState iMissionState{}; int missionID{}; LWOOBJID responder{}; Entity* player = nullptr; @@ -5030,15 +5209,15 @@ void GameMessages::HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* en } // Get the player's mission component - MissionComponent* missionComponent = static_cast(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* missionComponent = static_cast(player->GetComponent(eReplicaComponentType::MISSION)); if (!missionComponent) { Game::logger->Log("GameMessages", "Unable to get mission component for entity %llu to handle MissionDialogueOK", player->GetObjectID()); return; } - if (iMissionState == MissionState::MISSION_STATE_AVAILABLE || iMissionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE) { + if (iMissionState == eMissionState::AVAILABLE || iMissionState == eMissionState::COMPLETE_AVAILABLE) { missionComponent->AcceptMission(missionID); - } else if (iMissionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || iMissionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { + } else if (iMissionState == eMissionState::READY_TO_COMPLETE || iMissionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { missionComponent->CompleteMission(missionID); } } @@ -5054,7 +5233,7 @@ void GameMessages::HandleRequestLinkedMission(RakNet::BitStream* inStream, Entit auto* player = EntityManager::Instance()->GetEntity(playerId); - auto* missionOfferComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION_OFFER)); + auto* missionOfferComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION_OFFER)); if (missionOfferComponent != nullptr) { missionOfferComponent->OfferMissions(player, 0); @@ -5068,9 +5247,9 @@ void GameMessages::HandleHasBeenCollected(RakNet::BitStream* inStream, Entity* e Entity* player = EntityManager::Instance()->GetEntity(playerID); if (!player || !entity || entity->GetCollectibleID() == 0) return; - MissionComponent* missionComponent = static_cast(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* missionComponent = static_cast(player->GetComponent(eReplicaComponentType::MISSION)); if (missionComponent) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT, entity->GetLOT(), entity->GetObjectID()); + missionComponent->Progress(eMissionTaskType::COLLECTION, entity->GetLOT(), entity->GetObjectID()); } } @@ -5171,7 +5350,7 @@ void GameMessages::HandleEquipItem(RakNet::BitStream* inStream, Entity* entity) inStream->Read(immediate); //twice? inStream->Read(objectID); - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; Item* item = inv->FindItemById(objectID); @@ -5190,7 +5369,7 @@ void GameMessages::HandleUnequipItem(RakNet::BitStream* inStream, Entity* entity inStream->Read(immediate); inStream->Read(objectID); - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(objectID); @@ -5265,7 +5444,7 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream* inStream, En inStream->Read(iTradeIDIsDefault); if (iTradeIDIsDefault) inStream->Read(iTradeID); - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(iObjID); @@ -5289,7 +5468,7 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream* inStream, En auto* missionComponent = entity->GetComponent(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, item->GetLot(), LWOOBJID_EMPTY, "", -iStackCount); + missionComponent->Progress(eMissionTaskType::GATHER, item->GetLot(), LWOOBJID_EMPTY, "", -iStackCount); } } } @@ -5308,7 +5487,7 @@ void GameMessages::HandleMoveItemInInventory(RakNet::BitStream* inStream, Entity inStream->Read(responseCode); inStream->Read(slot); - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(iObjID); @@ -5385,7 +5564,7 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* if (!user) return; Entity* character = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!character) return; - InventoryComponent* inv = static_cast(character->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; Game::logger->Log("GameMessages", "Build finished"); @@ -5402,7 +5581,8 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* auto* temp = inv->GetInventory(TEMP_MODELS); std::vector modList; - + auto& oldPartList = character->GetVar(u"currentModifiedBuild"); + bool everyPieceSwapped = !oldPartList.empty(); // If the player didn't put a build in initially, then they should not get this achievement. if (count >= 3) { std::u16string modules; @@ -5410,7 +5590,8 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* uint32_t mod; inStream->Read(mod); modList.push_back(mod); - modules += u"1:" + (GeneralUtils::to_u16string(mod)); + auto modToStr = GeneralUtils::to_u16string(mod); + modules += u"1:" + (modToStr); if (k + 1 != count) modules += u"+"; if (temp->GetLotCount(mod) > 0) { @@ -5418,6 +5599,13 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* } else { inv->RemoveItem(mod, 1); } + + // Doing this check for 1 singular mission that needs to know when you've swapped every part out during a car modular build. + // since all 8129's are the same, skip checking that + if (mod != 8129) { + if (oldPartList.find(GeneralUtils::UTF16ToWTF8(modToStr)) != std::string::npos) everyPieceSwapped = false; + + } } const auto moduleAssembly = new LDFData(u"assemblyPartLOTs", modules); @@ -5435,12 +5623,13 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* if (entity->GetLOT() != 9980 || Game::server->GetZoneID() != 1200) { if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, entity->GetLOT(), entity->GetObjectID()); + missionComponent->Progress(eMissionTaskType::SCRIPT, entity->GetLOT(), entity->GetObjectID()); + if (count >= 7 && everyPieceSwapped) missionComponent->Progress(eMissionTaskType::RACING, LWOOBJID_EMPTY, (LWOOBJID)eRacingTaskParam::MODULAR_BUILDING); } } } - ScriptComponent* script = static_cast(entity->GetComponent(COMPONENT_TYPE_SCRIPT)); + ScriptComponent* script = static_cast(entity->GetComponent(eReplicaComponentType::SCRIPT)); for (CppScripts::Script* script : CppScripts::GetEntityScripts(entity)) { script->OnModularBuildExit(entity, character, count >= 3, modList); @@ -5463,7 +5652,7 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti if (!user) return; Entity* character = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); if (!character) return; - InventoryComponent* inv = static_cast(character->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; /** @@ -5514,7 +5703,7 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti */ if (PropertyManagementComponent::Instance() != nullptr) { - const auto& buildAreas = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_BUILD_BORDER); + const auto& buildAreas = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::BUILD_BORDER); const auto& entities = EntityManager::Instance()->GetEntitiesInGroup("PropertyPlaque"); @@ -5581,7 +5770,7 @@ void GameMessages::HandleModularBuildMoveAndEquip(RakNet::BitStream* inStream, E inStream->Read(templateID); - InventoryComponent* inv = static_cast(character->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemByLot(templateID, TEMP_MODELS); @@ -5622,7 +5811,7 @@ void GameMessages::HandleResurrect(RakNet::BitStream* inStream, Entity* entity) script->OnPlayerResurrected(zoneControl, entity); } - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { @@ -5633,13 +5822,13 @@ void GameMessages::HandleResurrect(RakNet::BitStream* inStream, Entity* entity) } void GameMessages::HandlePushEquippedItemsState(RakNet::BitStream* inStream, Entity* entity) { - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; inv->PushEquippedItems(); } void GameMessages::HandlePopEquippedItemsState(RakNet::BitStream* inStream, Entity* entity) { - InventoryComponent* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; inv->PopEquippedItems(); EntityManager::Instance()->SerializeEntity(entity); // so it updates on client side @@ -5651,23 +5840,23 @@ void GameMessages::HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* inStream->Read(itemConsumed); - auto* inventory = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto* inventory = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (inventory == nullptr) { return; } auto* item = inventory->FindItemById(itemConsumed); - if (item == nullptr) { return; } + LOT itemLot = item->GetLot(); item->Consume(); - auto* missions = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto* missions = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (missions != nullptr) { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_FOOD, item->GetLot()); + missions->Progress(eMissionTaskType::USE_ITEM, itemLot); } } @@ -5677,17 +5866,13 @@ void GameMessages::HandleUseNonEquipmentItem(RakNet::BitStream* inStream, Entity inStream->Read(itemConsumed); - auto* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; auto* item = inv->FindItemById(itemConsumed); - if (item == nullptr) { - return; - } - - item->UseNonEquip(); + if (item) item->UseNonEquip(item); } void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entity) { @@ -5712,11 +5897,11 @@ void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entit inStream->Read(type); inStream->Read(value); - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY); + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); if (type == 0) { // join if (value != 0) { for (Entity* scriptedAct : scriptedActs) { - ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY)); + ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY)); if (!comp) continue; if (comp->GetActivityID() == value) { comp->PlayerJoin(entity); @@ -5727,7 +5912,7 @@ void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entit } } else if (type == 1) { // ready/unready for (Entity* scriptedAct : scriptedActs) { - ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(COMPONENT_TYPE_SCRIPTED_ACTIVITY)); + ScriptedActivityComponent* comp = static_cast(scriptedAct->GetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY)); if (!comp) continue; if (comp->PlayerIsInQueue(entity)) { comp->PlayerReady(entity, value); @@ -5845,7 +6030,7 @@ void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) void GameMessages::HandleClientRailMovementReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_RAIL_ACTIVATOR); + const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); for (const auto* possibleRail : possibleRails) { const auto* rail = possibleRail->GetComponent(); if (rail != nullptr) { @@ -5857,7 +6042,7 @@ GameMessages::HandleClientRailMovementReady(RakNet::BitStream* inStream, Entity* void GameMessages::HandleCancelRailMovement(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { const auto immediate = inStream->ReadBit(); - const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_RAIL_ACTIVATOR); + const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); for (const auto* possibleRail : possibleRails) { auto* rail = possibleRail->GetComponent(); if (rail != nullptr) { @@ -5881,7 +6066,7 @@ void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream* inStre int32_t waypointNumber; inStream->Read(waypointNumber); - const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_RAIL_ACTIVATOR); + const auto possibleRails = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); for (auto* possibleRail : possibleRails) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(possibleRail)) { script->OnPlayerRailArrived(possibleRail, entity, pathName, waypointNumber); @@ -5930,3 +6115,79 @@ void GameMessages::HandleUpdatePlayerStatistic(RakNet::BitStream* inStream, Enti characterComponent->UpdatePlayerStatistic((StatisticID)updateID, (uint64_t)std::max(updateValue, int64_t(0))); } } + +void GameMessages::HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity) { + auto controllablePhysicsComponent = entity->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->DeactivateBubbleBuff(); +} + +void GameMessages::HandleActivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity) { + bool specialAnimations; + if (!inStream->Read(specialAnimations)) return; + + std::u16string type = GeneralUtils::ReadWString(inStream); + auto bubbleType = eBubbleType::DEFAULT; + if (type == u"skunk") bubbleType = eBubbleType::SKUNK; + else if (type == u"energy") bubbleType = eBubbleType::ENERGY; + + auto controllablePhysicsComponent = entity->GetComponent(); + if (controllablePhysicsComponent) controllablePhysicsComponent->ActivateBubbleBuff(bubbleType, specialAnimations); +} + +void GameMessages::SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_ACTIVATE_BUBBLE_BUFF_FROM_SERVER); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_DEACTIVATE_BUBBLE_BUFF_FROM_SERVER); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; +} + +void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity) { + LWOOBJID player_id; + inStream->Read(player_id); + auto target = EntityManager::Instance()->GetEntity(player_id); + entity->TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, target); +}; + +void GameMessages::SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_SET_NAME_BILLBOARD_STATE); + + // Technically these bits would be written, however the client does not + // contain a deserialize method to actually deserialize, so we are leaving it out. + // As such this GM only turns the billboard off. + + // bitStream.Write(overrideDefault); + // bitStream.Write(state); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + else SEND_PACKET +} + +void GameMessages::SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(GAME_MSG::GAME_MSG_SHOW_BILLBOARD_INTERACT_ICON); + + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST + else SEND_PACKET +} diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 31bdebb3..68f4542f 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -1,25 +1,28 @@ - #ifndef GAMEMESSAGES_H #define GAMEMESSAGES_H #include "dCommonVars.h" -#include "RakNetTypes.h" +#include #include -#include "InventoryComponent.h" -#include "dMessageIdentifiers.h" -#include "AMFFormat.h" -#include "AMFFormat_BitStream.h" -#include "NiQuaternion.h" -#include "PropertySelectQueryProperty.h" -#include "TradingManager.h" -#include "LeaderboardManager.h" -#include "MovingPlatformComponent.h" +#include +#include "eMovementPlatformState.h" +#include "NiPoint3.h" +#include "eEndBehavior.h" +class AMFValue; +class Entity; +class Item; class NiQuaternion; class User; -class Entity; -class NiPoint3; +class Leaderboard; +class PropertySelectQueryProperty; +class TradeItem; + +enum class eAnimationFlags : uint32_t; + enum class eUnequippableActiveType; +enum eInventoryType : uint32_t; +enum class eGameMasterLevel : uint8_t; namespace GameMessages { class PropertyDataMessage; @@ -30,7 +33,8 @@ namespace GameMessages { void SendPlayerAllowedRespawn(LWOOBJID entityID, bool doNotPromptRespawn, const SystemAddress& systemAddress); void SendInvalidZoneTransferList(Entity* entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer); void SendKnockback(const LWOOBJID& objectID, const LWOOBJID& caster, const LWOOBJID& originator, int knockBackTimeMS, const NiPoint3& vector); - + // https://lcdruniverse.org/lu_packets/lu_packets/world/gm/client/struct.VehicleStopBoost.html + void SendVehicleStopBoost(Entity* targetEntity, const SystemAddress& playerSysAddr, bool affectPassive); void SendStartArrangingWithItem( Entity* entity, const SystemAddress& sysAddr, @@ -55,12 +59,12 @@ namespace GameMessages { void SendStartPathing(Entity* entity); void SendPlatformResync(Entity* entity, const SystemAddress& sysAddr, bool bStopAtDesiredWaypoint = false, int iIndex = 0, int iDesiredWaypointIndex = 1, int nextIndex = 1, - MovementPlatformState movementState = MovementPlatformState::Moving); + eMovementPlatformState movementState = eMovementPlatformState::Moving); void SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr); void SendServerDoneLoadingAllObjects(Entity* entity, const SystemAddress& sysAddr); - void SendGMLevelBroadcast(const LWOOBJID& objectID, uint8_t level); - void SendChatModeUpdate(const LWOOBJID& objectID, uint8_t level); + void SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLevel level); + void SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel level); void SendAddItemToInventoryClientSync(Entity* entity, const SystemAddress& sysAddr, Item* item, const LWOOBJID& objectID, bool showFlyingLoot, int itemCount, LWOOBJID subKey = LWOOBJID_EMPTY, eLootSourceType lootSourceType = eLootSourceType::LOOT_SOURCE_NONE); void SendNotifyClientFlagChange(const LWOOBJID& objectID, int iFlagID, bool bFlag, const SystemAddress& sysAddr); @@ -72,8 +76,8 @@ namespace GameMessages { void NotifyLevelRewards(LWOOBJID objectID, const SystemAddress& sysAddr, int level, bool sending_rewards); void SendModifyLEGOScore(Entity* entity, const SystemAddress& sysAddr, int64_t score, eLootSourceType sourceType); - void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, NDGFxValue args); - void SendUIMessageServerToAllClients(const std::string& message, NDGFxValue args); + void SendUIMessageServerToSingleClient(Entity* entity, const SystemAddress& sysAddr, const std::string& message, AMFValue* args); + void SendUIMessageServerToAllClients(const std::string& message, AMFValue* args); void SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, std::u16string effectName, const LWOOBJID& fromObjectID, float radius); void SendPlayFXEffect(Entity* entity, int32_t effectID, const std::u16string& effectType, const std::string& name, LWOOBJID secondary, float priority = 1, float scale = 1, bool serialize = true); @@ -121,8 +125,12 @@ namespace GameMessages { void SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response); void SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, int type); + void HandleUnUseModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID); + // https://lcdruniverse.org/lu_packets/lu_packets/world/gm/client/struct.SetResurrectRestoreValues.html + void SendSetResurrectRestoreValues(Entity* targetEntity, int32_t armorRestore, int32_t healthRestore, int32_t imaginationRestore); + /** * Sends a message to an Entity to smash itself, but not delete or destroy itself from the world * @@ -197,6 +205,16 @@ namespace GameMessages { void SendDownloadPropertyData(LWOOBJID objectId, const PropertyDataMessage& data, const SystemAddress& sysAddr); + /** + * @brief Send an updated item id to the client when they load a blueprint in brick build mode + * + * @param sysAddr SystemAddress to respond to + * @param oldItemId The item ID that was requested to be loaded + * @param newItemId The new item ID of the loaded item + * + */ + void SendBlueprintLoadItemResponse(const SystemAddress& sysAddr, bool success, LWOOBJID oldItemId, LWOOBJID newItemId); + void SendPropertyRentalResponse(LWOOBJID objectId, LWOCLONEID cloneId, uint32_t code, LWOOBJID propertyId, int64_t rentDue, const SystemAddress& sysAddr); void SendLockNodeRotation(Entity* entity, std::string nodeName); @@ -249,14 +267,14 @@ namespace GameMessages { void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, bool allowGhostUpdates = true, bool bCloseMultiInteract = true, bool bSendServerNotify = false, bool bUseControlledObjectForAudioListener = false, - int endBehavior = 0, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false, + eEndBehavior endBehavior = eEndBehavior::RETURN, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false, bool lockPlayer = true, bool result = false, bool skipIfSamePath = false, float startTimeAdvance = 0); void SendEndCinematic(LWOOBJID objectID, std::u16string pathName, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, float leadOut = -1.0f, bool leavePlayerLocked = false); void HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, const SystemAddress& sysAddr, + void SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, LWOOBJID originator = LWOOBJID_EMPTY, bool bCantAttack = false, bool bCantEquip = false, bool bCantInteract = false, bool bCantJump = false, bool bCantMove = false, bool bCantTurn = false, bool bCantUseItem = false, bool bDontTerminateInteract = false, bool bIgnoreImmunity = true, @@ -265,6 +283,35 @@ namespace GameMessages { bool bCantMoveOutChangeWasApplied = false, bool bCantTurnOutChangeWasApplied = false, bool bCantUseItemOutChangeWasApplied = false); + void SendSetStunImmunity( + LWOOBJID target, + eStateChangeType state, + const SystemAddress& sysAddr, + LWOOBJID originator = LWOOBJID_EMPTY, + bool bImmuneToStunAttack = false, + bool bImmuneToStunEquip = false, + bool bImmuneToStunInteract = false, + bool bImmuneToStunJump = false, + bool bImmuneToStunMove = false, + bool bImmuneToStunTurn = false, + bool bImmuneToStunUseItem = false + ); + + void SendSetStatusImmunity( + LWOOBJID objectId, + eStateChangeType state, + const SystemAddress& sysAddr, + bool bImmuneToBasicAttack = false, + bool bImmuneToDamageOverTime = false, + bool bImmuneToKnockback = false, + bool bImmuneToInterrupt = false, + bool bImmuneToSpeed = false, + bool bImmuneToImaginationGain = false, + bool bImmuneToImaginationLoss = false, + bool bImmuneToQuickbuildInterrupt = false, + bool bImmuneToPullToPoint = false + ); + void SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr); void SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, uint32_t modifier, const SystemAddress& sysAddr); @@ -362,6 +409,15 @@ namespace GameMessages { void SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr); + /** + * @brief + * + * @param objectId ID of the entity to set idle flags + * @param FlagsOn Flag to turn on + * @param FlagsOff Flag to turn off + */ + void SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags FlagsOn, eAnimationFlags FlagsOff, const SystemAddress& sysAddr); + // Mounts /** * @brief Set the Inventory LWOOBJID of the mount @@ -520,6 +576,8 @@ namespace GameMessages { void HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId); + void SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId); void HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleSellToVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); @@ -566,549 +624,18 @@ namespace GameMessages { void HandleReportBug(RakNet::BitStream* inStream, Entity* entity); - /* Message to synchronize a skill cast */ - class EchoSyncSkill { - static const GAME_MSG MsgID = GAME_MSG_ECHO_SYNC_SKILL; + void SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId); - public: - EchoSyncSkill() { - bDone = false; - } + // bubble + void HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); - EchoSyncSkill(std::string _sBitStream, unsigned int _uiBehaviorHandle, unsigned int _uiSkillHandle, bool _bDone = false) { - bDone = _bDone; - sBitStream = _sBitStream; - uiBehaviorHandle = _uiBehaviorHandle; - uiSkillHandle = _uiSkillHandle; - } + void HandleActivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); - EchoSyncSkill(RakNet::BitStream* stream) { - bDone = false; + void SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); - Deserialize(stream); - } + void SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); - ~EchoSyncSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bDone); - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(uiBehaviorHandle); - stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bDone); - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(uiBehaviorHandle); - stream->Read(uiSkillHandle); - - return true; - } - - bool bDone{}; - std::string sBitStream{}; - unsigned int uiBehaviorHandle{}; - unsigned int uiSkillHandle{}; - }; - - /* Message to synchronize a skill cast */ - class SyncSkill { - static const GAME_MSG MsgID = GAME_MSG_SYNC_SKILL; - - public: - SyncSkill() { - bDone = false; - } - - SyncSkill(std::string _sBitStream, unsigned int _uiBehaviorHandle, unsigned int _uiSkillHandle, bool _bDone = false) { - bDone = _bDone; - sBitStream = _sBitStream; - uiBehaviorHandle = _uiBehaviorHandle; - uiSkillHandle = _uiSkillHandle; - } - - SyncSkill(RakNet::BitStream* stream) { - bDone = false; - Deserialize(stream); - } - - ~SyncSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bDone); - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(uiBehaviorHandle); - stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bDone); - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(uiBehaviorHandle); - stream->Read(uiSkillHandle); - - return true; - } - - bool bDone{}; - std::string sBitStream{}; - unsigned int uiBehaviorHandle{}; - unsigned int uiSkillHandle{}; - }; - - /* Notifying the server that a locally owned projectil impacted. Sent to the caster of the projectile - should always be the local char. */ - class RequestServerProjectileImpact { - static const GAME_MSG MsgID = GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT; - - public: - RequestServerProjectileImpact() { - i64LocalID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - } - - RequestServerProjectileImpact(std::string _sBitStream, LWOOBJID _i64LocalID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { - i64LocalID = _i64LocalID; - i64TargetID = _i64TargetID; - sBitStream = _sBitStream; - } - - RequestServerProjectileImpact(RakNet::BitStream* stream) { - i64LocalID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - - Deserialize(stream); - } - - ~RequestServerProjectileImpact() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(i64LocalID != LWOOBJID_EMPTY); - if (i64LocalID != LWOOBJID_EMPTY) stream->Write(i64LocalID); - - stream->Write(i64TargetID != LWOOBJID_EMPTY); - if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - } - - bool Deserialize(RakNet::BitStream* stream) { - bool i64LocalIDIsDefault{}; - stream->Read(i64LocalIDIsDefault); - if (i64LocalIDIsDefault != 0) stream->Read(i64LocalID); - - bool i64TargetIDIsDefault{}; - stream->Read(i64TargetIDIsDefault); - if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - - return true; - } - - LWOOBJID i64LocalID; - LWOOBJID i64TargetID; - std::string sBitStream; - }; - - /* Tell a client local projectile to impact */ - class DoClientProjectileImpact { - static const GAME_MSG MsgID = GAME_MSG_DO_CLIENT_PROJECTILE_IMPACT; - - public: - DoClientProjectileImpact() { - i64OrgID = LWOOBJID_EMPTY; - i64OwnerID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - } - - DoClientProjectileImpact(std::string _sBitStream, LWOOBJID _i64OrgID = LWOOBJID_EMPTY, LWOOBJID _i64OwnerID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { - i64OrgID = _i64OrgID; - i64OwnerID = _i64OwnerID; - i64TargetID = _i64TargetID; - sBitStream = _sBitStream; - } - - DoClientProjectileImpact(RakNet::BitStream* stream) { - i64OrgID = LWOOBJID_EMPTY; - i64OwnerID = LWOOBJID_EMPTY; - i64TargetID = LWOOBJID_EMPTY; - - Deserialize(stream); - } - - ~DoClientProjectileImpact() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(i64OrgID != LWOOBJID_EMPTY); - if (i64OrgID != LWOOBJID_EMPTY) stream->Write(i64OrgID); - - stream->Write(i64OwnerID != LWOOBJID_EMPTY); - if (i64OwnerID != LWOOBJID_EMPTY) stream->Write(i64OwnerID); - - stream->Write(i64TargetID != LWOOBJID_EMPTY); - if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - } - - bool Deserialize(RakNet::BitStream* stream) { - bool i64OrgIDIsDefault{}; - stream->Read(i64OrgIDIsDefault); - if (i64OrgIDIsDefault != 0) stream->Read(i64OrgID); - - bool i64OwnerIDIsDefault{}; - stream->Read(i64OwnerIDIsDefault); - if (i64OwnerIDIsDefault != 0) stream->Read(i64OwnerID); - - bool i64TargetIDIsDefault{}; - stream->Read(i64TargetIDIsDefault); - if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - - return true; - } - - LWOOBJID i64OrgID; - LWOOBJID i64OwnerID; - LWOOBJID i64TargetID; - std::string sBitStream; - }; - - /* Same as start skill but with different network options. An echo down to other clients that need to play the skill. */ - class EchoStartSkill { - static const GAME_MSG MsgID = GAME_MSG_ECHO_START_SKILL; - - public: - EchoStartSkill() { - bUsedMouse = false; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - } - - EchoStartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, float _fCasterLatency = 0.0f, int _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, unsigned int _uiSkillHandle = 0) { - bUsedMouse = _bUsedMouse; - fCasterLatency = _fCasterLatency; - iCastType = _iCastType; - lastClickedPosit = _lastClickedPosit; - optionalOriginatorID = _optionalOriginatorID; - optionalTargetID = _optionalTargetID; - originatorRot = _originatorRot; - sBitStream = _sBitStream; - skillID = _skillID; - uiSkillHandle = _uiSkillHandle; - } - - EchoStartSkill(RakNet::BitStream* stream) { - bUsedMouse = false; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - - Deserialize(stream); - } - - ~EchoStartSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bUsedMouse); - - stream->Write(fCasterLatency != 0.0f); - if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); - - stream->Write(iCastType != 0); - if (iCastType != 0) stream->Write(iCastType); - - stream->Write(lastClickedPosit != NiPoint3::ZERO); - if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); - - stream->Write(optionalOriginatorID); - - stream->Write(optionalTargetID != LWOOBJID_EMPTY); - if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); - - stream->Write(originatorRot != NiQuaternion::IDENTITY); - if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(skillID); - - stream->Write(uiSkillHandle != 0); - if (uiSkillHandle != 0) stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bUsedMouse); - - bool fCasterLatencyIsDefault{}; - stream->Read(fCasterLatencyIsDefault); - if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); - - bool iCastTypeIsDefault{}; - stream->Read(iCastTypeIsDefault); - if (iCastTypeIsDefault != 0) stream->Read(iCastType); - - bool lastClickedPositIsDefault{}; - stream->Read(lastClickedPositIsDefault); - if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); - - stream->Read(optionalOriginatorID); - - bool optionalTargetIDIsDefault{}; - stream->Read(optionalTargetIDIsDefault); - if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); - - bool originatorRotIsDefault{}; - stream->Read(originatorRotIsDefault); - if (originatorRotIsDefault != 0) stream->Read(originatorRot); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(skillID); - - bool uiSkillHandleIsDefault{}; - stream->Read(uiSkillHandleIsDefault); - if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); - - return true; - } - - bool bUsedMouse; - float fCasterLatency; - int iCastType; - NiPoint3 lastClickedPosit; - LWOOBJID optionalOriginatorID; - LWOOBJID optionalTargetID; - NiQuaternion originatorRot; - std::string sBitStream; - TSkillID skillID; - unsigned int uiSkillHandle; - }; - - /* Same as sync skill but with different network options. An echo down to other clients that need to play the skill. */ - class StartSkill { - static const GAME_MSG MsgID = GAME_MSG_START_SKILL; - - public: - StartSkill() { - bUsedMouse = false; - consumableItemID = LWOOBJID_EMPTY; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - } - - StartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, LWOOBJID _consumableItemID = LWOOBJID_EMPTY, float _fCasterLatency = 0.0f, int _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, unsigned int _uiSkillHandle = 0) { - bUsedMouse = _bUsedMouse; - consumableItemID = _consumableItemID; - fCasterLatency = _fCasterLatency; - iCastType = _iCastType; - lastClickedPosit = _lastClickedPosit; - optionalOriginatorID = _optionalOriginatorID; - optionalTargetID = _optionalTargetID; - originatorRot = _originatorRot; - sBitStream = _sBitStream; - skillID = _skillID; - uiSkillHandle = _uiSkillHandle; - } - - StartSkill(RakNet::BitStream* stream) { - bUsedMouse = false; - consumableItemID = LWOOBJID_EMPTY; - fCasterLatency = 0.0f; - iCastType = 0; - lastClickedPosit = NiPoint3::ZERO; - optionalTargetID = LWOOBJID_EMPTY; - originatorRot = NiQuaternion::IDENTITY; - uiSkillHandle = 0; - - Deserialize(stream); - } - - ~StartSkill() { - } - - void Serialize(RakNet::BitStream* stream) { - stream->Write((unsigned short)MsgID); - - stream->Write(bUsedMouse); - - stream->Write(consumableItemID != LWOOBJID_EMPTY); - if (consumableItemID != LWOOBJID_EMPTY) stream->Write(consumableItemID); - - stream->Write(fCasterLatency != 0.0f); - if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); - - stream->Write(iCastType != 0); - if (iCastType != 0) stream->Write(iCastType); - - stream->Write(lastClickedPosit != NiPoint3::ZERO); - if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); - - stream->Write(optionalOriginatorID); - - stream->Write(optionalTargetID != LWOOBJID_EMPTY); - if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); - - stream->Write(originatorRot != NiQuaternion::IDENTITY); - if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); - - uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); - } - - stream->Write(skillID); - - stream->Write(uiSkillHandle != 0); - if (uiSkillHandle != 0) stream->Write(uiSkillHandle); - } - - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bUsedMouse); - - bool consumableItemIDIsDefault{}; - stream->Read(consumableItemIDIsDefault); - if (consumableItemIDIsDefault != 0) stream->Read(consumableItemID); - - bool fCasterLatencyIsDefault{}; - stream->Read(fCasterLatencyIsDefault); - if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); - - bool iCastTypeIsDefault{}; - stream->Read(iCastTypeIsDefault); - if (iCastTypeIsDefault != 0) stream->Read(iCastType); - - bool lastClickedPositIsDefault{}; - stream->Read(lastClickedPositIsDefault); - if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); - - stream->Read(optionalOriginatorID); - - bool optionalTargetIDIsDefault{}; - stream->Read(optionalTargetIDIsDefault); - if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); - - bool originatorRotIsDefault{}; - stream->Read(originatorRotIsDefault); - if (originatorRotIsDefault != 0) stream->Read(originatorRot); - - uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); - for (unsigned int k = 0; k < sBitStreamLength; k++) { - unsigned char character; - stream->Read(character); - sBitStream.push_back(character); - } - - stream->Read(skillID); - - bool uiSkillHandleIsDefault{}; - stream->Read(uiSkillHandleIsDefault); - if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); - - return true; - } - - bool bUsedMouse = false; - LWOOBJID consumableItemID{}; - float fCasterLatency{}; - int iCastType{}; - NiPoint3 lastClickedPosit{}; - LWOOBJID optionalOriginatorID{}; - LWOOBJID optionalTargetID{}; - NiQuaternion originatorRot{}; - std::string sBitStream = ""; - TSkillID skillID = 0; - unsigned int uiSkillHandle = 0; - }; + void HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity); }; #endif // GAMEMESSAGES_H diff --git a/dGame/dGameMessages/PropertyDataMessage.cpp b/dGame/dGameMessages/PropertyDataMessage.cpp index e0b792ad..c3443f31 100644 --- a/dGame/dGameMessages/PropertyDataMessage.cpp +++ b/dGame/dGameMessages/PropertyDataMessage.cpp @@ -6,6 +6,8 @@ #include "dLogger.h" #include "CDClientManager.h" +#include "CDPropertyTemplateTable.h" + void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) const { stream.Write(0); // - property id @@ -101,8 +103,7 @@ void GameMessages::PropertyDataMessage::Serialize(RakNet::BitStream& stream) con } GameMessages::PropertyDataMessage::PropertyDataMessage(uint32_t mapID) { - const auto propertyTemplate = CDClientManager::Instance()-> - GetTable("PropertyTemplate")->GetByMapID(mapID); + const auto propertyTemplate = CDClientManager::Instance().GetTable()->GetByMapID(mapID); TemplateID = propertyTemplate.id; ZoneId = propertyTemplate.mapID; diff --git a/dGame/dGameMessages/RequestServerProjectileImpact.h b/dGame/dGameMessages/RequestServerProjectileImpact.h new file mode 100644 index 00000000..01426361 --- /dev/null +++ b/dGame/dGameMessages/RequestServerProjectileImpact.h @@ -0,0 +1,74 @@ +#ifndef __REQUESTSERVERPROJECTILEIMPACT__H__ +#define __REQUESTSERVERPROJECTILEIMPACT__H__ + +#include "dCommonVars.h" +#include "dMessageIdentifiers.h" + +/* Notifying the server that a locally owned projectile impacted. Sent to the caster of the projectile + should always be the local char. */ +class RequestServerProjectileImpact { + static const GAME_MSG MsgID = GAME_MSG_REQUEST_SERVER_PROJECTILE_IMPACT; + +public: + RequestServerProjectileImpact() { + i64LocalID = LWOOBJID_EMPTY; + i64TargetID = LWOOBJID_EMPTY; + } + + RequestServerProjectileImpact(std::string _sBitStream, LWOOBJID _i64LocalID = LWOOBJID_EMPTY, LWOOBJID _i64TargetID = LWOOBJID_EMPTY) { + i64LocalID = _i64LocalID; + i64TargetID = _i64TargetID; + sBitStream = _sBitStream; + } + + RequestServerProjectileImpact(RakNet::BitStream* stream) : RequestServerProjectileImpact() { + Deserialize(stream); + } + + ~RequestServerProjectileImpact() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(i64LocalID != LWOOBJID_EMPTY); + if (i64LocalID != LWOOBJID_EMPTY) stream->Write(i64LocalID); + + stream->Write(i64TargetID != LWOOBJID_EMPTY); + if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + } + + bool Deserialize(RakNet::BitStream* stream) { + bool i64LocalIDIsDefault{}; + stream->Read(i64LocalIDIsDefault); + if (i64LocalIDIsDefault != 0) stream->Read(i64LocalID); + + bool i64TargetIDIsDefault{}; + stream->Read(i64TargetIDIsDefault); + if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + + return true; + } + + LWOOBJID i64LocalID; + LWOOBJID i64TargetID; + std::string sBitStream; +}; + +#endif //!__REQUESTSERVERPROJECTILEIMPACT__H__ diff --git a/dGame/dGameMessages/StartSkill.h b/dGame/dGameMessages/StartSkill.h new file mode 100644 index 00000000..af82a9b4 --- /dev/null +++ b/dGame/dGameMessages/StartSkill.h @@ -0,0 +1,144 @@ +#ifndef __STARTSKILL__H__ +#define __STARTSKILL__H__ + +#include "dCommonVars.h" +#include "dMessageIdentifiers.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" + +/** + * Same as sync skill but with different network options. An echo down to other clients that need to play the skill. + */ +class StartSkill { + static const GAME_MSG MsgID = GAME_MSG_START_SKILL; + +public: + StartSkill() { + bUsedMouse = false; + consumableItemID = LWOOBJID_EMPTY; + fCasterLatency = 0.0f; + iCastType = 0; + lastClickedPosit = NiPoint3::ZERO; + optionalTargetID = LWOOBJID_EMPTY; + originatorRot = NiQuaternion::IDENTITY; + uiSkillHandle = 0; + } + + StartSkill(LWOOBJID _optionalOriginatorID, std::string _sBitStream, TSkillID _skillID, bool _bUsedMouse = false, LWOOBJID _consumableItemID = LWOOBJID_EMPTY, float _fCasterLatency = 0.0f, int32_t _iCastType = 0, NiPoint3 _lastClickedPosit = NiPoint3::ZERO, LWOOBJID _optionalTargetID = LWOOBJID_EMPTY, NiQuaternion _originatorRot = NiQuaternion::IDENTITY, uint32_t _uiSkillHandle = 0) { + bUsedMouse = _bUsedMouse; + consumableItemID = _consumableItemID; + fCasterLatency = _fCasterLatency; + iCastType = _iCastType; + lastClickedPosit = _lastClickedPosit; + optionalOriginatorID = _optionalOriginatorID; + optionalTargetID = _optionalTargetID; + originatorRot = _originatorRot; + sBitStream = _sBitStream; + skillID = _skillID; + uiSkillHandle = _uiSkillHandle; + } + + StartSkill(RakNet::BitStream* stream) : StartSkill() { + Deserialize(stream); + } + + ~StartSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(bUsedMouse); + + stream->Write(consumableItemID != LWOOBJID_EMPTY); + if (consumableItemID != LWOOBJID_EMPTY) stream->Write(consumableItemID); + + stream->Write(fCasterLatency != 0.0f); + if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); + + stream->Write(iCastType != 0); + if (iCastType != 0) stream->Write(iCastType); + + stream->Write(lastClickedPosit != NiPoint3::ZERO); + if (lastClickedPosit != NiPoint3::ZERO) stream->Write(lastClickedPosit); + + stream->Write(optionalOriginatorID); + + stream->Write(optionalTargetID != LWOOBJID_EMPTY); + if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); + + stream->Write(originatorRot != NiQuaternion::IDENTITY); + if (originatorRot != NiQuaternion::IDENTITY) stream->Write(originatorRot); + + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(skillID); + + stream->Write(uiSkillHandle != 0); + if (uiSkillHandle != 0) stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bUsedMouse); + + bool consumableItemIDIsDefault{}; + stream->Read(consumableItemIDIsDefault); + if (consumableItemIDIsDefault != 0) stream->Read(consumableItemID); + + bool fCasterLatencyIsDefault{}; + stream->Read(fCasterLatencyIsDefault); + if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); + + bool iCastTypeIsDefault{}; + stream->Read(iCastTypeIsDefault); + if (iCastTypeIsDefault != 0) stream->Read(iCastType); + + bool lastClickedPositIsDefault{}; + stream->Read(lastClickedPositIsDefault); + if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); + + stream->Read(optionalOriginatorID); + + bool optionalTargetIDIsDefault{}; + stream->Read(optionalTargetIDIsDefault); + if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); + + bool originatorRotIsDefault{}; + stream->Read(originatorRotIsDefault); + if (originatorRotIsDefault != 0) stream->Read(originatorRot); + + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(skillID); + + bool uiSkillHandleIsDefault{}; + stream->Read(uiSkillHandleIsDefault); + if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); + + return true; + } + + bool bUsedMouse = false; + LWOOBJID consumableItemID{}; + float fCasterLatency{}; + int32_t iCastType{}; + NiPoint3 lastClickedPosit{}; + LWOOBJID optionalOriginatorID{}; + LWOOBJID optionalTargetID{}; + NiQuaternion originatorRot{}; + std::string sBitStream = ""; + TSkillID skillID = 0; + uint32_t uiSkillHandle = 0; +}; + +#endif //!__STARTSKILL__H__ diff --git a/dGame/dGameMessages/SyncSkill.h b/dGame/dGameMessages/SyncSkill.h new file mode 100644 index 00000000..72a88839 --- /dev/null +++ b/dGame/dGameMessages/SyncSkill.h @@ -0,0 +1,68 @@ +#ifndef __SYNCSKILL__H__ +#define __SYNCSKILL__H__ + +#include +#include + +#include "BitStream.h" + +/* Message to synchronize a skill cast */ +class SyncSkill { + static const GAME_MSG MsgID = GAME_MSG_SYNC_SKILL; + +public: + SyncSkill() { + bDone = false; + } + + SyncSkill(std::string _sBitStream, uint32_t _uiBehaviorHandle, uint32_t _uiSkillHandle, bool _bDone = false) { + bDone = _bDone; + sBitStream = _sBitStream; + uiBehaviorHandle = _uiBehaviorHandle; + uiSkillHandle = _uiSkillHandle; + } + + SyncSkill(RakNet::BitStream* stream) : SyncSkill() { + Deserialize(stream); + } + + ~SyncSkill() { + } + + void Serialize(RakNet::BitStream* stream) { + stream->Write(MsgID); + + stream->Write(bDone); + uint32_t sBitStreamLength = sBitStream.length(); + stream->Write(sBitStreamLength); + for (unsigned int k = 0; k < sBitStreamLength; k++) { + stream->Write(sBitStream[k]); + } + + stream->Write(uiBehaviorHandle); + stream->Write(uiSkillHandle); + } + + bool Deserialize(RakNet::BitStream* stream) { + stream->Read(bDone); + uint32_t sBitStreamLength{}; + stream->Read(sBitStreamLength); + for (uint32_t k = 0; k < sBitStreamLength; k++) { + unsigned char character; + stream->Read(character); + sBitStream.push_back(character); + } + + stream->Read(uiBehaviorHandle); + stream->Read(uiSkillHandle); + + return true; + } + + bool bDone{}; + std::string sBitStream{}; + uint32_t uiBehaviorHandle{}; + uint32_t uiSkillHandle{}; +}; + +#endif //!__SYNCSKILL__H__ diff --git a/dGame/dInventory/Inventory.cpp b/dGame/dInventory/Inventory.cpp index 151e3164..d752f87d 100644 --- a/dGame/dInventory/Inventory.cpp +++ b/dGame/dInventory/Inventory.cpp @@ -2,7 +2,11 @@ #include "GameMessages.h" #include "Game.h" #include "Item.h" +#include "InventoryComponent.h" #include "eItemType.h" +#include "eReplicaComponentType.h" + +#include "CDComponentsRegistryTable.h" std::vector Inventory::m_GameMasterRestrictedItems = { 1727, // GM Only - JetPack @@ -230,52 +234,53 @@ eInventoryType Inventory::FindInventoryTypeForLot(const LOT lot) { const auto itemType = static_cast(itemComponent.itemType); switch (itemType) { - case eItemType::ITEM_TYPE_BRICK: + case eItemType::BRICK: return BRICKS; - case eItemType::ITEM_TYPE_BEHAVIOR: + case eItemType::BEHAVIOR: return BEHAVIORS; - case eItemType::ITEM_TYPE_PROPERTY: + case eItemType::PROPERTY: return PROPERTY_DEEDS; - case eItemType::ITEM_TYPE_MODEL: - case eItemType::ITEM_TYPE_VEHICLE: - case eItemType::ITEM_TYPE_LOOT_MODEL: - case eItemType::ITEM_TYPE_MOUNT: + case eItemType::MODEL: + case eItemType::VEHICLE: + case eItemType::LOOT_MODEL: + case eItemType::LUP_MODEL: + case eItemType::MOUNT: return MODELS; - case eItemType::ITEM_TYPE_HAT: - case eItemType::ITEM_TYPE_HAIR: - case eItemType::ITEM_TYPE_NECK: - case eItemType::ITEM_TYPE_LEFT_HAND: - case eItemType::ITEM_TYPE_RIGHT_HAND: - case eItemType::ITEM_TYPE_LEGS: - case eItemType::ITEM_TYPE_LEFT_TRINKET: - case eItemType::ITEM_TYPE_RIGHT_TRINKET: - case eItemType::ITEM_TYPE_COLLECTIBLE: - case eItemType::ITEM_TYPE_CONSUMABLE: - case eItemType::ITEM_TYPE_CHEST: - case eItemType::ITEM_TYPE_EGG: - case eItemType::ITEM_TYPE_PET_FOOD: - case eItemType::ITEM_TYPE_PET_INVENTORY_ITEM: - case eItemType::ITEM_TYPE_PACKAGE: - case eItemType::ITEM_TYPE_CURRENCY: + case eItemType::HAT: + case eItemType::HAIR: + case eItemType::NECK: + case eItemType::LEFT_HAND: + case eItemType::RIGHT_HAND: + case eItemType::LEGS: + case eItemType::LEFT_TRINKET: + case eItemType::RIGHT_TRINKET: + case eItemType::COLLECTIBLE: + case eItemType::CONSUMABLE: + case eItemType::CHEST: + case eItemType::EGG: + case eItemType::PET_FOOD: + case eItemType::PET_INVENTORY_ITEM: + case eItemType::PACKAGE: + return ITEMS; - case eItemType::ITEM_TYPE_QUEST_OBJECT: - case eItemType::ITEM_TYPE_UNKNOWN: + case eItemType::QUEST_OBJECT: + case eItemType::UNKNOWN: default: - return HIDDEN; + return QUEST; } } const CDItemComponent& Inventory::FindItemComponent(const LOT lot) { - auto* registry = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + auto* registry = CDClientManager::Instance().GetTable(); - auto* itemComponents = CDClientManager::Instance()->GetTable("ItemComponent"); + auto* itemComponents = CDClientManager::Instance().GetTable(); - const auto componentId = registry->GetByIDAndType(lot, COMPONENT_TYPE_ITEM); + const auto componentId = registry->GetByIDAndType(lot, eReplicaComponentType::ITEM); if (componentId == 0) { Game::logger->Log("Inventory", "Failed to find item component for (%i)!", lot); @@ -289,9 +294,9 @@ const CDItemComponent& Inventory::FindItemComponent(const LOT lot) { } bool Inventory::IsValidItem(const LOT lot) { - auto* registry = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + auto* registry = CDClientManager::Instance().GetTable(); - const auto componentId = registry->GetByIDAndType(lot, COMPONENT_TYPE_ITEM); + const auto componentId = registry->GetByIDAndType(lot, eReplicaComponentType::ITEM); return componentId != 0; } @@ -300,6 +305,12 @@ const std::vector& Inventory::GetAllGMItems() { return m_GameMasterRestrictedItems; } +void Inventory::DeleteAllItems() { + while (!this->items.empty()) { + if (items.begin()->second) items.begin()->second->SetCount(0); + } +} + Inventory::~Inventory() { for (auto item : items) { delete item.second; diff --git a/dGame/dInventory/Inventory.h b/dGame/dInventory/Inventory.h index 30f753da..5e0ac8d6 100644 --- a/dGame/dInventory/Inventory.h +++ b/dGame/dInventory/Inventory.h @@ -6,10 +6,11 @@ #include #include - +#include "CDItemComponentTable.h" #include "CDClientManager.h" #include "dCommonVars.h" +enum eInventoryType : uint32_t; class Item; class InventoryComponent; @@ -95,7 +96,7 @@ public: * @param lot the lot to find items for * @param ignoreEquipped ignores equipped items * @param ignoreBound ignores bound items - * @return item in the inventory for the provided LOT + * @return item with the lowest stack count in the inventory for the provided LOT */ Item* FindItemByLot(LOT lot, bool ignoreEquipped = false, bool ignoreBound = false) const; @@ -152,6 +153,11 @@ public: */ static const std::vector& GetAllGMItems(); + /** + * Remove ALL Items from this inventory. + */ + void DeleteAllItems(); + ~Inventory(); private: diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index 655af84e..5795ab12 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -14,9 +14,14 @@ #include "CharacterComponent.h" #include "eItemType.h" #include "AssetManager.h" +#include "InventoryComponent.h" +#include "Loot.h" +#include "eReplicaComponentType.h" -class Inventory; - +#include "CDBrickIDTableTable.h" +#include "CDObjectSkillsTable.h" +#include "CDComponentsRegistryTable.h" +#include "CDPackageComponentTable.h" Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector& config, const LWOOBJID parent, LWOOBJID subKey, eLootSourceType lootSourceType) { if (!Inventory::IsValidItem(lot)) { @@ -77,7 +82,7 @@ Item::Item( const auto type = static_cast(info->itemType); - if (type == eItemType::ITEM_TYPE_MOUNT) { + if (type == eItemType::MOUNT) { id = GeneralUtils::SetBit(id, OBJECT_BIT_CLIENT); } @@ -238,7 +243,7 @@ bool Item::IsEquipped() const { } bool Item::Consume() { - auto* skillsTable = CDClientManager::Instance()->GetTable("ObjectSkills"); + auto* skillsTable = CDClientManager::Instance().GetTable(); auto skills = skillsTable->Query([=](const CDObjectSkills entry) { return entry.objectTemplate == static_cast(lot); @@ -253,7 +258,7 @@ bool Item::Consume() { } } - Game::logger->Log("Item", "Consumed (%i) / (%llu) with (%d)", lot, id, success); + Game::logger->LogDebug("Item", "Consumed LOT (%i) itemID (%llu). Success=(%d)", lot, id, success); GameMessages::SendUseItemResult(inventory->GetComponent()->GetParent(), lot, success); @@ -264,36 +269,83 @@ bool Item::Consume() { return success; } -void Item::UseNonEquip() { +void Item::UseNonEquip(Item* item) { + LOT thisLot = this->GetLot(); + if (!GetInventory()) { + Game::logger->LogDebug("Item", "item %i has no inventory??", this->GetLot()); + return; + } + + auto* playerInventoryComponent = GetInventory()->GetComponent(); + if (!playerInventoryComponent) { + Game::logger->LogDebug("Item", "no inventory component attached to item id %llu lot %i", this->GetId(), this->GetLot()); + return; + } + + auto* playerEntity = playerInventoryComponent->GetParent(); + if (!playerEntity) { + Game::logger->LogDebug("Item", "no player entity attached to inventory? item id is %llu", this->GetId()); + return; + } + const auto type = static_cast(info->itemType); - if (type == eItemType::ITEM_TYPE_MOUNT) { - GetInventory()->GetComponent()->HandlePossession(this); - } else if (type == eItemType::ITEM_TYPE_PET_INVENTORY_ITEM && subKey != LWOOBJID_EMPTY) { - const auto& databasePet = GetInventory()->GetComponent()->GetDatabasePet(subKey); + if (type == eItemType::MOUNT) { + playerInventoryComponent->HandlePossession(this); + // TODO Check if mounts are allowed to be spawned + } else if (type == eItemType::PET_INVENTORY_ITEM && subKey != LWOOBJID_EMPTY) { + const auto& databasePet = playerInventoryComponent->GetDatabasePet(subKey); if (databasePet.lot != LOT_NULL) { - GetInventory()->GetComponent()->SpawnPet(this); + playerInventoryComponent->SpawnPet(this); } + // This precondition response is taken care of in SpawnPet(). } else { - auto* compRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_PACKAGE); + bool success = false; + auto inventory = item->GetInventory(); + if (inventory && inventory->GetType() == eInventoryType::ITEMS) { + auto* compRegistryTable = CDClientManager::Instance().GetTable(); + const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::PACKAGE); - if (packageComponentId == 0) return; + if (packageComponentId == 0) return; - auto* packCompTable = CDClientManager::Instance()->GetTable("PackageComponent"); - auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast(packageComponentId); }); + auto* packCompTable = CDClientManager::Instance().GetTable(); + auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast(packageComponentId); }); - const auto success = !packages.empty(); - if (success) { - auto* entityParent = inventory->GetComponent()->GetParent(); - for (auto& pack : packages) { - std::unordered_map result{}; - result = LootGenerator::Instance().RollLootMatrix(entityParent, pack.LootMatrixIndex); - if (!inventory->GetComponent()->HasSpaceForLoot(result)) { + auto success = !packages.empty(); + if (success) { + if (this->GetPreconditionExpression()->Check(playerInventoryComponent->GetParent())) { + auto* entityParent = playerInventoryComponent->GetParent(); + // Roll the loot for all the packages then see if it all fits. If it fits, give it to the player, otherwise don't. + std::unordered_map rolledLoot{}; + for (auto& pack : packages) { + auto thisPackage = LootGenerator::Instance().RollLootMatrix(entityParent, pack.LootMatrixIndex); + for (auto& loot : thisPackage) { + // If we already rolled this lot, add it to the existing one, otherwise create a new entry. + auto existingLoot = rolledLoot.find(loot.first); + if (existingLoot == rolledLoot.end()) { + rolledLoot.insert(loot); + } else { + existingLoot->second += loot.second; + } + } + } + if (playerInventoryComponent->HasSpaceForLoot(rolledLoot)) { + LootGenerator::Instance().GiveLoot(playerInventoryComponent->GetParent(), rolledLoot, eLootSourceType::LOOT_SOURCE_CONSUMPTION); + item->SetCount(item->GetCount() - 1); + } else { + success = false; + } + } else { + GameMessages::SendUseItemRequirementsResponse( + playerInventoryComponent->GetParent()->GetObjectID(), + playerInventoryComponent->GetParent()->GetSystemAddress(), + UseItemResponse::FailedPrecondition + ); + success = false; } - LootGenerator::Instance().GiveLoot(inventory->GetComponent()->GetParent(), result, eLootSourceType::LOOT_SOURCE_CONSUMPTION); } - inventory->GetComponent()->RemoveItem(lot, 1); } + Game::logger->LogDebug("Item", "Player %llu %s used item %i", playerEntity->GetObjectID(), success ? "successfully" : "unsuccessfully", thisLot); + GameMessages::SendUseItemResult(playerInventoryComponent->GetParent(), thisLot, success); } } @@ -302,6 +354,15 @@ void Item::Disassemble(const eInventoryType inventoryType) { if (data->GetKey() == u"assemblyPartLOTs") { auto modStr = data->GetValueAsString(); + // This shouldn't be null but always check your pointers. + if (GetInventory()) { + auto inventoryComponent = GetInventory()->GetComponent(); + if (inventoryComponent) { + auto entity = inventoryComponent->GetParent(); + if (entity) entity->SetVar(u"currentModifiedBuild", modStr); + } + } + std::vector modArray; std::stringstream ssData(modStr); @@ -324,26 +385,34 @@ void Item::Disassemble(const eInventoryType inventoryType) { } void Item::DisassembleModel() { - auto* table = CDClientManager::Instance()->GetTable("ComponentsRegistry"); + auto* table = CDClientManager::Instance().GetTable(); - const auto componentId = table->GetByIDAndType(GetLot(), COMPONENT_TYPE_RENDER); + const auto componentId = table->GetByIDAndType(GetLot(), eReplicaComponentType::RENDER); auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT render_asset FROM RenderComponent WHERE id = ?;"); + "SELECT render_asset, LXFMLFolder FROM RenderComponent WHERE id = ?;"); query.bind(1, (int)componentId); auto result = query.execQuery(); - if (result.eof()) { + if (result.eof() || result.fieldIsNull(0)) { return; } - std::string renderAsset = result.fieldIsNull(0) ? "" : std::string(result.getStringField(0)); - std::vector renderAssetSplit = GeneralUtils::SplitString(renderAsset, '\\'); + std::string renderAsset = std::string(result.getStringField(0)); + std::string lxfmlFolderName = std::string(result.getStringField(1)); - std::string lxfmlPath = "BrickModels/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.').at(0) + ".lxfml"; + std::vector renderAssetSplit = GeneralUtils::SplitString(renderAsset, '\\'); + if (renderAssetSplit.size() == 0) return; + + std::string lxfmlPath = "BrickModels/" + lxfmlFolderName + "/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.').at(0) + ".lxfml"; auto buffer = Game::assetManager->GetFileAsBuffer(lxfmlPath.c_str()); + if (!buffer.m_Success) { + Game::logger->Log("Item", "Failed to load %s to disassemble model into bricks, check that this file exists", lxfmlPath.c_str()); + return; + } + std::istream file(&buffer); result.finalize(); @@ -396,7 +465,7 @@ void Item::DisassembleModel() { currentBrick = currentBrick->NextSiblingElement(searchTerm.c_str()); } - auto* brickIDTable = CDClientManager::Instance()->GetTable("BrickIDTable"); + auto* brickIDTable = CDClientManager::Instance().GetTable(); for (unsigned int part : parts) { const auto brickID = brickIDTable->Query([=](const CDBrickIDTable& entry) { diff --git a/dGame/dInventory/Item.h b/dGame/dInventory/Item.h index db7e246a..6993a0ba 100644 --- a/dGame/dInventory/Item.h +++ b/dGame/dInventory/Item.h @@ -6,6 +6,7 @@ #include "CDClientManager.h" #include "dLogger.h" #include "Preconditions.h" +#include "eInventoryType.h" /** * An item that can be stored in an inventory and optionally consumed or equipped @@ -194,7 +195,7 @@ public: /** * Uses this item if its non equip, essentially an interface for the linked GM */ - void UseNonEquip(); + void UseNonEquip(Item* item); /** * Disassembles the part LOTs of this item back into the inventory, if it has any diff --git a/dGame/dInventory/ItemSet.cpp b/dGame/dInventory/ItemSet.cpp index 5063139e..a8e58739 100644 --- a/dGame/dInventory/ItemSet.cpp +++ b/dGame/dInventory/ItemSet.cpp @@ -6,8 +6,11 @@ #include "CDClientDatabase.h" #include "Game.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" #include +#include "CDSkillBehaviorTable.h" + ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) { this->m_ID = id; this->m_InventoryComponent = inventoryComponent; @@ -126,11 +129,11 @@ void ItemSet::OnEquip(const LOT lot) { auto* missionComponent = m_InventoryComponent->GetParent()->GetComponent(); for (const auto skill : skillSet) { - auto* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + auto* skillTable = CDClientManager::Instance().GetTable(); const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, skill); + missionComponent->Progress(eMissionTaskType::USE_SKILL, skill); skillComponent->HandleUnmanaged(behaviorId, m_InventoryComponent->GetParent()->GetObjectID()); } @@ -158,7 +161,7 @@ void ItemSet::OnUnEquip(const LOT lot) { const auto& skillComponent = m_InventoryComponent->GetParent()->GetComponent(); for (const auto skill : skillSet) { - auto* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + auto* skillTable = CDClientManager::Instance().GetTable(); const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID; @@ -180,9 +183,9 @@ void ItemSet::Update(float deltaTime) { } } -void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger) { +void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target) { for (auto& passiveAbility : m_PassiveAbilities) { - passiveAbility.Trigger(trigger); + passiveAbility.Trigger(trigger, target); } } diff --git a/dGame/dInventory/ItemSet.h b/dGame/dInventory/ItemSet.h index 7c713f03..d167cfaa 100644 --- a/dGame/dInventory/ItemSet.h +++ b/dGame/dInventory/ItemSet.h @@ -52,7 +52,7 @@ public: * Triggers all the passive abilities in this item set that match this trigger * @param trigger the trigger to use to trigger passive abilities */ - void TriggerPassiveAbility(PassiveAbilityTrigger trigger); + void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr); /** * Returns the skills that can be equipped for a specified amount of equipped items diff --git a/dGame/dInventory/ItemSetPassiveAbility.cpp b/dGame/dInventory/ItemSetPassiveAbility.cpp index d90f6e4e..bf7c19cb 100644 --- a/dGame/dInventory/ItemSetPassiveAbility.cpp +++ b/dGame/dInventory/ItemSetPassiveAbility.cpp @@ -3,7 +3,7 @@ #include "DestroyableComponent.h" #include "SkillComponent.h" #include "ItemSet.h" -#include "ItemSetPassiveAbilityID.h" +#include "eItemSetPassiveAbilityID.h" ItemSetPassiveAbility::ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Entity* parent, ItemSet* itemSet) { m_Trigger = trigger; @@ -16,12 +16,12 @@ ItemSetPassiveAbility::ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Enti ItemSetPassiveAbility::~ItemSetPassiveAbility() { } -void ItemSetPassiveAbility::Trigger(PassiveAbilityTrigger trigger) { +void ItemSetPassiveAbility::Trigger(PassiveAbilityTrigger trigger, Entity* target) { if (m_Trigger != trigger || m_Cooldown > 0.0f) { return; } - Activate(); + Activate(target); } void ItemSetPassiveAbility::Update(float deltaTime) { @@ -30,9 +30,9 @@ void ItemSetPassiveAbility::Update(float deltaTime) { } } -void ItemSetPassiveAbility::Activate() { +void ItemSetPassiveAbility::Activate(Entity* target) { if (m_Trigger == PassiveAbilityTrigger::EnemySmashed) { - OnEnemySmshed(); + OnEnemySmshed(target); return; } @@ -46,31 +46,31 @@ void ItemSetPassiveAbility::Activate() { EntityManager::Instance()->SerializeEntity(m_Parent); - const auto id = static_cast(m_ItemSet->GetID()); + const auto id = static_cast(m_ItemSet->GetID()); const auto parentID = m_Parent->GetObjectID(); const auto equippedCount = m_ItemSet->GetEquippedCount(); switch (id) { // Assembly - case ItemSetPassiveAbilityID::InventorRank1: - case ItemSetPassiveAbilityID::SummonerRank1: - case ItemSetPassiveAbilityID::EngineerRank1: { + case eItemSetPassiveAbilityID::InventorRank1: + case eItemSetPassiveAbilityID::SummonerRank1: + case eItemSetPassiveAbilityID::EngineerRank1: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(394, 4401, parentID); break; } - case ItemSetPassiveAbilityID::InventorRank2: - case ItemSetPassiveAbilityID::SummonerRank2: - case ItemSetPassiveAbilityID::EngineerRank2: { + case eItemSetPassiveAbilityID::InventorRank2: + case eItemSetPassiveAbilityID::SummonerRank2: + case eItemSetPassiveAbilityID::EngineerRank2: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(581, 9433, parentID); break; } - case ItemSetPassiveAbilityID::InventorRank3: - case ItemSetPassiveAbilityID::SummonerRank3: - case ItemSetPassiveAbilityID::EngineerRank3: { + case eItemSetPassiveAbilityID::InventorRank3: + case eItemSetPassiveAbilityID::SummonerRank3: + case eItemSetPassiveAbilityID::EngineerRank3: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(582, 9435, parentID); @@ -78,57 +78,57 @@ void ItemSetPassiveAbility::Activate() { } // Sentinel - case ItemSetPassiveAbilityID::KnightRank1: { + case eItemSetPassiveAbilityID::KnightRank1: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(559, 8884, parentID); break; } - case ItemSetPassiveAbilityID::KnightRank2: { + case eItemSetPassiveAbilityID::KnightRank2: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(560, 8885, parentID); break; } - case ItemSetPassiveAbilityID::KnightRank3: { + case eItemSetPassiveAbilityID::KnightRank3: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(561, 8890, parentID); break; } - case ItemSetPassiveAbilityID::SpaceRangerRank1: { + case eItemSetPassiveAbilityID::SpaceRangerRank1: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(1101, 24612, parentID); break; } - case ItemSetPassiveAbilityID::SpaceRangerRank2: { + case eItemSetPassiveAbilityID::SpaceRangerRank2: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(1102, 24617, parentID); break; } - case ItemSetPassiveAbilityID::SpaceRangerRank3: { + case eItemSetPassiveAbilityID::SpaceRangerRank3: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(1103, 24622, parentID); break; } - case ItemSetPassiveAbilityID::SamuraiRank1: { + case eItemSetPassiveAbilityID::SamuraiRank1: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(562, 8899, parentID); break; } - case ItemSetPassiveAbilityID::SamuraiRank2: { + case eItemSetPassiveAbilityID::SamuraiRank2: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(563, 8904, parentID); break; } - case ItemSetPassiveAbilityID::SamuraiRank3: { + case eItemSetPassiveAbilityID::SamuraiRank3: { if (equippedCount < 4) return; m_Cooldown = 11.0f; skillComponent->CalculateBehavior(564, 8909, parentID); @@ -143,47 +143,47 @@ void ItemSetPassiveAbility::Activate() { std::vector ItemSetPassiveAbility::FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet) { std::vector abilities; - switch (static_cast(itemSetID)) { + switch (static_cast(itemSetID)) { // Assembly - case ItemSetPassiveAbilityID::SummonerRank1: - case ItemSetPassiveAbilityID::SummonerRank2: - case ItemSetPassiveAbilityID::SummonerRank3: - case ItemSetPassiveAbilityID::InventorRank1: - case ItemSetPassiveAbilityID::InventorRank2: - case ItemSetPassiveAbilityID::InventorRank3: - case ItemSetPassiveAbilityID::EngineerRank1: - case ItemSetPassiveAbilityID::EngineerRank2: - case ItemSetPassiveAbilityID::EngineerRank3: { + case eItemSetPassiveAbilityID::SummonerRank1: + case eItemSetPassiveAbilityID::SummonerRank2: + case eItemSetPassiveAbilityID::SummonerRank3: + case eItemSetPassiveAbilityID::InventorRank1: + case eItemSetPassiveAbilityID::InventorRank2: + case eItemSetPassiveAbilityID::InventorRank3: + case eItemSetPassiveAbilityID::EngineerRank1: + case eItemSetPassiveAbilityID::EngineerRank2: + case eItemSetPassiveAbilityID::EngineerRank3: { abilities.emplace_back(PassiveAbilityTrigger::AssemblyImagination, parent, itemSet); break; } // Sentinel - case ItemSetPassiveAbilityID::KnightRank1: - case ItemSetPassiveAbilityID::KnightRank2: - case ItemSetPassiveAbilityID::KnightRank3: - case ItemSetPassiveAbilityID::SpaceRangerRank1: - case ItemSetPassiveAbilityID::SpaceRangerRank2: - case ItemSetPassiveAbilityID::SpaceRangerRank3: - case ItemSetPassiveAbilityID::SamuraiRank1: - case ItemSetPassiveAbilityID::SamuraiRank2: - case ItemSetPassiveAbilityID::SamuraiRank3: { + case eItemSetPassiveAbilityID::KnightRank1: + case eItemSetPassiveAbilityID::KnightRank2: + case eItemSetPassiveAbilityID::KnightRank3: + case eItemSetPassiveAbilityID::SpaceRangerRank1: + case eItemSetPassiveAbilityID::SpaceRangerRank2: + case eItemSetPassiveAbilityID::SpaceRangerRank3: + case eItemSetPassiveAbilityID::SamuraiRank1: + case eItemSetPassiveAbilityID::SamuraiRank2: + case eItemSetPassiveAbilityID::SamuraiRank3: { abilities.emplace_back(PassiveAbilityTrigger::SentinelArmor, parent, itemSet); abilities.emplace_back(PassiveAbilityTrigger::EnemySmashed, parent, itemSet); break; } // Paradox - case ItemSetPassiveAbilityID::BatLord: - case ItemSetPassiveAbilityID::SpaceMarauderRank1: - case ItemSetPassiveAbilityID::SpaceMarauderRank2: - case ItemSetPassiveAbilityID::SpaceMarauderRank3: - case ItemSetPassiveAbilityID::SorcererRank1: - case ItemSetPassiveAbilityID::SorcererRank2: - case ItemSetPassiveAbilityID::SorcererRank3: - case ItemSetPassiveAbilityID::ShinobiRank1: - case ItemSetPassiveAbilityID::ShinobiRank2: - case ItemSetPassiveAbilityID::ShinobiRank3: { + case eItemSetPassiveAbilityID::BatLord: + case eItemSetPassiveAbilityID::SpaceMarauderRank1: + case eItemSetPassiveAbilityID::SpaceMarauderRank2: + case eItemSetPassiveAbilityID::SpaceMarauderRank3: + case eItemSetPassiveAbilityID::SorcererRank1: + case eItemSetPassiveAbilityID::SorcererRank2: + case eItemSetPassiveAbilityID::SorcererRank3: + case eItemSetPassiveAbilityID::ShinobiRank1: + case eItemSetPassiveAbilityID::ShinobiRank2: + case eItemSetPassiveAbilityID::ShinobiRank3: { abilities.emplace_back(PassiveAbilityTrigger::EnemySmashed, parent, itemSet); break; @@ -195,7 +195,7 @@ std::vector ItemSetPassiveAbility::FindAbilities(uint32_t return abilities; } -void ItemSetPassiveAbility::OnEnemySmshed() { +void ItemSetPassiveAbility::OnEnemySmshed(Entity* target) { auto* destroyableComponent = m_Parent->GetComponent(); auto* skillComponent = m_Parent->GetComponent(); @@ -205,110 +205,110 @@ void ItemSetPassiveAbility::OnEnemySmshed() { EntityManager::Instance()->SerializeEntity(m_Parent); - const auto id = static_cast(m_ItemSet->GetID()); + const auto id = static_cast(m_ItemSet->GetID()); const auto parentID = m_Parent->GetObjectID(); const auto equippedCount = m_ItemSet->GetEquippedCount(); switch (id) { // Bat Lord - case ItemSetPassiveAbilityID::BatLord: { + case eItemSetPassiveAbilityID::BatLord: { if (equippedCount < 5) return; destroyableComponent->Heal(3); break; } // Sentinel - case ItemSetPassiveAbilityID::KnightRank1: { + case eItemSetPassiveAbilityID::KnightRank1: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } - case ItemSetPassiveAbilityID::KnightRank2: { + case eItemSetPassiveAbilityID::KnightRank2: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } - case ItemSetPassiveAbilityID::KnightRank3: { + case eItemSetPassiveAbilityID::KnightRank3: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } - case ItemSetPassiveAbilityID::SpaceRangerRank1: { + case eItemSetPassiveAbilityID::SpaceRangerRank1: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } - case ItemSetPassiveAbilityID::SpaceRangerRank2: { + case eItemSetPassiveAbilityID::SpaceRangerRank2: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } - case ItemSetPassiveAbilityID::SpaceRangerRank3: { + case eItemSetPassiveAbilityID::SpaceRangerRank3: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } - case ItemSetPassiveAbilityID::SamuraiRank1: { + case eItemSetPassiveAbilityID::SamuraiRank1: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } - case ItemSetPassiveAbilityID::SamuraiRank2: { + case eItemSetPassiveAbilityID::SamuraiRank2: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } - case ItemSetPassiveAbilityID::SamuraiRank3: { + case eItemSetPassiveAbilityID::SamuraiRank3: { if (equippedCount < 5) return; destroyableComponent->Repair(1); break; } // Paradox - case ItemSetPassiveAbilityID::SpaceMarauderRank1: { + case eItemSetPassiveAbilityID::SpaceMarauderRank1: { if (equippedCount < 4) return; destroyableComponent->Imagine(1); break; } - case ItemSetPassiveAbilityID::SpaceMarauderRank2: { + case eItemSetPassiveAbilityID::SpaceMarauderRank2: { if (equippedCount < 4) return; destroyableComponent->Imagine(2); break; } - case ItemSetPassiveAbilityID::SpaceMarauderRank3: { + case eItemSetPassiveAbilityID::SpaceMarauderRank3: { if (equippedCount < 4) return; destroyableComponent->Imagine(3); break; } - case ItemSetPassiveAbilityID::ShinobiRank1: { + case eItemSetPassiveAbilityID::ShinobiRank1: { if (equippedCount < 4) return; destroyableComponent->Imagine(1); break; } - case ItemSetPassiveAbilityID::ShinobiRank2: { + case eItemSetPassiveAbilityID::ShinobiRank2: { if (equippedCount < 4) return; destroyableComponent->Imagine(2); break; } - case ItemSetPassiveAbilityID::ShinobiRank3: { + case eItemSetPassiveAbilityID::ShinobiRank3: { if (equippedCount < 4) return; destroyableComponent->Imagine(3); break; } - case ItemSetPassiveAbilityID::SorcererRank1: { + case eItemSetPassiveAbilityID::SorcererRank1: { if (equippedCount < 4) return; destroyableComponent->Imagine(1); break; } - case ItemSetPassiveAbilityID::SorcererRank2: { + case eItemSetPassiveAbilityID::SorcererRank2: { if (equippedCount < 4) return; destroyableComponent->Imagine(2); break; } - case ItemSetPassiveAbilityID::SorcererRank3: { + case eItemSetPassiveAbilityID::SorcererRank3: { if (equippedCount < 4) return; destroyableComponent->Imagine(3); break; diff --git a/dGame/dInventory/ItemSetPassiveAbility.h b/dGame/dInventory/ItemSetPassiveAbility.h index ff945df2..8735e695 100644 --- a/dGame/dInventory/ItemSetPassiveAbility.h +++ b/dGame/dInventory/ItemSetPassiveAbility.h @@ -30,12 +30,12 @@ public: * Attempts to trigger a passive ability for this item set, if this is the wrong trigger this is a no-op * @param trigger the trigger to attempt to fire */ - void Trigger(PassiveAbilityTrigger trigger); + void Trigger(PassiveAbilityTrigger trigger, Entity* target = nullptr); /** * Activates the passive ability */ - void Activate(); + void Activate(Entity* target = nullptr); /** * Finds all the passive abilities associated with a certain item set @@ -47,7 +47,7 @@ public: static std::vector FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet); private: - void OnEnemySmshed(); + void OnEnemySmshed(Entity* target = nullptr); /** * The means of triggering this ability diff --git a/dGame/dInventory/ItemSetPassiveAbilityID.h b/dGame/dInventory/ItemSetPassiveAbilityID.h deleted file mode 100644 index 92caea19..00000000 --- a/dGame/dInventory/ItemSetPassiveAbilityID.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -/** -2 Engineer (Rank 1) Item Set -3 Engineer (Rank 2) Item Set -4 Engineer (Rank 3) Item Set -7 Knight (Rank 1) Item Set -8 Knight (Rank 2) Item Set -9 Knight (Rank 3) Item Set -10 Space Ranger (Rank 1) Item Set -11 Space Ranger (Rank 2) Item Set -12 Space Ranger (Rank 3) Item Set -13 Samurai (Rank 1) Item Set -14 Samurai (Rank 2) Item Set -15 Samurai (Rank 3) Item Set -16 Sorcerer (Rank 1) Item Set -17 Sorcerer (Rank 2) Item Set -18 Sorcerer (Rank 3) Item Set -19 Space Marauder (Rank 1) Item Set -20 Space Marauder (Rank 2) Item Set -21 Space Marauder (Rank 3) Item Set -22 Shinobi (Rank 1) Item Set -23 Shinobi (Rank 2) Item Set -24 Shinobi (Rank 3) Item Set -25 Inventor (Rank 1) Item Set -26 Inventor (Rank 2) Item Set -27 Inventor (Rank 3) Item Set -28 Summoner (Rank 1) Item Set -29 Summoner (Rank 2) Item Set -30 Summoner (Rank 3) Item Set -31 Adventurer (Rank 1) Item Set -32 Adventurer (Rank 2) Item Set -33 Adventurer (Rank 3) Item Set -34 Daredevil (Rank 1) Item Set -35 Daredevil (Rank 2) Item Set -36 Daredevil (Rank 3) Item Set -37 Buccaneer (Rank 1) Item Set -38 Buccaneer (Rank 2) Item Set -39 Buccaneer (Rank 3) Item Set -40 Bone Suit Item Set -41 Imagination Spinjitzu Item Set -42 Bat Lord Item Set -43 Mosaic Jester Item Set -44 Explorien Bot Item Set -45 [Unnamed] Item Set -46 [Unnamed] Item Set -47 [Unnamed] Item Set -48 Earth Spinjitzu Item Set -49 [Unnamed] Item Set -50 Fire Spinjitzu Item Set -51 Ice Spinjitzu Item Set -52 Lightning Spinjitzu Item Set - */ -enum class ItemSetPassiveAbilityID -{ - EngineerRank1 = 2, - EngineerRank2 = 3, - EngineerRank3 = 4, - KnightRank1 = 7, - KnightRank2 = 8, - KnightRank3 = 9, - SpaceRangerRank1 = 10, - SpaceRangerRank2 = 11, - SpaceRangerRank3 = 12, - SamuraiRank1 = 13, - SamuraiRank2 = 14, - SamuraiRank3 = 15, - SorcererRank1 = 16, - SorcererRank2 = 17, - SorcererRank3 = 18, - SpaceMarauderRank1 = 19, - SpaceMarauderRank2 = 20, - SpaceMarauderRank3 = 21, - ShinobiRank1 = 22, - ShinobiRank2 = 23, - ShinobiRank3 = 24, - InventorRank1 = 25, - InventorRank2 = 26, - InventorRank3 = 27, - SummonerRank1 = 28, - SummonerRank2 = 29, - SummonerRank3 = 30, - AdventurerRank1 = 31, - AdventurerRank2 = 32, - AdventurerRank3 = 33, - DaredevilRank1 = 34, - DaredevilRank2 = 35, - DaredevilRank3 = 36, - BuccaneerRank1 = 37, - BuccaneerRank2 = 38, - BuccaneerRank3 = 39, - BoneSuit = 40, - ImaginationSpinjitzu = 41, - BatLord = 42, - MosaicJester = 43, - ExplorienBot = 44, - Unnamed1 = 45, - Unnamed2 = 46, - Unnamed3 = 47, - EarthSpinjitzu = 48, - Unnamed4 = 49, - FireSpinjitzu = 50, - IceSpinjitzu = 51, - LightningSpinjitzu = 52 -}; diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 6020e51c..9cfdaaa7 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -12,12 +12,20 @@ #include "GameMessages.h" #include "Mail.h" #include "MissionComponent.h" -#include "RacingTaskParam.h" -#include "dLocale.h" +#include "eRacingTaskParam.h" #include "dLogger.h" #include "dServer.h" #include "dZoneManager.h" +#include "InventoryComponent.h" +#include "User.h" #include "Database.h" +#include "WorldConfig.h" +#include "eMissionState.h" +#include "eMissionTaskType.h" +#include "eMissionLockState.h" +#include "eReplicaComponentType.h" + +#include "CDMissionEmailTable.h" Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { m_MissionComponent = missionComponent; @@ -30,9 +38,9 @@ Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { m_Reward = 0; - m_State = MissionState::MISSION_STATE_UNKNOWN; + m_State = eMissionState::UNKNOWN; - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + auto* missionsTable = CDClientManager::Instance().GetTable(); info = missionsTable->GetPtrByMissionID(missionId); @@ -42,7 +50,7 @@ Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { return; } - auto* tasksTable = CDClientManager::Instance()->GetTable("MissionTasks"); + auto* tasksTable = CDClientManager::Instance().GetTable(); auto tasks = tasksTable->GetByMissionID(missionId); @@ -58,7 +66,7 @@ Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { void Mission::LoadFromXml(tinyxml2::XMLElement* element) { // Start custom XML if (element->Attribute("state") != nullptr) { - m_State = static_cast(std::stoul(element->Attribute("state"))); + m_State = static_cast(std::stoul(element->Attribute("state"))); } // End custom XML @@ -83,8 +91,8 @@ void Mission::LoadFromXml(tinyxml2::XMLElement* element) { const auto type = m_Tasks[index]->GetType(); - if (type == MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT || - type == MissionTaskType::MISSION_TASK_TYPE_VISIT_PROPERTY) { + if (type == eMissionTaskType::COLLECTION || + type == eMissionTaskType::VISIT_PROPERTY) { std::vector uniques; const auto value = std::stoul(task->Attribute("v")); @@ -98,7 +106,7 @@ void Mission::LoadFromXml(tinyxml2::XMLElement* element) { uniques.push_back(unique); - if (m_MissionComponent != nullptr && type == MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT) { + if (m_MissionComponent != nullptr && type == eMissionTaskType::COLLECTION) { m_MissionComponent->AddCollectible(unique); } @@ -142,8 +150,8 @@ void Mission::UpdateXml(tinyxml2::XMLElement* element) { } for (auto* task : m_Tasks) { - if (task->GetType() == MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT || - task->GetType() == MissionTaskType::MISSION_TASK_TYPE_VISIT_PROPERTY) { + if (task->GetType() == eMissionTaskType::COLLECTION || + task->GetType() == eMissionTaskType::VISIT_PROPERTY) { auto* child = element->GetDocument()->NewElement("sv"); @@ -170,7 +178,7 @@ void Mission::UpdateXml(tinyxml2::XMLElement* element) { } bool Mission::IsValidMission(const uint32_t missionId) { - auto* table = CDClientManager::Instance()->GetTable("Missions"); + auto* table = CDClientManager::Instance().GetTable(); const auto missions = table->Query([=](const CDMissions& entry) { return entry.id == static_cast(missionId); @@ -180,7 +188,7 @@ bool Mission::IsValidMission(const uint32_t missionId) { } bool Mission::IsValidMission(const uint32_t missionId, CDMissions& info) { - auto* table = CDClientManager::Instance()->GetTable("Missions"); + auto* table = CDClientManager::Instance().GetTable(); const auto missions = table->Query([=](const CDMissions& entry) { return entry.id == static_cast(missionId); @@ -227,7 +235,7 @@ std::vector Mission::GetTasks() const { return m_Tasks; } -MissionState Mission::GetMissionState() const { +eMissionState Mission::GetMissionState() const { return m_State; } @@ -244,47 +252,47 @@ bool Mission::IsRepeatable() const { } bool Mission::IsComplete() const { - return m_State == MissionState::MISSION_STATE_COMPLETE; + return m_State == eMissionState::COMPLETE; } bool Mission::IsActive() const { - return m_State == MissionState::MISSION_STATE_ACTIVE || m_State == MissionState::MISSION_STATE_COMPLETE_AVAILABLE; + return m_State == eMissionState::ACTIVE || m_State == eMissionState::COMPLETE_AVAILABLE; } void Mission::MakeActive() { - SetMissionState(m_Completions == 0 ? MissionState::MISSION_STATE_ACTIVE : MissionState::MISSION_STATE_COMPLETE_ACTIVE); + SetMissionState(m_Completions == 0 ? eMissionState::ACTIVE : eMissionState::COMPLETE_ACTIVE); } bool Mission::IsReadyToComplete() const { - return m_State == MissionState::MISSION_STATE_READY_TO_COMPLETE || m_State == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE; + return m_State == eMissionState::READY_TO_COMPLETE || m_State == eMissionState::COMPLETE_READY_TO_COMPLETE; } void Mission::MakeReadyToComplete() { - SetMissionState(m_Completions == 0 ? MissionState::MISSION_STATE_READY_TO_COMPLETE : MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE); + SetMissionState(m_Completions == 0 ? eMissionState::READY_TO_COMPLETE : eMissionState::COMPLETE_READY_TO_COMPLETE); } bool Mission::IsAvalible() const { - return m_State == MissionState::MISSION_STATE_AVAILABLE || m_State == MissionState::MISSION_STATE_COMPLETE_AVAILABLE; + return m_State == eMissionState::AVAILABLE || m_State == eMissionState::COMPLETE_AVAILABLE; } bool Mission::IsFetchMission() const { - return m_Tasks.size() == 1 && m_Tasks[0]->GetType() == MissionTaskType::MISSION_TASK_TYPE_MISSION_INTERACTION; + return m_Tasks.size() == 1 && m_Tasks[0]->GetType() == eMissionTaskType::TALK_TO_NPC; } void Mission::MakeAvalible() { - SetMissionState(m_Completions == 0 ? MissionState::MISSION_STATE_AVAILABLE : MissionState::MISSION_STATE_COMPLETE_AVAILABLE); + SetMissionState(m_Completions == 0 ? eMissionState::AVAILABLE : eMissionState::COMPLETE_AVAILABLE); } void Mission::Accept() { - SetMissionTypeState(MissionLockState::MISSION_LOCK_NEW, info->defined_type, info->defined_subtype); + SetMissionTypeState(eMissionLockState::NEW, info->defined_type, info->defined_subtype); - SetMissionState(m_Completions > 0 ? MissionState::MISSION_STATE_COMPLETE_ACTIVE : MissionState::MISSION_STATE_ACTIVE); + SetMissionState(m_Completions > 0 ? eMissionState::COMPLETE_ACTIVE : eMissionState::ACTIVE); Catchup(); } void Mission::Complete(const bool yieldRewards) { - if (m_State != MissionState::MISSION_STATE_ACTIVE && m_State != MissionState::MISSION_STATE_COMPLETE_ACTIVE) { + if (m_State != eMissionState::ACTIVE && m_State != eMissionState::COMPLETE_ACTIVE) { // If we are accepting a mission here there is no point to giving it a unique ID since we just complete it immediately. Accept(); } @@ -293,13 +301,13 @@ void Mission::Complete(const bool yieldRewards) { task->Complete(); } - SetMissionState(MissionState::MISSION_STATE_REWARDING, true); + SetMissionState(eMissionState::REWARDING, true); if (yieldRewards) { YieldRewards(); } - SetMissionState(MissionState::MISSION_STATE_COMPLETE); + SetMissionState(eMissionState::COMPLETE); m_Completions++; @@ -318,13 +326,13 @@ void Mission::Complete(const bool yieldRewards) { auto* missionComponent = entity->GetComponent(); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MISSION_COMPLETE, info->id); + missionComponent->Progress(eMissionTaskType::META, info->id); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, info->id, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COMPLETE_ANY_RACING_TASK); + missionComponent->Progress(eMissionTaskType::RACING, info->id, (LWOOBJID)eRacingTaskParam::COMPLETE_ANY_RACING_TASK); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, info->id, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COMPLETE_TRACK_TASKS); + missionComponent->Progress(eMissionTaskType::RACING, info->id, (LWOOBJID)eRacingTaskParam::COMPLETE_TRACK_TASKS); - auto* missionEmailTable = CDClientManager::Instance()->GetTable("MissionEmail"); + auto* missionEmailTable = CDClientManager::Instance().GetTable(); const auto missionId = GetMissionId(); @@ -335,13 +343,10 @@ void Mission::Complete(const bool yieldRewards) { for (const auto& email : missionEmails) { const auto missionEmailBase = "MissionEmail_" + std::to_string(email.ID) + "_"; - const auto senderLocale = missionEmailBase + "senderName"; - const auto announceLocale = missionEmailBase + "announceText"; - - if (email.messageType == 1 && Game::locale->HasPhrase(senderLocale)) { - const auto subject = dLocale::GetTemplate(missionEmailBase + "subjectText"); - const auto body = dLocale::GetTemplate(missionEmailBase + "bodyText"); - const auto sender = dLocale::GetTemplate(senderLocale); + if (email.messageType == 1) { + const auto subject = "%[" + missionEmailBase + "subjectText]"; + const auto body = "%[" + missionEmailBase + "bodyText]"; + const auto sender = "%[" + missionEmailBase + "senderName]"; Mail::SendMail(LWOOBJID_EMPTY, sender, GetAssociate(), subject, body, email.attachmentLOT, 1); } @@ -367,12 +372,12 @@ void Mission::CheckCompletion() { void Mission::Catchup() { auto* entity = GetAssociate(); - auto* inventory = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto* inventory = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); for (auto* task : m_Tasks) { const auto type = task->GetType(); - if (type == MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION) { + if (type == eMissionTaskType::GATHER) { for (auto target : task->GetAllTargets()) { const auto count = inventory->GetLotCountNonTransfer(target); @@ -382,7 +387,7 @@ void Mission::Catchup() { } } - if (type == MissionTaskType::MISSION_TASK_TYPE_PLAYER_FLAG) { + if (type == eMissionTaskType::PLAYER_FLAG) { for (auto target : task->GetAllTargets()) { const auto flag = GetUser()->GetLastUsedChar()->GetPlayerFlag(target); @@ -417,7 +422,7 @@ void Mission::YieldRewards() { // Remove mission items for (auto* task : m_Tasks) { - if (task->GetType() != MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION) { + if (task->GetType() != eMissionTaskType::GATHER) { continue; } @@ -428,9 +433,9 @@ void Mission::YieldRewards() { for (const auto target : task->GetAllTargets()) { // This is how live did it. ONLY remove item collection items from the items and hidden inventories and none of the others. inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::ITEMS); - inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::HIDDEN); + inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::QUEST); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, target, LWOOBJID_EMPTY, "", -task->GetClientInfo().targetValue); + missionComponent->Progress(eMissionTaskType::GATHER, target, LWOOBJID_EMPTY, "", -task->GetClientInfo().targetValue); } } } @@ -438,9 +443,9 @@ void Mission::YieldRewards() { int32_t coinsToSend = 0; if (info->LegoScore > 0) { eLootSourceType lootSource = info->isMission ? eLootSourceType::LOOT_SOURCE_MISSION : eLootSourceType::LOOT_SOURCE_ACHIEVEMENT; - if (levelComponent->GetLevel() >= dZoneManager::Instance()->GetMaxLevel()) { + if (levelComponent->GetLevel() >= dZoneManager::Instance()->GetWorldConfig()->levelCap) { // Since the character is at the level cap we reward them with coins instead of UScore. - coinsToSend += info->LegoScore * dZoneManager::Instance()->GetLevelCapCurrencyConversion(); + coinsToSend += info->LegoScore * dZoneManager::Instance()->GetWorldConfig()->levelCapCurrencyConversion; } else { characterComponent->SetUScore(characterComponent->GetUScore() + info->LegoScore); GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), info->LegoScore, lootSource); @@ -526,7 +531,7 @@ void Mission::YieldRewards() { } if (info->reward_reputation > 0) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_EARN_REPUTATION, 0, 0L, "", info->reward_reputation); + missionComponent->Progress(eMissionTaskType::EARN_REPUTATION, 0, 0L, "", info->reward_reputation); auto character = entity->GetComponent(); if (character) { character->SetReputation(character->GetReputation() + info->reward_reputation); @@ -561,7 +566,7 @@ void Mission::YieldRewards() { } } -void Mission::Progress(MissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count) { +void Mission::Progress(eMissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count) { const auto isRemoval = count < 0; if (isRemoval && (IsComplete() || IsAchievement())) { @@ -585,7 +590,7 @@ void Mission::Progress(MissionTaskType type, int32_t value, LWOOBJID associate, } } -void Mission::SetMissionState(const MissionState state, const bool sendingRewards) { +void Mission::SetMissionState(const eMissionState state, const bool sendingRewards) { this->m_State = state; auto* entity = GetAssociate(); @@ -597,7 +602,7 @@ void Mission::SetMissionState(const MissionState state, const bool sendingReward GameMessages::SendNotifyMission(entity, entity->GetParentUser()->GetSystemAddress(), info->id, static_cast(state), sendingRewards); } -void Mission::SetMissionTypeState(MissionLockState state, const std::string& type, const std::string& subType) { +void Mission::SetMissionTypeState(eMissionLockState state, const std::string& type, const std::string& subType) { // TODO } diff --git a/dGame/dMission/Mission.h b/dGame/dMission/Mission.h index b8892f3d..b04c3548 100644 --- a/dGame/dMission/Mission.h +++ b/dGame/dMission/Mission.h @@ -10,9 +10,12 @@ #include "MissionTask.h" #include "dCommonVars.h" #include "Entity.h" -#include "MissionState.h" -#include "MissionLockState.h" +namespace tinyxml2 { + class XMLElement; +}; +enum class eMissionState : int; +enum class eMissionLockState : int; class MissionComponent; /** @@ -49,7 +52,7 @@ public: * Returns the current state of this mission * @return the current state of this mission */ - MissionState GetMissionState() const; + eMissionState GetMissionState() const; /** * Returns the database information that represents to this mission. @@ -98,12 +101,12 @@ public: * @param state the mission state to set * @param sendingRewards a flag indicating to the client that rewards wil lfollow */ - void SetMissionState(MissionState state, bool sendingRewards = false); + void SetMissionState(eMissionState state, bool sendingRewards = false); /** * Currently unimplemented */ - void SetMissionTypeState(MissionLockState state, const std::string& type, const std::string& subType); + void SetMissionTypeState(eMissionLockState state, const std::string& type, const std::string& subType); /** * Returns whether this mission is an achievement @@ -204,7 +207,7 @@ public: * @param targets optional multiple targets that need to be met for progression * @param count optional count to progress with */ - void Progress(MissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1); + void Progress(eMissionTaskType type, int32_t value, LWOOBJID associate = 0, const std::string& targets = "", int32_t count = 1); /** * Returns if the mission ID that's given belongs to an existing mission @@ -223,7 +226,7 @@ public: /** * @brief Returns the unique mission order ID - * + * * @return The unique order ID */ uint32_t GetUniqueMissionOrderID() { return m_UniqueMissionID; }; @@ -247,7 +250,7 @@ private: /** * The current state this mission is in */ - MissionState m_State; + eMissionState m_State; /** * The number of times the entity has completed this mission diff --git a/dGame/dMission/MissionLockState.h b/dGame/dMission/MissionLockState.h deleted file mode 100644 index 9fd2252a..00000000 --- a/dGame/dMission/MissionLockState.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#ifndef MISSIONLOCKSTATE_H -#define MISSIONLOCKSTATE_H - -enum class MissionLockState : int -{ - MISSION_LOCK_LOCKED, - MISSION_LOCK_NEW, - MISSION_LOCK_UNLOCKED, -}; - -#endif diff --git a/dGame/dMission/MissionPrerequisites.cpp b/dGame/dMission/MissionPrerequisites.cpp index 46fa73a6..ec4522b9 100644 --- a/dGame/dMission/MissionPrerequisites.cpp +++ b/dGame/dMission/MissionPrerequisites.cpp @@ -106,8 +106,8 @@ bool PrerequisiteExpression::Execute(const std::unordered_mapsub != 0) { // Special case for one Wisp Lee repeatable mission. a = mission->GetClientInfo().id == 1883 ? - mission->GetMissionState() == static_cast(this->sub) : - mission->GetMissionState() >= static_cast(this->sub); + mission->GetMissionState() == static_cast(this->sub) : + mission->GetMissionState() >= static_cast(this->sub); } else if (mission->IsComplete()) { a = true; } @@ -163,7 +163,7 @@ bool MissionPrerequisites::CheckPrerequisites(uint32_t missionId, const std::uno return index->second->Execute(missions); } - auto* missionsTable = CDClientManager::Instance()->GetTable("Missions"); + auto* missionsTable = CDClientManager::Instance().GetTable(); const auto missionEntries = missionsTable->Query([=](const CDMissions& entry) { return entry.id == static_cast(missionId); }); diff --git a/dGame/dMission/MissionState.h b/dGame/dMission/MissionState.h deleted file mode 100644 index fb1841d3..00000000 --- a/dGame/dMission/MissionState.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#ifndef __MISSIONSTATE__H__ -#define __MISSIONSTATE__H__ - -/** - * Represents the possible states a mission can be in - */ -enum class MissionState : int { - /** - * The mission state is unknown - */ - MISSION_STATE_UNKNOWN = -1, - - /** - * The mission is yielding rewards - */ - MISSION_STATE_REWARDING = 0, - - /** - * The mission can be accepted - */ - MISSION_STATE_AVAILABLE = 1, - - /** - * The mission has been accepted but not yet completed - */ - MISSION_STATE_ACTIVE = 2, - - /** - * All the tasks for the mission have been completed and the entity can turn the mission in to complete it - */ - MISSION_STATE_READY_TO_COMPLETE = 4, //!< The mission is ready to complete - - /** - * The mission has been completed - */ - MISSION_STATE_COMPLETE = 8, - - /** - * The mission is available again and has been completed before. Used for daily missions. - */ - MISSION_STATE_COMPLETE_AVAILABLE = 9, - - /** - * The mission is active and has been completed before. Used for daily missions. - */ - MISSION_STATE_COMPLETE_ACTIVE = 10, - - /** - * The mission has been completed before and has now been completed again. Used for daily missions. - */ - MISSION_STATE_COMPLETE_READY_TO_COMPLETE = 12 -}; - -#endif //!__MISSIONSTATE__H__ diff --git a/dGame/dMission/MissionTask.cpp b/dGame/dMission/MissionTask.cpp index dc2cb149..344427c6 100644 --- a/dGame/dMission/MissionTask.cpp +++ b/dGame/dMission/MissionTask.cpp @@ -11,8 +11,10 @@ #include "ScriptedActivityComponent.h" #include "GameMessages.h" #include "dZoneManager.h" +#include "InventoryComponent.h" #include "MissionComponent.h" - +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" MissionTask::MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask) { this->info = info; @@ -42,8 +44,8 @@ MissionTask::MissionTask(Mission* mission, CDMissionTasks* info, uint32_t mask) } -MissionTaskType MissionTask::GetType() const { - return static_cast(info->taskType); +eMissionTaskType MissionTask::GetType() const { + return static_cast(info->taskType); } @@ -187,7 +189,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& const auto type = GetType(); if (count < 0) { - if (mission->IsMission() && type == MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION && InAllTargets(value)) { + if (mission->IsMission() && type == eMissionTaskType::GATHER && InAllTargets(value)) { if (parameters.size() > 0 && (parameters[0] & 1) != 0) { return; } @@ -218,10 +220,10 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& std::vector settings; switch (type) { - case MissionTaskType::MISSION_TASK_TYPE_UNKNOWN: + case eMissionTaskType::UNKNOWN: break; - case MissionTaskType::MISSION_TASK_TYPE_ACTIVITY: + case eMissionTaskType::ACTIVITY: { if (InAllTargets(value)) { AddProgress(count); @@ -236,7 +238,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - activity = static_cast(entity->GetComponent(COMPONENT_TYPE_REBUILD)); + activity = static_cast(entity->GetComponent(eReplicaComponentType::QUICK_BUILD)); if (activity == nullptr) { break; } @@ -256,8 +258,8 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_FOOD: - case MissionTaskType::MISSION_TASK_TYPE_MISSION_INTERACTION: + case eMissionTaskType::USE_ITEM: + case eMissionTaskType::TALK_TO_NPC: { if (GetTarget() != value) break; @@ -266,7 +268,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_EMOTE: + case eMissionTaskType::EMOTE: { if (!InParameters(value)) break; @@ -287,7 +289,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_SKILL: + case eMissionTaskType::USE_SKILL: { // This is a complicated check because for some missions we need to check for the associate being in the parameters instead of the value being in the parameters. if (associate == LWOOBJID_EMPTY && GetAllTargets().size() == 1 && GetAllTargets()[0] == -1) { @@ -298,7 +300,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_MINIGAME: + case eMissionTaskType::PERFORM_ACTIVITY: { auto* minigameManager = EntityManager::Instance()->GetEntity(associate); if (minigameManager == nullptr) @@ -327,7 +329,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_VISIT_PROPERTY: + case eMissionTaskType::VISIT_PROPERTY: { if (!InAllTargets(value)) break; @@ -340,7 +342,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_ENVIRONMENT: + case eMissionTaskType::COLLECTION: { if (!InAllTargets(value)) break; @@ -375,7 +377,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_LOCATION: + case eMissionTaskType::EXPLORE: { if (info->targetGroup != targets) break; @@ -384,9 +386,9 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_RACING: + case eMissionTaskType::RACING: { - // The meaning of associate can be found in RacingTaskParam.h + // The meaning of associate can be found in eRacingTaskParam.h if (parameters.empty()) break; if (!InAllTargets(dZoneManager::Instance()->GetZone()->GetWorldID()) && !(parameters[0] == 4 || parameters[0] == 5) && !InAllTargets(value)) break; @@ -426,15 +428,15 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_PET_TAMING: - case MissionTaskType::MISSION_TASK_TYPE_SCRIPT: - case MissionTaskType::MISSION_TASK_TYPE_NON_MISSION_INTERACTION: - case MissionTaskType::MISSION_TASK_TYPE_MISSION_COMPLETE: - case MissionTaskType::MISSION_TASK_TYPE_POWERUP: - case MissionTaskType::MISSION_TASK_TYPE_SMASH: - case MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION: - case MissionTaskType::MISSION_TASK_TYPE_PLAYER_FLAG: - case MissionTaskType::MISSION_TASK_TYPE_EARN_REPUTATION: + case eMissionTaskType::PET_TAMING: + case eMissionTaskType::SCRIPT: + case eMissionTaskType::INTERACT: + case eMissionTaskType::META: + case eMissionTaskType::POWERUP: + case eMissionTaskType::SMASH: + case eMissionTaskType::GATHER: + case eMissionTaskType::PLAYER_FLAG: + case eMissionTaskType::EARN_REPUTATION: { if (!InAllTargets(value)) break; @@ -442,7 +444,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& break; } - case MissionTaskType::MISSION_TASK_TYPE_PLACE_MODEL: + case eMissionTaskType::PLACE_MODEL: { AddProgress(count); break; diff --git a/dGame/dMission/MissionTask.h b/dGame/dMission/MissionTask.h index ea4b8a05..f867b632 100644 --- a/dGame/dMission/MissionTask.h +++ b/dGame/dMission/MissionTask.h @@ -4,9 +4,9 @@ #define MISSIONTASK_H #include "CDMissionTasksTable.h" -#include "MissionTaskType.h" #include "dCommonVars.h" +enum class eMissionTaskType : int; class Mission; /** @@ -57,7 +57,7 @@ public: * Returns the type of this task * @return the type of this task */ - MissionTaskType GetType() const; + eMissionTaskType GetType() const; /** * Returns the value that should be progressed to, to complete the mission (the target value) diff --git a/dGame/dMission/MissionTaskType.h b/dGame/dMission/MissionTaskType.h deleted file mode 100644 index 6c9b2668..00000000 --- a/dGame/dMission/MissionTaskType.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#ifndef MISSIONTASKTYPE_H -#define MISSIONTASKTYPE_H - -//! An enum for mission task types -enum class MissionTaskType : int { - MISSION_TASK_TYPE_UNKNOWN = -1, //!< The task type is unknown - MISSION_TASK_TYPE_SMASH = 0, //!< A task for smashing something - MISSION_TASK_TYPE_SCRIPT = 1, //!< A task handled by a server LUA script - MISSION_TASK_TYPE_ACTIVITY = 2, //!< A task for completing a quickbuild - MISSION_TASK_TYPE_ENVIRONMENT = 3, //!< A task for something in the environment - MISSION_TASK_TYPE_MISSION_INTERACTION = 4, //!< A task for interacting with a mission - MISSION_TASK_TYPE_EMOTE = 5, //!< A task for playing an emote - MISSION_TASK_TYPE_FOOD = 9, //!< A task for eating food - MISSION_TASK_TYPE_SKILL = 10, //!< A task for performing a skill - MISSION_TASK_TYPE_ITEM_COLLECTION = 11, //!< A task for collecting an item - MISSION_TASK_TYPE_LOCATION = 12, //!< A task for finding a location - MISSION_TASK_TYPE_MINIGAME = 14, //!< A task for doing something in a minigame - MISSION_TASK_TYPE_NON_MISSION_INTERACTION = 15, //!< A task for interacting with a non-mission - MISSION_TASK_TYPE_MISSION_COMPLETE = 16, //!< A task for completing a mission - MISSION_TASK_TYPE_EARN_REPUTATION = 17, //!< A task for earning reputation - MISSION_TASK_TYPE_POWERUP = 21, //!< A task for collecting a powerup - MISSION_TASK_TYPE_PET_TAMING = 22, //!< A task for taming a pet - MISSION_TASK_TYPE_RACING = 23, //!< A task for racing - MISSION_TASK_TYPE_PLAYER_FLAG = 24, //!< A task for setting a player flag - MISSION_TASK_TYPE_PLACE_MODEL = 25, //!< A task for picking up a model - MISSION_TASK_TYPE_VISIT_PROPERTY = 30 //!< A task for visiting a property -}; - -#endif diff --git a/dGame/dMission/RacingTaskParam.h b/dGame/dMission/RacingTaskParam.h deleted file mode 100644 index 5958cb5a..00000000 --- a/dGame/dMission/RacingTaskParam.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -enum class RacingTaskParam : int32_t { - RACING_TASK_PARAM_FINISH_WITH_PLACEMENT = 1, // + +enum class BehaviorState : uint32_t { + HOME_STATE = 0, //!< The HOME behavior state + CIRCLE_STATE, //!< The CIRCLE behavior state + SQUARE_STATE, //!< The SQUARE behavior state + DIAMOND_STATE, //!< The DIAMOND behavior state + TRIANGLE_STATE, //!< The TRIANGLE behavior state + STAR_STATE //!< The STAR behavior state +}; + +#endif //!__BEHAVIORSTATES__H__ diff --git a/dGame/dPropertyBehaviors/BlockDefinition.cpp b/dGame/dPropertyBehaviors/BlockDefinition.cpp new file mode 100644 index 00000000..2950ac82 --- /dev/null +++ b/dGame/dPropertyBehaviors/BlockDefinition.cpp @@ -0,0 +1,9 @@ +#include "BlockDefinition.h" + +BlockDefinition BlockDefinition::blockDefinitionDefault{}; + +BlockDefinition::BlockDefinition(std::string defaultValue, float minimumValue, float maximumValue) { + this->defaultValue = defaultValue; + this->minimumValue = minimumValue; + this->maximumValue = maximumValue; +} diff --git a/dGame/dPropertyBehaviors/BlockDefinition.h b/dGame/dPropertyBehaviors/BlockDefinition.h new file mode 100644 index 00000000..3a5a6bf1 --- /dev/null +++ b/dGame/dPropertyBehaviors/BlockDefinition.h @@ -0,0 +1,25 @@ +#ifndef __BLOCKDEFINITION__H__ +#define __BLOCKDEFINITION__H__ + +#include + +class AMFArrayValue; + +class BlockDefinition { +public: + BlockDefinition(std::string defaultValue = "", float minimumValue = 0.0f, float maximumValue = 0.0f); + static BlockDefinition blockDefinitionDefault; + + std::string& GetDefaultValue() { return defaultValue; }; + float GetMinimumValue() { return minimumValue; }; + float GetMaximumValue() { return maximumValue; }; + void SetDefaultValue(std::string value) { defaultValue = value; }; + void SetMinimumValue(float value) { minimumValue = value; }; + void SetMaximumValue(float value) { maximumValue = value; }; +private: + std::string defaultValue; + float minimumValue; + float maximumValue; +}; + +#endif //!__BLOCKDEFINITION__H__ diff --git a/dGame/dPropertyBehaviors/CMakeLists.txt b/dGame/dPropertyBehaviors/CMakeLists.txt index 4f5d60aa..5e33a5f5 100644 --- a/dGame/dPropertyBehaviors/CMakeLists.txt +++ b/dGame/dPropertyBehaviors/CMakeLists.txt @@ -1,4 +1,12 @@ set(DGAME_DPROPERTYBEHAVIORS_SOURCES + "BlockDefinition.cpp" "ControlBehaviors.cpp" - PARENT_SCOPE ) + +add_subdirectory(ControlBehaviorMessages) + +foreach(file ${DGAME_DPROPERTYBEHAVIORS_CONTROLBEHAVIORMESSAGES}) + set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} "ControlBehaviorMessages/${file}") +endforeach() + +set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} PARENT_SCOPE) diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp new file mode 100644 index 00000000..7da286b0 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp @@ -0,0 +1,31 @@ +#include "Action.h" + +Action::Action() { + type = ""; + valueParameterName = ""; + valueParameterString = ""; + valueParameterDouble = 0.0; +} + +Action::Action(AMFArrayValue* arguments) { + type = ""; + valueParameterName = ""; + valueParameterString = ""; + valueParameterDouble = 0.0; + for (auto& typeValueMap : arguments->GetAssociativeMap()) { + if (typeValueMap.first == "Type") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + type = static_cast(typeValueMap.second)->GetStringValue(); + } else { + valueParameterName = typeValueMap.first; + // Message is the only known string parameter + if (valueParameterName == "Message") { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFString) continue; + valueParameterString = static_cast(typeValueMap.second)->GetStringValue(); + } else { + if (typeValueMap.second->GetValueType() != AMFValueType::AMFDouble) continue; + valueParameterDouble = static_cast(typeValueMap.second)->GetDoubleValue(); + } + } + } +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h new file mode 100644 index 00000000..c97b4050 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h @@ -0,0 +1,25 @@ +#ifndef __ACTION__H__ +#define __ACTION__H__ + +#include "BehaviorMessageBase.h" + +/** + * @brief Sent if a ControlBehavior message has an Action associated with it + * + */ +class Action { +public: + Action(); + Action(AMFArrayValue* arguments); + const std::string& GetType() { return type; }; + const std::string& GetValueParameterName() { return valueParameterName; }; + const std::string& GetValueParameterString() { return valueParameterString; }; + const double GetValueParameterDouble() { return valueParameterDouble; }; +private: + std::string type; + std::string valueParameterName; + std::string valueParameterString; + double valueParameterDouble; +}; + +#endif //!__ACTION__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp new file mode 100644 index 00000000..480eef45 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp @@ -0,0 +1,31 @@ +#include "ActionContext.h" + +#include + +#include "AMFFormat.h" + +ActionContext::ActionContext() { + stripId = 0; + stateId = BehaviorState::HOME_STATE; +} + +ActionContext::ActionContext(AMFArrayValue* arguments, std::string customStateKey, std::string customStripKey) { + stripId = 0; + stateId = BehaviorState::HOME_STATE; + stripId = GetStripIdFromArgument(arguments, customStripKey); + stateId = GetBehaviorStateFromArgument(arguments, customStateKey); +} + +BehaviorState ActionContext::GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key) { + auto* stateIDValue = arguments->FindValue(key); + if (!stateIDValue) throw std::invalid_argument("Unable to find behavior state from argument \"" + key + "\""); + + return static_cast(stateIDValue->GetDoubleValue()); +} + +StripId ActionContext::GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key) { + auto* stripIdValue = arguments->FindValue(key); + if (!stripIdValue) throw std::invalid_argument("Unable to find strip ID from argument \"" + key + "\""); + + return static_cast(stripIdValue->GetDoubleValue()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h new file mode 100644 index 00000000..5f46fd8c --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h @@ -0,0 +1,26 @@ +#ifndef __ACTIONCONTEXT__H__ +#define __ACTIONCONTEXT__H__ + +#include "BehaviorStates.h" +#include "dCommonVars.h" + +class AMFArrayValue; + +/** + * @brief Sent if contextual State and Strip informationis needed for a ControlBehaviors message + * + */ +class ActionContext { +public: + ActionContext(); + ActionContext(AMFArrayValue* arguments, std::string customStateKey = "stateID", std::string customStripKey = "stripID"); + const StripId GetStripId() { return stripId; }; + const BehaviorState GetStateId() { return stateId; }; +private: + BehaviorState GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key); + StripId GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key); + StripId stripId; + BehaviorState stateId; +}; + +#endif //!__ACTIONCONTEXT__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp new file mode 100644 index 00000000..4fc7f82b --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp @@ -0,0 +1,13 @@ +#include "AddActionMessage.h" + +AddActionMessage::AddActionMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + actionIndex = GetActionIndexFromArgument(arguments); + + auto* actionValue = arguments->FindValue("action"); + if (!actionValue) return; + + action = Action(actionValue); + + Game::logger->LogDebug("AddActionMessage", "actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i", actionIndex, actionContext.GetStripId(), actionContext.GetStateId(), action.GetType().c_str(), action.GetValueParameterName().c_str(), action.GetValueParameterString().c_str(), action.GetValueParameterDouble(), behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h new file mode 100644 index 00000000..4faf6a53 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h @@ -0,0 +1,26 @@ +#ifndef __ADDACTIONMESSAGE__H__ +#define __ADDACTIONMESSAGE__H__ + +#include "Action.h" +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Send if a player takes an Action A from the toolbox and adds it to an already existing strip + * + */ +class AddActionMessage : public BehaviorMessageBase { +public: + AddActionMessage(AMFArrayValue* arguments); + const uint32_t GetActionIndex() { return actionIndex; }; + Action GetAction() { return action; }; + ActionContext GetActionContext() { return actionContext; }; +private: + uint32_t actionIndex; + ActionContext actionContext; + Action action; +}; + +#endif //!__ADDACTIONMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp new file mode 100644 index 00000000..4f2123b4 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp @@ -0,0 +1,11 @@ +#include "AddMessage.h" + +AddMessage::AddMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + behaviorIndex = 0; + auto* behaviorIndexValue = arguments->FindValue("BehaviorIndex"); + + if (!behaviorIndexValue) return; + + behaviorIndex = static_cast(behaviorIndexValue->GetDoubleValue()); + Game::logger->LogDebug("AddMessage", "behaviorId %i index %i", behaviorId, behaviorIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h new file mode 100644 index 00000000..a46d5f98 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h @@ -0,0 +1,18 @@ +#ifndef __ADDMESSAGE__H__ +#define __ADDMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +/** + * @brief Sent when a player adds a Behavior A from their inventory to a model. + * + */ +class AddMessage : public BehaviorMessageBase { +public: + AddMessage(AMFArrayValue* arguments); + const uint32_t GetBehaviorIndex() { return behaviorIndex; }; +private: + uint32_t behaviorIndex; +}; + +#endif //!__ADDMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp new file mode 100644 index 00000000..c4729c57 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp @@ -0,0 +1,25 @@ +#include "AddStripMessage.h" + +#include "Action.h" + +AddStripMessage::AddStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + + position = StripUiPosition(arguments); + + auto* strip = arguments->FindValue("strip"); + if (!strip) return; + + auto* actions = strip->FindValue("actions"); + if (!actions) return; + + for (uint32_t actionNumber = 0; actionNumber < actions->GetDenseValueSize(); actionNumber++) { + auto* actionValue = actions->GetValueAt(actionNumber); + if (!actionValue) continue; + + actionsToAdd.push_back(Action(actionValue)); + + Game::logger->LogDebug("AddStripMessage", "xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", position.GetX(), position.GetY(), actionContext.GetStripId(), actionContext.GetStateId(), behaviorId, actionsToAdd.back().GetType().c_str(), actionsToAdd.back().GetValueParameterName().c_str(), actionsToAdd.back().GetValueParameterString().c_str(), actionsToAdd.back().GetValueParameterDouble()); + } + Game::logger->Log("AddStripMessage", "number of actions %i", actionsToAdd.size()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h new file mode 100644 index 00000000..db75aef7 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h @@ -0,0 +1,31 @@ +#ifndef __ADDSTRIPMESSAGE__H__ +#define __ADDSTRIPMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" +#include "StripUiPosition.h" + +#include + +class Action; +class AMFArrayValue; + +/** + * @brief Sent in 2 contexts: + * A player adds an Action A from their toolbox without attaching it to an existing Strip. In this case, only 1 action is sent. + * A player moves a Strip from BehaviorState A directly to BehaviorState B. In this case, a list of actions are sent. + * + */ +class AddStripMessage : public BehaviorMessageBase { +public: + AddStripMessage(AMFArrayValue* arguments); + StripUiPosition GetPosition() { return position; }; + ActionContext GetActionContext() { return actionContext; }; + std::vector GetActionsToAdd() { return actionsToAdd; }; +private: + StripUiPosition position; + ActionContext actionContext; + std::vector actionsToAdd; +}; + +#endif //!__ADDSTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp new file mode 100644 index 00000000..b3d98d51 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp @@ -0,0 +1,33 @@ +#include "BehaviorMessageBase.h" + +#include "AMFFormat.h" +#include "BehaviorStates.h" +#include "dCommonVars.h" + +BehaviorMessageBase::BehaviorMessageBase(AMFArrayValue* arguments) { + behaviorId = 0; + behaviorId = GetBehaviorIdFromArgument(arguments); +} + +int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(AMFArrayValue* arguments) { + const auto* key = "BehaviorID"; + auto* behaviorIDValue = arguments->FindValue(key); + int32_t behaviorID = -1; + + if (behaviorIDValue) { + behaviorID = std::stoul(behaviorIDValue->GetStringValue()); + } else if (!arguments->FindValue(key)) { + throw std::invalid_argument("Unable to find behavior ID"); + } + + return behaviorID; +} + +uint32_t BehaviorMessageBase::GetActionIndexFromArgument(AMFArrayValue* arguments, const std::string& keyName) { + auto* actionIndexAmf = arguments->FindValue(keyName); + if (!actionIndexAmf) { + throw std::invalid_argument("Unable to find actionIndex"); + } + + return static_cast(actionIndexAmf->GetDoubleValue()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h new file mode 100644 index 00000000..13b00a35 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h @@ -0,0 +1,29 @@ +#ifndef __BEHAVIORMESSAGEBASE__H__ +#define __BEHAVIORMESSAGEBASE__H__ + +#include +#include + +#include "AMFFormat.h" +#include "dCommonVars.h" + +#include "Game.h" +#include "dLogger.h" + +enum class BehaviorState : uint32_t; + +/** + * @brief The behaviorID target of this ControlBehaviors message + * + */ +class BehaviorMessageBase { +public: + const uint32_t GetBehaviorId() { return behaviorId; }; +protected: + BehaviorMessageBase(AMFArrayValue* arguments); + int32_t GetBehaviorIdFromArgument(AMFArrayValue* arguments); + uint32_t GetActionIndexFromArgument(AMFArrayValue* arguments, const std::string& keyName = "actionIndex"); + int32_t behaviorId = -1; +}; + +#endif //!__BEHAVIORMESSAGEBASE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt b/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt new file mode 100644 index 00000000..49b0f460 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/CMakeLists.txt @@ -0,0 +1,20 @@ +set(DGAME_DPROPERTYBEHAVIORS_CONTROLBEHAVIORMESSAGES + "Action.cpp" + "ActionContext.cpp" + "AddActionMessage.cpp" + "AddMessage.cpp" + "AddStripMessage.cpp" + "BehaviorMessageBase.cpp" + "MergeStripsMessage.cpp" + "MigrateActionsMessage.cpp" + "MoveToInventoryMessage.cpp" + "RearrangeStripMessage.cpp" + "RemoveActionsMessage.cpp" + "RemoveStripMessage.cpp" + "RenameMessage.cpp" + "SplitStripMessage.cpp" + "StripUiPosition.cpp" + "UpdateActionMessage.cpp" + "UpdateStripUiMessage.cpp" + PARENT_SCOPE +) diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp new file mode 100644 index 00000000..df50641a --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp @@ -0,0 +1,11 @@ +#include "MergeStripsMessage.h" + +MergeStripsMessage::MergeStripsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); + + destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); + dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); + + Game::logger->LogDebug("MergeStripsMessage", "srcstripId %i dststripId %i srcstateId %i dststateId %i dstactionIndex %i behaviorId %i", sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), dstActionIndex, behaviorId); +} + diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h new file mode 100644 index 00000000..0aff7f3a --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h @@ -0,0 +1,25 @@ +#ifndef __MERGESTRIPSMESSAGE__H__ +#define __MERGESTRIPSMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player adds the first Action of Strip A to a Strip B + * + */ +class MergeStripsMessage : public BehaviorMessageBase { +public: + MergeStripsMessage(AMFArrayValue* arguments); + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + ActionContext GetSourceActionContext() { return sourceActionContext; }; + ActionContext GetDestinationActionContext() { return destinationActionContext; }; +private: + ActionContext sourceActionContext; + ActionContext destinationActionContext; + uint32_t dstActionIndex; +}; + +#endif //!__MERGESTRIPSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp new file mode 100644 index 00000000..08f830a4 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp @@ -0,0 +1,11 @@ +#include "MigrateActionsMessage.h" + +MigrateActionsMessage::MigrateActionsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); + srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); + + destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); + dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); + + Game::logger->LogDebug("MigrateActionsMessage", "srcactionIndex %i dstactionIndex %i srcstripId %i dststripId %i srcstateId %i dststateId %i behaviorId %i", srcActionIndex, dstActionIndex, sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h new file mode 100644 index 00000000..f60e8748 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h @@ -0,0 +1,27 @@ +#ifndef __MIGRATEACTIONSMESSAGE__H__ +#define __MIGRATEACTIONSMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player moves an Action after the first Action to a different Strip + * + */ +class MigrateActionsMessage : public BehaviorMessageBase { +public: + MigrateActionsMessage(AMFArrayValue* arguments); + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + ActionContext GetSourceActionContext() { return sourceActionContext; }; + ActionContext GetDestinationActionContext() { return destinationActionContext; }; +private: + ActionContext sourceActionContext; + ActionContext destinationActionContext; + uint32_t srcActionIndex; + uint32_t dstActionIndex; +}; + +#endif //!__MIGRATEACTIONSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp new file mode 100644 index 00000000..92700076 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp @@ -0,0 +1,9 @@ +#include "MoveToInventoryMessage.h" + +MoveToInventoryMessage::MoveToInventoryMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + auto* behaviorIndexValue = arguments->FindValue("BehaviorIndex"); + if (!behaviorIndexValue) return; + + behaviorIndex = static_cast(behaviorIndexValue->GetDoubleValue()); + Game::logger->LogDebug("MoveToInventoryMessage", "behaviorId %i behaviorIndex %i", behaviorId, behaviorIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h new file mode 100644 index 00000000..c48f7d17 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h @@ -0,0 +1,21 @@ +#ifndef __MOVETOINVENTORYMESSAGE__H__ +#define __MOVETOINVENTORYMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player moves a Behavior A at position B to their inventory. + * + */ +#pragma warning("This Control Behavior Message does not have a test yet. Non-developers can ignore this warning.") +class MoveToInventoryMessage : public BehaviorMessageBase { +public: + MoveToInventoryMessage(AMFArrayValue* arguments); + const uint32_t GetBehaviorIndex() { return behaviorIndex; }; +private: + uint32_t behaviorIndex; +}; + +#endif //!__MOVETOINVENTORYMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp new file mode 100644 index 00000000..4018a423 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp @@ -0,0 +1,10 @@ +#include "RearrangeStripMessage.h" + +RearrangeStripMessage::RearrangeStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); + + dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); + + Game::logger->LogDebug("RearrangeStripMessage", "srcactionIndex %i dstactionIndex %i stripId %i behaviorId %i stateId %i", srcActionIndex, dstActionIndex, actionContext.GetStripId(), behaviorId, actionContext.GetStateId()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h new file mode 100644 index 00000000..46819404 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h @@ -0,0 +1,23 @@ +#ifndef __REARRANGESTRIPMESSAGE__H__ +#define __REARRANGESTRIPMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +/** + * @brief Sent when a player moves an Action around in the same strip + * + */ +class RearrangeStripMessage : public BehaviorMessageBase { +public: + RearrangeStripMessage(AMFArrayValue* arguments); + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + const uint32_t GetDstActionIndex() { return dstActionIndex; }; + ActionContext GetActionContext() { return actionContext; }; +private: + ActionContext actionContext; + uint32_t srcActionIndex; + uint32_t dstActionIndex; +}; + +#endif //!__REARRANGESTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp new file mode 100644 index 00000000..8f00d2b0 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp @@ -0,0 +1,8 @@ +#include "RemoveActionsMessage.h" + +RemoveActionsMessage::RemoveActionsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + actionIndex = GetActionIndexFromArgument(arguments); + + Game::logger->LogDebug("RemoveActionsMessage", "behaviorId %i actionIndex %i stripId %i stateId %i", behaviorId, actionIndex, actionContext.GetStripId(), actionContext.GetStateId()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h new file mode 100644 index 00000000..457ddba8 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h @@ -0,0 +1,23 @@ +#ifndef __REMOVEACTIONSMESSAGE__H__ +#define __REMOVEACTIONSMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player removes any Action after the first one from a Strip + * + */ +class RemoveActionsMessage : public BehaviorMessageBase { +public: + RemoveActionsMessage(AMFArrayValue* arguments); + const uint32_t GetActionIndex() { return actionIndex; }; + ActionContext GetActionContext() { return actionContext; }; +private: + ActionContext actionContext; + uint32_t actionIndex; +}; + +#endif //!__REMOVEACTIONSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp new file mode 100644 index 00000000..40288b07 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp @@ -0,0 +1,7 @@ +#include "RemoveStripMessage.h" + +RemoveStripMessage::RemoveStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + + Game::logger->LogDebug("RemoveStripMessage", "stripId %i stateId %i behaviorId %i", actionContext.GetStripId(), actionContext.GetStateId(), behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h new file mode 100644 index 00000000..36e2e401 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h @@ -0,0 +1,19 @@ +#ifndef __REMOVESTRIPMESSAGE__H__ +#define __REMOVESTRIPMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +/** + * @brief Sent when a player removes the first Action from a strip. + * + */ +class RemoveStripMessage : public BehaviorMessageBase { +public: + RemoveStripMessage(AMFArrayValue* arguments); + ActionContext GetActionContext() { return actionContext; }; +private: + ActionContext actionContext; +}; + +#endif //!__REMOVESTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp new file mode 100644 index 00000000..0ea3b6d6 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp @@ -0,0 +1,9 @@ +#include "RenameMessage.h" + +RenameMessage::RenameMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + auto* nameAmf = arguments->FindValue("Name"); + if (!nameAmf) return; + + name = nameAmf->GetStringValue(); + Game::logger->LogDebug("RenameMessage", "behaviorId %i n %s", behaviorId, name.c_str()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h new file mode 100644 index 00000000..ba181f63 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h @@ -0,0 +1,20 @@ +#ifndef __RENAMEMESSAGE__H__ +#define __RENAMEMESSAGE__H__ + +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player renames this behavior + * + */ +class RenameMessage : public BehaviorMessageBase { +public: + RenameMessage(AMFArrayValue* arguments); + const std::string& GetName() { return name; }; +private: + std::string name; +}; + +#endif //!__RENAMEMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp new file mode 100644 index 00000000..b4601a17 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp @@ -0,0 +1,11 @@ +#include "SplitStripMessage.h" + +SplitStripMessage::SplitStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); + srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); + + destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); + destinationPosition = StripUiPosition(arguments, "dstStripUI"); + + Game::logger->LogDebug("SplitStripMessage", "behaviorId %i xPosition %f yPosition %f sourceStrip %i destinationStrip %i sourceState %i destinationState %i srcActindex %i", behaviorId, destinationPosition.GetX(), destinationPosition.GetY(), sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), srcActionIndex); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h new file mode 100644 index 00000000..9210efb0 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h @@ -0,0 +1,28 @@ +#ifndef __SPLITSTRIPMESSAGE__H__ +#define __SPLITSTRIPMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" +#include "StripUiPosition.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player takes an Action from Strip A and does not add it to an existing strip + * + */ +class SplitStripMessage : public BehaviorMessageBase { +public: + SplitStripMessage(AMFArrayValue* arguments); + ActionContext GetSourceActionContext() { return sourceActionContext; }; + ActionContext GetDestinationActionContext() { return destinationActionContext; }; + const uint32_t GetSrcActionIndex() { return srcActionIndex; }; + StripUiPosition GetPosition() { return destinationPosition; }; +private: + ActionContext sourceActionContext; + ActionContext destinationActionContext; + uint32_t srcActionIndex; + StripUiPosition destinationPosition; +}; + +#endif //!__SPLITSTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp new file mode 100644 index 00000000..4ddccc55 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp @@ -0,0 +1,22 @@ +#include "StripUiPosition.h" + +#include "AMFFormat.h" + +StripUiPosition::StripUiPosition() { + xPosition = 0.0; + yPosition = 0.0; +} + +StripUiPosition::StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName) { + xPosition = 0.0; + yPosition = 0.0; + auto* uiArray = arguments->FindValue(uiKeyName); + if (!uiArray) return; + + auto* xPositionValue = uiArray->FindValue("x"); + auto* yPositionValue = uiArray->FindValue("y"); + if (!xPositionValue || !yPositionValue) return; + + yPosition = yPositionValue->GetDoubleValue(); + xPosition = xPositionValue->GetDoubleValue(); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h new file mode 100644 index 00000000..809f8890 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h @@ -0,0 +1,21 @@ +#ifndef __STRIPUIPOSITION__H__ +#define __STRIPUIPOSITION__H__ + +class AMFArrayValue; + +/** + * @brief The position of the first Action in a Strip + * + */ +class StripUiPosition { +public: + StripUiPosition(); + StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName = "ui"); + double GetX() { return xPosition; }; + double GetY() { return yPosition; }; +private: + double xPosition; + double yPosition; +}; + +#endif //!__STRIPUIPOSITION__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp new file mode 100644 index 00000000..53e2d570 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp @@ -0,0 +1,15 @@ +#include "UpdateActionMessage.h" + +#include "Action.h" + +UpdateActionMessage::UpdateActionMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + actionContext = ActionContext(arguments); + + auto* actionValue = arguments->FindValue("action"); + if (!actionValue) return; + + action = Action(actionValue); + actionIndex = GetActionIndexFromArgument(arguments); + + Game::logger->LogDebug("UpdateActionMessage", "type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", action.GetType().c_str(), action.GetValueParameterName().c_str(), action.GetValueParameterString().c_str(), action.GetValueParameterDouble(), behaviorId, actionIndex, actionContext.GetStripId(), actionContext.GetStateId()); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h new file mode 100644 index 00000000..0a03ce9e --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h @@ -0,0 +1,26 @@ +#ifndef __UPDATEACTIONMESSAGE__H__ +#define __UPDATEACTIONMESSAGE__H__ + +#include "Action.h" +#include "ActionContext.h" +#include "BehaviorMessageBase.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player updates the value in an Action + * + */ +class UpdateActionMessage : public BehaviorMessageBase { +public: + UpdateActionMessage(AMFArrayValue* arguments); + const uint32_t GetActionIndex() { return actionIndex; }; + ActionContext GetActionContext() { return actionContext; }; + Action GetAction() { return action; }; +private: + uint32_t actionIndex; + ActionContext actionContext; + Action action; +}; + +#endif //!__UPDATEACTIONMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp new file mode 100644 index 00000000..073db9b4 --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp @@ -0,0 +1,8 @@ +#include "UpdateStripUiMessage.h" + +UpdateStripUiMessage::UpdateStripUiMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { + position = StripUiPosition(arguments); + actionContext = ActionContext(arguments); + + Game::logger->LogDebug("UpdateStripUIMessage", "xPosition %f yPosition %f stripId %i stateId %i behaviorId %i", position.GetX(), position.GetY(), actionContext.GetStripId(), actionContext.GetStateId(), behaviorId); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h new file mode 100644 index 00000000..6d96f90c --- /dev/null +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h @@ -0,0 +1,24 @@ +#ifndef __UPDATESTRIPUIMESSAGE__H__ +#define __UPDATESTRIPUIMESSAGE__H__ + +#include "ActionContext.h" +#include "BehaviorMessageBase.h" +#include "StripUiPosition.h" + +class AMFArrayValue; + +/** + * @brief Sent when a player moves the first Action in a Strip + * + */ +class UpdateStripUiMessage : public BehaviorMessageBase { +public: + UpdateStripUiMessage(AMFArrayValue* arguments); + StripUiPosition GetPosition() { return position; }; + ActionContext GetActionContext() { return actionContext; }; +private: + StripUiPosition position; + ActionContext actionContext; +}; + +#endif //!__UPDATESTRIPUIMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.cpp b/dGame/dPropertyBehaviors/ControlBehaviors.cpp index 4e922ee0..dfb22b59 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviors.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviors.cpp @@ -5,59 +5,63 @@ #include "Game.h" #include "GameMessages.h" #include "ModelComponent.h" +#include "../../dWorldServer/ObjectIDManager.h" #include "dLogger.h" +#include "BehaviorStates.h" +#include "AssetManager.h" +#include "BlockDefinition.h" +#include "User.h" +#include "tinyxml2.h" +#include "CDClientDatabase.h" -void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner) { - if (!modelEntity || !modelOwner || !arguments) return; +// Message includes +#include "Action.h" +#include "AddActionMessage.h" +#include "AddStripMessage.h" +#include "AddMessage.h" +#include "MigrateActionsMessage.h" +#include "MoveToInventoryMessage.h" +#include "MergeStripsMessage.h" +#include "RearrangeStripMessage.h" +#include "RemoveActionsMessage.h" +#include "RemoveStripMessage.h" +#include "RenameMessage.h" +#include "SplitStripMessage.h" +#include "UpdateActionMessage.h" +#include "UpdateStripUiMessage.h" - if (command == "sendBehaviorListToClient") - SendBehaviorListToClient(modelEntity, sysAddr, modelOwner); - else if (command == "modelTypeChanged") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "toggleExecutionUpdates") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "addStrip") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "removeStrip") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "mergeStrips") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "splitStrip") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "updateStripUI") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "addAction") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "migrateActions") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "rearrangeStrip") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "add") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "removeActions") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "rename") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "sendBehaviorBlocksToClient") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "moveToInventory") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else if (command == "updateAction") - Game::logger->Log("ControlBehaviors", "Got command %s but is not implemented!", command.c_str()); - else - Game::logger->Log("ControlBehaviors", "Unknown behavior command (%s)\n", command.c_str()); +void ControlBehaviors::RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr) { + // auto behavior = modelComponent->FindBehavior(behaviorID); + // if (behavior->GetBehaviorID() == -1 || behavior->GetShouldSetNewID()) { + // ObjectIDManager::Instance()->RequestPersistentID( + // [behaviorID, behavior, modelComponent, modelOwner, sysAddr](uint32_t persistentId) { + // behavior->SetShouldGetNewID(false); + // behavior->SetIsTemplated(false); + // behavior->SetBehaviorID(persistentId); + + // // This updates the behavior ID of the behavior should this be a new behavior + // AMFArrayValue args; + + // AMFStringValue* behaviorIDString = new AMFStringValue(); + // behaviorIDString->SetStringValue(std::to_string(persistentId)); + // args.InsertValue("behaviorID", behaviorIDString); + + // AMFStringValue* objectIDAsString = new AMFStringValue(); + // objectIDAsString->SetStringValue(std::to_string(modelComponent->GetParent()->GetObjectID())); + // args.InsertValue("objectID", objectIDAsString); + + // GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorID", &args); + // ControlBehaviors::SendBehaviorListToClient(modelComponent->GetParent(), sysAddr, modelOwner); + // }); + // } } -void ControlBehaviors::SendBehaviorListToClient( - Entity* modelEntity, - const SystemAddress& sysAddr, - Entity* modelOwner - ) { +void ControlBehaviors::SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner) { auto* modelComponent = modelEntity->GetComponent(); if (!modelComponent) return; - AMFArrayValue behaviorsToSerialize; + AMFArrayValue behaviorsToSerialize; AMFArrayValue* behaviors = new AMFArrayValue(); // Empty for now @@ -79,3 +83,380 @@ void ControlBehaviors::SendBehaviorListToClient( behaviorsToSerialize.InsertValue("objectID", amfStringValueForObjectID); GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorList", &behaviorsToSerialize); } + +void ControlBehaviors::ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent) { + auto* modelTypeAmf = arguments->FindValue("ModelType"); + if (!modelTypeAmf) return; + + uint32_t modelType = static_cast(modelTypeAmf->GetDoubleValue()); + + //TODO Update the model type here +} + +void ControlBehaviors::ToggleExecutionUpdates() { + //TODO do something with this info +} + +void ControlBehaviors::AddStrip(AMFArrayValue* arguments) { + AddStripMessage addStripMessage(arguments); +} + +void ControlBehaviors::RemoveStrip(AMFArrayValue* arguments) { + RemoveStripMessage removeStrip(arguments); +} + +void ControlBehaviors::MergeStrips(AMFArrayValue* arguments) { + MergeStripsMessage mergeStripsMessage(arguments); +} + +void ControlBehaviors::SplitStrip(AMFArrayValue* arguments) { + SplitStripMessage splitStripMessage(arguments); +} + +void ControlBehaviors::UpdateStripUI(AMFArrayValue* arguments) { + UpdateStripUiMessage updateStripUiMessage(arguments); +} + +void ControlBehaviors::AddAction(AMFArrayValue* arguments) { + AddActionMessage addActionMessage(arguments); +} + +void ControlBehaviors::MigrateActions(AMFArrayValue* arguments) { + MigrateActionsMessage migrateActionsMessage(arguments); +} + +void ControlBehaviors::RearrangeStrip(AMFArrayValue* arguments) { + RearrangeStripMessage rearrangeStripMessage(arguments); +} + +void ControlBehaviors::Add(AMFArrayValue* arguments) { + AddMessage addMessage(arguments); +} + +void ControlBehaviors::RemoveActions(AMFArrayValue* arguments) { + RemoveActionsMessage removeActionsMessage(arguments); +} + +void ControlBehaviors::Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { + RenameMessage renameMessage(arguments); +} + +// TODO This is also supposed to serialize the state of the behaviors in progress but those aren't implemented yet +void ControlBehaviors::SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { + // uint32_t behaviorID = ControlBehaviors::GetBehaviorIDFromArgument(arguments); + + // auto modelBehavior = modelComponent->FindBehavior(behaviorID); + + // if (!modelBehavior) return; + + // modelBehavior->VerifyStates(); + + // auto states = modelBehavior->GetBehaviorStates(); + + // // Begin serialization. + + // /** + // * for each state + // * strip id + // * ui info + // * x + // * y + // * actions + // * action1 + // * action2 + // * ... + // * behaviorID of strip + // * objectID of strip + // */ + // LWOOBJID targetObjectID = LWOOBJID_EMPTY; + // behaviorID = 0; + // AMFArrayValue behaviorInfo; + + // AMFArrayValue* stateSerialize = new AMFArrayValue(); + + // for (auto it = states.begin(); it != states.end(); it++) { + // Game::logger->Log("PropertyBehaviors", "Begin serialization of state %i!\n", it->first); + // AMFArrayValue* state = new AMFArrayValue(); + + // AMFDoubleValue* stateAsDouble = new AMFDoubleValue(); + // stateAsDouble->SetDoubleValue(it->first); + // state->InsertValue("id", stateAsDouble); + + // AMFArrayValue* strips = new AMFArrayValue(); + // auto stripsInState = it->second->GetStrips(); + // for (auto strip = stripsInState.begin(); strip != stripsInState.end(); strip++) { + // Game::logger->Log("PropertyBehaviors", "Begin serialization of strip %i!\n", strip->first); + // AMFArrayValue* thisStrip = new AMFArrayValue(); + + // AMFDoubleValue* stripID = new AMFDoubleValue(); + // stripID->SetDoubleValue(strip->first); + // thisStrip->InsertValue("id", stripID); + + // AMFArrayValue* uiArray = new AMFArrayValue(); + // AMFDoubleValue* yPosition = new AMFDoubleValue(); + // yPosition->SetDoubleValue(strip->second->GetYPosition()); + // uiArray->InsertValue("y", yPosition); + + // AMFDoubleValue* xPosition = new AMFDoubleValue(); + // xPosition->SetDoubleValue(strip->second->GetXPosition()); + // uiArray->InsertValue("x", xPosition); + + // thisStrip->InsertValue("ui", uiArray); + // targetObjectID = modelComponent->GetParent()->GetObjectID(); + // behaviorID = modelBehavior->GetBehaviorID(); + + // AMFArrayValue* stripSerialize = new AMFArrayValue(); + // for (auto behaviorAction : strip->second->GetActions()) { + // Game::logger->Log("PropertyBehaviors", "Begin serialization of action %s!\n", behaviorAction->actionName.c_str()); + // AMFArrayValue* thisAction = new AMFArrayValue(); + + // AMFStringValue* actionName = new AMFStringValue(); + // actionName->SetStringValue(behaviorAction->actionName); + // thisAction->InsertValue("Type", actionName); + + // if (behaviorAction->parameterValueString != "") + // { + // AMFStringValue* valueAsString = new AMFStringValue(); + // valueAsString->SetStringValue(behaviorAction->parameterValueString); + // thisAction->InsertValue(behaviorAction->parameterName, valueAsString); + // } + // else if (behaviorAction->parameterValueDouble != 0.0) + // { + // AMFDoubleValue* valueAsDouble = new AMFDoubleValue(); + // valueAsDouble->SetDoubleValue(behaviorAction->parameterValueDouble); + // thisAction->InsertValue(behaviorAction->parameterName, valueAsDouble); + // } + // stripSerialize->PushBackValue(thisAction); + // } + // thisStrip->InsertValue("actions", stripSerialize); + // strips->PushBackValue(thisStrip); + // } + // state->InsertValue("strips", strips); + // stateSerialize->PushBackValue(state); + // } + // behaviorInfo.InsertValue("states", stateSerialize); + + // AMFStringValue* objectidAsString = new AMFStringValue(); + // objectidAsString->SetStringValue(std::to_string(targetObjectID)); + // behaviorInfo.InsertValue("objectID", objectidAsString); + + // AMFStringValue* behaviorIDAsString = new AMFStringValue(); + // behaviorIDAsString->SetStringValue(std::to_string(behaviorID)); + // behaviorInfo.InsertValue("BehaviorID", behaviorIDAsString); + + // GameMessages::SendUIMessageServerToSingleClient(modelOwner, sysAddr, "UpdateBehaviorBlocks", &behaviorInfo); +} + +void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) { + UpdateActionMessage updateActionMessage(arguments); + auto* blockDefinition = GetBlockInfo(updateActionMessage.GetAction().GetType()); + + if (!blockDefinition) { + Game::logger->Log("ControlBehaviors", "Received undefined block type %s. Ignoring.", updateActionMessage.GetAction().GetType().c_str()); + return; + } + + if (updateActionMessage.GetAction().GetValueParameterString().size() > 0) { + if (updateActionMessage.GetAction().GetValueParameterString().size() < blockDefinition->GetMinimumValue() || + updateActionMessage.GetAction().GetValueParameterString().size() > blockDefinition->GetMaximumValue()) { + Game::logger->Log("ControlBehaviors", "Updated block %s is out of range. Ignoring update", updateActionMessage.GetAction().GetType().c_str()); + return; + } + } else { + if (updateActionMessage.GetAction().GetValueParameterDouble() < blockDefinition->GetMinimumValue() || + updateActionMessage.GetAction().GetValueParameterDouble() > blockDefinition->GetMaximumValue()) { + Game::logger->Log("ControlBehaviors", "Updated block %s is out of range. Ignoring update", updateActionMessage.GetAction().GetType().c_str()); + return; + } + } +} + +void ControlBehaviors::MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments) { + // This closes the UI menu should it be open while the player is removing behaviors + AMFArrayValue args; + + AMFFalseValue* stateToPop = new AMFFalseValue(); + args.InsertValue("visible", stateToPop); + + GameMessages::SendUIMessageServerToSingleClient(modelOwner, modelOwner->GetParentUser()->GetSystemAddress(), "ToggleBehaviorEditor", &args); + + MoveToInventoryMessage moveToInventoryMessage(arguments); + + SendBehaviorListToClient(modelComponent->GetParent(), sysAddr, modelOwner); +} + +void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner) { + if (!isInitialized || !modelEntity || !modelOwner || !arguments) return; + auto* modelComponent = modelEntity->GetComponent(); + + if (!modelComponent) return; + + if (command == "sendBehaviorListToClient") + SendBehaviorListToClient(modelEntity, sysAddr, modelOwner); + else if (command == "modelTypeChanged") + ModelTypeChanged(arguments, modelComponent); + else if (command == "toggleExecutionUpdates") + ToggleExecutionUpdates(); + else if (command == "addStrip") + AddStrip(arguments); + else if (command == "removeStrip") + RemoveStrip(arguments); + else if (command == "mergeStrips") + MergeStrips(arguments); + else if (command == "splitStrip") + SplitStrip(arguments); + else if (command == "updateStripUI") + UpdateStripUI(arguments); + else if (command == "addAction") + AddAction(arguments); + else if (command == "migrateActions") + MigrateActions(arguments); + else if (command == "rearrangeStrip") + RearrangeStrip(arguments); + else if (command == "add") + Add(arguments); + else if (command == "removeActions") + RemoveActions(arguments); + else if (command == "rename") + Rename(modelEntity, sysAddr, modelOwner, arguments); + else if (command == "sendBehaviorBlocksToClient") + SendBehaviorBlocksToClient(modelComponent, sysAddr, modelOwner, arguments); + else if (command == "moveToInventory") + MoveToInventory(modelComponent, sysAddr, modelOwner, arguments); + else if (command == "updateAction") + UpdateAction(arguments); + else + Game::logger->Log("ControlBehaviors", "Unknown behavior command (%s)\n", command.c_str()); +} + +ControlBehaviors::ControlBehaviors() { + auto blocksDefStreamBuffer = Game::assetManager->GetFileAsBuffer("ui\\ingame\\blocksdef.xml"); + if (!blocksDefStreamBuffer.m_Success) { + Game::logger->Log("ControlBehaviors", "failed to open blocksdef"); + return; + } + std::istream blocksBuffer(&blocksDefStreamBuffer); + if (!blocksBuffer.good()) { + Game::logger->Log("ControlBehaviors", "Blocks buffer is not good!"); + return; + } + + tinyxml2::XMLDocument m_Doc; + + std::string read{}; + + std::string buffer{}; + bool commentBlockStart = false; + while (std::getline(blocksBuffer, read)) { + // tinyxml2 should handle comment blocks but the client has one that fails the processing. + // This preprocessing just removes all comments from the read file out of an abundance of caution. + if (read.find("") != std::string::npos) { + commentBlockStart = false; + continue; + } + if (!commentBlockStart) buffer += read; + } + + auto ret = m_Doc.Parse(buffer.c_str()); + if (ret == tinyxml2::XML_SUCCESS) { + Game::logger->LogDebug("ControlBehaviors", "Successfully parsed the blocksdef file!"); + } else { + Game::logger->Log("Character", "Failed to parse BlocksDef xmlData due to error %i!", ret); + return; + } + auto* blockLibrary = m_Doc.FirstChildElement(); + if (!blockLibrary) { + Game::logger->Log("ControlBehaviors", "No Block Library child element found."); + return; + } + + // Now parse the blocksdef for the cheat detection server side. + // The client does these checks, but a bad actor can bypass the client checks + auto* blockSections = blockLibrary->FirstChildElement(); + while (blockSections) { + auto* block = blockSections->FirstChildElement(); + std::string blockName{}; + while (block) { + blockName = block->Name(); + + BlockDefinition* blockDefinition = new BlockDefinition(); + std::string name{}; + std::string typeName{}; + + auto* argument = block->FirstChildElement("Argument"); + if (argument) { + auto* defaultDefinition = argument->FirstChildElement("DefaultValue"); + if (defaultDefinition) blockDefinition->SetDefaultValue(defaultDefinition->GetText()); + + auto* typeDefinition = argument->FirstChildElement("Type"); + if (typeDefinition) typeName = typeDefinition->GetText(); + + auto* nameDefinition = argument->FirstChildElement("Name"); + if (nameDefinition) name = nameDefinition->GetText(); + + // Now we parse the blocksdef file for the relevant information + if (typeName == "String") { + blockDefinition->SetMaximumValue(50); // The client has a hardcoded limit of 50 characters in a string field + } else if (typeName == "Float" || typeName == "Integer") { + auto* maximumDefinition = argument->FirstChildElement("Maximum"); + if (maximumDefinition) blockDefinition->SetMaximumValue(std::stof(maximumDefinition->GetText())); + + auto* minimumDefinition = argument->FirstChildElement("Minimum"); + if (minimumDefinition) blockDefinition->SetMinimumValue(std::stof(minimumDefinition->GetText())); + } else if (typeName == "Enumeration") { + auto* values = argument->FirstChildElement("Values"); + if (values) { + auto* value = values->FirstChildElement("Value"); + while (value) { + if (value->GetText() == blockDefinition->GetDefaultValue()) blockDefinition->GetDefaultValue() = std::to_string(blockDefinition->GetMaximumValue()); + blockDefinition->SetMaximumValue(blockDefinition->GetMaximumValue() + 1); + value = value->NextSiblingElement("Value"); + } + blockDefinition->SetMaximumValue(blockDefinition->GetMaximumValue() - 1); // Maximum value is 0 indexed + } else { + values = argument->FirstChildElement("EnumerationSource"); + if (!values) { + Game::logger->Log("ControlBehaviors", "Failed to parse EnumerationSource from block (%s)", blockName.c_str()); + continue; + } + + auto* serviceNameNode = values->FirstChildElement("ServiceName"); + if (!serviceNameNode) { + Game::logger->Log("ControlBehaviors", "Failed to parse ServiceName from block (%s)", blockName.c_str()); + continue; + } + + std::string serviceName = serviceNameNode->GetText(); + if (serviceName == "GetBehaviorSoundList") { + auto res = CDClientDatabase::ExecuteQuery("SELECT MAX(id) as countSounds FROM UGBehaviorSounds;"); + blockDefinition->SetMaximumValue(res.getIntField("countSounds")); + blockDefinition->SetDefaultValue("0"); + } else { + Game::logger->Log("ControlBehaviors", "Unsupported Enumeration ServiceType (%s)", serviceName.c_str()); + continue; + } + } + } else { + Game::logger->Log("ControlBehaviors", "Unsupported block value type (%s)!", typeName.c_str()); + continue; + } + } + blockTypes.insert(std::make_pair(blockName, blockDefinition)); + block = block->NextSiblingElement(); + } + blockSections = blockSections->NextSiblingElement(); + } + isInitialized = true; + Game::logger->LogDebug("ControlBehaviors", "Created all base block classes"); + for (auto b : blockTypes) { + Game::logger->LogDebug("ControlBehaviors", "block name is %s default %s min %f max %f", b.first.c_str(), b.second->GetDefaultValue().c_str(), b.second->GetMinimumValue(), b.second->GetMaximumValue()); + } +} + +BlockDefinition* ControlBehaviors::GetBlockInfo(const BlockName& blockName) { + auto blockDefinition = blockTypes.find(blockName); + return blockDefinition != blockTypes.end() ? blockDefinition->second : nullptr; +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.h b/dGame/dPropertyBehaviors/ControlBehaviors.h index 7c24da68..a562aafe 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviors.h +++ b/dGame/dPropertyBehaviors/ControlBehaviors.h @@ -3,14 +3,23 @@ #ifndef __CONTROLBEHAVIORS__H__ #define __CONTROLBEHAVIORS__H__ +#include #include -#include "RakNetTypes.h" +#include "Singleton.h" -class Entity; class AMFArrayValue; +class BlockDefinition; +class Entity; +class ModelComponent; +class SystemAddress; -namespace ControlBehaviors { +// Type definition to clarify what is used where +typedef std::string BlockName; //! A block name + +class ControlBehaviors: public Singleton { +public: + ControlBehaviors(); /** * @brief Main driver for processing Property Behavior commands * @@ -23,13 +32,37 @@ namespace ControlBehaviors { void ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner); /** - * @brief Helper function to send the behavior list to the client - * - * @param modelEntity The model that sent this command - * @param sysAddr The SystemAddress to respond to - * @param modelOwner The owner of the model which sent this command + * @brief Gets a blocks parameter values by the name + * No exception will be thrown in this function. + * + * @param blockName The block name to get the parameters of + * + * @return A pair of the block parameter name to its typing */ + BlockDefinition* GetBlockInfo(const BlockName& blockName); +private: + void RequestUpdatedID(int32_t behaviorID, ModelComponent* modelComponent, Entity* modelOwner, const SystemAddress& sysAddr); void SendBehaviorListToClient(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner); + void ModelTypeChanged(AMFArrayValue* arguments, ModelComponent* ModelComponent); + void ToggleExecutionUpdates(); + void AddStrip(AMFArrayValue* arguments); + void RemoveStrip(AMFArrayValue* arguments); + void MergeStrips(AMFArrayValue* arguments); + void SplitStrip(AMFArrayValue* arguments); + void UpdateStripUI(AMFArrayValue* arguments); + void AddAction(AMFArrayValue* arguments); + void MigrateActions(AMFArrayValue* arguments); + void RearrangeStrip(AMFArrayValue* arguments); + void Add(AMFArrayValue* arguments); + void RemoveActions(AMFArrayValue* arguments); + void Rename(Entity* modelEntity, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + void SendBehaviorBlocksToClient(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + void UpdateAction(AMFArrayValue* arguments); + void MoveToInventory(ModelComponent* modelComponent, const SystemAddress& sysAddr, Entity* modelOwner, AMFArrayValue* arguments); + std::map blockTypes{}; + + // If false, property behaviors will not be able to be edited. + bool isInitialized = false; }; #endif //!__CONTROLBEHAVIORS__H__ diff --git a/dGame/dUtilities/BrickDatabase.cpp b/dGame/dUtilities/BrickDatabase.cpp index c36a1097..a6c43d52 100644 --- a/dGame/dUtilities/BrickDatabase.cpp +++ b/dGame/dUtilities/BrickDatabase.cpp @@ -4,6 +4,7 @@ #include "BrickDatabase.h" #include "Game.h" #include "AssetManager.h" +#include "tinyxml2.h" std::vector BrickDatabase::emptyCache{}; BrickDatabase* BrickDatabase::m_Address = nullptr; @@ -19,6 +20,11 @@ std::vector& BrickDatabase::GetBricks(const std::string& lxfmlPath) { } AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer((lxfmlPath).c_str()); + + if (!buffer.m_Success) { + return emptyCache; + } + std::istream file(&buffer); if (!file.good()) { return emptyCache; diff --git a/dGame/dUtilities/CMakeLists.txt b/dGame/dUtilities/CMakeLists.txt index 0c848bf4..55ca5797 100644 --- a/dGame/dUtilities/CMakeLists.txt +++ b/dGame/dUtilities/CMakeLists.txt @@ -1,6 +1,4 @@ set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp" - "dLocale.cpp" - "GameConfig.cpp" "GUID.cpp" "Loot.cpp" "Mail.cpp" diff --git a/dGame/dUtilities/GameConfig.cpp b/dGame/dUtilities/GameConfig.cpp deleted file mode 100644 index ad201e6f..00000000 --- a/dGame/dUtilities/GameConfig.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "GameConfig.h" -#include - -std::map GameConfig::m_Config{}; -std::string GameConfig::m_EmptyString{}; - -void GameConfig::Load(const std::string& filepath) { - m_EmptyString = ""; - std::ifstream in(filepath); - if (!in.good()) return; - - std::string line; - while (std::getline(in, line)) { - if (line.length() > 0) { - if (line[0] != '#') ProcessLine(line); - } - } -} - -const std::string& GameConfig::GetValue(const std::string& key) { - const auto& it = m_Config.find(key); - - if (it != m_Config.end()) { - return it->second; - } - - return m_EmptyString; -} - -void GameConfig::SetValue(const std::string& key, const std::string& value) { - m_Config.insert_or_assign(key, value); -} - -void GameConfig::ProcessLine(const std::string& line) { - std::stringstream ss(line); - std::string segment; - std::vector seglist; - - while (std::getline(ss, segment, '=')) { - seglist.push_back(segment); - } - - if (seglist.size() != 2) return; - - //Make sure that on Linux, we remove special characters: - if (!seglist[1].empty() && seglist[1][seglist[1].size() - 1] == '\r') - seglist[1].erase(seglist[1].size() - 1); - - m_Config.insert_or_assign(seglist[0], seglist[1]); -} diff --git a/dGame/dUtilities/GameConfig.h b/dGame/dUtilities/GameConfig.h deleted file mode 100644 index 55089f89..00000000 --- a/dGame/dUtilities/GameConfig.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include -#include -#include -#include - -#include "GeneralUtils.h" - -class GameConfig { -public: - static void Load(const std::string& filepath); - - static const std::string& GetValue(const std::string& key); - - static void SetValue(const std::string& key, const std::string& value); - - template - static T GetValue(const std::string& key) { - T value; - - if (GeneralUtils::TryParse(GetValue(key), value)) { - return value; - } - - return T(); - } - - template - static void SetValue(const std::string& key, const T& value) { - SetValue(key, std::to_string(value)); - } - -private: - static void ProcessLine(const std::string& line); - - static std::map m_Config; - static std::string m_EmptyString; -}; diff --git a/dGame/dUtilities/Loot.cpp b/dGame/dUtilities/Loot.cpp index 784d873f..da0f2487 100644 --- a/dGame/dUtilities/Loot.cpp +++ b/dGame/dUtilities/Loot.cpp @@ -7,19 +7,23 @@ #include "CDLootMatrixTable.h" #include "CDLootTableTable.h" #include "CDRarityTableTable.h" +#include "CDActivityRewardsTable.h" +#include "CDCurrencyTableTable.h" #include "Character.h" #include "Entity.h" #include "GameMessages.h" #include "GeneralUtils.h" #include "InventoryComponent.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" LootGenerator::LootGenerator() { - CDLootTableTable* lootTableTable = CDClientManager::Instance()->GetTable("LootTable"); - CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance()->GetTable("ComponentsRegistry"); - CDItemComponentTable* itemComponentTable = CDClientManager::Instance()->GetTable("ItemComponent"); - CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance()->GetTable("LootMatrix"); - CDRarityTableTable* rarityTableTable = CDClientManager::Instance()->GetTable("RarityTable"); + CDLootTableTable* lootTableTable = CDClientManager::Instance().GetTable(); + CDComponentsRegistryTable* componentsRegistryTable = CDClientManager::Instance().GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::Instance().GetTable(); + CDLootMatrixTable* lootMatrixTable = CDClientManager::Instance().GetTable(); + CDRarityTableTable* rarityTableTable = CDClientManager::Instance().GetTable(); // ============================== // Cache Item Rarities @@ -36,7 +40,7 @@ LootGenerator::LootGenerator() { uniqueItems.erase(std::unique(uniqueItems.begin(), uniqueItems.end()), uniqueItems.end()); for (const uint32_t itemID : uniqueItems) { - uint32_t itemComponentID = componentsRegistryTable->GetByIDAndType(itemID, COMPONENT_TYPE_ITEM); + uint32_t itemComponentID = componentsRegistryTable->GetByIDAndType(itemID, eReplicaComponentType::ITEM); const CDItemComponent& item = itemComponentTable->GetItemComponentByID(itemComponentID); m_ItemRarities.insert({ itemID, item.rarity }); @@ -186,13 +190,13 @@ std::unordered_map LootGenerator::RollLootMatrix(Entity* player, u // convert faction token proxy if (drop.itemID == 13763) { - if (missionComponent->GetMissionState(545) == MissionState::MISSION_STATE_COMPLETE) + if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) drop.itemID = 8318; // "Assembly Token" - else if (missionComponent->GetMissionState(556) == MissionState::MISSION_STATE_COMPLETE) + else if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) drop.itemID = 8321; // "Venture League Token" - else if (missionComponent->GetMissionState(567) == MissionState::MISSION_STATE_COMPLETE) + else if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) drop.itemID = 8319; // "Sentinels Token" - else if (missionComponent->GetMissionState(578) == MissionState::MISSION_STATE_COMPLETE) + else if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) drop.itemID = 8320; // "Paradox Token" } @@ -290,7 +294,7 @@ void LootGenerator::GiveLoot(Entity* player, std::unordered_map& r } void LootGenerator::GiveActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) { - CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable("ActivityRewards"); + CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable(); std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); const CDActivityRewards* selectedReward = nullptr; @@ -306,7 +310,7 @@ void LootGenerator::GiveActivityLoot(Entity* player, Entity* source, uint32_t ac uint32_t minCoins = 0; uint32_t maxCoins = 0; - CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance()->GetTable("CurrencyTable"); + CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance().GetTable(); std::vector currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); }); if (currencyTable.size() > 0) { @@ -360,7 +364,7 @@ void LootGenerator::DropLoot(Entity* player, Entity* killedObject, std::unordere } void LootGenerator::DropActivityLoot(Entity* player, Entity* source, uint32_t activityID, int32_t rating) { - CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance()->GetTable("ActivityRewards"); + CDActivityRewardsTable* activityRewardsTable = CDClientManager::Instance().GetTable(); std::vector activityRewards = activityRewardsTable->Query([activityID](CDActivityRewards entry) { return (entry.objectTemplate == activityID); }); const CDActivityRewards* selectedReward = nullptr; @@ -377,7 +381,7 @@ void LootGenerator::DropActivityLoot(Entity* player, Entity* source, uint32_t ac uint32_t minCoins = 0; uint32_t maxCoins = 0; - CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance()->GetTable("CurrencyTable"); + CDCurrencyTableTable* currencyTableTable = CDClientManager::Instance().GetTable(); std::vector currencyTable = currencyTableTable->Query([selectedReward](CDCurrencyTable entry) { return (entry.currencyIndex == selectedReward->CurrencyIndex && entry.npcminlevel == 1); }); if (currencyTable.size() > 0) { diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index 8280b627..9490f748 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -22,6 +22,10 @@ #include "MissionComponent.h" #include "ChatPackets.h" #include "Character.h" +#include "dZoneManager.h" +#include "WorldConfig.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" void Mail::SendMail(const Entity* recipient, const std::string& subject, const std::string& body, const LOT attachment, const uint16_t attachmentCount) { @@ -74,12 +78,12 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ auto* ins = Database::CreatePreppedStmt("INSERT INTO `mail`(`sender_id`, `sender_name`, `receiver_id`, `receiver_name`, `time_sent`, `subject`, `body`, `attachment_id`, `attachment_lot`, `attachment_subkey`, `attachment_count`, `was_read`) VALUES (?,?,?,?,?,?,?,?,?,?,?,0)"); ins->setUInt(1, sender); - ins->setString(2, senderName); + ins->setString(2, senderName.c_str()); ins->setUInt(3, recipient); ins->setString(4, recipientName.c_str()); ins->setUInt64(5, time(nullptr)); - ins->setString(6, subject); - ins->setString(7, body); + ins->setString(6, subject.c_str()); + ins->setString(7, body.c_str()); ins->setUInt(8, 0); ins->setInt(9, attachment); ins->setInt(10, 0); @@ -163,7 +167,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd if (!character) return; - if (character->HasPermission(PermissionMap::RestrictedMailAccess)) { + if (character->HasPermission(ePermissionMap::RestrictedMailAccess)) { // Send a message to the player ChatPackets::SendSystemMessage( sysAddr, @@ -191,15 +195,15 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd uint32_t itemID = static_cast(attachmentID); LOT itemLOT = 0; //Inventory::InventoryType itemType; - int mailCost = 25; + int mailCost = dZoneManager::Instance()->GetWorldConfig()->mailBaseFee; int stackSize = 0; - auto inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); Item* item = nullptr; if (itemID > 0 && attachmentCount > 0 && inv) { item = inv->FindItemById(attachmentID); if (item) { - mailCost += (item->GetInfo().baseValue * 0.1f); + mailCost += (item->GetInfo().baseValue * dZoneManager::Instance()->GetWorldConfig()->mailPercentAttachmentFee); stackSize = item->GetCount(); itemLOT = item->GetLot(); } else { @@ -266,7 +270,7 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd auto* missionCompoent = entity->GetComponent(); if (missionCompoent != nullptr) { - missionCompoent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, itemLOT, LWOOBJID_EMPTY, "", -attachmentCount); + missionCompoent->Progress(eMissionTaskType::GATHER, itemLOT, LWOOBJID_EMPTY, "", -attachmentCount); } } @@ -352,7 +356,7 @@ void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddres attachmentCount = res->getInt(2); } - auto inv = static_cast(player->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto inv = static_cast(player->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; inv->AddItem(attachmentLOT, attachmentCount, eLootSourceType::LOOT_SOURCE_MAIL); diff --git a/dGame/dUtilities/Preconditions.cpp b/dGame/dUtilities/Preconditions.cpp index 1f719433..8602586c 100644 --- a/dGame/dUtilities/Preconditions.cpp +++ b/dGame/dUtilities/Preconditions.cpp @@ -12,7 +12,7 @@ #include "LevelProgressionComponent.h" #include "DestroyableComponent.h" #include "GameMessages.h" - +#include "eMissionState.h" std::map Preconditions::cache = {}; @@ -142,19 +142,19 @@ bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluat case PreconditionType::HasAchievement: mission = missionComponent->GetMission(value); - return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_COMPLETE; + return mission == nullptr || mission->GetMissionState() >= eMissionState::COMPLETE; case PreconditionType::MissionAvailable: mission = missionComponent->GetMission(value); - return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_AVAILABLE; + return mission == nullptr || mission->GetMissionState() >= eMissionState::AVAILABLE; case PreconditionType::OnMission: mission = missionComponent->GetMission(value); - return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_ACTIVE; + return mission == nullptr || mission->GetMissionState() >= eMissionState::ACTIVE; case PreconditionType::MissionComplete: mission = missionComponent->GetMission(value); - return mission == nullptr || mission->GetMissionState() >= MissionState::MISSION_STATE_COMPLETE; + return mission == nullptr ? false : mission->GetMissionState() >= eMissionState::COMPLETE; case PreconditionType::PetDeployed: return false; // TODO case PreconditionType::HasFlag: @@ -277,11 +277,6 @@ bool PreconditionExpression::Check(Entity* player, bool evaluateCosts) const { return true; } - if (player->GetGMLevel() >= 9) // Developers can skip this for testing - { - return true; - } - const auto a = Preconditions::Check(player, condition, evaluateCosts); if (!a) { diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index e8f1659e..8693abe9 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -50,6 +50,9 @@ #include "Item.h" #include "PropertyManagementComponent.h" #include "PacketUtils.h" +#include "Loot.h" +#include "EntityInfo.h" +#include "LUTriggers.h" #include "Player.h" #include "PhantomPhysicsComponent.h" #include "ProximityMonitorComponent.h" @@ -60,65 +63,59 @@ #include "BuffComponent.h" #include "SkillComponent.h" #include "VanityUtilities.h" -#include "GameConfig.h" #include "ScriptedActivityComponent.h" #include "LevelProgressionComponent.h" #include "AssetManager.h" +#include "BinaryPathFinder.h" +#include "dConfig.h" +#include "eBubbleType.h" +#include "AMFFormat.h" +#include "MovingPlatformComponent.h" +#include "dMessageIdentifiers.h" +#include "eMissionState.h" +#include "TriggerComponent.h" +#include "eServerDisconnectIdentifiers.h" +#include "eGameMasterLevel.h" +#include "eReplicaComponentType.h" + +#include "CDObjectsTable.h" +#include "CDZoneTableTable.h" void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) { + auto commandCopy = command; + // Sanity check that a command was given + if (command.empty() || command.front() != u'/') return; + commandCopy.erase(commandCopy.begin()); + + // Split the command by spaces std::string chatCommand; std::vector args; + auto wideCommand = GeneralUtils::SplitString(commandCopy, u' '); + if (wideCommand.empty()) return; - uint32_t breakIndex = 0; - for (uint32_t i = 1; i < command.size(); ++i) { - if (command[i] == L' ') { - breakIndex = i; - break; - } + // Convert the command to lowercase + chatCommand = GeneralUtils::UTF16ToWTF8(wideCommand.front()); + std::transform(chatCommand.begin(), chatCommand.end(), chatCommand.begin(), ::tolower); + wideCommand.erase(wideCommand.begin()); - chatCommand.push_back(static_cast(command[i])); - breakIndex++; - } - - uint32_t index = ++breakIndex; - while (true) { - std::string arg; - - while (index < command.size()) { - if (command[index] == L' ') { - args.push_back(arg); - arg = ""; - index++; - continue; - } - - arg.push_back(static_cast(command[index])); - index++; - } - - if (arg != "") { - args.push_back(arg); - } - - break; - } - - //Game::logger->Log("SlashCommandHandler", "Received chat command \"%s\"", GeneralUtils::UTF16ToWTF8(command).c_str()); + // Convert the arguements to not u16strings + for (auto wideArg : wideCommand) args.push_back(GeneralUtils::UTF16ToWTF8(wideArg)); User* user = UserManager::Instance()->GetUser(sysAddr); - if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > GAME_MASTER_LEVEL_CIVILIAN) { + if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > eGameMasterLevel::CIVILIAN) { if (args.size() != 1) return; - uint32_t level; + uint32_t level_intermed = 0; - if (!GeneralUtils::TryParse(args[0], level)) { + if (!GeneralUtils::TryParse(args[0], level_intermed)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid gm level."); return; } + eGameMasterLevel level = static_cast(level_intermed); #ifndef DEVELOPER_SERVER - if (user->GetMaxGMLevel() == GAME_MASTER_LEVEL_JUNIOR_DEVELOPER) { - level = GAME_MASTER_LEVEL_CIVILIAN; + if (user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER) { + level = eGameMasterLevel::CIVILIAN; } #endif @@ -131,9 +128,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit if (success) { - if (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN && level == GAME_MASTER_LEVEL_CIVILIAN) { + if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && level == eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); - } else if (entity->GetGMLevel() == GAME_MASTER_LEVEL_CIVILIAN && level > GAME_MASTER_LEVEL_CIVILIAN) { + } else if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN && level > eGameMasterLevel::CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); } @@ -145,10 +142,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } #ifndef DEVELOPER_SERVER - if ((entity->GetGMLevel() > user->GetMaxGMLevel()) || (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN && user->GetMaxGMLevel() == GAME_MASTER_LEVEL_JUNIOR_DEVELOPER)) { - WorldPackets::SendGMLevelChange(sysAddr, true, user->GetMaxGMLevel(), entity->GetGMLevel(), GAME_MASTER_LEVEL_CIVILIAN); - GameMessages::SendChatModeUpdate(entity->GetObjectID(), GAME_MASTER_LEVEL_CIVILIAN); - entity->SetGMLevel(GAME_MASTER_LEVEL_CIVILIAN); + if ((entity->GetGMLevel() > user->GetMaxGMLevel()) || (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER)) { + WorldPackets::SendGMLevelChange(sysAddr, true, user->GetMaxGMLevel(), entity->GetGMLevel(), eGameMasterLevel::CIVILIAN); + GameMessages::SendChatModeUpdate(entity->GetObjectID(), eGameMasterLevel::CIVILIAN); + entity->SetGMLevel(eGameMasterLevel::CIVILIAN); GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); @@ -156,6 +153,19 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } #endif + if (chatCommand == "togglenameplate" && (Game::config->GetValue("allow_nameplate_off") == "1" || entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER)) { + auto* character = entity->GetCharacter(); + + if (character && character->GetBillboardVisible()) { + character->SetBillboardVisible(false); + ChatPackets::SendSystemMessage(sysAddr, u"Your nameplate has been turned off and is not visible to players currently in this zone."); + } else { + character->SetBillboardVisible(true); + ChatPackets::SendSystemMessage(sysAddr, u"Your nameplate is now on and visible to all players."); + } + return; + } + //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE! //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -210,22 +220,6 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "skip-ags") { - auto* missionComponent = entity->GetComponent(); - - if (missionComponent != nullptr && missionComponent->HasMission(479)) { - missionComponent->CompleteMission(479); - } - } - - if (chatCommand == "skip-sg") { - auto* missionComponent = entity->GetComponent(); - - if (missionComponent != nullptr && missionComponent->HasMission(229)) { - missionComponent->CompleteMission(229); - } - } - if (chatCommand == "fix-stats") { // Reset skill component and buff component auto* skillComponent = entity->GetComponent(); @@ -248,7 +242,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } if (chatCommand == "credits" || chatCommand == "info") { - const auto& customText = chatCommand == "credits" ? VanityUtilities::ParseMarkdown("./vanity/CREDITS.md") : VanityUtilities::ParseMarkdown("./vanity/INFO.md"); + const auto& customText = chatCommand == "credits" ? VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/CREDITS.md").string()) : VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/INFO.md").string()); { AMFArrayValue args; @@ -337,7 +331,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit }); } - if (user->GetMaxGMLevel() == 0 || entity->GetGMLevel() >= 0) { + if (user->GetMaxGMLevel() == eGameMasterLevel::CIVILIAN || entity->GetGMLevel() >= eGameMasterLevel::CIVILIAN) { if (chatCommand == "die") { entity->Smash(entity->GetObjectID()); } @@ -363,7 +357,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID()))); } - if (entity->GetGMLevel() == 0) return; + if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) return; } // Log command to database @@ -373,7 +367,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit stmt->execute(); delete stmt; - if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_FORUM_MODERATOR) { // could break characters so only allow if GM > 0 + if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { // could break characters so only allow if GM > 0 int32_t minifigItemId; if (!GeneralUtils::TryParse(args[1], minifigItemId)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig Item Id ID."); @@ -417,7 +411,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); // need to retoggle because it gets reenabled on creation of new character } - if ((chatCommand == "playanimation" || chatCommand == "playanim") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "playanimation" || chatCommand == "playanim") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::u16string anim = GeneralUtils::ASCIIToUTF16(args[0], args[0].size()); GameMessages::SendPlayAnimation(entity, anim); auto* possessorComponent = entity->GetComponent(); @@ -427,7 +421,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "list-spawns" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "list-spawns" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { for (const auto& pair : EntityManager::Instance()->GetSpawnPointEntities()) { ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(pair.first)); } @@ -437,7 +431,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "unlock-emote" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "unlock-emote" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t emoteID; if (!GeneralUtils::TryParse(args[0], emoteID)) { @@ -448,11 +442,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->UnlockEmote(emoteID); } - if (chatCommand == "force-save" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "force-save" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { entity->GetCharacter()->SaveXMLToDatabase(); } - if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { ChatPackets::SendSystemMessage(sysAddr, u"Brutally murdering that player, if online on this server."); auto* user = UserManager::Instance()->GetUser(args[0]); @@ -467,7 +461,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "speedboost" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "speedboost" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { float boost; if (!GeneralUtils::TryParse(args[0], boost)) { @@ -498,7 +492,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "freecam" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "freecam" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto state = !entity->GetVar(u"freecam"); entity->SetVar(u"freecam", state); @@ -508,7 +502,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setcontrolscheme" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setcontrolscheme" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { uint32_t scheme; if (!GeneralUtils::TryParse(args[0], scheme)) { @@ -522,7 +516,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "approveproperty" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_LEAD_MODERATOR) { + if (chatCommand == "approveproperty" && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { if (PropertyManagementComponent::Instance() != nullptr) { PropertyManagementComponent::Instance()->UpdateApprovedStatus(true); @@ -531,7 +525,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setuistate" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setuistate" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { AMFStringValue* value = new AMFStringValue(); value->SetStringValue(args[0]); @@ -544,7 +538,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "toggle" && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "toggle" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { AMFTrueValue* value = new AMFTrueValue(); AMFArrayValue amfArgs; @@ -556,27 +550,48 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if ((chatCommand == "setinventorysize" || chatCommand == "setinvsize") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - if (args.size() != 1) return; - + if ((chatCommand == "setinventorysize" || chatCommand == "setinvsize") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { uint32_t size; - if (!GeneralUtils::TryParse(args[0], size)) { + if (!GeneralUtils::TryParse(args.at(0), size)) { ChatPackets::SendSystemMessage(sysAddr, u"Invalid size."); return; } - InventoryComponent* inventory = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); - if (inventory) { - auto* items = inventory->GetInventory(ITEMS); + eInventoryType selectedInventory = eInventoryType::ITEMS; - items->SetSize(size); + // a possible inventory was provided if we got more than 1 argument + if (args.size() >= 2) { + selectedInventory = eInventoryType::INVALID; + if (!GeneralUtils::TryParse(args.at(1), selectedInventory)) { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(args.at(1).begin(), args.at(1).end(), args.at(1).begin(), ::toupper); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(args.at(1)) == std::string_view(InventoryType::InventoryTypeToString(static_cast(index)))) selectedInventory = static_cast(index); + } + } + if (selectedInventory == eInventoryType::INVALID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory."); + return; + } + + ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory " + + GeneralUtils::ASCIIToUTF16(args.at(1)) + + u" to size " + + GeneralUtils::to_u16string(size)); + } else ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory ITEMS to size " + GeneralUtils::to_u16string(size)); + + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) { + auto* inventory = inventoryComponent->GetInventory(selectedInventory); + + inventory->SetSize(size); } return; } - if (chatCommand == "runmacro" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "runmacro" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() != 1) return; // Only process if input does not contain separator charaters @@ -584,6 +599,12 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit if (args[0].find("\\") != std::string::npos) return; auto buf = Game::assetManager->GetFileAsBuffer(("macros/" + args[0] + ".scm").c_str()); + + if (!buf.m_Success) { + ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); + return; + } + std::istream infile(&buf); if (infile.good()) { @@ -600,7 +621,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "addmission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "addmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; @@ -610,12 +631,12 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - auto comp = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (comp) comp->AcceptMission(missionID, true); return; } - if (chatCommand == "completemission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "completemission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; @@ -625,12 +646,12 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - auto comp = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (comp) comp->CompleteMission(missionID, true); return; } - if (chatCommand == "setflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { uint32_t flagId; if (!GeneralUtils::TryParse(args[0], flagId)) { @@ -641,7 +662,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->SetPlayerFlag(flagId, true); } - if (chatCommand == "setflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 2) { + if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 2) { uint32_t flagId; std::string onOffFlag = args[0]; if (!GeneralUtils::TryParse(args[1], flagId)) { @@ -654,7 +675,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } entity->GetCharacter()->SetPlayerFlag(flagId, onOffFlag == "on"); } - if (chatCommand == "clearflag" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "clearflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { uint32_t flagId; if (!GeneralUtils::TryParse(args[0], flagId)) { @@ -665,7 +686,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit entity->GetCharacter()->SetPlayerFlag(flagId, false); } - if (chatCommand == "resetmission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "resetmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 0) return; uint32_t missionID; @@ -675,7 +696,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - auto* comp = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); + auto* comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (comp == nullptr) { return; @@ -687,12 +708,12 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - mission->SetMissionState(MissionState::MISSION_STATE_ACTIVE); + mission->SetMissionState(eMissionState::ACTIVE); return; } - if (chatCommand == "playeffect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 3) { + if (chatCommand == "playeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { int32_t effectID = 0; if (!GeneralUtils::TryParse(args[0], effectID)) { @@ -703,11 +724,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendPlayFXEffect(entity->GetObjectID(), effectID, GeneralUtils::ASCIIToUTF16(args[1]), args[2]); } - if (chatCommand == "stopeffect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "stopeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { GameMessages::SendStopFXEffect(entity, true, args[0]); } - if (chatCommand == "setanntitle" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setanntitle" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() < 0) return; std::stringstream ss; @@ -718,7 +739,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setannmsg" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setannmsg" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() < 0) return; std::stringstream ss; @@ -729,7 +750,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "announce" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "announce" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (entity->GetCharacter()->GetAnnouncementTitle().size() == 0 || entity->GetCharacter()->GetAnnouncementMessage().size() == 0) { ChatPackets::SendSystemMessage(sysAddr, u"Use /setanntitle & /setannmsg <msg> first!"); return; @@ -739,7 +760,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "shutdownuniverse" && entity->GetGMLevel() == GAME_MASTER_LEVEL_OPERATOR) { + if (chatCommand == "shutdownuniverse" && entity->GetGMLevel() == eGameMasterLevel::OPERATOR) { //Tell the master server that we're going to be shutting down whole "universe": CBITSTREAM; PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN_UNIVERSE); @@ -751,8 +772,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "getnavmeshheight" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + if (chatCommand == "getnavmeshheight" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!control) return; float y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(control->GetPosition()); @@ -760,7 +781,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, msg); } - if (chatCommand == "gmadditem" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "gmadditem" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { if (args.size() == 1) { uint32_t itemLOT; @@ -769,7 +790,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); inventory->AddItem(itemLOT, 1, eLootSourceType::LOOT_SOURCE_MODERATION); } else if (args.size() == 2) { @@ -787,7 +808,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); + InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); inventory->AddItem(itemLOT, count, eLootSourceType::LOOT_SOURCE_MODERATION); } else { @@ -795,7 +816,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "mailitem" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_MODERATOR && args.size() >= 2) { + if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) { const auto& playerName = args[0]; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT id from charinfo WHERE name=? LIMIT 1;"); @@ -844,7 +865,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "setname" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "setname" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::string name = ""; for (const auto& arg : args) { @@ -854,7 +875,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); } - if (chatCommand == "title" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "title" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { std::string name = entity->GetCharacter()->GetName() + " - "; for (const auto& arg : args) { @@ -864,7 +885,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); } - if ((chatCommand == "teleport" || chatCommand == "tele") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_MODERATOR) { + if ((chatCommand == "teleport" || chatCommand == "tele") && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { NiPoint3 pos{}; if (args.size() == 3) { @@ -930,10 +951,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "tpall" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "tpall" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto pos = entity->GetPosition(); - const auto characters = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CHARACTER); + const auto characters = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); for (auto* character : characters) { GameMessages::SendTeleport(character->GetObjectID(), pos, NiQuaternion(), character->GetSystemAddress()); @@ -942,7 +963,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "dismount" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "dismount" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* possessorComponent = entity->GetComponent<PossessorComponent>(); if (possessorComponent) { auto possessableId = possessorComponent->GetPossessable(); @@ -953,7 +974,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "fly" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_DEVELOPER) { + if (chatCommand == "fly" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { auto* character = entity->GetCharacter(); if (character) { @@ -989,7 +1010,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit //------- GM COMMANDS TO ACTUALLY MODERATE -------- - if (chatCommand == "mute" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_DEVELOPER) { + if (chatCommand == "mute" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { if (args.size() >= 1) { auto* player = Player::GetPlayer(args[0]); @@ -1084,7 +1105,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "kick" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_JUNIOR_MODERATOR) { + if (chatCommand == "kick" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { if (args.size() == 1) { auto* player = Player::GetPlayer(args[0]); @@ -1094,7 +1115,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - Game::server->Disconnect(player->GetSystemAddress(), SERVER_DISCON_KICK); + Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); } else { @@ -1102,7 +1123,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "ban" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_SENIOR_MODERATOR) { + if (chatCommand == "ban" && entity->GetGMLevel() >= eGameMasterLevel::SENIOR_MODERATOR) { if (args.size() == 1) { auto* player = Player::GetPlayer(args[0]); @@ -1140,7 +1161,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit delete userUpdate; if (player != nullptr) { - Game::server->Disconnect(player->GetSystemAddress(), SERVER_DISCON_KICK); + Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); } ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(args[0])); @@ -1151,8 +1172,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit //------------------------------------------------- - if (chatCommand == "buffme" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + if (chatCommand == "buffme" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth(999); dest->SetMaxHealth(999.0f); @@ -1164,7 +1185,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "startcelebration" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "startcelebration" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { int32_t celebration; if (!GeneralUtils::TryParse(args[0], celebration)) { @@ -1175,8 +1196,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration); } - if (chatCommand == "buffmed" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + if (chatCommand == "buffmed" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth(9); dest->SetMaxHealth(9.0f); @@ -1188,9 +1209,9 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "refillstats" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "refillstats" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetHealth((int)dest->GetMaxHealth()); dest->SetArmor((int)dest->GetMaxArmor()); @@ -1200,11 +1221,17 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(entity); } - if (chatCommand == "lookup" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { + if (chatCommand == "lookup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto query = CDClientDatabase::CreatePreppedStmt( "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE ?1 OR `name` LIKE ?1 OR `description` LIKE ?1 LIMIT 50"); + // Concatenate all of the arguments into a single query so a multi word query can be used properly. + std::string conditional = args[0]; + args.erase(args.begin()); + for (auto& argument : args) { + conditional += ' ' + argument; + } - const std::string query_text = "%" + args[0] + "%"; + const std::string query_text = "%" + conditional + "%"; query.bind(1, query_text.c_str()); auto tables = query.execQuery(); @@ -1216,8 +1243,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "spawn" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { - ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + if (chatCommand == "spawn" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { + ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!comp) return; uint32_t lot; @@ -1257,7 +1284,58 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->ConstructEntity(newEntity); } - if ((chatCommand == "giveuscore") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "spawngroup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { + auto controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); + if (!controllablePhysicsComponent) return; + + LOT lot{}; + uint32_t numberToSpawn{}; + float radiusToSpawnWithin{}; + + if (!GeneralUtils::TryParse(args[0], lot)) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); + return; + } + + if (!GeneralUtils::TryParse(args[1], numberToSpawn) && numberToSpawn > 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid number of enemies to spawn."); + return; + } + + // Must spawn within a radius of at least 0.0f + if (!GeneralUtils::TryParse(args[2], radiusToSpawnWithin) && radiusToSpawnWithin < 0.0f) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid radius to spawn within."); + return; + } + + EntityInfo info; + info.lot = lot; + info.spawner = nullptr; + info.spawnerID = entity->GetObjectID(); + info.spawnerNodeID = 0; + + auto playerPosition = controllablePhysicsComponent->GetPosition(); + while (numberToSpawn > 0) { + auto randomAngle = GeneralUtils::GenerateRandomNumber<float>(0.0f, 2 * PI); + auto randomRadius = GeneralUtils::GenerateRandomNumber<float>(0.0f, radiusToSpawnWithin); + + // Set the position to the generated random position plus the player position. This will + // spawn the entity in a circle around the player. As you get further from the player, the angle chosen will get less accurate. + info.pos = playerPosition + NiPoint3(cos(randomAngle) * randomRadius, 0.0f, sin(randomAngle) * randomRadius); + info.rot = NiQuaternion(); + + auto newEntity = EntityManager::Instance()->CreateEntity(info); + if (newEntity == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); + return; + } + + EntityManager::Instance()->ConstructEntity(newEntity); + numberToSpawn--; + } + } + + if ((chatCommand == "giveuscore") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t uscore; if (!GeneralUtils::TryParse(args[0], uscore)) { @@ -1268,10 +1346,18 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit CharacterComponent* character = entity->GetComponent<CharacterComponent>(); if (character) character->SetUScore(character->GetUScore() + uscore); // LOOT_SOURCE_MODERATION should work but it doesn't. Relog to see uscore changes - GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, eLootSourceType::LOOT_SOURCE_MODERATION); + + eLootSourceType lootType = eLootSourceType::LOOT_SOURCE_MODERATION; + + int32_t type; + if (args.size() >= 2 && GeneralUtils::TryParse(args[1], type)) { + lootType = (eLootSourceType)type; + } + + GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType); } - if ((chatCommand == "setlevel") && args.size() >= 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "setlevel") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { // We may be trying to set a specific players level to a level. If so override the entity with the requested players. std::string requestedPlayerToSetLevelOf = ""; if (args.size() > 1) { @@ -1339,7 +1425,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "pos" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "pos" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto position = entity->GetPosition(); ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">"); @@ -1347,7 +1433,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit std::cout << position.x << ", " << position.y << ", " << position.z << std::endl; } - if (chatCommand == "rot" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "rot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto rotation = entity->GetRotation(); ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">"); @@ -1355,22 +1441,22 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit std::cout << rotation.w << ", " << rotation.x << ", " << rotation.y << ", " << rotation.z << std::endl; } - if (chatCommand == "locrow" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { const auto position = entity->GetPosition(); const auto rotation = entity->GetRotation(); std::cout << "<location x=\"" << position.x << "\" y=\"" << position.y << "\" z=\"" << position.z << "\" rw=\"" << rotation.w << "\" rx=\"" << rotation.x << "\" ry=\"" << rotation.y << "\" rz=\"" << rotation.z << "\" />" << std::endl; } - if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendPlayFXEffect(entity, 7074, u"create", "7074", LWOOBJID_EMPTY, 1.0f, 1.0f, true); } - if (chatCommand == "playrebuildfx" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "playrebuildfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendPlayFXEffect(entity, 230, u"rebuild", "230", LWOOBJID_EMPTY, 1.0f, 1.0f, true); } - if ((chatCommand == "freemoney" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) && args.size() == 1) { + if ((chatCommand == "freemoney" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) && args.size() == 1) { int32_t money; if (!GeneralUtils::TryParse(args[0], money)) { @@ -1382,7 +1468,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ch->SetCoins(ch->GetCoins() + money, eLootSourceType::LOOT_SOURCE_MODERATION); } - if ((chatCommand == "setcurrency") && args.size() == 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "setcurrency") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { int32_t money; if (!GeneralUtils::TryParse(args[0], money)) { @@ -1395,13 +1481,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } // Allow for this on even while not a GM, as it sometimes toggles incorrrectly. - if (chatCommand == "gminvis" && entity->GetParentUser()->GetMaxGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "gminvis" && entity->GetParentUser()->GetMaxGMLevel() >= eGameMasterLevel::DEVELOPER) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); return; } - if (chatCommand == "gmimmune" && args.size() >= 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "gmimmune" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); int32_t state = false; @@ -1418,7 +1504,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* buffComponent = entity->GetComponent<BuffComponent>(); int32_t id = 0; @@ -1441,7 +1527,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if ((chatCommand == "testmap" && args.size() >= 1) && entity->GetGMLevel() >= GAME_MASTER_LEVEL_FORUM_MODERATOR) { + if ((chatCommand == "testmap" && args.size() >= 1) && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { ChatPackets::SendSystemMessage(sysAddr, u"Requesting map change..."); uint32_t reqZone; LWOCLONEID cloneId = 0; @@ -1500,7 +1586,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "createprivate" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 3) { + if (chatCommand == "createprivate" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { uint32_t zone; if (!GeneralUtils::TryParse(args[0], zone)) { @@ -1524,13 +1610,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if ((chatCommand == "debugui") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "debugui") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger..."); AMFArrayValue args; GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleUIDebugger;", nullptr); } - if ((chatCommand == "boost") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "boost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* possessorComponent = entity->GetComponent<PossessorComponent>(); if (possessorComponent == nullptr) { @@ -1562,7 +1648,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } - if ((chatCommand == "unboost") && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if ((chatCommand == "unboost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { auto* possessorComponent = entity->GetComponent<PossessorComponent>(); if (possessorComponent == nullptr) return; @@ -1572,7 +1658,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); } - if (chatCommand == "activatespawner" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "activatespawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto spawners = dZoneManager::Instance()->GetSpawnersByName(args[0]); for (auto* spawner : spawners) { @@ -1586,20 +1672,20 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "spawnphysicsverts" && entity->GetGMLevel() >= 6) { + if (chatCommand == "spawnphysicsverts" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { //Go tell physics to spawn all the vertices: - auto entities = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PHANTOM_PHYSICS); + auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PHANTOM_PHYSICS); for (auto en : entities) { - auto phys = static_cast<PhantomPhysicsComponent*>(en->GetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS)); + auto phys = static_cast<PhantomPhysicsComponent*>(en->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); if (phys) phys->SpawnVertices(); } } - if (chatCommand == "reportproxphys" && entity->GetGMLevel() >= 6) { - auto entities = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_PROXIMITY_MONITOR); + if (chatCommand == "reportproxphys" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { + auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROXIMITY_MONITOR); for (auto en : entities) { - auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(COMPONENT_TYPE_PROXIMITY_MONITOR)); + auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(eReplicaComponentType::PROXIMITY_MONITOR)); if (phys) { for (auto prox : phys->GetProximitiesData()) { if (!prox.second) continue; @@ -1612,7 +1698,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "triggerspawner" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "triggerspawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { auto spawners = dZoneManager::Instance()->GetSpawnersByName(args[0]); for (auto* spawner : spawners) { @@ -1626,7 +1712,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit } } - if (chatCommand == "reforge" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 2) { + if (chatCommand == "reforge" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 2) { LOT baseItem; LOT reforgedItem; @@ -1643,7 +1729,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit inventoryComponent->AddItem(baseItem, 1, eLootSourceType::LOOT_SOURCE_MODERATION, eInventoryType::INVALID, data); } - if (chatCommand == "crash" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR) { + if (chatCommand == "crash" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR) { ChatPackets::SendSystemMessage(sysAddr, u"Crashing..."); int* badPtr = nullptr; @@ -1652,26 +1738,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "config-set" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 2) { - GameConfig::SetValue(args[0], args[1]); - - ChatPackets::SendSystemMessage( - sysAddr, u"Set config value: " + GeneralUtils::UTF8ToUTF16(args[0]) + u" to " + GeneralUtils::UTF8ToUTF16(args[1]) - ); - } - - if (chatCommand == "config-get" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { - const auto& value = GameConfig::GetValue(args[0]); - - std::u16string u16key = GeneralUtils::UTF8ToUTF16(args[0]); - if (value.empty()) { - ChatPackets::SendSystemMessage(sysAddr, u"No value found for " + u16key); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Value for " + u16key + u": " + GeneralUtils::UTF8ToUTF16(value)); - } - } - - if (chatCommand == "metrics" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "metrics" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { for (const auto variable : Metrics::GetAllMetrics()) { auto* metric = Metrics::GetMetric(variable); @@ -1708,7 +1775,23 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if (chatCommand == "rollloot" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_OPERATOR && args.size() >= 3) { + if (chatCommand == "reloadconfig" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { + Game::config->ReloadConfig(); + VanityUtilities::SpawnVanity(); + dpWorld::Instance().Reload(); + auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); + for (auto entity : entities) { + auto* scriptedActivityComponent = entity->GetComponent<ScriptedActivityComponent>(); + if (!scriptedActivityComponent) continue; + + scriptedActivityComponent->ReloadConfig(); + } + Game::server->UpdateMaximumMtuSize(); + Game::server->UpdateBandwidthLimit(); + ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); + } + + if (chatCommand == "rollloot" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR && args.size() >= 3) { uint32_t lootMatrixIndex = 0; uint32_t targetLot = 0; uint32_t loops = 1; @@ -1745,17 +1828,44 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit ChatPackets::SendSystemMessage(sysAddr, message); } - if (chatCommand == "inspect" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + if (chatCommand == "deleteinven" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { + eInventoryType inventoryType = eInventoryType::INVALID; + if (!GeneralUtils::TryParse(args[0], inventoryType)) { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(args[0].begin(), args[0].end(), args[0].begin(), ::toupper); + Game::logger->Log("SlashCommandHandler", "looking for inventory %s", args[0].c_str()); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(args[0]) == std::string_view(InventoryType::InventoryTypeToString(static_cast<eInventoryType>(index)))) inventoryType = static_cast<eInventoryType>(index); + } + } + + if (inventoryType == eInventoryType::INVALID || inventoryType >= NUMBER_OF_INVENTORIES) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory provided."); + return; + } + + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (!inventoryComponent) return; + + auto* inventoryToDelete = inventoryComponent->GetInventory(inventoryType); + if (!inventoryToDelete) return; + + inventoryToDelete->DeleteAllItems(); + Game::logger->Log("SlashCommandHandler", "Deleted inventory %s for user %llu", args[0].c_str(), entity->GetObjectID()); + ChatPackets::SendSystemMessage(sysAddr, u"Deleted inventory " + GeneralUtils::UTF8ToUTF16(args[0])); + } + + if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { Entity* closest = nullptr; - int32_t component; + eReplicaComponentType component; std::u16string ldf; bool isLDF = false; if (!GeneralUtils::TryParse(args[0], component)) { - component = -1; + component = eReplicaComponentType::INVALID; ldf = GeneralUtils::UTF8ToUTF16(args[0]); @@ -1800,7 +1910,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit EntityManager::Instance()->SerializeEntity(closest); - auto* table = CDClientManager::Instance()->GetTable<CDObjectsTable>("Objects"); + auto* table = CDClientManager::Instance().GetTable<CDObjectsTable>(); const auto& info = table->GetByID(closest->GetLOT()); @@ -1815,7 +1925,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit std::stringstream stream; - stream << "Component [" << std::to_string(id) << "]"; + stream << "Component [" << std::to_string(static_cast<uint32_t>(id)) << "]"; ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(stream.str())); } @@ -1888,15 +1998,19 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit auto* phantomPhysicsComponent = closest->GetComponent<PhantomPhysicsComponent>(); if (phantomPhysicsComponent != nullptr) { - ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetEffectType()))); + ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(static_cast<uint32_t>(phantomPhysicsComponent->GetEffectType())))); const auto dir = phantomPhysicsComponent->GetDirection(); ChatPackets::SendSystemMessage(sysAddr, u"Direction: <" + (GeneralUtils::to_u16string(dir.x)) + u", " + (GeneralUtils::to_u16string(dir.y)) + u", " + (GeneralUtils::to_u16string(dir.z)) + u">"); ChatPackets::SendSystemMessage(sysAddr, u"Multiplier: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetDirectionalMultiplier()))); ChatPackets::SendSystemMessage(sysAddr, u"Active: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetPhysicsEffectActive()))); } - if (closest->GetTrigger() != nullptr) { - ChatPackets::SendSystemMessage(sysAddr, u"Trigger: " + (GeneralUtils::to_u16string(closest->GetTrigger()->id))); + auto* triggerComponent = closest->GetComponent<TriggerComponent>(); + if (triggerComponent) { + auto trigger = triggerComponent->GetTrigger(); + if (trigger) { + ChatPackets::SendSystemMessage(sysAddr, u"Trigger: " + (GeneralUtils::to_u16string(trigger->id))); + } } } } @@ -1905,7 +2019,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit bool SlashCommandHandler::CheckIfAccessibleZone(const unsigned int zoneID) { //We're gonna go ahead and presume we've got the db loaded already: - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); const CDZoneTable* zone = zoneTable->Query(zoneID); if (zone != nullptr) { return Game::assetManager->HasFile(("maps/" + zone->zoneName).c_str()); diff --git a/dGame/dUtilities/VanityUtilities.cpp b/dGame/dUtilities/VanityUtilities.cpp index 733d94c4..7fabfbce 100644 --- a/dGame/dUtilities/VanityUtilities.cpp +++ b/dGame/dUtilities/VanityUtilities.cpp @@ -13,6 +13,8 @@ #include "tinyxml2.h" #include "Game.h" #include "dLogger.h" +#include "BinaryPathFinder.h" +#include "EntityInfo.h" #include <fstream> @@ -27,7 +29,7 @@ void VanityUtilities::SpawnVanity() { const uint32_t zoneID = Game::server->GetZoneID(); - ParseXML("./vanity/NPC.xml"); + ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity/NPC.xml").string()); // Loop through all parties for (const auto& party : m_Parties) { @@ -63,17 +65,21 @@ void VanityUtilities::SpawnVanity() { npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1); } - const auto& npc = npcList[npcIndex]; + auto& npc = npcList[npcIndex]; taken.push_back(npcIndex); // Spawn the NPC - std::vector<LDFBaseData*> data = { new LDFData<std::vector<std::u16string>>( - u"syncLDF", { u"custom_script_client" }), - new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") }; + Game::logger->Log("VanityUtilities", "ldf size is %i", npc.ldf.size()); + if (npc.ldf.empty()) { + npc.ldf = { + new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }), + new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") + }; + } // Spawn the NPC - auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, data); + auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf); npcEntity->SetVar<std::vector<std::string>>(u"chats", m_PartyPhrases); @@ -84,11 +90,11 @@ void VanityUtilities::SpawnVanity() { } // Loop through all NPCs - for (const auto& pair : m_NPCs) { - if (pair.m_Locations.find(Game::server->GetZoneID()) == pair.m_Locations.end()) + for (auto& npc : m_NPCs) { + if (npc.m_Locations.find(Game::server->GetZoneID()) == npc.m_Locations.end()) continue; - const std::vector<VanityNPCLocation>& locations = pair.m_Locations.at(Game::server->GetZoneID()); + const std::vector<VanityNPCLocation>& locations = npc.m_Locations.at(Game::server->GetZoneID()); // Pick a random location const auto& location = locations[GeneralUtils::GenerateRandomNumber<int>( @@ -99,27 +105,30 @@ void VanityUtilities::SpawnVanity() { continue; } - std::vector<LDFBaseData*> data = { new LDFData<std::vector<std::u16string>>( - u"syncLDF", { u"custom_script_client" }), - new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") }; + if (npc.ldf.empty()) { + npc.ldf = { + new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }), + new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") + }; + } // Spawn the NPC - auto* npc = SpawnNPC(pair.m_LOT, pair.m_Name, location.m_Position, location.m_Rotation, pair.m_Equipment, data); + auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf); - npc->SetVar<std::vector<std::string>>(u"chats", pair.m_Phrases); + npcEntity->SetVar<std::vector<std::string>>(u"chats", npc.m_Phrases); - auto* scriptComponent = npc->GetComponent<ScriptComponent>(); + auto* scriptComponent = npcEntity->GetComponent<ScriptComponent>(); if (scriptComponent != nullptr) { - scriptComponent->SetScript(pair.m_Script); + scriptComponent->SetScript(npc.m_Script); scriptComponent->SetSerialized(false); - for (const auto& pair : pair.m_Flags) { - npc->SetVar<bool>(GeneralUtils::ASCIIToUTF16(pair.first), pair.second); + for (const auto& npc : npc.m_Flags) { + npcEntity->SetVar<bool>(GeneralUtils::ASCIIToUTF16(npc.first), npc.second); } } - SetupNPCTalk(npc); + SetupNPCTalk(npcEntity); } if (zoneID == 1200) { @@ -131,7 +140,7 @@ void VanityUtilities::SpawnVanity() { info.spawnerID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); info.settings = { new LDFData<bool>(u"hasCustomText", true), - new LDFData<std::string>(u"customText", ParseMarkdown("./vanity/TESTAMENT.md")) }; + new LDFData<std::string>(u"customText", ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/TESTAMENT.md").string())) }; auto* entity = EntityManager::Instance()->CreateEntity(info); @@ -264,10 +273,7 @@ void VanityUtilities::ParseXML(const std::string& file) { // Get the NPC name auto* name = npc->Attribute("name"); - if (name == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC name"); - continue; - } + if (!name) name = ""; // Get the NPC lot auto* lot = npc->Attribute("lot"); @@ -279,71 +285,76 @@ void VanityUtilities::ParseXML(const std::string& file) { // Get the equipment auto* equipment = npc->FirstChildElement("equipment"); - - if (equipment == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC equipment"); - continue; - } - - auto* text = equipment->GetText(); - std::vector<LOT> inventory; - if (text != nullptr) { - std::string equipmentString(text); + if (equipment) { + auto* text = equipment->GetText(); - std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ','); + if (text != nullptr) { + std::string equipmentString(text); - for (auto& item : splitEquipment) { - inventory.push_back(std::stoi(item)); + std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ','); + + for (auto& item : splitEquipment) { + inventory.push_back(std::stoi(item)); + } } } + // Get the phrases auto* phrases = npc->FirstChildElement("phrases"); - if (phrases == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC phrases"); - continue; - } + std::vector<std::string> phraseList = {}; - std::vector<std::string> phraseList; - - for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr; - phrase = phrase->NextSiblingElement("phrase")) { - // Get the phrase - auto* text = phrase->GetText(); - - if (text == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC phrase"); - continue; + if (phrases) { + for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr; + phrase = phrase->NextSiblingElement("phrase")) { + // Get the phrase + auto* text = phrase->GetText(); + if (text == nullptr) { + Game::logger->Log("VanityUtilities", "Failed to parse NPC phrase"); + continue; + } + phraseList.push_back(text); } - - phraseList.push_back(text); } // Get the script auto* scriptElement = npc->FirstChildElement("script"); - std::string scriptName; + std::string scriptName = ""; if (scriptElement != nullptr) { auto* scriptNameAttribute = scriptElement->Attribute("name"); - - if (scriptNameAttribute == nullptr) { - Game::logger->Log("VanityUtilities", "Failed to parse NPC script name"); - continue; - } - - scriptName = scriptNameAttribute; + if (scriptNameAttribute) scriptName = scriptNameAttribute; } + auto* ldfElement = npc->FirstChildElement("ldf"); + std::vector<std::u16string> keys = {}; + + std::vector<LDFBaseData*> ldf = {}; + if(ldfElement) { + for (auto* entry = ldfElement->FirstChildElement("entry"); entry != nullptr; + entry = entry->NextSiblingElement("entry")) { + // Get the ldf data + auto* data = entry->Attribute("data"); + if (!data) continue; + + LDFBaseData* ldfData = LDFBaseData::DataFromString(data); + keys.push_back(ldfData->GetKey()); + ldf.push_back(ldfData); + } + } + if (!keys.empty()) ldf.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys)); + VanityNPC npcData; npcData.m_Name = name; npcData.m_LOT = std::stoi(lot); npcData.m_Equipment = inventory; npcData.m_Phrases = phraseList; npcData.m_Script = scriptName; + npcData.ldf = ldf; // Get flags auto* flags = npc->FirstChildElement("flags"); diff --git a/dGame/dUtilities/VanityUtilities.h b/dGame/dUtilities/VanityUtilities.h index 2f1886ed..0cca0aba 100644 --- a/dGame/dUtilities/VanityUtilities.h +++ b/dGame/dUtilities/VanityUtilities.h @@ -20,6 +20,7 @@ struct VanityNPC std::string m_Script; std::map<std::string, bool> m_Flags; std::map<uint32_t, std::vector<VanityNPCLocation>> m_Locations; + std::vector<LDFBaseData*> ldf; }; struct VanityParty diff --git a/dGame/dUtilities/dLocale.cpp b/dGame/dUtilities/dLocale.cpp deleted file mode 100644 index 65ef3a58..00000000 --- a/dGame/dUtilities/dLocale.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "dLocale.h" - -#include <clocale> -#include <fstream> -#include <sstream> -#include <vector> -#include <algorithm> - -#include "tinyxml2.h" -#include "Game.h" -#include "dConfig.h" - -dLocale::dLocale() { - if (Game::config->GetValue("locale_enabled") != "1") { - return; - } - - std::ifstream file(m_LocalePath); - - if (!file.good()) { - return; - } - - std::stringstream data; - data << file.rdbuf(); - - if (data.str().empty()) { - return; - } - - auto* doc = new tinyxml2::XMLDocument(); - - if (doc == nullptr) { - return; - } - - if (doc->Parse(data.str().c_str(), data.str().size()) != 0) { - return; - } - - std::hash<std::string> hash; - - auto* localization = doc->FirstChildElement("localization"); - auto* phrases = localization->FirstChildElement("phrases"); - - auto* phrase = phrases->FirstChildElement("phrase"); - - while (phrase != nullptr) { - // Add the phrase hash to the vector - m_Phrases.push_back(hash(phrase->Attribute("id"))); - phrase = phrase->NextSiblingElement("phrase"); - } - - file.close(); - - delete doc; -} - -dLocale::~dLocale() = default; - -std::string dLocale::GetTemplate(const std::string& phraseID) { - return "%[" + phraseID + "]"; -} - -bool dLocale::HasPhrase(const std::string& phraseID) { - if (Game::config->GetValue("locale_enabled") != "1") { - return true; - } - - // Compute the hash and see if it's in the vector - std::hash<std::string> hash; - std::size_t hashValue = hash(phraseID); - return std::find(m_Phrases.begin(), m_Phrases.end(), hashValue) != m_Phrases.end(); -} - -/*std::string dLocale::GetPhrase(const std::string& phraseID) { - if (m_Phrases.find(phraseID) == m_Phrases.end()) { - return ""; - } - return m_Phrases[phraseID]; -}*/ diff --git a/dGame/dUtilities/dLocale.h b/dGame/dUtilities/dLocale.h deleted file mode 100644 index db5d2a4f..00000000 --- a/dGame/dUtilities/dLocale.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include <map> -#include <string> -#include <vector> -#include <cstdint> - -class dLocale { -public: - dLocale(); - ~dLocale(); - static std::string GetTemplate(const std::string& phraseID); - bool HasPhrase(const std::string& phraseID); - //std::string GetPhrase(const std::string& phraseID); - -private: - std::string m_LocalePath = "./locale/locale.xml"; - std::string m_Locale = "en_US"; // TODO: add to config - std::vector<std::size_t> m_Phrases; -}; diff --git a/dMasterServer/CMakeLists.txt b/dMasterServer/CMakeLists.txt index 08fc63db..2161681f 100644 --- a/dMasterServer/CMakeLists.txt +++ b/dMasterServer/CMakeLists.txt @@ -1,9 +1,13 @@ -set(DMASTERSERVER_SOURCES "InstanceManager.cpp" - "MasterServer.cpp" - "ObjectIDManager.cpp") - -add_executable(MasterServer ${DMASTERSERVER_SOURCES}) -target_link_libraries(MasterServer ${COMMON_LIBRARIES}) +set(DMASTERSERVER_SOURCES + "InstanceManager.cpp" + "ObjectIDManager.cpp" +) + +add_library(dMasterServer ${DMASTERSERVER_SOURCES}) +add_executable(MasterServer "MasterServer.cpp") + +target_link_libraries(dMasterServer ${COMMON_LIBRARIES}) +target_link_libraries(MasterServer ${COMMON_LIBRARIES} dMasterServer) if(WIN32) add_dependencies(MasterServer WorldServer AuthServer ChatServer) diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 0c605ed6..fe62a5e5 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -10,6 +10,7 @@ #include "dMessageIdentifiers.h" #include "MasterPackets.h" #include "PacketUtils.h" +#include "BinaryPathFinder.h" InstanceManager::InstanceManager(dLogger* logger, const std::string& externalIP) { mLogger = logger; @@ -30,6 +31,15 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW Instance* instance = FindInstance(mapID, isFriendTransfer, cloneID); if (instance) return instance; + // If we are shutting down, return a nullptr so a new instance is not created. + if (m_IsShuttingDown) { + Game::logger->Log("InstanceManager", + "Tried to create a new instance map/instance/clone %i/%i/%i, but Master is shutting down.", + mapID, + m_LastInstanceID + 1, + cloneID); + return nullptr; + } //TODO: Update this so that the IP is read from a configuration file instead int softCap = 8; @@ -48,13 +58,13 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW //Start the actual process: #ifdef _WIN32 - std::string cmd = "start ./WorldServer.exe -zone "; + std::string cmd = "start " + (BinaryPathFinder::GetBinaryDir() / "WorldServer.exe").string() + " -zone "; #else std::string cmd; if (std::atoi(Game::config->GetValue("use_sudo_world").c_str())) { - cmd = "sudo ./WorldServer -zone "; + cmd = "sudo " + (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; } else { - cmd = "./WorldServer -zone "; + cmd = (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; } #endif @@ -73,7 +83,7 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW cmd.append("&"); //Sends our next process to the background on Linux #endif - system(cmd.c_str()); + auto ret = system(cmd.c_str()); m_Instances.push_back(instance); @@ -149,7 +159,7 @@ void InstanceManager::RemoveInstance(Instance* instance) { if (m_Instances[i] == instance) { instance->SetShutdownComplete(true); - RedirectPendingRequests(instance); + if (!Game::shouldShutdown) RedirectPendingRequests(instance); delete m_Instances[i]; @@ -237,7 +247,7 @@ void InstanceManager::RedirectPendingRequests(Instance* instance) { for (const auto& request : instance->GetPendingAffirmations()) { auto* in = Game::im->GetInstance(zoneId.GetMapID(), false, zoneId.GetCloneID()); - if (!in->GetIsReady()) // Instance not ready, make a pending request + if (in && !in->GetIsReady()) // Instance not ready, make a pending request { in->GetPendingRequests().push_back(request); @@ -294,16 +304,25 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon return instance; } + if (m_IsShuttingDown) { + Game::logger->Log("InstanceManager", + "Tried to create a new private instance map/instance/clone %i/%i/%i, but Master is shutting down.", + mapID, + m_LastInstanceID + 1, + cloneID); + return nullptr; + } + int maxPlayers = 999; uint32_t port = GetFreePort(); instance = new Instance(mExternalIP, port, mapID, ++m_LastInstanceID, cloneID, maxPlayers, maxPlayers, true, password); //Start the actual process: - std::string cmd = "start ./WorldServer.exe -zone "; + std::string cmd = "start " + (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; #ifndef _WIN32 - cmd = "./WorldServer -zone "; + cmd = (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone "; #endif cmd.append(std::to_string(mapID)); @@ -321,7 +340,7 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon cmd.append("&"); //Sends our next process to the background on Linux #endif - system(cmd.c_str()); + auto ret = system(cmd.c_str()); m_Instances.push_back(instance); @@ -350,7 +369,7 @@ Instance* InstanceManager::FindPrivateInstance(const std::string& password) { } int InstanceManager::GetSoftCap(LWOMAPID mapID) { - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); if (zoneTable) { const CDZoneTable* zone = zoneTable->Query(mapID); @@ -363,7 +382,7 @@ int InstanceManager::GetSoftCap(LWOMAPID mapID) { } int InstanceManager::GetHardCap(LWOMAPID mapID) { - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); if (zoneTable) { const CDZoneTable* zone = zoneTable->Query(mapID); @@ -390,5 +409,5 @@ void Instance::Shutdown() { Game::server->Send(&bitStream, this->m_SysAddr, false); - Game::logger->Log("Instance", "Triggered world shutdown"); + Game::logger->Log("Instance", "Triggered world shutdown for zone/clone/instance %i/%i/%i", GetMapID(), GetCloneID(), GetInstanceID()); } diff --git a/dMasterServer/InstanceManager.h b/dMasterServer/InstanceManager.h index 2c5083d4..5f48f93b 100644 --- a/dMasterServer/InstanceManager.h +++ b/dMasterServer/InstanceManager.h @@ -128,6 +128,7 @@ public: Instance* CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password); Instance* FindPrivateInstance(const std::string& password); + void SetIsShuttingDown(bool value) { this->m_IsShuttingDown = value; }; private: dLogger* mLogger; @@ -136,6 +137,11 @@ private: unsigned short m_LastPort; LWOINSTANCEID m_LastInstanceID; + /** + * Whether or not the master server is currently shutting down. + */ + bool m_IsShuttingDown = false; + //Private functions: bool IsInstanceFull(Instance* instance, bool isFriendTransfer); int GetSoftCap(LWOMAPID mapID); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 061a91c7..cc2bdd90 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -26,6 +26,7 @@ #include "dLogger.h" #include "dServer.h" #include "AssetManager.h" +#include "BinaryPathFinder.h" //RakNet includes: #include "RakNetDefines.h" @@ -39,27 +40,31 @@ #include "ObjectIDManager.h" #include "PacketUtils.h" #include "dMessageIdentifiers.h" +#include "FdbToSqlite.h" namespace Game { - dLogger* logger; - dServer* server; - InstanceManager* im; - dConfig* config; - AssetManager* assetManager; + dLogger* logger = nullptr; + dServer* server = nullptr; + InstanceManager* im = nullptr; + dConfig* config = nullptr; + AssetManager* assetManager = nullptr; + bool shouldShutdown = false; } //namespace Game bool shutdownSequenceStarted = false; -void ShutdownSequence(); -int FinalizeShutdown(); +void ShutdownSequence(int32_t signal = -1); +int32_t FinalizeShutdown(int32_t signal = -1); dLogger* SetupLogger(); void StartAuthServer(); void StartChatServer(); void HandlePacket(Packet* packet); std::map<uint32_t, std::string> activeSessions; -bool shouldShutdown = false; +SystemAddress authServerMasterPeerSysAddr; SystemAddress chatServerMasterPeerSysAddr; int main(int argc, char** argv) { + constexpr uint32_t masterFramerate = mediumFramerate; + constexpr uint32_t masterFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Master"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); @@ -69,29 +74,52 @@ int main(int argc, char** argv) { #endif //Triggers the shutdown sequence at application exit - std::atexit(ShutdownSequence); - signal(SIGINT, [](int) { ShutdownSequence(); }); - signal(SIGTERM, [](int) { ShutdownSequence(); }); + std::atexit([]() { ShutdownSequence(); }); + signal(SIGINT, [](int32_t signal) { ShutdownSequence(EXIT_FAILURE); }); + signal(SIGTERM, [](int32_t signal) { ShutdownSequence(EXIT_FAILURE); }); //Create all the objects we need to run our service: Game::logger = SetupLogger(); if (!Game::logger) return EXIT_FAILURE; + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "authconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find authconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "chatconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find chatconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "masterconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find masterconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find sharedconfig.ini"); + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "worldconfig.ini")) { + Game::logger->Log("MasterServer", "Couldnt find worldconfig.ini"); + return EXIT_FAILURE; + } + + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "masterconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); + Game::logger->Log("MasterServer", "Starting Master server..."); Game::logger->Log("MasterServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("MasterServer", "Compiled on: %s", __TIMESTAMP__); - //Read our config: - dConfig config("masterconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); @@ -102,9 +130,14 @@ int main(int argc, char** argv) { } try { - std::string client_path = config.GetValue("client_location"); - if (client_path.empty()) client_path = "./res"; - Game::assetManager = new AssetManager(client_path); + std::string clientPathStr = Game::config->GetValue("client_location"); + if (clientPathStr.empty()) clientPathStr = "./res"; + std::filesystem::path clientPath = std::filesystem::path(clientPathStr); + if (clientPath.is_relative()) { + clientPath = BinaryPathFinder::GetBinaryDir() / clientPath; + } + + Game::assetManager = new AssetManager(clientPath); } catch (std::runtime_error& ex) { Game::logger->Log("MasterServer", "Got an error while setting up assets: %s", ex.what()); @@ -113,37 +146,41 @@ int main(int argc, char** argv) { MigrationRunner::RunMigrations(); - // Check CDClient exists - if (!std::filesystem::exists(Game::assetManager->GetResPath() / "CDServer.sqlite")) { - Game::logger->Log("WorldServer", "CDServer.sqlite could not be opened. Looking for cdclient.fdb to convert to sqlite."); + const bool cdServerExists = std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); + const bool oldCDServerExists = std::filesystem::exists(Game::assetManager->GetResPath() / "CDServer.sqlite"); + const bool fdbExists = std::filesystem::exists(Game::assetManager->GetResPath() / "cdclient.fdb"); - if (!std::filesystem::exists(Game::assetManager->GetResPath() / "cdclient.fdb")) { - Game::logger->Log("WorldServer", "cdclient.fdb could not be opened. Please move a cdclient.fdb or an already converted database to build/res."); - return EXIT_FAILURE; - } + if (!cdServerExists) { + if (oldCDServerExists) { + // If the file doesn't exist in the new CDServer location, copy it there. We copy because we may not have write permissions from the previous directory. + Game::logger->Log("MasterServer", "CDServer.sqlite is not located at resServer, but is located at res path. Copying file..."); + std::filesystem::copy_file(Game::assetManager->GetResPath() / "CDServer.sqlite", BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite"); + } else { + Game::logger->Log("MasterServer", + "%s could not be found in resServer or res. Looking for %s to convert to sqlite.", + (BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").c_str(), + (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); - Game::logger->Log("WorldServer", "Found cdclient.fdb. Clearing cdserver migration_history then copying and converting to sqlite."); - auto stmt = Database::CreatePreppedStmt(R"#(DELETE FROM migration_history WHERE name LIKE "%cdserver%";)#"); - stmt->executeUpdate(); - delete stmt; + AssetMemoryBuffer cdClientBuffer = Game::assetManager->GetFileAsBuffer("cdclient.fdb"); + if (!cdClientBuffer.m_Success) { + Game::logger->Log("MasterServer", "Failed to load %s", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); + throw std::runtime_error("Aborting initialization due to missing cdclient.fdb."); + } - std::string res = "python3 ../thirdparty/docker-utils/utils/fdb_to_sqlite.py " + (Game::assetManager->GetResPath() / "cdclient.fdb").string(); + Game::logger->Log("MasterServer", "Found %s. Converting to SQLite", (Game::assetManager->GetResPath() / "cdclient.fdb").c_str()); + Game::logger->Flush(); - int result = system(res.c_str()); - if (result != 0) { - Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite"); - return EXIT_FAILURE; - } - - if (std::rename("./cdclient.sqlite", (Game::assetManager->GetResPath() / "CDServer.sqlite").string().c_str()) != 0) { - Game::logger->Log("MasterServer", "Failed to move cdclient file."); - return EXIT_FAILURE; + if (FdbToSqlite::Convert((BinaryPathFinder::GetBinaryDir() / "resServer").string()).ConvertDatabase(cdClientBuffer) == false) { + Game::logger->Log("MasterServer", "Failed to convert fdb to sqlite."); + return EXIT_FAILURE; + } + cdClientBuffer.close(); } } //Connect to CDClient try { - CDClientDatabase::Connect((Game::assetManager->GetResPath() / "CDServer.sqlite").string()); + CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").string()); } catch (CppSQLite3Exception& e) { Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); @@ -156,7 +193,7 @@ int main(int argc, char** argv) { //Get CDClient initial information try { - CDClientManager::Instance()->Initialize(); + CDClientManager::Instance(); } catch (CppSQLite3Exception& e) { Game::logger->Log("WorldServer", "Failed to initialize CDServer SQLite Database"); Game::logger->Log("WorldServer", "May be caused by corrupted file: %s", (Game::assetManager->GetResPath() / "CDServer.sqlite").string().c_str()); @@ -175,60 +212,96 @@ int main(int argc, char** argv) { std::cout << "Enter a username: "; std::cin >> username; + std::unique_ptr<sql::PreparedStatement> userLookupStatement(Database::CreatePreppedStmt("SELECT id FROM accounts WHERE name=? LIMIT 1;")); + userLookupStatement->setString(1, username.c_str()); + std::unique_ptr<sql::ResultSet> res(userLookupStatement->executeQuery()); + if (res->rowsCount() > 0) { + Game::logger->Log("MasterServer", "Account with name \"%s\" already exists", username.c_str()); + std::cout << "Do you want to change the password of that account? [y/n]?"; + std::string prompt = ""; + std::cin >> prompt; + if (prompt == "y" || prompt == "yes"){ + uint32_t accountId = 0; + res->next(); + accountId = res->getUInt(1); + if (accountId == 0) return EXIT_FAILURE; + + //Read the password from the console without echoing it. + #ifdef __linux__ + //This function is obsolete, but it only meant to be used by the + //sysadmin to create their first account. + password = getpass("Enter a password: "); + #else + std::cout << "Enter a password: "; + std::cin >> password; + #endif + + // Regenerate hash based on new password + char salt[BCRYPT_HASHSIZE]; + char hash[BCRYPT_HASHSIZE]; + int32_t bcryptState = ::bcrypt_gensalt(12, salt); + assert(bcryptState == 0); + bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash); + assert(bcryptState == 0); + + std::unique_ptr<sql::PreparedStatement> userUpdateStatement(Database::CreatePreppedStmt("UPDATE accounts SET password = ? WHERE id = ?;")); + userUpdateStatement->setString(1, std::string(hash, BCRYPT_HASHSIZE).c_str()); + userUpdateStatement->setUInt(2, accountId); + userUpdateStatement->execute(); + + Game::logger->Log("MasterServer", "Account \"%s\" password updated successfully!", username.c_str()); + } else { + Game::logger->Log("MasterServer", "Account \"%s\" was not updated.", username.c_str()); + } + return EXIT_SUCCESS; + } + //Read the password from the console without echoing it. -#ifdef __linux__ - //This function is obsolete, but it only meant to be used by the - //sysadmin to create their first account. - password = getpass("Enter a password: "); -#else - std::cout << "Enter a password: "; - std::cin >> password; -#endif + #ifdef __linux__ + //This function is obsolete, but it only meant to be used by the + //sysadmin to create their first account. + password = getpass("Enter a password: "); + #else + std::cout << "Enter a password: "; + std::cin >> password; + #endif //Generate new hash for bcrypt - char salt[BCRYPT_HASHSIZE]; char hash[BCRYPT_HASHSIZE]; - int32_t bcryptState = ::bcrypt_gensalt(12, salt); - assert(bcryptState == 0); - bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash); - assert(bcryptState == 0); //Create account + try { + std::unique_ptr<sql::PreparedStatement> statement(Database::CreatePreppedStmt("INSERT INTO accounts (name, password, gm_level) VALUES (?, ?, ?);")); + statement->setString(1, username.c_str()); + statement->setString(2, std::string(hash, BCRYPT_HASHSIZE).c_str()); + statement->setInt(3, 9); + statement->execute(); + } catch(sql::SQLException& e) { + Game::logger->Log("MasterServer", "A SQL error occurred!:\n %s", e.what()); + return EXIT_FAILURE; + } - auto* statement = Database::CreatePreppedStmt("INSERT INTO accounts (name, password, ""gm_level) VALUES (?, ?, ?);"); - statement->setString(1, username); - statement->setString(2, std::string(hash, BCRYPT_HASHSIZE).c_str()); - statement->setInt(3, 9); - - statement->execute(); - - delete statement; - - std::cout << "Account created successfully!\n"; - - Database::Destroy("MasterServer"); - delete Game::logger; - + Game::logger->Log("MasterServer", "Account created successfully!"); return EXIT_SUCCESS; } - int maxClients = 999; - int ourPort = 1000; - if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients")); - if (config.GetValue("port") != "") ourPort = std::stoi(config.GetValue("port")); + uint32_t maxClients = 999; + uint32_t ourPort = 1000; + if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); + if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port")); - Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master); + Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::shouldShutdown); //Query for the database for a server labeled "master" auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'"); auto* result = masterLookupStatement->executeQuery(); - auto master_server_ip = config.GetValue("master_ip"); + auto master_server_ip = Game::config->GetValue("master_ip"); if (master_server_ip == "") { master_server_ip = Game::server->GetIP(); @@ -256,20 +329,24 @@ int main(int argc, char** argv) { Game::im = new InstanceManager(Game::logger, Game::server->GetIP()); //Depending on the config, start up servers: - if (config.GetValue("prestart_servers") != "" && config.GetValue("prestart_servers") == "1") { + if (Game::config->GetValue("prestart_servers") != "" && Game::config->GetValue("prestart_servers") == "1") { StartChatServer(); - Game::im->GetInstance(0, false, 0)->SetIsReady(true); - Game::im->GetInstance(1000, false, 0)->SetIsReady(true); + Game::im->GetInstance(0, false, 0); + Game::im->GetInstance(1000, false, 0); StartAuthServer(); } auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceLastSQLPing = 0; - int framesSinceKillUniverseCommand = 0; + constexpr uint32_t logFlushTime = 15 * masterFramerate; + constexpr uint32_t sqlPingTime = 10 * 60 * masterFramerate; + constexpr uint32_t shutdownUniverseTime = 10 * 60 * masterFramerate; + constexpr uint32_t instanceReadyTimeout = 30 * masterFramerate; + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceLastSQLPing = 0; + uint32_t framesSinceKillUniverseCommand = 0; while (true) { //In world we'd update our other systems here. @@ -283,17 +360,17 @@ int main(int argc, char** argv) { } //Push our log every 15s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -309,8 +386,8 @@ int main(int argc, char** argv) { framesSinceLastSQLPing++; //10m shutdown for universe kill command - if (shouldShutdown) { - if (framesSinceKillUniverseCommand >= 40000) { + if (Game::shouldShutdown) { + if (framesSinceKillUniverseCommand >= shutdownUniverseTime) { //Break main loop and exit break; } else @@ -334,7 +411,7 @@ int main(int argc, char** argv) { instance->SetAffirmationTimeout(affirmTimeout); - if (affirmTimeout == 1000) { + if (affirmTimeout == instanceReadyTimeout) { instance->Shutdown(); instance->SetIsShuttingDown(true); @@ -353,17 +430,15 @@ int main(int argc, char** argv) { } } - t += std::chrono::milliseconds(highFrameRate); + t += std::chrono::milliseconds(masterFrameDelta); std::this_thread::sleep_until(t); } - FinalizeShutdown(); - exit(EXIT_SUCCESS); - return EXIT_SUCCESS; + return FinalizeShutdown(EXIT_SUCCESS); } dLogger* SetupLogger() { std::string logPath = - "./logs/MasterServer_" + std::to_string(time(nullptr)) + ".log"; + (BinaryPathFinder::GetBinaryDir() / ("logs/MasterServer_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; #ifdef _DEBUG @@ -387,9 +462,15 @@ void HandlePacket(Packet* packet) { Game::im->RemoveInstance(instance); //Delete the old } - if (packet->systemAddress == chatServerMasterPeerSysAddr && !shouldShutdown) { + if (packet->systemAddress == chatServerMasterPeerSysAddr) { + chatServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; StartChatServer(); } + + if (packet->systemAddress == authServerMasterPeerSysAddr) { + authServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; + StartAuthServer(); + } } if (packet->data[0] == ID_CONNECTION_LOST) { @@ -400,12 +481,17 @@ void HandlePacket(Packet* packet) { if (instance) { LWOZONEID zoneID = instance->GetZoneID(); //Get the zoneID so we can recreate a server Game::im->RemoveInstance(instance); //Delete the old - //Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new } - if (packet->systemAddress == chatServerMasterPeerSysAddr && !shouldShutdown) { + if (packet->systemAddress == chatServerMasterPeerSysAddr) { + chatServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; StartChatServer(); } + + if (packet->systemAddress == authServerMasterPeerSysAddr) { + authServerMasterPeerSysAddr = UNASSIGNED_SYSTEM_ADDRESS; + StartAuthServer(); + } } if (packet->data[1] == MASTER) { @@ -435,14 +521,17 @@ void HandlePacket(Packet* packet) { inStream.Read(mythranShift); inStream.Read(zoneID); inStream.Read(zoneClone); - + if (shutdownSequenceStarted) { + Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not creating a new zone."); + break; + } Instance* in = Game::im->GetInstance(zoneID, false, zoneClone); for (auto* instance : Game::im->GetInstances()) { Game::logger->Log("MasterServer", "Instance: %i/%i/%i -> %i", instance->GetMapID(), instance->GetCloneID(), instance->GetInstanceID(), instance == in); } - if (!in->GetIsReady()) //Instance not ready, make a pending request + if (in && !in->GetIsReady()) //Instance not ready, make a pending request { in->GetPendingRequests().push_back({ requestID, static_cast<bool>(mythranShift), packet->systemAddress }); Game::logger->Log("MasterServer", "Server not ready, adding pending request %llu %i %i", requestID, zoneID, zoneClone); @@ -501,6 +590,14 @@ void HandlePacket(Packet* packet) { chatServerMasterPeerSysAddr = copy; } + if (theirServerType == ServerType::Auth) { + SystemAddress copy; + copy.binaryAddress = packet->systemAddress.binaryAddress; + copy.port = packet->systemAddress.port; + + authServerMasterPeerSysAddr = copy; + } + Game::logger->Log("MasterServer", "Received server info, instance: %i port: %i", theirInstanceID, theirPort); break; @@ -606,7 +703,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read<uint32_t>(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read<char>(character); password += character; @@ -632,7 +729,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read<uint32_t>(len); - for (int i = 0; i < len; i++) { + for (uint32_t i = 0; i < len; i++) { char character; inStream.Read<char>(character); password += character; } @@ -680,11 +777,15 @@ void HandlePacket(Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); - int zoneID; + int32_t zoneID; inStream.Read(zoneID); - - Game::logger->Log("MasterServer", "Prepping zone %i", zoneID); - Game::im->GetInstance(zoneID, false, 0); + if (shutdownSequenceStarted) { + Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not prepping a new zone."); + break; + } else { + Game::logger->Log("MasterServer", "Prepping zone %i", zoneID); + Game::im->GetInstance(zoneID, false, 0); + } break; } @@ -725,7 +826,7 @@ void HandlePacket(Packet* packet) { case MSG_MASTER_SHUTDOWN_UNIVERSE: { Game::logger->Log("MasterServer", "Received shutdown universe command, shutting down in 10 minutes."); - shouldShutdown = true; + Game::shouldShutdown = true; break; } @@ -736,76 +837,95 @@ void HandlePacket(Packet* packet) { } void StartChatServer() { + if (Game::shouldShutdown) { + Game::logger->Log("MasterServer", "Currently shutting down. Chat will not be restarted."); + return; + } #ifdef __APPLE__ //macOS doesn't need sudo to run on ports < 1024 - system("./ChatServer&"); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); #elif _WIN32 - system("start ./ChatServer.exe"); + auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); #else if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) { - system("sudo ./ChatServer&"); + auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } else { - system("./ChatServer&"); - } + auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); +} #endif } void StartAuthServer() { + if (Game::shouldShutdown) { + Game::logger->Log("MasterServer", "Currently shutting down. Auth will not be restarted."); + return; + } #ifdef __APPLE__ - system("./AuthServer&"); + auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); #elif _WIN32 - system("start ./AuthServer.exe"); + auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); #else if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) { - system("sudo ./AuthServer&"); + auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } else { - system("./AuthServer&"); - } + auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); +} #endif } -void ShutdownSequence() { +void ShutdownSequence(int32_t signal) { if (shutdownSequenceStarted) { return; } + if (!Game::im) { + FinalizeShutdown(EXIT_FAILURE); + } + + Game::im->SetIsShuttingDown(true); shutdownSequenceStarted = true; + Game::shouldShutdown = true; - if (Game::im) { - for (auto* instance : Game::im->GetInstances()) { - if (instance == nullptr) { - continue; - } - - instance->Shutdown(); - } + { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN); + Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::logger->Log("MasterServer", "Triggered master shutdown"); } auto* objIdManager = ObjectIDManager::TryInstance(); - if (objIdManager != nullptr) { + if (objIdManager) { objIdManager->SaveToDatabase(); Game::logger->Log("MasterServer", "Saved ObjectIDTracker to DB"); } - auto t = std::chrono::high_resolution_clock::now(); - auto ticks = 0; + // A server might not be finished spinning up yet, remove all of those here. + for (auto* instance : Game::im->GetInstances()) { + if (!instance->GetIsReady()) { + Game::im->RemoveInstance(instance); + } + } - if (!Game::im) { - exit(EXIT_SUCCESS); + for (auto* instance : Game::im->GetInstances()) { + instance->SetIsShuttingDown(true); } Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds..."); + auto t = std::chrono::high_resolution_clock::now(); + uint32_t framesSinceShutdownStart = 0; + constexpr uint32_t maxShutdownTime = 60 * mediumFramerate; + bool allInstancesShutdown = false; + Packet* packet = nullptr; while (true) { - - auto packet = Game::server->Receive(); + packet = Game::server->Receive(); if (packet) { HandlePacket(packet); Game::server->DeallocatePacket(packet); packet = nullptr; } - auto done = true; + allInstancesShutdown = true; for (auto* instance : Game::im->GetInstances()) { if (instance == nullptr) { @@ -813,36 +933,37 @@ void ShutdownSequence() { } if (!instance->GetShutdownComplete()) { - done = false; + allInstancesShutdown = false; } } - if (done) { + if (allInstancesShutdown && authServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS && chatServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS) { Game::logger->Log("MasterServer", "Finished shutting down MasterServer!"); break; } - t += std::chrono::milliseconds(highFrameRate); + t += std::chrono::milliseconds(mediumFrameDelta); std::this_thread::sleep_until(t); - ticks++; + framesSinceShutdownStart++; - if (ticks == 600 * 6) { + if (framesSinceShutdownStart == maxShutdownTime) { Game::logger->Log("MasterServer", "Finished shutting down by timeout!"); break; } } - FinalizeShutdown(); + FinalizeShutdown(signal); } -int FinalizeShutdown() { +int32_t FinalizeShutdown(int32_t signal) { //Delete our objects here: Database::Destroy("MasterServer"); + if (Game::config) delete Game::config; if (Game::im) delete Game::im; if (Game::server) delete Game::server; if (Game::logger) delete Game::logger; - exit(EXIT_SUCCESS); - return EXIT_SUCCESS; + if (signal != EXIT_SUCCESS) exit(signal); + return signal; } diff --git a/dMasterServer/ObjectIDManager.cpp b/dMasterServer/ObjectIDManager.cpp index 0f3b98c9..83dde8dd 100644 --- a/dMasterServer/ObjectIDManager.cpp +++ b/dMasterServer/ObjectIDManager.cpp @@ -51,13 +51,13 @@ uint32_t ObjectIDManager::GeneratePersistentID(void) { uint32_t toReturn = ++this->currentPersistentID; // So we peroidically save our ObjID to the database: - if (toReturn % 25 == 0) { // TEMP: DISABLED FOR DEBUG / DEVELOPMENT! + // if (toReturn % 25 == 0) { // TEMP: DISABLED FOR DEBUG / DEVELOPMENT! sql::PreparedStatement* stmt = Database::CreatePreppedStmt( "UPDATE object_id_tracker SET last_object_id=?"); stmt->setUInt(1, toReturn); stmt->execute(); delete stmt; - } + // } return toReturn; } diff --git a/dNavigation/dNavMesh.cpp b/dNavigation/dNavMesh.cpp index e5ba0129..fdba4a2d 100644 --- a/dNavigation/dNavMesh.cpp +++ b/dNavigation/dNavMesh.cpp @@ -7,6 +7,7 @@ #include "dPlatforms.h" #include "NiPoint3.h" #include "BinaryIO.h" +#include "BinaryPathFinder.h" #include "dZoneManager.h" @@ -43,7 +44,7 @@ dNavMesh::~dNavMesh() { void dNavMesh::LoadNavmesh() { - std::string path = "./navmeshes/" + std::to_string(m_ZoneId) + ".bin"; + std::string path = (BinaryPathFinder::GetBinaryDir() / "navmeshes/" / (std::to_string(m_ZoneId) + ".bin")).string(); if (!BinaryIO::DoesFileExist(path)) { return; diff --git a/dNet/AuthPackets.cpp b/dNet/AuthPackets.cpp index 60fe13c5..4e7cb0a6 100644 --- a/dNet/AuthPackets.cpp +++ b/dNet/AuthPackets.cpp @@ -21,6 +21,7 @@ #include "Game.h" #include "dConfig.h" +#include "eServerDisconnectIdentifiers.h" void AuthPackets::HandleHandshake(dServer* server, Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); @@ -29,16 +30,16 @@ void AuthPackets::HandleHandshake(dServer* server, Packet* packet) { inStream.Read(clientVersion); server->GetLogger()->Log("AuthPackets", "Received client version: %i", clientVersion); - SendHandshake(server, packet->systemAddress, server->GetIP(), server->GetPort()); + SendHandshake(server, packet->systemAddress, server->GetIP(), server->GetPort(), server->GetServerType()); } -void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort) { +void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServerType serverType) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, SERVER, MSG_SERVER_VERSION_CONFIRM); bitStream.Write<unsigned int>(NET_VERSION); bitStream.Write(uint32_t(0x93)); - if (nextServerPort == 1001) bitStream.Write(uint32_t(1)); //Conn: auth + if (serverType == ServerType::Auth) bitStream.Write(uint32_t(1)); //Conn: auth else bitStream.Write(uint32_t(4)); //Conn: world bitStream.Write(uint32_t(0)); //Server process ID diff --git a/dNet/AuthPackets.h b/dNet/AuthPackets.h index e972d2f7..378a5862 100644 --- a/dNet/AuthPackets.h +++ b/dNet/AuthPackets.h @@ -5,11 +5,12 @@ #include "dCommonVars.h" #include "dNetCommon.h" +enum class ServerType : uint32_t; class dServer; namespace AuthPackets { void HandleHandshake(dServer* server, Packet* packet); - void SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort); + void SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServerType serverType); void HandleLoginRequest(dServer* server, Packet* packet); void SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username); diff --git a/dNet/ClientPackets.cpp b/dNet/ClientPackets.cpp index 39e835d2..a1c08938 100644 --- a/dNet/ClientPackets.cpp +++ b/dNet/ClientPackets.cpp @@ -31,8 +31,9 @@ #include "dConfig.h" #include "CharacterComponent.h" #include "Database.h" - - +#include "dMessageIdentifiers.h" +#include "eGameMasterLevel.h" +#include "eReplicaComponentType.h" void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* packet) { User* user = UserManager::Instance()->GetUser(sysAddr); @@ -66,7 +67,7 @@ void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* pack } std::string playerName = user->GetLastUsedChar()->GetName(); - bool isMythran = user->GetLastUsedChar()->GetGMLevel() > 0; + bool isMythran = user->GetLastUsedChar()->GetGMLevel() > eGameMasterLevel::CIVILIAN; if (!user->GetLastChatMessageApproved() && !isMythran) return; @@ -89,7 +90,7 @@ void ClientPackets::HandleClientPositionUpdate(const SystemAddress& sysAddr, Pac Entity* entity = EntityManager::Instance()->GetEntity(user->GetLastUsedChar()->GetObjectID()); if (!entity) return; - ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!comp) return; /* @@ -268,7 +269,7 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa // Check if the player has restricted chat access auto* character = entity->GetCharacter(); - if (character->HasPermission(PermissionMap::RestrictedChatAccess)) { + if (character->HasPermission(ePermissionMap::RestrictedChatAccess)) { // Send a message to the player ChatPackets::SendSystemMessage( sysAddr, diff --git a/dNet/WorldPackets.cpp b/dNet/WorldPackets.cpp index f6a8f558..febb6bc1 100644 --- a/dNet/WorldPackets.cpp +++ b/dNet/WorldPackets.cpp @@ -15,6 +15,7 @@ #include "CharacterComponent.h" #include "ZCompression.h" + void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_LOAD_STATIC_ZONE); @@ -127,7 +128,7 @@ void WorldPackets::SendServerState(const SystemAddress& sysAddr) { SEND_PACKET; } -void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, int32_t gm) { +void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CREATE_CHARACTER); @@ -144,8 +145,8 @@ void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* ent LDFData<LOT>* lot = new LDFData<LOT>(u"template", 1); LDFData<std::string>* xmlConfigData = new LDFData<std::string>(u"xmlData", xmlData); LDFData<std::u16string>* name = new LDFData<std::u16string>(u"name", username); - LDFData<int32_t>* gmlevel = new LDFData<int32_t>(u"gmlevel", gm); - LDFData<int32_t>* chatmode = new LDFData<int32_t>(u"chatmode", gm); + LDFData<int32_t>* gmlevel = new LDFData<int32_t>(u"gmlevel", static_cast<int32_t>(gm)); + LDFData<int32_t>* chatmode = new LDFData<int32_t>(u"chatmode", static_cast<int32_t>(gm)); LDFData<int64_t>* reputation = new LDFData<int64_t>(u"reputation", character->GetReputation()); objid->WriteToPacket(&data); @@ -220,14 +221,14 @@ void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool SEND_PACKET; } -void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, uint8_t highestLevel, uint8_t prevLevel, uint8_t newLevel) { +void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel) { CBITSTREAM; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_MAKE_GM_RESPONSE); bitStream.Write<uint8_t>(success); - bitStream.Write<uint16_t>(highestLevel); - bitStream.Write<uint16_t>(prevLevel); - bitStream.Write<uint16_t>(newLevel); + bitStream.Write(static_cast<uint16_t>(highestLevel)); + bitStream.Write(static_cast<uint16_t>(prevLevel)); + bitStream.Write(static_cast<uint16_t>(newLevel)); SEND_PACKET; } diff --git a/dNet/WorldPackets.h b/dNet/WorldPackets.h index d9951941..ec20ac22 100644 --- a/dNet/WorldPackets.h +++ b/dNet/WorldPackets.h @@ -8,6 +8,7 @@ class User; struct SystemAddress; +enum class eGameMasterLevel : uint8_t; namespace WorldPackets { void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum); @@ -17,9 +18,9 @@ namespace WorldPackets { void SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response); void SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift); void SendServerState(const SystemAddress& sysAddr); - void SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, int32_t gm); + void SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm); void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems); - void SendGMLevelChange(const SystemAddress& sysAddr, bool success, uint8_t highestLevel, uint8_t prevLevel, uint8_t newLevel); + void SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel); } #endif // WORLDPACKETS_H diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index 4c032f33..c91c7508 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -2,6 +2,7 @@ #include "dServer.h" #include "dNetCommon.h" #include "dLogger.h" +#include "dConfig.h" #include "RakNetworkFactory.h" #include "MessageIdentifiers.h" @@ -35,7 +36,7 @@ public: } } ReceiveDownloadCompleteCB; -dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, unsigned int zoneID) { +dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, bool* shouldShutdown, unsigned int zoneID) { mIP = ip; mPort = port; mZoneID = zoneID; @@ -50,7 +51,8 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect mNetIDManager = nullptr; mReplicaManager = nullptr; mServerType = serverType; - + mConfig = config; + mShouldShutdown = shouldShutdown; //Attempt to start our server here: mIsOkay = Startup(); @@ -123,8 +125,11 @@ Packet* dServer::ReceiveFromMaster() { ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet); break; } + case MSG_MASTER_SHUTDOWN: + *mShouldShutdown = true; + break; - //When we handle these packets in World instead dServer, we just return the packet's pointer. + //When we handle these packets in World instead dServer, we just return the packet's pointer. default: return packet; @@ -159,7 +164,7 @@ void dServer::SendToMaster(RakNet::BitStream* bitStream) { mMasterPeer->Send(bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, mMasterSystemAddress, false); } -void dServer::Disconnect(const SystemAddress& sysAddr, uint32_t disconNotifyID) { +void dServer::Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID) { RakNet::BitStream bitStream; PacketUtils::WriteHeader(bitStream, SERVER, MSG_SERVER_DISCONNECT_NOTIFY); bitStream.Write(disconNotifyID); @@ -182,7 +187,8 @@ bool dServer::Startup() { if (mIsInternal) { mPeer->SetIncomingPassword("3.25 DARKFLAME1", 15); } else { - //mPeer->SetPerConnectionOutgoingBandwidthLimit(800000); //100Kb/s + UpdateBandwidthLimit(); + UpdateMaximumMtuSize(); mPeer->SetIncomingPassword("3.25 ND1", 8); } @@ -192,8 +198,21 @@ bool dServer::Startup() { return true; } +void dServer::UpdateMaximumMtuSize() { + auto maxMtuSize = mConfig->GetValue("maximum_mtu_size"); + mPeer->SetMTUSize(maxMtuSize.empty() ? 1228 : std::stoi(maxMtuSize)); +} + +void dServer::UpdateBandwidthLimit() { + auto newBandwidth = mConfig->GetValue("maximum_outgoing_bandwidth"); + mPeer->SetPerConnectionOutgoingBandwidthLimit(!newBandwidth.empty() ? std::stoi(newBandwidth) : 0); +} + void dServer::Shutdown() { - mPeer->Shutdown(1000); + if (mPeer) { + mPeer->Shutdown(1000); + RakNetworkFactory::DestroyRakPeerInterface(mPeer); + } if (mNetIDManager) { delete mNetIDManager; @@ -205,10 +224,9 @@ void dServer::Shutdown() { mReplicaManager = nullptr; } - //RakNetworkFactory::DestroyRakPeerInterface(mPeer); //Not needed, we already called Shutdown ourselves. - if (mServerType != ServerType::Master) { + if (mServerType != ServerType::Master && mMasterPeer) { mMasterPeer->Shutdown(1000); - //RakNetworkFactory::DestroyRakPeerInterface(mMasterPeer); + RakNetworkFactory::DestroyRakPeerInterface(mMasterPeer); } } diff --git a/dNet/dServer.h b/dNet/dServer.h index bd052f86..797647b6 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -5,6 +5,8 @@ #include "NetworkIDManager.h" class dLogger; +class dConfig; +enum class eServerDisconnectIdentifiers : uint32_t; enum class ServerType : uint32_t { Master, @@ -15,17 +17,32 @@ enum class ServerType : uint32_t { class dServer { public: - dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, unsigned int zoneID = 0); + // Default constructor should only used for testing! + dServer() {}; + dServer( + const std::string& ip, + int port, + int instanceID, + int maxConnections, + bool isInternal, + bool useEncryption, + dLogger* logger, + const std::string masterIP, + int masterPort, + ServerType serverType, + dConfig* config, + bool* shouldShutdown, + unsigned int zoneID = 0); ~dServer(); Packet* ReceiveFromMaster(); Packet* Receive(); void DeallocatePacket(Packet* packet); void DeallocateMasterPacket(Packet* packet); - void Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast); + virtual void Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast); void SendToMaster(RakNet::BitStream* bitStream); - void Disconnect(const SystemAddress& sysAddr, uint32_t disconNotifyID); + void Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID); bool IsConnected(const SystemAddress& sysAddr); const std::string& GetIP() const { return mIP; } @@ -40,6 +57,8 @@ public: const int GetInstanceID() const { return mInstanceID; } ReplicaManager* GetReplicaManager() { return mReplicaManager; } void UpdateReplica(); + void UpdateBandwidthLimit(); + void UpdateMaximumMtuSize(); int GetPing(const SystemAddress& sysAddr) const; int GetLatestPing(const SystemAddress& sysAddr) const; @@ -55,10 +74,16 @@ private: bool ConnectToMaster(); private: - dLogger* mLogger; - RakPeerInterface* mPeer; - ReplicaManager* mReplicaManager; - NetworkIDManager* mNetIDManager; + dLogger* mLogger = nullptr; + dConfig* mConfig = nullptr; + RakPeerInterface* mPeer = nullptr; + ReplicaManager* mReplicaManager = nullptr; + NetworkIDManager* mNetIDManager = nullptr; + + /** + * Whether or not to shut down the server. Pointer to Game::shouldShutdown. + */ + bool* mShouldShutdown = nullptr; SocketDescriptor mSocketDescriptor; std::string mIP; int mPort; @@ -71,7 +96,7 @@ private: bool mMasterConnectionActive; ServerType mServerType; - RakPeerInterface* mMasterPeer; + RakPeerInterface* mMasterPeer = nullptr; SocketDescriptor mMasterSocketDescriptor; SystemAddress mMasterSystemAddress; std::string mMasterIP; diff --git a/dPhysics/dpGrid.cpp b/dPhysics/dpGrid.cpp index 6e44ade9..b4fe385e 100644 --- a/dPhysics/dpGrid.cpp +++ b/dPhysics/dpGrid.cpp @@ -6,6 +6,7 @@ dpGrid::dpGrid(int numCells, int cellSize) { NUM_CELLS = numCells; CELL_SIZE = cellSize; + m_DeleteGrid = true; //dumb method but i can't be bothered @@ -23,6 +24,7 @@ dpGrid::dpGrid(int numCells, int cellSize) { } dpGrid::~dpGrid() { + if (!this->m_DeleteGrid) return; for (auto& x : m_Cells) { //x for (auto& y : x) { //y for (auto en : y) { diff --git a/dPhysics/dpGrid.h b/dPhysics/dpGrid.h index a10f165e..229e7449 100644 --- a/dPhysics/dpGrid.h +++ b/dPhysics/dpGrid.h @@ -23,6 +23,15 @@ public: void Update(float deltaTime); + /** + * Sets the delete grid parameter to value. When false, the grid will not clean up memory. + * + * @param value Whether or not to delete entities on deletion of the grid. + */ + void SetDeleteGrid(bool value) { this->m_DeleteGrid = value; }; + + std::vector<std::vector<std::forward_list<dpEntity*>>> GetCells() { return this->m_Cells; }; + private: void HandleEntity(dpEntity* entity, dpEntity* other); void HandleCell(int x, int z, float deltaTime); @@ -31,4 +40,5 @@ private: //cells on X, cells on Y for that X, then another vector that contains the entities within that cell. std::vector<std::vector<std::forward_list<dpEntity*>>> m_Cells; std::map<LWOOBJID, dpEntity*> m_GargantuanObjects; + bool m_DeleteGrid = true; }; diff --git a/dPhysics/dpWorld.cpp b/dPhysics/dpWorld.cpp index 510da518..70fbfa3a 100644 --- a/dPhysics/dpWorld.cpp +++ b/dPhysics/dpWorld.cpp @@ -9,7 +9,7 @@ #include "dLogger.h" #include "dConfig.h" -void dpWorld::Initialize(unsigned int zoneID) { +void dpWorld::Initialize(unsigned int zoneID, bool generateNewNavMesh) { phys_sp_tilecount = std::atoi(Game::config->GetValue("phys_sp_tilecount").c_str()); phys_sp_tilesize = std::atoi(Game::config->GetValue("phys_sp_tilesize").c_str()); @@ -21,13 +21,37 @@ void dpWorld::Initialize(unsigned int zoneID) { m_Grid = new dpGrid(phys_sp_tilecount, phys_sp_tilesize); } - m_NavMesh = new dNavMesh(zoneID); + if (generateNewNavMesh) m_NavMesh = new dNavMesh(zoneID); Game::logger->Log("dpWorld", "Physics world initialized!"); + m_ZoneID = zoneID; +} + +void dpWorld::Reload() { + if (m_Grid) { + m_Grid->SetDeleteGrid(false); + auto oldGridCells = m_Grid->GetCells(); + delete m_Grid; + m_Grid = nullptr; + + Initialize(m_ZoneID, false); + for (auto column : oldGridCells) { + for (auto row : column) { + for (auto entity : row) { + AddEntity(entity); + } + } + } + Game::logger->Log("dpWorld", "Successfully reloaded physics world!"); + } else { + Game::logger->Log("dpWorld", "No physics world to reload!"); + } } dpWorld::~dpWorld() { if (m_Grid) { + // Triple check this is true + m_Grid->SetDeleteGrid(true); delete m_Grid; m_Grid = nullptr; } @@ -103,14 +127,14 @@ bool dpWorld::ShouldUseSP(unsigned int zoneID) { // Only large maps should be added as tiling likely makes little difference on small maps. switch (zoneID) { - case 1100: // Avant Gardens - case 1200: // Nimbus Station - case 1300: // Gnarled Forest - case 1400: // Forbidden Valley - case 1800: // Crux Prime - case 1900: // Nexus Tower - case 2000: // Ninjago - return true; + case 1100: // Avant Gardens + case 1200: // Nimbus Station + case 1300: // Gnarled Forest + case 1400: // Forbidden Valley + case 1800: // Crux Prime + case 1900: // Nexus Tower + case 2000: // Ninjago + return true; } return false; diff --git a/dPhysics/dpWorld.h b/dPhysics/dpWorld.h index 45e550cb..d48435d0 100644 --- a/dPhysics/dpWorld.h +++ b/dPhysics/dpWorld.h @@ -19,7 +19,8 @@ class dpGrid; class dpWorld : public Singleton<dpWorld> { public: - void Initialize(unsigned int zoneID); + void Initialize(unsigned int zoneID, bool generateNewNavMesh = true); + void Reload(); ~dpWorld(); @@ -43,4 +44,5 @@ private: std::vector<dpEntity*> m_DynamicEntites; dNavMesh* m_NavMesh = nullptr; + uint32_t m_ZoneID = 0; }; diff --git a/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp index f785ff1a..a3b9cc3f 100644 --- a/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp +++ b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp @@ -13,6 +13,7 @@ #include "GameMessages.h" #include "SkillComponent.h" +#include "eReplicaComponentType.h" #include <vector> @@ -27,9 +28,9 @@ void BossSpiderQueenEnemyServer::OnStartup(Entity* self) { //self:SetStatusImmunity{ StateChangeType = "PUSH", bImmuneToPullToPoint = true, bImmuneToKnockback = true, bImmuneToInterrupt = true } //Get our components: - destroyable = static_cast<DestroyableComponent*>(self->GetComponent(COMPONENT_TYPE_DESTROYABLE)); - controllable = static_cast<ControllablePhysicsComponent*>(self->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); - combat = static_cast<BaseCombatAIComponent*>(self->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI)); + destroyable = static_cast<DestroyableComponent*>(self->GetComponent(eReplicaComponentType::DESTROYABLE)); + controllable = static_cast<ControllablePhysicsComponent*>(self->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); + combat = static_cast<BaseCombatAIComponent*>(self->GetComponent(eReplicaComponentType::BASE_COMBAT_AI)); if (!destroyable || !controllable) return; @@ -47,8 +48,6 @@ void BossSpiderQueenEnemyServer::OnStartup(Entity* self) { m_CurrentBossStage = 1; // Obtain faction and collision group to save for subsequent resets - //self : SetVar("SBFactionList", self:GetFaction().factionList) - //self : SetVar("SBCollisionGroup", self:GetCollisionGroup().colGroup) } void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) { @@ -162,9 +161,6 @@ void BossSpiderQueenEnemyServer::SpawnSpiderWave(Entity* self, int spiderCount) // The Spider Queen Boss is withdrawing and requesting the spawn // of a hatchling wave - /*auto SpiderEggNetworkID = self->GetI64(u"SpiderEggNetworkID"); - if (SpiderEggNetworkID == 0) return;*/ - // Clamp invalid Spiderling number requests to the maximum amount of eggs available if ((spiderCount > maxSpiderEggCnt) || (spiderCount < 0)) spiderCount = maxSpiderEggCnt; @@ -173,44 +169,13 @@ void BossSpiderQueenEnemyServer::SpawnSpiderWave(Entity* self, int spiderCount) hatchCounter = spiderCount; hatchList = {}; - Game::logger->Log("SpiderQueen", "Trying to spawn %i spiders", hatchCounter); - - // Run the wave manager SpiderWaveManager(self); - } void BossSpiderQueenEnemyServer::SpiderWaveManager(Entity* self) { auto SpiderEggNetworkID = self->GetI64(u"SpiderEggNetworkID"); - // Reset the spider egg spawner network to ensure a maximum number of eggs - //SpiderEggNetworkID:SpawnerReset() - - // Obtain a list of all the eggs on the egg spawner network - - //auto spiderEggList = SpiderEggNetworkID:SpawnerGetAllObjectIDsSpawned().objects; - - //if (table.maxn(spiderEggList) <= 0) { - // self->AddTimer("PollSpiderWaveManager", 1.0f); - // return; - //} - // - //// A check for (wave mangement across multiple spawn iterations - //if(hatchCounter < spiderWaveCnt) { - // // We have already prepped some objects for (hatching, - // // remove them from our list for (random egg pulls - // for (i, sVal in ipairs(spiderEggList) { - // if(hatchList[sVal:GetID()]) { - // // We have found a prepped egg, remove it from the spiderEggList - // spiderEggList[i] = nil - // } - // } - - //} - - - std::vector<LWOOBJID> spiderEggs{}; auto spooders = EntityManager::Instance()->GetEntitiesInGroup("EGG"); @@ -220,44 +185,43 @@ void BossSpiderQueenEnemyServer::SpiderWaveManager(Entity* self) { // Select a number of random spider eggs from the list equal to the // current number needed to complete the current wave - for (int i = 0; i < hatchCounter; i++) { - // Select a random spider egg - auto randomEggLoc = GeneralUtils::GenerateRandomNumber<int>(0, spiderEggs.size() - 1); - auto randomEgg = spiderEggs[randomEggLoc]; + if (!spiderEggs.empty()) { + for (int i = 0; i < hatchCounter; i++) { + // Select a random spider egg + auto randomEggLoc = GeneralUtils::GenerateRandomNumber<int>(0, spiderEggs.size() - 1); + auto randomEgg = spiderEggs[randomEggLoc]; - //Just a quick check to try and prevent dupes: - for (auto en : hatchList) { - if (en == randomEgg) { - randomEggLoc++; - randomEgg = spiderEggs[randomEggLoc]; - } - } - - if (randomEgg) { - auto* eggEntity = EntityManager::Instance()->GetEntity(randomEgg); - - if (eggEntity == nullptr) { - continue; + //Just a quick check to try and prevent dupes: + for (auto en : hatchList) { + if (en == randomEgg) { + randomEggLoc++; + randomEgg = spiderEggs[randomEggLoc]; + } } - // Prep the selected spider egg - //randomEgg:FireEvent{s}erID=self, args="prepEgg"} - eggEntity->OnFireEventServerSide(self, "prepEgg"); - Game::logger->Log("SpiderQueen", "Prepping egg %llu", eggEntity->GetObjectID()); + if (randomEgg) { + auto* eggEntity = EntityManager::Instance()->GetEntity(randomEgg); - // Add the prepped egg to our hatchList - hatchList.push_back(eggEntity->GetObjectID()); + if (eggEntity == nullptr) { + continue; + } - // Decrement the hatchCounter - hatchCounter = hatchCounter - 1; - } + // Prep the selected spider egg + eggEntity->OnFireEventServerSide(self, "prepEgg"); - // Remove it from our spider egg list - //table.remove(spiderEggList, randomEggLoc); - spiderEggs[randomEggLoc] = LWOOBJID_EMPTY; + // Add the prepped egg to our hatchList + hatchList.push_back(eggEntity->GetObjectID()); - if (spiderEggs.size() <= 0 || (hatchCounter <= 0)) { - break; + // Decrement the hatchCounter + hatchCounter = hatchCounter - 1; + } + + // Remove it from our spider egg list + spiderEggs[randomEggLoc] = LWOOBJID_EMPTY; + + if (spiderEggs.size() <= 0 || (hatchCounter <= 0)) { + break; + } } } @@ -276,14 +240,12 @@ void BossSpiderQueenEnemyServer::SpiderWaveManager(Entity* self) { } eggEntity->OnFireEventServerSide(self, "hatchEgg"); - Game::logger->Log("SpiderQueen", "hatching egg %llu", eggEntity->GetObjectID()); auto time = PlayAnimAndReturnTime(self, spiderWithdrawIdle); combat->SetStunImmune(false); combat->Stun(time += 6.0f); combat->SetStunImmune(true); - //self->AddTimer("disableWaitForIdle", defaultAnimPause); self->AddTimer("checkForSpiders", 6.0f); } @@ -394,10 +356,6 @@ void BossSpiderQueenEnemyServer::RapidFireShooterManager(Entity* self) { } void BossSpiderQueenEnemyServer::RunRapidFireShooter(Entity* self) { - /* - const auto targets = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CHARACTER); - */ - const auto targets = self->GetTargetsInPhantom(); if (self->GetBoolean(u"stoppedFlag")) { @@ -430,8 +388,6 @@ void BossSpiderQueenEnemyServer::RunRapidFireShooter(Entity* self) { PlayAnimAndReturnTime(self, spiderSingleShot); - Game::logger->Log("BossSpiderQueenEnemyServer", "Ran RFS"); - self->AddTimer("RFS", GeneralUtils::GenerateRandomNumber<float>(10, 15)); } @@ -553,26 +509,6 @@ void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string tim GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake-bridge", self->GetObjectID(), 100.0f); } else if (timerName == "AdvanceComplete") { - //Reset faction and collision - /*local SBFactionList = self:GetVar("SBFactionList") - local SBCollisionGroup = self:GetVar("SBCollisionGroup") - - for i, fVal in ipairs(SBFactionList) { - if(i == 1) { - //Our first faction - flush and add - self:SetFaction{faction = fVal} - else - //Add - self:ModifyFaction{factionID = fVal, bAddFaction = true} - } - }*/ - - /* - auto SBCollisionGroup = self->GetI32(u"SBCollisionGroup"); - - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", SBCollisionGroup, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); - */ - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SetColGroup", 11, 0, 0, "", UNASSIGNED_SYSTEM_ADDRESS); //Wind up, telegraphing next round @@ -622,7 +558,6 @@ void BossSpiderQueenEnemyServer::OnTimerDone(Entity* self, const std::string tim //Did we queue a spcial attack? if (self->GetBoolean(u"bSpecialQueued")) { self->SetBoolean(u"bSpecialQueued", false); - //SpiderSkillManager(self, true); } } } @@ -670,17 +605,6 @@ void BossSpiderQueenEnemyServer::OnUpdate(Entity* self) { controllable->SetStatic(true); EntityManager::Instance()->SerializeEntity(self); - - //if (waitForIdle) return; - - ////Play the Spider Boss' mountain idle anim - //PlayAnimAndReturnTime(self, spiderWithdrawIdle); - - ////If there are still baby spiders, don't do anyhting either - //auto spooders = EntityManager::Instance()->GetEntitiesInGroup("BabySpider"); - //if (spooders.size() > 0) return; - //else - // WithdrawSpider(self, false); } //---------------------------------------------- diff --git a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp index 8ec49d3e..28ba0044 100644 --- a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp +++ b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp @@ -5,6 +5,8 @@ #include "GameMessages.h" #include "SkillComponent.h" #include "BaseCombatAIComponent.h" +#include "EntityInfo.h" +#include "eAninmationFlags.h" void AmDarklingDragon::OnStartup(Entity* self) { self->SetVar<int32_t>(u"weakspot", 0); @@ -63,10 +65,11 @@ void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t if (skillComponent != nullptr) { skillComponent->Interrupt(); + skillComponent->Reset(); } self->SetVar<int32_t>(u"weakpoint", 2); - + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); self->AddTimer("timeToStunLoop", 1); @@ -131,7 +134,9 @@ void AmDarklingDragon::OnTimerDone(Entity* self, std::string timerName) { } if (skillComponent != nullptr) { skillComponent->Interrupt(); + skillComponent->Reset(); } + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); self->SetVar<int32_t>(u"weakspot", -1); GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); } diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp index 47ddb4bf..e78f537f 100644 --- a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp +++ b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp @@ -3,6 +3,8 @@ #include "SkillComponent.h" #include "BaseCombatAIComponent.h" #include "DestroyableComponent.h" +#include "eAninmationFlags.h" +#include "EntityInfo.h" void FvMaelstromDragon::OnStartup(Entity* self) { self->SetVar<int32_t>(u"weakspot", 0); @@ -59,8 +61,6 @@ void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_ auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); if (destroyableComponent != nullptr) { - Game::logger->Log("FvMaelstromDragon", "Hit %i", destroyableComponent->GetArmor()); - if (destroyableComponent->GetArmor() > 0) return; auto weakpoint = self->GetVar<int32_t>(u"weakpoint"); @@ -80,10 +80,12 @@ void FvMaelstromDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_ if (skillComponent != nullptr) { skillComponent->Interrupt(); + skillComponent->Reset(); } self->SetVar<int32_t>(u"weakpoint", 2); + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); self->AddTimer("timeToStunLoop", 1); @@ -150,8 +152,9 @@ void FvMaelstromDragon::OnTimerDone(Entity* self, std::string timerName) { if (skillComponent != nullptr) { skillComponent->Interrupt(); + skillComponent->Reset(); } - + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); self->SetVar<int32_t>(u"weakspot", -1); GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); diff --git a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp index 3d0b8e25..ea3ce9b8 100644 --- a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp @@ -3,7 +3,9 @@ #include "DestroyableComponent.h" #include "GameMessages.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "SkillComponent.h" +#include "eAninmationFlags.h" void BaseEnemyApe::OnStartup(Entity* self) { self->SetVar<uint32_t>(u"timesStunned", 2); @@ -31,9 +33,12 @@ void BaseEnemyApe::OnHit(Entity* self, Entity* attacker) { if (destroyableComponent != nullptr && destroyableComponent->GetArmor() < 1 && !self->GetBoolean(u"knockedOut")) { StunApe(self, true); self->CancelTimer("spawnQBTime"); - + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (skillComponent) { + skillComponent->Reset(); + } GameMessages::SendPlayAnimation(self, u"disable", 1.7f); - + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); const auto reviveTime = self->GetVar<float_t>(u"reviveTime") != 0.0f ? self->GetVar<float_t>(u"reviveTime") : 12.0f; self->AddTimer("reviveTime", reviveTime); @@ -50,6 +55,7 @@ void BaseEnemyApe::OnTimerDone(Entity* self, std::string timerName) { destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned); } EntityManager::Instance()->SerializeEntity(self); + GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); self->SetVar<uint32_t>(u"timesStunned", timesStunned + 1); StunApe(self, false); @@ -125,7 +131,7 @@ void BaseEnemyApe::StunApe(Entity* self, bool stunState) { skillComponent->Interrupt(); } - GameMessages::SendSetStunned(self->GetObjectID(), stunState ? PUSH : POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(), + GameMessages::SendSetStunned(self->GetObjectID(), stunState ? eStateChangeType::PUSH : eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(), true, true, true, true, true, true, true, true, true); diff --git a/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp b/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp index 8017be2c..ce42585c 100644 --- a/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyMech.cpp @@ -3,8 +3,10 @@ #include "ControllablePhysicsComponent.h" #include "EntityManager.h" #include "dpWorld.h" +#include "EntityInfo.h" #include "GeneralUtils.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" void BaseEnemyMech::OnStartup(Entity* self) { auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); @@ -14,7 +16,7 @@ void BaseEnemyMech::OnStartup(Entity* self) { } void BaseEnemyMech::OnDie(Entity* self, Entity* killer) { - ControllablePhysicsComponent* controlPhys = static_cast<ControllablePhysicsComponent*>(self->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + ControllablePhysicsComponent* controlPhys = static_cast<ControllablePhysicsComponent*>(self->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); if (!controlPhys) return; NiPoint3 newLoc = { controlPhys->GetPosition().x, dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(controlPhys->GetPosition()), controlPhys->GetPosition().z }; diff --git a/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp index 15f0709c..19788677 100644 --- a/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp +++ b/dScripts/02_server/Enemy/General/TreasureChestDragonServer.cpp @@ -2,6 +2,7 @@ #include "ScriptedActivityComponent.h" #include "TeamManager.h" #include "EntityManager.h" +#include "Loot.h" void TreasureChestDragonServer::OnStartup(Entity* self) { diff --git a/dScripts/02_server/Equipment/BootyDigServer.cpp b/dScripts/02_server/Equipment/BootyDigServer.cpp index d38791d8..375bc4e5 100644 --- a/dScripts/02_server/Equipment/BootyDigServer.cpp +++ b/dScripts/02_server/Equipment/BootyDigServer.cpp @@ -2,7 +2,9 @@ #include "EntityManager.h" #include "RenderComponent.h" #include "MissionComponent.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "Loot.h" void BootyDigServer::OnStartup(Entity* self) { auto* zoneControlObject = EntityManager::Instance()->GetZoneControlEntity(); @@ -36,8 +38,8 @@ BootyDigServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { auto* mission = missionComponent->GetMission(1881); - if (mission != nullptr && (mission->GetMissionState() == MissionState::MISSION_STATE_ACTIVE || mission->GetMissionState() == MissionState::MISSION_STATE_COMPLETE_ACTIVE)) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + if (mission != nullptr && (mission->GetMissionState() == eMissionState::ACTIVE || mission->GetMissionState() == eMissionState::COMPLETE_ACTIVE)) { + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); auto* renderComponent = self->GetComponent<RenderComponent>(); if (renderComponent != nullptr) diff --git a/dScripts/02_server/Equipment/MaestromExtracticatorServer.cpp b/dScripts/02_server/Equipment/MaestromExtracticatorServer.cpp index caaba28f..c01d2362 100644 --- a/dScripts/02_server/Equipment/MaestromExtracticatorServer.cpp +++ b/dScripts/02_server/Equipment/MaestromExtracticatorServer.cpp @@ -3,6 +3,7 @@ #include "GeneralUtils.h" #include "EntityManager.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" void MaestromExtracticatorServer::OnStartup(Entity* self) { //self:SetNetworkVar("current_anim", failAnim) @@ -24,7 +25,7 @@ void MaestromExtracticatorServer::OnFireEventServerSide(Entity* self, Entity* se auto missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, 14718); + missionComponent->Progress(eMissionTaskType::SMASH, 14718); CollectSample(self, sender->GetObjectID()); sender->ScheduleKillAfterUpdate(); } diff --git a/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp b/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp index 6d1360de..3c400e5d 100644 --- a/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp +++ b/dScripts/02_server/Map/AG/AgCagedBricksServer.cpp @@ -3,6 +3,7 @@ #include "GameMessages.h" #include "Character.h" #include "EntityManager.h" +#include "eReplicaComponentType.h" void AgCagedBricksServer::OnUse(Entity* self, Entity* user) { //Tell the client to spawn the baby spiderling: @@ -19,7 +20,7 @@ void AgCagedBricksServer::OnUse(Entity* self, Entity* user) { character->SetPlayerFlag(74, true); //Remove the maelstrom cube: - auto inv = static_cast<InventoryComponent*>(user->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto inv = static_cast<InventoryComponent*>(user->GetComponent(eReplicaComponentType::INVENTORY)); if (inv) { inv->RemoveItem(14553, 1); diff --git a/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp b/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp index 9efae1ca..703625d2 100644 --- a/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp +++ b/dScripts/02_server/Map/AG/AgLaserSensorServer.cpp @@ -5,12 +5,14 @@ #include "EntityManager.h" #include "AgMonumentLaserServer.h" #include "EntityManager.h" +#include "ePhysicsEffectType.h" +#include "eReplicaComponentType.h" void AgLaserSensorServer::OnStartup(Entity* self) { - PhantomPhysicsComponent* physComp = static_cast<PhantomPhysicsComponent*>(self->GetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS)); + PhantomPhysicsComponent* physComp = static_cast<PhantomPhysicsComponent*>(self->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); physComp->SetPhysicsEffectActive(true); - physComp->SetEffectType(2); // repulse (prolly should make definitions of these are in Entity.cpp) + physComp->SetEffectType(ePhysicsEffectType::REPULSE); physComp->SetDirectionalMultiplier(static_cast<float>(m_RepelForce)); physComp->SetDirection(NiPoint3::UNIT_Y); @@ -25,7 +27,7 @@ void AgLaserSensorServer::OnCollisionPhantom(Entity* self, Entity* target) { Entity* laser = nullptr; - for (auto script : EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_SCRIPT)) { + for (auto script : EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPT)) { AgMonumentLaserServer* hasLaser = (AgMonumentLaserServer*)script; diff --git a/dScripts/02_server/Map/AG/AgMonumentRaceGoal.cpp b/dScripts/02_server/Map/AG/AgMonumentRaceGoal.cpp index 78bbaee5..0dd91bf2 100644 --- a/dScripts/02_server/Map/AG/AgMonumentRaceGoal.cpp +++ b/dScripts/02_server/Map/AG/AgMonumentRaceGoal.cpp @@ -7,9 +7,9 @@ void AgMonumentRaceGoal::OnStartup(Entity* self) { } void AgMonumentRaceGoal::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { - if (name == "RaceGoal" && entering->IsPlayer() && status == "ENTER") { - auto* manager = EntityManager::Instance()->GetEntitiesInGroup("race_manager")[0]; - - manager->OnFireEventServerSide(entering, "course_finish"); + if (name == "RaceGoal" && entering && entering->IsPlayer() && status == "ENTER") { + auto managers = EntityManager::Instance()->GetEntitiesInGroup("race_manager"); + if (managers.empty() || !managers.at(0)) return; + managers.at(0)->OnFireEventServerSide(entering, "course_finish"); } } diff --git a/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp b/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp index 503d966a..d2cc647e 100644 --- a/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp +++ b/dScripts/02_server/Map/AG/NpcAgCourseStarter.cpp @@ -3,6 +3,8 @@ #include "ScriptedActivityComponent.h" #include "GameMessages.h" #include "LeaderboardManager.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" #include "MissionComponent.h" #include <ctime> @@ -89,7 +91,7 @@ void NpcAgCourseStarter::OnFireEventServerSide(Entity* self, Entity* sender, std auto* missionComponent = sender->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { missionComponent->ForceProgressTaskType(1884, 1, 1, false); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, -finish, self->GetObjectID(), + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, -finish, self->GetObjectID(), "performact_time"); } diff --git a/dScripts/02_server/Map/AG/NpcCowboyServer.cpp b/dScripts/02_server/Map/AG/NpcCowboyServer.cpp index c4940e4d..c5a0e8f9 100644 --- a/dScripts/02_server/Map/AG/NpcCowboyServer.cpp +++ b/dScripts/02_server/Map/AG/NpcCowboyServer.cpp @@ -1,8 +1,8 @@ #include "NpcCowboyServer.h" -#include "MissionState.h" +#include "eMissionState.h" #include "InventoryComponent.h" -void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { if (missionID != 1880) { return; } @@ -13,14 +13,14 @@ void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int miss return; } - if (missionState == MissionState::MISSION_STATE_COMPLETE_ACTIVE || - missionState == MissionState::MISSION_STATE_ACTIVE || - missionState == MissionState::MISSION_STATE_AVAILABLE || - missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE) { + if (missionState == eMissionState::COMPLETE_ACTIVE || + missionState == eMissionState::ACTIVE || + missionState == eMissionState::AVAILABLE || + missionState == eMissionState::COMPLETE_AVAILABLE) { if (inventoryComponent->GetLotCount(14378) == 0) { inventoryComponent->AddItem(14378, 1, eLootSourceType::LOOT_SOURCE_NONE); } - } else if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { + } else if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { inventoryComponent->RemoveItem(14378, 1); } } diff --git a/dScripts/02_server/Map/AG/NpcCowboyServer.h b/dScripts/02_server/Map/AG/NpcCowboyServer.h index e600d798..4493315c 100644 --- a/dScripts/02_server/Map/AG/NpcCowboyServer.h +++ b/dScripts/02_server/Map/AG/NpcCowboyServer.h @@ -3,5 +3,5 @@ class NpcCowboyServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; }; diff --git a/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp b/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp index f6b8f5c4..a928e9d9 100644 --- a/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp +++ b/dScripts/02_server/Map/AG/NpcEpsilonServer.cpp @@ -1,7 +1,7 @@ #include "NpcEpsilonServer.h" #include "GameMessages.h" -void NpcEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NpcEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { //If we are completing the Nexus Force join mission, play the celebration for it: if (missionID == 1851) { diff --git a/dScripts/02_server/Map/AG/NpcEpsilonServer.h b/dScripts/02_server/Map/AG/NpcEpsilonServer.h index 798da33e..4de76bcd 100644 --- a/dScripts/02_server/Map/AG/NpcEpsilonServer.h +++ b/dScripts/02_server/Map/AG/NpcEpsilonServer.h @@ -2,6 +2,6 @@ #include "CppScripts.h" class NpcEpsilonServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); }; diff --git a/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp b/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp index a53d8ba3..8ee2e988 100644 --- a/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp +++ b/dScripts/02_server/Map/AG/NpcNjAssistantServer.cpp @@ -3,25 +3,27 @@ #include "InventoryComponent.h" #include "MissionComponent.h" #include "Item.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" -void NpcNjAssistantServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NpcNjAssistantServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { if (missionID != mailMission) return; - if (missionState == MissionState::MISSION_STATE_COMPLETE || missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { + if (missionState == eMissionState::COMPLETE || missionState == eMissionState::READY_TO_COMPLETE) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"switch", 0, 0, LWOOBJID_EMPTY, "", target->GetSystemAddress()); - auto* inv = static_cast<InventoryComponent*>(target->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto* inv = static_cast<InventoryComponent*>(target->GetComponent(eReplicaComponentType::INVENTORY)); // If we are ready to complete our missions, we take the kit from you: - if (inv && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { + if (inv && missionState == eMissionState::READY_TO_COMPLETE) { auto* id = inv->FindItemByLot(14397); //the kit's lot if (id != nullptr) { inv->RemoveItem(id->GetLot(), id->GetCount()); } } - } else if (missionState == MissionState::MISSION_STATE_AVAILABLE) { - auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(COMPONENT_TYPE_MISSION)); + } else if (missionState == eMissionState::AVAILABLE) { + auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(eReplicaComponentType::MISSION)); missionComponent->CompleteMission(mailAchievement, true); } } diff --git a/dScripts/02_server/Map/AG/NpcNjAssistantServer.h b/dScripts/02_server/Map/AG/NpcNjAssistantServer.h index 7ba847d0..1f932752 100644 --- a/dScripts/02_server/Map/AG/NpcNjAssistantServer.h +++ b/dScripts/02_server/Map/AG/NpcNjAssistantServer.h @@ -2,7 +2,7 @@ #include "CppScripts.h" class NpcNjAssistantServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); private: int mailMission = 1728; //mission to get the item out of your mailbox diff --git a/dScripts/02_server/Map/AG/NpcPirateServer.cpp b/dScripts/02_server/Map/AG/NpcPirateServer.cpp index 47571fa6..6e7e696c 100644 --- a/dScripts/02_server/Map/AG/NpcPirateServer.cpp +++ b/dScripts/02_server/Map/AG/NpcPirateServer.cpp @@ -1,16 +1,17 @@ #include "NpcPirateServer.h" +#include "eMissionState.h" #include "InventoryComponent.h" -void NpcPirateServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NpcPirateServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { auto* inventory = target->GetComponent<InventoryComponent>(); if (inventory != nullptr && missionID == 1881) { auto* luckyShovel = inventory->FindItemByLot(14591); // Add or remove the lucky shovel based on whether the mission was completed or started - if ((missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE) + if ((missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE) && luckyShovel == nullptr) { inventory->AddItem(14591, 1, eLootSourceType::LOOT_SOURCE_NONE); - } else if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { + } else if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { inventory->RemoveItem(14591, 1); } } diff --git a/dScripts/02_server/Map/AG/NpcPirateServer.h b/dScripts/02_server/Map/AG/NpcPirateServer.h index dcb399c5..118aec89 100644 --- a/dScripts/02_server/Map/AG/NpcPirateServer.h +++ b/dScripts/02_server/Map/AG/NpcPirateServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class NpcPirateServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; }; diff --git a/dScripts/02_server/Map/AG/NpcWispServer.cpp b/dScripts/02_server/Map/AG/NpcWispServer.cpp index cd4a4d9c..99345973 100644 --- a/dScripts/02_server/Map/AG/NpcWispServer.cpp +++ b/dScripts/02_server/Map/AG/NpcWispServer.cpp @@ -3,8 +3,9 @@ #include "EntityManager.h" #include "Entity.h" #include "GameMessages.h" +#include "eMissionState.h" -void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { if (missionID != 1849 && missionID != 1883) return; @@ -16,16 +17,16 @@ void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missio auto* maelstromVacuum = inventory->FindItemByLot(maelstromVacuumLot); // For the daily we add the maelstrom vacuum if the player doesn't have it yet - if (missionID == 1883 && (missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE) + if (missionID == 1883 && (missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE) && maelstromVacuum == nullptr) { inventory->AddItem(maelstromVacuumLot, 1, eLootSourceType::LOOT_SOURCE_NONE); - } else if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { + } else if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { inventory->RemoveItem(maelstromVacuumLot, 1); } // Next up hide or show the samples based on the mission state auto visible = 1; - if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { + if (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { visible = 0; } diff --git a/dScripts/02_server/Map/AG/NpcWispServer.h b/dScripts/02_server/Map/AG/NpcWispServer.h index 86c9c33d..6eaa09e9 100644 --- a/dScripts/02_server/Map/AG/NpcWispServer.h +++ b/dScripts/02_server/Map/AG/NpcWispServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class NpcWispServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); }; diff --git a/dScripts/02_server/Map/AG/RemoveRentalGear.cpp b/dScripts/02_server/Map/AG/RemoveRentalGear.cpp index 06d964b9..18177e57 100644 --- a/dScripts/02_server/Map/AG/RemoveRentalGear.cpp +++ b/dScripts/02_server/Map/AG/RemoveRentalGear.cpp @@ -1,7 +1,9 @@ #include "RemoveRentalGear.h" #include "InventoryComponent.h" #include "Item.h" +#include "eMissionState.h" #include "Character.h" +#include "eReplicaComponentType.h" /* -------------------------------------------------------------- @@ -16,11 +18,11 @@ -------------------------------------------------------------- */ -void RemoveRentalGear::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void RemoveRentalGear::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { if (missionID != defaultMission && missionID != 313) return; - if (missionState == MissionState::MISSION_STATE_COMPLETE || missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { - auto inv = static_cast<InventoryComponent*>(target->GetComponent(COMPONENT_TYPE_INVENTORY)); + if (missionState == eMissionState::COMPLETE || missionState == eMissionState::READY_TO_COMPLETE) { + auto inv = static_cast<InventoryComponent*>(target->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; //remove the inventory items diff --git a/dScripts/02_server/Map/AG/RemoveRentalGear.h b/dScripts/02_server/Map/AG/RemoveRentalGear.h index 49ca0860..cc33b5f6 100644 --- a/dScripts/02_server/Map/AG/RemoveRentalGear.h +++ b/dScripts/02_server/Map/AG/RemoveRentalGear.h @@ -2,7 +2,7 @@ #include "CppScripts.h" class RemoveRentalGear : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); private: int defaultMission = 768; //mission to remove gearSets on completion diff --git a/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp index ea517448..5996548f 100644 --- a/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp +++ b/dScripts/02_server/Map/AG_Spider_Queen/ZoneAgSpiderQueen.cpp @@ -3,6 +3,7 @@ #include "EntityManager.h" #include "ZoneAgProperty.h" #include "DestroyableComponent.h" +#include "EntityInfo.h" void ZoneAgSpiderQueen::SetGameVariables(Entity* self) { ZoneAgProperty::SetGameVariables(self); diff --git a/dScripts/02_server/Map/AM/AmBlueX.cpp b/dScripts/02_server/Map/AM/AmBlueX.cpp index 97f80e77..8e32694c 100644 --- a/dScripts/02_server/Map/AM/AmBlueX.cpp +++ b/dScripts/02_server/Map/AM/AmBlueX.cpp @@ -1,6 +1,7 @@ #include "AmBlueX.h" #include "SkillComponent.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "Character.h" void AmBlueX::OnUse(Entity* self, Entity* user) { diff --git a/dScripts/02_server/Map/AM/AmDropshipComputer.cpp b/dScripts/02_server/Map/AM/AmDropshipComputer.cpp index 909beaaf..15ca7267 100644 --- a/dScripts/02_server/Map/AM/AmDropshipComputer.cpp +++ b/dScripts/02_server/Map/AM/AmDropshipComputer.cpp @@ -3,6 +3,7 @@ #include "RebuildComponent.h" #include "InventoryComponent.h" #include "dZoneManager.h" +#include "eMissionState.h" void AmDropshipComputer::OnStartup(Entity* self) { self->AddTimer("reset", 45.0f); @@ -22,7 +23,7 @@ void AmDropshipComputer::OnUse(Entity* self, Entity* user) { return; } - if (inventoryComponent->GetLotCount(m_NexusTalonDataCard) != 0 || missionComponent->GetMission(979)->GetMissionState() == MissionState::MISSION_STATE_COMPLETE) { + if (inventoryComponent->GetLotCount(m_NexusTalonDataCard) != 0 || missionComponent->GetMission(979)->GetMissionState() == eMissionState::COMPLETE) { return; } diff --git a/dScripts/02_server/Map/AM/AmShieldGenerator.cpp b/dScripts/02_server/Map/AM/AmShieldGenerator.cpp index d16acb87..5d1b7d08 100644 --- a/dScripts/02_server/Map/AM/AmShieldGenerator.cpp +++ b/dScripts/02_server/Map/AM/AmShieldGenerator.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "GameMessages.h" +#include "EntityInfo.h" #include "MovementAIComponent.h" #include "BaseCombatAIComponent.h" #include "SkillComponent.h" diff --git a/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp index 9f27b904..3188db33 100644 --- a/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp +++ b/dScripts/02_server/Map/AM/AmShieldGeneratorQuickbuild.cpp @@ -5,6 +5,7 @@ #include "MovementAIComponent.h" #include "BaseCombatAIComponent.h" #include "SkillComponent.h" +#include "EntityInfo.h" #include "RebuildComponent.h" #include "MissionComponent.h" diff --git a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp index 321660e2..da1954d6 100644 --- a/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp +++ b/dScripts/02_server/Map/AM/AmSkullkinDrill.cpp @@ -4,6 +4,7 @@ #include "DestroyableComponent.h" #include "ProximityMonitorComponent.h" #include "MissionComponent.h" +#include "EntityInfo.h" void AmSkullkinDrill::OnStartup(Entity* self) { self->SetNetworkVar(u"bIsInUse", false); @@ -146,21 +147,21 @@ void AmSkullkinDrill::OnUse(Entity* self, Entity* user) { } void AmSkullkinDrill::FreezePlayer(Entity* self, Entity* player, bool bFreeze) { - eStunState eChangeType = POP; + auto StateChangeType = eStateChangeType::POP; if (bFreeze) { if (player->GetIsDead()) { return; } - eChangeType = PUSH; + StateChangeType = eStateChangeType::PUSH; } else { if (player->GetIsDead()) { // } } - GameMessages::SendSetStunned(player->GetObjectID(), eChangeType, player->GetSystemAddress(), self->GetObjectID(), + GameMessages::SendSetStunned(player->GetObjectID(), StateChangeType, player->GetSystemAddress(), self->GetObjectID(), true, false, true, false, true, false, true ); } diff --git a/dScripts/02_server/Map/AM/AmSkullkinTower.cpp b/dScripts/02_server/Map/AM/AmSkullkinTower.cpp index 180bbdac..01acdeaf 100644 --- a/dScripts/02_server/Map/AM/AmSkullkinTower.cpp +++ b/dScripts/02_server/Map/AM/AmSkullkinTower.cpp @@ -2,6 +2,7 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "MovingPlatformComponent.h" +#include "EntityInfo.h" #include "GameMessages.h" #include "MissionComponent.h" diff --git a/dScripts/02_server/Map/AM/AmTeapotServer.cpp b/dScripts/02_server/Map/AM/AmTeapotServer.cpp index 32abafd6..1f47cb1a 100644 --- a/dScripts/02_server/Map/AM/AmTeapotServer.cpp +++ b/dScripts/02_server/Map/AM/AmTeapotServer.cpp @@ -1,14 +1,21 @@ #include "AmTeapotServer.h" #include "InventoryComponent.h" #include "GameMessages.h" - +#include "Item.h" void AmTeapotServer::OnUse(Entity* self, Entity* user) { auto* inventoryComponent = user->GetComponent<InventoryComponent>(); if (!inventoryComponent) return; - if (inventoryComponent->GetLotCount(BLUE_FLOWER_LEAVES) >= 10) { - inventoryComponent->RemoveItem(BLUE_FLOWER_LEAVES, 10); + auto* blueFlowerItem = inventoryComponent->FindItemByLot(BLUE_FLOWER_LEAVES, eInventoryType::ITEMS); + if (!blueFlowerItem) { + blueFlowerItem = inventoryComponent->FindItemByLot(BLUE_FLOWER_LEAVES, eInventoryType::VAULT_ITEMS); + if (!blueFlowerItem) return; + } + + // The client allows you to use the teapot only if you have a stack of 10 leaves in some inventory somewhere. + if (blueFlowerItem->GetCount() >= 10) { + blueFlowerItem->SetCount(blueFlowerItem->GetCount() - 10); inventoryComponent->AddItem(WU_S_IMAGINATION_TEA, 1); } GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); diff --git a/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp b/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp index b6cae3bb..cfc58fa0 100644 --- a/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp +++ b/dScripts/02_server/Map/FV/EnemyRoninSpawner.cpp @@ -1,6 +1,7 @@ #include "EnemyRoninSpawner.h" #include "SkillComponent.h" #include "RenderComponent.h" +#include "EntityInfo.h" #include "EntityManager.h" void EnemyRoninSpawner::OnStartup(Entity* self) { diff --git a/dScripts/02_server/Map/FV/FvCandle.cpp b/dScripts/02_server/Map/FV/FvCandle.cpp index efd717ee..0c4344d0 100644 --- a/dScripts/02_server/Map/FV/FvCandle.cpp +++ b/dScripts/02_server/Map/FV/FvCandle.cpp @@ -1,11 +1,12 @@ #include "FvCandle.h" #include "MissionComponent.h" #include "RenderComponent.h" +#include "eReplicaComponentType.h" std::vector<int32_t> FvCandle::m_Missions = { 850, 1431, 1529, 1566, 1603 }; void FvCandle::OnStartup(Entity* self) { - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (render == nullptr) return; @@ -22,7 +23,7 @@ void FvCandle::BlowOutCandle(Entity* self, Entity* blower) { if (self->GetBoolean(u"AmHit")) return; - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (render == nullptr) return; @@ -46,7 +47,7 @@ void FvCandle::BlowOutCandle(Entity* self, Entity* blower) { void FvCandle::OnTimerDone(Entity* self, std::string timerName) { self->SetBoolean(u"AmHit", false); - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (render == nullptr) return; diff --git a/dScripts/02_server/Map/FV/FvFong.cpp b/dScripts/02_server/Map/FV/FvFong.cpp index 7f63e5e5..13c637e7 100644 --- a/dScripts/02_server/Map/FV/FvFong.cpp +++ b/dScripts/02_server/Map/FV/FvFong.cpp @@ -1,9 +1,9 @@ #include "FvFong.h" #include "Darkitect.h" -#include "MissionState.h" +#include "eMissionState.h" -void FvFong::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { - if (missionID == 734 && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { +void FvFong::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID == 734 && missionState == eMissionState::READY_TO_COMPLETE) { Darkitect Baron; Baron.Reveal(self, target); } diff --git a/dScripts/02_server/Map/FV/FvFong.h b/dScripts/02_server/Map/FV/FvFong.h index 074e6d8c..c0b6d48b 100644 --- a/dScripts/02_server/Map/FV/FvFong.h +++ b/dScripts/02_server/Map/FV/FvFong.h @@ -4,5 +4,5 @@ class FvFong : public CppScripts::Script { public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; }; diff --git a/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp index 4a12324f..9c7b858f 100644 --- a/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp +++ b/dScripts/02_server/Map/FV/ImgBrickConsoleQB.cpp @@ -4,6 +4,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eMissionState.h" #include "InventoryComponent.h" int32_t ImgBrickConsoleQB::ResetBricks = 30; @@ -71,13 +72,13 @@ void ImgBrickConsoleQB::OnUse(Entity* self, Entity* user) { auto* inventoryComponent = player->GetComponent<InventoryComponent>(); if (missionComponent != nullptr && inventoryComponent != nullptr) { - if (missionComponent->GetMissionState(1302) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(1302) == eMissionState::ACTIVE) { inventoryComponent->RemoveItem(13074, 1); missionComponent->ForceProgressTaskType(1302, 1, 1); } - if (missionComponent->GetMissionState(1926) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(1926) == eMissionState::ACTIVE) { inventoryComponent->RemoveItem(14472, 1); missionComponent->ForceProgressTaskType(1926, 1, 1); diff --git a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp index 7d67c781..eeabeef6 100644 --- a/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp +++ b/dScripts/02_server/Map/GF/GfCaptainsCannon.cpp @@ -13,7 +13,7 @@ void GfCaptainsCannon::OnUse(Entity* self, Entity* user) { self->SetVar<bool>(u"bIsInUse", true); self->SetNetworkVar<bool>(u"bIsInUse", true); - GameMessages::SendSetStunned(user->GetObjectID(), PUSH, user->GetSystemAddress(), + GameMessages::SendSetStunned(user->GetObjectID(), eStateChangeType::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true ); @@ -63,7 +63,7 @@ void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) { GameMessages::SendPlay2DAmbientSound(player, "{7457d85c-4537-4317-ac9d-2f549219ea87}"); } else if (timerName == "cinematicTimer") { - GameMessages::SendSetStunned(playerId, POP, player->GetSystemAddress(), + GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true ); diff --git a/dScripts/02_server/Map/GF/GfTikiTorch.cpp b/dScripts/02_server/Map/GF/GfTikiTorch.cpp index 3a06b054..22420679 100644 --- a/dScripts/02_server/Map/GF/GfTikiTorch.cpp +++ b/dScripts/02_server/Map/GF/GfTikiTorch.cpp @@ -3,6 +3,8 @@ #include "EntityManager.h" #include "MissionComponent.h" #include "RenderComponent.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" void GfTikiTorch::OnStartup(Entity* self) { LightTorch(self); @@ -41,7 +43,7 @@ void GfTikiTorch::OnTimerDone(Entity* self, std::string timerName) { } void GfTikiTorch::LightTorch(Entity* self) { - auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (renderComponent == nullptr) return; @@ -65,7 +67,7 @@ void GfTikiTorch::OnSkillEventFired(Entity* self, Entity* caster, const std::str auto* casterMissionComponent = caster->GetComponent<MissionComponent>(); if (casterMissionComponent != nullptr) { for (const auto missionID : m_missions) { - casterMissionComponent->ForceProgressTaskType(missionID, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1); + casterMissionComponent->ForceProgressTaskType(missionID, static_cast<uint32_t>(eMissionTaskType::SCRIPT), 1); } } diff --git a/dScripts/02_server/Map/GF/MastTeleport.cpp b/dScripts/02_server/Map/GF/MastTeleport.cpp index ebde7b20..8b8453b9 100644 --- a/dScripts/02_server/Map/GF/MastTeleport.cpp +++ b/dScripts/02_server/Map/GF/MastTeleport.cpp @@ -2,6 +2,8 @@ #include "EntityManager.h" #include "GameMessages.h" #include "Preconditions.h" +#include "eEndBehavior.h" +#include "DestroyableComponent.h" #ifdef _WIN32 #define _USE_MATH_DEFINES @@ -16,9 +18,11 @@ void MastTeleport::OnRebuildComplete(Entity* self, Entity* target) { if (Preconditions::Check(target, 154) && Preconditions::Check(target, 44)) { self->SetVar<LWOOBJID>(u"userID", target->GetObjectID()); - GameMessages::SendSetStunned(target->GetObjectID(), PUSH, target->GetSystemAddress(), + GameMessages::SendSetStunned(target->GetObjectID(), eStateChangeType::PUSH, target->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); + auto* destroyableComponent = target->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, true, true, true, true, false, false, true, true); self->AddTimer("Start", 3); } @@ -49,13 +53,13 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { if (!cinematic.empty()) { GameMessages::SendPlayCinematic(playerId, GeneralUtils::ASCIIToUTF16(cinematic), player->GetSystemAddress(), - true, true, false, false, 0, false, leanIn + true, true, false, false, eEndBehavior::RETURN, false, leanIn ); } GameMessages::SendPlayFXEffect(playerId, 6039, u"hook", "hook", LWOOBJID_EMPTY, 1, 1, true); - GameMessages::SendPlayAnimation(player, u"crow-swing-no-equip"); + GameMessages::SendPlayAnimation(player, u"crow-swing-no-equip", 4.0f); GameMessages::SendPlayAnimation(self, u"swing"); @@ -81,8 +85,11 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) { GameMessages::SendTeleport(playerId, position, NiQuaternion::IDENTITY, player->GetSystemAddress()); - GameMessages::SendSetStunned(playerId, POP, player->GetSystemAddress(), + GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); + auto* destroyableComponent = player->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, false, false, true, true); + EntityManager::Instance()->SerializeEntity(player); } } diff --git a/dScripts/02_server/Map/General/BankInteractServer.cpp b/dScripts/02_server/Map/General/BankInteractServer.cpp index db5ebb98..b96187cf 100644 --- a/dScripts/02_server/Map/General/BankInteractServer.cpp +++ b/dScripts/02_server/Map/General/BankInteractServer.cpp @@ -1,5 +1,7 @@ #include "BankInteractServer.h" #include "GameMessages.h" +#include "Entity.h" +#include "AMFFormat.h" void BankInteractServer::OnUse(Entity* self, Entity* user) { AMFArrayValue args; diff --git a/dScripts/02_server/Map/General/ExplodingAsset.cpp b/dScripts/02_server/Map/General/ExplodingAsset.cpp index 46ff1522..16340ee6 100644 --- a/dScripts/02_server/Map/General/ExplodingAsset.cpp +++ b/dScripts/02_server/Map/General/ExplodingAsset.cpp @@ -3,6 +3,7 @@ #include "GameMessages.h" #include "MissionComponent.h" #include "SkillComponent.h" +#include "eMissionTaskType.h" //TODO: this has to be updated so that you only get killed if you're in a certain radius. //And so that all entities in a certain radius are killed, not just the attacker. @@ -51,14 +52,14 @@ void ExplodingAsset::OnHit(Entity* self, Entity* attacker) { if (missionComponent != nullptr) { if (missionID != 0) { missionComponent->ForceProgressValue(missionID, - static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), + static_cast<uint32_t>(eMissionTaskType::SCRIPT), self->GetLOT(), false); } if (!achievementIDs.empty()) { for (const auto& achievementID : GeneralUtils::SplitString(achievementIDs, u'_')) { missionComponent->ForceProgressValue(std::stoi(GeneralUtils::UTF16ToWTF8(achievementID)), - static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), + static_cast<uint32_t>(eMissionTaskType::SCRIPT), self->GetLOT()); } } diff --git a/dScripts/02_server/Map/General/ForceVolumeServer.cpp b/dScripts/02_server/Map/General/ForceVolumeServer.cpp index fbaad6ee..ed9024c1 100644 --- a/dScripts/02_server/Map/General/ForceVolumeServer.cpp +++ b/dScripts/02_server/Map/General/ForceVolumeServer.cpp @@ -1,6 +1,7 @@ #include "ForceVolumeServer.h" #include "PhantomPhysicsComponent.h" #include "EntityManager.h" +#include "ePhysicsEffectType.h" void ForceVolumeServer::OnStartup(Entity* self) { auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>(); @@ -12,7 +13,7 @@ void ForceVolumeServer::OnStartup(Entity* self) { const auto forceY = self->GetVar<float>(u"ForceY"); const auto forceZ = self->GetVar<float>(u"ForceZ"); - phantomPhysicsComponent->SetEffectType(0); // PUSH + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); phantomPhysicsComponent->SetDirectionalMultiplier(forceAmount); phantomPhysicsComponent->SetDirection({ forceX, forceY, forceZ }); phantomPhysicsComponent->SetPhysicsEffectActive(true); diff --git a/dScripts/02_server/Map/General/GrowingFlower.cpp b/dScripts/02_server/Map/General/GrowingFlower.cpp index 7b495841..ad88528f 100644 --- a/dScripts/02_server/Map/General/GrowingFlower.cpp +++ b/dScripts/02_server/Map/General/GrowingFlower.cpp @@ -1,5 +1,8 @@ #include "GrowingFlower.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "Loot.h" void GrowingFlower::OnSkillEventFired(Entity* self, Entity* target, const std::string& message) { if (!self->GetVar<bool>(u"blooming") && (message == "waterspray" || message == "shovelgrow")) { @@ -15,13 +18,13 @@ void GrowingFlower::OnSkillEventFired(Entity* self, Entity* target, const std::s auto* missionComponent = target->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { for (const auto mission : achievementIDs) - missionComponent->ForceProgressTaskType(mission, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1); + missionComponent->ForceProgressTaskType(mission, static_cast<uint32_t>(eMissionTaskType::SCRIPT), 1); - if (mission1 && missionComponent->GetMissionState(mission1) == MissionState::MISSION_STATE_ACTIVE) - missionComponent->ForceProgressTaskType(mission1, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1); + if (mission1 && missionComponent->GetMissionState(mission1) == eMissionState::ACTIVE) + missionComponent->ForceProgressTaskType(mission1, static_cast<uint32_t>(eMissionTaskType::SCRIPT), 1); - if (mission2 && missionComponent->GetMissionState(mission2) == MissionState::MISSION_STATE_ACTIVE) - missionComponent->ForceProgressTaskType(mission2, static_cast<uint32_t>(MissionTaskType::MISSION_TASK_TYPE_SCRIPT), 1); + if (mission2 && missionComponent->GetMissionState(mission2) == eMissionState::ACTIVE) + missionComponent->ForceProgressTaskType(mission2, static_cast<uint32_t>(eMissionTaskType::SCRIPT), 1); } } } diff --git a/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp b/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp index 1e0d35cf..8b3da9fa 100644 --- a/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp +++ b/dScripts/02_server/Map/General/ImaginationBackpackHealServer.cpp @@ -1,6 +1,8 @@ #include "ImaginationBackpackHealServer.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" void ImaginationBackpackHealServer::OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) { if (message == "CastImaginationBackpack") { @@ -11,8 +13,8 @@ void ImaginationBackpackHealServer::OnSkillEventFired(Entity* self, Entity* cast return; auto* missionComponent = caster->GetComponent<MissionComponent>(); - if (missionComponent != nullptr && missionComponent->GetMissionState(healMission) == MissionState::MISSION_STATE_ACTIVE) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + if (missionComponent != nullptr && missionComponent->GetMissionState(healMission) == eMissionState::ACTIVE) { + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"ClearMaelstrom", 0, 0, caster->GetObjectID(), "", caster->GetSystemAddress()); } diff --git a/dScripts/02_server/Map/General/PetDigServer.cpp b/dScripts/02_server/Map/General/PetDigServer.cpp index e26b079a..81d70faf 100644 --- a/dScripts/02_server/Map/General/PetDigServer.cpp +++ b/dScripts/02_server/Map/General/PetDigServer.cpp @@ -4,6 +4,8 @@ #include "EntityManager.h" #include "Character.h" #include "PetComponent.h" +#include "User.h" +#include "eMissionState.h" std::vector<LWOOBJID> PetDigServer::treasures{}; @@ -162,13 +164,13 @@ void PetDigServer::ProgressPetDigMissions(const Entity* owner, const Entity* che if (missionComponent != nullptr) { // Can You Dig It progress const auto digMissionState = missionComponent->GetMissionState(843); - if (digMissionState == MissionState::MISSION_STATE_ACTIVE) { + if (digMissionState == eMissionState::ACTIVE) { missionComponent->ForceProgress(843, 1216, 1); } // Pet Excavator progress const auto excavatorMissionState = missionComponent->GetMissionState(505); - if (excavatorMissionState == MissionState::MISSION_STATE_ACTIVE) { + if (excavatorMissionState == eMissionState::ACTIVE) { if (chest->HasVar(u"PetDig")) { int32_t playerFlag = 1260 + chest->GetVarAs<int32_t>(u"PetDig"); Character* player = owner->GetCharacter(); @@ -192,7 +194,7 @@ void PetDigServer::SpawnPet(Entity* self, const Entity* owner, const DigInfo dig // Some treasures require a mission to be active if (digInfo.requiredMission >= 0) { auto* missionComponent = owner->GetComponent<MissionComponent>(); - if (missionComponent != nullptr && missionComponent->GetMissionState(digInfo.requiredMission) < MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent != nullptr && missionComponent->GetMissionState(digInfo.requiredMission) < eMissionState::ACTIVE) { return; } } diff --git a/dScripts/02_server/Map/General/PropertyDevice.cpp b/dScripts/02_server/Map/General/PropertyDevice.cpp index 64771de1..0ad9f5c9 100644 --- a/dScripts/02_server/Map/General/PropertyDevice.cpp +++ b/dScripts/02_server/Map/General/PropertyDevice.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "EntityManager.h" #include "MissionComponent.h" +#include "eMissionState.h" void PropertyDevice::OnStartup(Entity* self) { auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); @@ -17,7 +18,7 @@ void PropertyDevice::OnRebuildComplete(Entity* self, Entity* target) { auto* missionComponent = target->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - if (missionComponent->GetMissionState(m_PropertyMissionID) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(m_PropertyMissionID) == eMissionState::ACTIVE) { GameMessages::SendPlayFXEffect(self->GetObjectID(), 641, u"create", "callhome"); missionComponent->ForceProgress(m_PropertyMissionID, 1793, self->GetLOT()); } diff --git a/dScripts/02_server/Map/General/PropertyPlatform.cpp b/dScripts/02_server/Map/General/PropertyPlatform.cpp index 89687ac3..902b9646 100644 --- a/dScripts/02_server/Map/General/PropertyPlatform.cpp +++ b/dScripts/02_server/Map/General/PropertyPlatform.cpp @@ -1,6 +1,7 @@ #include "PropertyPlatform.h" #include "RebuildComponent.h" #include "GameMessages.h" +#include "MovingPlatformComponent.h" void PropertyPlatform::OnRebuildComplete(Entity* self, Entity* target) { // auto* movingPlatform = self->GetComponent<MovingPlatformComponent>(); @@ -9,7 +10,7 @@ void PropertyPlatform::OnRebuildComplete(Entity* self, Entity* target) { // movingPlatform->SetNoAutoStart(true); // } GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 0, 0, MovementPlatformState::Stationary); + 0, 0, eMovementPlatformState::Stationary); } void PropertyPlatform::OnUse(Entity* self, Entity* user) { @@ -20,7 +21,7 @@ void PropertyPlatform::OnUse(Entity* self, Entity* user) { // movingPlatform->GotoWaypoint(1); // } GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); + 1, 1, eMovementPlatformState::Moving); self->AddCallbackTimer(movementDelay + effectDelay, [self, this]() { self->SetNetworkVar<float_t>(u"startEffect", dieDelay); diff --git a/dScripts/02_server/Map/General/QbEnemyStunner.cpp b/dScripts/02_server/Map/General/QbEnemyStunner.cpp index 5d31a788..441d743c 100644 --- a/dScripts/02_server/Map/General/QbEnemyStunner.cpp +++ b/dScripts/02_server/Map/General/QbEnemyStunner.cpp @@ -1,7 +1,11 @@ #include "QbEnemyStunner.h" #include "SkillComponent.h" +#include "CDClientManager.h" #include "DestroyableComponent.h" +#include "CDObjectSkillsTable.h" +#include "CDSkillBehaviorTable.h" + void QbEnemyStunner::OnRebuildComplete(Entity* self, Entity* target) { auto* destroyable = self->GetComponent<DestroyableComponent>(); @@ -13,12 +17,12 @@ void QbEnemyStunner::OnRebuildComplete(Entity* self, Entity* target) { if (!skillComponent) return; // Get the skill IDs of this object. - CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable<CDObjectSkillsTable>("ObjectSkills"); + CDObjectSkillsTable* skillsTable = CDClientManager::Instance().GetTable<CDObjectSkillsTable>(); auto skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); }); std::map<uint32_t, uint32_t> skillBehaviorMap; // For each skill, cast it with the associated behavior ID. for (auto skill : skills) { - CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior"); + CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>(); CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID); skillBehaviorMap.insert(std::make_pair(skill.skillID, behaviorData.behaviorID)); diff --git a/dScripts/02_server/Map/General/QbSpawner.cpp b/dScripts/02_server/Map/General/QbSpawner.cpp index edee6148..d5c9d001 100644 --- a/dScripts/02_server/Map/General/QbSpawner.cpp +++ b/dScripts/02_server/Map/General/QbSpawner.cpp @@ -1,5 +1,6 @@ #include "QbSpawner.h" #include "BaseCombatAIComponent.h" +#include "EntityInfo.h" #include "MovementAIComponent.h" void QbSpawner::OnStartup(Entity* self) { @@ -133,4 +134,3 @@ void QbSpawner::AggroTargetObject(Entity* self, Entity* enemy) { } } - diff --git a/dScripts/02_server/Map/General/TokenConsoleServer.cpp b/dScripts/02_server/Map/General/TokenConsoleServer.cpp index f21938d1..5212a9b5 100644 --- a/dScripts/02_server/Map/General/TokenConsoleServer.cpp +++ b/dScripts/02_server/Map/General/TokenConsoleServer.cpp @@ -2,11 +2,12 @@ #include "InventoryComponent.h" #include "GameMessages.h" #include "Character.h" +#include "eReplicaComponentType.h" //2021-05-03 - max - added script, omitted some parts related to inheritance in lua which we don't need void TokenConsoleServer::OnUse(Entity* self, Entity* user) { - auto* inv = static_cast<InventoryComponent*>(user->GetComponent(COMPONENT_TYPE_INVENTORY)); + auto* inv = static_cast<InventoryComponent*>(user->GetComponent(eReplicaComponentType::INVENTORY)); //make sure the user has the required amount of infected bricks if (inv && inv->GetLotCount(6194) >= bricksToTake) { diff --git a/dScripts/02_server/Map/General/TouchMissionUpdateServer.cpp b/dScripts/02_server/Map/General/TouchMissionUpdateServer.cpp index f732305e..7b2495d0 100644 --- a/dScripts/02_server/Map/General/TouchMissionUpdateServer.cpp +++ b/dScripts/02_server/Map/General/TouchMissionUpdateServer.cpp @@ -3,6 +3,8 @@ #include "Entity.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" void TouchMissionUpdateServer::OnStartup(Entity* self) { self->SetProximityRadius(20, "touchCheck"); // Those does not have a collider for some reason? @@ -15,7 +17,7 @@ void TouchMissionUpdateServer::OnCollisionPhantom(Entity* self, Entity* target) return; } - auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(COMPONENT_TYPE_MISSION)); + auto* missionComponent = static_cast<MissionComponent*>(target->GetComponent(eReplicaComponentType::MISSION)); if (missionComponent == nullptr) { return; @@ -29,7 +31,7 @@ void TouchMissionUpdateServer::OnCollisionPhantom(Entity* self, Entity* target) const auto state = mission->GetMissionState(); - if (state >= MissionState::MISSION_STATE_COMPLETE || mission->GetCompletions() > 1) { + if (state >= eMissionState::COMPLETE || mission->GetCompletions() > 1) { return; } diff --git a/dScripts/02_server/Map/General/WishingWellServer.cpp b/dScripts/02_server/Map/General/WishingWellServer.cpp index 8ac9e0b2..fa3e13e0 100644 --- a/dScripts/02_server/Map/General/WishingWellServer.cpp +++ b/dScripts/02_server/Map/General/WishingWellServer.cpp @@ -1,6 +1,8 @@ #include "WishingWellServer.h" #include "ScriptedActivityComponent.h" #include "GameMessages.h" +#include "Loot.h" +#include "EntityManager.h" void WishingWellServer::OnStartup(Entity* self) { } diff --git a/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp b/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp index 33436525..a338d9c9 100644 --- a/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp +++ b/dScripts/02_server/Map/NS/NsConcertChoiceBuildManager.cpp @@ -1,4 +1,5 @@ #include "NsConcertChoiceBuildManager.h" +#include "EntityInfo.h" #include "EntityManager.h" const std::vector<Crate> NsConcertChoiceBuildManager::crates{ diff --git a/dScripts/02_server/Map/NS/NsLegoClubDoor.h b/dScripts/02_server/Map/NS/NsLegoClubDoor.h index 0a7a6ee0..db1dcae4 100644 --- a/dScripts/02_server/Map/NS/NsLegoClubDoor.h +++ b/dScripts/02_server/Map/NS/NsLegoClubDoor.h @@ -2,6 +2,7 @@ #include "CppScripts.h" #include "ChooseYourDestinationNsToNt.h" #include "BaseConsoleTeleportServer.h" +#include "AMFFormat.h" class NsLegoClubDoor : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer { diff --git a/dScripts/02_server/Map/NS/NsLupTeleport.h b/dScripts/02_server/Map/NS/NsLupTeleport.h index 35edf0bc..28bab016 100644 --- a/dScripts/02_server/Map/NS/NsLupTeleport.h +++ b/dScripts/02_server/Map/NS/NsLupTeleport.h @@ -2,6 +2,7 @@ #include "CppScripts.h" #include "ChooseYourDestinationNsToNt.h" #include "BaseConsoleTeleportServer.h" +#include "AMFFormat.h" class NsLupTeleport : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer { diff --git a/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.cpp b/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.cpp index 6f78acb6..184132fe 100644 --- a/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.cpp +++ b/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.cpp @@ -439,7 +439,7 @@ std::vector<Wave> ZoneNsWaves::GetWaves() { 5.0f, (uint32_t)-1, true, - 30, + 60, }, }; } diff --git a/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.h b/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.h index 06503d19..637aceb7 100644 --- a/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.h +++ b/dScripts/02_server/Map/NS/Waves/ZoneNsWaves.h @@ -1,6 +1,8 @@ #pragma once #include "BaseWavesServer.h" +#include "dCommonVars.h" + enum SpawnerName { interior_A, interior_B, diff --git a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp index f30f4fc7..74f9bd16 100644 --- a/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp +++ b/dScripts/02_server/Map/NT/NtAssemblyTubeServer.cpp @@ -2,6 +2,9 @@ #include "GameMessages.h" #include "EntityManager.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" +#include "eEndBehavior.h" void NtAssemblyTubeServer::OnStartup(Entity* self) { self->SetProximityRadius(5, "teleport"); @@ -22,7 +25,7 @@ void NtAssemblyTubeServer::OnProximityUpdate(Entity* self, Entity* entering, std auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } } @@ -36,14 +39,14 @@ void NtAssemblyTubeServer::RunAssemblyTube(Entity* self, Entity* player) { if (player->IsPlayer() && !bPlayerBeingTeleported) { auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic"); - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); if (!teleCinematic.empty()) { const auto teleCinematicUname = teleCinematic; GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress(), - true, true, true, false, 0, false, -1, false, true + true, true, true, false, eEndBehavior::RETURN, false, -1, false, true ); } @@ -108,7 +111,7 @@ void NtAssemblyTubeServer::UnlockPlayer(Entity* self, Entity* player) { m_TeleportingPlayerTable[playerID] = false; - GameMessages::SendSetStunned(playerID, POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); } diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp index 2b88ccf8..d27ac1f6 100644 --- a/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp +++ b/dScripts/02_server/Map/NT/NtCombatChallengeServer.cpp @@ -1,6 +1,7 @@ #include "NtCombatChallengeServer.h" #include "GameMessages.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "InventoryComponent.h" #include "MissionComponent.h" diff --git a/dScripts/02_server/Map/NT/NtDukeServer.cpp b/dScripts/02_server/Map/NT/NtDukeServer.cpp index 327d3290..d48d50c7 100644 --- a/dScripts/02_server/Map/NT/NtDukeServer.cpp +++ b/dScripts/02_server/Map/NT/NtDukeServer.cpp @@ -1,6 +1,7 @@ #include "NtDukeServer.h" #include "InventoryComponent.h" #include "MissionComponent.h" +#include "eMissionState.h" void NtDukeServer::SetVariables(Entity* self) { self->SetVar<float_t>(m_SpyProximityVariable, 35.0f); @@ -19,7 +20,7 @@ void NtDukeServer::SetVariables(Entity* self) { self->SetVar<std::vector<LWOOBJID>>(m_SpyCinematicObjectsVariable, { self->GetObjectID() }); } -void NtDukeServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NtDukeServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { // Handles adding and removing the sword for the Crux Prime Sword mission auto* missionComponent = target->GetComponent<MissionComponent>(); @@ -29,9 +30,9 @@ void NtDukeServer::OnMissionDialogueOK(Entity* self, Entity* target, int mission auto state = missionComponent->GetMissionState(m_SwordMissionID); auto lotCount = inventoryComponent->GetLotCount(m_SwordLot); - if ((state == MissionState::MISSION_STATE_AVAILABLE || state == MissionState::MISSION_STATE_ACTIVE) && lotCount < 1) { + if ((state == eMissionState::AVAILABLE || state == eMissionState::ACTIVE) && lotCount < 1) { inventoryComponent->AddItem(m_SwordLot, 1, eLootSourceType::LOOT_SOURCE_NONE); - } else if (state == MissionState::MISSION_STATE_READY_TO_COMPLETE) { + } else if (state == eMissionState::READY_TO_COMPLETE) { inventoryComponent->RemoveItem(m_SwordLot, lotCount); } } diff --git a/dScripts/02_server/Map/NT/NtDukeServer.h b/dScripts/02_server/Map/NT/NtDukeServer.h index 0878e86c..2103ba8d 100644 --- a/dScripts/02_server/Map/NT/NtDukeServer.h +++ b/dScripts/02_server/Map/NT/NtDukeServer.h @@ -3,7 +3,7 @@ class NtDukeServer : public NtFactionSpyServer { void SetVariables(Entity* self) override; - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; const uint32_t m_SwordMissionID = 1448; const LOT m_SwordLot = 13777; }; diff --git a/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp index 06482c82..0cb0bec4 100644 --- a/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxPanelServer.cpp @@ -3,6 +3,7 @@ #include "MissionComponent.h" #include "EntityManager.h" #include "Character.h" +#include "eMissionState.h" void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"bActive", 1, 0, user->GetObjectID(), "", user->GetSystemAddress()); @@ -16,7 +17,7 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { const auto playerID = user->GetObjectID(); for (const auto mission : tPlayerOnMissions) { - if (missionComponent->GetMissionState(mission) != MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(mission) != eMissionState::ACTIVE) { continue; } @@ -34,11 +35,11 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) { GameMessages::SendPlayAnimation(player, u"rebuild-celebrate"); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SparkStop", 0, 0, player->GetObjectID(), "", player->GetSystemAddress()); - GameMessages::SendSetStunned(player->GetObjectID(), eStunState::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); + GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); self->SetVar(u"bActive", false); }); GameMessages::SendPlayAnimation(user, u"nexus-powerpanel", 6.0f); - GameMessages::SendSetStunned(user->GetObjectID(), eStunState::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); + GameMessages::SendSetStunned(user->GetObjectID(), eStateChangeType::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true); return; } diff --git a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp index 8003e93f..8b4f19fe 100644 --- a/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp +++ b/dScripts/02_server/Map/NT/NtParadoxTeleServer.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "EntityManager.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" void NtParadoxTeleServer::OnStartup(Entity* self) { self->SetProximityRadius(5, "teleport"); @@ -22,7 +23,7 @@ void NtParadoxTeleServer::OnProximityUpdate(Entity* self, Entity* entering, std: const auto bPlayerBeingTeleported = m_TeleportingPlayerTable[playerID]; if (player->IsPlayer() && !bPlayerBeingTeleported) { - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); @@ -44,7 +45,7 @@ void NtParadoxTeleServer::OnProximityUpdate(Entity* self, Entity* entering, std: auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } } @@ -100,7 +101,7 @@ void NtParadoxTeleServer::UnlockPlayer(Entity* self, Entity* player) { m_TeleportingPlayerTable[playerID] = false; - GameMessages::SendSetStunned(playerID, POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); diff --git a/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp b/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp index 7b943172..257bf6da 100644 --- a/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp +++ b/dScripts/02_server/Map/NT/NtSentinelWalkwayServer.cpp @@ -2,6 +2,8 @@ #include "PhantomPhysicsComponent.h" #include "EntityManager.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "ePhysicsEffectType.h" void NtSentinelWalkwayServer::OnStartup(Entity* self) { auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>(); @@ -18,7 +20,7 @@ void NtSentinelWalkwayServer::OnStartup(Entity* self) { const auto forward = self->GetRotation().GetRightVector() * -1; - phantomPhysicsComponent->SetEffectType(0); // PUSH + phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH); phantomPhysicsComponent->SetDirectionalMultiplier(force); phantomPhysicsComponent->SetDirection(forward); phantomPhysicsComponent->SetPhysicsEffectActive(true); @@ -38,6 +40,6 @@ void NtSentinelWalkwayServer::OnProximityUpdate(Entity* self, Entity* entering, auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } } diff --git a/dScripts/02_server/Map/NT/NtVandaServer.cpp b/dScripts/02_server/Map/NT/NtVandaServer.cpp index bfc35203..7750d566 100644 --- a/dScripts/02_server/Map/NT/NtVandaServer.cpp +++ b/dScripts/02_server/Map/NT/NtVandaServer.cpp @@ -1,10 +1,11 @@ #include "NtVandaServer.h" #include "InventoryComponent.h" +#include "eMissionState.h" -void NtVandaServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NtVandaServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { // Removes the alien parts after completing the mission - if (missionID == m_AlienPartMissionID && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE) { + if (missionID == m_AlienPartMissionID && missionState == eMissionState::READY_TO_COMPLETE) { auto* inventoryComponent = target->GetComponent<InventoryComponent>(); for (const auto& alienPartLot : m_AlienPartLots) { inventoryComponent->RemoveItem(alienPartLot, 1); diff --git a/dScripts/02_server/Map/NT/NtVandaServer.h b/dScripts/02_server/Map/NT/NtVandaServer.h index 69e868f5..58162cd9 100644 --- a/dScripts/02_server/Map/NT/NtVandaServer.h +++ b/dScripts/02_server/Map/NT/NtVandaServer.h @@ -2,7 +2,7 @@ #include "CppScripts.h" class NtVandaServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; const uint32_t m_AlienPartMissionID = 1183; const std::vector<LOT> m_AlienPartLots = { 12479, 12480, 12481 }; }; diff --git a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp index d7f4cb99..874d8aa1 100644 --- a/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp +++ b/dScripts/02_server/Map/NT/NtVentureCannonServer.cpp @@ -1,6 +1,7 @@ #include "NtVentureCannonServer.h" #include "GameMessages.h" #include "EntityManager.h" +#include "eEndBehavior.h" void NtVentureCannonServer::OnUse(Entity* self, Entity* user) { auto* player = user; @@ -14,7 +15,7 @@ void NtVentureCannonServer::OnUse(Entity* self, Entity* user) { self->SetNetworkVar(u"bIsInUse", true); - GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); @@ -73,7 +74,7 @@ void NtVentureCannonServer::EnterCannonEnded(Entity* self, Entity* player) { const auto exitCinematicUname = exitCinematic; GameMessages::SendPlayCinematic(player->GetObjectID(), exitCinematicUname, player->GetSystemAddress(), - true, true, true, false, 0, false, 0, false, false + true, true, true, false, eEndBehavior::RETURN, false, 0, false, false ); self->AddCallbackTimer(1.5f, [this, self, playerID]() { @@ -92,7 +93,7 @@ void NtVentureCannonServer::ExitCannonEnded(Entity* self, Entity* player) { } void NtVentureCannonServer::UnlockCannonPlayer(Entity* self, Entity* player) { - GameMessages::SendSetStunned(player->GetObjectID(), POP, player->GetSystemAddress(), LWOOBJID_EMPTY, + GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true ); diff --git a/dScripts/02_server/Map/NT/NtVentureSpeedPadServer.cpp b/dScripts/02_server/Map/NT/NtVentureSpeedPadServer.cpp index 0995d1df..07d33555 100644 --- a/dScripts/02_server/Map/NT/NtVentureSpeedPadServer.cpp +++ b/dScripts/02_server/Map/NT/NtVentureSpeedPadServer.cpp @@ -1,6 +1,7 @@ #include "NtVentureSpeedPadServer.h" #include "SkillComponent.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" void NtVentureSpeedPadServer::OnStartup(Entity* self) { self->SetProximityRadius(3, "speedboost"); @@ -17,7 +18,7 @@ void NtVentureSpeedPadServer::OnProximityUpdate(Entity* self, Entity* entering, auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + missionComponent->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } auto* skillComponent = player->GetComponent<SkillComponent>(); diff --git a/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp b/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp index 22e5ff59..2b7e3904 100644 --- a/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp +++ b/dScripts/02_server/Map/PR/SpawnGryphonServer.cpp @@ -2,6 +2,7 @@ #include "InventoryComponent.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eMissionState.h" void SpawnGryphonServer::SetVariables(Entity* self) { self->SetVar<LOT>(u"petLOT", 12433); @@ -17,7 +18,7 @@ void SpawnGryphonServer::OnUse(Entity* self, Entity* user) { // Little extra for handling the case of the egg being placed the first time if (missionComponent != nullptr && inventoryComponent != nullptr - && missionComponent->GetMissionState(1391) == MissionState::MISSION_STATE_ACTIVE) { + && missionComponent->GetMissionState(1391) == eMissionState::ACTIVE) { inventoryComponent->RemoveItem(12483, inventoryComponent->GetLotCount(12483)); GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); return; diff --git a/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp index 96302a33..0d4f568e 100644 --- a/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp +++ b/dScripts/02_server/Map/Property/AG_Small/EnemySpiderSpawner.cpp @@ -1,7 +1,9 @@ #include "EnemySpiderSpawner.h" #include "GameMessages.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" //---------------------------------------------- //--Initiate egg hatching on call @@ -13,7 +15,7 @@ void EnemySpiderSpawner::OnFireEventServerSide(Entity* self, Entity* sender, std GameMessages::SendPlayFXEffect(self->GetObjectID(), 2856, u"maelstrom", "test", LWOOBJID_EMPTY, 1.0f, 1.0f, true); // Make indestructible - auto dest = static_cast<DestroyableComponent*>(self->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + auto dest = static_cast<DestroyableComponent*>(self->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { dest->SetFaction(-1); } diff --git a/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp index db2bb78a..215e22c2 100644 --- a/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp +++ b/dScripts/02_server/Map/Property/AG_Small/ZoneAgProperty.cpp @@ -6,6 +6,8 @@ #include "dZoneManager.h" #include "RenderComponent.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" void ZoneAgProperty::SetGameVariables(Entity* self) { self->SetVar<std::string>(GuardGroup, "Guard"); @@ -80,7 +82,7 @@ void ZoneAgProperty::PropGuardCheck(Entity* self, Entity* player) { const auto state = missionComponent->GetMissionState(self->GetVar<uint32_t>(guardMissionFlag)); const auto firstState = missionComponent->GetMissionState(self->GetVar<uint32_t>(guardFirstMissionFlag)); - if (firstState < MissionState::MISSION_STATE_COMPLETE || (state != MissionState::MISSION_STATE_COMPLETE && state != MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE)) + if (firstState < eMissionState::COMPLETE || (state != eMissionState::COMPLETE && state != eMissionState::COMPLETE_READY_TO_COMPLETE)) ActivateSpawner(self->GetVar<std::string>(PropertyMGSpawner)); } @@ -255,7 +257,7 @@ void ZoneAgProperty::BaseTimerDone(Entity* self, const std::string& timerName) { DeactivateSpawner(self->GetVar<std::string>(SpiderScreamSpawner)); DestroySpawner(self->GetVar<std::string>(SpiderScreamSpawner)); - for (auto* player : EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_CHARACTER)) { + for (auto* player : EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER)) { GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); } @@ -304,13 +306,13 @@ void ZoneAgProperty::OnZonePropertyModelPlaced(Entity* self, Entity* player) { if (!character->GetPlayerFlag(101)) { BaseZonePropertyModelPlaced(self, player); character->SetPlayerFlag(101, true); - if (missionComponent->GetMissionState(871) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(871) == eMissionState::ACTIVE) { self->SetNetworkVar<std::u16string>(u"Tooltip", u"AnotherModel"); } } else if (!character->GetPlayerFlag(102)) { character->SetPlayerFlag(102, true); - if (missionComponent->GetMissionState(871) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(871) == eMissionState::ACTIVE) { self->SetNetworkVar<std::u16string>(u"Tooltip", u"TwoMoreModels"); } @@ -331,7 +333,7 @@ void ZoneAgProperty::OnZonePropertyModelPickedUp(Entity* self, Entity* player) { if (!character->GetPlayerFlag(109)) { character->SetPlayerFlag(109, true); - if (missionComponent->GetMissionState(891) == MissionState::MISSION_STATE_ACTIVE && !character->GetPlayerFlag(110)) { + if (missionComponent->GetMissionState(891) == eMissionState::ACTIVE && !character->GetPlayerFlag(110)) { self->SetNetworkVar<std::u16string>(u"Tooltip", u"Rotate"); } } @@ -353,7 +355,7 @@ void ZoneAgProperty::OnZonePropertyModelRotated(Entity* self, Entity* player) { if (!character->GetPlayerFlag(110)) { character->SetPlayerFlag(110, true); - if (missionComponent->GetMissionState(891) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(891) == eMissionState::ACTIVE) { self->SetNetworkVar<std::u16string>(u"Tooltip", u"PlaceModel"); self->SetVar<std::string>(u"tutorial", "place_model"); } diff --git a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp index 788768ca..9e727f39 100644 --- a/dScripts/02_server/Map/Property/PropertyBankInteract.cpp +++ b/dScripts/02_server/Map/Property/PropertyBankInteract.cpp @@ -1,6 +1,7 @@ #include "PropertyBankInteract.h" #include "EntityManager.h" #include "GameMessages.h" +#include "AMFFormat.h" void PropertyBankInteract::OnStartup(Entity* self) { auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); diff --git a/dScripts/02_server/Map/SS/SsModularBuildServer.cpp b/dScripts/02_server/Map/SS/SsModularBuildServer.cpp index d5b6da50..dfb29168 100644 --- a/dScripts/02_server/Map/SS/SsModularBuildServer.cpp +++ b/dScripts/02_server/Map/SS/SsModularBuildServer.cpp @@ -1,14 +1,16 @@ #include "SsModularBuildServer.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" void SsModularBuildServer::OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector<LOT> modules) { int missionNum = 1732; if (bCompleted) { - MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION)); Mission* rocketMission = mission->GetMission(missionNum); - if (rocketMission->GetMissionState() == MissionState::MISSION_STATE_ACTIVE) { + if (rocketMission->GetMissionState() == eMissionState::ACTIVE) { mission->ForceProgress(missionNum, 2478, 1); } } diff --git a/dScripts/02_server/Map/VE/VeBricksampleServer.cpp b/dScripts/02_server/Map/VE/VeBricksampleServer.cpp index 5166d0c3..36306d07 100644 --- a/dScripts/02_server/Map/VE/VeBricksampleServer.cpp +++ b/dScripts/02_server/Map/VE/VeBricksampleServer.cpp @@ -3,10 +3,11 @@ #include "EntityManager.h" #include "MissionComponent.h" #include "GameMessages.h" +#include "eMissionState.h" void VeBricksampleServer::OnUse(Entity* self, Entity* user) { auto* missionComponent = user->GetComponent<MissionComponent>(); - if (missionComponent != nullptr && missionComponent->GetMissionState(1183) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent != nullptr && missionComponent->GetMissionState(1183) == eMissionState::ACTIVE) { const auto loot = self->GetVar<int32_t>(m_LootVariable); auto* inventoryComponent = user->GetComponent<InventoryComponent>(); diff --git a/dScripts/02_server/Map/VE/VeEpsilonServer.cpp b/dScripts/02_server/Map/VE/VeEpsilonServer.cpp index cc6ecafe..c69f9cc2 100644 --- a/dScripts/02_server/Map/VE/VeEpsilonServer.cpp +++ b/dScripts/02_server/Map/VE/VeEpsilonServer.cpp @@ -2,15 +2,17 @@ #include "Character.h" #include "EntityManager.h" #include "GameMessages.h" +#include "eMissionState.h" +#include "Entity.h" -void VeEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void VeEpsilonServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { auto* character = target->GetCharacter(); if (character == nullptr) return; // Resets the player flags that track which consoles they've used if ((missionID == m_ConsoleMissionID || missionID == m_ConsoleRepeatMissionID) - && (missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE)) { + && (missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE)) { for (auto i = 0; i < 10; i++) { character->SetPlayerFlag(m_ConsoleBaseFlag + i, false); diff --git a/dScripts/02_server/Map/VE/VeEpsilonServer.h b/dScripts/02_server/Map/VE/VeEpsilonServer.h index d1236e96..971cd93e 100644 --- a/dScripts/02_server/Map/VE/VeEpsilonServer.h +++ b/dScripts/02_server/Map/VE/VeEpsilonServer.h @@ -2,7 +2,7 @@ #include "CppScripts.h" class VeEpsilonServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; const uint32_t m_ConsoleMissionID = 1220; const uint32_t m_ConsoleRepeatMissionID = 1225; const uint32_t m_ConsoleBaseFlag = 1010; diff --git a/dScripts/02_server/Map/VE/VeMissionConsole.cpp b/dScripts/02_server/Map/VE/VeMissionConsole.cpp index 2a424c4d..534f8c06 100644 --- a/dScripts/02_server/Map/VE/VeMissionConsole.cpp +++ b/dScripts/02_server/Map/VE/VeMissionConsole.cpp @@ -2,6 +2,7 @@ #include "InventoryComponent.h" #include "Character.h" #include "GameMessages.h" +#include "Loot.h" void VeMissionConsole::OnUse(Entity* self, Entity* user) { LootGenerator::Instance().DropActivityLoot(user, self, 12551); diff --git a/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp b/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp index 451fa1d5..0e2e4005 100644 --- a/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp +++ b/dScripts/02_server/Map/njhub/EnemySkeletonSpawner.cpp @@ -2,6 +2,7 @@ #include "SkillComponent.h" #include "RenderComponent.h" #include "EntityManager.h" +#include "EntityInfo.h" void EnemySkeletonSpawner::OnStartup(Entity* self) { self->SetProximityRadius(15, "ronin"); diff --git a/dScripts/02_server/Map/njhub/NjColeNPC.cpp b/dScripts/02_server/Map/njhub/NjColeNPC.cpp index f151db40..672fdd95 100644 --- a/dScripts/02_server/Map/njhub/NjColeNPC.cpp +++ b/dScripts/02_server/Map/njhub/NjColeNPC.cpp @@ -1,6 +1,7 @@ #include "NjColeNPC.h" #include "MissionComponent.h" #include "InventoryComponent.h" +#include "eMissionState.h" void NjColeNPC::OnEmoteReceived(Entity* self, int32_t emote, Entity* target) { if (emote != 393) { @@ -26,10 +27,10 @@ void NjColeNPC::OnEmoteReceived(Entity* self, int32_t emote, Entity* target) { missionComponent->ForceProgressTaskType(1818, 1, 1); } -void NjColeNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NjColeNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(self, target, missionID, missionState); - if (missionID == 1818 && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) { + if (missionID == 1818 && missionState >= eMissionState::READY_TO_COMPLETE) { auto* missionComponent = target->GetComponent<MissionComponent>(); auto* inventoryComponent = target->GetComponent<InventoryComponent>(); diff --git a/dScripts/02_server/Map/njhub/NjColeNPC.h b/dScripts/02_server/Map/njhub/NjColeNPC.h index cf8e67e1..a2536e32 100644 --- a/dScripts/02_server/Map/njhub/NjColeNPC.h +++ b/dScripts/02_server/Map/njhub/NjColeNPC.h @@ -3,5 +3,5 @@ class NjColeNPC : public NjNPCMissionSpinjitzuServer { void OnEmoteReceived(Entity* self, int32_t emote, Entity* target) override; - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; }; diff --git a/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp index fa4d8556..be9fcbd9 100644 --- a/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp +++ b/dScripts/02_server/Map/njhub/NjDragonEmblemChestServer.cpp @@ -1,5 +1,8 @@ #include "NjDragonEmblemChestServer.h" #include "Character.h" +#include "EntityInfo.h" +#include "Loot.h" +#include "Entity.h" #include "DestroyableComponent.h" void NjDragonEmblemChestServer::OnUse(Entity* self, Entity* user) { diff --git a/dScripts/02_server/Map/njhub/NjJayMissionItems.cpp b/dScripts/02_server/Map/njhub/NjJayMissionItems.cpp index cc871b86..46131446 100644 --- a/dScripts/02_server/Map/njhub/NjJayMissionItems.cpp +++ b/dScripts/02_server/Map/njhub/NjJayMissionItems.cpp @@ -1,6 +1,6 @@ #include "NjJayMissionItems.h" -void NjJayMissionItems::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NjJayMissionItems::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(self, target, missionID, missionState); NPCAddRemoveItem::OnMissionDialogueOK(self, target, missionID, missionState); } diff --git a/dScripts/02_server/Map/njhub/NjJayMissionItems.h b/dScripts/02_server/Map/njhub/NjJayMissionItems.h index c49f49ea..bdaee3ea 100644 --- a/dScripts/02_server/Map/njhub/NjJayMissionItems.h +++ b/dScripts/02_server/Map/njhub/NjJayMissionItems.h @@ -5,6 +5,6 @@ #include <map> class NjJayMissionItems : public NjNPCMissionSpinjitzuServer, NPCAddRemoveItem { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; std::map<uint32_t, std::vector<ItemSetting>> GetSettings() override; }; diff --git a/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp index 19f5f42a..30bba804 100644 --- a/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp +++ b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.cpp @@ -1,12 +1,12 @@ #include "NjNPCMissionSpinjitzuServer.h" #include "Character.h" #include "EntityManager.h" +#include "eMissionState.h" -void NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, - MissionState missionState) { +void NjNPCMissionSpinjitzuServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { const auto& element = self->GetVar<std::u16string>(ElementVariable); - if (missionID == ElementMissions.at(element) && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) { + if (missionID == ElementMissions.at(element) && missionState >= eMissionState::READY_TO_COMPLETE) { const auto targetID = target->GetObjectID(); diff --git a/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.h b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.h index 8f25a86a..3c705925 100644 --- a/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.h +++ b/dScripts/02_server/Map/njhub/NjNPCMissionSpinjitzuServer.h @@ -18,7 +18,7 @@ static std::map<std::u16string, uint32_t> ElementMissions = { class NjNPCMissionSpinjitzuServer : public CppScripts::Script { public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; private: const std::u16string ElementVariable = u"element"; }; diff --git a/dScripts/02_server/Map/njhub/NjWuNPC.cpp b/dScripts/02_server/Map/njhub/NjWuNPC.cpp index 855e4433..9efc623b 100644 --- a/dScripts/02_server/Map/njhub/NjWuNPC.cpp +++ b/dScripts/02_server/Map/njhub/NjWuNPC.cpp @@ -3,8 +3,9 @@ #include "Character.h" #include "EntityManager.h" #include "GameMessages.h" +#include "eMissionState.h" -void NjWuNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NjWuNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { // The Dragon statue daily mission if (missionID == m_MainDragonMissionID) { @@ -14,8 +15,8 @@ void NjWuNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, M return; switch (missionState) { - case MissionState::MISSION_STATE_AVAILABLE: - case MissionState::MISSION_STATE_COMPLETE_AVAILABLE: + case eMissionState::AVAILABLE: + case eMissionState::COMPLETE_AVAILABLE: { // Reset the sub missions for (const auto& subMissionID : m_SubDragonMissionIDs) { @@ -33,8 +34,8 @@ void NjWuNPC::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, M return; } - case MissionState::MISSION_STATE_READY_TO_COMPLETE: - case MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE: + case eMissionState::READY_TO_COMPLETE: + case eMissionState::COMPLETE_READY_TO_COMPLETE: { character->SetPlayerFlag(NJ_WU_SHOW_DAILY_CHEST, true); diff --git a/dScripts/02_server/Map/njhub/NjWuNPC.h b/dScripts/02_server/Map/njhub/NjWuNPC.h index d0cd750b..f8c52303 100644 --- a/dScripts/02_server/Map/njhub/NjWuNPC.h +++ b/dScripts/02_server/Map/njhub/NjWuNPC.h @@ -2,7 +2,7 @@ #include "AmTemplateSkillVolume.h" class NjWuNPC : public AmTemplateSkillVolume { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; const uint32_t m_MainDragonMissionID = 2040; const std::vector<uint32_t> m_SubDragonMissionIDs = { 2064, 2065, 2066, 2067 }; diff --git a/dScripts/02_server/Map/njhub/RainOfArrows.cpp b/dScripts/02_server/Map/njhub/RainOfArrows.cpp index 141cd3ab..b7c4c074 100644 --- a/dScripts/02_server/Map/njhub/RainOfArrows.cpp +++ b/dScripts/02_server/Map/njhub/RainOfArrows.cpp @@ -1,6 +1,7 @@ #include "RainOfArrows.h" #include "EntityManager.h" #include "SkillComponent.h" +#include "EntityInfo.h" #include "GameMessages.h" void RainOfArrows::OnStartup(Entity* self) { diff --git a/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp index 66222d59..7df8fc12 100644 --- a/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp +++ b/dScripts/02_server/Minigame/General/MinigameTreasureChestServer.cpp @@ -3,6 +3,7 @@ #include "TeamManager.h" #include "EntityManager.h" #include "dZoneManager.h" +#include "Loot.h" void MinigameTreasureChestServer::OnUse(Entity* self, Entity* user) { auto* sac = self->GetComponent<ScriptedActivityComponent>(); diff --git a/dScripts/02_server/Objects/StinkyFishTarget.cpp b/dScripts/02_server/Objects/StinkyFishTarget.cpp index 19dbce88..459e0bbe 100644 --- a/dScripts/02_server/Objects/StinkyFishTarget.cpp +++ b/dScripts/02_server/Objects/StinkyFishTarget.cpp @@ -1,5 +1,7 @@ #include "StinkyFishTarget.h" #include "EntityManager.h" +#include "EntityInfo.h" +#include "Entity.h" void StinkyFishTarget::OnStartup(Entity* self) { auto position = self->GetPosition(); @@ -15,6 +17,7 @@ void StinkyFishTarget::OnSkillEventFired(Entity* self, Entity* caster, const std self->SetVar<LWOOBJID>(u"player", caster->GetObjectID()); EntityInfo entityInfo{}; + entityInfo.lot = SHARK_LOT; entityInfo.pos = self->GetPosition(); entityInfo.rot = self->GetRotation(); entityInfo.spawnerID = self->GetObjectID(); @@ -34,7 +37,7 @@ void StinkyFishTarget::OnTimerDone(Entity* self, std::string timerName) { const auto playerID = self->GetVar<LWOOBJID>(u"player"); auto* fish = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(u"fish")); - if (fish != nullptr) { + if (fish) { fish->Smash(playerID); self->Smash(playerID); } diff --git a/dScripts/02_server/Objects/StinkyFishTarget.h b/dScripts/02_server/Objects/StinkyFishTarget.h index 6c52171d..b8f9e9ae 100644 --- a/dScripts/02_server/Objects/StinkyFishTarget.h +++ b/dScripts/02_server/Objects/StinkyFishTarget.h @@ -2,7 +2,10 @@ #include "CppScripts.h" class StinkyFishTarget : public CppScripts::Script { +public: void OnStartup(Entity* self) override; void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override; void OnTimerDone(Entity* self, std::string timerName) override; +private: + const LOT SHARK_LOT = 8570; }; diff --git a/dScripts/ActivityManager.cpp b/dScripts/ActivityManager.cpp index 4374337e..249b2282 100644 --- a/dScripts/ActivityManager.cpp +++ b/dScripts/ActivityManager.cpp @@ -5,6 +5,7 @@ #include "GameMessages.h" #include <algorithm> #include "dLogger.h" +#include "Loot.h" bool ActivityManager::IsPlayerInActivity(Entity* self, LWOOBJID playerID) { const auto* sac = self->GetComponent<ScriptedActivityComponent>(); @@ -123,7 +124,6 @@ void ActivityManager::ActivityTimerStart(Entity* self, const std::string& timerN const float_t stopTime) { auto* timer = new ActivityTimer{ timerName, updateInterval, stopTime }; activeTimers.push_back(timer); - self->AddTimer(GetPrefixedName(timer->name), timer->updateInterval); } diff --git a/dScripts/BaseConsoleTeleportServer.cpp b/dScripts/BaseConsoleTeleportServer.cpp index a8538de5..d0162e9c 100644 --- a/dScripts/BaseConsoleTeleportServer.cpp +++ b/dScripts/BaseConsoleTeleportServer.cpp @@ -15,7 +15,8 @@ void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* s if (button == 1) { - GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), player->GetObjectID(), + GameMessages::SendSetStunned( + player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), player->GetObjectID(), true, true, true, true, true, true, true ); @@ -82,11 +83,10 @@ void BaseConsoleTeleportServer::TransferPlayer(Entity* self, Entity* player, int return; } - // Ignoring extra effects for now - - /*GameMessages::SendSetStunned(player->GetObjectID(), POP, player->GetSystemAddress(), player->GetObjectID(), + GameMessages::SendSetStunned( + player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), player->GetObjectID(), true, true, true, true, true, true, true - );*/ + ); GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, player->GetObjectID()); diff --git a/dScripts/BasePropertyServer.cpp b/dScripts/BasePropertyServer.cpp index a182c9c1..a9f35e25 100644 --- a/dScripts/BasePropertyServer.cpp +++ b/dScripts/BasePropertyServer.cpp @@ -8,6 +8,8 @@ #include "RenderComponent.h" #include "PropertyManagementComponent.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" void BasePropertyServer::SetGameVariables(Entity* self) { self->SetVar<std::string>(ClaimMarkerGroup, ""); @@ -97,7 +99,7 @@ void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { if (missionComponent != nullptr) { missionComponent->Progress( - MissionTaskType::MISSION_TASK_TYPE_VISIT_PROPERTY, + eMissionTaskType::VISIT_PROPERTY, mapID.GetMapID(), mapID.GetCloneID() ); @@ -150,7 +152,7 @@ void BasePropertyServer::PropGuardCheck(Entity* self, Entity* player) { auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr - && missionComponent->GetMissionState(self->GetVar<uint32_t>(guardMissionFlag)) != MissionState::MISSION_STATE_COMPLETE) { + && missionComponent->GetMissionState(self->GetVar<uint32_t>(guardMissionFlag)) != eMissionState::COMPLETE) { ActivateSpawner(self->GetVar<std::string>(PropertyMGSpawner)); } } @@ -301,18 +303,8 @@ void BasePropertyServer::ResetSpawner(const std::string& spawnerName) { void BasePropertyServer::DestroySpawner(const std::string& spawnerName) { for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { - for (auto* node : spawner->m_Info.nodes) { - for (const auto& element : node->entities) { - auto* entity = EntityManager::Instance()->GetEntity(element); - if (entity == nullptr) - continue; - - entity->Kill(); - } - - node->entities.clear(); - } - + if (!spawner) return; + spawner->DestroyAllEntities(); spawner->Deactivate(); } } diff --git a/dScripts/BaseSurvivalServer.cpp b/dScripts/BaseSurvivalServer.cpp index 270b6741..3d72628d 100644 --- a/dScripts/BaseSurvivalServer.cpp +++ b/dScripts/BaseSurvivalServer.cpp @@ -4,7 +4,8 @@ #include "EntityManager.h" #include "dZoneManager.h" #include "Player.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" #include "MissionComponent.h" #include "Character.h" @@ -361,16 +362,16 @@ void BaseSurvivalServer::GameOver(Entity* self) { // Update all mission progression auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, time, self->GetObjectID(), + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, time, self->GetObjectID(), self->GetVar<std::string>(MissionTypeVariable)); for (const auto& survivalMission : missionsToUpdate) { auto* mission = missionComponent->GetMission(survivalMission.first); if (mission != nullptr && (uint32_t)time >= survivalMission.second - && (mission->GetMissionState() == MissionState::MISSION_STATE_ACTIVE - || mission->GetMissionState() == MissionState::MISSION_STATE_COMPLETE_ACTIVE)) { + && (mission->GetMissionState() == eMissionState::ACTIVE + || mission->GetMissionState() == eMissionState::COMPLETE_ACTIVE)) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } } } diff --git a/dScripts/BaseWavesServer.cpp b/dScripts/BaseWavesServer.cpp index 8c32f984..00340bd0 100644 --- a/dScripts/BaseWavesServer.cpp +++ b/dScripts/BaseWavesServer.cpp @@ -4,7 +4,8 @@ #include "EntityManager.h" #include "dZoneManager.h" #include "Player.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" +#include "eMissionState.h" #include "MissionComponent.h" #include "Character.h" @@ -373,7 +374,7 @@ void BaseWavesServer::GameOver(Entity* self, bool won) { // Update all mission progression auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, time, self->GetObjectID(), self->GetVar<std::string>(MissionTypeVariable)); + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, time, self->GetObjectID(), self->GetVar<std::string>(MissionTypeVariable)); } StopActivity(self, playerID, wave, time, score); @@ -429,7 +430,7 @@ void BaseWavesServer::SpawnWave(Entity* self) { for (const auto& playerID : state.players) { auto* player = EntityManager::Instance()->GetEntity(playerID); - if (player != nullptr) { + if (player && player->GetIsDead()) { player->Resurrect(); } } @@ -510,15 +511,15 @@ bool BaseWavesServer::UpdateSpawnedEnemies(Entity* self, LWOOBJID enemyID, uint3 // Get the mission state auto missionState = missionComponent->GetMissionState(missionID); // For some reason these achievements are not accepted by default, so we accept them here if they arent already. - if (missionState != MissionState::MISSION_STATE_COMPLETE && missionState != MissionState::MISSION_STATE_UNKNOWN) { + if (missionState != eMissionState::COMPLETE && missionState != eMissionState::UNKNOWN) { missionComponent->AcceptMission(missionID); missionState = missionComponent->GetMissionState(missionID); } - if (missionState != MissionState::MISSION_STATE_COMPLETE) { + if (missionState != eMissionState::COMPLETE) { auto mission = missionComponent->GetMission(missionID); if (mission != nullptr) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } } } @@ -528,15 +529,15 @@ bool BaseWavesServer::UpdateSpawnedEnemies(Entity* self, LWOOBJID enemyID, uint3 // Get the mission state auto missionState = missionComponent->GetMissionState(missionID); // For some reason these achievements are not accepted by default, so we accept them here if they arent already. - if (missionState != MissionState::MISSION_STATE_COMPLETE && missionState != MissionState::MISSION_STATE_UNKNOWN) { + if (missionState != eMissionState::COMPLETE && missionState != eMissionState::UNKNOWN) { missionComponent->AcceptMission(missionID); missionState = missionComponent->GetMissionState(missionID); } - if (missionState != MissionState::MISSION_STATE_COMPLETE) { + if (missionState != eMissionState::COMPLETE) { auto mission = missionComponent->GetMission(missionID); if (mission != nullptr) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } } } @@ -564,14 +565,14 @@ void BaseWavesServer::UpdateMissionForAllPlayers(Entity* self, uint32_t missionI // Get the mission state auto missionState = missionComponent->GetMissionState(missionID); // For some reason these achievements are not accepted by default, so we accept them here if they arent already. - if (missionState != MissionState::MISSION_STATE_COMPLETE && missionState != MissionState::MISSION_STATE_UNKNOWN) { + if (missionState != eMissionState::COMPLETE && missionState != eMissionState::UNKNOWN) { missionComponent->AcceptMission(missionID); missionState = missionComponent->GetMissionState(missionID); } - if (missionState != MissionState::MISSION_STATE_COMPLETE) { + if (missionState != eMissionState::COMPLETE) { auto mission = missionComponent->GetMission(missionID); if (mission != nullptr) { - mission->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } } } diff --git a/dScripts/CMakeLists.txt b/dScripts/CMakeLists.txt index fce3b721..ac600dbc 100644 --- a/dScripts/CMakeLists.txt +++ b/dScripts/CMakeLists.txt @@ -39,6 +39,12 @@ foreach(file ${DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS}) set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "EquipmentScripts/${file}") endforeach() +add_subdirectory(EquipmentTriggers) + +foreach(file ${DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS}) + set(DSCRIPTS_SOURCES ${DSCRIPTS_SOURCES} "EquipmentTriggers/${file}") +endforeach() + add_subdirectory(zone) foreach(file ${DSCRIPTS_SOURCES_ZONE}) diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index dce77e4b..7ed7373f 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -278,6 +278,10 @@ #include "ImaginationBackpackHealServer.h" #include "LegoDieRoll.h" #include "BuccaneerValiantShip.h" +#include "GemPack.h" +#include "ShardArmor.h" +#include "TeslaPack.h" +#include "StunImmunity.h" // Survival scripts #include "AgSurvivalStromling.h" @@ -291,6 +295,12 @@ // WBL scripts #include "WblGenericZone.h" +// Wild Scripts +#include "WildAndScared.h" +#include "WildGfGlowbug.h" +#include "WildAmbientCrab.h" +#include "WildPants.h" + //Big bad global bc this is a namespace and not a class: InvalidScript* invalidToReturn = new InvalidScript(); std::map<std::string, CppScripts::Script*> m_Scripts; @@ -837,6 +847,14 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new BuccaneerValiantShip(); else if (scriptName == "scripts\\EquipmentScripts\\FireFirstSkillonStartup.lua") script = new FireFirstSkillonStartup(); + else if (scriptName == "scripts\\equipmenttriggers\\gempack.lua") + script = new GemPack(); + else if (scriptName == "scripts\\equipmenttriggers\\shardarmor.lua") + script = new ShardArmor(); + else if (scriptName == "scripts\\equipmenttriggers\\coilbackpack.lua") + script = new TeslaPack(); + else if (scriptName == "scripts\\EquipmentScripts\\stunImmunity.lua") + script = new StunImmunity(); // FB else if (scriptName == "scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_BROKEN.lua") @@ -848,11 +866,22 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\zone\\LUPs\\WBL_generic_zone.lua") script = new WblGenericZone(); + // Wild + if (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_RAT.lua" || scriptName == "scripts\\ai\\WILD\\L_WILD_GF_SNAIL.lua") + script = new WildAndScared(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_GLOWBUG.lua") + script = new WildGfGlowbug(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_AMBIENT_CRAB.lua") + script = new WildAmbientCrab(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_PANTS.lua") + script = new WildPants(); + // handle invalid script reporting if the path is greater than zero and it's not an ignored script // information not really needed for sys admins but is for developers else if (script == invalidToReturn) { if ((scriptName.length() > 0) && !((scriptName == "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua") || (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua") || + (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_FROG.lua") || (scriptName == "scripts\\empty.lua") )) Game::logger->LogDebug("CppScripts", "LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str()); } diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index 916d2638..21ff8427 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -1,12 +1,13 @@ #pragma once -#include "dCommonVars.h" -#include "MissionState.h" + +#include <cstdint> #include <string> #include <vector> class User; class Entity; class NiPoint3; +enum class eMissionState : int32_t; namespace CppScripts { /** @@ -48,7 +49,7 @@ namespace CppScripts { * * Equivalent to 'function onMissionDialogueOK(self, msg)' */ - virtual void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) {}; + virtual void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) {}; /** * Invoked when the client or the server invoked an event server-side. @@ -172,6 +173,13 @@ namespace CppScripts { */ virtual void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {}; + /** + * Invoked when self has received either a hit or heal. Only used for scripts subscribed to an entity. + * + * Equivalent to 'function notifyHitOrHealResult(self, msg)' + */ + virtual void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {}; + /** * Invoked when a player has responsed to a mission. * @@ -316,6 +324,22 @@ namespace CppScripts { virtual void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, float_t pathTime, float_t totalTime, int32_t waypoint) { }; + + /** + * Used by items to tell their owner that they were equipped. + * + * @param itemOwner The owner of the item + * @param itemObjId The items Object ID + */ + virtual void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) {}; + + /** + * Used by items to tell their owner that they were unequipped. + * + * @param itemOwner The owner of the item + * @param itemObjId The items Object ID + */ + virtual void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) {}; }; Script* GetScript(Entity* parent, const std::string& scriptName); diff --git a/dScripts/Darkitect.cpp b/dScripts/Darkitect.cpp index 323d0247..b4364332 100644 --- a/dScripts/Darkitect.cpp +++ b/dScripts/Darkitect.cpp @@ -4,6 +4,7 @@ #include "EntityManager.h" #include "GameMessages.h" #include "Character.h" +#include "eMissionState.h" void Darkitect::Reveal(Entity* self, Entity* player) { const auto playerID = player->GetObjectID(); @@ -24,7 +25,7 @@ void Darkitect::Reveal(Entity* self, Entity* player) { destroyableComponent->SetHealth(1); destroyableComponent->SetImagination(0); - if (missionComponent->GetMissionState(1295) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(1295) == eMissionState::ACTIVE) { character->SetPlayerFlag(1911, true); } diff --git a/dScripts/EquipmentScripts/CMakeLists.txt b/dScripts/EquipmentScripts/CMakeLists.txt index c870ae31..696be03d 100644 --- a/dScripts/EquipmentScripts/CMakeLists.txt +++ b/dScripts/EquipmentScripts/CMakeLists.txt @@ -1,4 +1,4 @@ -set(DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS +set(DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS "Sunflower.cpp" "AnvilOfArmor.cpp" "FountainOfImagination.cpp" @@ -6,4 +6,5 @@ set(DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS "PersonalFortress.cpp" "BuccaneerValiantShip.cpp" "FireFirstSkillonStartup.cpp" + "StunImmunity.cpp" PARENT_SCOPE) diff --git a/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp b/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp index cd0d94f2..389f3621 100644 --- a/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp +++ b/dScripts/EquipmentScripts/FireFirstSkillonStartup.cpp @@ -3,18 +3,20 @@ #include "SkillComponent.h" #include "CDClientDatabase.h" #include "CDObjectSkillsTable.h" +#include "CDSkillBehaviorTable.h" +#include "CDClientManager.h" void FireFirstSkillonStartup::OnStartup(Entity* self) { auto skillComponent = self->GetComponent<SkillComponent>(); if (!skillComponent) return; // Get the skill IDs of this object. - CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable<CDObjectSkillsTable>("ObjectSkills"); + CDObjectSkillsTable* skillsTable = CDClientManager::Instance().GetTable<CDObjectSkillsTable>(); std::vector<CDObjectSkills> skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); }); // For each skill, cast it with the associated behavior ID. for (auto skill : skills) { - CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior"); + CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>(); CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID); // Should parent entity be null, make the originator self. diff --git a/dScripts/EquipmentScripts/PersonalFortress.cpp b/dScripts/EquipmentScripts/PersonalFortress.cpp index e7e89e80..f5062f9b 100644 --- a/dScripts/EquipmentScripts/PersonalFortress.cpp +++ b/dScripts/EquipmentScripts/PersonalFortress.cpp @@ -2,49 +2,56 @@ #include "GameMessages.h" #include "SkillComponent.h" #include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" #include "EntityManager.h" void PersonalFortress::OnStartup(Entity* self) { auto* owner = self->GetOwner(); self->AddTimer("FireSkill", 1.5); - GameMessages::SendSetStunned(owner->GetObjectID(), PUSH, owner->GetSystemAddress(), LWOOBJID_EMPTY, - true, true, true, true, true, true, true, true, true - ); auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity( + eStateChangeType::PUSH, + true, true, true, true, true, false, true, false, false + ); - if (destroyableComponent != nullptr) { - destroyableComponent->PushImmunity(); - } + auto* controllablePhysicsComponent = owner->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::PUSH, LWOOBJID_EMPTY, + true, true, true, true, true, true + ); + + GameMessages::SendSetStunned(owner->GetObjectID(), eStateChangeType::PUSH, owner->GetSystemAddress(), LWOOBJID_EMPTY, + true, true, true, true, true, true, true, true, true + ); EntityManager::Instance()->SerializeEntity(owner); } void PersonalFortress::OnDie(Entity* self, Entity* killer) { auto* owner = self->GetOwner(); - GameMessages::SendSetStunned(owner->GetObjectID(), POP, owner->GetSystemAddress(), LWOOBJID_EMPTY, + auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); + if (destroyableComponent) destroyableComponent->SetStatusImmunity( + eStateChangeType::POP, + true, true, true, true, true, false, true, false, false + ); + + auto* controllablePhysicsComponent = owner->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::POP, LWOOBJID_EMPTY, + true, true, true, true, true, true + ); + + GameMessages::SendSetStunned(owner->GetObjectID(), eStateChangeType::POP, owner->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true, true ); - auto* destroyableComponent = owner->GetComponent<DestroyableComponent>(); - - if (destroyableComponent != nullptr) { - destroyableComponent->PopImmunity(); - } - EntityManager::Instance()->SerializeEntity(owner); } void PersonalFortress::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "FireSkill") { - auto* owner = self->GetOwner(); - auto* skillComponent = self->GetComponent<SkillComponent>(); - - if (skillComponent == nullptr) { - return; - } - - skillComponent->CalculateBehavior(650, 13364, LWOOBJID_EMPTY, true, false); + if (skillComponent) skillComponent->CalculateBehavior(650, 13364, LWOOBJID_EMPTY, true, false); } } diff --git a/dScripts/EquipmentScripts/StunImmunity.cpp b/dScripts/EquipmentScripts/StunImmunity.cpp new file mode 100644 index 00000000..f35fe261 --- /dev/null +++ b/dScripts/EquipmentScripts/StunImmunity.cpp @@ -0,0 +1,19 @@ +#include "StunImmunity.h" +#include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" + +void StunImmunity::OnStartup(Entity* self) { + auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + destroyableComponent->SetStatusImmunity( + eStateChangeType::PUSH, false, false, true, true, false, false, false, false, true + ); + } + + auto* controllablePhysicsComponent = self->GetComponent<ControllablePhysicsComponent>(); + if (controllablePhysicsComponent) { + controllablePhysicsComponent->SetStunImmunity( + eStateChangeType::PUSH, self->GetObjectID(), true + ); + } +} diff --git a/dScripts/EquipmentScripts/StunImmunity.h b/dScripts/EquipmentScripts/StunImmunity.h new file mode 100644 index 00000000..0faaf061 --- /dev/null +++ b/dScripts/EquipmentScripts/StunImmunity.h @@ -0,0 +1,6 @@ +#pragma once +#include "CppScripts.h" + +class StunImmunity : public CppScripts::Script { + void OnStartup(Entity* self) override; +}; diff --git a/dScripts/EquipmentTriggers/CMakeLists.txt b/dScripts/EquipmentTriggers/CMakeLists.txt new file mode 100644 index 00000000..416ef553 --- /dev/null +++ b/dScripts/EquipmentTriggers/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS + "CoilBackpackBase.cpp" + PARENT_SCOPE) diff --git a/dScripts/EquipmentTriggers/CoilBackpackBase.cpp b/dScripts/EquipmentTriggers/CoilBackpackBase.cpp new file mode 100644 index 00000000..4e323a08 --- /dev/null +++ b/dScripts/EquipmentTriggers/CoilBackpackBase.cpp @@ -0,0 +1,25 @@ +#include "CoilBackpackBase.h" + +#include "Entity.h" +#include "SkillComponent.h" + +void CoilBackpackBase::OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) { + itemOwner->Subscribe(itemObjId, this, "HitOrHealResult"); + itemOwner->SetVar<uint8_t>(u"coilCount", 0); +} + +void CoilBackpackBase::NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + if (damage > 0) { + self->SetVar<uint8_t>(u"coilCount", self->GetVar<uint8_t>(u"coilCount") + 1); + if (self->GetVar<uint8_t>(u"coilCount") > 4) { + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (!skillComponent) return; + skillComponent->CastSkill(m_SkillId); + self->SetVar<uint8_t>(u"coilCount", 0); + } + } +} + +void CoilBackpackBase::OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) { + itemOwner->Unsubscribe(itemObjId, "HitOrHealResult"); +} diff --git a/dScripts/EquipmentTriggers/CoilBackpackBase.h b/dScripts/EquipmentTriggers/CoilBackpackBase.h new file mode 100644 index 00000000..2d641346 --- /dev/null +++ b/dScripts/EquipmentTriggers/CoilBackpackBase.h @@ -0,0 +1,19 @@ +#ifndef __GemPackBase__H__ +#define __GemPackBase__H__ + +#include "CppScripts.h" + +class CoilBackpackBase: public CppScripts::Script { +public: + CoilBackpackBase(uint32_t skillId) { + m_SkillId = skillId; + }; + + void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) override; + void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) override; +private: + uint32_t m_SkillId = 0; +}; + +#endif //!__GemPackBase__H__ diff --git a/dScripts/EquipmentTriggers/GemPack.h b/dScripts/EquipmentTriggers/GemPack.h new file mode 100644 index 00000000..d71181ab --- /dev/null +++ b/dScripts/EquipmentTriggers/GemPack.h @@ -0,0 +1,13 @@ +#ifndef __GEMPACK__H__ +#define __GEMPACK__H__ + +#include "CoilBackpackBase.h" + +class GemPack : public CoilBackpackBase { +public: + GemPack() : CoilBackpackBase(skillId) {}; +private: + static const uint32_t skillId = 1488; +}; + +#endif //!__GEMPACK__H__ diff --git a/dScripts/EquipmentTriggers/ShardArmor.h b/dScripts/EquipmentTriggers/ShardArmor.h new file mode 100644 index 00000000..5486db54 --- /dev/null +++ b/dScripts/EquipmentTriggers/ShardArmor.h @@ -0,0 +1,13 @@ +#ifndef __SHARDARMOR__H__ +#define __SHARDARMOR__H__ + +#include "CoilBackpackBase.h" + +class ShardArmor : public CoilBackpackBase { +public: + ShardArmor() : CoilBackpackBase(skillId) {}; +private: + static const uint32_t skillId = 1249; +}; + +#endif //!__SHARDARMOR__H__ diff --git a/dScripts/EquipmentTriggers/TeslaPack.h b/dScripts/EquipmentTriggers/TeslaPack.h new file mode 100644 index 00000000..3ba09f5c --- /dev/null +++ b/dScripts/EquipmentTriggers/TeslaPack.h @@ -0,0 +1,13 @@ +#ifndef __TESLAPACK__H__ +#define __TESLAPACK__H__ + +#include "CoilBackpackBase.h" + +class TeslaPack : public CoilBackpackBase { +public: + TeslaPack() : CoilBackpackBase(skillId) {}; +private: + static const uint32_t skillId = 1001; +}; + +#endif //!__TESLAPACK__H__ diff --git a/dScripts/NPCAddRemoveItem.cpp b/dScripts/NPCAddRemoveItem.cpp index ce47b12a..f1ef8c0d 100644 --- a/dScripts/NPCAddRemoveItem.cpp +++ b/dScripts/NPCAddRemoveItem.cpp @@ -1,7 +1,8 @@ #include "NPCAddRemoveItem.h" #include "InventoryComponent.h" +#include "eMissionState.h" -void NPCAddRemoveItem::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void NPCAddRemoveItem::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { auto* inventory = target->GetComponent<InventoryComponent>(); if (inventory == nullptr) return; @@ -10,9 +11,9 @@ void NPCAddRemoveItem::OnMissionDialogueOK(Entity* self, Entity* target, int mis if (missionSetting.first == missionID) { for (const auto& itemSetting : missionSetting.second) { for (const auto& lot : itemSetting.items) { - if (itemSetting.add && (missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_COMPLETE_AVAILABLE)) { + if (itemSetting.add && (missionState == eMissionState::AVAILABLE || missionState == eMissionState::COMPLETE_AVAILABLE)) { inventory->AddItem(lot, 1, eLootSourceType::LOOT_SOURCE_NONE); - } else if (itemSetting.remove && (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE || missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE)) { + } else if (itemSetting.remove && (missionState == eMissionState::READY_TO_COMPLETE || missionState == eMissionState::COMPLETE_READY_TO_COMPLETE)) { inventory->RemoveItem(lot, 1); } } diff --git a/dScripts/NPCAddRemoveItem.h b/dScripts/NPCAddRemoveItem.h index a266f817..73a7f2c9 100644 --- a/dScripts/NPCAddRemoveItem.h +++ b/dScripts/NPCAddRemoveItem.h @@ -12,7 +12,7 @@ struct ItemSetting { */ class NPCAddRemoveItem : public CppScripts::Script { protected: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; virtual std::map<uint32_t, std::vector<ItemSetting>> GetSettings(); private: void OnStartup(Entity* self) override; diff --git a/dScripts/NtFactionSpyServer.cpp b/dScripts/NtFactionSpyServer.cpp index ac068a32..dc62855a 100644 --- a/dScripts/NtFactionSpyServer.cpp +++ b/dScripts/NtFactionSpyServer.cpp @@ -4,6 +4,8 @@ #include "InventoryComponent.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" void NtFactionSpyServer::OnStartup(Entity* self) { SetVariables(self); @@ -12,7 +14,7 @@ void NtFactionSpyServer::OnStartup(Entity* self) { auto* proximityMonitor = self->GetComponent<ProximityMonitorComponent>(); if (proximityMonitor == nullptr) { proximityMonitor = new ProximityMonitorComponent(self, -1, -1); - self->AddComponent(COMPONENT_TYPE_PROXIMITY_MONITOR, proximityMonitor); + self->AddComponent(eReplicaComponentType::PROXIMITY_MONITOR, proximityMonitor); } proximityMonitor->SetProximityRadius(self->GetVar<float_t>(m_SpyProximityVariable), m_ProximityName); @@ -54,7 +56,7 @@ bool NtFactionSpyServer::IsSpy(Entity* self, Entity* possibleSpy) { auto* character = possibleSpy->GetCharacter(); // A player is a spy if they have the spy mission, have the spy equipment equipped and don't have the spy flag set yet - return missionComponent != nullptr && missionComponent->GetMissionState(spyData.missionID) == MissionState::MISSION_STATE_ACTIVE + return missionComponent != nullptr && missionComponent->GetMissionState(spyData.missionID) == eMissionState::ACTIVE && inventoryComponent != nullptr && inventoryComponent->IsEquipped(spyData.itemID) && character != nullptr && !character->GetPlayerFlag(spyData.flagID); } diff --git a/dScripts/ScriptComponent.h b/dScripts/ScriptComponent.h index 94226627..77dff5bf 100644 --- a/dScripts/ScriptComponent.h +++ b/dScripts/ScriptComponent.h @@ -9,6 +9,7 @@ #include "CppScripts.h" #include "Component.h" #include <string> +#include "eReplicaComponentType.h" class Entity; @@ -18,7 +19,7 @@ class Entity; */ class ScriptComponent : public Component { public: - static const uint32_t ComponentType = COMPONENT_TYPE_SCRIPT; + static const eReplicaComponentType ComponentType = eReplicaComponentType::SCRIPT; ScriptComponent(Entity* parent, std::string scriptName, bool serialized, bool client = false); ~ScriptComponent() override; diff --git a/dScripts/ScriptedPowerupSpawner.cpp b/dScripts/ScriptedPowerupSpawner.cpp index 730e65ba..3c1d1cca 100644 --- a/dScripts/ScriptedPowerupSpawner.cpp +++ b/dScripts/ScriptedPowerupSpawner.cpp @@ -1,6 +1,7 @@ #include "ScriptedPowerupSpawner.h" #include "RenderComponent.h" #include "EntityManager.h" +#include "Loot.h" void ScriptedPowerupSpawner::OnTemplateStartup(Entity* self) { self->SetVar<uint32_t>(u"currentCycle", 1); diff --git a/dScripts/SpawnPetBaseServer.cpp b/dScripts/SpawnPetBaseServer.cpp index 1d73a5b8..d3c87288 100644 --- a/dScripts/SpawnPetBaseServer.cpp +++ b/dScripts/SpawnPetBaseServer.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "EntityManager.h" #include "PetComponent.h" +#include "EntityInfo.h" void SpawnPetBaseServer::OnStartup(Entity* self) { SetVariables(self); diff --git a/dScripts/ai/ACT/ActPlayerDeathTrigger.cpp b/dScripts/ai/ACT/ActPlayerDeathTrigger.cpp index 28f1ef43..0674f0dd 100644 --- a/dScripts/ai/ACT/ActPlayerDeathTrigger.cpp +++ b/dScripts/ai/ACT/ActPlayerDeathTrigger.cpp @@ -1,5 +1,7 @@ #include "ActPlayerDeathTrigger.h" +#include "Entity.h" + void ActPlayerDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) { if (!target->IsPlayer() || target->GetIsDead() || !target->GetPlayerReadyForUpdates()) return; //Don't kill already dead players or players not ready diff --git a/dScripts/ai/AG/ActSharkPlayerDeathTrigger.cpp b/dScripts/ai/AG/ActSharkPlayerDeathTrigger.cpp index 420fc4d7..49fb6b87 100644 --- a/dScripts/ai/AG/ActSharkPlayerDeathTrigger.cpp +++ b/dScripts/ai/AG/ActSharkPlayerDeathTrigger.cpp @@ -1,6 +1,6 @@ #include "ActSharkPlayerDeathTrigger.h" #include "MissionComponent.h" -#include "MissionTaskType.h" +#include "eMissionTaskType.h" #include "Entity.h" void ActSharkPlayerDeathTrigger::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, @@ -9,7 +9,7 @@ void ActSharkPlayerDeathTrigger::OnFireEventServerSide(Entity* self, Entity* sen auto missionComponent = sender->GetComponent<MissionComponent>(); if (!missionComponent) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, 8419); + missionComponent->Progress(eMissionTaskType::SCRIPT, 8419); if (sender->GetIsDead() || !sender->GetPlayerReadyForUpdates()) return; //Don't kill already dead players or players not ready diff --git a/dScripts/ai/AG/AgFans.cpp b/dScripts/ai/AG/AgFans.cpp index 27d3b940..e05fe68d 100644 --- a/dScripts/ai/AG/AgFans.cpp +++ b/dScripts/ai/AG/AgFans.cpp @@ -4,6 +4,7 @@ #include "GameMessages.h" #include "PhantomPhysicsComponent.h" #include "RenderComponent.h" +#include "eReplicaComponentType.h" void AgFans::OnStartup(Entity* self) { self->SetVar<bool>(u"alive", true); @@ -11,7 +12,7 @@ void AgFans::OnStartup(Entity* self) { ToggleFX(self, false); - auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (renderComponent == nullptr) { return; @@ -24,7 +25,7 @@ void AgFans::ToggleFX(Entity* self, bool hit) { std::string fanGroup = self->GetGroups()[0]; std::vector<Entity*> fanVolumes = EntityManager::Instance()->GetEntitiesInGroup(fanGroup); - auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* renderComponent = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (renderComponent == nullptr) { return; @@ -39,7 +40,7 @@ void AgFans::ToggleFX(Entity* self, bool hit) { self->SetVar<bool>(u"on", false); for (Entity* volume : fanVolumes) { - PhantomPhysicsComponent* volumePhys = static_cast<PhantomPhysicsComponent*>(volume->GetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS)); + PhantomPhysicsComponent* volumePhys = static_cast<PhantomPhysicsComponent*>(volume->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); if (!volumePhys) continue; volumePhys->SetPhysicsEffectActive(false); EntityManager::Instance()->SerializeEntity(volume); @@ -55,7 +56,7 @@ void AgFans::ToggleFX(Entity* self, bool hit) { self->SetVar<bool>(u"on", true); for (Entity* volume : fanVolumes) { - PhantomPhysicsComponent* volumePhys = static_cast<PhantomPhysicsComponent*>(volume->GetComponent(COMPONENT_TYPE_PHANTOM_PHYSICS)); + PhantomPhysicsComponent* volumePhys = static_cast<PhantomPhysicsComponent*>(volume->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); if (!volumePhys) continue; volumePhys->SetPhysicsEffectActive(true); EntityManager::Instance()->SerializeEntity(volume); diff --git a/dScripts/ai/AG/AgImagSmashable.cpp b/dScripts/ai/AG/AgImagSmashable.cpp index 593294e5..5e8331b1 100644 --- a/dScripts/ai/AG/AgImagSmashable.cpp +++ b/dScripts/ai/AG/AgImagSmashable.cpp @@ -2,13 +2,15 @@ #include "EntityManager.h" #include "GeneralUtils.h" #include "GameMessages.h" +#include "EntityInfo.h" #include "DestroyableComponent.h" +#include "eReplicaComponentType.h" void AgImagSmashable::OnDie(Entity* self, Entity* killer) { bool maxImagGreaterThanZero = false; if (killer) { - DestroyableComponent* dest = static_cast<DestroyableComponent*>(killer->GetComponent(COMPONENT_TYPE_DESTROYABLE)); + DestroyableComponent* dest = static_cast<DestroyableComponent*>(killer->GetComponent(eReplicaComponentType::DESTROYABLE)); if (dest) { maxImagGreaterThanZero = dest->GetMaxImagination() > 0; } diff --git a/dScripts/ai/AG/AgJetEffectServer.cpp b/dScripts/ai/AG/AgJetEffectServer.cpp index 8c7eca3b..9546bc4d 100644 --- a/dScripts/ai/AG/AgJetEffectServer.cpp +++ b/dScripts/ai/AG/AgJetEffectServer.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "EntityManager.h" #include "SkillComponent.h" +#include "eReplicaComponentType.h" void AgJetEffectServer::OnUse(Entity* self, Entity* user) { if (inUse) { @@ -86,12 +87,12 @@ void AgJetEffectServer::OnTimerDone(Entity* self, std::string timerName) { auto* mortar = entities[selected]; - Game::logger->Log("AgJetEffectServer", "Mortar (%i) (&d)", mortar->GetLOT(), mortar->HasComponent(COMPONENT_TYPE_SKILL)); + Game::logger->Log("AgJetEffectServer", "Mortar (%i) (&d)", mortar->GetLOT(), mortar->HasComponent(eReplicaComponentType::SKILL)); mortar->SetOwnerOverride(builder); SkillComponent* skillComponent; - if (!mortar->TryGetComponent(COMPONENT_TYPE_SKILL, skillComponent)) { + if (!mortar->TryGetComponent(eReplicaComponentType::SKILL, skillComponent)) { return; } diff --git a/dScripts/ai/AG/AgPicnicBlanket.cpp b/dScripts/ai/AG/AgPicnicBlanket.cpp index 30fb2950..d2a54d57 100644 --- a/dScripts/ai/AG/AgPicnicBlanket.cpp +++ b/dScripts/ai/AG/AgPicnicBlanket.cpp @@ -1,5 +1,7 @@ #include "AgPicnicBlanket.h" +#include "Loot.h" #include "GameMessages.h" +#include "Entity.h" void AgPicnicBlanket::OnUse(Entity* self, Entity* user) { GameMessages::SendTerminateInteraction(user->GetObjectID(), FROM_INTERACTION, self->GetObjectID()); diff --git a/dScripts/ai/AG/AgQbElevator.cpp b/dScripts/ai/AG/AgQbElevator.cpp index ccb4d3b1..f1ac7bb5 100644 --- a/dScripts/ai/AG/AgQbElevator.cpp +++ b/dScripts/ai/AG/AgQbElevator.cpp @@ -15,7 +15,7 @@ void AgQbElevator::OnRebuildComplete(Entity* self, Entity* target) { if (delayTime < 1) delayTime = 1; GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 0, 0, MovementPlatformState::Stationary); + 0, 0, eMovementPlatformState::Stationary); //add a timer that will kill the QB if no players get on in the killTime self->AddTimer("startKillTimer", killTime); @@ -33,7 +33,7 @@ void AgQbElevator::OnProximityUpdate(Entity* self, Entity* entering, std::string self->CancelTimer("StartElevator"); GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); + 1, 1, eMovementPlatformState::Moving); } else if (!self->GetBoolean(u"StartTimer")) { self->SetBoolean(u"StartTimer", true); self->AddTimer("StartElevator", startTime); @@ -45,7 +45,7 @@ void AgQbElevator::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "StartElevator") { GameMessages::SendPlatformResync(self, UNASSIGNED_SYSTEM_ADDRESS, true, 0, - 1, 1, MovementPlatformState::Moving); + 1, 1, eMovementPlatformState::Moving); } else if (timerName == "startKillTimer") { killTimerStartup(self); } else if (timerName == "KillTimer") { diff --git a/dScripts/ai/AG/AgSpaceStuff.cpp b/dScripts/ai/AG/AgSpaceStuff.cpp index 80a87e70..30929ebf 100644 --- a/dScripts/ai/AG/AgSpaceStuff.cpp +++ b/dScripts/ai/AG/AgSpaceStuff.cpp @@ -1,4 +1,5 @@ #include "AgSpaceStuff.h" +#include "EntityInfo.h" #include "GeneralUtils.h" #include "GameMessages.h" #include "EntityManager.h" diff --git a/dScripts/ai/AG/AgStromlingProperty.cpp b/dScripts/ai/AG/AgStromlingProperty.cpp index 36d8d378..9a9ae33b 100644 --- a/dScripts/ai/AG/AgStromlingProperty.cpp +++ b/dScripts/ai/AG/AgStromlingProperty.cpp @@ -1,5 +1,6 @@ #include "AgStromlingProperty.h" #include "MovementAIComponent.h" +#include "eReplicaComponentType.h" void AgStromlingProperty::OnStartup(Entity* self) { auto movementInfo = MovementAIInfo{ @@ -12,5 +13,5 @@ void AgStromlingProperty::OnStartup(Entity* self) { }; auto* movementAIComponent = new MovementAIComponent(self, movementInfo); - self->AddComponent(COMPONENT_TYPE_MOVEMENT_AI, movementAIComponent); + self->AddComponent(eReplicaComponentType::MOVEMENT_AI, movementAIComponent); } diff --git a/dScripts/ai/FV/ActParadoxPipeFix.cpp b/dScripts/ai/FV/ActParadoxPipeFix.cpp index 1dddde64..517474a9 100644 --- a/dScripts/ai/FV/ActParadoxPipeFix.cpp +++ b/dScripts/ai/FV/ActParadoxPipeFix.cpp @@ -3,6 +3,7 @@ #include "RebuildComponent.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eEndBehavior.h" void ActParadoxPipeFix::OnRebuildComplete(Entity* self, Entity* target) { const auto myGroup = "AllPipes"; @@ -42,7 +43,7 @@ void ActParadoxPipeFix::OnRebuildComplete(Entity* self, Entity* target) { missionComponent->ForceProgressTaskType(769, 1, 1, false); } - GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, 0, false, 2.0f); + GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, eEndBehavior::RETURN, false, 2.0f); } object->SetVar(u"PlayerID", LWOOBJID_EMPTY); diff --git a/dScripts/ai/FV/FvFreeGfNinjas.cpp b/dScripts/ai/FV/FvFreeGfNinjas.cpp index 1751b6a7..d690a6f7 100644 --- a/dScripts/ai/FV/FvFreeGfNinjas.cpp +++ b/dScripts/ai/FV/FvFreeGfNinjas.cpp @@ -1,9 +1,10 @@ #include "FvFreeGfNinjas.h" #include "Character.h" #include "MissionComponent.h" +#include "eMissionState.h" -void FvFreeGfNinjas::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { - if (missionID == 705 && missionState == MissionState::MISSION_STATE_AVAILABLE) { +void FvFreeGfNinjas::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID == 705 && missionState == eMissionState::AVAILABLE) { auto* missionComponent = target->GetComponent<MissionComponent>(); if (missionComponent == nullptr) return; @@ -29,7 +30,7 @@ void FvFreeGfNinjas::OnUse(Entity* self, Entity* user) { if (missionComponent == nullptr) return; - if (missionComponent->GetMissionState(705) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(705) == eMissionState::ACTIVE) { auto* character = user->GetCharacter(); if (character != nullptr) character->SetPlayerFlag(68, true); diff --git a/dScripts/ai/FV/FvFreeGfNinjas.h b/dScripts/ai/FV/FvFreeGfNinjas.h index c7e4876e..01b0b6bd 100644 --- a/dScripts/ai/FV/FvFreeGfNinjas.h +++ b/dScripts/ai/FV/FvFreeGfNinjas.h @@ -3,6 +3,6 @@ class FvFreeGfNinjas : public CppScripts::Script { public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; void OnUse(Entity* self, Entity* user) override; }; diff --git a/dScripts/ai/FV/FvNinjaGuard.cpp b/dScripts/ai/FV/FvNinjaGuard.cpp index 6a841ccf..58267999 100644 --- a/dScripts/ai/FV/FvNinjaGuard.cpp +++ b/dScripts/ai/FV/FvNinjaGuard.cpp @@ -19,12 +19,6 @@ void FvNinjaGuard::OnEmoteReceived(Entity* self, const int32_t emote, Entity* ta GameMessages::SendPlayAnimation(self, u"scared"); - auto* missionComponent = target->GetComponent<MissionComponent>(); - - if (missionComponent != nullptr && missionComponent->HasMission(737)) { - missionComponent->ForceProgressTaskType(737, 5, 1, false); - } - if (self->GetLOT() == 7412) { auto* rightGuard = EntityManager::Instance()->GetEntity(m_RightGuard); @@ -39,4 +33,3 @@ void FvNinjaGuard::OnEmoteReceived(Entity* self, const int32_t emote, Entity* ta } } } - diff --git a/dScripts/ai/FV/FvPandaSpawnerServer.cpp b/dScripts/ai/FV/FvPandaSpawnerServer.cpp index e1f3fb96..d7dcabcd 100644 --- a/dScripts/ai/FV/FvPandaSpawnerServer.cpp +++ b/dScripts/ai/FV/FvPandaSpawnerServer.cpp @@ -2,6 +2,7 @@ #include "Character.h" #include "EntityManager.h" #include "GameMessages.h" +#include "EntityInfo.h" #include "ScriptedActivityComponent.h" void FvPandaSpawnerServer::OnCollisionPhantom(Entity* self, Entity* target) { diff --git a/dScripts/ai/GENERAL/LegoDieRoll.cpp b/dScripts/ai/GENERAL/LegoDieRoll.cpp index e86550f9..89819271 100644 --- a/dScripts/ai/GENERAL/LegoDieRoll.cpp +++ b/dScripts/ai/GENERAL/LegoDieRoll.cpp @@ -2,6 +2,7 @@ #include "Entity.h" #include "GameMessages.h" #include "MissionComponent.h" +#include "eMissionState.h" void LegoDieRoll::OnStartup(Entity* self) { self->AddTimer("DoneRolling", 10.0f); @@ -39,7 +40,7 @@ void LegoDieRoll::OnTimerDone(Entity* self, std::string timerName) { if (missionComponent != nullptr) { const auto rollMissionState = missionComponent->GetMissionState(756); - if (rollMissionState == MissionState::MISSION_STATE_ACTIVE) { + if (rollMissionState == eMissionState::ACTIVE) { missionComponent->ForceProgress(756, 1103, 1); } } diff --git a/dScripts/ai/GF/GfBanana.cpp b/dScripts/ai/GF/GfBanana.cpp index 3a71eded..95a831cd 100644 --- a/dScripts/ai/GF/GfBanana.cpp +++ b/dScripts/ai/GF/GfBanana.cpp @@ -2,6 +2,7 @@ #include "Entity.h" #include "DestroyableComponent.h" +#include "EntityInfo.h" #include "EntityManager.h" void GfBanana::SpawnBanana(Entity* self) { diff --git a/dScripts/ai/GF/GfCampfire.cpp b/dScripts/ai/GF/GfCampfire.cpp index 95e29a9a..6a10b39e 100644 --- a/dScripts/ai/GF/GfCampfire.cpp +++ b/dScripts/ai/GF/GfCampfire.cpp @@ -4,13 +4,14 @@ #include "MissionComponent.h" #include "RenderComponent.h" #include "EntityManager.h" +#include "eReplicaComponentType.h" void GfCampfire::OnStartup(Entity* self) { self->SetI32(u"counter", static_cast<int32_t>(0)); self->SetProximityRadius(2.0f, "placeholder"); self->SetBoolean(u"isBurning", true); - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); if (render == nullptr) return; @@ -20,7 +21,7 @@ void GfCampfire::OnStartup(Entity* self) { void GfCampfire::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { if (args == "physicsReady") { - auto* render = static_cast<RenderComponent*>(self->GetComponent(COMPONENT_TYPE_RENDER)); + auto* render = static_cast<RenderComponent*>(self->GetComponent(eReplicaComponentType::RENDER)); render->PlayEffect(295, u"running", "Burn"); } diff --git a/dScripts/ai/GF/GfJailkeepMission.cpp b/dScripts/ai/GF/GfJailkeepMission.cpp index eaa8c73d..b8d4cd30 100644 --- a/dScripts/ai/GF/GfJailkeepMission.cpp +++ b/dScripts/ai/GF/GfJailkeepMission.cpp @@ -1,18 +1,19 @@ #include "GfJailkeepMission.h" #include "MissionComponent.h" #include "Character.h" +#include "eMissionState.h" -void GfJailkeepMission::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void GfJailkeepMission::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { auto* missionComponent = target->GetComponent<MissionComponent>(); if (missionComponent == nullptr) return; - if (missionID == 385 && missionState == MissionState::MISSION_STATE_AVAILABLE) { + if (missionID == 385 && missionState == eMissionState::AVAILABLE) { missionComponent->AcceptMission(386, true); missionComponent->AcceptMission(387, true); missionComponent->AcceptMission(388, true); missionComponent->AcceptMission(390, true); - } else if (missionID == 385 && missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { + } else if (missionID == 385 && missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { auto* character = target->GetCharacter(); if (character != nullptr && character->GetPlayerFlag(68)) { missionComponent->AcceptMission(701); @@ -28,7 +29,7 @@ void GfJailkeepMission::OnUse(Entity* self, Entity* user) { if (missionComponent == nullptr) return; - if (missionComponent->GetMissionState(385) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent->GetMissionState(385) == eMissionState::ACTIVE) { missionComponent->AcceptMission(386, true); missionComponent->AcceptMission(387, true); missionComponent->AcceptMission(388, true); diff --git a/dScripts/ai/GF/GfJailkeepMission.h b/dScripts/ai/GF/GfJailkeepMission.h index a120d29b..651a6e1b 100644 --- a/dScripts/ai/GF/GfJailkeepMission.h +++ b/dScripts/ai/GF/GfJailkeepMission.h @@ -5,5 +5,5 @@ class GfJailkeepMission final : public CppScripts::Script { public: void OnUse(Entity* self, Entity* user) override; - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; }; diff --git a/dScripts/ai/GF/PetDigBuild.cpp b/dScripts/ai/GF/PetDigBuild.cpp index ae159575..2c3da9fc 100644 --- a/dScripts/ai/GF/PetDigBuild.cpp +++ b/dScripts/ai/GF/PetDigBuild.cpp @@ -1,6 +1,8 @@ #include "PetDigBuild.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "MissionComponent.h" +#include "eMissionState.h" void PetDigBuild::OnRebuildComplete(Entity* self, Entity* target) { auto flagNumber = self->GetVar<std::u16string>(u"flagNum"); @@ -21,7 +23,7 @@ void PetDigBuild::OnRebuildComplete(Entity* self, Entity* target) { info.settings.push_back(new LDFData<std::u16string>(u"groupID", u"Flag" + flagNumber)); } else { auto* missionComponent = target->GetComponent<MissionComponent>(); - if (missionComponent != nullptr && missionComponent->GetMissionState(746) == MissionState::MISSION_STATE_ACTIVE) { + if (missionComponent != nullptr && missionComponent->GetMissionState(746) == eMissionState::ACTIVE) { info.lot = 9307; // Special Captain Jack treasure that drops a mission item } else { info.lot = 3495; // Normal AG treasure diff --git a/dScripts/ai/GF/PirateRep.cpp b/dScripts/ai/GF/PirateRep.cpp index eb4cf510..ccfa7af6 100644 --- a/dScripts/ai/GF/PirateRep.cpp +++ b/dScripts/ai/GF/PirateRep.cpp @@ -1,8 +1,10 @@ #include "PirateRep.h" #include "Character.h" +#include "eMissionState.h" +#include "Entity.h" -void PirateRep::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { - if (missionID == m_PirateRepMissionID && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) { +void PirateRep::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID == m_PirateRepMissionID && missionState >= eMissionState::READY_TO_COMPLETE) { auto* character = target->GetCharacter(); if (character) { character->SetPlayerFlag(ePlayerFlags::GF_PIRATE_REP, true); diff --git a/dScripts/ai/GF/PirateRep.h b/dScripts/ai/GF/PirateRep.h index 8fc82c5e..754971be 100644 --- a/dScripts/ai/GF/PirateRep.h +++ b/dScripts/ai/GF/PirateRep.h @@ -3,7 +3,7 @@ class PirateRep : public CppScripts::Script { public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; private: const int m_PirateRepMissionID = 301; }; diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index 9eb32002..ad94b2eb 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -11,6 +11,10 @@ #include "MovementAIComponent.h" #include "../dWorldServer/ObjectIDManager.h" #include "MissionComponent.h" +#include "Loot.h" +#include "InventoryComponent.h" +#include "eMissionTaskType.h" +#include "eReplicaComponentType.h" void SGCannon::OnStartup(Entity* self) { Game::logger->Log("SGCannon", "OnStartup"); @@ -75,7 +79,7 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable)); if (player != nullptr) { Game::logger->Log("SGCannon", "Player is ready"); - /*GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, + /*GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true);*/ Game::logger->Log("SGCannon", "Sending ActivityEnter"); @@ -290,7 +294,6 @@ void SGCannon::OnActivityTimerDone(Entity* self, const std::string& name) { if (enemy) { EntityManager::Instance()->ConstructEntity(enemy); auto* movementAI = enemy->GetComponent<MovementAIComponent>(); - if (!movementAI) return; movementAI->SetSpeed(toSpawn.initialSpeed); @@ -541,9 +544,9 @@ void SGCannon::StopGame(Entity* self, bool cancel) { auto* missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, self->GetVar<uint32_t>(TotalScoreVariable), self->GetObjectID(), "performact_score"); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MINIGAME, self->GetVar<uint32_t>(MaxStreakVariable), self->GetObjectID(), "performact_streak"); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ACTIVITY, m_CannonLot, 0, "", self->GetVar<uint32_t>(TotalScoreVariable)); + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, self->GetVar<uint32_t>(TotalScoreVariable), self->GetObjectID(), "performact_score"); + missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, self->GetVar<uint32_t>(MaxStreakVariable), self->GetObjectID(), "performact_streak"); + missionComponent->Progress(eMissionTaskType::ACTIVITY, m_CannonLot, 0, "", self->GetVar<uint32_t>(TotalScoreVariable)); } LootGenerator::Instance().GiveActivityLoot(player, self, GetGameID(self), self->GetVar<uint32_t>(TotalScoreVariable)); @@ -653,7 +656,7 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time auto missionComponent = player->GetComponent<MissionComponent>(); if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SMASH, spawnInfo.lot, self->GetObjectID()); + missionComponent->Progress(eMissionTaskType::SMASH, spawnInfo.lot, self->GetObjectID()); } void SGCannon::UpdateStreak(Entity* self) { @@ -711,7 +714,7 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { Game::logger->Log("SGCannon", "Player has %d equipped items", equippedItems.size()); auto skillID = constants.cannonSkill; - auto coolDown = constants.cannonRefireRate; + auto cooldown = constants.cannonRefireRate; auto* selfInventoryComponent = self->GetComponent<InventoryComponent>(); @@ -727,7 +730,7 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { // TODO: Equip items skillID = constants.cannonSuperChargeSkill; - coolDown = 400; + cooldown = 400; } else { selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 }); @@ -750,7 +753,7 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { } } } - + cooldown = 800; self->SetVar<uint32_t>(NumberOfChargesVariable, 0); } @@ -766,7 +769,7 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) { properties.cannonFOV = 58.6f; properties.cannonVelocity = 129.0; - properties.cannonRefireRate = 800; + properties.cannonRefireRate = cooldown; properties.cannonMinDistance = 30; properties.cannonTimeout = -1; diff --git a/dScripts/ai/NP/NpcNpSpacemanBob.cpp b/dScripts/ai/NP/NpcNpSpacemanBob.cpp index 5157e488..2195f4b4 100644 --- a/dScripts/ai/NP/NpcNpSpacemanBob.cpp +++ b/dScripts/ai/NP/NpcNpSpacemanBob.cpp @@ -1,12 +1,14 @@ #include "NpcNpSpacemanBob.h" #include "DestroyableComponent.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" -void NpcNpSpacemanBob::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { - if (missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE && missionID == 173) { - DestroyableComponent* destroyable = static_cast<DestroyableComponent*>(target->GetComponent(COMPONENT_TYPE_DESTROYABLE)); +void NpcNpSpacemanBob::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionState == eMissionState::READY_TO_COMPLETE && missionID == 173) { + DestroyableComponent* destroyable = static_cast<DestroyableComponent*>(target->GetComponent(eReplicaComponentType::DESTROYABLE)); destroyable->SetImagination(6); - MissionComponent* mission = static_cast<MissionComponent*>(target->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* mission = static_cast<MissionComponent*>(target->GetComponent(eReplicaComponentType::MISSION)); mission->CompleteMission(664); } diff --git a/dScripts/ai/NP/NpcNpSpacemanBob.h b/dScripts/ai/NP/NpcNpSpacemanBob.h index 08cc850d..84c59deb 100644 --- a/dScripts/ai/NP/NpcNpSpacemanBob.h +++ b/dScripts/ai/NP/NpcNpSpacemanBob.h @@ -4,6 +4,6 @@ class NpcNpSpacemanBob : public CppScripts::Script { public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState); + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState); }; diff --git a/dScripts/ai/NS/NsConcertInstrument.cpp b/dScripts/ai/NS/NsConcertInstrument.cpp index 508b7b5b..c7478a05 100644 --- a/dScripts/ai/NS/NsConcertInstrument.cpp +++ b/dScripts/ai/NS/NsConcertInstrument.cpp @@ -5,7 +5,10 @@ #include "EntityManager.h" #include "RebuildComponent.h" #include "SoundTriggerComponent.h" +#include "InventoryComponent.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eMissionTaskType.h" // Constants are at the bottom @@ -145,8 +148,8 @@ void NsConcertInstrument::StopPlayingInstrument(Entity* self, Entity* player) { // Player might be null if they left if (player != nullptr) { auto* missions = player->GetComponent<MissionComponent>(); - if (missions != nullptr && missions->GetMissionState(176) == MissionState::MISSION_STATE_ACTIVE) { - missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, self->GetLOT()); + if (missions != nullptr && missions->GetMissionState(176) == eMissionState::ACTIVE) { + missions->Progress(eMissionTaskType::SCRIPT, self->GetLOT()); } GameMessages::SendEndCinematic(player->GetObjectID(), cinematics.at(instrumentLot), UNASSIGNED_SYSTEM_ADDRESS, 1.0f); diff --git a/dScripts/ai/NS/NsGetFactionMissionServer.cpp b/dScripts/ai/NS/NsGetFactionMissionServer.cpp index d759e3ad..cfecb249 100644 --- a/dScripts/ai/NS/NsGetFactionMissionServer.cpp +++ b/dScripts/ai/NS/NsGetFactionMissionServer.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "MissionComponent.h" #include "Character.h" +#include "eReplicaComponentType.h" void NsGetFactionMissionServer::OnRespondToMission(Entity* self, int missionID, Entity* player, int reward) { if (missionID != 474) return; @@ -44,7 +45,7 @@ void NsGetFactionMissionServer::OnRespondToMission(Entity* self, int missionID, player->GetCharacter()->SetPlayerFlag(flagID, true); } - MissionComponent* mis = static_cast<MissionComponent*>(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* mis = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION)); for (int mission : factionMissions) { mis->AcceptMission(mission); diff --git a/dScripts/ai/NS/NsJohnnyMissionServer.cpp b/dScripts/ai/NS/NsJohnnyMissionServer.cpp index 2d9ae93c..107d3c44 100644 --- a/dScripts/ai/NS/NsJohnnyMissionServer.cpp +++ b/dScripts/ai/NS/NsJohnnyMissionServer.cpp @@ -1,8 +1,9 @@ #include "NsJohnnyMissionServer.h" #include "MissionComponent.h" +#include "eMissionState.h" -void NsJohnnyMissionServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { - if (missionID == 773 && missionState <= MissionState::MISSION_STATE_ACTIVE) { +void NsJohnnyMissionServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { + if (missionID == 773 && missionState <= eMissionState::ACTIVE) { auto* missionComponent = target->GetComponent<MissionComponent>(); if (missionComponent != nullptr) { missionComponent->AcceptMission(774); diff --git a/dScripts/ai/NS/NsJohnnyMissionServer.h b/dScripts/ai/NS/NsJohnnyMissionServer.h index 8de39afa..c37ea06c 100644 --- a/dScripts/ai/NS/NsJohnnyMissionServer.h +++ b/dScripts/ai/NS/NsJohnnyMissionServer.h @@ -2,5 +2,5 @@ #include "CppScripts.h" class NsJohnnyMissionServer : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; }; diff --git a/dScripts/ai/NS/NsModularBuild.cpp b/dScripts/ai/NS/NsModularBuild.cpp index 065d061e..1922eb17 100644 --- a/dScripts/ai/NS/NsModularBuild.cpp +++ b/dScripts/ai/NS/NsModularBuild.cpp @@ -1,11 +1,13 @@ #include "NsModularBuild.h" #include "MissionComponent.h" +#include "eMissionState.h" +#include "eReplicaComponentType.h" void NsModularBuild::OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector<LOT> modules) { if (bCompleted) { - MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(COMPONENT_TYPE_MISSION)); + MissionComponent* mission = static_cast<MissionComponent*>(player->GetComponent(eReplicaComponentType::MISSION)); - if (mission->GetMissionState(m_MissionNum) == MissionState::MISSION_STATE_ACTIVE) { + if (mission->GetMissionState(m_MissionNum) == eMissionState::ACTIVE) { for (LOT mod : modules) { if (mod == 9516 || mod == 9517 || mod == 9518) { mission->ForceProgress(m_MissionNum, 1178, 1); diff --git a/dScripts/ai/NS/WH/RockHydrantSmashable.cpp b/dScripts/ai/NS/WH/RockHydrantSmashable.cpp index d76eca8d..b3a01567 100644 --- a/dScripts/ai/NS/WH/RockHydrantSmashable.cpp +++ b/dScripts/ai/NS/WH/RockHydrantSmashable.cpp @@ -1,5 +1,6 @@ #include "RockHydrantSmashable.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "GeneralUtils.h" void RockHydrantSmashable::OnDie(Entity* self, Entity* killer) { diff --git a/dScripts/ai/PETS/HydrantSmashable.cpp b/dScripts/ai/PETS/HydrantSmashable.cpp index 20baa58b..1ff082ea 100644 --- a/dScripts/ai/PETS/HydrantSmashable.cpp +++ b/dScripts/ai/PETS/HydrantSmashable.cpp @@ -1,5 +1,6 @@ #include "HydrantSmashable.h" #include "EntityManager.h" +#include "EntityInfo.h" #include "GeneralUtils.h" void HydrantSmashable::OnDie(Entity* self, Entity* killer) { diff --git a/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp b/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp index 51f76a27..853da92d 100644 --- a/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp +++ b/dScripts/ai/PROPERTY/AG/AgPropGuard.cpp @@ -5,18 +5,19 @@ #include "InventoryComponent.h" #include "MissionComponent.h" #include "Item.h" +#include "eMissionState.h" -void AgPropGuard::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void AgPropGuard::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { auto* character = target->GetCharacter(); auto* missionComponent = target->GetComponent<MissionComponent>(); auto* inventoryComponent = target->GetComponent<InventoryComponent>(); const auto state = missionComponent->GetMissionState(320); - if (missionID == 768 && missionState == MissionState::MISSION_STATE_AVAILABLE) { + if (missionID == 768 && missionState == eMissionState::AVAILABLE) { if (!character->GetPlayerFlag(71)) { // TODO: Cinematic "MissionCam" } - } else if (missionID == 768 && missionState >= MissionState::MISSION_STATE_READY_TO_COMPLETE) { + } else if (missionID == 768 && missionState >= eMissionState::READY_TO_COMPLETE) { //remove the inventory items for (int item : gearSets) { auto* id = inventoryComponent->FindItemByLot(item); @@ -27,8 +28,8 @@ void AgPropGuard::OnMissionDialogueOK(Entity* self, Entity* target, int missionI } } } else if ( - (missionID == 320 && state == MissionState::MISSION_STATE_AVAILABLE) /*|| - (state == MissionState::MISSION_STATE_COMPLETE && missionID == 891 && missionState == MissionState::MISSION_STATE_READY_TO_COMPLETE)*/ + (missionID == 320 && state == eMissionState::AVAILABLE) /*|| + (state == eMissionState::COMPLETE && missionID == 891 && missionState == eMissionState::READY_TO_COMPLETE)*/ ) { //GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), u"GuardChat", target->GetObjectID(), 0, target->GetObjectID(), "", target->GetSystemAddress()); diff --git a/dScripts/ai/PROPERTY/AG/AgPropGuard.h b/dScripts/ai/PROPERTY/AG/AgPropGuard.h index f68573dd..2b41f006 100644 --- a/dScripts/ai/PROPERTY/AG/AgPropGuard.h +++ b/dScripts/ai/PROPERTY/AG/AgPropGuard.h @@ -4,7 +4,7 @@ class AgPropGuard final : public CppScripts::Script { public: - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; private: std::vector<int> gearSets = { 14359,14321,14353,14315 }; diff --git a/dScripts/ai/PROPERTY/AgPropguards.cpp b/dScripts/ai/PROPERTY/AgPropguards.cpp index 674c4bdd..9fc6010a 100644 --- a/dScripts/ai/PROPERTY/AgPropguards.cpp +++ b/dScripts/ai/PROPERTY/AgPropguards.cpp @@ -3,8 +3,9 @@ #include "GameMessages.h" #include "EntityManager.h" #include "dZoneManager.h" +#include "eMissionState.h" -void AgPropguards::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { +void AgPropguards::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) { auto* character = target->GetCharacter(); if (character == nullptr) return; @@ -13,11 +14,11 @@ void AgPropguards::OnMissionDialogueOK(Entity* self, Entity* target, int mission if (flag == 0) return; - if ((missionState == MissionState::MISSION_STATE_AVAILABLE || missionState == MissionState::MISSION_STATE_ACTIVE) + if ((missionState == eMissionState::AVAILABLE || missionState == eMissionState::ACTIVE) && !character->GetPlayerFlag(flag)) { // If the player just started the mission, play a cinematic highlighting the target GameMessages::SendPlayCinematic(target->GetObjectID(), u"MissionCam", target->GetSystemAddress()); - } else if (missionState == MissionState::MISSION_STATE_COMPLETE_READY_TO_COMPLETE) { + } else if (missionState == eMissionState::COMPLETE_READY_TO_COMPLETE) { // Makes the guard disappear once the mission has been completed const auto zoneControlID = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); GameMessages::SendNotifyClientObject(zoneControlID, u"GuardChat", 0, 0, self->GetObjectID(), diff --git a/dScripts/ai/PROPERTY/AgPropguards.h b/dScripts/ai/PROPERTY/AgPropguards.h index 511b7b6a..25701f86 100644 --- a/dScripts/ai/PROPERTY/AgPropguards.h +++ b/dScripts/ai/PROPERTY/AgPropguards.h @@ -2,7 +2,7 @@ #include "CppScripts.h" class AgPropguards : public CppScripts::Script { - void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override; + void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, eMissionState missionState) override; private: static uint32_t GetFlagForMission(uint32_t missionID); }; diff --git a/dScripts/ai/PROPERTY/PropertyFXDamage.cpp b/dScripts/ai/PROPERTY/PropertyFXDamage.cpp index d12cc9e1..56079384 100644 --- a/dScripts/ai/PROPERTY/PropertyFXDamage.cpp +++ b/dScripts/ai/PROPERTY/PropertyFXDamage.cpp @@ -12,7 +12,7 @@ void PropertyFXDamage::OnCollisionPhantom(Entity* self, Entity* target) { if (skills != nullptr && targetStats != nullptr) { auto targetFactions = targetStats->GetFactionIDs(); if (std::find(targetFactions.begin(), targetFactions.end(), 1) != targetFactions.end()) { - skills->CalculateBehavior(11386, 692, target->GetObjectID()); + skills->CalculateBehavior(692, 11386, target->GetObjectID()); } } } diff --git a/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.cpp b/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.cpp index 32dbf619..f69a3eb6 100644 --- a/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.cpp +++ b/dScripts/ai/RACING/OBJECTS/FvRaceSmashEggImagineServer.cpp @@ -3,8 +3,9 @@ #include "DestroyableComponent.h" #include "EntityManager.h" #include "PossessableComponent.h" -#include "RacingTaskParam.h" +#include "eRacingTaskParam.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" void FvRaceSmashEggImagineServer::OnDie(Entity* self, Entity* killer) { if (killer != nullptr) { @@ -29,8 +30,8 @@ void FvRaceSmashEggImagineServer::OnDie(Entity* self, Entity* killer) { } if (missionComponent == nullptr) return; // Dragon eggs have their own smash server so we handle mission progression for them here. - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASHABLES); - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, self->GetLOT(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASH_SPECIFIC_SMASHABLE); + missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::SMASHABLES); + missionComponent->Progress(eMissionTaskType::RACING, self->GetLOT(), (LWOOBJID)eRacingTaskParam::SMASH_SPECIFIC_SMASHABLE); } } diff --git a/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.cpp b/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.cpp index a35007b4..6a29f9a8 100644 --- a/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.cpp +++ b/dScripts/ai/RACING/OBJECTS/RaceImagineCrateServer.cpp @@ -3,9 +3,10 @@ #include "EntityManager.h" #include "PossessableComponent.h" #include "RaceImagineCrateServer.h" -#include "RacingTaskParam.h" +#include "eRacingTaskParam.h" #include "MissionComponent.h" #include "SkillComponent.h" +#include "eMissionTaskType.h" void RaceImagineCrateServer::OnDie(Entity* self, Entity* killer) { if (self->GetVar<bool>(u"bIsDead")) { @@ -49,7 +50,7 @@ void RaceImagineCrateServer::OnDie(Entity* self, Entity* killer) { // Progress racing smashable missions if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASHABLES); + missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::SMASHABLES); } } } diff --git a/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.cpp b/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.cpp index 9bdd0813..92a50873 100644 --- a/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.cpp +++ b/dScripts/ai/RACING/OBJECTS/RaceImaginePowerup.cpp @@ -2,8 +2,9 @@ #include "EntityManager.h" #include "PossessorComponent.h" #include "RaceImaginePowerup.h" -#include "RacingTaskParam.h" +#include "eRacingTaskParam.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" void RaceImaginePowerup::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { @@ -31,6 +32,6 @@ void RaceImaginePowerup::OnFireEventServerSide(Entity* self, Entity* sender, std auto* missionComponent = sender->GetComponent<MissionComponent>(); if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, self->GetLOT(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_COLLECT_IMAGINATION); + missionComponent->Progress(eMissionTaskType::RACING, self->GetLOT(), (LWOOBJID)eRacingTaskParam::COLLECT_IMAGINATION); } } diff --git a/dScripts/ai/RACING/OBJECTS/RaceSmashServer.cpp b/dScripts/ai/RACING/OBJECTS/RaceSmashServer.cpp index d0dc3d78..295f38ee 100644 --- a/dScripts/ai/RACING/OBJECTS/RaceSmashServer.cpp +++ b/dScripts/ai/RACING/OBJECTS/RaceSmashServer.cpp @@ -2,8 +2,9 @@ #include "EntityManager.h" #include "PossessableComponent.h" #include "RaceSmashServer.h" -#include "RacingTaskParam.h" +#include "eRacingTaskParam.h" #include "MissionComponent.h" +#include "eMissionTaskType.h" void RaceSmashServer::OnDie(Entity* self, Entity* killer) { // Crate is smashed by the car @@ -22,9 +23,9 @@ void RaceSmashServer::OnDie(Entity* self, Entity* killer) { // Progress racing smashable missions if (missionComponent == nullptr) return; - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, 0, (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASHABLES); + missionComponent->Progress(eMissionTaskType::RACING, 0, (LWOOBJID)eRacingTaskParam::SMASHABLES); // Progress missions that ask us to smash a specific smashable. - missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_RACING, self->GetLOT(), (LWOOBJID)RacingTaskParam::RACING_TASK_PARAM_SMASH_SPECIFIC_SMASHABLE); + missionComponent->Progress(eMissionTaskType::RACING, self->GetLOT(), (LWOOBJID)eRacingTaskParam::SMASH_SPECIFIC_SMASHABLE); } } } diff --git a/dScripts/ai/SPEC/SpecialImaginePowerupSpawner.cpp b/dScripts/ai/SPEC/SpecialImaginePowerupSpawner.cpp index c6cab294..43ae9e89 100644 --- a/dScripts/ai/SPEC/SpecialImaginePowerupSpawner.cpp +++ b/dScripts/ai/SPEC/SpecialImaginePowerupSpawner.cpp @@ -4,6 +4,7 @@ #include "SkillComponent.h" #include "DestroyableComponent.h" #include "EntityManager.h" +#include "eReplicaComponentType.h" void SpecialImaginePowerupSpawner::OnStartup(Entity* self) { self->SetProximityRadius(1.5f, "powerupEnter"); @@ -26,7 +27,7 @@ void SpecialImaginePowerupSpawner::OnProximityUpdate(Entity* self, Entity* enter GameMessages::SendPlayFXEffect(self, -1, u"pickup", "", LWOOBJID_EMPTY, 1, 1, true); SkillComponent* skillComponent; - if (!self->TryGetComponent(COMPONENT_TYPE_SKILL, skillComponent)) { + if (!self->TryGetComponent(eReplicaComponentType::SKILL, skillComponent)) { return; } @@ -35,7 +36,7 @@ void SpecialImaginePowerupSpawner::OnProximityUpdate(Entity* self, Entity* enter skillComponent->CalculateBehavior(13, 20, source); DestroyableComponent* destroyableComponent; - if (!self->TryGetComponent(COMPONENT_TYPE_DESTROYABLE, destroyableComponent)) { + if (!self->TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) { return; } diff --git a/dScripts/ai/WILD/CMakeLists.txt b/dScripts/ai/WILD/CMakeLists.txt index 57470f72..d3e499db 100644 --- a/dScripts/ai/WILD/CMakeLists.txt +++ b/dScripts/ai/WILD/CMakeLists.txt @@ -1,4 +1,8 @@ -set(DSCRIPTS_SOURCES_AI_WILD +set(DSCRIPTS_SOURCES_AI_WILD "AllCrateChicken.cpp" "WildAmbients.cpp" + "WildAmbientCrab.cpp" + "WildAndScared.cpp" + "WildGfGlowbug.cpp" + "WildPants.cpp" PARENT_SCOPE) diff --git a/dScripts/ai/WILD/WildAmbientCrab.cpp b/dScripts/ai/WILD/WildAmbientCrab.cpp new file mode 100644 index 00000000..7b5b3d45 --- /dev/null +++ b/dScripts/ai/WILD/WildAmbientCrab.cpp @@ -0,0 +1,27 @@ +#include "WildAmbientCrab.h" +#include "GameMessages.h" + +void WildAmbientCrab::OnStartup(Entity* self){ + self->SetVar(u"flipped", true); + GameMessages::SendPlayAnimation(self, u"idle"); +} + +void WildAmbientCrab::OnUse(Entity* self, Entity* user) { + auto flipped = self->GetVar<bool>(u"flipped"); + if (flipped) { + self->AddTimer("Flipping", 0.6f); + GameMessages::SendPlayAnimation(self, u"flip-over"); + self->SetVar(u"flipped", false); + } else if (!flipped) { + self->AddTimer("Flipback", 0.8f); + GameMessages::SendPlayAnimation(self, u"flip-back"); + self->SetVar(u"flipped", true); + } +} + +void WildAmbientCrab::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "Flipping") GameMessages::SendPlayAnimation(self, u"over-idle"); + else if (timerName == "Flipback") GameMessages::SendPlayAnimation(self, u"idle"); +} + + diff --git a/dScripts/ai/WILD/WildAmbientCrab.h b/dScripts/ai/WILD/WildAmbientCrab.h new file mode 100644 index 00000000..0e1b3877 --- /dev/null +++ b/dScripts/ai/WILD/WildAmbientCrab.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildAmbientCrab final : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnUse(Entity* self, Entity* user) override; +}; diff --git a/dScripts/ai/WILD/WildAndScared.cpp b/dScripts/ai/WILD/WildAndScared.cpp new file mode 100644 index 00000000..d2e89c40 --- /dev/null +++ b/dScripts/ai/WILD/WildAndScared.cpp @@ -0,0 +1,6 @@ +#include "WildAndScared.h" +#include "GameMessages.h" + +void WildAndScared::OnUse(Entity* self, Entity* user) { + GameMessages::SendPlayAnimation(self, u"scared"); +} diff --git a/dScripts/ai/WILD/WildAndScared.h b/dScripts/ai/WILD/WildAndScared.h new file mode 100644 index 00000000..c94fb06d --- /dev/null +++ b/dScripts/ai/WILD/WildAndScared.h @@ -0,0 +1,7 @@ +#pragma once +#include "CppScripts.h" + +class WildAndScared : public CppScripts::Script { +public: + void OnUse(Entity* self, Entity* user) override; +}; diff --git a/dScripts/ai/WILD/WildGfGlowbug.cpp b/dScripts/ai/WILD/WildGfGlowbug.cpp new file mode 100644 index 00000000..d834f5b5 --- /dev/null +++ b/dScripts/ai/WILD/WildGfGlowbug.cpp @@ -0,0 +1,28 @@ +#include "WildGfGlowbug.h" +#include "GameMessages.h" + +void WildGfGlowbug::OnStartup(Entity* self){ + self->SetVar(u"switch", false); +} + +void WildGfGlowbug::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args == "physicsReady") { + auto switchState = self->GetVar<bool>(u"switch"); + if (!switchState) { + GameMessages::SendStopFXEffect(self, true, "glowlight"); + } else if (switchState) { + GameMessages::SendPlayFXEffect(self, -1, u"light", "glowlight", LWOOBJID_EMPTY); + } + } +} + +void WildGfGlowbug::OnUse(Entity* self, Entity* user) { + auto switchState = self->GetVar<bool>(u"switch"); + if (switchState) { + GameMessages::SendStopFXEffect(self, true, "glowlight"); + self->SetVar(u"switch", false); + } else if (!switchState) { + GameMessages::SendPlayFXEffect(self, -1, u"light", "glowlight", LWOOBJID_EMPTY); + self->SetVar(u"switch", true); + } +} diff --git a/dScripts/ai/WILD/WildGfGlowbug.h b/dScripts/ai/WILD/WildGfGlowbug.h new file mode 100644 index 00000000..03242372 --- /dev/null +++ b/dScripts/ai/WILD/WildGfGlowbug.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildGfGlowbug : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; + void OnUse(Entity* self, Entity* user) override; +}; diff --git a/dScripts/ai/WILD/WildPants.cpp b/dScripts/ai/WILD/WildPants.cpp new file mode 100644 index 00000000..7c5e1cd2 --- /dev/null +++ b/dScripts/ai/WILD/WildPants.cpp @@ -0,0 +1,10 @@ +#include "WildPants.h" +#include "GameMessages.h" + +void WildPants::OnStartup(Entity* self) { + self->SetProximityRadius(5, "scardyPants"); +} + +void WildPants::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (status == "ENTER") GameMessages::SendPlayAnimation(self, u"scared"); +} diff --git a/dScripts/ai/WILD/WildPants.h b/dScripts/ai/WILD/WildPants.h new file mode 100644 index 00000000..c6968045 --- /dev/null +++ b/dScripts/ai/WILD/WildPants.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildPants : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; +}; diff --git a/dWorldServer/CMakeLists.txt b/dWorldServer/CMakeLists.txt index fcf29838..c616da87 100644 --- a/dWorldServer/CMakeLists.txt +++ b/dWorldServer/CMakeLists.txt @@ -1,6 +1,11 @@ -set(DWORLDSERVER_SOURCES "ObjectIDManager.cpp" - "PerformanceManager.cpp" - "WorldServer.cpp") +set(DWORLDSERVER_SOURCES + "ObjectIDManager.cpp" + "PerformanceManager.cpp" +) + +add_library(dWorldServer ${DWORLDSERVER_SOURCES}) +add_executable(WorldServer "WorldServer.cpp") + +target_link_libraries(dWorldServer ${COMMON_LIBRARIES}) +target_link_libraries(WorldServer ${COMMON_LIBRARIES} dChatFilter dGame dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dNavigation) -add_executable(WorldServer ${DWORLDSERVER_SOURCES}) -target_link_libraries(WorldServer ${COMMON_LIBRARIES} dChatFilter dGame dZoneManager Detour Recast dPhysics tinyxml2 dNavigation) diff --git a/dWorldServer/PerformanceManager.cpp b/dWorldServer/PerformanceManager.cpp index 85546f28..19f38d00 100644 --- a/dWorldServer/PerformanceManager.cpp +++ b/dWorldServer/PerformanceManager.cpp @@ -2,23 +2,18 @@ #include "UserManager.h" -//Times are 1 / fps, in ms -#define HIGH 16 //60 fps -#define MEDIUM 33 //30 fps -#define LOW 66 //15 fps - -#define SOCIAL { LOW } -#define SOCIAL_HUB { MEDIUM } //Added to compensate for the large playercounts in NS and NT -#define BATTLE { HIGH } -#define BATTLE_INSTANCE { MEDIUM } -#define RACE { HIGH } -#define PROPERTY { LOW } +#define SOCIAL { lowFrameDelta } +#define SOCIAL_HUB { mediumFrameDelta } //Added to compensate for the large playercounts in NS and NT +#define BATTLE { highFrameDelta } +#define BATTLE_INSTANCE { mediumFrameDelta } +#define RACE { highFrameDelta } +#define PROPERTY { lowFrameDelta } PerformanceProfile PerformanceManager::m_CurrentProfile = SOCIAL; PerformanceProfile PerformanceManager::m_DefaultProfile = SOCIAL; -PerformanceProfile PerformanceManager::m_InactiveProfile = { LOW }; +PerformanceProfile PerformanceManager::m_InactiveProfile = { lowFrameDelta }; std::map<LWOMAPID, PerformanceProfile> PerformanceManager::m_Profiles = { // VE @@ -72,13 +67,6 @@ std::map<LWOMAPID, PerformanceProfile> PerformanceManager::m_Profiles = { { 2001, BATTLE_INSTANCE }, }; - -PerformanceManager::PerformanceManager() { -} - -PerformanceManager::~PerformanceManager() { -} - void PerformanceManager::SelectProfile(LWOMAPID mapID) { const auto pair = m_Profiles.find(mapID); @@ -91,10 +79,10 @@ void PerformanceManager::SelectProfile(LWOMAPID mapID) { m_CurrentProfile = pair->second; } -uint32_t PerformanceManager::GetServerFramerate() { +uint32_t PerformanceManager::GetServerFrameDelta() { if (UserManager::Instance()->GetUserCount() == 0) { - return m_InactiveProfile.serverFramerate; + return m_InactiveProfile.serverFrameDelta; } - return m_CurrentProfile.serverFramerate; + return m_CurrentProfile.serverFrameDelta; } diff --git a/dWorldServer/PerformanceManager.h b/dWorldServer/PerformanceManager.h index b8a090e0..c584d4ac 100644 --- a/dWorldServer/PerformanceManager.h +++ b/dWorldServer/PerformanceManager.h @@ -5,21 +5,16 @@ #include "dCommonVars.h" struct PerformanceProfile { - uint32_t serverFramerate; + uint32_t serverFrameDelta; }; - class PerformanceManager { public: - ~PerformanceManager(); - static void SelectProfile(LWOMAPID mapID); - static uint32_t GetServerFramerate(); + static uint32_t GetServerFrameDelta(); private: - PerformanceManager(); - static PerformanceProfile m_CurrentProfile; static PerformanceProfile m_DefaultProfile; static PerformanceProfile m_InactiveProfile; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index d4e55cb5..8a603878 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -17,6 +17,7 @@ #include "Metrics.hpp" #include "PerformanceManager.h" #include "Diagnostics.h" +#include "BinaryPathFinder.h" //RakNet includes: #include "RakNetDefines.h" @@ -41,13 +42,15 @@ #include "CharacterComponent.h" #include "EntityManager.h" +#include "EntityInfo.h" +#include "User.h" +#include "Loot.h" #include "Entity.h" #include "Character.h" #include "ChatPackets.h" #include "GameMessageHandler.h" #include "GameMessages.h" #include "Mail.h" -#include "dLocale.h" #include "TeamManager.h" #include "SkillComponent.h" #include "DestroyableComponent.h" @@ -56,35 +59,36 @@ #include "Player.h" #include "PropertyManagementComponent.h" #include "AssetManager.h" +#include "LevelProgressionComponent.h" +#include "eBlueprintSaveResponseType.h" +#include "AMFFormat.h" +#include "NiPoint3.h" +#include "eServerDisconnectIdentifiers.h" #include "ZCompression.h" namespace Game { - dLogger* logger; - dServer* server; - dZoneManager* zoneManager; - dpWorld* physicsWorld; - dChatFilter* chatFilter; - dConfig* config; - dLocale* locale; + dLogger* logger = nullptr; + dServer* server = nullptr; + dpWorld* physicsWorld = nullptr; + dChatFilter* chatFilter = nullptr; + dConfig* config = nullptr; + AssetManager* assetManager = nullptr; + RakPeerInterface* chatServer = nullptr; std::mt19937 randomEngine; - - AssetManager* assetManager; - - RakPeerInterface* chatServer; SystemAddress chatSysAddr; -} + bool shouldShutdown = false; +} // namespace Game bool chatDisabled = false; bool chatConnected = false; -bool worldShutdownSequenceStarted = false; bool worldShutdownSequenceComplete = false; void WorldShutdownSequence(); void WorldShutdownProcess(uint32_t zoneId); void FinalizeShutdown(); void SendShutdownMessageToMaster(); -dLogger* SetupLogger(int zoneID, int instanceID); +dLogger* SetupLogger(uint32_t zoneID, uint32_t instanceID); void HandlePacketChat(Packet* packet); void HandlePacket(Packet* packet); @@ -94,8 +98,8 @@ struct tempSessionInfo { }; std::map<std::string, tempSessionInfo> m_PendingUsers; -int instanceID = 0; -int g_CloneID = 0; +uint32_t instanceID = 0; +uint32_t g_CloneID = 0; std::string databaseChecksum = ""; int main(int argc, char** argv) { @@ -109,13 +113,13 @@ int main(int argc, char** argv) { signal(SIGINT, [](int) { WorldShutdownSequence(); }); signal(SIGTERM, [](int) { WorldShutdownSequence(); }); - int zoneID = 1000; - int cloneID = 0; - int maxClients = 8; - int ourPort = 2007; + uint32_t zoneID = 1000; + uint32_t cloneID = 0; + uint32_t maxClients = 8; + uint32_t ourPort = 2007; //Check our arguments: - for (int i = 0; i < argc; ++i) { + for (int32_t i = 0; i < argc; ++i) { std::string argument(argv[i]); if (argument == "-zone") zoneID = atoi(argv[i + 1]); @@ -127,28 +131,27 @@ int main(int argc, char** argv) { //Create all the objects we need to run our service: Game::logger = SetupLogger(zoneID, instanceID); - if (!Game::logger) return 0; + if (!Game::logger) return EXIT_FAILURE; + + //Read our config: + Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "worldconfig.ini").string()); + Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0"); + Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1"); - Game::logger->SetLogToConsole(true); //We want this info to always be logged. Game::logger->Log("WorldServer", "Starting World server..."); Game::logger->Log("WorldServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("WorldServer", "Compiled on: %s", __TIMESTAMP__); -#ifndef _DEBUG - Game::logger->SetLogToConsole(false); //By default, turn it back off if not in debug. -#endif - - //Read our config: - dConfig config("worldconfig.ini"); - Game::config = &config; - Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console")))); - Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1"); - if (config.GetValue("disable_chat") == "1") chatDisabled = true; + if (Game::config->GetValue("disable_chat") == "1") chatDisabled = true; try { - std::string client_path = config.GetValue("client_location"); - if (client_path.empty()) client_path = "./res"; - Game::assetManager = new AssetManager(client_path); + std::string clientPathStr = Game::config->GetValue("client_location"); + if (clientPathStr.empty()) clientPathStr = "./res"; + std::filesystem::path clientPath = std::filesystem::path(clientPathStr); + if (clientPath.is_relative()) { + clientPath = BinaryPathFinder::GetBinaryDir() / clientPath; + } + Game::assetManager = new AssetManager(clientPath); } catch (std::runtime_error& ex) { Game::logger->Log("WorldServer", "Got an error while setting up assets: %s", ex.what()); @@ -157,38 +160,38 @@ int main(int argc, char** argv) { // Connect to CDClient try { - CDClientDatabase::Connect((Game::assetManager->GetResPath() / "CDServer.sqlite").string()); + CDClientDatabase::Connect((BinaryPathFinder::GetBinaryDir() / "resServer" / "CDServer.sqlite").string()); } catch (CppSQLite3Exception& e) { Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode()); - return -1; + return EXIT_FAILURE; } - CDClientManager::Instance()->Initialize(); + CDClientManager::Instance(); //Connect to the MySQL Database - std::string mysql_host = config.GetValue("mysql_host"); - std::string mysql_database = config.GetValue("mysql_database"); - std::string mysql_username = config.GetValue("mysql_username"); - std::string mysql_password = config.GetValue("mysql_password"); + std::string mysql_host = Game::config->GetValue("mysql_host"); + std::string mysql_database = Game::config->GetValue("mysql_database"); + std::string mysql_username = Game::config->GetValue("mysql_username"); + std::string mysql_password = Game::config->GetValue("mysql_password"); - Diagnostics::SetProduceMemoryDump(config.GetValue("generate_dump") == "1"); + Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1"); - if (!config.GetValue("dump_folder").empty()) { - Diagnostics::SetOutDirectory(config.GetValue("dump_folder")); + if (!Game::config->GetValue("dump_folder").empty()) { + Diagnostics::SetOutDirectory(Game::config->GetValue("dump_folder")); } try { Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); } catch (sql::SQLException& ex) { Game::logger->Log("WorldServer", "Got an error while connecting to the database: %s", ex.what()); - return 0; + return EXIT_FAILURE; } //Find out the master's IP: std::string masterIP = "localhost"; - int masterPort = 1000; + uint32_t masterPort = 1000; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -202,13 +205,13 @@ int main(int argc, char** argv) { ObjectIDManager::Instance()->Initialize(); UserManager::Instance()->Initialize(); LootGenerator::Instance(); - Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf")))); + Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); - Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, zoneID); + Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::shouldShutdown, zoneID); //Connect to the chat server: - int chatPort = 1501; - if (config.GetValue("chat_server_port") != "") chatPort = std::atoi(config.GetValue("chat_server_port").c_str()); + uint32_t chatPort = 1501; + if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str()); auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); Game::chatServer = RakNetworkFactory::GetRakPeerInterface(); @@ -217,29 +220,28 @@ int main(int argc, char** argv) { //Set up other things: Game::randomEngine = std::mt19937(time(0)); - Game::locale = new dLocale(); //Run it until server gets a kill message from Master: auto lastTime = std::chrono::high_resolution_clock::now(); auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceChatDisconnect = 0; - int framesSinceLastUsersSave = 0; - int framesSinceLastSQLPing = 0; - int framesSinceLastUser = 0; + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceChatDisconnect = 0; + uint32_t framesSinceLastUsersSave = 0; + uint32_t framesSinceLastSQLPing = 0; + uint32_t framesSinceLastUser = 0; const float maxPacketProcessingTime = 1.5f; //0.015f; - const int maxPacketsToProcess = 1024; + const uint32_t maxPacketsToProcess = 1024; bool ready = false; - int framesSinceMasterStatus = 0; - int framesSinceShutdownSequence = 0; - int currentFramerate = highFrameRate; + uint32_t framesSinceMasterStatus = 0; + uint32_t framesSinceShutdownSequence = 0; + uint32_t currentFramerate = highFramerate; - int ghostingStepCount = 0; + uint32_t ghostingStepCount = 0; auto ghostingLastTime = std::chrono::high_resolution_clock::now(); PerformanceManager::SelectProfile(zoneID); @@ -247,7 +249,6 @@ int main(int argc, char** argv) { //Load our level: if (zoneID != 0) { dpWorld::Instance().Initialize(zoneID); - Game::physicsWorld = &dpWorld::Instance(); //just in case some old code references it dZoneManager::Instance()->Initialize(LWOZONEID(zoneID, instanceID, cloneID)); g_CloneID = cloneID; @@ -269,7 +270,7 @@ int main(int argc, char** argv) { } } - const int bufferSize = 1024; + const int32_t bufferSize = 1024; MD5* md5 = new MD5(); char fileStreamBuffer[1024] = {}; @@ -293,6 +294,15 @@ int main(int argc, char** argv) { } } + uint32_t currentFrameDelta = highFrameDelta; + // These values are adjust them selves to the current framerate should it update. + uint32_t logFlushTime = 15 * currentFramerate; // 15 seconds in frames + uint32_t shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + uint32_t chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + uint32_t saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t emptyShutdownTime = (cloneID == 0 ? 30 : 5) * 60 * currentFramerate; // 30 minutes for main worlds, 5 for all others. while (true) { Metrics::StartMeasurement(MetricVariable::Frame); Metrics::StartMeasurement(MetricVariable::GameLoop); @@ -305,25 +315,47 @@ int main(int argc, char** argv) { const auto occupied = UserManager::Instance()->GetUserCount() != 0; + uint32_t newFrameDelta = currentFrameDelta; if (!ready) { - currentFramerate = highFrameRate; + newFrameDelta = highFrameDelta; } else { - currentFramerate = PerformanceManager::GetServerFramerate(); + newFrameDelta = PerformanceManager::GetServerFrameDelta(); + } + + // Update to the new framerate and scale all timings to said new framerate + if (newFrameDelta != currentFrameDelta) { + float_t ratioBeforeToAfter = (float)currentFrameDelta / (float)newFrameDelta; + currentFrameDelta = newFrameDelta; + currentFramerate = MS_TO_FRAMES(newFrameDelta); + Game::logger->LogDebug("WorldServer", "Framerate for zone/instance/clone %i/%i/%i is now %i", zoneID, instanceID, cloneID, currentFramerate); + logFlushTime = 15 * currentFramerate; // 15 seconds in frames + framesSinceLastFlush *= ratioBeforeToAfter; + shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastUser *= ratioBeforeToAfter; + noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + framesSinceMasterDisconnect *= ratioBeforeToAfter; + chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + framesSinceChatDisconnect *= ratioBeforeToAfter; + saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastUsersSave *= ratioBeforeToAfter; + sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastSQLPing *= ratioBeforeToAfter; + emptyShutdownTime = (cloneID == 0 ? 30 : 5) * 60 * currentFramerate; // 30 minutes for main worlds, 5 for all others. + framesSinceLastUser *= ratioBeforeToAfter; } //Warning if we ran slow - if (deltaTime > currentFramerate) { - Game::logger->Log("WorldServer", "We're running behind, dT: %f > %f (framerate)", deltaTime, currentFramerate); + if (deltaTime > currentFrameDelta) { + Game::logger->Log("WorldServer", "We're running behind, dT: %f > %f (framerate %i)", deltaTime, currentFrameDelta, currentFramerate); } //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - int framesToWaitForMaster = ready ? 10 : 200; - if (framesSinceMasterDisconnect >= framesToWaitForMaster && !worldShutdownSequenceStarted) { - Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", framesToWaitForMaster); - worldShutdownSequenceStarted = true; + if (framesSinceMasterDisconnect >= noMasterConnectionTimeout && !Game::shouldShutdown) { + Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", noMasterConnectionTimeout); + Game::shouldShutdown = true; } } else framesSinceMasterDisconnect = 0; @@ -331,8 +363,7 @@ int main(int argc, char** argv) { if (!chatConnected) { framesSinceChatDisconnect++; - // Attempt to reconnect every 30 seconds. - if (framesSinceChatDisconnect >= 2000) { + if (framesSinceChatDisconnect >= chatReconnectionTime) { framesSinceChatDisconnect = 0; Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8); @@ -384,14 +415,14 @@ int main(int argc, char** argv) { UserManager::Instance()->DeletePendingRemovals(); auto t1 = std::chrono::high_resolution_clock::now(); - for (int curPacket = 0; curPacket < maxPacketsToProcess && timeSpent < maxPacketProcessingTime; curPacket++) { + for (uint32_t curPacket = 0; curPacket < maxPacketsToProcess && timeSpent < maxPacketProcessingTime; curPacket++) { packet = Game::server->Receive(); if (packet) { auto t1 = std::chrono::high_resolution_clock::now(); HandlePacket(packet); auto t2 = std::chrono::high_resolution_clock::now(); - timeSpent += std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count(); + timeSpent += std::chrono::duration_cast<std::chrono::duration<float>>(t2 - t1).count(); Game::server->DeallocatePacket(packet); packet = nullptr; } else { @@ -409,7 +440,7 @@ int main(int argc, char** argv) { Metrics::EndMeasurement(MetricVariable::UpdateReplica); //Push our log every 15s: - if (framesSinceLastFlush >= 1000) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; @@ -418,15 +449,15 @@ int main(int argc, char** argv) { framesSinceLastUser++; //If we haven't had any players for a while, time out and shut down: - if (framesSinceLastUser == (cloneID != 0 ? 4000 : 40000)) { - worldShutdownSequenceStarted = true; + if (framesSinceLastUser >= emptyShutdownTime) { + Game::shouldShutdown = true; } } else { framesSinceLastUser = 0; } //Save all connected users every 10 minutes: - if (framesSinceLastUsersSave >= 40000 && zoneID != 0) { + if (framesSinceLastUsersSave >= saveTime && zoneID != 0) { UserManager::Instance()->SaveAllActiveCharacters(); framesSinceLastUsersSave = 0; @@ -436,10 +467,10 @@ int main(int argc, char** argv) { } else framesSinceLastUsersSave++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; - int masterPort; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -457,7 +488,7 @@ int main(int argc, char** argv) { Metrics::StartMeasurement(MetricVariable::Sleep); - t += std::chrono::milliseconds(currentFramerate); + t += std::chrono::milliseconds(currentFrameDelta); std::this_thread::sleep_until(t); Metrics::EndMeasurement(MetricVariable::Sleep); @@ -476,7 +507,7 @@ int main(int argc, char** argv) { } } - if (worldShutdownSequenceStarted && !worldShutdownSequenceComplete) { + if (Game::shouldShutdown && !worldShutdownSequenceComplete) { WorldShutdownProcess(zoneID); break; } @@ -488,8 +519,8 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } -dLogger* SetupLogger(int zoneID, int instanceID) { - std::string logPath = "./logs/WorldServer_" + std::to_string(zoneID) + "_" + std::to_string(instanceID) + "_" + std::to_string(time(nullptr)) + ".log"; +dLogger* SetupLogger(uint32_t zoneID, uint32_t instanceID) { + std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/WorldServer_" + std::to_string(zoneID) + "_" + std::to_string(instanceID) + "_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; #ifdef _DEBUG @@ -530,7 +561,7 @@ void HandlePacketChat(Packet* packet) { //Write our stream outwards: CBITSTREAM; - for (int i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { + for (BitSize_t i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { bitStream.Write(packet->data[i + 16]); //16 bytes == header + playerID to skip } @@ -549,7 +580,7 @@ void HandlePacketChat(Packet* packet) { uint32_t len; inStream.Read<uint32_t>(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read<char>(character); title += character; @@ -557,7 +588,7 @@ void HandlePacketChat(Packet* packet) { len = 0; inStream.Read<uint32_t>(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read<char>(character); msg += character; @@ -735,7 +766,7 @@ void HandlePacket(Packet* packet) { //Verify it: if (userHash != it->second.hash) { Game::logger->Log("WorldServer", "SOMEONE IS TRYING TO HACK? SESSION KEY MISMATCH: ours: %s != master: %s", userHash.c_str(), it->second.hash.c_str()); - Game::server->Disconnect(it->second.sysAddr, SERVER_DISCON_INVALID_SESSION_KEY); + Game::server->Disconnect(it->second.sysAddr, eServerDisconnectIdentifiers::INVALID_SESSION_KEY); return; } else { Game::logger->Log("WorldServer", "User %s authenticated with correct key.", username.c_str()); @@ -795,7 +826,7 @@ void HandlePacket(Packet* packet) { } case MSG_MASTER_SHUTDOWN: { - worldShutdownSequenceStarted = true; + Game::shouldShutdown = true; Game::logger->Log("WorldServer", "Got shutdown request from master, zone (%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID()); break; } @@ -810,7 +841,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; i < len; i++) { + for (uint32_t i = 0; i < len; i++) { char character; inStream.Read<char>(character); username += character; } @@ -825,7 +856,7 @@ void HandlePacket(Packet* packet) { //Check the key: if (sessionKey != std::atoi(user->GetSessionKey().c_str())) { Game::logger->Log("WorldServer", "Got new session alert for user %s, but the session key is invalid.", username.c_str()); - Game::server->Disconnect(user->GetSystemAddress(), SERVER_DISCON_INVALID_SESSION_KEY); + Game::server->Disconnect(user->GetSystemAddress(), eServerDisconnectIdentifiers::INVALID_SESSION_KEY); return; } break; @@ -866,7 +897,7 @@ void HandlePacket(Packet* packet) { // Developers may skip this check if (gmLevel < 8 && clientDatabaseChecksum != databaseChecksum) { Game::logger->Log("WorldServer", "Client's database checksum does not match the server's, aborting connection."); - Game::server->Disconnect(packet->systemAddress, SERVER_DISCON_KICK); + Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::WRONG_GAME_VERSION); return; } } @@ -999,9 +1030,29 @@ void HandlePacket(Packet* packet) { player->GetComponent<CharacterComponent>()->RocketUnEquip(player); } - c->SetRetroactiveFlags(); + // Do charxml fixes here + auto* levelComponent = player->GetComponent<LevelProgressionComponent>(); + if (!levelComponent) return; - player->RetroactiveVaultSize(); + auto version = levelComponent->GetCharacterVersion(); + switch(version) { + case eCharacterVersion::RELEASE: + // TODO: Implement, super low priority + case eCharacterVersion::LIVE: + Game::logger->Log("WorldServer", "Updating Character Flags"); + c->SetRetroactiveFlags(); + levelComponent->SetCharacterVersion(eCharacterVersion::PLAYER_FACTION_FLAGS); + case eCharacterVersion::PLAYER_FACTION_FLAGS: + Game::logger->Log("WorldServer", "Updating Vault Size"); + player->RetroactiveVaultSize(); + levelComponent->SetCharacterVersion(eCharacterVersion::VAULT_SIZE); + case eCharacterVersion::VAULT_SIZE: + Game::logger->Log("WorldServer", "Updaing Speedbase"); + levelComponent->SetRetroactiveBaseSpeed(); + levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); + case eCharacterVersion::UP_TO_DATE: + break; + } player->GetCharacter()->SetTargetScene(""); @@ -1033,7 +1084,7 @@ void HandlePacket(Packet* packet) { //Check for BBB models: auto stmt = Database::CreatePreppedStmt("SELECT ugc_id FROM properties_contents WHERE lot=14 AND property_id=?"); - int templateId = result.getIntField(0); + int32_t templateId = result.getIntField(0); result.finalize(); @@ -1077,9 +1128,9 @@ void HandlePacket(Packet* packet) { CBITSTREAM; PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_BLUEPRINT_SAVE_RESPONSE); - bitStream.Write<LWOOBJID>(0); //always zero so that a check on the client passes - bitStream.Write<unsigned int>(0); - bitStream.Write<unsigned int>(1); + bitStream.Write<LWOOBJID>(LWOOBJID_EMPTY); //always zero so that a check on the client passes + bitStream.Write(eBlueprintSaveResponseType::EverythingWorked); + bitStream.Write<uint32_t>(1); bitStream.Write(blueprintID); bitStream.Write<uint32_t>(lxfmlSize); @@ -1134,7 +1185,7 @@ void HandlePacket(Packet* packet) { } } else { Game::logger->Log("WorldServer", "Couldn't find character to log in with for user %s (%i)!", user->GetUsername().c_str(), user->GetAccountID()); - Game::server->Disconnect(packet->systemAddress, SERVER_DISCON_CHARACTER_NOT_FOUND); + Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::CHARACTER_NOT_FOUND); } } else { Game::logger->Log("WorldServer", "Couldn't get user for level load complete!"); @@ -1219,7 +1270,7 @@ void HandlePacket(Packet* packet) { if (user) { user->UserOutOfSync(); } else { - Game::server->Disconnect(packet->systemAddress, SERVER_DISCON_KICK); + Game::server->Disconnect(packet->systemAddress, eServerDisconnectIdentifiers::KICK); } break; } @@ -1259,17 +1310,17 @@ void WorldShutdownProcess(uint32_t zoneId) { while (Game::server->GetReplicaManager()->GetParticipantCount() > 0) { const auto& player = Game::server->GetReplicaManager()->GetParticipantAtIndex(0); - Game::server->Disconnect(player, SERVER_DISCON_KICK); + Game::server->Disconnect(player, eServerDisconnectIdentifiers::SERVER_SHUTDOWN); } SendShutdownMessageToMaster(); } void WorldShutdownSequence() { - if (worldShutdownSequenceStarted || worldShutdownSequenceComplete) { + if (Game::shouldShutdown || worldShutdownSequenceComplete) { return; } - worldShutdownSequenceStarted = true; + Game::shouldShutdown = true; Game::logger->Log("WorldServer", "Zone (%i) instance (%i) shutting down outside of main loop!", Game::server->GetZoneID(), instanceID); WorldShutdownProcess(Game::server->GetZoneID()); @@ -1277,17 +1328,15 @@ void WorldShutdownSequence() { } void FinalizeShutdown() { - //Delete our objects here: - if (Game::physicsWorld) Game::physicsWorld = nullptr; - if (Game::zoneManager) delete Game::zoneManager; - Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)", Game::server->GetZoneID(), instanceID); + //Delete our objects here: Metrics::Clear(); Database::Destroy("WorldServer"); - delete Game::chatFilter; - delete Game::server; - delete Game::logger; + if (Game::chatFilter) delete Game::chatFilter; + if (Game::server) delete Game::server; + if (Game::logger) delete Game::logger; + if (Game::config) delete Game::config; worldShutdownSequenceComplete = true; diff --git a/dZoneManager/LUTriggers.h b/dZoneManager/LUTriggers.h new file mode 100644 index 00000000..a93cd67d --- /dev/null +++ b/dZoneManager/LUTriggers.h @@ -0,0 +1,33 @@ +#ifndef __LUTRIGGERS__H__ +#define __LUTRIGGERS__H__ + +#include <string> +#include <vector> + +class Command; +class Event; +enum class eTriggerCommandType; +enum class eTriggerEventType; + + +namespace LUTriggers { + struct Command { + eTriggerCommandType id; + std::string target; + std::string targetName; + std::string args; + }; + + struct Event { + eTriggerEventType id; + std::vector<Command*> commands; + }; + + struct Trigger { + uint32_t id; + bool enabled; + std::vector<Event*> events; + }; +}; + +#endif //!__LUTRIGGERS__H__ diff --git a/dZoneManager/Level.cpp b/dZoneManager/Level.cpp index dd38d208..55790592 100644 --- a/dZoneManager/Level.cpp +++ b/dZoneManager/Level.cpp @@ -162,7 +162,7 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) { uint32_t objectsCount = 0; BinaryIO::BinaryRead(file, objectsCount); - CDFeatureGatingTable* featureGatingTable = CDClientManager::Instance()->GetTable<CDFeatureGatingTable>("FeatureGating"); + CDFeatureGatingTable* featureGatingTable = CDClientManager::Instance().GetTable<CDFeatureGatingTable>(); for (uint32_t i = 0; i < objectsCount; ++i) { SceneObject obj; diff --git a/dZoneManager/Spawner.cpp b/dZoneManager/Spawner.cpp index 57b4e988..28f77fea 100644 --- a/dZoneManager/Spawner.cpp +++ b/dZoneManager/Spawner.cpp @@ -134,24 +134,23 @@ void Spawner::AddEntitySpawnedCallback(std::function<void(Entity*)> callback) { void Spawner::Reset() { m_Start = true; - - for (auto* node : m_Info.nodes) { - for (const auto& spawned : node->entities) { - auto* entity = EntityManager::Instance()->GetEntity(spawned); - - if (entity == nullptr) continue; - - entity->Kill(); - } - - node->entities.clear(); - } - + DestroyAllEntities(); m_Entities.clear(); m_AmountSpawned = 0; m_NeedsUpdate = true; } +void Spawner::DestroyAllEntities(){ + for (auto* node : m_Info.nodes) { + for (const auto& element : node->entities) { + auto* entity = EntityManager::Instance()->GetEntity(element); + if (entity == nullptr) continue; + entity->Kill(); + } + node->entities.clear(); + } +} + void Spawner::SoftReset() { m_Start = true; m_AmountSpawned = 0; diff --git a/dZoneManager/Spawner.h b/dZoneManager/Spawner.h index 908bb3a3..1f610b71 100644 --- a/dZoneManager/Spawner.h +++ b/dZoneManager/Spawner.h @@ -9,6 +9,7 @@ #include <string> #include <functional> #include "LDFFormat.h" +#include "EntityInfo.h" struct SpawnerNode { NiPoint3 position = NiPoint3::ZERO; @@ -60,6 +61,7 @@ public: void AddEntitySpawnedCallback(std::function<void(Entity*)> callback); void SetSpawnLot(LOT lot); void Reset(); + void DestroyAllEntities(); void SoftReset(); void SetRespawnTime(float time); void SetNumToMaintain(int32_t value); diff --git a/dZoneManager/WorldConfig.h b/dZoneManager/WorldConfig.h new file mode 100644 index 00000000..a98433a1 --- /dev/null +++ b/dZoneManager/WorldConfig.h @@ -0,0 +1,67 @@ +#ifndef __WORLDCONFIG__H__ +#define __WORLDCONFIG__H__ + +#include <cstdint> +#include <string> + +struct WorldConfig { + int32_t worldConfigID{}; //! Primary key for WorlcConfig table + float peGravityValue{}; //! Unknown + float peBroadphaseWorldSize{}; //! Unknown + float peGameObjScaleFactor{}; //! Unknown + float characterRotationSpeed{}; //! The players' rotation speed + float characterWalkForwardSpeed{}; //! The players' walk forward speed + float characterWalkBackwardSpeed{}; //! The players' walk backwards speed + float characterWalkStrafeSpeed{}; //! The players' strafe speed + float characterWalkStrafeForwardSpeed{}; //! The players' walk strafe forward speed + float characterWalkStrafeBackwardSpeed{}; //! The players' walk strage backwards speed + float characterRunBackwardSpeed{}; //! The players' run backwards speed + float characterRunStrafeSpeed{}; //! The players' run strafe speed + float characterRunStrafeForwardSpeed{}; //! The players' run strafe forward speed + float characterRunStrafeBackwardSpeed{}; //! The players' run strage backwards speed + float globalCooldown{}; //! The global ability cooldown + float characterGroundedTime{}; //! Unknown + float characterGroundedSpeed{}; //! Unknown + float globalImmunityTime{}; //! Unknown + float characterMaxSlope{}; //! Unknown + float defaultRespawnTime{}; //! Unknown + float missionTooltipTimeout{}; + float vendorBuyMultiplier{}; //! The buy scalar for buying from vendors + float petFollowRadius{}; //! The players' pet follow radius + float characterEyeHeight{}; //! The players' eye height + float flightVerticalVelocity{}; //! Unknown + float flightAirspeed{}; //! Unknown + float flightFuelRatio{}; //! Unknown + float flightMaxAirspeed{}; //! Unknown + float fReputationPerVote{}; //! Unknown + int32_t propertyCloneLimit{}; //! Unknown + int32_t defaultHomespaceTemplate{}; //! Unknown + float coinsLostOnDeathPercent{}; //! The percentage of coins to lose on a player death + int32_t coinsLostOnDeathMin{}; //! The minimum number of coins to lose on a player death + int32_t coinsLostOnDeathMax{}; //! The maximum number of coins to lose on a player death + int32_t characterVotesPerDay{}; //! Unknown + int32_t propertyModerationRequestApprovalCost{};//! Unknown + int32_t propertyModerationRequestReviewCost{}; //! Unknown + int32_t propertyModRequestsAllowedSpike{}; //! Unknown + int32_t propertyModRequestsAllowedInterval{}; //! Unknown + int32_t propertyModRequestsAllowedTotal{}; //! Unknown + int32_t propertyModRequestsSpikeDuration{}; //! Unknown + int32_t propertyModRequestsIntervalDuration{}; //! Unknown + bool modelModerateOnCreate{}; //! Unknown + float defaultPropertyMaxHeight{}; //! Unknown + float reputationPerVoteCast{}; //! Unknown + float reputationPerVoteReceived{}; //! Unknown + int32_t showcaseTopModelConsiderationBattles{}; //! Unknown + float reputationPerBattlePromotion{}; //! Unknown + float coinsLostOnDeathMinTimeout{}; //! Unknown + float coinsLostOnDeathMaxTimeout{}; //! Unknown + int32_t mailBaseFee{}; //! The base fee to take when a player sends mail + float mailPercentAttachmentFee{}; //! The scalar multiplied by an items base cost to determine how much that item costs to be mailed + int32_t propertyReputationDelay{}; //! Unknown + int32_t levelCap{}; //! The maximum player level + std::string levelUpBehaviorEffect{}; //! Unknown + int32_t characterVersion{}; //! Unknown + int32_t levelCapCurrencyConversion{}; //! The ratio of UScore (LEGO Score) to coins +}; + +#endif //! __WORLDCONFIG__H__ diff --git a/dZoneManager/Zone.cpp b/dZoneManager/Zone.cpp index 5d3a7879..03444af5 100644 --- a/dZoneManager/Zone.cpp +++ b/dZoneManager/Zone.cpp @@ -6,6 +6,7 @@ #include "dLogger.h" #include "GeneralUtils.h" #include "BinaryIO.h" +#include "LUTriggers.h" #include "AssetManager.h" #include "CDClientManager.h" @@ -13,6 +14,9 @@ #include "Spawner.h" #include "dZoneManager.h" +#include "eTriggerCommandType.h" +#include "eTriggerEventType.h" + Zone::Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) : m_ZoneID(mapID, instanceID, cloneID) { m_NumberOfScenesLoaded = 0; @@ -42,6 +46,12 @@ void Zone::LoadZoneIntoMemory() { if (m_ZoneFilePath == "ERR") return; AssetMemoryBuffer buffer = Game::assetManager->GetFileAsBuffer(m_ZoneFilePath.c_str()); + + if (!buffer.m_Success) { + Game::logger->Log("Zone", "Failed to load %s", m_ZoneFilePath.c_str()); + throw std::runtime_error("Aborting Zone loading due to no Zone File."); + } + std::istream file(&buffer); if (file) { BinaryIO::BinaryRead(file, m_ZoneFileFormatVersion); @@ -92,15 +102,12 @@ void Zone::LoadZoneIntoMemory() { if (m_ZoneFileFormatVersion >= Zone::ZoneFileFormatVersion::EarlyAlpha) { BinaryIO::BinaryRead(file, m_PathDataLength); - uint32_t unknown; - uint32_t pathCount; + BinaryIO::BinaryRead(file, m_PathChunkVersion); // always should be 1 - BinaryIO::BinaryRead(file, unknown); + uint32_t pathCount; BinaryIO::BinaryRead(file, pathCount); - for (uint32_t i = 0; i < pathCount; ++i) { - LoadPath(file); - } + for (uint32_t i = 0; i < pathCount; ++i) LoadPath(file); for (Path path : m_Paths) { if (path.pathType == PathType::Spawner) { @@ -157,7 +164,7 @@ void Zone::LoadZoneIntoMemory() { std::string Zone::GetFilePathForZoneID() { //We're gonna go ahead and presume we've got the db loaded already: - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); const CDZoneTable* zone = zoneTable->Query(this->GetZoneID().GetMapID()); if (zone != nullptr) { std::string toReturn = "maps/" + zone->zoneName; @@ -230,7 +237,8 @@ void Zone::LoadScene(std::istream& file) { scene.filename = BinaryIO::ReadString(file, sceneFilenameLength); std::string luTriggersPath = scene.filename.substr(0, scene.filename.size() - 4) + ".lutriggers"; - std::vector<LUTriggers::Trigger*> triggers = LoadLUTriggers(luTriggersPath, scene.id); + std::vector<LUTriggers::Trigger*> triggers; + if(Game::assetManager->HasFile((m_ZonePath + luTriggersPath).c_str())) triggers = LoadLUTriggers(luTriggersPath, scene.id); for (LUTriggers::Trigger* trigger : triggers) { scene.triggers.insert({ trigger->id, trigger }); @@ -245,15 +253,6 @@ void Zone::LoadScene(std::istream& file) { scene.name = BinaryIO::ReadString(file, sceneNameLength); file.ignore(3); - /* - if (m_Scenes.find(scene.id) != m_Scenes.end()) { - //Extract the layer id from the filename (bad I know, but it's reliable at least): - std::string layer = scene.filename.substr(scene.filename.rfind('x') + 1); - layer = layer.substr(0, layer.find('_')); - lwoSceneID.SetLayerID(std::atoi(layer.c_str())); - } - */ - lwoSceneID.SetLayerID(scene.sceneType); m_Scenes.insert(std::make_pair(lwoSceneID, scene)); @@ -265,7 +264,10 @@ std::vector<LUTriggers::Trigger*> Zone::LoadLUTriggers(std::string triggerFile, auto buffer = Game::assetManager->GetFileAsBuffer((m_ZonePath + triggerFile).c_str()); - if (!buffer.m_Success) return lvlTriggers; + if (!buffer.m_Success) { + Game::logger->Log("Zone", "Failed to load %s from disk. Skipping loading triggers", (m_ZonePath + triggerFile).c_str()); + return lvlTriggers; + } std::istream file(&buffer); std::stringstream data; @@ -297,11 +299,11 @@ std::vector<LUTriggers::Trigger*> Zone::LoadLUTriggers(std::string triggerFile, auto currentEvent = currentTrigger->FirstChildElement("event"); while (currentEvent) { LUTriggers::Event* newEvent = new LUTriggers::Event(); - newEvent->eventID = currentEvent->Attribute("id"); + newEvent->id = TriggerEventType::StringToTriggerEventType(currentEvent->Attribute("id")); auto currentCommand = currentEvent->FirstChildElement("command"); while (currentCommand) { LUTriggers::Command* newCommand = new LUTriggers::Command(); - newCommand->id = currentCommand->Attribute("id"); + newCommand->id = TriggerCommandType::StringToTriggerCommandType(currentCommand->Attribute("id")); newCommand->target = currentCommand->Attribute("target"); if (currentCommand->Attribute("targetName") != NULL) { newCommand->targetName = currentCommand->Attribute("targetName"); @@ -368,14 +370,10 @@ SceneTransitionInfo Zone::LoadSceneTransitionInfo(std::istream& file) { } void Zone::LoadPath(std::istream& file) { - // Currently only spawner (type 4) paths are supported Path path = Path(); - uint32_t unknown1; - uint32_t pathType; - uint32_t pathBehavior; - BinaryIO::BinaryRead(file, path.pathVersion); + uint8_t stringLength; BinaryIO::BinaryRead(file, stringLength); for (uint8_t i = 0; i < stringLength; ++i) { @@ -383,16 +381,14 @@ void Zone::LoadPath(std::istream& file) { BinaryIO::BinaryRead(file, character); path.pathName.push_back(character); } - BinaryIO::BinaryRead(file, pathType); - path.pathType = PathType(pathType); - BinaryIO::BinaryRead(file, unknown1); - BinaryIO::BinaryRead(file, pathBehavior); - path.pathType = PathType(pathType); + + BinaryIO::BinaryRead(file, path.pathType); + BinaryIO::BinaryRead(file, path.flags); + BinaryIO::BinaryRead(file, path.pathBehavior); if (path.pathType == PathType::MovingPlatform) { if (path.pathVersion >= 18) { - uint8_t unknown; - BinaryIO::BinaryRead(file, unknown); + BinaryIO::BinaryRead(file, path.movingPlatform.timeBasedMovement); } else if (path.pathVersion >= 13) { uint8_t count; BinaryIO::BinaryRead(file, count); @@ -403,10 +399,9 @@ void Zone::LoadPath(std::istream& file) { } } } else if (path.pathType == PathType::Property) { - int32_t unknown; - BinaryIO::BinaryRead(file, unknown); + BinaryIO::BinaryRead(file, path.property.pathType); BinaryIO::BinaryRead(file, path.property.price); - BinaryIO::BinaryRead(file, path.property.rentalTime); + BinaryIO::BinaryRead(file, path.property.rentalTimeUnit); BinaryIO::BinaryRead(file, path.property.associatedZone); if (path.pathVersion >= 5) { @@ -426,10 +421,7 @@ void Zone::LoadPath(std::istream& file) { } } - if (path.pathVersion >= 6) { - int32_t unknown1; - BinaryIO::BinaryRead(file, unknown1); - } + if (path.pathVersion >= 6) BinaryIO::BinaryRead(file, path.property.type); if (path.pathVersion >= 7) { BinaryIO::BinaryRead(file, path.property.cloneLimit); @@ -453,11 +445,10 @@ void Zone::LoadPath(std::istream& file) { path.camera.nextPath.push_back(character); } if (path.pathVersion >= 14) { - uint8_t unknown; - BinaryIO::BinaryRead(file, unknown); + BinaryIO::BinaryRead(file, path.camera.rotatePlayer); + } } else if (path.pathType == PathType::Spawner) { - //SpawnerPath* path = static_cast<SpawnerPath*>(path); // Convert to a spawner path BinaryIO::BinaryRead(file, path.spawner.spawnedLOT); BinaryIO::BinaryRead(file, path.spawner.respawnTime); BinaryIO::BinaryRead(file, path.spawner.maxToSpawn); @@ -478,7 +469,7 @@ void Zone::LoadPath(std::istream& file) { BinaryIO::BinaryRead(file, waypoint.position.z); - if (path.pathType == PathType::Spawner || path.pathType == PathType::MovingPlatform || path.pathType == PathType::Race) { + if (path.pathType == PathType::Spawner || path.pathType == PathType::MovingPlatform || path.pathType == PathType::Race || path.pathType == PathType::Camera || path.pathType == PathType::Rail) { BinaryIO::BinaryRead(file, waypoint.rotation.w); BinaryIO::BinaryRead(file, waypoint.rotation.x); BinaryIO::BinaryRead(file, waypoint.rotation.y); @@ -506,33 +497,19 @@ void Zone::LoadPath(std::istream& file) { } } } else if (path.pathType == PathType::Camera) { - float unknown; - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); BinaryIO::BinaryRead(file, waypoint.camera.time); - BinaryIO::BinaryRead(file, unknown); + BinaryIO::BinaryRead(file, waypoint.camera.fov); BinaryIO::BinaryRead(file, waypoint.camera.tension); BinaryIO::BinaryRead(file, waypoint.camera.continuity); BinaryIO::BinaryRead(file, waypoint.camera.bias); } else if (path.pathType == PathType::Race) { - uint8_t unknown; - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - float unknown1; - BinaryIO::BinaryRead(file, unknown1); - BinaryIO::BinaryRead(file, unknown1); - BinaryIO::BinaryRead(file, unknown1); + BinaryIO::BinaryRead(file, waypoint.racing.isResetNode); + BinaryIO::BinaryRead(file, waypoint.racing.isNonHorizontalCamera); + BinaryIO::BinaryRead(file, waypoint.racing.planeWidth); + BinaryIO::BinaryRead(file, waypoint.racing.planeHeight); + BinaryIO::BinaryRead(file, waypoint.racing.shortestDistanceToEnd); } else if (path.pathType == PathType::Rail) { - float unknown; - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - BinaryIO::BinaryRead(file, unknown); - if (path.pathVersion >= 17) { - BinaryIO::BinaryRead(file, unknown); - } + if (path.pathVersion > 16) BinaryIO::BinaryRead(file, waypoint.rail.speed); } // object LDF configs @@ -557,7 +534,7 @@ void Zone::LoadPath(std::istream& file) { value.push_back(character); } LDFBaseData* ldfConfig = nullptr; - if (path.pathType == PathType::Movement) { + if (path.pathType == PathType::Movement || path.pathType == PathType::Rail) { ldfConfig = LDFBaseData::DataFromString(parameter + "=0:" + value); } else { ldfConfig = LDFBaseData::DataFromString(parameter + "=" + value); diff --git a/dZoneManager/Zone.h b/dZoneManager/Zone.h index f041b616..9c5322a1 100644 --- a/dZoneManager/Zone.h +++ b/dZoneManager/Zone.h @@ -1,35 +1,18 @@ #pragma once + #include "dZMCommon.h" #include "LDFFormat.h" -#include "../thirdparty/tinyxml2/tinyxml2.h" +#include "tinyxml2.h" #include <string> #include <vector> #include <map> -class Level; - -class LUTriggers { -public: - - struct Command { - std::string id; - std::string target; - std::string targetName; - std::string args; - }; - - struct Event { - std::string eventID; - std::vector<Command*> commands; - }; - - struct Trigger { - uint32_t id; - bool enabled; - std::vector<Event*> events; - }; +namespace LUTriggers { + struct Trigger; }; +class Level; + struct SceneRef { std::string filename; uint32_t id; @@ -59,16 +42,31 @@ struct MovingPlatformPathWaypoint { struct CameraPathWaypoint { float time; + float fov; float tension; float continuity; float bias; }; +struct RacingPathWaypoint { + uint8_t isResetNode; + uint8_t isNonHorizontalCamera; + float planeWidth; + float planeHeight; + float shortestDistanceToEnd; +}; + +struct RailPathWaypoint { + float speed; +}; + struct PathWaypoint { NiPoint3 position; NiQuaternion rotation; // not included in all, but it's more convenient here MovingPlatformPathWaypoint movingPlatform; CameraPathWaypoint camera; + RacingPathWaypoint racing; + RailPathWaypoint rail; std::vector<LDFBaseData*> config; }; @@ -89,6 +87,19 @@ enum class PathBehavior : uint32_t { Once = 2 }; +enum class PropertyPathType : int32_t { + Path = 0, + EntireZone = 1, + GenetatedRectangle = 2 +}; + +enum class PropertyType : int32_t { + Premiere = 0, + Prize = 1, + LUP = 2, + Headspace = 3 +}; + enum class PropertyRentalTimeUnit : int32_t { Forever = 0, Seconds = 1, @@ -116,17 +127,19 @@ enum class PropertyAchievmentRequired : int32_t { struct MovingPlatformPath { std::string platformTravelSound; + uint8_t timeBasedMovement; }; struct PropertyPath { + PropertyPathType pathType; int32_t price; - int32_t rentalTime; + PropertyRentalTimeUnit rentalTimeUnit; uint64_t associatedZone; std::string displayName; std::string displayDesc; + PropertyType type; int32_t cloneLimit; float repMultiplier; - PropertyRentalTimeUnit rentalTimeUnit; PropertyAchievmentRequired achievementRequired; NiPoint3 playerZoneCoords; float maxBuildHeight; @@ -134,6 +147,7 @@ struct PropertyPath { struct CameraPath { std::string nextPath; + uint8_t rotatePlayer; }; struct SpawnerPath { @@ -150,6 +164,7 @@ struct Path { uint32_t pathVersion; PathType pathType; std::string pathName; + uint32_t flags; PathBehavior pathBehavior; uint32_t waypointCount; std::vector<PathWaypoint> pathWaypoints; @@ -190,7 +205,7 @@ public: uint32_t GetWorldID() const { return m_WorldID; } [[nodiscard]] std::string GetZoneName() const { return m_ZoneName; } - std::string GetZoneRawPath() const { return m_ZoneRawPath;} + std::string GetZoneRawPath() const { return m_ZoneRawPath; } std::string GetZonePath() const { return m_ZonePath; } const NiPoint3& GetSpawnPos() const { return m_Spawnpoint; } @@ -219,9 +234,11 @@ private: std::map<LWOSCENEID, SceneRef, mapCompareLwoSceneIDs> m_Scenes; std::vector<SceneTransition> m_SceneTransitions; + uint32_t m_PathDataLength; - //std::vector<char> m_PathData; //Binary path data + uint32_t m_PathChunkVersion; std::vector<Path> m_Paths; + std::map<LWOSCENEID, uint32_t, mapCompareLwoSceneIDs> m_MapRevisions; //rhs is the revision! //private ("helper") functions: diff --git a/dZoneManager/dZoneManager.cpp b/dZoneManager/dZoneManager.cpp index 102fb3af..ac3a7008 100644 --- a/dZoneManager/dZoneManager.cpp +++ b/dZoneManager/dZoneManager.cpp @@ -8,6 +8,8 @@ #include "DestroyableComponent.h" #include "GameMessages.h" #include "VanityUtilities.h" +#include "WorldConfig.h" +#include "CDZoneTableTable.h" #include <chrono> #include "../dWorldServer/ObjectIDManager.h" @@ -26,7 +28,7 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { LOT zoneControlTemplate = 2365; - CDZoneTableTable* zoneTable = CDClientManager::Instance()->GetTable<CDZoneTableTable>("ZoneTable"); + CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); if (zoneTable != nullptr) { const CDZoneTable* zone = zoneTable->Query(zoneID.GetMapID()); @@ -53,6 +55,8 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { endTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count(); + LoadWorldConfig(); + Game::logger->Log("dZoneManager", "Zone prepared in: %llu ms", (endTime - startTime)); VanityUtilities::SpawnVanity(); @@ -69,6 +73,7 @@ dZoneManager::~dZoneManager() { m_Spawners.erase(p.first); } + if (m_WorldConfig) delete m_WorldConfig; } Zone* dZoneManager::GetZone() { @@ -117,24 +122,6 @@ LWOZONEID dZoneManager::GetZoneID() const { return m_ZoneID; } -uint32_t dZoneManager::GetMaxLevel() { - if (m_MaxLevel == 0) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT LevelCap FROM WorldConfig WHERE WorldConfigID = 1 LIMIT 1;"); - m_MaxLevel = tableData.getIntField(0, -1); - tableData.finalize(); - } - return m_MaxLevel; -} - -int32_t dZoneManager::GetLevelCapCurrencyConversion() { - if (m_CurrencyConversionRate == 0) { - auto tableData = CDClientDatabase::ExecuteQuery("SELECT LevelCapCurrencyConversion FROM WorldConfig WHERE WorldConfigID = 1 LIMIT 1;"); - m_CurrencyConversionRate = tableData.getIntField(0, -1); - tableData.finalize(); - } - return m_CurrencyConversionRate; -} - void dZoneManager::Update(float deltaTime) { for (auto spawner : m_Spawners) { spawner.second->Update(deltaTime); @@ -195,17 +182,7 @@ void dZoneManager::RemoveSpawner(const LWOOBJID id) { Game::logger->Log("dZoneManager", "Failed to find spawner entity (%llu)", id); } - for (auto* node : spawner->m_Info.nodes) { - for (const auto& element : node->entities) { - auto* nodeEntity = EntityManager::Instance()->GetEntity(element); - - if (nodeEntity == nullptr) continue; - - nodeEntity->Kill(); - } - - node->entities.clear(); - } + spawner->DestroyAllEntities(); spawner->Deactivate(); @@ -249,3 +226,77 @@ uint32_t dZoneManager::GetUniqueMissionIdStartingValue() { } return m_UniqueMissionIdStart; } + +void dZoneManager::LoadWorldConfig() { + Game::logger->Log("dZoneManager", "Loading WorldConfig into memory"); + + auto worldConfig = CDClientDatabase::ExecuteQuery("SELECT * FROM WorldConfig;"); + + if (!m_WorldConfig) m_WorldConfig = new WorldConfig(); + + if (worldConfig.eof()) { + Game::logger->Log("dZoneManager", "WorldConfig table is empty. Is this intended?"); + return; + } + + // Now read in the giant table + m_WorldConfig->worldConfigID = worldConfig.getIntField("WorldConfigID"); + m_WorldConfig->peGravityValue = worldConfig.getFloatField("pegravityvalue"); + m_WorldConfig->peBroadphaseWorldSize = worldConfig.getFloatField("pebroadphaseworldsize"); + m_WorldConfig->peGameObjScaleFactor = worldConfig.getFloatField("pegameobjscalefactor"); + m_WorldConfig->characterRotationSpeed = worldConfig.getFloatField("character_rotation_speed"); + m_WorldConfig->characterWalkForwardSpeed = worldConfig.getFloatField("character_walk_forward_speed"); + m_WorldConfig->characterWalkBackwardSpeed = worldConfig.getFloatField("character_walk_backward_speed"); + m_WorldConfig->characterWalkStrafeSpeed = worldConfig.getFloatField("character_walk_strafe_speed"); + m_WorldConfig->characterWalkStrafeForwardSpeed = worldConfig.getFloatField("character_walk_strafe_forward_speed"); + m_WorldConfig->characterWalkStrafeBackwardSpeed = worldConfig.getFloatField("character_walk_strafe_backward_speed"); + m_WorldConfig->characterRunBackwardSpeed = worldConfig.getFloatField("character_run_backward_speed"); + m_WorldConfig->characterRunStrafeSpeed = worldConfig.getFloatField("character_run_strafe_speed"); + m_WorldConfig->characterRunStrafeForwardSpeed = worldConfig.getFloatField("character_run_strafe_forward_speed"); + m_WorldConfig->characterRunStrafeBackwardSpeed = worldConfig.getFloatField("character_run_strafe_backward_speed"); + m_WorldConfig->globalCooldown = worldConfig.getFloatField("global_cooldown"); + m_WorldConfig->characterGroundedTime = worldConfig.getFloatField("characterGroundedTime"); + m_WorldConfig->characterGroundedSpeed = worldConfig.getFloatField("characterGroundedSpeed"); + m_WorldConfig->globalImmunityTime = worldConfig.getFloatField("globalImmunityTime"); + m_WorldConfig->characterMaxSlope = worldConfig.getFloatField("character_max_slope"); + m_WorldConfig->defaultRespawnTime = worldConfig.getFloatField("defaultrespawntime"); + m_WorldConfig->missionTooltipTimeout = worldConfig.getFloatField("mission_tooltip_timeout"); + m_WorldConfig->vendorBuyMultiplier = worldConfig.getFloatField("vendor_buy_multiplier"); + m_WorldConfig->petFollowRadius = worldConfig.getFloatField("pet_follow_radius"); + m_WorldConfig->characterEyeHeight = worldConfig.getFloatField("character_eye_height"); + m_WorldConfig->flightVerticalVelocity = worldConfig.getFloatField("flight_vertical_velocity"); + m_WorldConfig->flightAirspeed = worldConfig.getFloatField("flight_airspeed"); + m_WorldConfig->flightFuelRatio = worldConfig.getFloatField("flight_fuel_ratio"); + m_WorldConfig->flightMaxAirspeed = worldConfig.getFloatField("flight_max_airspeed"); + m_WorldConfig->fReputationPerVote = worldConfig.getFloatField("fReputationPerVote"); + m_WorldConfig->propertyCloneLimit = worldConfig.getIntField("nPropertyCloneLimit"); + m_WorldConfig->defaultHomespaceTemplate = worldConfig.getIntField("defaultHomespaceTemplate"); + m_WorldConfig->coinsLostOnDeathPercent = worldConfig.getFloatField("coins_lost_on_death_percent"); + m_WorldConfig->coinsLostOnDeathMin = worldConfig.getIntField("coins_lost_on_death_min"); + m_WorldConfig->coinsLostOnDeathMax = worldConfig.getIntField("coins_lost_on_death_max"); + m_WorldConfig->characterVotesPerDay = worldConfig.getIntField("character_votes_per_day"); + m_WorldConfig->propertyModerationRequestApprovalCost = worldConfig.getIntField("property_moderation_request_approval_cost"); + m_WorldConfig->propertyModerationRequestReviewCost = worldConfig.getIntField("property_moderation_request_review_cost"); + m_WorldConfig->propertyModRequestsAllowedSpike = worldConfig.getIntField("propertyModRequestsAllowedSpike"); + m_WorldConfig->propertyModRequestsAllowedInterval = worldConfig.getIntField("propertyModRequestsAllowedInterval"); + m_WorldConfig->propertyModRequestsAllowedTotal = worldConfig.getIntField("propertyModRequestsAllowedTotal"); + m_WorldConfig->propertyModRequestsSpikeDuration = worldConfig.getIntField("propertyModRequestsSpikeDuration"); + m_WorldConfig->propertyModRequestsIntervalDuration = worldConfig.getIntField("propertyModRequestsIntervalDuration"); + m_WorldConfig->modelModerateOnCreate = worldConfig.getIntField("modelModerateOnCreate") != 0; + m_WorldConfig->defaultPropertyMaxHeight = worldConfig.getFloatField("defaultPropertyMaxHeight"); + m_WorldConfig->reputationPerVoteCast = worldConfig.getFloatField("reputationPerVoteCast"); + m_WorldConfig->reputationPerVoteReceived = worldConfig.getFloatField("reputationPerVoteReceived"); + m_WorldConfig->showcaseTopModelConsiderationBattles = worldConfig.getIntField("showcaseTopModelConsiderationBattles"); + m_WorldConfig->reputationPerBattlePromotion = worldConfig.getFloatField("reputationPerBattlePromotion"); + m_WorldConfig->coinsLostOnDeathMinTimeout = worldConfig.getFloatField("coins_lost_on_death_min_timeout"); + m_WorldConfig->coinsLostOnDeathMaxTimeout = worldConfig.getFloatField("coins_lost_on_death_max_timeout"); + m_WorldConfig->mailBaseFee = worldConfig.getIntField("mail_base_fee"); + m_WorldConfig->mailPercentAttachmentFee = worldConfig.getFloatField("mail_percent_attachment_fee"); + m_WorldConfig->propertyReputationDelay = worldConfig.getIntField("propertyReputationDelay"); + m_WorldConfig->levelCap = worldConfig.getIntField("LevelCap"); + m_WorldConfig->levelUpBehaviorEffect = worldConfig.getStringField("LevelUpBehaviorEffect"); + m_WorldConfig->characterVersion = worldConfig.getIntField("CharacterVersion"); + m_WorldConfig->levelCapCurrencyConversion = worldConfig.getIntField("LevelCapCurrencyConversion"); + worldConfig.finalize(); + Game::logger->Log("dZoneManager", "Loaded WorldConfig into memory"); +} diff --git a/dZoneManager/dZoneManager.h b/dZoneManager/dZoneManager.h index b2fef1e3..c1776e79 100644 --- a/dZoneManager/dZoneManager.h +++ b/dZoneManager/dZoneManager.h @@ -4,6 +4,8 @@ #include "Spawner.h" #include <map> +class WorldConfig; + class dZoneManager { public: enum class dZoneNotifier { @@ -16,6 +18,12 @@ public: InvalidNotifier }; +private: + /** + * Reads the WorldConfig from the CDClientDatabase into memory + */ + void LoadWorldConfig(); + public: static dZoneManager* Instance() { if (!m_Address) { @@ -33,8 +41,6 @@ public: void NotifyZone(const dZoneNotifier& notifier, const LWOOBJID& objectID); //Notifies the zone of a certain event or command. void AddSpawner(LWOOBJID id, Spawner* spawner); LWOZONEID GetZoneID() const; - uint32_t GetMaxLevel(); - int32_t GetLevelCapCurrencyConversion(); LWOOBJID MakeSpawner(SpawnerInfo info); Spawner* GetSpawner(LWOOBJID id); void RemoveSpawner(LWOOBJID id); @@ -45,27 +51,24 @@ public: bool GetPlayerLoseCoinOnDeath() { return m_PlayerLoseCoinsOnDeath; } uint32_t GetUniqueMissionIdStartingValue(); + // The world config should not be modified by a caller. + const WorldConfig* GetWorldConfig() { + if (!m_WorldConfig) LoadWorldConfig(); + return m_WorldConfig; + }; + private: - /** - * The maximum level of the world. - */ - uint32_t m_MaxLevel = 0; - - /** - * The ratio of LEGO Score to currency when the character has hit the max level. - */ - int32_t m_CurrencyConversionRate = 0; - /** * The starting unique mission ID. */ uint32_t m_UniqueMissionIdStart = 0; static dZoneManager* m_Address; //Singleton - Zone* m_pZone; + Zone* m_pZone = nullptr; LWOZONEID m_ZoneID; bool m_PlayerLoseCoinsOnDeath; //Do players drop coins in this zone when smashed std::map<LWOOBJID, Spawner*> m_Spawners; + WorldConfig* m_WorldConfig = nullptr; - Entity* m_ZoneControlObject; + Entity* m_ZoneControlObject = nullptr; }; diff --git a/docker/Dockerfile b/docker/Dockerfile index 50f5b083..a7d91855 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,7 +6,7 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \ echo "Install build dependencies" && \ apt update && \ apt remove -y libmysqlcppconn7v5 libmysqlcppconn-dev && \ - apt install cmake zlib1g zlib1g-dev unzip -yqq --no-install-recommends && \ + apt install cmake zlib1g zlib1g-dev -yqq --no-install-recommends && \ rm -rf /var/lib/apt/lists/* COPY dAuthServer/ /build/dAuthServer @@ -35,12 +35,11 @@ ARG BUILD_VERSION=171022 RUN echo "Build server" && \ mkdir -p cmake_build && \ cd cmake_build && \ - sed -i -e "s/171022/${BUILD_VERSION}/g" ../CMakeVariables.txt && \ + sed -i -e "s/NET_VERSION=.*/NET_VERSION=${BUILD_VERSION}/g" ../CMakeVariables.txt && \ + sed -i -e "s/__maria_db_connector_compile_jobs__=.*/__maria_db_connector_compile_jobs__=${BUILD_THREADS}/g" ../CMakeVariables.txt && \ cmake .. -DCMAKE_BUILD_RPATH_USE_ORIGIN=TRUE && \ make -j $BUILD_THREADS -RUN unzip /build/resources/navmeshes.zip -d /build/cmake_build/res/maps - FROM gcc:11 as runtime RUN --mount=type=cache,id=runtime-apt-cache,target=/var/cache/apt \ diff --git a/docker/setup.Dockerfile b/docker/setup.Dockerfile index 2664e2fa..18bb2d06 100644 --- a/docker/setup.Dockerfile +++ b/docker/setup.Dockerfile @@ -1,23 +1,12 @@ -FROM rust:alpine3.14 as LUnpack - -WORKDIR /build_LUnpack - -COPY ./thirdparty/LUnpack . - -RUN apk add musl-dev --no-cache && cargo build --release - FROM python:3.10-alpine3.14 as prep -RUN apk add sqlite bash --no-cache +RUN apk add bash --no-cache WORKDIR /setup # copy needed files from repo COPY resources/ resources/ -COPY migrations/cdserver/ migrations/cdserver -COPY --from=LUnpack /build_LUnpack/target/release/lunpack /usr/local/bin/lunpack -ADD thirdparty/docker-utils/utils/*.py utils/ COPY docker/setup.sh /setup.sh -CMD [ "/setup.sh" ] \ No newline at end of file +CMD [ "/setup.sh" ] diff --git a/docker/setup.sh b/docker/setup.sh index 1a95f4de..ade67d2e 100755 --- a/docker/setup.sh +++ b/docker/setup.sh @@ -7,7 +7,7 @@ function update_ini() { FILE="/docker/configs/$1" KEY=$2 NEW_VALUE=$3 - sed -i "/^$KEY=/s/=.*/=$NEW_VALUE/" $FILE + sed -i "s~$2=.*~$2=$3~" $FILE } function update_database_ini_values_for() { @@ -30,66 +30,13 @@ function update_ini_values() { cp resources/authconfig.ini /docker/configs/ cp resources/chatconfig.ini /docker/configs/ cp resources/worldconfig.ini /docker/configs/ - - update_ini worldconfig.ini chat_server_port $CHAT_SERVER_PORT - update_ini worldconfig.ini max_clients $MAX_CLIENTS + cp resources/sharedconfig.ini /docker/configs/ # always use the internal docker hostname update_ini masterconfig.ini master_ip "darkflame" + update_ini sharedconfig.ini client_location "/client" - update_database_ini_values_for masterconfig.ini - update_database_ini_values_for authconfig.ini - update_database_ini_values_for chatconfig.ini - update_database_ini_values_for worldconfig.ini -} - -function fdb_to_sqlite() { - echo "Run fdb_to_sqlite" - python3 utils/fdb_to_sqlite.py /client/client/res/cdclient.fdb --sqlite_path /client/client/res/CDServer.sqlite - - ( - cd migrations/cdserver - readarray -d '' entries < <(printf '%s\0' *.sql | sort -zV) - for entry in "${entries[@]}"; do - echo "Execute $entry" - sqlite3 /client/client/res/CDServer.sqlite < $entry - done - ) + update_database_ini_values_for sharedconfig.ini } update_ini_values - -if [[ ! -d "/client" ]]; then - echo "Client not found." - echo "Did you forget to mount the client into the \"/client\" directory?" - exit 1 -fi - -if [[ ! -f "/client/extracted" ]]; then - echo "Start client resource extraction" - - touch globs.txt - - echo "client/res/macros/**" >> globs.txt - echo "client/res/BrickModels/**" >> globs.txt - echo "client/res/maps/**" >> globs.txt - echo "*.fdb" >> globs.txt - - lunpack -g ./globs.txt /client/ - - touch /client/extracted -else - echo "Client already extracted. Skip this step..." - echo "If you want to force a re-extract, just delete the file called \"extracted\" in the client directory" -fi - -if [[ ! -f "/client/migrated" ]]; then - echo "Start client db migration" - - fdb_to_sqlite - - touch /client/migrated -else - echo "Client db already migrated. Skip this step..." - echo "If you want to force a re-migrate, just delete the file called \"migrated\" in the client directory" -fi diff --git a/docker/start_server.sh b/docker/start_server.sh index feb61361..2e2e8c28 100755 --- a/docker/start_server.sh +++ b/docker/start_server.sh @@ -1,23 +1,5 @@ #!/bin/bash -function symlink_client_files() { - echo "Creating symlinks for client files" - ln -s /client/client/res/macros/ /app/res/macros - ln -s /client/client/res/BrickModels/ /app/res/BrickModels - ln -s /client/client/res/chatplus_en_us.txt /app/res/chatplus_en_us.txt - ln -s /client/client/res/names/ /app/res/names - ln -s /client/client/res/CDServer.sqlite /app/res/CDServer.sqlite - ln -s /client/client/locale/locale.xml /app/locale/locale.xml - # need to iterate over entries in maps due to maps already being a directory with navmeshes/ in it - ( - cd /client/client/res/maps - readarray -d '' entries < <(printf '%s\0' * | sort -zV) - for entry in "${entries[@]}"; do - ln -s /client/client/res/maps/$entry /app/res/maps/ - done - ) -} - function symlink_config_files() { echo "Creating symlinks for config files" rm /app/*.ini @@ -25,17 +7,11 @@ function symlink_config_files() { ln -s /shared_configs/configs/chatconfig.ini /app/chatconfig.ini ln -s /shared_configs/configs/masterconfig.ini /app/masterconfig.ini ln -s /shared_configs/configs/worldconfig.ini /app/worldconfig.ini + ln -s /shared_configs/configs/sharedconfig.ini /app/sharedconfig.ini } -# check to make sure the setup has completed -while [ ! -f "/client/extracted" ] || [ ! -f "/client/migrated" ]; do - echo "Client setup not finished. Waiting for setup container to complete..." - sleep 5 -done - if [[ ! -f "/app/initialized" ]]; then # setup symlinks for volume files - symlink_client_files symlink_config_files # do not run symlinks more than once touch /app/initialized @@ -46,4 +22,4 @@ fi # start the server echo "Starting MasterServer" ./MasterServer -tail -f /dev/null \ No newline at end of file +tail -f /dev/null diff --git a/docs/Commands.md b/docs/Commands.md index 95ec28f9..c997c3c4 100644 --- a/docs/Commands.md +++ b/docs/Commands.md @@ -1,6 +1,5 @@ # In-game commands - -Here is a summary of the commands available in-game. All commands are prefixed by `/` and typed in the in-game chat window. Some commands requires admin privileges. Operands within `<>` are required, operands within `()` are not. For the full list of in-game commands, please checkout [the source file](../dGame/dUtilities/SlashCommandHandler.cpp). +* All commands are prefixed by `/` and typed in the in-game chat window. Some commands require elevated gmlevel privileges. Operands within `<>` are required, operands within `()` are not. ## General Commands @@ -14,8 +13,6 @@ Here is a summary of the commands available in-game. All commands are prefixed b |pvp|`/pvp`|Toggle your PVP flag.|| |resurrect|`/resurrect`|Resurrects the player.|| |requestmailcount|`/requestmailcount`|Sends notification with number of unread messages in the player's mailbox.|| -|skip-ags|`/skip-ags`|Skips the Avant Gardens Survival minigame mission, "Impress the Sentinel Faction".|| -|skip-sg|`/skip-sg`|Skips the Shooting Gallery minigame mission, "Monarch of the Sea".|| |who|`/who`|Displays in chat all players on the instance.|| ## Moderation Commands @@ -39,8 +36,6 @@ Here is a summary of the commands available in-game. All commands are prefixed b |Command|Usage|Description|Admin Level Requirement| |--- |--- |--- |--- | |announce|`/announce`|Sends a announcement. `/setanntitle` and `/setannmsg` must be called first to configure the announcement.|8| -|config-set|`/config-set <key> <value>`|Set configuration item.|8| -|config-get|`/config-get <key>`|Get current value of a configuration item.|8| |kill|`/kill <username>`|Smashes the character whom the given user is playing.|8| |metrics|`/metrics`|Prints some information about the server's performance.|8| |setannmsg|`/setannmsg <title>`|Sets the message of an announcement.|8| @@ -53,6 +48,7 @@ These commands are primarily for development and testing. The usage of many of t |Command|Usage|Description|Admin Level Requirement| |--- |--- |--- |--- | +|togglenameplate|`/togglenameplate`|Turns the nameplate above your head that is visible to other players off and on.|8 or if `allow_nameplate_off` is set to exactly `1` in the settings| |fix-stats|`/fix-stats`|Resets skills, buffs, and destroyables.|| |join|`/join <password>`|Joins a private zone with given password.|| |leave-zone|`/leave-zone`|If you are in an instanced zone, transfers you to the closest main world. For example, if you are in an instance of Avant Gardens Survival or the Spider Queen Battle, you are sent to Avant Gardens. If you are in the Battle of Nimbus Station, you are sent to Nimbus Station.|| @@ -73,6 +69,7 @@ These commands are primarily for development and testing. The usage of many of t |createprivate|`/createprivate <zone id> <clone id> <password>`|Creates a private zone with password.|8| |debugui|`/debugui`|Toggle Debug UI.|8| |dismount|`/dismount`|Dismounts you from the vehicle or mount.|8| +|reloadconfig|`/reloadconfig`|Reloads the server with the new config values.|8| |force-save|`/force-save`|While saving to database usually happens on regular intervals and when you disconnect from the server, this command saves your player's data to the database.|8| |freecam|`/freecam`|Toggles freecam mode.|8| |freemoney|`/freemoney <coins>`|Gives coins.|8| @@ -82,7 +79,7 @@ These commands are primarily for development and testing. The usage of many of t |inspect|`/inspect <component> (-m <waypoint> \| -a <animation> \| -s \| -p \| -f (faction) \| -t)`|Finds the closest entity with the given component or LDF variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has. See [Detailed `/inspect` Usage](#detailed-inspect-usage) below.|8| |list-spawns|`/list-spawns`|Lists all the character spawn points in the zone. Additionally, this command will display the current scene that plays when the character lands in the next zone, if there is one.|8| |locrow|`/locrow`|Prints the your current position and rotation information to the console.|8| -|lookup|`/lookup <query>`|Searches through the Objects table in the client SQLite database for items whose display name, name, or description contains the query.|8| +|lookup|`/lookup <query>`|Searches through the Objects table in the client SQLite database for items whose display name, name, or description contains the query. Query can be multiple words delimited by spaces.|8| |playanimation|`/playanimation <id>`|Plays animation with given ID. Alias: `/playanim`.|8| |playeffect|`/playeffect <effect id> <effect type> <effect name>`|Plays an effect.|8| |playlvlfx|`/playlvlfx`|Plays the level up animation on your character.|8| @@ -96,7 +93,7 @@ These commands are primarily for development and testing. The usage of many of t |setcontrolscheme|`/setcontrolscheme <scheme number>`|Sets the character control scheme to the specified number.|8| |setcurrency|`/setcurrency <coins>`|Sets your coins.|8| |setflag|`/setflag (value) <flag id>`|Sets the given inventory or health flag to the given value, where value can be one of "on" or "off". If no value is given, by default this adds the flag to your character (equivalent of calling `/setflag on <flag id>`).|8| -|setinventorysize|`/setinventorysize <size>`|Sets your inventory size to the given size. Alias: `/setinvsize`|8| +|setinventorysize|`/setinventorysize <size> (inventory)`|Sets your inventory size to the given size. If `inventory` is provided, the number or string will be used to set that inventory to the requested size. Alias: `/setinvsize`|8| |setuistate|`/setuistate <ui state>`|Changes UI state.|8| |spawn|`/spawn <id>`|Spawns an object at your location by id.|8| |speedboost|`/speedboost <amount>`|Sets the speed multiplier to the given amount. `/speedboost 1.5` will set the speed multiplier to 1.5x the normal speed.|8| @@ -131,13 +128,13 @@ There are 9 Game master levels |Level|Variable Name|Description| |--- |--- |--- | -|0|GAME_MASTER_LEVEL_CIVILIAN|Normal player| -|1|GAME_MASTER_LEVEL_FORUM_MODERATOR|Forum moderator. No permissions on live servers.| -|2|GAME_MASTER_LEVEL_JUNIOR_MODERATOR|Can kick/mute and pull chat logs| -|3|GAME_MASTER_LEVEL_MODERATOR|Can return lost items| -|4|GAME_MASTER_LEVEL_SENIOR_MODERATOR|Can ban| -|5|GAME_MASTER_LEVEL_LEAD_MODERATOR|Can approve properties| -|6|GAME_MASTER_LEVEL_JUNIOR_DEVELOPER|Junior developer & future content team. Civilan on live.| -|7|GAME_MASTER_LEVEL_INACTIVE_DEVELOPER|Inactive developer, limited permissions.| -|8|GAME_MASTER_LEVEL_DEVELOPER|Active developer, full permissions on live.| -|9|GAME_MASTER_LEVEL_OPERATOR|Can shutdown server for restarts & updates.| +|0|CIVILIAN|Normal player| +|1|FORUM_MODERATOR|Forum moderator. No permissions on live servers.| +|2|JUNIOR_MODERATOR|Can kick/mute and pull chat logs| +|3|MODERATOR|Can return lost items| +|4|SENIOR_MODERATOR|Can ban| +|5|LEAD_MODERATOR|Can approve properties| +|6|JUNIOR_DEVELOPER|Junior developer & future content team. Civilan on live.| +|7|INACTIVE_DEVELOPER|Inactive developer, limited permissions.| +|8|DEVELOPER|Active developer, full permissions on live.| +|9|OPERATOR|Can shutdown server for restarts & updates.| diff --git a/migrations/cdserver/5_serratorizer_chargeup_fix.sql b/migrations/cdserver/5_serratorizer_chargeup_fix.sql new file mode 100644 index 00000000..a61da2c2 --- /dev/null +++ b/migrations/cdserver/5_serratorizer_chargeup_fix.sql @@ -0,0 +1 @@ +UPDATE behaviorParameter SET value = 20 WHERE behaviorID = 21001 AND parameterID = "value 2"; diff --git a/migrations/dlu/7_make_play_key_id_nullable.sql b/migrations/dlu/7_make_play_key_id_nullable.sql new file mode 100644 index 00000000..11239967 --- /dev/null +++ b/migrations/dlu/7_make_play_key_id_nullable.sql @@ -0,0 +1 @@ +ALTER TABLE accounts MODIFY play_key_id INT DEFAULT 0; diff --git a/migrations/dlu/8_foreign_play_key.sql b/migrations/dlu/8_foreign_play_key.sql new file mode 100644 index 00000000..6f171bb5 --- /dev/null +++ b/migrations/dlu/8_foreign_play_key.sql @@ -0,0 +1 @@ +ALTER TABLE accounts MODIFY play_key_id INT DEFAULT NULL; diff --git a/resources/sharedconfig.ini b/resources/sharedconfig.ini index 847a6b7c..d2c43d11 100644 --- a/resources/sharedconfig.ini +++ b/resources/sharedconfig.ini @@ -25,3 +25,14 @@ dump_folder= # The location of the client # Either the folder with /res or with /client and /versions client_location= + +# The maximum outgoing bandwidth in bits. If your clients are having +# issues with enemies taking a while to catch up to them, increse this value. +maximum_outgoing_bandwidth=80000 + +# The Maximum Translation Unit (MTU) size for packets. If players are +# getting stuck at 55% on the loading screen, lower this number to +# reduce the chances of packet loss. This value only has an effect +# from 512 <= maximum_mtu_size <= 1492 so make sure to keep this +# value within that range. +maximum_mtu_size=1228 diff --git a/resources/worldconfig.ini b/resources/worldconfig.ini index ee6b6651..b05614b4 100644 --- a/resources/worldconfig.ini +++ b/resources/worldconfig.ini @@ -43,3 +43,21 @@ pets_take_imagination=1 # If you would like to increase the maximum number of best friends a player can have on the server # Change the value below to what you would like this to be (5 is live accurate) max_number_of_best_friends=5 + +# Disables loot drops +disable_drops=0 + +# Hardcore mode settings +hardcore_mode=0 + +# Drop your entire inventory on death + coins (drops on the ground, so can be retrieved) +hardcore_dropinventory_on_death=1 + +# Enemies drop their max hp * this value. 0 will effectively disable it. +hardcore_uscore_enemies_multiplier=2 + +# Percentage of u-score to lose on player death +hardcore_lose_uscore_on_death_percent=10 + +# Allow civilian players the ability to turn the nameplate above their head off. Must be exactly 1 to be enabled for civilians. +allow_nameplate_off=0 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fb1ed5ac..9ba75a2f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,34 +1,21 @@ -# create the testing file and list of tests -create_test_sourcelist (Tests - CommonCxxTests.cpp - AMFDeserializeTests.cpp - TestNiPoint3.cpp - TestLDFFormat.cpp - TestEncoding.cpp +message (STATUS "Testing is enabled. Fetching gtest...") +enable_testing() + +include(FetchContent) +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.12.1 ) -# add the executable -add_executable (CommonCxxTests ${Tests}) -target_link_libraries(CommonCxxTests ${COMMON_LIBRARIES}) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -# remove the test driver source file -set (TestsToRun ${Tests}) -remove (TestsToRun CommonCxxTests.cpp) +FetchContent_MakeAvailable(GoogleTest) +include(GoogleTest) -# Copy test files to testing directory -configure_file( - ${CMAKE_SOURCE_DIR}/tests/TestBitStreams/AMFBitStreamTest.bin ${PROJECT_BINARY_DIR}/tests/AMFBitStreamTest.bin - COPYONLY -) +message(STATUS "gtest fetched and is now ready.") -configure_file( - ${CMAKE_SOURCE_DIR}/tests/TestBitStreams/AMFBitStreamUnimplementedTest.bin ${PROJECT_BINARY_DIR}/tests/AMFBitStreamUnimplementedTest.bin - COPYONLY -) - -# Add all the ADD_TEST for each test -foreach (test ${TestsToRun}) - get_filename_component (TName ${test} NAME_WE) - add_test (NAME ${TName} COMMAND CommonCxxTests ${TName}) - set_property(TEST ${TName} PROPERTY ENVIRONMENT CTEST_OUTPUT_ON_FAILURE=1) -endforeach () +# Add the subdirectories +add_subdirectory(dCommonTests) +add_subdirectory(dGameTests) diff --git a/tests/CommonCxxTests.cpp b/tests/CommonCxxTests.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/CommonCxxTests.h b/tests/CommonCxxTests.h deleted file mode 100644 index f1894927..00000000 --- a/tests/CommonCxxTests.h +++ /dev/null @@ -1,4 +0,0 @@ -#include <cstdio> - -#define ASSERT_EQ(a,b) { if (!(a == b)) { printf("Failed assertion: " #a " == " #b " \n in %s:%d\n", __FILE__, __LINE__); return 1; }} -#define ASSERT_NE(a,b) { if (!(a != b)) { printf("Failed assertion: " #a " != " #b " \n in %s:%d\n", __FILE__, __LINE__); return 1; }} diff --git a/tests/TestEncoding.cpp b/tests/TestEncoding.cpp deleted file mode 100644 index c23e2db6..00000000 --- a/tests/TestEncoding.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include <stdexcept> -#include <string> - -#include "GeneralUtils.h" -#include "CommonCxxTests.h" - -int TestEncoding(int argc, char** const argv) { - std::string x = "Hello World!"; - std::string_view v(x); - - uint32_t out; - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 'H'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 'e'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 'l'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 'l'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 'o'); - ASSERT_EQ(GeneralUtils::_NextUTF8Char(v, out), true); - - x = u8"Frühling"; - v = x; - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'F'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'r'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'ü'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'h'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'l'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'i'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'n'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'g'); - ASSERT_EQ(GeneralUtils::_NextUTF8Char(v, out), false); - - x = "中文字"; - v = x; - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'中'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'文'); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, U'字'); - ASSERT_EQ(GeneralUtils::_NextUTF8Char(v, out), false); - - x = "👨‍⚖️"; - v = x; - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 0x1F468); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 0x200D); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 0x2696); - GeneralUtils::_NextUTF8Char(v, out); ASSERT_EQ(out, 0xFE0F); - ASSERT_EQ(GeneralUtils::_NextUTF8Char(v, out), false); - - ASSERT_EQ(GeneralUtils::UTF8ToUTF16("Hello World!"), u"Hello World!"); - ASSERT_EQ(GeneralUtils::UTF8ToUTF16("Frühling"), u"Frühling"); - ASSERT_EQ(GeneralUtils::UTF8ToUTF16("中文字"), u"中文字"); - ASSERT_EQ(GeneralUtils::UTF8ToUTF16("👨‍⚖️"), u"👨‍⚖️"); - - return 0; -} diff --git a/tests/AMFDeserializeTests.cpp b/tests/dCommonTests/AMFDeserializeTests.cpp similarity index 82% rename from tests/AMFDeserializeTests.cpp rename to tests/dCommonTests/AMFDeserializeTests.cpp index 8d4974a3..3811a706 100644 --- a/tests/AMFDeserializeTests.cpp +++ b/tests/dCommonTests/AMFDeserializeTests.cpp @@ -1,52 +1,65 @@ -#include <chrono> #include <fstream> -#include <iostream> #include <memory> +#include <gtest/gtest.h> #include "AMFDeserialize.h" #include "AMFFormat.h" -#include "CommonCxxTests.h" +/** + * Helper method that all tests use to get their respective AMF. + */ std::unique_ptr<AMFValue> ReadFromBitStream(RakNet::BitStream* bitStream) { AMFDeserialize deserializer; std::unique_ptr<AMFValue> returnValue(deserializer.Read(bitStream)); return returnValue; } -int ReadAMFUndefinedFromBitStream() { - CBITSTREAM; +/** + * @brief Test reading an AMFUndefined value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFUndefinedTest) { + CBITSTREAM bitStream.Write<uint8_t>(0x00); std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); ASSERT_EQ(res->GetValueType(), AMFValueType::AMFUndefined); - return 0; } -int ReadAMFNullFromBitStream() { - CBITSTREAM; +/** + * @brief Test reading an AMFNull value from a BitStream. + * + */ +TEST(dCommonTests, AMFDeserializeAMFNullTest) { + CBITSTREAM bitStream.Write<uint8_t>(0x01); std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); ASSERT_EQ(res->GetValueType(), AMFValueType::AMFNull); - return 0; } -int ReadAMFFalseFromBitStream() { - CBITSTREAM; +/** + * @brief Test reading an AMFFalse value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFFalseTest) { + CBITSTREAM bitStream.Write<uint8_t>(0x02); std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); ASSERT_EQ(res->GetValueType(), AMFValueType::AMFFalse); - return 0; } -int ReadAMFTrueFromBitStream() { - CBITSTREAM; +/** + * @brief Test reading an AMFTrue value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFTrueTest) { + CBITSTREAM bitStream.Write<uint8_t>(0x03); std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); ASSERT_EQ(res->GetValueType(), AMFValueType::AMFTrue); - return 0; } -int ReadAMFIntegerFromBitStream() { - CBITSTREAM; +/** + * @brief Test reading an AMFInteger value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFIntegerTest) { + CBITSTREAM { bitStream.Write<uint8_t>(0x04); // 127 == 01111111 @@ -91,21 +104,25 @@ int ReadAMFIntegerFromBitStream() { // Check that 2 byte max can be read correctly ASSERT_EQ(static_cast<AMFIntegerValue*>(res.get())->GetIntegerValue(), 16383); } - return 0; } -int ReadAMFDoubleFromBitStream() { - CBITSTREAM; +/** + * @brief Test reading an AMFDouble value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFDoubleTest) { + CBITSTREAM bitStream.Write<uint8_t>(0x05); bitStream.Write<double>(25346.4f); std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); ASSERT_EQ(res->GetValueType(), AMFValueType::AMFDouble); ASSERT_EQ(static_cast<AMFDoubleValue*>(res.get())->GetDoubleValue(), 25346.4f); - return 0; } -int ReadAMFStringFromBitStream() { - CBITSTREAM; +/** + * @brief Test reading an AMFString value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFStringTest) { + CBITSTREAM bitStream.Write<uint8_t>(0x06); bitStream.Write<uint8_t>(0x0F); std::string toWrite = "stateID"; @@ -113,11 +130,13 @@ int ReadAMFStringFromBitStream() { std::unique_ptr<AMFValue> res(ReadFromBitStream(&bitStream)); ASSERT_EQ(res->GetValueType(), AMFValueType::AMFString); ASSERT_EQ(static_cast<AMFStringValue*>(res.get())->GetStringValue(), "stateID"); - return 0; } -int ReadAMFArrayFromBitStream() { - CBITSTREAM; +/** + * @brief Test reading an AMFArray value from a BitStream. + */ +TEST(dCommonTests, AMFDeserializeAMFArrayTest) { + CBITSTREAM // Test empty AMFArray bitStream.Write<uint8_t>(0x09); bitStream.Write<uint8_t>(0x01); @@ -149,15 +168,15 @@ int ReadAMFArrayFromBitStream() { ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->FindValue<AMFStringValue>("BehaviorID")->GetStringValue(), "10447"); ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetValueAt<AMFStringValue>(0)->GetStringValue(), "10447"); } - // Test a dense array - return 0; } /** - * This test checks that if we recieve an unimplemented AMFValueType + * @brief This test checks that if we recieve an unimplemented AMFValueType * we correctly throw an error and can actch it. + * */ -int TestUnimplementedAMFValues() { +#pragma message("-- The AMFDeserializeUnimplementedValuesTest causes a known memory leak of 880 bytes since it throws errors! --") +TEST(dCommonTests, AMFDeserializeUnimplementedValuesTest) { std::vector<AMFValueType> unimplementedValues = { AMFValueType::AMFXMLDoc, AMFValueType::AMFDate, @@ -196,13 +215,15 @@ int TestUnimplementedAMFValues() { } catch (AMFValueType unimplementedValueType) { caughtException = true; } - std::cout << "Testing unimplemented value " << amfValueType << " Did we catch an exception: " << (caughtException ? "YES" : "NO") << std::endl; + ASSERT_EQ(caughtException, true); } - return 0; } -int TestLiveCapture() { +/** + * @brief Test reading a packet capture from live from a BitStream + */ +TEST(dCommonTests, AMFDeserializeLivePacketTest) { std::ifstream testFileStream; testFileStream.open("AMFBitStreamTest.bin", std::ios::binary); @@ -237,9 +258,9 @@ int TestLiveCapture() { ASSERT_EQ(actionIndex->GetDoubleValue(), 0.0f); - auto stripIDExecution = stripsPosition0->FindValue<AMFDoubleValue>("id"); + auto stripIdExecution = stripsPosition0->FindValue<AMFDoubleValue>("id"); - ASSERT_EQ(stripIDExecution->GetDoubleValue(), 0.0f); + ASSERT_EQ(stripIdExecution->GetDoubleValue(), 0.0f); auto stateIDExecution = executionState->FindValue<AMFDoubleValue>("stateID"); @@ -267,9 +288,9 @@ int TestLiveCapture() { auto actionID = firstStrip->FindValue<AMFDoubleValue>("id"); - ASSERT_EQ(actionID->GetDoubleValue(), 0.0f) + ASSERT_EQ(actionID->GetDoubleValue(), 0.0f); - auto uiArray = firstStrip->FindValue<AMFArrayValue>("ui"); + auto uiArray = firstStrip->FindValue<AMFArrayValue>("ui"); auto xPos = uiArray->FindValue<AMFDoubleValue>("x"); auto yPos = uiArray->FindValue<AMFDoubleValue>("y"); @@ -277,11 +298,11 @@ int TestLiveCapture() { ASSERT_EQ(xPos->GetDoubleValue(), 103.0f); ASSERT_EQ(yPos->GetDoubleValue(), 82.0f); - auto stripID = firstStrip->FindValue<AMFDoubleValue>("id"); + auto stripId = firstStrip->FindValue<AMFDoubleValue>("id"); - ASSERT_EQ(stripID->GetDoubleValue(), 0.0f) + ASSERT_EQ(stripId->GetDoubleValue(), 0.0f); - auto firstAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[0]); + auto firstAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[0]); auto firstType = firstAction->FindValue<AMFStringValue>("Type"); @@ -318,17 +339,17 @@ int TestLiveCapture() { auto thirdDistance = thirdAction->FindValue<AMFDoubleValue>("Distance"); ASSERT_EQ(thirdDistance->GetDoubleValue(), 25.0f); - - return 0; } -int TestNullStream() { +/** + * @brief Tests that having no BitStream returns a nullptr. + */ +TEST(dCommonTests, AMFDeserializeNullTest) { auto result = ReadFromBitStream(nullptr); ASSERT_EQ(result.get(), nullptr); - return 0; } -int TestBadConversion() { +TEST(dCommonTests, AMFBadConversionTest) { std::ifstream testFileStream; testFileStream.open("AMFBitStreamTest.bin", std::ios::binary); @@ -360,30 +381,6 @@ int TestBadConversion() { // Value is out of bounds ASSERT_EQ(result->GetValueAt<AMFTrueValue>(1), nullptr); - - return 0; -} - -int AMFDeserializeTests(int argc, char** const argv) { - std::cout << "Checking that using a null bitstream doesnt cause exception" << std::endl; - if (TestNullStream()) return 1; - std::cout << "passed nullptr test, checking basic tests" << std::endl; - if (ReadAMFUndefinedFromBitStream() != 0) return 1; - if (ReadAMFNullFromBitStream() != 0) return 1; - if (ReadAMFFalseFromBitStream() != 0) return 1; - if (ReadAMFTrueFromBitStream() != 0) return 1; - if (ReadAMFIntegerFromBitStream() != 0) return 1; - if (ReadAMFDoubleFromBitStream() != 0) return 1; - if (ReadAMFStringFromBitStream() != 0) return 1; - if (ReadAMFArrayFromBitStream() != 0) return 1; - std::cout << "Passed basic test, checking live capture" << std::endl; - if (TestLiveCapture() != 0) return 1; - std::cout << "Passed live capture, checking unimplemented amf values" << std::endl; - if (TestUnimplementedAMFValues() != 0) return 1; - std::cout << "Passed unimplemented values, checking poor casting" << std::endl; - if (TestBadConversion() != 0) return 1; - std::cout << "Passed all tests." << std::endl; - return 0; } /** diff --git a/tests/dCommonTests/CMakeLists.txt b/tests/dCommonTests/CMakeLists.txt new file mode 100644 index 00000000..86c00c58 --- /dev/null +++ b/tests/dCommonTests/CMakeLists.txt @@ -0,0 +1,19 @@ +set(DCOMMONTEST_SOURCES + "AMFDeserializeTests.cpp" + "TestLDFFormat.cpp" + "TestNiPoint3.cpp" + "TestEncoding.cpp" +) + +# Set our executable +add_executable(dCommonTests ${DCOMMONTEST_SOURCES}) + +# Link needed libraries +target_link_libraries(dCommonTests ${COMMON_LIBRARIES} GTest::gtest_main) + +# Copy test files to testing directory +add_subdirectory(TestBitStreams) +file(COPY ${TESTBITSTREAMS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +# Discover the tests +gtest_discover_tests(dCommonTests) diff --git a/tests/TestBitStreams/AMFBitStreamTest.bin b/tests/dCommonTests/TestBitStreams/AMFBitStreamTest.bin similarity index 100% rename from tests/TestBitStreams/AMFBitStreamTest.bin rename to tests/dCommonTests/TestBitStreams/AMFBitStreamTest.bin diff --git a/tests/TestBitStreams/AMFBitStreamUnimplementedTest.bin b/tests/dCommonTests/TestBitStreams/AMFBitStreamUnimplementedTest.bin similarity index 100% rename from tests/TestBitStreams/AMFBitStreamUnimplementedTest.bin rename to tests/dCommonTests/TestBitStreams/AMFBitStreamUnimplementedTest.bin diff --git a/tests/dCommonTests/TestBitStreams/CMakeLists.txt b/tests/dCommonTests/TestBitStreams/CMakeLists.txt new file mode 100644 index 00000000..93606df6 --- /dev/null +++ b/tests/dCommonTests/TestBitStreams/CMakeLists.txt @@ -0,0 +1,11 @@ +set(TESTBITSTREAMS + "AMFBitStreamTest.bin" + "AMFBitStreamUnimplementedTest.bin" +) + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM TESTBITSTREAMS PREPEND "${thisFolderName}/") + +# Export our list of files +set(TESTBITSTREAMS ${TESTBITSTREAMS} PARENT_SCOPE) diff --git a/tests/dCommonTests/TestEncoding.cpp b/tests/dCommonTests/TestEncoding.cpp new file mode 100644 index 00000000..c103ccbf --- /dev/null +++ b/tests/dCommonTests/TestEncoding.cpp @@ -0,0 +1,68 @@ +#include <string> +#include <gtest/gtest.h> +#include <string_view> + +#include "GeneralUtils.h" + +class EncodingTest : public ::testing::Test { +protected: + std::string originalWord; + std::string_view originalWordSv; + uint32_t out; +}; + +TEST_F(EncodingTest, TestEncodingHello) { + originalWord = "Hello World!"; + originalWordSv = originalWord; + + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'H'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'e'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'o'); + EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), true); + + EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Hello World!"), u"Hello World!"); +}; + +TEST_F(EncodingTest, TestEncodingUmlaut) { + originalWord = u8"Frühling"; + originalWordSv = originalWord; + + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'F'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'r'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'ü'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'h'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'l'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'i'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'n'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'g'); + EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + + EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Frühling"), u"Frühling"); +}; + +TEST_F(EncodingTest, TestEncodingChinese) { + originalWord = "中文字"; + originalWordSv = originalWord; + + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'中'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'文'); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'字'); + EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + + EXPECT_EQ(GeneralUtils::UTF8ToUTF16("中文字"), u"中文字"); +}; + +TEST_F(EncodingTest, TestEncodingEmoji) { + originalWord = "👨‍⚖️"; + originalWordSv = originalWord; + + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x1F468); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x200D); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x2696); + GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0xFE0F); + EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + + EXPECT_EQ(GeneralUtils::UTF8ToUTF16("👨‍⚖️"), u"👨‍⚖️"); +}; diff --git a/tests/TestLDFFormat.cpp b/tests/dCommonTests/TestLDFFormat.cpp similarity index 69% rename from tests/TestLDFFormat.cpp rename to tests/dCommonTests/TestLDFFormat.cpp index a7433e96..647c3cbf 100644 --- a/tests/TestLDFFormat.cpp +++ b/tests/dCommonTests/TestLDFFormat.cpp @@ -1,14 +1,10 @@ #include "LDFFormat.h" -#include "CommonCxxTests.h" +#include <gtest/gtest.h> /** * @brief Test parsing an LDF value - * - * @param argc Number of command line arguments for this test - * @param argv Command line arguments - * @return 0 on success, non-zero on failure */ -int TestLDFFormat(int argc, char** const argv) { +TEST(dCommonTests, LDFTest) { // Create auto* data = LDFBaseData::DataFromString("KEY=0:VALUE"); @@ -26,6 +22,4 @@ int TestLDFFormat(int argc, char** const argv) { // Cleanup the object delete data; - - return 0; } diff --git a/tests/TestNiPoint3.cpp b/tests/dCommonTests/TestNiPoint3.cpp similarity index 59% rename from tests/TestNiPoint3.cpp rename to tests/dCommonTests/TestNiPoint3.cpp index d1588b8b..33cd51d2 100644 --- a/tests/TestNiPoint3.cpp +++ b/tests/dCommonTests/TestNiPoint3.cpp @@ -1,13 +1,14 @@ -#include <stdexcept> +#include <gtest/gtest.h> #include "NiPoint3.h" -#include "CommonCxxTests.h" -int TestNiPoint3(int argc, char** const argv) { +/** + * @brief Basic test for NiPoint3 functionality + * + */ +TEST(dCommonTests, NiPoint3Test) { // Check that Unitize works ASSERT_EQ(NiPoint3(3, 0, 0).Unitize(), NiPoint3::UNIT_X); // Check what unitize does to a vector of length 0 ASSERT_EQ(NiPoint3::ZERO.Unitize(), NiPoint3::ZERO); - // If we get here, all was successful - return 0; } diff --git a/tests/dGameTests/CMakeLists.txt b/tests/dGameTests/CMakeLists.txt new file mode 100644 index 00000000..b1fdaa07 --- /dev/null +++ b/tests/dGameTests/CMakeLists.txt @@ -0,0 +1,19 @@ +set(DGAMETEST_SOURCES + "GameDependencies.cpp" +) + +add_subdirectory(dComponentsTests) +list(APPEND DGAMETEST_SOURCES ${DCOMPONENTS_TESTS}) + +add_subdirectory(dGameMessagesTests) +list(APPEND DGAMETEST_SOURCES ${DGAMEMESSAGES_TESTS}) + +file(COPY ${GAMEMESSAGE_TESTBITSTREAMS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +# Add the executable. Remember to add all tests above this! +add_executable(dGameTests ${DGAMETEST_SOURCES}) + +target_link_libraries(dGameTests ${COMMON_LIBRARIES} GTest::gtest_main dGame dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dChatFilter dNavigation) + +# Discover the tests +gtest_discover_tests(dGameTests) diff --git a/tests/dGameTests/GameDependencies.cpp b/tests/dGameTests/GameDependencies.cpp new file mode 100644 index 00000000..7b0a8412 --- /dev/null +++ b/tests/dGameTests/GameDependencies.cpp @@ -0,0 +1,13 @@ +#include "GameDependencies.h" + +namespace Game { + dLogger* logger; + dServer* server; + dZoneManager* zoneManager; + dChatFilter* chatFilter; + dConfig* config; + std::mt19937 randomEngine; + RakPeerInterface* chatServer; + AssetManager* assetManager; + SystemAddress chatSysAddr; +} diff --git a/tests/dGameTests/GameDependencies.h b/tests/dGameTests/GameDependencies.h new file mode 100644 index 00000000..353b53b8 --- /dev/null +++ b/tests/dGameTests/GameDependencies.h @@ -0,0 +1,50 @@ +#ifndef __GAMEDEPENDENCIES__H__ +#define __GAMEDEPENDENCIES__H__ + +#include "Game.h" +#include "dLogger.h" +#include "dServer.h" +#include "EntityInfo.h" +#include "EntityManager.h" +#include "dConfig.h" +#include <gtest/gtest.h> + +class dZoneManager; +class AssetManager; + +class dServerMock : public dServer { + RakNet::BitStream* sentBitStream = nullptr; +public: + dServerMock() {}; + ~dServerMock() {}; + RakNet::BitStream* GetMostRecentBitStream() { return sentBitStream; }; + void Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast) override { sentBitStream = bitStream; }; +}; + +class GameDependenciesTest : public ::testing::Test { +protected: + void SetUpDependencies() { + info.pos = NiPoint3::ZERO; + info.rot = NiQuaternion::IDENTITY; + info.scale = 1.0f; + info.spawner = nullptr; + info.lot = 999; + Game::logger = new dLogger("./testing.log", true, true); + Game::server = new dServerMock(); + Game::config = new dConfig("worldconfig.ini"); + } + + void TearDownDependencies() { + if (Game::server) delete Game::server; + delete EntityManager::Instance(); + if (Game::logger) { + Game::logger->Flush(); + delete Game::logger; + } + if (Game::config) delete Game::config; + } + + EntityInfo info; +}; + +#endif //!__GAMEDEPENDENCIES__H__ diff --git a/tests/dGameTests/dComponentsTests/CMakeLists.txt b/tests/dGameTests/dComponentsTests/CMakeLists.txt new file mode 100644 index 00000000..17e69a2f --- /dev/null +++ b/tests/dGameTests/dComponentsTests/CMakeLists.txt @@ -0,0 +1,10 @@ +set(DCOMPONENTS_TESTS + "DestroyableComponentTests.cpp" +) + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM DCOMPONENTS_TESTS PREPEND "${thisFolderName}/") + +# Export to parent scope +set(DCOMPONENTS_TESTS ${DCOMPONENTS_TESTS} PARENT_SCOPE) diff --git a/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp b/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp new file mode 100644 index 00000000..7399456d --- /dev/null +++ b/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp @@ -0,0 +1,532 @@ +#include "GameDependencies.h" +#include <gtest/gtest.h> + +#include "BitStream.h" +#include "DestroyableComponent.h" +#include "Entity.h" +#include "eReplicaComponentType.h" + +class DestroyableTest : public GameDependenciesTest { +protected: + Entity* baseEntity; + DestroyableComponent* destroyableComponent; + CBITSTREAM + uint32_t flags = 0; + void SetUp() override { + SetUpDependencies(); + baseEntity = new Entity(15, GameDependenciesTest::info); + destroyableComponent = new DestroyableComponent(baseEntity); + baseEntity->AddComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent); + // Initialize some values to be not default + destroyableComponent->SetMaxHealth(12345.0f); + destroyableComponent->SetHealth(23); + destroyableComponent->SetMaxArmor(14.0f); + destroyableComponent->SetArmor(7); + destroyableComponent->SetMaxImagination(14000.0f); + destroyableComponent->SetImagination(6000); + destroyableComponent->SetIsSmashable(true); + destroyableComponent->SetExplodeFactor(1.1f); + destroyableComponent->AddFactionNoLookup(-1); + destroyableComponent->AddFactionNoLookup(6); + } + + void TearDown() override { + delete baseEntity; + TearDownDependencies(); + } +}; + +/** + * Test Construction of a DestroyableComponent + */ +TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) { + destroyableComponent->Serialize(&bitStream, true, flags); + // Assert that the full number of bits are present + ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 748); + { + // Now read in the full serialized construction BitStream + bool optionStatusImmunityInfo{}; + uint32_t ImmuneToBasicAttackCount{}; + uint32_t ImmuneToDamageOverTimeCount{}; + uint32_t ImmuneToKnockbackCount{}; + uint32_t ImmuneToInterruptCount{}; + uint32_t ImmuneToSpeedCount{}; + uint32_t ImmuneToImaginationGainCount{}; + uint32_t ImmuneToImaginationLossCount{}; + uint32_t ImmuneToQuickbuildInterruptCount{}; + uint32_t ImmuneToPullToPointCount{}; + bool optionStatsInfo{}; + uint32_t currentHealth{}; + float maxHealth{}; + uint32_t currentArmor{}; + float maxArmor{}; + uint32_t currentImagination{}; + float maxImagination{}; + uint32_t damageAbsorptionPoints{}; + bool hasImmunity{}; + bool isGmImmune{}; + bool isShielded{}; + float actualMaxHealth{}; + float actualMaxArmor{}; + float actualMaxImagination{}; + uint32_t factionsSize{}; + std::vector<int32_t> factions{}; + bool isSmashable{}; + bool isDead{}; + bool isSmashed{}; + bool isModuleAssembly{}; + bool optionExplodeFactor{}; + float explodeFactor{}; + bool optionIsOnThreatList{}; + bool isThreatened{}; + bitStream.Read(optionStatusImmunityInfo); + bitStream.Read(ImmuneToBasicAttackCount); + bitStream.Read(ImmuneToDamageOverTimeCount); + bitStream.Read(ImmuneToKnockbackCount); + bitStream.Read(ImmuneToInterruptCount); + bitStream.Read(ImmuneToSpeedCount); + bitStream.Read(ImmuneToImaginationGainCount); + bitStream.Read(ImmuneToImaginationLossCount); + bitStream.Read(ImmuneToQuickbuildInterruptCount); + bitStream.Read(ImmuneToPullToPointCount); + bitStream.Read(optionStatsInfo); + bitStream.Read(currentHealth); + bitStream.Read(maxHealth); + bitStream.Read(currentArmor); + bitStream.Read(maxArmor); + bitStream.Read(currentImagination); + bitStream.Read(maxImagination); + bitStream.Read(damageAbsorptionPoints); + bitStream.Read(hasImmunity); + bitStream.Read(isGmImmune); + bitStream.Read(isShielded); + bitStream.Read(actualMaxHealth); + bitStream.Read(actualMaxArmor); + bitStream.Read(actualMaxImagination); + bitStream.Read(factionsSize); + for (uint32_t i = 0; i < factionsSize; i++) { + int32_t factionID{}; + bitStream.Read(factionID); + factions.push_back(factionID); + } + bitStream.Read(isSmashable); // This is an option later and also a flag at this spot + bitStream.Read(isDead); + bitStream.Read(isSmashed); + // if IsSmashable is true, read the next bits. + bitStream.Read(isModuleAssembly); + bitStream.Read(optionExplodeFactor); + bitStream.Read(explodeFactor); + + bitStream.Read(optionIsOnThreatList); + bitStream.Read(isThreatened); + EXPECT_EQ(optionStatusImmunityInfo, true); + EXPECT_EQ(ImmuneToBasicAttackCount, 0); + EXPECT_EQ(ImmuneToDamageOverTimeCount, 0); + EXPECT_EQ(ImmuneToKnockbackCount, 0); + EXPECT_EQ(ImmuneToInterruptCount, 0); + EXPECT_EQ(ImmuneToSpeedCount, 0); + EXPECT_EQ(ImmuneToImaginationGainCount, 0); + EXPECT_EQ(ImmuneToImaginationLossCount, 0); + EXPECT_EQ(ImmuneToQuickbuildInterruptCount, 0); + EXPECT_EQ(ImmuneToPullToPointCount, 0); + + EXPECT_EQ(optionStatsInfo, true); + EXPECT_EQ(currentHealth, 23); + EXPECT_EQ(maxHealth, 12345.0f); + EXPECT_EQ(currentArmor, 7); + EXPECT_EQ(maxArmor, 14.0f); + EXPECT_EQ(currentImagination, 6000); + EXPECT_EQ(maxImagination, 14000.0f); + EXPECT_EQ(damageAbsorptionPoints, 0.0f); + EXPECT_EQ(hasImmunity, false); + EXPECT_EQ(isGmImmune, false); + EXPECT_EQ(isShielded, false); + EXPECT_EQ(actualMaxHealth, 12345.0f); + EXPECT_EQ(actualMaxArmor, 14.0f); + EXPECT_EQ(actualMaxImagination, 14000.0f); + EXPECT_EQ(factionsSize, 2); + EXPECT_NE(std::find(factions.begin(), factions.end(), -1), factions.end()); + EXPECT_NE(std::find(factions.begin(), factions.end(), 6), factions.end()); + EXPECT_EQ(isSmashable, true); + EXPECT_EQ(isDead, false); + EXPECT_EQ(isSmashed, false); + EXPECT_EQ(isSmashable, true); // For the sake of readability with the struct viewers, we will test this twice since its used as an option here, but as a bool above. + EXPECT_EQ(isModuleAssembly, false); + EXPECT_EQ(optionExplodeFactor, true); + EXPECT_EQ(explodeFactor, 1.1f); + + EXPECT_EQ(optionIsOnThreatList, true); + EXPECT_EQ(isThreatened, false); + } + bitStream.Reset(); +} + +/** + * Test serialization of a DestroyableComponent + */ +TEST_F(DestroyableTest, DestroyableComponentSerializeTest) { + bitStream.Reset(); + // Initialize some values to be not default so we can test a full serialization + destroyableComponent->SetMaxHealth(1233.0f); + + // Now we test a serialization for correctness. + destroyableComponent->Serialize(&bitStream, false, flags); + ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 422); + { + // Now read in the full serialized BitStream + bool optionStatsInfo{}; + uint32_t currentHealth{}; + float maxHealth{}; + uint32_t currentArmor{}; + float maxArmor{}; + uint32_t currentImagination{}; + float maxImagination{}; + uint32_t damageAbsorptionPoints{}; + bool hasImmunity{}; + bool isGmImmune{}; + bool isShielded{}; + float actualMaxHealth{}; + float actualMaxArmor{}; + float actualMaxImagination{}; + uint32_t factionsSize{}; + std::vector<int32_t> factions{}; + bool isSmashable{}; + bool optionIsOnThreatList{}; + bitStream.Read(optionStatsInfo); + bitStream.Read(currentHealth); + bitStream.Read(maxHealth); + bitStream.Read(currentArmor); + bitStream.Read(maxArmor); + bitStream.Read(currentImagination); + bitStream.Read(maxImagination); + bitStream.Read(damageAbsorptionPoints); + bitStream.Read(hasImmunity); + bitStream.Read(isGmImmune); + bitStream.Read(isShielded); + bitStream.Read(actualMaxHealth); + bitStream.Read(actualMaxArmor); + bitStream.Read(actualMaxImagination); + bitStream.Read(factionsSize); + for (uint32_t i = 0; i < factionsSize; i++) { + int32_t factionID{}; + bitStream.Read(factionID); + factions.push_back(factionID); + } + bitStream.Read(isSmashable); + + bitStream.Read(optionIsOnThreatList); + + EXPECT_EQ(optionStatsInfo, true); + EXPECT_EQ(currentHealth, 23); + EXPECT_EQ(maxHealth, 1233.0f); + EXPECT_EQ(currentArmor, 7); + EXPECT_EQ(maxArmor, 14.0f); + EXPECT_EQ(currentImagination, 6000); + EXPECT_EQ(maxImagination, 14000.0f); + EXPECT_EQ(damageAbsorptionPoints, 0.0f); + EXPECT_EQ(hasImmunity, false); + EXPECT_EQ(isGmImmune, false); + EXPECT_EQ(isShielded, false); + EXPECT_EQ(actualMaxHealth, 1233.0f); + EXPECT_EQ(actualMaxArmor, 14.0f); + EXPECT_EQ(actualMaxImagination, 14000.0f); + EXPECT_EQ(factionsSize, 2); + EXPECT_NE(std::find(factions.begin(), factions.end(), -1), factions.end()); + EXPECT_NE(std::find(factions.begin(), factions.end(), 6), factions.end()); + EXPECT_EQ(isSmashable, true); + + EXPECT_EQ(optionIsOnThreatList, false); // Always zero for now on serialization + } +} + +/** + * Test the Damage method of DestroyableComponent + */ +TEST_F(DestroyableTest, DestroyableComponentDamageTest) { + // Do some actions + destroyableComponent->SetMaxHealth(100.0f); + destroyableComponent->SetHealth(100); + destroyableComponent->SetMaxArmor(0.0f); + destroyableComponent->Damage(10, LWOOBJID_EMPTY); + // Check that we take damage + ASSERT_EQ(destroyableComponent->GetHealth(), 90); + // Check that if we have armor, we take the correct amount of damage + destroyableComponent->SetMaxArmor(10.0f); + destroyableComponent->SetArmor(5); + destroyableComponent->Damage(10, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 85); + // Check that if we have damage absorption we take the correct damage + destroyableComponent->SetDamageToAbsorb(10); + destroyableComponent->Damage(9, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 85); + ASSERT_EQ(destroyableComponent->GetDamageToAbsorb(), 1); + destroyableComponent->Damage(6, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 80); + // Check that we take the correct reduced damage if we take reduced damage + destroyableComponent->SetDamageReduction(2); + destroyableComponent->Damage(7, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 75); + destroyableComponent->Damage(2, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 74); + ASSERT_EQ(destroyableComponent->GetDamageReduction(), 2); + destroyableComponent->SetDamageReduction(0); + // Check that blocking works + destroyableComponent->SetAttacksToBlock(1); + destroyableComponent->Damage(UINT32_MAX, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 74); + destroyableComponent->Damage(4, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 70); + // Check that immunity works + destroyableComponent->SetIsImmune(true); + destroyableComponent->Damage(UINT32_MAX, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 70); + ASSERT_TRUE(destroyableComponent->IsImmune()); + destroyableComponent->SetIsImmune(false); + destroyableComponent->SetIsGMImmune(true); + destroyableComponent->Damage(UINT32_MAX, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 70); + ASSERT_TRUE(destroyableComponent->IsImmune()); + destroyableComponent->SetIsGMImmune(false); + // Check knockback immunity + destroyableComponent->SetIsShielded(true); + ASSERT_TRUE(destroyableComponent->IsKnockbackImmune()); + // Finally deal enough damage to kill the Entity + destroyableComponent->Damage(71, LWOOBJID_EMPTY); + ASSERT_EQ(destroyableComponent->GetHealth(), 0); + // Now lets heal some stats + destroyableComponent->Heal(15); + ASSERT_EQ(destroyableComponent->GetHealth(), 15); + destroyableComponent->Heal(15000); + ASSERT_EQ(destroyableComponent->GetHealth(), 100); + destroyableComponent->Repair(10); + ASSERT_EQ(destroyableComponent->GetArmor(), 10); + destroyableComponent->Repair(15000); + ASSERT_EQ(destroyableComponent->GetArmor(), 10); + destroyableComponent->SetMaxImagination(100.0f); + destroyableComponent->SetImagination(0); + destroyableComponent->Imagine(99); + ASSERT_EQ(destroyableComponent->GetImagination(), 99); + destroyableComponent->Imagine(4); + ASSERT_EQ(destroyableComponent->GetImagination(), 100); +} + +TEST_F(DestroyableTest, DestroyableComponentFactionTest) { + ASSERT_TRUE(destroyableComponent->HasFaction(-1)); + ASSERT_TRUE(destroyableComponent->HasFaction(6)); +} + +TEST_F(DestroyableTest, DestroyableComponentValiditiyTest) { + auto* enemyEntity = new Entity(19, info); + auto* enemyDestroyableComponent = new DestroyableComponent(enemyEntity); + enemyEntity->AddComponent(eReplicaComponentType::DESTROYABLE, enemyDestroyableComponent); + enemyDestroyableComponent->AddFactionNoLookup(16); + destroyableComponent->AddEnemyFaction(16); + EXPECT_TRUE(destroyableComponent->IsEnemy(enemyEntity)); + EXPECT_FALSE(destroyableComponent->IsFriend(enemyEntity)); + delete enemyEntity; +} + +TEST_F(DestroyableTest, DestroyableComponentImmunityTest) { + // assert to show that they are empty + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // set them all to true (count 1) and check + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, true, true, true, true, true, true, true, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_TRUE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_TRUE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_TRUE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_TRUE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToPullToPoint()); + + // remove them to check that they get removed properly + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, true, true, true, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + + // should not crash to remove them again + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, true, true, true, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + + // just do one + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // now stack it to 2 on basic attack + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // remove one and still shoudl be true + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // go back to 0 + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + // check individual ones now + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, false, false, false, false, false, false, false, false); + ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, false, false, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, true, false, false, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_TRUE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, true, false, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, true, false, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_TRUE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, true, false, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, true, false, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_TRUE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, true, false, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, true, false, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, true, false, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, true, false, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, true, false, false, false); + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, true, false, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, true, false, false); + + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, false, true, false); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_TRUE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, false, true, false); + + + destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, false, false, true); + ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack()); + ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime()); + ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback()); + ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt()); + ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain()); + ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss()); + ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt()); + ASSERT_TRUE(destroyableComponent->GetImmuneToPullToPoint()); + destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, false, false, true); + +} + diff --git a/tests/dGameTests/dGameMessagesTests/CMakeLists.txt b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt new file mode 100644 index 00000000..54c43777 --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/CMakeLists.txt @@ -0,0 +1,14 @@ +SET(DGAMEMESSAGES_TESTS + "GameMessageTests.cpp") + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM DGAMEMESSAGES_TESTS PREPEND "${thisFolderName}/") + +# Copy test files to testing directory +add_subdirectory(TestBitStreams) +list(TRANSFORM GAMEMESSAGE_TESTBITSTREAMS PREPEND "${thisFolderName}/") +set(GAMEMESSAGE_TESTBITSTREAMS ${GAMEMESSAGE_TESTBITSTREAMS} PARENT_SCOPE) + +# Export to parent scope +set(DGAMEMESSAGES_TESTS ${DGAMEMESSAGES_TESTS} PARENT_SCOPE) diff --git a/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp new file mode 100644 index 00000000..631f0d2d --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp @@ -0,0 +1,226 @@ +#include "Action.h" +#include "AMFFormat.h" +#include "AMFDeserialize.h" +#include "GameMessages.h" +#include "GameDependencies.h" + +#include <gtest/gtest.h> + +// Message includes +#include "AddActionMessage.h" +#include "AddStripMessage.h" +#include "AddMessage.h" +#include "MigrateActionsMessage.h" +#include "MoveToInventoryMessage.h" +#include "MergeStripsMessage.h" +#include "RearrangeStripMessage.h" +#include "RemoveActionsMessage.h" +#include "RemoveStripMessage.h" +#include "RenameMessage.h" +#include "SplitStripMessage.h" +#include "UpdateActionMessage.h" +#include "UpdateStripUiMessage.h" + +class GameMessageTests: public GameDependenciesTest { +protected: + void SetUp() override { + SetUpDependencies(); + } + void TearDown() override { + TearDownDependencies(); + } + std::string ReadFromFile(std::string filename) { + std::ifstream file(filename, std::ios::binary); + std::string readFile; + while (file.good()) { + char readCharacter = file.get(); + readFile.push_back(readCharacter); + } + return readFile; + } + AMFArrayValue* ReadArrayFromBitStream(RakNet::BitStream* inStream) { + AMFDeserialize des; + AMFValue* readArray = des.Read(inStream); + EXPECT_EQ(readArray->GetValueType(), AMFValueType::AMFArray); + return static_cast<AMFArrayValue*>(readArray); + } +}; + +/** + * @brief Tests that the serialization struct BlueprintLoadItemResponse is serialized correctly + * + */ +TEST_F(GameMessageTests, SendBlueprintLoadItemResponse) { + GameMessages::SendBlueprintLoadItemResponse(UNASSIGNED_SYSTEM_ADDRESS, true, 515, 990); + auto* bitStream = static_cast<dServerMock*>(Game::server)->GetMostRecentBitStream(); + ASSERT_NE(bitStream, nullptr); + ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 200); + // First read in the packets' header + uint8_t rakNetPacketId{}; + uint16_t remoteConnectionType{}; + uint32_t packetId{}; + uint8_t always0{}; + + bitStream->Read(rakNetPacketId); + bitStream->Read(remoteConnectionType); + bitStream->Read(packetId); + bitStream->Read(always0); + ASSERT_EQ(rakNetPacketId, 0x53); + ASSERT_EQ(remoteConnectionType, 0x05); + ASSERT_EQ(packetId, 0x17); + ASSERT_EQ(always0, 0x00); + + // Next read in packet data + + uint8_t bSuccess{}; // unsigned bool + LWOOBJID previousId{}; + LWOOBJID newId{}; + bitStream->Read(bSuccess); + bitStream->Read(previousId); + bitStream->Read(newId); + ASSERT_EQ(bSuccess, static_cast<uint8_t>(true)); + ASSERT_EQ(previousId, 515); + ASSERT_EQ(newId, 990); + + ASSERT_EQ(bitStream->GetNumberOfUnreadBits(), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorAddStrip) { + auto data = ReadFromFile("addStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddStripMessage addStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_FLOAT_EQ(addStrip.GetPosition().GetX(), 50.65); + ASSERT_FLOAT_EQ(addStrip.GetPosition().GetY(), 178.05); + ASSERT_EQ(addStrip.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(addStrip.GetActionContext().GetStateId()), 0); + ASSERT_EQ(addStrip.GetBehaviorId(), -1); + ASSERT_EQ(addStrip.GetActionsToAdd().front().GetType(), "DropImagination"); + ASSERT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterName(), "Amount"); + ASSERT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterString(), ""); + ASSERT_FLOAT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterDouble(), 1.0); +} + +TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) { + auto data = ReadFromFile("removeStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RemoveStripMessage removeStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStripId()), 1); + ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStateId()), 0); + ASSERT_EQ(removeStrip.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorMergeStrips) { + auto data = ReadFromFile("mergeStrips"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + MergeStripsMessage mergeStrips(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(mergeStrips.GetSourceActionContext().GetStripId(), 2); + ASSERT_EQ(mergeStrips.GetDestinationActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetSourceActionContext().GetStateId()), 0); + ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetDestinationActionContext().GetStateId()), 0); + ASSERT_EQ(mergeStrips.GetDstActionIndex(), 0); + ASSERT_EQ(mergeStrips.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorSplitStrip) { + auto data = ReadFromFile("splitStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + SplitStripMessage splitStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(splitStrip.GetBehaviorId(), -1); + + ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetX(), 275.65); + ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetY(), 28.7); + ASSERT_EQ(splitStrip.GetSourceActionContext().GetStripId(), 0); + ASSERT_EQ(splitStrip.GetDestinationActionContext().GetStripId(), 2); + ASSERT_EQ(static_cast<uint32_t>(splitStrip.GetSourceActionContext().GetStateId()), 0); + ASSERT_EQ(static_cast<uint32_t>(splitStrip.GetDestinationActionContext().GetStateId()), 0); + ASSERT_EQ(splitStrip.GetSrcActionIndex(), 1); +} + +TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) { + auto data = ReadFromFile("updateStripUI"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + UpdateStripUiMessage updateStripUi(ReadArrayFromBitStream(&inStream)); + ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetX(), 116.65); + ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetY(), 35.35); + ASSERT_EQ(updateStripUi.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(updateStripUi.GetActionContext().GetStateId()), 0); + ASSERT_EQ(updateStripUi.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorAddAction) { + auto data = ReadFromFile("addAction"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddActionMessage addAction(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(addAction.GetActionIndex(), 3); + ASSERT_EQ(addAction.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(addAction.GetActionContext().GetStateId()), 0); + ASSERT_EQ(addAction.GetAction().GetType(), "DoDamage"); + ASSERT_EQ(addAction.GetAction().GetValueParameterName(), ""); + ASSERT_EQ(addAction.GetAction().GetValueParameterString(), ""); + ASSERT_EQ(addAction.GetAction().GetValueParameterDouble(), 0.0); + ASSERT_EQ(addAction.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorMigrateActions) { + auto data = ReadFromFile("migrateActions"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + MigrateActionsMessage migrateActions(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(migrateActions.GetSrcActionIndex(), 1); + ASSERT_EQ(migrateActions.GetDstActionIndex(), 2); + ASSERT_EQ(migrateActions.GetSourceActionContext().GetStripId(), 1); + ASSERT_EQ(migrateActions.GetDestinationActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(migrateActions.GetSourceActionContext().GetStateId()), 0); + ASSERT_EQ(static_cast<uint32_t>(migrateActions.GetDestinationActionContext().GetStateId()), 0); + ASSERT_EQ(migrateActions.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) { + auto data = ReadFromFile("rearrangeStrip"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RearrangeStripMessage rearrangeStrip(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(rearrangeStrip.GetSrcActionIndex(), 2); + ASSERT_EQ(rearrangeStrip.GetDstActionIndex(), 1); + ASSERT_EQ(rearrangeStrip.GetActionContext().GetStripId(), 0); + ASSERT_EQ(rearrangeStrip.GetBehaviorId(), -1); + ASSERT_EQ(static_cast<uint32_t>(rearrangeStrip.GetActionContext().GetStateId()), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorAdd) { + auto data = ReadFromFile("add"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + AddMessage add(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(add.GetBehaviorId(), 10446); + ASSERT_EQ(add.GetBehaviorIndex(), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorRemoveActions) { + auto data = ReadFromFile("removeActions"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RemoveActionsMessage removeActions(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(removeActions.GetBehaviorId(), -1); + ASSERT_EQ(removeActions.GetActionIndex(), 1); + ASSERT_EQ(removeActions.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(removeActions.GetActionContext().GetStateId()), 0); +} + +TEST_F(GameMessageTests, ControlBehaviorRename) { + auto data = ReadFromFile("rename"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + RenameMessage rename(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(rename.GetName(), "test"); + ASSERT_EQ(rename.GetBehaviorId(), -1); +} + +TEST_F(GameMessageTests, ControlBehaviorUpdateAction) { + auto data = ReadFromFile("updateAction"); + RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); + UpdateActionMessage updateAction(ReadArrayFromBitStream(&inStream)); + ASSERT_EQ(updateAction.GetAction().GetType(), "FlyDown"); + ASSERT_EQ(updateAction.GetAction().GetValueParameterName(), "Distance"); + ASSERT_EQ(updateAction.GetAction().GetValueParameterString(), ""); + ASSERT_EQ(updateAction.GetAction().GetValueParameterDouble(), 50.0); + ASSERT_EQ(updateAction.GetBehaviorId(), -1); + ASSERT_EQ(updateAction.GetActionIndex(), 1); + ASSERT_EQ(updateAction.GetActionContext().GetStripId(), 0); + ASSERT_EQ(static_cast<uint32_t>(updateAction.GetActionContext().GetStateId()), 0); +} diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt b/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt new file mode 100644 index 00000000..e32ed3ef --- /dev/null +++ b/tests/dGameTests/dGameMessagesTests/TestBitStreams/CMakeLists.txt @@ -0,0 +1,24 @@ +set(GAMEMESSAGE_TESTBITSTREAMS +"sendBehaviorListToClient" +"modelTypeChanged" +"toggleExecutionUpdates" +"addStrip" +"removeStrip" +"mergeStrips" +"splitStrip" +"updateStripUI" +"addAction" +"migrateActions" +"rearrangeStrip" +"add" +"removeActions" +"rename" +"updateAction" +) + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM GAMEMESSAGE_TESTBITSTREAMS PREPEND "${thisFolderName}/") + +# Export our list of files +set(GAMEMESSAGE_TESTBITSTREAMS ${GAMEMESSAGE_TESTBITSTREAMS} PARENT_SCOPE) diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/add b/tests/dGameTests/dGameMessagesTests/TestBitStreams/add new file mode 100644 index 00000000..13c0dd92 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/add differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/addAction b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addAction new file mode 100644 index 00000000..d91d0ee4 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addAction differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip new file mode 100644 index 00000000..60ba6521 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/addStrip differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/mergeStrips b/tests/dGameTests/dGameMessagesTests/TestBitStreams/mergeStrips new file mode 100644 index 00000000..062fd10b Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/mergeStrips differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/migrateActions b/tests/dGameTests/dGameMessagesTests/TestBitStreams/migrateActions new file mode 100644 index 00000000..217f44d9 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/migrateActions differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged b/tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged new file mode 100644 index 00000000..ef282ce2 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/modelTypeChanged differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip new file mode 100644 index 00000000..06dda90b Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rearrangeStrip differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions new file mode 100644 index 00000000..56e158e5 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeActions differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeStrip new file mode 100644 index 00000000..46ca0640 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/removeStrip differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/rename b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rename new file mode 100644 index 00000000..bc8827dc Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/rename differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient b/tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient new file mode 100644 index 00000000..fcca696d Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/sendBehaviorListToClient differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/splitStrip b/tests/dGameTests/dGameMessagesTests/TestBitStreams/splitStrip new file mode 100644 index 00000000..a23c1682 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/splitStrip differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates b/tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates new file mode 100644 index 00000000..02a72181 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/toggleExecutionUpdates differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction new file mode 100644 index 00000000..e007d5e6 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateAction differ diff --git a/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI new file mode 100644 index 00000000..7d0eed92 Binary files /dev/null and b/tests/dGameTests/dGameMessagesTests/TestBitStreams/updateStripUI differ diff --git a/thirdparty/LUnpack b/thirdparty/LUnpack deleted file mode 160000 index f8d7e442..00000000 --- a/thirdparty/LUnpack +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f8d7e442a78910b298fe1cd5780f07c9c9285b8c diff --git a/thirdparty/docker-utils b/thirdparty/docker-utils deleted file mode 160000 index 3f0129e0..00000000 --- a/thirdparty/docker-utils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3f0129e0939ce5ccf41f0808dcbbe71a6243e37f diff --git a/thirdparty/raknet/Source/SocketLayer.cpp b/thirdparty/raknet/Source/SocketLayer.cpp index b6af8751..6cb4f7c6 100644 --- a/thirdparty/raknet/Source/SocketLayer.cpp +++ b/thirdparty/raknet/Source/SocketLayer.cpp @@ -417,8 +417,14 @@ int SocketLayer::RecvFrom( const SOCKET s, RakPeer *rakPeer, int *errorCode, uns assert( 0 ); #endif - *errorCode = -1; - return -1; + //*errorCode = -1; +#ifdef __linux__ + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN); + printf("[RakNet] SocketLayer::RecvFrom: empty datagram from %s", str); +#endif + //return -1; + return 0; } if ( len > 0 ) @@ -479,6 +485,47 @@ int SocketLayer::RecvFrom( const SOCKET s, RakPeer *rakPeer, int *errorCode, uns } #endif } +#elif defined(__linux__) + if (len < -1) + { + printf("[RakNet] SocketLayer::RecvFrom: Unexpected return value."); + return -1; + } + + int local_errno = errno; + if (local_errno == EAGAIN || local_errno == EWOULDBLOCK) + { + return 0; // no data + } + + if (local_errno == EINTR) + { + printf("[RakNet] SocketLayer::RecvFrom: The receive was interrupted by delivery of a signal before any data were available."); + return 0; // log, but ignore + } + + char str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN); + printf("[RakNet] SocketLayer::RecvFrom: Error receiving data from %s", str); + + switch (local_errno) { + case EINVAL: + printf("[RakNet] SocketLayer::RecvFrom: Invalid argument passed."); break; + case ENOMEM: + case ENOBUFS: + printf("[RakNet] SocketLayer::RecvFrom: Could not allocate memory for recvmsg()."); break; + case EFAULT: + printf("[RakNet] SocketLayer::RecvFrom: The receive buffer pointer(s) point outside the process's address space."); break; + case EBADF: + printf("[RakNet] SocketLayer::RecvFrom: The argument sockfd is an invalid descriptor."); break; + case ENOTSOCK: + printf("[RakNet] SocketLayer::RecvFrom: The argument sockfd does not refer to a socket."); break; + case EPIPE: + printf("[RakNet] SocketLayer::RecvFrom: The connection was unexpectedly closed or shut down by the other end. "); break; + default: + printf("[RakNet] SocketLayer::RecvFrom: Unknown Error %d", local_errno); break; + } + return -1; #endif } diff --git a/vanity/CREDITS.md b/vanity/CREDITS.md index e130cfb3..6780cff7 100644 --- a/vanity/CREDITS.md +++ b/vanity/CREDITS.md @@ -1,18 +1,17 @@ # CREDITS -## Developers +## DLU Team DarwinAnim8or (Max) Wincent01 Mick averysumner (codeshaunted) Jon002 Jonny -EmosewaMC -Jettford - -## Research & Tooling Xiphoseer lcdr - -## Community Management +Aaron K. Neal + +## Active Contributors +EmosewaMC +Jettford \ No newline at end of file diff --git a/vanity/NPC.xml b/vanity/NPC.xml index 3bb5ae9f..2311ab46 100644 --- a/vanity/NPC.xml +++ b/vanity/NPC.xml @@ -17,6 +17,19 @@ </locations> </zone> </npc> + <npc name="EmosewaMC - Quickbuilder" lot="6738"> + <equipment>12947, 12949, 12962, 12963</equipment> + <phrases> + <phrase>I hope quickbulds are still working!</phrase> + <phrase>Be careful crossing the gap!</phrase> + <phrase>Have The Maelstrom stopped going invisible?</phrase> + </phrases> + <zone id="1800"> + <locations> + <location x="745.756" y="75.262" z="-207.989" rw="0.838565" rx="0.0" ry="0.544801" rz="0.0" /> + </locations> + </zone> + </npc> <npc name="Neal - Paradox Scout" lot="6738"> <equipment>9950, 9944, 14102, 14092</equipment> <phrases>