Compare commits

...

73 Commits

Author SHA1 Message Date
David Markowitz
05dc5d6fcd Add lots of logs 2023-01-07 20:30:36 -08:00
David Markowitz
c24c756f73 Merge branch 'pr/946' into MM12-Testing-branch 2023-01-07 19:59:21 -08:00
David Markowitz
bdb380aed2 Fix missing template 2023-01-07 19:57:47 -08:00
David Markowitz
2baef3f198 Merge remote-tracking branch 'upstream/main' 2023-01-07 19:50:42 -08:00
EmosewaMC
fbf7833b7b Removed build speedups 2023-01-07 12:53:48 -08:00
David Markowitz
8920cd1063 Use field names instead of numbers for CDClient tables (#945) 2023-01-07 01:48:59 -08:00
David Markowitz
05c67fd712 Add try catch around packet handling for sql error 2023-01-06 22:51:19 -08:00
David Markowitz
a580e3a2f5 Update lookup command (#909)
* Update lookup command

* Fix bugs

Update SlashCommandHandler.cpp
2023-01-07 00:17:09 -06:00
David Markowitz
a28a2e60cf Add property Teleport behavior (#846)
* Add property Teleport behavior

Untested.  Will mark pr as ready for review when this has been tested

* Fix issues
2023-01-07 00:16:43 -06:00
5374c555f5 Implement bubble seriliaztion in controllable physics (#942)
* bubble

* "Correct" serialization and enum

* Enum update

* figured out what things do

* accurate types and cleanup

* add sanity check
add getter
add slash command for testing

* fix default

* cleanup slash command

* handle game message probably
remove funny slash command
add all bubble GM's

Co-authored-by: Jett <55758076+Jettford@users.noreply.github.com>
2023-01-07 00:14:51 -06:00
80f8dd8003 Imminuty updates (#925)
* WIP Immunities

* Immunity getters

* remove redundent variable
replace it use with it's equivalent

* remove unused lookups, fix typos

* fix tests

* added imunity test

* address feedback

* more immunity tests

* explicit this
2023-01-06 23:59:19 -06:00
David Markowitz
1ac898ba00 Remove GameConfig (#874)
* Remove GameConfig

* Fully remove GmeConfig

* Update worldconfig.ini

Co-authored-by: Aaron Kimbrell <aronwk.aaron@gmail.com>
2023-01-06 23:21:40 -06:00
David Markowitz
fc75d6048f dGame Precompiled header improvements (#876)
* moving branch

* Add deleteinven slash command

* Change name of BRICKS_IN_BBB

* Use string_view instead of strcmp

* Clean up include tree

* Remove unneeded headers from PCH files

Removes unneeded headers from pre-compiled headers.  This increases compile time, however reduces development time for most files.

* Update Entity.h

* Update EntityManager.h

* Update GameMessages.cpp

* There it compiles now

Co-authored-by: Aaron Kimbrell <aronwk.aaron@gmail.com>
2023-01-06 23:17:05 -06:00
David Markowitz
9d4d618e63 Merge remote-tracking branch 'upstream/main' 2023-01-06 21:13:30 -08:00
David Markowitz
8bcb4bd36d Fix smashables not counting towards whole team (#944) 2023-01-06 23:06:24 -06:00
David Markowitz
bad3845d83 Address Docker issues and remove need to extract cdclient.fdb (#895)
* Implement a server res directory

* Only convert if neither exist

* Remove unzip, Update RegEx

* readme updates

Run setup after setting working dir

Address several docker issues

Revert "Run setup after setting working dir"

This reverts commit fd2fb9228e82a350204c1ef61f7ba059479bb12f.

Fix docker

* Remove extra submodules

* Rework logic

* Switch if block

* Remove need to extract fdb from client

* Change log name

* Update FdbToSqlite.cpp
2023-01-06 23:04:20 -06:00
Gie "Max" Vanommeslaeghe
7fcc8a6e84 Merge pull request #935 from EmosewaMC/WorldConfig
Eliminate WorldConfig Based Magic Numbers
2023-01-07 03:41:40 +01:00
David Markowitz
1a34f6f74a Fix debug logging newline (#940) 2023-01-04 08:15:06 -06:00
David Markowitz
1789ec7f20 delta compression fixes (#937) 2023-01-03 11:22:04 -06:00
David Markowitz
dc7d0ce142 Fix Stuns of duration zero (#938) 2023-01-03 11:21:57 -06:00
David Markowitz
203a150a56 Update DestroyableComponent.cpp 2023-01-01 16:36:10 -08:00
EmosewaMC
19be0a61b2 Eliminate WorldConfig Magic Numbers
Add comments for fields

Use the name directly
2023-01-01 05:20:03 -08:00
David Markowitz
6aa7c592a2 Merge remote-tracking branch 'upstream/main' 2023-01-01 02:10:36 -08:00
David Markowitz
09157506bf Fix Complete Overhaul (#934)
Check your pointers :)
2022-12-31 11:44:09 -08:00
David Markowitz
737eaba54d Serialize target with GameMessageStartSkill (#933) 2022-12-31 03:56:30 -08:00
David Markowitz
fab4414204 Fix serratorizer chargeup time (#931) 2022-12-31 03:56:12 -08:00
34b5f0f9d6 add uncast to speed behavior (#932) 2022-12-31 02:46:25 -06:00
David Markowitz
68187d9f96 Merge remote-tracking branch 'upstream/main' 2022-12-30 02:34:19 -08:00
David Markowitz
9adbb7aa86 Address World Server Packet timing and erroneous log (#929)
* Fix overread in projectile behavior

* Fix stuns

* Correctly read in bitStream

* Fix projectile behavior

* Address movement type issues

* Update shutdown time to be accurate

* Fix small issues
2022-12-29 08:34:53 -06:00
David Markowitz
bd28e4051f Fix Hash Collisions in CDBehaviorParameter table (#930)
* Fix hashing

* Update CDBehaviorParameterTable.cpp
2022-12-29 03:43:52 -06:00
David Markowitz
716e8c646c Fix small issues 2022-12-28 18:21:26 -08:00
David Markowitz
d2cecd0073 Merge remote-tracking branch 'upstream/main' 2022-12-28 16:43:19 -08:00
David Markowitz
99c0ca253c Basic Attack Behavior Live Accuracy Improvements (#926)
* Overhaul BasicAttack Behavior so it matches the live 1.10.64 client
2022-12-28 14:04:37 -08:00
David Markowitz
0e9c0a8917 Fix MovementSwitch Behavior (#927) 2022-12-28 14:03:07 -08:00
David Markowitz
e41ed68447 Update README (#806)
* Update README

The README is very out of date, the following changes have been made
- Update what the file tree should look like
- Remove client Avant Gardens Survival script fix
- Update some incorrect commands or commands that were missing packages.
- Add packed client setup instructions
- Add *config.ini setup instructions
- Describe what configs should be modified and what you may want to change
- More detail in the verify step
- Change Account Manager link to Nexus Dashboard
- Remove table of commands and reference Commands.md instead
- Specify that UGCSERVERIP may need to be changed to localhost as well

* Fix Avant Gardens Survival

This addresses the Avant Gardens Survival bug.  Squeezing it in with the README changes since it is a small change.

* Remove Locale

* Update README.md

Co-authored-by: Jonathan Romano <jonathan@luxaritas.com>

* Remove dLocale again?

* Saving for the night

* Revert "Fix Avant Gardens Survival"

This reverts commit b1a1ce2d84.

* Update Mission.cpp

* Update README.md

Move comments and add pre-processor define

Update README.md

Update README.md

Update CMakePresets.json

Update CMakeVariables.txt

Update README.md

i love readmes

Update README.md

Update README.md

Update README.md

Update README.md

Update README.md

Update README.md

Update README.md

* Update README.md

Co-authored-by: Daniel Seiler <me@xiphoseer.de>

* Address feedback

* Update README.md

* Update Database.cpp

* Update README.md

* Revert tcp specification

Co-authored-by: Jonathan Romano <jonathan@luxaritas.com>
Co-authored-by: Aaron Kimbrell <aronwk.aaron@gmail.com>
Co-authored-by: Daniel Seiler <me@xiphoseer.de>
2022-12-28 13:58:53 -08:00
EmosewaMC
d97f374a90 Merge remote-tracking branch 'upstream/main' 2022-12-27 19:26:24 -08:00
5cc7d47074 sanity check on opening packages (#923) 2022-12-24 14:41:13 -08:00
David Markowitz
1470af99c3 Correct Property FX incorrect skill cast (#920) 2022-12-24 04:06:27 -08:00
David Markowitz
85ab573665 Fix duping issue (#921) 2022-12-24 09:51:59 +01:00
6ec921025d Use new logic for applying speed changes in ApplyBuff (#919) 2022-12-24 00:49:31 -08:00
David Markowitz
bbd5a49ea2 Update DarkInspirationBehavior.cpp (#897) 2022-12-23 18:05:30 -08:00
EmosewaMC
a6c6474e67 Merge remote-tracking branch 'upstream/main' 2022-12-23 04:12:38 -08:00
David Markowitz
675cf1d2a4 Fix baseEnemyApe stuns and fix IdleFlags serialization (#914)
* Fix baseEnemyApe stuns

* Correct serialization
2022-12-23 00:14:51 -06:00
9ebb06ba24 Qb team credit (#912)
* give credit to whole team for qb's

* fix compiling
2022-12-22 07:24:59 -06:00
David Markowitz
96313ecd69 Calculate world shutdown timer (#910) 2022-12-22 05:16:35 -08:00
David Markowitz
015cbc06ea Fix racing spawn positions (#913) 2022-12-22 05:16:18 -08:00
David Markowitz
dff02773a0 Fix dragon stuns (#915) 2022-12-22 05:16:08 -08:00
David Markowitz
d052ed6a63 Update MigrationRunner.cpp (#911) 2022-12-22 06:06:59 -06:00
David Markowitz
fd9757d121 Implement a server res directory for server required client files (#891) 2022-12-21 22:34:11 -08:00
David Markowitz
bd7f532a28 Implement the Imaginite Backpack and Shard armor scripts (#886)
* Imaginite Pack now works

* Remove unused params

* Address issues

* Add TeslaPack script

Co-authored-by: aronwk-aaron <aronwk.aaron@gmail.com>
2022-12-21 14:33:41 -08:00
EmosewaMC
dbdf4ac46a Update shutdown time to be accurate 2022-12-21 14:06:42 -08:00
David Markowitz
51dd56f0a0 Add MTU config option (#908)
* Add config option

* Add reloading
2022-12-21 10:51:27 -06:00
David Markowitz
6ed504c88e Merge remote-tracking branch 'upstream/main' 2022-12-21 02:26:45 -08:00
David Markowitz
9be2ab03b6 Address movement type issues 2022-12-21 02:00:46 -08:00
David Markowitz
38eb441ca1 Correct Projectile behavior bitStream reads (#907) 2022-12-21 00:26:17 -08:00
David Markowitz
e53e31021f Fix projectile behavior 2022-12-20 19:05:30 -08:00
David Markowitz
41b8762c8f Merge remote-tracking branch 'upstream/main' 2022-12-20 14:45:15 -08:00
Gie "Max" Vanommeslaeghe
559894024c Merge pull request #889 from EmosewaMC/MoreImprovements
Continued improvements to Servers
2022-12-20 23:11:24 +01:00
Neal Spellman
0a31db9d44 Updated README and CREDITS (#904)
- README now has proper capitalization for categories in the credits.
- New layout with former contributors moved to below active contributors.
- LEGO Universe credits linked for the special thanks.
- Aronwk properly recognized as DLU team member after mistakenly not included.
- Vanity credits updated to more closely mirror categories in README's credits.
2022-12-20 14:10:54 -08:00
David Markowitz
f2fa81b5c3 Fix lobbies (#901) 2022-12-20 15:20:44 -06:00
EmosewaMC
da07a70d4d Merge remote-tracking branch 'upstream/main' 2022-12-19 17:59:56 -08:00
David Markowitz
9f47b1f0bb Merge remote-tracking branch 'upstream/main' into MoreImprovements 2022-12-19 03:53:51 -08:00
David Markowitz
d78b2958d3 Correctly read in bitStream 2022-12-19 00:24:39 -08:00
David Markowitz
9cfc126842 Fix stuns 2022-12-18 20:44:30 -08:00
David Markowitz
56e3d07669 Fix overread in projectile behavior 2022-12-18 15:57:40 -08:00
David Markowitz
2b56dfbc89 Merge remote-tracking branch 'upstream/main' into MoreImprovements 2022-12-16 19:08:51 -08:00
David Markowitz
b33a3df012 Scale timers 2022-12-16 04:02:54 -08:00
David Markowitz
0d460c0eb3 Update WorldServer timings 2022-12-16 03:46:38 -08:00
David Markowitz
3f1b4339f5 Improve chat and Auth
Also change most uses of int to specified lengths.
2022-12-16 02:24:02 -08:00
David Markowitz
e78dc0b874 Merge branch 'MoreImprovements' of https://github.com/EmosewaMC/DarkflameServer into MoreImprovements 2022-12-16 01:28:52 -08:00
David Markowitz
b1d4153f00 Merge remote-tracking branch 'upstream/main' into MoreImprovements 2022-12-16 01:28:34 -08:00
EmosewaMC
3c581fffbb Remove magic numbers
Replace magic numbers with constexpr calculated times.

Tested that trying to create a new instance while shutting down doesn't allow a new instance to be created.
2022-12-15 20:39:29 -08:00
EmosewaMC
4775dbf27f Condense frame rates 2022-12-15 19:55:07 -08:00
237 changed files with 4043 additions and 2473 deletions

6
.gitmodules vendored
View File

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

View File

@@ -89,8 +89,8 @@ 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 /resServer directory
make_directory(${CMAKE_BINARY_DIR}/resServer)
# Create a /logs directory
make_directory(${CMAKE_BINARY_DIR}/logs)
@@ -176,6 +176,7 @@ set(INCLUDED_DIRECTORIES
"dScripts/ai"
"dScripts/client"
"dScripts/EquipmentScripts"
"dScripts/EquipmentTriggers"
"dScripts/zone"
"dScripts/02_server/DLU"
"dScripts/02_server/Enemy"

View File

@@ -23,10 +23,7 @@
"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/opt/openssl@3/"
}
"inherits": "default"
},
{
"name": "ci-windows-2022",

View File

@@ -8,15 +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.
__enable_testing__=1
__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/

View File

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

View File

@@ -25,7 +25,7 @@
11. Once the command has completed (you can see you path again and can enter commands), close the window.
12. Inside the downloaded folder, copy `.env.example` and name the copy `.env`
13. Open `.env` with Notepad by right-clicking it and selecting _Open With_ -> _More apps_ -> _Notepad_.
14. Change the text after `CLIENT_PATH=` to the location of your client. The folder you are pointing to must contain a folder called `client` which should contain the client files.
14. Change the text after `CLIENT_PATH=` to the location of your client. This folder must contain either a folder `client` or `legouniverse.exe`.
> If you need the extra performance, place the client files in `\\wsl$\<your linux OS>\...` to avoid working across file systems, see [Docker Best Practices](https://docs.docker.com/desktop/windows/wsl/#best-practices) and [WSL documentation](https://docs.microsoft.com/en-us/windows/wsl/filesystems#file-storage-and-performance-across-file-systems).
15. Optionally, you can change the number after `BUILD_THREADS=` to the number of cores / threads your processor has. If your computer crashes while building, you can try to reduce this value.

611
README.md
View File

@@ -18,210 +18,188 @@ Darkflame Universe is licensed under AGPLv3, please read [LICENSE](LICENSE). Som
Throughout the entire build and setup process a level of familiarity with the command line and preferably a Unix-like development environment is greatly advantageous.
### Hosting a server
We do not recommend hosting public servers. DLU is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks.
We do not recommend hosting public servers. Darkflame Universe is intended for small scale deployment, for example within a group of friends. It has not been tested for large scale deployment which comes with additional security risks.
### Supply of resource files
Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed in the resources tab below when checking if a client will work.
Darkflame Universe is a server emulator and does not distribute any LEGO® Universe files. A separate game client is required to setup this server emulator and play the game, which we cannot supply. Users are strongly suggested to refer to the safe checksums listed [here](#verifying-your-client-files) to see if a client will work.
## Build
Development of the latest iteration of Darkflame Universe has been done primarily in a Unix-like environment and is where it has been tested and designed for deployment. It is therefore highly recommended that Darkflame Universe be built and deployed using a Unix-like environment for the most streamlined experience.
## Steps to setup server
* [Clone this repository](#clone-the-repository)
* [Install dependencies](#install-dependencies)
* [Database setup](#database-setup)
* [Build the server](#build-the-server)
* [Configuring your server](#configuring-your-server)
* [Required Configuration](#required-configuration)
* [Optional Configuration](#optional-configuration)
* [Verify your setup](#verify-your-setup)
* [Running the server](#running-the-server)
* [User Guide](#user-guide)
### Prerequisites
#### Clone the repository
## Clone the repository
If you are on Windows, you will need to download and install git from [here](https://git-scm.com/download/win)
Then run the following command
```bash
git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
```
#### Python
Some tools utilized to streamline the setup process require Python 3, make sure you have it installed.
## Install dependencies
### Windows packages
Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed.
You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.18**</font> or later!).
### Choosing the right version for your client
DLU clients identify themselves using a higher version number than the regular live clients out there.
This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client.
### MacOS packages
Ensure you have [brew](https://brew.sh) installed.
You will need to install the following packages
```bash
brew install cmake gcc mariadb openssl zlib
```
If you're using a DLU client you'll have to go into the "CMakeVariables.txt" file and change the NET_VERSION variable to 171023 to match the modified client's version number.
### Linux packages
Make sure packages like `gcc`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. You will also need a MySQL database solution to use. We recommend using `mariadb-server`.
### Enabling testing
While it is highly recommended to enable testing, if you would like to save compilation time, you'll want to comment out the enable_testing variable in CMakeVariables.txt.
It is recommended that after building and if testing is enabled, to run `ctest` and make sure all the tests pass.
For Ubuntu, you would run the following commands. On other systems, the package install command will differ.
### Using Docker
Refer to [Docker.md](/Docker.md).
```bash
sudo apt update && sudo apt upgrade
For Windows, refer to [Docker_Windows.md](/Docker_Windows.md).
# Install packages
sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-server cmake
```
### 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`.
#### Required CMake version
This project uses <font size="4">**CMake version 3.18**</font> or higher and as such you will need to ensure you have this version installed.
You can check your CMake version by using the following command in a terminal.
```bash
cmake --version
```
CMake must be version 3.14 or higher!
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.
#### Build the repository
The general approach to do so would be to obtain a copy of the signing key and then add the CMake repository to your apt.
You can do so with the following commands.
[Source of the below commands](https://askubuntu.com/questions/355565/how-do-i-install-the-latest-version-of-cmake-from-the-command-line)
```bash
# Remove the old version of CMake
sudo apt purge --auto-remove cmake
# Prepare for installation
sudo apt update && sudo apt install -y software-properties-common lsb-release && sudo apt clean all
# Obtain a copy of the signing key
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
# Add the repository to your sources list.
sudo apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main"
# Next you'll want to ensure that Kitware's keyring stays up to date
sudo apt update
sudo apt install kitware-archive-keyring
sudo rm /etc/apt/trusted.gpg.d/kitware.gpg
# If sudo apt update above returned an error, copy the public key at the end of the error message and run the following command
# if the error message was "The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 6AF7F09730B3F0A4"
# then the below command would be "sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6AF7F09730B3F0A4"
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys <TheCopiedPublicKey>
# Finally update and install
sudo apt update
sudo apt install cmake
```
## Database setup
First you'll need to start MariaDB.
For Windows the service is always running by default.
For MacOS, run the following command
```bash
brew services start mariadb
```
For Linux, run the following command
```bash
sudo systemctl start mysql
# If systemctl is not a known command on your distribution, try the following instead
sudo service mysql start
```
<font size="4">**You will need to run this command every time you restart your environment**</font>
If you are using Linux and `systemctl` and want the MariaDB instance to start on startup, run the following command
```bash
sudo systemctl enable --now mysql
```
Once MariaDB is started, you'll need to create a user and an empty database for Darkflame Universe to use.
First, login to the MariaDB instance.
To do this on Ubuntu/Linux, MacOS, or another Unix like operating system, run the following command in a terminal
```bash
# Logs you into the MariaDB instance as root
sudo mysql
```
For Windows, run the following command in the `Command Prompt (MariaDB xx.xx)` terminal
```bash
# Logs you into the mysql instance
mysql -u root -p
# You will then be prompted for the password you set for root during installation of MariaDB
```
Now that you are logged in, run the following commands.
```bash
# Creates a user for this computer which uses a password and grant said user all privileges.
# Change mydarkflameuser to a custom username and password to a custom password.
GRANT ALL ON *.* TO 'mydarkflameuser'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION;
FLUSH PRIVILEGES;
# Then create a database for Darkflame Universe to use.
CREATE DATABASE darkflame;
```
## Build the server
You can either run `build.sh` when in the root folder of the repository:
```bash
./build.sh
```
Or manually run the commands used in `build.sh`:
Or manually run the commands used in [build.sh](build.sh).
```bash
# Create the build directory, preserving it if it already exists
mkdir -p build
cd build
### 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.
# Run CMake to generate make files
cmake ..
## Configuring your server
This server has a few steps that need to be taken to configure the server for your use case.
# 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
```
### 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.
### MacOS builds
Ensure `cmake`, `zlib` and `open ssl` are installed as well as a compiler (e.g `clang` or `gcc`).
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
# Run CMake to generate build files
cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl
# Get cmake to build the project. If make files are being used then using make and appending `-j` and the amount of cores to utilize may be preferable, for example `make -j8`
cmake --build . --config Release
```
### Windows builds (native)
Ensure that you have either the [MSVC](https://visualstudio.microsoft.com/vs/) or the [Clang](https://github.com/llvm/llvm-project/releases/) (recommended) compiler installed. You will also need to install [CMake](https://cmake.org/download/). Currently on native Windows the server will only work in Release mode.
#### Build the repository
```batch
:: Create the build directory
mkdir build
cd build
:: Run CMake to generate make files
cmake ..
:: Run CMake with build flag to build
cmake --build . --config Release
```
#### Windows for ARM has not been tested but should build by doing the following
```batch
:: Create the build directory
mkdir build
cd build
:: Run CMake to generate make files
cmake .. -DMARIADB_BUILD_SOURCE=ON
:: Run CMake with build flag to build
cmake --build . --config Release
```
### Windows builds (WSL)
This section will go through how to install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and building in a Linux environment under Windows. WSL requires Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11.
#### Open the Command Prompt application with Administrator permissions and run the following:
```bash
# Installing Windows Subsystem for Linux
wsl --install
```
#### Open the Ubuntu application and run the following:
```bash
# Make sure the install is up to date
apt update && apt upgrade
# Make sure the gcc, cmake, and build-essentials are installed
sudo apt install gcc
sudo apt install cmake
sudo apt install build-essential
```
[**Follow the Linux instructions**](#linux-builds)
### ARM builds
AArch64 builds should work on linux and MacOS using their respective build steps. Windows ARM should build but it has not been tested
### Updating your build
To update your server to the latest version navigate to your cloned directory
```bash
cd /path/to/DarkflameServer
```
run the following commands to update to the latest changes
```bash
git pull
git submodule update --init --recursive
```
now follow the build section for your system
## Setting up the environment
### Resources
#### LEGO® Universe 1.10.64
This repository does not distribute any LEGO® Universe files. A full install of LEGO® Universe version 1.10.64 (latest) is required to finish setting up Darkflame Universe.
Known good SHA256 checksums of the client:
- `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed)
- `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed)
- `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
Known good *SHA1* checksum of the DLU client:
- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed)
How to generate a SHA256 checksum:
```bash
# Replace <file> with the file path to the client
# If on Linux or MacOS
shasum -a 256 <file>
# If on Windows
certutil -hashfile <file> SHA256
```
#### Unpacking the client
* Clone lcdr's utilities repository [here](https://github.com/lcdr/utils)
* Use `pkextractor.pyw` to unpack the client files if they are not already unpacked
#### Setup resource directory
* In the `build` directory create a `res` directory if it does not already exist.
* Copy over or create symlinks from `macros`, `BrickModels`, `chatplus_en_us.txt`, `names`, and `maps` in your client `res` directory to the server `build/res` directory
* Unzip the navmeshes [here](./resources/navmeshes.zip) and place them in `build/res/maps/navmeshes`
#### Setup locale
* In the `build` directory create a `locale` directory if it does not already exist
* Copy over or create symlinks from `locale.xml` in your client `locale` directory to the `build/locale` directory
#### Client database
* 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
@@ -230,42 +208,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:`
@@ -273,159 +244,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.
### Brick-By-Brick building
## 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.
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.
<font size="4">**If you do not plan on doing any Brick Building, then you can skip this step.**</font>
### 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).
The easiest way to do this is to install [python](https://www.python.org/downloads/).
<table>
<thead>
<th>
Command
</th>
<th>
Usage
</th>
<th>
Description
</th>
<th>
Admin Level Requirement
</th>
</thead>
<tbody>
<tr>
<td>
info
</td>
<td>
/info
</td>
<td>
Displays server info to the user, including where to find the server's source code.
</td>
<td>
</td>
</tr>
<tr>
<td>
credits
</td>
<td>
/credits
</td>
<td>
Displays the names of the people behind Darkflame Universe.
</td>
<td>
</td>
</tr>
<tr>
<td>
instanceinfo
</td>
<td>
/instanceinfo
</td>
<td>
Displays in the chat the current zone, clone, and instance id.
</td>
<td>
</td>
</tr>
<tr>
<td>
gmlevel
</td>
<td>
/gmlevel &#60;level&#62;
</td>
<td>
Within the authorized range of levels for the current account, changes the character's game master level to the specified value. This is required to use certain commands.
</td>
<td>
</td>
</tr>
<tr>
<td>
testmap
</td>
<td>
/testmap &#60;zone&#62; (clone-id)
</td>
<td>
Transfers you to the given zone by id and clone id.
</td>
<td>
1
</td>
</tr>
<tr>
<td>
ban
</td>
<td>
/ban &#60;username&#62;
</td>
<td>
Bans a user from the server.
</td>
<td>
4
</td>
</tr>
<tr>
<td>
gmadditem
</td>
<td>
/gmadditem &#60;id&#62; (count)
</td>
<td>
Adds the given item to your inventory by id.
</td>
<td>
8
</td>
</tr>
<tr>
<td>
spawn
</td>
<td>
/spawn &#60;id&#62;
</td>
<td>
Spawns an object at your location by id.
</td>
<td>
8
</td>
</tr>
<tr>
<td>
metrics
</td>
<td>
/metrics
</td>
<td>
Prints some information about the server's performance.
</td>
<td>
8
</td>
</tr>
</tbody>
</table>
### 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
# 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
```
## 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.
## In-game commands
* A list of all in-game commands can be found [here](./docs/Commands.md).
## Verifying your client files
### LEGO® Universe 1.10.64
To verify that you are indeed using a LEGO® Universe 1.10.64 client, make sure you have the full client compressed **in a rar file** and run the following command.
```bash
# Replace <file> with the file path to the zipped client
# If on Linux or MacOS
shasum -a 256 <file>
# If on Windows using the Command Prompt
certutil -hashfile <file> SHA256
```
Below are known good SHA256 checksums of the client:
* `8f6c7e84eca3bab93232132a88c4ae6f8367227d7eafeaa0ef9c40e86c14edf5` (packed client, rar compressed)
* `c1531bf9401426042e8bab2de04ba1b723042dc01d9907c2635033d417de9e05` (packed client, includes extra locales, rar compressed)
* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64.
### Darkflame Universe Client
Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there.
This was done make sure that older and incomplete clients wouldn't produce false positive bug reports for us, and because we made bug fixes and new content for the client.
To verify that you are indeed using a Darkflame Universe client, make sure you have the full client compressed **in a zip file** and run the following command.
```bash
# Replace <file> with the file path to the zipped client
# If on Linux or MacOS
shasum -a 1 <file>
# If on Windows using the Command Prompt
certutil -hashfile <file> SHA1
```
Known good *SHA1* checksum of the Darkflame Universe client:
- `91498e09b83ce69f46baf9e521d48f23fe502985` (packed client, zip compressed)
# Development Documentation
This is a Work in Progress, but below are some quick links to documentaion for systems and structs in the server
[Networked message structs](https://lcdruniverse.org/lu_packets/lu_packets/index.html)
[General system documentation](https://docs.lu-dev.net/en/latest/index.html)
# Credits
## Active Contributors
* [EmosewaMC](https://github.com/EmosewaMC)
* [Jettford](https://github.com/Jettford)
* [Aaron K.](https://github.com/aronwk-aaron)
## DLU Team
* [DarwinAnim8or](https://github.com/DarwinAnim8or)
@@ -434,25 +334,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)

View File

@@ -32,6 +32,8 @@ 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();
@@ -67,7 +69,7 @@ int main(int argc, char** argv) {
//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()) {
@@ -79,8 +81,8 @@ 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.
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());
@@ -89,16 +91,18 @@ int main(int argc, char** argv) {
//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 (!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;
@@ -114,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()) {
@@ -138,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);
}

View File

@@ -19,6 +19,9 @@
#include "ChatPacketHandler.h"
#include "Game.h"
//RakNet includes:
#include "RakNetDefines.h"
namespace Game {
dLogger* logger = nullptr;
dServer* server = nullptr;
@@ -28,8 +31,6 @@ namespace Game {
bool shouldShutdown = false;
}
//RakNet includes:
#include "RakNetDefines.h"
dLogger* SetupLogger();
void HandlePacket(Packet* packet);
@@ -37,6 +38,8 @@ 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();
@@ -65,7 +68,7 @@ int main(int argc, char** argv) {
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;
}
@@ -87,7 +90,7 @@ int main(int argc, char** argv) {
//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()) {
@@ -99,8 +102,8 @@ 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;
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());
@@ -111,16 +114,18 @@ int main(int argc, char** argv) {
//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 (!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;
@@ -136,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()) {
@@ -160,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);
}

View File

@@ -10,10 +10,11 @@
#include "GeneralUtils.h"
#include "Game.h"
#include "dLogger.h"
#include "AssetManager.h"
#include "eSqliteDataType.h"
std::map<eSqliteDataType, std::string> FdbToSqlite::Convert::sqliteType = {
std::map<eSqliteDataType, std::string> FdbToSqlite::Convert::m_SqliteType = {
{ eSqliteDataType::NONE, "none"},
{ eSqliteDataType::INT32, "int32"},
{ eSqliteDataType::REAL, "real"},
@@ -23,20 +24,23 @@ std::map<eSqliteDataType, std::string> FdbToSqlite::Convert::sqliteType = {
{ eSqliteDataType::TEXT_8, "text_8"}
};
FdbToSqlite::Convert::Convert(std::string basePath) {
this->basePath = basePath;
FdbToSqlite::Convert::Convert(std::string binaryOutPath) {
this->m_BinaryOutPath = binaryOutPath;
}
bool FdbToSqlite::Convert::ConvertDatabase() {
fdb.open(basePath + "/cdclient.fdb", std::ios::binary);
bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
if (m_ConversionStarted) return false;
std::istream cdClientBuffer(&buffer);
this->m_ConversionStarted = true;
try {
CDClientDatabase::Connect(basePath + "/CDServer.sqlite");
CDClientDatabase::Connect(m_BinaryOutPath + "/CDServer.sqlite");
CDClientDatabase::ExecuteQuery("BEGIN TRANSACTION;");
int32_t numberOfTables = ReadInt32();
ReadTables(numberOfTables);
int32_t numberOfTables = ReadInt32(cdClientBuffer);
ReadTables(numberOfTables, cdClientBuffer);
CDClientDatabase::ExecuteQuery("COMMIT;");
} catch (CppSQLite3Exception& e) {
@@ -44,138 +48,133 @@ bool FdbToSqlite::Convert::ConvertDatabase() {
return false;
}
fdb.close();
return true;
}
int32_t FdbToSqlite::Convert::ReadInt32() {
int32_t FdbToSqlite::Convert::ReadInt32(std::istream& cdClientBuffer) {
int32_t nextInt{};
BinaryIO::BinaryRead(fdb, nextInt);
BinaryIO::BinaryRead(cdClientBuffer, nextInt);
return nextInt;
}
int64_t FdbToSqlite::Convert::ReadInt64() {
int32_t prevPosition = SeekPointer();
int64_t FdbToSqlite::Convert::ReadInt64(std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(cdClientBuffer);
int64_t value{};
BinaryIO::BinaryRead(fdb, value);
BinaryIO::BinaryRead(cdClientBuffer, value);
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
return value;
}
std::string FdbToSqlite::Convert::ReadString() {
int32_t prevPosition = SeekPointer();
std::string FdbToSqlite::Convert::ReadString(std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(cdClientBuffer);
auto readString = BinaryIO::ReadString(fdb);
auto readString = BinaryIO::ReadString(cdClientBuffer);
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
return readString;
}
int32_t FdbToSqlite::Convert::SeekPointer() {
int32_t FdbToSqlite::Convert::SeekPointer(std::istream& cdClientBuffer) {
int32_t position{};
BinaryIO::BinaryRead(fdb, position);
int32_t prevPosition = fdb.tellg();
fdb.seekg(position);
BinaryIO::BinaryRead(cdClientBuffer, position);
int32_t prevPosition = cdClientBuffer.tellg();
cdClientBuffer.seekg(position);
return prevPosition;
}
std::string FdbToSqlite::Convert::ReadColumnHeader() {
int32_t prevPosition = SeekPointer();
std::string FdbToSqlite::Convert::ReadColumnHeader(std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(cdClientBuffer);
int32_t numberOfColumns = ReadInt32();
std::string tableName = ReadString();
int32_t numberOfColumns = ReadInt32(cdClientBuffer);
std::string tableName = ReadString(cdClientBuffer);
auto columns = ReadColumns(numberOfColumns);
auto columns = ReadColumns(numberOfColumns, cdClientBuffer);
std::string newTable = "CREATE TABLE IF NOT EXISTS '" + tableName + "' (" + columns + ");";
CDClientDatabase::ExecuteDML(newTable);
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
return tableName;
}
void FdbToSqlite::Convert::ReadTables(int32_t& numberOfTables) {
int32_t prevPosition = SeekPointer();
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();
ReadRowHeader(columnHeader);
auto columnHeader = ReadColumnHeader(cdClientBuffer);
ReadRowHeader(columnHeader, cdClientBuffer);
}
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
}
std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns) {
std::string FdbToSqlite::Convert::ReadColumns(int32_t& numberOfColumns, std::istream& cdClientBuffer) {
std::stringstream columnsToCreate;
int32_t prevPosition = SeekPointer();
int32_t prevPosition = SeekPointer(cdClientBuffer);
std::string name{};
eSqliteDataType dataType{};
for (int32_t i = 0; i < numberOfColumns; i++) {
if (i != 0) columnsToCreate << ", ";
dataType = static_cast<eSqliteDataType>(ReadInt32());
name = ReadString();
columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::sqliteType[dataType];
dataType = static_cast<eSqliteDataType>(ReadInt32(cdClientBuffer));
name = ReadString(cdClientBuffer);
columnsToCreate << "'" << name << "' " << FdbToSqlite::Convert::m_SqliteType[dataType];
}
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
return columnsToCreate.str();
}
void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName) {
int32_t prevPosition = SeekPointer();
void FdbToSqlite::Convert::ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(cdClientBuffer);
int32_t numberOfAllocatedRows = ReadInt32();
int32_t numberOfAllocatedRows = ReadInt32(cdClientBuffer);
if (numberOfAllocatedRows != 0) assert((numberOfAllocatedRows & (numberOfAllocatedRows - 1)) == 0); // assert power of 2 allocation size
ReadRows(numberOfAllocatedRows, tableName);
ReadRows(numberOfAllocatedRows, tableName, cdClientBuffer);
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
}
void FdbToSqlite::Convert::ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName) {
int32_t prevPosition = SeekPointer();
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();
int32_t rowPointer = ReadInt32(cdClientBuffer);
if (rowPointer == -1) rowid++;
else ReadRow(rowid, rowPointer, tableName);
else ReadRow(rowPointer, tableName, cdClientBuffer);
}
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
}
void FdbToSqlite::Convert::ReadRow(int32_t& rowid, int32_t& position, std::string& tableName) {
int32_t prevPosition = fdb.tellg();
fdb.seekg(position);
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);
int32_t linked = ReadInt32();
rowid += 1;
ReadRowInfo(tableName, cdClientBuffer);
int32_t linked = ReadInt32(cdClientBuffer);
if (linked == -1) break;
fdb.seekg(linked);
cdClientBuffer.seekg(linked);
}
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
}
void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName) {
int32_t prevPosition = SeekPointer();
void FdbToSqlite::Convert::ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(cdClientBuffer);
int32_t numberOfColumns = ReadInt32();
ReadRowValues(numberOfColumns, tableName);
int32_t numberOfColumns = ReadInt32(cdClientBuffer);
ReadRowValues(numberOfColumns, tableName, cdClientBuffer);
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
}
void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName) {
int32_t prevPosition = SeekPointer();
void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string& tableName, std::istream& cdClientBuffer) {
int32_t prevPosition = SeekPointer(cdClientBuffer);
int32_t emptyValue{};
int32_t intValue{};
@@ -189,26 +188,26 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string&
for (int32_t i = 0; i < numberOfColumns; i++) {
if (i != 0) insertedRow << ", "; // Only append comma and space after first entry in row.
switch (static_cast<eSqliteDataType>(ReadInt32())) {
switch (static_cast<eSqliteDataType>(ReadInt32(cdClientBuffer))) {
case eSqliteDataType::NONE:
BinaryIO::BinaryRead(fdb, emptyValue);
BinaryIO::BinaryRead(cdClientBuffer, emptyValue);
assert(emptyValue == 0);
insertedRow << "NULL";
break;
case eSqliteDataType::INT32:
intValue = ReadInt32();
intValue = ReadInt32(cdClientBuffer);
insertedRow << intValue;
break;
case eSqliteDataType::REAL:
BinaryIO::BinaryRead(fdb, floatValue);
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();
stringValue = ReadString(cdClientBuffer);
size_t position = 0;
// Need to escape quote with a double of ".
@@ -224,12 +223,12 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string&
}
case eSqliteDataType::INT_BOOL:
BinaryIO::BinaryRead(fdb, boolValue);
BinaryIO::BinaryRead(cdClientBuffer, boolValue);
insertedRow << static_cast<bool>(boolValue);
break;
case eSqliteDataType::INT64:
int64Value = ReadInt64();
int64Value = ReadInt64(cdClientBuffer);
insertedRow << std::to_string(int64Value);
break;
@@ -244,5 +243,5 @@ void FdbToSqlite::Convert::ReadRowValues(int32_t& numberOfColumns, std::string&
auto copiedString = insertedRow.str();
CDClientDatabase::ExecuteDML(copiedString);
fdb.seekg(prevPosition);
cdClientBuffer.seekg(prevPosition);
}

View File

@@ -7,43 +7,139 @@
#include <iosfwd>
#include <map>
class AssetMemoryBuffer;
enum class eSqliteDataType : int32_t;
namespace FdbToSqlite {
class Convert {
public:
Convert(std::string inputFile);
/**
* 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);
bool ConvertDatabase();
/**
* 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);
int32_t ReadInt32();
/**
* @brief Reads a 32 bit int from the fdb file.
*
* @return The read value
*/
int32_t ReadInt32(std::istream& cdClientBuffer);
int64_t ReadInt64();
/**
* @brief Reads a 64 bit integer from the fdb file.
*
* @return The read value
*/
int64_t ReadInt64(std::istream& cdClientBuffer);
std::string ReadString();
/**
* @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);
int32_t SeekPointer();
/**
* @brief Seeks to a pointer position.
*
* @return The previous position before the seek
*/
int32_t SeekPointer(std::istream& cdClientBuffer);
std::string ReadColumnHeader();
/**
* @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);
void ReadTables(int32_t& numberOfTables);
/**
* @brief Read the tables from the fdb file.
*
* @param numberOfTables The number of tables to read
*/
void ReadTables(int32_t& numberOfTables, std::istream& cdClientBuffer);
std::string ReadColumns(int32_t& numberOfColumns);
/**
* @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);
void ReadRowHeader(std::string& tableName);
/**
* @brief Reads the row header from the fdb file.
*
* @param tableName The tables name
*/
void ReadRowHeader(std::string& tableName, std::istream& cdClientBuffer);
void ReadRows(int32_t& numberOfAllocatedRows, std::string& tableName);
/**
* @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);
void ReadRow(int32_t& rowid, int32_t& position, std::string& tableName);
/**
* @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);
void ReadRowInfo(std::string& tableName);
/**
* @brief Reads the row info from the fdb file.
*
* @param tableName The tables name
*/
void ReadRowInfo(std::string& tableName, std::istream& cdClientBuffer);
void ReadRowValues(int32_t& numberOfColumns, std::string& tableName);
/**
* @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:
static std::map<eSqliteDataType, std::string> sqliteType;
std::string basePath{};
std::ifstream fdb{};
}; // class FdbToSqlite
/**
* Maps each sqlite data type to its string equivalent.
*/
static std::map<eSqliteDataType, std::string> m_SqliteType;
/**
* Base path of the folder containing the fdb file
*/
std::string m_BasePath{};
/**
* Whether or not a conversion was started. If one was started, do not attempt to convert the file again.
*/
bool m_ConversionStarted{};
/**
* The path where the CDServer will be stored
*/
std::string m_BinaryOutPath{};
}; //! class FdbToSqlite
}; //! namespace FdbToSqlite
#endif //!__FDBTOSQLITE__H__

View File

@@ -45,9 +45,6 @@ AssetManager::AssetManager(const std::filesystem::path& path) {
switch (m_AssetBundleType) {
case eAssetBundleType::Packed: {
this->LoadPackIndex();
this->UnpackRequiredAssets();
break;
}
}
@@ -160,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;

View File

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

View File

@@ -24,7 +24,6 @@ public:
* Reloads the config file to reset values
*/
void ReloadConfig();
private:
void ProcessLine(const std::string& line);

View File

@@ -6,7 +6,7 @@
/**
* Represents the possible states a mission can be in
*/
enum class MissionState : int {
enum class MissionState : int32_t {
/**
* The mission state is unknown
*/

View File

@@ -6,15 +6,25 @@
#include <cstdint>
#include <string>
#include <set>
#include "../thirdparty/raknet/Source/BitStream.h"
#include "BitStream.h"
#pragma warning (disable:4251) //Disables SQL warnings
typedef int RESTICKET;
const int highFrameRate = 16; //60fps
const int mediumFramerate = 33; //30fps
const int lowFramerate = 66; //15fps
// These are the same define, but they mean two different things in different contexts
// so a different define to distinguish what calculation is happening will help clarity.
#define FRAMES_TO_MS(x) 1000 / x
#define MS_TO_FRAMES(x) 1000 / x
//=========== FRAME TIMINGS ===========
constexpr uint32_t highFramerate = 60;
constexpr uint32_t mediumFramerate = 30;
constexpr uint32_t lowFramerate = 15;
constexpr uint32_t highFrameDelta = FRAMES_TO_MS(highFramerate);
constexpr uint32_t mediumFrameDelta = FRAMES_TO_MS(mediumFramerate);
constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
//========== MACROS ===========
@@ -356,7 +366,7 @@ enum eControlSceme {
SCHEME_WEAR_A_ROBOT //== freecam?
};
enum eStunState {
enum class eStateChangeType : uint32_t {
PUSH,
POP
};

View File

@@ -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,
@@ -512,6 +518,7 @@ enum GAME_MSG : unsigned short {
GAME_MSG_UPDATE_CHAT_MODE = 1395,
GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE = 1396,
GAME_MSG_SET_CONSUMABLE_ITEM = 1409,
GAME_MSG_SET_STATUS_IMMUNITY = 1435,
GAME_MSG_SET_PET_NAME_MODERATED = 1448,
GAME_MSG_MODIFY_LEGO_SCORE = 1459,
GAME_MSG_RESTORE_TO_POST_LOAD_STATS = 1468,

View File

@@ -0,0 +1,12 @@
#ifndef __EBASICATTACKSUCCESSTYPES__H__
#define __EBASICATTACKSUCCESSTYPES__H__
#include <cstdint>
enum class eBasicAttackSuccessTypes : uint8_t {
SUCCESS = 1,
FAILARMOR,
FAILIMMUNE
};
#endif //!__EBASICATTACKSUCCESSTYPES__H__

View File

@@ -0,0 +1,14 @@
#pragma once
#ifndef __EBUBBLETYPE__H__
#define __EBUBBLETYPE__H__
#include <cstdint>
enum class eBubbleType : uint32_t {
DEFAULT = 0,
ENERGY = 1,
SKUNK = 2,
};
#endif //!__EBUBBLETYPE__H__

View File

@@ -0,0 +1,16 @@
#ifndef __EMOVEMENTPLATFORMSTATE__H__
#define __EMOVEMENTPLATFORMSTATE__H__
#include <cstdint>
/**
* The different types of platform movement state, supposedly a bitmap
*/
enum class eMovementPlatformState : uint32_t
{
Moving = 0b00010,
Stationary = 0b11001,
Stopped = 0b01100
};
#endif //!__EMOVEMENTPLATFORMSTATE__H__

View File

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

View File

@@ -54,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());

View File

@@ -21,25 +21,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();
@@ -70,3 +70,4 @@ std::vector<CDActivities> CDActivitiesTable::Query(std::function<bool(CDActiviti
std::vector<CDActivities> CDActivitiesTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -21,13 +21,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();
@@ -58,3 +58,4 @@ std::vector<CDActivityRewards> CDActivityRewardsTable::Query(std::function<bool(
std::vector<CDActivityRewards> CDActivityRewardsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -21,19 +21,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();
@@ -64,3 +64,4 @@ std::vector<CDAnimations> CDAnimationsTable::Query(std::function<bool(CDAnimatio
std::vector<CDAnimations> CDAnimationsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -4,25 +4,23 @@
//! 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();
@@ -38,32 +36,30 @@ std::string CDBehaviorParameterTable::GetName(void) const {
return "BehaviorParameter";
}
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;
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;
size_t hash = 0;
GeneralUtils::hash_combine(hash, behaviorID);
GeneralUtils::hash_combine(hash, name);
uint64_t hash = behaviorID;
hash = (hash << 31U) | parameterID->second;
// Search for specific parameter
const auto& it = m_Entries.find(hash);
return it != m_Entries.end() ? it->second : returnValue;
return it != m_Entries.end() ? it->second.value : defaultValue;
}
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
size_t hash;
uint64_t hashBase = behaviorID;
std::map<std::string, float> returnInfo;
for (auto parameterCandidate : m_ParametersList) {
hash = 0;
GeneralUtils::hash_combine(hash, behaviorID);
GeneralUtils::hash_combine(hash, parameterCandidate);
uint64_t hash;
for (auto& parameterCandidate : m_ParametersList) {
hash = (hashBase << 31U) | parameterCandidate.second;
auto infoCandidate = m_Entries.find(hash);
if (infoCandidate != m_Entries.end()) {
returnInfo.insert(std::make_pair(*(infoCandidate->second.parameterID), infoCandidate->second.value));
returnInfo.insert(std::make_pair(infoCandidate->second.parameterID->first, infoCandidate->second.value));
}
}
return returnInfo;
}

View File

@@ -12,16 +12,16 @@
//! BehaviorParameter Entry Struct
struct CDBehaviorParameter {
unsigned int behaviorID; //!< The Behavior ID
std::unordered_set<std::string>::iterator parameterID; //!< The Parameter ID
float value; //!< The value of the behavior template
unsigned int behaviorID; //!< The Behavior ID
std::unordered_map<std::string, uint32_t>::iterator parameterID; //!< The Parameter ID
float value; //!< The value of the behavior template
};
//! BehaviorParameter table
class CDBehaviorParameterTable : public CDTable {
private:
std::unordered_map<size_t, CDBehaviorParameter> m_Entries;
std::unordered_set<std::string> m_ParametersList;
std::unordered_map<uint64_t, CDBehaviorParameter> m_Entries;
std::unordered_map<std::string, uint32_t> m_ParametersList;
public:
//! Constructor
@@ -36,7 +36,7 @@ public:
*/
std::string GetName(void) const override;
CDBehaviorParameter GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0);
float GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0);
std::map<std::string, float> GetParametersByBehaviorID(uint32_t behaviorID);
};

View File

@@ -21,9 +21,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()) {
@@ -75,3 +75,4 @@ const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behav
return entry->second;
}
}

View File

@@ -21,8 +21,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();
@@ -53,3 +53,4 @@ std::vector<CDBrickIDTable> CDBrickIDTableTable::Query(std::function<bool(CDBric
std::vector<CDBrickIDTable> CDBrickIDTableTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -24,9 +24,9 @@ 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 = tableData.getIntField("component_type", -1);
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);
@@ -91,9 +91,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 +126,4 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componen
return defaultValue;
#endif
}

View File

@@ -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();
@@ -56,3 +56,4 @@ std::vector<CDCurrencyTable> CDCurrencyTableTable::Query(std::function<bool(CDCu
std::vector<CDCurrencyTable> CDCurrencyTableTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -65,3 +65,4 @@ std::vector<CDDestructibleComponent> CDDestructibleComponentTable::Query(std::fu
std::vector<CDDestructibleComponent> CDDestructibleComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -42,3 +42,4 @@ CDEmoteTable* CDEmoteTableTable::GetEmote(int id) {
return nullptr;
}

View File

@@ -19,7 +19,7 @@ struct CDEmoteTable {
channel = -1;
locked = false;
localize = false;
gateVersion = -1;
gateVersion = "";
}
int ID;
@@ -29,7 +29,7 @@ struct CDEmoteTable {
int channel;
bool locked;
bool localize;
int gateVersion;
std::string gateVersion;
};
//! CDEmoteTable table

View File

@@ -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();
@@ -66,3 +66,4 @@ bool CDFeatureGatingTable::FeatureUnlocked(const std::string& feature) const {
std::vector<CDFeatureGating> CDFeatureGatingTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -55,3 +55,4 @@ std::vector<CDInventoryComponent> CDInventoryComponentTable::Query(std::function
std::vector<CDInventoryComponent> CDInventoryComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -101,48 +101,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 +177,4 @@ std::map<LOT, uint32_t> CDItemComponentTable::ParseCraftingCurrencies(const CDIt
return currencies;
}

View File

@@ -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();
@@ -65,3 +65,4 @@ std::vector<CDItemSetSkills> CDItemSetSkillsTable::GetBySkillID(unsigned int Ski
return toReturn;
}

View File

@@ -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();
@@ -66,3 +66,4 @@ std::vector<CDItemSets> CDItemSetsTable::Query(std::function<bool(CDItemSets)> p
std::vector<CDItemSets> CDItemSetsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -54,3 +54,4 @@ std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::Query(std::
std::vector<CDLevelProgressionLookup> CDLevelProgressionLookupTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -60,3 +60,4 @@ std::vector<CDLootMatrix> CDLootMatrixTable::Query(std::function<bool(CDLootMatr
const std::vector<CDLootMatrix>& CDLootMatrixTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -57,3 +57,4 @@ std::vector<CDLootTable> CDLootTableTable::Query(std::function<bool(CDLootTable)
const std::vector<CDLootTable>& CDLootTableTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -59,3 +59,4 @@ std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMiss
std::vector<CDMissionEmail> CDMissionEmailTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -56,3 +56,4 @@ std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::Query(std::functi
std::vector<CDMissionNPCComponent> CDMissionNPCComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -78,3 +78,4 @@ std::vector<CDMissionTasks*> CDMissionTasksTable::GetByMissionID(uint32_t missio
const std::vector<CDMissionTasks>& CDMissionTasksTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -131,3 +131,4 @@ const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& foun
return Default;
}

View File

@@ -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();
@@ -59,3 +59,4 @@ std::vector<CDMovementAIComponent> CDMovementAIComponentTable::Query(std::functi
std::vector<CDMovementAIComponent> CDMovementAIComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -55,3 +55,4 @@ std::vector<CDObjectSkills> CDObjectSkillsTable::Query(std::function<bool(CDObje
std::vector<CDObjectSkills> CDObjectSkillsTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -71,20 +71,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 +100,4 @@ const CDObjects& CDObjectsTable::GetByID(unsigned int LOT) {
return m_default;
}

View File

@@ -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();
@@ -54,3 +54,4 @@ std::vector<CDPackageComponent> CDPackageComponentTable::Query(std::function<boo
std::vector<CDPackageComponent> CDPackageComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -47,3 +47,4 @@ CDPhysicsComponent* CDPhysicsComponentTable::GetByID(unsigned int componentID) {
return nullptr;
}

View File

@@ -18,11 +18,11 @@ CDPropertyEntranceComponentTable::CDPropertyEntranceComponentTable() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PropertyEntranceComponent;");
while (!tableData.eof()) {
auto entry = CDPropertyEntranceComponent{
static_cast<uint32_t>(tableData.getIntField(0, -1)),
static_cast<uint32_t>(tableData.getIntField(1, -1)),
tableData.getStringField(2, ""),
static_cast<bool>(tableData.getIntField(3, false)),
tableData.getStringField(4, "")
static_cast<uint32_t>(tableData.getIntField("id", -1)),
static_cast<uint32_t>(tableData.getIntField("mapID", -1)),
tableData.getStringField("propertyName", ""),
static_cast<bool>(tableData.getIntField("isOnProperty", false)),
tableData.getStringField("groupType", "")
};
this->entries.push_back(entry);
@@ -46,3 +46,4 @@ CDPropertyEntranceComponent CDPropertyEntranceComponentTable::GetByID(uint32_t i
return defaultEntry;
}

View File

@@ -17,10 +17,10 @@ CDPropertyTemplateTable::CDPropertyTemplateTable() {
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PropertyTemplate;");
while (!tableData.eof()) {
auto entry = CDPropertyTemplate{
static_cast<uint32_t>(tableData.getIntField(0, -1)),
static_cast<uint32_t>(tableData.getIntField(1, -1)),
static_cast<uint32_t>(tableData.getIntField(2, -1)),
tableData.getStringField(3, "")
static_cast<uint32_t>(tableData.getIntField("id", -1)),
static_cast<uint32_t>(tableData.getIntField("mapID", -1)),
static_cast<uint32_t>(tableData.getIntField("vendorMapID", -1)),
tableData.getStringField("spawnName", "")
};
this->entries.push_back(entry);
@@ -44,3 +44,4 @@ CDPropertyTemplate CDPropertyTemplateTable::GetByMapID(uint32_t mapID) {
return defaultEntry;
}

View File

@@ -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();
@@ -55,3 +55,4 @@ std::vector<CDProximityMonitorComponent> CDProximityMonitorComponentTable::Query
std::vector<CDProximityMonitorComponent> CDProximityMonitorComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -70,3 +70,4 @@ std::pair<uint32_t, std::u16string> CDRailActivatorComponentTable::EffectPairFro
return {};
}

View File

@@ -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();
@@ -55,3 +55,4 @@ std::vector<CDRarityTable> CDRarityTableTable::Query(std::function<bool(CDRarity
const std::vector<CDRarityTable>& CDRarityTableTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -61,3 +61,4 @@ std::vector<CDRebuildComponent> CDRebuildComponentTable::Query(std::function<boo
std::vector<CDRebuildComponent> CDRebuildComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -38,3 +38,4 @@ std::vector<CDRewards*> CDRewardsTable::GetByLevelID(uint32_t levelID) {
return result;
}

View File

@@ -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();
@@ -45,3 +45,4 @@ const CDScriptComponent& CDScriptComponentTable::GetByID(unsigned int id) {
return m_ToReturnWhenNoneFound;
}

View File

@@ -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);
@@ -82,3 +82,4 @@ const CDSkillBehavior& CDSkillBehaviorTable::GetSkillByID(unsigned int skillID)
return m_empty;
}

View File

@@ -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();
@@ -56,3 +56,4 @@ std::vector<CDVendorComponent> CDVendorComponentTable::Query(std::function<bool(
std::vector<CDVendorComponent> CDVendorComponentTable::GetEntries(void) const {
return this->entries;
}

View File

@@ -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();
@@ -71,3 +71,4 @@ const CDZoneTable* CDZoneTableTable::Query(unsigned int zoneID) {
return nullptr;
}

View File

@@ -17,6 +17,11 @@
#include "UserManager.h"
#include "dpWorld.h"
#include "Player.h"
#include "LUTriggers.h"
#include "User.h"
#include "EntityTimer.h"
#include "EntityCallbackTimer.h"
#include "Loot.h"
//Component includes:
#include "Component.h"
@@ -824,6 +829,22 @@ std::vector<ScriptComponent*> Entity::GetScriptComponents() {
return comps;
}
void Entity::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName) {
if (notificationName == "HitOrHealResult" || notificationName == "Hit") {
auto* destroyableComponent = GetComponent<DestroyableComponent>();
if (!destroyableComponent) return;
destroyableComponent->Subscribe(scriptObjId, scriptToAdd);
}
}
void Entity::Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName) {
if (notificationName == "HitOrHealResult" || notificationName == "Hit") {
auto* destroyableComponent = GetComponent<DestroyableComponent>();
if (!destroyableComponent) return;
destroyableComponent->Unsubscribe(scriptObjId);
}
}
void Entity::SetProximityRadius(float proxRadius, std::string name) {
ProximityMonitorComponent* proxMon = GetComponent<ProximityMonitorComponent>();
if (!proxMon) {

View File

@@ -4,29 +4,39 @@
#include <functional>
#include <typeinfo>
#include <type_traits>
#include <unordered_map>
#include <vector>
#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;
};
namespace LUTriggers {
struct Trigger;
};
class Player;
class EntityInfo;
class User;
class Spawner;
class ScriptComponent;
class dpEntity;
class EntityTimer;
class Component;
class Item;
class Character;
class EntityCallbackTimer;
namespace CppScripts {
class Script;
};
/**
* An entity in the world. Has multiple components.
@@ -139,6 +149,9 @@ public:
std::vector<ScriptComponent*> 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);

View File

@@ -17,6 +17,7 @@
#include "MissionComponent.h"
#include "Game.h"
#include "dLogger.h"
#include "MessageIdentifiers.h"
EntityManager* EntityManager::m_Address = nullptr;

View File

@@ -2,15 +2,17 @@
#define ENTITYMANAGER_H
#include "dCommonVars.h"
#include "../thirdparty/raknet/Source/Replica.h"
#include <map>
#include <stack>
#include "Entity.h"
#include <vector>
#include <unordered_map>
class Entity;
class EntityInfo;
class Player;
class User;
struct SystemAddress;
class User;
class EntityManager {
public:

View File

@@ -13,7 +13,9 @@
#include "dZoneManager.h"
#include "CharacterComponent.h"
#include "Mail.h"
#include "User.h"
#include "CppScripts.h"
#include "Loot.h"
std::vector<Player*> Player::m_Players = {};

View File

@@ -22,6 +22,7 @@
#include "SkillComponent.h"
#include "AssetManager.h"
#include "CDClientDatabase.h"
#include "dMessageIdentifiers.h"
UserManager* UserManager::m_Address = nullptr;

View File

@@ -48,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;
}
@@ -79,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;
}

View File

@@ -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) {
@@ -31,130 +31,120 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
}
Game::logger->LogDebug("BasicAttackBehavior", "Number of allocated bits %i", allocatedBits);
const auto baseAddress = bitStream->GetReadOffset();
DoHandleBehavior(context, bitStream, branch);
bitStream->SetReadOffset(baseAddress + allocatedBits);
}
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<DestroyableComponent>();
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->LogDebug("BasicAttackBehavior", "Unable to read isBlocked");
Game::logger->Log("BasicAttackBehavior", "Unable to read isBlocked");
return;
}
if (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->LogDebug("BasicAttackBehavior", "Unable to read isImmune");
Game::logger->Log("BasicAttackBehavior", "Unable to read isImmune");
return;
}
if (isImmune) return;
if (isImmune) {
this->m_OnFailImmune->Handle(context, bitStream, branch);
return;
}
if (bitStream->Read(isSuccess) && isSuccess) { // Success
uint32_t unknown{};
if (!bitStream->Read(unknown)) {
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read unknown");
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 damageDealt{};
if (!bitStream->Read(damageDealt)) {
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read damageDealt");
uint32_t healthDamageDealt{};
if (!bitStream->Read(healthDamageDealt)) {
Game::logger->Log("BasicAttackBehavior", "Unable to read healthDamageDealt");
return;
}
// 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;
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;
}
auto* entity = EntityManager::Instance()->GetEntity(branch.target);
bool died{};
if (!bitStream->Read(died)) {
Game::logger->LogDebug("BasicAttackBehavior", "Unable to read died");
Game::logger->Log("BasicAttackBehavior", "Unable to read died");
return;
}
if (entity != nullptr) {
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (destroyableComponent != nullptr) {
PlayFx(u"onhit", entity->GetObjectID());
destroyableComponent->Damage(damageDealt, context->originator, context->skillID);
}
}
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->LogDebug("BasicAttackBehavior", "Unable to read success state");
Game::logger->Log("BasicAttackBehavior", "Unable to read success state");
return;
}
switch (successState) {
case 1:
switch (static_cast<eBasicAttackSuccessTypes>(successState)) {
case eBasicAttackSuccessTypes::SUCCESS:
this->m_OnSuccess->Handle(context, bitStream, branch);
break;
case eBasicAttackSuccessTypes::FAILARMOR:
this->m_OnFailArmor->Handle(context, bitStream, branch);
break;
default:
Game::logger->LogDebug("BasicAttackBehavior", "Unknown success state (%i)!", successState);
if (static_cast<eBasicAttackSuccessTypes>(successState) != eBasicAttackSuccessTypes::FAILIMMUNE) {
Game::logger->Log("BasicAttackBehavior", "Unknown success state (%i)!", successState);
return;
}
this->m_OnFailImmune->Handle(context, bitStream, branch);
break;
}
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->LogDebug("BasicAttackBehavior", "Invalid self entity (%llu)!", context->originator);
return;
}
bitStream->AlignWriteToByteBoundary();
const auto allocatedAddress = bitStream->GetWriteOffset();
bitStream->Write(uint16_t(0));
bitStream->Write<uint16_t>(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<DestroyableComponent>();
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->LogDebug("BasicAttackBehavior", "Unknown success state (%i)!", successState);
break;
}
DoBehaviorCalculation(context, bitStream, branch);
const auto endAddress = bitStream->GetWriteOffset();
const uint16_t allocate = endAddress - startAddress + 1;
@@ -164,6 +154,87 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream*
bitStream->SetWriteOffset(startAddress + allocate);
}
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;
}
auto* destroyableComponent = targetEntity->GetComponent<DestroyableComponent>();
if (!destroyableComponent || !destroyableComponent->GetParent()) {
Game::logger->Log("BasicAttackBehavior", "No destroyable component on %llu", branch.target);
return;
}
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<eBasicAttackSuccessTypes>(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<eBasicAttackSuccessTypes>(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;
@@ -171,7 +242,14 @@ void BasicAttackBehavior::Load() {
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");
}

View File

@@ -7,10 +7,45 @@ public:
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;
@@ -20,4 +55,8 @@ private:
Behavior* m_OnSuccess;
Behavior* m_OnFailArmor;
Behavior* m_OnFailImmune;
Behavior* m_OnFailBlocked;
};

View File

@@ -48,6 +48,7 @@
#include "PlayEffectBehavior.h"
#include "DamageAbsorptionBehavior.h"
#include "VentureVisionBehavior.h"
#include "PropertyTeleportBehavior.h"
#include "BlockBehavior.h"
#include "ClearTargetBehavior.h"
#include "PullToPointBehavior.h"
@@ -61,6 +62,7 @@
#include "DamageReductionBehavior.h"
#include "JetPackBehavior.h"
#include "ChangeIdleFlagsBehavior.h"
#include "DarkInspirationBehavior.h"
//CDClient includes
#include "CDBehaviorParameterTable.h"
@@ -169,7 +171,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;
@@ -260,7 +264,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;
@@ -436,7 +442,7 @@ 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<CDBehaviorParameterTable>("BehaviorParameter");
return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue).value;
return BehaviorParameterTable->GetValue(this->m_behaviorId, name, defaultValue);
}

View File

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

View File

@@ -10,8 +10,9 @@
#include <sstream>
#include "dMessageIdentifiers.h"
#include "DestroyableComponent.h"
#include "EchoSyncSkill.h"
#include "PhantomPhysicsComponent.h"
#include "RebuildComponent.h"
@@ -51,6 +52,7 @@ void BehaviorContext::RegisterSyncBehavior(const uint32_t syncId, Behavior* beha
entry.handle = syncId;
entry.behavior = behavior;
entry.branchContext = branchContext;
entry.branchContext.isSync = true;
entry.ignoreInterrupts = ignoreInterrupts;
this->syncEntries.push_back(entry);
@@ -215,7 +217,7 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) {
}
// Echo sync
GameMessages::EchoSyncSkill echo;
EchoSyncSkill echo;
echo.bDone = true;
echo.uiBehaviorHandle = entry.handle;

View File

@@ -18,6 +18,7 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp"
"ClearTargetBehavior.cpp"
"DamageAbsorptionBehavior.cpp"
"DamageReductionBehavior.cpp"
"DarkInspirationBehavior.cpp"
"DurationBehavior.cpp"
"EmptyBehavior.cpp"
"EndBehavior.cpp"
@@ -34,6 +35,7 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp"
"OverTimeBehavior.cpp"
"PlayEffectBehavior.cpp"
"ProjectileAttackBehavior.cpp"
"PropertyTeleportBehavior.cpp"
"PullToPointBehavior.cpp"
"RemoveBuffBehavior.cpp"
"RepairBehavior.cpp"

View File

@@ -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<DestroyableComponent>();
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<DestroyableComponent>();
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");
}

View File

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

View File

@@ -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<DestroyableComponent*>(target->GetComponent(COMPONENT_TYPE_DESTROYABLE));
if (destroyable == nullptr) {
return;
auto* destroyableComponent = target->GetComponent<DestroyableComponent>();
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<ControllablePhysicsComponent>();
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<DestroyableComponent*>(target->GetComponent(COMPONENT_TYPE_DESTROYABLE));
if (destroyable == nullptr) {
return;
auto* destroyableComponent = target->GetComponent<DestroyableComponent>();
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<ControllablePhysicsComponent>();
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);
}

View File

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

View File

@@ -4,17 +4,17 @@
#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) {
return;
}
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;
};
@@ -27,33 +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");
}

View File

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

View File

@@ -31,7 +31,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
return;
}
if (m_ProjectileType == 1) {
if (m_useMouseposit && !branch.isSync) {
NiPoint3 targetPosition = NiPoint3::ZERO;
if (!bitStream->Read(targetPosition)) {
Game::logger->Log("ProjectileAttackBehavior", "Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());

View File

@@ -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<CharacterComponent>()->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"));
}

View File

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

View File

@@ -7,6 +7,8 @@
#include "dLogger.h"
#include "DestroyableComponent.h"
#include "RebuildComponent.h"
#include "Entity.h"
#include "EntityInfo.h"
void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* origin = EntityManager::Instance()->GetEntity(context->originator);

View File

@@ -29,6 +29,14 @@ void SpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitSt
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) {
End(context, branch, second);
}
void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (!target) return;
@@ -40,10 +48,6 @@ void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch,
EntityManager::Instance()->SerializeEntity(target);
}
void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
End(context, branch, second);
}
void SpeedBehavior::Load() {
m_RunSpeed = GetFloat("run_speed");
m_AffectsCaster = GetBoolean("affects_caster");

View File

@@ -15,6 +15,8 @@ public:
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;

View File

@@ -23,9 +23,9 @@
#include "RebuildComponent.h"
#include "DestroyableComponent.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;
@@ -179,7 +179,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 +192,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) {
return;
}
if (m_Stunned) {
if (stunnedThisFrame) {
m_MovementAI->Stop();
return;
@@ -206,7 +206,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:
@@ -248,13 +248,13 @@ 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;
}
@@ -320,9 +320,9 @@ 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) {
@@ -348,7 +348,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
}
if (m_Target == LWOOBJID_EMPTY) {
m_State = AiState::idle;
SetAiState(AiState::idle);
return;
}
@@ -375,7 +375,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
m_MovementAI->Stop();
}
m_State = AiState::aggro;
SetAiState(AiState::aggro);
m_Timer = 0;
@@ -532,11 +532,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 +594,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 +712,7 @@ void BaseCombatAIComponent::OnAggro() {
m_MovementAI->SetDestination(targetPos);
m_State = AiState::tether;
SetAiState(AiState::tether);
}
m_Timer += 0.5f;
@@ -726,7 +738,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;

View File

@@ -243,6 +243,12 @@ private:
*/
std::vector<LWOOBJID> GetTargetWithinAggroRange() const;
/**
* @brief Sets the AiState and prepares the entity for serialization next frame.
*
*/
void SetAiState(AiState newState);
/**
* The current state of the AI
*/
@@ -374,6 +380,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

View File

@@ -170,17 +170,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<ControllablePhysicsComponent>();
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);
}
}
}
@@ -213,17 +206,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<ControllablePhysicsComponent>();
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);
}
}
}

View File

@@ -13,6 +13,7 @@
#include "VehiclePhysicsComponent.h"
#include "GameMessages.h"
#include "Item.h"
#include "AMFFormat.h"
CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) {
m_Character = character;

View File

@@ -31,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;
@@ -71,7 +86,14 @@ 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_IgnoreMultipliers) m_DirtyCheats = false;
@@ -84,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) {
@@ -248,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;
}
}
@@ -264,7 +294,7 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) {
// 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;
@@ -298,3 +328,62 @@ void ControllablePhysicsComponent::RemoveSpeedboost(float value) {
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
);
}

View File

@@ -9,6 +9,7 @@
#include "Component.h"
#include "dpCollisionChecks.h"
#include "PhantomPhysicsComponent.h"
#include "eBubbleType.h"
class Entity;
class dpEntity;
@@ -257,13 +258,63 @@ public:
*/
std::vector<float> 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<float> 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
@@ -363,7 +414,7 @@ private:
/**
* Whether the pickup scale is dirty.
*/
bool m_DirtyPickupRadiusScale;
bool m_DirtyEquippedItemInfo;
/**
* The list of pickup radius scales for this entity
@@ -389,6 +440,37 @@ private:
* 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

View File

@@ -30,6 +30,7 @@
#include "PossessorComponent.h"
#include "InventoryComponent.h"
#include "dZoneManager.h"
#include "WorldConfig.h"
DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_iArmor = 0;
@@ -54,8 +55,17 @@ 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() {
@@ -105,7 +115,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);
@@ -335,7 +354,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 +457,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 {
@@ -631,6 +650,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);
@@ -648,6 +668,29 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
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);
@@ -670,13 +713,13 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
auto* inventoryComponent = owner->GetComponent<InventoryComponent>();
if (inventoryComponent != nullptr && isEnemy) {
inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed);
inventoryComponent->TriggerPassiveAbility(PassiveAbilityTrigger::EnemySmashed, m_Parent);
}
auto* missions = owner->GetComponent<MissionComponent>();
if (missions != nullptr) {
if (team != nullptr && isEnemy) {
if (team != nullptr) {
for (const auto memberId : team->members) {
auto* member = EntityManager::Instance()->GetEntity(memberId);
@@ -739,22 +782,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<uint64_t>(coinsTotal * coinPercentageToLose), minCoinsToLose);
coinsToLose = std::min(maxCoinsToLose, coinsToLose);
if (coinsTotal >= 200) {
float hundreth = (coinsTotal / 100.0f);
coinsToLoose = static_cast<int>(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);
}
}
@@ -784,12 +822,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() {

View File

@@ -7,6 +7,10 @@
#include "Entity.h"
#include "Component.h"
namespace CppScripts {
class Script;
}; //! namespace CppScripts
/**
* Represents the stats of an entity, for example its health, imagination and armor. Also handles factions, which
* indicate which enemies this entity has.
@@ -392,16 +396,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
@@ -422,6 +441,17 @@ public:
*/
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);
private:
/**
* Whether or not the health should be serialized
@@ -478,11 +508,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
*/
@@ -557,6 +582,24 @@ private:
* The list of callbacks that will be called when this entity gets hit
*/
std::vector<std::function<void(Entity*)>> m_OnHitCallbacks;
/**
* The list of scripts subscribed to this components actions
*/
std::map<LWOOBJID, CppScripts::Script*> 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

View File

@@ -27,8 +27,9 @@
#include "dConfig.h"
#include "eItemType.h"
#include "eUnequippableActiveType.h"
#include "CppScripts.h"
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) {
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document): Component(parent) {
this->m_Dirty = true;
this->m_Equipped = {};
this->m_Pushed = {};
@@ -867,6 +868,8 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
AddItemSkills(item->GetLot());
EquipScripts(item);
EntityManager::Instance()->SerializeEntity(m_Parent);
}
@@ -895,6 +898,8 @@ void InventoryComponent::UnEquipItem(Item* item) {
PurgeProxies(item);
UnequipScripts(item);
EntityManager::Instance()->SerializeEntity(m_Parent);
// Trigger property event
@@ -904,6 +909,37 @@ void InventoryComponent::UnEquipItem(Item* item) {
}
}
void InventoryComponent::EquipScripts(Item* equippedItem) {
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
if (!compRegistryTable) return;
int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), COMPONENT_TYPE_SCRIPT, -1);
if (scriptComponentID > -1) {
CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable<CDScriptComponentTable>("ScriptComponent");
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<CDComponentsRegistryTable>("ComponentsRegistry");
if (!compRegistryTable) return;
int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), COMPONENT_TYPE_SCRIPT, -1);
if (scriptComponentID > -1) {
CDScriptComponentTable* scriptCompTable = CDClientManager::Instance()->GetTable<CDScriptComponentTable>("ScriptComponent");
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<CharacterComponent>();
if (!characterComponent) return;
@@ -923,7 +959,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());
@@ -1160,9 +1196,9 @@ 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);
}
}

View File

@@ -283,7 +283,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
@@ -352,6 +352,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:

View File

@@ -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<MoverSubComponent*>(m_MoverSubComponent);
subComponent->mState = value;
@@ -152,7 +153,7 @@ void MovingPlatformComponent::StartPathing() {
auto* subComponent = static_cast<MoverSubComponent*>(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<MoverSubComponent*>(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;

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