diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index fc44885d9..9c7341666 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -16,12 +16,12 @@ jobs: os: [ windows-2022, ubuntu-22.04, macos-13 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true - name: Add msbuild to PATH (Windows only) if: ${{ matrix.os == 'windows-2022' }} - uses: microsoft/setup-msbuild@v1.1 + uses: microsoft/setup-msbuild@v2 with: vs-version: '[17,18)' msbuild-architecture: x64 @@ -33,21 +33,19 @@ jobs: - name: cmake uses: lukka/run-cmake@v10 with: - configurePreset: "ci-${{matrix.os}}" - buildPreset: "ci-${{matrix.os}}" - testPreset: "ci-${{matrix.os}}" + workflowPreset: "ci-${{matrix.os}}" - name: artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: build-${{matrix.os}} path: | - build/*Server* - build/*.ini - build/*.so - build/*.dll - build/vanity/ - build/navmeshes/ - build/migrations/ - build/*.dcf - !build/*.pdb - !build/d*/ + build/*/*Server* + build/*/*.ini + build/*/*.so + build/*/*.dll + build/*/vanity/ + build/*/navmeshes/ + build/*/migrations/ + build/*/*.dcf + !build/*/*.pdb + !build/*/d*/ diff --git a/.gitignore b/.gitignore index 12a3b284f..0b0d2ecf7 100644 --- a/.gitignore +++ b/.gitignore @@ -122,4 +122,7 @@ docker/__pycache__ docker-compose.override.yml !*Test.bin + +# CMake scripts !cmake/* +!cmake/toolchains/* diff --git a/CMakeLists.txt b/CMakeLists.txt index b36bdb290..0d9d394b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,23 @@ -cmake_minimum_required(VERSION 3.18) -project(Darkflame) +cmake_minimum_required(VERSION 3.25) +project(Darkflame + HOMEPAGE_URL "https://github.com/DarkflameUniverse/DarkflameServer" + LANGUAGES C CXX +) + +# check if the path to the source directory contains a space +if("${CMAKE_SOURCE_DIR}" MATCHES " ") + message(FATAL_ERROR "The server cannot build in the path (" ${CMAKE_SOURCE_DIR} ") because it contains a space. Please move the server to a path without spaces.") +endif() + include(CTest) +set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 20) -set(CXX_STANDARD_REQUIRED ON) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export the compile commands for debugging +set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects +set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Set C and C++ symbol visibility to hide inlined functions set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") # Read variables from file @@ -52,33 +66,36 @@ set(RECASTNAVIGATION_EXAMPLES OFF CACHE BOOL "" FORCE) # Disabled no-register # Disabled unknown pragmas because Linux doesn't understand Windows pragmas. if(UNIX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wuninitialized -fPIC") + add_compile_options("-fPIC") add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0) - if(NOT APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -lstdc++fs") + # For all except Clang and Apple Clang + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options("-static-libgcc" "-lstdc++fs") endif() if(${DYNAMIC} AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") + add_compile_options("-rdynamic") endif() if(${GGDB}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") + add_compile_options("-ggdb") endif() - - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC") elseif(MSVC) # Skip warning for invalid conversion from size_t to uint32_t for all targets below for now - add_compile_options("/wd4267" "/utf-8") + # Also disable non-portable MSVC volatile behavior + add_compile_options("/wd4267" "/utf-8" "/volatile:iso" "/Zc:inline") elseif(WIN32) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() # Our output dir -set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR}) +#set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON) # unfortunately, forces all libraries to be built in series, which will slow down the build process # TODO make this not have to override the build type directories +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) @@ -90,37 +107,47 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +find_package(MariaDB) + # Create a /resServer directory make_directory(${CMAKE_BINARY_DIR}/resServer) # Create a /logs directory make_directory(${CMAKE_BINARY_DIR}/logs) +# Get DLU config directory +if(DEFINED ENV{DLU_CONFIG_DIR}) + set(DLU_CONFIG_DIR $ENV{DLU_CONFIG_DIR}) +else() + set(DLU_CONFIG_DIR ${PROJECT_BINARY_DIR}) +endif() +message(STATUS "Variable: DLU_CONFIG_DIR = ${DLU_CONFIG_DIR}") + # Copy resource files on first build -set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf") +set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blocklist.dcf") message(STATUS "Checking resource file integrity") include(Utils) -UpdateConfigOption(${PROJECT_BINARY_DIR}/authconfig.ini "port" "auth_server_port") -UpdateConfigOption(${PROJECT_BINARY_DIR}/chatconfig.ini "port" "chat_server_port") -UpdateConfigOption(${PROJECT_BINARY_DIR}/masterconfig.ini "port" "master_server_port") +UpdateConfigOption(${DLU_CONFIG_DIR}/authconfig.ini "port" "auth_server_port") +UpdateConfigOption(${DLU_CONFIG_DIR}/chatconfig.ini "port" "chat_server_port") +UpdateConfigOption(${DLU_CONFIG_DIR}/masterconfig.ini "port" "master_server_port") foreach(resource_file ${RESOURCE_FILES}) set(file_size 0) - if(EXISTS ${PROJECT_BINARY_DIR}/${resource_file}) - file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size) + if(EXISTS ${DLU_CONFIG_DIR}/${resource_file}) + file(SIZE ${DLU_CONFIG_DIR}/${resource_file} file_size) endif() if(${file_size} EQUAL 0) configure_file( - ${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file} + ${CMAKE_SOURCE_DIR}/resources/${resource_file} ${DLU_CONFIG_DIR}/${resource_file} COPYONLY ) - message(STATUS "Moved " ${resource_file} " to project binary directory") + message(STATUS "Moved " ${resource_file} " to DLU config directory") elseif(resource_file MATCHES ".ini") message(STATUS "Checking " ${resource_file} " for missing config options") - file(READ ${PROJECT_BINARY_DIR}/${resource_file} current_file_contents) + file(READ ${DLU_CONFIG_DIR}/${resource_file} current_file_contents) string(REPLACE "\\\n" "" current_file_contents ${current_file_contents}) string(REPLACE "\n" ";" current_file_contents ${current_file_contents}) set(parsed_current_file_contents "") @@ -151,10 +178,10 @@ foreach(resource_file ${RESOURCE_FILES}) set(line_to_add ${line_to_add} ${line}) foreach(line_to_append ${line_to_add}) - file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append}) + file(APPEND ${DLU_CONFIG_DIR}/${resource_file} "\n" ${line_to_append}) endforeach() - file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n") + file(APPEND ${DLU_CONFIG_DIR}/${resource_file} "\n") endif() set(line_to_add "") @@ -179,7 +206,7 @@ file(ARCHIVE_EXTRACT INPUT ${PROJECT_BINARY_DIR}/navmeshes.zip DESTINATION ${PRO file(REMOVE ${PROJECT_BINARY_DIR}/navmeshes.zip) # Copy vanity files on first build -set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "root.xml" "dev-tribute.xml" "atm.xml") +set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "root.xml" "dev-tribute.xml" "atm.xml" "demo.xml") foreach(file ${VANITY_FILES}) configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY) @@ -202,42 +229,28 @@ foreach(file ${SQL_FILES}) configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file}) endforeach() -# Create our list of include directories -set(INCLUDED_DIRECTORIES - "dCommon" - "dCommon/dClient" - "dCommon/dEnums" - - "dChatFilter" - - "dGame" - "dGame/dBehaviors" - "dGame/dComponents" - "dGame/dGameMessages" - "dGame/dInventory" - "dGame/dMission" - "dGame/dEntity" - "dGame/dPropertyBehaviors" - "dGame/dPropertyBehaviors/ControlBehaviorMessages" - "dGame/dUtilities" +# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux) +if (APPLE) + include_directories("/usr/local/include/") +endif() +# Load all of our third party directories +add_subdirectory(thirdparty SYSTEM) + +# Create our list of include directories +include_directories( "dPhysics" "dNavigation" - "dNavigation/dTerrain" - - "dZoneManager" - - "dDatabase" - "dDatabase/CDClientDatabase" - "dDatabase/CDClientDatabase/CDClientTables" - "dDatabase/GameDatabase" - "dDatabase/GameDatabase/ITables" - "dDatabase/GameDatabase/MySQL" - "dDatabase/GameDatabase/MySQL/Tables" "dNet" + "tests" + "tests/dCommonTests" + "tests/dGameTests" + "tests/dGameTests/dComponentsTests" + + SYSTEM "thirdparty/magic_enum/include/magic_enum" "thirdparty/raknet/Source" "thirdparty/tinyxml2" @@ -246,47 +259,25 @@ set(INCLUDED_DIRECTORIES "thirdparty/cpplinq" "thirdparty/cpp-httplib" "thirdparty/MD5" - - "tests" - "tests/dCommonTests" - "tests/dGameTests" - "tests/dGameTests/dComponentsTests" ) # Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux) +# TODO: Should probably not do this. if(APPLE) include_directories("/usr/local/include/") endif() -# Actually include the directories from our list -foreach(dir ${INCLUDED_DIRECTORIES}) - include_directories(${PROJECT_SOURCE_DIR}/${dir}) -endforeach() - -if(NOT WIN32) - include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt") +# Set warning flags +if(MSVC) + # add_compile_options("/W4") + # Want to enable warnings eventually, but WAY too much noise right now +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + add_compile_options("-Wuninitialized" "-Wold-style-cast") +else() + message(WARNING "Unknown compiler: '${CMAKE_CXX_COMPILER_ID}' - No warning flags enabled.") endif() -include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include") - # Add linking directories: -link_directories(${PROJECT_BINARY_DIR}) - -# Load all of our third party directories -add_subdirectory(thirdparty) -if (UNIX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") -endif() -# Glob together all headers that need to be precompiled -file( - GLOB HEADERS_DDATABASE - LIST_DIRECTORIES false - ${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/*.h - ${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables/*.h - ${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables/*.h - ${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h -) - file( GLOB HEADERS_DZONEMANAGER LIST_DIRECTORIES false @@ -321,7 +312,7 @@ add_subdirectory(dPhysics) add_subdirectory(dServer) # Create a list of common libraries shared between all binaries -set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum" "MD5") +set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "MariaDB::ConnCpp" "magic_enum") # Add platform specific common libraries if(UNIX) @@ -343,12 +334,6 @@ target_precompile_headers( ${HEADERS_DZONEMANAGER} ) -# Need to specify to use the CXX compiler language here or else we get errors including . -target_precompile_headers( - dDatabase PRIVATE - "$<$:${HEADERS_DDATABASE}>" -) - target_precompile_headers( dCommon PRIVATE ${HEADERS_DCOMMON} diff --git a/CMakePresets.json b/CMakePresets.json index 2feabc538..c4595ed51 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,128 +1,641 @@ { - "version": 3, - "cmakeMinimumRequired": { - "major": 3, - "minor": 14, - "patch": 0 - }, - "configurePresets": [ - { - "name": "default", - "displayName": "Default configure step", - "description": "Use 'build' dir and Unix makefiles", - "binaryDir": "${sourceDir}/build", - "generator": "Unix Makefiles" - }, - { - "name": "ci-ubuntu-22.04", - "displayName": "CI configure step for Ubuntu", - "description": "Same as default, Used in GitHub actions workflow", - "inherits": "default" - }, - { - "name": "ci-macos-13", - "displayName": "CI configure step for MacOS", - "description": "Same as default, Used in GitHub actions workflow", - "inherits": "default" - }, - { - "name": "ci-windows-2022", - "displayName": "CI configure step for Windows", - "description": "Set architecture to 64-bit (b/c RakNet)", - "inherits": "default", - "generator": "Visual Studio 17 2022", - "architecture": { - "value": "x64" - }, - "cacheVariables": { - "CMAKE_BUILD_TYPE": "RelWithDebInfo" - } - }, - { - "name": "windows-default", - "inherits": "ci-windows-2022", - "displayName": "Windows only Configure Settings", - "description": "Sets build and install directories", - "generator": "Ninja", - "architecture": { - "value": "x64", - "strategy": "external" - } - } - ], - "buildPresets": [ - { - "name": "default", - "configurePreset": "default", - "displayName": "Default Build", - "description": "Default Build", - "jobs": 2 - }, - { - "name": "ci-windows-2022", - "configurePreset": "ci-windows-2022", - "displayName": "Windows CI Build", - "description": "This preset is used by the CI build on windows", - "configuration": "RelWithDebInfo", - "jobs": 2 - }, - { - "name": "ci-ubuntu-22.04", - "configurePreset": "ci-ubuntu-22.04", - "displayName": "Linux CI Build", - "description": "This preset is used by the CI build on linux", - "jobs": 2 - }, - { - "name": "ci-macos-13", - "configurePreset": "ci-macos-13", - "displayName": "MacOS CI Build", - "description": "This preset is used by the CI build on MacOS", - "jobs": 2 - } - ], - "testPresets": [ - { - "name": "ci-ubuntu-22.04", - "configurePreset": "ci-ubuntu-22.04", - "displayName": "CI Tests on Linux", - "description": "Runs all tests on a linux configuration", - "execution": { - "jobs": 2 + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 25, + "patch": 0 + }, + "configurePresets": [ + { + "name": "default", + "displayName": "Default configure step", + "description": "Use 'build' dir and Unix makefiles", + "binaryDir": "${sourceDir}/build", + "environment": { + "DLU_CONFIG_DIR": "${sourceDir}/build" + }, + "generator": "Unix Makefiles" }, - "output": { - "outputOnFailure": true - } - }, - { - "name": "ci-macos-13", - "configurePreset": "ci-macos-13", - "displayName": "CI Tests on MacOS", - "description": "Runs all tests on a Mac configuration", - "execution": { - "jobs": 2 + { + "name": "debug-config", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "relwithdebinfo-config", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, + { + "name": "release-config", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "clang-config", + "hidden": true, + "toolchainFile": "${sourceDir}/cmake/toolchains/linux-clang.cmake" + }, + { + "name": "gnu-config", + "hidden": true, + "toolchainFile": "${sourceDir}/cmake/toolchains/linux-gnu.cmake" + }, + { + "name": "windows-msvc", + "inherits": "default", + "displayName": "[Multi] Windows (MSVC)", + "description": "Set architecture to 64-bit (b/c RakNet)", + "generator": "Visual Studio 17 2022", + "binaryDir": "${sourceDir}/build/msvc", + "architecture": { + "value": "x64" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "windows-default", + "inherits": "windows-msvc", + "displayName": "Windows only Configure Settings", + "description": "Sets build and install directories", + "generator": "Ninja", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + }, + "architecture": { + "value": "x64" + } + }, + { + "name": "linux-config", + "inherits": "default", + "hidden": true, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } + }, + { + "name": "linux-clang-debug", + "inherits": [ + "linux-config", + "clang-config", + "debug-config" + ], + "displayName": "EXPERIMENTAL - [Debug] Linux (Clang)", + "description": "Create a debug build using the Clang toolchain for Linux", + "binaryDir": "${sourceDir}/build/clang-debug" }, - "output": { - "outputOnFailure": true - } - }, - { - "name": "ci-windows-2022", - "configurePreset": "ci-windows-2022", - "displayName": "CI Tests on windows", - "description": "Runs all tests on a windows configuration", - "configuration": "RelWithDebInfo", - "execution": { + { + "name": "linux-clang-relwithdebinfo", + "inherits": [ + "linux-config", + "clang-config", + "relwithdebinfo-config" + ], + "displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)", + "description": "Create a release build with debug info using the Clang toolchain for Linux", + "binaryDir": "${sourceDir}/build/clang-relwithdebinfo" + }, + { + "name": "linux-clang-release", + "inherits": [ + "linux-config", + "clang-config", + "release-config" + ], + "displayName": "EXPERIMENTAL - [Release] Linux (Clang)", + "description": "Create a release build using the Clang toolchain for Linux", + "binaryDir": "${sourceDir}/build/clang-release" + }, + { + "name": "linux-gnu-debug", + "inherits": [ + "linux-config", + "gnu-config", + "debug-config" + ], + "displayName": "[Debug] Linux (GNU)", + "description": "Create a debug build using the GNU toolchain for Linux", + "binaryDir": "${sourceDir}/build/gnu-debug" + }, + { + "name": "linux-gnu-relwithdebinfo", + "inherits": [ + "linux-config", + "gnu-config", + "relwithdebinfo-config" + ], + "displayName": "[RelWithDebInfo] Linux (GNU)", + "description": "Create a release build with debug info using the GNU toolchain for Linux", + "binaryDir": "${sourceDir}/build/gnu-relwithdebinfo" + }, + { + "name": "linux-gnu-release", + "inherits": [ + "linux-config", + "gnu-config", + "release-config" + ], + "displayName": "[Release] Linux (GNU)", + "description": "Create a release build using the GNU toolchain for Linux", + "binaryDir": "${sourceDir}/build/gnu-release" + }, + { + "name": "macos", + "inherits": "default", + "displayName": "[Multi] MacOS", + "description": "Create a build for MacOS", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + }, + "binaryDir": "${sourceDir}/build/macos" + } + ], + "buildPresets": [ + { + "name": "default", + "configurePreset": "default", + "displayName": "Default Build", + "description": "Default Build", "jobs": 2 }, - "output": { - "outputOnFailure": true - }, - "filter": { - "exclude": { - "name": "((example)|(minigzip))+" + { + "name": "windows-msvc-debug", + "inherits": "default", + "configurePreset": "windows-msvc", + "displayName": "[Debug] Windows (MSVC)", + "description": "This preset is used to build in debug mode using the MSVC toolchain on Windows", + "configuration": "Debug" + }, + { + "name": "windows-msvc-relwithdebinfo", + "inherits": "default", + "configurePreset": "windows-msvc", + "displayName": "[RelWithDebInfo] Windows (MSVC)", + "description": "This preset is used to build in debug mode using the MSVC toolchain on Windows", + "configuration": "RelWithDebInfo" + }, + { + "name": "windows-msvc-release", + "inherits": "default", + "configurePreset": "windows-msvc", + "displayName": "[Release] Windows (MSVC)", + "description": "This preset is used to build in release mode using the MSVC toolchain on Windows", + "configuration": "Release" + }, + { + "name": "linux-clang-debug", + "inherits": "default", + "configurePreset": "linux-clang-debug", + "displayName": "EXPERIMENTAL - [Debug] Linux (Clang)", + "description": "This preset is used to build in debug mode using the Clang toolchain on Linux", + "configuration": "Debug" + }, + { + "name": "linux-clang-relwithdebinfo", + "inherits": "default", + "configurePreset": "linux-clang-relwithdebinfo", + "displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)", + "description": "This preset is used to build in release mode with debug info using the Clang toolchain on Linux", + "configuration": "RelWithDebInfo" + }, + { + "name": "linux-clang-release", + "inherits": "default", + "configurePreset": "linux-clang-release", + "displayName": "EXPERIMENTAL - [Release] Linux (Clang)", + "description": "This preset is used to build in release mode using the Clang toolchain on Linux", + "configuration": "Release" + }, + { + "name": "linux-gnu-debug", + "inherits": "default", + "configurePreset": "linux-gnu-debug", + "displayName": "[Debug] Linux (GNU)", + "description": "This preset is used to build in debug mode using the GNU toolchain on Linux", + "configuration": "Debug" + }, + { + "name": "linux-gnu-relwithdebinfo", + "inherits": "default", + "configurePreset": "linux-gnu-relwithdebinfo", + "displayName": "[RelWithDebInfo] Linux (GNU)", + "description": "This preset is used to build in release mode with debug info using the GNU toolchain on Linux", + "configuration": "RelWithDebInfo" + }, + { + "name": "linux-gnu-release", + "inherits": "default", + "configurePreset": "linux-gnu-release", + "displayName": "[Release] Linux (GNU)", + "description": "This preset is used to build in release mode using the GNU toolchain on Linux", + "configuration": "Release" + }, + { + "name": "macos-debug", + "inherits": "default", + "configurePreset": "macos", + "displayName": "[Debug] MacOS", + "description": "This preset is used to build in debug mode on MacOS", + "configuration": "Debug" + }, + { + "name": "macos-relwithdebinfo", + "inherits": "default", + "configurePreset": "macos", + "displayName": "[RelWithDebInfo] MacOS", + "description": "This preset is used to build in release mode with debug info on MacOS", + "configuration": "RelWithDebInfo" + }, + { + "name": "macos-release", + "inherits": "default", + "configurePreset": "macos", + "displayName": "[Release] MacOS", + "description": "This preset is used to build in release mode on MacOS", + "configuration": "Release" + } + ], + "testPresets": [ + { + "name": "default", + "configurePreset": "default", + "execution": { + "jobs": 2 + }, + "output": { + "outputOnFailure": true + } + }, + { + "name": "windows-msvc-test", + "inherits": "default", + "configurePreset": "windows-msvc", + "hidden": true, + "filter": { + "exclude": { + "name": "((example)|(minigzip))+" + } } + }, + { + "name": "windows-msvc-debug", + "inherits": "windows-msvc-test", + "configurePreset": "windows-msvc", + "displayName": "[Debug] Windows (MSVC)", + "description": "Runs all tests on a Windows configuration", + "configuration": "Debug" + }, + { + "name": "windows-msvc-relwithdebinfo", + "inherits": "windows-msvc-test", + "configurePreset": "windows-msvc", + "displayName": "[RelWithDebInfo] Windows (MSVC)", + "description": "Runs all tests on a Windows configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "windows-msvc-release", + "inherits": "windows-msvc-test", + "configurePreset": "windows-msvc", + "displayName": "[Release] Windows (MSVC)", + "description": "Runs all tests on a Windows configuration", + "configuration": "Release" + }, + { + "name": "linux-clang-debug", + "inherits": "default", + "configurePreset": "linux-clang-debug", + "displayName": "EXPERIMENTAL - [Debug] Linux (Clang)", + "description": "Runs all tests on a Linux Clang configuration", + "configuration": "Release" + }, + { + "name": "linux-clang-relwithdebinfo", + "inherits": "default", + "configurePreset": "linux-clang-relwithdebinfo", + "displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)", + "description": "Runs all tests on a Linux Clang configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "linux-clang-release", + "inherits": "default", + "configurePreset": "linux-clang-release", + "displayName": "EXPERIMENTAL - [Release] Linux (Clang)", + "description": "Runs all tests on a Linux Clang configuration", + "configuration": "Release" + }, + { + "name": "linux-gnu-debug", + "inherits": "default", + "configurePreset": "linux-gnu-debug", + "displayName": "[Debug] Linux (GNU)", + "description": "Runs all tests on a Linux GNU configuration", + "configuration": "Release" + }, + { + "name": "linux-gnu-relwithdebinfo", + "inherits": "default", + "configurePreset": "linux-gnu-relwithdebinfo", + "displayName": "[RelWithDebInfo] Linux (GNU)", + "description": "Runs all tests on a Linux GNU configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "linux-gnu-release", + "inherits": "default", + "configurePreset": "linux-gnu-release", + "displayName": "[Release] Linux (GNU)", + "description": "Runs all tests on a Linux GNU configuration", + "configuration": "Release" + }, + { + "name": "macos-debug", + "inherits": "default", + "configurePreset": "macos", + "displayName": "[Debug] MacOS", + "description": "Runs all tests on a MacOS configuration", + "configuration": "Debug" + }, + { + "name": "macos-relwithdebinfo", + "inherits": "default", + "configurePreset": "macos", + "displayName": "[RelWithDebInfo] MacOS", + "description": "Runs all tests on a MacOS configuration", + "configuration": "RelWithDebInfo" + }, + { + "name": "macos-release", + "inherits": "default", + "configurePreset": "macos", + "displayName": "[Release] MacOS", + "description": "Runs all tests on a MacOS configuration", + "configuration": "Release" + } + ], + "workflowPresets": [ + { + "name": "default", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "default" + }, + { + "type": "test", + "name": "default" + } + ] + }, + { + "name": "windows-msvc-debug", + "displayName": "[Debug] Windows (MSVC)", + "description": "MSVC debug workflow preset for Windows", + "steps": [ + { + "type": "configure", + "name": "windows-msvc" + }, + { + "type": "build", + "name": "windows-msvc-debug" + }, + { + "type": "test", + "name": "windows-msvc-debug" + } + ] + }, + { + "name": "windows-msvc-relwithdebinfo", + "displayName": "[RelWithDebInfo] Windows (MSVC)", + "description": "MSVC release with debug info workflow preset for Windows", + "steps": [ + { + "type": "configure", + "name": "windows-msvc" + }, + { + "type": "build", + "name": "windows-msvc-relwithdebinfo" + }, + { + "type": "test", + "name": "windows-msvc-relwithdebinfo" + } + ] + }, + { + "name": "ci-windows-2022", + "displayName": "[Release] Windows (MSVC)", + "description": "CI workflow preset for Windows", + "steps": [ + { + "type": "configure", + "name": "windows-msvc" + }, + { + "type": "build", + "name": "windows-msvc-release" + }, + { + "type": "test", + "name": "windows-msvc-release" + } + ] + }, + { + "name": "linux-gnu-debug", + "displayName": "[Debug] Linux (GNU)", + "description": "GNU debug workflow preset for Linux", + "steps": [ + { + "type": "configure", + "name": "linux-gnu-debug" + }, + { + "type": "build", + "name": "linux-gnu-debug" + }, + { + "type": "test", + "name": "linux-gnu-debug" + } + ] + }, + { + "name": "linux-gnu-relwithdebinfo", + "displayName": "[RelWithDebInfo] Linux (GNU)", + "description": "GNU release with debug info workflow preset for Linux", + "steps": [ + { + "type": "configure", + "name": "linux-gnu-relwithdebinfo" + }, + { + "type": "build", + "name": "linux-gnu-relwithdebinfo" + }, + { + "type": "test", + "name": "linux-gnu-relwithdebinfo" + } + ] + }, + { + "name": "ci-ubuntu-22.04", + "displayName": "[Release] Linux (GNU)", + "description": "CI workflow preset for Ubuntu", + "steps": [ + { + "type": "configure", + "name": "linux-gnu-release" + }, + { + "type": "build", + "name": "linux-gnu-release" + }, + { + "type": "test", + "name": "linux-gnu-release" + } + ] + }, + { + "name": "linux-clang-debug", + "displayName": "EXPERIMENTAL - [Debug] Linux (Clang)", + "description": "Clang debug workflow preset for Linux", + "steps": [ + { + "type": "configure", + "name": "linux-clang-debug" + }, + { + "type": "build", + "name": "linux-clang-debug" + }, + { + "type": "test", + "name": "linux-clang-debug" + } + ] + }, + { + "name": "linux-clang-relwithdebinfo", + "displayName": "EXPERIMENTAL - [RelWithDebInfo] Linux (Clang)", + "description": "Clang release with debug info workflow preset for Linux", + "steps": [ + { + "type": "configure", + "name": "linux-clang-relwithdebinfo" + }, + { + "type": "build", + "name": "linux-clang-relwithdebinfo" + }, + { + "type": "test", + "name": "linux-clang-relwithdebinfo" + } + ] + }, + { + "name": "linux-clang-release", + "displayName": "EXPERIMENTAL - [Release] Linux (Clang)", + "description": "Clang release workflow preset for Linux", + "steps": [ + { + "type": "configure", + "name": "linux-clang-release" + }, + { + "type": "build", + "name": "linux-clang-release" + }, + { + "type": "test", + "name": "linux-clang-release" + } + ] + }, + { + "name": "macos-debug", + "displayName": "[Debug] MacOS", + "description": "Release workflow preset for MacOS", + "steps": [ + { + "type": "configure", + "name": "macos" + }, + { + "type": "build", + "name": "macos-debug" + }, + { + "type": "test", + "name": "macos-debug" + } + ] + }, + { + "name": "macos-relwithdebinfo", + "displayName": "[RelWithDebInfo] MacOS", + "description": "Release with debug info workflow preset for MacOS", + "steps": [ + { + "type": "configure", + "name": "macos" + }, + { + "type": "build", + "name": "macos-relwithdebinfo" + }, + { + "type": "test", + "name": "macos-relwithdebinfo" + } + ] + }, + { + "name": "ci-macos-13", + "displayName": "[Release] MacOS", + "description": "CI workflow preset for MacOS", + "steps": [ + { + "type": "configure", + "name": "macos" + }, + { + "type": "build", + "name": "macos-release" + }, + { + "type": "test", + "name": "macos-release" + } + ] } - } - ] - } + ] +} diff --git a/CMakeVariables.txt b/CMakeVariables.txt index d9430d9d0..4ded5f593 100644 --- a/CMakeVariables.txt +++ b/CMakeVariables.txt @@ -1,6 +1,6 @@ -PROJECT_VERSION_MAJOR=1 -PROJECT_VERSION_MINOR=1 -PROJECT_VERSION_PATCH=1 +PROJECT_VERSION_MAJOR=2 +PROJECT_VERSION_MINOR=3 +PROJECT_VERSION_PATCH=0 # Debugging # Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs. diff --git a/Dockerfile b/Dockerfile index c1316a60f..9086cf17d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,8 +23,7 @@ RUN --mount=type=cache,id=build-apt-cache,target=/var/cache/apt \ rm -rf /var/lib/apt/lists/* # Grab libraries and load them -COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadbcpp.so /usr/local/lib/ -COPY --from=build /app/build/mariadbcpp/src/mariadb_connector_cpp-build/libmariadb/libmariadb/libmariadb.so.3 /usr/local/lib +COPY --from=build /app/build/mariadbcpp/libmariadbcpp.so /usr/local/lib/ RUN ldconfig # Server bins @@ -32,7 +31,7 @@ COPY --from=build /app/build/*Server /app/ # Necessary suplimentary files COPY --from=build /app/build/*.ini /app/configs/ -COPY --from=build /app/build/vanity/*.* /app/vanity/* +COPY --from=build /app/build/vanity/*.* /app/vanity/ COPY --from=build /app/build/navmeshes /app/navmeshes COPY --from=build /app/build/migrations /app/migrations COPY --from=build /app/build/*.dcf /app/ @@ -40,7 +39,7 @@ COPY --from=build /app/build/*.dcf /app/ # backup of config and vanity files to copy to the host incase # of a mount clobbering the copy from above COPY --from=build /app/build/*.ini /app/default-configs/ -COPY --from=build /app/build/vanity/*.* /app/default-vanity/* +COPY --from=build /app/build/vanity/*.* /app/default-vanity/ # needed as the container runs with the root user # and therefore sudo doesn't exist diff --git a/README.md b/README.md index f0f2ac361..1caa0fb00 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer ### Windows packages Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed. -You'll also need to download and install [CMake](https://cmake.org/download/) (version **CMake version 3.18** or later!). +You'll also need to download and install [CMake](https://cmake.org/download/) (version **CMake version 3.25** or later!). ### MacOS packages Ensure you have [brew](https://brew.sh) installed. @@ -73,7 +73,7 @@ sudo apt install build-essential gcc zlib1g-dev libssl-dev openssl mariadb-serve ``` #### Required CMake version -This project uses **CMake version 3.18** or higher and as such you will need to ensure you have this version installed. +This project uses **CMake version 3.25** 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 diff --git a/build.sh b/build.sh index b8d33492a..3f36e8a3c 100755 --- a/build.sh +++ b/build.sh @@ -6,8 +6,7 @@ mkdir -p build cd build # Run cmake to generate make files -cmake .. +cmake -DCMAKE_BUILD_TYPE="Release" .. # 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 $1 - diff --git a/cmake/FindGoogleTest.cmake b/cmake/FindGoogleTest.cmake new file mode 100644 index 000000000..69d16247a --- /dev/null +++ b/cmake/FindGoogleTest.cmake @@ -0,0 +1,17 @@ +include(FetchContent) + +message(STATUS "Fetching gtest...") + +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG release-1.12.1 +) + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +FetchContent_MakeAvailable(GoogleTest) + +message(STATUS "gtest fetched and is now ready.") +set(GoogleTest_FOUND TRUE) diff --git a/thirdparty/CMakeMariaDBLists.txt b/cmake/FindMariaDB.cmake similarity index 58% rename from thirdparty/CMakeMariaDBLists.txt rename to cmake/FindMariaDB.cmake index d7a17f28c..d3f899312 100644 --- a/thirdparty/CMakeMariaDBLists.txt +++ b/cmake/FindMariaDB.cmake @@ -23,14 +23,14 @@ if(WIN32 AND NOT MARIADB_BUILD_SOURCE) set(MARIADB_CONNECTOR_CPP_MSI "mariadb-connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}-win64.msi") if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" ) - message("Downloading mariadb connector/c") + message(STATUS "Downloading mariadb connector/c") file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_C_BUCKET}/Connectors/c/connector-c-${MARIADB_CONNECTOR_C_VERSION}/${MARIADB_CONNECTOR_C_MSI} "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" EXPECTED_HASH MD5=${MARIADB_CONNECTOR_C_MD5}) endif() if(NOT EXISTS "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" ) - message("Downloading mariadb connector/c++") + message(STATUS "Downloading mariadb connector/c++") file(DOWNLOAD https://dlm.mariadb.com/${MARIADB_CONNECTOR_CPP_BUCKET}/Connectors/cpp/connector-cpp-${MARIADB_CONNECTOR_CPP_VERSION}/${MARIADB_CONNECTOR_CPP_MSI} "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" EXPECTED_HASH MD5=${MARIADB_CONNECTOR_CPP_MD5}) @@ -43,27 +43,28 @@ if(WIN32 AND NOT MARIADB_BUILD_SOURCE) file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_C_MSI}" MSI_DIR) execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) endif() + set(MARIADBC_SHARED_LIBRARY_LOCATION "${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll") if(NOT EXISTS "${MARIADB_CPP_CONNECTOR_DIR}") file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/${MARIADB_CONNECTOR_CPP_MSI}" MSI_DIR) execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) endif() - set(MARIADB_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll") + set(MARIADBCPP_SHARED_LIBRARY_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll") set(MARIADB_IMPLIB_LOCATION "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.lib") set(MARIADB_INCLUDE_DIR "${MARIADB_CPP_CONNECTOR_DIR}/include/mariadb") add_custom_target(mariadb_connector_cpp) add_custom_command(TARGET mariadb_connector_cpp POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${MARIADB_CPP_CONNECTOR_DIR}/mariadbcpp.dll" - "${MARIADB_C_CONNECTOR_DIR}/lib/libmariadb.dll" + "${MARIADBCPP_SHARED_LIBRARY_LOCATION}" + "${MARIADBC_SHARED_LIBRARY_LOCATION}" "${PROJECT_BINARY_DIR}") # MariaDB uses plugins that the database needs to load, the prebuilt binaries by default will try to find the libraries in system directories, # so set this define and the servers will set the MARIADB_PLUGIN_DIR environment variable to the appropriate directory. # Plugin directory is determined at dll load time (this will happen before main()) so we need to delay the dll load so that we can set the environment variable - add_link_options(/DELAYLOAD:${MARIADB_SHARED_LIBRARY_LOCATION}) + add_link_options(/DELAYLOAD:${MARIADBCPP_SHARED_LIBRARY_LOCATION}) add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADB_CPP_CONNECTOR_DIR}/plugin") else() # Build from source @@ -85,77 +86,61 @@ else() # Build from source -DCMAKE_CXX_FLAGS=-D_GLIBCXX_USE_CXX11_ABI=0) endif() + set(MARIADBCPP_INSTALL_DIR ${PROJECT_BINARY_DIR}/prefix) + set(MARIADBCPP_LIBRARY_DIR ${PROJECT_BINARY_DIR}/mariadbcpp) + set(MARIADBCPP_PLUGIN_DIR ${MARIADBCPP_LIBRARY_DIR}/plugin) + set(MARIADBCPP_SOURCE_DIR ${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp) + set(MARIADB_INCLUDE_DIR "${MARIADBCPP_SOURCE_DIR}/include") ExternalProject_Add(mariadb_connector_cpp - SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp - CMAKE_ARGS -Wno-dev - -DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN} - -DCMAKE_INSTALL_PREFIX=./mariadbcpp # Points the connector to the correct plugin directory - -DINSTALL_PLUGINDIR=plugin - ${MARIADB_EXTRA_CMAKE_ARGS} - PREFIX "${PROJECT_BINARY_DIR}/mariadbcpp" - BUILD_COMMAND cmake --build . --config RelWithDebInfo -j${MARIADB_CONNECTOR_COMPILE_JOBS} - INSTALL_COMMAND "") - - ExternalProject_Get_Property(mariadb_connector_cpp BINARY_DIR) + PREFIX "${PROJECT_BINARY_DIR}/thirdparty/mariadb-connector-cpp" + SOURCE_DIR ${MARIADBCPP_SOURCE_DIR} + INSTALL_DIR ${MARIADBCPP_INSTALL_DIR} + CMAKE_ARGS -Wno-dev + -DWITH_UNIT_TESTS=OFF + -DMARIADB_LINK_DYNAMIC=OFF + -DCMAKE_BUILD_RPATH_USE_ORIGIN=${CMAKE_BUILD_RPATH_USE_ORIGIN} + -DCMAKE_INSTALL_PREFIX= + -DINSTALL_LIBDIR=${MARIADBCPP_LIBRARY_DIR} + -DINSTALL_PLUGINDIR=${MARIADBCPP_PLUGIN_DIR} + ${MARIADB_EXTRA_CMAKE_ARGS} + BUILD_ALWAYS true + ) if(WIN32) set(MARIADB_SHARED_LIBRARY_NAME mariadbcpp.dll) set(MARIADB_PLUGIN_SUFFIX .dll) - set(MARIADB_IMPLIB_LOCATION "${BINARY_DIR}/RelWithDebInfo/mariadbcpp.lib") + set(MARIADB_IMPLIB_LOCATION "${MARIADBCPP_LIBRARY_DIR}/mariadbcpp.lib") # When built from source windows only seems to check same folder as exe instead specified folder, so use # environment variable to force it add_link_options(/DELAYLOAD:mariadbcpp.dll) - add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${PROJECT_BINARY_DIR}/mariadbcpp/plugin") + add_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADBCPP_PLUGIN_DIR}") else() set(MARIADB_SHARED_LIBRARY_NAME libmariadbcpp${CMAKE_SHARED_LIBRARY_SUFFIX}) - set(MARIADB_PLUGIN_SUFFIX .so) + set(MARIADB_PLUGIN_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX}) endif() - get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) - if(isMultiConfig) - set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/RelWithDebInfo/${MARIADB_SHARED_LIBRARY_NAME}") - set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}/$") - set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb/RelWithDebInfo") - else() - set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}") - set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}") - set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb") + set(MARIADBCPP_SHARED_LIBRARY_LOCATION "${MARIADBCPP_LIBRARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}") + if(WIN32) + set(MARIADBC_SHARED_LIBRARY_LOCATION "${MARIADBCPP_LIBRARY_DIR}/libmariadb.lib") endif() - - set(MARIADB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include/") - - add_custom_command(TARGET mariadb_connector_cpp POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - ${BINARY_DIR}/mariadbcpp/plugin - ${MARIADB_SHARED_LIBRARY_COPY_LOCATION} - - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${MARIADB_SHARED_LIBRARY_LOCATION} - ${MARIADB_SHARED_LIBRARY_COPY_LOCATION} - - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${MARIADB_PLUGINS_LOCATION}/caching_sha2_password${MARIADB_PLUGIN_SUFFIX} - ${MARIADB_PLUGINS_LOCATION}/client_ed25519${MARIADB_PLUGIN_SUFFIX} - ${MARIADB_PLUGINS_LOCATION}/dialog${MARIADB_PLUGIN_SUFFIX} - ${MARIADB_PLUGINS_LOCATION}/mysql_clear_password${MARIADB_PLUGIN_SUFFIX} - ${MARIADB_PLUGINS_LOCATION}/sha256_password${MARIADB_PLUGIN_SUFFIX} - ${BINARY_DIR}/mariadbcpp/plugin) -endif() - -# Remove the CMakeLists.txt file from the tests folder for the maria-db-connector so we dont compile the tests. -if(EXISTS "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt") - file(REMOVE "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt") endif() # Create mariadb connector library object -add_library(mariadbConnCpp SHARED IMPORTED GLOBAL) -set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_LOCATION ${MARIADB_SHARED_LIBRARY_LOCATION}) +add_library(MariaDB::ConnCpp SHARED IMPORTED GLOBAL) +add_dependencies(MariaDB::ConnCpp mariadb_connector_cpp) +set_target_properties(MariaDB::ConnCpp PROPERTIES + IMPORTED_LOCATION "${MARIADBCPP_SHARED_LIBRARY_LOCATION}") if(WIN32) - set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_IMPLIB ${MARIADB_IMPLIB_LOCATION}) + set_target_properties(MariaDB::ConnCpp PROPERTIES + IMPORTED_IMPLIB "${MARIADB_IMPLIB_LOCATION}") +elseif(APPLE) + set_target_properties(MariaDB::ConnCpp PROPERTIES + IMPORTED_SONAME "libmariadbcpp") endif() # Add directories to include lists -target_include_directories(mariadbConnCpp INTERFACE ${MARIADB_INCLUDE_DIR}) -add_dependencies(mariadbConnCpp mariadb_connector_cpp) +target_include_directories(MariaDB::ConnCpp SYSTEM INTERFACE ${MARIADB_INCLUDE_DIR}) + +set(MariaDB_FOUND TRUE) diff --git a/cmake/toolchains/linux-clang.cmake b/cmake/toolchains/linux-clang.cmake new file mode 100644 index 000000000..b4578a38b --- /dev/null +++ b/cmake/toolchains/linux-clang.cmake @@ -0,0 +1,14 @@ +# Try and find a clang-16 install, falling back to a generic clang install otherwise +find_program(CLANG_C_COMPILER clang-16 | clang REQUIRED) +find_program(CLANG_CXX_COMPILER clang++-16 | clang++ REQUIRED) + +# Debug messages +message(DEBUG "CLANG_C_COMPILER = ${CLANG_C_COMPILER}") +message(DEBUG "CLANG_CXX_COMPILER = ${CLANG_CXX_COMPILER}") + +# Set compilers to clang (need to cache for VSCode tools to work correctly) +set(CMAKE_C_COMPILER ${CLANG_C_COMPILER} CACHE STRING "Set C compiler") +set(CMAKE_CXX_COMPILER ${CLANG_CXX_COMPILER} CACHE STRING "Set C++ compiler") + +# Set linker to lld +add_link_options("-fuse-ld=lld") diff --git a/cmake/toolchains/linux-gnu.cmake b/cmake/toolchains/linux-gnu.cmake new file mode 100644 index 000000000..3eadbc9eb --- /dev/null +++ b/cmake/toolchains/linux-gnu.cmake @@ -0,0 +1,11 @@ +# Try and find a gcc/g++ install +find_program(GNU_C_COMPILER cc | gcc REQUIRED) +find_program(GNU_CXX_COMPILER c++ | g++ REQUIRED) + +# Debug messages +message(DEBUG "GNU_C_COMPILER = ${GNU_C_COMPILER}") +message(DEBUG "GNU_CXX_COMPILER = ${GNU_CXX_COMPILER}") + +# Set compilers to GNU (need to cache for VSCode tools to work correctly) +set(CMAKE_C_COMPILER ${GNU_C_COMPILER} CACHE STRING "Set C compiler") +set(CMAKE_CXX_COMPILER ${GNU_CXX_COMPILER} CACHE STRING "Set C++ compiler") diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 476e1a689..d306eb70e 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -21,8 +21,8 @@ //Auth includes: #include "AuthPackets.h" #include "eConnectionType.h" -#include "eServerMessageType.h" -#include "eAuthMessageType.h" +#include "MessageType/Server.h" +#include "MessageType/Auth.h" #include "Game.h" #include "Server.h" @@ -102,7 +102,7 @@ int main(int argc, char** argv) { uint32_t framesSinceLastSQLPing = 0; AuthPackets::LoadClaimCodes(); - + Game::logger->Flush(); // once immediately before main loop while (!Game::ShouldShutdown()) { //Check if we're still connected to master: @@ -166,11 +166,11 @@ void HandlePacket(Packet* packet) { if (packet->data[0] == ID_USER_PACKET_ENUM) { if (static_cast(packet->data[1]) == eConnectionType::SERVER) { - if (static_cast(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) { + if (static_cast(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) { AuthPackets::HandleHandshake(Game::server, packet); } } else if (static_cast(packet->data[1]) == eConnectionType::AUTH) { - if (static_cast(packet->data[3]) == eAuthMessageType::LOGIN_REQUEST) { + if (static_cast(packet->data[3]) == MessageType::Auth::LOGIN_REQUEST) { AuthPackets::HandleLoginRequest(Game::server, packet); } } diff --git a/dChatFilter/dChatFilter.cpp b/dChatFilter/dChatFilter.cpp index 6e81db3b8..844e34118 100644 --- a/dChatFilter/dChatFilter.cpp +++ b/dChatFilter/dChatFilter.cpp @@ -27,8 +27,8 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) { ExportWordlistToDCF(filepath + ".dcf", true); } - if (BinaryIO::DoesFileExist("blacklist.dcf")) { - ReadWordlistDCF("blacklist.dcf", false); + if (BinaryIO::DoesFileExist("blocklist.dcf")) { + ReadWordlistDCF("blocklist.dcf", false); } //Read player names that are ok as well: @@ -44,20 +44,20 @@ dChatFilter::~dChatFilter() { m_DeniedWords.clear(); } -void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) { +void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool allowList) { std::ifstream file(filepath); if (file) { std::string line; while (std::getline(file, line)) { line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase - if (whiteList) m_ApprovedWords.push_back(CalculateHash(line)); + if (allowList) m_ApprovedWords.push_back(CalculateHash(line)); else m_DeniedWords.push_back(CalculateHash(line)); } } } -bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) { +bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool allowList) { std::ifstream file(filepath, std::ios::binary); if (file) { fileHeader hdr; @@ -70,13 +70,13 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) { if (hdr.formatVersion == formatVersion) { size_t wordsToRead = 0; BinaryIO::BinaryRead(file, wordsToRead); - if (whiteList) m_ApprovedWords.reserve(wordsToRead); + if (allowList) m_ApprovedWords.reserve(wordsToRead); else m_DeniedWords.reserve(wordsToRead); size_t word = 0; for (size_t i = 0; i < wordsToRead; ++i) { BinaryIO::BinaryRead(file, word); - if (whiteList) m_ApprovedWords.push_back(word); + if (allowList) m_ApprovedWords.push_back(word); else m_DeniedWords.push_back(word); } @@ -90,14 +90,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) { return false; } -void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) { +void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool allowList) { std::ofstream file(filepath, std::ios::binary | std::ios_base::out); if (file) { BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header)); BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion)); - BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size())); + BinaryIO::BinaryWrite(file, size_t(allowList ? m_ApprovedWords.size() : m_DeniedWords.size())); - for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) { + for (size_t word : allowList ? m_ApprovedWords : m_DeniedWords) { BinaryIO::BinaryWrite(file, word); } @@ -105,10 +105,10 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis } } -std::vector> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList) { +std::vector> dChatFilter::IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList) { if (gmLevel > eGameMasterLevel::FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. if (message.empty()) return { }; - if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } }; + if (!allowList && m_DeniedWords.empty()) return { { 0, message.length() } }; std::stringstream sMessage(message); std::string segment; @@ -126,16 +126,16 @@ std::vector> dChatFilter::IsSentenceOkay(const std:: size_t hash = CalculateHash(segment); - if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) { + if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && allowList) { listOfBadSegments.emplace_back(position, originalSegment.length()); } - if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) { + if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && allowList) { m_UserUnapprovedWordCache.push_back(hash); listOfBadSegments.emplace_back(position, originalSegment.length()); } - if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) { + if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !allowList) { m_UserUnapprovedWordCache.push_back(hash); listOfBadSegments.emplace_back(position, originalSegment.length()); } diff --git a/dChatFilter/dChatFilter.h b/dChatFilter/dChatFilter.h index d00525ce5..0f1e49bac 100644 --- a/dChatFilter/dChatFilter.h +++ b/dChatFilter/dChatFilter.h @@ -21,10 +21,10 @@ class dChatFilter dChatFilter(const std::string& filepath, bool dontGenerateDCF); ~dChatFilter(); - void ReadWordlistPlaintext(const std::string& filepath, bool whiteList); - bool ReadWordlistDCF(const std::string& filepath, bool whiteList); - void ExportWordlistToDCF(const std::string& filepath, bool whiteList); - std::vector> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool whiteList = true); + void ReadWordlistPlaintext(const std::string& filepath, bool allowList); + bool ReadWordlistDCF(const std::string& filepath, bool allowList); + void ExportWordlistToDCF(const std::string& filepath, bool allowList); + std::vector> IsSentenceOkay(const std::string& message, eGameMasterLevel gmLevel, bool allowList = true); private: bool m_DontGenerateDCF; diff --git a/dChatServer/CMakeLists.txt b/dChatServer/CMakeLists.txt index cc4cee1f5..c7eea041e 100644 --- a/dChatServer/CMakeLists.txt +++ b/dChatServer/CMakeLists.txt @@ -5,10 +5,12 @@ set(DCHATSERVER_SOURCES ) add_executable(ChatServer "ChatServer.cpp") -add_library(dChatServer ${DCHATSERVER_SOURCES}) -target_include_directories(dChatServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer) +target_include_directories(ChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dChatFilter") add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"") +add_library(dChatServer ${DCHATSERVER_SOURCES}) +target_include_directories(dChatServer PRIVATE "${PROJECT_SOURCE_DIR}/dServer") + target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter) target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer dServer) diff --git a/dChatServer/ChatIgnoreList.cpp b/dChatServer/ChatIgnoreList.cpp index f0c55eb08..3e0fbb934 100644 --- a/dChatServer/ChatIgnoreList.cpp +++ b/dChatServer/ChatIgnoreList.cpp @@ -1,6 +1,6 @@ #include "ChatIgnoreList.h" #include "PlayerContainer.h" -#include "eChatInternalMessageType.h" +#include "MessageType/Chat.h" #include "BitStreamUtils.h" #include "Game.h" #include "Logger.h" @@ -13,7 +13,7 @@ // The only thing not auto-handled is instance activities force joining the team on the server. void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) { - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receivingPlayer); //portion that will get routed: diff --git a/dChatServer/ChatPacketHandler.cpp b/dChatServer/ChatPacketHandler.cpp index 5e2e58d7d..891119dc2 100644 --- a/dChatServer/ChatPacketHandler.cpp +++ b/dChatServer/ChatPacketHandler.cpp @@ -13,12 +13,12 @@ #include "dConfig.h" #include "eObjectBits.h" #include "eConnectionType.h" -#include "eChatMessageType.h" -#include "eChatInternalMessageType.h" -#include "eClientMessageType.h" -#include "eGameMessageType.h" +#include "MessageType/Chat.h" +#include "MessageType/Client.h" +#include "MessageType/Game.h" #include "StringifiedEnum.h" #include "eGameMasterLevel.h" +#include "ChatPackets.h" void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { //Get from the packet which player we want to do something with: @@ -60,11 +60,11 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { //Now, we need to send the friendlist to the server they came from: CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(playerID); //portion that will get routed: - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GET_FRIENDS_LIST_RESPONSE); bitStream.Write(0); bitStream.Write(1); //Length of packet -- just writing one as it doesn't matter, client skips it. bitStream.Write(player.friends.size()); @@ -355,7 +355,68 @@ void ChatPacketHandler::HandleGMLevelUpdate(Packet* packet) { inStream.Read(player.gmLevel); } -// the structure the client uses to send this packet is shared in many chat messages + +void ChatPacketHandler::HandleWho(Packet* packet) { + CINSTREAM_SKIP_HEADER; + FindPlayerRequest request; + request.Deserialize(inStream); + + const auto& sender = Game::playerContainer.GetPlayerData(request.requestor); + if (!sender) return; + + const auto& player = Game::playerContainer.GetPlayerData(request.playerName.GetAsString()); + bool online = player; + + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); + bitStream.Write(request.requestor); + + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::WHO_RESPONSE); + bitStream.Write(online); + bitStream.Write(player.zoneID.GetMapID()); + bitStream.Write(player.zoneID.GetInstanceID()); + bitStream.Write(player.zoneID.GetCloneID()); + bitStream.Write(request.playerName); + + SystemAddress sysAddr = sender.sysAddr; + SEND_PACKET; +} + +void ChatPacketHandler::HandleShowAll(Packet* packet) { + CINSTREAM_SKIP_HEADER; + ShowAllRequest request; + request.Deserialize(inStream); + + const auto& sender = Game::playerContainer.GetPlayerData(request.requestor); + if (!sender) return; + + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); + bitStream.Write(request.requestor); + + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::SHOW_ALL_RESPONSE); + bitStream.Write(!request.displayZoneData && !request.displayIndividualPlayers); + bitStream.Write(Game::playerContainer.GetPlayerCount()); + bitStream.Write(Game::playerContainer.GetSimCount()); + bitStream.Write(request.displayIndividualPlayers); + bitStream.Write(request.displayZoneData); + if (request.displayZoneData || request.displayIndividualPlayers){ + for (auto& [playerID, playerData ]: Game::playerContainer.GetAllPlayers()){ + if (!playerData) continue; + bitStream.Write(0); // structure packing + if (request.displayIndividualPlayers) bitStream.Write(LUWString(playerData.playerName)); + if (request.displayZoneData) { + bitStream.Write(playerData.zoneID.GetMapID()); + bitStream.Write(playerData.zoneID.GetInstanceID()); + bitStream.Write(playerData.zoneID.GetCloneID()); + } + } + } + SystemAddress sysAddr = sender.sysAddr; + SEND_PACKET; +} + +// the structure the client uses to send this packet is shared in many chat messages // that are sent to the server. Because of this, there are large gaps of unused data in chat messages void ChatPacketHandler::HandleChatMessage(Packet* packet) { CINSTREAM_SKIP_HEADER; @@ -367,7 +428,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) { eChatChannel channel; uint32_t size; - + inStream.IgnoreBytes(4); inStream.Read(channel); inStream.Read(size); @@ -375,7 +436,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) { LUWString message(size); inStream.Read(message); - + LOG("Got a message from (%s) via [%s]: %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str()); switch (channel) { @@ -396,7 +457,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) { } } -// the structure the client uses to send this packet is shared in many chat messages +// the structure the client uses to send this packet is shared in many chat messages // that are sent to the server. Because of this, there are large gaps of unused data in chat messages void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { CINSTREAM_SKIP_HEADER; @@ -423,7 +484,7 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { LUWString message(size); inStream.Read(message); - + LOG("Got a message from (%s) via [%s]: %s to %s", sender.playerName.c_str(), StringifiedEnum::ToString(channel).data(), message.GetAsString().c_str(), receiverName.c_str()); const auto& receiver = Game::playerContainer.GetPlayerData(receiverName); @@ -454,10 +515,10 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { void ChatPacketHandler::SendPrivateChatMessage(const PlayerData& sender, const PlayerData& receiver, const PlayerData& routeTo, const LUWString& message, const eChatChannel channel, const eChatMessageResponseCode responseCode) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(routeTo.playerID); - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::PRIVATE_CHAT_MESSAGE); bitStream.Write(sender.playerID); bitStream.Write(channel); bitStream.Write(0); // not used @@ -696,11 +757,11 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) { void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerData& sender) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TEAM_INVITE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::TEAM_INVITE); bitStream.Write(LUWString(sender.playerName.c_str())); bitStream.Write(sender.playerID); @@ -711,14 +772,14 @@ void ChatPacketHandler::SendTeamInvite(const PlayerData& receiver, const PlayerD void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: CMSGHEADER; bitStream.Write(receiver.playerID); - bitStream.Write(eGameMessageType::TEAM_INVITE_CONFIRM); + bitStream.Write(MessageType::Game::TEAM_INVITE_CONFIRM); bitStream.Write(bLeaderIsFreeTrial); bitStream.Write(i64LeaderID); @@ -738,14 +799,14 @@ void ChatPacketHandler::SendTeamInviteConfirm(const PlayerData& receiver, bool b void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: CMSGHEADER; bitStream.Write(receiver.playerID); - bitStream.Write(eGameMessageType::TEAM_GET_STATUS_RESPONSE); + bitStream.Write(MessageType::Game::TEAM_GET_STATUS_RESPONSE); bitStream.Write(i64LeaderID); bitStream.Write(i64LeaderZoneID); @@ -763,14 +824,14 @@ void ChatPacketHandler::SendTeamStatus(const PlayerData& receiver, LWOOBJID i64L void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i64PlayerID) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: CMSGHEADER; bitStream.Write(receiver.playerID); - bitStream.Write(eGameMessageType::TEAM_SET_LEADER); + bitStream.Write(MessageType::Game::TEAM_SET_LEADER); bitStream.Write(i64PlayerID); @@ -780,14 +841,14 @@ void ChatPacketHandler::SendTeamSetLeader(const PlayerData& receiver, LWOOBJID i void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: CMSGHEADER; bitStream.Write(receiver.playerID); - bitStream.Write(eGameMessageType::TEAM_ADD_PLAYER); + bitStream.Write(MessageType::Game::TEAM_ADD_PLAYER); bitStream.Write(bIsFreeTrial); bitStream.Write(bLocal); @@ -809,14 +870,14 @@ void ChatPacketHandler::SendTeamAddPlayer(const PlayerData& receiver, bool bIsFr void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: CMSGHEADER; bitStream.Write(receiver.playerID); - bitStream.Write(eGameMessageType::TEAM_REMOVE_PLAYER); + bitStream.Write(MessageType::Game::TEAM_REMOVE_PLAYER); bitStream.Write(bDisband); bitStream.Write(bIsKicked); @@ -835,14 +896,14 @@ void ChatPacketHandler::SendTeamRemovePlayer(const PlayerData& receiver, bool bD void ChatPacketHandler::SendTeamSetOffWorldFlag(const PlayerData& receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: CMSGHEADER; bitStream.Write(receiver.playerID); - bitStream.Write(eGameMessageType::TEAM_SET_OFF_WORLD_FLAG); + bitStream.Write(MessageType::Game::TEAM_SET_OFF_WORLD_FLAG); bitStream.Write(i64PlayerID); if (receiver.zoneID.GetCloneID() == zoneID.GetCloneID()) { @@ -869,11 +930,11 @@ void ChatPacketHandler::SendFriendUpdate(const PlayerData& friendData, const Pla [bool] - is FTP*/ CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(friendData.playerID); //portion that will get routed: - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::UPDATE_FRIEND_NOTIFY); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::UPDATE_FRIEND_NOTIFY); bitStream.Write(notifyType); std::string playerName = playerData.playerName.c_str(); @@ -906,11 +967,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play } CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_REQUEST); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::ADD_FRIEND_REQUEST); bitStream.Write(LUWString(sender.playerName)); bitStream.Write(0); // This is a BFF flag however this is unused in live and does not have an implementation client side. @@ -920,11 +981,11 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const PlayerData& sender, eAddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); // Portion that will get routed: - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::ADD_FRIEND_RESPONSE); bitStream.Write(responseCode); // For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver. bitStream.Write(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender.sysAddr != UNASSIGNED_SYSTEM_ADDRESS); @@ -943,11 +1004,11 @@ void ChatPacketHandler::SendFriendResponse(const PlayerData& receiver, const Pla void ChatPacketHandler::SendRemoveFriend(const PlayerData& receiver, std::string& personToRemove, bool isSuccessful) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::REMOVE_FRIEND_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::REMOVE_FRIEND_RESPONSE); bitStream.Write(isSuccessful); //isOnline bitStream.Write(LUWString(personToRemove)); diff --git a/dChatServer/ChatPacketHandler.h b/dChatServer/ChatPacketHandler.h index 847fc899d..def9c9b96 100644 --- a/dChatServer/ChatPacketHandler.h +++ b/dChatServer/ChatPacketHandler.h @@ -50,6 +50,8 @@ namespace ChatPacketHandler { void HandleFriendResponse(Packet* packet); void HandleRemoveFriend(Packet* packet); void HandleGMLevelUpdate(Packet* packet); + void HandleWho(Packet* packet); + void HandleShowAll(Packet* packet); void HandleChatMessage(Packet* packet); void HandlePrivateChatMessage(Packet* packet); diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index 9ba700260..022175e5e 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -16,9 +16,8 @@ #include "eConnectionType.h" #include "PlayerContainer.h" #include "ChatPacketHandler.h" -#include "eChatMessageType.h" -#include "eChatInternalMessageType.h" -#include "eWorldMessageType.h" +#include "MessageType/Chat.h" +#include "MessageType/World.h" #include "ChatIgnoreList.h" #include "StringifiedEnum.h" @@ -101,7 +100,7 @@ int main(int argc, char** argv) { //It's safe to pass 'localhost' here, as the IP is only used as the external IP. std::string ourIP = "localhost"; const uint32_t maxClients = GeneralUtils::TryParse(Game::config->GetValue("max_clients")).value_or(999); - const uint32_t ourPort = GeneralUtils::TryParse(Game::config->GetValue("chat_server_port")).value_or(1501); + const uint32_t ourPort = GeneralUtils::TryParse(Game::config->GetValue("chat_server_port")).value_or(2005); const auto externalIPString = Game::config->GetValue("external_ip"); if (!externalIPString.empty()) ourIP = externalIPString; @@ -109,7 +108,7 @@ int main(int argc, char** argv) { const bool dontGenerateDCF = GeneralUtils::TryParse(Game::config->GetValue("dont_generate_dcf")).value_or(false); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF); - + Game::randomEngine = std::mt19937(time(0)); Game::playerContainer.Initialize(); @@ -180,185 +179,168 @@ int main(int argc, char** argv) { } void HandlePacket(Packet* packet) { + if (packet->length < 1) return; if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { LOG("A server has disconnected, erasing their connected players from the list."); - } - - if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) { + } else if (packet->data[0] == ID_NEW_INCOMING_CONNECTION) { LOG("A server is connecting, awaiting user list."); - } + } else if (packet->length < 4 || packet->data[0] != ID_USER_PACKET_ENUM) return; // Nothing left to process or not the right packet type - if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue. + CINSTREAM; + inStream.SetReadOffset(BYTES_TO_BITS(1)); - if (static_cast(packet->data[1]) == eConnectionType::CHAT_INTERNAL) { - switch (static_cast(packet->data[3])) { - case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION: - Game::playerContainer.InsertPlayer(packet); - break; + eConnectionType connection; + MessageType::Chat chatMessageID; - case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION: - Game::playerContainer.RemovePlayer(packet); - break; + inStream.Read(connection); + if (connection != eConnectionType::CHAT) return; + inStream.Read(chatMessageID); - case eChatInternalMessageType::MUTE_UPDATE: + switch (chatMessageID) { + case MessageType::Chat::GM_MUTE: Game::playerContainer.MuteUpdate(packet); break; - case eChatInternalMessageType::CREATE_TEAM: + case MessageType::Chat::CREATE_TEAM: Game::playerContainer.CreateTeamServer(packet); break; - case eChatInternalMessageType::ANNOUNCEMENT: { - //we just forward this packet to every connected server - CINSTREAM; - Game::server->Send(inStream, packet->systemAddress, true); //send to everyone except origin - break; - } - - default: - LOG("Unknown CHAT_INTERNAL id: %i", int(packet->data[3])); - } - } - - if (static_cast(packet->data[1]) == eConnectionType::CHAT) { - eChatMessageType chat_message_type = static_cast(packet->data[3]); - switch (chat_message_type) { - case eChatMessageType::GET_FRIENDS_LIST: + case MessageType::Chat::GET_FRIENDS_LIST: ChatPacketHandler::HandleFriendlistRequest(packet); break; - case eChatMessageType::GET_IGNORE_LIST: + case MessageType::Chat::GET_IGNORE_LIST: ChatIgnoreList::GetIgnoreList(packet); break; - case eChatMessageType::ADD_IGNORE: + case MessageType::Chat::ADD_IGNORE: ChatIgnoreList::AddIgnore(packet); break; - case eChatMessageType::REMOVE_IGNORE: + case MessageType::Chat::REMOVE_IGNORE: ChatIgnoreList::RemoveIgnore(packet); break; - case eChatMessageType::TEAM_GET_STATUS: + case MessageType::Chat::TEAM_GET_STATUS: ChatPacketHandler::HandleTeamStatusRequest(packet); break; - case eChatMessageType::ADD_FRIEND_REQUEST: + case MessageType::Chat::ADD_FRIEND_REQUEST: //this involves someone sending the initial request, the response is below, response as in from the other player. //We basically just check to see if this player is online or not and route the packet. ChatPacketHandler::HandleFriendRequest(packet); break; - case eChatMessageType::ADD_FRIEND_RESPONSE: + case MessageType::Chat::ADD_FRIEND_RESPONSE: //This isn't the response a server sent, rather it is a player's response to a received request. //Here, we'll actually have to add them to eachother's friend lists depending on the response code. ChatPacketHandler::HandleFriendResponse(packet); break; - case eChatMessageType::REMOVE_FRIEND: + case MessageType::Chat::REMOVE_FRIEND: ChatPacketHandler::HandleRemoveFriend(packet); break; - case eChatMessageType::GENERAL_CHAT_MESSAGE: + case MessageType::Chat::GENERAL_CHAT_MESSAGE: ChatPacketHandler::HandleChatMessage(packet); break; - case eChatMessageType::PRIVATE_CHAT_MESSAGE: + case MessageType::Chat::PRIVATE_CHAT_MESSAGE: //This message is supposed to be echo'd to both the sender and the receiver //BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up. ChatPacketHandler::HandlePrivateChatMessage(packet); break; - case eChatMessageType::TEAM_INVITE: + case MessageType::Chat::TEAM_INVITE: ChatPacketHandler::HandleTeamInvite(packet); break; - case eChatMessageType::TEAM_INVITE_RESPONSE: + case MessageType::Chat::TEAM_INVITE_RESPONSE: ChatPacketHandler::HandleTeamInviteResponse(packet); break; - case eChatMessageType::TEAM_LEAVE: + case MessageType::Chat::TEAM_LEAVE: ChatPacketHandler::HandleTeamLeave(packet); break; - case eChatMessageType::TEAM_SET_LEADER: + case MessageType::Chat::TEAM_SET_LEADER: ChatPacketHandler::HandleTeamPromote(packet); break; - case eChatMessageType::TEAM_KICK: + case MessageType::Chat::TEAM_KICK: ChatPacketHandler::HandleTeamKick(packet); break; - case eChatMessageType::TEAM_SET_LOOT: + case MessageType::Chat::TEAM_SET_LOOT: ChatPacketHandler::HandleTeamLootOption(packet); break; - case eChatMessageType::GMLEVEL_UPDATE: + case MessageType::Chat::GMLEVEL_UPDATE: ChatPacketHandler::HandleGMLevelUpdate(packet); break; - case eChatMessageType::LOGIN_SESSION_NOTIFY: - case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE: - case eChatMessageType::WORLD_DISCONNECT_REQUEST: - case eChatMessageType::WORLD_PROXIMITY_RESPONSE: - case eChatMessageType::WORLD_PARCEL_RESPONSE: - case eChatMessageType::TEAM_MISSED_INVITE_CHECK: - case eChatMessageType::GUILD_CREATE: - case eChatMessageType::GUILD_INVITE: - case eChatMessageType::GUILD_INVITE_RESPONSE: - case eChatMessageType::GUILD_LEAVE: - case eChatMessageType::GUILD_KICK: - case eChatMessageType::GUILD_GET_STATUS: - case eChatMessageType::GUILD_GET_ALL: - case eChatMessageType::SHOW_ALL: - case eChatMessageType::BLUEPRINT_MODERATED: - case eChatMessageType::BLUEPRINT_MODEL_READY: - case eChatMessageType::PROPERTY_READY_FOR_APPROVAL: - case eChatMessageType::PROPERTY_MODERATION_CHANGED: - case eChatMessageType::PROPERTY_BUILDMODE_CHANGED: - case eChatMessageType::PROPERTY_BUILDMODE_CHANGED_REPORT: - case eChatMessageType::MAIL: - case eChatMessageType::WORLD_INSTANCE_LOCATION_REQUEST: - case eChatMessageType::REPUTATION_UPDATE: - case eChatMessageType::SEND_CANNED_TEXT: - case eChatMessageType::CHARACTER_NAME_CHANGE_REQUEST: - case eChatMessageType::CSR_REQUEST: - case eChatMessageType::CSR_REPLY: - case eChatMessageType::GM_KICK: - case eChatMessageType::GM_ANNOUNCE: - case eChatMessageType::WORLD_ROUTE_PACKET: - case eChatMessageType::GET_ZONE_POPULATIONS: - case eChatMessageType::REQUEST_MINIMUM_CHAT_MODE: - case eChatMessageType::MATCH_REQUEST: - case eChatMessageType::UGCMANIFEST_REPORT_MISSING_FILE: - case eChatMessageType::UGCMANIFEST_REPORT_DONE_FILE: - case eChatMessageType::UGCMANIFEST_REPORT_DONE_BLUEPRINT: - case eChatMessageType::UGCC_REQUEST: - case eChatMessageType::WHO: - case eChatMessageType::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE: - case eChatMessageType::ACHIEVEMENT_NOTIFY: - case eChatMessageType::GM_CLOSE_PRIVATE_CHAT_WINDOW: - case eChatMessageType::UNEXPECTED_DISCONNECT: - case eChatMessageType::PLAYER_READY: - case eChatMessageType::GET_DONATION_TOTAL: - case eChatMessageType::UPDATE_DONATION: - case eChatMessageType::PRG_CSR_COMMAND: - case eChatMessageType::HEARTBEAT_REQUEST_FROM_WORLD: - case eChatMessageType::UPDATE_FREE_TRIAL_STATUS: - LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chat_message_type).data(), chat_message_type); + case MessageType::Chat::LOGIN_SESSION_NOTIFY: + Game::playerContainer.InsertPlayer(packet); break; - default: - LOG("Unknown CHAT Message id: %i", chat_message_type); - } - } - - if (static_cast(packet->data[1]) == eConnectionType::WORLD) { - switch (static_cast(packet->data[3])) { - case eWorldMessageType::ROUTE_PACKET: { - LOG("Routing packet from world"); + case MessageType::Chat::GM_ANNOUNCE:{ + // we just forward this packet to every connected server + inStream.ResetReadPointer(); + Game::server->Send(inStream, packet->systemAddress, true); // send to everyone except origin + } + break; + case MessageType::Chat::UNEXPECTED_DISCONNECT: + Game::playerContainer.RemovePlayer(packet); + break; + case MessageType::Chat::WHO: + ChatPacketHandler::HandleWho(packet); + break; + case MessageType::Chat::SHOW_ALL: + ChatPacketHandler::HandleShowAll(packet); + break; + case MessageType::Chat::USER_CHANNEL_CHAT_MESSAGE: + case MessageType::Chat::WORLD_DISCONNECT_REQUEST: + case MessageType::Chat::WORLD_PROXIMITY_RESPONSE: + case MessageType::Chat::WORLD_PARCEL_RESPONSE: + case MessageType::Chat::TEAM_MISSED_INVITE_CHECK: + case MessageType::Chat::GUILD_CREATE: + case MessageType::Chat::GUILD_INVITE: + case MessageType::Chat::GUILD_INVITE_RESPONSE: + case MessageType::Chat::GUILD_LEAVE: + case MessageType::Chat::GUILD_KICK: + case MessageType::Chat::GUILD_GET_STATUS: + case MessageType::Chat::GUILD_GET_ALL: + case MessageType::Chat::BLUEPRINT_MODERATED: + case MessageType::Chat::BLUEPRINT_MODEL_READY: + case MessageType::Chat::PROPERTY_READY_FOR_APPROVAL: + case MessageType::Chat::PROPERTY_MODERATION_CHANGED: + case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED: + case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED_REPORT: + case MessageType::Chat::MAIL: + case MessageType::Chat::WORLD_INSTANCE_LOCATION_REQUEST: + case MessageType::Chat::REPUTATION_UPDATE: + case MessageType::Chat::SEND_CANNED_TEXT: + case MessageType::Chat::CHARACTER_NAME_CHANGE_REQUEST: + case MessageType::Chat::CSR_REQUEST: + case MessageType::Chat::CSR_REPLY: + case MessageType::Chat::GM_KICK: + case MessageType::Chat::WORLD_ROUTE_PACKET: + case MessageType::Chat::GET_ZONE_POPULATIONS: + case MessageType::Chat::REQUEST_MINIMUM_CHAT_MODE: + case MessageType::Chat::MATCH_REQUEST: + case MessageType::Chat::UGCMANIFEST_REPORT_MISSING_FILE: + case MessageType::Chat::UGCMANIFEST_REPORT_DONE_FILE: + case MessageType::Chat::UGCMANIFEST_REPORT_DONE_BLUEPRINT: + case MessageType::Chat::UGCC_REQUEST: + case MessageType::Chat::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE: + case MessageType::Chat::ACHIEVEMENT_NOTIFY: + case MessageType::Chat::GM_CLOSE_PRIVATE_CHAT_WINDOW: + case MessageType::Chat::PLAYER_READY: + case MessageType::Chat::GET_DONATION_TOTAL: + case MessageType::Chat::UPDATE_DONATION: + case MessageType::Chat::PRG_CSR_COMMAND: + case MessageType::Chat::HEARTBEAT_REQUEST_FROM_WORLD: + case MessageType::Chat::UPDATE_FREE_TRIAL_STATUS: + LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chatMessageID).data(), chatMessageID); break; - } - default: - LOG("Unknown World id: %i", int(packet->data[3])); - } + LOG("Unknown CHAT Message id: %i", chatMessageID); } } diff --git a/dChatServer/PlayerContainer.cpp b/dChatServer/PlayerContainer.cpp index 4e4d1be50..d1141ce77 100644 --- a/dChatServer/PlayerContainer.cpp +++ b/dChatServer/PlayerContainer.cpp @@ -9,9 +9,9 @@ #include "BitStreamUtils.h" #include "Database.h" #include "eConnectionType.h" -#include "eChatInternalMessageType.h" #include "ChatPackets.h" #include "dConfig.h" +#include "MessageType/Chat.h" void PlayerContainer::Initialize() { m_MaxNumberOfBestFriends = @@ -36,19 +36,23 @@ void PlayerContainer::InsertPlayer(Packet* packet) { data.playerID = playerId; uint32_t len; - inStream.Read(len); + if (!inStream.Read(len)) return; - for (int i = 0; i < len; i++) { - char character; inStream.Read(character); - data.playerName += character; + if (len > 33) { + LOG("Received a really long player name, probably a fake packet %i.", len); + return; } - inStream.Read(data.zoneID); - inStream.Read(data.muteExpire); - inStream.Read(data.gmLevel); + data.playerName.resize(len); + inStream.ReadAlignedBytes(reinterpret_cast(data.playerName.data()), len); + + if (!inStream.Read(data.zoneID)) return; + if (!inStream.Read(data.muteExpire)) return; + if (!inStream.Read(data.gmLevel)) return; data.sysAddr = packet->systemAddress; m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName); + m_PlayerCount++; LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID()); @@ -87,6 +91,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) { } } + m_PlayerCount--; LOG("Removed user: %llu", playerID); m_Players.erase(playerID); @@ -120,6 +125,11 @@ void PlayerContainer::CreateTeamServer(Packet* packet) { size_t membersSize = 0; inStream.Read(membersSize); + if (membersSize >= 4) { + LOG("Tried to create a team with more than 4 players"); + return; + } + std::vector members; members.reserve(membersSize); @@ -138,14 +148,13 @@ void PlayerContainer::CreateTeamServer(Packet* packet) { if (team != nullptr) { team->zoneId = zoneId; + UpdateTeamsOnWorld(team, false); } - - UpdateTeamsOnWorld(team, false); } void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_MUTE); bitStream.Write(player); bitStream.Write(time); @@ -352,7 +361,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) { void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::TEAM_GET_STATUS); bitStream.Write(team->teamID); bitStream.Write(deleteTeam); @@ -390,7 +399,7 @@ LWOOBJID PlayerContainer::GetId(const std::u16string& playerName) { } PlayerData& PlayerContainer::GetPlayerDataMutable(const LWOOBJID& playerID) { - return m_Players[playerID]; + return m_Players.contains(playerID) ? m_Players[playerID] : m_Players[LWOOBJID_EMPTY]; } PlayerData& PlayerContainer::GetPlayerDataMutable(const std::string& playerName) { diff --git a/dChatServer/PlayerContainer.h b/dChatServer/PlayerContainer.h index 3f2d783a6..9a17f9278 100644 --- a/dChatServer/PlayerContainer.h +++ b/dChatServer/PlayerContainer.h @@ -71,6 +71,9 @@ class PlayerContainer { const PlayerData& GetPlayerData(const std::string& playerName); PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID); PlayerData& GetPlayerDataMutable(const std::string& playerName); + uint32_t GetPlayerCount() { return m_PlayerCount; }; + uint32_t GetSimCount() { return m_SimCount; }; + const std::map& GetAllPlayers() { return m_Players; }; TeamData* CreateLocalTeam(std::vector members); TeamData* CreateTeam(LWOOBJID leader, bool local = false); @@ -93,5 +96,7 @@ class PlayerContainer { std::unordered_map m_Names; uint32_t m_MaxNumberOfBestFriends = 5; uint32_t m_MaxNumberOfFriends = 50; + uint32_t m_PlayerCount = 0; + uint32_t m_SimCount = 0; }; diff --git a/dCommon/CMakeLists.txt b/dCommon/CMakeLists.txt index c5fff63a9..d020ff72f 100644 --- a/dCommon/CMakeLists.txt +++ b/dCommon/CMakeLists.txt @@ -30,11 +30,15 @@ foreach(file ${DCOMMON_DCLIENT_SOURCES}) set(DCOMMON_SOURCES ${DCOMMON_SOURCES} "dClient/${file}") endforeach() -include_directories(${PROJECT_SOURCE_DIR}/dCommon/) - add_library(dCommon STATIC ${DCOMMON_SOURCES}) - -target_link_libraries(dCommon bcrypt dDatabase tinyxml2) +target_include_directories(dCommon + PUBLIC "." "dClient" "dEnums" + PRIVATE + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase" + "${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include" +) if (UNIX) find_package(ZLIB REQUIRED) @@ -65,4 +69,6 @@ else () ) endif () -target_link_libraries(dCommon ZLIB::ZLIB) +target_link_libraries(dCommon + PRIVATE ZLIB::ZLIB bcrypt tinyxml2 + INTERFACE dDatabase) diff --git a/dCommon/Diagnostics.cpp b/dCommon/Diagnostics.cpp index 46c17e437..9f1291945 100644 --- a/dCommon/Diagnostics.cpp +++ b/dCommon/Diagnostics.cpp @@ -120,6 +120,8 @@ void CatchUnhandled(int sig) { if (eptr) std::rethrow_exception(eptr); } catch(const std::exception& e) { LOG("Caught exception: '%s'", e.what()); + } catch (...) { + LOG("Caught unknown exception."); } #ifndef INCLUDE_BACKTRACE @@ -199,7 +201,7 @@ void OnTerminate() { } void MakeBacktrace() { - struct sigaction sigact; + struct sigaction sigact{}; sigact.sa_sigaction = CritErrHdlr; sigact.sa_flags = SA_RESTART | SA_SIGINFO; diff --git a/dCommon/GeneralUtils.cpp b/dCommon/GeneralUtils.cpp index 27ebfb2c6..522879048 100644 --- a/dCommon/GeneralUtils.cpp +++ b/dCommon/GeneralUtils.cpp @@ -8,23 +8,23 @@ #include template -inline size_t MinSize(size_t size, const std::basic_string_view& string) { - if (size == size_t(-1) || size > string.size()) { +static inline size_t MinSize(const size_t size, const std::basic_string_view string) { + if (size == SIZE_MAX || size > string.size()) { return string.size(); } else { return size; } } -inline bool IsLeadSurrogate(char16_t c) { +inline bool IsLeadSurrogate(const char16_t c) { return (0xD800 <= c) && (c <= 0xDBFF); } -inline bool IsTrailSurrogate(char16_t c) { +inline bool IsTrailSurrogate(const char16_t c) { return (0xDC00 <= c) && (c <= 0xDFFF); } -inline void PushUTF8CodePoint(std::string& ret, char32_t cp) { +inline void PushUTF8CodePoint(std::string& ret, const char32_t cp) { if (cp <= 0x007F) { ret.push_back(static_cast(cp)); } else if (cp <= 0x07FF) { @@ -46,16 +46,16 @@ inline void PushUTF8CodePoint(std::string& ret, char32_t cp) { constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD; -bool _IsSuffixChar(uint8_t c) { +bool static _IsSuffixChar(const uint8_t c) { return (c & 0xC0) == 0x80; } -bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) { - size_t rem = slice.length(); +bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out) { + const size_t rem = slice.length(); if (slice.empty()) return false; const uint8_t* bytes = reinterpret_cast(&slice.front()); if (rem > 0) { - uint8_t first = bytes[0]; + const uint8_t first = bytes[0]; if (first < 0x80) { // 1 byte character out = static_cast(first & 0x7F); slice.remove_prefix(1); @@ -64,7 +64,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) { // middle byte, not valid at start, fall through } else if (first < 0xE0) { // two byte character if (rem > 1) { - uint8_t second = bytes[1]; + const uint8_t second = bytes[1]; if (_IsSuffixChar(second)) { out = (static_cast(first & 0x1F) << 6) + static_cast(second & 0x3F); @@ -74,8 +74,8 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) { } } else if (first < 0xF0) { // three byte character if (rem > 2) { - uint8_t second = bytes[1]; - uint8_t third = bytes[2]; + const uint8_t second = bytes[1]; + const uint8_t third = bytes[2]; if (_IsSuffixChar(second) && _IsSuffixChar(third)) { out = (static_cast(first & 0x0F) << 12) + (static_cast(second & 0x3F) << 6) @@ -86,9 +86,9 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) { } } else if (first < 0xF8) { // four byte character if (rem > 3) { - uint8_t second = bytes[1]; - uint8_t third = bytes[2]; - uint8_t fourth = bytes[3]; + const uint8_t second = bytes[1]; + const uint8_t third = bytes[2]; + const uint8_t fourth = bytes[3]; if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) { out = (static_cast(first & 0x07) << 18) + (static_cast(second & 0x3F) << 12) @@ -107,7 +107,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) { } /// See -bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) { +bool PushUTF16CodePoint(std::u16string& output, const uint32_t U, const size_t size) { if (output.length() >= size) return false; if (U < 0x10000) { // If U < 0x10000, encode U as a 16-bit unsigned integer and terminate. @@ -120,7 +120,7 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) { // Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF, // U' must be less than or equal to 0xFFFFF. That is, U' can be // represented in 20 bits. - uint32_t Ut = U - 0x10000; + const uint32_t Ut = U - 0x10000; // Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and // 0xDC00, respectively. These integers each have 10 bits free to @@ -141,25 +141,25 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) { } else return false; } -std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) { - size_t newSize = MinSize(size, string); +std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view string, const size_t size) { + const size_t newSize = MinSize(size, string); std::u16string output; output.reserve(newSize); std::string_view iterator = string; uint32_t c; - while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {} + while (details::_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {} return output; } //! Converts an std::string (ASCII) to UCS-2 / UTF-16 -std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) { - size_t newSize = MinSize(size, string); +std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view string, const size_t size) { + const size_t newSize = MinSize(size, string); std::u16string ret; ret.reserve(newSize); - for (size_t i = 0; i < newSize; i++) { - char c = string[i]; + for (size_t i = 0; i < newSize; ++i) { + const char c = string[i]; // Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t ret.push_back((c > 0 && c <= 127) ? static_cast(c) : REPLACEMENT_CHARACTER); } @@ -169,18 +169,18 @@ std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t //! Converts a (potentially-ill-formed) UTF-16 string to UTF-8 //! See: -std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) { - size_t newSize = MinSize(size, string); +std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view string, const size_t size) { + const size_t newSize = MinSize(size, string); std::string ret; ret.reserve(newSize); - for (size_t i = 0; i < newSize; i++) { - char16_t u = string[i]; + for (size_t i = 0; i < newSize; ++i) { + const char16_t u = string[i]; if (IsLeadSurrogate(u) && (i + 1) < newSize) { - char16_t next = string[i + 1]; + const char16_t next = string[i + 1]; if (IsTrailSurrogate(next)) { i += 1; - char32_t cp = 0x10000 + const char32_t cp = 0x10000 + ((static_cast(u) - 0xD800) << 10) + (static_cast(next) - 0xDC00); PushUTF8CodePoint(ret, cp); @@ -195,40 +195,40 @@ std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t return ret; } -bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) { +bool GeneralUtils::CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b) { return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); }); } // MARK: Bits //! Sets a specific bit in a signed 64-bit integer -int64_t GeneralUtils::SetBit(int64_t value, uint32_t index) { +int64_t GeneralUtils::SetBit(int64_t value, const uint32_t index) { return value |= 1ULL << index; } //! Clears a specific bit in a signed 64-bit integer -int64_t GeneralUtils::ClearBit(int64_t value, uint32_t index) { +int64_t GeneralUtils::ClearBit(int64_t value, const uint32_t index) { return value &= ~(1ULL << index); } //! Checks a specific bit in a signed 64-bit integer -bool GeneralUtils::CheckBit(int64_t value, uint32_t index) { +bool GeneralUtils::CheckBit(int64_t value, const uint32_t index) { return value & (1ULL << index); } -bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) { - size_t start_pos = str.find(from); +bool GeneralUtils::ReplaceInString(std::string& str, const std::string_view from, const std::string_view to) { + const size_t start_pos = str.find(from); if (start_pos == std::string::npos) return false; str.replace(start_pos, from.length(), to); return true; } -std::vector GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) { +std::vector GeneralUtils::SplitString(const std::wstring_view str, const wchar_t delimiter) { std::vector vector = std::vector(); std::wstring current; - for (const auto& c : str) { + for (const wchar_t c : str) { if (c == delimiter) { vector.push_back(current); current = L""; @@ -237,15 +237,15 @@ std::vector GeneralUtils::SplitString(std::wstring& str, wchar_t d } } - vector.push_back(current); + vector.push_back(std::move(current)); return vector; } -std::vector GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) { +std::vector GeneralUtils::SplitString(const std::u16string_view str, const char16_t delimiter) { std::vector vector = std::vector(); std::u16string current; - for (const auto& c : str) { + for (const char16_t c : str) { if (c == delimiter) { vector.push_back(current); current = u""; @@ -254,17 +254,15 @@ std::vector GeneralUtils::SplitString(const std::u16string& str, } } - vector.push_back(current); + vector.push_back(std::move(current)); return vector; } -std::vector GeneralUtils::SplitString(const std::string& str, char delimiter) { +std::vector GeneralUtils::SplitString(const std::string_view str, const char delimiter) { std::vector vector = std::vector(); std::string current = ""; - for (size_t i = 0; i < str.length(); i++) { - char c = str[i]; - + for (const char c : str) { if (c == delimiter) { vector.push_back(current); current = ""; @@ -273,8 +271,7 @@ std::vector GeneralUtils::SplitString(const std::string& str, char } } - vector.push_back(current); - + vector.push_back(std::move(current)); return vector; } @@ -283,7 +280,7 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) { inStream.Read(length); std::u16string string; - for (auto i = 0; i < length; i++) { + for (uint32_t i = 0; i < length; ++i) { uint16_t c; inStream.Read(c); string.push_back(c); @@ -292,35 +289,35 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) { return string; } -std::vector GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) { +std::vector GeneralUtils::GetSqlFileNamesFromFolder(const std::string_view folder) { // Because we dont know how large the initial number before the first _ is we need to make it a map like so. - std::map filenames{}; - for (auto& t : std::filesystem::directory_iterator(folder)) { - auto filename = t.path().filename().string(); - auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0)); - filenames.insert(std::make_pair(index, filename)); + std::map filenames{}; + for (const auto& t : std::filesystem::directory_iterator(folder)) { + auto filename = t.path().filename().string(); + const auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0)); + filenames.emplace(index, std::move(filename)); } // Now sort the map by the oldest migration. std::vector sortedFiles{}; - auto fileIterator = filenames.begin(); - std::map::iterator oldest = filenames.begin(); + auto fileIterator = filenames.cbegin(); + auto oldest = filenames.cbegin(); while (!filenames.empty()) { - if (fileIterator == filenames.end()) { + if (fileIterator == filenames.cend()) { sortedFiles.push_back(oldest->second); filenames.erase(oldest); - fileIterator = filenames.begin(); - oldest = filenames.begin(); + fileIterator = filenames.cbegin(); + oldest = filenames.cbegin(); continue; } if (oldest->first > fileIterator->first) oldest = fileIterator; - fileIterator++; + ++fileIterator; } return sortedFiles; } -#ifdef DARKFLAME_PLATFORM_MACOS +#if !(__GNUC__ >= 11 || _MSC_VER >= 1924) // MacOS floating-point parse function specializations namespace GeneralUtils::details { diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index cba3f3d53..2c93b656d 100644 --- a/dCommon/GeneralUtils.h +++ b/dCommon/GeneralUtils.h @@ -3,17 +3,18 @@ // C++ #include #include -#include #include +#include +#include +#include +#include +#include #include #include -#include -#include #include -#include + #include "BitStream.h" #include "NiPoint3.h" - #include "dPlatforms.h" #include "Game.h" #include "Logger.h" @@ -32,29 +33,31 @@ namespace GeneralUtils { //! Converts a plain ASCII string to a UTF-16 string /*! \param string The string to convert - \param size A size to trim the string to. Default is -1 (No trimming) + \param size A size to trim the string to. Default is SIZE_MAX (No trimming) \return An UTF-16 representation of the string */ - std::u16string ASCIIToUTF16(const std::string_view& string, size_t size = -1); + std::u16string ASCIIToUTF16(const std::string_view string, const size_t size = SIZE_MAX); //! Converts a UTF-8 String to a UTF-16 string /*! \param string The string to convert - \param size A size to trim the string to. Default is -1 (No trimming) + \param size A size to trim the string to. Default is SIZE_MAX (No trimming) \return An UTF-16 representation of the string */ - std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1); + std::u16string UTF8ToUTF16(const std::string_view string, const size_t size = SIZE_MAX); - //! Internal, do not use - bool _NextUTF8Char(std::string_view& slice, uint32_t& out); + namespace details { + //! Internal, do not use + bool _NextUTF8Char(std::string_view& slice, uint32_t& out); + } //! Converts a UTF-16 string to a UTF-8 string /*! \param string The string to convert - \param size A size to trim the string to. Default is -1 (No trimming) + \param size A size to trim the string to. Default is SIZE_MAX (No trimming) \return An UTF-8 representation of the string */ - std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1); + std::string UTF16ToWTF8(const std::u16string_view string, const size_t size = SIZE_MAX); /** * Compares two basic strings but does so ignoring case sensitivity @@ -62,7 +65,7 @@ namespace GeneralUtils { * \param b the second string to compare against the first string * @return if the two strings are equal */ - bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b); + bool CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b); // MARK: Bits @@ -70,9 +73,9 @@ namespace GeneralUtils { //! Sets a bit on a numerical value template - inline void SetBit(T& value, eObjectBits bits) { + inline void SetBit(T& value, const eObjectBits bits) { static_assert(std::is_arithmetic::value, "Not an arithmetic type"); - auto index = static_cast(bits); + const auto index = static_cast(bits); if (index > (sizeof(T) * 8) - 1) { return; } @@ -82,9 +85,9 @@ namespace GeneralUtils { //! Clears a bit on a numerical value template - inline void ClearBit(T& value, eObjectBits bits) { + inline void ClearBit(T& value, const eObjectBits bits) { static_assert(std::is_arithmetic::value, "Not an arithmetic type"); - auto index = static_cast(bits); + const auto index = static_cast(bits); if (index > (sizeof(T) * 8 - 1)) { return; } @@ -97,14 +100,14 @@ namespace GeneralUtils { \param value The value to set the bit for \param index The index of the bit */ - int64_t SetBit(int64_t value, uint32_t index); + int64_t SetBit(int64_t value, const uint32_t index); //! Clears a specific bit in a signed 64-bit integer /*! \param value The value to clear the bit from \param index The index of the bit */ - int64_t ClearBit(int64_t value, uint32_t index); + int64_t ClearBit(int64_t value, const uint32_t index); //! Checks a specific bit in a signed 64-bit integer /*! @@ -112,19 +115,19 @@ namespace GeneralUtils { \param index The index of the bit \return Whether or not the bit is set */ - bool CheckBit(int64_t value, uint32_t index); + bool CheckBit(int64_t value, const uint32_t index); - bool ReplaceInString(std::string& str, const std::string& from, const std::string& to); + bool ReplaceInString(std::string& str, const std::string_view from, const std::string_view to); std::u16string ReadWString(RakNet::BitStream& inStream); - std::vector SplitString(std::wstring& str, wchar_t delimiter); + std::vector SplitString(const std::wstring_view str, const wchar_t delimiter); - std::vector SplitString(const std::u16string& str, char16_t delimiter); + std::vector SplitString(const std::u16string_view str, const char16_t delimiter); - std::vector SplitString(const std::string& str, char delimiter); + std::vector SplitString(const std::string_view str, const char delimiter); - std::vector GetSqlFileNamesFromFolder(const std::string& folder); + std::vector GetSqlFileNamesFromFolder(const std::string_view folder); /** * Transparent string hasher - used to allow string_view key lookups for maps storing std::string keys @@ -167,7 +170,7 @@ namespace GeneralUtils { // If a boolean, present an alias to an intermediate integral type for parsing template requires std::same_as - struct numeric_parse { using type = uint32_t; }; + struct numeric_parse { using type = uint8_t; }; // Shorthand type alias template @@ -179,8 +182,9 @@ namespace GeneralUtils { * @returns An std::optional containing the desired value if it is equivalent to the string */ template - [[nodiscard]] std::optional TryParse(const std::string_view str) { + [[nodiscard]] std::optional TryParse(std::string_view str) { numeric_parse_t result; + while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1); const char* const strEnd = str.data() + str.size(); const auto [parseEnd, ec] = std::from_chars(str.data(), strEnd, result); @@ -189,7 +193,7 @@ namespace GeneralUtils { return isParsed ? static_cast(result) : std::optional{}; } -#ifdef DARKFLAME_PLATFORM_MACOS +#if !(__GNUC__ >= 11 || _MSC_VER >= 1924) // MacOS floating-point parse helper function specializations namespace details { @@ -204,8 +208,10 @@ namespace GeneralUtils { * @returns An std::optional containing the desired value if it is equivalent to the string */ template - [[nodiscard]] std::optional TryParse(const std::string_view str) noexcept + [[nodiscard]] std::optional TryParse(std::string_view str) noexcept try { + while (!str.empty() && std::isspace(str.front())) str.remove_prefix(1); + size_t parseNum; const T result = details::_parse(str, parseNum); const bool isParsed = str.length() == parseNum; @@ -225,7 +231,7 @@ namespace GeneralUtils { * @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters */ template - [[nodiscard]] std::optional TryParse(const std::string& strX, const std::string& strY, const std::string& strZ) { + [[nodiscard]] std::optional TryParse(const std::string_view strX, const std::string_view strY, const std::string_view strZ) { const auto x = TryParse(strX); if (!x) return std::nullopt; @@ -237,17 +243,17 @@ namespace GeneralUtils { } /** - * The TryParse overload for handling NiPoint3 by passingn a reference to a vector of three strings - * @param str The string vector representing the X, Y, and Xcoordinates + * The TryParse overload for handling NiPoint3 by passing a span of three strings + * @param str The string vector representing the X, Y, and Z coordinates * @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters */ template - [[nodiscard]] std::optional TryParse(const std::vector& str) { + [[nodiscard]] std::optional TryParse(const std::span str) { return (str.size() == 3) ? TryParse(str[0], str[1], str[2]) : std::nullopt; } template - std::u16string to_u16string(T value) { + std::u16string to_u16string(const T value) { return GeneralUtils::ASCIIToUTF16(std::to_string(value)); } @@ -266,7 +272,7 @@ namespace GeneralUtils { \param max The maximum to generate to */ template - inline T GenerateRandomNumber(std::size_t min, std::size_t max) { + inline T GenerateRandomNumber(const std::size_t min, const std::size_t max) { // Make sure it is a numeric type static_assert(std::is_arithmetic::value, "Not an arithmetic type"); @@ -287,16 +293,16 @@ namespace GeneralUtils { * @returns The enum entry's value in its underlying type */ template - constexpr typename std::underlying_type_t CastUnderlyingType(const eType entry) noexcept { - return static_cast>(entry); + constexpr std::underlying_type_t ToUnderlying(const eType entry) noexcept { + return static_cast>(entry); } // on Windows we need to undef these or else they conflict with our numeric limits calls // DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS - #ifdef _WIN32 - #undef min - #undef max - #endif +#ifdef _WIN32 +#undef min +#undef max +#endif template inline T GenerateRandomNumber() { diff --git a/dCommon/Implementation.h b/dCommon/Implementation.h new file mode 100644 index 000000000..7cfa20122 --- /dev/null +++ b/dCommon/Implementation.h @@ -0,0 +1,92 @@ +#ifndef __IMPLEMENTATION_H__ +#define __IMPLEMENTATION_H__ + +#include +#include + +/** + * @brief A way to defer the implementation of an action. + * + * @tparam R The result of the action. + * @tparam T The types of the arguments that the implementation requires. + */ +template +class Implementation { +public: + typedef std::function(T...)> ImplementationFunction; + + /** + * @brief Sets the implementation of the action. + * + * @param implementation The implementation of the action. + */ + void SetImplementation(const ImplementationFunction& implementation) { + this->implementation = implementation; + } + + /** + * @brief Clears the implementation of the action. + */ + void ClearImplementation() { + implementation.reset(); + } + + /** + * @brief Checks if the implementation is set. + * + * @return true If the implementation is set. + * @return false If the implementation is not set. + */ + bool IsSet() const { + return implementation.has_value(); + } + + /** + * @brief Executes the implementation if it is set. + * + * @param args The arguments to pass to the implementation. + * @return std::optional The optional result of the implementation. If the result is not set, it indicates that the default action should be taken. + */ + std::optional Execute(T... args) const { + return IsSet() ? implementation.value()(args...) : std::nullopt; + } + + /** + * @brief Exectues the implementation if it is set, otherwise returns a default value. + * + * @param args The arguments to pass to the implementation. + * @param defaultValue The default value to return if the implementation is not set or should not be deferred. + */ + R ExecuteWithDefault(T... args, const R& defaultValue) const { + return Execute(args...).value_or(defaultValue); + } + + /** + * = operator overload. + */ + Implementation& operator=(const Implementation& other) { + implementation = other.implementation; + return *this; + } + + /** + * = operator overload. + */ + Implementation& operator=(const ImplementationFunction& implementation) { + this->implementation = implementation; + return *this; + } + + /** + * () operator overload. + */ + std::optional operator()(T... args) { + return !IsSet() ? std::nullopt : implementation(args...); + } + +private: + std::optional implementation; + +}; + +#endif //!__IMPLEMENTATION_H__ diff --git a/dCommon/LDFFormat.h b/dCommon/LDFFormat.h index 2cd9156c5..054ddb428 100644 --- a/dCommon/LDFFormat.h +++ b/dCommon/LDFFormat.h @@ -31,22 +31,22 @@ class LDFBaseData { virtual ~LDFBaseData() {} - virtual void WriteToPacket(RakNet::BitStream& packet) = 0; + virtual void WriteToPacket(RakNet::BitStream& packet) const = 0; - virtual const std::u16string& GetKey() = 0; + virtual const std::u16string& GetKey() const = 0; - virtual eLDFType GetValueType() = 0; + virtual eLDFType GetValueType() const = 0; /** Gets a string from the key/value pair * @param includeKey Whether or not to include the key in the data * @param includeTypeId Whether or not to include the type id in the data * @return The string representation of the data */ - virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) = 0; + virtual std::string GetString(bool includeKey = true, bool includeTypeId = true) const = 0; - virtual std::string GetValueAsString() = 0; + virtual std::string GetValueAsString() const = 0; - virtual LDFBaseData* Copy() = 0; + virtual LDFBaseData* Copy() const = 0; /** * Given an input string, return the data as a LDF key. @@ -62,7 +62,7 @@ class LDFData: public LDFBaseData { T value; //! Writes the key to the packet - void WriteKey(RakNet::BitStream& packet) { + void WriteKey(RakNet::BitStream& packet) const { packet.Write(this->key.length() * sizeof(uint16_t)); for (uint32_t i = 0; i < this->key.length(); ++i) { packet.Write(this->key[i]); @@ -70,7 +70,7 @@ class LDFData: public LDFBaseData { } //! Writes the value to the packet - void WriteValue(RakNet::BitStream& packet) { + void WriteValue(RakNet::BitStream& packet) const { packet.Write(this->GetValueType()); packet.Write(this->value); } @@ -90,7 +90,7 @@ class LDFData: public LDFBaseData { /*! \return The value */ - const T& GetValue(void) { return this->value; } + const T& GetValue(void) const { return this->value; } //! Sets the value /*! @@ -102,13 +102,13 @@ class LDFData: public LDFBaseData { /*! \return The value string */ - std::string GetValueString(void) { return ""; } + std::string GetValueString(void) const { return ""; } //! Writes the data to a packet /*! \param packet The packet */ - void WriteToPacket(RakNet::BitStream& packet) override { + void WriteToPacket(RakNet::BitStream& packet) const override { this->WriteKey(packet); this->WriteValue(packet); } @@ -117,13 +117,13 @@ class LDFData: public LDFBaseData { /*! \return The key */ - const std::u16string& GetKey(void) override { return this->key; } + const std::u16string& GetKey(void) const override { return this->key; } //! Gets the LDF Type /*! \return The LDF value type */ - eLDFType GetValueType(void) override { return LDF_TYPE_UNKNOWN; } + eLDFType GetValueType(void) const override { return LDF_TYPE_UNKNOWN; } //! Gets the string data /*! @@ -131,7 +131,7 @@ class LDFData: public LDFBaseData { \param includeTypeId Whether or not to include the type id in the data \return The string representation of the data */ - std::string GetString(const bool includeKey = true, const bool includeTypeId = true) override { + std::string GetString(const bool includeKey = true, const bool includeTypeId = true) const override { if (GetValueType() == -1) { return GeneralUtils::UTF16ToWTF8(this->key) + "=-1:"; } @@ -154,11 +154,11 @@ class LDFData: public LDFBaseData { return stream.str(); } - std::string GetValueAsString() override { + std::string GetValueAsString() const override { return this->GetValueString(); } - LDFBaseData* Copy() override { + LDFBaseData* Copy() const override { return new LDFData(key, value); } @@ -166,19 +166,19 @@ class LDFData: public LDFBaseData { }; // LDF Types -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_UTF_16; }; -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_S32; }; -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_FLOAT; }; -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_DOUBLE; }; -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_U32; }; -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_BOOLEAN; }; -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_U64; }; -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_OBJID; }; -template<> inline eLDFType LDFData::GetValueType(void) { return LDF_TYPE_UTF_8; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_UTF_16; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_S32; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_FLOAT; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_DOUBLE; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_U32; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_BOOLEAN; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_U64; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_OBJID; }; +template<> inline eLDFType LDFData::GetValueType(void) const { return LDF_TYPE_UTF_8; }; // The specialized version for std::u16string (UTF-16) template<> -inline void LDFData::WriteValue(RakNet::BitStream& packet) { +inline void LDFData::WriteValue(RakNet::BitStream& packet) const { packet.Write(this->GetValueType()); packet.Write(this->value.length()); @@ -189,7 +189,7 @@ inline void LDFData::WriteValue(RakNet::BitStream& packet) { // The specialized version for bool template<> -inline void LDFData::WriteValue(RakNet::BitStream& packet) { +inline void LDFData::WriteValue(RakNet::BitStream& packet) const { packet.Write(this->GetValueType()); packet.Write(this->value); @@ -197,7 +197,7 @@ inline void LDFData::WriteValue(RakNet::BitStream& packet) { // The specialized version for std::string (UTF-8) template<> -inline void LDFData::WriteValue(RakNet::BitStream& packet) { +inline void LDFData::WriteValue(RakNet::BitStream& packet) const { packet.Write(this->GetValueType()); packet.Write(this->value.length()); @@ -206,18 +206,18 @@ inline void LDFData::WriteValue(RakNet::BitStream& packet) { } } -template<> inline std::string LDFData::GetValueString() { +template<> inline std::string LDFData::GetValueString() const { return GeneralUtils::UTF16ToWTF8(this->value, this->value.size()); } -template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString() { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() const { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() const { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() const { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() const { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() const { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() const { return std::to_string(this->value); } +template<> inline std::string LDFData::GetValueString() const { return std::to_string(this->value); } -template<> inline std::string LDFData::GetValueString() { return this->value; } +template<> inline std::string LDFData::GetValueString() const { return this->value; } #endif //!__LDFFORMAT__H__ diff --git a/dCommon/Observable.h b/dCommon/Observable.h new file mode 100644 index 000000000..3acee05e9 --- /dev/null +++ b/dCommon/Observable.h @@ -0,0 +1,73 @@ +#ifndef __OBSERVABLE_H__ +#define __OBSERVABLE_H__ + +#include +#include + +/** + * @brief An event which can be observed by multiple observers. + * + * @tparam T The types of the arguments to be passed to the observers. + */ +template +class Observable { +public: + typedef std::function Observer; + + /** + * @brief Adds an observer to the event. + * + * @param observer The observer to add. + */ + void AddObserver(const Observer& observer) { + observers.push_back(observer); + } + + /** + * @brief Removes an observer from the event. + * + * @param observer The observer to remove. + */ + void RemoveObserver(const Observer& observer) { + observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end()); + } + + /** + * @brief Notifies all observers of the event. + * + * @param args The arguments to pass to the observers. + */ + void Notify(T... args) { + for (const auto& observer : observers) { + observer(args...); + } + } + + /** + * += operator overload. + */ + Observable& operator+=(const Observer& observer) { + AddObserver(observer); + return *this; + } + + /** + * -= operator overload. + */ + Observable& operator-=(const Observer& observer) { + RemoveObserver(observer); + return *this; + } + + /** + * () operator overload. + */ + void operator()(T... args) { + Notify(args...); + } + +private: + std::vector observers; +}; + +#endif //!__OBSERVABLE_H__ \ No newline at end of file diff --git a/dCommon/PositionUpdate.h b/dCommon/PositionUpdate.h index 4d591a97b..f28c682d9 100644 --- a/dCommon/PositionUpdate.h +++ b/dCommon/PositionUpdate.h @@ -6,28 +6,14 @@ struct RemoteInputInfo { - RemoteInputInfo() { - m_RemoteInputX = 0; - m_RemoteInputY = 0; - m_IsPowersliding = false; - m_IsModified = false; - } - - void operator=(const RemoteInputInfo& other) { - m_RemoteInputX = other.m_RemoteInputX; - m_RemoteInputY = other.m_RemoteInputY; - m_IsPowersliding = other.m_IsPowersliding; - m_IsModified = other.m_IsModified; - } - bool operator==(const RemoteInputInfo& other) { return m_RemoteInputX == other.m_RemoteInputX && m_RemoteInputY == other.m_RemoteInputY && m_IsPowersliding == other.m_IsPowersliding && m_IsModified == other.m_IsModified; } - float m_RemoteInputX; - float m_RemoteInputY; - bool m_IsPowersliding; - bool m_IsModified; + float m_RemoteInputX = 0; + float m_RemoteInputY = 0; + bool m_IsPowersliding = false; + bool m_IsModified = false; }; struct LocalSpaceInfo { diff --git a/dCommon/dConfig.cpp b/dCommon/dConfig.cpp index 56a438484..bed274b04 100644 --- a/dCommon/dConfig.cpp +++ b/dCommon/dConfig.cpp @@ -1,6 +1,7 @@ #include "dConfig.h" #include +#include #include "BinaryPathFinder.h" #include "GeneralUtils.h" diff --git a/dCommon/dEnums/MessageType/Auth.h b/dCommon/dEnums/MessageType/Auth.h new file mode 100644 index 000000000..12e28dcb0 --- /dev/null +++ b/dCommon/dEnums/MessageType/Auth.h @@ -0,0 +1,13 @@ +#pragma once +#include + +namespace MessageType { + enum class Auth : uint32_t { + LOGIN_REQUEST = 0, + LOGOUT_REQUEST, + CREATE_NEW_ACCOUNT_REQUEST, + LEGOINTERFACE_AUTH_RESPONSE, + SESSIONKEY_RECEIVED_CONFIRM, + RUNTIME_CONFIG + }; +} diff --git a/dCommon/dEnums/MessageType/Chat.h b/dCommon/dEnums/MessageType/Chat.h new file mode 100644 index 000000000..09f4ef69e --- /dev/null +++ b/dCommon/dEnums/MessageType/Chat.h @@ -0,0 +1,78 @@ +#pragma once +#include + +namespace MessageType { + //! The Internal Chat Packet Identifiers + enum class Chat : uint32_t { + LOGIN_SESSION_NOTIFY = 0, + GENERAL_CHAT_MESSAGE, + PRIVATE_CHAT_MESSAGE, + USER_CHANNEL_CHAT_MESSAGE, + WORLD_DISCONNECT_REQUEST, + WORLD_PROXIMITY_RESPONSE, + WORLD_PARCEL_RESPONSE, + ADD_FRIEND_REQUEST, + ADD_FRIEND_RESPONSE, + REMOVE_FRIEND, + GET_FRIENDS_LIST, + ADD_IGNORE, + REMOVE_IGNORE, + GET_IGNORE_LIST, + TEAM_MISSED_INVITE_CHECK, + TEAM_INVITE, + TEAM_INVITE_RESPONSE, + TEAM_KICK, + TEAM_LEAVE, + TEAM_SET_LOOT, + TEAM_SET_LEADER, + TEAM_GET_STATUS, + GUILD_CREATE, + GUILD_INVITE, + GUILD_INVITE_RESPONSE, + GUILD_LEAVE, + GUILD_KICK, + GUILD_GET_STATUS, + GUILD_GET_ALL, + SHOW_ALL, + BLUEPRINT_MODERATED, + BLUEPRINT_MODEL_READY, + PROPERTY_READY_FOR_APPROVAL, + PROPERTY_MODERATION_CHANGED, + PROPERTY_BUILDMODE_CHANGED, + PROPERTY_BUILDMODE_CHANGED_REPORT, + MAIL, + WORLD_INSTANCE_LOCATION_REQUEST, + REPUTATION_UPDATE, + SEND_CANNED_TEXT, + GMLEVEL_UPDATE, + CHARACTER_NAME_CHANGE_REQUEST, + CSR_REQUEST, + CSR_REPLY, + GM_KICK, + GM_ANNOUNCE, + GM_MUTE, + ACTIVITY_UPDATE, + WORLD_ROUTE_PACKET, + GET_ZONE_POPULATIONS, + REQUEST_MINIMUM_CHAT_MODE, + REQUEST_MINIMUM_CHAT_MODE_PRIVATE, + MATCH_REQUEST, + UGCMANIFEST_REPORT_MISSING_FILE, + UGCMANIFEST_REPORT_DONE_FILE, + UGCMANIFEST_REPORT_DONE_BLUEPRINT, + UGCC_REQUEST, + WHO, + WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE, + ACHIEVEMENT_NOTIFY, + GM_CLOSE_PRIVATE_CHAT_WINDOW, + UNEXPECTED_DISCONNECT, + PLAYER_READY, + GET_DONATION_TOTAL, + UPDATE_DONATION, + PRG_CSR_COMMAND, + HEARTBEAT_REQUEST_FROM_WORLD, + UPDATE_FREE_TRIAL_STATUS, + // CUSTOM DLU MESSAGE ID FOR INTERNAL USE + CREATE_TEAM, + }; +} diff --git a/dCommon/dEnums/MessageType/Client.h b/dCommon/dEnums/MessageType/Client.h new file mode 100644 index 000000000..f80425d0c --- /dev/null +++ b/dCommon/dEnums/MessageType/Client.h @@ -0,0 +1,74 @@ +#pragma once +#include + +namespace MessageType { + enum class Client : uint32_t { + LOGIN_RESPONSE = 0, + LOGOUT_RESPONSE, + LOAD_STATIC_ZONE, + CREATE_OBJECT, + CREATE_CHARACTER, + CREATE_CHARACTER_EXTENDED, + CHARACTER_LIST_RESPONSE, + CHARACTER_CREATE_RESPONSE, + CHARACTER_RENAME_RESPONSE, + CHAT_CONNECT_RESPONSE, + AUTH_ACCOUNT_CREATE_RESPONSE, + DELETE_CHARACTER_RESPONSE, + GAME_MSG, + CONNECT_CHAT, + TRANSFER_TO_WORLD, + IMPENDING_RELOAD_NOTIFY, + MAKE_GM_RESPONSE, + HTTP_MONITOR_INFO_RESPONSE, + SLASH_PUSH_MAP_RESPONSE, + SLASH_PULL_MAP_RESPONSE, + SLASH_LOCK_MAP_RESPONSE, + BLUEPRINT_SAVE_RESPONSE, + BLUEPRINT_LUP_SAVE_RESPONSE, + BLUEPRINT_LOAD_RESPONSE_ITEMID, + BLUEPRINT_GET_ALL_DATA_RESPONSE, + MODEL_INSTANTIATE_RESPONSE, + DEBUG_OUTPUT, + ADD_FRIEND_REQUEST, + ADD_FRIEND_RESPONSE, + REMOVE_FRIEND_RESPONSE, + GET_FRIENDS_LIST_RESPONSE, + UPDATE_FRIEND_NOTIFY, + ADD_IGNORE_RESPONSE, + REMOVE_IGNORE_RESPONSE, + GET_IGNORE_LIST_RESPONSE, + TEAM_INVITE, + TEAM_INVITE_INITIAL_RESPONSE, + GUILD_CREATE_RESPONSE, + GUILD_GET_STATUS_RESPONSE, + GUILD_INVITE, + GUILD_INVITE_INITIAL_RESPONSE, + GUILD_INVITE_FINAL_RESPONSE, + GUILD_INVITE_CONFIRM, + GUILD_ADD_PLAYER, + GUILD_REMOVE_PLAYER, + GUILD_LOGIN_LOGOUT, + GUILD_RANK_CHANGE, + GUILD_DATA, + GUILD_STATUS, + MAIL, + DB_PROXY_RESULT, + SHOW_ALL_RESPONSE, + WHO_RESPONSE, + SEND_CANNED_TEXT, + UPDATE_CHARACTER_NAME, + SET_NETWORK_SIMULATOR, + INVALID_CHAT_MESSAGE, + MINIMUM_CHAT_MODE_RESPONSE, + MINIMUM_CHAT_MODE_RESPONSE_PRIVATE, + CHAT_MODERATION_STRING, + UGC_MANIFEST_RESPONSE, + IN_LOGIN_QUEUE, + SERVER_STATES, + GM_CLOSE_TARGET_CHAT_WINDOW, + GENERAL_TEXT_FOR_LOCALIZATION, + UPDATE_FREE_TRIAL_STATUS, + UGC_DOWNLOAD_FAILED = 120 + }; +} diff --git a/dCommon/dEnums/MessageType/Game.h b/dCommon/dEnums/MessageType/Game.h new file mode 100644 index 000000000..8c5bddae7 --- /dev/null +++ b/dCommon/dEnums/MessageType/Game.h @@ -0,0 +1,1612 @@ +#pragma once +#include + +#include "magic_enum.hpp" + +namespace MessageType { + enum class Game : uint16_t { + GET_POSITION = 0, + GET_ROTATION = 1, + GET_LINEAR_VELOCITY = 2, + GET_ANGULAR_VELOCITY = 3, + GET_FORWARD_VELOCITY = 4, + GET_PLAYER_FORWARD = 5, + GET_FORWARD_VECTOR = 6, + SET_POSITION = 7, + SET_LOCAL_POSITION = 8, + SET_ROTATION = 9, + SET_LINEAR_VELOCITY = 10, + MODIFY_LINEAR_VELOCITY = 11, + SET_ANGULAR_VELOCITY = 12, + MODIFY_ANGULAR_VELOCITY = 13, + DEFLECT = 14, + SEND_POSITION_UPDATE = 15, + SET_OBJECT_SCALE = 16, + GET_OBJECT_SCALE = 17, + TIMED_SCALE_FINISHED = 18, + TELEPORT = 19, + TOGGLE_PLAYER_FWD_TO_CAMERA = 20, + LOCK_PLAYER_ROT_TO_CAMERA = 21, + UNLOCK_PLAYER_ROT_FROM_CAMERA = 22, + TOGGLE_PLAYER_ROT_LOCK_TO_MOUSE = 23, + LOCK_PLAYER_ROT_TO_MOUSE = 24, + UNLOCK_PLAYER_ROT_FROM_MOUSE = 25, + SET_PLAYER_CONTROL_SCHEME = 26, + GET_PLAYER_CONTROL_SCHEME = 27, + RESET_PLAYER_CONTROL_SCHEME = 28, + PLAYER_TO_PREVIOUS_CONTROL_SCHEME = 29, + DROP_CLIENT_LOOT = 30, + GET_SPEED = 34, + GET_ROT_SPEED = 35, + IS_DEAD = 36, + DIE = 37, + REQUEST_DIE = 38, + ADD_OBJECT = 39, + PLAY_EMOTE = 41, + PRELOAD_ANIMATION = 42, + PLAY_ANIMATION = 43, + ANIMATION_COMPLETE = 44, + ENABLE_HIGHLIGHT = 45, + DISABLE_HIGHLIGHT = 46, + GET_ANIMATION_NAMES = 47, + CONTROL_BEHAVIORS = 48, + BLEND_PRIMARY_ANIMATION = 52, + SET_OFFSCREEN_ANIMATION = 53, + GET_MOVEMENT_INPUT_VALUES = 54, + SWAP_TEXTURE = 55, + SWAP_COLOR = 56, + ATTACH_HAIR = 57, + GET_ENTITY_STRUCT = 58, + SET_ENTITY_STRUCT = 59, + SET_ATTR = 60, + GET_ATTR = 61, + ON_HIT = 62, + HIT_OR_HEAL_RESULT = 63, + SHOW_ATTACK = 64, + GO_TO = 65, + GET_CONFIG_DATA = 66, + SET_CONFIG_DATA = 68, + GET_INVENTORY_EXTRA_INFO = 69, + GET_DISPLAY_NAME = 70, + GET_NAME = 71, + SET_NAME = 72, + IS_NAME_LOCALIZED = 73, + GET_HAIR_COLOR = 74, + SET_HAIR_COLOR = 75, + GET_HAIR_STYLE = 76, + SET_HAIR_STYLE = 77, + GET_HEAD = 78, + SET_HEAD = 79, + GET_TORSO = 80, + SET_TORSO = 81, + GET_LEGS = 82, + SET_LEGS = 83, + SET_PROXIMITY_RADIUS = 84, + PROXIMITY_UPDATE = 85, + GET_PROXIMITY_OBJECTS = 86, + UNSET_PROXIMITY_RADIUS = 87, + CLEAR_PROXIMITY_RADIUS = 88, + GET_PROXIMITY_DATA = 89, + SET_PROXIMITY_RADIUS_ICON = 90, + TOGGLE_TAC_ARC = 93, + CAST_SKILL = 95, + CAST_LOCAL_SKILL = 96, + ECHO_LOCAL_SKILL = 97, + QUEUE_AI_SKILL = 98, + ADD_THREAT_RATING = 99, + GET_THREAT_RATING = 100, + CLEAR_THREAT_LIST = 103, + GET_TIME_FOR_NPC_SKILL = 111, + ENEMY_HEAL_NOTIFICATION = 112, + RESET_SCRIPTED_AI_STATE = 113, + ENABLE_COMBAT_AI_COMPONENT = 114, + COMBAT_AI_FORCE_TETHER = 115, + SUSPEND_MOVEMENT_AI = 116, + NOTIFY_SCRIPT_VARS_INITIALIZED = 117, + ECHO_START_SKILL = 118, + START_SKILL = 119, + CASTER_DEAD = 120, + VERIFY_ACK = 121, + ADD_PENDING_VERIFY = 122, + MAP_SKILL = 123, + SELECT_SKILL = 124, + CAST_ACTIVE_SKILL = 125, + MODIFY_SKILL_COOLDOWN = 126, + ADD_SKILL = 127, + REMOVE_SKILL = 128, + LOG = 129, + LOG_CHAT = 130, + SET_MAX_CURRENCY = 131, + GET_MAX_CURRENCY = 132, + SET_CURRENCY = 133, + GET_CURRENCY = 134, + ADD_PENDING_CURRENCY = 136, + PICKUP_CURRENCY = 137, + SERVER_DELETE_LOOT_ITEM = 138, + PICKUP_ITEM = 139, + TEAM_PICKUP_ITEM = 140, + CLIENT_DELETE_LOOT_ITEM = 141, + CLIENT_SET_LOOT_ITEM_FFA = 143, + COLLISION_PHANTOM = 144, + OFF_COLLISION_PHANTOM = 145, + COLLISION_PROXIMITY = 146, + OFF_COLLISION_PROXIMITY = 147, + COLLISION = 148, + OFF_COLLISION = 149, + GET_SKILLS = 150, + CLEAR_FX_SINGLE_EFFECT = 152, + GET_FX_EXIST_EFFECT = 153, + PLAY_FX_EFFECT = 154, + STOP_FX_EFFECT = 155, + CLEAR_FX_ALL_CREATE_EFFECTS = 156, + UPDATE_FX_ALL_CREATE_EFFECTS = 157, + REQUEST_RESURRECT = 159, + RESURRECT = 160, + UPDATE_FROM_GHOST = 162, + FETCH_GHOST = 163, + KFM_LOADED = 164, + NIF_LOADED = 165, + HKX_LOADED = 166, + MOVE_TO_DELETE_QUEUE = 167, + RESTORE_FROM_DELETE_QUEUE = 168, + IS_ENEMY = 169, + GET_FACTION = 170, + SET_IMAGINATION = 171, + GET_IMAGINATION = 172, + SET_MAX_IMAGINATION = 173, + GET_MAX_IMAGINATION = 174, + MODIFY_IMAGINATION = 175, + MODIFY_MAX_IMAGINATION = 176, + SET_HEALTH = 177, + GET_HEALTH = 178, + SET_MAX_HEALTH = 179, + GET_MAX_HEALTH = 180, + MODIFY_HEALTH = 181, + MODIFY_MAX_HEALTH = 182, + SET_ARMOR = 183, + GET_ARMOR = 184, + SET_MAX_ARMOR = 185, + GET_MAX_ARMOR = 186, + MODIFY_ARMOR = 187, + MODIFY_MAX_ARMOR = 188, + POP_HEALTH_STATE = 190, + PUSH_EQUIPPED_ITEMS_STATE = 191, + POP_EQUIPPED_ITEMS_STATE = 192, + SET_GM_LEVEL = 193, + GET_GM_LEVEL = 194, + ADD_STATUS_EFFECT = 196, + REMOVE_STATUS_EFFECT = 197, + SET_STUNNED = 198, + GET_STUNNED = 199, + SET_STUN_IMMUNITY = 200, + GET_STUN_IMMUNITY = 201, + KNOCKBACK = 202, + SET_VISIBLE = 203, + GET_VISIBLE = 204, + REPORT_ITEM_INFO = 205, + GET_REBUILD_STATE = 207, + REBUILD_CANCEL = 209, + REBUILD_START = 211, + ENABLE_REBUILD = 213, + SKILL_FAILURE = 214, + IS_ATTACK_STANCE = 216, + SET_OBJECT_RENDER = 217, + REQUEST_MAPPED_SKILLS = 218, + UI_SELECT_MAPPED_SKILL = 219, + GET_INVENTORY_ITEM_IN_SLOT = 220, + GET_FIRST_INVENTORY_ITEM_BY_LOT = 221, + GET_SMALLEST_INVENTORY_STACK_BY_LOT = 222, + MOVE_ITEM_IN_INVENTORY = 224, + ADD_ITEM_TO_INVENTORY_CLIENT_SYNC = 227, + GET_EQUIPPED_ITEMS = 229, + REMOVE_ITEM_FROM_INVENTORY = 230, + EQUIP_INVENTORY = 231, + UN_EQUIP_INVENTORY = 233, + EQUIP_ITEM = 234, + UN_EQUIP_ITEM = 235, + IS_ITEM_RESPOND = 236, + IS_ITEM_EQUIPPED = 237, + ATTACH_ITEM = 238, + DETACH_ITEM = 239, + GET_NODE = 240, + GET_LOT = 241, + IS_ITEM_EQUIPPABLE = 242, + GET_CURRENT_ANIMATION = 243, + GET_INV_ITEM_COUNT = 244, + POST_LOAD_EQUIP = 245, + SET_PHYSICS_ACTIVE_STATE = 246, + GET_CURRENT_SKILL_TAC_ARC = 247, + OFFER_MISSION = 248, + RESPOND_TO_MISSION = 249, + GET_MISSION_STATE = 250, + GET_MISSION_COMPLETE_TIMESTAMP = 251, + NOTIFY_MISSION = 254, + NOTIFY_MISSION_TASK = 255, + ARE_GFX_LOADED = 257, + ADDED_TO_WORLD = 258, + REMOVE_EXTRA_GFX_FROM_PIPE = 259, + HIDE_EQUIPED_WEAPON = 260, + UN_HIDE_EQUIPED_WEAPON = 261, + GET_ITEM_SLOT = 262, + IS_CHARACTER = 263, + SET_IMMUNITY = 264, + TOGGLE_TOOLTIPS = 266, + GET_TOOLTIPS_DISABLED = 267, + GET_BOUNDING_INFO = 268, + OVERRIDE_BOUNDING_RADIUS = 269, + GET_OFFSCREEN = 270, + USE_STATE_MACHINE = 271, + ADD_STATE = 272, + ADD_SUB_STATE = 273, + SET_STATE = 274, + SET_SUB_STATE = 275, + ADD_MESSAGE = 276, + RELOAD_SCRIPT = 277, + RELOAD_ALL_SCRIPTS = 278, + FRIEND_INVITE_MSG = 279, + ADD_FRIEND_REPOSNSE_MSG = 280, + REMOVE_FRIEND_RESPONSE_MSG = 281, + ADD_FRIEND_FROM_UI_MSG = 282, + GET_CACHED_FRIENDS_LIST_MSG = 283, + REQUEST_NEW_FRIENDS_LIST_MSG = 284, + REPOPULATE_FRIENDS_LIST_MSG = 285, + ADD_IGNORE_REPONSE_MSG = 286, + REMOVE_IGNORE_RESPONSE_MSG = 287, + ADD_IGNORE_FROM_UI_MSG = 288, + GET_CACHED_IGNORE_LIST_MSG = 289, + REQUEST_NEW_IGNORE_LIST_MSG = 290, + REMOVE_FRIEND_BY_NAME = 291, + REMOVE_IGNORE_BY_NAME = 292, + IS_PLAYER_IN_IGNORE_LIST_MSG = 293, + REPOPULATE_IGNORE_LIST_MSG = 294, + GET_INVENTORY_LIST = 295, + UPDATE_FRIEND_MSG = 296, + UPDATE_FRIEND_NAME_MSG = 297, + UPDATE_IGNORE_NAME_MSG = 298, + DEPARTED = 299, + ARRIVED = 300, + TEMPLATE_CHANGE_WAYPOINTS = 301, + CANCELLED = 302, + FLUSH_CACHED_GRAPHICS = 303, + FOLLOW_TARGET = 304, + TIMER_DONE = 305, + TIMER_CANCELLED = 306, + SET_TETHER_POINT = 307, + GET_TETHER_POINT = 308, + LEFT_TETHER_RADIUS = 309, + GET_SCRIPT_VARS_PTR = 310, + FACE_TARGET = 311, + ROTATE_BY_DEGREES = 312, + STRING_RENDERED = 313, + RESET_PRIMARY_ANIMATION = 314, + FACE_PLAY_STREAM = 315, + TORSO_PLAY_STREAM = 316, + CAN_PICKUP = 317, + GET_INVENTORY_SIZE = 318, + GET_INVENTORY_COUNT = 319, + GET_OBJECTS_IN_GROUP = 320, + HIDE_ITEM = 321, + IS_OBJECT_IN_FOV = 322, + GET_TYPE = 323, + TEAM_INVITE_MSG = 324, + TEAM_GET_SIZE = 325, + TEAM_REQUEST_SET_LOOT = 326, + TEAM_REMOVE_PLAYER_MSG = 327, + TEAM_UPDATE_PLAYER_NAME_MSG = 328, + SET_UPDATABLE = 329, + REQUEST_TEAM_UI_UPDATE = 330, + SET_COLLISION_GROUP = 331, + GET_COLLISION_GROUP = 332, + GET_ORIGINAL_COLLISION_GROUP = 333, + SET_COLLISION_GROUP_TO_ORIGINAL = 334, + GET_OBJECT_RADIUS = 335, + REBUILD_NOTIFY_STATE = 336, + GET_PLAYER_INTERACTION = 337, + SET_PLAYER_INTERACTION = 338, + FORCE_PLAYER_TO_INTERACT = 339, + GET_SELECTED_POTENTIAL_INTERACTION = 340, + SET_SELECTED_POTENTIAL_INTERACTION = 341, + GET_INTERACTION_DISTANCE = 342, + SET_INTERACTION_DISTANCE = 343, + CALCULATE_INTERACTION_DISTANCE = 344, + INTERACTION_ATTEMPT_FROM_OUT_OF_RANGE = 345, + SET_PICKING_TARGET = 346, + CLIENT_UNUSE = 347, + BEGIN_PET_INTERACTION = 348, + WANTS_INTERACTION_ICON = 349, + PROPERTY_EDIT_ICON_INTERACTION = 350, + PROPERTY_MODEL_INTERACTION = 351, + GET_INTERACTION_DETAILS = 352, + GET_DISABLED_INTERACTION_TYPES = 353, + GET_INTERACTION_INFO = 354, + INTERACTION_GAME_STATE_CHANGE = 355, + TOGGLE_INTERACTION_UPDATES = 356, + TERMINATE_INTERACTION = 357, + SERVER_TERMINATE_INTERACTION = 358, + GET_PLAYERS_TARGET_FOR_SELECTION = 359, + PROCESS_INTERACTION_UNDER_CURSOR = 360, + HANDLE_INTERACT_ACTION = 361, + ATTEMPT_INTERACTION = 362, + HANDLE_INTERACTION_CAMERA = 363, + REQUEST_USE = 364, + CLIENT_USE = 366, + GET_PLAYER_MULTI_INTERACTION = 367, + GET_MULTI_INTERACTION_STATE = 368, + VENDOR_OPEN_WINDOW = 369, + VENDOR_CLOSE_WINDOW = 370, + EMOTE_PLAYED = 371, + EMOTE_RECEIVED = 372, + BUY_FROM_VENDOR = 373, + SELL_TO_VENDOR = 374, + ADD_DONATION_ITEM = 375, + REMOVE_DONATION_ITEM = 376, + CONFIRM_DONATION_ON_PLAYER = 378, + CANCEL_DONATION_ON_PLAYER = 379, + TEAM_GET_LEADER = 380, + TEAM_GET_ON_WORLD_MEMBERS = 381, + TEAM_GET_ALL_MEMBERS = 382, + TEAM_SET_OFF_WORLD_FLAG = 383, + SET_TRANSPARENCY = 385, + GET_PREFERS_FADE = 386, + PROJECTILE_IMPACT = 387, + SET_PROJECTILE_PARAMS = 388, + SET_INVENTORY_SIZE = 389, + ACKNOWLEDGE_POSSESSION = 391, + SET_POSSESSED_OBJECT = 392, + CHANGE_POSSESSOR = 393, + GET_POSSESSION_TYPE = 395, + GET_POSSESSED_OBJECT = 396, + GET_POSSESSOR = 397, + IS_POSSESSED = 398, + ENABLE_ACTIVITY = 399, + SET_SHOOTING_GALLERY_PARAMS = 400, + OPEN_ACTIVITY_START_DIALOG = 401, + REQUEST_ACTIVITY_START_STOP = 402, + REQUEST_ACTIVITY_ENTER = 403, + REQUEST_ACTIVITY_EXIT = 404, + ACTIVITY_ENTER = 405, + ACTIVITY_EXIT = 406, + ACTIVITY_START = 407, + ACTIVITY_STOP = 408, + SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409, + ROTATE_TO_POINT = 410, + SHOOTING_GALLERY_FIRE = 411, + CALCULATE_FIRING_PARAMETERS = 412, + GET_MUZZLE_OFFSET = 413, + GET_ACTIVITY_POINTS = 414, + TEAM_IS_ON_WORLD_MEMBER = 415, + REQUEST_VENDOR_STATUS_UPDATE = 416, + VENDOR_STATUS_UPDATE = 417, + CANCEL_MISSION = 418, + RESET_MISSIONS = 419, + RENDER_COMPONENT_READY = 420, + SEND_MINIFIG_DECALS = 421, + PHYSICS_COMPONENT_READY = 422, + ENTER_STANDBY_MODE = 423, + LEAVE_STANDBY_MODE = 424, + NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425, + REQUEST_CONSUME_ITEM = 426, + CONSUME_CLIENT_ITEM = 427, + CLIENT_ITEM_CONSUMED = 428, + QUERY_STANDBY_MODE = 429, + GET_NI_BOUND = 430, + MISSION_FAILURE = 431, + GET_ANIMATION_TIME = 432, + GET_CURRENT_ACTIVITY = 434, + SET_EYEBROWS = 435, + GET_EYEBROWS = 436, + SET_EYES = 437, + GET_EYES = 438, + SET_MOUTH = 439, + GET_MOUTH = 440, + IS_OBJECT_SMASHABLE = 441, + SMASHABLE_STATE_CHANGED = 443, + USE_STATE_LOGGER = 444, + ROTATE_SUB_NODE = 445, + GET_SUB_NODE_POSITION = 446, + GET_SUB_NODE = 447, + UPDATE_SHOOTING_GALLERY_ROTATION = 448, + RENDER_FLOATING_TEXT = 449, + REQUEST2_D_TEXT_ELEMENT = 450, + UPDATE2_D_TEXT_ELEMENT = 451, + REMOVE2_D_TEXT_ELEMENT = 452, + SET_COLOR = 453, + GET_COLOR = 454, + HKX_CHARACTER_LOADED = 455, + ACTIVATE_PHYSICS = 457, + SET_ICON_ABOVE_HEAD = 458, + ADD_ICON_COMPOSITE = 459, + CLEAR_ICON_COMPOSITES = 460, + ICON_NIF_LOADED = 461, + ICON_KFM_LOADED = 462, + GET_OVERHEAD_ICON_PROPERTIES_FROM_PARENT = 463, + BOUNCE_PLAYER = 464, + SET_USER_CTRL_COMP_PAUSE = 466, + HAS_COLLIDED = 467, + GET_TOOLTIP_FLAG = 468, + SET_TOOLTIP_FLAG = 469, + GET_FLAG = 470, + SET_FLAG = 471, + NOTIFY_CLIENT_FLAG_CHANGE = 472, + CURSOR_ON = 473, + CURSOR_OFF = 474, + HELP = 475, + VENDOR_TRANSACTION_RESULT = 476, + PERFORM_SPECIAL_DEATH = 477, + GET_SHADER_ID = 478, + GET_RENDER_ENVIRONMENT = 479, + FINISHED_LOADING_SCENE = 480, + GET_SKILL_INFO = 481, + ACTIVITY_CANCEL = 482, + MISSION_USES_OBJECT = 483, + GET_POSITIONAL_ID = 484, + SET_COLLECTIBLE_STATUS = 485, + HAS_BEEN_COLLECTED = 486, + HAS_BEEN_COLLECTED_BY_CLIENT = 487, + GET_POS_UPDATE_STATS = 488, + GET_NUM_VIEWERS_SCOPING_THIS = 489, + GET_ACTIVITY_USER = 490, + GET_ALL_ACTIVITY_USERS = 491, + GET_MISSION_FOR_PLAYER = 492, + SET_FACTION = 493, + SET_PLATFORM_IDLE_STATE = 494, + DISPLAY_CHAT_BUBBLE = 495, + REQUEST_CHAT_BUBBLE_ELEMENT = 496, + GET_MISSION_DATA = 497, + SPAWN_PET = 498, + DESPAWN_PET = 499, + SET_LOCAL_SPACE_STATE = 500, + GET_LOCAL_SPACE_STATE = 501, + SET_POSITION_TO_LOCAL_POSITION = 502, + ALLOW_LOCAL_SPACE_UPDATE = 503, + TOGGLE_FREE_CAM_MODE = 504, + PLAYER_LOADED = 505, + PLAYER_ADDED_TO_WORLD_LOCAL = 506, + OBJECT_LOADED = 507, + GET_PLAYER_READY = 508, + PLAYER_READY = 509, + SET_SMASHABLE_PARAMS = 510, + IS_LOOTABLE_CHEST = 511, + LOOT_OPEN_WINDOW = 512, + LOOT_SELECTION_UPDATE = 513, + TAKE_LOOT_CHEST_ITEM = 514, + REQUEST_LINKED_MISSION = 515, + TRANSFER_TO_ZONE = 516, + TRANSFER_TO_ZONE_CHECKED_IM = 517, + SECURED_TRANSFER_TO_ZONE = 518, + INVALID_ZONE_TRANSFER_LIST = 519, + MISSION_DIALOGUE_OK = 520, + GET_OBJECT_IN_SCOPE = 521, + SET_LAUNCHED_STATE = 522, + P_CREATE_EFFECT_FINISHED = 523, + SMASHED_OBJECT = 524, + CHECK_SMASHCHAIN_OVERRIDE = 525, + DISPLAY_REBUILD_ACTIVATOR = 526, + TRANSFER_TO_LAST_NON_INSTANCE = 527, + SET_ACTIVE_LOCAL_CHARACTER_ID = 528, + DISPLAY_MESSAGE_BOX = 529, + MESSAGE_BOX_RESPOND = 530, + CHOICE_BOX_RESPOND = 531, + SERVER_SET_USER_CTRL_COMP_PAUSE = 532, + SET_CHARACTER_AUTO_RUN = 533, + FOLLOW_WAYPOINTS = 534, + SWAP_DECAL_AND_COLOR = 535, + CONTINUE_WAYPOINTS = 536, + SMASH = 537, + UN_SMASH = 538, + GET_IS_SMASHED = 539, + GET_UP_VECTOR = 540, + SET_GRAVITY_SCALE = 541, + SET_GRAVITY_SCALE_FOR_RIGID_BODY = 542, + STOP_MOVING = 543, + SET_PATHING_SPEED = 544, + SET_SHIELDED = 545, + SET_SHOOTING_GALLERY_RETICULE_EFFECT = 546, + PLACE_MODEL_RESPONSE = 547, + SET_DODGE_INFO = 548, + GET_DODGE_INFO = 549, + SET_SKILL_ATTACK_SPEED = 550, + GET_SKILL_COOLDOWN_GROUP = 551, + GET_INITIAL_SKILL_COOLDOWN = 552, + GET_SKILL_COOLDOWN_REMAINING = 553, + GET_GLOBAL_COOLDOWN = 554, + SET_GLOBAL_COOLDOWN = 555, + RESET_GLOBAL_COOLDOWN = 556, + FINDINVENTORY_ITEM = 558, + PATH_STUCK = 559, + SET_CURRENT_PATH = 560, + SET_JET_PACK_MODE = 561, + SET_JET_PACK_TIME = 562, + PET_FOLLOW_OWNER = 563, + PLAYER_DIED = 564, + REGISTER_PET_ID = 565, + REGISTER_PET_DBID = 566, + GET_PET_ID = 567, + SHOW_ACTIVITY_COUNTDOWN = 568, + DISPLAY_TOOLTIP = 569, + SET_PHANTOM_BASE = 570, + GET_MOTION_STATE = 571, + GET_MOTION_CONFIG = 572, + SET_ACTIVE_PROJECTILE_SKILL = 573, + INITIALIZE_MISSION_VISUALS = 574, + GET_MISSIONS = 575, + START_ACTIVITY_TIME = 576, + ADD_ACTIVITY_TIME = 577, + GUILD_GET_SIZE = 578, + GUILD_CAN_WE_INVITE = 579, + GUILD_CAN_WE_KICK = 580, + SET_CHAR_GUILD_INFO = 581, + GET_CHAR_GUILD_INFO = 582, + GET_CHAR_IS_IN_GUILD = 583, + RE_RENDER_NAME_BILLBOARD = 584, + IS_IN_LOCAL_CHAR_PROXIMITY = 585, + GUILD_SET_STATUS = 586, + GUILD_ADD_PLAYER = 587, + GUILD_REMOVE_PLAYER = 588, + GUILD_UPDATE_PLAYER_NAME = 589, + GUILD_SET_PLAYER_RANK = 590, + GUILD_SET_ONLINE_STATUS = 591, + GUILD_INVITE = 592, + REQUEST_GUILD_DATA = 593, + POPULATE_GUILD_DATA = 594, + GET_CACHED_GUILD_DATA = 595, + GUILD_RENDER_NAME = 596, + GET_IS_SUPPORTED = 600, + CHARACTER_SUPPORT_CHANGED = 601, + ACTIVITY_PAUSE = 602, + USE_NON_EQUIPMENT_ITEM = 603, + REQUEST_USE_ITEM_ON = 604, + REQUEST_USE_ITEM_ON_TARGET = 605, + USE_ITEM_ON = 606, + USE_ITEM_RESULT = 607, + GET_PARENT_OBJ = 608, + SET_PARENT_OBJ = 609, + GET_UPDATES_WITH_PARENT_POSITION = 610, + PARENT_REMOVED = 611, + PARENT_LEFT_SCOPE = 612, + PARENT_ENTERED_SCOPE = 613, + CHILD_LOADED = 614, + CHILD_REMOVED = 615, + CHILD_DETACHED = 616, + CHILD_ENTERED_SCOPE = 617, + CHILD_LEFT_SCOPE = 618, + GET_CHILD_OBJECTS = 619, + ZONE_TRANSFER_FINISHED = 621, + CHAT_CONNECTION_UPDATE = 622, + PLATFORM_AT_LAST_WAYPOINT = 623, + LOOT_TAKE_ALL = 624, + GET_EQUIPPED_ITEM_INFO = 625, + DISPLAY_GUILD_CREATE_BOX = 626, + GET_EDITOR_LEVEL = 627, + GET_ACCOUNT_ID = 628, + GET_LAST_LOGOUT = 629, + GET_LAST_PROP_MOD_DISPLAY_TIME = 630, + SET_LAST_PROP_MOD_DISPLAY_TIME = 631, + SHOW_ACTIVITY_SUMMARY = 632, + CAN_RECEIVE_ALL_REWARDS = 633, + GET_ACTIVITY_REWARD = 634, + LOOT_CLOSE_WINDOW = 635, + GET_BLUEPRINT_ID = 636, + NOTIFY_BLUEPRINT_UPDATE = 637, + FETCH_MODEL_METADATA_REQUEST = 638, + FETCH_MODEL_METADATA_RESPONSE = 639, + COMMAND_PET = 640, + PET_RESPONSE = 641, + GET_ICON_ABOVE_HEAD_STATE = 642, + GET_ICON_ABOVE_HEAD = 643, + ICON_FINISHED_LOADING = 644, + ADD_PET_STATE = 645, + REMOVE_PET_STATE = 646, + SET_PET_STATE = 647, + REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 648, + SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 649, + SET_ON_TEAM = 650, + GET_PET_HAS_STATE = 651, + FIND_PROPERTY = 652, + SET_PET_MOVEMENT_STATE = 653, + GET_ITEM_TYPE = 654, + GET_ITEM_INFO_KEY = 655, + NOTIFY_OBJECT = 656, + IS_PET_WILD = 657, + CLIENT_NOTIFY_PET = 659, + NOTIFY_PET = 660, + NOTIFY_PET_TAMING_MINIGAME = 661, + START_SERVER_PET_MINIGAME_TIMER = 662, + CLIENT_EXIT_TAMING_MINIGAME = 663, + GET_BUILDMODE_ACTIVE = 664, + GET_PET_TAMING_MINIGAME_ACTIVE = 665, + PET_TAMING_OBJECT_PICKED = 666, + PET_TAMING_MINIGAME_RESULT = 667, + PET_TAMING_TRY_BUILD_RESULT = 668, + SET_PET_TAMING_MODEL = 669, + GET_PET_TAMING_MODEL = 670, + PET_ON_SWITCH = 671, + PET_OFF_SWITCH = 672, + NOTIFY_TAMING_BUILD_SUCCESS = 673, + NOTIFY_TAMING_MODEL_LOADED_ON_SERVER = 674, + NOTIFY_TAMING_PUZZLE_SELECTED = 675, + GET_INSTRUCTION_COUNT = 676, + GET_IS_NPC = 677, + ACTIVATE_BUBBLE_BUFF = 678, + DECTIVATE_BUBBLE_BUFF = 679, // This is spelled wrong in the client, so we misspell it here. + EXHIBIT_VOTE = 680, + ADD_PET_TO_PLAYER = 681, + REMOVE_PET_FROM_PLAYER = 682, + REQUEST_SET_PET_NAME = 683, + SET_PET_NAME = 684, + PET_NAME_CHANGED = 686, + GET_PET_AT_INDEX = 687, + GET_LOT_FOR_PET_BY_DBID = 688, + GET_NAME_FOR_PET_BY_DBID = 689, + GET_ACTIVE_PET_OBJ_ID = 690, + GET_ACTIVE_PET_INVENTORY_OBJ_ID = 691, + SHOW_PET_ACTION_BUTTON = 692, + SET_EMOTE_LOCK_STATE = 693, + GET_EMOTE_LOCK_STATE = 694, + LEAVE_TEAM_MSG = 695, + TEAM_KICK_PLAYER_MSG = 697, + TEAM_SET_LEADER_SEND_MSG = 698, + USE_ITEM_ON_CLIENT = 699, + DOES_FORWARD_TARGET_CLICKING = 700, + CHECK_USE_REQUIREMENTS = 701, + USE_REQUIREMENTS_RESPONSE = 702, + USE_ITEM_REQUIREMENTS_RESPONSE = 703, + PET_ADDED_TO_WORLD = 704, + BOUNCER_TRIGGERED = 705, + EXHIBIT_QUERY_CURRENT_MODEL = 706, + EXHIBIT_QUERY_CURRENT_MODEL_RESPONSE = 707, + EXHIBIT_ATTEMPT_VOTE = 708, + EXHIBIT_VOTE_RESPONSE = 709, + EHIBIT_REQUERYMODELS = 710, + IS_SKILL_ACTIVE = 711, + TOGGLE_ACTIVE_SKILL = 712, + PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT = 713, + EXHIBIT_GET_INFO = 714, + GET_PROPERTY_DATA = 715, + DOWNLOAD_PROPERTY_DATA = 716, + QUERY_PROPERTY_DATA = 717, + MODEL_MODERATION_ACTION = 719, + NOTIFY_SERVER_UGC_REVIEW_READY = 720, + NOTIFY_CLIENT_UGC_REVIEW_READY = 721, + OLD_USE_ITEM_ON = 722, + FIND_PROPERTY_FOR_SALE_RESPONSE = 723, + PROPERTY_EDITOR_BEGIN = 724, + PROPERTY_EDITOR_END = 725, + PROPERTY_EDITOR_SET_MODE = 726, + TOGGLE_TRIGGER = 727, + FIRE_EVENT = 728, + IS_MINIFIG_IN_A_BUBBLE = 729, + GET_ITEM_INFO = 730, + MISSION_NEEDS_LOT = 731, + STOP_PATHING = 732, + START_PATHING = 733, + ACTIVATE_BUBBLE_BUFF_FROM_SERVER = 734, + DEACTIVATE_BUBBLE_BUFF_FROM_SERVER = 735, + HAS_SKILL = 736, + NOTIFY_CLIENT_ZONE_OBJECT = 737, + MOVE_OBJECT = 738, + ROTATE_OBJECT = 739, + GET_SPAWNER_CONFIG_DATA = 740, + UPDATE_SPAWNER_CONFIG_DATA = 741, + TURN_AROUND = 743, + GO_FORWARD = 744, + GO_BACKWARD = 745, + UPDATE_REPUTATION = 746, + GET_REPUTATION = 747, + ADD_REPUTATION = 748, + UPDATE_PROPERTY_DATA = 749, + PROPERTY_RENTAL_RESPONSE = 750, + EXHIBIT_PLACEMENT_RESPONSE = 751, + SQUIRT_WITH_WATERGUN = 752, + GET_VOTES_LEFT = 753, + ADJUST_VOTES_LEFT = 754, + EVADE_TARGET = 755, + STOPPED_EVADING = 756, + GET_PET_HAS_ABILITY = 757, + REQUEST_PLATFORM_RESYNC = 760, + PLATFORM_RESYNC = 761, + PLAY_CINEMATIC = 762, + END_CINEMATIC = 763, + CINEMATIC_UPDATE = 764, + ATTACH_CAMERA_TO_RAIL = 765, + DETACH_CAMERA_FROM_RAIL = 766, + TOGGLE_GHOST_REFERENCE_OVERRIDE = 767, + SET_GHOST_REFERENCE_POSITION = 768, + GET_GHOST_REFERENCE_POSITION = 769, + FIRE_EVENT_SERVER_SIDE = 770, + GET_PET_ABILITY_OBJECT = 771, + TEAM_INVITE_MSG_FROM_UI = 772, + ADD_CAMERA_EFFECT = 773, + REMOVE_CAMERA_EFFECT = 774, + REMOVE_ALL_CAMERA_EFFECTS = 775, + GET_MY_PROPERTIES_IN_THIS_ZONE = 776, + IS_MODEL_WITHIN_PROPERTY_BOUNDS = 777, + PROPERTY_DATA_RESULTS = 778, + ON_UN_SERIALIZE = 779, + SCRIPT_NETWORK_VAR_UPDATE = 781, + ADD_OBJECT_TO_GROUP = 783, + REMOVE_OBJECT_FROM_GROUP = 784, + IS_OBJECT_STATIC = 785, + GET_HAS_MISSION = 786, + GET_MISSION_TARGET_LOT = 787, + GET_MISSION_OFFERER_LOT = 788, + USE_UNIQUE_ITEM = 789, + GET_IS_PET = 790, + DELETE_PROPERTY = 791, + CREATEMODEL_FROM_CLIENT = 792, + UPDATE_MODEL_FROM_CLIENT = 793, + DELETE_MODEL_FROM_CLIENT = 794, + SHOW_PROPERTY_BOUNDS = 795, + SET_PROPERTY_I_DS = 796, + PLAY_FACE_DECAL_ANIMATION = 797, + ADD_ACTIVITY_USER = 798, + REMOVE_ACTIVITY_USER = 799, + GET_NUM_ACTIVITY_USERS = 800, + ACTIVITY_USER_EXISTS = 801, + DO_COMPLETE_ACTIVITY_EVENTS = 805, + SET_ACTIVITY_PARAMS = 806, + SET_ACTIVITY_USER_DATA = 807, + GET_ACTIVITY_USER_DATA = 808, + DO_CALCULATE_ACTIVITY_RATING = 809, + ND_AUDIO_POST_SETUP = 812, + ND_AUDIO_PRE_SHUTDOWN = 813, + SET_ND_AUDION_LISTENER_STANCE = 814, + SET_UP_ND_AUDIO_EMIITTER = 815, + SHUT_DOWN_ND_AUDIO_EMITTER = 816, + METAIFY_ND_AUDIO_EMITTER = 817, + UN_METAIFY_ND_AUDIO_EMITTER = 818, + METAIFY_ND_AUDIO_EMITTERS = 819, + UN_METAIFY_ND_AUDIO_EMITTERS = 820, + PLAY_ND_AUDIO_EMITTER = 821, + STOP_ND_AUDIO_EMITTER = 822, + STOP_ND_AUDIO_EMITTER_ALL = 823, + SET_ND_AUDIO_EMITTER_PARAMETER = 824, + SET_ND_AUDIO_EMITTERS_PARAMETER = 825, + ND_AUDIO_CALLBACK = 826, + ACTIVATE_ND_AUDIO_MUSIC_CUE = 827, + DEACTIVATE_ND_AUDIO_MUSIC_CUE = 828, + FLASH_ND_AUDIO_MUSIC_CUE = 829, + SET_ND_AUDIO_MUSIC_PARAMETER = 830, + PLAY2_D_AMBIENT_SOUND = 831, + STOP2_D_AMBIENT_SOUND = 832, + PLAY3_D_AMBIENT_SOUND = 834, + STOP3_D_AMBIENT_SOUND = 835, + ACTIVATE_ND_AUDIO_MIXER_PROGRAM = 836, + DEACTIVATE_ND_AUDIO_MIXER_PROGRAM = 837, + UPDATE_ACTIVITY_LEADERBOARD = 838, + ACTIVITY_LEADERBOARD_UPDATED = 839, + ENTER_PROPERTY1 = 840, + ENTER_PROPERTY2 = 841, + PROPERTY_ENTRANCE_SYNC = 842, + SEND_PROPERTY_POPULATION_TO_CLIENT = 843, + SEN_PROPERTY_PLAQUE_VIS_UPDATE = 844, + PROPERTY_SELECT_QUERY = 845, + CREATE_POSITION_STRING = 848, + GET_PARALLEL_POSITION = 849, + PARSE_CHAT_MESSAGE = 850, + SET_MISSION_TYPE_STATE = 851, + GET_LOCATIONS_VISITED = 852, + GET_MISSION_TYPE_STATES = 853, + GET_TIME_PLAYED = 854, + SET_MISSION_VIEWED = 855, + HKX_VEHICLE_LOADED = 856, + SLASH_COMMAND_TEXT_FEEDBACK = 857, + BROADCAST_TEXT_TO_CHATBOX = 858, + HANDLE_SLASH_COMMAND_KORE_DEBUGGER = 859, + OPEN_PROPERTY_MANAGEMENT = 860, + OPEN_PROPERTY_VENDOR = 861, + VOTE_ON_PROPERTY = 862, + UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK = 863, + NOTIFY_PLAYER_OF_PROPERTY_SUBMISSION = 865, + NOTIFY_PLAYER_OF_MODEL_SUBMISSION = 866, + PHYSICS_SYSTEM_LOADED = 867, + CLIENT_TRADE_REQUEST = 868, + SERVER_TRADE_REQUEST = 869, + SERVER_TRADE_INVITE = 870, + CLIENT_TRADE_REPLY = 871, + SERVER_TRADE_REPLY = 872, + SERVER_TRADE_INITIAL_REPLY = 873, + SERVER_TRADE_FINAL_REPLY = 874, + CLIENT_TRADE_UPDATE = 875, + SERVER_SIDE_TRADE_UPDATE = 876, + SERVER_TRADE_UPDATE = 877, + CLIENT_TRADE_CANCEL = 878, + CLIENT_SIDE_TRADE_CANCEL = 879, + CLIENT_TRADE_ACCEPT = 880, + SERVER_SIDE_TRADE_ACCEPT = 881, + SERVER_SIDE_TRADE_CANCEL = 882, + SERVER_TRADE_CANCEL = 883, + SERVER_TRADE_ACCEPT = 884, + GET_TRADE_INFO = 885, + KF_LOADED = 886, + BRICKS_LOADED = 887, + READY_FOR_UPDATES = 888, + SEND_READY_FOR_UPDATES = 889, + SET_LAST_CUSTOM_BUILD = 890, + GET_LAST_CUSTOM_BUILD = 891, + GET_STATUS_EFFECT_BY_ID = 892, + GET_ALL_STATUS_EFFECTS = 893, + CHILD_RENDER_COMPONENT_READY = 894, + NOTIFY_APPEARANCE_CHANGED_MSG = 895, + SET_PHYSICS_MOTION_STATE = 896, + GET_PHYSICS_MOTION_STATE = 897, + ATTACH_GRAYSCALE_EFFECT = 898, + ATTACH_FADE_EFFECT = 899, + ATTACH_CHANGE_RENDER_ENVIRONMENT_EFFECT = 900, + FORCE_MOVEMENT = 901, + CANCEL_FORCE_MOVEMENT = 902, + SET_IGNORE_PROJECTILE_COLLISION = 903, + GET_IGNORE_PROJECTILE_COLLISION = 904, + ORIENT_TO_OBJECT = 905, + ORIENT_TO_POSITION = 906, + ORIENT_TO_ANGLE = 907, + NOTIFY_CLIENT_UGC_MODEL_READY = 909, + NOTIFY_CLIENT_UGC_ICON_READY = 911, + PROPERTY_BUILD_MODE_CHANGED = 912, + PROPERTY_BUILD_MODE_UPDATE = 913, + PROPERTY_DELETION_ACTION = 914, + PROPERTY_MODERATION_STATUS_ACTION = 915, + PROPERTY_MODERATION_STATUS_ACTION_RESPONSE = 916, + PROPERTY_MODERATION_STATUS_UPDATE = 917, + PROPERTY_NEEDS_GM_ATTENTION = 918, + PROPERTY_MODERATION_CHANGED = 919, + INVENTORY_REFRESH_ITEM_DETAILS = 922, + INVENTORY_LOAD_CUSTOM_ICON = 923, + GET_STATUS_EFFECT_BY_TYPE = 924, + RELEASE_CHARGED_SKILL = 925, + PROPERTY_RELOAD_DB = 926, + SET_PLAYER_TARGET = 927, + GET_PLAYER_TARGET = 928, + LOCK_CAMERA_NETWORKED = 929, + MOVE_CAMERA_NETWORKED = 930, + REBUILD_ACTIVATED = 931, + BOUNCE_NOTIFICATION = 932, + REQUEST_CLIENT_BOUNCE = 934, + GET_RECENT_BOUNCED = 935, + SET_RECENT_BOUNCED = 936, + SET_ACTIVE_STATE = 937, + GET_ACTIVE_STATE = 938, + HAS_COMPONENT_TYPE = 939, + GET_COMPONENT_LIST = 940, + RESPONDS_TO_FACTION = 941, + BOUNCER_ACTIVE_STATUS = 942, + HF_ATTRIBUTES_PUSH = 943, + HF_ATTRIBUTES_PULL = 944, + HF_ATTRIBUTES_PATH_DISPLAY = 945, + HF_CONTROLS_PULL = 946, + HF_OBJECT_SELECTED = 947, + HF_PLACEHOLDER_UPDATE = 948, + HF_PLACEHOLDER_TOGGLE = 949, + HF_GET_ASSOCIATED_PATHS = 950, + HF_GETS_WANT_PATH = 951, + GET_RECENT_MOVEMENT_KEYS = 952, + TRACK_RECENT_MOVEMENT_KEYS = 953, + PHYSICS_MOVEMENT_NOTIFICATION_REQUEST = 954, + PHYSICS_MOVEMENT_NOTIFICATION = 955, + MOVE_INVENTORY_SINGLE = 956, + MOVE_INVENTORY_BATCH = 957, + MINI_GAME_SET_PARAMETERS = 958, + MINI_GAME_GET_TEAM_SKILLS = 961, + MINI_GAME_GET_TEAM_SCORE = 963, + MINI_GAME_GET_PLAYER_SCORE = 967, + MINI_GAME_GET_TEAM_COLOR = 972, + MINI_GAME_GET_TEAM_PLAYERS = 975, + MINI_GAME_UPDATE_CLIENT = 976, + MINI_GAME_GET_TEAM = 977, + MINI_GAME_GET_PARAMETERS = 978, + OBJECT_ACTIVATED_CLIENT = 980, + IS_RESURRECTING = 983, + GET_ITEM_OWNER = 984, + GET_STORED_CONFIG_DATA = 985, + SET_STORED_CONFIG_DATA = 986, + ON_PLAYER_RESSURECTED = 988, + PLAYER_RESURRECTION_FINISHED = 989, + TRANSFORM_CHANGELING_BUILD = 990, + RETURN_CHANGELING_BUILD_ID = 991, + SPEND_BRICK_INVENTORY_FOR_LXFML = 992, + BRICK_INVENTORY_FOR_LXFML_SPENT = 993, + REBUILD_BBB_AUTOSAVE_MSG = 995, + SET_BBB_AUTOSAVE = 996, + USE_BBB_INVENTORY = 998, + UN_USE_BBB_MODEL = 999, + BBB_LOAD_ITEM_REQUEST = 1000, + BBB_SAVE_REQUEST = 1001, + BBBLUP_SAVE_REQUEST = 1002, + BBB_GET_METADATA_SOURCE_ITEM = 1003, + BBB_RESET_METADATA_SOURCE_ITEM = 1004, + BBB_SAVE_RESPONSE = 1005, + PLAYER_EXIT = 1006, + SET_PVP_STATUS = 1008, + GET_PVP_STATUS = 1009, + IS_VALID_PVP_TARGET = 1010, + PVP_RENDER_NAME = 1011, + ATTACH_OBJECT = 1012, + DETACH_OBJECT = 1013, + BOUNCE_SUCCEEDED = 1014, + GET_GAME_OBJECT_POINTER = 1015, + PHANTOM_HKX_LOADED = 1016, + DELAY_CREATE_EFFECT = 1017, + CHOICE_BUILD_SELECTION_CONFIRMED = 1018, + NOTIFY_FADE_UP_VIS_COMPLETE = 1019, + ITEM_HAS_NEW_INFO = 1020, + RESET_SECONDARY_ANIMATION = 1021, + GET_PICK_TYPE = 1022, + SET_PICK_TYPE = 1023, + GET_PRIORITY_PICK_LIST_TYPE = 1024, + REQUEST_PICK_TYPE_UPDATE = 1025, + GET_OVERRIDE_PICK_TYPE = 1026, + REQUEST_DISPLAY_OBJECT_INFO = 1027, + REQUEST_SERVER_OBJECT_INFO = 1028, + REQUEST_OBJECT_INFO_AS_XML = 1029, + GET_OBJECT_REPORT_INFO = 1030, + GET_OBJECT_REPORT_WINDOW_CLOSE = 1031, + GET_OBJECT_REPORT_STATUS = 1032, + GET_MISSION_DATA_FOR_OBJECT_REPORT = 1033, + GET_OBJECT_ROLLOVER_INFO = 1034, + PERFORM_ZONE_ANALYSIS = 1035, + UPDATE_HK_VISUAL_IZATION = 1036, + CLEAR_ITEMS_OWNER = 1037, + APPLY_LINEAR_IMPULSE = 1038, + APPLY_ANGULAR_IMPULSE = 1039, + GET_CONTACT_NORMALS = 1040, + IS_WATCHING_FOR_EMOTE = 1041, + NOTIFY_CLIENT_OBJECT = 1042, + DISPLAY_ZONE_SUMMARY = 1043, + ZONE_SUMMARY_DISMISSED = 1044, + GET_PLAYER_ZONE_STATISTIC = 1045, + MODIFY_PLAYER_ZONE_STATISTIC = 1046, + APPLY_EXTERNAL_FORCE = 1049, + GET_APPLIED_EXTERNAL_FORCE = 1050, + ITEM_EQUIPPED = 1052, + ACTIVITY_STATE_CHANGE_REQUEST = 1053, + OVERRIDE_FRICTION = 1054, + ARRANGE_WITH_ITEM = 1055, + CHECK_CAN_BUILD_WITH_ITEM = 1056, + START_BUILDING_WITH_ITEM = 1057, + START_BUILD_SESSION = 1058, + FINISH_BUILD_SESSION = 1059, + DONE_BUILD_SESSION = 1060, + START_ARRANGING_WITH_ITEM = 1061, + FINISH_ARRANGING_WITH_ITEM = 1062, + DONE_ARRANGING_WITH_ITEM = 1063, + START_ARRANGE_MODE = 1064, + ARRANGE_MODE_WITH_ITEM = 1065, + FINISH_ARRANGE_MODE = 1066, + DONE_ARRANGE_MODE = 1067, + SET_BUILD_MODE = 1068, + BUILD_MODE_SET = 1069, + CONFIRM_BUILD_MODE = 1070, + BUILD_MODE_CONFIRMATION = 1071, + BUILD_EXIT_CONFIRMATION = 1072, + SET_BUILD_MODE_CONFIRMED = 1073, + BUILD_MODE_NOTIFICATION = 1074, + BUILD_MODE_NOTIFICATION_REPORT = 1075, + CLIENT_USE_MODULE_ON = 1076, + SET_MODEL_TO_BUILD = 1077, + SPAWN_MODEL_BRICKS = 1078, + CHECK_PRECONDITION = 1079, + CHECK_ALL_PRECONDITIONS = 1080, + NOTIFY_CLIENT_FAILED_PRECONDITION = 1081, + GET_IS_ITEM_EQUIPPED_BY_LOT = 1082, + GET_IS_ITEM_EQUIPPED_BY_ID = 1083, + GET_OBJECT_DIRECTION_VECTORS = 1084, + GET_CASTABLE_SKILLS = 1085, + CHOICEBUILD_COMPLETE = 1086, + GET_MISSION_CHAT = 1087, + GET_MISSION_AUDIO = 1088, + MODULE_EQUIPPED = 1089, + MODULE_DROPPED = 1090, + MODULE_PICKED_UP = 1091, + MODULE_INFO = 1092, + MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1093, + MODULAR_BUILD_BEGIN = 1094, + MODULAR_BUILD_END = 1095, + MODULAR_BUILD_MOVE_AND_EQUIP = 1096, + MODULAR_BUILD_FINISH = 1097, + SET_REGISTRATION_FOR_UI_UPDATE = 1114, + GO_TO_WAYPOINT = 1115, + ARRIVED_AT_DESIRED_WAYPOINT = 1116, + CHECK_WITHIN_BOUNDS = 1117, + ATTACH_TO_BUILD_ASSEMBLY = 1118, + SET_BUILD_ASSEMBLY = 1119, + RESET_BUILD_ASSEMBLY = 1120, + GET_INVENTORY_ITEM_INFO = 1125, + GET_ITEM_DETAILS = 1126, + GET_BUILD_ACTIVATOR = 1127, + GET_MISSION_ANIMATION = 1128, + MISSION_DIALOGUE_CANCELLED = 1129, + MODULE_ASSEMBLY_DB_DATA = 1130, + MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131, + MODULE_ASSEMBLY_QUERY_DATA = 1132, + MODULE_ASSEMBLY_HKX_LOADED = 1133, + MODULE_ASSEMBLY_NIF_LOADED = 1134, + MODULE_ASSEMBLY_MAIN_NIF_LOADED = 1135, + MODULE_ASSEMBLY_KFM_LOADED = 1136, + GET_PRECONDITION_INFO = 1137, + GET_MODEL_LOT = 1138, + ANIMATION_FINISHED_PRELOADING = 1139, + CHILD_BUILD_ASSEMBLY_COMPLETE = 1140, + CHARACTER_UNSERIALIZED = 1141, + CHARACTER_NEEDS_TRANSITION = 1142, + SET_NEEDS_TRANSITION = 1143, + ECHO_SYNC_SKILL = 1144, + SYNC_SKILL = 1145, + GET_BEHAVIOR_HANDLE = 1146, + ADD_OUTSTANDING_BEHAVIOR = 1147, + REQUEST_SERVER_PROJECTILE_IMPACT = 1148, + OFF_WORLD_IMPACT_REQUEST = 1149, + SERVER_IMPACT_REQUEST = 1150, + DO_CLIENT_PROJECTILE_IMPACT = 1151, + MODULE_ASSEMBLY_PART_INFO = 1152, + GET_BUILD_TYPE = 1153, + CHECK_BUILD_TYPE = 1154, + MODULAR_BUILD_CONVERT_MODEL = 1155, + DO_NPC_SHOWCASE_MODEL_SUBMISSION = 1156, + GET_MISSION_I_DS_LIST = 1157, + SET_SHOWCASE_MISSION_NPC_VALS = 1158, + NOTIFY_SHOWCASE_MISSION_NP_COF_SUCCESS = 1159, + SEND_LUA_NOTIFICATION_REQUEST = 1160, + SEND_LUA_NOTIFICATION_CANCEL = 1161, + ACTIVATOR_TOGGLE = 1162, + MAKE_PHYSICS = 1163, + SET_RESPAWN_GROUP = 1164, + SET_PLAYER_ALLOWED_RESPAWN = 1165, + TOGGLE_SENDING_POSITION_UPDATES = 1166, + TOGGLE_RECEIVING_POSITION_UPDATES = 1167, + GET_ENEMY_PRECONDITIONS = 1168, + START_MODEL_VISUALIZATION = 1169, + PLACE_PROPERTY_MODEL = 1170, + PROPERTY_MODEL_PLACED = 1171, + OPEN_EXHIBIT_REPLACE_MODEL_UI = 1172, + REPLACE_SHOWCASEMODEL = 1173, + CLEAR_UI_HOOK_EXHIBIT_REPLACEMENT = 1174, + ATTACH_FLYTO_SCREEN_POS = 1175, + VEHICLE_GET_DEBUG_INFO = 1176, + VEHICLE_GET_MOVEMENT_INPUT_VALUES = 1177, + ACTIVITY_TIMER_SET = 1178, + ACTIVITY_TIMER_UPDATE = 1179, + ACTIVITY_TIMER_GET = 1180, + ACTIVITY_TIMER_STOP = 1181, + ACTIVITY_TIMER_DONE = 1182, + GET_ATTACK_PRIORITY = 1183, + UI_MESSAGE_SERVER_TO_SINGLE_CLIENT = 1184, + UI_MESSAGE_SERVER_TO_ALL_CLIENTS = 1185, + SET_LOSE_COINS_ON_DEATH = 1186, + LOAD_EFFECTS = 1187, + SET_CUSTOM_BUILD = 1188, + ACTIVITY_TIMER_RESET = 1189, + ACTIVITY_TIMER_STOP_ALL_TIMERS = 1190, + ACTIVITY_TIMER_MODIFY = 1191, + SET_KEYFRAM_TRANSFORM = 1192, + ADD_ACTIVITY_OWNER = 1193, + REMOVE_ACTIVITY_OWNER = 1194, + GET_CURRENT_ACTIVITY_OWNERS = 1195, + TOGGLE_SKILL_DEBUGGING = 1196, + PET_TAMING_TRY_BUILD = 1197, + REPORT_BUG = 1198, + REPORT_OFFENSIVE_MODEL = 1199, + REPORT_OFFENSIVE_PROPERTY = 1200, + GET_ACTIVITY_ID = 1201, + REQUEST_SMASH_PLAYER = 1202, + GET_TIMES_REQUESTED_SMASH = 1203, + RESPONSE_SMASH_PLAYER = 1204, + MODIFY_DAMAGE_ABSORPTION = 1205, + UNCAST_SKILL = 1206, + GET_SHOWCASE_MODEL_READY = 1207, + IS_SKILL_NEEDED = 1208, + GET_COMPONENT_DATA = 1209, + VEHICLE_SET_POWERSLIDE_METHOD = 1210, + SHOWS_NAMETAG = 1211, + FIRE_EVENT_CLIENT_SIDE = 1213, + GET_REQUIRES_NAME_RESUBMISSION = 1216, + SET_REQUIRES_NAME_RESUBMISSION = 1217, + TOGGLE_GM_INVIS = 1218, + GET_GM_INVIS = 1219, + KILLED_PLAYER = 1220, + GET_PICKUP_SKILLS = 1221, + GET_FACTION_SKILL = 1222, + CHANGE_OBJECT_WORLD_STATE = 1223, + GET_OBJECT_WORLD_STATE = 1224, + VISIBILITY_CHANGED = 1225, + MOTION_EFFECT_COMPLETE = 1226, + TOGGLE_FREEZE_MODE = 1227, + SHADER_RENDER_MSG_APPLIED = 1228, + PLAYER_RENAME_REQUEST = 1229, + VEHICLE_LOCK_INPUT = 1230, + VEHICLE_UNLOCK_INPUT = 1231, + SET_AIR_MOVEMENT = 1232, + MOVEMENT_STATE_CHANGED = 1233, + SKILL_MOVEMENT_CANCELLED = 1234, + AIR_MOVEMENT_COMPLETE = 1235, + CANCEL_AIR_MOVEMENT = 1236, + FORCE_MINIFIGURE_TEXTURE_UPDATE = 1237, + RESYNC_EQUIPMENT = 1238, + ADD_COMPONENT_TO_OBJECT = 1239, + VEHICLE_GET_MAX_GAME_SPEED = 1240, + VEHICLE_GET_MAX_GAME_SPEED_WITH_BOOST = 1241, + GET_SPEED_FACTOR = 1242, + FREEZE_INVENTORY = 1243, + ADD_STAT_TRIGGER = 1244, + ADD_STAT_TRIGGER_CHILD = 1245, + CHECK_TRIGGERS_AND_FIRE_IF_NEEDED = 1246, + STAT_EVENT_TRIGGERED = 1247, + GET_CURRENT_SPEED = 1248, + RACING_PLAYER_RANK_CHANGED = 1249, + RACING_PLAYER_WRONG_WAY_STATUS_CHANGED = 1250, + RACING_PLAYER_CROSSED_FINISH_LINE = 1251, + RACING_RESET_PLAYER_TO_LAST_RESET = 1252, + RACING_SERVER_SET_PLAYER_LAP_AND_PLANE = 1253, + RACING_SET_PLAYER_RESET_INFO = 1254, + RACING_PLAYER_INFO_RESET_FINISHED = 1255, + RACING_PLAYER_OUT_OF_TRACK_BOUNDS = 1256, + RACING_SYNC_INFO = 1257, + RACING_PLAYER_KEEP_ALIVE = 1258, + RACING_SERVER_KEEP_ALIVE = 1259, + LOCK_NODE_ROTATION = 1260, + GET_PHYSICS_COLLIDABLE = 1261, + SET_PHYSICS_COLOR_FOR_DEBUG = 1262, + GET_PHYSICS_COLOR_FOR_DEBUG = 1263, + SET_PHYSICS_TEXT_AND_STATE_FOR_DEBUG = 1264, + REQUEST_INFO_FOR_PHYSICS_DEBUGGER = 1265, + GET_COLLIDABLE_AT_ADDRESS = 1266, + REQUEST_SERVER_GET_COLLIDABLE_REPORT = 1267, + COLLISION_POINT_ADDED = 1268, + COLLISION_POINT_REMOVED = 1269, + SET_ATTACHED = 1270, + SET_DESTROYABLE_MODEL_BRICKS = 1271, + VEHICLE_SET_POWERSLIDE_LOCK_WHEELS = 1272, + VEHICLE_SET_WHEEL_LOCK_STATE = 1273, + SHOW_HEALTH_BAR = 1274, + GET_SHOWS_HEALTH_BAR = 1275, + NOTIFY_VEHICLE_OF_RACING_OBJECT = 1276, + ENABLE_CLIENT_EQUIP_MODE = 1278, + CLIENT_EQUIP_MODE_WAS_CHANGED = 1279, + VEHICLE_GET_SPAWN_HEIGHT = 1281, + SET_NAME_BILLBOARD_STATE = 1284, + CHECK_TARGETING_REQUIREMENTS = 1285, + VEHICLE_CAN_WRECK = 1286, + ATTACH_RENDER_EFFECT = 1287, + DETACH_RENDER_EFFECT = 1288, + IS_PET_USING_ABILITY = 1289, + SET_BLOCKING = 1290, + GET_BLOCKING = 1291, + UPDATE_BLOCKING = 1292, + CHECK_DAMAGE_RESULTS = 1293, + GET_OBJECT_IS_IN_RENDER_PIPE = 1294, + ATTACH_MOTION_FX_ARC = 1295, + PLAYER_REACHED_RESPAWN_CHECKPOINT = 1296, + GET_LAST_RESPAWN_CHECKPOINT = 1297, + GET_VEHICLE_DEBUG_COLLISIONS = 1298, + VISITING_PROPERTY = 1299, + HANDLE_UGC_POST_DELETE_BASED_ON_EDIT_MODE = 1300, + HANDLE_UGC_POST_CREATE_BASED_ON_EDIT_MODE = 1301, + WORLD_CHECK_RESPONSE = 1302, + ADD_DAMAGE_REDUCTION = 1303, + REMOVE_DAMAGE_REDUCTION = 1304, + PROPERTY_CONTENTS_FROM_CLIENT = 1305, + GET_MODELS_ON_PROPERTY = 1306, + IS_SHOWCASE_DISPLAY_PEDESTAL = 1307, + MATCH_REQUEST = 1308, + MATCH_RESPONSE = 1309, + MATCH_UPDATE = 1310, + IS_DEFAULT_SKILL_ACTIVE = 1311, + PROPERTY_EDITOR_CARRY = 1312, + GET_LOOT_OWNER_ID = 1313, + GET_ENEMY_LOOT_TAG = 1314, + GET_NUM_SPAWNED_BRICKS = 1315, + SET_ITEM_EQUIP_TRANSFORM = 1316, + GET_ITEM_EQUIP_TRANSFORM = 1317, + GET_PROPERTY_BUDGET_INFO = 1318, + CHATBOX_IS_INIT = 1319, + GET_SPAWNED_I_DS = 1320, + GET_IMMUNITY = 1321, + GET_GM_IMMUNITY = 1322, + PROCESS_REMOTE_SLASH_COMMAND = 1323, + IS_FRIEND_MSG = 1324, + RACING_PLAYER_EVENT = 1325, + GET_PROPERTY_EDIT_VALID = 1326, + REFRESH_RENDER_ASSET = 1327, + VEHICLE_APPLY_STAT_CHANGE = 1328, + ZONE_LOADED_INFO = 1329, + B3_INTERFACE_ACTION = 1330, + RACING_STAT_MODIFIERS_FROM_CLIENT = 1332, + GET_RACING_STAT_MODIFIERS = 1333, + SET_RACING_STAT_MODIFIERS = 1334, + GET_RACING_LICENSE_LEVEL = 1335, + ADD_EQUIP_CAST = 1336, + SHOW_BILLBOARD_INTERACT_ICON = 1337, + CHANGE_IDLE_FLAGS = 1338, + GET_ANIMATION_FLAG = 1339, + VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340, + VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341, + NOTIFY_SERVER_VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1342, + NOTIFY_SERVER_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1343, + VEHICLE_ADD_SLOWDOWN_ACTION = 1344, + VEHICLE_REMOVE_SLOWDOWN_ACTION = 1345, + NOTIFY_SERVER_VEHICLE_ADD_SLOWDOWN_ACTION = 1346, + NOTIFY_SERVER_VEHICLE_REMOVE_SLOWDOWN_ACTION = 1347, + FORCE_UPDATE_ANIMATIONS = 1348, + MATCH_GET_DATA_FOR_PLAYER = 1349, + BUYBACK_FROM_VENDOR = 1350, + SET_INVENTORY_FILTER = 1351, + GET_INVENTORY_FILTER = 1352, + GET_INVENTORY_GROUPS = 1353, + GET_INVENTORY_GROUP = 1354, + UPDATE_INVENTORY_GROUP = 1355, + UPDATE_INVENTORY_UI = 1356, + UPDATE_INVENTORY_GROUP_CONTENTS = 1357, + CAN_REMOVE_ITEM_FROM_INVENTORY = 1362, + DRIVE_THIS_CAR = 1363, + VEHICLE_CAN_ADD_ACTIVE_BOOST = 1364, + VEHICLE_ADD_ACTIVE_BOOST = 1365, + SET_PROPERTY_ACCESS = 1366, + ZONE_PROPERTY_MODEL_PLACED = 1369, + ZONE_PROPERTY_MODEL_ROTATED = 1370, + ZONE_PROPERTY_MODEL_REMOVED_WHILE_EQUIPPED = 1371, + ZONE_PROPERTY_MODEL_EQUIPPED = 1372, + ZONE_PROPERTY_MODEL_PICKED_UP = 1373, + ZONE_PROPERTY_MODEL_REMOVED = 1374, + GET_VERSIONING_INFO = 1381, + OPEN_UG_BEHAVIOR_UI = 1382, + VEHICLE_NOTIFY_HIT_SMASHABLE = 1383, + GET_TETHER_RADIUS = 1384, + VEHICLE_NOTIFY_HIT_EXPLODER = 1385, + CHECK_NEAREST_ROCKET_LAUNCH_PRE_CONDITIONS = 1386, + REQUEST_NEAREST_ROCKET_LAUNCH_PRE_CONDITIONS = 1387, + CONFIGURE_RACING_CONTROL_CLIENT = 1389, + NOTIFY_RACING_CLIENT = 1390, + RACING_PLAYER_HACK_CAR = 1391, + RACING_PLAYER_LOADED = 1392, + RACING_CLIENT_READY = 1393, + POSSESSION_FINISHED_ATTACH = 1394, + UPDATE_CHAT_MODE = 1395, + VEHICLE_NOTIFY_FINISHED_RACE = 1396, + EQUIPPED_ITEM_STARTUP = 1397, + FACTION_TRIGGER_ITEM_EQUIPPED = 1400, + FACTION_TRIGGER_ITEM_UNEQUIPPED = 1401, + TOGGLE_PROPERTY_BEHAVIORS = 1402, + GET_UG_OBJECT_INFO = 1405, + RESET_PROPERTY_BEHAVIORS = 1406, + IS_PROPERTY_MODEL_RESET = 1407, + SET_UG_OBJECT_NAME_AND_DESCRIPTION = 1408, + SET_CONSUMABLE_ITEM = 1409, + VEHICLE_GET_CURRENT_LAP = 1410, + GET_UGID = 1411, + SET_UGID = 1412, + UGID_CHANGED = 1413, + RACING_GET_CURRENT_LAP_FOR_PLAYER = 1414, + SUB_ITEM_UN_EQUIPPED = 1415, + SET_CUSTOM_DROP_SHADOW_TEXTURE = 1416, + GET_PLAYER_KIT_FACTION = 1418, + USED_INFORMATION_PLAQUE = 1419, + RACING_ENABLE_WRONG_WAY_RESET = 1420, + RACING_TOGGLE_RUBBER_BANDING = 1421, + GET_RACING_CONTROL_DEBUG_INFO = 1422, + SET_PROPERTY_BOUNDS_VISIBILITY = 1423, + SET_PROPERTY_VENDOR_VISIBILITY = 1424, + SET_EQUIP_STATE = 1425, + NOTIFY_COMBAT_AI_STATE_CHANGE = 1426, + SET_PROPERTY_MODEL_INTERACTIVE = 1430, + SERVER_STATE_NOTIFY = 1431, + GET_SERVER_STATE = 1432, + GET_ICON_FOR_PROXIMITY = 1433, + GET_LEGO_CLUB_MEMBERSHIP_STATUS = 1434, + SET_STATUS_IMMUNITY = 1435, + GET_STATUS_IMMUNITY = 1436, + TEAM_IS_MEMBER = 1437, + ACTIVATE_BRICK_MODE = 1438, + GET_BUILD_OBJECT_ID = 1439, + SET_ANIMATION_ENABLED = 1444, + PAUSE_COOLDOWNS = 1446, + FORCE_UPDATE_RENDER_NODE = 1447, + SET_PET_NAME_MODERATED = 1448, + TOGGLE_STRAFE_MODE = 1449, + SET_SCHEME_SPEED_SCALE = 1450, + CANCEL_SKILL_CAST = 1451, + CHECK_PLAYER_ASSEMBLY_FOR_UNIQUE_MODULE_BY_LOT = 1454, + MODULE_ASSEMBLY_DB_DATA_TO_LUA = 1455, + IS_ALLY = 1458, + MODIFY_LEGO_SCORE = 1459, + GET_LEGO_SCORE = 1460, + GET_PLAYER_LEVEL = 1461, + NOTIFY_LEGO_SCORE_UPDATE = 1462, + SET_LEGO_SCORE = 1463, + UPDATE_BEHAVIOR_EXECUTION_DETAILS = 1466, + RESTORE_TO_POST_LOAD_STATS = 1468, + PICKUP_OBJECT_ERROR = 1469, + CHECK_AND_SHOW_INVENTORY_FULL_TIP = 1470, + SET_RAIL_MOVEMENT = 1471, + START_RAIL_MOVEMENT = 1472, + SET_UP_VECTOR = 1473, + CANCEL_RAIL_MOVEMENT = 1474, + GET_RAIL_INFO = 1475, + CLIENT_RAIL_MOVEMENT_READY = 1476, + PLAYER_RAIL_ARRIVED_NOTIFICATION = 1477, + NOTIFY_RAIL_ACTOVATOR_STATE_CHANGE = 1478, + REQUEST_RAIL_ACTIVATOR_STATE = 1479, + NOTIFY_REWARD_MAILED = 1480, + UPDATE_PLAYER_STATISTIC = 1481, + IS_IN_COMBAT = 1482, + IS_PRIMITIVE_MODEL_MSG = 1483, + SCALE_PRIMITICE_MODEL_MSG = 1484, + MODIFY_GHOSTING_DISTANCE = 1485, + PRIMITIVE_MODEL_CHANGED_MSG = 1487, + GET_PROPRTY_CLONE_ID = 1488, + REQUEST_LEAVE_PROPERTY = 1489, + REQUERY_PROPERTY_MODELS = 1491, + GET_BEHAVIOR_COUNT = 1492, + UPDATE_BEHAVIOR_CONTROLS = 1493, + MODULE_ASSEMBLY_LXFML_LOADED = 1494, + REQUEST_ASSEMBLED_LXFML = 1495, + ASSEMBLED_LXFML_LOADED = 1496, + GET_REORIENT_UP_VECTOR = 1497, + MODULAR_ASSEMBLY_NIF_COMPLETED = 1498, + CHARACTER_DISCONNECT_BEFORE_CREATE = 1499, + SEND_LAUNCH_TO_PREVIOUS_ZONE_TO_CLIENT = 1500, + ROCKETLAUNCH_REQUEST_DEFAULT_MAP_ID = 1501, + BEGIN_LAUNCH = 1502, + PROCESS_CLAIM_CODES = 1503, + GET_LAST_ZONE_ID = 1504, + ADD_RUN_SPEED_MODIFIER = 1505, + REMOVE_RUN_SPEED_MODIFIER = 1506, + SKILL_EVENT_FIRED = 1507, + SEND_HOT_PROPERTY_DATA = 1510, + GET_HOT_PROPERTY_DATA = 1511, + GET_EQUIPPED_ITEMS_IN_SET = 1512, + IS_ITEM_IN_SET = 1513, + GET_INVENTORY_TYPE_FOR_LOT = 1514, + GET_BANK_TYPE_FOR_LOT = 1515, + NOTIFY_NOT_ENOUGH_INV_SPACE = 1516, + IMPORT_MODEL_TO_BBB = 1517, + SEARCH_NEARBY_OBJECTS = 1518, + SEARCH_NEARBY_OBJECTS_REQUEST_BY_LOT = 1519, + REQUEST_OBJECT_POSITION_BY_ID = 1520, + SEARCH_NEARBY_OBJECTS_REQUEST_BY_COMPONENT = 1521, + SEARCH_NEARBY_OBJECTS_RESPONSE = 1522, + BROADCAST_NON_STANDARD_COLLISIONS = 1523, + GET_REGISTERED_NON_STANDARD_COLLISION_GROUP = 1524, + BROADCAST_CRUSHED_NOTIFICATIONS = 1525, + GET_REGISTERED_CRUSHED_COLLISION_GROUPS = 1526, + IS_BEING_CRUSHED = 1527, + GET_SUPPORTING_OBJECT = 1528, + TREAT_RIGID_BODY_COLLSIONS_AS_FIXED = 1529, + BROADCAST_TELEPORTED_WITHIN_NOTIFICATION = 1530, + GET_REGISTERED_TELEPORTED_WITHIN_OBJECT_GROUP = 1531, + GET_INTERPENTRATING_INFORMATION = 1532, + OBJECT_TELEPORTED_WITHIN = 1533, + SET_PHYSICS_SOLVER_PROPERTIES = 1534, + HAS_BEHAVIORS = 1535, + PLAY_BEHAVIOR_SOUND = 1536, + GET_PLAYER_BEHAVIOR_TIER = 1537, + GET_EMOTE_ANIMATION_TIME = 1538, + GET_CHARACTER_STAT_TRACKING = 1539, + PLAYER_INVENTORY_READY = 1540, + SET_PRECONDITIONS = 1541, + DETACH_SHADOW = 1542, + GET_LOOT_INFO = 1543, + GET_PLAYERS_ON_PROPERTY = 1544, + PROPERTY_SPAWN_BY_BEHAVIOR = 1545, + NOTIFY_PROPERTY_OF_EDIT_MODE = 1546, + UPDATE_PROPERTY_PERFORMANCE_COST = 1547, + GET_PROPERTY_PERFORMANCE_COST = 1548, + GET_INVENTORY_ITEM_WITH_SUBKEY = 1549, + DISPLAY_PROPERTY_SUMMARY_SCREEN = 1550, + VALIDATE_BBB_MODEL = 1551, + BBB_MODEL_VALIDATION = 1552, + PROPERTY_ENTRANCE_BEGIN = 1553, + CHECK_LIST_OF_PRECONDITIONS_FROM_LUA = 1554, + GET_PROPERTYIN_ZONE = 1555, + GET_ZONE_ID_FROM_MULTI_ZONE_ENTRANCE = 1556, + TEAM_SET_LEADER = 1557, + TEAM_INVITE_CONFIRM = 1558, + TEAM_GET_STATUS_RESPONSE = 1559, + MINI_GAME_ENABLE_LOCAL_TEAMS = 1560, + TEAM_INVITE_FINAL_RESPONSE = 1561, + TEAM_ADD_PLAYER = 1562, + TEAM_REMOVE_PLAYER = 1563, + TEAM_CREATE_LOCAL = 1564, + TEAM_GET_LOOT = 1565, + TEAM_SET_LOOT = 1566, + SET_ZERO_IMPULSE_AGAINST_COLLISION_GROUPS = 1567, + SET_CENTER_OF_MASS_TO_PHYSICAL_CENTER = 1568, + SET_INERTIA_INVERSE = 1569, + ADD_REMOVE_CLIMBING_LISTENER = 1570, + GET_INVENTORYITEM_DETAILS = 1571, + PERFORM_CLIENT_SIDE_DEATH = 1572, + LEGO_CLUB_ACCESS_RESULT = 1573, + VEHICLE_GET_IS_REVERSING = 1574, + CHECK_CLAIM_CODE = 1575, + GET_HOLIDAY_EVENT = 1576, + SET_EMOTES_ENABLED = 1577, + GET_EMOTES_ENABLED = 1578, + FREEZE_ANIMATION = 1579, + LOCALIZED_ANNOUNCEMENT_SERVER_TO_SINGLE_CLIENT = 1580, + ANCHOR_FX_NODE = 1581, + WS_GET_FRIEND_LIST_MESSAGE = 1582, + WS_ADD_FRIEND_RESPONSE = 1583, + WS_REMOVE_FRIEND_REPSONSE = 1584, + WS_UPDATE_FRIEND_STATUS = 1585, + WS_UPDATE_FRIEND_NAME = 1586, + IS_BEST_FRIEND = 1587, + TEAM_NOTIFY_UPDATE_MISSION_TASK = 1588, + VEHICLE_ADD_SLIPPERY_ACTION = 1589, + VEHICLE_REMOVE_SLIPPERY_ACTION = 1590, + SET_RESURRECT_RESTORE_VALUES = 1591, + GET_MASS = 1592, + SET_PROPERTY_MODERATION_STATUS = 1593, + UPDATE_PROPERTY_MODEL_DEFAULTS = 1594, + UPDATE_PROPERTYMODEL_COUNT = 1595, + GET_PROPERTY_MODEL_COUNT = 1596, + IS_PLAYER_LOADED = 1597, + ATTACH_RENDER_EFFECT_FROM_LUA = 1598, + DETACH_RENDER_EFFECT_FROM_LUA = 1599, + TEAM_IS_LOCAL = 1600, + CREATE_CAMERA_PARTICLES = 1602, + SET_SMASHABLE_GRAVITY_FACTOR = 1603, + VEHICLE_SET_SURFACE_TYPE_OVERRIDE = 1604, + VEHICLE_NOTIFY_HIT_IMAGINATION = 1605, + VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER = 1606, + GET_SPAWNED_OBJECT_SPAWNER_INFO = 1607, + SAVE_PROPERTY = 1608, + SET_PROPERTY_DIRTY = 1609, + GET_PROPERTY_DIRTY = 1610, + GET_MODEL_LIST_FROM_PLAQUE = 1611, + GET_ORIGINAL_POSITION_AND_ROTATION = 1612, + VEHICLE_SET_MASS_FOR_COLLISION = 1613, + GET_INVENTORY_GROUP_COUNT = 1614, + GET_LATEST_CHAT_CHANNEL_USED = 1615, + SET_SUGGEST_LIST_LANGUAGE = 1616, + VEHICLE_STOP_BOOST = 1617, + START_CELEBRATION_EFFECT = 1618, + LOCK_PLAYER = 1619, + VEHICLE_IS_INPUT_LOCKED = 1620, + GET_MULTI_NODE = 1621, + RENEW_PROPERTY = 1622, + RENEW_PROPERTY_RESULT = 1623, + CHARGE_ACTIVITY_COST = 1624, + CAN_RECEIVE_LOOT = 1625, + JOIN_PLAYER_FACTION = 1626, + SET_PROXIMITY_UPDATE_RATE = 1627, + BBB_MODELS_TO_SAVE = 1628, + BELONGS_TO_FACTION = 1629, + MODIFY_FACTION = 1630, + FACTION_UPDATE = 1631, + CELEBRATION_COMPLETED = 1632, + PLAY_PRIMARY_MODULE_SOUNDS = 1633, + STOP_PRIMARY_MODULE_SOUNDS = 1634, + REQUEST_TEAM_PLAYER_UI_UPDATE = 1635, + SET_LOCAL_TEAM = 1636, + TEAM_GET_WORLD_MEMBERS_IN_RADIUS = 1637, + GET_PARENTAL_LEVEL = 1638, + GET_OBJECTS_MESSAGE_HANDLERS = 1639, + PROPERTY_FEATURED = 1640, + PROPERTY_NOTIFY_MODEL_SPAWNED = 1641, + SERVER_DONE_LOADING_ALL_OBJECTS = 1642, + GET_DONATION_TOTAL = 1643, + UPDATE_DONATION_VALUES = 1644, + DELAYED_DELETE_DROP_EFFECT_BRICK = 1645, + SET_CAMERA_UNLOCK_ROTATION_STATE = 1646, + ADD_BUFF = 1647, + REMOVE_BUFF = 1648, + CHECK_FOR_BUFF = 1649, + TEAM_MEMBERS_DISOWNS_LOOT = 1650, + GET_WHEEL_TEMPLATE = 1651, + ADD_SKILL_IN_PROGRESS = 1652, + REMOVE_SKILL_IN_PROGRESS = 1653, + SET_OVERHEAD_ICON_OFFSET = 1654, + SET_BILLBOARD_OFFSET = 1655, + SET_CHAT_BUBBLE_OFFSET = 1656, + SET_NO_TEAM_INVITES = 1657, + RESET_MODEL_TO_DEFAULTS = 1658, + IS_PROPERTY_IN_EDIT_MODE = 1659, + GET_OBJECTS_IN_PHYSICS_BOUNDS = 1660, + ENABLE_LU_REMOTE = 1661, + SET_IS_USING_FREE_TRIAL = 1662, + GET_IS_USING_FREE_TRIAL = 1663, + GET_ACCOUNT_FREE_TRIAL_MODE = 1664, + TOGGLE_INVENTORY_ITEM_LOCK = 1665, + REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666, + RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667, + REMOVE_SUB_COMPONENT = 1668, + TEAM_GET_LOOT_MEMBERS = 1669, + GET_FACTION_TOKEN_TYPE = 1670, + GET_SUBSCRIPTION_PRICING = 1671, + INFORM_AFK = 1672, + OVERHEAD_INDICATOR_CREATED = 1673, + SET_OVERHEAD_INDICATOR_GRID_LOCATION = 1674, + PLAYSTREAM_LOAD_PENDING = 1675, + PLAYER_SET_CAMERA_CYCLING_MODE = 1676, + PLAYER_GET_CAMERA_CYCLING_MODE = 1677, + FORCE_CAMERA_TARGET_CYCLE = 1678, + GET_OBJECT_CONFIG_DATA = 1679, + GET_OBJECT_CONFIG_DATA_NON_CONST = 1680, + SCOPE_CHANGED = 1681, + SET_ALLOW_JUMP_WITHOUT_SUPPORT = 1682, + GET_ALLOW_JUMP_WITHOUT_SUPPORT = 1683, + SET_JUMP_HEIGHT_SCALE = 1684, + GET_JUMP_HEIGHT_SCALE = 1685, + SET_VELOCITY_RESISTANCE = 1686, + GET_VELOCITY_RESISTANCE = 1687, + GATE_RUSH_VEHICLE_HIT_GATE = 1688, + GATE_RUSH_PLAYER_COLLECTED_GATE = 1689, + GATE_RUSH_ADD_GATE = 1690, + GATE_RUSH_REMOVE_GATE = 1691, + NOTIFY_VEHICLE_UPDATED = 1692, + VEHICLE_NOTIFY_HIT_WEAPON_POWERUP = 1693, + VEHICLE_NOTIFY_HIT_WEAPON_POWERUP_SERVER = 1694, + LOCAL_PLAYER_TARGETED = 1696, + SKILL_COUNT_CHANGED = 1697, + DO_YAW_ROTATION = 1698, + DO_PITCH_ROTATION = 1699, + DO_ROLL_ROTATION = 1700, + GET_CURRENT_LOOT_MATRIX = 1701, + SEND_MULTI_MISSION_OFFER_UPDATE_I_DS = 1702, + SET_AIR_SPEED_VALUES = 1703, + USE_LAUNCHER = 1704, + START_LAUNCHER = 1705, + STOP_LAUNCHER = 1706, + CAN_USE_JET_PACK = 1707, + JET_PACK_STATE_CHANGED = 1708, + TURN_OFF_JET_PACK = 1709, + ADD_PLAYER_JET_PACK_PAD = 1710, + SET_JET_PACK_WARNING = 1711, + JET_PACK_DISABLED = 1712, + JET_PACK_PAD_ENTERED = 1713, + UPDATE_RENDER_POSSESSION_FLAG = 1714, + POSSESSABLE_GET_ATTACH_OFFSET = 1715, + ATTEMPT_TO_CRAFT_ITEM = 1718, + CRAFT_ATTEMPT_RESPONSE = 1719, + SET_C_SCORE = 1720, + FILL_IN_RENDERER = 1721, + TOGGLE_CRAFTING_WINDOW = 1722, + REMOVE_TEAM_BUFFS = 1724, + REQUEST_FREE_TRIAL_STATUS_REFRESH = 1725, + REMOVE_BUFFS_APPLIED_BY_OBJECT = 1726, + SET_MOUNT_INVENTORY_ID = 1727, + GET_MOUNT_INVENTORY_ID = 1728, + GET_BUILD_CINEMATIC_TIME_REMAINING = 1730, + JET_PACK_FLYING = 1731, + NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE = 1734, + NOTIFY_LEVEL_REWARDS = 1735, + CHARACTER_VERSION_CHANGED = 1736, + SET_FREE_TRIAL_RENAME_AVAILABLE = 1737, + SET_PROJECTILE_LAUNCHER_PARAMS = 1738, + RACE_PRECOUNTDOWN_DONE = 1739, + CHECK_INVITE_SPAMMING = 1740, + GET_RESPAWN_VOLUME_INFO = 1741, + INVITE_ACCEPTED = 1742, + TELEPORT_TO_NEAREST_RESPAWN = 1743, + SET_SKILL_CANCEL_ON_MOVE = 1744, + CANCEL_MOVE_SKILL = 1745, + SERVER_CANCEL_MOVE_SKILL = 1746, + CLIENT_CANCEL_MOVE_SKILL = 1747, + END_LAUNCH_SEQUENCE = 1748, + CANCEL_QUEUE = 1749, + UPDATE_PROJECTILE_LAUNCHER_ROTATION = 1750, + GET_CHARACTER_VERSION_INFO = 1751, + GET_CON_INFO = 1753, + GET_SKILLS_FOR_LOT = 1755, + DISMOUNT_COMPLETE = 1756, + MOUNT_FAILURE_RESPONSE = 1757, + CLEAR_BILLBOARD_OFFSET = 1758, + GET_INVENTORY_ITEM_ANIMATION_FLAG = 1759, + SET_JET_PACK_ALLOWED = 1760, + GET_BUILD_TIME_DETAILS = 1761, + USE_SKILL_SET = 1762, + SET_SKILL_SET_POSSESSOR = 1763, + POPULATE_ACTION_BAR = 1764, + GET_COMPONENT_TEMPLATE_ID = 1765, + GET_POSSESSABLE_SKILL_SET = 1766, + MARK_INVENTORY_ITEM_AS_ACTIVE = 1767, + UPDATE_FORGED_ITEM = 1768, + CAN_ITEMS_BE_REFORGED = 1769, + NOTIFY_CLIENT_RAIL_START_FAILED = 1771, + GET_IS_ON_RAIL = 1772 + }; +} + +template <> +struct magic_enum::customize::enum_range { + static constexpr int min = 0; + static constexpr int max = 1772; +}; diff --git a/dCommon/dEnums/MessageType/Master.h b/dCommon/dEnums/MessageType/Master.h new file mode 100644 index 000000000..b6054d7fa --- /dev/null +++ b/dCommon/dEnums/MessageType/Master.h @@ -0,0 +1,34 @@ +#pragma once +#include + +namespace MessageType { + enum class Master : uint32_t { + REQUEST_PERSISTENT_ID = 1, + REQUEST_PERSISTENT_ID_RESPONSE, + REQUEST_ZONE_TRANSFER, + REQUEST_ZONE_TRANSFER_RESPONSE, + SERVER_INFO, + REQUEST_SESSION_KEY, + SET_SESSION_KEY, + SESSION_KEY_RESPONSE, + PLAYER_ADDED, + PLAYER_REMOVED, + + CREATE_PRIVATE_ZONE, + REQUEST_PRIVATE_ZONE, + + WORLD_READY, + PREP_ZONE, + + SHUTDOWN, + SHUTDOWN_RESPONSE, + SHUTDOWN_IMMEDIATE, + + SHUTDOWN_UNIVERSE, + + AFFIRM_TRANSFER_REQUEST, + AFFIRM_TRANSFER_RESPONSE, + + NEW_SESSION_ALERT + }; +} diff --git a/dCommon/dEnums/MessageType/Server.h b/dCommon/dEnums/MessageType/Server.h new file mode 100644 index 000000000..8a75153c7 --- /dev/null +++ b/dCommon/dEnums/MessageType/Server.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace MessageType { + //! The Internal Server Packet Identifiers + enum class Server : uint32_t { + VERSION_CONFIRM = 0, + DISCONNECT_NOTIFY, + GENERAL_NOTIFY + }; +} diff --git a/dCommon/dEnums/MessageType/World.h b/dCommon/dEnums/MessageType/World.h new file mode 100644 index 000000000..acca62466 --- /dev/null +++ b/dCommon/dEnums/MessageType/World.h @@ -0,0 +1,49 @@ +#pragma once +#include + +#include "magic_enum.hpp" + +namespace MessageType { + enum class World : uint32_t { + VALIDATION = 1, // Session info + CHARACTER_LIST_REQUEST, + CHARACTER_CREATE_REQUEST, + LOGIN_REQUEST, // Character selected + GAME_MSG, + CHARACTER_DELETE_REQUEST, + CHARACTER_RENAME_REQUEST, + HAPPY_FLOWER_MODE_NOTIFY, + SLASH_RELOAD_MAP, // Reload map cmp + SLASH_PUSH_MAP_REQUEST, // Push map req cmd + SLASH_PUSH_MAP, // Push map cmd + SLASH_PULL_MAP, // Pull map cmd + LOCK_MAP_REQUEST, + GENERAL_CHAT_MESSAGE, // General chat message + HTTP_MONITOR_INFO_REQUEST, + SLASH_DEBUG_SCRIPTS, // Debug scripts cmd + MODELS_CLEAR, + EXHIBIT_INSERT_MODEL, + LEVEL_LOAD_COMPLETE, // Character data request + TMP_GUILD_CREATE, + ROUTE_PACKET, // Social? + POSITION_UPDATE, + MAIL, + WORD_CHECK, // AllowList word check + STRING_CHECK, // AllowList string check + GET_PLAYERS_IN_ZONE, + REQUEST_UGC_MANIFEST_INFO, + BLUEPRINT_GET_ALL_DATA_REQUEST, + CANCEL_MAP_QUEUE, + HANDLE_FUNNESS, + FAKE_PRG_CSR_MESSAGE, + REQUEST_FREE_TRIAL_REFRESH, + GM_SET_FREE_TRIAL_STATUS, + UI_HELP_TOP_5 = 91 + }; +} + +template <> +struct magic_enum::customize::enum_range { + static constexpr int min = 0; + static constexpr int max = 91; +}; diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index 7cdbfdb6a..70eb1dc9e 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -8,7 +8,7 @@ #include #include "BitStream.h" #include "eConnectionType.h" -#include "eClientMessageType.h" +#include "MessageType/Client.h" #include "BitStreamUtils.h" #pragma warning (disable:4251) //Disables SQL warnings @@ -33,7 +33,7 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate); #define CBITSTREAM RakNet::BitStream bitStream; #define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false); #define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits()); -#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); +#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::GAME_MSG); #define SEND_PACKET Game::server->Send(bitStream, sysAddr, false); #define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); diff --git a/dCommon/dEnums/eAninmationFlags.h b/dCommon/dEnums/eAnimationFlags.h similarity index 100% rename from dCommon/dEnums/eAninmationFlags.h rename to dCommon/dEnums/eAnimationFlags.h diff --git a/dCommon/dEnums/eAuthMessageType.h b/dCommon/dEnums/eAuthMessageType.h deleted file mode 100644 index ecc17a37b..000000000 --- a/dCommon/dEnums/eAuthMessageType.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __EAUTHMESSAGETYPE__H__ -#define __EAUTHMESSAGETYPE__H__ - -#include - -enum class eAuthMessageType : uint32_t { - LOGIN_REQUEST = 0, - LOGOUT_REQUEST, - CREATE_NEW_ACCOUNT_REQUEST, - LEGOINTERFACE_AUTH_RESPONSE, - SESSIONKEY_RECEIVED_CONFIRM, - RUNTIME_CONFIG -}; - -#endif //!__EAUTHMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eCharacterVersion.h b/dCommon/dEnums/eCharacterVersion.h index 0fab4498e..683951e31 100644 --- a/dCommon/dEnums/eCharacterVersion.h +++ b/dCommon/dEnums/eCharacterVersion.h @@ -15,7 +15,8 @@ enum class eCharacterVersion : uint32_t { // Fixes vault size value VAULT_SIZE, // Fixes speed base value in level component - UP_TO_DATE, // will become SPEED_BASE + SPEED_BASE, + UP_TO_DATE, // will become NJ_JAYMISSIONS }; #endif //!__ECHARACTERVERSION__H__ diff --git a/dCommon/dEnums/eChatInternalMessageType.h b/dCommon/dEnums/eChatInternalMessageType.h deleted file mode 100644 index d3b7020b3..000000000 --- a/dCommon/dEnums/eChatInternalMessageType.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __ECHATINTERNALMESSAGETYPE__H__ -#define __ECHATINTERNALMESSAGETYPE__H__ - -#include - -enum eChatInternalMessageType : uint32_t { - PLAYER_ADDED_NOTIFICATION = 0, - PLAYER_REMOVED_NOTIFICATION, - ADD_FRIEND, - ADD_BEST_FRIEND, - ADD_TO_TEAM, - ADD_BLOCK, - REMOVE_FRIEND, - REMOVE_BLOCK, - REMOVE_FROM_TEAM, - DELETE_TEAM, - REPORT, - PRIVATE_CHAT, - PRIVATE_CHAT_RESPONSE, - ANNOUNCEMENT, - MAIL_COUNT_UPDATE, - MAIL_SEND_NOTIFY, - REQUEST_USER_LIST, - FRIEND_LIST, - ROUTE_TO_PLAYER, - TEAM_UPDATE, - MUTE_UPDATE, - CREATE_TEAM, -}; - -#endif //!__ECHATINTERNALMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eChatMessageType.h b/dCommon/dEnums/eChatMessageType.h deleted file mode 100644 index 52895ba3e..000000000 --- a/dCommon/dEnums/eChatMessageType.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef __ECHATMESSAGETYPE__H__ -#define __ECHATMESSAGETYPE__H__ - -#include - -//! The Internal Chat Packet Identifiers -enum class eChatMessageType :uint32_t { - LOGIN_SESSION_NOTIFY = 0, - GENERAL_CHAT_MESSAGE, - PRIVATE_CHAT_MESSAGE, - USER_CHANNEL_CHAT_MESSAGE, - WORLD_DISCONNECT_REQUEST, - WORLD_PROXIMITY_RESPONSE, - WORLD_PARCEL_RESPONSE, - ADD_FRIEND_REQUEST, - ADD_FRIEND_RESPONSE, - REMOVE_FRIEND, - GET_FRIENDS_LIST, - ADD_IGNORE, - REMOVE_IGNORE, - GET_IGNORE_LIST, - TEAM_MISSED_INVITE_CHECK, - TEAM_INVITE, - TEAM_INVITE_RESPONSE, - TEAM_KICK, - TEAM_LEAVE, - TEAM_SET_LOOT, - TEAM_SET_LEADER, - TEAM_GET_STATUS, - GUILD_CREATE, - GUILD_INVITE, - GUILD_INVITE_RESPONSE, - GUILD_LEAVE, - GUILD_KICK, - GUILD_GET_STATUS, - GUILD_GET_ALL, - SHOW_ALL, - BLUEPRINT_MODERATED, - BLUEPRINT_MODEL_READY, - PROPERTY_READY_FOR_APPROVAL, - PROPERTY_MODERATION_CHANGED, - PROPERTY_BUILDMODE_CHANGED, - PROPERTY_BUILDMODE_CHANGED_REPORT, - MAIL, - WORLD_INSTANCE_LOCATION_REQUEST, - REPUTATION_UPDATE, - SEND_CANNED_TEXT, - GMLEVEL_UPDATE, - CHARACTER_NAME_CHANGE_REQUEST, - CSR_REQUEST, - CSR_REPLY, - GM_KICK, - GM_ANNOUNCE, - GM_MUTE, - ACTIVITY_UPDATE, - WORLD_ROUTE_PACKET, - GET_ZONE_POPULATIONS, - REQUEST_MINIMUM_CHAT_MODE, - REQUEST_MINIMUM_CHAT_MODE_PRIVATE, - MATCH_REQUEST, - UGCMANIFEST_REPORT_MISSING_FILE, - UGCMANIFEST_REPORT_DONE_FILE, - UGCMANIFEST_REPORT_DONE_BLUEPRINT, - UGCC_REQUEST, - WHO, - WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE, - ACHIEVEMENT_NOTIFY, - GM_CLOSE_PRIVATE_CHAT_WINDOW, - UNEXPECTED_DISCONNECT, - PLAYER_READY, - GET_DONATION_TOTAL, - UPDATE_DONATION, - PRG_CSR_COMMAND, - HEARTBEAT_REQUEST_FROM_WORLD, - UPDATE_FREE_TRIAL_STATUS -}; - -#endif //!__ECHATMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eClientMessageType.h b/dCommon/dEnums/eClientMessageType.h deleted file mode 100644 index aafccc363..000000000 --- a/dCommon/dEnums/eClientMessageType.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef __ECLIENTMESSAGETYPE__H__ -#define __ECLIENTMESSAGETYPE__H__ - -#include - -enum class eClientMessageType : uint32_t { - LOGIN_RESPONSE = 0, - LOGOUT_RESPONSE, - LOAD_STATIC_ZONE, - CREATE_OBJECT, - CREATE_CHARACTER, - CREATE_CHARACTER_EXTENDED, - CHARACTER_LIST_RESPONSE, - CHARACTER_CREATE_RESPONSE, - CHARACTER_RENAME_RESPONSE, - CHAT_CONNECT_RESPONSE, - AUTH_ACCOUNT_CREATE_RESPONSE, - DELETE_CHARACTER_RESPONSE, - GAME_MSG, - CONNECT_CHAT, - TRANSFER_TO_WORLD, - IMPENDING_RELOAD_NOTIFY, - MAKE_GM_RESPONSE, - HTTP_MONITOR_INFO_RESPONSE, - SLASH_PUSH_MAP_RESPONSE, - SLASH_PULL_MAP_RESPONSE, - SLASH_LOCK_MAP_RESPONSE, - BLUEPRINT_SAVE_RESPONSE, - BLUEPRINT_LUP_SAVE_RESPONSE, - BLUEPRINT_LOAD_RESPONSE_ITEMID, - BLUEPRINT_GET_ALL_DATA_RESPONSE, - MODEL_INSTANTIATE_RESPONSE, - DEBUG_OUTPUT, - ADD_FRIEND_REQUEST, - ADD_FRIEND_RESPONSE, - REMOVE_FRIEND_RESPONSE, - GET_FRIENDS_LIST_RESPONSE, - UPDATE_FRIEND_NOTIFY, - ADD_IGNORE_RESPONSE, - REMOVE_IGNORE_RESPONSE, - GET_IGNORE_LIST_RESPONSE, - TEAM_INVITE, - TEAM_INVITE_INITIAL_RESPONSE, - GUILD_CREATE_RESPONSE, - GUILD_GET_STATUS_RESPONSE, - GUILD_INVITE, - GUILD_INVITE_INITIAL_RESPONSE, - GUILD_INVITE_FINAL_RESPONSE, - GUILD_INVITE_CONFIRM, - GUILD_ADD_PLAYER, - GUILD_REMOVE_PLAYER, - GUILD_LOGIN_LOGOUT, - GUILD_RANK_CHANGE, - GUILD_DATA, - GUILD_STATUS, - MAIL, - DB_PROXY_RESULT, - SHOW_ALL_RESPONSE, - WHO_RESPONSE, - SEND_CANNED_TEXT, - UPDATE_CHARACTER_NAME, - SET_NETWORK_SIMULATOR, - INVALID_CHAT_MESSAGE, - MINIMUM_CHAT_MODE_RESPONSE, - MINIMUM_CHAT_MODE_RESPONSE_PRIVATE, - CHAT_MODERATION_STRING, - UGC_MANIFEST_RESPONSE, - IN_LOGIN_QUEUE, - SERVER_STATES, - GM_CLOSE_TARGET_CHAT_WINDOW, - GENERAL_TEXT_FOR_LOCALIZATION, - UPDATE_FREE_TRIAL_STATUS, - UGC_DOWNLOAD_FAILED = 120 -}; - -#endif //!__ECLIENTMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eConnectionType.h b/dCommon/dEnums/eConnectionType.h index ce1ff90cd..406110a9e 100644 --- a/dCommon/dEnums/eConnectionType.h +++ b/dCommon/dEnums/eConnectionType.h @@ -5,8 +5,7 @@ enum class eConnectionType : uint16_t { SERVER = 0, AUTH, CHAT, - CHAT_INTERNAL, - WORLD, + WORLD = 4, CLIENT, MASTER }; diff --git a/dCommon/dEnums/eGameMessageType.h b/dCommon/dEnums/eGameMessageType.h deleted file mode 100644 index e3fc22b6b..000000000 --- a/dCommon/dEnums/eGameMessageType.h +++ /dev/null @@ -1,1613 +0,0 @@ -#ifndef __EGAMEMESSAGETYPE__H__ -#define __EGAMEMESSAGETYPE__H__ - -#include - -#include "magic_enum.hpp" - -enum class eGameMessageType : uint16_t { - GET_POSITION = 0, - GET_ROTATION = 1, - GET_LINEAR_VELOCITY = 2, - GET_ANGULAR_VELOCITY = 3, - GET_FORWARD_VELOCITY = 4, - GET_PLAYER_FORWARD = 5, - GET_FORWARD_VECTOR = 6, - SET_POSITION = 7, - SET_LOCAL_POSITION = 8, - SET_ROTATION = 9, - SET_LINEAR_VELOCITY = 10, - MODIFY_LINEAR_VELOCITY = 11, - SET_ANGULAR_VELOCITY = 12, - MODIFY_ANGULAR_VELOCITY = 13, - DEFLECT = 14, - SEND_POSITION_UPDATE = 15, - SET_OBJECT_SCALE = 16, - GET_OBJECT_SCALE = 17, - TIMED_SCALE_FINISHED = 18, - TELEPORT = 19, - TOGGLE_PLAYER_FWD_TO_CAMERA = 20, - LOCK_PLAYER_ROT_TO_CAMERA = 21, - UNLOCK_PLAYER_ROT_FROM_CAMERA = 22, - TOGGLE_PLAYER_ROT_LOCK_TO_MOUSE = 23, - LOCK_PLAYER_ROT_TO_MOUSE = 24, - UNLOCK_PLAYER_ROT_FROM_MOUSE = 25, - SET_PLAYER_CONTROL_SCHEME = 26, - GET_PLAYER_CONTROL_SCHEME = 27, - RESET_PLAYER_CONTROL_SCHEME = 28, - PLAYER_TO_PREVIOUS_CONTROL_SCHEME = 29, - DROP_CLIENT_LOOT = 30, - GET_SPEED = 34, - GET_ROT_SPEED = 35, - IS_DEAD = 36, - DIE = 37, - REQUEST_DIE = 38, - ADD_OBJECT = 39, - PLAY_EMOTE = 41, - PRELOAD_ANIMATION = 42, - PLAY_ANIMATION = 43, - ANIMATION_COMPLETE = 44, - ENABLE_HIGHLIGHT = 45, - DISABLE_HIGHLIGHT = 46, - GET_ANIMATION_NAMES = 47, - CONTROL_BEHAVIORS = 48, - BLEND_PRIMARY_ANIMATION = 52, - SET_OFFSCREEN_ANIMATION = 53, - GET_MOVEMENT_INPUT_VALUES = 54, - SWAP_TEXTURE = 55, - SWAP_COLOR = 56, - ATTACH_HAIR = 57, - GET_ENTITY_STRUCT = 58, - SET_ENTITY_STRUCT = 59, - SET_ATTR = 60, - GET_ATTR = 61, - ON_HIT = 62, - HIT_OR_HEAL_RESULT = 63, - SHOW_ATTACK = 64, - GO_TO = 65, - GET_CONFIG_DATA = 66, - SET_CONFIG_DATA = 68, - GET_INVENTORY_EXTRA_INFO = 69, - GET_DISPLAY_NAME = 70, - GET_NAME = 71, - SET_NAME = 72, - IS_NAME_LOCALIZED = 73, - GET_HAIR_COLOR = 74, - SET_HAIR_COLOR = 75, - GET_HAIR_STYLE = 76, - SET_HAIR_STYLE = 77, - GET_HEAD = 78, - SET_HEAD = 79, - GET_TORSO = 80, - SET_TORSO = 81, - GET_LEGS = 82, - SET_LEGS = 83, - SET_PROXIMITY_RADIUS = 84, - PROXIMITY_UPDATE = 85, - GET_PROXIMITY_OBJECTS = 86, - UNSET_PROXIMITY_RADIUS = 87, - CLEAR_PROXIMITY_RADIUS = 88, - GET_PROXIMITY_DATA = 89, - SET_PROXIMITY_RADIUS_ICON = 90, - TOGGLE_TAC_ARC = 93, - CAST_SKILL = 95, - CAST_LOCAL_SKILL = 96, - ECHO_LOCAL_SKILL = 97, - QUEUE_AI_SKILL = 98, - ADD_THREAT_RATING = 99, - GET_THREAT_RATING = 100, - CLEAR_THREAT_LIST = 103, - GET_TIME_FOR_NPC_SKILL = 111, - ENEMY_HEAL_NOTIFICATION = 112, - RESET_SCRIPTED_AI_STATE = 113, - ENABLE_COMBAT_AI_COMPONENT = 114, - COMBAT_AI_FORCE_TETHER = 115, - SUSPEND_MOVEMENT_AI = 116, - NOTIFY_SCRIPT_VARS_INITIALIZED = 117, - ECHO_START_SKILL = 118, - START_SKILL = 119, - CASTER_DEAD = 120, - VERIFY_ACK = 121, - ADD_PENDING_VERIFY = 122, - MAP_SKILL = 123, - SELECT_SKILL = 124, - CAST_ACTIVE_SKILL = 125, - MODIFY_SKILL_COOLDOWN = 126, - ADD_SKILL = 127, - REMOVE_SKILL = 128, - LOG = 129, - LOG_CHAT = 130, - SET_MAX_CURRENCY = 131, - GET_MAX_CURRENCY = 132, - SET_CURRENCY = 133, - GET_CURRENCY = 134, - ADD_PENDING_CURRENCY = 136, - PICKUP_CURRENCY = 137, - SERVER_DELETE_LOOT_ITEM = 138, - PICKUP_ITEM = 139, - TEAM_PICKUP_ITEM = 140, - CLIENT_DELETE_LOOT_ITEM = 141, - CLIENT_SET_LOOT_ITEM_FFA = 143, - COLLISION_PHANTOM = 144, - OFF_COLLISION_PHANTOM = 145, - COLLISION_PROXIMITY = 146, - OFF_COLLISION_PROXIMITY = 147, - COLLISION = 148, - OFF_COLLISION = 149, - GET_SKILLS = 150, - CLEAR_FX_SINGLE_EFFECT = 152, - GET_FX_EXIST_EFFECT = 153, - PLAY_FX_EFFECT = 154, - STOP_FX_EFFECT = 155, - CLEAR_FX_ALL_CREATE_EFFECTS = 156, - UPDATE_FX_ALL_CREATE_EFFECTS = 157, - REQUEST_RESURRECT = 159, - RESURRECT = 160, - UPDATE_FROM_GHOST = 162, - FETCH_GHOST = 163, - KFM_LOADED = 164, - NIF_LOADED = 165, - HKX_LOADED = 166, - MOVE_TO_DELETE_QUEUE = 167, - RESTORE_FROM_DELETE_QUEUE = 168, - IS_ENEMY = 169, - GET_FACTION = 170, - SET_IMAGINATION = 171, - GET_IMAGINATION = 172, - SET_MAX_IMAGINATION = 173, - GET_MAX_IMAGINATION = 174, - MODIFY_IMAGINATION = 175, - MODIFY_MAX_IMAGINATION = 176, - SET_HEALTH = 177, - GET_HEALTH = 178, - SET_MAX_HEALTH = 179, - GET_MAX_HEALTH = 180, - MODIFY_HEALTH = 181, - MODIFY_MAX_HEALTH = 182, - SET_ARMOR = 183, - GET_ARMOR = 184, - SET_MAX_ARMOR = 185, - GET_MAX_ARMOR = 186, - MODIFY_ARMOR = 187, - MODIFY_MAX_ARMOR = 188, - POP_HEALTH_STATE = 190, - PUSH_EQUIPPED_ITEMS_STATE = 191, - POP_EQUIPPED_ITEMS_STATE = 192, - SET_GM_LEVEL = 193, - GET_GM_LEVEL = 194, - ADD_STATUS_EFFECT = 196, - REMOVE_STATUS_EFFECT = 197, - SET_STUNNED = 198, - GET_STUNNED = 199, - SET_STUN_IMMUNITY = 200, - GET_STUN_IMMUNITY = 201, - KNOCKBACK = 202, - SET_VISIBLE = 203, - GET_VISIBLE = 204, - REPORT_ITEM_INFO = 205, - GET_REBUILD_STATE = 207, - REBUILD_CANCEL = 209, - REBUILD_START = 211, - ENABLE_REBUILD = 213, - SKILL_FAILURE = 214, - IS_ATTACK_STANCE = 216, - SET_OBJECT_RENDER = 217, - REQUEST_MAPPED_SKILLS = 218, - UI_SELECT_MAPPED_SKILL = 219, - GET_INVENTORY_ITEM_IN_SLOT = 220, - GET_FIRST_INVENTORY_ITEM_BY_LOT = 221, - GET_SMALLEST_INVENTORY_STACK_BY_LOT = 222, - MOVE_ITEM_IN_INVENTORY = 224, - ADD_ITEM_TO_INVENTORY_CLIENT_SYNC = 227, - GET_EQUIPPED_ITEMS = 229, - REMOVE_ITEM_FROM_INVENTORY = 230, - EQUIP_INVENTORY = 231, - UN_EQUIP_INVENTORY = 233, - EQUIP_ITEM = 234, - UN_EQUIP_ITEM = 235, - IS_ITEM_RESPOND = 236, - IS_ITEM_EQUIPPED = 237, - ATTACH_ITEM = 238, - DETACH_ITEM = 239, - GET_NODE = 240, - GET_LOT = 241, - IS_ITEM_EQUIPPABLE = 242, - GET_CURRENT_ANIMATION = 243, - GET_INV_ITEM_COUNT = 244, - POST_LOAD_EQUIP = 245, - SET_PHYSICS_ACTIVE_STATE = 246, - GET_CURRENT_SKILL_TAC_ARC = 247, - OFFER_MISSION = 248, - RESPOND_TO_MISSION = 249, - GET_MISSION_STATE = 250, - GET_MISSION_COMPLETE_TIMESTAMP = 251, - NOTIFY_MISSION = 254, - NOTIFY_MISSION_TASK = 255, - ARE_GFX_LOADED = 257, - ADDED_TO_WORLD = 258, - REMOVE_EXTRA_GFX_FROM_PIPE = 259, - HIDE_EQUIPED_WEAPON = 260, - UN_HIDE_EQUIPED_WEAPON = 261, - GET_ITEM_SLOT = 262, - IS_CHARACTER = 263, - SET_IMMUNITY = 264, - TOGGLE_TOOLTIPS = 266, - GET_TOOLTIPS_DISABLED = 267, - GET_BOUNDING_INFO = 268, - OVERRIDE_BOUNDING_RADIUS = 269, - GET_OFFSCREEN = 270, - USE_STATE_MACHINE = 271, - ADD_STATE = 272, - ADD_SUB_STATE = 273, - SET_STATE = 274, - SET_SUB_STATE = 275, - ADD_MESSAGE = 276, - RELOAD_SCRIPT = 277, - RELOAD_ALL_SCRIPTS = 278, - FRIEND_INVITE_MSG = 279, - ADD_FRIEND_REPOSNSE_MSG = 280, - REMOVE_FRIEND_RESPONSE_MSG = 281, - ADD_FRIEND_FROM_UI_MSG = 282, - GET_CACHED_FRIENDS_LIST_MSG = 283, - REQUEST_NEW_FRIENDS_LIST_MSG = 284, - REPOPULATE_FRIENDS_LIST_MSG = 285, - ADD_IGNORE_REPONSE_MSG = 286, - REMOVE_IGNORE_RESPONSE_MSG = 287, - ADD_IGNORE_FROM_UI_MSG = 288, - GET_CACHED_IGNORE_LIST_MSG = 289, - REQUEST_NEW_IGNORE_LIST_MSG = 290, - REMOVE_FRIEND_BY_NAME = 291, - REMOVE_IGNORE_BY_NAME = 292, - IS_PLAYER_IN_IGNORE_LIST_MSG = 293, - REPOPULATE_IGNORE_LIST_MSG = 294, - GET_INVENTORY_LIST = 295, - UPDATE_FRIEND_MSG = 296, - UPDATE_FRIEND_NAME_MSG = 297, - UPDATE_IGNORE_NAME_MSG = 298, - DEPARTED = 299, - ARRIVED = 300, - TEMPLATE_CHANGE_WAYPOINTS = 301, - CANCELLED = 302, - FLUSH_CACHED_GRAPHICS = 303, - FOLLOW_TARGET = 304, - TIMER_DONE = 305, - TIMER_CANCELLED = 306, - SET_TETHER_POINT = 307, - GET_TETHER_POINT = 308, - LEFT_TETHER_RADIUS = 309, - GET_SCRIPT_VARS_PTR = 310, - FACE_TARGET = 311, - ROTATE_BY_DEGREES = 312, - STRING_RENDERED = 313, - RESET_PRIMARY_ANIMATION = 314, - FACE_PLAY_STREAM = 315, - TORSO_PLAY_STREAM = 316, - CAN_PICKUP = 317, - GET_INVENTORY_SIZE = 318, - GET_INVENTORY_COUNT = 319, - GET_OBJECTS_IN_GROUP = 320, - HIDE_ITEM = 321, - IS_OBJECT_IN_FOV = 322, - GET_TYPE = 323, - TEAM_INVITE_MSG = 324, - TEAM_GET_SIZE = 325, - TEAM_REQUEST_SET_LOOT = 326, - TEAM_REMOVE_PLAYER_MSG = 327, - TEAM_UPDATE_PLAYER_NAME_MSG = 328, - SET_UPDATABLE = 329, - REQUEST_TEAM_UI_UPDATE = 330, - SET_COLLISION_GROUP = 331, - GET_COLLISION_GROUP = 332, - GET_ORIGINAL_COLLISION_GROUP = 333, - SET_COLLISION_GROUP_TO_ORIGINAL = 334, - GET_OBJECT_RADIUS = 335, - REBUILD_NOTIFY_STATE = 336, - GET_PLAYER_INTERACTION = 337, - SET_PLAYER_INTERACTION = 338, - FORCE_PLAYER_TO_INTERACT = 339, - GET_SELECTED_POTENTIAL_INTERACTION = 340, - SET_SELECTED_POTENTIAL_INTERACTION = 341, - GET_INTERACTION_DISTANCE = 342, - SET_INTERACTION_DISTANCE = 343, - CALCULATE_INTERACTION_DISTANCE = 344, - INTERACTION_ATTEMPT_FROM_OUT_OF_RANGE = 345, - SET_PICKING_TARGET = 346, - CLIENT_UNUSE = 347, - BEGIN_PET_INTERACTION = 348, - WANTS_INTERACTION_ICON = 349, - PROPERTY_EDIT_ICON_INTERACTION = 350, - PROPERTY_MODEL_INTERACTION = 351, - GET_INTERACTION_DETAILS = 352, - GET_DISABLED_INTERACTION_TYPES = 353, - GET_INTERACTION_INFO = 354, - INTERACTION_GAME_STATE_CHANGE = 355, - TOGGLE_INTERACTION_UPDATES = 356, - TERMINATE_INTERACTION = 357, - SERVER_TERMINATE_INTERACTION = 358, - GET_PLAYERS_TARGET_FOR_SELECTION = 359, - PROCESS_INTERACTION_UNDER_CURSOR = 360, - HANDLE_INTERACT_ACTION = 361, - ATTEMPT_INTERACTION = 362, - HANDLE_INTERACTION_CAMERA = 363, - REQUEST_USE = 364, - CLIENT_USE = 366, - GET_PLAYER_MULTI_INTERACTION = 367, - GET_MULTI_INTERACTION_STATE = 368, - VENDOR_OPEN_WINDOW = 369, - VENDOR_CLOSE_WINDOW = 370, - EMOTE_PLAYED = 371, - EMOTE_RECEIVED = 372, - BUY_FROM_VENDOR = 373, - SELL_TO_VENDOR = 374, - ADD_DONATION_ITEM = 375, - REMOVE_DONATION_ITEM = 376, - CONFIRM_DONATION_ON_PLAYER = 378, - CANCEL_DONATION_ON_PLAYER = 379, - TEAM_GET_LEADER = 380, - TEAM_GET_ON_WORLD_MEMBERS = 381, - TEAM_GET_ALL_MEMBERS = 382, - TEAM_SET_OFF_WORLD_FLAG = 383, - SET_TRANSPARENCY = 385, - GET_PREFERS_FADE = 386, - PROJECTILE_IMPACT = 387, - SET_PROJECTILE_PARAMS = 388, - SET_INVENTORY_SIZE = 389, - ACKNOWLEDGE_POSSESSION = 391, - SET_POSSESSED_OBJECT = 392, - CHANGE_POSSESSOR = 393, - GET_POSSESSION_TYPE = 395, - GET_POSSESSED_OBJECT = 396, - GET_POSSESSOR = 397, - IS_POSSESSED = 398, - ENABLE_ACTIVITY = 399, - SET_SHOOTING_GALLERY_PARAMS = 400, - OPEN_ACTIVITY_START_DIALOG = 401, - REQUEST_ACTIVITY_START_STOP = 402, - REQUEST_ACTIVITY_ENTER = 403, - REQUEST_ACTIVITY_EXIT = 404, - ACTIVITY_ENTER = 405, - ACTIVITY_EXIT = 406, - ACTIVITY_START = 407, - ACTIVITY_STOP = 408, - SHOOTING_GALLERY_CLIENT_AIM_UPDATE = 409, - ROTATE_TO_POINT = 410, - SHOOTING_GALLERY_FIRE = 411, - CALCULATE_FIRING_PARAMETERS = 412, - GET_MUZZLE_OFFSET = 413, - GET_ACTIVITY_POINTS = 414, - TEAM_IS_ON_WORLD_MEMBER = 415, - REQUEST_VENDOR_STATUS_UPDATE = 416, - VENDOR_STATUS_UPDATE = 417, - CANCEL_MISSION = 418, - RESET_MISSIONS = 419, - RENDER_COMPONENT_READY = 420, - SEND_MINIFIG_DECALS = 421, - PHYSICS_COMPONENT_READY = 422, - ENTER_STANDBY_MODE = 423, - LEAVE_STANDBY_MODE = 424, - NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE = 425, - REQUEST_CONSUME_ITEM = 426, - CONSUME_CLIENT_ITEM = 427, - CLIENT_ITEM_CONSUMED = 428, - QUERY_STANDBY_MODE = 429, - GET_NI_BOUND = 430, - MISSION_FAILURE = 431, - GET_ANIMATION_TIME = 432, - GET_CURRENT_ACTIVITY = 434, - SET_EYEBROWS = 435, - GET_EYEBROWS = 436, - SET_EYES = 437, - GET_EYES = 438, - SET_MOUTH = 439, - GET_MOUTH = 440, - IS_OBJECT_SMASHABLE = 441, - SMASHABLE_STATE_CHANGED = 443, - USE_STATE_LOGGER = 444, - ROTATE_SUB_NODE = 445, - GET_SUB_NODE_POSITION = 446, - GET_SUB_NODE = 447, - UPDATE_SHOOTING_GALLERY_ROTATION = 448, - RENDER_FLOATING_TEXT = 449, - REQUEST2_D_TEXT_ELEMENT = 450, - UPDATE2_D_TEXT_ELEMENT = 451, - REMOVE2_D_TEXT_ELEMENT = 452, - SET_COLOR = 453, - GET_COLOR = 454, - HKX_CHARACTER_LOADED = 455, - ACTIVATE_PHYSICS = 457, - SET_ICON_ABOVE_HEAD = 458, - ADD_ICON_COMPOSITE = 459, - CLEAR_ICON_COMPOSITES = 460, - ICON_NIF_LOADED = 461, - ICON_KFM_LOADED = 462, - GET_OVERHEAD_ICON_PROPERTIES_FROM_PARENT = 463, - BOUNCE_PLAYER = 464, - SET_USER_CTRL_COMP_PAUSE = 466, - HAS_COLLIDED = 467, - GET_TOOLTIP_FLAG = 468, - SET_TOOLTIP_FLAG = 469, - GET_FLAG = 470, - SET_FLAG = 471, - NOTIFY_CLIENT_FLAG_CHANGE = 472, - CURSOR_ON = 473, - CURSOR_OFF = 474, - HELP = 475, - VENDOR_TRANSACTION_RESULT = 476, - PERFORM_SPECIAL_DEATH = 477, - GET_SHADER_ID = 478, - GET_RENDER_ENVIRONMENT = 479, - FINISHED_LOADING_SCENE = 480, - GET_SKILL_INFO = 481, - ACTIVITY_CANCEL = 482, - MISSION_USES_OBJECT = 483, - GET_POSITIONAL_ID = 484, - SET_COLLECTIBLE_STATUS = 485, - HAS_BEEN_COLLECTED = 486, - HAS_BEEN_COLLECTED_BY_CLIENT = 487, - GET_POS_UPDATE_STATS = 488, - GET_NUM_VIEWERS_SCOPING_THIS = 489, - GET_ACTIVITY_USER = 490, - GET_ALL_ACTIVITY_USERS = 491, - GET_MISSION_FOR_PLAYER = 492, - SET_FACTION = 493, - SET_PLATFORM_IDLE_STATE = 494, - DISPLAY_CHAT_BUBBLE = 495, - REQUEST_CHAT_BUBBLE_ELEMENT = 496, - GET_MISSION_DATA = 497, - SPAWN_PET = 498, - DESPAWN_PET = 499, - SET_LOCAL_SPACE_STATE = 500, - GET_LOCAL_SPACE_STATE = 501, - SET_POSITION_TO_LOCAL_POSITION = 502, - ALLOW_LOCAL_SPACE_UPDATE = 503, - TOGGLE_FREE_CAM_MODE = 504, - PLAYER_LOADED = 505, - PLAYER_ADDED_TO_WORLD_LOCAL = 506, - OBJECT_LOADED = 507, - GET_PLAYER_READY = 508, - PLAYER_READY = 509, - SET_SMASHABLE_PARAMS = 510, - IS_LOOTABLE_CHEST = 511, - LOOT_OPEN_WINDOW = 512, - LOOT_SELECTION_UPDATE = 513, - TAKE_LOOT_CHEST_ITEM = 514, - REQUEST_LINKED_MISSION = 515, - TRANSFER_TO_ZONE = 516, - TRANSFER_TO_ZONE_CHECKED_IM = 517, - SECURED_TRANSFER_TO_ZONE = 518, - INVALID_ZONE_TRANSFER_LIST = 519, - MISSION_DIALOGUE_OK = 520, - GET_OBJECT_IN_SCOPE = 521, - SET_LAUNCHED_STATE = 522, - P_CREATE_EFFECT_FINISHED = 523, - SMASHED_OBJECT = 524, - CHECK_SMASHCHAIN_OVERRIDE = 525, - DISPLAY_REBUILD_ACTIVATOR = 526, - TRANSFER_TO_LAST_NON_INSTANCE = 527, - SET_ACTIVE_LOCAL_CHARACTER_ID = 528, - DISPLAY_MESSAGE_BOX = 529, - MESSAGE_BOX_RESPOND = 530, - CHOICE_BOX_RESPOND = 531, - SERVER_SET_USER_CTRL_COMP_PAUSE = 532, - SET_CHARACTER_AUTO_RUN = 533, - FOLLOW_WAYPOINTS = 534, - SWAP_DECAL_AND_COLOR = 535, - CONTINUE_WAYPOINTS = 536, - SMASH = 537, - UN_SMASH = 538, - GET_IS_SMASHED = 539, - GET_UP_VECTOR = 540, - SET_GRAVITY_SCALE = 541, - SET_GRAVITY_SCALE_FOR_RIGID_BODY = 542, - STOP_MOVING = 543, - SET_PATHING_SPEED = 544, - SET_SHIELDED = 545, - SET_SHOOTING_GALLERY_RETICULE_EFFECT = 546, - PLACE_MODEL_RESPONSE = 547, - SET_DODGE_INFO = 548, - GET_DODGE_INFO = 549, - SET_SKILL_ATTACK_SPEED = 550, - GET_SKILL_COOLDOWN_GROUP = 551, - GET_INITIAL_SKILL_COOLDOWN = 552, - GET_SKILL_COOLDOWN_REMAINING = 553, - GET_GLOBAL_COOLDOWN = 554, - SET_GLOBAL_COOLDOWN = 555, - RESET_GLOBAL_COOLDOWN = 556, - FINDINVENTORY_ITEM = 558, - PATH_STUCK = 559, - SET_CURRENT_PATH = 560, - SET_JET_PACK_MODE = 561, - SET_JET_PACK_TIME = 562, - PET_FOLLOW_OWNER = 563, - PLAYER_DIED = 564, - REGISTER_PET_ID = 565, - REGISTER_PET_DBID = 566, - GET_PET_ID = 567, - SHOW_ACTIVITY_COUNTDOWN = 568, - DISPLAY_TOOLTIP = 569, - SET_PHANTOM_BASE = 570, - GET_MOTION_STATE = 571, - GET_MOTION_CONFIG = 572, - SET_ACTIVE_PROJECTILE_SKILL = 573, - INITIALIZE_MISSION_VISUALS = 574, - GET_MISSIONS = 575, - START_ACTIVITY_TIME = 576, - ADD_ACTIVITY_TIME = 577, - GUILD_GET_SIZE = 578, - GUILD_CAN_WE_INVITE = 579, - GUILD_CAN_WE_KICK = 580, - SET_CHAR_GUILD_INFO = 581, - GET_CHAR_GUILD_INFO = 582, - GET_CHAR_IS_IN_GUILD = 583, - RE_RENDER_NAME_BILLBOARD = 584, - IS_IN_LOCAL_CHAR_PROXIMITY = 585, - GUILD_SET_STATUS = 586, - GUILD_ADD_PLAYER = 587, - GUILD_REMOVE_PLAYER = 588, - GUILD_UPDATE_PLAYER_NAME = 589, - GUILD_SET_PLAYER_RANK = 590, - GUILD_SET_ONLINE_STATUS = 591, - GUILD_INVITE = 592, - REQUEST_GUILD_DATA = 593, - POPULATE_GUILD_DATA = 594, - GET_CACHED_GUILD_DATA = 595, - GUILD_RENDER_NAME = 596, - GET_IS_SUPPORTED = 600, - CHARACTER_SUPPORT_CHANGED = 601, - ACTIVITY_PAUSE = 602, - USE_NON_EQUIPMENT_ITEM = 603, - REQUEST_USE_ITEM_ON = 604, - REQUEST_USE_ITEM_ON_TARGET = 605, - USE_ITEM_ON = 606, - USE_ITEM_RESULT = 607, - GET_PARENT_OBJ = 608, - SET_PARENT_OBJ = 609, - GET_UPDATES_WITH_PARENT_POSITION = 610, - PARENT_REMOVED = 611, - PARENT_LEFT_SCOPE = 612, - PARENT_ENTERED_SCOPE = 613, - CHILD_LOADED = 614, - CHILD_REMOVED = 615, - CHILD_DETACHED = 616, - CHILD_ENTERED_SCOPE = 617, - CHILD_LEFT_SCOPE = 618, - GET_CHILD_OBJECTS = 619, - ZONE_TRANSFER_FINISHED = 621, - CHAT_CONNECTION_UPDATE = 622, - PLATFORM_AT_LAST_WAYPOINT = 623, - LOOT_TAKE_ALL = 624, - GET_EQUIPPED_ITEM_INFO = 625, - DISPLAY_GUILD_CREATE_BOX = 626, - GET_EDITOR_LEVEL = 627, - GET_ACCOUNT_ID = 628, - GET_LAST_LOGOUT = 629, - GET_LAST_PROP_MOD_DISPLAY_TIME = 630, - SET_LAST_PROP_MOD_DISPLAY_TIME = 631, - SHOW_ACTIVITY_SUMMARY = 632, - CAN_RECEIVE_ALL_REWARDS = 633, - GET_ACTIVITY_REWARD = 634, - LOOT_CLOSE_WINDOW = 635, - GET_BLUEPRINT_ID = 636, - NOTIFY_BLUEPRINT_UPDATE = 637, - FETCH_MODEL_METADATA_REQUEST = 638, - FETCH_MODEL_METADATA_RESPONSE = 639, - COMMAND_PET = 640, - PET_RESPONSE = 641, - GET_ICON_ABOVE_HEAD_STATE = 642, - GET_ICON_ABOVE_HEAD = 643, - ICON_FINISHED_LOADING = 644, - ADD_PET_STATE = 645, - REMOVE_PET_STATE = 646, - SET_PET_STATE = 647, - REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 648, - SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA = 649, - SET_ON_TEAM = 650, - GET_PET_HAS_STATE = 651, - FIND_PROPERTY = 652, - SET_PET_MOVEMENT_STATE = 653, - GET_ITEM_TYPE = 654, - GET_ITEM_INFO_KEY = 655, - NOTIFY_OBJECT = 656, - IS_PET_WILD = 657, - CLIENT_NOTIFY_PET = 659, - NOTIFY_PET = 660, - NOTIFY_PET_TAMING_MINIGAME = 661, - START_SERVER_PET_MINIGAME_TIMER = 662, - CLIENT_EXIT_TAMING_MINIGAME = 663, - GET_BUILDMODE_ACTIVE = 664, - GET_PET_TAMING_MINIGAME_ACTIVE = 665, - PET_TAMING_OBJECT_PICKED = 666, - PET_TAMING_MINIGAME_RESULT = 667, - PET_TAMING_TRY_BUILD_RESULT = 668, - SET_PET_TAMING_MODEL = 669, - GET_PET_TAMING_MODEL = 670, - PET_ON_SWITCH = 671, - PET_OFF_SWITCH = 672, - NOTIFY_TAMING_BUILD_SUCCESS = 673, - NOTIFY_TAMING_MODEL_LOADED_ON_SERVER = 674, - NOTIFY_TAMING_PUZZLE_SELECTED = 675, - GET_INSTRUCTION_COUNT = 676, - GET_IS_NPC = 677, - ACTIVATE_BUBBLE_BUFF = 678, - DECTIVATE_BUBBLE_BUFF = 679, // This is spelled wrong in the client, so we misspell it here. - EXHIBIT_VOTE = 680, - ADD_PET_TO_PLAYER = 681, - REMOVE_PET_FROM_PLAYER = 682, - REQUEST_SET_PET_NAME = 683, - SET_PET_NAME = 684, - PET_NAME_CHANGED = 686, - GET_PET_AT_INDEX = 687, - GET_LOT_FOR_PET_BY_DBID = 688, - GET_NAME_FOR_PET_BY_DBID = 689, - GET_ACTIVE_PET_OBJ_ID = 690, - GET_ACTIVE_PET_INVENTORY_OBJ_ID = 691, - SHOW_PET_ACTION_BUTTON = 692, - SET_EMOTE_LOCK_STATE = 693, - GET_EMOTE_LOCK_STATE = 694, - LEAVE_TEAM_MSG = 695, - TEAM_KICK_PLAYER_MSG = 697, - TEAM_SET_LEADER_SEND_MSG = 698, - USE_ITEM_ON_CLIENT = 699, - DOES_FORWARD_TARGET_CLICKING = 700, - CHECK_USE_REQUIREMENTS = 701, - USE_REQUIREMENTS_RESPONSE = 702, - USE_ITEM_REQUIREMENTS_RESPONSE = 703, - PET_ADDED_TO_WORLD = 704, - BOUNCER_TRIGGERED = 705, - EXHIBIT_QUERY_CURRENT_MODEL = 706, - EXHIBIT_QUERY_CURRENT_MODEL_RESPONSE = 707, - EXHIBIT_ATTEMPT_VOTE = 708, - EXHIBIT_VOTE_RESPONSE = 709, - EHIBIT_REQUERYMODELS = 710, - IS_SKILL_ACTIVE = 711, - TOGGLE_ACTIVE_SKILL = 712, - PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT = 713, - EXHIBIT_GET_INFO = 714, - GET_PROPERTY_DATA = 715, - DOWNLOAD_PROPERTY_DATA = 716, - QUERY_PROPERTY_DATA = 717, - MODEL_MODERATION_ACTION = 719, - NOTIFY_SERVER_UGC_REVIEW_READY = 720, - NOTIFY_CLIENT_UGC_REVIEW_READY = 721, - OLD_USE_ITEM_ON = 722, - FIND_PROPERTY_FOR_SALE_RESPONSE = 723, - PROPERTY_EDITOR_BEGIN = 724, - PROPERTY_EDITOR_END = 725, - PROPERTY_EDITOR_SET_MODE = 726, - TOGGLE_TRIGGER = 727, - FIRE_EVENT = 728, - IS_MINIFIG_IN_A_BUBBLE = 729, - GET_ITEM_INFO = 730, - MISSION_NEEDS_LOT = 731, - STOP_PATHING = 732, - START_PATHING = 733, - ACTIVATE_BUBBLE_BUFF_FROM_SERVER = 734, - DEACTIVATE_BUBBLE_BUFF_FROM_SERVER = 735, - HAS_SKILL = 736, - NOTIFY_CLIENT_ZONE_OBJECT = 737, - MOVE_OBJECT = 738, - ROTATE_OBJECT = 739, - GET_SPAWNER_CONFIG_DATA = 740, - UPDATE_SPAWNER_CONFIG_DATA = 741, - TURN_AROUND = 743, - GO_FORWARD = 744, - GO_BACKWARD = 745, - UPDATE_REPUTATION = 746, - GET_REPUTATION = 747, - ADD_REPUTATION = 748, - UPDATE_PROPERTY_DATA = 749, - PROPERTY_RENTAL_RESPONSE = 750, - EXHIBIT_PLACEMENT_RESPONSE = 751, - SQUIRT_WITH_WATERGUN = 752, - GET_VOTES_LEFT = 753, - ADJUST_VOTES_LEFT = 754, - EVADE_TARGET = 755, - STOPPED_EVADING = 756, - GET_PET_HAS_ABILITY = 757, - REQUEST_PLATFORM_RESYNC = 760, - PLATFORM_RESYNC = 761, - PLAY_CINEMATIC = 762, - END_CINEMATIC = 763, - CINEMATIC_UPDATE = 764, - ATTACH_CAMERA_TO_RAIL = 765, - DETACH_CAMERA_FROM_RAIL = 766, - TOGGLE_GHOST_REFERENCE_OVERRIDE = 767, - SET_GHOST_REFERENCE_POSITION = 768, - GET_GHOST_REFERENCE_POSITION = 769, - FIRE_EVENT_SERVER_SIDE = 770, - GET_PET_ABILITY_OBJECT = 771, - TEAM_INVITE_MSG_FROM_UI = 772, - ADD_CAMERA_EFFECT = 773, - REMOVE_CAMERA_EFFECT = 774, - REMOVE_ALL_CAMERA_EFFECTS = 775, - GET_MY_PROPERTIES_IN_THIS_ZONE = 776, - IS_MODEL_WITHIN_PROPERTY_BOUNDS = 777, - PROPERTY_DATA_RESULTS = 778, - ON_UN_SERIALIZE = 779, - SCRIPT_NETWORK_VAR_UPDATE = 781, - ADD_OBJECT_TO_GROUP = 783, - REMOVE_OBJECT_FROM_GROUP = 784, - IS_OBJECT_STATIC = 785, - GET_HAS_MISSION = 786, - GET_MISSION_TARGET_LOT = 787, - GET_MISSION_OFFERER_LOT = 788, - USE_UNIQUE_ITEM = 789, - GET_IS_PET = 790, - DELETE_PROPERTY = 791, - CREATEMODEL_FROM_CLIENT = 792, - UPDATE_MODEL_FROM_CLIENT = 793, - DELETE_MODEL_FROM_CLIENT = 794, - SHOW_PROPERTY_BOUNDS = 795, - SET_PROPERTY_I_DS = 796, - PLAY_FACE_DECAL_ANIMATION = 797, - ADD_ACTIVITY_USER = 798, - REMOVE_ACTIVITY_USER = 799, - GET_NUM_ACTIVITY_USERS = 800, - ACTIVITY_USER_EXISTS = 801, - DO_COMPLETE_ACTIVITY_EVENTS = 805, - SET_ACTIVITY_PARAMS = 806, - SET_ACTIVITY_USER_DATA = 807, - GET_ACTIVITY_USER_DATA = 808, - DO_CALCULATE_ACTIVITY_RATING = 809, - ND_AUDIO_POST_SETUP = 812, - ND_AUDIO_PRE_SHUTDOWN = 813, - SET_ND_AUDION_LISTENER_STANCE = 814, - SET_UP_ND_AUDIO_EMIITTER = 815, - SHUT_DOWN_ND_AUDIO_EMITTER = 816, - METAIFY_ND_AUDIO_EMITTER = 817, - UN_METAIFY_ND_AUDIO_EMITTER = 818, - METAIFY_ND_AUDIO_EMITTERS = 819, - UN_METAIFY_ND_AUDIO_EMITTERS = 820, - PLAY_ND_AUDIO_EMITTER = 821, - STOP_ND_AUDIO_EMITTER = 822, - STOP_ND_AUDIO_EMITTER_ALL = 823, - SET_ND_AUDIO_EMITTER_PARAMETER = 824, - SET_ND_AUDIO_EMITTERS_PARAMETER = 825, - ND_AUDIO_CALLBACK = 826, - ACTIVATE_ND_AUDIO_MUSIC_CUE = 827, - DEACTIVATE_ND_AUDIO_MUSIC_CUE = 828, - FLASH_ND_AUDIO_MUSIC_CUE = 829, - SET_ND_AUDIO_MUSIC_PARAMETER = 830, - PLAY2_D_AMBIENT_SOUND = 831, - STOP2_D_AMBIENT_SOUND = 832, - PLAY3_D_AMBIENT_SOUND = 834, - STOP3_D_AMBIENT_SOUND = 835, - ACTIVATE_ND_AUDIO_MIXER_PROGRAM = 836, - DEACTIVATE_ND_AUDIO_MIXER_PROGRAM = 837, - UPDATE_ACTIVITY_LEADERBOARD = 838, - ACTIVITY_LEADERBOARD_UPDATED = 839, - ENTER_PROPERTY1 = 840, - ENTER_PROPERTY2 = 841, - PROPERTY_ENTRANCE_SYNC = 842, - SEND_PROPERTY_POPULATION_TO_CLIENT = 843, - SEN_PROPERTY_PLAQUE_VIS_UPDATE = 844, - PROPERTY_SELECT_QUERY = 845, - CREATE_POSITION_STRING = 848, - GET_PARALLEL_POSITION = 849, - PARSE_CHAT_MESSAGE = 850, - SET_MISSION_TYPE_STATE = 851, - GET_LOCATIONS_VISITED = 852, - GET_MISSION_TYPE_STATES = 853, - GET_TIME_PLAYED = 854, - SET_MISSION_VIEWED = 855, - SLASH_COMMAND_TEXT_FEEDBACK = 856, - HANDLE_SLASH_COMMAND_KORE_DEBUGGER = 857, - BROADCAST_TEXT_TO_CHATBOX = 858, - OPEN_PROPERTY_MANAGEMENT = 860, - OPEN_PROPERTY_VENDOR = 861, - VOTE_ON_PROPERTY = 862, - UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK = 863, - NOTIFY_PLAYER_OF_PROPERTY_SUBMISSION = 865, - NOTIFY_PLAYER_OF_MODEL_SUBMISSION = 866, - PHYSICS_SYSTEM_LOADED = 867, - CLIENT_TRADE_REQUEST = 868, - SERVER_TRADE_REQUEST = 869, - SERVER_TRADE_INVITE = 870, - CLIENT_TRADE_REPLY = 871, - SERVER_TRADE_REPLY = 872, - SERVER_TRADE_INITIAL_REPLY = 873, - SERVER_TRADE_FINAL_REPLY = 874, - CLIENT_TRADE_UPDATE = 875, - SERVER_SIDE_TRADE_UPDATE = 876, - SERVER_TRADE_UPDATE = 877, - CLIENT_TRADE_CANCEL = 878, - CLIENT_SIDE_TRADE_CANCEL = 879, - CLIENT_TRADE_ACCEPT = 880, - SERVER_SIDE_TRADE_ACCEPT = 881, - SERVER_SIDE_TRADE_CANCEL = 882, - SERVER_TRADE_CANCEL = 883, - SERVER_TRADE_ACCEPT = 884, - GET_TRADE_INFO = 885, - KF_LOADED = 886, - BRICKS_LOADED = 887, - READY_FOR_UPDATES = 888, - SEND_READY_FOR_UPDATES = 889, - SET_LAST_CUSTOM_BUILD = 890, - GET_LAST_CUSTOM_BUILD = 891, - GET_STATUS_EFFECT_BY_ID = 892, - GET_ALL_STATUS_EFFECTS = 893, - CHILD_RENDER_COMPONENT_READY = 894, - NOTIFY_APPEARANCE_CHANGED_MSG = 895, - SET_PHYSICS_MOTION_STATE = 896, - GET_PHYSICS_MOTION_STATE = 897, - ATTACH_GRAYSCALE_EFFECT = 898, - ATTACH_FADE_EFFECT = 899, - ATTACH_CHANGE_RENDER_ENVIRONMENT_EFFECT = 900, - FORCE_MOVEMENT = 901, - CANCEL_FORCE_MOVEMENT = 902, - SET_IGNORE_PROJECTILE_COLLISION = 903, - GET_IGNORE_PROJECTILE_COLLISION = 904, - ORIENT_TO_OBJECT = 905, - ORIENT_TO_POSITION = 906, - ORIENT_TO_ANGLE = 907, - NOTIFY_CLIENT_UGC_MODEL_READY = 909, - NOTIFY_CLIENT_UGC_ICON_READY = 911, - PROPERTY_BUILD_MODE_CHANGED = 912, - PROPERTY_BUILD_MODE_UPDATE = 913, - PROPERTY_DELETION_ACTION = 914, - PROPERTY_MODERATION_STATUS_ACTION = 915, - PROPERTY_MODERATION_STATUS_ACTION_RESPONSE = 916, - PROPERTY_MODERATION_STATUS_UPDATE = 917, - PROPERTY_NEEDS_GM_ATTENTION = 918, - PROPERTY_MODERATION_CHANGED = 919, - INVENTORY_REFRESH_ITEM_DETAILS = 922, - INVENTORY_LOAD_CUSTOM_ICON = 923, - GET_STATUS_EFFECT_BY_TYPE = 924, - RELEASE_CHARGED_SKILL = 925, - PROPERTY_RELOAD_DB = 926, - SET_PLAYER_TARGET = 927, - GET_PLAYER_TARGET = 928, - LOCK_CAMERA_NETWORKED = 929, - MOVE_CAMERA_NETWORKED = 930, - REBUILD_ACTIVATED = 931, - BOUNCE_NOTIFICATION = 932, - REQUEST_CLIENT_BOUNCE = 934, - GET_RECENT_BOUNCED = 935, - SET_RECENT_BOUNCED = 936, - SET_ACTIVE_STATE = 937, - GET_ACTIVE_STATE = 938, - HAS_COMPONENT_TYPE = 939, - GET_COMPONENT_LIST = 940, - RESPONDS_TO_FACTION = 941, - BOUNCER_ACTIVE_STATUS = 942, - HF_ATTRIBUTES_PUSH = 943, - HF_ATTRIBUTES_PULL = 944, - HF_ATTRIBUTES_PATH_DISPLAY = 945, - HF_CONTROLS_PULL = 946, - HF_OBJECT_SELECTED = 947, - HF_PLACEHOLDER_UPDATE = 948, - HF_PLACEHOLDER_TOGGLE = 949, - HF_GET_ASSOCIATED_PATHS = 950, - HF_GETS_WANT_PATH = 951, - GET_RECENT_MOVEMENT_KEYS = 952, - TRACK_RECENT_MOVEMENT_KEYS = 953, - PHYSICS_MOVEMENT_NOTIFICATION_REQUEST = 954, - PHYSICS_MOVEMENT_NOTIFICATION = 955, - MOVE_INVENTORY_SINGLE = 956, - MOVE_INVENTORY_BATCH = 957, - MINI_GAME_SET_PARAMETERS = 958, - MINI_GAME_GET_TEAM_SKILLS = 961, - MINI_GAME_GET_TEAM_SCORE = 963, - MINI_GAME_GET_PLAYER_SCORE = 967, - MINI_GAME_GET_TEAM_COLOR = 972, - MINI_GAME_GET_TEAM_PLAYERS = 975, - MINI_GAME_UPDATE_CLIENT = 976, - MINI_GAME_GET_TEAM = 977, - MINI_GAME_GET_PARAMETERS = 978, - OBJECT_ACTIVATED_CLIENT = 980, - IS_RESURRECTING = 983, - GET_ITEM_OWNER = 984, - GET_STORED_CONFIG_DATA = 985, - SET_STORED_CONFIG_DATA = 986, - ON_PLAYER_RESSURECTED = 988, - PLAYER_RESURRECTION_FINISHED = 989, - TRANSFORM_CHANGELING_BUILD = 990, - RETURN_CHANGELING_BUILD_ID = 991, - SPEND_BRICK_INVENTORY_FOR_LXFML = 992, - BRICK_INVENTORY_FOR_LXFML_SPENT = 993, - REBUILD_BBB_AUTOSAVE_MSG = 995, - SET_BBB_AUTOSAVE = 996, - USE_BBB_INVENTORY = 998, - UN_USE_BBB_MODEL = 999, - BBB_LOAD_ITEM_REQUEST = 1000, - BBB_SAVE_REQUEST = 1001, - BBBLUP_SAVE_REQUEST = 1002, - BBB_GET_METADATA_SOURCE_ITEM = 1003, - BBB_RESET_METADATA_SOURCE_ITEM = 1004, - BBB_SAVE_RESPONSE = 1005, - PLAYER_EXIT = 1006, - SET_PVP_STATUS = 1008, - GET_PVP_STATUS = 1009, - IS_VALID_PVP_TARGET = 1010, - PVP_RENDER_NAME = 1011, - ATTACH_OBJECT = 1012, - DETACH_OBJECT = 1013, - BOUNCE_SUCCEEDED = 1014, - GET_GAME_OBJECT_POINTER = 1015, - PHANTOM_HKX_LOADED = 1016, - DELAY_CREATE_EFFECT = 1017, - CHOICE_BUILD_SELECTION_CONFIRMED = 1018, - NOTIFY_FADE_UP_VIS_COMPLETE = 1019, - ITEM_HAS_NEW_INFO = 1020, - RESET_SECONDARY_ANIMATION = 1021, - GET_PICK_TYPE = 1022, - SET_PICK_TYPE = 1023, - GET_PRIORITY_PICK_LIST_TYPE = 1024, - REQUEST_PICK_TYPE_UPDATE = 1025, - GET_OVERRIDE_PICK_TYPE = 1026, - REQUEST_DISPLAY_OBJECT_INFO = 1027, - REQUEST_SERVER_OBJECT_INFO = 1028, - REQUEST_OBJECT_INFO_AS_XML = 1029, - GET_OBJECT_REPORT_INFO = 1030, - GET_OBJECT_REPORT_WINDOW_CLOSE = 1031, - GET_OBJECT_REPORT_STATUS = 1032, - GET_MISSION_DATA_FOR_OBJECT_REPORT = 1033, - GET_OBJECT_ROLLOVER_INFO = 1034, - PERFORM_ZONE_ANALYSIS = 1035, - UPDATE_HK_VISUAL_IZATION = 1036, - CLEAR_ITEMS_OWNER = 1037, - APPLY_LINEAR_IMPULSE = 1038, - APPLY_ANGULAR_IMPULSE = 1039, - GET_CONTACT_NORMALS = 1040, - IS_WATCHING_FOR_EMOTE = 1041, - NOTIFY_CLIENT_OBJECT = 1042, - DISPLAY_ZONE_SUMMARY = 1043, - ZONE_SUMMARY_DISMISSED = 1044, - GET_PLAYER_ZONE_STATISTIC = 1045, - MODIFY_PLAYER_ZONE_STATISTIC = 1046, - APPLY_EXTERNAL_FORCE = 1049, - GET_APPLIED_EXTERNAL_FORCE = 1050, - ITEM_EQUIPPED = 1052, - ACTIVITY_STATE_CHANGE_REQUEST = 1053, - OVERRIDE_FRICTION = 1054, - ARRANGE_WITH_ITEM = 1055, - CHECK_CAN_BUILD_WITH_ITEM = 1056, - START_BUILDING_WITH_ITEM = 1057, - START_BUILD_SESSION = 1058, - FINISH_BUILD_SESSION = 1059, - DONE_BUILD_SESSION = 1060, - START_ARRANGING_WITH_ITEM = 1061, - FINISH_ARRANGING_WITH_ITEM = 1062, - DONE_ARRANGING_WITH_ITEM = 1063, - START_ARRANGE_MODE = 1064, - ARRANGE_MODE_WITH_ITEM = 1065, - FINISH_ARRANGE_MODE = 1066, - DONE_ARRANGE_MODE = 1067, - SET_BUILD_MODE = 1068, - BUILD_MODE_SET = 1069, - CONFIRM_BUILD_MODE = 1070, - BUILD_MODE_CONFIRMATION = 1071, - BUILD_EXIT_CONFIRMATION = 1072, - SET_BUILD_MODE_CONFIRMED = 1073, - BUILD_MODE_NOTIFICATION = 1074, - BUILD_MODE_NOTIFICATION_REPORT = 1075, - CLIENT_USE_MODULE_ON = 1076, - SET_MODEL_TO_BUILD = 1077, - SPAWN_MODEL_BRICKS = 1078, - CHECK_PRECONDITION = 1079, - CHECK_ALL_PRECONDITIONS = 1080, - NOTIFY_CLIENT_FAILED_PRECONDITION = 1081, - GET_IS_ITEM_EQUIPPED_BY_LOT = 1082, - GET_IS_ITEM_EQUIPPED_BY_ID = 1083, - GET_OBJECT_DIRECTION_VECTORS = 1084, - GET_CASTABLE_SKILLS = 1085, - CHOICEBUILD_COMPLETE = 1086, - GET_MISSION_CHAT = 1087, - GET_MISSION_AUDIO = 1088, - MODULE_EQUIPPED = 1089, - MODULE_DROPPED = 1090, - MODULE_PICKED_UP = 1091, - MODULE_INFO = 1092, - MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1093, - MODULAR_BUILD_BEGIN = 1094, - MODULAR_BUILD_END = 1095, - MODULAR_BUILD_MOVE_AND_EQUIP = 1096, - MODULAR_BUILD_FINISH = 1097, - SET_REGISTRATION_FOR_UI_UPDATE = 1114, - GO_TO_WAYPOINT = 1115, - ARRIVED_AT_DESIRED_WAYPOINT = 1116, - CHECK_WITHIN_BOUNDS = 1117, - ATTACH_TO_BUILD_ASSEMBLY = 1118, - SET_BUILD_ASSEMBLY = 1119, - RESET_BUILD_ASSEMBLY = 1120, - GET_INVENTORY_ITEM_INFO = 1125, - GET_ITEM_DETAILS = 1126, - GET_BUILD_ACTIVATOR = 1127, - GET_MISSION_ANIMATION = 1128, - MISSION_DIALOGUE_CANCELLED = 1129, - MODULE_ASSEMBLY_DB_DATA = 1130, - MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT = 1131, - MODULE_ASSEMBLY_QUERY_DATA = 1132, - MODULE_ASSEMBLY_HKX_LOADED = 1133, - MODULE_ASSEMBLY_NIF_LOADED = 1134, - MODULE_ASSEMBLY_MAIN_NIF_LOADED = 1135, - MODULE_ASSEMBLY_KFM_LOADED = 1136, - GET_PRECONDITION_INFO = 1137, - GET_MODEL_LOT = 1138, - ANIMATION_FINISHED_PRELOADING = 1139, - CHILD_BUILD_ASSEMBLY_COMPLETE = 1140, - CHARACTER_UNSERIALIZED = 1141, - CHARACTER_NEEDS_TRANSITION = 1142, - SET_NEEDS_TRANSITION = 1143, - ECHO_SYNC_SKILL = 1144, - SYNC_SKILL = 1145, - GET_BEHAVIOR_HANDLE = 1146, - ADD_OUTSTANDING_BEHAVIOR = 1147, - REQUEST_SERVER_PROJECTILE_IMPACT = 1148, - OFF_WORLD_IMPACT_REQUEST = 1149, - SERVER_IMPACT_REQUEST = 1150, - DO_CLIENT_PROJECTILE_IMPACT = 1151, - MODULE_ASSEMBLY_PART_INFO = 1152, - GET_BUILD_TYPE = 1153, - CHECK_BUILD_TYPE = 1154, - MODULAR_BUILD_CONVERT_MODEL = 1155, - DO_NPC_SHOWCASE_MODEL_SUBMISSION = 1156, - GET_MISSION_I_DS_LIST = 1157, - SET_SHOWCASE_MISSION_NPC_VALS = 1158, - NOTIFY_SHOWCASE_MISSION_NP_COF_SUCCESS = 1159, - SEND_LUA_NOTIFICATION_REQUEST = 1160, - SEND_LUA_NOTIFICATION_CANCEL = 1161, - ACTIVATOR_TOGGLE = 1162, - MAKE_PHYSICS = 1163, - SET_RESPAWN_GROUP = 1164, - SET_PLAYER_ALLOWED_RESPAWN = 1165, - TOGGLE_SENDING_POSITION_UPDATES = 1166, - TOGGLE_RECEIVING_POSITION_UPDATES = 1167, - GET_ENEMY_PRECONDITIONS = 1168, - START_MODEL_VISUALIZATION = 1169, - PLACE_PROPERTY_MODEL = 1170, - PROPERTY_MODEL_PLACED = 1171, - OPEN_EXHIBIT_REPLACE_MODEL_UI = 1172, - REPLACE_SHOWCASEMODEL = 1173, - CLEAR_UI_HOOK_EXHIBIT_REPLACEMENT = 1174, - ATTACH_FLYTO_SCREEN_POS = 1175, - VEHICLE_GET_DEBUG_INFO = 1176, - VEHICLE_GET_MOVEMENT_INPUT_VALUES = 1177, - ACTIVITY_TIMER_SET = 1178, - ACTIVITY_TIMER_UPDATE = 1179, - ACTIVITY_TIMER_GET = 1180, - ACTIVITY_TIMER_STOP = 1181, - ACTIVITY_TIMER_DONE = 1182, - GET_ATTACK_PRIORITY = 1183, - UI_MESSAGE_SERVER_TO_SINGLE_CLIENT = 1184, - UI_MESSAGE_SERVER_TO_ALL_CLIENTS = 1185, - SET_LOSE_COINS_ON_DEATH = 1186, - LOAD_EFFECTS = 1187, - SET_CUSTOM_BUILD = 1188, - ACTIVITY_TIMER_RESET = 1189, - ACTIVITY_TIMER_STOP_ALL_TIMERS = 1190, - ACTIVITY_TIMER_MODIFY = 1191, - SET_KEYFRAM_TRANSFORM = 1192, - ADD_ACTIVITY_OWNER = 1193, - REMOVE_ACTIVITY_OWNER = 1194, - GET_CURRENT_ACTIVITY_OWNERS = 1195, - TOGGLE_SKILL_DEBUGGING = 1196, - PET_TAMING_TRY_BUILD = 1197, - REPORT_BUG = 1198, - REPORT_OFFENSIVE_MODEL = 1199, - REPORT_OFFENSIVE_PROPERTY = 1200, - GET_ACTIVITY_ID = 1201, - REQUEST_SMASH_PLAYER = 1202, - GET_TIMES_REQUESTED_SMASH = 1203, - RESPONSE_SMASH_PLAYER = 1204, - MODIFY_DAMAGE_ABSORPTION = 1205, - UNCAST_SKILL = 1206, - GET_SHOWCASE_MODEL_READY = 1207, - IS_SKILL_NEEDED = 1208, - GET_COMPONENT_DATA = 1209, - VEHICLE_SET_POWERSLIDE_METHOD = 1210, - SHOWS_NAMETAG = 1211, - FIRE_EVENT_CLIENT_SIDE = 1213, - GET_REQUIRES_NAME_RESUBMISSION = 1216, - SET_REQUIRES_NAME_RESUBMISSION = 1217, - TOGGLE_GM_INVIS = 1218, - GET_GM_INVIS = 1219, - KILLED_PLAYER = 1220, - GET_PICKUP_SKILLS = 1221, - GET_FACTION_SKILL = 1222, - CHANGE_OBJECT_WORLD_STATE = 1223, - GET_OBJECT_WORLD_STATE = 1224, - VISIBILITY_CHANGED = 1225, - MOTION_EFFECT_COMPLETE = 1226, - TOGGLE_FREEZE_MODE = 1227, - SHADER_RENDER_MSG_APPLIED = 1228, - PLAYER_RENAME_REQUEST = 1229, - VEHICLE_LOCK_INPUT = 1230, - VEHICLE_UNLOCK_INPUT = 1231, - SET_AIR_MOVEMENT = 1232, - MOVEMENT_STATE_CHANGED = 1233, - SKILL_MOVEMENT_CANCELLED = 1234, - AIR_MOVEMENT_COMPLETE = 1235, - CANCEL_AIR_MOVEMENT = 1236, - FORCE_MINIFIGURE_TEXTURE_UPDATE = 1237, - RESYNC_EQUIPMENT = 1238, - ADD_COMPONENT_TO_OBJECT = 1239, - VEHICLE_GET_MAX_GAME_SPEED = 1240, - VEHICLE_GET_MAX_GAME_SPEED_WITH_BOOST = 1241, - GET_SPEED_FACTOR = 1242, - FREEZE_INVENTORY = 1243, - ADD_STAT_TRIGGER = 1244, - ADD_STAT_TRIGGER_CHILD = 1245, - CHECK_TRIGGERS_AND_FIRE_IF_NEEDED = 1246, - STAT_EVENT_TRIGGERED = 1247, - GET_CURRENT_SPEED = 1248, - RACING_PLAYER_RANK_CHANGED = 1249, - RACING_PLAYER_WRONG_WAY_STATUS_CHANGED = 1250, - RACING_PLAYER_CROSSED_FINISH_LINE = 1251, - RACING_RESET_PLAYER_TO_LAST_RESET = 1252, - RACING_SERVER_SET_PLAYER_LAP_AND_PLANE = 1253, - RACING_SET_PLAYER_RESET_INFO = 1254, - RACING_PLAYER_INFO_RESET_FINISHED = 1255, - RACING_PLAYER_OUT_OF_TRACK_BOUNDS = 1256, - RACING_SYNC_INFO = 1257, - RACING_PLAYER_KEEP_ALIVE = 1258, - RACING_SERVER_KEEP_ALIVE = 1259, - LOCK_NODE_ROTATION = 1260, - GET_PHYSICS_COLLIDABLE = 1261, - SET_PHYSICS_COLOR_FOR_DEBUG = 1262, - GET_PHYSICS_COLOR_FOR_DEBUG = 1263, - SET_PHYSICS_TEXT_AND_STATE_FOR_DEBUG = 1264, - REQUEST_INFO_FOR_PHYSICS_DEBUGGER = 1265, - GET_COLLIDABLE_AT_ADDRESS = 1266, - REQUEST_SERVER_GET_COLLIDABLE_REPORT = 1267, - COLLISION_POINT_ADDED = 1268, - COLLISION_POINT_REMOVED = 1269, - SET_ATTACHED = 1270, - SET_DESTROYABLE_MODEL_BRICKS = 1271, - VEHICLE_SET_POWERSLIDE_LOCK_WHEELS = 1272, - VEHICLE_SET_WHEEL_LOCK_STATE = 1273, - SHOW_HEALTH_BAR = 1274, - GET_SHOWS_HEALTH_BAR = 1275, - NOTIFY_VEHICLE_OF_RACING_OBJECT = 1276, - ENABLE_CLIENT_EQUIP_MODE = 1278, - CLIENT_EQUIP_MODE_WAS_CHANGED = 1279, - VEHICLE_GET_SPAWN_HEIGHT = 1281, - SET_NAME_BILLBOARD_STATE = 1284, - CHECK_TARGETING_REQUIREMENTS = 1285, - VEHICLE_CAN_WRECK = 1286, - ATTACH_RENDER_EFFECT = 1287, - DETACH_RENDER_EFFECT = 1288, - IS_PET_USING_ABILITY = 1289, - SET_BLOCKING = 1290, - GET_BLOCKING = 1291, - UPDATE_BLOCKING = 1292, - CHECK_DAMAGE_RESULTS = 1293, - GET_OBJECT_IS_IN_RENDER_PIPE = 1294, - ATTACH_MOTION_FX_ARC = 1295, - PLAYER_REACHED_RESPAWN_CHECKPOINT = 1296, - GET_LAST_RESPAWN_CHECKPOINT = 1297, - GET_VEHICLE_DEBUG_COLLISIONS = 1298, - VISITING_PROPERTY = 1299, - HANDLE_UGC_POST_DELETE_BASED_ON_EDIT_MODE = 1300, - HANDLE_UGC_POST_CREATE_BASED_ON_EDIT_MODE = 1301, - WORLD_CHECK_RESPONSE = 1302, - ADD_DAMAGE_REDUCTION = 1303, - REMOVE_DAMAGE_REDUCTION = 1304, - PROPERTY_CONTENTS_FROM_CLIENT = 1305, - GET_MODELS_ON_PROPERTY = 1306, - IS_SHOWCASE_DISPLAY_PEDESTAL = 1307, - MATCH_REQUEST = 1308, - MATCH_RESPONSE = 1309, - MATCH_UPDATE = 1310, - IS_DEFAULT_SKILL_ACTIVE = 1311, - PROPERTY_EDITOR_CARRY = 1312, - GET_LOOT_OWNER_ID = 1313, - GET_ENEMY_LOOT_TAG = 1314, - GET_NUM_SPAWNED_BRICKS = 1315, - SET_ITEM_EQUIP_TRANSFORM = 1316, - GET_ITEM_EQUIP_TRANSFORM = 1317, - GET_PROPERTY_BUDGET_INFO = 1318, - CHATBOX_IS_INIT = 1319, - GET_SPAWNED_I_DS = 1320, - GET_IMMUNITY = 1321, - GET_GM_IMMUNITY = 1322, - PROCESS_REMOTE_SLASH_COMMAND = 1323, - IS_FRIEND_MSG = 1324, - RACING_PLAYER_EVENT = 1325, - GET_PROPERTY_EDIT_VALID = 1326, - REFRESH_RENDER_ASSET = 1327, - VEHICLE_APPLY_STAT_CHANGE = 1328, - ZONE_LOADED_INFO = 1329, - B3_INTERFACE_ACTION = 1330, - RACING_STAT_MODIFIERS_FROM_CLIENT = 1332, - GET_RACING_STAT_MODIFIERS = 1333, - SET_RACING_STAT_MODIFIERS = 1334, - GET_RACING_LICENSE_LEVEL = 1335, - ADD_EQUIP_CAST = 1336, - SHOW_BILLBOARD_INTERACT_ICON = 1337, - CHANGE_IDLE_FLAGS = 1338, - GET_ANIMATION_FLAG = 1339, - VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1340, - VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1341, - NOTIFY_SERVER_VEHICLE_ADD_PASSIVE_BOOST_ACTION = 1342, - NOTIFY_SERVER_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION = 1343, - VEHICLE_ADD_SLOWDOWN_ACTION = 1344, - VEHICLE_REMOVE_SLOWDOWN_ACTION = 1345, - NOTIFY_SERVER_VEHICLE_ADD_SLOWDOWN_ACTION = 1346, - NOTIFY_SERVER_VEHICLE_REMOVE_SLOWDOWN_ACTION = 1347, - FORCE_UPDATE_ANIMATIONS = 1348, - MATCH_GET_DATA_FOR_PLAYER = 1349, - BUYBACK_FROM_VENDOR = 1350, - SET_INVENTORY_FILTER = 1351, - GET_INVENTORY_FILTER = 1352, - GET_INVENTORY_GROUPS = 1353, - GET_INVENTORY_GROUP = 1354, - UPDATE_INVENTORY_GROUP = 1355, - UPDATE_INVENTORY_UI = 1356, - UPDATE_INVENTORY_GROUP_CONTENTS = 1357, - CAN_REMOVE_ITEM_FROM_INVENTORY = 1362, - DRIVE_THIS_CAR = 1363, - VEHICLE_CAN_ADD_ACTIVE_BOOST = 1364, - VEHICLE_ADD_ACTIVE_BOOST = 1365, - SET_PROPERTY_ACCESS = 1366, - ZONE_PROPERTY_MODEL_PLACED = 1369, - ZONE_PROPERTY_MODEL_ROTATED = 1370, - ZONE_PROPERTY_MODEL_REMOVED_WHILE_EQUIPPED = 1371, - ZONE_PROPERTY_MODEL_EQUIPPED = 1372, - ZONE_PROPERTY_MODEL_PICKED_UP = 1373, - ZONE_PROPERTY_MODEL_REMOVED = 1374, - GET_VERSIONING_INFO = 1381, - OPEN_UG_BEHAVIOR_UI = 1382, - VEHICLE_NOTIFY_HIT_SMASHABLE = 1383, - GET_TETHER_RADIUS = 1384, - VEHICLE_NOTIFY_HIT_EXPLODER = 1385, - CHECK_NEAREST_ROCKET_LAUNCH_PRE_CONDITIONS = 1386, - REQUEST_NEAREST_ROCKET_LAUNCH_PRE_CONDITIONS = 1387, - CONFIGURE_RACING_CONTROL_CLIENT = 1389, - NOTIFY_RACING_CLIENT = 1390, - RACING_PLAYER_HACK_CAR = 1391, - RACING_PLAYER_LOADED = 1392, - RACING_CLIENT_READY = 1393, - POSSESSION_FINISHED_ATTACH = 1394, - UPDATE_CHAT_MODE = 1395, - VEHICLE_NOTIFY_FINISHED_RACE = 1396, - EQUIPPED_ITEM_STARTUP = 1397, - FACTION_TRIGGER_ITEM_EQUIPPED = 1400, - FACTION_TRIGGER_ITEM_UNEQUIPPED = 1401, - TOGGLE_PROPERTY_BEHAVIORS = 1402, - GET_UG_OBJECT_INFO = 1405, - RESET_PROPERTY_BEHAVIORS = 1406, - IS_PROPERTY_MODEL_RESET = 1407, - SET_UG_OBJECT_NAME_AND_DESCRIPTION = 1408, - SET_CONSUMABLE_ITEM = 1409, - VEHICLE_GET_CURRENT_LAP = 1410, - GET_UGID = 1411, - SET_UGID = 1412, - UGID_CHANGED = 1413, - RACING_GET_CURRENT_LAP_FOR_PLAYER = 1414, - SUB_ITEM_UN_EQUIPPED = 1415, - SET_CUSTOM_DROP_SHADOW_TEXTURE = 1416, - GET_PLAYER_KIT_FACTION = 1418, - USED_INFORMATION_PLAQUE = 1419, - RACING_ENABLE_WRONG_WAY_RESET = 1420, - RACING_TOGGLE_RUBBER_BANDING = 1421, - GET_RACING_CONTROL_DEBUG_INFO = 1422, - SET_PROPERTY_BOUNDS_VISIBILITY = 1423, - SET_PROPERTY_VENDOR_VISIBILITY = 1424, - SET_EQUIP_STATE = 1425, - NOTIFY_COMBAT_AI_STATE_CHANGE = 1426, - SET_PROPERTY_MODEL_INTERACTIVE = 1430, - SERVER_STATE_NOTIFY = 1431, - GET_SERVER_STATE = 1432, - GET_ICON_FOR_PROXIMITY = 1433, - GET_LEGO_CLUB_MEMBERSHIP_STATUS = 1434, - SET_STATUS_IMMUNITY = 1435, - GET_STATUS_IMMUNITY = 1436, - TEAM_IS_MEMBER = 1437, - ACTIVATE_BRICK_MODE = 1438, - GET_BUILD_OBJECT_ID = 1439, - SET_ANIMATION_ENABLED = 1444, - PAUSE_COOLDOWNS = 1446, - FORCE_UPDATE_RENDER_NODE = 1447, - SET_PET_NAME_MODERATED = 1448, - TOGGLE_STRAFE_MODE = 1449, - SET_SCHEME_SPEED_SCALE = 1450, - CANCEL_SKILL_CAST = 1451, - CHECK_PLAYER_ASSEMBLY_FOR_UNIQUE_MODULE_BY_LOT = 1454, - MODULE_ASSEMBLY_DB_DATA_TO_LUA = 1455, - IS_ALLY = 1458, - MODIFY_LEGO_SCORE = 1459, - GET_LEGO_SCORE = 1460, - GET_PLAYER_LEVEL = 1461, - NOTIFY_LEGO_SCORE_UPDATE = 1462, - SET_LEGO_SCORE = 1463, - UPDATE_BEHAVIOR_EXECUTION_DETAILS = 1466, - RESTORE_TO_POST_LOAD_STATS = 1468, - PICKUP_OBJECT_ERROR = 1469, - CHECK_AND_SHOW_INVENTORY_FULL_TIP = 1470, - SET_RAIL_MOVEMENT = 1471, - START_RAIL_MOVEMENT = 1472, - SET_UP_VECTOR = 1473, - CANCEL_RAIL_MOVEMENT = 1474, - GET_RAIL_INFO = 1475, - CLIENT_RAIL_MOVEMENT_READY = 1476, - PLAYER_RAIL_ARRIVED_NOTIFICATION = 1477, - NOTIFY_RAIL_ACTOVATOR_STATE_CHANGE = 1478, - REQUEST_RAIL_ACTIVATOR_STATE = 1479, - NOTIFY_REWARD_MAILED = 1480, - UPDATE_PLAYER_STATISTIC = 1481, - IS_IN_COMBAT = 1482, - IS_PRIMITIVE_MODEL_MSG = 1483, - SCALE_PRIMITICE_MODEL_MSG = 1484, - MODIFY_GHOSTING_DISTANCE = 1485, - PRIMITIVE_MODEL_CHANGED_MSG = 1487, - GET_PROPRTY_CLONE_ID = 1488, - REQUEST_LEAVE_PROPERTY = 1489, - REQUERY_PROPERTY_MODELS = 1491, - GET_BEHAVIOR_COUNT = 1492, - UPDATE_BEHAVIOR_CONTROLS = 1493, - MODULE_ASSEMBLY_LXFML_LOADED = 1494, - REQUEST_ASSEMBLED_LXFML = 1495, - ASSEMBLED_LXFML_LOADED = 1496, - GET_REORIENT_UP_VECTOR = 1497, - MODULAR_ASSEMBLY_NIF_COMPLETED = 1498, - CHARACTER_DISCONNECT_BEFORE_CREATE = 1499, - SEND_LAUNCH_TO_PREVIOUS_ZONE_TO_CLIENT = 1500, - ROCKETLAUNCH_REQUEST_DEFAULT_MAP_ID = 1501, - BEGIN_LAUNCH = 1502, - PROCESS_CLAIM_CODES = 1503, - GET_LAST_ZONE_ID = 1504, - ADD_RUN_SPEED_MODIFIER = 1505, - REMOVE_RUN_SPEED_MODIFIER = 1506, - SKILL_EVENT_FIRED = 1507, - SEND_HOT_PROPERTY_DATA = 1510, - GET_HOT_PROPERTY_DATA = 1511, - GET_EQUIPPED_ITEMS_IN_SET = 1512, - IS_ITEM_IN_SET = 1513, - GET_INVENTORY_TYPE_FOR_LOT = 1514, - GET_BANK_TYPE_FOR_LOT = 1515, - NOTIFY_NOT_ENOUGH_INV_SPACE = 1516, - IMPORT_MODEL_TO_BBB = 1517, - SEARCH_NEARBY_OBJECTS = 1518, - SEARCH_NEARBY_OBJECTS_REQUEST_BY_LOT = 1519, - REQUEST_OBJECT_POSITION_BY_ID = 1520, - SEARCH_NEARBY_OBJECTS_REQUEST_BY_COMPONENT = 1521, - SEARCH_NEARBY_OBJECTS_RESPONSE = 1522, - BROADCAST_NON_STANDARD_COLLISIONS = 1523, - GET_REGISTERED_NON_STANDARD_COLLISION_GROUP = 1524, - BROADCAST_CRUSHED_NOTIFICATIONS = 1525, - GET_REGISTERED_CRUSHED_COLLISION_GROUPS = 1526, - IS_BEING_CRUSHED = 1527, - GET_SUPPORTING_OBJECT = 1528, - TREAT_RIGID_BODY_COLLSIONS_AS_FIXED = 1529, - BROADCAST_TELEPORTED_WITHIN_NOTIFICATION = 1530, - GET_REGISTERED_TELEPORTED_WITHIN_OBJECT_GROUP = 1531, - GET_INTERPENTRATING_INFORMATION = 1532, - OBJECT_TELEPORTED_WITHIN = 1533, - SET_PHYSICS_SOLVER_PROPERTIES = 1534, - HAS_BEHAVIORS = 1535, - PLAY_BEHAVIOR_SOUND = 1536, - GET_PLAYER_BEHAVIOR_TIER = 1537, - GET_EMOTE_ANIMATION_TIME = 1538, - GET_CHARACTER_STAT_TRACKING = 1539, - PLAYER_INVENTORY_READY = 1540, - SET_PRECONDITIONS = 1541, - DETACH_SHADOW = 1542, - GET_LOOT_INFO = 1543, - GET_PLAYERS_ON_PROPERTY = 1544, - PROPERTY_SPAWN_BY_BEHAVIOR = 1545, - NOTIFY_PROPERTY_OF_EDIT_MODE = 1546, - UPDATE_PROPERTY_PERFORMANCE_COST = 1547, - GET_PROPERTY_PERFORMANCE_COST = 1548, - GET_INVENTORY_ITEM_WITH_SUBKEY = 1549, - DISPLAY_PROPERTY_SUMMARY_SCREEN = 1550, - VALIDATE_BBB_MODEL = 1551, - BBB_MODEL_VALIDATION = 1552, - PROPERTY_ENTRANCE_BEGIN = 1553, - CHECK_LIST_OF_PRECONDITIONS_FROM_LUA = 1554, - GET_PROPERTYIN_ZONE = 1555, - GET_ZONE_ID_FROM_MULTI_ZONE_ENTRANCE = 1556, - TEAM_SET_LEADER = 1557, - TEAM_INVITE_CONFIRM = 1558, - TEAM_GET_STATUS_RESPONSE = 1559, - MINI_GAME_ENABLE_LOCAL_TEAMS = 1560, - TEAM_INVITE_FINAL_RESPONSE = 1561, - TEAM_ADD_PLAYER = 1562, - TEAM_REMOVE_PLAYER = 1563, - TEAM_CREATE_LOCAL = 1564, - TEAM_GET_LOOT = 1565, - TEAM_SET_LOOT = 1566, - SET_ZERO_IMPULSE_AGAINST_COLLISION_GROUPS = 1567, - SET_CENTER_OF_MASS_TO_PHYSICAL_CENTER = 1568, - SET_INERTIA_INVERSE = 1569, - ADD_REMOVE_CLIMBING_LISTENER = 1570, - GET_INVENTORYITEM_DETAILS = 1571, - PERFORM_CLIENT_SIDE_DEATH = 1572, - LEGO_CLUB_ACCESS_RESULT = 1573, - VEHICLE_GET_IS_REVERSING = 1574, - CHECK_CLAIM_CODE = 1575, - GET_HOLIDAY_EVENT = 1576, - SET_EMOTES_ENABLED = 1577, - GET_EMOTES_ENABLED = 1578, - FREEZE_ANIMATION = 1579, - LOCALIZED_ANNOUNCEMENT_SERVER_TO_SINGLE_CLIENT = 1580, - ANCHOR_FX_NODE = 1581, - WS_GET_FRIEND_LIST_MESSAGE = 1582, - WS_ADD_FRIEND_RESPONSE = 1583, - WS_REMOVE_FRIEND_REPSONSE = 1584, - WS_UPDATE_FRIEND_STATUS = 1585, - WS_UPDATE_FRIEND_NAME = 1586, - IS_BEST_FRIEND = 1587, - TEAM_NOTIFY_UPDATE_MISSION_TASK = 1588, - VEHICLE_ADD_SLIPPERY_ACTION = 1589, - VEHICLE_REMOVE_SLIPPERY_ACTION = 1590, - SET_RESURRECT_RESTORE_VALUES = 1591, - GET_MASS = 1592, - SET_PROPERTY_MODERATION_STATUS = 1593, - UPDATE_PROPERTY_MODEL_DEFAULTS = 1594, - UPDATE_PROPERTYMODEL_COUNT = 1595, - GET_PROPERTY_MODEL_COUNT = 1596, - IS_PLAYER_LOADED = 1597, - ATTACH_RENDER_EFFECT_FROM_LUA = 1598, - DETACH_RENDER_EFFECT_FROM_LUA = 1599, - TEAM_IS_LOCAL = 1600, - CREATE_CAMERA_PARTICLES = 1602, - SET_SMASHABLE_GRAVITY_FACTOR = 1603, - VEHICLE_SET_SURFACE_TYPE_OVERRIDE = 1604, - VEHICLE_NOTIFY_HIT_IMAGINATION = 1605, - VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER = 1606, - GET_SPAWNED_OBJECT_SPAWNER_INFO = 1607, - SAVE_PROPERTY = 1608, - SET_PROPERTY_DIRTY = 1609, - GET_PROPERTY_DIRTY = 1610, - GET_MODEL_LIST_FROM_PLAQUE = 1611, - GET_ORIGINAL_POSITION_AND_ROTATION = 1612, - VEHICLE_SET_MASS_FOR_COLLISION = 1613, - GET_INVENTORY_GROUP_COUNT = 1614, - GET_LATEST_CHAT_CHANNEL_USED = 1615, - SET_SUGGEST_LIST_LANGUAGE = 1616, - VEHICLE_STOP_BOOST = 1617, - START_CELEBRATION_EFFECT = 1618, - LOCK_PLAYER = 1619, - VEHICLE_IS_INPUT_LOCKED = 1620, - GET_MULTI_NODE = 1621, - RENEW_PROPERTY = 1622, - RENEW_PROPERTY_RESULT = 1623, - CHARGE_ACTIVITY_COST = 1624, - CAN_RECEIVE_LOOT = 1625, - JOIN_PLAYER_FACTION = 1626, - SET_PROXIMITY_UPDATE_RATE = 1627, - BBB_MODELS_TO_SAVE = 1628, - BELONGS_TO_FACTION = 1629, - MODIFY_FACTION = 1630, - FACTION_UPDATE = 1631, - CELEBRATION_COMPLETED = 1632, - PLAY_PRIMARY_MODULE_SOUNDS = 1633, - STOP_PRIMARY_MODULE_SOUNDS = 1634, - REQUEST_TEAM_PLAYER_UI_UPDATE = 1635, - SET_LOCAL_TEAM = 1636, - TEAM_GET_WORLD_MEMBERS_IN_RADIUS = 1637, - GET_PARENTAL_LEVEL = 1638, - GET_OBJECTS_MESSAGE_HANDLERS = 1639, - PROPERTY_FEATURED = 1640, - PROPERTY_NOTIFY_MODEL_SPAWNED = 1641, - SERVER_DONE_LOADING_ALL_OBJECTS = 1642, - GET_DONATION_TOTAL = 1643, - UPDATE_DONATION_VALUES = 1644, - DELAYED_DELETE_DROP_EFFECT_BRICK = 1645, - SET_CAMERA_UNLOCK_ROTATION_STATE = 1646, - ADD_BUFF = 1647, - REMOVE_BUFF = 1648, - CHECK_FOR_BUFF = 1649, - TEAM_MEMBERS_DISOWNS_LOOT = 1650, - GET_WHEEL_TEMPLATE = 1651, - ADD_SKILL_IN_PROGRESS = 1652, - REMOVE_SKILL_IN_PROGRESS = 1653, - SET_OVERHEAD_ICON_OFFSET = 1654, - SET_BILLBOARD_OFFSET = 1655, - SET_CHAT_BUBBLE_OFFSET = 1656, - SET_NO_TEAM_INVITES = 1657, - RESET_MODEL_TO_DEFAULTS = 1658, - IS_PROPERTY_IN_EDIT_MODE = 1659, - GET_OBJECTS_IN_PHYSICS_BOUNDS = 1660, - ENABLE_LU_REMOTE = 1661, - SET_IS_USING_FREE_TRIAL = 1662, - GET_IS_USING_FREE_TRIAL = 1663, - GET_ACCOUNT_FREE_TRIAL_MODE = 1664, - TOGGLE_INVENTORY_ITEM_LOCK = 1665, - REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666, - RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667, - REMOVE_SUB_COMPONENT = 1668, - TEAM_GET_LOOT_MEMBERS = 1669, - GET_FACTION_TOKEN_TYPE = 1670, - GET_SUBSCRIPTION_PRICING = 1671, - INFORM_AFK = 1672, - OVERHEAD_INDICATOR_CREATED = 1673, - SET_OVERHEAD_INDICATOR_GRID_LOCATION = 1674, - PLAYSTREAM_LOAD_PENDING = 1675, - PLAYER_SET_CAMERA_CYCLING_MODE = 1676, - PLAYER_GET_CAMERA_CYCLING_MODE = 1677, - FORCE_CAMERA_TARGET_CYCLE = 1678, - GET_OBJECT_CONFIG_DATA = 1679, - GET_OBJECT_CONFIG_DATA_NON_CONST = 1680, - SCOPE_CHANGED = 1681, - SET_ALLOW_JUMP_WITHOUT_SUPPORT = 1682, - GET_ALLOW_JUMP_WITHOUT_SUPPORT = 1683, - SET_JUMP_HEIGHT_SCALE = 1684, - GET_JUMP_HEIGHT_SCALE = 1685, - SET_VELOCITY_RESISTANCE = 1686, - GET_VELOCITY_RESISTANCE = 1687, - GATE_RUSH_VEHICLE_HIT_GATE = 1688, - GATE_RUSH_PLAYER_COLLECTED_GATE = 1689, - GATE_RUSH_ADD_GATE = 1690, - GATE_RUSH_REMOVE_GATE = 1691, - NOTIFY_VEHICLE_UPDATED = 1692, - VEHICLE_NOTIFY_HIT_WEAPON_POWERUP = 1693, - VEHICLE_NOTIFY_HIT_WEAPON_POWERUP_SERVER = 1694, - LOCAL_PLAYER_TARGETED = 1696, - SKILL_COUNT_CHANGED = 1697, - DO_YAW_ROTATION = 1698, - DO_PITCH_ROTATION = 1699, - DO_ROLL_ROTATION = 1700, - GET_CURRENT_LOOT_MATRIX = 1701, - SEND_MULTI_MISSION_OFFER_UPDATE_I_DS = 1702, - SET_AIR_SPEED_VALUES = 1703, - USE_LAUNCHER = 1704, - START_LAUNCHER = 1705, - STOP_LAUNCHER = 1706, - CAN_USE_JET_PACK = 1707, - JET_PACK_STATE_CHANGED = 1708, - TURN_OFF_JET_PACK = 1709, - ADD_PLAYER_JET_PACK_PAD = 1710, - SET_JET_PACK_WARNING = 1711, - JET_PACK_DISABLED = 1712, - JET_PACK_PAD_ENTERED = 1713, - UPDATE_RENDER_POSSESSION_FLAG = 1714, - POSSESSABLE_GET_ATTACH_OFFSET = 1715, - ATTEMPT_TO_CRAFT_ITEM = 1718, - CRAFT_ATTEMPT_RESPONSE = 1719, - SET_C_SCORE = 1720, - FILL_IN_RENDERER = 1721, - TOGGLE_CRAFTING_WINDOW = 1722, - REMOVE_TEAM_BUFFS = 1724, - REQUEST_FREE_TRIAL_STATUS_REFRESH = 1725, - REMOVE_BUFFS_APPLIED_BY_OBJECT = 1726, - SET_MOUNT_INVENTORY_ID = 1727, - GET_MOUNT_INVENTORY_ID = 1728, - GET_BUILD_CINEMATIC_TIME_REMAINING = 1730, - JET_PACK_FLYING = 1731, - NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE = 1734, - NOTIFY_LEVEL_REWARDS = 1735, - CHARACTER_VERSION_CHANGED = 1736, - SET_FREE_TRIAL_RENAME_AVAILABLE = 1737, - SET_PROJECTILE_LAUNCHER_PARAMS = 1738, - RACE_PRECOUNTDOWN_DONE = 1739, - CHECK_INVITE_SPAMMING = 1740, - GET_RESPAWN_VOLUME_INFO = 1741, - INVITE_ACCEPTED = 1742, - TELEPORT_TO_NEAREST_RESPAWN = 1743, - SET_SKILL_CANCEL_ON_MOVE = 1744, - CANCEL_MOVE_SKILL = 1745, - SERVER_CANCEL_MOVE_SKILL = 1746, - CLIENT_CANCEL_MOVE_SKILL = 1747, - END_LAUNCH_SEQUENCE = 1748, - CANCEL_QUEUE = 1749, - UPDATE_PROJECTILE_LAUNCHER_ROTATION = 1750, - GET_CHARACTER_VERSION_INFO = 1751, - GET_CON_INFO = 1753, - GET_SKILLS_FOR_LOT = 1755, - DISMOUNT_COMPLETE = 1756, - MOUNT_FAILURE_RESPONSE = 1757, - CLEAR_BILLBOARD_OFFSET = 1758, - GET_INVENTORY_ITEM_ANIMATION_FLAG = 1759, - SET_JET_PACK_ALLOWED = 1760, - GET_BUILD_TIME_DETAILS = 1761, - USE_SKILL_SET = 1762, - SET_SKILL_SET_POSSESSOR = 1763, - POPULATE_ACTION_BAR = 1764, - GET_COMPONENT_TEMPLATE_ID = 1765, - GET_POSSESSABLE_SKILL_SET = 1766, - MARK_INVENTORY_ITEM_AS_ACTIVE = 1767, - UPDATE_FORGED_ITEM = 1768, - CAN_ITEMS_BE_REFORGED = 1769, - NOTIFY_CLIENT_RAIL_START_FAILED = 1771, - GET_IS_ON_RAIL = 1772 -}; - -template <> -struct magic_enum::customize::enum_range { - static constexpr int min = 0; - static constexpr int max = 1772; -}; - -#endif //!__EGAMEMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eInventoryType.h b/dCommon/dEnums/eInventoryType.h index 12573aa4b..1c6688b22 100644 --- a/dCommon/dEnums/eInventoryType.h +++ b/dCommon/dEnums/eInventoryType.h @@ -4,6 +4,9 @@ #define __EINVENTORYTYPE__H__ #include + +#include "magic_enum.hpp" + static const uint8_t NUMBER_OF_INVENTORIES = 17; /** * Represents the different types of inventories an entity may have @@ -56,4 +59,10 @@ class InventoryType { }; }; +template <> +struct magic_enum::customize::enum_range { + static constexpr int min = 0; + static constexpr int max = 16; +}; + #endif //!__EINVENTORYTYPE__H__ diff --git a/dCommon/dEnums/eMasterMessageType.h b/dCommon/dEnums/eMasterMessageType.h deleted file mode 100644 index 5c867d70f..000000000 --- a/dCommon/dEnums/eMasterMessageType.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __EMASTERMESSAGETYPE__H__ -#define __EMASTERMESSAGETYPE__H__ - -#include - -enum class eMasterMessageType : uint32_t { - REQUEST_PERSISTENT_ID = 1, - REQUEST_PERSISTENT_ID_RESPONSE, - REQUEST_ZONE_TRANSFER, - REQUEST_ZONE_TRANSFER_RESPONSE, - SERVER_INFO, - REQUEST_SESSION_KEY, - SET_SESSION_KEY, - SESSION_KEY_RESPONSE, - PLAYER_ADDED, - PLAYER_REMOVED, - - CREATE_PRIVATE_ZONE, - REQUEST_PRIVATE_ZONE, - - WORLD_READY, - PREP_ZONE, - - SHUTDOWN, - SHUTDOWN_RESPONSE, - SHUTDOWN_IMMEDIATE, - - SHUTDOWN_UNIVERSE, - - AFFIRM_TRANSFER_REQUEST, - AFFIRM_TRANSFER_RESPONSE, - - NEW_SESSION_ALERT -}; - -#endif //!__EMASTERMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eReponseMoveItemBetweenInventoryTypeCode.h b/dCommon/dEnums/eReponseMoveItemBetweenInventoryTypeCode.h new file mode 100644 index 000000000..b99687d0d --- /dev/null +++ b/dCommon/dEnums/eReponseMoveItemBetweenInventoryTypeCode.h @@ -0,0 +1,21 @@ +#ifndef __EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__ +#define __EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__ + +#include + +enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t { + SUCCESS, + FAIL_GENERIC, + FAIL_INV_FULL, + FAIL_ITEM_NOT_FOUND, + FAIL_CANT_MOVE_TO_THAT_INV_TYPE, + FAIL_NOT_NEAR_BANK, + FAIL_CANT_SWAP_ITEMS, + FAIL_SOURCE_TYPE, + FAIL_WRONG_DEST_TYPE, + FAIL_SWAP_DEST_TYPE, + FAIL_CANT_MOVE_THINKING_HAT, + FAIL_DISMOUNT_BEFORE_MOVING +}; + +#endif //!__EREPONSEMOVEITEMBETWEENINVENTORYTYPECODE__H__ diff --git a/dCommon/dEnums/eServerMessageType.h b/dCommon/dEnums/eServerMessageType.h deleted file mode 100644 index 7f211ffb4..000000000 --- a/dCommon/dEnums/eServerMessageType.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __ESERVERMESSAGETYPE__H__ -#define __ESERVERMESSAGETYPE__H__ - -#include -//! The Internal Server Packet Identifiers -enum class eServerMessageType : uint32_t { - VERSION_CONFIRM = 0, - DISCONNECT_NOTIFY, - GENERAL_NOTIFY -}; - -#endif //!__ESERVERMESSAGETYPE__H__ diff --git a/dCommon/dEnums/eWaypointCommandType.h b/dCommon/dEnums/eWaypointCommandType.h new file mode 100644 index 000000000..308f37647 --- /dev/null +++ b/dCommon/dEnums/eWaypointCommandType.h @@ -0,0 +1,59 @@ + +#ifndef __EWAYPOINTCOMMANDTYPES__H__ +#define __EWAYPOINTCOMMANDTYPES__H__ + +#include + +enum class eWaypointCommandType : uint32_t { + INVALID, + BOUNCE, + STOP, + GROUP_EMOTE, + SET_VARIABLE, + CAST_SKILL, + EQUIP_INVENTORY, + UNEQUIP_INVENTORY, + DELAY, + EMOTE, + TELEPORT, + PATH_SPEED, + REMOVE_NPC, + CHANGE_WAYPOINT, + DELETE_SELF, + KILL_SELF, + SPAWN_OBJECT, + PLAY_SOUND, +}; + +class WaypointCommandType { +public: + static eWaypointCommandType StringToWaypointCommandType(std::string commandString) { + const std::map WaypointCommandTypeMap = { + {"bounce", eWaypointCommandType::BOUNCE}, + {"stop", eWaypointCommandType::STOP}, + {"groupemote", eWaypointCommandType::GROUP_EMOTE}, + {"setvar", eWaypointCommandType::SET_VARIABLE}, + {"castskill", eWaypointCommandType::CAST_SKILL}, + {"eqInvent", eWaypointCommandType::EQUIP_INVENTORY}, + {"unInvent", eWaypointCommandType::UNEQUIP_INVENTORY}, + {"delay", eWaypointCommandType::DELAY}, + {"femote", eWaypointCommandType::EMOTE}, + {"emote", eWaypointCommandType::EMOTE}, + {"teleport", eWaypointCommandType::TELEPORT}, + {"pathspeed", eWaypointCommandType::PATH_SPEED}, + {"removeNPC", eWaypointCommandType::REMOVE_NPC}, + {"changeWP", eWaypointCommandType::CHANGE_WAYPOINT}, + {"DeleteSelf", eWaypointCommandType::DELETE_SELF}, + {"killself", eWaypointCommandType::KILL_SELF}, + {"removeself", eWaypointCommandType::DELETE_SELF}, + {"spawnOBJ", eWaypointCommandType::SPAWN_OBJECT}, + {"playSound", eWaypointCommandType::PLAY_SOUND}, + }; + + auto intermed = WaypointCommandTypeMap.find(commandString); + return (intermed != WaypointCommandTypeMap.end()) ? intermed->second : eWaypointCommandType::INVALID; + }; +}; + + +#endif //!__EWAYPOINTCOMMANDTYPES__H__ diff --git a/dCommon/dEnums/eWorldMessageType.h b/dCommon/dEnums/eWorldMessageType.h deleted file mode 100644 index bfaa110bb..000000000 --- a/dCommon/dEnums/eWorldMessageType.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __EWORLDMESSAGETYPE__H__ -#define __EWORLDMESSAGETYPE__H__ - -#include - -#include "magic_enum.hpp" - -enum class eWorldMessageType : uint32_t { - VALIDATION = 1, // Session info - CHARACTER_LIST_REQUEST, - CHARACTER_CREATE_REQUEST, - LOGIN_REQUEST, // Character selected - GAME_MSG, - CHARACTER_DELETE_REQUEST, - CHARACTER_RENAME_REQUEST, - HAPPY_FLOWER_MODE_NOTIFY, - SLASH_RELOAD_MAP, // Reload map cmp - SLASH_PUSH_MAP_REQUEST, // Push map req cmd - SLASH_PUSH_MAP, // Push map cmd - SLASH_PULL_MAP, // Pull map cmd - LOCK_MAP_REQUEST, - GENERAL_CHAT_MESSAGE, // General chat message - HTTP_MONITOR_INFO_REQUEST, - SLASH_DEBUG_SCRIPTS, // Debug scripts cmd - MODELS_CLEAR, - EXHIBIT_INSERT_MODEL, - LEVEL_LOAD_COMPLETE, // Character data request - TMP_GUILD_CREATE, - ROUTE_PACKET, // Social? - POSITION_UPDATE, - MAIL, - WORD_CHECK, // Whitelist word check - STRING_CHECK, // Whitelist string check - GET_PLAYERS_IN_ZONE, - REQUEST_UGC_MANIFEST_INFO, - BLUEPRINT_GET_ALL_DATA_REQUEST, - CANCEL_MAP_QUEUE, - HANDLE_FUNNESS, - FAKE_PRG_CSR_MESSAGE, - REQUEST_FREE_TRIAL_REFRESH, - GM_SET_FREE_TRIAL_STATUS, - UI_HELP_TOP_5 = 91 -}; - -template <> -struct magic_enum::customize::enum_range { - static constexpr int min = 0; - static constexpr int max = 91; -}; - -#endif //!__EWORLDMESSAGETYPE__H__ diff --git a/dDatabase/CDClientDatabase/CDClientManager.cpp b/dDatabase/CDClientDatabase/CDClientManager.cpp index 0e05c0b83..6ecfb0ad0 100644 --- a/dDatabase/CDClientDatabase/CDClientManager.cpp +++ b/dDatabase/CDClientDatabase/CDClientManager.cpp @@ -25,6 +25,7 @@ #include "CDScriptComponentTable.h" #include "CDSkillBehaviorTable.h" #include "CDZoneTableTable.h" +#include "CDTamingBuildPuzzleTable.h" #include "CDVendorComponentTable.h" #include "CDActivitiesTable.h" #include "CDPackageComponentTable.h" @@ -41,8 +42,6 @@ #include "CDRewardCodesTable.h" #include "CDPetComponentTable.h" -#include - #ifndef CDCLIENT_CACHE_ALL // Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory. // A vanilla CDClient takes about 46MB of memory + the regular world data. @@ -55,13 +54,6 @@ #define CDCLIENT_DONT_CACHE_TABLE(x) #endif -class CDClientConnectionException : public std::exception { -public: - virtual const char* what() const throw() { - return "CDClientDatabase is not connected!"; - } -}; - // Using a macro to reduce repetitive code and issues from copy and paste. // As a note, ## in a macro is used to concatenate two tokens together. @@ -108,11 +100,14 @@ DEFINE_TABLE_STORAGE(CDRewardCodesTable); DEFINE_TABLE_STORAGE(CDRewardsTable); DEFINE_TABLE_STORAGE(CDScriptComponentTable); DEFINE_TABLE_STORAGE(CDSkillBehaviorTable); +DEFINE_TABLE_STORAGE(CDTamingBuildPuzzleTable); DEFINE_TABLE_STORAGE(CDVendorComponentTable); DEFINE_TABLE_STORAGE(CDZoneTableTable); void CDClientManager::LoadValuesFromDatabase() { - if (!CDClientDatabase::isConnected) throw CDClientConnectionException(); + if (!CDClientDatabase::isConnected) { + throw std::runtime_error{ "CDClientDatabase is not connected!" }; + } CDActivityRewardsTable::Instance().LoadValuesFromDatabase(); CDActivitiesTable::Instance().LoadValuesFromDatabase(); @@ -152,6 +147,7 @@ void CDClientManager::LoadValuesFromDatabase() { CDRewardsTable::Instance().LoadValuesFromDatabase(); CDScriptComponentTable::Instance().LoadValuesFromDatabase(); CDSkillBehaviorTable::Instance().LoadValuesFromDatabase(); + CDTamingBuildPuzzleTable::Instance().LoadValuesFromDatabase(); CDVendorComponentTable::Instance().LoadValuesFromDatabase(); CDZoneTableTable::Instance().LoadValuesFromDatabase(); } diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.cpp index d5e9d4dc6..0781897f5 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.cpp @@ -58,7 +58,7 @@ void CDLootTableTable::LoadValuesFromDatabase() { CDLootTable entry; uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1); - entries[lootTableIndex].push_back(ReadRow(tableData)); + entries[lootTableIndex].emplace_back(ReadRow(tableData)); tableData.nextRow(); } for (auto& [id, table] : entries) { @@ -66,7 +66,7 @@ void CDLootTableTable::LoadValuesFromDatabase() { } } -const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) { +const LootTableEntries& CDLootTableTable::GetTable(const uint32_t tableId) { auto& entries = GetEntriesMutable(); auto itr = entries.find(tableId); if (itr != entries.end()) { @@ -79,7 +79,7 @@ const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) { while (!tableData.eof()) { CDLootTable entry; - entries[tableId].push_back(ReadRow(tableData)); + entries[tableId].emplace_back(ReadRow(tableData)); tableData.nextRow(); } SortTable(entries[tableId]); diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.h index 416bd87ae..c88ba03cf 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDLootTableTable.h @@ -3,6 +3,8 @@ // Custom Classes #include "CDTable.h" +#include + struct CDLootTable { uint32_t itemid; //!< The LOT of the item uint32_t LootTableIndex; //!< The Loot Table Index @@ -20,6 +22,5 @@ class CDLootTableTable : public CDTable + struct CDMissionEmail { uint32_t ID; uint32_t messageType; diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.cpp index efe284d45..e475a9989 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.cpp @@ -20,18 +20,15 @@ void CDMissionNPCComponentTable::LoadValuesFromDatabase() { // Now get the data auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionNPCComponent"); while (!tableData.eof()) { - CDMissionNPCComponent entry; + auto& entry = entries.emplace_back(); 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", ""); - entries.push_back(entry); tableData.nextRow(); } - - tableData.finalize(); } //! Queries the table with a custom "where" clause diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.h index 1eba2fad0..dde812513 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMissionNPCComponentTable.h @@ -3,6 +3,8 @@ // Custom Classes #include "CDTable.h" +#include + struct CDMissionNPCComponent { uint32_t id; //!< The ID uint32_t missionID; //!< The Mission ID @@ -17,4 +19,3 @@ class CDMissionNPCComponentTable : public CDTable Query(std::function predicate); }; - diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.cpp index c5b6620fe..b95840327 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.cpp @@ -20,7 +20,7 @@ void CDMissionTasksTable::LoadValuesFromDatabase() { // Now get the data auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MissionTasks"); while (!tableData.eof()) { - CDMissionTasks entry; + auto& entry = entries.emplace_back(); entry.id = tableData.getIntField("id", -1); UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); entry.taskType = tableData.getIntField("taskType", -1); @@ -35,11 +35,8 @@ void CDMissionTasksTable::LoadValuesFromDatabase() { UNUSED(entry.localize = tableData.getIntField("localize", -1) == 1 ? true : false); UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); - entries.push_back(entry); tableData.nextRow(); } - - tableData.finalize(); } std::vector CDMissionTasksTable::Query(std::function predicate) { @@ -51,7 +48,7 @@ std::vector CDMissionTasksTable::Query(std::function CDMissionTasksTable::GetByMissionID(uint32_t missionID) { +std::vector CDMissionTasksTable::GetByMissionID(const uint32_t missionID) { std::vector tasks; // TODO: this should not be linear(?) and also shouldnt need to be a pointer diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.h index 975533591..60a210735 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMissionTasksTable.h @@ -3,6 +3,8 @@ // Custom Classes #include "CDTable.h" +#include + struct CDMissionTasks { uint32_t id; //!< The Mission ID that the task belongs to UNUSED(uint32_t locStatus); //!< ??? @@ -25,7 +27,7 @@ class CDMissionTasksTable : public CDTable Query(std::function predicate); - std::vector GetByMissionID(uint32_t missionID); + std::vector GetByMissionID(const uint32_t missionID); // TODO: Remove this and replace it with a proper lookup function. const CDTable::StorageType& GetEntries() const; diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.cpp index 97dcde9fc..c98254ea5 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.cpp @@ -22,7 +22,7 @@ void CDMissionsTable::LoadValuesFromDatabase() { // Now get the data auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Missions"); while (!tableData.eof()) { - CDMissions entry; + auto& entry = entries.emplace_back(); entry.id = tableData.getIntField("id", -1); entry.defined_type = tableData.getStringField("defined_type", ""); entry.defined_subtype = tableData.getStringField("defined_subtype", ""); @@ -76,7 +76,6 @@ void CDMissionsTable::LoadValuesFromDatabase() { UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1)); entry.reward_bankinventory = tableData.getIntField("reward_bankinventory", -1); - entries.push_back(entry); tableData.nextRow(); } tableData.finalize(); diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h index 5067f2e2b..c5ae0e88c 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h @@ -75,4 +75,3 @@ class CDMissionsTable : public CDTable> static CDMissions Default; }; - diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.cpp index 48964a590..cec27bb94 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.cpp @@ -20,7 +20,7 @@ void CDMovementAIComponentTable::LoadValuesFromDatabase() { // Now get the data auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM MovementAIComponent"); while (!tableData.eof()) { - CDMovementAIComponent entry; + auto& entry = entries.emplace_back(); entry.id = tableData.getIntField("id", -1); entry.MovementType = tableData.getStringField("MovementType", ""); entry.WanderChance = tableData.getFloatField("WanderChance", -1.0f); @@ -30,11 +30,8 @@ void CDMovementAIComponentTable::LoadValuesFromDatabase() { entry.WanderRadius = tableData.getFloatField("WanderRadius", -1.0f); entry.attachedPath = tableData.getStringField("attachedPath", ""); - entries.push_back(entry); tableData.nextRow(); } - - tableData.finalize(); } std::vector CDMovementAIComponentTable::Query(std::function predicate) { diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.h index 34d01e3dc..6671d9452 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMovementAIComponentTable.h @@ -3,6 +3,8 @@ // Custom Classes #include "CDTable.h" +#include + struct CDMovementAIComponent { uint32_t id; std::string MovementType; diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.cpp index 9933fe7f3..a07446b5a 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.cpp @@ -20,17 +20,14 @@ void CDObjectSkillsTable::LoadValuesFromDatabase() { // Now get the data auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ObjectSkills"); while (!tableData.eof()) { - CDObjectSkills entry; + auto &entry = entries.emplace_back(); entry.objectTemplate = tableData.getIntField("objectTemplate", -1); entry.skillID = tableData.getIntField("skillID", -1); entry.castOnType = tableData.getIntField("castOnType", -1); entry.AICombatWeight = tableData.getIntField("AICombatWeight", -1); - entries.push_back(entry); tableData.nextRow(); } - - tableData.finalize(); } std::vector CDObjectSkillsTable::Query(std::function predicate) { diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.h index a2a8d4407..731f6657b 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDObjectSkillsTable.h @@ -3,6 +3,8 @@ // Custom Classes #include "CDTable.h" +#include + struct CDObjectSkills { uint32_t objectTemplate; //!< The LOT of the item uint32_t skillID; //!< The Skill ID of the object diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.cpp index d1f6771e9..738a13ac2 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.cpp @@ -1,7 +1,7 @@ #include "CDObjectsTable.h" namespace { - CDObjects m_default; + CDObjects ObjDefault; }; void CDObjectsTable::LoadValuesFromDatabase() { @@ -20,8 +20,10 @@ void CDObjectsTable::LoadValuesFromDatabase() { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Objects"); auto& entries = GetEntriesMutable(); while (!tableData.eof()) { - CDObjects entry; - entry.id = tableData.getIntField("id", -1); + const uint32_t lot = tableData.getIntField("id", 0); + + auto& entry = entries[lot]; + entry.id = lot; entry.name = tableData.getStringField("name", ""); UNUSED_COLUMN(entry.placeable = tableData.getIntField("placeable", -1);) entry.type = tableData.getStringField("type", ""); @@ -36,35 +38,34 @@ void CDObjectsTable::LoadValuesFromDatabase() { UNUSED_COLUMN(entry.gate_version = tableData.getStringField("gate_version", "");) UNUSED_COLUMN(entry.HQ_valid = tableData.getIntField("HQ_valid", -1);) - entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); } - tableData.finalize(); - - m_default.id = 0; + ObjDefault.id = 0; } -const CDObjects& CDObjectsTable::GetByID(uint32_t LOT) { +const CDObjects& CDObjectsTable::GetByID(const uint32_t lot) { auto& entries = GetEntriesMutable(); - const auto& it = entries.find(LOT); + const auto& it = entries.find(lot); if (it != entries.end()) { return it->second; } auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Objects WHERE id = ?;"); - query.bind(1, static_cast(LOT)); + query.bind(1, static_cast(lot)); auto tableData = query.execQuery(); if (tableData.eof()) { - entries.insert(std::make_pair(LOT, m_default)); - return m_default; + entries.emplace(lot, ObjDefault); + return ObjDefault; } // Now get the data while (!tableData.eof()) { - CDObjects entry; - entry.id = tableData.getIntField("id", -1); + const uint32_t lot = tableData.getIntField("id", 0); + + auto& entry = entries[lot]; + entry.id = lot; entry.name = tableData.getStringField("name", ""); UNUSED(entry.placeable = tableData.getIntField("placeable", -1)); entry.type = tableData.getStringField("type", ""); @@ -79,17 +80,15 @@ const CDObjects& CDObjectsTable::GetByID(uint32_t LOT) { UNUSED(entry.gate_version = tableData.getStringField("gate_version", "")); UNUSED(entry.HQ_valid = tableData.getIntField("HQ_valid", -1)); - entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); } tableData.finalize(); - const auto& it2 = entries.find(LOT); + const auto& it2 = entries.find(lot); if (it2 != entries.end()) { return it2->second; } - return m_default; + return ObjDefault; } - diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.h index add21c8f1..13bb90fab 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDObjectsTable.h @@ -3,6 +3,8 @@ // Custom Classes #include "CDTable.h" +#include + struct CDObjects { uint32_t id; //!< The LOT of the object std::string name; //!< The internal name of the object @@ -24,6 +26,6 @@ class CDObjectsTable : public CDTable + struct CDPackageComponent { uint32_t id; uint32_t LootMatrixIndex; diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.cpp index f3371ecb8..80c101122 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDPetComponentTable.cpp @@ -50,7 +50,7 @@ void CDPetComponentTable::LoadValuesFromDatabase() { } void CDPetComponentTable::LoadValuesFromDefaults() { - GetEntriesMutable().insert(std::make_pair(defaultEntry.id, defaultEntry)); + GetEntriesMutable().emplace(defaultEntry.id, defaultEntry); } CDPetComponent& CDPetComponentTable::GetByID(const uint32_t componentID) { diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.cpp b/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.cpp index 34671f3c6..050312b11 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.cpp +++ b/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.cpp @@ -4,32 +4,31 @@ void CDPhysicsComponentTable::LoadValuesFromDatabase() { auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM PhysicsComponent"); auto& entries = GetEntriesMutable(); while (!tableData.eof()) { - CDPhysicsComponent entry; - entry.id = tableData.getIntField("id", -1); + const uint32_t componentID = tableData.getIntField("id", -1); + + auto& entry = entries[componentID]; + entry.id = componentID; 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"); + UNUSED_COLUMN(entry.jump = tableData.getIntField("jump", -1) != 0;) + UNUSED_COLUMN(entry.doubleJump = tableData.getIntField("doublejump", -1) != 0;) + entry.speed = static_cast(tableData.getFloatField("speed", -1)); + UNUSED_COLUMN(entry.rotSpeed = tableData.getFloatField("rotSpeed", -1);) + entry.playerHeight = static_cast(tableData.getFloatField("playerHeight")); + entry.playerRadius = static_cast(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")); + UNUSED_COLUMN(entry.airSpeed = tableData.getFloatField("airSpeed");) + UNUSED_COLUMN(entry.boundaryAsset = tableData.getStringField("boundaryAsset");) + UNUSED_COLUMN(entry.jumpAirSpeed = tableData.getFloatField("jumpAirSpeed");) + UNUSED_COLUMN(entry.friction = tableData.getFloatField("friction");) + UNUSED_COLUMN(entry.gravityVolumeAsset = tableData.getStringField("gravityVolumeAsset");) - entries.insert(std::make_pair(entry.id, entry)); tableData.nextRow(); } - - tableData.finalize(); } -CDPhysicsComponent* CDPhysicsComponentTable::GetByID(uint32_t componentID) { +CDPhysicsComponent* CDPhysicsComponentTable::GetByID(const uint32_t componentID) { auto& entries = GetEntriesMutable(); auto itr = entries.find(componentID); return itr != entries.end() ? &itr->second : nullptr; diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.h index f0a621390..b783a8264 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDPhysicsComponentTable.h @@ -1,5 +1,6 @@ #pragma once #include "CDTable.h" +#include #include struct CDPhysicsComponent { @@ -7,7 +8,7 @@ struct CDPhysicsComponent { bool bStatic; std::string physicsAsset; UNUSED(bool jump); - UNUSED(bool doublejump); + UNUSED(bool doubleJump); float speed; UNUSED(float rotSpeed); float playerHeight; @@ -26,5 +27,5 @@ class CDPhysicsComponentTable : public CDTable(tableData.getIntField("NPCLot", LOT_NULL)); + entries.emplace(lot, CDTamingBuildPuzzle{ + .puzzleModelLot = lot, + .validPieces{ tableData.getStringField("ValidPiecesLXF") }, + .timeLimit = static_cast(tableData.getFloatField("Timelimit", 30.0f)), + .numValidPieces = tableData.getIntField("NumValidPieces", 6), + .imaginationCost = tableData.getIntField("imagCostPerBuild", 10) + }); + tableData.nextRow(); + } +} + +const CDTamingBuildPuzzle* CDTamingBuildPuzzleTable::GetByLOT(const LOT lot) const { + const auto& entries = GetEntries(); + const auto itr = entries.find(lot); + return itr != entries.cend() ? &itr->second : nullptr; +} diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDTamingBuildPuzzleTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDTamingBuildPuzzleTable.h new file mode 100644 index 000000000..acbd65bfa --- /dev/null +++ b/dDatabase/CDClientDatabase/CDClientTables/CDTamingBuildPuzzleTable.h @@ -0,0 +1,60 @@ +#pragma once +#include "CDTable.h" + +/** + * Information for the minigame to be completed + */ +struct CDTamingBuildPuzzle { + UNUSED_COLUMN(uint32_t id = 0;) + + // The LOT of the object that is to be created + LOT puzzleModelLot = LOT_NULL; + + // The LOT of the NPC + UNUSED_COLUMN(LOT npcLot = LOT_NULL;) + + // The .lxfml file that contains the bricks required to build the model + std::string validPieces{}; + + // The .lxfml file that contains the bricks NOT required to build the model + UNUSED_COLUMN(std::string invalidPieces{};) + + // Difficulty value + UNUSED_COLUMN(int32_t difficulty = 1;) + + // The time limit to complete the build + float timeLimit = 30.0f; + + // The number of pieces required to complete the minigame + int32_t numValidPieces = 6; + + // Number of valid pieces + UNUSED_COLUMN(int32_t totalNumPieces = 16;) + + // Model name + UNUSED_COLUMN(std::string modelName{};) + + // The .lxfml file that contains the full model + UNUSED_COLUMN(std::string fullModel{};) + + // The duration of the pet taming minigame + UNUSED_COLUMN(float duration = 45.0f;) + + // The imagination cost for the tamer to start the minigame + int32_t imaginationCost = 10; +}; + +class CDTamingBuildPuzzleTable : public CDTable> { +public: + /** + * Load values from the CD client database + */ + void LoadValuesFromDatabase(); + + /** + * Gets the pet ability table corresponding to the pet LOT + * @returns A pointer to the corresponding table, or nullptr if one cannot be found + */ + [[nodiscard]] + const CDTamingBuildPuzzle* GetByLOT(const LOT lot) const; +}; diff --git a/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt b/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt index af401db29..f45516463 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt +++ b/dDatabase/CDClientDatabase/CDClientTables/CMakeLists.txt @@ -36,5 +36,6 @@ set(DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES "CDActivitiesTable.cpp" "CDRewardsTable.cpp" "CDScriptComponentTable.cpp" "CDSkillBehaviorTable.cpp" + "CDTamingBuildPuzzleTable.cpp" "CDVendorComponentTable.cpp" "CDZoneTableTable.cpp" PARENT_SCOPE) diff --git a/dDatabase/CDClientDatabase/CMakeLists.txt b/dDatabase/CDClientDatabase/CMakeLists.txt index 2645c2155..13d59ffbc 100644 --- a/dDatabase/CDClientDatabase/CMakeLists.txt +++ b/dDatabase/CDClientDatabase/CMakeLists.txt @@ -9,4 +9,28 @@ foreach(file ${DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES}) set(DDATABASE_CDCLIENTDATABASE_SOURCES ${DDATABASE_CDCLIENTDATABASE_SOURCES} "CDClientTables/${file}") endforeach() -set(DDATABASE_CDCLIENTDATABASE_SOURCES ${DDATABASE_CDCLIENTDATABASE_SOURCES} PARENT_SCOPE) +add_library(dDatabaseCDClient STATIC ${DDATABASE_CDCLIENTDATABASE_SOURCES}) +target_include_directories(dDatabaseCDClient PUBLIC "." + "CDClientTables" + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" +) +target_link_libraries(dDatabaseCDClient PRIVATE sqlite3) + +if (${CDCLIENT_CACHE_ALL}) + add_compile_definitions(dDatabaseCDClient PRIVATE CDCLIENT_CACHE_ALL=${CDCLIENT_CACHE_ALL}) +endif() + +file( + GLOB HEADERS_DDATABASE_CDCLIENT + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h + CDClientTables/*.h + *.h +) + +# Need to specify to use the CXX compiler language here or else we get errors including . +target_precompile_headers( + dDatabaseCDClient PRIVATE + "$<$:${HEADERS_DDATABASE_CDCLIENT}>" +) diff --git a/dDatabase/CMakeLists.txt b/dDatabase/CMakeLists.txt index f0fe54b4e..004bdc147 100644 --- a/dDatabase/CMakeLists.txt +++ b/dDatabase/CMakeLists.txt @@ -1,20 +1,7 @@ -set(DDATABASE_SOURCES) - add_subdirectory(CDClientDatabase) - -foreach(file ${DDATABASE_CDCLIENTDATABASE_SOURCES}) - set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "CDClientDatabase/${file}") -endforeach() - add_subdirectory(GameDatabase) -foreach(file ${DDATABASE_GAMEDATABASE_SOURCES}) - set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "GameDatabase/${file}") -endforeach() - -add_library(dDatabase STATIC ${DDATABASE_SOURCES}) -target_link_libraries(dDatabase sqlite3 mariadbConnCpp) - -if (${CDCLIENT_CACHE_ALL}) - add_compile_definitions(dDatabase CDCLIENT_CACHE_ALL=${CDCLIENT_CACHE_ALL}) -endif() +add_library(dDatabase STATIC "MigrationRunner.cpp") +target_include_directories(dDatabase PUBLIC ".") +target_link_libraries(dDatabase + PUBLIC dDatabaseCDClient dDatabaseGame) diff --git a/dDatabase/GameDatabase/CMakeLists.txt b/dDatabase/GameDatabase/CMakeLists.txt index c32007bb7..32fe414af 100644 --- a/dDatabase/GameDatabase/CMakeLists.txt +++ b/dDatabase/GameDatabase/CMakeLists.txt @@ -1,6 +1,5 @@ set(DDATABASE_GAMEDATABASE_SOURCES "Database.cpp" - "MigrationRunner.cpp" ) add_subdirectory(MySQL) @@ -9,4 +8,31 @@ foreach(file ${DDATABSE_DATABSES_MYSQL_SOURCES}) set(DDATABASE_GAMEDATABASE_SOURCES ${DDATABASE_GAMEDATABASE_SOURCES} "MySQL/${file}") endforeach() -set(DDATABASE_GAMEDATABASE_SOURCES ${DDATABASE_GAMEDATABASE_SOURCES} PARENT_SCOPE) +add_subdirectory(TestSQL) + +foreach(file ${DDATABSE_DATABSES_TEST_SQL_SOURCES}) + set(DDATABASE_GAMEDATABASE_SOURCES ${DDATABASE_GAMEDATABASE_SOURCES} "TestSQL/${file}") +endforeach() + +add_library(dDatabaseGame STATIC ${DDATABASE_GAMEDATABASE_SOURCES}) +target_include_directories(dDatabaseGame PUBLIC "." + "ITables" PRIVATE "MySQL" "TestSQL" + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" +) +target_link_libraries(dDatabaseGame + PUBLIC MariaDB::ConnCpp + INTERFACE dCommon) + +# Glob together all headers that need to be precompiled +file( + GLOB HEADERS_DDATABASE_GAME + LIST_DIRECTORIES false + ITables/*.h +) + +# Need to specify to use the CXX compiler language here or else we get errors including . +target_precompile_headers( + dDatabaseGame PRIVATE + "$<$:${HEADERS_DDATABASE_GAME}>" +) diff --git a/dDatabase/GameDatabase/Database.cpp b/dDatabase/GameDatabase/Database.cpp index cb4f989a3..fef9ab39a 100644 --- a/dDatabase/GameDatabase/Database.cpp +++ b/dDatabase/GameDatabase/Database.cpp @@ -38,3 +38,8 @@ void Database::Destroy(std::string source) { LOG("Trying to destroy database when it's not connected!"); } } + +void Database::_setDatabase(GameDatabase* const db) { + if (database) delete database; + database = db; +} diff --git a/dDatabase/GameDatabase/Database.h b/dDatabase/GameDatabase/Database.h index 3eb292d16..65b047222 100644 --- a/dDatabase/GameDatabase/Database.h +++ b/dDatabase/GameDatabase/Database.h @@ -9,4 +9,8 @@ namespace Database { void Connect(); GameDatabase* Get(); void Destroy(std::string source = ""); + + // Used for assigning a test database as the handler for database logic. + // Do not use in production code. + void _setDatabase(GameDatabase* const db); }; diff --git a/dDatabase/GameDatabase/GameDatabase.h b/dDatabase/GameDatabase/GameDatabase.h index bcd8550ba..f52c8c4e2 100644 --- a/dDatabase/GameDatabase/GameDatabase.h +++ b/dDatabase/GameDatabase/GameDatabase.h @@ -23,6 +23,7 @@ #include "IActivityLog.h" #include "IIgnoreList.h" #include "IAccountsRewardCodes.h" +#include "IBehaviors.h" namespace sql { class Statement; @@ -40,7 +41,8 @@ class GameDatabase : public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports, public IPropertyContents, public IProperty, public IPetNames, public ICharXml, public IMigrationHistory, public IUgc, public IFriends, public ICharInfo, - public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList { + public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList, + public IBehaviors { public: virtual ~GameDatabase() = default; // TODO: These should be made private. diff --git a/dDatabase/GameDatabase/ITables/IAccounts.h b/dDatabase/GameDatabase/ITables/IAccounts.h index 1b1f85a74..a0377f4ba 100644 --- a/dDatabase/GameDatabase/ITables/IAccounts.h +++ b/dDatabase/GameDatabase/ITables/IAccounts.h @@ -3,6 +3,7 @@ #include #include +#include #include enum class eGameMasterLevel : uint8_t; @@ -32,6 +33,9 @@ class IAccounts { // Add a new account to the database. virtual void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) = 0; + + // Update the GameMaster level of an account. + virtual void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) = 0; }; #endif //!__IACCOUNTS__H__ diff --git a/dDatabase/GameDatabase/ITables/IBehaviors.h b/dDatabase/GameDatabase/ITables/IBehaviors.h new file mode 100644 index 000000000..531167e2e --- /dev/null +++ b/dDatabase/GameDatabase/ITables/IBehaviors.h @@ -0,0 +1,22 @@ +#ifndef IBEHAVIORS_H +#define IBEHAVIORS_H + +#include + +#include "dCommonVars.h" + +class IBehaviors { +public: + struct Info { + int32_t behaviorId{}; + uint32_t characterId{}; + std::string behaviorInfo; + }; + + // This Add also takes care of updating if it exists. + virtual void AddBehavior(const Info& info) = 0; + virtual std::string GetBehavior(const int32_t behaviorId) = 0; + virtual void RemoveBehavior(const int32_t behaviorId) = 0; +}; + +#endif //!IBEHAVIORS_H diff --git a/dDatabase/GameDatabase/ITables/IPropertyContents.h b/dDatabase/GameDatabase/ITables/IPropertyContents.h index c862ca943..0d8d8b5cf 100644 --- a/dDatabase/GameDatabase/ITables/IPropertyContents.h +++ b/dDatabase/GameDatabase/ITables/IPropertyContents.h @@ -1,6 +1,7 @@ #ifndef __IPROPERTIESCONTENTS__H__ #define __IPROPERTIESCONTENTS__H__ +#include #include #include @@ -16,6 +17,7 @@ class IPropertyContents { LWOOBJID id{}; LOT lot{}; uint32_t ugcId{}; + std::array behaviors{}; }; // Inserts a new UGC model into the database. @@ -32,7 +34,7 @@ class IPropertyContents { virtual void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) = 0; // Update the model position and rotation for the given property id. - virtual void UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) = 0; + virtual void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array, 5>& behaviors) = 0; // Remove the model for the given property id. virtual void RemoveModel(const LWOOBJID& modelId) = 0; diff --git a/dDatabase/GameDatabase/MySQL/MySQLDatabase.cpp b/dDatabase/GameDatabase/MySQL/MySQLDatabase.cpp index 259c3866e..20e92677a 100644 --- a/dDatabase/GameDatabase/MySQL/MySQLDatabase.cpp +++ b/dDatabase/GameDatabase/MySQL/MySQLDatabase.cpp @@ -4,6 +4,7 @@ #include "Game.h" #include "dConfig.h" #include "Logger.h" +#include "dPlatforms.h" namespace { std::string databaseName; @@ -39,14 +40,13 @@ void MySQLDatabase::Connect() { properties["autoReconnect"] = "true"; databaseName = Game::config->GetValue("mysql_database").c_str(); - // `connect(const Properties& props)` segfaults in windows debug, but // `connect(const SQLString& host, const SQLString& user, const SQLString& pwd)` doesn't handle pipes/unix sockets correctly - if (properties.find("localSocket") != properties.end() || properties.find("pipe") != properties.end()) { - con = driver->connect(properties); - } else { +#if defined(DARKFLAME_PLATFORM_WIN32) && defined(_DEBUG) con = driver->connect(properties["hostName"].c_str(), properties["user"].c_str(), properties["password"].c_str()); - } +#else + con = driver->connect(properties); +#endif con->setSchema(databaseName.c_str()); } diff --git a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h index 836ab56c4..a3019bea3 100644 --- a/dDatabase/GameDatabase/MySQL/MySQLDatabase.h +++ b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h @@ -74,7 +74,7 @@ class MySQLDatabase : public GameDatabase { std::vector GetPropertyModels(const LWOOBJID& propertyId) override; void RemoveUnreferencedUgcModels() override; void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) override; - void UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) override; + void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array, 5>& behaviors) override; void RemoveModel(const LWOOBJID& modelId) override; void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override; void InsertNewBugReport(const IBugReports::Info& info) override; @@ -108,6 +108,10 @@ class MySQLDatabase : public GameDatabase { std::vector GetIgnoreList(const uint32_t playerId) override; void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override; std::vector GetRewardCodesByAccountID(const uint32_t account_id) override; + void AddBehavior(const IBehaviors::Info& info) override; + std::string GetBehavior(const int32_t behaviorId) override; + void RemoveBehavior(const int32_t characterId) override; + void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) override; private: // Generic query functions that can be used for any query. diff --git a/dDatabase/GameDatabase/MySQL/Tables/Accounts.cpp b/dDatabase/GameDatabase/MySQL/Tables/Accounts.cpp index 801f444db..9e9812f30 100644 --- a/dDatabase/GameDatabase/MySQL/Tables/Accounts.cpp +++ b/dDatabase/GameDatabase/MySQL/Tables/Accounts.cpp @@ -35,3 +35,7 @@ void MySQLDatabase::UpdateAccountPassword(const uint32_t accountId, const std::s void MySQLDatabase::InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) { ExecuteInsert("INSERT INTO accounts (name, password, gm_level) VALUES (?, ?, ?);", username, bcryptpassword, static_cast(eGameMasterLevel::OPERATOR)); } + +void MySQLDatabase::UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) { + ExecuteUpdate("UPDATE accounts SET gm_level = ? WHERE id = ?;", static_cast(gmLevel), accountId); +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/Behaviors.cpp b/dDatabase/GameDatabase/MySQL/Tables/Behaviors.cpp new file mode 100644 index 000000000..f46478659 --- /dev/null +++ b/dDatabase/GameDatabase/MySQL/Tables/Behaviors.cpp @@ -0,0 +1,19 @@ +#include "IBehaviors.h" + +#include "MySQLDatabase.h" + +void MySQLDatabase::AddBehavior(const IBehaviors::Info& info) { + ExecuteInsert( + "INSERT INTO behaviors (behavior_info, character_id, behavior_id) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE behavior_info = ?", + info.behaviorInfo, info.characterId, info.behaviorId, info.behaviorInfo + ); +} + +void MySQLDatabase::RemoveBehavior(const int32_t behaviorId) { + ExecuteDelete("DELETE FROM behaviors WHERE behavior_id = ?", behaviorId); +} + +std::string MySQLDatabase::GetBehavior(const int32_t behaviorId) { + auto result = ExecuteSelect("SELECT behavior_info FROM behaviors WHERE behavior_id = ?", behaviorId); + return result->next() ? result->getString("behavior_info").c_str() : ""; +} diff --git a/dDatabase/GameDatabase/MySQL/Tables/CMakeLists.txt b/dDatabase/GameDatabase/MySQL/Tables/CMakeLists.txt index 9f0e7baa6..47cd220ea 100644 --- a/dDatabase/GameDatabase/MySQL/Tables/CMakeLists.txt +++ b/dDatabase/GameDatabase/MySQL/Tables/CMakeLists.txt @@ -2,6 +2,7 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES "Accounts.cpp" "AccountsRewardCodes.cpp" "ActivityLog.cpp" + "Behaviors.cpp" "BugReports.cpp" "CharInfo.cpp" "CharXml.cpp" diff --git a/dDatabase/GameDatabase/MySQL/Tables/PropertyContents.cpp b/dDatabase/GameDatabase/MySQL/Tables/PropertyContents.cpp index dba82d560..05998785e 100644 --- a/dDatabase/GameDatabase/MySQL/Tables/PropertyContents.cpp +++ b/dDatabase/GameDatabase/MySQL/Tables/PropertyContents.cpp @@ -1,7 +1,10 @@ #include "MySQLDatabase.h" std::vector MySQLDatabase::GetPropertyModels(const LWOOBJID& propertyId) { - auto result = ExecuteSelect("SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id FROM properties_contents WHERE property_id = ?;", propertyId); + auto result = ExecuteSelect( + "SELECT id, lot, x, y, z, rx, ry, rz, rw, ugc_id, " + "behavior_1, behavior_2, behavior_3, behavior_4, behavior_5 " + "FROM properties_contents WHERE property_id = ?;", propertyId); std::vector toReturn; toReturn.reserve(result->rowsCount()); @@ -17,6 +20,12 @@ std::vector MySQLDatabase::GetPropertyModels(const LWO model.rotation.y = result->getFloat("ry"); model.rotation.z = result->getFloat("rz"); model.ugcId = result->getUInt64("ugc_id"); + model.behaviors[0] = result->getInt("behavior_1"); + model.behaviors[1] = result->getInt("behavior_2"); + model.behaviors[2] = result->getInt("behavior_3"); + model.behaviors[3] = result->getInt("behavior_4"); + model.behaviors[4] = result->getInt("behavior_5"); + toReturn.push_back(std::move(model)); } return toReturn; @@ -32,21 +41,23 @@ void MySQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const IPr model.id, propertyId, model.ugcId == 0 ? std::nullopt : std::optional(model.ugcId), static_cast(model.lot), model.position.x, model.position.y, model.position.z, model.rotation.x, model.rotation.y, model.rotation.z, model.rotation.w, name, "", // Model description. TODO implement this. - 0, // behavior 1. TODO implement this. - 0, // behavior 2. TODO implement this. - 0, // behavior 3. TODO implement this. - 0, // behavior 4. TODO implement this. - 0 // behavior 5. TODO implement this. + model.behaviors[0], // behavior 1 + model.behaviors[1], // behavior 2 + model.behaviors[2], // behavior 3 + model.behaviors[3], // behavior 4 + model.behaviors[4] // behavior 5 ); } catch (sql::SQLException& e) { LOG("Error inserting new property model: %s", e.what()); } } -void MySQLDatabase::UpdateModelPositionRotation(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation) { +void MySQLDatabase::UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array, 5>& behaviors) { ExecuteUpdate( - "UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ? WHERE id = ?;", - position.x, position.y, position.z, rotation.x, rotation.y, rotation.z, rotation.w, propertyId); + "UPDATE properties_contents SET x = ?, y = ?, z = ?, rx = ?, ry = ?, rz = ?, rw = ?, " + "behavior_1 = ?, behavior_2 = ?, behavior_3 = ?, behavior_4 = ?, behavior_5 = ? WHERE id = ?;", + position.x, position.y, position.z, rotation.x, rotation.y, rotation.z, rotation.w, + behaviors[0].first, behaviors[1].first, behaviors[2].first, behaviors[3].first, behaviors[4].first, propertyId); } void MySQLDatabase::RemoveModel(const LWOOBJID& modelId) { diff --git a/dDatabase/GameDatabase/TestSQL/CMakeLists.txt b/dDatabase/GameDatabase/TestSQL/CMakeLists.txt new file mode 100644 index 000000000..cf07f4197 --- /dev/null +++ b/dDatabase/GameDatabase/TestSQL/CMakeLists.txt @@ -0,0 +1,4 @@ +SET(DDATABSE_DATABSES_TEST_SQL_SOURCES + "TestSQLDatabase.cpp" + PARENT_SCOPE +) diff --git a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp new file mode 100644 index 000000000..e44cd1f7c --- /dev/null +++ b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.cpp @@ -0,0 +1,306 @@ +#include "TestSQLDatabase.h" + +void TestSQLDatabase::Connect() { + +} + +void TestSQLDatabase::Destroy(std::string source) { + +} + +sql::PreparedStatement* TestSQLDatabase::CreatePreppedStmt(const std::string& query) { + return nullptr; +} + +void TestSQLDatabase::Commit() { + +} + +bool TestSQLDatabase::GetAutoCommit() { + return {}; +} + +void TestSQLDatabase::SetAutoCommit(bool value) { + +} + +void TestSQLDatabase::ExecuteCustomQuery(const std::string_view query) { + +} + +std::optional TestSQLDatabase::GetMasterInfo() { + return {}; +} + +std::vector TestSQLDatabase::GetApprovedCharacterNames() { + return {}; +} + +std::vector TestSQLDatabase::GetFriendsList(uint32_t charID) { + return {}; +} + +std::optional TestSQLDatabase::GetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId) { + return {}; +} + +void TestSQLDatabase::SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) { + +} + +void TestSQLDatabase::AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) { + +} + +void TestSQLDatabase::RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) { + +} + +void TestSQLDatabase::UpdateActivityLog(const uint32_t characterId, const eActivityType activityType, const LWOMAPID mapId) { + +} + +void TestSQLDatabase::DeleteUgcModelData(const LWOOBJID& modelId) { + +} + +void TestSQLDatabase::UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) { + +} + +std::vector TestSQLDatabase::GetAllUgcModels() { + return {}; +} + +void TestSQLDatabase::CreateMigrationHistoryTable() { + +} + +bool TestSQLDatabase::IsMigrationRun(const std::string_view str) { + return {}; +} + +void TestSQLDatabase::InsertMigration(const std::string_view str) { + +} + +std::optional TestSQLDatabase::GetCharacterInfo(const uint32_t charId) { + return {}; +} + +std::optional TestSQLDatabase::GetCharacterInfo(const std::string_view charId) { + return {}; +} + +std::string TestSQLDatabase::GetCharacterXml(const uint32_t accountId) { + return {}; +} + +void TestSQLDatabase::UpdateCharacterXml(const uint32_t characterId, const std::string_view lxfml) { + +} + +std::optional TestSQLDatabase::GetAccountInfo(const std::string_view username) { + return {}; +} + +void TestSQLDatabase::InsertNewCharacter(const ICharInfo::Info info) { + +} + +void TestSQLDatabase::InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) { + +} + +std::vector TestSQLDatabase::GetAccountCharacterIds(uint32_t accountId) { + return {}; +} + +void TestSQLDatabase::DeleteCharacter(const uint32_t characterId) { + +} + +void TestSQLDatabase::SetCharacterName(const uint32_t characterId, const std::string_view name) { + +} + +void TestSQLDatabase::SetPendingCharacterName(const uint32_t characterId, const std::string_view name) { + +} + +void TestSQLDatabase::UpdateLastLoggedInCharacter(const uint32_t characterId) { + +} + +void TestSQLDatabase::SetPetNameModerationStatus(const LWOOBJID& petId, const IPetNames::Info& info) { + +} + +std::optional TestSQLDatabase::GetPetNameInfo(const LWOOBJID& petId) { + return {}; +} + +std::optional TestSQLDatabase::GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) { + return {}; +} + +void TestSQLDatabase::UpdatePropertyModerationInfo(const IProperty::Info& info) { + +} + +void TestSQLDatabase::UpdatePropertyDetails(const IProperty::Info& info) { + +} + +void TestSQLDatabase::InsertNewProperty(const IProperty::Info& info, const uint32_t templateId, const LWOZONEID& zoneId) { + +} + +std::vector TestSQLDatabase::GetPropertyModels(const LWOOBJID& propertyId) { + return {}; +} + +void TestSQLDatabase::RemoveUnreferencedUgcModels() { + +} + +void TestSQLDatabase::InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) { + +} + +void TestSQLDatabase::UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array, 5>& behaviors) { + +} + +void TestSQLDatabase::RemoveModel(const LWOOBJID& modelId) { + +} + +void TestSQLDatabase::UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) { + +} + +void TestSQLDatabase::InsertNewBugReport(const IBugReports::Info& info) { + +} + +void TestSQLDatabase::InsertCheatDetection(const IPlayerCheatDetections::Info& info) { + +} + +void TestSQLDatabase::InsertNewMail(const IMail::MailInfo& mail) { + +} + +void TestSQLDatabase::InsertNewUgcModel(std::istringstream& sd0Data, const uint32_t blueprintId, const uint32_t accountId, const uint32_t characterId) { + +} + +std::vector TestSQLDatabase::GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) { + return {}; +} + +std::optional TestSQLDatabase::GetMail(const uint64_t mailId) { + return {}; +} + +uint32_t TestSQLDatabase::GetUnreadMailCount(const uint32_t characterId) { + return {}; +} + +void TestSQLDatabase::MarkMailRead(const uint64_t mailId) { + +} + +void TestSQLDatabase::DeleteMail(const uint64_t mailId) { + +} + +void TestSQLDatabase::ClaimMailItem(const uint64_t mailId) { + +} + +void TestSQLDatabase::InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) { + +} + +void TestSQLDatabase::UpdateAccountUnmuteTime(const uint32_t accountId, const uint64_t timeToUnmute) { + +} + +void TestSQLDatabase::UpdateAccountBan(const uint32_t accountId, const bool banned) { + +} + +void TestSQLDatabase::UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) { + +} + +void TestSQLDatabase::InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) { + +} + +void TestSQLDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) { + +} + +std::optional TestSQLDatabase::GetCurrentPersistentId() { + return {}; +} + +void TestSQLDatabase::InsertDefaultPersistentId() { + +} + +void TestSQLDatabase::UpdatePersistentId(const uint32_t id) { + +} + +std::optional TestSQLDatabase::GetDonationTotal(const uint32_t activityId) { + return {}; +} + +std::optional TestSQLDatabase::IsPlaykeyActive(const int32_t playkeyId) { + return {}; +} + +std::vector TestSQLDatabase::GetUgcModels(const LWOOBJID& propertyId) { + return {}; +} + +void TestSQLDatabase::AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) { + +} + +void TestSQLDatabase::RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) { + +} + +std::vector TestSQLDatabase::GetIgnoreList(const uint32_t playerId) { + return {}; +} + +void TestSQLDatabase::InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) { + +} + +std::vector TestSQLDatabase::GetRewardCodesByAccountID(const uint32_t account_id) { + return {}; +} + +void TestSQLDatabase::AddBehavior(const IBehaviors::Info& info) { + +} + +std::string TestSQLDatabase::GetBehavior(const int32_t behaviorId) { + return {}; +} + +void TestSQLDatabase::RemoveBehavior(const int32_t behaviorId) { + +} + +void TestSQLDatabase::UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) { + +} + diff --git a/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h new file mode 100644 index 000000000..6fbdf879f --- /dev/null +++ b/dDatabase/GameDatabase/TestSQL/TestSQLDatabase.h @@ -0,0 +1,95 @@ +#ifndef TESTSQLDATABASE_H +#define TESTSQLDATABASE_H + +#include "GameDatabase.h" + +class TestSQLDatabase : public GameDatabase { + void Connect() override; + void Destroy(std::string source = "") override; + + sql::PreparedStatement* CreatePreppedStmt(const std::string& query) override; + void Commit() override; + bool GetAutoCommit() override; + void SetAutoCommit(bool value) override; + void ExecuteCustomQuery(const std::string_view query) override; + + // Overloaded queries + std::optional GetMasterInfo() override; + + std::vector GetApprovedCharacterNames() override; + + std::vector GetFriendsList(uint32_t charID) override; + + std::optional GetBestFriendStatus(const uint32_t playerCharacterId, const uint32_t friendCharacterId) override; + void SetBestFriendStatus(const uint32_t playerAccountId, const uint32_t friendAccountId, const uint32_t bestFriendStatus) override; + void AddFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) override; + void RemoveFriend(const uint32_t playerAccountId, const uint32_t friendAccountId) override; + void UpdateActivityLog(const uint32_t characterId, const eActivityType activityType, const LWOMAPID mapId) override; + void DeleteUgcModelData(const LWOOBJID& modelId) override; + void UpdateUgcModelData(const LWOOBJID& modelId, std::istringstream& lxfml) override; + std::vector GetAllUgcModels() override; + void CreateMigrationHistoryTable() override; + bool IsMigrationRun(const std::string_view str) override; + void InsertMigration(const std::string_view str) override; + std::optional GetCharacterInfo(const uint32_t charId) override; + std::optional GetCharacterInfo(const std::string_view charId) override; + std::string GetCharacterXml(const uint32_t accountId) override; + void UpdateCharacterXml(const uint32_t characterId, const std::string_view lxfml) override; + std::optional GetAccountInfo(const std::string_view username) override; + void InsertNewCharacter(const ICharInfo::Info info) override; + void InsertCharacterXml(const uint32_t accountId, const std::string_view lxfml) override; + std::vector GetAccountCharacterIds(uint32_t accountId) override; + void DeleteCharacter(const uint32_t characterId) override; + void SetCharacterName(const uint32_t characterId, const std::string_view name) override; + void SetPendingCharacterName(const uint32_t characterId, const std::string_view name) override; + void UpdateLastLoggedInCharacter(const uint32_t characterId) override; + void SetPetNameModerationStatus(const LWOOBJID& petId, const IPetNames::Info& info) override; + std::optional GetPetNameInfo(const LWOOBJID& petId) override; + std::optional GetPropertyInfo(const LWOMAPID mapId, const LWOCLONEID cloneId) override; + void UpdatePropertyModerationInfo(const IProperty::Info& info) override; + void UpdatePropertyDetails(const IProperty::Info& info) override; + void InsertNewProperty(const IProperty::Info& info, const uint32_t templateId, const LWOZONEID& zoneId) override; + std::vector GetPropertyModels(const LWOOBJID& propertyId) override; + void RemoveUnreferencedUgcModels() override; + void InsertNewPropertyModel(const LWOOBJID& propertyId, const IPropertyContents::Model& model, const std::string_view name) override; + void UpdateModel(const LWOOBJID& propertyId, const NiPoint3& position, const NiQuaternion& rotation, const std::array, 5>& behaviors) override; + void RemoveModel(const LWOOBJID& modelId) override; + void UpdatePerformanceCost(const LWOZONEID& zoneId, const float performanceCost) override; + void InsertNewBugReport(const IBugReports::Info& info) override; + void InsertCheatDetection(const IPlayerCheatDetections::Info& info) override; + void InsertNewMail(const IMail::MailInfo& mail) override; + void InsertNewUgcModel( + std::istringstream& sd0Data, + const uint32_t blueprintId, + const uint32_t accountId, + const uint32_t characterId) override; + std::vector GetMailForPlayer(const uint32_t characterId, const uint32_t numberOfMail) override; + std::optional GetMail(const uint64_t mailId) override; + uint32_t GetUnreadMailCount(const uint32_t characterId) override; + void MarkMailRead(const uint64_t mailId) override; + void DeleteMail(const uint64_t mailId) override; + void ClaimMailItem(const uint64_t mailId) override; + void InsertSlashCommandUsage(const uint32_t characterId, const std::string_view command) override; + void UpdateAccountUnmuteTime(const uint32_t accountId, const uint64_t timeToUnmute) override; + void UpdateAccountBan(const uint32_t accountId, const bool banned) override; + void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override; + void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override; + void SetMasterIp(const std::string_view ip, const uint32_t port) override; + std::optional GetCurrentPersistentId() override; + void InsertDefaultPersistentId() override; + void UpdatePersistentId(const uint32_t id) override; + std::optional GetDonationTotal(const uint32_t activityId) override; + std::optional IsPlaykeyActive(const int32_t playkeyId) override; + std::vector GetUgcModels(const LWOOBJID& propertyId) override; + void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override; + void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override; + std::vector GetIgnoreList(const uint32_t playerId) override; + void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override; + std::vector GetRewardCodesByAccountID(const uint32_t account_id) override; + void AddBehavior(const IBehaviors::Info& info) override; + std::string GetBehavior(const int32_t behaviorId) override; + void RemoveBehavior(const int32_t behaviorId) override; + void UpdateAccountGmLevel(const uint32_t accountId, const eGameMasterLevel gmLevel) override; +}; + +#endif //!TESTSQLDATABASE_H diff --git a/dDatabase/GameDatabase/MigrationRunner.cpp b/dDatabase/MigrationRunner.cpp similarity index 100% rename from dDatabase/GameDatabase/MigrationRunner.cpp rename to dDatabase/MigrationRunner.cpp diff --git a/dDatabase/GameDatabase/MigrationRunner.h b/dDatabase/MigrationRunner.h similarity index 100% rename from dDatabase/GameDatabase/MigrationRunner.h rename to dDatabase/MigrationRunner.h diff --git a/dGame/CMakeLists.txt b/dGame/CMakeLists.txt index 627f163a9..26eb859a9 100644 --- a/dGame/CMakeLists.txt +++ b/dGame/CMakeLists.txt @@ -13,11 +13,25 @@ include_directories( ${PROJECT_SOURCE_DIR}/dGame ) -add_library(dGameBase ${DGAME_SOURCES}) +add_library(dGameBase OBJECT ${DGAME_SOURCES}) target_precompile_headers(dGameBase PRIVATE ${HEADERS_DGAME}) -target_link_libraries(dGameBase - PUBLIC dDatabase dPhysics - INTERFACE dComponents dEntity) +target_include_directories(dGameBase PUBLIC "." "dEntity" + PRIVATE "dComponents" "dGameMessages" "dBehaviors" "dMission" "dUtilities" "dInventory" + $ + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" + "${PROJECT_SOURCE_DIR}/dCommon/dClient" + # dDatabase + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables" + "${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include" + # dPhysics + "${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Include" + "${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Include" + "${PROJECT_SOURCE_DIR}/dZoneManager" +) add_subdirectory(dBehaviors) add_subdirectory(dComponents) @@ -28,7 +42,26 @@ add_subdirectory(dMission) add_subdirectory(dPropertyBehaviors) add_subdirectory(dUtilities) -add_library(dGame INTERFACE) -target_link_libraries(dGame INTERFACE - dGameBase dBehaviors dComponents dEntity dGameMessages dInventory dMission dPropertyBehaviors dUtilities dScripts +add_library(dGame STATIC + $ + $ + $ + $ + $ + $ + $ + $ + $ +) +target_link_libraries(dGame INTERFACE dNet) +target_include_directories(dGame INTERFACE + $ + $ + $ + $ + $ + $ + $ + $ + $ ) diff --git a/dGame/Character.cpp b/dGame/Character.cpp index eab7583f8..2e62dae85 100644 --- a/dGame/Character.cpp +++ b/dGame/Character.cpp @@ -27,12 +27,11 @@ Character::Character(uint32_t id, User* parentUser) { m_ID = id; m_ParentUser = parentUser; m_OurEntity = nullptr; - m_Doc = nullptr; + m_GMLevel = eGameMasterLevel::CIVILIAN; + m_PermissionMap = static_cast(0); } Character::~Character() { - if (m_Doc) delete m_Doc; - m_Doc = nullptr; m_OurEntity = nullptr; m_ParentUser = nullptr; } @@ -41,8 +40,8 @@ void Character::UpdateInfoFromDatabase() { auto charInfo = Database::Get()->GetCharacterInfo(m_ID); if (charInfo) { - m_Name = charInfo->name; - m_UnapprovedName = charInfo->pendingName; + m_Name = charInfo->name; + m_UnapprovedName = charInfo->pendingName; m_NameRejected = charInfo->needsRename; m_PropertyCloneID = charInfo->cloneId; m_PermissionMap = charInfo->permissionMap; @@ -55,8 +54,6 @@ void Character::UpdateInfoFromDatabase() { m_ZoneInstanceID = 0; //These values don't really matter, these are only used on the char select screen and seem unused. m_ZoneCloneID = 0; - m_Doc = nullptr; - //Quickly and dirtly parse the xmlData to get the info we need: DoQuickXMLDataParse(); @@ -70,26 +67,21 @@ void Character::UpdateInfoFromDatabase() { } void Character::UpdateFromDatabase() { - if (m_Doc) delete m_Doc; UpdateInfoFromDatabase(); } void Character::DoQuickXMLDataParse() { if (m_XMLData.size() == 0) return; - delete m_Doc; - m_Doc = new tinyxml2::XMLDocument(); - if (!m_Doc) return; - - if (m_Doc->Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) { + if (m_Doc.Parse(m_XMLData.c_str(), m_XMLData.size()) == 0) { LOG("Loaded xmlData for character %s (%i)!", m_Name.c_str(), m_ID); } else { - LOG("Failed to load xmlData!"); + LOG("Failed to load xmlData (%i) (%s) (%s)!", m_Doc.ErrorID(), m_Doc.ErrorIDToName(m_Doc.ErrorID()), m_Doc.ErrorStr()); //Server::rakServer->CloseConnection(m_ParentUser->GetSystemAddress(), true); return; } - tinyxml2::XMLElement* mf = m_Doc->FirstChildElement("obj")->FirstChildElement("mf"); + tinyxml2::XMLElement* mf = m_Doc.FirstChildElement("obj")->FirstChildElement("mf"); if (!mf) { LOG("Failed to find mf tag!"); return; @@ -108,7 +100,7 @@ void Character::DoQuickXMLDataParse() { mf->QueryAttribute("ess", &m_Eyes); mf->QueryAttribute("ms", &m_Mouth); - tinyxml2::XMLElement* inv = m_Doc->FirstChildElement("obj")->FirstChildElement("inv"); + tinyxml2::XMLElement* inv = m_Doc.FirstChildElement("obj")->FirstChildElement("inv"); if (!inv) { LOG("Char has no inv!"); return; @@ -141,7 +133,7 @@ void Character::DoQuickXMLDataParse() { } - tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); + tinyxml2::XMLElement* character = m_Doc.FirstChildElement("obj")->FirstChildElement("char"); if (character) { character->QueryAttribute("cc", &m_Coins); int32_t gm_level = 0; @@ -205,7 +197,7 @@ void Character::DoQuickXMLDataParse() { character->QueryAttribute("lzrw", &m_OriginalRotation.w); } - auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag"); if (flags) { auto* currentChild = flags->FirstChildElement(); while (currentChild) { @@ -239,12 +231,10 @@ void Character::SetBuildMode(bool buildMode) { } void Character::SaveXMLToDatabase() { - if (!m_Doc) return; - //For metrics, we'll record the time it took to save: auto start = std::chrono::system_clock::now(); - tinyxml2::XMLElement* character = m_Doc->FirstChildElement("obj")->FirstChildElement("char"); + tinyxml2::XMLElement* character = m_Doc.FirstChildElement("obj")->FirstChildElement("char"); if (character) { character->SetAttribute("gm", static_cast(m_GMLevel)); character->SetAttribute("cc", m_Coins); @@ -266,11 +256,11 @@ void Character::SaveXMLToDatabase() { } auto emotes = character->FirstChildElement("ue"); - if (!emotes) emotes = m_Doc->NewElement("ue"); + if (!emotes) emotes = m_Doc.NewElement("ue"); emotes->DeleteChildren(); for (int emoteID : m_UnlockedEmotes) { - auto emote = m_Doc->NewElement("e"); + auto emote = m_Doc.NewElement("e"); emote->SetAttribute("id", emoteID); emotes->LinkEndChild(emote); @@ -280,15 +270,15 @@ void Character::SaveXMLToDatabase() { } //Export our flags: - auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag"); if (!flags) { - flags = m_Doc->NewElement("flag"); //Create a flags tag if we don't have one - m_Doc->FirstChildElement("obj")->LinkEndChild(flags); //Link it to the obj tag so we can find next time + flags = m_Doc.NewElement("flag"); //Create a flags tag if we don't have one + m_Doc.FirstChildElement("obj")->LinkEndChild(flags); //Link it to the obj tag so we can find next time } flags->DeleteChildren(); //Clear it if we have anything, so that we can fill it up again without dupes for (std::pair flag : m_PlayerFlags) { - auto* f = m_Doc->NewElement("f"); + auto* f = m_Doc.NewElement("f"); f->SetAttribute("id", flag.first); //Because of the joy that is tinyxml2, it doesn't offer a function to set a uint64 as an attribute. @@ -301,7 +291,7 @@ void Character::SaveXMLToDatabase() { // Prevents the news feed from showing up on world transfers if (GetPlayerFlag(ePlayerFlag::IS_NEWS_SCREEN_VISIBLE)) { - auto* s = m_Doc->NewElement("s"); + auto* s = m_Doc.NewElement("s"); s->SetAttribute("si", ePlayerFlag::IS_NEWS_SCREEN_VISIBLE); flags->LinkEndChild(s); } @@ -326,7 +316,7 @@ void Character::SaveXMLToDatabase() { void Character::SetIsNewLogin() { // If we dont have a flag element, then we cannot have a s element as a child of flag. - auto* flags = m_Doc->FirstChildElement("obj")->FirstChildElement("flag"); + auto* flags = m_Doc.FirstChildElement("obj")->FirstChildElement("flag"); if (!flags) return; auto* currentChild = flags->FirstChildElement(); @@ -344,7 +334,7 @@ void Character::SetIsNewLogin() { void Character::WriteToDatabase() { //Dump our xml into m_XMLData: tinyxml2::XMLPrinter printer(0, true, 0); - m_Doc->Print(&printer); + m_Doc.Print(&printer); //Finally, save to db: Database::Get()->UpdateCharacterXml(m_ID, printer.CStr()); @@ -421,15 +411,15 @@ void Character::SetRetroactiveFlags() { void Character::SaveXmlRespawnCheckpoints() { //Export our respawn points: - auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res"); + auto* points = m_Doc.FirstChildElement("obj")->FirstChildElement("res"); if (!points) { - points = m_Doc->NewElement("res"); - m_Doc->FirstChildElement("obj")->LinkEndChild(points); + points = m_Doc.NewElement("res"); + m_Doc.FirstChildElement("obj")->LinkEndChild(points); } points->DeleteChildren(); for (const auto& point : m_WorldRespawnCheckpoints) { - auto* r = m_Doc->NewElement("r"); + auto* r = m_Doc.NewElement("r"); r->SetAttribute("w", point.first); r->SetAttribute("x", point.second.x); @@ -443,7 +433,7 @@ void Character::SaveXmlRespawnCheckpoints() { void Character::LoadXmlRespawnCheckpoints() { m_WorldRespawnCheckpoints.clear(); - auto* points = m_Doc->FirstChildElement("obj")->FirstChildElement("res"); + auto* points = m_Doc.FirstChildElement("obj")->FirstChildElement("res"); if (!points) { return; } diff --git a/dGame/Character.h b/dGame/Character.h index b994fb61a..0f41c634c 100644 --- a/dGame/Character.h +++ b/dGame/Character.h @@ -37,7 +37,8 @@ class Character { void LoadXmlRespawnCheckpoints(); const std::string& GetXMLData() const { return m_XMLData; } - tinyxml2::XMLDocument* GetXMLDoc() const { return m_Doc; } + const tinyxml2::XMLDocument& GetXMLDoc() const { return m_Doc; } + void _setXmlDoc(tinyxml2::XMLDocument& doc) { doc.DeepCopy(&m_Doc); } /** * Out of abundance of safety and clarity of what this saves, this is its own function. @@ -459,27 +460,31 @@ class Character { User* GetParentUser() const { return m_ParentUser; } + void _doQuickXMLDataParse() { DoQuickXMLDataParse(); } + + void _setXmlData(const std::string& xmlData) { m_XMLData = xmlData; } + private: void UpdateInfoFromDatabase(); /** * The ID of this character. First 32 bits of the ObjectID. */ - uint32_t m_ID; + uint32_t m_ID{}; /** * The 64-bit unique ID used in the game. */ - LWOOBJID m_ObjectID; + LWOOBJID m_ObjectID{ LWOOBJID_EMPTY }; /** * The user that owns this character. */ - User* m_ParentUser; + User* m_ParentUser{}; /** * If the character is in game, this is the entity that it represents, else nullptr. */ - Entity* m_OurEntity; + Entity* m_OurEntity{}; /** * 0-9, the Game Master level of this character. @@ -506,17 +511,17 @@ class Character { /** * Whether the custom name of this character is rejected */ - bool m_NameRejected; + bool m_NameRejected{}; /** * The current amount of coins of this character */ - int64_t m_Coins; + int64_t m_Coins{}; /** * Whether the character is building */ - bool m_BuildMode; + bool m_BuildMode{}; /** * The items equipped by the character on world load @@ -583,7 +588,7 @@ class Character { /** * The ID of the properties of this character */ - uint32_t m_PropertyCloneID; + uint32_t m_PropertyCloneID{}; /** * The XML data for this character, stored as string @@ -613,7 +618,7 @@ class Character { /** * The last time this character logged in */ - uint64_t m_LastLogin; + uint64_t m_LastLogin{}; /** * The gameplay flags this character has (not just true values) @@ -623,7 +628,7 @@ class Character { /** * The character XML belonging to this character */ - tinyxml2::XMLDocument* m_Doc; + tinyxml2::XMLDocument m_Doc; /** * Title of an announcement this character made (reserved for GMs) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 55b2b85fc..8066ce619 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -24,7 +24,7 @@ #include "eTriggerEventType.h" #include "eObjectBits.h" #include "PositionUpdate.h" -#include "eChatMessageType.h" +#include "MessageType/Chat.h" #include "PlayerManager.h" //Component includes: @@ -96,6 +96,8 @@ #include "CDSkillBehaviorTable.h" #include "CDZoneTableTable.h" +Observable Entity::OnPlayerPositionUpdate; + Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Entity* parentEntity) { m_ObjectID = objectID; m_TemplateID = info.lot; @@ -146,17 +148,15 @@ Entity::~Entity() { return; } - Entity* zoneControl = Game::entityManager->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerExit(zoneControl, this); + auto* zoneControl = Game::entityManager->GetZoneControlEntity(); + if (zoneControl) { + zoneControl->GetScript()->OnPlayerExit(zoneControl, this); } std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerExit(scriptEntity, this); - } + scriptEntity->GetScript()->OnPlayerExit(scriptEntity, this); } } } @@ -227,7 +227,7 @@ void Entity::Initialize() { AddComponent(simplePhysicsComponentID); - AddComponent(); + AddComponent()->LoadBehaviors(); AddComponent(); @@ -478,8 +478,7 @@ void Entity::Initialize() { } if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::INVENTORY) > 0 || m_Character) { - auto* xmlDoc = m_Character ? m_Character->GetXMLDoc() : nullptr; - AddComponent(xmlDoc); + AddComponent(); } // if this component exists, then we initialize it. it's value is always 0 if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MULTI_ZONE_ENTRANCE, -1) != -1) { @@ -652,7 +651,7 @@ void Entity::Initialize() { } if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MODEL, -1) != -1 && !GetComponent()) { - AddComponent(); + AddComponent()->LoadBehaviors(); if (!HasComponent(eReplicaComponentType::DESTROYABLE)) { auto* destroyableComponent = AddComponent(); destroyableComponent->SetHealth(1); @@ -733,15 +732,21 @@ void Entity::Initialize() { // if we have a moving platform path, then we need a moving platform component if (path->pathType == PathType::MovingPlatform) { AddComponent(pathName); - // else if we are a movement path - } /*else if (path->pathType == PathType::Movement) { - auto movementAIcomp = GetComponent(); - if (movementAIcomp){ - // TODO: set path in existing movementAIComp + } else if (path->pathType == PathType::Movement) { + auto movementAIcomponent = GetComponent(); + if (movementAIcomponent && combatAiId == 0) { + movementAIcomponent->SetPath(pathName); } else { - // TODO: create movementAIcomp and set path + MovementAIInfo moveInfo = MovementAIInfo(); + moveInfo.movementType = ""; + moveInfo.wanderChance = 0; + moveInfo.wanderRadius = 16; + moveInfo.wanderSpeed = 2.5f; + moveInfo.wanderDelayMax = 5; + moveInfo.wanderDelayMin = 2; + AddComponent(moveInfo); } - }*/ + } } else { // else we still need to setup moving platform if it has a moving platform comp but no path int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1); @@ -762,9 +767,7 @@ void Entity::Initialize() { // Hacky way to trigger these when the object has had a chance to get constructed AddCallbackTimer(0, [this]() { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnStartup(this); - } + this->GetScript()->OnStartup(this); }); if (!m_Character && Game::entityManager->GetGhostingEnabled()) { @@ -839,17 +842,6 @@ bool Entity::HasComponent(const eReplicaComponentType componentId) const { return m_Components.find(componentId) != m_Components.end(); } -std::vector Entity::GetScriptComponents() { - std::vector comps; - for (std::pair p : m_Components) { - if (p.first == eReplicaComponentType::SCRIPT) { - comps.push_back(static_cast(p.second)); - } - } - - return comps; -} - void Entity::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName) { if (notificationName == "HitOrHealResult" || notificationName == "Hit") { auto* destroyableComponent = GetComponent(); @@ -891,7 +883,7 @@ void Entity::SetGMLevel(eGameMasterLevel value) { // Update the chat server of our GM Level { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GMLEVEL_UPDATE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GMLEVEL_UPDATE); bitStream.Write(m_ObjectID); bitStream.Write(m_GMLevel); @@ -1253,7 +1245,7 @@ void Entity::WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType outBitStream.Write0(); } -void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) { +void Entity::UpdateXMLDoc(tinyxml2::XMLDocument& doc) { //This function should only ever be called from within Character, meaning doc should always exist when this is called. //Naturally, we don't include any non-player components in this update function. @@ -1278,9 +1270,7 @@ void Entity::Update(const float deltaTime) { // Remove the timer from the list of timers first so that scripts and events can remove timers without causing iterator invalidation auto timerName = timer.GetName(); m_Timers.erase(m_Timers.begin() + timerPosition); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnTimerDone(this, timerName); - } + GetScript()->OnTimerDone(this, timerName); TriggerEvent(eTriggerEventType::TIMER_DONE, this); } else { @@ -1326,9 +1316,7 @@ void Entity::Update(const float deltaTime) { Wake(); } - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnUpdate(this); - } + GetScript()->OnUpdate(this); for (const auto& pair : m_Components) { if (pair.second == nullptr) continue; @@ -1345,9 +1333,7 @@ void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxN Entity* other = Game::entityManager->GetEntity(otherEntity); if (!other) return; - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnProximityUpdate(this, other, proxName, status); - } + GetScript()->OnProximityUpdate(this, other, proxName, status); RocketLaunchpadControlComponent* rocketComp = GetComponent(); if (!rocketComp) return; @@ -1359,9 +1345,7 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) { auto* other = Game::entityManager->GetEntity(otherEntity); if (!other) return; - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnCollisionPhantom(this, other); - } + GetScript()->OnCollisionPhantom(this, other); for (const auto& callback : m_PhantomCollisionCallbacks) { callback(other); @@ -1400,9 +1384,7 @@ void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) { auto* other = Game::entityManager->GetEntity(otherEntity); if (!other) return; - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnOffCollisionPhantom(this, other); - } + GetScript()->OnOffCollisionPhantom(this, other); TriggerEvent(eTriggerEventType::EXIT, other); @@ -1419,46 +1401,32 @@ void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) { } void Entity::OnFireEventServerSide(Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnFireEventServerSide(this, sender, args, param1, param2, param3); - } + GetScript()->OnFireEventServerSide(this, sender, args, param1, param2, param3); } void Entity::OnActivityStateChangeRequest(LWOOBJID senderID, int32_t value1, int32_t value2, const std::u16string& stringValue) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnActivityStateChangeRequest(this, senderID, value1, value2, stringValue); - } + GetScript()->OnActivityStateChangeRequest(this, senderID, value1, value2, stringValue); } void Entity::OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName, float_t pathTime, float_t totalTime, int32_t waypoint) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnCinematicUpdate(self, sender, event, pathName, pathTime, totalTime, waypoint); - } + GetScript()->OnCinematicUpdate(self, sender, event, pathName, pathTime, totalTime, waypoint); } void Entity::NotifyObject(Entity* sender, const std::string& name, int32_t param1, int32_t param2) { GameMessages::SendNotifyObject(GetObjectID(), sender->GetObjectID(), GeneralUtils::ASCIIToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnNotifyObject(this, sender, name, param1, param2); - } + GetScript()->OnNotifyObject(this, sender, name, param1, param2); } void Entity::OnEmoteReceived(const int32_t emote, Entity* target) { - for (auto* script : CppScripts::GetEntityScripts(this)) { - script->OnEmoteReceived(this, emote, target); - } + GetScript()->OnEmoteReceived(this, emote, target); } void Entity::OnUse(Entity* originator) { TriggerEvent(eTriggerEventType::INTERACT, originator); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnUse(this, originator); - } - - // component base class when + GetScript()->OnUse(this, originator); for (const auto& pair : m_Components) { if (pair.second == nullptr) continue; @@ -1468,82 +1436,63 @@ void Entity::OnUse(Entity* originator) { } void Entity::OnHitOrHealResult(Entity* attacker, int32_t damage) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnHitOrHealResult(this, attacker, damage); - } + GetScript()->OnHitOrHealResult(this, attacker, damage); } void Entity::OnHit(Entity* attacker) { TriggerEvent(eTriggerEventType::HIT, attacker); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnHit(this, attacker); - } + GetScript()->OnHit(this, attacker); } void Entity::OnZonePropertyEditBegin() { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnZonePropertyEditBegin(this); - } + GetScript()->OnZonePropertyEditBegin(this); } void Entity::OnZonePropertyEditEnd() { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnZonePropertyEditEnd(this); - } + GetScript()->OnZonePropertyEditEnd(this); } void Entity::OnZonePropertyModelEquipped() { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnZonePropertyModelEquipped(this); - } + GetScript()->OnZonePropertyModelEquipped(this); } void Entity::OnZonePropertyModelPlaced(Entity* player) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnZonePropertyModelPlaced(this, player); - } + GetScript()->OnZonePropertyModelPlaced(this, player); } void Entity::OnZonePropertyModelPickedUp(Entity* player) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnZonePropertyModelPickedUp(this, player); - } + GetScript()->OnZonePropertyModelPickedUp(this, player); } void Entity::OnZonePropertyModelRemoved(Entity* player) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnZonePropertyModelRemoved(this, player); - } + GetScript()->OnZonePropertyModelRemoved(this, player); } void Entity::OnZonePropertyModelRemovedWhileEquipped(Entity* player) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnZonePropertyModelRemovedWhileEquipped(this, player); - } + GetScript()->OnZonePropertyModelRemovedWhileEquipped(this, player); } void Entity::OnZonePropertyModelRotated(Entity* player) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnZonePropertyModelRotated(this, player); - } + GetScript()->OnZonePropertyModelRotated(this, player); } void Entity::OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnMessageBoxResponse(this, sender, button, identifier, userData); - } + GetScript()->OnMessageBoxResponse(this, sender, button, identifier, userData); } void Entity::OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnChoiceBoxResponse(this, sender, button, buttonIdentifier, identifier); - } + GetScript()->OnChoiceBoxResponse(this, sender, button, buttonIdentifier, identifier); } void Entity::RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnRequestActivityExit(sender, player, canceled); - } + GetScript()->OnRequestActivityExit(sender, player, canceled); +} + +CppScripts::Script* const Entity::GetScript() { + auto* scriptComponent = GetComponent(); + auto* script = scriptComponent ? scriptComponent->GetScript() : CppScripts::GetInvalidScript(); + DluAssert(script != nullptr); + return script; } void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType) { @@ -1576,9 +1525,7 @@ void Entity::Kill(Entity* murderer, const eKillType killType) { //OMAI WA MOU, SHINDERIU - for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { - script->OnDie(this, murderer); - } + GetScript()->OnDie(this, murderer); if (m_Spawner != nullptr) { m_Spawner->NotifyOfEntityDeath(m_ObjectID); @@ -1589,7 +1536,7 @@ void Entity::Kill(Entity* murderer, const eKillType killType) { bool waitForDeathAnimation = false; if (destroyableComponent) { - waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0 && killType != eKillType::SILENT; + waitForDeathAnimation = !destroyableComponent->GetIsSmashable() && destroyableComponent->GetDeathBehavior() == 0 && killType != eKillType::SILENT; } // Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction! @@ -1689,10 +1636,8 @@ void Entity::PickupItem(const LWOOBJID& objectID) { CDObjectSkillsTable* skillsTable = CDClientManager::GetTable(); std::vector skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == p.second.lot); }); for (CDObjectSkills skill : skills) { - CDSkillBehaviorTable* skillBehTable = CDClientManager::GetTable(); - auto* skillComponent = GetComponent(); - if (skillComponent) skillComponent->CastSkill(skill.skillID, GetObjectID(), GetObjectID()); + if (skillComponent) skillComponent->CastSkill(skill.skillID, GetObjectID(), GetObjectID(), skill.castOnType, NiQuaternion(0, 0, 0, 0)); auto* missionComponent = GetComponent(); @@ -1897,6 +1842,12 @@ const NiPoint3& Entity::GetPosition() const { return vehicel->GetPosition(); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + return rigidBodyPhantomPhysicsComponent->GetPosition(); + } + return NiPoint3Constant::ZERO; } @@ -1925,6 +1876,12 @@ const NiQuaternion& Entity::GetRotation() const { return vehicel->GetRotation(); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + return rigidBodyPhantomPhysicsComponent->GetRotation(); + } + return NiQuaternionConstant::IDENTITY; } @@ -1953,6 +1910,12 @@ void Entity::SetPosition(const NiPoint3& position) { vehicel->SetPosition(position); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + rigidBodyPhantomPhysicsComponent->SetPosition(position); + } + Game::entityManager->SerializeEntity(this); } @@ -1981,6 +1944,12 @@ void Entity::SetRotation(const NiQuaternion& rotation) { vehicel->SetRotation(rotation); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + rigidBodyPhantomPhysicsComponent->SetRotation(rotation); + } + Game::entityManager->SerializeEntity(this); } @@ -2126,9 +2095,7 @@ void Entity::ProcessPositionUpdate(PositionUpdate& update) { havokVehiclePhysicsComponent->SetIsOnGround(update.onGround); havokVehiclePhysicsComponent->SetIsOnRail(update.onRail); havokVehiclePhysicsComponent->SetVelocity(update.velocity); - havokVehiclePhysicsComponent->SetDirtyVelocity(update.velocity != NiPoint3Constant::ZERO); havokVehiclePhysicsComponent->SetAngularVelocity(update.angularVelocity); - havokVehiclePhysicsComponent->SetDirtyAngularVelocity(update.angularVelocity != NiPoint3Constant::ZERO); havokVehiclePhysicsComponent->SetRemoteInputInfo(update.remoteInputInfo); } else { // Need to get the mount's controllable physics @@ -2139,9 +2106,7 @@ void Entity::ProcessPositionUpdate(PositionUpdate& update) { possessedControllablePhysicsComponent->SetIsOnGround(update.onGround); possessedControllablePhysicsComponent->SetIsOnRail(update.onRail); possessedControllablePhysicsComponent->SetVelocity(update.velocity); - possessedControllablePhysicsComponent->SetDirtyVelocity(update.velocity != NiPoint3Constant::ZERO); possessedControllablePhysicsComponent->SetAngularVelocity(update.angularVelocity); - possessedControllablePhysicsComponent->SetDirtyAngularVelocity(update.angularVelocity != NiPoint3Constant::ZERO); } Game::entityManager->SerializeEntity(possassableEntity); } @@ -2163,15 +2128,15 @@ void Entity::ProcessPositionUpdate(PositionUpdate& update) { controllablePhysicsComponent->SetIsOnGround(update.onGround); controllablePhysicsComponent->SetIsOnRail(update.onRail); controllablePhysicsComponent->SetVelocity(update.velocity); - controllablePhysicsComponent->SetDirtyVelocity(update.velocity != NiPoint3Constant::ZERO); controllablePhysicsComponent->SetAngularVelocity(update.angularVelocity); - controllablePhysicsComponent->SetDirtyAngularVelocity(update.angularVelocity != NiPoint3Constant::ZERO); auto* ghostComponent = GetComponent(); if (ghostComponent) ghostComponent->SetGhostReferencePoint(update.position); Game::entityManager->QueueGhostUpdate(GetObjectID()); if (updateChar) Game::entityManager->SerializeEntity(this); + + OnPlayerPositionUpdate.Notify(this, update); } const SystemAddress& Entity::GetSystemAddress() const { @@ -2197,9 +2162,3 @@ void Entity::SetRespawnRot(const NiQuaternion& rotation) { auto* characterComponent = GetComponent(); if (characterComponent) characterComponent->SetRespawnRot(rotation); } - -void Entity::SetScale(const float scale) { - if (scale == m_Scale) return; - m_Scale = scale; - Game::entityManager->SerializeEntity(this); -} \ No newline at end of file diff --git a/dGame/Entity.h b/dGame/Entity.h index 711e0b635..5d2b95272 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -11,6 +11,7 @@ #include "NiQuaternion.h" #include "LDFFormat.h" #include "eKillType.h" +#include "Observable.h" namespace Loot { class Info; @@ -146,7 +147,8 @@ class Entity { void AddComponent(eReplicaComponentType componentId, Component* component); - std::vector GetScriptComponents(); + // This is expceted to never return nullptr, an assert checks this. + CppScripts::Script* const GetScript(); void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, const std::string& notificationName); void Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationName); @@ -173,7 +175,7 @@ class Entity { void WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacketType packetType); void WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType packetType); - void UpdateXMLDoc(tinyxml2::XMLDocument* doc); + void UpdateXMLDoc(tinyxml2::XMLDocument& doc); void Update(float deltaTime); // Events @@ -295,8 +297,14 @@ class Entity { void ProcessPositionUpdate(PositionUpdate& update); - void SetScale(const float scale); + // Scale will only be communicated to the client when the construction packet is sent + void SetScale(const float scale) { m_Scale = scale; }; + /** + * @brief The observable for player entity position updates. + */ + static Observable OnPlayerPositionUpdate; + protected: LWOOBJID m_ObjectID; diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 4d648bbdc..c95af3d7f 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -418,10 +418,16 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) } void EntityManager::SerializeEntity(Entity* entity) { - if (!entity || entity->GetNetworkId() == 0) return; + if (!entity) return; + + EntityManager::SerializeEntity(*entity); +} + +void EntityManager::SerializeEntity(const Entity& entity) { + if (entity.GetNetworkId() == 0) return; - if (std::find(m_EntitiesToSerialize.begin(), m_EntitiesToSerialize.end(), entity->GetObjectID()) == m_EntitiesToSerialize.end()) { - m_EntitiesToSerialize.push_back(entity->GetObjectID()); + if (std::find(m_EntitiesToSerialize.cbegin(), m_EntitiesToSerialize.cend(), entity.GetObjectID()) == m_EntitiesToSerialize.cend()) { + m_EntitiesToSerialize.push_back(entity.GetObjectID()); } } diff --git a/dGame/EntityManager.h b/dGame/EntityManager.h index abffe5466..fdbb1a554 100644 --- a/dGame/EntityManager.h +++ b/dGame/EntityManager.h @@ -45,6 +45,7 @@ class EntityManager { void ConstructEntity(Entity* entity, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, bool skipChecks = false); void DestructEntity(Entity* entity, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SerializeEntity(Entity* entity); + void SerializeEntity(const Entity& entity); void ConstructAllEntities(const SystemAddress& sysAddr); void DestructAllEntities(const SystemAddress& sysAddr); diff --git a/dGame/User.cpp b/dGame/User.cpp index 0b2c3c3fc..806d46110 100644 --- a/dGame/User.cpp +++ b/dGame/User.cpp @@ -12,6 +12,7 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std: m_AccountID = 0; m_Username = ""; m_SessionKey = ""; + m_MuteExpire = 0; m_MaxGMLevel = eGameMasterLevel::CIVILIAN; //The max GM level this account can assign to it's characters m_LastCharID = 0; diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 0fde2eb66..e0e37e7cb 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -26,7 +26,7 @@ #include "eCharacterCreationResponse.h" #include "eRenameResponse.h" #include "eConnectionType.h" -#include "eChatInternalMessageType.h" +#include "MessageType/Chat.h" #include "BitStreamUtils.h" #include "CheatDetection.h" @@ -83,7 +83,7 @@ void UserManager::Initialize() { auto chatListStream = Game::assetManager->GetFile("chatplus_en_us.txt"); if (!chatListStream) { LOG("Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str()); - throw std::runtime_error("Aborting initialization due to missing chat whitelist file."); + throw std::runtime_error("Aborting initialization due to missing chat allowlist file."); } while (std::getline(chatListStream, line, '\n')) { @@ -216,7 +216,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) { } RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_LIST_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::CHARACTER_LIST_RESPONSE); std::vector characters = u->GetCharacters(); bitStream.Write(characters.size()); @@ -266,7 +266,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) { void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet) { User* u = GetUser(sysAddr); if (!u) return; - + LUWString LUWStringName; uint32_t firstNameIndex; uint32_t middleNameIndex; @@ -422,7 +422,7 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) Database::Get()->DeleteCharacter(charID); CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::UNEXPECTED_DISCONNECT); bitStream.Write(objectID); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); @@ -439,7 +439,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet) CINSTREAM_SKIP_HEADER; LWOOBJID objectID; - inStream.Read(objectID); + inStream.Read(objectID); GeneralUtils::ClearBit(objectID, eObjectBits::CHARACTER); GeneralUtils::ClearBit(objectID, eObjectBits::PERSISTENT); @@ -536,13 +536,13 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) { try { auto stmt = CDClientDatabase::CreatePreppedStmt( - "select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?" + "select obj.id as objectId from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?" ); stmt.bind(1, "character create shirt"); stmt.bind(2, static_cast(shirtColor)); stmt.bind(3, static_cast(shirtStyle)); auto tableData = stmt.execQuery(); - auto shirtLOT = tableData.getIntField(0, 4069); + auto shirtLOT = tableData.getIntField("objectId", 4069); tableData.finalize(); return shirtLOT; } catch (const std::exception& ex) { @@ -555,12 +555,12 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) { uint32_t FindCharPantsID(uint32_t pantsColor) { try { auto stmt = CDClientDatabase::CreatePreppedStmt( - "select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?" + "select obj.id as objectId from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?" ); stmt.bind(1, "cc pants"); stmt.bind(2, static_cast(pantsColor)); auto tableData = stmt.execQuery(); - auto pantsLOT = tableData.getIntField(0, 2508); + auto pantsLOT = tableData.getIntField("objectId", 2508); tableData.finalize(); return pantsLOT; } catch (const std::exception& ex) { diff --git a/dGame/dBehaviors/BasicAttackBehavior.cpp b/dGame/dBehaviors/BasicAttackBehavior.cpp index 3d45d9a77..97ceb846d 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.cpp +++ b/dGame/dBehaviors/BasicAttackBehavior.cpp @@ -222,7 +222,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet if (healthDamageDealt >= 1) { successState = eBasicAttackSuccessTypes::SUCCESS; } else if (armorDamageDealt >= 1) { - successState = this->m_OnFailArmor->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY ? eBasicAttackSuccessTypes::FAILIMMUNE : eBasicAttackSuccessTypes::FAILARMOR; + successState = this->m_OnFailArmor->m_templateId == BehaviorTemplate::EMPTY ? eBasicAttackSuccessTypes::FAILIMMUNE : eBasicAttackSuccessTypes::FAILARMOR; } bitStream.Write(armorDamageDealt); diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index 36607a666..7cefd4dd7 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -5,7 +5,7 @@ #include "CDActivitiesTable.h" #include "Game.h" #include "Logger.h" -#include "BehaviorTemplates.h" +#include "BehaviorTemplate.h" #include "BehaviorBranchContext.h" #include @@ -110,176 +110,176 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { Behavior* behavior = nullptr; switch (templateId) { - case BehaviorTemplates::BEHAVIOR_EMPTY: break; - case BehaviorTemplates::BEHAVIOR_BASIC_ATTACK: + case BehaviorTemplate::EMPTY: break; + case BehaviorTemplate::BASIC_ATTACK: behavior = new BasicAttackBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_TAC_ARC: + case BehaviorTemplate::TAC_ARC: behavior = new TacArcBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_AND: + case BehaviorTemplate::AND: behavior = new AndBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PROJECTILE_ATTACK: + case BehaviorTemplate::PROJECTILE_ATTACK: behavior = new ProjectileAttackBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_HEAL: + case BehaviorTemplate::HEAL: behavior = new HealBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_MOVEMENT_SWITCH: + case BehaviorTemplate::MOVEMENT_SWITCH: behavior = new MovementSwitchBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_AREA_OF_EFFECT: + case BehaviorTemplate::AREA_OF_EFFECT: behavior = new AreaOfEffectBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PLAY_EFFECT: + case BehaviorTemplate::PLAY_EFFECT: behavior = new PlayEffectBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_IMMUNITY: + case BehaviorTemplate::IMMUNITY: behavior = new ImmunityBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_DAMAGE_BUFF: break; - case BehaviorTemplates::BEHAVIOR_DAMAGE_ABSORBTION: + case BehaviorTemplate::DAMAGE_BUFF: break; + case BehaviorTemplate::DAMAGE_ABSORBTION: behavior = new DamageAbsorptionBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_OVER_TIME: + case BehaviorTemplate::OVER_TIME: behavior = new OverTimeBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_IMAGINATION: + case BehaviorTemplate::IMAGINATION: behavior = new ImaginationBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_TARGET_CASTER: + case BehaviorTemplate::TARGET_CASTER: behavior = new TargetCasterBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_STUN: + case BehaviorTemplate::STUN: behavior = new StunBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_DURATION: + case BehaviorTemplate::DURATION: behavior = new DurationBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_KNOCKBACK: + case BehaviorTemplate::KNOCKBACK: behavior = new KnockbackBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_ATTACK_DELAY: + case BehaviorTemplate::ATTACK_DELAY: behavior = new AttackDelayBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_CAR_BOOST: + case BehaviorTemplate::CAR_BOOST: behavior = new CarBoostBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_FALL_SPEED: + case BehaviorTemplate::FALL_SPEED: behavior = new FallSpeedBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_SHIELD: break; - case BehaviorTemplates::BEHAVIOR_REPAIR_ARMOR: + case BehaviorTemplate::SHIELD: break; + case BehaviorTemplate::REPAIR_ARMOR: behavior = new RepairBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_SPEED: + case BehaviorTemplate::SPEED: behavior = new SpeedBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION: + case BehaviorTemplate::DARK_INSPIRATION: behavior = new DarkInspirationBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_LOOT_BUFF: + case BehaviorTemplate::LOOT_BUFF: behavior = new LootBuffBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_VENTURE_VISION: + case BehaviorTemplate::VENTURE_VISION: behavior = new VentureVisionBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_SPAWN_OBJECT: + case BehaviorTemplate::SPAWN_OBJECT: behavior = new SpawnBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_LAY_BRICK: break; - case BehaviorTemplates::BEHAVIOR_SWITCH: + case BehaviorTemplate::LAY_BRICK: break; + case BehaviorTemplate::SWITCH: behavior = new SwitchBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_BUFF: + case BehaviorTemplate::BUFF: behavior = new BuffBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_JETPACK: + case BehaviorTemplate::JETPACK: behavior = new JetPackBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_SKILL_EVENT: + case BehaviorTemplate::SKILL_EVENT: behavior = new SkillEventBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_CONSUME_ITEM: + case BehaviorTemplate::CONSUME_ITEM: behavior = new ConsumeItemBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_SKILL_CAST_FAILED: + case BehaviorTemplate::SKILL_CAST_FAILED: behavior = new SkillCastFailedBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_IMITATION_SKUNK_STINK: break; - case BehaviorTemplates::BEHAVIOR_CHANGE_IDLE_FLAGS: + case BehaviorTemplate::IMITATION_SKUNK_STINK: break; + case BehaviorTemplate::CHANGE_IDLE_FLAGS: behavior = new ChangeIdleFlagsBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_APPLY_BUFF: + case BehaviorTemplate::APPLY_BUFF: behavior = new ApplyBuffBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_CHAIN: + case BehaviorTemplate::CHAIN: behavior = new ChainBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_CHANGE_ORIENTATION: + case BehaviorTemplate::CHANGE_ORIENTATION: behavior = new ChangeOrientationBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_FORCE_MOVEMENT: + case BehaviorTemplate::FORCE_MOVEMENT: behavior = new ForceMovementBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_INTERRUPT: + case BehaviorTemplate::INTERRUPT: behavior = new InterruptBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_ALTER_COOLDOWN: break; - case BehaviorTemplates::BEHAVIOR_CHARGE_UP: + case BehaviorTemplate::ALTER_COOLDOWN: break; + case BehaviorTemplate::CHARGE_UP: behavior = new ChargeUpBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_SWITCH_MULTIPLE: + case BehaviorTemplate::SWITCH_MULTIPLE: behavior = new SwitchMultipleBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_START: + case BehaviorTemplate::START: behavior = new StartBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_END: + case BehaviorTemplate::END: behavior = new EndBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_ALTER_CHAIN_DELAY: break; - case BehaviorTemplates::BEHAVIOR_CAMERA: break; - case BehaviorTemplates::BEHAVIOR_REMOVE_BUFF: + case BehaviorTemplate::ALTER_CHAIN_DELAY: break; + case BehaviorTemplate::CAMERA: break; + case BehaviorTemplate::REMOVE_BUFF: behavior = new RemoveBuffBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_GRAB: break; - case BehaviorTemplates::BEHAVIOR_MODULAR_BUILD: break; - case BehaviorTemplates::BEHAVIOR_NPC_COMBAT_SKILL: + case BehaviorTemplate::GRAB: break; + case BehaviorTemplate::MODULAR_BUILD: break; + case BehaviorTemplate::NPC_COMBAT_SKILL: behavior = new NpcCombatSkillBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_BLOCK: + case BehaviorTemplate::BLOCK: behavior = new BlockBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_VERIFY: + case BehaviorTemplate::VERIFY: behavior = new VerifyBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_TAUNT: + case BehaviorTemplate::TAUNT: behavior = new TauntBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_AIR_MOVEMENT: + case BehaviorTemplate::AIR_MOVEMENT: behavior = new AirMovementBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_SPAWN_QUICKBUILD: + case BehaviorTemplate::SPAWN_QUICKBUILD: behavior = new SpawnBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PULL_TO_POINT: + case BehaviorTemplate::PULL_TO_POINT: behavior = new PullToPointBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PROPERTY_ROTATE: break; - case BehaviorTemplates::BEHAVIOR_DAMAGE_REDUCTION: + case BehaviorTemplate::PROPERTY_ROTATE: break; + case BehaviorTemplate::DAMAGE_REDUCTION: behavior = new DamageReductionBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PROPERTY_TELEPORT: + case BehaviorTemplate::PROPERTY_TELEPORT: behavior = new PropertyTeleportBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_PROPERTY_CLEAR_TARGET: + case BehaviorTemplate::PROPERTY_CLEAR_TARGET: behavior = new ClearTargetBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_TAKE_PICTURE: break; - case BehaviorTemplates::BEHAVIOR_MOUNT: break; - case BehaviorTemplates::BEHAVIOR_SKILL_SET: break; + case BehaviorTemplate::TAKE_PICTURE: break; + case BehaviorTemplate::MOUNT: break; + case BehaviorTemplate::SKILL_SET: break; default: //LOG("Failed to load behavior with invalid template id (%i)!", templateId); break; @@ -296,19 +296,19 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { return behavior; } -BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) { +BehaviorTemplate Behavior::GetBehaviorTemplate(const uint32_t behaviorId) { auto behaviorTemplateTable = CDClientManager::GetTable(); - BehaviorTemplates templateID = BehaviorTemplates::BEHAVIOR_EMPTY; + BehaviorTemplate templateID = BehaviorTemplate::EMPTY; // Find behavior template by its behavior id. Default to 0. if (behaviorTemplateTable) { auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId); if (templateEntry.behaviorID == behaviorId) { - templateID = static_cast(templateEntry.templateID); + templateID = static_cast(templateEntry.templateID); } } - if (templateID == BehaviorTemplates::BEHAVIOR_EMPTY && behaviorId != 0) { + if (templateID == BehaviorTemplate::EMPTY && behaviorId != 0) { LOG("Failed to load behavior template with id (%i)!", behaviorId); } @@ -335,26 +335,22 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID const auto typeString = GeneralUtils::UTF16ToWTF8(type); - if (m_effectNames == nullptr) { - m_effectNames = new std::unordered_map(); - } else { - const auto pair = m_effectNames->find(typeString); - - if (type.empty()) { - type = GeneralUtils::ASCIIToUTF16(*m_effectType); - } + const auto itr = m_effectNames.find(typeString); - if (pair != m_effectNames->end()) { - if (renderComponent == nullptr) { - GameMessages::SendPlayFXEffect(targetEntity, effectId, type, pair->second, secondary, 1, 1, true); - - return; - } + if (type.empty()) { + type = GeneralUtils::ASCIIToUTF16(m_effectType); + } - renderComponent->PlayEffect(effectId, type, pair->second, secondary); + if (itr != m_effectNames.end()) { + if (renderComponent == nullptr) { + GameMessages::SendPlayFXEffect(targetEntity, effectId, type, itr->second, secondary, 1, 1, true); return; } + + renderComponent->PlayEffect(effectId, type, itr->second, secondary); + + return; } // The SQlite result object becomes invalid if the query object leaves scope. @@ -381,19 +377,19 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID return; } - const auto name = std::string(result.getStringField(0)); + const auto name = std::string(result.getStringField("effectName")); if (type.empty()) { - const auto typeResult = result.getStringField(1); + const auto typeResult = result.getStringField("effectType"); type = GeneralUtils::ASCIIToUTF16(typeResult); - m_effectType = new std::string(typeResult); + m_effectType = typeResult; } result.finalize(); - m_effectNames->insert_or_assign(typeString, name); + m_effectNames.insert_or_assign(typeString, name); if (renderComponent == nullptr) { GameMessages::SendPlayFXEffect(targetEntity, effectId, type, name, secondary, 1, 1, true); @@ -423,8 +419,7 @@ Behavior::Behavior(const uint32_t behaviorId) { if (behaviorId == 0) { this->m_effectId = 0; - this->m_effectHandle = nullptr; - this->m_templateId = BehaviorTemplates::BEHAVIOR_EMPTY; + this->m_templateId = BehaviorTemplate::EMPTY; } // Make sure we do not proceed if we are trying to load an invalid behavior @@ -432,17 +427,16 @@ Behavior::Behavior(const uint32_t behaviorId) { LOG("Failed to load behavior with id (%i)!", behaviorId); this->m_effectId = 0; - this->m_effectHandle = nullptr; - this->m_templateId = BehaviorTemplates::BEHAVIOR_EMPTY; + this->m_templateId = BehaviorTemplate::EMPTY; return; } - this->m_templateId = static_cast(templateInDatabase.templateID); + this->m_templateId = static_cast(templateInDatabase.templateID); this->m_effectId = templateInDatabase.effectID; - this->m_effectHandle = *templateInDatabase.effectHandle != "" ? new std::string(*templateInDatabase.effectHandle) : nullptr; + this->m_effectHandle = *templateInDatabase.effectHandle; } @@ -507,9 +501,3 @@ void Behavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, void Behavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { } - -Behavior::~Behavior() { - delete m_effectNames; - delete m_effectType; - delete m_effectHandle; -} diff --git a/dGame/dBehaviors/Behavior.h b/dGame/dBehaviors/Behavior.h index af7fd206f..f9867ffe1 100644 --- a/dGame/dBehaviors/Behavior.h +++ b/dGame/dBehaviors/Behavior.h @@ -6,7 +6,7 @@ #include #include "BitStream.h" -#include "BehaviorTemplates.h" +#include "BehaviorTemplate.h" #include "dCommonVars.h" struct BehaviorContext; @@ -26,7 +26,7 @@ class Behavior static Behavior* CreateBehavior(uint32_t behaviorId); - static BehaviorTemplates GetBehaviorTemplate(uint32_t behaviorId); + static BehaviorTemplate GetBehaviorTemplate(uint32_t behaviorId); /* * Utilities @@ -39,11 +39,11 @@ class Behavior */ uint32_t m_behaviorId; - BehaviorTemplates m_templateId; + BehaviorTemplate m_templateId; uint32_t m_effectId; - std::string* m_effectHandle = nullptr; - std::unordered_map* m_effectNames = nullptr; - std::string* m_effectType = nullptr; + std::string m_effectHandle; + std::unordered_map m_effectNames; + std::string m_effectType; /* * Behavior parameters @@ -88,5 +88,11 @@ class Behavior */ explicit Behavior(uint32_t behaviorId); - virtual ~Behavior(); + virtual ~Behavior() = default; + + Behavior(const Behavior& other) = default; + Behavior(Behavior&& other) = default; + + Behavior& operator=(const Behavior& other) = default; + Behavior& operator=(Behavior&& other) = default; }; diff --git a/dGame/dBehaviors/BehaviorContext.cpp b/dGame/dBehaviors/BehaviorContext.cpp index 5ca335b1b..452df3ada 100644 --- a/dGame/dBehaviors/BehaviorContext.cpp +++ b/dGame/dBehaviors/BehaviorContext.cpp @@ -105,7 +105,7 @@ void BehaviorContext::ExecuteUpdates() { this->scheduledUpdates.clear(); } -void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream& bitStream) { +bool BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream& bitStream) { BehaviorSyncEntry entry; auto found = false; @@ -128,7 +128,7 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream& bit if (!found) { LOG("Failed to find behavior sync entry with sync id (%i)!", syncId); - return; + return false; } auto* behavior = entry.behavior; @@ -137,10 +137,11 @@ void BehaviorContext::SyncBehavior(const uint32_t syncId, RakNet::BitStream& bit if (behavior == nullptr) { LOG("Invalid behavior for sync id (%i)!", syncId); - return; + return false; } behavior->Sync(this, bitStream, branch); + return true; } @@ -198,6 +199,26 @@ void BehaviorContext::UpdatePlayerSyncs(float deltaTime) { i++; continue; } + + if (this->skillUId != 0 && !clientInitalized) { + EchoSyncSkill echo; + echo.bDone = true; + echo.uiSkillHandle = this->skillUId; + echo.uiBehaviorHandle = entry.handle; + + RakNet::BitStream bitStream{}; + entry.behavior->SyncCalculation(this, bitStream, entry.branchContext); + + echo.sBitStream.assign(reinterpret_cast(bitStream.GetData()), bitStream.GetNumberOfBytesUsed()); + + RakNet::BitStream message; + BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, MessageType::Client::GAME_MSG); + message.Write(this->originator); + echo.Serialize(message); + + Game::server->Send(message, UNASSIGNED_SYSTEM_ADDRESS, true); + } + this->syncEntries.erase(this->syncEntries.begin() + i); } } @@ -224,6 +245,16 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) { for (auto i = 0u; i < this->syncEntries.size(); ++i) { auto entry = this->syncEntries.at(i); + if (entry.behavior->m_templateId == BehaviorTemplate::ATTACK_DELAY) { + auto* self = Game::entityManager->GetEntity(originator); + if (self) { + auto* destroyableComponent = self->GetComponent(); + if (destroyableComponent && destroyableComponent->GetHealth() <= 0) { + continue; + } + } + } + if (entry.time > 0) { entry.time -= deltaTime; @@ -254,7 +285,7 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) { // Write message RakNet::BitStream message; - BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); + BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, MessageType::Client::GAME_MSG); message.Write(this->originator); echo.Serialize(message); @@ -333,7 +364,7 @@ void BehaviorContext::FilterTargets(std::vector& targets, std::forward_ } // handle targeting the caster - if (candidate == caster){ + if (candidate == caster) { // if we aren't targeting self, erase, otherise increment and continue if (!targetSelf) index = targets.erase(index); else index++; @@ -356,24 +387,24 @@ void BehaviorContext::FilterTargets(std::vector& targets, std::forward_ } // if they are dead, then earse and continue - if (candidateDestroyableComponent->GetIsDead()){ + if (candidateDestroyableComponent->GetIsDead()) { index = targets.erase(index); continue; } // if their faction is explicitly included, increment and continue auto candidateFactions = candidateDestroyableComponent->GetFactionIDs(); - if (CheckFactionList(includeFactionList, candidateFactions)){ + if (CheckFactionList(includeFactionList, candidateFactions)) { index++; continue; } // check if they are a team member - if (targetTeam){ + if (targetTeam) { auto* team = TeamManager::Instance()->GetTeam(this->caster); - if (team){ + if (team) { // if we find a team member keep it and continue to skip enemy checks - if(std::find(team->members.begin(), team->members.end(), candidate->GetObjectID()) != team->members.end()){ + if (std::find(team->members.begin(), team->members.end(), candidate->GetObjectID()) != team->members.end()) { index++; continue; } @@ -419,8 +450,8 @@ bool BehaviorContext::CheckTargetingRequirements(const Entity* target) const { // returns true if any of the object factions are in the faction list bool BehaviorContext::CheckFactionList(std::forward_list& factionList, std::vector& objectsFactions) const { if (factionList.empty() || objectsFactions.empty()) return false; - for (auto faction : factionList){ - if(std::find(objectsFactions.begin(), objectsFactions.end(), faction) != objectsFactions.end()) return true; + for (auto faction : factionList) { + if (std::find(objectsFactions.begin(), objectsFactions.end(), faction) != objectsFactions.end()) return true; } return false; } diff --git a/dGame/dBehaviors/BehaviorContext.h b/dGame/dBehaviors/BehaviorContext.h index 3e6c0b1df..4922f736f 100644 --- a/dGame/dBehaviors/BehaviorContext.h +++ b/dGame/dBehaviors/BehaviorContext.h @@ -93,7 +93,7 @@ struct BehaviorContext void ExecuteUpdates(); - void SyncBehavior(uint32_t syncId, RakNet::BitStream& bitStream); + bool SyncBehavior(uint32_t syncId, RakNet::BitStream& bitStream); void Update(float deltaTime); diff --git a/dGame/dBehaviors/BehaviorTemplate.h b/dGame/dBehaviors/BehaviorTemplate.h new file mode 100644 index 000000000..175dce50c --- /dev/null +++ b/dGame/dBehaviors/BehaviorTemplate.h @@ -0,0 +1,70 @@ +#pragma once + +enum class BehaviorTemplate : unsigned int { + EMPTY, // Not a real behavior, indicates invalid behaviors + BASIC_ATTACK, + TAC_ARC, + AND, + PROJECTILE_ATTACK, + HEAL, + MOVEMENT_SWITCH, + AREA_OF_EFFECT, + PLAY_EFFECT, + IMMUNITY, + DAMAGE_BUFF, + DAMAGE_ABSORBTION, + OVER_TIME, + IMAGINATION, + TARGET_CASTER, + STUN, + DURATION, + KNOCKBACK, + ATTACK_DELAY, + CAR_BOOST, + FALL_SPEED, + SHIELD, + REPAIR_ARMOR, + SPEED, + DARK_INSPIRATION, + LOOT_BUFF, + VENTURE_VISION, + SPAWN_OBJECT, + LAY_BRICK, + SWITCH, + BUFF, + JETPACK, + SKILL_EVENT, + CONSUME_ITEM, + SKILL_CAST_FAILED, + IMITATION_SKUNK_STINK, + CHANGE_IDLE_FLAGS, + APPLY_BUFF, + CHAIN, + CHANGE_ORIENTATION, + FORCE_MOVEMENT, + INTERRUPT, + ALTER_COOLDOWN, + CHARGE_UP, + SWITCH_MULTIPLE, + START, + END, + ALTER_CHAIN_DELAY, + CAMERA, + REMOVE_BUFF, + GRAB, + MODULAR_BUILD, + NPC_COMBAT_SKILL, + BLOCK, + VERIFY, + TAUNT, + AIR_MOVEMENT, + SPAWN_QUICKBUILD, + PULL_TO_POINT, + PROPERTY_ROTATE, + DAMAGE_REDUCTION, + PROPERTY_TELEPORT, + PROPERTY_CLEAR_TARGET, + TAKE_PICTURE, + MOUNT, + SKILL_SET +}; diff --git a/dGame/dBehaviors/BehaviorTemplates.cpp b/dGame/dBehaviors/BehaviorTemplates.cpp deleted file mode 100644 index 8719fbe7f..000000000 --- a/dGame/dBehaviors/BehaviorTemplates.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "BehaviorTemplates.h" diff --git a/dGame/dBehaviors/BehaviorTemplates.h b/dGame/dBehaviors/BehaviorTemplates.h deleted file mode 100644 index 87cde6943..000000000 --- a/dGame/dBehaviors/BehaviorTemplates.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -enum class BehaviorTemplates : unsigned int { - BEHAVIOR_EMPTY, // Not a real behavior, indicates invalid behaviors - BEHAVIOR_BASIC_ATTACK, - BEHAVIOR_TAC_ARC, - BEHAVIOR_AND, - BEHAVIOR_PROJECTILE_ATTACK, - BEHAVIOR_HEAL, - BEHAVIOR_MOVEMENT_SWITCH, - BEHAVIOR_AREA_OF_EFFECT, - BEHAVIOR_PLAY_EFFECT, - BEHAVIOR_IMMUNITY, - BEHAVIOR_DAMAGE_BUFF, - BEHAVIOR_DAMAGE_ABSORBTION, - BEHAVIOR_OVER_TIME, - BEHAVIOR_IMAGINATION, - BEHAVIOR_TARGET_CASTER, - BEHAVIOR_STUN, - BEHAVIOR_DURATION, - BEHAVIOR_KNOCKBACK, - BEHAVIOR_ATTACK_DELAY, - BEHAVIOR_CAR_BOOST, - BEHAVIOR_FALL_SPEED, - BEHAVIOR_SHIELD, - BEHAVIOR_REPAIR_ARMOR, - BEHAVIOR_SPEED, - BEHAVIOR_DARK_INSPIRATION, - BEHAVIOR_LOOT_BUFF, - BEHAVIOR_VENTURE_VISION, - BEHAVIOR_SPAWN_OBJECT, - BEHAVIOR_LAY_BRICK, - BEHAVIOR_SWITCH, - BEHAVIOR_BUFF, - BEHAVIOR_JETPACK, - BEHAVIOR_SKILL_EVENT, - BEHAVIOR_CONSUME_ITEM, - BEHAVIOR_SKILL_CAST_FAILED, - BEHAVIOR_IMITATION_SKUNK_STINK, - BEHAVIOR_CHANGE_IDLE_FLAGS, - BEHAVIOR_APPLY_BUFF, - BEHAVIOR_CHAIN, - BEHAVIOR_CHANGE_ORIENTATION, - BEHAVIOR_FORCE_MOVEMENT, - BEHAVIOR_INTERRUPT, - BEHAVIOR_ALTER_COOLDOWN, - BEHAVIOR_CHARGE_UP, - BEHAVIOR_SWITCH_MULTIPLE, - BEHAVIOR_START, - BEHAVIOR_END, - BEHAVIOR_ALTER_CHAIN_DELAY, - BEHAVIOR_CAMERA, - BEHAVIOR_REMOVE_BUFF, - BEHAVIOR_GRAB, - BEHAVIOR_MODULAR_BUILD, - BEHAVIOR_NPC_COMBAT_SKILL, - BEHAVIOR_BLOCK, - BEHAVIOR_VERIFY, - BEHAVIOR_TAUNT, - BEHAVIOR_AIR_MOVEMENT, - BEHAVIOR_SPAWN_QUICKBUILD, - BEHAVIOR_PULL_TO_POINT, - BEHAVIOR_PROPERTY_ROTATE, - BEHAVIOR_DAMAGE_REDUCTION, - BEHAVIOR_PROPERTY_TELEPORT, - BEHAVIOR_PROPERTY_CLEAR_TARGET, - BEHAVIOR_TAKE_PICTURE, - BEHAVIOR_MOUNT, - BEHAVIOR_SKILL_SET -}; diff --git a/dGame/dBehaviors/CMakeLists.txt b/dGame/dBehaviors/CMakeLists.txt index c8cb0be07..35d8cae66 100644 --- a/dGame/dBehaviors/CMakeLists.txt +++ b/dGame/dBehaviors/CMakeLists.txt @@ -7,7 +7,6 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" "Behavior.cpp" "BehaviorBranchContext.cpp" "BehaviorContext.cpp" - "BehaviorTemplates.cpp" "BlockBehavior.cpp" "BuffBehavior.cpp" "CarBoostBehavior.cpp" @@ -21,7 +20,6 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" "DamageReductionBehavior.cpp" "DarkInspirationBehavior.cpp" "DurationBehavior.cpp" - "EmptyBehavior.cpp" "EndBehavior.cpp" "FallSpeedBehavior.cpp" "ForceMovementBehavior.cpp" @@ -56,7 +54,15 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" "VentureVisionBehavior.cpp" "VerifyBehavior.cpp") -add_library(dBehaviors STATIC ${DGAME_DBEHAVIORS_SOURCES}) -target_link_libraries(dBehaviors PUBLIC dPhysics) -target_include_directories(dBehaviors PUBLIC ".") +add_library(dBehaviors OBJECT ${DGAME_DBEHAVIORS_SOURCES}) +target_link_libraries(dBehaviors PUBLIC dDatabaseCDClient dPhysics) +target_include_directories(dBehaviors PUBLIC "." + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # via BehaviorContext.h + PRIVATE + "${PROJECT_SOURCE_DIR}/dGame/dComponents" # direct BuffComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" # Preconditions.h via QuickBuildComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # via dZoneManager.h, Spawner.h + "${PROJECT_SOURCE_DIR}/dGame/dInventory" # via CharacterComponent.h + "${PROJECT_SOURCE_DIR}/dZoneManager" # via BasicAttackBehavior.cpp +) target_precompile_headers(dBehaviors REUSE_FROM dGameBase) diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.h b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h index e40af3ccf..cf2d7f016 100644 --- a/dGame/dBehaviors/ChangeIdleFlagsBehavior.h +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h @@ -1,7 +1,7 @@ #pragma once #include "Behavior.h" -#include "eAninmationFlags.h" +#include "eAnimationFlags.h" class ChangeIdleFlagsBehavior final : public Behavior { public: diff --git a/dGame/dBehaviors/DamageAbsorptionBehavior.cpp b/dGame/dBehaviors/DamageAbsorptionBehavior.cpp index f657c8fd0..e5711f4d1 100644 --- a/dGame/dBehaviors/DamageAbsorptionBehavior.cpp +++ b/dGame/dBehaviors/DamageAbsorptionBehavior.cpp @@ -27,6 +27,8 @@ void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStrea destroyable->SetIsShielded(true); context->RegisterTimerBehavior(this, branch, target->GetObjectID()); + + Game::entityManager->SerializeEntity(target); } void DamageAbsorptionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { @@ -52,7 +54,13 @@ void DamageAbsorptionBehavior::Timer(BehaviorContext* context, BehaviorBranchCon const auto toRemove = std::min(present, this->m_absorbAmount); - destroyable->SetDamageToAbsorb(present - toRemove); + const auto remaining = present - toRemove; + + destroyable->SetDamageToAbsorb(remaining); + + destroyable->SetIsShielded(remaining > 0); + + Game::entityManager->SerializeEntity(target); } void DamageAbsorptionBehavior::Load() { diff --git a/dGame/dBehaviors/EmptyBehavior.cpp b/dGame/dBehaviors/EmptyBehavior.cpp deleted file mode 100644 index 8828f5de7..000000000 --- a/dGame/dBehaviors/EmptyBehavior.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#include "EmptyBehavior.h" - diff --git a/dGame/dBehaviors/ForceMovementBehavior.cpp b/dGame/dBehaviors/ForceMovementBehavior.cpp index 83c6fabc7..04dad7150 100644 --- a/dGame/dBehaviors/ForceMovementBehavior.cpp +++ b/dGame/dBehaviors/ForceMovementBehavior.cpp @@ -7,7 +7,7 @@ #include "Logger.h" void ForceMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { - if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + if (this->m_hitAction->m_templateId == BehaviorTemplate::EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplate::EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplate::EMPTY) { return; } @@ -38,7 +38,7 @@ void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream& bi } void ForceMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { - if (this->m_hitAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplates::BEHAVIOR_EMPTY) { + if (this->m_hitAction->m_templateId == BehaviorTemplate::EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplate::EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplate::EMPTY) { return; } diff --git a/dGame/dBehaviors/InterruptBehavior.cpp b/dGame/dBehaviors/InterruptBehavior.cpp index 0b23c34d0..c2f2fe707 100644 --- a/dGame/dBehaviors/InterruptBehavior.cpp +++ b/dGame/dBehaviors/InterruptBehavior.cpp @@ -8,36 +8,50 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { - if (branch.target != context->originator) { - bool unknown = false; + LWOOBJID usedTarget = m_target ? branch.target : context->originator; - if (!bitStream.Read(unknown)) { - LOG("Unable to read unknown1 from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); + if (usedTarget != context->originator) { + bool isTargetImmuneStuns = false; + if (!bitStream.Read(isTargetImmuneStuns)) { + LOG("Unable to read isTargetImmune from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; - if (unknown) return; + if (isTargetImmuneStuns) return; } if (!this->m_interruptBlock) { - bool unknown = false; - - if (!bitStream.Read(unknown)) { - LOG("Unable to read unknown2 from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); + bool isBlockingInterrupts = false; + if (!bitStream.Read(isBlockingInterrupts)) { + LOG("Unable to read isBlockingInterrupts from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; - if (unknown) return; + if (isBlockingInterrupts) return; } - if (this->m_target) // Guess... - { - bool unknown = false; - - if (!bitStream.Read(unknown)) { - LOG("Unable to read unknown3 from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); - return; - }; + bool hasInterruptedStatusEffects = false; + if (!bitStream.Read(hasInterruptedStatusEffects)) { + LOG("Unable to read hasInterruptedStatusEffects from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); + return; + }; + + if (hasInterruptedStatusEffects) { + bool hasMoreInterruptedStatusEffects = false; + int32_t loopLimit = 0; + while (bitStream.Read(hasMoreInterruptedStatusEffects) && hasMoreInterruptedStatusEffects) { + int32_t statusEffectID = 0; + bitStream.Read(statusEffectID); + // nothing happens with this data yes. I have no idea why or what it was used for, but the client literally just reads it and does nothing with it. + // 0x004faca4 for a reference. it also has a hard loop limit of 100 soo, + loopLimit++; + if (loopLimit > 100) { + // if this is hit you have a problem + LOG("Loop limit reached for interrupted status effects, aborting Handle due to bad bitstream! %i", bitStream.GetNumberOfUnreadBits()); + break; + } + LOG_DEBUG("Interrupted status effect ID: %i", statusEffectID); + } } if (branch.target == context->originator) return; @@ -55,7 +69,8 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitS void InterruptBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { - if (branch.target != context->originator) { + LWOOBJID usedTarget = m_target ? branch.target : context->originator; + if (usedTarget != context->originator) { bitStream.Write(false); } diff --git a/dGame/dBehaviors/MovementSwitchBehavior.cpp b/dGame/dBehaviors/MovementSwitchBehavior.cpp index cc2d7b347..7d7d3a178 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.cpp +++ b/dGame/dBehaviors/MovementSwitchBehavior.cpp @@ -6,13 +6,13 @@ void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { 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) { + if (this->m_groundAction->m_templateId == BehaviorTemplate::EMPTY && + this->m_jumpAction->m_templateId == BehaviorTemplate::EMPTY && + this->m_fallingAction->m_templateId == BehaviorTemplate::EMPTY && + this->m_doubleJumpAction->m_templateId == BehaviorTemplate::EMPTY && + this->m_airAction->m_templateId == BehaviorTemplate::EMPTY && + this->m_jetpackAction->m_templateId == BehaviorTemplate::EMPTY && + this->m_movingAction->m_templateId == BehaviorTemplate::EMPTY) { return; } LOG("Unable to read movementType from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); @@ -47,7 +47,7 @@ void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream& 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) { + if (actionValue == -1.0f && loadedBehavior->m_templateId == BehaviorTemplate::EMPTY) { loadedBehavior = this->m_groundAction; } return loadedBehavior; diff --git a/dGame/dBehaviors/SkillEventBehavior.cpp b/dGame/dBehaviors/SkillEventBehavior.cpp index e007fbe2b..9161f5d32 100644 --- a/dGame/dBehaviors/SkillEventBehavior.cpp +++ b/dGame/dBehaviors/SkillEventBehavior.cpp @@ -3,26 +3,22 @@ #include "BehaviorContext.h" #include "EntityManager.h" #include "CppScripts.h" +#include "Entity.h" void SkillEventBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); auto* caster = Game::entityManager->GetEntity(context->originator); - if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) { - script->OnSkillEventFired(target, caster, *this->m_effectHandle); - } + if (caster != nullptr && target != nullptr && !this->m_effectHandle.empty()) { + target->GetScript()->OnSkillEventFired(target, caster, this->m_effectHandle); } } -void -SkillEventBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { +void SkillEventBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); auto* caster = Game::entityManager->GetEntity(context->originator); - if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) { - script->OnSkillEventFired(target, caster, *this->m_effectHandle); - } + if (caster != nullptr && target != nullptr && !this->m_effectHandle.empty()) { + target->GetScript()->OnSkillEventFired(target, caster, this->m_effectHandle); } } diff --git a/dGame/dBehaviors/SwitchBehavior.cpp b/dGame/dBehaviors/SwitchBehavior.cpp index 88f2d85a0..a53b00010 100644 --- a/dGame/dBehaviors/SwitchBehavior.cpp +++ b/dGame/dBehaviors/SwitchBehavior.cpp @@ -7,9 +7,9 @@ #include "BuffComponent.h" void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { - auto state = true; + bool state = true; - if (this->m_imagination > 0 || !this->m_isEnemyFaction) { + if (m_imagination > 0 || m_targetHasBuff > 0 || m_Distance > -1.0f) { if (!bitStream.Read(state)) { LOG("Unable to read state from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; @@ -18,49 +18,59 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStre auto* entity = Game::entityManager->GetEntity(context->originator); - if (entity == nullptr) { - return; - } + if (!entity) return; auto* destroyableComponent = entity->GetComponent(); - if (destroyableComponent == nullptr) { - return; - } - - LOG_DEBUG("[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); + if (destroyableComponent) { + if (m_isEnemyFaction) { + auto* target = Game::entityManager->GetEntity(branch.target); + if (target) state = destroyableComponent->IsEnemy(target); + } - if (state) { - this->m_actionTrue->Handle(context, bitStream, branch); - } else { - this->m_actionFalse->Handle(context, bitStream, branch); + LOG_DEBUG("[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); } + + auto* behaviorToCall = state ? m_actionTrue : m_actionFalse; + behaviorToCall->Handle(context, bitStream, branch); } void SwitchBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { - auto state = true; - - if (this->m_imagination > 0 || !this->m_isEnemyFaction) { + bool state = true; + if (m_imagination > 0 || m_targetHasBuff > 0 || m_Distance > -1.0f) { auto* entity = Game::entityManager->GetEntity(branch.target); state = entity != nullptr; - if (state && m_targetHasBuff != 0) { - auto* buffComponent = entity->GetComponent(); + if (state) { + if (m_targetHasBuff != 0) { + auto* buffComponent = entity->GetComponent(); - if (buffComponent != nullptr && !buffComponent->HasBuff(m_targetHasBuff)) { - state = false; + if (buffComponent != nullptr && !buffComponent->HasBuff(m_targetHasBuff)) { + state = false; + } + } else if (m_imagination > 0) { + auto* destroyableComponent = entity->GetComponent(); + + if (destroyableComponent && destroyableComponent->GetImagination() < m_imagination) { + state = false; + } + } else if (m_Distance > -1.0f) { + auto* originator = Game::entityManager->GetEntity(context->originator); + + if (originator) { + const auto distance = (originator->GetPosition() - entity->GetPosition()).Length(); + + state = distance <= m_Distance; + } } } bitStream.Write(state); } - if (state) { - this->m_actionTrue->Calculate(context, bitStream, branch); - } else { - this->m_actionFalse->Calculate(context, bitStream, branch); - } + auto* behaviorToCall = state ? m_actionTrue : m_actionFalse; + behaviorToCall->Calculate(context, bitStream, branch); } void SwitchBehavior::Load() { @@ -72,5 +82,7 @@ void SwitchBehavior::Load() { this->m_isEnemyFaction = GetBoolean("isEnemyFaction"); - this->m_targetHasBuff = GetInt("target_has_buff"); + this->m_targetHasBuff = GetInt("target_has_buff", -1); + + this->m_Distance = GetFloat("distance", -1.0f); } diff --git a/dGame/dBehaviors/SwitchBehavior.h b/dGame/dBehaviors/SwitchBehavior.h index b7fcb6537..1a8ed3a8b 100644 --- a/dGame/dBehaviors/SwitchBehavior.h +++ b/dGame/dBehaviors/SwitchBehavior.h @@ -14,6 +14,8 @@ class SwitchBehavior final : public Behavior int32_t m_targetHasBuff; + float m_Distance; + /* * Inherited */ diff --git a/dGame/dBehaviors/SwitchMultipleBehavior.cpp b/dGame/dBehaviors/SwitchMultipleBehavior.cpp index 92c9a8def..00d639d56 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.cpp +++ b/dGame/dBehaviors/SwitchMultipleBehavior.cpp @@ -47,11 +47,11 @@ void SwitchMultipleBehavior::Load() { auto result = query.execQuery(); while (!result.eof()) { - const auto behavior_id = static_cast(result.getFloatField(1)); + const auto behavior_id = static_cast(result.getFloatField("behavior")); auto* behavior = CreateBehavior(behavior_id); - auto value = result.getFloatField(2); + auto value = result.getFloatField("value"); this->m_behaviors.emplace_back(value, behavior); diff --git a/dGame/dComponents/AchievementVendorComponent.cpp b/dGame/dComponents/AchievementVendorComponent.cpp index 10a0ca29d..006a2b6f0 100644 --- a/dGame/dComponents/AchievementVendorComponent.cpp +++ b/dGame/dComponents/AchievementVendorComponent.cpp @@ -9,11 +9,15 @@ #include "UserManager.h" #include "CDMissionsTable.h" +AchievementVendorComponent::AchievementVendorComponent(Entity* parent) : VendorComponent(parent) { + RefreshInventory(true); +}; + bool AchievementVendorComponent::SellsItem(Entity* buyer, const LOT lot) { auto* missionComponent = buyer->GetComponent(); if (!missionComponent) return false; - if (m_PlayerPurchasableItems[buyer->GetObjectID()].contains(lot)){ + if (m_PlayerPurchasableItems[buyer->GetObjectID()].contains(lot)) { return true; } @@ -35,7 +39,7 @@ void AchievementVendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) { int itemCompID = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::ITEM); CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); uint32_t costLOT = itemComp.commendationLOT; - + if (costLOT == -1 || !SellsItem(buyer, lot)) { auto* user = UserManager::Instance()->GetUser(buyer->GetSystemAddress()); CheatDetection::ReportCheat(user, buyer->GetSystemAddress(), "Attempted to buy item %i from achievement vendor %i that is not purchasable", lot, m_Parent->GetLOT()); @@ -44,7 +48,7 @@ void AchievementVendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) { } auto* inventoryComponent = buyer->GetComponent(); - if (!inventoryComponent) { + if (!inventoryComponent) { GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); return; } @@ -69,4 +73,9 @@ void AchievementVendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) { inventoryComponent->AddItem(lot, count, eLootSourceType::VENDOR); GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_SUCCESS); -} \ No newline at end of file +} + +void AchievementVendorComponent::RefreshInventory(bool isCreation) { + SetHasStandardCostItems(true); + Game::entityManager->SerializeEntity(m_Parent); +} diff --git a/dGame/dComponents/AchievementVendorComponent.h b/dGame/dComponents/AchievementVendorComponent.h index bffd39836..ba6c7c2a0 100644 --- a/dGame/dComponents/AchievementVendorComponent.h +++ b/dGame/dComponents/AchievementVendorComponent.h @@ -11,7 +11,9 @@ class Entity; class AchievementVendorComponent final : public VendorComponent { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::ACHIEVEMENT_VENDOR; - AchievementVendorComponent(Entity* parent) : VendorComponent(parent) {}; + AchievementVendorComponent(Entity* parent); + + void RefreshInventory(bool isCreation = false) override; bool SellsItem(Entity* buyer, const LOT lot); void Buy(Entity* buyer, LOT lot, uint32_t count); diff --git a/dGame/dComponents/ActivityComponent.cpp b/dGame/dComponents/ActivityComponent.cpp index ce82abe00..54c7101b2 100644 --- a/dGame/dComponents/ActivityComponent.cpp +++ b/dGame/dComponents/ActivityComponent.cpp @@ -21,7 +21,7 @@ #include "eMissionTaskType.h" #include "eMatchUpdate.h" #include "eConnectionType.h" -#include "eChatInternalMessageType.h" +#include "MessageType/Chat.h" #include "CDCurrencyTableTable.h" #include "CDActivityRewardsTable.h" @@ -501,7 +501,7 @@ void ActivityInstance::StartZone() { // only make a team if we have more than one participant if (participants.size() > 1) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::CREATE_TEAM); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::CREATE_TEAM); bitStream.Write(leader->GetObjectID()); bitStream.Write(m_Participants.size()); diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index d40cf73ea..bfb0bbfa8 100644 --- a/dGame/dComponents/BaseCombatAIComponent.cpp +++ b/dGame/dComponents/BaseCombatAIComponent.cpp @@ -29,7 +29,8 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): Component(parent) { m_Target = LWOOBJID_EMPTY; - SetAiState(AiState::spawn); + m_DirtyStateOrTarget = true; + m_State = AiState::spawn; m_Timer = 1.0f; m_StartPosition = parent->GetPosition(); m_MovementAI = nullptr; @@ -45,20 +46,20 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): auto componentResult = componentQuery.execQuery(); if (!componentResult.eof()) { - if (!componentResult.fieldIsNull(0)) - m_AggroRadius = componentResult.getFloatField(0); + if (!componentResult.fieldIsNull("aggroRadius")) + m_AggroRadius = componentResult.getFloatField("aggroRadius"); - if (!componentResult.fieldIsNull(1)) - m_TetherSpeed = componentResult.getFloatField(1); + if (!componentResult.fieldIsNull("tetherSpeed")) + m_TetherSpeed = componentResult.getFloatField("tetherSpeed"); - if (!componentResult.fieldIsNull(2)) - m_PursuitSpeed = componentResult.getFloatField(2); + if (!componentResult.fieldIsNull("pursuitSpeed")) + m_PursuitSpeed = componentResult.getFloatField("pursuitSpeed"); - if (!componentResult.fieldIsNull(3)) - m_SoftTetherRadius = componentResult.getFloatField(3); + if (!componentResult.fieldIsNull("softTetherRadius")) + m_SoftTetherRadius = componentResult.getFloatField("softTetherRadius"); - if (!componentResult.fieldIsNull(4)) - m_HardTetherRadius = componentResult.getFloatField(4); + if (!componentResult.fieldIsNull("hardTetherRadius")) + m_HardTetherRadius = componentResult.getFloatField("hardTetherRadius"); } componentResult.finalize(); @@ -82,11 +83,11 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): auto result = skillQuery.execQuery(); while (!result.eof()) { - const auto skillId = static_cast(result.getIntField(0)); + const auto skillId = static_cast(result.getIntField("skillID")); - const auto abilityCooldown = static_cast(result.getFloatField(1)); + const auto abilityCooldown = static_cast(result.getFloatField("cooldown")); - const auto behaviorId = static_cast(result.getIntField(2)); + const auto behaviorId = static_cast(result.getIntField("behaviorID")); auto* behavior = Behavior::CreateBehavior(behaviorId); @@ -150,19 +151,18 @@ void BaseCombatAIComponent::Update(const float deltaTime) { m_dpEntityEnemy->SetPosition(m_Parent->GetPosition()); //Process enter events - for (auto en : m_dpEntity->GetNewObjects()) { - m_Parent->OnCollisionPhantom(en->GetObjectID()); + for (const auto id : m_dpEntity->GetNewObjects()) { + m_Parent->OnCollisionPhantom(id); } //Process exit events - for (auto en : m_dpEntity->GetRemovedObjects()) { - m_Parent->OnCollisionLeavePhantom(en->GetObjectID()); + for (const auto id : m_dpEntity->GetRemovedObjects()) { + m_Parent->OnCollisionLeavePhantom(id); } // Check if we should stop the tether effect if (m_TetherEffectActive) { m_TetherTime -= deltaTime; - const auto& info = m_MovementAI->GetInfo(); if (m_Target != LWOOBJID_EMPTY || (NiPoint3::DistanceSquared( m_StartPosition, m_Parent->GetPosition()) < 20 * 20 && m_TetherTime <= 0) diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index 8b76e4234..2c9406475 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -326,9 +326,9 @@ Entity* BuffComponent::GetParent() const { return m_Parent; } -void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { +void BuffComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { // Load buffs - auto* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); + auto* dest = doc.FirstChildElement("obj")->FirstChildElement("dest"); // Make sure we have a clean buff element. auto* buffElement = dest->FirstChildElement("buff"); @@ -386,15 +386,15 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { } } -void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) { +void BuffComponent::UpdateXml(tinyxml2::XMLDocument& doc) { // Save buffs - auto* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); + auto* dest = doc.FirstChildElement("obj")->FirstChildElement("dest"); // Make sure we have a clean buff element. auto* buffElement = dest->FirstChildElement("buff"); if (buffElement == nullptr) { - buffElement = doc->NewElement("buff"); + buffElement = doc.NewElement("buff"); dest->LinkEndChild(buffElement); } else { @@ -402,7 +402,7 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) { } for (const auto& [id, buff] : m_Buffs) { - auto* buffEntry = doc->NewElement("b"); + auto* buffEntry = doc.NewElement("b"); // TODO: change this if to if (buff.cancelOnZone || buff.cancelOnLogout) handling at some point. No current way to differentiate between zone transfer and logout. if (buff.cancelOnZone) continue; @@ -450,7 +450,7 @@ const std::vector& BuffComponent::GetBuffParameters(int32_t buffI param.value = result.getFloatField("NumberValue"); param.effectId = result.getIntField("EffectID"); - if (!result.fieldIsNull(3)) { + if (!result.fieldIsNull("StringValue")) { std::istringstream stream(result.getStringField("StringValue")); std::string token; diff --git a/dGame/dComponents/BuffComponent.h b/dGame/dComponents/BuffComponent.h index df3c6a781..507e53a02 100644 --- a/dGame/dComponents/BuffComponent.h +++ b/dGame/dComponents/BuffComponent.h @@ -57,9 +57,9 @@ class BuffComponent final : public Component { Entity* GetParent() const; - void LoadFromXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; diff --git a/dGame/dComponents/CMakeLists.txt b/dGame/dComponents/CMakeLists.txt index 21fe92071..c60e135fe 100644 --- a/dGame/dComponents/CMakeLists.txt +++ b/dGame/dComponents/CMakeLists.txt @@ -48,11 +48,35 @@ set(DGAME_DCOMPONENTS_SOURCES "HavokVehiclePhysicsComponent.cpp" "VendorComponent.cpp" "MiniGameControlComponent.cpp" + "ScriptComponent.cpp" ) -add_library(dComponents STATIC ${DGAME_DCOMPONENTS_SOURCES}) -target_include_directories(dComponents PRIVATE ${PROJECT_SOURCE_DIR}/dScripts/02_server/Map/General) # PetDigServer.h +add_library(dComponents OBJECT ${DGAME_DCOMPONENTS_SOURCES}) +target_include_directories(dComponents PUBLIC "." + "${PROJECT_SOURCE_DIR}/dGame/dPropertyBehaviors" # via ModelComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dPropertyBehaviors/ControlBehaviorMessages" + "${PROJECT_SOURCE_DIR}/dGame/dMission" # via MissionComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dBehaviors" # via InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dInventory" # via InventoryComponent.h + PRIVATE + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables" + "${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include" + # dPhysics (via dpWorld.h) + "${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Include" + "${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Include" + + "${PROJECT_SOURCE_DIR}/dScripts/02_server/Map/General" # PetDigServer.h + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # direct + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" # direct Loot.h + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # via dZoneManager/Spawner.h + "${PROJECT_SOURCE_DIR}/dZoneManager" # via BouncerComponent.cpp, ActivityComponent.cpp + "${PROJECT_SOURCE_DIR}/dChatFilter" # via PetComponent.cpp +) target_precompile_headers(dComponents REUSE_FROM dGameBase) -target_link_libraries(dComponents - PUBLIC dPhysics dDatabase - INTERFACE dUtilities dCommon dBehaviors dChatFilter dMission dInventory) + +target_link_libraries(dComponents INTERFACE dBehaviors) diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index 3eafd9244..d706af9c2 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -186,9 +186,9 @@ void CharacterComponent::SetGMLevel(eGameMasterLevel gmlevel) { m_GMLevel = gmlevel; } -void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { +void CharacterComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { - tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); + auto* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag while loading XML!"); return; @@ -299,8 +299,8 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { } } -void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* minifig = doc->FirstChildElement("obj")->FirstChildElement("mf"); +void CharacterComponent::UpdateXml(tinyxml2::XMLDocument& doc) { + tinyxml2::XMLElement* minifig = doc.FirstChildElement("obj")->FirstChildElement("mf"); if (!minifig) { LOG("Failed to find mf tag while updating XML!"); return; @@ -320,7 +320,7 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { // done with minifig - tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); + tinyxml2::XMLElement* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag while updating XML!"); return; @@ -338,11 +338,11 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) { // Set the zone statistics of the form ... auto zoneStatistics = character->FirstChildElement("zs"); - if (!zoneStatistics) zoneStatistics = doc->NewElement("zs"); + if (!zoneStatistics) zoneStatistics = doc.NewElement("zs"); zoneStatistics->DeleteChildren(); for (auto pair : m_ZoneStatistics) { - auto zoneStatistic = doc->NewElement("s"); + auto zoneStatistic = doc.NewElement("s"); zoneStatistic->SetAttribute("map", pair.first); zoneStatistic->SetAttribute("ac", pair.second.m_AchievementsCollected); diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index 797347edc..c8cfa988d 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -5,7 +5,6 @@ #include "RakNetTypes.h" #include "Character.h" #include "Component.h" -#include "Item.h" #include #include "CDMissionsTable.h" #include "tinyxml2.h" @@ -15,6 +14,8 @@ enum class eGameActivity : uint32_t; +class Item; + /** * The statistics that can be achieved per zone */ @@ -24,6 +25,8 @@ struct ZoneStatistics { uint64_t m_CoinsCollected; uint64_t m_EnemiesSmashed; uint64_t m_QuickBuildsCompleted; + + bool operator==(const ZoneStatistics& rhs) const = default; }; /** @@ -69,8 +72,8 @@ class CharacterComponent final : public Component { CharacterComponent(Entity* parent, Character* character, const SystemAddress& systemAddress); ~CharacterComponent() override; - void LoadFromXml(tinyxml2::XMLDocument* doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; @@ -278,9 +281,9 @@ class CharacterComponent final : public Component { */ void UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const; - void SetCurrentInteracting(LWOOBJID objectID) {m_CurrentInteracting = objectID;}; + void SetCurrentInteracting(LWOOBJID objectID) { m_CurrentInteracting = objectID; }; - LWOOBJID GetCurrentInteracting() {return m_CurrentInteracting;}; + LWOOBJID GetCurrentInteracting() { return m_CurrentInteracting; }; /** * Sends a player to another zone with an optional clone ID @@ -306,6 +309,14 @@ class CharacterComponent final : public Component { void SetDroppedCoins(const uint64_t value) { m_DroppedCoins = value; }; + const std::array& GetClaimCodes() const { return m_ClaimCodes; }; + + const std::map& GetZoneStatistics() const { return m_ZoneStatistics; }; + + const std::u16string& GetLastRocketConfig() const { return m_LastRocketConfig; }; + + uint64_t GetTotalTimePlayed() const { return m_TotalTimePlayed; }; + /** * Character info regarding this character, including clothing styles, etc. */ diff --git a/dGame/dComponents/Component.cpp b/dGame/dComponents/Component.cpp index 705c44a76..8f38fb615 100644 --- a/dGame/dComponents/Component.cpp +++ b/dGame/dComponents/Component.cpp @@ -21,11 +21,11 @@ void Component::OnUse(Entity* originator) { } -void Component::UpdateXml(tinyxml2::XMLDocument* doc) { +void Component::UpdateXml(tinyxml2::XMLDocument& doc) { } -void Component::LoadFromXml(tinyxml2::XMLDocument* doc) { +void Component::LoadFromXml(const tinyxml2::XMLDocument& doc) { } diff --git a/dGame/dComponents/Component.h b/dGame/dComponents/Component.h index 062924f77..160565fbb 100644 --- a/dGame/dComponents/Component.h +++ b/dGame/dComponents/Component.h @@ -34,13 +34,13 @@ class Component { * Save data from this componennt to character XML * @param doc the document to write data to */ - virtual void UpdateXml(tinyxml2::XMLDocument* doc); + virtual void UpdateXml(tinyxml2::XMLDocument& doc); /** * Load base data for this component from character XML * @param doc the document to read data from */ - virtual void LoadFromXml(tinyxml2::XMLDocument* doc); + virtual void LoadFromXml(const tinyxml2::XMLDocument& doc); virtual void Serialize(RakNet::BitStream& outBitStream, bool isConstruction); diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index daa14ac3f..18e4b19d4 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -21,14 +21,11 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Phy m_InJetpackMode = false; m_IsOnGround = true; m_IsOnRail = false; - m_DirtyVelocity = true; - m_DirtyAngularVelocity = true; m_dpEntity = nullptr; m_Static = false; m_SpeedMultiplier = 1; m_GravityScale = 1; m_DirtyCheats = false; - m_IgnoreMultipliers = false; m_DirtyEquippedItemInfo = true; m_PickupRadius = 0.0f; @@ -94,31 +91,31 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bo outBitStream.Write(m_ImmuneToStunInteractCount); } - if (m_IgnoreMultipliers) m_DirtyCheats = false; - - outBitStream.Write(m_DirtyCheats); - if (m_DirtyCheats) { + outBitStream.Write(m_DirtyCheats || bIsInitialUpdate); + if (m_DirtyCheats || bIsInitialUpdate) { outBitStream.Write(m_GravityScale); outBitStream.Write(m_SpeedMultiplier); - m_DirtyCheats = false; + if (!bIsInitialUpdate) m_DirtyCheats = false; } - outBitStream.Write(m_DirtyEquippedItemInfo); - if (m_DirtyEquippedItemInfo) { + outBitStream.Write(m_DirtyEquippedItemInfo || bIsInitialUpdate); + if (m_DirtyEquippedItemInfo || bIsInitialUpdate) { outBitStream.Write(m_PickupRadius); outBitStream.Write(m_InJetpackMode); - m_DirtyEquippedItemInfo = false; + + if (!bIsInitialUpdate) m_DirtyEquippedItemInfo = false; } - outBitStream.Write(m_DirtyBubble); - if (m_DirtyBubble) { + outBitStream.Write(m_DirtyBubble || bIsInitialUpdate); + if (m_DirtyBubble || bIsInitialUpdate) { outBitStream.Write(m_IsInBubble); if (m_IsInBubble) { outBitStream.Write(m_BubbleType); outBitStream.Write(m_SpecialAnims); } - m_DirtyBubble = false; + + if (!bIsInitialUpdate) m_DirtyBubble = false; } outBitStream.Write(m_DirtyPosition || bIsInitialUpdate); @@ -135,31 +132,34 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bo outBitStream.Write(m_IsOnGround); outBitStream.Write(m_IsOnRail); - outBitStream.Write(m_DirtyVelocity); - if (m_DirtyVelocity) { + bool isNotZero = m_Velocity != NiPoint3Constant::ZERO; + outBitStream.Write(isNotZero); + if (isNotZero) { outBitStream.Write(m_Velocity.x); outBitStream.Write(m_Velocity.y); outBitStream.Write(m_Velocity.z); } - outBitStream.Write(m_DirtyAngularVelocity); - if (m_DirtyAngularVelocity) { + isNotZero = m_AngularVelocity != NiPoint3Constant::ZERO; + outBitStream.Write(isNotZero); + if (isNotZero) { outBitStream.Write(m_AngularVelocity.x); outBitStream.Write(m_AngularVelocity.y); outBitStream.Write(m_AngularVelocity.z); } - outBitStream.Write0(); - } + outBitStream.Write0(); // local_space_info, always zero for now. - if (!bIsInitialUpdate) { - outBitStream.Write(m_IsTeleporting); - m_IsTeleporting = false; + if (!bIsInitialUpdate) { + m_DirtyPosition = false; + outBitStream.Write(m_IsTeleporting); + m_IsTeleporting = false; + } } } -void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); +void ControllablePhysicsComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { + auto* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag!"); return; @@ -178,8 +178,8 @@ void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { m_DirtyPosition = true; } -void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char"); +void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument& doc) { + tinyxml2::XMLElement* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag while updating XML!"); return; @@ -211,33 +211,29 @@ void ControllablePhysicsComponent::SetRotation(const NiQuaternion& rot) { } void ControllablePhysicsComponent::SetVelocity(const NiPoint3& vel) { - if (m_Static) { - return; - } + if (m_Static || m_Velocity == vel) return; m_Velocity = vel; m_DirtyPosition = true; - m_DirtyVelocity = true; if (m_dpEntity) m_dpEntity->SetVelocity(vel); } void ControllablePhysicsComponent::SetAngularVelocity(const NiPoint3& vel) { - if (m_Static) { - return; - } + if (m_Static || m_AngularVelocity == vel) return; m_AngularVelocity = vel; m_DirtyPosition = true; - m_DirtyAngularVelocity = true; } void ControllablePhysicsComponent::SetIsOnGround(bool val) { + if (m_IsOnGround == val) return; m_DirtyPosition = true; m_IsOnGround = val; } void ControllablePhysicsComponent::SetIsOnRail(bool val) { + if (m_IsOnRail == val) return; m_DirtyPosition = true; m_IsOnRail = val; } @@ -245,15 +241,6 @@ void ControllablePhysicsComponent::SetIsOnRail(bool val) { void ControllablePhysicsComponent::SetDirtyPosition(bool val) { m_DirtyPosition = val; } - -void ControllablePhysicsComponent::SetDirtyVelocity(bool val) { - m_DirtyVelocity = val; -} - -void ControllablePhysicsComponent::SetDirtyAngularVelocity(bool val) { - m_DirtyAngularVelocity = val; -} - void ControllablePhysicsComponent::AddPickupRadiusScale(float value) { m_ActivePickupRadiusScales.push_back(value); if (value > m_PickupRadius) { @@ -309,7 +296,7 @@ void ControllablePhysicsComponent::RemoveSpeedboost(float value) { Game::entityManager->SerializeEntity(m_Parent); } -void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims){ +void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims) { if (m_IsInBubble) { LOG("Already in bubble"); return; @@ -321,7 +308,7 @@ void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bo Game::entityManager->SerializeEntity(m_Parent); } -void ControllablePhysicsComponent::DeactivateBubbleBuff(){ +void ControllablePhysicsComponent::DeactivateBubbleBuff() { m_DirtyBubble = true; m_IsInBubble = false; Game::entityManager->SerializeEntity(m_Parent); @@ -336,9 +323,9 @@ void ControllablePhysicsComponent::SetStunImmunity( const bool bImmuneToStunJump, const bool bImmuneToStunMove, const bool bImmuneToStunTurn, - const bool bImmuneToStunUseItem){ + const bool bImmuneToStunUseItem) { - if (state == eStateChangeType::POP){ + 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; diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index 313f80dee..6309b8fc3 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -28,8 +28,8 @@ class ControllablePhysicsComponent : public PhysicsComponent { void Update(float deltaTime) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; - void LoadFromXml(tinyxml2::XMLDocument* doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Sets the position of this entity, also ensures this update is serialized next tick. @@ -104,18 +104,6 @@ class ControllablePhysicsComponent : public PhysicsComponent { */ void SetDirtyPosition(bool val); - /** - * Mark the velocity as dirty, forcing a serializtion update next tick - * @param val whether or not the velocity is dirty - */ - void SetDirtyVelocity(bool val); - - /** - * Mark the angular velocity as dirty, forcing a serialization update next tick - * @param val whether or not the angular velocity is dirty - */ - void SetDirtyAngularVelocity(bool val); - /** * Sets whether or not the entity is currently wearing a jetpack * @param val whether or not the entity is currently wearing a jetpack @@ -186,18 +174,6 @@ class ControllablePhysicsComponent : public PhysicsComponent { */ const float GetGravityScale() const { return m_GravityScale; } - /** - * Sets the ignore multipliers value, allowing you to skip the serialization of speed and gravity multipliers - * @param value whether or not to ignore multipliers - */ - void SetIgnoreMultipliers(bool value) { m_IgnoreMultipliers = value; } - - /** - * Returns the current ignore multipliers value - * @return the current ignore multipliers value - */ - const bool GetIgnoreMultipliers() const { return m_IgnoreMultipliers; } - /** * Can make an entity static, making it unable to move around * @param value whether or not the entity is static @@ -310,21 +286,11 @@ class ControllablePhysicsComponent : public PhysicsComponent { */ dpEntity* m_dpEntity; - /** - * Whether or not the velocity is dirty, forcing a serialization of the velocity - */ - bool m_DirtyVelocity; - /** * The current velocity of the entity */ NiPoint3 m_Velocity; - /** - * Whether or not the angular velocity is dirty, forcing a serialization - */ - bool m_DirtyAngularVelocity; - /** * The current angular velocity of the entity */ @@ -375,11 +341,6 @@ class ControllablePhysicsComponent : public PhysicsComponent { */ bool m_DirtyCheats; - /** - * Makes it so that the speed multiplier and gravity scale are no longer serialized if false - */ - bool m_IgnoreMultipliers; - /** * Whether this entity is static, making it unable to move */ diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 39643baf0..cb8afd5a6 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -38,6 +38,9 @@ #include "CDComponentsRegistryTable.h" +Implementation DestroyableComponent::IsEnemyImplentation; +Implementation DestroyableComponent::IsFriendImplentation; + DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { m_iArmor = 0; m_fMaxArmor = 0.0f; @@ -185,8 +188,8 @@ void DestroyableComponent::Update(float deltaTime) { m_DamageCooldownTimer -= deltaTime; } -void DestroyableComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); +void DestroyableComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { + auto* dest = doc.FirstChildElement("obj")->FirstChildElement("dest"); if (!dest) { LOG("Failed to find dest tag!"); return; @@ -207,8 +210,8 @@ void DestroyableComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { m_DirtyHealth = true; } -void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* dest = doc->FirstChildElement("obj")->FirstChildElement("dest"); +void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument& doc) { + tinyxml2::XMLElement* dest = doc.FirstChildElement("obj")->FirstChildElement("dest"); if (!dest) { LOG("Failed to find dest tag!"); return; @@ -389,9 +392,9 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore if (result.eof()) return; - if (result.fieldIsNull(0)) return; + if (result.fieldIsNull("enemyList")) return; - const auto* list_string = result.getStringField(0); + const auto* list_string = result.getStringField("enemyList"); std::stringstream ss(list_string); std::string token; @@ -418,6 +421,7 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore } bool DestroyableComponent::IsEnemy(const Entity* other) const { + if (IsEnemyImplentation.ExecuteWithDefault(other, false)) return true; if (m_Parent->IsPlayer() && other->IsPlayer()) { auto* thisCharacterComponent = m_Parent->GetComponent(); if (!thisCharacterComponent) return false; @@ -440,6 +444,7 @@ bool DestroyableComponent::IsEnemy(const Entity* other) const { } bool DestroyableComponent::IsFriend(const Entity* other) const { + if (IsFriendImplentation.ExecuteWithDefault(other, false)) return true; const auto* otherDestroyableComponent = other->GetComponent(); if (otherDestroyableComponent != nullptr) { for (const auto enemyFaction : m_EnemyFactionIDs) { @@ -785,16 +790,12 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType } Entity* zoneControl = Game::entityManager->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerDied(zoneControl, m_Parent); - } + if (zoneControl) zoneControl->GetScript()->OnPlayerDied(zoneControl, m_Parent); std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerDied(scriptEntity, m_Parent); - } + scriptEntity->GetScript()->OnPlayerDied(scriptEntity, m_Parent); } } } diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index 85a4f941c..8b3cd14cc 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -7,6 +7,7 @@ #include "Entity.h" #include "Component.h" #include "eReplicaComponentType.h" +#include "Implementation.h" namespace CppScripts { class Script; @@ -26,8 +27,8 @@ class DestroyableComponent final : public Component { void Update(float deltaTime) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; - void LoadFromXml(tinyxml2::XMLDocument* doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Initializes the component using a different LOT @@ -463,6 +464,9 @@ class DestroyableComponent final : public Component { // handle hardcode mode drops void DoHardcoreModeDrops(const LWOOBJID source); + static Implementation IsEnemyImplentation; + static Implementation IsFriendImplentation; + private: /** * Whether or not the health should be serialized diff --git a/dGame/dComponents/HavokVehiclePhysicsComponent.cpp b/dGame/dComponents/HavokVehiclePhysicsComponent.cpp index 464cb3572..635830cc5 100644 --- a/dGame/dComponents/HavokVehiclePhysicsComponent.cpp +++ b/dGame/dComponents/HavokVehiclePhysicsComponent.cpp @@ -7,8 +7,6 @@ HavokVehiclePhysicsComponent::HavokVehiclePhysicsComponent(Entity* parent) : Phy m_IsOnGround = true; m_IsOnRail = false; m_DirtyPosition = true; - m_DirtyVelocity = true; - m_DirtyAngularVelocity = true; m_EndBehavior = GeneralUtils::GenerateRandomNumber(0, 7); } @@ -37,17 +35,9 @@ void HavokVehiclePhysicsComponent::SetIsOnRail(bool val) { } void HavokVehiclePhysicsComponent::SetRemoteInputInfo(const RemoteInputInfo& remoteInputInfo) { - if (m_RemoteInputInfo == remoteInputInfo) return; + if (remoteInputInfo == m_RemoteInputInfo) return; this->m_RemoteInputInfo = remoteInputInfo; - m_DirtyRemoteInput = true; -} - -void HavokVehiclePhysicsComponent::SetDirtyVelocity(bool val) { - m_DirtyVelocity = val; -} - -void HavokVehiclePhysicsComponent::SetDirtyAngularVelocity(bool val) { - m_DirtyAngularVelocity = val; + m_DirtyPosition = true; } void HavokVehiclePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { @@ -67,34 +57,32 @@ void HavokVehiclePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bo outBitStream.Write(m_IsOnGround); outBitStream.Write(m_IsOnRail); - outBitStream.Write(bIsInitialUpdate || m_DirtyVelocity); - - if (bIsInitialUpdate || m_DirtyVelocity) { + bool isNotZero = m_Velocity != NiPoint3Constant::ZERO; + outBitStream.Write(isNotZero); + if (isNotZero) { outBitStream.Write(m_Velocity.x); outBitStream.Write(m_Velocity.y); outBitStream.Write(m_Velocity.z); - m_DirtyVelocity = false; } - outBitStream.Write(bIsInitialUpdate || m_DirtyAngularVelocity); - - if (bIsInitialUpdate || m_DirtyAngularVelocity) { + isNotZero = m_AngularVelocity != NiPoint3Constant::ZERO; + outBitStream.Write(isNotZero); + if (isNotZero) { outBitStream.Write(m_AngularVelocity.x); outBitStream.Write(m_AngularVelocity.y); outBitStream.Write(m_AngularVelocity.z); - m_DirtyAngularVelocity = false; } outBitStream.Write0(); // local_space_info. TODO: Implement this - outBitStream.Write(m_DirtyRemoteInput || bIsInitialUpdate); // remote_input_info - if (m_DirtyRemoteInput || bIsInitialUpdate) { - outBitStream.Write(m_RemoteInputInfo.m_RemoteInputX); - outBitStream.Write(m_RemoteInputInfo.m_RemoteInputY); - outBitStream.Write(m_RemoteInputInfo.m_IsPowersliding); - outBitStream.Write(m_RemoteInputInfo.m_IsModified); - m_DirtyRemoteInput = false; - } + // This structure only has this bool flag set to false if a ptr to the peVehicle is null, which we don't have + // therefore, this will always be 1, even if all the values in the structure are 0. + outBitStream.Write1(); // has remote_input_info + outBitStream.Write(m_RemoteInputInfo.m_RemoteInputX); + outBitStream.Write(m_RemoteInputInfo.m_RemoteInputY); + outBitStream.Write(m_RemoteInputInfo.m_IsPowersliding); + outBitStream.Write(m_RemoteInputInfo.m_IsModified); + outBitStream.Write(125.0f); // remote_input_ping TODO: Figure out how this should be calculated as it seems to be constant through the whole race. @@ -110,12 +98,3 @@ void HavokVehiclePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bo outBitStream.Write0(); } - -void HavokVehiclePhysicsComponent::Update(float deltaTime) { - if (m_SoftUpdate > 5) { - Game::entityManager->SerializeEntity(m_Parent); - m_SoftUpdate = 0; - } else { - m_SoftUpdate += deltaTime; - } -} diff --git a/dGame/dComponents/HavokVehiclePhysicsComponent.h b/dGame/dComponents/HavokVehiclePhysicsComponent.h index 94c14ec64..83eb82fe6 100644 --- a/dGame/dComponents/HavokVehiclePhysicsComponent.h +++ b/dGame/dComponents/HavokVehiclePhysicsComponent.h @@ -17,8 +17,6 @@ class HavokVehiclePhysicsComponent : public PhysicsComponent { void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; - void Update(float deltaTime) override; - /** * Sets the velocity * @param vel the new velocity @@ -67,22 +65,16 @@ class HavokVehiclePhysicsComponent : public PhysicsComponent { */ const bool GetIsOnRail() const { return m_IsOnRail; } - void SetDirtyPosition(bool val); - void SetDirtyVelocity(bool val); - void SetDirtyAngularVelocity(bool val); void SetRemoteInputInfo(const RemoteInputInfo&); private: - bool m_DirtyVelocity; NiPoint3 m_Velocity; - - bool m_DirtyAngularVelocity; NiPoint3 m_AngularVelocity; + bool m_IsOnGround; bool m_IsOnRail; float m_SoftUpdate = 0; uint32_t m_EndBehavior; RemoteInputInfo m_RemoteInputInfo; - bool m_DirtyRemoteInput; }; diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 161d7b916..d6883e178 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -37,8 +37,11 @@ #include "CDScriptComponentTable.h" #include "CDObjectSkillsTable.h" #include "CDSkillBehaviorTable.h" +#include "StringifiedEnum.h" -InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) { +#include + +InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) { this->m_Dirty = true; this->m_Equipped = {}; this->m_Pushed = {}; @@ -48,7 +51,8 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do const auto lot = parent->GetLOT(); if (lot == 1) { - LoadXml(document); + auto* character = m_Parent->GetCharacter(); + if (character) LoadXml(character->GetXMLDoc()); CheckProxyIntegrity(); @@ -472,10 +476,10 @@ bool InventoryComponent::HasSpaceForLoot(const std::unordered_map& return true; } -void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { +void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) { LoadPetXml(document); - auto* inventoryElement = document->FirstChildElement("obj")->FirstChildElement("inv"); + auto* inventoryElement = document.FirstChildElement("obj")->FirstChildElement("inv"); if (inventoryElement == nullptr) { LOG("Failed to find 'inv' xml element!"); @@ -491,6 +495,11 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { return; } + auto* const groups = inventoryElement->FirstChildElement("grps"); + if (groups) { + LoadGroupXml(*groups); + } + m_Consumable = inventoryElement->IntAttribute("csl", LOT_NULL); auto* bag = bags->FirstChildElement(); @@ -557,19 +566,9 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { itemElement->QueryAttribute("parent", &parent); // End custom xml - std::vector config; - - auto* extraInfo = itemElement->FirstChildElement("x"); - - if (extraInfo) { - std::string modInfo = extraInfo->Attribute("ma"); - - LDFBaseData* moduleAssembly = new LDFData(u"assemblyPartLOTs", GeneralUtils::ASCIIToUTF16(modInfo.substr(2, modInfo.size() - 1))); - - config.push_back(moduleAssembly); - } + auto* item = new Item(id, lot, inventory, slot, count, bound, {}, parent, subKey); - const auto* item = new Item(id, lot, inventory, slot, count, bound, config, parent, subKey); + item->LoadConfigXml(*itemElement); if (equipped) { const auto info = Inventory::FindItemComponent(lot); @@ -594,10 +593,10 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { } } -void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { +void InventoryComponent::UpdateXml(tinyxml2::XMLDocument& document) { UpdatePetXml(document); - auto* inventoryElement = document->FirstChildElement("obj")->FirstChildElement("inv"); + auto* inventoryElement = document.FirstChildElement("obj")->FirstChildElement("inv"); if (inventoryElement == nullptr) { LOG("Failed to find 'inv' xml element!"); @@ -631,7 +630,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { bags->DeleteChildren(); for (const auto* inventory : inventoriesToSave) { - auto* bag = document->NewElement("b"); + auto* bag = document.NewElement("b"); bag->SetAttribute("t", inventory->GetType()); bag->SetAttribute("m", static_cast(inventory->GetSize())); @@ -639,6 +638,15 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { bags->LinkEndChild(bag); } + auto* groups = inventoryElement->FirstChildElement("grps"); + if (groups) { + groups->DeleteChildren(); + } else { + groups = inventoryElement->InsertNewChildElement("grps"); + } + + UpdateGroupXml(*groups); + auto* items = inventoryElement->FirstChildElement("items"); if (items == nullptr) { @@ -654,14 +662,14 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { continue; } - auto* bagElement = document->NewElement("in"); + auto* bagElement = document.NewElement("in"); bagElement->SetAttribute("t", inventory->GetType()); for (const auto& pair : inventory->GetItems()) { auto* item = pair.second; - auto* itemElement = document->NewElement("i"); + auto* itemElement = document.NewElement("i"); itemElement->SetAttribute("l", item->GetLot()); itemElement->SetAttribute("id", item->GetId()); @@ -675,17 +683,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { itemElement->SetAttribute("parent", item->GetParent()); // End custom xml - for (auto* data : item->GetConfig()) { - if (data->GetKey() != u"assemblyPartLOTs") { - continue; - } - - auto* extraInfo = document->NewElement("x"); - - extraInfo->SetAttribute("ma", data->GetString(false).c_str()); - - itemElement->LinkEndChild(extraInfo); - } + item->SaveConfigXml(*itemElement); bagElement->LinkEndChild(itemElement); } @@ -894,8 +892,6 @@ void InventoryComponent::UnEquipItem(Item* item) { RemoveSlot(item->GetInfo().equipLocation); - PurgeProxies(item); - UnequipScripts(item); Game::entityManager->SerializeEntity(m_Parent); @@ -905,6 +901,8 @@ void InventoryComponent::UnEquipItem(Item* item) { PropertyManagementComponent::Instance()->GetParent()->OnZonePropertyModelRemovedWhileEquipped(m_Parent); Game::zoneManager->GetZoneControlObject()->OnZonePropertyModelRemovedWhileEquipped(m_Parent); } + + PurgeProxies(item); } @@ -1093,7 +1091,7 @@ void InventoryComponent::CheckItemSet(const LOT lot) { auto result = query.execQuery(); while (!result.eof()) { - const auto id = result.getIntField(0); + const auto id = result.getIntField("setID"); bool found = false; @@ -1524,10 +1522,10 @@ void InventoryComponent::PurgeProxies(Item* item) { const auto root = item->GetParent(); if (root != LWOOBJID_EMPTY) { - item = FindItemById(root); + Item* itemRoot = FindItemById(root); - if (item != nullptr) { - UnEquipItem(item); + if (itemRoot != nullptr) { + UnEquipItem(itemRoot); } return; @@ -1542,8 +1540,8 @@ void InventoryComponent::PurgeProxies(Item* item) { } } -void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) { - auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); +void InventoryComponent::LoadPetXml(const tinyxml2::XMLDocument& document) { + auto* petInventoryElement = document.FirstChildElement("obj")->FirstChildElement("pet"); if (petInventoryElement == nullptr) { m_Pets.clear(); @@ -1574,19 +1572,19 @@ void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) { } } -void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) { - auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); +void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument& document) { + auto* petInventoryElement = document.FirstChildElement("obj")->FirstChildElement("pet"); if (petInventoryElement == nullptr) { - petInventoryElement = document->NewElement("pet"); + petInventoryElement = document.NewElement("pet"); - document->FirstChildElement("obj")->LinkEndChild(petInventoryElement); + document.FirstChildElement("obj")->LinkEndChild(petInventoryElement); } petInventoryElement->DeleteChildren(); for (const auto& pet : m_Pets) { - auto* petElement = document->NewElement("p"); + auto* petElement = document.NewElement("p"); petElement->SetAttribute("id", pet.first); petElement->SetAttribute("l", pet.second.lot); @@ -1599,18 +1597,18 @@ void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) { } -bool InventoryComponent::SetSkill(int32_t slot, uint32_t skillId){ +bool InventoryComponent::SetSkill(int32_t slot, uint32_t skillId) { BehaviorSlot behaviorSlot = BehaviorSlot::Invalid; - if (slot == 1 ) behaviorSlot = BehaviorSlot::Primary; - else if (slot == 2 ) behaviorSlot = BehaviorSlot::Offhand; - else if (slot == 3 ) behaviorSlot = BehaviorSlot::Neck; - else if (slot == 4 ) behaviorSlot = BehaviorSlot::Head; - else if (slot == 5 ) behaviorSlot = BehaviorSlot::Consumable; + if (slot == 1) behaviorSlot = BehaviorSlot::Primary; + else if (slot == 2) behaviorSlot = BehaviorSlot::Offhand; + else if (slot == 3) behaviorSlot = BehaviorSlot::Neck; + else if (slot == 4) behaviorSlot = BehaviorSlot::Head; + else if (slot == 5) behaviorSlot = BehaviorSlot::Consumable; else return false; return SetSkill(behaviorSlot, skillId); } -bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){ +bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId) { if (skillId == 0) return false; const auto index = m_Skills.find(slot); if (index != m_Skills.end()) { @@ -1623,3 +1621,109 @@ bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){ return true; } +void InventoryComponent::UpdateGroup(const GroupUpdate& groupUpdate) { + if (groupUpdate.groupId.empty()) return; + + if (groupUpdate.inventory != eInventoryType::BRICKS && groupUpdate.inventory != eInventoryType::MODELS) { + LOG("Invalid inventory type for grouping %s", StringifiedEnum::ToString(groupUpdate.inventory).data()); + return; + } + + auto& groups = m_Groups[groupUpdate.inventory]; + auto groupItr = std::ranges::find_if(groups, [&groupUpdate](const Group& group) { + return group.groupId == groupUpdate.groupId; + }); + + if (groupUpdate.command != GroupUpdateCommand::ADD && groupItr == groups.end()) { + LOG("Group %s not found in inventory %s. Cannot process command.", groupUpdate.groupId.c_str(), StringifiedEnum::ToString(groupUpdate.inventory).data()); + return; + } + + if (groupUpdate.command == GroupUpdateCommand::ADD && groups.size() >= MaximumGroupCount) { + LOG("Cannot add group to inventory %s. Maximum group count reached.", StringifiedEnum::ToString(groupUpdate.inventory).data()); + return; + } + + switch (groupUpdate.command) { + case GroupUpdateCommand::ADD: { + auto& group = groups.emplace_back(); + group.groupId = groupUpdate.groupId; + group.groupName = groupUpdate.groupName; + break; + } + case GroupUpdateCommand::ADD_LOT: { + groupItr->lots.insert(groupUpdate.lot); + break; + } + case GroupUpdateCommand::REMOVE: { + groups.erase(groupItr); + break; + } + case GroupUpdateCommand::REMOVE_LOT: { + groupItr->lots.erase(groupUpdate.lot); + break; + } + case GroupUpdateCommand::MODIFY: { + groupItr->groupName = groupUpdate.groupName; + break; + } + default: { + LOG("Invalid group update command %i", groupUpdate.command); + break; + } + } +} + +void InventoryComponent::UpdateGroupXml(tinyxml2::XMLElement& groups) const { + for (const auto& [inventory, groupsData] : m_Groups) { + for (const auto& group : groupsData) { + auto* const groupElement = groups.InsertNewChildElement("grp"); + + groupElement->SetAttribute("id", group.groupId.c_str()); + groupElement->SetAttribute("n", group.groupName.c_str()); + groupElement->SetAttribute("t", static_cast(inventory)); + groupElement->SetAttribute("u", 0); + std::ostringstream lots; + bool first = true; + for (const auto lot : group.lots) { + if (!first) lots << ' '; + first = false; + + lots << lot; + } + groupElement->SetAttribute("l", lots.str().c_str()); + } + } +} + +void InventoryComponent::LoadGroupXml(const tinyxml2::XMLElement& groups) { + auto* groupElement = groups.FirstChildElement("grp"); + + while (groupElement) { + const char* groupId = nullptr; + const char* groupName = nullptr; + const char* lots = nullptr; + uint32_t inventory = eInventoryType::INVALID; + + groupElement->QueryStringAttribute("id", &groupId); + groupElement->QueryStringAttribute("n", &groupName); + groupElement->QueryStringAttribute("l", &lots); + groupElement->QueryAttribute("t", &inventory); + + if (!groupId || !groupName || !lots) { + LOG("Failed to load group from xml id %i name %i lots %i", + groupId == nullptr, groupName == nullptr, lots == nullptr); + } else { + auto& group = m_Groups[static_cast(inventory)].emplace_back(); + group.groupId = groupId; + group.groupName = groupName; + + for (const auto& lotStr : GeneralUtils::SplitString(lots, ' ')) { + auto lot = GeneralUtils::TryParse(lotStr); + if (lot) group.lots.insert(*lot); + } + } + + groupElement = groupElement->NextSiblingElement("grp"); + } +} diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index 8f58a523b..28158ab58 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -37,13 +37,42 @@ enum class eItemType : int32_t; */ class InventoryComponent final : public Component { public: + struct Group { + // Generated ID for the group. The ID is sent by the client and has the format user_group + Math.random() * UINT_MAX. + std::string groupId; + // Custom name assigned by the user. + std::string groupName; + // All the lots the user has in the group. + std::set lots; + }; + + enum class GroupUpdateCommand { + ADD, + ADD_LOT, + MODIFY, + REMOVE, + REMOVE_LOT, + }; + + // Based on the command, certain fields will be used or not used. + // for example, ADD_LOT wont use groupName, MODIFY wont use lots, etc. + struct GroupUpdate { + std::string groupId; + std::string groupName; + LOT lot; + eInventoryType inventory; + GroupUpdateCommand command; + }; + + static constexpr uint32_t MaximumGroupCount = 50; + static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY; - explicit InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document = nullptr); + InventoryComponent(Entity* parent); void Update(float deltaTime) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; - void LoadXml(tinyxml2::XMLDocument* document); - void UpdateXml(tinyxml2::XMLDocument* document) override; + void LoadXml(const tinyxml2::XMLDocument& document); + void UpdateXml(tinyxml2::XMLDocument& document) override; /** * Returns an inventory of the specified type, if it exists @@ -367,14 +396,23 @@ class InventoryComponent final : public Component { */ void UnequipScripts(Item* unequippedItem); - std::map GetSkills(){ return m_Skills; }; + std::map GetSkills() { return m_Skills; }; bool SetSkill(int slot, uint32_t skillId); bool SetSkill(BehaviorSlot slot, uint32_t skillId); + void UpdateGroup(const GroupUpdate& groupUpdate); + void RemoveGroup(const std::string& groupId); + ~InventoryComponent() override; private: + /** + * The key is the inventory the group belongs to, the value maps' key is the id for the group. + * This is only used for bricks and model inventories. + */ + std::map> m_Groups{ { eInventoryType::BRICKS, {} }, { eInventoryType::MODELS, {} } }; + /** * All the inventory this entity possesses */ @@ -470,13 +508,16 @@ class InventoryComponent final : public Component { * Saves all the pet information stored in inventory items to the database * @param document the xml doc to save to */ - void LoadPetXml(tinyxml2::XMLDocument* document); + void LoadPetXml(const tinyxml2::XMLDocument& document); /** * Loads all the pet information from an xml doc into items * @param document the xml doc to load from */ - void UpdatePetXml(tinyxml2::XMLDocument* document); + void UpdatePetXml(tinyxml2::XMLDocument& document); + + void LoadGroupXml(const tinyxml2::XMLElement& groups); + void UpdateGroupXml(tinyxml2::XMLElement& groups) const; }; #endif diff --git a/dGame/dComponents/LevelProgressionComponent.cpp b/dGame/dComponents/LevelProgressionComponent.cpp index 2d3d5144f..a6801a40a 100644 --- a/dGame/dComponents/LevelProgressionComponent.cpp +++ b/dGame/dComponents/LevelProgressionComponent.cpp @@ -13,8 +13,8 @@ LevelProgressionComponent::LevelProgressionComponent(Entity* parent) : Component m_CharacterVersion = eCharacterVersion::LIVE; } -void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* level = doc->FirstChildElement("obj")->FirstChildElement("lvl"); +void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument& doc) { + tinyxml2::XMLElement* level = doc.FirstChildElement("obj")->FirstChildElement("lvl"); if (!level) { LOG("Failed to find lvl tag while updating XML!"); return; @@ -24,8 +24,8 @@ void LevelProgressionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { level->SetAttribute("cv", static_cast(m_CharacterVersion)); } -void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - tinyxml2::XMLElement* level = doc->FirstChildElement("obj")->FirstChildElement("lvl"); +void LevelProgressionComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { + auto* level = doc.FirstChildElement("obj")->FirstChildElement("lvl"); if (!level) { LOG("Failed to find lvl tag while loading XML!"); return; diff --git a/dGame/dComponents/LevelProgressionComponent.h b/dGame/dComponents/LevelProgressionComponent.h index a27039f36..e9981ab6a 100644 --- a/dGame/dComponents/LevelProgressionComponent.h +++ b/dGame/dComponents/LevelProgressionComponent.h @@ -27,13 +27,13 @@ class LevelProgressionComponent final : public Component { * Save data from this componennt to character XML * @param doc the document to write data to */ - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Load base data for this component from character XML * @param doc the document to read data from */ - void LoadFromXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; /** * Gets the current level of the entity diff --git a/dGame/dComponents/MissionComponent.cpp b/dGame/dComponents/MissionComponent.cpp index 151fcf2f7..0760d8e40 100644 --- a/dGame/dComponents/MissionComponent.cpp +++ b/dGame/dComponents/MissionComponent.cpp @@ -466,8 +466,8 @@ bool MissionComponent::RequiresItem(const LOT lot) { return false; } - if (!result.fieldIsNull(0)) { - const auto type = std::string(result.getStringField(0)); + if (!result.fieldIsNull("type")) { + const auto type = std::string(result.getStringField("type")); result.finalize(); @@ -504,10 +504,8 @@ bool MissionComponent::RequiresItem(const LOT lot) { } -void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { - if (doc == nullptr) return; - - auto* mis = doc->FirstChildElement("obj")->FirstChildElement("mis"); +void MissionComponent::LoadFromXml(const tinyxml2::XMLDocument& doc) { + auto* mis = doc.FirstChildElement("obj")->FirstChildElement("mis"); if (mis == nullptr) return; @@ -523,7 +521,7 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { auto* mission = new Mission(this, missionId); - mission->LoadFromXml(doneM); + mission->LoadFromXml(*doneM); doneM = doneM->NextSiblingElement(); @@ -540,7 +538,7 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { auto* mission = new Mission(this, missionId); - mission->LoadFromXml(currentM); + mission->LoadFromXml(*currentM); if (currentM->QueryAttribute("o", &missionOrder) == tinyxml2::XML_SUCCESS && mission->IsMission()) { mission->SetUniqueMissionOrderID(missionOrder); @@ -554,25 +552,23 @@ void MissionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { } -void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { - if (doc == nullptr) return; - +void MissionComponent::UpdateXml(tinyxml2::XMLDocument& doc) { auto shouldInsertMis = false; - auto* obj = doc->FirstChildElement("obj"); + auto* obj = doc.FirstChildElement("obj"); auto* mis = obj->FirstChildElement("mis"); if (mis == nullptr) { - mis = doc->NewElement("mis"); + mis = doc.NewElement("mis"); shouldInsertMis = true; } mis->DeleteChildren(); - auto* done = doc->NewElement("done"); - auto* cur = doc->NewElement("cur"); + auto* done = doc.NewElement("done"); + auto* cur = doc.NewElement("cur"); for (const auto& pair : m_Missions) { auto* mission = pair.second; @@ -580,10 +576,10 @@ void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { if (mission) { const auto complete = mission->IsComplete(); - auto* m = doc->NewElement("m"); + auto* m = doc.NewElement("m"); if (complete) { - mission->UpdateXml(m); + mission->UpdateXml(*m); done->LinkEndChild(m); @@ -591,7 +587,7 @@ void MissionComponent::UpdateXml(tinyxml2::XMLDocument* doc) { } if (mission->IsMission()) m->SetAttribute("o", mission->GetUniqueMissionOrderID()); - mission->UpdateXml(m); + mission->UpdateXml(*m); cur->LinkEndChild(m); } diff --git a/dGame/dComponents/MissionComponent.h b/dGame/dComponents/MissionComponent.h index 866f16501..a01794f01 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -31,8 +31,8 @@ class MissionComponent final : public Component { explicit MissionComponent(Entity* parent); ~MissionComponent() override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void LoadFromXml(tinyxml2::XMLDocument* doc) override; - void UpdateXml(tinyxml2::XMLDocument* doc) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Returns all the missions for this entity, mapped by mission ID diff --git a/dGame/dComponents/ModelComponent.cpp b/dGame/dComponents/ModelComponent.cpp index 75f2a0190..3a273c9b6 100644 --- a/dGame/dComponents/ModelComponent.cpp +++ b/dGame/dComponents/ModelComponent.cpp @@ -6,6 +6,10 @@ #include "BehaviorStates.h" #include "ControlBehaviorMsgs.h" +#include "tinyxml2.h" +#include "SimplePhysicsComponent.h" + +#include "Database.h" ModelComponent::ModelComponent(Entity* parent) : Component(parent) { m_OriginalPosition = m_Parent->GetDefaultPosition(); @@ -14,6 +18,33 @@ ModelComponent::ModelComponent(Entity* parent) : Component(parent) { m_userModelID = m_Parent->GetVarAs(u"userModelID"); } +void ModelComponent::LoadBehaviors() { + auto behaviors = GeneralUtils::SplitString(m_Parent->GetVar(u"userModelBehaviors"), ','); + for (const auto& behavior : behaviors) { + if (behavior.empty()) continue; + + const auto behaviorId = GeneralUtils::TryParse(behavior); + if (!behaviorId.has_value() || behaviorId.value() == 0) continue; + + LOG_DEBUG("Loading behavior %d", behaviorId.value()); + auto& inserted = m_Behaviors.emplace_back(); + inserted.SetBehaviorId(*behaviorId); + + const auto behaviorStr = Database::Get()->GetBehavior(behaviorId.value()); + + tinyxml2::XMLDocument behaviorXml; + auto res = behaviorXml.Parse(behaviorStr.c_str(), behaviorStr.size()); + LOG_DEBUG("Behavior %i %d: %s", res, behaviorId.value(), behaviorStr.c_str()); + + const auto* const behaviorRoot = behaviorXml.FirstChildElement("Behavior"); + if (!behaviorRoot) { + LOG("Failed to load behavior %d due to missing behavior root", behaviorId.value()); + continue; + } + inserted.Deserialize(*behaviorRoot); + } +} + void ModelComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { // ItemComponent Serialization. Pets do not get this serialization. if (!m_Parent->HasComponent(eReplicaComponentType::PET)) { @@ -65,10 +96,42 @@ void ModelComponent::AddBehavior(AddMessage& msg) { for (auto& behavior : m_Behaviors) if (behavior.GetBehaviorId() == msg.GetBehaviorId()) return; m_Behaviors.insert(m_Behaviors.begin() + msg.GetBehaviorIndex(), PropertyBehavior()); m_Behaviors.at(msg.GetBehaviorIndex()).HandleMsg(msg); + auto* const simplePhysComponent = m_Parent->GetComponent(); + if (simplePhysComponent) { + simplePhysComponent->SetPhysicsMotionState(1); + Game::entityManager->SerializeEntity(m_Parent); + } } void ModelComponent::MoveToInventory(MoveToInventoryMessage& msg) { if (msg.GetBehaviorIndex() >= m_Behaviors.size() || m_Behaviors.at(msg.GetBehaviorIndex()).GetBehaviorId() != msg.GetBehaviorId()) return; m_Behaviors.erase(m_Behaviors.begin() + msg.GetBehaviorIndex()); // TODO move to the inventory + if (m_Behaviors.empty()) { + auto* const simplePhysComponent = m_Parent->GetComponent(); + if (simplePhysComponent) { + simplePhysComponent->SetPhysicsMotionState(4); + Game::entityManager->SerializeEntity(m_Parent); + } + } +} + +std::array, 5> ModelComponent::GetBehaviorsForSave() const { + std::array, 5> toReturn{}; + for (auto i = 0; i < m_Behaviors.size(); i++) { + const auto& behavior = m_Behaviors.at(i); + if (behavior.GetBehaviorId() == -1) continue; + auto& [id, behaviorData] = toReturn[i]; + id = behavior.GetBehaviorId(); + + tinyxml2::XMLDocument doc; + auto* root = doc.NewElement("Behavior"); + behavior.Serialize(*root); + doc.InsertFirstChild(root); + + tinyxml2::XMLPrinter printer(0, true, 0); + doc.Print(&printer); + behaviorData = printer.CStr(); + } + return toReturn; } diff --git a/dGame/dComponents/ModelComponent.h b/dGame/dComponents/ModelComponent.h index d798a69cf..12ef7744e 100644 --- a/dGame/dComponents/ModelComponent.h +++ b/dGame/dComponents/ModelComponent.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "dCommonVars.h" @@ -28,6 +29,8 @@ class ModelComponent final : public Component { ModelComponent(Entity* parent); + void LoadBehaviors(); + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** @@ -109,6 +112,8 @@ class ModelComponent final : public Component { void VerifyBehaviors(); + std::array, 5> GetBehaviorsForSave() const; + private: /** * The behaviors of the model diff --git a/dGame/dComponents/MovementAIComponent.cpp b/dGame/dComponents/MovementAIComponent.cpp index 8377031af..b6a16803f 100644 --- a/dGame/dComponents/MovementAIComponent.cpp +++ b/dGame/dComponents/MovementAIComponent.cpp @@ -50,9 +50,44 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) : m_CurrentSpeed = 0; m_MaxSpeed = 0; m_LockRotation = false; + m_Path = nullptr; + m_SourcePosition = m_Parent->GetPosition(); + m_Paused = false; + m_SavedVelocity = NiPoint3Constant::ZERO; + + if (!m_Parent->GetComponent()) SetPath(m_Parent->GetVarAsString(u"attached_path")); +} + +void MovementAIComponent::SetPath(const std::string pathName) { + m_Path = Game::zoneManager->GetZone()->GetPath(pathName); + if (!pathName.empty()) LOG("WARNING: %s path %s", m_Path ? "Found" : "Failed to find", pathName.c_str()); + if (!m_Path) return; + SetMaxSpeed(1); + SetCurrentSpeed(m_BaseSpeed); + SetPath(m_Path->pathWaypoints); +} + +void MovementAIComponent::Pause() { + if (m_Paused) return; + m_Paused = true; + SetPosition(ApproximateLocation()); + m_SavedVelocity = GetVelocity(); + SetVelocity(NiPoint3Constant::ZERO); + Game::entityManager->SerializeEntity(m_Parent); +} + +void MovementAIComponent::Resume() { + if (!m_Paused) return; + m_Paused = false; + SetVelocity(m_SavedVelocity); + m_SavedVelocity = NiPoint3Constant::ZERO; + SetRotation(NiQuaternion::LookAt(m_Parent->GetPosition(), m_NextWaypoint)); + Game::entityManager->SerializeEntity(m_Parent); } void MovementAIComponent::Update(const float deltaTime) { + if (m_Paused) return; + if (m_PullingToPoint) { const auto source = GetCurrentWaypoint(); @@ -81,64 +116,65 @@ void MovementAIComponent::Update(const float deltaTime) { } m_TimeTravelled += deltaTime; + + SetPosition(ApproximateLocation()); + if (m_TimeTravelled < m_TimeToTravel) return; m_TimeTravelled = 0.0f; const auto source = GetCurrentWaypoint(); SetPosition(source); - - NiPoint3 velocity = NiPoint3Constant::ZERO; + m_SourcePosition = source; if (m_Acceleration > 0 && m_BaseSpeed > 0 && AdvanceWaypointIndex()) // Do we have another waypoint to seek? { m_NextWaypoint = GetCurrentWaypoint(); - if (m_NextWaypoint == source) { m_TimeToTravel = 0.0f; + } else { + m_CurrentSpeed = std::min(m_CurrentSpeed + m_Acceleration, m_MaxSpeed); - goto nextAction; - } + const auto speed = m_CurrentSpeed * m_BaseSpeed; // scale speed based on base speed - if (m_CurrentSpeed < m_MaxSpeed) { - m_CurrentSpeed += m_Acceleration; - } - - if (m_CurrentSpeed > m_MaxSpeed) { - m_CurrentSpeed = m_MaxSpeed; - } + const auto delta = m_NextWaypoint - source; - const auto speed = m_CurrentSpeed * m_BaseSpeed; // scale speed based on base speed + // Normalize the vector + const auto length = delta.Length(); + if (length > 0.0f) { + SetVelocity((delta / length) * speed); + } - const auto delta = m_NextWaypoint - source; + // Calclute the time it will take to reach the next waypoint with the current speed + m_TimeTravelled = 0.0f; + m_TimeToTravel = length / speed; - // Normalize the vector - const auto length = delta.Length(); - if (length > 0) { - velocity = (delta / length) * speed; + SetRotation(NiQuaternion::LookAt(source, m_NextWaypoint)); } - - // Calclute the time it will take to reach the next waypoint with the current speed - m_TimeTravelled = 0.0f; - m_TimeToTravel = length / speed; - - SetRotation(NiQuaternion::LookAt(source, m_NextWaypoint)); } else { // Check if there are more waypoints in the queue, if so set our next destination to the next waypoint if (m_CurrentPath.empty()) { - Stop(); - - return; + if (m_Path) { + if (m_Path->pathBehavior == PathBehavior::Loop) { + SetPath(m_Path->pathWaypoints); + } else if (m_Path->pathBehavior == PathBehavior::Bounce) { + std::vector waypoints = m_Path->pathWaypoints; + std::reverse(waypoints.begin(), waypoints.end()); + SetPath(waypoints); + } else if (m_Path->pathBehavior == PathBehavior::Once) { + Stop(); + return; + } + } else { + Stop(); + return; + } } - SetDestination(m_CurrentPath.top()); + SetDestination(m_CurrentPath.top().position); m_CurrentPath.pop(); } -nextAction: - - SetVelocity(velocity); - Game::entityManager->SerializeEntity(m_Parent); } @@ -161,7 +197,7 @@ NiPoint3 MovementAIComponent::GetCurrentWaypoint() const { } NiPoint3 MovementAIComponent::ApproximateLocation() const { - auto source = m_Parent->GetPosition(); + auto source = m_SourcePosition; if (AtFinalWaypoint()) return source; @@ -227,13 +263,13 @@ void MovementAIComponent::PullToPoint(const NiPoint3& point) { m_PullPoint = point; } -void MovementAIComponent::SetPath(std::vector path) { +void MovementAIComponent::SetPath(std::vector path) { if (path.empty()) return; - std::for_each(path.rbegin(), path.rend() - 1, [this](const NiPoint3& point) { + std::for_each(path.rbegin(), path.rend() - 1, [this](const PathWaypoint& point) { this->m_CurrentPath.push(point); }); - SetDestination(path.front()); + SetDestination(path.front().position); } float MovementAIComponent::GetBaseSpeed(LOT lot) { @@ -278,6 +314,23 @@ void MovementAIComponent::SetRotation(const NiQuaternion& value) { if (!m_LockRotation) m_Parent->SetRotation(value); } +NiPoint3 MovementAIComponent::GetVelocity() const { + auto* controllablePhysicsComponent = m_Parent->GetComponent(); + + if (controllablePhysicsComponent != nullptr) { + return controllablePhysicsComponent->GetVelocity(); + } + + auto* simplePhysicsComponent = m_Parent->GetComponent(); + + if (simplePhysicsComponent != nullptr) { + return simplePhysicsComponent->GetVelocity(); + } + + return NiPoint3Constant::ZERO; + +} + void MovementAIComponent::SetVelocity(const NiPoint3& value) { auto* controllablePhysicsComponent = m_Parent->GetComponent(); @@ -294,7 +347,7 @@ void MovementAIComponent::SetVelocity(const NiPoint3& value) { } } -void MovementAIComponent::SetDestination(const NiPoint3& destination) { +void MovementAIComponent::SetDestination(const NiPoint3 destination) { if (m_PullingToPoint) return; const auto location = ApproximateLocation(); @@ -303,6 +356,8 @@ void MovementAIComponent::SetDestination(const NiPoint3& destination) { SetPosition(location); } + m_SourcePosition = location; + std::vector computedPath; if (dpWorld::IsLoaded()) { computedPath = dpWorld::GetNavMesh()->GetPath(m_Parent->GetPosition(), destination, m_Info.wanderSpeed); @@ -319,8 +374,7 @@ void MovementAIComponent::SetDestination(const NiPoint3& destination) { auto step = delta / 10.0f; for (int i = 0; i < 10; i++) { - // TODO: Replace this with += when the NiPoint3::operator+= is fixed - start = start + step; + start += step; computedPath.push_back(start); } diff --git a/dGame/dComponents/MovementAIComponent.h b/dGame/dComponents/MovementAIComponent.h index 852f70014..15b5aaede 100644 --- a/dGame/dComponents/MovementAIComponent.h +++ b/dGame/dComponents/MovementAIComponent.h @@ -14,11 +14,14 @@ #include "Logger.h" #include "Component.h" #include "eReplicaComponentType.h" +#include "Zone.h" #include class ControllablePhysicsComponent; class BaseCombatAIComponent; +struct Path; + /** * Information that describes the different variables used to make an entity move around */ @@ -61,6 +64,8 @@ class MovementAIComponent final : public Component { MovementAIComponent(Entity* parentEntity, MovementAIInfo info); + void SetPath(const std::string pathName); + void Update(float deltaTime) override; /** @@ -73,7 +78,7 @@ class MovementAIComponent final : public Component { * Set a destination point for the entity to move towards * @param value the destination point to move towards */ - void SetDestination(const NiPoint3& value); + void SetDestination(const NiPoint3 value); /** * Returns the current rotation this entity is moving towards @@ -189,7 +194,13 @@ class MovementAIComponent final : public Component { * Sets a path to follow for the AI * @param path the path to follow */ - void SetPath(std::vector path); + void SetPath(std::vector path); + + void Pause(); + + void Resume(); + + NiPoint3 GetVelocity() const; /** * Returns the base speed from the DB for a given LOT @@ -301,7 +312,15 @@ class MovementAIComponent final : public Component { /** * The path from the current position to the destination. */ - std::stack m_CurrentPath; + std::stack m_CurrentPath; + + const Path* m_Path = nullptr; + + NiPoint3 m_SourcePosition; + + bool m_Paused; + + NiPoint3 m_SavedVelocity; }; #endif // MOVEMENTAICOMPONENT_H diff --git a/dGame/dComponents/MovingPlatformComponent.cpp b/dGame/dComponents/MovingPlatformComponent.cpp index 4bcf78c02..77acbb8d2 100644 --- a/dGame/dComponents/MovingPlatformComponent.cpp +++ b/dGame/dComponents/MovingPlatformComponent.cpp @@ -162,7 +162,7 @@ void MovingPlatformComponent::StartPathing() { const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; subComponent->mPosition = currentWaypoint.position; - subComponent->mSpeed = currentWaypoint.movingPlatform.speed; + subComponent->mSpeed = currentWaypoint.speed; subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; targetPosition = nextWaypoint.position; @@ -183,9 +183,7 @@ void MovingPlatformComponent::StartPathing() { const auto travelNext = subComponent->mWaitTime + travelTime; m_Parent->AddCallbackTimer(travelTime, [subComponent, this] { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex); - } + this->m_Parent->GetScript()->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex); }); m_Parent->AddCallbackTimer(travelNext, [this] { @@ -213,7 +211,7 @@ void MovingPlatformComponent::ContinuePathing() { const auto& nextWaypoint = m_Path->pathWaypoints[subComponent->mNextWaypointIndex]; subComponent->mPosition = currentWaypoint.position; - subComponent->mSpeed = currentWaypoint.movingPlatform.speed; + subComponent->mSpeed = currentWaypoint.speed; subComponent->mWaitTime = currentWaypoint.movingPlatform.wait; // + 2; pathSize = m_Path->pathWaypoints.size() - 1; @@ -295,9 +293,7 @@ void MovingPlatformComponent::ContinuePathing() { const auto travelNext = subComponent->mWaitTime + travelTime; m_Parent->AddCallbackTimer(travelTime, [subComponent, this] { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex); - } + this->m_Parent->GetScript()->OnWaypointReached(m_Parent, subComponent->mNextWaypointIndex); }); m_Parent->AddCallbackTimer(travelNext, [this] { diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index a016eb36f..4e34db258 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -2,6 +2,7 @@ #include "GameMessages.h" #include "BrickDatabase.h" #include "CDClientDatabase.h" +#include "CDTamingBuildPuzzleTable.h" #include "ChatPackets.h" #include "EntityManager.h" #include "Character.h" @@ -31,8 +32,9 @@ #include "eGameMasterLevel.h" #include "eMissionState.h" #include "dNavMesh.h" +#include "eGameActivity.h" +#include "eStateChangeType.h" -std::unordered_map PetComponent::buildCache{}; std::unordered_map PetComponent::currentActivities{}; std::unordered_map PetComponent::activePets{}; @@ -40,7 +42,7 @@ std::unordered_map PetComponent::activePets{}; * Maps all the pet lots to a flag indicating that the player has caught it. All basic pets have been guessed by ObjID * while the faction ones could be checked using their respective missions. */ -std::map PetComponent::petFlags = { +const std::map PetComponent::petFlags{ { 3050, 801 }, // Elephant { 3054, 803 }, // Cat { 3195, 806 }, // Triceratops @@ -86,8 +88,7 @@ PetComponent::PetComponent(Entity* parentEntity, uint32_t componentId) : Compone m_Ability = ePetAbilityType::Invalid; m_StartPosition = NiPoint3Constant::ZERO; m_MovementAI = nullptr; - m_TresureTime = 0; - m_Preconditions = nullptr; + m_TreasureTime = 0; std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parentEntity->GetVar(u"CheckPrecondition")); @@ -152,96 +153,53 @@ void PetComponent::OnUse(Entity* originator) { m_Tamer = LWOOBJID_EMPTY; } - auto* inventoryComponent = originator->GetComponent(); - + auto* const inventoryComponent = originator->GetComponent(); if (inventoryComponent == nullptr) { return; } - if (m_Preconditions != nullptr && !m_Preconditions->Check(originator, true)) { + if (m_Preconditions.has_value() && !m_Preconditions->Check(originator, true)) { return; } - auto* movementAIComponent = m_Parent->GetComponent(); - + auto* const movementAIComponent = m_Parent->GetComponent(); if (movementAIComponent != nullptr) { movementAIComponent->Stop(); } inventoryComponent->DespawnPet(); - const auto& cached = buildCache.find(m_Parent->GetLOT()); - int32_t imaginationCost = 0; - - std::string buildFile; - - if (cached == buildCache.end()) { - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = ?;"); - query.bind(1, static_cast(m_Parent->GetLOT())); - - auto result = query.execQuery(); - - if (result.eof()) { - ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to find the puzzle minigame for this pet."); - - return; - } - - if (result.fieldIsNull(0)) { - result.finalize(); - - return; - } - - buildFile = std::string(result.getStringField(0)); - - PetPuzzleData data; - data.buildFile = buildFile; - data.puzzleModelLot = result.getIntField(1); - data.timeLimit = result.getFloatField(2); - data.numValidPieces = result.getIntField(3); - data.imaginationCost = result.getIntField(4); - if (data.timeLimit <= 0) data.timeLimit = 60; - imaginationCost = data.imaginationCost; - - buildCache[m_Parent->GetLOT()] = data; - - result.finalize(); - } else { - buildFile = cached->second.buildFile; - imaginationCost = cached->second.imaginationCost; + const auto* const entry = CDClientManager::GetTable()->GetByLOT(m_Parent->GetLOT()); + if (!entry) { + ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to find the puzzle minigame for this pet."); + return; } - auto* destroyableComponent = originator->GetComponent(); - + const auto* const destroyableComponent = originator->GetComponent(); if (destroyableComponent == nullptr) { return; } - auto imagination = destroyableComponent->GetImagination(); - - if (imagination < imaginationCost) { + const auto imagination = destroyableComponent->GetImagination(); + if (imagination < entry->imaginationCost) { return; } - const auto& bricks = BrickDatabase::GetBricks(buildFile); - + const auto& bricks = BrickDatabase::GetBricks(entry->validPieces); if (bricks.empty()) { ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to load the puzzle minigame for this pet."); - LOG("Couldn't find %s for minigame!", buildFile.c_str()); + LOG("Couldn't find %s for minigame!", entry->validPieces.c_str()); return; } - auto petPosition = m_Parent->GetPosition(); + const auto petPosition = m_Parent->GetPosition(); - auto originatorPosition = originator->GetPosition(); + const auto originatorPosition = originator->GetPosition(); m_Parent->SetRotation(NiQuaternion::LookAt(petPosition, originatorPosition)); float interactionDistance = m_Parent->GetVar(u"interaction_distance"); - if (interactionDistance <= 0) { interactionDistance = 15; } @@ -254,24 +212,23 @@ void PetComponent::OnUse(Entity* originator) { if (dpWorld::IsLoaded()) { NiPoint3 attempt = petPosition + forward * interactionDistance; - float y = dpWorld::GetNavMesh()->GetHeightAtPoint(attempt); + NiPoint3 nearestPoint = dpWorld::GetNavMesh()->NearestPoint(attempt); - while (std::abs(y - petPosition.y) > 4 && interactionDistance > 10) { + while (std::abs(nearestPoint.y - petPosition.y) > 4 && interactionDistance > 10) { const NiPoint3 forward = m_Parent->GetRotation().GetForwardVector(); attempt = originatorPosition + forward * interactionDistance; - y = dpWorld::GetNavMesh()->GetHeightAtPoint(attempt); + nearestPoint = dpWorld::GetNavMesh()->NearestPoint(attempt); interactionDistance -= 0.5f; } - position = attempt; + position = nearestPoint; } else { position = petPosition + forward * interactionDistance; } - auto rotation = NiQuaternion::LookAt(position, petPosition); GameMessages::SendNotifyPetTamingMinigame( @@ -290,11 +247,11 @@ void PetComponent::OnUse(Entity* originator) { m_Parent->GetObjectID(), LWOOBJID_EMPTY, originator->GetObjectID(), - true, + false, ePetTamingNotifyType::BEGIN, - petPosition, - position, - rotation, + NiPoint3Constant::ZERO, + NiPoint3Constant::ZERO, + NiQuaternion(0.0f, 0.0f, 0.0f, 0.0f), UNASSIGNED_SYSTEM_ADDRESS ); @@ -302,12 +259,17 @@ void PetComponent::OnUse(Entity* originator) { m_Tamer = originator->GetObjectID(); SetStatus(5); + Game::entityManager->SerializeEntity(m_Parent); currentActivities.insert_or_assign(m_Tamer, m_Parent->GetObjectID()); // Notify the start of a pet taming minigame - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnNotifyPetTamingMinigame(m_Parent, originator, ePetTamingNotifyType::BEGIN); + m_Parent->GetScript()->OnNotifyPetTamingMinigame(m_Parent, originator, ePetTamingNotifyType::BEGIN); + + auto* characterComponent = originator->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->SetCurrentActivity(eGameActivity::PET_TAMING); + Game::entityManager->SerializeEntity(originator); } } @@ -357,27 +319,27 @@ void PetComponent::Update(float deltaTime) { return; } - if (m_TresureTime > 0) { - auto* tresure = Game::entityManager->GetEntity(m_Interaction); + if (m_TreasureTime > 0) { + auto* treasure = Game::entityManager->GetEntity(m_Interaction); - if (tresure == nullptr) { - m_TresureTime = 0; + if (treasure == nullptr) { + m_TreasureTime = 0; return; } - m_TresureTime -= deltaTime; + m_TreasureTime -= deltaTime; m_MovementAI->Stop(); - if (m_TresureTime <= 0) { + if (m_TreasureTime <= 0) { m_Parent->SetOwnerOverride(m_Owner); - tresure->Smash(m_Parent->GetObjectID()); + treasure->Smash(m_Parent->GetObjectID()); m_Interaction = LWOOBJID_EMPTY; - m_TresureTime = 0; + m_TreasureTime = 0; } return; @@ -434,30 +396,30 @@ void PetComponent::Update(float deltaTime) { // Determine if the "Lost Tags" mission has been completed and digging has been unlocked const bool digUnlocked = missionComponent->GetMissionState(842) == eMissionState::COMPLETE; - Entity* closestTresure = PetDigServer::GetClosestTresure(position); + Entity* closestTreasure = PetDigServer::GetClosestTreasure(position); - if (closestTresure != nullptr && digUnlocked) { + if (closestTreasure != nullptr && digUnlocked) { // Skeleton Dragon Pat special case for bone digging - if (closestTresure->GetLOT() == 12192 && m_Parent->GetLOT() != 13067) { - goto skipTresure; + if (closestTreasure->GetLOT() == 12192 && m_Parent->GetLOT() != 13067) { + goto skipTreasure; } - NiPoint3 tresurePosition = closestTresure->GetPosition(); - float distance = Vector3::DistanceSquared(position, tresurePosition); + NiPoint3 treasurePosition = closestTreasure->GetPosition(); + float distance = Vector3::DistanceSquared(position, treasurePosition); if (distance < 5 * 5) { - m_Interaction = closestTresure->GetObjectID(); + m_Interaction = closestTreasure->GetObjectID(); Command(NiPoint3Constant::ZERO, LWOOBJID_EMPTY, 1, 202, true); - m_TresureTime = 2; + m_TreasureTime = 2; } else if (distance < 10 * 10) { haltDistance = 1; - destination = tresurePosition; + destination = treasurePosition; } } -skipTresure: +skipTreasure: m_MovementAI->SetHaltDistance(haltDistance); @@ -479,9 +441,8 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) { return; } - const auto& cached = buildCache.find(m_Parent->GetLOT()); - - if (cached == buildCache.end()) return; + const auto* const entry = CDClientManager::GetTable()->GetByLOT(m_Parent->GetLOT()); + if (!entry) return; auto* destroyableComponent = tamer->GetComponent(); @@ -489,14 +450,14 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) { auto imagination = destroyableComponent->GetImagination(); - imagination -= cached->second.imaginationCost; + imagination -= entry->imaginationCost; destroyableComponent->SetImagination(imagination); Game::entityManager->SerializeEntity(tamer); if (clientFailed) { - if (imagination < cached->second.imaginationCost) { + if (imagination < entry->imaginationCost) { ClientFailTamingMinigame(); } } else { @@ -519,17 +480,14 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { return; } - const auto& cached = buildCache.find(m_Parent->GetLOT()); - - if (cached == buildCache.end()) { - return; - } + const auto* const entry = CDClientManager::GetTable()->GetByLOT(m_Parent->GetLOT()); + if (!entry) return; GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true); RenderComponent::PlayAnimation(tamer, u"rebuild-celebrate"); EntityInfo info{}; - info.lot = cached->second.puzzleModelLot; + info.lot = entry->puzzleModelLot; info.pos = position; info.rot = NiQuaternionConstant::IDENTITY; info.spawnerID = tamer->GetObjectID(); @@ -677,6 +635,11 @@ void PetComponent::RequestSetPetName(std::u16string name) { UNASSIGNED_SYSTEM_ADDRESS ); + auto* characterComponent = tamer->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->SetCurrentActivity(eGameActivity::NONE); + Game::entityManager->SerializeEntity(tamer); + } GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); auto* modelEntity = Game::entityManager->GetEntity(m_ModelId); @@ -690,9 +653,7 @@ void PetComponent::RequestSetPetName(std::u16string name) { m_Tamer = LWOOBJID_EMPTY; // Notify the end of a pet taming minigame - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::SUCCESS); - } + m_Parent->GetScript()->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::SUCCESS); } void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) { @@ -718,6 +679,11 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) { UNASSIGNED_SYSTEM_ADDRESS ); + auto* characterComponent = tamer->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->SetCurrentActivity(eGameActivity::NONE); + Game::entityManager->SerializeEntity(tamer); + } GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); @@ -731,19 +697,14 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) { Game::entityManager->SerializeEntity(m_Parent); // Notify the end of a pet taming minigame - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::QUIT); - } + m_Parent->GetScript()->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::QUIT); } void PetComponent::StartTimer() { - const auto& cached = buildCache.find(m_Parent->GetLOT()); + const auto* const entry = CDClientManager::GetTable()->GetByLOT(m_Parent->GetLOT()); + if (!entry) return; - if (cached == buildCache.end()) { - return; - } - - m_Timer = cached->second.timeLimit; + m_Timer = entry->timeLimit; } void PetComponent::ClientFailTamingMinigame() { @@ -769,6 +730,11 @@ void PetComponent::ClientFailTamingMinigame() { UNASSIGNED_SYSTEM_ADDRESS ); + auto* characterComponent = tamer->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->SetCurrentActivity(eGameActivity::NONE); + Game::entityManager->SerializeEntity(tamer); + } GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); @@ -782,9 +748,7 @@ void PetComponent::ClientFailTamingMinigame() { Game::entityManager->SerializeEntity(m_Parent); // Notify the end of a pet taming minigame - for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::FAILED); - } + m_Parent->GetScript()->OnNotifyPetTamingMinigame(m_Parent, tamer, ePetTamingNotifyType::FAILED); } void PetComponent::Wander() { @@ -831,8 +795,6 @@ void PetComponent::Wander() { } void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { - AddDrainImaginationTimer(item, fromTaming); - m_ItemId = item->GetId(); m_DatabaseId = item->GetSubKey(); @@ -843,6 +805,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { inventoryComponent->DespawnPet(); m_Owner = inventoryComponent->GetParent()->GetObjectID(); + AddDrainImaginationTimer(fromTaming); auto* owner = GetOwner(); @@ -895,17 +858,14 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { } } -void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { +void PetComponent::AddDrainImaginationTimer(bool fromTaming) { if (Game::config->GetValue("pets_take_imagination") != "1") return; - auto playerInventory = item->GetInventory(); - if (!playerInventory) return; - - auto playerInventoryComponent = playerInventory->GetComponent(); - if (!playerInventoryComponent) return; - - auto playerEntity = playerInventoryComponent->GetParent(); - if (!playerEntity) return; + auto* playerEntity = Game::entityManager->GetEntity(m_Owner); + if (!playerEntity) { + LOG("owner was null or didnt exist!"); + return; + } auto playerDestroyableComponent = playerEntity->GetComponent(); if (!playerDestroyableComponent) return; @@ -914,12 +874,16 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { if (!fromTaming) playerDestroyableComponent->Imagine(-1); // Set this to a variable so when this is called back from the player the timer doesn't fire off. - m_Parent->AddCallbackTimer(m_PetInfo.imaginationDrainRate, [playerDestroyableComponent, this, item]() { - if (!playerDestroyableComponent) { - LOG("No petComponent and/or no playerDestroyableComponent"); + m_Parent->AddCallbackTimer(m_PetInfo.imaginationDrainRate, [this]() { + const auto* owner = Game::entityManager->GetEntity(m_Owner); + if (!owner) { + LOG("owner was null or didnt exist!"); return; } + const auto* playerDestroyableComponent = owner->GetComponent(); + if (!playerDestroyableComponent) return; + // If we are out of imagination despawn the pet. if (playerDestroyableComponent->GetImagination() == 0) { this->Deactivate(); @@ -929,15 +893,13 @@ void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), eUseItemResponse::NoImaginationForPet); } - this->AddDrainImaginationTimer(item); + this->AddDrainImaginationTimer(); }); } void PetComponent::Deactivate() { GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true); - GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, eUnequippableActiveType::PET, m_ItemId, GetOwner()->GetSystemAddress()); - activePets.erase(m_Owner); m_Parent->Kill(); @@ -946,6 +908,8 @@ void PetComponent::Deactivate() { if (owner == nullptr) return; + GameMessages::SendMarkInventoryItemAsActive(m_Owner, false, eUnequippableActiveType::PET, m_ItemId, owner->GetSystemAddress()); + GameMessages::SendAddPetToPlayer(m_Owner, 0, u"", LWOOBJID_EMPTY, LOT_NULL, owner->GetSystemAddress()); GameMessages::SendRegisterPetID(m_Owner, LWOOBJID_EMPTY, owner->GetSystemAddress()); @@ -1070,6 +1034,7 @@ Entity* PetComponent::GetParentEntity() const { } PetComponent::~PetComponent() { + m_Owner = LWOOBJID_EMPTY; } void PetComponent::SetPetNameForModeration(const std::string& petName) { @@ -1094,6 +1059,6 @@ void PetComponent::LoadPetNameFromModeration() { } } -void PetComponent::SetPreconditions(std::string& preconditions) { - m_Preconditions = new PreconditionExpression(preconditions); +void PetComponent::SetPreconditions(const std::string& preconditions) { + m_Preconditions = std::make_optional(preconditions); } diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 0254c5f51..fed3f49a3 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -165,7 +165,7 @@ class PetComponent final : public Component * Sets preconditions for the pet that need to be met before it can be tamed * @param conditions the preconditions to set */ - void SetPreconditions(std::string& conditions); + void SetPreconditions(const std::string& conditions); /** * Returns the entity that this component belongs to @@ -205,7 +205,7 @@ class PetComponent final : public Component * * @param item The item that represents this pet in the inventory. */ - void AddDrainImaginationTimer(Item* item, bool fromTaming = false); + void AddDrainImaginationTimer(bool fromTaming = false); private: @@ -250,15 +250,10 @@ class PetComponent final : public Component */ static std::unordered_map currentActivities; - /** - * Cache of all the minigames and their information from the database - */ - static std::unordered_map buildCache; - /** * Flags that indicate that a player has tamed a pet, indexed by the LOT of the pet */ - static std::map petFlags; + static const std::map petFlags; /** * The ID of the component in the pet component table @@ -334,7 +329,7 @@ class PetComponent final : public Component * Timer that tracks how long a pet has been digging up some treasure, required to spawn the treasure contents * on time */ - float m_TresureTime; + float m_TreasureTime; /** * The position that this pet was spawned at @@ -349,11 +344,10 @@ class PetComponent final : public Component /** * Preconditions that need to be met before an entity can tame this pet */ - PreconditionExpression* m_Preconditions; + std::optional m_Preconditions{}; /** * Pet information loaded from the CDClientDatabase - * TODO: Switch to a reference when safe to do so */ CDPetComponent m_PetInfo; }; diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index 276184b1e..95fed36e6 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -47,7 +47,7 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsCompon m_Direction = NiPoint3(); // * m_DirectionalMultiplier if (m_Parent->GetVar(u"create_physics")) { - CreatePhysics(); + m_dpEntity = CreatePhysicsLnv(m_Scale, ComponentType); } if (m_Parent->GetVar(u"respawnVol")) { @@ -89,105 +89,9 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsCompon m_RespawnRot = m_Rotation; } - /* - for (LDFBaseData* data : settings) { - if (data) { - if (data->GetKey() == u"create_physics") { - if (bool(std::stoi(data->GetValueAsString()))) { - CreatePhysics(settings); - } - } - - if (data->GetKey() == u"respawnVol") { - if (bool(std::stoi(data->GetValueAsString()))) { - m_IsRespawnVolume = true; - } - } - - if (m_IsRespawnVolume) { - if (data->GetKey() == u"rspPos") { - //Joy, we get to split strings! - std::stringstream test(data->GetValueAsString()); - std::string segment; - std::vector seglist; - - while (std::getline(test, segment, '\x1f')) { - seglist.push_back(segment); - } - - m_RespawnPos = NiPoint3(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2])); - } - - if (data->GetKey() == u"rspRot") { - //Joy, we get to split strings! - std::stringstream test(data->GetValueAsString()); - std::string segment; - std::vector seglist; - - while (std::getline(test, segment, '\x1f')) { - seglist.push_back(segment); - } - - m_RespawnRot = NiQuaternion(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2]), std::stof(seglist[3])); - } - } - - if (m_Parent->GetLOT() == 4945) // HF - RespawnPoints - { - m_IsRespawnVolume = true; - m_RespawnPos = m_Position; - m_RespawnRot = m_Rotation; - } - } - } - */ - - if (!m_HasCreatedPhysics) { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); - auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS); - - CDPhysicsComponentTable* physComp = CDClientManager::GetTable(); - - if (physComp == nullptr) return; - - auto* info = physComp->GetByID(componentID); - if (info == nullptr || info->physicsAsset == "" || info->physicsAsset == "NO_PHYSICS") return; - - //temp test - if (info->physicsAsset == "miscellaneous\\misc_phys_10x1x5.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 5.0f, 1.0f); - } else if (info->physicsAsset == "miscellaneous\\misc_phys_640x640.hkx") { - // TODO Fix physics simulation to do simulation at high velocities due to bullet through paper problem... - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1638.4f, 13.521004f * 2.0f, 1638.4f); - - // Move this down by 13.521004 units so it is still effectively at the same height as before - m_Position = m_Position - NiPoint3Constant::UNIT_Y * 13.521004f; - } else if (info->physicsAsset == "env\\trigger_wall_tall.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 25.0f, 1.0f); - } else if (info->physicsAsset == "env\\env_gen_placeholderphysics.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 20.0f, 20.0f, 20.0f); - } else if (info->physicsAsset == "env\\POI_trigger_wall.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 12.5f, 20.0f); // Not sure what the real size is - } else if (info->physicsAsset == "env\\NG_NinjaGo\\env_ng_gen_gate_chamber_puzzle_ceiling_tile_falling_phantom.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 18.0f, 5.0f, 15.0f); - m_Position += m_Rotation.GetForwardVector() * 7.5f; - } else if (info->physicsAsset == "env\\NG_NinjaGo\\ng_flamejet_brick_phantom.HKX") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 1.0f, 12.0f); - m_Position += m_Rotation.GetForwardVector() * 6.0f; - } else if (info->physicsAsset == "env\\Ring_Trigger.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 6.0f, 6.0f, 6.0f); - } else if (info->physicsAsset == "env\\vfx_propertyImaginationBall.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 4.5f); - } else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true); - m_Position.y -= (111.467964f * m_Scale) / 2; - } else { - // LOG_DEBUG("This one is supposed to have %s", info->physicsAsset.c_str()); - - //add fallback cube: - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f); - } - + if (!m_dpEntity) { + m_dpEntity = CreatePhysicsEntity(ComponentType); + if (!m_dpEntity) return; m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position); @@ -201,69 +105,6 @@ PhantomPhysicsComponent::~PhantomPhysicsComponent() { } } -void PhantomPhysicsComponent::CreatePhysics() { - unsigned char alpha; - unsigned char red; - unsigned char green; - unsigned char blue; - int type = -1; - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; - float width = 0.0f; //aka "radius" - float height = 0.0f; - - if (m_Parent->HasVar(u"primitiveModelType")) { - type = m_Parent->GetVar(u"primitiveModelType"); - x = m_Parent->GetVar(u"primitiveModelValueX"); - y = m_Parent->GetVar(u"primitiveModelValueY"); - z = m_Parent->GetVar(u"primitiveModelValueZ"); - } else { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); - auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS); - - CDPhysicsComponentTable* physComp = CDClientManager::GetTable(); - - if (physComp == nullptr) return; - - auto info = physComp->GetByID(componentID); - - if (info == nullptr) return; - - type = info->pcShapeType; - width = info->playerRadius; - height = info->playerHeight; - } - - switch (type) { - case 1: { //Make a new box shape - NiPoint3 boxSize(x, y, z); - if (x == 0.0f) { - //LU has some weird values, so I think it's best to scale them down a bit - if (height < 0.5f) height = 2.0f; - if (width < 0.5f) width = 2.0f; - - //Scale them: - width = width * m_Scale; - height = height * m_Scale; - - boxSize = NiPoint3(width, height, width); - } - - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), boxSize); - break; - } - } - - if (!m_dpEntity) return; - - m_dpEntity->SetPosition({ m_Position.x, m_Position.y - (height / 2), m_Position.z }); - - dpWorld::AddEntity(m_dpEntity); - - m_HasCreatedPhysics = true; -} - void PhantomPhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate); @@ -308,8 +149,9 @@ void ApplyCollisionEffect(const LWOOBJID& target, const ePhysicsEffectType effec controllablePhysicsComponent->SetGravityScale(effectScale); GameMessages::SendSetGravityScale(target, effectScale, targetEntity->GetSystemAddress()); } + break; } - // The other types are not handled by the server + case ePhysicsEffectType::ATTRACT: case ePhysicsEffectType::FRICTION: case ePhysicsEffectType::PUSH: @@ -317,20 +159,20 @@ void ApplyCollisionEffect(const LWOOBJID& target, const ePhysicsEffectType effec default: break; } + // The other types are not handled by the server and are here to handle all cases of the enum. } void PhantomPhysicsComponent::Update(float deltaTime) { if (!m_dpEntity) return; //Process enter events - for (auto en : m_dpEntity->GetNewObjects()) { - if (!en) continue; - ApplyCollisionEffect(en->GetObjectID(), m_EffectType, m_DirectionalMultiplier); - m_Parent->OnCollisionPhantom(en->GetObjectID()); + for (const auto id : m_dpEntity->GetNewObjects()) { + ApplyCollisionEffect(id, m_EffectType, m_DirectionalMultiplier); + m_Parent->OnCollisionPhantom(id); //If we are a respawn volume, inform the client: if (m_IsRespawnVolume) { - auto entity = Game::entityManager->GetEntity(en->GetObjectID()); + auto* const entity = Game::entityManager->GetEntity(id); if (entity) { GameMessages::SendPlayerReachedRespawnCheckpoint(entity, m_RespawnPos, m_RespawnRot); @@ -341,10 +183,9 @@ void PhantomPhysicsComponent::Update(float deltaTime) { } //Process exit events - for (auto en : m_dpEntity->GetRemovedObjects()) { - if (!en) continue; - ApplyCollisionEffect(en->GetObjectID(), m_EffectType, 1.0f); - m_Parent->OnCollisionLeavePhantom(en->GetObjectID()); + for (const auto id : m_dpEntity->GetRemovedObjects()) { + ApplyCollisionEffect(id, m_EffectType, 1.0f); + m_Parent->OnCollisionLeavePhantom(id); } } @@ -358,24 +199,12 @@ void PhantomPhysicsComponent::SetDirection(const NiPoint3& pos) { m_IsDirectional = true; } -void PhantomPhysicsComponent::SpawnVertices() { - if (!m_dpEntity) return; - - LOG("%llu", m_Parent->GetObjectID()); - auto box = static_cast(m_dpEntity->GetShape()); - for (auto vert : box->GetVertices()) { - LOG("%f, %f, %f", vert.x, vert.y, vert.z); - - EntityInfo info; - info.lot = 33; - info.pos = vert; - info.spawner = nullptr; - info.spawnerID = m_Parent->GetObjectID(); - info.spawnerNodeID = 0; - - Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr); - Game::entityManager->ConstructEntity(newEntity); +void PhantomPhysicsComponent::SpawnVertices() const { + if (!m_dpEntity) { + LOG("No dpEntity to spawn vertices for %llu:%i", m_Parent->GetObjectID(), m_Parent->GetLOT()); + return; } + PhysicsComponent::SpawnVertices(m_dpEntity); } void PhantomPhysicsComponent::SetDirectionalMultiplier(float mul) { diff --git a/dGame/dComponents/PhantomPhysicsComponent.h b/dGame/dComponents/PhantomPhysicsComponent.h index 1aae95278..89cfb857c 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.h +++ b/dGame/dComponents/PhantomPhysicsComponent.h @@ -18,6 +18,7 @@ class LDFBaseData; class Entity; class dpEntity; enum class ePhysicsEffectType : uint32_t ; +enum class eReplicaComponentType : uint32_t; /** * Allows the creation of phantom physics for an entity: a physics object that is generally invisible but can be @@ -34,11 +35,6 @@ class PhantomPhysicsComponent final : public PhysicsComponent { void Update(float deltaTime) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; - /** - * Creates the physics shape for this entity based on LDF data - */ - void CreatePhysics(); - /** * Sets the direction this physics object is pointed at * @param pos the direction to set @@ -109,7 +105,7 @@ class PhantomPhysicsComponent final : public PhysicsComponent { /** * Spawns an object at each of the vertices for debugging purposes */ - void SpawnVertices(); + void SpawnVertices() const; /** * Legacy stuff no clue what this does @@ -166,11 +162,6 @@ class PhantomPhysicsComponent final : public PhysicsComponent { */ dpEntity* m_dpEntity; - /** - * Whether or not the physics object has been created yet - */ - bool m_HasCreatedPhysics = false; - /** * Whether or not this physics object represents an object that updates the respawn pos of an entity that crosses it */ diff --git a/dGame/dComponents/PhysicsComponent.cpp b/dGame/dComponents/PhysicsComponent.cpp index 3a84c4ce3..4a250a6a9 100644 --- a/dGame/dComponents/PhysicsComponent.cpp +++ b/dGame/dComponents/PhysicsComponent.cpp @@ -1,5 +1,19 @@ #include "PhysicsComponent.h" +#include "eReplicaComponentType.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" + +#include "CDComponentsRegistryTable.h" +#include "CDPhysicsComponentTable.h" + +#include "dpEntity.h" +#include "dpWorld.h" +#include "dpShapeBox.h" +#include "dpShapeSphere.h" + +#include "EntityInfo.h" + PhysicsComponent::PhysicsComponent(Entity* parent) : Component(parent) { m_Position = NiPoint3Constant::ZERO; m_Rotation = NiQuaternionConstant::IDENTITY; @@ -19,3 +33,190 @@ void PhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitia if (!bIsInitialUpdate) m_DirtyPosition = false; } } + +dpEntity* PhysicsComponent::CreatePhysicsEntity(eReplicaComponentType type) { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); + auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), type); + + CDPhysicsComponentTable* physComp = CDClientManager::GetTable(); + + if (physComp == nullptr) return nullptr; + + auto* info = physComp->GetByID(componentID); + if (info == nullptr || info->physicsAsset == "" || info->physicsAsset == "NO_PHYSICS") return nullptr; + + dpEntity* toReturn; + if (info->physicsAsset == "miscellaneous\\misc_phys_10x1x5.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 10.0f, 5.0f, 1.0f); + } else if (info->physicsAsset == "miscellaneous\\misc_phys_640x640.hkx") { + // TODO Fix physics simulation to do simulation at high velocities due to bullet through paper problem... + toReturn = new dpEntity(m_Parent->GetObjectID(), 1638.4f, 13.521004f * 2.0f, 1638.4f); + + // Move this down by 13.521004 units so it is still effectively at the same height as before + m_Position = m_Position - NiPoint3Constant::UNIT_Y * 13.521004f; + } else if (info->physicsAsset == "env\\trigger_wall_tall.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 10.0f, 25.0f, 1.0f); + } else if (info->physicsAsset == "env\\env_gen_placeholderphysics.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 20.0f, 20.0f, 20.0f); + } else if (info->physicsAsset == "env\\POI_trigger_wall.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 1.0f, 12.5f, 20.0f); // Not sure what the real size is + } else if (info->physicsAsset == "env\\NG_NinjaGo\\env_ng_gen_gate_chamber_puzzle_ceiling_tile_falling_phantom.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 18.0f, 5.0f, 15.0f); + m_Position += m_Rotation.GetForwardVector() * 7.5f; + } else if (info->physicsAsset == "env\\NG_NinjaGo\\ng_flamejet_brick_phantom.HKX") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 1.0f, 1.0f, 12.0f); + m_Position += m_Rotation.GetForwardVector() * 6.0f; + } else if (info->physicsAsset == "env\\Ring_Trigger.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 6.0f, 6.0f, 6.0f); + } else if (info->physicsAsset == "env\\vfx_propertyImaginationBall.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 4.5f); + } else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true); + m_Position.y -= (111.467964f * m_Parent->GetDefaultScale()) / 2; + } else { + // LOG_DEBUG("This one is supposed to have %s", info->physicsAsset.c_str()); + + //add fallback cube: + toReturn = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f); + } + return toReturn; +} + +dpEntity* PhysicsComponent::CreatePhysicsLnv(const float scale, const eReplicaComponentType type) const { + int pcShapeType = -1; + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; + float width = 0.0f; //aka "radius" + float height = 0.0f; + dpEntity* toReturn = nullptr; + + if (m_Parent->HasVar(u"primitiveModelType")) { + pcShapeType = m_Parent->GetVar(u"primitiveModelType"); + x = m_Parent->GetVar(u"primitiveModelValueX"); + y = m_Parent->GetVar(u"primitiveModelValueY"); + z = m_Parent->GetVar(u"primitiveModelValueZ"); + } else { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); + auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), type); + + CDPhysicsComponentTable* physComp = CDClientManager::GetTable(); + + if (physComp == nullptr) return nullptr; + + auto info = physComp->GetByID(componentID); + + if (info == nullptr) return nullptr; + + pcShapeType = info->pcShapeType; + width = info->playerRadius; + height = info->playerHeight; + } + + switch (pcShapeType) { + case 0: { // HKX type + break; + } + case 1: { //Make a new box shape + NiPoint3 boxSize(x, y, z); + if (x == 0.0f) { + //LU has some weird values, so I think it's best to scale them down a bit + if (height < 0.5f) height = 2.0f; + if (width < 0.5f) width = 2.0f; + + //Scale them: + width = width * scale; + height = height * scale; + + boxSize = NiPoint3(width, height, width); + } + + toReturn = new dpEntity(m_Parent->GetObjectID(), boxSize); + + toReturn->SetPosition({ m_Position.x, m_Position.y - (height / 2), m_Position.z }); + break; + } + case 2: { //Make a new cylinder shape + break; + } + case 3: { //Make a new sphere shape + auto [x, y, z] = m_Position; + toReturn = new dpEntity(m_Parent->GetObjectID(), width); + toReturn->SetPosition({ x, y, z }); + break; + } + case 4: { //Make a new capsule shape + break; + } + } + + if (toReturn) dpWorld::AddEntity(toReturn); + + return toReturn; +} + +void PhysicsComponent::SpawnVertices(dpEntity* entity) const { + if (!entity) return; + + LOG("Spawning vertices for %llu", m_Parent->GetObjectID()); + EntityInfo info; + info.lot = 33; + info.spawner = nullptr; + info.spawnerID = m_Parent->GetObjectID(); + info.spawnerNodeID = 0; + + // These don't use overloaded methods as dPhysics does not link with dGame at the moment. + auto box = dynamic_cast(entity->GetShape()); + if (box) { + for (auto vert : box->GetVertices()) { + LOG("Vertex at %f, %f, %f", vert.x, vert.y, vert.z); + + info.pos = vert; + Entity* newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + } + } + auto sphere = dynamic_cast(entity->GetShape()); + if (sphere) { + auto [x, y, z] = entity->GetPosition(); // Use shapes position instead of the parent's position in case it's different + float plusX = x + sphere->GetRadius(); + float minusX = x - sphere->GetRadius(); + float plusY = y + sphere->GetRadius(); + float minusY = y - sphere->GetRadius(); + float plusZ = z + sphere->GetRadius(); + float minusZ = z - sphere->GetRadius(); + + auto radius = sphere->GetRadius(); + LOG("Radius: %f", radius); + LOG("Plus Vertices %f %f %f", plusX, plusY, plusZ); + LOG("Minus Vertices %f %f %f", minusX, minusY, minusZ); + + info.pos = NiPoint3{ x, plusY, z }; + Entity* newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ x, minusY, z }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ plusX, y, z }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ minusX, y, z }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ x, y, plusZ }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ x, y, minusZ }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ x, y, z }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + } +} diff --git a/dGame/dComponents/PhysicsComponent.h b/dGame/dComponents/PhysicsComponent.h index 71f52e546..4bf0828a0 100644 --- a/dGame/dComponents/PhysicsComponent.h +++ b/dGame/dComponents/PhysicsComponent.h @@ -9,6 +9,10 @@ namespace Raknet { class BitStream; }; +enum class eReplicaComponentType : uint32_t; + +class dpEntity; + class PhysicsComponent : public Component { public: PhysicsComponent(Entity* parent); @@ -22,6 +26,12 @@ class PhysicsComponent : public Component { const NiQuaternion& GetRotation() const { return m_Rotation; } virtual void SetRotation(const NiQuaternion& rot) { if (m_Rotation == rot) return; m_Rotation = rot; m_DirtyPosition = true; } protected: + dpEntity* CreatePhysicsEntity(eReplicaComponentType type); + + dpEntity* CreatePhysicsLnv(const float scale, const eReplicaComponentType type) const; + + void SpawnVertices(dpEntity* entity) const; + NiPoint3 m_Position; NiQuaternion m_Rotation; diff --git a/dGame/dComponents/PossessableComponent.cpp b/dGame/dComponents/PossessableComponent.cpp index ae5b05b34..e0e8c8adc 100644 --- a/dGame/dComponents/PossessableComponent.cpp +++ b/dGame/dComponents/PossessableComponent.cpp @@ -18,8 +18,8 @@ PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId) // Should a result not exist for this default to attached visible if (!result.eof()) { - m_PossessionType = static_cast(result.getIntField(0, 1)); // Default to Attached Visible - m_DepossessOnHit = static_cast(result.getIntField(1, 0)); + m_PossessionType = static_cast(result.getIntField("possessionType", 1)); // Default to Attached Visible + m_DepossessOnHit = static_cast(result.getIntField("depossessOnHit", 0)); } else { m_PossessionType = ePossessionType::ATTACHED_VISIBLE; m_DepossessOnHit = false; diff --git a/dGame/dComponents/PossessableComponent.h b/dGame/dComponents/PossessableComponent.h index 6f1968a5d..2102f7fe6 100644 --- a/dGame/dComponents/PossessableComponent.h +++ b/dGame/dComponents/PossessableComponent.h @@ -5,7 +5,7 @@ #include "Component.h" #include "Item.h" #include "PossessorComponent.h" -#include "eAninmationFlags.h" +#include "eAnimationFlags.h" #include "eReplicaComponentType.h" /** diff --git a/dGame/dComponents/PropertyManagementComponent.cpp b/dGame/dComponents/PropertyManagementComponent.cpp index 0dfc04af9..d7be22ac4 100644 --- a/dGame/dComponents/PropertyManagementComponent.cpp +++ b/dGame/dComponents/PropertyManagementComponent.cpp @@ -21,9 +21,11 @@ #include "eObjectBits.h" #include "CharacterComponent.h" #include "PlayerManager.h" +#include "ModelComponent.h" #include #include "CppScripts.h" +#include PropertyManagementComponent* PropertyManagementComponent::instance = nullptr; @@ -49,11 +51,11 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo auto result = query.execQuery(); - if (result.eof() || result.fieldIsNull(0)) { + if (result.eof() || result.fieldIsNull("id")) { return; } - templateId = result.getIntField(0); + templateId = result.getIntField("id"); auto propertyInfo = Database::Get()->GetPropertyInfo(zoneId, cloneId); @@ -105,7 +107,7 @@ std::vector PropertyManagementComponent::GetPaths() const { std::vector points; - std::istringstream stream(result.getStringField(0)); + std::istringstream stream(result.getStringField("path")); std::string token; while (std::getline(stream, token, ' ')) { @@ -214,9 +216,7 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) { Database::Get()->InsertNewProperty(info, templateId, worldId); auto* zoneControlObject = Game::zoneManager->GetZoneControlObject(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControlObject)) { - script->OnZonePropertyRented(zoneControlObject, entity); - } + if (zoneControlObject) zoneControlObject->GetScript()->OnZonePropertyRented(zoneControlObject, entity); return true; } @@ -354,16 +354,11 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N auto* spawner = Game::zoneManager->GetSpawner(spawnerId); - auto ldfModelBehavior = new LDFData(u"modelBehaviors", 0); - auto userModelID = new LDFData(u"userModelID", info.spawnerID); - auto modelType = new LDFData(u"modelType", 2); - auto propertyObjectID = new LDFData(u"propertyObjectID", true); - auto componentWhitelist = new LDFData(u"componentWhitelist", 1); - info.nodes[0]->config.push_back(componentWhitelist); - info.nodes[0]->config.push_back(ldfModelBehavior); - info.nodes[0]->config.push_back(modelType); - info.nodes[0]->config.push_back(propertyObjectID); - info.nodes[0]->config.push_back(userModelID); + info.nodes[0]->config.push_back(new LDFData(u"modelBehaviors", 0)); + info.nodes[0]->config.push_back(new LDFData(u"userModelID", info.spawnerID)); + info.nodes[0]->config.push_back(new LDFData(u"modelType", 2)); + info.nodes[0]->config.push_back(new LDFData(u"propertyObjectID", true)); + info.nodes[0]->config.push_back(new LDFData(u"componentWhitelist", 1)); auto* model = spawner->Spawn(); @@ -587,31 +582,33 @@ void PropertyManagementComponent::Load() { GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER); GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT); - LDFBaseData* ldfBlueprintID = new LDFData(u"blueprintid", blueprintID); - LDFBaseData* componentWhitelist = new LDFData(u"componentWhitelist", 1); - LDFBaseData* modelType = new LDFData(u"modelType", 2); - LDFBaseData* propertyObjectID = new LDFData(u"propertyObjectID", true); - LDFBaseData* userModelID = new LDFData(u"userModelID", databaseModel.id); - - settings.push_back(ldfBlueprintID); - settings.push_back(componentWhitelist); - settings.push_back(modelType); - settings.push_back(propertyObjectID); - settings.push_back(userModelID); + settings.push_back(new LDFData(u"blueprintid", blueprintID)); + settings.push_back(new LDFData(u"componentWhitelist", 1)); + settings.push_back(new LDFData(u"modelType", 2)); + settings.push_back(new LDFData(u"propertyObjectID", true)); + settings.push_back(new LDFData(u"userModelID", databaseModel.id)); } else { - auto modelType = new LDFData(u"modelType", 2); - auto userModelID = new LDFData(u"userModelID", databaseModel.id); - auto ldfModelBehavior = new LDFData(u"modelBehaviors", 0); - auto propertyObjectID = new LDFData(u"propertyObjectID", true); - auto componentWhitelist = new LDFData(u"componentWhitelist", 1); - - settings.push_back(componentWhitelist); - settings.push_back(ldfModelBehavior); - settings.push_back(modelType); - settings.push_back(propertyObjectID); - settings.push_back(userModelID); + settings.push_back(new LDFData(u"modelType", 2)); + settings.push_back(new LDFData(u"userModelID", databaseModel.id)); + settings.push_back(new LDFData(u"modelBehaviors", 0)); + settings.push_back(new LDFData(u"propertyObjectID", true)); + settings.push_back(new LDFData(u"componentWhitelist", 1)); } + std::ostringstream userModelBehavior; + bool firstAdded = false; + for (auto behavior : databaseModel.behaviors) { + if (behavior < 0) { + LOG("Invalid behavior ID: %d, removing behavior reference from model", behavior); + behavior = 0; + } + if (firstAdded) userModelBehavior << ","; + userModelBehavior << behavior; + firstAdded = true; + } + + settings.push_back(new LDFData(u"userModelBehaviors", userModelBehavior.str())); + node->config = settings; const auto spawnerId = Game::zoneManager->MakeSpawner(info); @@ -629,6 +626,12 @@ void PropertyManagementComponent::Save() { return; } + const auto* const owner = GetOwner(); + if (!owner) return; + + const auto* const character = owner->GetCharacter(); + if (!character) return; + auto present = Database::Get()->GetPropertyModels(propertyId); std::vector modelIds; @@ -643,6 +646,20 @@ void PropertyManagementComponent::Save() { if (entity == nullptr) { continue; } + auto* modelComponent = entity->GetComponent(); + if (!modelComponent) continue; + const auto modelBehaviors = modelComponent->GetBehaviorsForSave(); + + // save the behaviors of the model + for (const auto& [behaviorId, behaviorStr] : modelBehaviors) { + if (behaviorStr.empty() || behaviorId == -1 || behaviorId == 0) continue; + IBehaviors::Info info { + .behaviorId = behaviorId, + .characterId = character->GetID(), + .behaviorInfo = behaviorStr + }; + Database::Get()->AddBehavior(info); + } const auto position = entity->GetPosition(); const auto rotation = entity->GetRotation(); @@ -654,10 +671,13 @@ void PropertyManagementComponent::Save() { model.position = position; model.rotation = rotation; model.ugcId = 0; + for (auto i = 0; i < model.behaviors.size(); i++) { + model.behaviors[i] = modelBehaviors[i].first; + } Database::Get()->InsertNewPropertyModel(propertyId, model, "Objects_" + std::to_string(model.lot) + "_name"); } else { - Database::Get()->UpdateModelPositionRotation(id, position, rotation); + Database::Get()->UpdateModel(id, position, rotation, modelBehaviors); } } diff --git a/dGame/dComponents/ProximityMonitorComponent.cpp b/dGame/dComponents/ProximityMonitorComponent.cpp index fbac8ddb2..3338dd430 100644 --- a/dGame/dComponents/ProximityMonitorComponent.cpp +++ b/dGame/dComponents/ProximityMonitorComponent.cpp @@ -5,7 +5,7 @@ #include "EntityManager.h" #include "SimplePhysicsComponent.h" -const std::map ProximityMonitorComponent::m_EmptyObjectMap = {}; +const std::unordered_set ProximityMonitorComponent::m_EmptyObjectSet = {}; ProximityMonitorComponent::ProximityMonitorComponent(Entity* parent, int radiusSmall, int radiusLarge) : Component(parent) { if (radiusSmall != -1 && radiusLarge != -1) { @@ -38,40 +38,41 @@ void ProximityMonitorComponent::SetProximityRadius(dpEntity* entity, const std:: m_ProximitiesData.insert(std::make_pair(name, entity)); } -const std::map& ProximityMonitorComponent::GetProximityObjects(const std::string& name) { - const auto& iter = m_ProximitiesData.find(name); +const std::unordered_set& ProximityMonitorComponent::GetProximityObjects(const std::string& name) { + const auto iter = m_ProximitiesData.find(name); - if (iter == m_ProximitiesData.end()) { - return m_EmptyObjectMap; + if (iter == m_ProximitiesData.cend()) { + return m_EmptyObjectSet; } return iter->second->GetCurrentlyCollidingObjects(); } bool ProximityMonitorComponent::IsInProximity(const std::string& name, LWOOBJID objectID) { - const auto& iter = m_ProximitiesData.find(name); + const auto iter = m_ProximitiesData.find(name); - if (iter == m_ProximitiesData.end()) { + if (iter == m_ProximitiesData.cend()) { return false; } - const auto& collitions = iter->second->GetCurrentlyCollidingObjects(); + const auto& collisions = iter->second->GetCurrentlyCollidingObjects(); - return collitions.find(objectID) != collitions.end(); + return collisions.contains(objectID); } void ProximityMonitorComponent::Update(float deltaTime) { for (const auto& prox : m_ProximitiesData) { if (!prox.second) continue; + prox.second->SetPosition(m_Parent->GetPosition()); //Process enter events - for (auto* en : prox.second->GetNewObjects()) { - m_Parent->OnCollisionProximity(en->GetObjectID(), prox.first, "ENTER"); + for (const auto id : prox.second->GetNewObjects()) { + m_Parent->OnCollisionProximity(id, prox.first, "ENTER"); } //Process exit events - for (auto* en : prox.second->GetRemovedObjects()) { - m_Parent->OnCollisionProximity(en->GetObjectID(), prox.first, "LEAVE"); + for (const auto id : prox.second->GetRemovedObjects()) { + m_Parent->OnCollisionProximity(id, prox.first, "LEAVE"); } } } diff --git a/dGame/dComponents/ProximityMonitorComponent.h b/dGame/dComponents/ProximityMonitorComponent.h index 512b28485..e80f1b5b5 100644 --- a/dGame/dComponents/ProximityMonitorComponent.h +++ b/dGame/dComponents/ProximityMonitorComponent.h @@ -6,6 +6,8 @@ #ifndef PROXIMITYMONITORCOMPONENT_H #define PROXIMITYMONITORCOMPONENT_H +#include + #include "BitStream.h" #include "Entity.h" #include "dpWorld.h" @@ -42,9 +44,9 @@ class ProximityMonitorComponent final : public Component { /** * Returns the last of entities that are used to check proximity, given a name * @param name the proximity name to retrieve physics objects for - * @return a map of physics entities for this name, indexed by object ID + * @return a set of physics entity object IDs for this name */ - const std::map& GetProximityObjects(const std::string& name); + const std::unordered_set& GetProximityObjects(const std::string& name); /** * Checks if the passed object is in proximity of the named proximity sensor @@ -70,7 +72,7 @@ class ProximityMonitorComponent final : public Component { /** * Default value for the proximity data */ - static const std::map m_EmptyObjectMap; + static const std::unordered_set m_EmptyObjectSet; }; #endif // PROXIMITYMONITORCOMPONENT_H diff --git a/dGame/dComponents/QuickBuildComponent.cpp b/dGame/dComponents/QuickBuildComponent.cpp index c8ca44074..e3aed82db 100644 --- a/dGame/dComponents/QuickBuildComponent.cpp +++ b/dGame/dComponents/QuickBuildComponent.cpp @@ -414,13 +414,11 @@ void QuickBuildComponent::StartQuickBuild(Entity* const user) { movingPlatform->OnQuickBuildInitilized(); } - for (auto* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnQuickBuildStart(m_Parent, user); - } + auto* script = m_Parent->GetScript(); + script->OnQuickBuildStart(m_Parent, user); // Notify scripts and possible subscribers - for (auto* script : CppScripts::GetEntityScripts(m_Parent)) - script->OnQuickBuildNotifyState(m_Parent, m_State); + script->OnQuickBuildNotifyState(m_Parent, m_State); for (const auto& cb : m_QuickBuildStateCallbacks) cb(m_State); } @@ -485,10 +483,9 @@ void QuickBuildComponent::CompleteQuickBuild(Entity* const user) { } // Notify scripts - for (auto* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnQuickBuildComplete(m_Parent, user); - script->OnQuickBuildNotifyState(m_Parent, m_State); - } + auto* script = m_Parent->GetScript(); + script->OnQuickBuildComplete(m_Parent, user); + script->OnQuickBuildNotifyState(m_Parent, m_State); // Notify subscribers for (const auto& callback : m_QuickBuildStateCallbacks) @@ -539,8 +536,7 @@ void QuickBuildComponent::ResetQuickBuild(const bool failed) { Game::entityManager->SerializeEntity(m_Parent); // Notify scripts and possible subscribers - for (auto* script : CppScripts::GetEntityScripts(m_Parent)) - script->OnQuickBuildNotifyState(m_Parent, m_State); + m_Parent->GetScript()->OnQuickBuildNotifyState(m_Parent, m_State); for (const auto& cb : m_QuickBuildStateCallbacks) cb(m_State); @@ -571,8 +567,7 @@ void QuickBuildComponent::CancelQuickBuild(Entity* const entity, const eQuickBui m_StateDirty = true; // Notify scripts and possible subscribers - for (auto* script : CppScripts::GetEntityScripts(m_Parent)) - script->OnQuickBuildNotifyState(m_Parent, m_State); + m_Parent->GetScript()->OnQuickBuildNotifyState(m_Parent, m_State); for (const auto& cb : m_QuickBuildStateCallbacks) cb(m_State); diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index d7e01f949..ab6d5d178 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -25,6 +25,7 @@ #include "LeaderboardManager.h" #include "dZoneManager.h" #include "CDActivitiesTable.h" +#include "eStateChangeType.h" #include #ifndef M_PI @@ -44,7 +45,6 @@ RacingControlComponent::RacingControlComponent(Entity* parent) m_LoadedPlayers = 0; m_LoadTimer = 0; m_Finished = 0; - m_StartTime = 0; m_EmptyTimer = 0; m_SoloRacing = Game::config->GetValue("solo_racing") == "1"; @@ -77,6 +77,9 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) { m_LoadedPlayers++; + // not live accurate to stun the player but prevents them from using skills during the race that are not meant to be used. + GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY, true, true, true, true, true, true, true, true, true); + LOG("Loading player %i", m_LoadedPlayers); m_LobbyPlayers.push_back(player->GetObjectID()); @@ -394,25 +397,6 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t bu GameMessages::SendNotifyRacingClient( m_Parent->GetObjectID(), 2, 0, LWOOBJID_EMPTY, u"", player->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - - auto* missionComponent = player->GetComponent(); - - if (missionComponent == nullptr) return; - - missionComponent->Progress(eMissionTaskType::RACING, 0, static_cast(eRacingTaskParam::COMPETED_IN_RACE)); // Progress task for competing in a race - missionComponent->Progress(eMissionTaskType::RACING, data->smashedTimes, static_cast(eRacingTaskParam::SAFE_DRIVER)); // Finish a race without being smashed. - - // If solo racing is enabled OR if there are 3 players in the race, progress placement tasks. - if (m_SoloRacing || m_LoadedPlayers > 2) { - missionComponent->Progress(eMissionTaskType::RACING, data->finished, static_cast(eRacingTaskParam::FINISH_WITH_PLACEMENT)); // Finish in 1st place on a race - if (data->finished == 1) { - missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), static_cast(eRacingTaskParam::FIRST_PLACE_MULTIPLE_TRACKS)); // Finish in 1st place on multiple tracks. - missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), static_cast(eRacingTaskParam::WIN_RACE_IN_WORLD)); // Finished first place in specific world. - } - if (data->finished == m_LoadedPlayers) { - missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), static_cast(eRacingTaskParam::LAST_PLACE_FINISH)); // Finished first place in specific world. - } - } } else if ((id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") && button == m_ActivityExitConfirm) { auto* vehicle = Game::entityManager->GetEntity(data->vehicleID); @@ -442,9 +426,9 @@ void RacingControlComponent::Serialize(RakNet::BitStream& outBitStream, bool bIs outBitStream.Write(player.playerID); outBitStream.Write(player.data[0]); - if (player.finished != 0) outBitStream.Write(player.raceTime); + if (player.finished != 0) outBitStream.Write(player.raceTime.count() / 1000.0f); else outBitStream.Write(player.data[1]); - if (player.finished != 0) outBitStream.Write(player.bestLapTime); + if (player.finished != 0) outBitStream.Write(player.bestLapTime.count() / 1000.0f); else outBitStream.Write(player.data[2]); if (player.finished == 1) outBitStream.Write(1.0f); else outBitStream.Write(player.data[3]); @@ -505,8 +489,8 @@ void RacingControlComponent::Serialize(RakNet::BitStream& outBitStream, bool bIs if (player.finished == 0) continue; outBitStream.Write1(); // Has more data outBitStream.Write(player.playerID); - outBitStream.Write(player.bestLapTime); - outBitStream.Write(player.raceTime); + outBitStream.Write(player.bestLapTime.count() / 1000.0f); + outBitStream.Write(player.raceTime.count() / 1000.0f); } outBitStream.Write0(); // No more data @@ -736,7 +720,7 @@ void RacingControlComponent::Update(float deltaTime) { Game::entityManager->SerializeEntity(m_Parent); - m_StartTime = std::time(nullptr); + m_StartTime = std::chrono::high_resolution_clock::now(); } m_StartTimer += deltaTime; @@ -817,52 +801,68 @@ void RacingControlComponent::Update(float deltaTime) { // Some offset up to make they don't fall through the terrain on a // respawn, seems to fix itself to the track anyhow - player.respawnPosition = position + NiPoint3Constant::UNIT_Y * 5; - player.respawnRotation = vehicle->GetRotation(); + if (waypoint.racing.isResetNode) { + player.respawnPosition = position + NiPoint3Constant::UNIT_Y * 5; + player.respawnRotation = vehicle->GetRotation(); + } player.respawnIndex = respawnIndex; // Reached the start point, lapped if (respawnIndex == 0) { - time_t lapTime = std::time(nullptr) - (player.lap == 0 ? m_StartTime : player.lapTime); + const auto now = std::chrono::high_resolution_clock::now(); + const auto lapTime = std::chrono::duration_cast(now - (player.lap == 0 ? m_StartTime : player.lapTime)); // Cheating check - if (lapTime < 40) { + if (lapTime.count() < 40000) { continue; } - player.lap++; - - player.lapTime = std::time(nullptr); + player.lapTime = now; - if (player.bestLapTime == 0 || player.bestLapTime > lapTime) { + if (player.bestLapTime > lapTime || player.lap == 0) { player.bestLapTime = lapTime; LOG("Best lap time (%llu)", lapTime); } + player.lap++; + auto* missionComponent = playerEntity->GetComponent(); if (missionComponent != nullptr) { // Progress lap time tasks - missionComponent->Progress(eMissionTaskType::RACING, (lapTime) * 1000, static_cast(eRacingTaskParam::LAP_TIME)); + missionComponent->Progress(eMissionTaskType::RACING, lapTime.count(), static_cast(eRacingTaskParam::LAP_TIME)); if (player.lap == 3) { m_Finished++; player.finished = m_Finished; - const auto raceTime = - (std::time(nullptr) - m_StartTime); + const auto raceTime = std::chrono::duration_cast(now - m_StartTime); player.raceTime = raceTime; - LOG("Completed time %llu, %llu", - raceTime, raceTime * 1000); + LOG("Completed time %llums %fs", raceTime.count(), raceTime.count() / 1000.0f); - LeaderboardManager::SaveScore(playerEntity->GetObjectID(), m_ActivityID, static_cast(player.raceTime), static_cast(player.bestLapTime), static_cast(player.finished == 1)); + LeaderboardManager::SaveScore(playerEntity->GetObjectID(), m_ActivityID, static_cast(player.raceTime.count()) / 1000, static_cast(player.bestLapTime.count()) / 1000, static_cast(player.finished == 1)); // Entire race time - missionComponent->Progress(eMissionTaskType::RACING, (raceTime) * 1000, static_cast(eRacingTaskParam::TOTAL_TRACK_TIME)); + missionComponent->Progress(eMissionTaskType::RACING, player.raceTime.count(), static_cast(eRacingTaskParam::TOTAL_TRACK_TIME)); + + missionComponent->Progress(eMissionTaskType::RACING, 0, static_cast(eRacingTaskParam::COMPETED_IN_RACE)); // Progress task for competing in a race + missionComponent->Progress(eMissionTaskType::RACING, player.smashedTimes, static_cast(eRacingTaskParam::SAFE_DRIVER)); // Finish a race without being smashed. + + // If solo racing is enabled OR if there are 3 players in the race, progress placement tasks. + if (m_SoloRacing || m_RacingPlayers.size() > 2) { + missionComponent->Progress(eMissionTaskType::RACING, player.finished, static_cast(eRacingTaskParam::FINISH_WITH_PLACEMENT)); // Finish in 1st place on a race + if (player.finished == 1) { + missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), static_cast(eRacingTaskParam::FIRST_PLACE_MULTIPLE_TRACKS)); // Finish in 1st place on multiple tracks. + missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), static_cast(eRacingTaskParam::WIN_RACE_IN_WORLD)); // Finished first place in specific world. + } + if (player.finished == m_RacingPlayers.size()) { + missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), static_cast(eRacingTaskParam::LAST_PLACE_FINISH)); // Finished first place in specific world. + } + } auto* characterComponent = playerEntity->GetComponent(); if (characterComponent != nullptr) { @@ -871,8 +871,8 @@ void RacingControlComponent::Update(float deltaTime) { } } - LOG("Lapped (%i) in (%llu)", player.lap, - lapTime); + LOG("Lapped (%i) in (%llums %fs)", player.lap, + lapTime.count(), lapTime.count() / 1000.0f); } LOG("Reached point (%i)/(%i)", player.respawnIndex, diff --git a/dGame/dComponents/RacingControlComponent.h b/dGame/dComponents/RacingControlComponent.h index 790459e31..43c7e158a 100644 --- a/dGame/dComponents/RacingControlComponent.h +++ b/dGame/dComponents/RacingControlComponent.h @@ -8,6 +8,7 @@ #include "Entity.h" #include "Component.h" #include "eReplicaComponentType.h" +#include /** * Information for each player in the race @@ -72,12 +73,12 @@ struct RacingPlayerInfo { /** * The fastest lap time of the player */ - time_t bestLapTime = 0; + std::chrono::milliseconds bestLapTime; /** * The current lap time of the player */ - time_t lapTime = 0; + std::chrono::high_resolution_clock::time_point lapTime; /** * The number of times this player smashed their car @@ -97,7 +98,7 @@ struct RacingPlayerInfo { /** * Unused */ - time_t raceTime = 0; + std::chrono::milliseconds raceTime; }; /** @@ -231,7 +232,7 @@ class RacingControlComponent final : public Component { /** * The time the race was started */ - time_t m_StartTime; + std::chrono::high_resolution_clock::time_point m_StartTime; /** * Timer for tracking how long a player was alone in this race diff --git a/dGame/dComponents/RenderComponent.cpp b/dGame/dComponents/RenderComponent.cpp index 2067ef2a8..cc5974a1e 100644 --- a/dGame/dComponents/RenderComponent.cpp +++ b/dGame/dComponents/RenderComponent.cpp @@ -117,7 +117,7 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e auto result = query.execQuery(); - if (result.eof() || result.fieldIsNull(0)) { + if (result.eof() || result.fieldIsNull("animation_length")) { result.finalize(); m_DurationCache[effectId] = 0; @@ -127,7 +127,7 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e return; } - effect.time = static_cast(result.getFloatField(0)); + effect.time = static_cast(result.getFloatField("animation_length")); result.finalize(); diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp index 30faa6885..df81aab36 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp @@ -1,16 +1,57 @@ -/* - * Darkflame Universe - * Copyright 2023 - */ +// Darkflame Universe +// Copyright 2024 #include "RigidbodyPhantomPhysicsComponent.h" #include "Entity.h" +#include "dpEntity.h" +#include "CDComponentsRegistryTable.h" +#include "CDPhysicsComponentTable.h" +#include "dpWorld.h" +#include "dpShapeBox.h" +#include "dpShapeSphere.h" +#include"EntityInfo.h" + RigidbodyPhantomPhysicsComponent::RigidbodyPhantomPhysicsComponent(Entity* parent) : PhysicsComponent(parent) { m_Position = m_Parent->GetDefaultPosition(); m_Rotation = m_Parent->GetDefaultRotation(); + m_Scale = m_Parent->GetDefaultScale(); + + if (m_Parent->GetVar(u"create_physics")) { + m_dpEntity = CreatePhysicsLnv(m_Scale, ComponentType); + if (!m_dpEntity) { + m_dpEntity = CreatePhysicsEntity(ComponentType); + if (!m_dpEntity) return; + m_dpEntity->SetScale(m_Scale); + m_dpEntity->SetRotation(m_Rotation); + m_dpEntity->SetPosition(m_Position); + dpWorld::AddEntity(m_dpEntity); + } + } } void RigidbodyPhantomPhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate); } + +void RigidbodyPhantomPhysicsComponent::Update(const float deltaTime) { + if (!m_dpEntity) return; + + //Process enter events + for (const auto id : m_dpEntity->GetNewObjects()) { + m_Parent->OnCollisionPhantom(id); + } + + //Process exit events + for (const auto id : m_dpEntity->GetRemovedObjects()) { + m_Parent->OnCollisionLeavePhantom(id); + } +} + +void RigidbodyPhantomPhysicsComponent::SpawnVertices() const { + if (!m_dpEntity) { + LOG("No dpEntity to spawn vertices for %llu:%i", m_Parent->GetObjectID(), m_Parent->GetLOT()); + return; + } + PhysicsComponent::SpawnVertices(m_dpEntity); +} diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h index 09820f8eb..11595ec03 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h @@ -1,10 +1,8 @@ -/* - * Darkflame Universe - * Copyright 2023 - */ +// Darkflame Universe +// Copyright 2024 -#ifndef __RIGIDBODYPHANTOMPHYSICS_H__ -#define __RIGIDBODYPHANTOMPHYSICS_H__ +#ifndef RIGIDBODYPHANTOMPHYSICS_H +#define RIGIDBODYPHANTOMPHYSICS_H #include "BitStream.h" #include "dCommonVars.h" @@ -13,6 +11,8 @@ #include "PhysicsComponent.h" #include "eReplicaComponentType.h" +class dpEntity; + /** * Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the * bananas that fall from trees in GF. @@ -23,7 +23,15 @@ class RigidbodyPhantomPhysicsComponent : public PhysicsComponent { RigidbodyPhantomPhysicsComponent(Entity* parent); + void Update(const float deltaTime) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; + + void SpawnVertices() const; +private: + float m_Scale{}; + + dpEntity* m_dpEntity{}; }; -#endif // __RIGIDBODYPHANTOMPHYSICS_H__ +#endif // RIGIDBODYPHANTOMPHYSICS_H diff --git a/dGame/dComponents/RocketLaunchpadControlComponent.cpp b/dGame/dComponents/RocketLaunchpadControlComponent.cpp index 2bc4deec8..8fde926b2 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.cpp +++ b/dGame/dComponents/RocketLaunchpadControlComponent.cpp @@ -18,7 +18,7 @@ #include "BitStreamUtils.h" #include "eObjectWorldState.h" #include "eConnectionType.h" -#include "eMasterMessageType.h" +#include "MessageType/Master.h" RocketLaunchpadControlComponent::RocketLaunchpadControlComponent(Entity* parent, int rocketId) : Component(parent) { auto query = CDClientDatabase::CreatePreppedStmt( @@ -27,12 +27,12 @@ RocketLaunchpadControlComponent::RocketLaunchpadControlComponent(Entity* parent, auto result = query.execQuery(); - if (!result.eof() && !result.fieldIsNull(0)) { - m_TargetZone = result.getIntField(0); - m_DefaultZone = result.getIntField(1); - m_TargetScene = result.getStringField(2); - m_AltPrecondition = new PreconditionExpression(result.getStringField(3)); - m_AltLandingScene = result.getStringField(4); + if (!result.eof() && !result.fieldIsNull("targetZone")) { + m_TargetZone = result.getIntField("targetZone"); + m_DefaultZone = result.getIntField("defaultZoneID"); + m_TargetScene = result.getStringField("targetScene"); + m_AltPrecondition = new PreconditionExpression(result.getStringField("altLandingPrecondition")); + m_AltLandingScene = result.getStringField("altLandingSpawnPointName"); } result.finalize(); @@ -137,7 +137,7 @@ LWOCLONEID RocketLaunchpadControlComponent::GetSelectedCloneId(LWOOBJID player) void RocketLaunchpadControlComponent::TellMasterToPrepZone(int zoneID) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PREP_ZONE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::PREP_ZONE); bitStream.Write(zoneID); Game::server->SendToMaster(bitStream); } diff --git a/dScripts/ScriptComponent.cpp b/dGame/dComponents/ScriptComponent.cpp similarity index 95% rename from dScripts/ScriptComponent.cpp rename to dGame/dComponents/ScriptComponent.cpp index 57e6e8324..d6bff5b52 100644 --- a/dScripts/ScriptComponent.cpp +++ b/dGame/dComponents/ScriptComponent.cpp @@ -41,7 +41,7 @@ void ScriptComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitial } } -CppScripts::Script* ScriptComponent::GetScript() { +CppScripts::Script* const ScriptComponent::GetScript() { return m_Script; } diff --git a/dScripts/ScriptComponent.h b/dGame/dComponents/ScriptComponent.h similarity index 97% rename from dScripts/ScriptComponent.h rename to dGame/dComponents/ScriptComponent.h index a1371109d..adc7cc8b0 100644 --- a/dScripts/ScriptComponent.h +++ b/dGame/dComponents/ScriptComponent.h @@ -30,7 +30,7 @@ class ScriptComponent final : public Component { * Returns the script that's attached to this entity * @return the script that's attached to this entity */ - CppScripts::Script* GetScript(); + CppScripts::Script* const GetScript(); /** * Sets whether the entity should be serialized, unused diff --git a/dGame/dComponents/SimplePhysicsComponent.cpp b/dGame/dComponents/SimplePhysicsComponent.cpp index 3b52395e9..6bc2e2bc9 100644 --- a/dGame/dComponents/SimplePhysicsComponent.cpp +++ b/dGame/dComponents/SimplePhysicsComponent.cpp @@ -27,6 +27,7 @@ SimplePhysicsComponent::SimplePhysicsComponent(Entity* parent, uint32_t componen } else { SetClimbableType(eClimbableType::CLIMBABLE_TYPE_NOT); } + m_PhysicsMotionState = m_Parent->GetVarAs(u"motionType"); } SimplePhysicsComponent::~SimplePhysicsComponent() { @@ -47,11 +48,10 @@ void SimplePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIs } // Physics motion state - if (m_PhysicsMotionState != 0) { - outBitStream.Write1(); + outBitStream.Write(m_DirtyPhysicsMotionState || bIsInitialUpdate); + if (m_DirtyPhysicsMotionState || bIsInitialUpdate) { outBitStream.Write(m_PhysicsMotionState); - } else { - outBitStream.Write0(); + m_DirtyPhysicsMotionState = false; } PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate); } @@ -61,5 +61,6 @@ uint32_t SimplePhysicsComponent::GetPhysicsMotionState() const { } void SimplePhysicsComponent::SetPhysicsMotionState(uint32_t value) { + m_DirtyPhysicsMotionState = m_PhysicsMotionState != value; m_PhysicsMotionState = value; } diff --git a/dGame/dComponents/SimplePhysicsComponent.h b/dGame/dComponents/SimplePhysicsComponent.h index c6ef52a00..b4491e127 100644 --- a/dGame/dComponents/SimplePhysicsComponent.h +++ b/dGame/dComponents/SimplePhysicsComponent.h @@ -102,7 +102,9 @@ class SimplePhysicsComponent : public PhysicsComponent { /** * The current physics motion state */ - uint32_t m_PhysicsMotionState = 0; + uint32_t m_PhysicsMotionState = 5; + + bool m_DirtyPhysicsMotionState = true; /** * Whether or not the entity is climbable diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index 329246f45..999bf9dba 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -24,7 +24,7 @@ #include "CDClientManager.h" #include "CDSkillBehaviorTable.h" #include "eConnectionType.h" -#include "eClientMessageType.h" +#include "MessageType/Client.h" ProjectileSyncEntry::ProjectileSyncEntry() { } @@ -38,7 +38,7 @@ bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t s context->skillID = skillID; - this->m_managedBehaviors.insert_or_assign(skillUid, context); + this->m_managedBehaviors.insert({ skillUid, context }); auto* behavior = Behavior::CreateBehavior(behaviorId); @@ -52,17 +52,24 @@ bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t s } void SkillComponent::SyncPlayerSkill(const uint32_t skillUid, const uint32_t syncId, RakNet::BitStream& bitStream) { - const auto index = this->m_managedBehaviors.find(skillUid); + const auto index = this->m_managedBehaviors.equal_range(skillUid); - if (index == this->m_managedBehaviors.end()) { + if (index.first == this->m_managedBehaviors.end()) { LOG("Failed to find skill with uid (%i)!", skillUid, syncId); return; } - auto* context = index->second; + bool foundSyncId = false; + for (auto it = index.first; it != index.second && !foundSyncId; ++it) { + const auto& context = it->second; - context->SyncBehavior(syncId, bitStream); + foundSyncId = context->SyncBehavior(syncId, bitStream); + } + + if (!foundSyncId) { + LOG("Failed to find sync id (%i) for skill with uid (%i)!", syncId, skillUid); + } } @@ -99,7 +106,7 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B return; } - const auto behavior_id = static_cast(result.getIntField(0)); + const auto behavior_id = static_cast(result.getIntField("behaviorID")); result.finalize(); @@ -138,7 +145,7 @@ void SkillComponent::Update(const float deltaTime) { for (const auto& pair : this->m_managedBehaviors) pair.second->UpdatePlayerSyncs(deltaTime); } - std::map keep{}; + std::multimap keep{}; for (const auto& pair : this->m_managedBehaviors) { auto* context = pair.second; @@ -176,7 +183,7 @@ void SkillComponent::Update(const float deltaTime) { } } - keep.insert_or_assign(pair.first, context); + keep.insert({ pair.first, context }); } this->m_managedBehaviors = keep; @@ -227,7 +234,7 @@ void SkillComponent::RegisterCalculatedProjectile(const LWOOBJID projectileId, B this->m_managedProjectiles.push_back(entry); } -bool SkillComponent::CastSkill(const uint32_t skillId, LWOOBJID target, const LWOOBJID optionalOriginatorID) { +bool SkillComponent::CastSkill(const uint32_t skillId, LWOOBJID target, const LWOOBJID optionalOriginatorID, const int32_t castType, const NiQuaternion rotationOverride) { uint32_t behaviorId = -1; // try to find it via the cache const auto& pair = m_skillBehaviorCache.find(skillId); @@ -247,11 +254,19 @@ bool SkillComponent::CastSkill(const uint32_t skillId, LWOOBJID target, const LW return false; } - return CalculateBehavior(skillId, behaviorId, target, false, false, optionalOriginatorID).success; + return CalculateBehavior(skillId, behaviorId, target, false, false, optionalOriginatorID, castType, rotationOverride).success; } -SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, const uint32_t behaviorId, const LWOOBJID target, const bool ignoreTarget, const bool clientInitalized, const LWOOBJID originatorOverride) { +SkillExecutionResult SkillComponent::CalculateBehavior( + const uint32_t skillId, + const uint32_t behaviorId, + const LWOOBJID target, + const bool ignoreTarget, + const bool clientInitalized, + const LWOOBJID originatorOverride, + const int32_t castType, + const NiQuaternion rotationOverride) { RakNet::BitStream bitStream{}; auto* behavior = Behavior::CreateBehavior(behaviorId); @@ -268,9 +283,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c behavior->Calculate(context, bitStream, { target, 0 }); - for (auto* script : CppScripts::GetEntityScripts(m_Parent)) { - script->OnSkillCast(m_Parent, skillId); - } + m_Parent->GetScript()->OnSkillCast(m_Parent, skillId); if (!context->foundTarget) { delete context; @@ -279,13 +292,13 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c return { false, 0 }; } - this->m_managedBehaviors.insert_or_assign(context->skillUId, context); + this->m_managedBehaviors.insert({ context->skillUId, context }); if (!clientInitalized) { // Echo start skill EchoStartSkill start; - start.iCastType = 0; + start.iCastType = castType; start.skillID = skillId; start.uiSkillHandle = context->skillUId; start.optionalOriginatorID = context->originator; @@ -296,6 +309,10 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c if (originator != nullptr) { start.originatorRot = originator->GetRotation(); } + + if (rotationOverride != NiQuaternionConstant::IDENTITY) { + start.originatorRot = rotationOverride; + } //start.optionalTargetID = target; start.sBitStream.assign(reinterpret_cast(bitStream.GetData()), bitStream.GetNumberOfBytesUsed()); @@ -303,7 +320,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c // Write message RakNet::BitStream message; - BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); + BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, MessageType::Client::GAME_MSG); message.Write(this->m_Parent->GetObjectID()); start.Serialize(message); @@ -415,7 +432,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) return; } - const auto behaviorId = static_cast(result.getIntField(0)); + const auto behaviorId = static_cast(result.getIntField("behaviorID")); result.finalize(); @@ -434,7 +451,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) RakNet::BitStream message; - BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); + BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, MessageType::Client::GAME_MSG); message.Write(this->m_Parent->GetObjectID()); projectileImpact.Serialize(message); @@ -466,7 +483,7 @@ void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID targ behavior->UnCast(&context, { target }); } -SkillComponent::SkillComponent(Entity* parent): Component(parent) { +SkillComponent::SkillComponent(Entity* parent) : Component(parent) { this->m_skillUid = 0; } diff --git a/dGame/dComponents/SkillComponent.h b/dGame/dComponents/SkillComponent.h index 2acae5d73..f74b4411a 100644 --- a/dGame/dComponents/SkillComponent.h +++ b/dGame/dComponents/SkillComponent.h @@ -127,7 +127,7 @@ class SkillComponent final : public Component { * @param optionalOriginatorID change the originator of the skill * @return if the case succeeded */ - bool CastSkill(const uint32_t skillId, LWOOBJID target = LWOOBJID_EMPTY, const LWOOBJID optionalOriginatorID = LWOOBJID_EMPTY); + bool CastSkill(const uint32_t skillId, LWOOBJID target = LWOOBJID_EMPTY, const LWOOBJID optionalOriginatorID = LWOOBJID_EMPTY, const int32_t castType = 0, const NiQuaternion rotationOverride = NiQuaternionConstant::IDENTITY); /** * Initializes a server-side skill calculation. @@ -139,7 +139,7 @@ class SkillComponent final : public Component { * @param originatorOverride an override for the originator of the skill calculation * @return the result of the skill calculation */ - SkillExecutionResult CalculateBehavior(uint32_t skillId, uint32_t behaviorId, LWOOBJID target, bool ignoreTarget = false, bool clientInitalized = false, LWOOBJID originatorOverride = LWOOBJID_EMPTY); + SkillExecutionResult CalculateBehavior(uint32_t skillId, uint32_t behaviorId, LWOOBJID target, bool ignoreTarget = false, bool clientInitalized = false, LWOOBJID originatorOverride = LWOOBJID_EMPTY, const int32_t castType = 0, const NiQuaternion rotationOverride = NiQuaternionConstant::IDENTITY); /** * Register a server-side projectile. @@ -188,7 +188,7 @@ class SkillComponent final : public Component { /** * All of the active skills mapped by their unique ID. */ - std::map m_managedBehaviors; + std::multimap m_managedBehaviors; /** * All active projectiles. diff --git a/dGame/dComponents/TriggerComponent.cpp b/dGame/dComponents/TriggerComponent.cpp index 5d4415f87..a9d00b155 100644 --- a/dGame/dComponents/TriggerComponent.cpp +++ b/dGame/dComponents/TriggerComponent.cpp @@ -13,9 +13,11 @@ #include "SkillComponent.h" #include "eEndBehavior.h" #include "PlayerManager.h" +#include "Game.h" +#include "EntityManager.h" +#include "MovementAIComponent.h" - -TriggerComponent::TriggerComponent(Entity* parent, const std::string triggerInfo): Component(parent) { +TriggerComponent::TriggerComponent(Entity* parent, const std::string triggerInfo) : Component(parent) { m_Parent = parent; m_Trigger = nullptr; @@ -42,7 +44,7 @@ void TriggerComponent::TriggerEvent(eTriggerEventType event, Entity* optionalTar } void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget) { - auto argArray = GeneralUtils::SplitString(command->args, ','); + auto argArray = GeneralUtils::SplitString(command->args, ','); // determine targets std::vector targetEntities = GatherTargets(command, optionalTarget); @@ -54,107 +56,119 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity if (!targetEntity) continue; switch (command->id) { - case eTriggerCommandType::ZONE_PLAYER: break; - case eTriggerCommandType::FIRE_EVENT: - HandleFireEvent(targetEntity, command->args); - break; - case eTriggerCommandType::DESTROY_OBJ: - HandleDestroyObject(targetEntity, command->args); - break; - case eTriggerCommandType::TOGGLE_TRIGGER: - HandleToggleTrigger(targetEntity, command->args); - break; - case eTriggerCommandType::RESET_REBUILD: - HandleResetRebuild(targetEntity, command->args); - break; - case eTriggerCommandType::SET_PATH: break; - case eTriggerCommandType::SET_PICK_TYPE: break; - case eTriggerCommandType::MOVE_OBJECT: - HandleMoveObject(targetEntity, argArray); - break; - case eTriggerCommandType::ROTATE_OBJECT: - HandleRotateObject(targetEntity, argArray); - break; - case eTriggerCommandType::PUSH_OBJECT: - HandlePushObject(targetEntity, argArray); - break; - case eTriggerCommandType::REPEL_OBJECT: - HandleRepelObject(targetEntity, command->args); - break; - case eTriggerCommandType::SET_TIMER: - HandleSetTimer(targetEntity, argArray); - break; - case eTriggerCommandType::CANCEL_TIMER: - HandleCancelTimer(targetEntity, command->args); - break; - case eTriggerCommandType::PLAY_CINEMATIC: - HandlePlayCinematic(targetEntity, argArray); - break; - case eTriggerCommandType::TOGGLE_BBB: - HandleToggleBBB(targetEntity, command->args); - break; - case eTriggerCommandType::UPDATE_MISSION: - HandleUpdateMission(targetEntity, argArray); - break; - case eTriggerCommandType::SET_BOUNCER_STATE: break; - case eTriggerCommandType::BOUNCE_ALL_ON_BOUNCER: break; - case eTriggerCommandType::TURN_AROUND_ON_PATH: break; - case eTriggerCommandType::GO_FORWARD_ON_PATH: break; - case eTriggerCommandType::GO_BACKWARD_ON_PATH: break; - case eTriggerCommandType::STOP_PATHING: break; - case eTriggerCommandType::START_PATHING: break; - case eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS: break; - case eTriggerCommandType::PLAY_EFFECT: - HandlePlayEffect(targetEntity, argArray); - break; - case eTriggerCommandType::STOP_EFFECT: - GameMessages::SendStopFXEffect(targetEntity, true, command->args); - break; - case eTriggerCommandType::CAST_SKILL: - HandleCastSkill(targetEntity, command->args); - break; - case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: - GameMessages::SendDisplayZoneSummary(targetEntity->GetObjectID(), targetEntity->GetSystemAddress(), false, command->args == "1", m_Parent->GetObjectID()); - break; - case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT: - HandleSetPhysicsVolumeEffect(targetEntity, argArray); - break; - case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS: - HandleSetPhysicsVolumeStatus(targetEntity, command->args); - break; - case eTriggerCommandType::SET_MODEL_TO_BUILD: break; - case eTriggerCommandType::SPAWN_MODEL_BRICKS: break; - case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK: - HandleActivateSpawnerNetwork(command->args); - break; - case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK: - HandleDeactivateSpawnerNetwork(command->args); - break; - case eTriggerCommandType::RESET_SPAWNER_NETWORK: - HandleResetSpawnerNetwork(command->args); - break; - case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS: - HandleDestroySpawnerNetworkObjects(command->args); - break; - case eTriggerCommandType::GO_TO_WAYPOINT: break; - case eTriggerCommandType::ACTIVATE_PHYSICS: - HandleActivatePhysics(targetEntity, command->args); - break; + case eTriggerCommandType::ZONE_PLAYER: break; + case eTriggerCommandType::FIRE_EVENT: + HandleFireEvent(targetEntity, command->args); + break; + case eTriggerCommandType::DESTROY_OBJ: + HandleDestroyObject(targetEntity, command->args); + break; + case eTriggerCommandType::TOGGLE_TRIGGER: + HandleToggleTrigger(targetEntity, command->args); + break; + case eTriggerCommandType::RESET_REBUILD: + HandleResetRebuild(targetEntity, command->args); + break; + case eTriggerCommandType::SET_PATH: + HandleSetPath(targetEntity, argArray); + break; + case eTriggerCommandType::SET_PICK_TYPE: break; + case eTriggerCommandType::MOVE_OBJECT: + HandleMoveObject(targetEntity, argArray); + break; + case eTriggerCommandType::ROTATE_OBJECT: + HandleRotateObject(targetEntity, argArray); + break; + case eTriggerCommandType::PUSH_OBJECT: + HandlePushObject(targetEntity, argArray); + break; + case eTriggerCommandType::REPEL_OBJECT: + HandleRepelObject(targetEntity, command->args); + break; + case eTriggerCommandType::SET_TIMER: + HandleSetTimer(targetEntity, argArray); + break; + case eTriggerCommandType::CANCEL_TIMER: + HandleCancelTimer(targetEntity, command->args); + break; + case eTriggerCommandType::PLAY_CINEMATIC: + HandlePlayCinematic(targetEntity, argArray); + break; + case eTriggerCommandType::TOGGLE_BBB: + HandleToggleBBB(targetEntity, command->args); + break; + case eTriggerCommandType::UPDATE_MISSION: + HandleUpdateMission(targetEntity, argArray); + break; + case eTriggerCommandType::SET_BOUNCER_STATE: break; + case eTriggerCommandType::BOUNCE_ALL_ON_BOUNCER: break; + case eTriggerCommandType::TURN_AROUND_ON_PATH: + HandleTurnAroundOnPath(targetEntity); + break; + case eTriggerCommandType::GO_FORWARD_ON_PATH: + HandleGoForwardOnPath(targetEntity); + break; + case eTriggerCommandType::GO_BACKWARD_ON_PATH: + HandleGoBackwardOnPath(targetEntity); + break; + case eTriggerCommandType::STOP_PATHING: + HandleStopPathing(targetEntity); + break; + case eTriggerCommandType::START_PATHING: + HandleStartPathing(targetEntity); + break; + case eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS: break; + case eTriggerCommandType::PLAY_EFFECT: + HandlePlayEffect(targetEntity, argArray); + break; + case eTriggerCommandType::STOP_EFFECT: + GameMessages::SendStopFXEffect(targetEntity, true, command->args); + break; + case eTriggerCommandType::CAST_SKILL: + HandleCastSkill(targetEntity, command->args); + break; + case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: + GameMessages::SendDisplayZoneSummary(targetEntity->GetObjectID(), targetEntity->GetSystemAddress(), false, command->args == "1", m_Parent->GetObjectID()); + break; + case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT: + HandleSetPhysicsVolumeEffect(targetEntity, argArray); + break; + case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS: + HandleSetPhysicsVolumeStatus(targetEntity, command->args); + break; + case eTriggerCommandType::SET_MODEL_TO_BUILD: break; + case eTriggerCommandType::SPAWN_MODEL_BRICKS: break; + case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK: + HandleActivateSpawnerNetwork(command->args); + break; + case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK: + HandleDeactivateSpawnerNetwork(command->args); + break; + case eTriggerCommandType::RESET_SPAWNER_NETWORK: + HandleResetSpawnerNetwork(command->args); + break; + case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS: + HandleDestroySpawnerNetworkObjects(command->args); + break; + case eTriggerCommandType::GO_TO_WAYPOINT: break; + case eTriggerCommandType::ACTIVATE_PHYSICS: + HandleActivatePhysics(targetEntity, command->args); + break; // DEPRECATED BLOCK START - case eTriggerCommandType::ACTIVATE_MUSIC_CUE: break; - case eTriggerCommandType::DEACTIVATE_MUSIC_CUE: break; - case eTriggerCommandType::FLASH_MUSIC_CUE: break; - case eTriggerCommandType::SET_MUSIC_PARAMETER: break; - case eTriggerCommandType::PLAY_2D_AMBIENT_SOUND: break; - case eTriggerCommandType::STOP_2D_AMBIENT_SOUND: break; - case eTriggerCommandType::PLAY_3D_AMBIENT_SOUND: break; - case eTriggerCommandType::STOP_3D_AMBIENT_SOUND: break; - case eTriggerCommandType::ACTIVATE_MIXER_PROGRAM: break; - case eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM: break; + case eTriggerCommandType::ACTIVATE_MUSIC_CUE: break; + case eTriggerCommandType::DEACTIVATE_MUSIC_CUE: break; + case eTriggerCommandType::FLASH_MUSIC_CUE: break; + case eTriggerCommandType::SET_MUSIC_PARAMETER: break; + case eTriggerCommandType::PLAY_2D_AMBIENT_SOUND: break; + case eTriggerCommandType::STOP_2D_AMBIENT_SOUND: break; + case eTriggerCommandType::PLAY_3D_AMBIENT_SOUND: break; + case eTriggerCommandType::STOP_3D_AMBIENT_SOUND: break; + case eTriggerCommandType::ACTIVATE_MIXER_PROGRAM: break; + case eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM: break; // DEPRECATED BLOCK END - default: - LOG_DEBUG("Event %i was not handled!", command->id); - break; + default: + LOG_DEBUG("Event %i was not handled!", command->id); + break; } } } @@ -163,36 +177,39 @@ std::vector TriggerComponent::GatherTargets(LUTriggers::Command* comman std::vector entities = {}; if (command->target == "self") entities.push_back(m_Parent); - else if (command->target == "zone") { /*TODO*/ } - else if (command->target == "target" && optionalTarget) entities.push_back(optionalTarget); - else if (command->target == "targetTeam" && optionalTarget) { + else if (command->target == "zone") { + /*TODO*/ + } else if (command->target == "target" && optionalTarget) { + entities.push_back(optionalTarget); + } else if (command->target == "targetTeam" && optionalTarget) { auto* team = TeamManager::Instance()->GetTeam(optionalTarget->GetObjectID()); for (const auto memberId : team->members) { auto* member = Game::entityManager->GetEntity(memberId); if (member) entities.push_back(member); } - } else if (command->target == "objGroup") entities = Game::entityManager->GetEntitiesInGroup(command->targetName); - else if (command->target == "allPlayers") { + } else if (command->target == "objGroup") { + entities = Game::entityManager->GetEntitiesInGroup(command->targetName); + } else if (command->target == "allPlayers") { for (auto* player : PlayerManager::GetAllPlayers()) { entities.push_back(player); } - } else if (command->target == "allNPCs") { /*UNUSED*/ } + } else if (command->target == "allNPCs") { + /*UNUSED*/ + } return entities; } void TriggerComponent::HandleFireEvent(Entity* targetEntity, std::string args) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(targetEntity)) { - script->OnFireEventServerSide(targetEntity, m_Parent, args, 0, 0, 0); - } + targetEntity->GetScript()->OnFireEventServerSide(targetEntity, m_Parent, args, 0, 0, 0); } -void TriggerComponent::HandleDestroyObject(Entity* targetEntity, std::string args){ +void TriggerComponent::HandleDestroyObject(Entity* targetEntity, std::string args) { const eKillType killType = GeneralUtils::TryParse(args).value_or(eKillType::VIOLENT); targetEntity->Smash(m_Parent->GetObjectID(), killType); } -void TriggerComponent::HandleToggleTrigger(Entity* targetEntity, std::string args){ +void TriggerComponent::HandleToggleTrigger(Entity* targetEntity, std::string args) { auto* triggerComponent = targetEntity->GetComponent(); if (!triggerComponent) { LOG_DEBUG("Trigger component not found!"); @@ -201,7 +218,7 @@ void TriggerComponent::HandleToggleTrigger(Entity* targetEntity, std::string arg triggerComponent->SetTriggerEnabled(args == "1"); } -void TriggerComponent::HandleResetRebuild(Entity* targetEntity, std::string args){ +void TriggerComponent::HandleResetRebuild(Entity* targetEntity, std::string args) { auto* quickBuildComponent = targetEntity->GetComponent(); if (!quickBuildComponent) { LOG_DEBUG("Rebuild component not found!"); @@ -210,7 +227,7 @@ void TriggerComponent::HandleResetRebuild(Entity* targetEntity, std::string args quickBuildComponent->ResetQuickBuild(args == "1"); } -void TriggerComponent::HandleMoveObject(Entity* targetEntity, std::vector argArray){ +void TriggerComponent::HandleMoveObject(Entity* targetEntity, std::vector argArray) { if (argArray.size() <= 2) return; NiPoint3 position = targetEntity->GetPosition(); @@ -220,7 +237,7 @@ void TriggerComponent::HandleMoveObject(Entity* targetEntity, std::vectorSetPosition(position); } -void TriggerComponent::HandleRotateObject(Entity* targetEntity, std::vector argArray){ +void TriggerComponent::HandleRotateObject(Entity* targetEntity, std::vector argArray) { if (argArray.size() <= 2) return; const NiPoint3 vector = GeneralUtils::TryParse(argArray).value_or(NiPoint3Constant::ZERO); @@ -229,7 +246,7 @@ void TriggerComponent::HandleRotateObject(Entity* targetEntity, std::vectorSetRotation(rotation); } -void TriggerComponent::HandlePushObject(Entity* targetEntity, std::vector argArray){ +void TriggerComponent::HandlePushObject(Entity* targetEntity, std::vector argArray) { if (argArray.size() < 3) return; auto* phantomPhysicsComponent = m_Parent->GetComponent(); @@ -247,7 +264,7 @@ void TriggerComponent::HandlePushObject(Entity* targetEntity, std::vectorGetComponent(); if (!phantomPhysicsComponent) { LOG_DEBUG("Phantom Physics component not found!"); @@ -271,7 +288,7 @@ void TriggerComponent::HandleRepelObject(Entity* targetEntity, std::string args) Game::entityManager->SerializeEntity(m_Parent); } -void TriggerComponent::HandleSetTimer(Entity* targetEntity, std::vector argArray){ +void TriggerComponent::HandleSetTimer(Entity* targetEntity, std::vector argArray) { if (argArray.size() != 2) { LOG_DEBUG("Not enough variables!"); return; @@ -280,7 +297,7 @@ void TriggerComponent::HandleSetTimer(Entity* targetEntity, std::vectorAddTimer(argArray.at(0), time); } -void TriggerComponent::HandleCancelTimer(Entity* targetEntity, std::string args){ +void TriggerComponent::HandleCancelTimer(Entity* targetEntity, std::string args) { m_Parent->CancelTimer(args); } @@ -328,7 +345,7 @@ void TriggerComponent::HandleUpdateMission(Entity* targetEntity, std::vectorGetComponent(); - if (!missionComponent){ + if (!missionComponent) { LOG_DEBUG("Mission component not found!"); return; } @@ -340,7 +357,7 @@ void TriggerComponent::HandlePlayEffect(Entity* targetEntity, std::vector(argArray.at(1)); if (!effectID) return; std::u16string effectType = GeneralUtils::UTF8ToUTF16(argArray.at(2)); - + float priority = 1; if (argArray.size() == 4) { priority = GeneralUtils::TryParse(argArray.at(3)).value_or(priority); @@ -349,7 +366,7 @@ void TriggerComponent::HandlePlayEffect(Entity* targetEntity, std::vectorGetComponent(); if (!skillComponent) { LOG_DEBUG("Skill component not found!"); @@ -377,7 +394,7 @@ void TriggerComponent::HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::v phantomPhysicsComponent->SetEffectType(effectType); phantomPhysicsComponent->SetDirectionalMultiplier(std::stof(argArray.at(1))); if (argArray.size() > 4) { - const NiPoint3 direction = + const NiPoint3 direction = GeneralUtils::TryParse(argArray.at(2), argArray.at(3), argArray.at(4)).value_or(NiPoint3Constant::ZERO); phantomPhysicsComponent->SetDirection(direction); @@ -403,25 +420,25 @@ void TriggerComponent::HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::s Game::entityManager->SerializeEntity(targetEntity); } -void TriggerComponent::HandleActivateSpawnerNetwork(std::string args){ +void TriggerComponent::HandleActivateSpawnerNetwork(std::string args) { for (auto* spawner : Game::zoneManager->GetSpawnersByName(args)) { if (spawner) spawner->Activate(); } } -void TriggerComponent::HandleDeactivateSpawnerNetwork(std::string args){ +void TriggerComponent::HandleDeactivateSpawnerNetwork(std::string args) { for (auto* spawner : Game::zoneManager->GetSpawnersByName(args)) { if (spawner) spawner->Deactivate(); } } -void TriggerComponent::HandleResetSpawnerNetwork(std::string args){ +void TriggerComponent::HandleResetSpawnerNetwork(std::string args) { for (auto* spawner : Game::zoneManager->GetSpawnersByName(args)) { if (spawner) spawner->Reset(); } } -void TriggerComponent::HandleDestroySpawnerNetworkObjects(std::string args){ +void TriggerComponent::HandleDestroySpawnerNetworkObjects(std::string args) { for (auto* spawner : Game::zoneManager->GetSpawnersByName(args)) { if (spawner) spawner->DestroyAllEntities(); } @@ -430,9 +447,50 @@ void TriggerComponent::HandleDestroySpawnerNetworkObjects(std::string args){ void TriggerComponent::HandleActivatePhysics(Entity* targetEntity, std::string args) { if (args == "true") { // TODO add physics entity if there isn't one - } else if (args == "false"){ + } else if (args == "false") { // TODO remove Phsyics entity if there is one } else { LOG_DEBUG("Invalid argument for ActivatePhysics Trigger: %s", args.c_str()); } } + +void TriggerComponent::HandleSetPath(Entity* targetEntity, std::vector argArray) { + auto* movementAIComponent = targetEntity->GetComponent(); + if (!movementAIComponent) return; + // movementAIComponent->SetupPath(argArray.at(0)); + if (argArray.size() >= 2) { + auto index = GeneralUtils::TryParse(argArray.at(1)); + if (!index) return; + // movementAIComponent->SetPathStartingWaypointIndex(index.value()); + } + if (argArray.size() >= 3 && argArray.at(2) == "1") { + // movementAIComponent->ReversePath(); + } +} + +void TriggerComponent::HandleTurnAroundOnPath(Entity* targetEntity) { + auto* movementAIComponent = targetEntity->GetComponent(); + // if (movementAIComponent) movementAIComponent->ReversePath(); +} + +void TriggerComponent::HandleGoForwardOnPath(Entity* targetEntity) { + auto* movementAIComponent = targetEntity->GetComponent(); + if (!movementAIComponent) return; + // if (movementAIComponent->GetIsInReverse()) movementAIComponent->ReversePath(); +} + +void TriggerComponent::HandleGoBackwardOnPath(Entity* targetEntity) { + auto* movementAIComponent = targetEntity->GetComponent(); + if (!movementAIComponent) return; + // if (!movementAIComponent->GetIsInReverse()) movementAIComponent->ReversePath(); +} + +void TriggerComponent::HandleStopPathing(Entity* targetEntity) { + auto* movementAIComponent = targetEntity->GetComponent(); + // if (movementAIComponent) movementAIComponent->Pause(); +} + +void TriggerComponent::HandleStartPathing(Entity* targetEntity) { + auto* movementAIComponent = targetEntity->GetComponent(); + // if (movementAIComponent) movementAIComponent->Resume(); +} diff --git a/dGame/dComponents/TriggerComponent.h b/dGame/dComponents/TriggerComponent.h index 5610f24a3..94a7682e1 100644 --- a/dGame/dComponents/TriggerComponent.h +++ b/dGame/dComponents/TriggerComponent.h @@ -44,6 +44,12 @@ class TriggerComponent final : public Component { void HandleResetSpawnerNetwork(std::string args); void HandleDestroySpawnerNetworkObjects(std::string args); void HandleActivatePhysics(Entity* targetEntity, std::string args); + void HandleTurnAroundOnPath(Entity* targetEntity); + void HandleGoForwardOnPath(Entity* targetEntity); + void HandleGoBackwardOnPath(Entity* targetEntity); + void HandleStopPathing(Entity* targetEntity); + void HandleStartPathing(Entity* targetEntity); + void HandleSetPath(Entity* targetEntity, std::vector argArray); LUTriggers::Trigger* m_Trigger; }; diff --git a/dGame/dComponents/VendorComponent.cpp b/dGame/dComponents/VendorComponent.cpp index 8a26399c1..b9286d256 100644 --- a/dGame/dComponents/VendorComponent.cpp +++ b/dGame/dComponents/VendorComponent.cpp @@ -40,9 +40,19 @@ void VendorComponent::RefreshInventory(bool isCreation) { SetHasMultiCostItems(false); m_Inventory.clear(); - // Custom code for Max vanity NPC and Mr.Ree cameras - if(isCreation && m_Parent->GetLOT() == 9749 && Game::server->GetZoneID() == 1201) { - SetupMaxCustomVendor(); + // Custom code for Vanity Vendor Invetory Override + if(m_Parent->HasVar(u"vendorInvOverride")) { + std::vector items = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"vendorInvOverride"), ','); + uint32_t sortPriority = -1; + for (auto& itemString : items) { + itemString.erase(remove_if(itemString.begin(), itemString.end(), isspace), itemString.end()); + auto item = GeneralUtils::TryParse(itemString); + if (!item) continue; + if (SetupItem(item.value())) { + sortPriority++; + m_Inventory.push_back(SoldItem(item.value(), sortPriority)); + } + } return; } @@ -52,24 +62,12 @@ void VendorComponent::RefreshInventory(bool isCreation) { if (lootMatrices.empty()) return; auto* lootTableTable = CDClientManager::GetTable(); - auto* itemComponentTable = CDClientManager::GetTable(); - auto* compRegistryTable = CDClientManager::GetTable(); for (const auto& lootMatrix : lootMatrices) { auto vendorItems = lootTableTable->GetTable(lootMatrix.LootTableIndex); if (lootMatrix.maxToDrop == 0 || lootMatrix.minToDrop == 0) { for (const auto& item : vendorItems) { - if (!m_HasStandardCostItems || !m_HasMultiCostItems) { - auto itemComponentID = compRegistryTable->GetByIDAndType(item.itemid, eReplicaComponentType::ITEM, -1); - if (itemComponentID == -1) { - LOG("Attempted to add item %i with ItemComponent ID -1 to vendor %i inventory. Not adding item!", itemComponentID, m_Parent->GetLOT()); - continue; - } - auto itemComponent = itemComponentTable->GetItemComponentByID(itemComponentID); - if (!m_HasStandardCostItems && itemComponent.baseValue != -1) SetHasStandardCostItems(true); - if (!m_HasMultiCostItems && !itemComponent.currencyCosts.empty()) SetHasMultiCostItems(true); - } - m_Inventory.push_back(SoldItem(item.itemid, item.sortPriority)); + if (SetupItem(item.itemid)) m_Inventory.push_back(SoldItem(item.itemid, item.sortPriority)); } } else { auto randomCount = GeneralUtils::GenerateRandomNumber(lootMatrix.minToDrop, lootMatrix.maxToDrop); @@ -78,18 +76,8 @@ void VendorComponent::RefreshInventory(bool isCreation) { if (vendorItems.empty()) break; auto randomItemIndex = GeneralUtils::GenerateRandomNumber(0, vendorItems.size() - 1); const auto& randomItem = vendorItems.at(randomItemIndex); + if (SetupItem(randomItem.itemid)) m_Inventory.push_back(SoldItem(randomItem.itemid, randomItem.sortPriority)); vendorItems.erase(vendorItems.begin() + randomItemIndex); - if (!m_HasStandardCostItems || !m_HasMultiCostItems) { - auto itemComponentID = compRegistryTable->GetByIDAndType(randomItem.itemid, eReplicaComponentType::ITEM, -1); - if (itemComponentID == -1) { - LOG("Attempted to add item %i with ItemComponent ID -1 to vendor %i inventory. Not adding item!", itemComponentID, m_Parent->GetLOT()); - continue; - } - auto itemComponent = itemComponentTable->GetItemComponentByID(itemComponentID); - if (!m_HasStandardCostItems && itemComponent.baseValue != -1) SetHasStandardCostItems(true); - if (!m_HasMultiCostItems && !itemComponent.currencyCosts.empty()) SetHasMultiCostItems(true); - } - m_Inventory.push_back(SoldItem(randomItem.itemid, randomItem.sortPriority)); } } } @@ -126,15 +114,6 @@ bool VendorComponent::SellsItem(const LOT item) const { }) > 0; } - -void VendorComponent::SetupMaxCustomVendor(){ - SetHasStandardCostItems(true); - m_Inventory.push_back(SoldItem(11909, 0)); // Top hat w frog - m_Inventory.push_back(SoldItem(7785, 0)); // Flash bulb - m_Inventory.push_back(SoldItem(12764, 0)); // Big fountain soda - m_Inventory.push_back(SoldItem(12241, 0)); // Hot cocoa (from fb) -} - void VendorComponent::HandleMrReeCameras(){ if (m_Parent->GetLOT() == 13569) { SetHasStandardCostItems(true); @@ -211,5 +190,25 @@ void VendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) { character->SetCoins(character->GetCoins() - (coinCost), eLootSourceType::VENDOR); inventoryComponent->AddItem(lot, count, eLootSourceType::VENDOR); GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_SUCCESS); +} + +bool VendorComponent::SetupItem(LOT item) { + + auto* itemComponentTable = CDClientManager::GetTable(); + auto* compRegistryTable = CDClientManager::GetTable(); + + auto itemComponentID = compRegistryTable->GetByIDAndType(item, eReplicaComponentType::ITEM, -1); + if (itemComponentID == -1) { + LOG("Attempted to add item %i with ItemComponent ID -1 to vendor %i inventory. Not adding item!", itemComponentID, m_Parent->GetLOT()); + return false; + } + + if (!m_HasStandardCostItems || !m_HasMultiCostItems) { + auto itemComponent = itemComponentTable->GetItemComponentByID(itemComponentID); + if (!m_HasStandardCostItems && itemComponent.baseValue != -1) SetHasStandardCostItems(true); + if (!m_HasMultiCostItems && !itemComponent.currencyCosts.empty()) SetHasMultiCostItems(true); + } + + return true; +} -} \ No newline at end of file diff --git a/dGame/dComponents/VendorComponent.h b/dGame/dComponents/VendorComponent.h index 2abd35366..432f18014 100644 --- a/dGame/dComponents/VendorComponent.h +++ b/dGame/dComponents/VendorComponent.h @@ -26,7 +26,7 @@ class VendorComponent : public Component { void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void OnUse(Entity* originator) override; - void RefreshInventory(bool isCreation = false); + virtual void RefreshInventory(bool isCreation = false); void SetupConstants(); bool SellsItem(const LOT item) const; float GetBuyScalar() const { return m_BuyScalar; } @@ -50,8 +50,8 @@ class VendorComponent : public Component { void Buy(Entity* buyer, LOT lot, uint32_t count); private: - void SetupMaxCustomVendor(); void HandleMrReeCameras(); + bool SetupItem(LOT item); float m_BuyScalar = 0.0f; float m_SellScalar = 0.0f; float m_RefreshTimeSeconds = 0.0f; diff --git a/dGame/dEntity/CMakeLists.txt b/dGame/dEntity/CMakeLists.txt index d7d96e147..2a418fb9e 100644 --- a/dGame/dEntity/CMakeLists.txt +++ b/dGame/dEntity/CMakeLists.txt @@ -2,6 +2,6 @@ set(DGAME_DENTITY_SOURCES "EntityCallbackTimer.cpp" "EntityTimer.cpp") -add_library(dEntity STATIC ${DGAME_DENTITY_SOURCES}) +add_library(dEntity OBJECT ${DGAME_DENTITY_SOURCES}) target_include_directories(dEntity PUBLIC ".") target_precompile_headers(dEntity REUSE_FROM dGameBase) diff --git a/dGame/dGameMessages/CMakeLists.txt b/dGame/dGameMessages/CMakeLists.txt index 7373633cc..0f28dea4f 100644 --- a/dGame/dGameMessages/CMakeLists.txt +++ b/dGame/dGameMessages/CMakeLists.txt @@ -4,6 +4,20 @@ set(DGAME_DGAMEMESSAGES_SOURCES "PropertyDataMessage.cpp" "PropertySelectQueryProperty.cpp") -add_library(dGameMessages STATIC ${DGAME_DGAMEMESSAGES_SOURCES}) -target_link_libraries(dGameMessages PUBLIC dDatabase) +add_library(dGameMessages OBJECT ${DGAME_DGAMEMESSAGES_SOURCES}) +target_link_libraries(dGameMessages + PUBLIC dDatabase + INTERFACE dGameBase # TradingManager +) +target_include_directories(dGameMessages PUBLIC "." + PRIVATE + "${PROJECT_SOURCE_DIR}/dGame/dComponents" # direct MissionComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" # direct SlashCommandHandler.h + "${PROJECT_SOURCE_DIR}/dGame/dPropertyBehaviors" # direct ControlBehaviors.h + "${PROJECT_SOURCE_DIR}/dGame/dMission" # via MissionComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dBehaviors" # via InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dInventory" # via InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # via dZoneManager/Spawner.h + "${PROJECT_SOURCE_DIR}/dZoneManager" # via GameMessages.cpp, GameMessageHandler.cpp +) target_precompile_headers(dGameMessages REUSE_FROM dGameBase) diff --git a/dGame/dGameMessages/DoClientProjectileImpact.h b/dGame/dGameMessages/DoClientProjectileImpact.h index b8e3b5286..c0354e476 100644 --- a/dGame/dGameMessages/DoClientProjectileImpact.h +++ b/dGame/dGameMessages/DoClientProjectileImpact.h @@ -27,7 +27,7 @@ class DoClientProjectileImpact { } void Serialize(RakNet::BitStream& stream) { - stream.Write(eGameMessageType::DO_CLIENT_PROJECTILE_IMPACT); + stream.Write(MessageType::Game::DO_CLIENT_PROJECTILE_IMPACT); stream.Write(i64OrgID != LWOOBJID_EMPTY); if (i64OrgID != LWOOBJID_EMPTY) stream.Write(i64OrgID); diff --git a/dGame/dGameMessages/EchoStartSkill.h b/dGame/dGameMessages/EchoStartSkill.h index dfb79021c..c2c6b1d4d 100644 --- a/dGame/dGameMessages/EchoStartSkill.h +++ b/dGame/dGameMessages/EchoStartSkill.h @@ -4,7 +4,7 @@ #include "dCommonVars.h" #include "NiPoint3.h" #include "NiQuaternion.h" -#include "eGameMessageType.h" +#include "MessageType/Game.h" /* Same as start skill but with different network options. An echo down to other clients that need to play the skill. */ class EchoStartSkill { @@ -40,7 +40,7 @@ class EchoStartSkill { } void Serialize(RakNet::BitStream& stream) { - stream.Write(eGameMessageType::ECHO_START_SKILL); + stream.Write(MessageType::Game::ECHO_START_SKILL); stream.Write(bUsedMouse); diff --git a/dGame/dGameMessages/EchoSyncSkill.h b/dGame/dGameMessages/EchoSyncSkill.h index f65daab7b..5ea866f17 100644 --- a/dGame/dGameMessages/EchoSyncSkill.h +++ b/dGame/dGameMessages/EchoSyncSkill.h @@ -4,7 +4,7 @@ #include #include "BitStream.h" -#include "eGameMessageType.h" +#include "MessageType/Game.h" /* Message to synchronize a skill cast */ @@ -29,7 +29,7 @@ class EchoSyncSkill { } void Serialize(RakNet::BitStream& stream) { - stream.Write(eGameMessageType::ECHO_SYNC_SKILL); + stream.Write(MessageType::Game::ECHO_SYNC_SKILL); stream.Write(bDone); uint32_t sBitStreamLength = sBitStream.length(); diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index 3aab4b3dd..f32d749fe 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -33,13 +33,13 @@ #include "eMissionTaskType.h" #include "eReplicaComponentType.h" #include "eConnectionType.h" -#include "eGameMessageType.h" +#include "MessageType/Game.h" #include "ePlayerFlag.h" #include "dConfig.h" #include "GhostComponent.h" #include "StringifiedEnum.h" -void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID) { +void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const SystemAddress& sysAddr, LWOOBJID objectID, MessageType::Game messageID) { CBITSTREAM; @@ -53,58 +53,58 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System return; } - if (messageID != eGameMessageType::READY_FOR_UPDATES) LOG_DEBUG("Received GM with ID and name: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data()); + if (messageID != MessageType::Game::READY_FOR_UPDATES) LOG_DEBUG("Received GM with ID and name: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data()); switch (messageID) { - case eGameMessageType::UN_USE_BBB_MODEL: { + case MessageType::Game::UN_USE_BBB_MODEL: { GameMessages::HandleUnUseModel(inStream, entity, sysAddr); break; } - case eGameMessageType::PLAY_EMOTE: { + case MessageType::Game::PLAY_EMOTE: { GameMessages::HandlePlayEmote(inStream, entity); break; } - case eGameMessageType::MOVE_ITEM_IN_INVENTORY: { + case MessageType::Game::MOVE_ITEM_IN_INVENTORY: { GameMessages::HandleMoveItemInInventory(inStream, entity); break; } - case eGameMessageType::REMOVE_ITEM_FROM_INVENTORY: { + case MessageType::Game::REMOVE_ITEM_FROM_INVENTORY: { GameMessages::HandleRemoveItemFromInventory(inStream, entity, sysAddr); break; } - case eGameMessageType::EQUIP_INVENTORY: + case MessageType::Game::EQUIP_INVENTORY: GameMessages::HandleEquipItem(inStream, entity); break; - case eGameMessageType::UN_EQUIP_INVENTORY: + case MessageType::Game::UN_EQUIP_INVENTORY: GameMessages::HandleUnequipItem(inStream, entity); break; - case eGameMessageType::RESPOND_TO_MISSION: { + case MessageType::Game::RESPOND_TO_MISSION: { GameMessages::HandleRespondToMission(inStream, entity); break; } - case eGameMessageType::REQUEST_USE: { + case MessageType::Game::REQUEST_USE: { GameMessages::HandleRequestUse(inStream, entity, sysAddr); break; } - case eGameMessageType::SET_FLAG: { + case MessageType::Game::SET_FLAG: { GameMessages::HandleSetFlag(inStream, entity); break; } - case eGameMessageType::HAS_BEEN_COLLECTED: { + case MessageType::Game::HAS_BEEN_COLLECTED: { GameMessages::HandleHasBeenCollected(inStream, entity); break; } - case eGameMessageType::PLAYER_LOADED: { + case MessageType::Game::PLAYER_LOADED: { GameMessages::SendRestoreToPostLoadStats(entity, sysAddr); entity->SetPlayerReadyForUpdates(); @@ -136,16 +136,14 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System } Entity* zoneControl = Game::entityManager->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerLoaded(zoneControl, entity); + if (zoneControl) { + zoneControl->GetScript()->OnPlayerLoaded(zoneControl, entity); } std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerLoaded(scriptEntity, entity); - } + scriptEntity->GetScript()->OnPlayerLoaded(scriptEntity, entity); } } @@ -185,82 +183,82 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System break; } - case eGameMessageType::REQUEST_LINKED_MISSION: { + case MessageType::Game::REQUEST_LINKED_MISSION: { GameMessages::HandleRequestLinkedMission(inStream, entity); break; } - case eGameMessageType::MISSION_DIALOGUE_OK: { + case MessageType::Game::MISSION_DIALOGUE_OK: { GameMessages::HandleMissionDialogOK(inStream, entity); break; } - case eGameMessageType::MISSION_DIALOGUE_CANCELLED: { + case MessageType::Game::MISSION_DIALOGUE_CANCELLED: { // This message is pointless for our implementation, as the client just carries on after // rejecting a mission offer. We dont need to do anything. This is just here to remove a warning in our logs :) break; } - case eGameMessageType::REQUEST_PLATFORM_RESYNC: { + case MessageType::Game::REQUEST_PLATFORM_RESYNC: { GameMessages::HandleRequestPlatformResync(inStream, entity, sysAddr); break; } - case eGameMessageType::FIRE_EVENT_SERVER_SIDE: { + case MessageType::Game::FIRE_EVENT_SERVER_SIDE: { GameMessages::HandleFireEventServerSide(inStream, entity, sysAddr); break; } - case eGameMessageType::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { + case MessageType::Game::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { GameMessages::HandleActivitySummaryLeaderboardData(inStream, entity, sysAddr); break; } - case eGameMessageType::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { + case MessageType::Game::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA: { GameMessages::HandleRequestActivitySummaryLeaderboardData(inStream, entity, sysAddr); break; } - case eGameMessageType::ACTIVITY_STATE_CHANGE_REQUEST: { + case MessageType::Game::ACTIVITY_STATE_CHANGE_REQUEST: { GameMessages::HandleActivityStateChangeRequest(inStream, entity); break; } - case eGameMessageType::PARSE_CHAT_MESSAGE: { + case MessageType::Game::PARSE_CHAT_MESSAGE: { GameMessages::HandleParseChatMessage(inStream, entity, sysAddr); break; } - case eGameMessageType::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE: { + case MessageType::Game::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE: { GameMessages::HandleNotifyServerLevelProcessingComplete(inStream, entity); break; } - case eGameMessageType::PICKUP_CURRENCY: { + case MessageType::Game::PICKUP_CURRENCY: { GameMessages::HandlePickupCurrency(inStream, entity); break; } - case eGameMessageType::PICKUP_ITEM: { + case MessageType::Game::PICKUP_ITEM: { GameMessages::HandlePickupItem(inStream, entity); break; } - case eGameMessageType::RESURRECT: { + case MessageType::Game::RESURRECT: { GameMessages::HandleResurrect(inStream, entity); break; } - case eGameMessageType::REQUEST_RESURRECT: { + case MessageType::Game::REQUEST_RESURRECT: { GameMessages::SendResurrect(entity); break; } - case eGameMessageType::GET_HOT_PROPERTY_DATA: { + case MessageType::Game::GET_HOT_PROPERTY_DATA: { GameMessages::HandleGetHotPropertyData(inStream, entity, sysAddr); break; } - case eGameMessageType::REQUEST_SERVER_PROJECTILE_IMPACT: + case MessageType::Game::REQUEST_SERVER_PROJECTILE_IMPACT: { auto message = RequestServerProjectileImpact(); @@ -277,7 +275,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System break; } - case eGameMessageType::START_SKILL: { + case MessageType::Game::START_SKILL: { StartSkill startSkill = StartSkill(); startSkill.Deserialize(inStream); // inStream replaces &bitStream @@ -313,7 +311,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System if (success) { //Broadcast our startSkill: RakNet::BitStream bitStreamLocal; - BitStreamUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); + BitStreamUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, MessageType::Client::GAME_MSG); bitStreamLocal.Write(entity->GetObjectID()); EchoStartSkill echoStartSkill; @@ -333,9 +331,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System } } break; - case eGameMessageType::SYNC_SKILL: { + case MessageType::Game::SYNC_SKILL: { RakNet::BitStream bitStreamLocal; - BitStreamUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); + BitStreamUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, MessageType::Client::GAME_MSG); bitStreamLocal.Write(entity->GetObjectID()); SyncSkill sync = SyncSkill(inStream); // inStream replaced &bitStream @@ -367,326 +365,333 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System Game::server->Send(bitStreamLocal, sysAddr, true); } break; - case eGameMessageType::REQUEST_SMASH_PLAYER: + case MessageType::Game::REQUEST_SMASH_PLAYER: entity->Smash(entity->GetObjectID()); break; - case eGameMessageType::MOVE_ITEM_BETWEEN_INVENTORY_TYPES: + case MessageType::Game::MOVE_ITEM_BETWEEN_INVENTORY_TYPES: GameMessages::HandleMoveItemBetweenInventoryTypes(inStream, entity, sysAddr); break; - case eGameMessageType::MODULAR_BUILD_FINISH: + case MessageType::Game::MODULAR_BUILD_FINISH: GameMessages::HandleModularBuildFinish(inStream, entity, sysAddr); break; - case eGameMessageType::PUSH_EQUIPPED_ITEMS_STATE: + case MessageType::Game::PUSH_EQUIPPED_ITEMS_STATE: GameMessages::HandlePushEquippedItemsState(inStream, entity); break; - case eGameMessageType::POP_EQUIPPED_ITEMS_STATE: + case MessageType::Game::POP_EQUIPPED_ITEMS_STATE: GameMessages::HandlePopEquippedItemsState(inStream, entity); break; - case eGameMessageType::BUY_FROM_VENDOR: + case MessageType::Game::BUY_FROM_VENDOR: GameMessages::HandleBuyFromVendor(inStream, entity, sysAddr); break; - case eGameMessageType::SELL_TO_VENDOR: + case MessageType::Game::SELL_TO_VENDOR: GameMessages::HandleSellToVendor(inStream, entity, sysAddr); break; - case eGameMessageType::BUYBACK_FROM_VENDOR: + case MessageType::Game::BUYBACK_FROM_VENDOR: GameMessages::HandleBuybackFromVendor(inStream, entity, sysAddr); break; - case eGameMessageType::MODULAR_BUILD_MOVE_AND_EQUIP: + case MessageType::Game::MODULAR_BUILD_MOVE_AND_EQUIP: GameMessages::HandleModularBuildMoveAndEquip(inStream, entity, sysAddr); break; - case eGameMessageType::DONE_ARRANGING_WITH_ITEM: + case MessageType::Game::DONE_ARRANGING_WITH_ITEM: GameMessages::HandleDoneArrangingWithItem(inStream, entity, sysAddr); break; - case eGameMessageType::MODULAR_BUILD_CONVERT_MODEL: + case MessageType::Game::MODULAR_BUILD_CONVERT_MODEL: GameMessages::HandleModularBuildConvertModel(inStream, entity, sysAddr); break; - case eGameMessageType::BUILD_MODE_SET: + case MessageType::Game::BUILD_MODE_SET: GameMessages::HandleBuildModeSet(inStream, entity); break; - case eGameMessageType::REBUILD_CANCEL: + case MessageType::Game::REBUILD_CANCEL: GameMessages::HandleQuickBuildCancel(inStream, entity); break; - case eGameMessageType::MATCH_REQUEST: + case MessageType::Game::MATCH_REQUEST: GameMessages::HandleMatchRequest(inStream, entity); break; - case eGameMessageType::USE_NON_EQUIPMENT_ITEM: + case MessageType::Game::USE_NON_EQUIPMENT_ITEM: GameMessages::HandleUseNonEquipmentItem(inStream, entity); break; - case eGameMessageType::CLIENT_ITEM_CONSUMED: + case MessageType::Game::CLIENT_ITEM_CONSUMED: GameMessages::HandleClientItemConsumed(inStream, entity); break; - case eGameMessageType::SET_CONSUMABLE_ITEM: + case MessageType::Game::SET_CONSUMABLE_ITEM: GameMessages::HandleSetConsumableItem(inStream, entity, sysAddr); break; - case eGameMessageType::VERIFY_ACK: + case MessageType::Game::VERIFY_ACK: GameMessages::HandleVerifyAck(inStream, entity, sysAddr); break; // Trading - case eGameMessageType::CLIENT_TRADE_REQUEST: + case MessageType::Game::CLIENT_TRADE_REQUEST: GameMessages::HandleClientTradeRequest(inStream, entity, sysAddr); break; - case eGameMessageType::CLIENT_TRADE_CANCEL: + case MessageType::Game::CLIENT_TRADE_CANCEL: GameMessages::HandleClientTradeCancel(inStream, entity, sysAddr); break; - case eGameMessageType::CLIENT_TRADE_ACCEPT: + case MessageType::Game::CLIENT_TRADE_ACCEPT: GameMessages::HandleClientTradeAccept(inStream, entity, sysAddr); break; - case eGameMessageType::CLIENT_TRADE_UPDATE: + case MessageType::Game::CLIENT_TRADE_UPDATE: GameMessages::HandleClientTradeUpdate(inStream, entity, sysAddr); break; // Pets - case eGameMessageType::PET_TAMING_TRY_BUILD: + case MessageType::Game::PET_TAMING_TRY_BUILD: GameMessages::HandlePetTamingTryBuild(inStream, entity, sysAddr); break; - case eGameMessageType::NOTIFY_TAMING_BUILD_SUCCESS: + case MessageType::Game::NOTIFY_TAMING_BUILD_SUCCESS: GameMessages::HandleNotifyTamingBuildSuccess(inStream, entity, sysAddr); break; - case eGameMessageType::REQUEST_SET_PET_NAME: + case MessageType::Game::REQUEST_SET_PET_NAME: GameMessages::HandleRequestSetPetName(inStream, entity, sysAddr); break; - case eGameMessageType::START_SERVER_PET_MINIGAME_TIMER: + case MessageType::Game::START_SERVER_PET_MINIGAME_TIMER: GameMessages::HandleStartServerPetMinigameTimer(inStream, entity, sysAddr); break; - case eGameMessageType::CLIENT_EXIT_TAMING_MINIGAME: + case MessageType::Game::CLIENT_EXIT_TAMING_MINIGAME: GameMessages::HandleClientExitTamingMinigame(inStream, entity, sysAddr); break; - case eGameMessageType::COMMAND_PET: + case MessageType::Game::COMMAND_PET: GameMessages::HandleCommandPet(inStream, entity, sysAddr); break; - case eGameMessageType::DESPAWN_PET: + case MessageType::Game::DESPAWN_PET: GameMessages::HandleDespawnPet(inStream, entity, sysAddr); break; - case eGameMessageType::MESSAGE_BOX_RESPOND: + case MessageType::Game::MESSAGE_BOX_RESPOND: GameMessages::HandleMessageBoxResponse(inStream, entity, sysAddr); break; - case eGameMessageType::CHOICE_BOX_RESPOND: + case MessageType::Game::CHOICE_BOX_RESPOND: GameMessages::HandleChoiceBoxRespond(inStream, entity, sysAddr); break; // Property - case eGameMessageType::QUERY_PROPERTY_DATA: + case MessageType::Game::QUERY_PROPERTY_DATA: GameMessages::HandleQueryPropertyData(inStream, entity, sysAddr); break; - case eGameMessageType::START_BUILDING_WITH_ITEM: + case MessageType::Game::START_BUILDING_WITH_ITEM: GameMessages::HandleStartBuildingWithItem(inStream, entity, sysAddr); break; - case eGameMessageType::SET_BUILD_MODE: + case MessageType::Game::SET_BUILD_MODE: GameMessages::HandleSetBuildMode(inStream, entity, sysAddr); break; - case eGameMessageType::PROPERTY_EDITOR_BEGIN: + case MessageType::Game::PROPERTY_EDITOR_BEGIN: GameMessages::HandlePropertyEditorBegin(inStream, entity, sysAddr); break; - case eGameMessageType::PROPERTY_EDITOR_END: + case MessageType::Game::PROPERTY_EDITOR_END: GameMessages::HandlePropertyEditorEnd(inStream, entity, sysAddr); break; - case eGameMessageType::PROPERTY_CONTENTS_FROM_CLIENT: + case MessageType::Game::PROPERTY_CONTENTS_FROM_CLIENT: GameMessages::HandlePropertyContentsFromClient(inStream, entity, sysAddr); break; - case eGameMessageType::ZONE_PROPERTY_MODEL_EQUIPPED: + case MessageType::Game::ZONE_PROPERTY_MODEL_EQUIPPED: GameMessages::HandlePropertyModelEquipped(inStream, entity, sysAddr); break; - case eGameMessageType::PLACE_PROPERTY_MODEL: + case MessageType::Game::PLACE_PROPERTY_MODEL: GameMessages::HandlePlacePropertyModel(inStream, entity, sysAddr); break; - case eGameMessageType::UPDATE_MODEL_FROM_CLIENT: + case MessageType::Game::UPDATE_MODEL_FROM_CLIENT: GameMessages::HandleUpdatePropertyModel(inStream, entity, sysAddr); break; - case eGameMessageType::DELETE_MODEL_FROM_CLIENT: + case MessageType::Game::DELETE_MODEL_FROM_CLIENT: GameMessages::HandleDeletePropertyModel(inStream, entity, sysAddr); break; - case eGameMessageType::BBB_LOAD_ITEM_REQUEST: + case MessageType::Game::BBB_LOAD_ITEM_REQUEST: GameMessages::HandleBBBLoadItemRequest(inStream, entity, sysAddr); break; - case eGameMessageType::BBB_SAVE_REQUEST: + case MessageType::Game::BBB_SAVE_REQUEST: GameMessages::HandleBBBSaveRequest(inStream, entity, sysAddr); break; - case eGameMessageType::CONTROL_BEHAVIORS: + case MessageType::Game::CONTROL_BEHAVIORS: GameMessages::HandleControlBehaviors(inStream, entity, sysAddr); break; - case eGameMessageType::PROPERTY_ENTRANCE_SYNC: + case MessageType::Game::PROPERTY_ENTRANCE_SYNC: GameMessages::HandlePropertyEntranceSync(inStream, entity, sysAddr); break; - case eGameMessageType::ENTER_PROPERTY1: + case MessageType::Game::ENTER_PROPERTY1: GameMessages::HandleEnterProperty(inStream, entity, sysAddr); break; - case eGameMessageType::ZONE_PROPERTY_MODEL_ROTATED: + case MessageType::Game::ZONE_PROPERTY_MODEL_ROTATED: Game::entityManager->GetZoneControlEntity()->OnZonePropertyModelRotated(usr->GetLastUsedChar()->GetEntity()); break; - case eGameMessageType::UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK: + case MessageType::Game::UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK: GameMessages::HandleUpdatePropertyOrModelForFilterCheck(inStream, entity, sysAddr); break; - case eGameMessageType::SET_PROPERTY_ACCESS: + case MessageType::Game::SET_PROPERTY_ACCESS: GameMessages::HandleSetPropertyAccess(inStream, entity, sysAddr); break; // Racing - case eGameMessageType::MODULE_ASSEMBLY_QUERY_DATA: + case MessageType::Game::MODULE_ASSEMBLY_QUERY_DATA: GameMessages::HandleModuleAssemblyQueryData(inStream, entity, sysAddr); break; - case eGameMessageType::ACKNOWLEDGE_POSSESSION: + case MessageType::Game::ACKNOWLEDGE_POSSESSION: GameMessages::HandleAcknowledgePossession(inStream, entity, sysAddr); break; - case eGameMessageType::VEHICLE_SET_WHEEL_LOCK_STATE: + case MessageType::Game::VEHICLE_SET_WHEEL_LOCK_STATE: GameMessages::HandleVehicleSetWheelLockState(inStream, entity, sysAddr); break; - case eGameMessageType::MODULAR_ASSEMBLY_NIF_COMPLETED: + case MessageType::Game::MODULAR_ASSEMBLY_NIF_COMPLETED: GameMessages::HandleModularAssemblyNIFCompleted(inStream, entity, sysAddr); break; - case eGameMessageType::RACING_CLIENT_READY: + case MessageType::Game::RACING_CLIENT_READY: GameMessages::HandleRacingClientReady(inStream, entity, sysAddr); break; - case eGameMessageType::REQUEST_DIE: + case MessageType::Game::REQUEST_DIE: GameMessages::HandleRequestDie(inStream, entity, sysAddr); break; - case eGameMessageType::NOTIFY_SERVER_VEHICLE_ADD_PASSIVE_BOOST_ACTION: + case MessageType::Game::NOTIFY_SERVER_VEHICLE_ADD_PASSIVE_BOOST_ACTION: GameMessages::HandleVehicleNotifyServerAddPassiveBoostAction(inStream, entity, sysAddr); break; - case eGameMessageType::NOTIFY_SERVER_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION: + case MessageType::Game::NOTIFY_SERVER_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION: GameMessages::HandleVehicleNotifyServerRemovePassiveBoostAction(inStream, entity, sysAddr); break; - case eGameMessageType::RACING_PLAYER_INFO_RESET_FINISHED: + case MessageType::Game::RACING_PLAYER_INFO_RESET_FINISHED: GameMessages::HandleRacingPlayerInfoResetFinished(inStream, entity, sysAddr); break; - case eGameMessageType::VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER: + case MessageType::Game::VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER: GameMessages::HandleVehicleNotifyHitImaginationServer(inStream, entity, sysAddr); break; - case eGameMessageType::UPDATE_PROPERTY_PERFORMANCE_COST: + case MessageType::Game::UPDATE_PROPERTY_PERFORMANCE_COST: GameMessages::HandleUpdatePropertyPerformanceCost(inStream, entity, sysAddr); break; // SG - case eGameMessageType::UPDATE_SHOOTING_GALLERY_ROTATION: + case MessageType::Game::UPDATE_SHOOTING_GALLERY_ROTATION: GameMessages::HandleUpdateShootingGalleryRotation(inStream, entity, sysAddr); break; // NT - case eGameMessageType::REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES: + case MessageType::Game::REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES: GameMessages::HandleRequestMoveItemBetweenInventoryTypes(inStream, entity, sysAddr); break; - case eGameMessageType::TOGGLE_GHOST_REFERENCE_OVERRIDE: + case MessageType::Game::TOGGLE_GHOST_REFERENCE_OVERRIDE: GameMessages::HandleToggleGhostReferenceOverride(inStream, entity, sysAddr); break; - case eGameMessageType::SET_GHOST_REFERENCE_POSITION: + case MessageType::Game::SET_GHOST_REFERENCE_POSITION: GameMessages::HandleSetGhostReferencePosition(inStream, entity, sysAddr); break; - case eGameMessageType::READY_FOR_UPDATES: + case MessageType::Game::READY_FOR_UPDATES: //We don't really care about this message, as it's simply here to inform us that the client is done loading an object. //In the event we _do_ send an update to an object that hasn't finished loading, the client will handle it anyway. break; - case eGameMessageType::REPORT_BUG: + case MessageType::Game::REPORT_BUG: GameMessages::HandleReportBug(inStream, entity); break; - case eGameMessageType::CLIENT_RAIL_MOVEMENT_READY: + case MessageType::Game::CLIENT_RAIL_MOVEMENT_READY: GameMessages::HandleClientRailMovementReady(inStream, entity, sysAddr); break; - case eGameMessageType::CANCEL_RAIL_MOVEMENT: + case MessageType::Game::CANCEL_RAIL_MOVEMENT: GameMessages::HandleCancelRailMovement(inStream, entity, sysAddr); break; - case eGameMessageType::PLAYER_RAIL_ARRIVED_NOTIFICATION: + case MessageType::Game::PLAYER_RAIL_ARRIVED_NOTIFICATION: GameMessages::HandlePlayerRailArrivedNotification(inStream, entity, sysAddr); break; - case eGameMessageType::CINEMATIC_UPDATE: + case MessageType::Game::CINEMATIC_UPDATE: GameMessages::HandleCinematicUpdate(inStream, entity, sysAddr); break; - case eGameMessageType::MODIFY_PLAYER_ZONE_STATISTIC: + case MessageType::Game::MODIFY_PLAYER_ZONE_STATISTIC: GameMessages::HandleModifyPlayerZoneStatistic(inStream, entity); break; - case eGameMessageType::UPDATE_PLAYER_STATISTIC: + case MessageType::Game::UPDATE_PLAYER_STATISTIC: GameMessages::HandleUpdatePlayerStatistic(inStream, entity); break; - case eGameMessageType::DISMOUNT_COMPLETE: + case MessageType::Game::DISMOUNT_COMPLETE: GameMessages::HandleDismountComplete(inStream, entity, sysAddr); break; - case eGameMessageType::DECTIVATE_BUBBLE_BUFF: + case MessageType::Game::DECTIVATE_BUBBLE_BUFF: GameMessages::HandleDeactivateBubbleBuff(inStream, entity); break; - case eGameMessageType::ACTIVATE_BUBBLE_BUFF: + case MessageType::Game::ACTIVATE_BUBBLE_BUFF: GameMessages::HandleActivateBubbleBuff(inStream, entity); break; - case eGameMessageType::ZONE_SUMMARY_DISMISSED: + case MessageType::Game::ZONE_SUMMARY_DISMISSED: GameMessages::HandleZoneSummaryDismissed(inStream, entity); break; - case eGameMessageType::REQUEST_ACTIVITY_EXIT: + case MessageType::Game::REQUEST_ACTIVITY_EXIT: GameMessages::HandleRequestActivityExit(inStream, entity); break; - case eGameMessageType::ADD_DONATION_ITEM: + case MessageType::Game::ADD_DONATION_ITEM: GameMessages::HandleAddDonationItem(inStream, entity, sysAddr); break; - case eGameMessageType::REMOVE_DONATION_ITEM: + case MessageType::Game::REMOVE_DONATION_ITEM: GameMessages::HandleRemoveDonationItem(inStream, entity, sysAddr); break; - case eGameMessageType::CONFIRM_DONATION_ON_PLAYER: + case MessageType::Game::CONFIRM_DONATION_ON_PLAYER: GameMessages::HandleConfirmDonationOnPlayer(inStream, entity); break; - case eGameMessageType::CANCEL_DONATION_ON_PLAYER: + case MessageType::Game::CANCEL_DONATION_ON_PLAYER: GameMessages::HandleCancelDonationOnPlayer(inStream, entity); break; - case eGameMessageType::REQUEST_VENDOR_STATUS_UPDATE: + case MessageType::Game::REQUEST_VENDOR_STATUS_UPDATE: GameMessages::SendVendorStatusUpdate(entity, sysAddr, true); break; + case MessageType::Game::UPDATE_INVENTORY_GROUP: + GameMessages::HandleUpdateInventoryGroup(inStream, entity, sysAddr); + break; + case MessageType::Game::UPDATE_INVENTORY_GROUP_CONTENTS: + GameMessages::HandleUpdateInventoryGroupContents(inStream, entity, sysAddr); + break; + default: LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data()); break; diff --git a/dGame/dGameMessages/GameMessageHandler.h b/dGame/dGameMessages/GameMessageHandler.h index 2fefd008b..c8026bb13 100644 --- a/dGame/dGameMessages/GameMessageHandler.h +++ b/dGame/dGameMessages/GameMessageHandler.h @@ -19,10 +19,10 @@ #include "Logger.h" #include "GameMessages.h" #include "CDClientDatabase.h" -#include "eGameMessageType.h" +#include "MessageType/Game.h" namespace GameMessageHandler { - void HandleMessage(RakNet::BitStream& inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID); + void HandleMessage(RakNet::BitStream& inStream, const SystemAddress& sysAddr, LWOOBJID objectID, MessageType::Game messageID); }; #endif // GAMEMESSAGEHANDLER_H diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 0bb9d008c..fc77e6904 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -90,25 +90,27 @@ #include "ControlBehaviors.h" #include "AMFDeserialize.h" #include "eBlueprintSaveResponseType.h" -#include "eAninmationFlags.h" +#include "eAnimationFlags.h" #include "AmfSerialize.h" #include "eReplicaComponentType.h" -#include "eClientMessageType.h" -#include "eGameMessageType.h" +#include "MessageType/Client.h" +#include "MessageType/Game.h" #include "ePetAbilityType.h" #include "ActivityManager.h" #include "PlayerManager.h" #include "eVendorTransactionResult.h" +#include "eReponseMoveItemBetweenInventoryTypeCode.h" #include "CDComponentsRegistryTable.h" #include "CDObjectsTable.h" +#include "eItemType.h" void GameMessages::SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::FIRE_EVENT_CLIENT_SIDE); + bitStream.Write(MessageType::Game::FIRE_EVENT_CLIENT_SIDE); //bitStream.Write(args); uint32_t argSize = args.size(); @@ -130,7 +132,7 @@ void GameMessages::SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, c CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::TELEPORT); + bitStream.Write(MessageType::Game::TELEPORT); bool bIgnoreY = (pos.y == 0.0f); bool bUseNavmesh = false; @@ -175,7 +177,7 @@ void GameMessages::SendPlayAnimation(Entity* entity, const std::u16string& anima bool bTriggerOnCompleteMsg = false; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::PLAY_ANIMATION); + bitStream.Write(MessageType::Game::PLAY_ANIMATION); bitStream.Write(animationIDLength); bitStream.Write(LUWString(animationName, animationIDLength)); @@ -199,7 +201,7 @@ void GameMessages::SendPlayerReady(Entity* entity, const SystemAddress& sysAddr) CBITSTREAM; CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::PLAYER_READY); + bitStream.Write(MessageType::Game::PLAYER_READY); SEND_PACKET; } @@ -208,7 +210,7 @@ void GameMessages::SendPlayerAllowedRespawn(LWOOBJID entityID, bool doNotPromptR CMSGHEADER; bitStream.Write(entityID); - bitStream.Write(eGameMessageType::SET_PLAYER_ALLOWED_RESPAWN); + bitStream.Write(MessageType::Game::SET_PLAYER_ALLOWED_RESPAWN); bitStream.Write(doNotPromptRespawn); SEND_PACKET; @@ -219,7 +221,7 @@ void GameMessages::SendInvalidZoneTransferList(Entity* entity, const SystemAddre CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::INVALID_ZONE_TRANSFER_LIST); + bitStream.Write(MessageType::Game::INVALID_ZONE_TRANSFER_LIST); uint32_t CustomerFeedbackURLLength = feedbackURL.size(); bitStream.Write(CustomerFeedbackURLLength); @@ -244,7 +246,7 @@ void GameMessages::SendKnockback(const LWOOBJID& objectID, const LWOOBJID& caste CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::KNOCKBACK); + bitStream.Write(MessageType::Game::KNOCKBACK); bool casterFlag = caster != LWOOBJID_EMPTY; bool originatorFlag = originator != LWOOBJID_EMPTY; @@ -280,7 +282,7 @@ void GameMessages::SendStartArrangingWithItem( CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::START_ARRANGING_WITH_ITEM); + bitStream.Write(MessageType::Game::START_ARRANGING_WITH_ITEM); bitStream.Write(bFirstTime); bitStream.Write(buildAreaID != LWOOBJID_EMPTY); @@ -304,7 +306,7 @@ void GameMessages::SendPlayerSetCameraCyclingMode(const LWOOBJID& objectID, cons CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::PLAYER_SET_CAMERA_CYCLING_MODE); + bitStream.Write(MessageType::Game::PLAYER_SET_CAMERA_CYCLING_MODE); bitStream.Write(bAllowCyclingWhileDeadOnly); @@ -321,9 +323,9 @@ void GameMessages::SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& s CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::PLAY_ND_AUDIO_EMITTER); - bitStream.Write0(); - bitStream.Write0(); + bitStream.Write(MessageType::Game::PLAY_ND_AUDIO_EMITTER); + bitStream.Write0(); // callback message data {lwoobjid} + bitStream.Write0(); // audio emitterid {uint32_t} uint32_t length = audioGUID.size(); bitStream.Write(length); @@ -331,9 +333,9 @@ void GameMessages::SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& s bitStream.Write(audioGUID[k]); } - bitStream.Write(0); - bitStream.Write0(); - bitStream.Write0(); + bitStream.Write(0); // size of NDAudioMetaEventName (then print the string like the guid) + bitStream.Write0(); // result {bool} + bitStream.Write0(); // m_TargetObjectIDForNDAudioCallbackMessages {lwoobjid} SEND_PACKET_BROADCAST; } @@ -343,7 +345,7 @@ void GameMessages::SendStartPathing(Entity* entity) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::START_PATHING); + bitStream.Write(MessageType::Game::START_PATHING); SEND_PACKET_BROADCAST; } @@ -353,7 +355,7 @@ void GameMessages::SendResetMissions(Entity* entity, const SystemAddress& sysAdd CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::RESET_MISSIONS); + bitStream.Write(MessageType::Game::RESET_MISSIONS); bitStream.Write(missionid != -1); if (missionid != -1) bitStream.Write(missionid); @@ -369,8 +371,8 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd const auto lot = entity->GetLOT(); - if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449) { - iDesiredWaypointIndex = 0; + if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449 || lot == 11306 || lot == 11308) { + iDesiredWaypointIndex = (lot == 11306 || lot == 11308) ? 1 : 0; iIndex = 0; nextIndex = 0; bStopAtDesiredWaypoint = true; @@ -378,7 +380,7 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd } bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::PLATFORM_RESYNC); + bitStream.Write(MessageType::Game::PLATFORM_RESYNC); bool bReverse = false; int eCommand = 0; @@ -412,14 +414,15 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd bitStream.Write(qUnexpectedRotation.w); } - SEND_PACKET_BROADCAST; + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; + SEND_PACKET; } void GameMessages::SendRestoreToPostLoadStats(Entity* entity, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::RESTORE_TO_POST_LOAD_STATS); + bitStream.Write(MessageType::Game::RESTORE_TO_POST_LOAD_STATS); SEND_PACKET; } @@ -427,7 +430,7 @@ void GameMessages::SendServerDoneLoadingAllObjects(Entity* entity, const SystemA CBITSTREAM; CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SERVER_DONE_LOADING_ALL_OBJECTS); + bitStream.Write(MessageType::Game::SERVER_DONE_LOADING_ALL_OBJECTS); SEND_PACKET; } @@ -435,7 +438,7 @@ void GameMessages::SendChatModeUpdate(const LWOOBJID& objectID, eGameMasterLevel CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::UPDATE_CHAT_MODE); + bitStream.Write(MessageType::Game::UPDATE_CHAT_MODE); bitStream.Write(level); SEND_PACKET_BROADCAST; } @@ -444,7 +447,7 @@ void GameMessages::SendGMLevelBroadcast(const LWOOBJID& objectID, eGameMasterLev CBITSTREAM; CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::SET_GM_LEVEL); + bitStream.Write(MessageType::Game::SET_GM_LEVEL); bitStream.Write1(); bitStream.Write(level); SEND_PACKET_BROADCAST; @@ -455,7 +458,7 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::ADD_ITEM_TO_INVENTORY_CLIENT_SYNC); + bitStream.Write(MessageType::Game::ADD_ITEM_TO_INVENTORY_CLIENT_SYNC); bitStream.Write(item->GetBound()); bitStream.Write(item->GetInfo().isBOE); bitStream.Write(item->GetInfo().isBOP); @@ -514,7 +517,7 @@ void GameMessages::SendNotifyClientFlagChange(const LWOOBJID& objectID, uint32_t CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::NOTIFY_CLIENT_FLAG_CHANGE); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_FLAG_CHANGE); bitStream.Write(bFlag); bitStream.Write(iFlagID); @@ -526,7 +529,7 @@ void GameMessages::SendChangeObjectWorldState(const LWOOBJID& objectID, eObjectW CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::CHANGE_OBJECT_WORLD_STATE); + bitStream.Write(MessageType::Game::CHANGE_OBJECT_WORLD_STATE); bitStream.Write(state); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST @@ -544,7 +547,7 @@ void GameMessages::SendOfferMission(const LWOOBJID& entity, const SystemAddress& CMSGHEADER; bitStream.Write(offererID); - bitStream.Write(eGameMessageType::OFFER_MISSION); + bitStream.Write(MessageType::Game::OFFER_MISSION); bitStream.Write(missionID); bitStream.Write(offererID); @@ -555,7 +558,7 @@ void GameMessages::SendOfferMission(const LWOOBJID& entity, const SystemAddress& CMSGHEADER; bitStream.Write(entity); - bitStream.Write(eGameMessageType::OFFER_MISSION); + bitStream.Write(MessageType::Game::OFFER_MISSION); bitStream.Write(missionID); bitStream.Write(offererID); @@ -568,7 +571,7 @@ void GameMessages::SendNotifyMission(Entity* entity, const SystemAddress& sysAdd CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::NOTIFY_MISSION); + bitStream.Write(MessageType::Game::NOTIFY_MISSION); bitStream.Write(missionID); bitStream.Write(missionState); bitStream.Write(sendingRewards); @@ -581,7 +584,7 @@ void GameMessages::SendNotifyMissionTask(Entity* entity, const SystemAddress& sy CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::NOTIFY_MISSION_TASK); + bitStream.Write(MessageType::Game::NOTIFY_MISSION_TASK); bitStream.Write(missionID); bitStream.Write(taskMask); @@ -599,7 +602,7 @@ void GameMessages::SendModifyLEGOScore(Entity* entity, const SystemAddress& sysA CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::MODIFY_LEGO_SCORE); + bitStream.Write(MessageType::Game::MODIFY_LEGO_SCORE); bitStream.Write(score); bitStream.Write(sourceType != eLootSourceType::NONE); @@ -613,7 +616,7 @@ void GameMessages::SendUIMessageServerToSingleClient(Entity* entity, const Syste CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT); + bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT); bitStream.Write(args); uint32_t strMessageNameLength = message.size(); @@ -632,7 +635,7 @@ void GameMessages::SendUIMessageServerToSingleClient(const std::string& message, LWOOBJID empty = 0; bitStream.Write(empty); - bitStream.Write(eGameMessageType::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); // This is intentional to allow the server to send a ui message to a client via their system address. + bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); // This is intentional to allow the server to send a ui message to a client via their system address. bitStream.Write(args); uint32_t strMessageNameLength = message.size(); @@ -651,7 +654,7 @@ void GameMessages::SendUIMessageServerToAllClients(const std::string& message, A LWOOBJID empty = 0; bitStream.Write(empty); - bitStream.Write(eGameMessageType::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); + bitStream.Write(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS); bitStream.Write(args); uint32_t strMessageNameLength = message.size(); @@ -669,7 +672,7 @@ void GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(Entity* entity, CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT); + bitStream.Write(MessageType::Game::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT); bitStream.Write(effectName.length()); for (uint32_t k = 0; k < effectName.length(); k++) { @@ -690,7 +693,7 @@ void GameMessages::SendPlayFXEffect(const LWOOBJID& entity, int32_t effectID, co CMSGHEADER; bitStream.Write(entity); - bitStream.Write(eGameMessageType::PLAY_FX_EFFECT); + bitStream.Write(MessageType::Game::PLAY_FX_EFFECT); bitStream.Write(effectID != -1); if (effectID != -1) bitStream.Write(effectID); @@ -724,7 +727,7 @@ void GameMessages::SendStopFXEffect(Entity* entity, bool killImmediate, std::str CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::STOP_FX_EFFECT); + bitStream.Write(MessageType::Game::STOP_FX_EFFECT); bitStream.Write(killImmediate); bitStream.Write(name.size()); @@ -738,7 +741,7 @@ void GameMessages::SendBroadcastTextToChatbox(Entity* entity, const SystemAddres CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::BROADCAST_TEXT_TO_CHATBOX); + bitStream.Write(MessageType::Game::BROADCAST_TEXT_TO_CHATBOX); LWONameValue attribs; attribs.name = attrs; @@ -764,7 +767,7 @@ void GameMessages::SendSetCurrency(Entity* entity, int64_t currency, int lootTyp CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SET_CURRENCY); + bitStream.Write(MessageType::Game::SET_CURRENCY); bitStream.Write(currency); @@ -794,7 +797,7 @@ void GameMessages::SendQuickBuildNotifyState(Entity* entity, eQuickBuildState pr CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::REBUILD_NOTIFY_STATE); + bitStream.Write(MessageType::Game::REBUILD_NOTIFY_STATE); bitStream.Write(prevState); bitStream.Write(state); @@ -808,7 +811,7 @@ void GameMessages::SendEnableQuickBuild(Entity* entity, bool enable, bool fail, CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::ENABLE_REBUILD); + bitStream.Write(MessageType::Game::ENABLE_REBUILD); bitStream.Write(enable); bitStream.Write(fail); @@ -828,7 +831,7 @@ void GameMessages::SendTerminateInteraction(const LWOOBJID& objectID, eTerminate CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::TERMINATE_INTERACTION); + bitStream.Write(MessageType::Game::TERMINATE_INTERACTION); bitStream.Write(terminator); bitStream.Write(type); @@ -841,7 +844,7 @@ void GameMessages::SendDieNoImplCode(Entity* entity, const LWOOBJID& killerID, c CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::DIE); + bitStream.Write(MessageType::Game::DIE); bitStream.Write(bClientDeath); bitStream.Write(bSpawnLoot); bitStream.Write(deathType); @@ -864,7 +867,7 @@ void GameMessages::SendDie(Entity* entity, const LWOOBJID& killerID, const LWOOB bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::DIE); + bitStream.Write(MessageType::Game::DIE); bitStream.Write(bClientDeath); bitStream.Write(bSpawnLoot); @@ -900,7 +903,7 @@ void GameMessages::SendSetInventorySize(Entity* entity, int invType, int size) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SET_INVENTORY_SIZE); + bitStream.Write(MessageType::Game::SET_INVENTORY_SIZE); bitStream.Write(invType); bitStream.Write(size); @@ -913,7 +916,7 @@ void GameMessages::SendSetEmoteLockState(Entity* entity, bool bLock, int emoteID CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SET_EMOTE_LOCK_STATE); + bitStream.Write(MessageType::Game::SET_EMOTE_LOCK_STATE); bitStream.Write(bLock); bitStream.Write(emoteID); @@ -934,7 +937,7 @@ void GameMessages::SendSetJetPackMode(Entity* entity, bool use, bool bypassCheck CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SET_JET_PACK_MODE); + bitStream.Write(MessageType::Game::SET_JET_PACK_MODE); bitStream.Write(bypassChecks); bitStream.Write(doHover); @@ -987,7 +990,7 @@ void GameMessages::SendResurrect(Entity* entity) { bool bRezImmediately = false; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::RESURRECT); + bitStream.Write(MessageType::Game::RESURRECT); bitStream.Write(bRezImmediately); SEND_PACKET_BROADCAST; @@ -998,7 +1001,7 @@ void GameMessages::SendStop2DAmbientSound(Entity* entity, bool force, std::strin CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::STOP2_D_AMBIENT_SOUND); + bitStream.Write(MessageType::Game::STOP2_D_AMBIENT_SOUND); uint32_t audioGUIDSize = audioGUID.size(); @@ -1021,7 +1024,7 @@ void GameMessages::SendPlay2DAmbientSound(Entity* entity, std::string audioGUID, CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::PLAY2_D_AMBIENT_SOUND); + bitStream.Write(MessageType::Game::PLAY2_D_AMBIENT_SOUND); uint32_t audioGUIDSize = audioGUID.size(); bitStream.Write(audioGUIDSize); @@ -1039,7 +1042,7 @@ void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress& CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SCRIPT_NETWORK_VAR_UPDATE); + bitStream.Write(MessageType::Game::SCRIPT_NETWORK_VAR_UPDATE); // FIXME: this is a bad place to need to do a conversion because we have no clue whether data is utf8 or plain ascii // an this has performance implications @@ -1098,7 +1101,7 @@ void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::DROP_CLIENT_LOOT); + bitStream.Write(MessageType::Game::DROP_CLIENT_LOOT); bitStream.Write(bUsePosition); @@ -1148,7 +1151,7 @@ void GameMessages::SendSetPlayerControlScheme(Entity* entity, eControlScheme con bool bSwitchCam = true; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SET_PLAYER_CONTROL_SCHEME); + bitStream.Write(MessageType::Game::SET_PLAYER_CONTROL_SCHEME); bitStream.Write(bDelayCamSwitchIfInCinematic); bitStream.Write(bSwitchCam); @@ -1165,7 +1168,7 @@ void GameMessages::SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPo CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::PLAYER_REACHED_RESPAWN_CHECKPOINT); + bitStream.Write(MessageType::Game::PLAYER_REACHED_RESPAWN_CHECKPOINT); bitStream.Write(position.x); bitStream.Write(position.y); @@ -1197,7 +1200,7 @@ void GameMessages::SendAddSkill(Entity* entity, TSkillID skillID, BehaviorSlot s CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::ADD_SKILL); + bitStream.Write(MessageType::Game::ADD_SKILL); bitStream.Write(AICombatWeight != 0); if (AICombatWeight != 0) bitStream.Write(AICombatWeight); @@ -1229,7 +1232,7 @@ void GameMessages::SendRemoveSkill(Entity* entity, TSkillID skillID) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::REMOVE_SKILL); + bitStream.Write(MessageType::Game::REMOVE_SKILL); bitStream.Write(false); bitStream.Write(skillID); @@ -1258,7 +1261,7 @@ void GameMessages::SendFinishArrangingWithItem(Entity* entity, const LWOOBJID& b bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::FINISH_ARRANGING_WITH_ITEM); + bitStream.Write(MessageType::Game::FINISH_ARRANGING_WITH_ITEM); bitStream.Write(buildAreaID != LWOOBJID_EMPTY); if (buildAreaID != LWOOBJID_EMPTY) bitStream.Write(buildAreaID); @@ -1284,7 +1287,7 @@ void GameMessages::SendModularBuildEnd(Entity* entity) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::MODULAR_BUILD_END); + bitStream.Write(MessageType::Game::MODULAR_BUILD_END); SystemAddress sysAddr = entity->GetSystemAddress(); SEND_PACKET; @@ -1295,7 +1298,7 @@ void GameMessages::SendVendorOpenWindow(Entity* entity, const SystemAddress& sys CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::VENDOR_OPEN_WINDOW); + bitStream.Write(MessageType::Game::VENDOR_OPEN_WINDOW); SEND_PACKET; } @@ -1310,7 +1313,7 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s auto vendorItems = vendor->GetInventory(); bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::VENDOR_STATUS_UPDATE); + bitStream.Write(MessageType::Game::VENDOR_STATUS_UPDATE); bitStream.Write(bUpdateOnly); bitStream.Write(vendorItems.size()); @@ -1331,7 +1334,7 @@ void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddre bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::VENDOR_TRANSACTION_RESULT); + bitStream.Write(MessageType::Game::VENDOR_TRANSACTION_RESULT); bitStream.Write(result); SEND_PACKET; @@ -1357,7 +1360,7 @@ void GameMessages::SendRemoveItemFromInventory(Entity* entity, const SystemAddre LWOOBJID iTradeID = LWOOBJID_EMPTY; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::REMOVE_ITEM_FROM_INVENTORY); + bitStream.Write(MessageType::Game::REMOVE_ITEM_FROM_INVENTORY); bitStream.Write(bConfirmed); bitStream.Write(bDeleteItem); bitStream.Write(bOutSuccess); @@ -1389,7 +1392,7 @@ void GameMessages::SendConsumeClientItem(Entity* entity, bool bSuccess, LWOOBJID CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::CONSUME_CLIENT_ITEM); + bitStream.Write(MessageType::Game::CONSUME_CLIENT_ITEM); bitStream.Write(bSuccess); bitStream.Write(item); @@ -1402,7 +1405,7 @@ void GameMessages::SendUseItemResult(Entity* entity, LOT templateID, bool useIte CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::USE_ITEM_RESULT); + bitStream.Write(MessageType::Game::USE_ITEM_RESULT); bitStream.Write(templateID); bitStream.Write(useItemResult); @@ -1415,7 +1418,7 @@ void GameMessages::SendUseItemRequirementsResponse(LWOOBJID objectID, const Syst CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::USE_ITEM_REQUIREMENTS_RESPONSE); + bitStream.Write(MessageType::Game::USE_ITEM_REQUIREMENTS_RESPONSE); bitStream.Write(itemResponse); @@ -1477,7 +1480,7 @@ void GameMessages::SendMatchResponse(Entity* entity, const SystemAddress& sysAdd CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::MATCH_RESPONSE); + bitStream.Write(MessageType::Game::MATCH_RESPONSE); bitStream.Write(response); SEND_PACKET; @@ -1488,7 +1491,7 @@ void GameMessages::SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::MATCH_UPDATE); + bitStream.Write(MessageType::Game::MATCH_UPDATE); bitStream.Write(data.size()); for (char character : data) { bitStream.Write(character); @@ -1507,7 +1510,7 @@ void GameMessages::SendRequestActivitySummaryLeaderboardData(const LWOOBJID& obj CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA); + bitStream.Write(MessageType::Game::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA); bitStream.Write(gameID != 0); if (gameID != 0) { @@ -1540,7 +1543,7 @@ void GameMessages::SendActivityPause(LWOOBJID objectId, bool pause, const System CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ACTIVITY_PAUSE); + bitStream.Write(MessageType::Game::ACTIVITY_PAUSE); bitStream.Write(pause); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; @@ -1552,7 +1555,7 @@ void GameMessages::SendStartActivityTime(LWOOBJID objectId, float_t startTime, c CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::START_ACTIVITY_TIME); + bitStream.Write(MessageType::Game::START_ACTIVITY_TIME); bitStream.Write(startTime); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; @@ -1564,7 +1567,7 @@ void GameMessages::SendRequestActivityEnter(LWOOBJID objectId, const SystemAddre CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::REQUEST_ACTIVITY_ENTER); + bitStream.Write(MessageType::Game::REQUEST_ACTIVITY_ENTER); bitStream.Write(bStart); bitStream.Write(userID); @@ -1577,7 +1580,7 @@ void GameMessages::NotifyLevelRewards(LWOOBJID objectID, const SystemAddress& sy CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::NOTIFY_LEVEL_REWARDS); + bitStream.Write(MessageType::Game::NOTIFY_LEVEL_REWARDS); bitStream.Write(level); bitStream.Write(sending_rewards); @@ -1598,7 +1601,7 @@ void GameMessages::SendSetShootingGalleryParams(LWOOBJID objectId, const SystemA CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SET_SHOOTING_GALLERY_PARAMS); + bitStream.Write(MessageType::Game::SET_SHOOTING_GALLERY_PARAMS); /* bitStream.Write(cameraFOV); bitStream.Write(cooldown); @@ -1633,7 +1636,7 @@ void GameMessages::SendNotifyClientShootingGalleryScore(LWOOBJID objectId, const CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE); bitStream.Write(addTime); bitStream.Write(score); bitStream.Write(target); @@ -1664,7 +1667,7 @@ void GameMessages::SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA); + bitStream.Write(MessageType::Game::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA); leaderboard->Serialize(bitStream); SEND_PACKET; @@ -1728,7 +1731,7 @@ void GameMessages::SendStartCelebrationEffect(Entity* entity, const SystemAddres CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::START_CELEBRATION_EFFECT); + bitStream.Write(MessageType::Game::START_CELEBRATION_EFFECT); bitStream.Write(0); //animation bitStream.Write0(); //No custom bg obj @@ -1757,7 +1760,7 @@ void GameMessages::SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForw CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::SET_RAIL_MOVEMENT); + bitStream.Write(MessageType::Game::SET_RAIL_MOVEMENT); bitStream.Write(pathGoForward); @@ -1791,7 +1794,7 @@ void GameMessages::SendStartRailMovement(const LWOOBJID& objectID, std::u16strin CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::START_RAIL_MOVEMENT); + bitStream.Write(MessageType::Game::START_RAIL_MOVEMENT); bitStream.Write(damageImmune); bitStream.Write(noAggro); @@ -1851,7 +1854,7 @@ void GameMessages::SendNotifyClientObject(const LWOOBJID& objectID, std::u16stri CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::NOTIFY_CLIENT_OBJECT); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_OBJECT); bitStream.Write(name.size()); for (auto character : name) { @@ -1880,7 +1883,7 @@ void GameMessages::SendNotifyClientZoneObject(const LWOOBJID& objectID, const st CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::NOTIFY_CLIENT_ZONE_OBJECT); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_ZONE_OBJECT); bitStream.Write(name.size()); for (const auto& character : name) { @@ -1906,7 +1909,7 @@ void GameMessages::SendNotifyClientFailedPrecondition(LWOOBJID objectId, const S CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::NOTIFY_CLIENT_FAILED_PRECONDITION); + bitStream.Write(MessageType::Game::NOTIFY_CLIENT_FAILED_PRECONDITION); bitStream.Write(failedReason.size()); for (uint16_t character : failedReason) { @@ -1924,7 +1927,7 @@ void GameMessages::SendToggleGMInvis(LWOOBJID objectId, bool enabled, const Syst CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::TOGGLE_GM_INVIS); + bitStream.Write(MessageType::Game::TOGGLE_GM_INVIS); bitStream.Write(enabled); // does not matter? if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; @@ -1936,7 +1939,7 @@ void GameMessages::SendSetName(LWOOBJID objectID, std::u16string name, const Sys CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::SET_NAME); + bitStream.Write(MessageType::Game::SET_NAME); bitStream.Write(name.size()); @@ -1952,7 +1955,7 @@ void GameMessages::SendBBBSaveResponse(const LWOOBJID& objectId, const LWOOBJID& CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::BBB_SAVE_RESPONSE); + bitStream.Write(MessageType::Game::BBB_SAVE_RESPONSE); bitStream.Write(localID); @@ -1978,7 +1981,7 @@ void GameMessages::SendOpenPropertyVendor(const LWOOBJID objectId, const SystemA CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::OPEN_PROPERTY_VENDOR); + bitStream.Write(MessageType::Game::OPEN_PROPERTY_VENDOR); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -1989,7 +1992,7 @@ void GameMessages::SendOpenPropertyManagment(const LWOOBJID objectId, const Syst CMSGHEADER; bitStream.Write(PropertyManagementComponent::Instance()->GetParent()->GetObjectID()); - bitStream.Write(eGameMessageType::OPEN_PROPERTY_MANAGEMENT); + bitStream.Write(MessageType::Game::OPEN_PROPERTY_MANAGEMENT); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -2000,7 +2003,7 @@ void GameMessages::SendDownloadPropertyData(const LWOOBJID objectId, const Prope CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::DOWNLOAD_PROPERTY_DATA); + bitStream.Write(MessageType::Game::DOWNLOAD_PROPERTY_DATA); data.Serialize(bitStream); @@ -2015,7 +2018,7 @@ void GameMessages::SendPropertyRentalResponse(const LWOOBJID objectId, const LWO CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PROPERTY_RENTAL_RESPONSE); + bitStream.Write(MessageType::Game::PROPERTY_RENTAL_RESPONSE); bitStream.Write(cloneId); bitStream.Write(code); @@ -2031,7 +2034,7 @@ void GameMessages::SendLockNodeRotation(Entity* entity, std::string nodeName) { CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::LOCK_NODE_ROTATION); + bitStream.Write(MessageType::Game::LOCK_NODE_ROTATION); bitStream.Write(nodeName.size()); for (char character : nodeName) { @@ -2046,7 +2049,7 @@ void GameMessages::SendSetBuildModeConfirmed(LWOOBJID objectId, const SystemAddr CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SET_BUILD_MODE_CONFIRMED); + bitStream.Write(MessageType::Game::SET_BUILD_MODE_CONFIRMED); bitStream.Write(start); bitStream.Write(warnVisitors); @@ -2066,7 +2069,7 @@ void GameMessages::SendGetModelsOnProperty(LWOOBJID objectId, std::map(models.size()); @@ -2086,7 +2089,7 @@ void GameMessages::SendZonePropertyModelEquipped(LWOOBJID objectId, LWOOBJID pla CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ZONE_PROPERTY_MODEL_EQUIPPED); + bitStream.Write(MessageType::Game::ZONE_PROPERTY_MODEL_EQUIPPED); bitStream.Write(playerId); bitStream.Write(propertyId); @@ -2101,7 +2104,7 @@ void GameMessages::SendPlaceModelResponse(LWOOBJID objectId, const SystemAddress CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PLACE_MODEL_RESPONSE); + bitStream.Write(MessageType::Game::PLACE_MODEL_RESPONSE); bitStream.Write(position != NiPoint3Constant::ZERO); if (position != NiPoint3Constant::ZERO) { @@ -2133,7 +2136,7 @@ void GameMessages::SendUGCEquipPreCreateBasedOnEditMode(LWOOBJID objectId, const CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::HANDLE_UGC_POST_CREATE_BASED_ON_EDIT_MODE); + bitStream.Write(MessageType::Game::HANDLE_UGC_POST_CREATE_BASED_ON_EDIT_MODE); bitStream.Write(modelCount); bitStream.Write(model); @@ -2147,7 +2150,7 @@ void GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(LWOOBJID objectId, cons CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::HANDLE_UGC_POST_DELETE_BASED_ON_EDIT_MODE); + bitStream.Write(MessageType::Game::HANDLE_UGC_POST_DELETE_BASED_ON_EDIT_MODE); bitStream.Write(inventoryItem); @@ -2197,7 +2200,7 @@ void GameMessages::HandleUnUseModel(RakNet::BitStream& inStream, Entity* entity, if (unknown) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::BLUEPRINT_SAVE_RESPONSE); bitStream.Write(LWOOBJID_EMPTY); //always zero so that a check on the client passes bitStream.Write(eBlueprintSaveResponseType::PlacementFailed); // Sending a non-zero error code here prevents the client from deleting its in progress build for some reason? bitStream.Write(0); @@ -2449,7 +2452,7 @@ void GameMessages::HandleBBBLoadItemRequest(RakNet::BitStream& inStream, Entity* void GameMessages::SendBlueprintLoadItemResponse(const SystemAddress& sysAddr, bool success, LWOOBJID oldItemId, LWOOBJID newItemId) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_LOAD_RESPONSE_ITEMID); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::BLUEPRINT_LOAD_RESPONSE_ITEMID); bitStream.Write(success); bitStream.Write(oldItemId); bitStream.Write(newItemId); @@ -2461,7 +2464,7 @@ void GameMessages::SendSmash(Entity* entity, float force, float ghostOpacity, LW CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SMASH); + bitStream.Write(MessageType::Game::SMASH); bitStream.Write(ignoreObjectVisibility); bitStream.Write(force); @@ -2476,7 +2479,7 @@ void GameMessages::SendUnSmash(Entity* entity, LWOOBJID builderID, float duratio CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::UN_SMASH); + bitStream.Write(MessageType::Game::UN_SMASH); bitStream.Write(builderID != LWOOBJID_EMPTY); if (builderID != LWOOBJID_EMPTY) bitStream.Write(builderID); @@ -2641,7 +2644,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* ent //Tell the client their model is saved: (this causes us to actually pop out of our current state): CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::BLUEPRINT_SAVE_RESPONSE); bitStream.Write(localId); bitStream.Write(eBlueprintSaveResponseType::EverythingWorked); bitStream.Write(1); @@ -2663,17 +2666,11 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* ent info.spawnerID = entity->GetObjectID(); info.spawnerNodeID = 0; - LDFBaseData* ldfBlueprintID = new LDFData(u"blueprintid", blueprintID); - LDFBaseData* componentWhitelist = new LDFData(u"componentWhitelist", 1); - LDFBaseData* modelType = new LDFData(u"modelType", 2); - LDFBaseData* propertyObjectID = new LDFData(u"propertyObjectID", true); - LDFBaseData* userModelID = new LDFData(u"userModelID", newIDL); - - info.settings.push_back(ldfBlueprintID); - info.settings.push_back(componentWhitelist); - info.settings.push_back(modelType); - info.settings.push_back(propertyObjectID); - info.settings.push_back(userModelID); + info.settings.push_back(new LDFData(u"blueprintid", blueprintID)); + info.settings.push_back(new LDFData(u"componentWhitelist", 1)); + info.settings.push_back(new LDFData(u"modelType", 2)); + info.settings.push_back(new LDFData(u"propertyObjectID", true)); + info.settings.push_back(new LDFData(u"userModelID", newIDL)); Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr); if (newEntity) { @@ -2777,7 +2774,7 @@ void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PLAY_CINEMATIC); + bitStream.Write(MessageType::Game::PLAY_CINEMATIC); bitStream.Write(allowGhostUpdates); bitStream.Write(bCloseMultiInteract); @@ -2816,7 +2813,7 @@ void GameMessages::SendEndCinematic(LWOOBJID objectId, std::u16string pathName, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::END_CINEMATIC); + bitStream.Write(MessageType::Game::END_CINEMATIC); bitStream.Write(leadOut != -1); if (leadOut != -1) bitStream.Write(leadOut); @@ -2889,7 +2886,7 @@ void GameMessages::SendSetStunned(LWOOBJID objectId, eStateChangeType stateChang CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SET_STUNNED); + bitStream.Write(MessageType::Game::SET_STUNNED); bitStream.Write(originator != LWOOBJID_EMPTY); if (originator != LWOOBJID_EMPTY) bitStream.Write(originator); @@ -2938,7 +2935,7 @@ void GameMessages::SendSetStunImmunity(LWOOBJID target, eStateChangeType state, CMSGHEADER; bitStream.Write(target); - bitStream.Write(eGameMessageType::SET_STUN_IMMUNITY); + bitStream.Write(MessageType::Game::SET_STUN_IMMUNITY); bitStream.Write(originator != LWOOBJID_EMPTY); if (originator != LWOOBJID_EMPTY) bitStream.Write(originator); @@ -2971,7 +2968,7 @@ void GameMessages::SendSetStatusImmunity(LWOOBJID objectId, eStateChangeType sta CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SET_STATUS_IMMUNITY); + bitStream.Write(MessageType::Game::SET_STATUS_IMMUNITY); bitStream.Write(state); @@ -2994,7 +2991,7 @@ void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ORIENT_TO_ANGLE); + bitStream.Write(MessageType::Game::ORIENT_TO_ANGLE); bitStream.Write(bRelativeToCurrent); bitStream.Write(fAngle); @@ -3009,7 +3006,7 @@ void GameMessages::SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, u CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ADD_RUN_SPEED_MODIFIER); + bitStream.Write(MessageType::Game::ADD_RUN_SPEED_MODIFIER); bitStream.Write(caster != LWOOBJID_EMPTY); if (caster != LWOOBJID_EMPTY) bitStream.Write(caster); @@ -3026,7 +3023,7 @@ void GameMessages::SendRemoveRunSpeedModifier(LWOOBJID objectId, uint32_t modifi CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::REMOVE_RUN_SPEED_MODIFIER); + bitStream.Write(MessageType::Game::REMOVE_RUN_SPEED_MODIFIER); bitStream.Write(modifier != 500); if (modifier != 500) bitStream.Write(modifier); @@ -3040,7 +3037,7 @@ void GameMessages::SendPropertyEntranceBegin(LWOOBJID objectId, const SystemAddr CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PROPERTY_ENTRANCE_BEGIN); + bitStream.Write(MessageType::Game::PROPERTY_ENTRANCE_BEGIN); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -3051,7 +3048,7 @@ void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PROPERTY_SELECT_QUERY); + bitStream.Write(MessageType::Game::PROPERTY_SELECT_QUERY); bitStream.Write(navOffset); bitStream.Write(thereAreMore); @@ -3074,7 +3071,7 @@ void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::NOTIFY_OBJECT); + bitStream.Write(MessageType::Game::NOTIFY_OBJECT); bitStream.Write(objIDSender); bitStream.Write(name.size()); @@ -3114,7 +3111,7 @@ void GameMessages::SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJ CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::TEAM_PICKUP_ITEM); + bitStream.Write(MessageType::Game::TEAM_PICKUP_ITEM); bitStream.Write(lootID); bitStream.Write(lootOwnerID); @@ -3130,7 +3127,7 @@ void GameMessages::SendServerTradeInvite(LWOOBJID objectId, bool bNeedInvitePopU CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SERVER_TRADE_INVITE); + bitStream.Write(MessageType::Game::SERVER_TRADE_INVITE); bitStream.Write(bNeedInvitePopUp); bitStream.Write(i64Requestor); @@ -3148,7 +3145,7 @@ void GameMessages::SendServerTradeInitialReply(LWOOBJID objectId, LWOOBJID i64In CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SERVER_TRADE_INITIAL_REPLY); + bitStream.Write(MessageType::Game::SERVER_TRADE_INITIAL_REPLY); bitStream.Write(i64Invitee); bitStream.Write(resultType); @@ -3166,7 +3163,7 @@ void GameMessages::SendServerTradeFinalReply(LWOOBJID objectId, bool bResult, LW CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SERVER_TRADE_FINAL_REPLY); + bitStream.Write(MessageType::Game::SERVER_TRADE_FINAL_REPLY); bitStream.Write(bResult); bitStream.Write(i64Invitee); @@ -3184,7 +3181,7 @@ void GameMessages::SendServerTradeAccept(LWOOBJID objectId, bool bFirst, const S CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SERVER_TRADE_ACCEPT); + bitStream.Write(MessageType::Game::SERVER_TRADE_ACCEPT); bitStream.Write(bFirst); @@ -3197,7 +3194,7 @@ void GameMessages::SendServerTradeCancel(LWOOBJID objectId, const SystemAddress& CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SERVER_TRADE_CANCEL); + bitStream.Write(MessageType::Game::SERVER_TRADE_CANCEL); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -3208,7 +3205,7 @@ void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, cons CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SERVER_TRADE_UPDATE); + bitStream.Write(MessageType::Game::SERVER_TRADE_UPDATE); bitStream.Write(false); bitStream.Write(coins); @@ -3386,7 +3383,7 @@ void GameMessages::SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::NOTIFY_PET_TAMING_MINIGAME); + bitStream.Write(MessageType::Game::NOTIFY_PET_TAMING_MINIGAME); bitStream.Write(petId); bitStream.Write(playerTamingId); @@ -3408,7 +3405,7 @@ void GameMessages::SendNotifyTamingModelLoadedOnServer(LWOOBJID objectId, const CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::NOTIFY_TAMING_MODEL_LOADED_ON_SERVER); + bitStream.Write(MessageType::Game::NOTIFY_TAMING_MODEL_LOADED_ON_SERVER); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -3419,7 +3416,7 @@ void GameMessages::SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, const st CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::NOTIFY_TAMING_PUZZLE_SELECTED); + bitStream.Write(MessageType::Game::NOTIFY_TAMING_PUZZLE_SELECTED); bitStream.Write(bricks.size()); for (const auto& brick : bricks) { @@ -3436,7 +3433,7 @@ void GameMessages::SendPetTamingTryBuildResult(LWOOBJID objectId, bool bSuccess, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PET_TAMING_TRY_BUILD_RESULT); + bitStream.Write(MessageType::Game::PET_TAMING_TRY_BUILD_RESULT); bitStream.Write(bSuccess); bitStream.Write(iNumCorrect != 0); @@ -3451,7 +3448,7 @@ void GameMessages::SendPetResponse(LWOOBJID objectId, LWOOBJID objIDPet, int32_t CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PET_RESPONSE); + bitStream.Write(MessageType::Game::PET_RESPONSE); bitStream.Write(objIDPet); bitStream.Write(iPetCommandType); @@ -3467,7 +3464,7 @@ void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ADD_PET_TO_PLAYER); + bitStream.Write(MessageType::Game::ADD_PET_TO_PLAYER); bitStream.Write(iElementalType); bitStream.Write(name.size()); @@ -3487,7 +3484,7 @@ void GameMessages::SendRegisterPetID(LWOOBJID objectId, LWOOBJID objID, const Sy CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::REGISTER_PET_ID); + bitStream.Write(MessageType::Game::REGISTER_PET_ID); bitStream.Write(objID); @@ -3500,7 +3497,7 @@ void GameMessages::SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, cons CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::REGISTER_PET_DBID); + bitStream.Write(MessageType::Game::REGISTER_PET_DBID); bitStream.Write(petDBID); @@ -3513,7 +3510,7 @@ void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::MARK_INVENTORY_ITEM_AS_ACTIVE); + bitStream.Write(MessageType::Game::MARK_INVENTORY_ITEM_AS_ACTIVE); bitStream.Write(bActive); @@ -3532,7 +3529,7 @@ void GameMessages::SendClientExitTamingMinigame(LWOOBJID objectId, bool bVolunta CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::CLIENT_EXIT_TAMING_MINIGAME); + bitStream.Write(MessageType::Game::CLIENT_EXIT_TAMING_MINIGAME); bitStream.Write(bVoluntaryExit); @@ -3545,7 +3542,7 @@ void GameMessages::SendShowPetActionButton(const LWOOBJID objectId, const ePetAb CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SHOW_PET_ACTION_BUTTON); + bitStream.Write(MessageType::Game::SHOW_PET_ACTION_BUTTON); bitStream.Write(petAbility); bitStream.Write(bShow); @@ -3559,7 +3556,7 @@ void GameMessages::SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID ta CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PLAY_EMOTE); + bitStream.Write(MessageType::Game::PLAY_EMOTE); bitStream.Write(emoteID); bitStream.Write(target); @@ -3573,7 +3570,7 @@ void GameMessages::SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeI CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::REMOVE_BUFF); + bitStream.Write(MessageType::Game::REMOVE_BUFF); bitStream.Write(false); // bFromRemoveBehavior but setting this to true makes the GM not do anything on the client? bitStream.Write(fromUnEquip); @@ -3588,7 +3585,7 @@ void GameMessages::SendBouncerActiveStatus(LWOOBJID objectId, bool bActive, cons CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::BOUNCER_ACTIVE_STATUS); + bitStream.Write(MessageType::Game::BOUNCER_ACTIVE_STATUS); bitStream.Write(bActive); @@ -3602,7 +3599,7 @@ void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJ CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SET_PET_NAME); + bitStream.Write(MessageType::Game::SET_PET_NAME); bitStream.Write(name.size()); for (const auto character : name) { @@ -3622,7 +3619,7 @@ void GameMessages::SendSetPetNameModerated(LWOOBJID objectId, LWOOBJID petDBID, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SET_PET_NAME_MODERATED); + bitStream.Write(MessageType::Game::SET_PET_NAME_MODERATED); bitStream.Write(petDBID != LWOOBJID_EMPTY); if (petDBID != LWOOBJID_EMPTY) bitStream.Write(petDBID); @@ -3639,7 +3636,7 @@ void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatu CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::PET_NAME_CHANGED); + bitStream.Write(MessageType::Game::PET_NAME_CHANGED); bitStream.Write(moderationStatus); @@ -3888,7 +3885,7 @@ void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::DISPLAY_ZONE_SUMMARY); + bitStream.Write(MessageType::Game::DISPLAY_ZONE_SUMMARY); bitStream.Write(isPropertyMap); bitStream.Write(isZoneStart); @@ -3906,7 +3903,7 @@ void GameMessages::SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeS CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::VEHICLE_NOTIFY_FINISHED_RACE); + bitStream.Write(MessageType::Game::VEHICLE_NOTIFY_FINISHED_RACE); bitStream.Write(freeSlotsNeeded); bitStream.Write(inventoryType != 0); @@ -3921,7 +3918,7 @@ void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::DISPLAY_MESSAGE_BOX); + bitStream.Write(MessageType::Game::DISPLAY_MESSAGE_BOX); bitStream.Write(bShow); bitStream.Write(callbackClient); @@ -3948,12 +3945,12 @@ void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID } void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr) { - // eGameMessageType::DISPLAY_CHAT_BUBBLE + // MessageType::Game::DISPLAY_CHAT_BUBBLE CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::DISPLAY_CHAT_BUBBLE); + bitStream.Write(MessageType::Game::DISPLAY_CHAT_BUBBLE); bitStream.Write(text.size()); for (const auto character : text) { @@ -3970,7 +3967,7 @@ void GameMessages::SendChangeIdleFlags(LWOOBJID objectId, eAnimationFlags flagsO CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::CHANGE_IDLE_FLAGS); + bitStream.Write(MessageType::Game::CHANGE_IDLE_FLAGS); bitStream.Write(flagsOff != eAnimationFlags::IDLE_NONE); if (flagsOff != eAnimationFlags::IDLE_NONE) bitStream.Write(flagsOff); bitStream.Write(flagsOn != eAnimationFlags::IDLE_NONE); @@ -3984,7 +3981,7 @@ void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objec CBITSTREAM; CMSGHEADER; bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SET_MOUNT_INVENTORY_ID); + bitStream.Write(MessageType::Game::SET_MOUNT_INVENTORY_ID); bitStream.Write(objectID); SEND_PACKET_BROADCAST; @@ -4193,7 +4190,7 @@ void GameMessages::SendUpdateReputation(const LWOOBJID objectId, const int64_t r CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::UPDATE_REPUTATION); + bitStream.Write(MessageType::Game::UPDATE_REPUTATION); bitStream.Write(reputation); @@ -4259,7 +4256,7 @@ void GameMessages::SendModuleAssemblyDBDataForClient(LWOOBJID objectId, LWOOBJID CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT); + bitStream.Write(MessageType::Game::MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT); bitStream.Write(assemblyID); @@ -4278,7 +4275,7 @@ void GameMessages::SendNotifyVehicleOfRacingObject(LWOOBJID objectId, LWOOBJID r CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::NOTIFY_VEHICLE_OF_RACING_OBJECT); + bitStream.Write(MessageType::Game::NOTIFY_VEHICLE_OF_RACING_OBJECT); bitStream.Write(racingObjectID != LWOOBJID_EMPTY); if (racingObjectID != LWOOBJID_EMPTY) bitStream.Write(racingObjectID); @@ -4293,7 +4290,7 @@ void GameMessages::SendRacingPlayerLoaded(LWOOBJID objectId, LWOOBJID playerID, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::RACING_PLAYER_LOADED); + bitStream.Write(MessageType::Game::RACING_PLAYER_LOADED); bitStream.Write(playerID); bitStream.Write(vehicleID); @@ -4308,7 +4305,7 @@ void GameMessages::SendVehicleUnlockInput(LWOOBJID objectId, bool bLockWheels, c CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::VEHICLE_UNLOCK_INPUT); + bitStream.Write(MessageType::Game::VEHICLE_UNLOCK_INPUT); bitStream.Write(bLockWheels); @@ -4322,7 +4319,7 @@ void GameMessages::SendVehicleSetWheelLockState(LWOOBJID objectId, bool bExtraFr CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::VEHICLE_SET_WHEEL_LOCK_STATE); + bitStream.Write(MessageType::Game::VEHICLE_SET_WHEEL_LOCK_STATE); bitStream.Write(bExtraFriction); bitStream.Write(bLocked); @@ -4337,7 +4334,7 @@ void GameMessages::SendRacingSetPlayerResetInfo(LWOOBJID objectId, int32_t curre CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::RACING_SET_PLAYER_RESET_INFO); + bitStream.Write(MessageType::Game::RACING_SET_PLAYER_RESET_INFO); bitStream.Write(currentLap); bitStream.Write(furthestResetPlane); @@ -4355,7 +4352,7 @@ void GameMessages::SendRacingResetPlayerToLastReset(LWOOBJID objectId, LWOOBJID CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::RACING_RESET_PLAYER_TO_LAST_RESET); + bitStream.Write(MessageType::Game::RACING_RESET_PLAYER_TO_LAST_RESET); bitStream.Write(playerID); @@ -4368,7 +4365,7 @@ void GameMessages::SendVehicleStopBoost(Entity* targetEntity, const SystemAddres CMSGHEADER; bitStream.Write(targetEntity->GetObjectID()); - bitStream.Write(eGameMessageType::VEHICLE_STOP_BOOST); + bitStream.Write(MessageType::Game::VEHICLE_STOP_BOOST); bitStream.Write(affectPassive); @@ -4380,7 +4377,7 @@ void GameMessages::SendSetResurrectRestoreValues(Entity* targetEntity, int32_t a CMSGHEADER; bitStream.Write(targetEntity->GetObjectID()); - bitStream.Write(eGameMessageType::SET_RESURRECT_RESTORE_VALUES); + bitStream.Write(MessageType::Game::SET_RESURRECT_RESTORE_VALUES); bitStream.Write(armorRestore != -1); if (armorRestore != -1) bitStream.Write(armorRestore); @@ -4399,7 +4396,7 @@ void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::NOTIFY_RACING_CLIENT); + bitStream.Write(MessageType::Game::NOTIFY_RACING_CLIENT); bitStream.Write(eventType != 0); if (eventType != 0) bitStream.Write(eventType); @@ -4425,7 +4422,7 @@ void GameMessages::SendActivityEnter(LWOOBJID objectId, const SystemAddress& sys CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ACTIVITY_ENTER); + bitStream.Write(MessageType::Game::ACTIVITY_ENTER); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -4437,7 +4434,7 @@ void GameMessages::SendActivityStart(LWOOBJID objectId, const SystemAddress& sys CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ACTIVITY_START); + bitStream.Write(MessageType::Game::ACTIVITY_START); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -4449,7 +4446,7 @@ void GameMessages::SendActivityExit(LWOOBJID objectId, const SystemAddress& sysA CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ACTIVITY_EXIT); + bitStream.Write(MessageType::Game::ACTIVITY_EXIT); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -4461,7 +4458,7 @@ void GameMessages::SendActivityStop(LWOOBJID objectId, bool bExit, bool bUserCan CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ACTIVITY_STOP); + bitStream.Write(MessageType::Game::ACTIVITY_STOP); bitStream.Write(bExit); bitStream.Write(bUserCancel); @@ -4476,7 +4473,7 @@ void GameMessages::SendVehicleAddPassiveBoostAction(LWOOBJID objectId, const Sys CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::VEHICLE_ADD_PASSIVE_BOOST_ACTION); + bitStream.Write(MessageType::Game::VEHICLE_ADD_PASSIVE_BOOST_ACTION); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -4488,7 +4485,7 @@ void GameMessages::SendVehicleRemovePassiveBoostAction(LWOOBJID objectId, const CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::VEHICLE_REMOVE_PASSIVE_BOOST_ACTION); + bitStream.Write(MessageType::Game::VEHICLE_REMOVE_PASSIVE_BOOST_ACTION); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -4500,7 +4497,7 @@ void GameMessages::SendVehicleNotifyFinishedRace(LWOOBJID objectId, const System CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::VEHICLE_NOTIFY_FINISHED_RACE); + bitStream.Write(MessageType::Game::VEHICLE_NOTIFY_FINISHED_RACE); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -4514,7 +4511,7 @@ void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uin CMSGHEADER; bitStream.Write(objectID); - bitStream.Write(eGameMessageType::ADD_BUFF); + bitStream.Write(MessageType::Game::ADD_BUFF); bitStream.Write(addedByTeammate); // Added by teammate bitStream.Write(applyOnTeammates); // Apply on teammates @@ -4569,16 +4566,31 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream& if (inStream.ReadBit()) inStream.Read(itemLOT); if (invTypeDst == invTypeSrc) { + SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_GENERIC); return; } auto* inventoryComponent = entity->GetComponent(); - if (inventoryComponent != nullptr) { + if (inventoryComponent) { if (itemID != LWOOBJID_EMPTY) { auto* item = inventoryComponent->FindItemById(itemID); - if (!item) return; + if (!item) { + SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_ITEM_NOT_FOUND); + return; + } + + if (item->GetLot() == 6086) { // Thinking hat + SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_CANT_MOVE_THINKING_HAT); + return; + } + + auto* destInv = inventoryComponent->GetInventory(invTypeDst); + if (destInv && destInv->GetEmptySlots() == 0) { + SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_INV_FULL); + return; + } // Despawn the pet if we are moving that pet to the vault. auto* petComponent = PetComponent::GetActivePet(entity->GetObjectID()); @@ -4587,17 +4599,39 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream& } inventoryComponent->MoveItemToInventory(item, invTypeDst, iStackCount, showFlyingLoot, false, false, destSlot); + SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::SUCCESS); } + } else { + SendResponseMoveItemBetweenInventoryTypes(entity->GetObjectID(), sysAddr, invTypeDst, invTypeSrc, eReponseMoveItemBetweenInventoryTypeCode::FAIL_GENERIC); } } +void GameMessages::SendResponseMoveItemBetweenInventoryTypes(LWOOBJID objectId, const SystemAddress& sysAddr, eInventoryType inventoryTypeDestination, eInventoryType inventoryTypeSource, eReponseMoveItemBetweenInventoryTypeCode response) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(objectId); + bitStream.Write(MessageType::Game::RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES); + + bitStream.Write(inventoryTypeDestination != eInventoryType::ITEMS); + if (inventoryTypeDestination != eInventoryType::ITEMS) bitStream.Write(inventoryTypeDestination); + + bitStream.Write(inventoryTypeSource != eInventoryType::ITEMS); + if (inventoryTypeSource != eInventoryType::ITEMS) bitStream.Write(inventoryTypeSource); + + bitStream.Write(response != eReponseMoveItemBetweenInventoryTypeCode::FAIL_GENERIC); + if (response != eReponseMoveItemBetweenInventoryTypeCode::FAIL_GENERIC) bitStream.Write(response); + + SEND_PACKET; +} + void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SHOW_ACTIVITY_COUNTDOWN); + bitStream.Write(MessageType::Game::SHOW_ACTIVITY_COUNTDOWN); bitStream.Write(bPlayAdditionalSound); @@ -4666,7 +4700,7 @@ void GameMessages::HandleBuyFromVendor(RakNet::BitStream& inStream, Entity* enti if (!user) return; Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar()); if (!player) return; - + // handle buying normal items auto* vendorComponent = entity->GetComponent(); if (vendorComponent) { @@ -5083,9 +5117,7 @@ void GameMessages::HandleRespondToMission(RakNet::BitStream& inStream, Entity* e return; } - for (CppScripts::Script* script : CppScripts::GetEntityScripts(offerer)) { - script->OnRespondToMission(offerer, missionID, Game::entityManager->GetEntity(playerID), reward); - } + offerer->GetScript()->OnRespondToMission(offerer, missionID, Game::entityManager->GetEntity(playerID), reward); } void GameMessages::HandleMissionDialogOK(RakNet::BitStream& inStream, Entity* entity) { @@ -5101,9 +5133,7 @@ void GameMessages::HandleMissionDialogOK(RakNet::BitStream& inStream, Entity* en inStream.Read(responder); player = Game::entityManager->GetEntity(responder); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(entity)) { - script->OnMissionDialogueOK(entity, player, missionID, iMissionState); - } + if (entity) entity->GetScript()->OnMissionDialogueOK(entity, player, missionID, iMissionState); // Get the player's mission component MissionComponent* missionComponent = static_cast(player->GetComponent(eReplicaComponentType::MISSION)); @@ -5300,7 +5330,7 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream& inStream, En bool iLootTypeSourceIsDefault = false; LWOOBJID iLootTypeSource = LWOOBJID_EMPTY; bool iObjIDIsDefault = false; - LWOOBJID iObjID; + LWOOBJID iObjID = LWOOBJID_EMPTY; bool iObjTemplateIsDefault = false; LOT iObjTemplate = LOT_NULL; bool iRequestingObjIDIsDefault = false; @@ -5361,17 +5391,18 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream& inStream, En iStackCount = std::min(item->GetCount(), iStackCount); if (bConfirmed) { - if (eInvType == eInventoryType::MODELS) { + const auto itemType = static_cast(item->GetInfo().itemType); + if (itemType == eItemType::MODEL || itemType == eItemType::LOOT_MODEL) { item->DisassembleModel(iStackCount); } - + auto lot = item->GetLot(); item->SetCount(item->GetCount() - iStackCount, true); Game::entityManager->SerializeEntity(entity); auto* missionComponent = entity->GetComponent(); if (missionComponent != nullptr) { - missionComponent->Progress(eMissionTaskType::GATHER, item->GetLot(), LWOOBJID_EMPTY, "", -iStackCount); + missionComponent->Progress(eMissionTaskType::GATHER, lot, LWOOBJID_EMPTY, "", -iStackCount); } } } @@ -5381,7 +5412,7 @@ void GameMessages::SendSetGravityScale(const LWOOBJID& target, const float effec CMSGHEADER; bitStream.Write(target); - bitStream.Write(eGameMessageType::SET_GRAVITY_SCALE); + bitStream.Write(MessageType::Game::SET_GRAVITY_SCALE); bitStream.Write(effectScale); @@ -5556,9 +5587,7 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream& inStream, Entity* ScriptComponent* script = static_cast(entity->GetComponent(eReplicaComponentType::SCRIPT)); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(entity)) { - script->OnModularBuildExit(entity, character, count >= 3, modList); - } + entity->GetScript()->OnModularBuildExit(entity, character, count >= 3, modList); // Move remaining temp models back to models std::vector items; @@ -5734,16 +5763,14 @@ void GameMessages::HandleResurrect(RakNet::BitStream& inStream, Entity* entity) bool immediate = inStream.ReadBit(); Entity* zoneControl = Game::entityManager->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerResurrected(zoneControl, entity); + if (zoneControl) { + zoneControl->GetScript()->OnPlayerResurrected(zoneControl, entity); } std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds - for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerResurrected(scriptEntity, entity); - } + scriptEntity->GetScript()->OnPlayerResurrected(scriptEntity, entity); } } } @@ -5872,7 +5899,7 @@ void GameMessages::SendGetHotPropertyData(RakNet::BitStream& inStream, Entity* e // TODO This needs to be implemented when reputation is implemented for getting hot properties. /** bitStream.Write(entity->GetObjectID()); - bitStream.Write(eGameMessageType::SEND_HOT_PROPERTY_DATA); + bitStream.Write(MessageType::Game::SEND_HOT_PROPERTY_DATA); std::vector t = {25166, 25188, 25191, 25194}; bitStream.Write(4); for (uint8_t i = 0; i < 4; i++) { @@ -5977,9 +6004,7 @@ void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream& inStre const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); for (auto* possibleRail : possibleRails) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(possibleRail)) { - script->OnPlayerRailArrived(possibleRail, entity, pathName, waypointNumber); - } + if (possibleRail) possibleRail->GetScript()->OnPlayerRailArrived(possibleRail, entity, pathName, waypointNumber); } } @@ -6048,7 +6073,7 @@ void GameMessages::SendActivateBubbleBuffFromServer(LWOOBJID objectId, const Sys CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::ACTIVATE_BUBBLE_BUFF_FROM_SERVER); + bitStream.Write(MessageType::Game::ACTIVATE_BUBBLE_BUFF_FROM_SERVER); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -6059,7 +6084,7 @@ void GameMessages::SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const S CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::DEACTIVATE_BUBBLE_BUFF_FROM_SERVER); + bitStream.Write(MessageType::Game::DEACTIVATE_BUBBLE_BUFF_FROM_SERVER); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -6077,7 +6102,7 @@ void GameMessages::SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOB CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SET_NAME_BILLBOARD_STATE); + bitStream.Write(MessageType::Game::SET_NAME_BILLBOARD_STATE); // Technically these bits would be written, however the client does not // contain a deserialize method to actually deserialize, so we are leaving it out. @@ -6095,7 +6120,7 @@ void GameMessages::SendShowBillboardInteractIcon(const SystemAddress& sysAddr, L CMSGHEADER; bitStream.Write(objectId); - bitStream.Write(eGameMessageType::SHOW_BILLBOARD_INTERACT_ICON); + bitStream.Write(MessageType::Game::SHOW_BILLBOARD_INTERACT_ICON); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST else SEND_PACKET @@ -6213,3 +6238,93 @@ void GameMessages::HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Ent if (!characterComponent) return; characterComponent->SetCurrentInteracting(LWOOBJID_EMPTY); } + +void GameMessages::SendSlashCommandFeedbackText(Entity* entity, std::u16string text) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::SLASH_COMMAND_TEXT_FEEDBACK); + bitStream.Write(text.size()); + bitStream.Write(text); + auto sysAddr = entity->GetSystemAddress(); + SEND_PACKET; +} + +void GameMessages::HandleUpdateInventoryGroup(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { + std::string action; + std::u16string groupName; + InventoryComponent::GroupUpdate groupUpdate; + bool locked{}; // All groups are locked by default + + uint32_t size{}; + if (!inStream.Read(size)) return; + action.resize(size); + if (!inStream.Read(action.data(), size)) return; + + if (!inStream.Read(size)) return; + groupUpdate.groupId.resize(size); + if (!inStream.Read(groupUpdate.groupId.data(), size)) return; + + if (!inStream.Read(size)) return; + groupName.resize(size); + if (!inStream.Read(reinterpret_cast(groupName.data()), size * 2)) return; + + if (!inStream.Read(groupUpdate.inventory)) return; + if (!inStream.Read(locked)) return; + + groupUpdate.groupName = GeneralUtils::UTF16ToWTF8(groupName); + + if (action == "ADD") groupUpdate.command = InventoryComponent::GroupUpdateCommand::ADD; + else if (action == "MODIFY") groupUpdate.command = InventoryComponent::GroupUpdateCommand::MODIFY; + else if (action == "REMOVE") groupUpdate.command = InventoryComponent::GroupUpdateCommand::REMOVE; + else { + LOG("Invalid action %s", action.c_str()); + return; + } + + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) inventoryComponent->UpdateGroup(groupUpdate); +} + +void GameMessages::HandleUpdateInventoryGroupContents(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { + std::string action; + InventoryComponent::GroupUpdate groupUpdate; + + uint32_t size{}; + if (!inStream.Read(size)) return; + action.resize(size); + if (!inStream.Read(action.data(), size)) return; + + if (action == "ADD") groupUpdate.command = InventoryComponent::GroupUpdateCommand::ADD_LOT; + else if (action == "REMOVE") groupUpdate.command = InventoryComponent::GroupUpdateCommand::REMOVE_LOT; + else { + LOG("Invalid action %s", action.c_str()); + return; + } + + if (!inStream.Read(size)) return; + groupUpdate.groupId.resize(size); + if (!inStream.Read(groupUpdate.groupId.data(), size)) return; + + if (!inStream.Read(groupUpdate.inventory)) return; + if (!inStream.Read(groupUpdate.lot)) return; + + auto* inventoryComponent = entity->GetComponent(); + if (inventoryComponent) inventoryComponent->UpdateGroup(groupUpdate); +} + +void GameMessages::SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(MessageType::Game::FORCE_CAMERA_TARGET_CYCLE); + bitStream.Write(bForceCycling); + bitStream.Write(cyclingMode != eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES); + if (cyclingMode != eCameraTargetCyclingMode::ALLOW_CYCLE_TEAMMATES) bitStream.Write(cyclingMode); + bitStream.Write(optionalTargetID); + + auto sysAddr = entity->GetSystemAddress(); + SEND_PACKET; +} diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 96bbf7c3c..090fcd4b9 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -39,6 +39,12 @@ enum class eQuickBuildFailReason : uint32_t; enum class eQuickBuildState : uint32_t; enum class BehaviorSlot : int32_t; enum class eVendorTransactionResult : uint32_t; +enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t; + +enum class eCameraTargetCyclingMode : int32_t { + ALLOW_CYCLE_TEAMMATES, + DISALLOW_CYCLING +}; namespace GameMessages { class PropertyDataMessage; @@ -589,6 +595,7 @@ namespace GameMessages { //NT: void HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void SendResponseMoveItemBetweenInventoryTypes(LWOOBJID objectId, const SystemAddress& sysAddr, eInventoryType inventoryTypeDestination, eInventoryType inventoryTypeSource, eReponseMoveItemBetweenInventoryTypeCode response); void SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr); @@ -664,6 +671,12 @@ namespace GameMessages { void HandleRemoveDonationItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void HandleConfirmDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity); void HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity); + + void SendSlashCommandFeedbackText(Entity* entity, std::u16string text); + + void HandleUpdateInventoryGroup(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleUpdateInventoryGroupContents(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID); }; #endif // GAMEMESSAGES_H diff --git a/dGame/dGameMessages/RequestServerProjectileImpact.h b/dGame/dGameMessages/RequestServerProjectileImpact.h index c15090c03..394bd9c7e 100644 --- a/dGame/dGameMessages/RequestServerProjectileImpact.h +++ b/dGame/dGameMessages/RequestServerProjectileImpact.h @@ -2,7 +2,7 @@ #define __REQUESTSERVERPROJECTILEIMPACT__H__ #include "dCommonVars.h" -#include "eGameMessageType.h" +#include "MessageType/Game.h" /* Notifying the server that a locally owned projectile impacted. Sent to the caster of the projectile should always be the local char. */ @@ -27,7 +27,7 @@ class RequestServerProjectileImpact { } void Serialize(RakNet::BitStream& stream) { - stream.Write(eGameMessageType::REQUEST_SERVER_PROJECTILE_IMPACT); + stream.Write(MessageType::Game::REQUEST_SERVER_PROJECTILE_IMPACT); stream.Write(i64LocalID != LWOOBJID_EMPTY); if (i64LocalID != LWOOBJID_EMPTY) stream.Write(i64LocalID); diff --git a/dGame/dGameMessages/StartSkill.h b/dGame/dGameMessages/StartSkill.h index bc0f18d73..157910399 100644 --- a/dGame/dGameMessages/StartSkill.h +++ b/dGame/dGameMessages/StartSkill.h @@ -4,7 +4,7 @@ #include "dCommonVars.h" #include "NiPoint3.h" #include "NiQuaternion.h" -#include "eGameMessageType.h" +#include "MessageType/Game.h" /** * Same as sync skill but with different network options. An echo down to other clients that need to play the skill. @@ -44,7 +44,7 @@ class StartSkill { } void Serialize(RakNet::BitStream& stream) { - stream.Write(eGameMessageType::START_SKILL); + stream.Write(MessageType::Game::START_SKILL); stream.Write(bUsedMouse); diff --git a/dGame/dGameMessages/SyncSkill.h b/dGame/dGameMessages/SyncSkill.h index b881d2705..fb5525bc1 100644 --- a/dGame/dGameMessages/SyncSkill.h +++ b/dGame/dGameMessages/SyncSkill.h @@ -5,7 +5,7 @@ #include #include "BitStream.h" -#include "eGameMessageType.h" +#include "MessageType/Game.h" /* Message to synchronize a skill cast */ class SyncSkill { @@ -29,7 +29,7 @@ class SyncSkill { } void Serialize(RakNet::BitStream& stream) { - stream.Write(eGameMessageType::SYNC_SKILL); + stream.Write(MessageType::Game::SYNC_SKILL); stream.Write(bDone); uint32_t sBitStreamLength = sBitStream.length(); diff --git a/dGame/dInventory/CMakeLists.txt b/dGame/dInventory/CMakeLists.txt index bc741efe9..b45b27bf1 100644 --- a/dGame/dInventory/CMakeLists.txt +++ b/dGame/dInventory/CMakeLists.txt @@ -5,11 +5,32 @@ set(DGAME_DINVENTORY_SOURCES "ItemSet.cpp" "ItemSetPassiveAbility.cpp") +add_library(dInventory OBJECT ${DGAME_DINVENTORY_SOURCES}) +target_include_directories(dInventory PUBLIC "." + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" # Item.h uses Preconditions.h + "${PROJECT_SOURCE_DIR}/dCommon/eEnums" # Item.h uses dCommonVars.h + PRIVATE + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" + "${PROJECT_SOURCE_DIR}/dCommon/dClient" # Item.cpp uses AssetManager + + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables" + + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # direct + "${PROJECT_SOURCE_DIR}/dGame/dComponents" # direct InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dBehaviors" # via InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # via dZoneManager/Spawner.h + "${PROJECT_SOURCE_DIR}/dGame/dMission" # via MissionComponent.h + "${PROJECT_SOURCE_DIR}/dZoneManager" # via Item.cpp +) +target_precompile_headers(dInventory REUSE_FROM dGameBase) # Workaround for compiler bug where the optimized code could result in a memcpy of 0 bytes, even though that isnt possible. # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97185 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set_source_files_properties("Item.cpp" PROPERTIES COMPILE_FLAGS "-Wno-stringop-overflow") endif() - -add_library(dInventory STATIC ${DGAME_DINVENTORY_SOURCES}) -target_precompile_headers(dInventory REUSE_FROM dGameBase) +# INTERFACE link w/o dependency +#set_property(TARGET dInventory APPEND PROPERTY INTERFACE_LINK_LIBRARIES +# dNet dDatabaseCDClient +#) diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index d3f15315a..326037614 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -27,6 +27,23 @@ #include "CDComponentsRegistryTable.h" #include "CDPackageComponentTable.h" +namespace { + const std::map ExtraSettingAbbreviations = { + { "assemblyPartLOTs", "ma" }, + { "blueprintID", "b" }, + { "userModelID", "ui" }, + { "userModelName", "un" }, + { "userModelDesc", "ud" }, + { "userModelHasBhvr", "ub" }, + { "userModelBehaviors", "ubh" }, + { "userModelBehaviorSourceID", "ubs" }, + { "userModelPhysicsType", "up" }, + { "userModelMod", "um" }, + { "userModelOpt", "uo" }, + { "reforgedLOT", "rl" }, + }; +} + Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector& config, const LWOOBJID parent, LWOOBJID subKey, eLootSourceType lootSourceType) { if (!Inventory::IsValidItem(lot)) { return; @@ -122,6 +139,10 @@ uint32_t Item::GetSlot() const { return slot; } +std::vector Item::GetConfig() const { + return config; +} + std::vector& Item::GetConfig() { return config; } @@ -251,7 +272,7 @@ bool Item::Consume() { auto skills = skillsTable->Query([this](const CDObjectSkills entry) { return entry.objectTemplate == static_cast(lot); - }); + }); auto success = false; @@ -405,18 +426,18 @@ void Item::DisassembleModel(uint32_t numToDismantle) { auto result = query.execQuery(); - if (result.eof() || result.fieldIsNull(0)) { + if (result.eof() || result.fieldIsNull("render_asset")) { return; } - std::string renderAsset = std::string(result.getStringField(0)); + std::string renderAsset = std::string(result.getStringField("render_asset")); // normalize path slashes for (auto& c : renderAsset) { if (c == '\\') c = '/'; } - std::string lxfmlFolderName = std::string(result.getStringField(1)); + std::string lxfmlFolderName = std::string(result.getStringField("LXFMLFolder")); if (!lxfmlFolderName.empty()) lxfmlFolderName.insert(0, "/"); std::vector renderAssetSplit = GeneralUtils::SplitString(renderAsset, '/'); @@ -515,3 +536,35 @@ Item::~Item() { config.clear(); } + +void Item::SaveConfigXml(tinyxml2::XMLElement& i) const { + tinyxml2::XMLElement* x = nullptr; + + for (const auto* config : this->config) { + const auto& key = GeneralUtils::UTF16ToWTF8(config->GetKey()); + const auto saveKey = ExtraSettingAbbreviations.find(key); + if (saveKey == ExtraSettingAbbreviations.end()) { + continue; + } + + if (!x) { + x = i.InsertNewChildElement("x"); + } + + const auto dataToSave = config->GetString(false); + x->SetAttribute(saveKey->second.c_str(), dataToSave.c_str()); + } +} + +void Item::LoadConfigXml(const tinyxml2::XMLElement& i) { + const auto* x = i.FirstChildElement("x"); + if (!x) return; + + for (const auto& pair : ExtraSettingAbbreviations) { + const auto* data = x->Attribute(pair.second.c_str()); + if (!data) continue; + + const auto value = pair.first + "=" + data; + config.push_back(LDFBaseData::DataFromString(value)); + } +} diff --git a/dGame/dInventory/Item.h b/dGame/dInventory/Item.h index 04d05d7c1..72ff264c7 100644 --- a/dGame/dInventory/Item.h +++ b/dGame/dInventory/Item.h @@ -9,6 +9,10 @@ #include "eInventoryType.h" #include "eLootSourceType.h" +namespace tinyxml2 { + class XMLElement; +}; + /** * An item that can be stored in an inventory and optionally consumed or equipped * TODO: ideally this should be a component @@ -116,6 +120,12 @@ class Item final */ std::vector& GetConfig(); + /** + * Returns current config info for this item, e.g. for rockets + * @return current config info for this item + */ + std::vector GetConfig() const; + /** * Returns the database info for this item * @return the database info for this item @@ -214,6 +224,10 @@ class Item final */ void RemoveFromInventory(); + void SaveConfigXml(tinyxml2::XMLElement& i) const; + + void LoadConfigXml(const tinyxml2::XMLElement& i); + private: /** * The object ID of this item diff --git a/dGame/dInventory/ItemSet.cpp b/dGame/dInventory/ItemSet.cpp index 1d0867866..d8d320ed0 100644 --- a/dGame/dInventory/ItemSet.cpp +++ b/dGame/dInventory/ItemSet.cpp @@ -8,10 +8,13 @@ #include "MissionComponent.h" #include "eMissionTaskType.h" #include +#include #include "CDSkillBehaviorTable.h" ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) { + using namespace std::string_view_literals; + this->m_ID = id; this->m_InventoryComponent = inventoryComponent; @@ -27,14 +30,16 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) { return; } - for (auto i = 0; i < 5; ++i) { - if (result.fieldIsNull(i)) { + constexpr std::array rowNames = { "skillSetWith2"sv, "skillSetWith3"sv, "skillSetWith4"sv, "skillSetWith5"sv, "skillSetWith6"sv }; + for (auto i = 0; i < rowNames.size(); ++i) { + const auto rowName = rowNames[i]; + if (result.fieldIsNull(rowName.data())) { continue; } auto skillQuery = CDClientDatabase::CreatePreppedStmt( "SELECT SkillID FROM ItemSetSkills WHERE SkillSetID = ?;"); - skillQuery.bind(1, result.getIntField(i)); + skillQuery.bind(1, result.getIntField(rowName.data())); auto skillResult = skillQuery.execQuery(); @@ -43,13 +48,13 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) { } while (!skillResult.eof()) { - if (skillResult.fieldIsNull(0)) { + if (skillResult.fieldIsNull("SkillID")) { skillResult.nextRow(); continue; } - const auto skillId = skillResult.getIntField(0); + const auto skillId = skillResult.getIntField("SkillID"); switch (i) { case 0: @@ -75,7 +80,7 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) { } } - std::string ids = result.getStringField(5); + std::string ids = result.getStringField("itemIDs"); ids.erase(std::remove_if(ids.begin(), ids.end(), ::isspace), ids.end()); diff --git a/dGame/dMission/CMakeLists.txt b/dGame/dMission/CMakeLists.txt index 4e4bdec2b..51f74c37d 100644 --- a/dGame/dMission/CMakeLists.txt +++ b/dGame/dMission/CMakeLists.txt @@ -3,6 +3,16 @@ set(DGAME_DMISSION_SOURCES "MissionPrerequisites.cpp" "MissionTask.cpp") -add_library(dMission STATIC ${DGAME_DMISSION_SOURCES}) +add_library(dMission OBJECT ${DGAME_DMISSION_SOURCES}) target_link_libraries(dMission PUBLIC dDatabase) +target_include_directories(dMission PUBLIC "." + PRIVATE + "${PROJECT_SOURCE_DIR}/dGame/dComponents" + "${PROJECT_SOURCE_DIR}/dGame/dInventory" # via CharacterComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" # via CharacterComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # via LevelProgressionComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # via dZoneManager/Spawner.h + "${PROJECT_SOURCE_DIR}/dGame/dBehaviors" # via InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dZoneManager" # via Mission.cpp, MissionTask.cpp +) target_precompile_headers(dMission REUSE_FROM dGameBase) diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 4ed80bf3a..2a841e39c 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -65,24 +65,24 @@ Mission::Mission(MissionComponent* missionComponent, const uint32_t missionId) { } } -void Mission::LoadFromXml(tinyxml2::XMLElement* element) { +void Mission::LoadFromXml(const tinyxml2::XMLElement& element) { // Start custom XML - if (element->Attribute("state") != nullptr) { - m_State = static_cast(std::stoul(element->Attribute("state"))); + if (element.Attribute("state") != nullptr) { + m_State = static_cast(std::stoul(element.Attribute("state"))); } // End custom XML - if (element->Attribute("cct") != nullptr) { - m_Completions = std::stoul(element->Attribute("cct")); + if (element.Attribute("cct") != nullptr) { + m_Completions = std::stoul(element.Attribute("cct")); - m_Timestamp = std::stoul(element->Attribute("cts")); + m_Timestamp = std::stoul(element.Attribute("cts")); if (IsComplete()) { return; } } - auto* task = element->FirstChildElement(); + auto* task = element.FirstChildElement(); auto index = 0U; @@ -132,19 +132,19 @@ void Mission::LoadFromXml(tinyxml2::XMLElement* element) { } } -void Mission::UpdateXml(tinyxml2::XMLElement* element) { +void Mission::UpdateXml(tinyxml2::XMLElement& element) { // Start custom XML - element->SetAttribute("state", static_cast(m_State)); + element.SetAttribute("state", static_cast(m_State)); // End custom XML - element->DeleteChildren(); + element.DeleteChildren(); - element->SetAttribute("id", static_cast(info.id)); + element.SetAttribute("id", static_cast(info.id)); if (m_Completions > 0) { - element->SetAttribute("cct", static_cast(m_Completions)); + element.SetAttribute("cct", static_cast(m_Completions)); - element->SetAttribute("cts", static_cast(m_Timestamp)); + element.SetAttribute("cts", static_cast(m_Timestamp)); if (IsComplete()) { return; @@ -155,27 +155,27 @@ void Mission::UpdateXml(tinyxml2::XMLElement* element) { if (task->GetType() == eMissionTaskType::COLLECTION || task->GetType() == eMissionTaskType::VISIT_PROPERTY) { - auto* child = element->GetDocument()->NewElement("sv"); + auto* child = element.GetDocument()->NewElement("sv"); child->SetAttribute("v", static_cast(task->GetProgress())); - element->LinkEndChild(child); + element.LinkEndChild(child); for (auto unique : task->GetUnique()) { - auto* uniqueElement = element->GetDocument()->NewElement("sv"); + auto* uniqueElement = element.GetDocument()->NewElement("sv"); uniqueElement->SetAttribute("v", static_cast(unique)); - element->LinkEndChild(uniqueElement); + element.LinkEndChild(uniqueElement); } break; } - auto* child = element->GetDocument()->NewElement("sv"); + auto* child = element.GetDocument()->NewElement("sv"); child->SetAttribute("v", static_cast(task->GetProgress())); - element->LinkEndChild(child); + element.LinkEndChild(child); } } @@ -454,6 +454,16 @@ void Mission::YieldRewards() { } } + // Even with no repeatable column, reputation is repeatable + if (info.reward_reputation > 0) { + missionComponent->Progress(eMissionTaskType::EARN_REPUTATION, 0, LWOOBJID_EMPTY, "", info.reward_reputation); + auto* const character = entity->GetComponent(); + if (character) { + character->SetReputation(character->GetReputation() + info.reward_reputation); + GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress()); + } + } + if (m_Completions > 0) { std::vector> items; @@ -532,15 +542,6 @@ void Mission::YieldRewards() { modelInventory->SetSize(modelInventory->GetSize() + info.reward_bankinventory); } - if (info.reward_reputation > 0) { - missionComponent->Progress(eMissionTaskType::EARN_REPUTATION, 0, 0L, "", info.reward_reputation); - auto character = entity->GetComponent(); - if (character) { - character->SetReputation(character->GetReputation() + info.reward_reputation); - GameMessages::SendUpdateReputation(entity->GetObjectID(), character->GetReputation(), entity->GetSystemAddress()); - } - } - if (info.reward_maxhealth > 0) { destroyableComponent->SetMaxHealth(destroyableComponent->GetMaxHealth() + static_cast(info.reward_maxhealth), true); } diff --git a/dGame/dMission/Mission.h b/dGame/dMission/Mission.h index d8c104e84..74b8d3526 100644 --- a/dGame/dMission/Mission.h +++ b/dGame/dMission/Mission.h @@ -28,8 +28,8 @@ class Mission final Mission(MissionComponent* missionComponent, uint32_t missionId); ~Mission(); - void LoadFromXml(tinyxml2::XMLElement* element); - void UpdateXml(tinyxml2::XMLElement* element); + void LoadFromXml(const tinyxml2::XMLElement& element); + void UpdateXml(tinyxml2::XMLElement& element); /** * Returns the ID of this mission diff --git a/dGame/dMission/MissionTask.cpp b/dGame/dMission/MissionTask.cpp index 2fe9bc9fa..aa2b9bcae 100644 --- a/dGame/dMission/MissionTask.cpp +++ b/dGame/dMission/MissionTask.cpp @@ -186,7 +186,7 @@ void MissionTask::Progress(int32_t value, LWOOBJID associate, const std::string& if (count < 0) { if (mission->IsMission() && type == eMissionTaskType::GATHER && InAllTargets(value)) { - if (parameters.size() > 0 && (parameters[0] & 1) != 0) { + if (parameters.size() > 0 && (parameters[0] & 4) != 0) { return; } diff --git a/dGame/dPropertyBehaviors/CMakeLists.txt b/dGame/dPropertyBehaviors/CMakeLists.txt index 47c8ff23e..3e03ba1d1 100644 --- a/dGame/dPropertyBehaviors/CMakeLists.txt +++ b/dGame/dPropertyBehaviors/CMakeLists.txt @@ -12,5 +12,15 @@ foreach(file ${DGAME_DPROPERTYBEHAVIORS_CONTROLBEHAVIORMESSAGES}) set(DGAME_DPROPERTYBEHAVIORS_SOURCES ${DGAME_DPROPERTYBEHAVIORS_SOURCES} "ControlBehaviorMessages/${file}") endforeach() -add_library(dPropertyBehaviors STATIC ${DGAME_DPROPERTYBEHAVIORS_SOURCES}) +add_library(dPropertyBehaviors OBJECT ${DGAME_DPROPERTYBEHAVIORS_SOURCES}) +target_link_libraries(dPropertyBehaviors PRIVATE dDatabaseCDClient) +target_include_directories(dPropertyBehaviors PUBLIC "." "ControlBehaviorMessages" + PRIVATE + "${PROJECT_SOURCE_DIR}/dCommon/dClient" # ControlBehaviors.cpp uses AssetManager + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" # ObjectIdManager.h + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # GameMessages.h + "${PROJECT_SOURCE_DIR}/dGame/dComponents" # ModelComponent.h +) target_precompile_headers(dPropertyBehaviors REUSE_FROM dGameBase) + +target_link_libraries(dPropertyBehaviors INTERFACE dComponents) diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp index 63ec39e30..8906cac26 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp @@ -1,6 +1,8 @@ #include "Action.h" #include "Amf3.h" +#include "tinyxml2.h" + Action::Action(const AMFArrayValue& arguments) { for (const auto& [paramName, paramValue] : arguments.GetAssociative()) { if (paramName == "Type") { @@ -32,3 +34,46 @@ void Action::SendBehaviorBlocksToClient(AMFArrayValue& args) const { actionArgs->Insert(m_ValueParameterName, m_ValueParameterDouble); } } + +void Action::Serialize(tinyxml2::XMLElement& action) const { + action.SetAttribute("Type", m_Type.c_str()); + + if (m_ValueParameterName.empty()) return; + + action.SetAttribute("ValueParameterName", m_ValueParameterName.c_str()); + + if (m_ValueParameterName == "Message") { + action.SetAttribute("Value", m_ValueParameterString.c_str()); + } else { + action.SetAttribute("Value", m_ValueParameterDouble); + } +} + +void Action::Deserialize(const tinyxml2::XMLElement& action) { + const char* type = nullptr; + action.QueryAttribute("Type", &type); + if (!type) { + LOG("No type found for an action?"); + return; + } + + m_Type = type; + + const char* valueParameterName = nullptr; + action.QueryAttribute("ValueParameterName", &valueParameterName); + if (valueParameterName) { + m_ValueParameterName = valueParameterName; + + if (m_ValueParameterName == "Message") { + const char* value = nullptr; + action.QueryAttribute("Value", &value); + if (value) { + m_ValueParameterString = value; + } else { + LOG("No value found for an action message?"); + } + } else { + action.QueryDoubleAttribute("Value", &m_ValueParameterDouble); + } + } +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h index 36715e324..44b0ce765 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h @@ -3,6 +3,10 @@ #include +namespace tinyxml2 { + class XMLElement; +}; + class AMFArrayValue; /** @@ -20,6 +24,8 @@ class Action { void SendBehaviorBlocksToClient(AMFArrayValue& args) const; + void Serialize(tinyxml2::XMLElement& action) const; + void Deserialize(const tinyxml2::XMLElement& action); private: double m_ValueParameterDouble{ 0.0 }; std::string m_Type{ "" }; diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp index 249aafcb7..5a5592ac7 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp @@ -1,6 +1,7 @@ #include "StripUiPosition.h" #include "Amf3.h" +#include "tinyxml2.h" StripUiPosition::StripUiPosition(const AMFArrayValue& arguments, const std::string_view uiKeyName) { const auto* const uiArray = arguments.GetArray(uiKeyName); @@ -21,3 +22,13 @@ void StripUiPosition::SendBehaviorBlocksToClient(AMFArrayValue& args) const { uiArgs->Insert("x", m_XPosition); uiArgs->Insert("y", m_YPosition); } + +void StripUiPosition::Serialize(tinyxml2::XMLElement& position) const { + position.SetAttribute("x", m_XPosition); + position.SetAttribute("y", m_YPosition); +} + +void StripUiPosition::Deserialize(const tinyxml2::XMLElement& position) { + position.QueryDoubleAttribute("x", &m_XPosition); + position.QueryDoubleAttribute("y", &m_YPosition); +} diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h index 932d6d23e..eeeb67bbc 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h @@ -3,6 +3,10 @@ class AMFArrayValue; +namespace tinyxml2 { + class XMLElement; +} + /** * @brief The position of the first Action in a Strip * @@ -15,6 +19,8 @@ class StripUiPosition { [[nodiscard]] double GetX() const noexcept { return m_XPosition; } [[nodiscard]] double GetY() const noexcept { return m_YPosition; } + void Serialize(tinyxml2::XMLElement& position) const; + void Deserialize(const tinyxml2::XMLElement& position); private: double m_XPosition{ 0.0 }; double m_YPosition{ 0.0 }; diff --git a/dGame/dPropertyBehaviors/PropertyBehavior.cpp b/dGame/dPropertyBehaviors/PropertyBehavior.cpp index 423751c42..5bdb5827d 100644 --- a/dGame/dPropertyBehaviors/PropertyBehavior.cpp +++ b/dGame/dPropertyBehaviors/PropertyBehavior.cpp @@ -3,6 +3,7 @@ #include "Amf3.h" #include "BehaviorStates.h" #include "ControlBehaviorMsgs.h" +#include "tinyxml2.h" PropertyBehavior::PropertyBehavior() { m_LastEditedState = BehaviorState::HOME_STATE; @@ -124,3 +125,31 @@ void PropertyBehavior::SendBehaviorBlocksToClient(AMFArrayValue& args) const { // TODO Serialize the execution state of the behavior } + +void PropertyBehavior::Serialize(tinyxml2::XMLElement& behavior) const { + behavior.SetAttribute("id", m_BehaviorId); + behavior.SetAttribute("name", m_Name.c_str()); + behavior.SetAttribute("isLocked", isLocked); + behavior.SetAttribute("isLoot", isLoot); + + for (const auto& [stateId, state] : m_States) { + if (state.IsEmpty()) continue; + auto* const stateElement = behavior.InsertNewChildElement("State"); + stateElement->SetAttribute("id", static_cast(stateId)); + state.Serialize(*stateElement); + } +} + + +void PropertyBehavior::Deserialize(const tinyxml2::XMLElement& behavior) { + m_Name = behavior.Attribute("name"); + behavior.QueryBoolAttribute("isLocked", &isLocked); + behavior.QueryBoolAttribute("isLoot", &isLoot); + + for (const auto* stateElement = behavior.FirstChildElement("State"); stateElement; stateElement = stateElement->NextSiblingElement("State")) { + int32_t stateId = -1; + stateElement->QueryIntAttribute("id", &stateId); + if (stateId < 0 || stateId > 5) continue; + m_States[static_cast(stateId)].Deserialize(*stateElement); + } +} diff --git a/dGame/dPropertyBehaviors/PropertyBehavior.h b/dGame/dPropertyBehaviors/PropertyBehavior.h index c9cb4b987..01eb19680 100644 --- a/dGame/dPropertyBehaviors/PropertyBehavior.h +++ b/dGame/dPropertyBehaviors/PropertyBehavior.h @@ -3,6 +3,10 @@ #include "State.h" +namespace tinyxml2 { + class XMLElement; +} + enum class BehaviorState : uint32_t; class AMFArrayValue; @@ -25,6 +29,8 @@ class PropertyBehavior { [[nodiscard]] int32_t GetBehaviorId() const noexcept { return m_BehaviorId; } void SetBehaviorId(int32_t id) noexcept { m_BehaviorId = id; } + void Serialize(tinyxml2::XMLElement& behavior) const; + void Deserialize(const tinyxml2::XMLElement& behavior); private: // The states this behavior has. diff --git a/dGame/dPropertyBehaviors/State.cpp b/dGame/dPropertyBehaviors/State.cpp index 0c8a11d95..1fb072c1b 100644 --- a/dGame/dPropertyBehaviors/State.cpp +++ b/dGame/dPropertyBehaviors/State.cpp @@ -2,6 +2,7 @@ #include "Amf3.h" #include "ControlBehaviorMsgs.h" +#include "tinyxml2.h" template <> void State::HandleMsg(AddStripMessage& msg) { @@ -134,4 +135,20 @@ void State::SendBehaviorBlocksToClient(AMFArrayValue& args) const { strip.SendBehaviorBlocksToClient(*stripArgs); } -}; +} + +void State::Serialize(tinyxml2::XMLElement& state) const { + for (const auto& strip : m_Strips) { + if (strip.IsEmpty()) continue; + + auto* const stripElement = state.InsertNewChildElement("Strip"); + strip.Serialize(*stripElement); + } +} + +void State::Deserialize(const tinyxml2::XMLElement& state) { + for (const auto* stripElement = state.FirstChildElement("Strip"); stripElement; stripElement = stripElement->NextSiblingElement("Strip")) { + auto& strip = m_Strips.emplace_back(); + strip.Deserialize(*stripElement); + } +} diff --git a/dGame/dPropertyBehaviors/State.h b/dGame/dPropertyBehaviors/State.h index f04257635..3e8c827fc 100644 --- a/dGame/dPropertyBehaviors/State.h +++ b/dGame/dPropertyBehaviors/State.h @@ -3,6 +3,10 @@ #include "Strip.h" +namespace tinyxml2 { + class XMLElement; +} + class AMFArrayValue; class State { @@ -13,6 +17,8 @@ class State { void SendBehaviorBlocksToClient(AMFArrayValue& args) const; bool IsEmpty() const; + void Serialize(tinyxml2::XMLElement& state) const; + void Deserialize(const tinyxml2::XMLElement& state); private: std::vector m_Strips; }; diff --git a/dGame/dPropertyBehaviors/Strip.cpp b/dGame/dPropertyBehaviors/Strip.cpp index 0f459e469..d6dc050ba 100644 --- a/dGame/dPropertyBehaviors/Strip.cpp +++ b/dGame/dPropertyBehaviors/Strip.cpp @@ -2,6 +2,7 @@ #include "Amf3.h" #include "ControlBehaviorMsgs.h" +#include "tinyxml2.h" template <> void Strip::HandleMsg(AddStripMessage& msg) { @@ -83,4 +84,25 @@ void Strip::SendBehaviorBlocksToClient(AMFArrayValue& args) const { for (const auto& action : m_Actions) { action.SendBehaviorBlocksToClient(*actions); } -}; +} + +void Strip::Serialize(tinyxml2::XMLElement& strip) const { + auto* const positionElement = strip.InsertNewChildElement("Position"); + m_Position.Serialize(*positionElement); + for (const auto& action : m_Actions) { + auto* const actionElement = strip.InsertNewChildElement("Action"); + action.Serialize(*actionElement); + } +} + +void Strip::Deserialize(const tinyxml2::XMLElement& strip) { + const auto* positionElement = strip.FirstChildElement("Position"); + if (positionElement) { + m_Position.Deserialize(*positionElement); + } + + for (const auto* actionElement = strip.FirstChildElement("Action"); actionElement; actionElement = actionElement->NextSiblingElement("Action")) { + auto& action = m_Actions.emplace_back(); + action.Deserialize(*actionElement); + } +} diff --git a/dGame/dPropertyBehaviors/Strip.h b/dGame/dPropertyBehaviors/Strip.h index 107fee112..8fd7d0fe3 100644 --- a/dGame/dPropertyBehaviors/Strip.h +++ b/dGame/dPropertyBehaviors/Strip.h @@ -6,6 +6,10 @@ #include +namespace tinyxml2 { + class XMLElement; +} + class AMFArrayValue; class Strip { @@ -16,6 +20,8 @@ class Strip { void SendBehaviorBlocksToClient(AMFArrayValue& args) const; bool IsEmpty() const noexcept { return m_Actions.empty(); } + void Serialize(tinyxml2::XMLElement& strip) const; + void Deserialize(const tinyxml2::XMLElement& strip); private: std::vector m_Actions; StripUiPosition m_Position; diff --git a/dGame/dUtilities/BrickDatabase.cpp b/dGame/dUtilities/BrickDatabase.cpp index 7b447b848..61a7341de 100644 --- a/dGame/dUtilities/BrickDatabase.cpp +++ b/dGame/dUtilities/BrickDatabase.cpp @@ -29,15 +29,14 @@ const BrickList& BrickDatabase::GetBricks(const LxfmlPath& lxfmlPath) { return emptyCache; } - auto* doc = new tinyxml2::XMLDocument(); - if (doc->Parse(data.str().c_str(), data.str().size()) != 0) { - delete doc; + tinyxml2::XMLDocument doc; + if (doc.Parse(data.str().c_str(), data.str().size()) != 0) { return emptyCache; } BrickList parts; - auto* lxfml = doc->FirstChildElement("LXFML"); + auto* lxfml = doc.FirstChildElement("LXFML"); auto* bricks = lxfml->FirstChildElement("Bricks"); std::string searchTerm = "Brick"; @@ -86,7 +85,5 @@ const BrickList& BrickDatabase::GetBricks(const LxfmlPath& lxfmlPath) { m_Cache[lxfmlPath] = parts; - delete doc; - return m_Cache[lxfmlPath]; } diff --git a/dGame/dUtilities/CMakeLists.txt b/dGame/dUtilities/CMakeLists.txt index 055cc7061..2202fddc1 100644 --- a/dGame/dUtilities/CMakeLists.txt +++ b/dGame/dUtilities/CMakeLists.txt @@ -8,8 +8,24 @@ set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp" "SlashCommandHandler.cpp" "VanityUtilities.cpp") -add_library(dUtilities STATIC ${DGAME_DUTILITIES_SOURCES}) +add_subdirectory(SlashCommands) + +foreach(file ${DGAME_DUTILITIES_SLASHCOMMANDS}) + set(DGAME_DUTILITIES_SOURCES ${DGAME_DUTILITIES_SOURCES} "SlashCommands/${file}") +endforeach() + +add_library(dUtilities OBJECT ${DGAME_DUTILITIES_SOURCES}) target_precompile_headers(dUtilities REUSE_FROM dGameBase) +target_include_directories(dUtilities PUBLIC "." "SlashCommands" + PRIVATE + "${PROJECT_SOURCE_DIR}/dGame/dComponents" + "${PROJECT_SOURCE_DIR}/dGame/dInventory" # transitive via PossessableComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" + "${PROJECT_SOURCE_DIR}/dGame/dBehaviors" # transitive via InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dMission" # transitive via MissionComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # transitive via dZoneManager/Spawner.h + "${PROJECT_SOURCE_DIR}/dZoneManager" # Mail.cpp +) target_link_libraries(dUtilities PUBLIC dDatabase dPhysics INTERFACE dZoneManager) diff --git a/dGame/dUtilities/CheatDetection.cpp b/dGame/dUtilities/CheatDetection.cpp index a87157a18..504b3d538 100644 --- a/dGame/dUtilities/CheatDetection.cpp +++ b/dGame/dUtilities/CheatDetection.cpp @@ -130,12 +130,6 @@ bool CheatDetection::VerifyLwoobjidIsSender(const LWOOBJID& id, const SystemAddr // This will be true if the player does not possess the entity they are trying to send a packet as. // or if the user does not own the character they are trying to send a packet as. - if (invalidPacket) { - va_list args; - va_start(args, messageIfNotSender); - LogAndSaveFailedAntiCheatCheck(id, sysAddr, checkType, messageIfNotSender, args); - va_end(args); - } return !invalidPacket; } diff --git a/dGame/dUtilities/Loot.h b/dGame/dUtilities/Loot.h index dacd3dcdd..ac4d52332 100644 --- a/dGame/dUtilities/Loot.h +++ b/dGame/dUtilities/Loot.h @@ -1,6 +1,7 @@ #pragma once #include "dCommonVars.h" +#include "eLootSourceType.h" #include class Entity; diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index a610c3a77..e2ffbf79f 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -94,35 +94,6 @@ void Mail::SendMail(const LWOOBJID sender, const std::string& senderName, LWOOBJ SendNotification(sysAddr, 1); //Show the "one new mail" message } -//Because we need it: -std::string ReadWStringAsString(RakNet::BitStream& bitStream, uint32_t size) { - std::string toReturn = ""; - uint8_t buffer; - bool isFinishedReading = false; - - for (uint32_t i = 0; i < size; ++i) { - bitStream.Read(buffer); - if (!isFinishedReading) toReturn.push_back(buffer); - if (buffer == '\0') isFinishedReading = true; //so we don't continue to read garbage as part of the string. - bitStream.Read(buffer); //Read the null term - } - - return toReturn; -} - -void WriteStringAsWString(RakNet::BitStream& bitStream, std::string str, uint32_t size) { - uint32_t sizeToFill = size - str.size(); - - for (uint32_t i = 0; i < str.size(); ++i) { - bitStream.Write(str[i]); - bitStream.Write(uint8_t(0)); - } - - for (uint32_t i = 0; i < sizeToFill; ++i) { - bitStream.Write(uint16_t(0)); - } -} - void Mail::HandleMailStuff(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) { int mailStuffID = 0; packet.Read(mailStuffID); @@ -176,11 +147,20 @@ void Mail::HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAdd return; } - std::string subject = ReadWStringAsString(packet, 50); - std::string body = ReadWStringAsString(packet, 400); - std::string recipient = ReadWStringAsString(packet, 32); + LUWString subjectRead(50); + packet.Read(subjectRead); + + LUWString bodyRead(400); + packet.Read(bodyRead); + + LUWString recipientRead(32); + packet.Read(recipientRead); + + const std::string subject = subjectRead.GetAsString(); + const std::string body = bodyRead.GetAsString(); + //Cleanse recipient: - recipient = std::regex_replace(recipient, std::regex("[^0-9a-zA-Z]+"), ""); + const std::string recipient = std::regex_replace(recipientRead.GetAsString(), std::regex("[^0-9a-zA-Z]+"), ""); uint64_t unknown64 = 0; LWOOBJID attachmentID; @@ -265,42 +245,46 @@ void Mail::HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sys auto playerMail = Database::Get()->GetMailForPlayer(player->GetCharacter()->GetID(), 20); RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL); bitStream.Write(int(MailMessageID::MailData)); - bitStream.Write(int(0)); + bitStream.Write(int(0)); // throttled - bitStream.Write(playerMail.size()); + bitStream.Write(playerMail.size()); // size bitStream.Write(0); for (const auto& mail : playerMail) { bitStream.Write(mail.id); //MailID - WriteStringAsWString(bitStream, mail.subject.c_str(), 50); //subject - WriteStringAsWString(bitStream, mail.body.c_str(), 400); //body - WriteStringAsWString(bitStream, mail.senderUsername.c_str(), 32); //sender + const LUWString subject(mail.subject, 50); + bitStream.Write(subject); //subject + const LUWString body(mail.body, 400); + bitStream.Write(body); //body + const LUWString sender(mail.senderUsername, 32); + bitStream.Write(sender); //sender + bitStream.Write(uint32_t(0)); // packing - bitStream.Write(uint32_t(0)); - bitStream.Write(uint64_t(0)); + bitStream.Write(uint64_t(0)); // attachedCurrency bitStream.Write(mail.itemID); //Attachment ID LOT lot = mail.itemLOT; if (lot <= 0) bitStream.Write(LOT(-1)); else bitStream.Write(lot); - bitStream.Write(uint32_t(0)); + bitStream.Write(uint32_t(0)); // packing - bitStream.Write(mail.itemSubkey); //Attachment subKey - bitStream.Write(mail.itemCount); //Attachment count + bitStream.Write(mail.itemSubkey); // Attachment subKey - bitStream.Write(uint32_t(0)); - bitStream.Write(uint16_t(0)); + bitStream.Write(mail.itemCount); // Attachment count + bitStream.Write(uint8_t(0)); // subject type (used for auction) + bitStream.Write(uint8_t(0)); // packing + bitStream.Write(uint32_t(0)); // packing - bitStream.Write(mail.timeSent); //time sent (twice?) - bitStream.Write(mail.timeSent); + bitStream.Write(mail.timeSent); // expiration date + bitStream.Write(mail.timeSent);// send date bitStream.Write(mail.wasRead); //was read - bitStream.Write(uint8_t(0)); - bitStream.Write(uint16_t(0)); - bitStream.Write(uint32_t(0)); + bitStream.Write(uint8_t(0)); // isLocalized + bitStream.Write(uint16_t(0)); // packing + bitStream.Write(uint32_t(0)); // packing } Game::server->Send(bitStream, sysAddr, false); @@ -364,7 +348,7 @@ void Mail::HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t obje void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL); bitStream.Write(int(MailMessageID::SendResponse)); bitStream.Write(int(response)); Game::server->Send(bitStream, sysAddr, false); @@ -372,7 +356,7 @@ void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse respo void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL); uint64_t messageType = 2; uint64_t s1 = 0; uint64_t s2 = 0; @@ -391,7 +375,7 @@ void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) { void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL); bitStream.Write(int(MailMessageID::AttachmentCollectConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); @@ -400,7 +384,7 @@ void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t ma void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL); bitStream.Write(int(MailMessageID::MailDeleteConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); @@ -411,7 +395,7 @@ void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOO void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAIL); bitStream.Write(int(MailMessageID::MailReadConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); diff --git a/dGame/dUtilities/Preconditions.cpp b/dGame/dUtilities/Preconditions.cpp index bd855962c..a0aac27e7 100644 --- a/dGame/dUtilities/Preconditions.cpp +++ b/dGame/dUtilities/Preconditions.cpp @@ -26,17 +26,18 @@ Precondition::Precondition(const uint32_t condition) { if (result.eof()) { this->type = PreconditionType::ItemEquipped; this->count = 1; - this->values = { 0 }; + this->values.clear(); + this->values.push_back(0); LOG("Failed to find precondition of id (%i)!", condition); return; } - this->type = static_cast(result.fieldIsNull(0) ? 0 : result.getIntField(0)); + this->type = static_cast(result.fieldIsNull("type") ? 0 : result.getIntField("type")); - if (!result.fieldIsNull(1)) { - std::istringstream stream(result.getStringField(1)); + if (!result.fieldIsNull("targetLOT")) { + std::istringstream stream(result.getStringField("targetLOT")); std::string token; while (std::getline(stream, token, ',')) { @@ -45,7 +46,7 @@ Precondition::Precondition(const uint32_t condition) { } } - this->count = result.fieldIsNull(2) ? 1 : result.getIntField(2); + this->count = result.fieldIsNull("targetCount") ? 1 : result.getIntField("targetCount"); result.finalize(); } @@ -138,21 +139,20 @@ bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluat case PreconditionType::DoesNotHaveItem: return inventoryComponent->IsEquipped(value) < count; case PreconditionType::HasAchievement: - mission = missionComponent->GetMission(value); - - return mission == nullptr || mission->GetMissionState() >= eMissionState::COMPLETE; + if (missionComponent == nullptr) return false; + return missionComponent->GetMissionState(value) >= eMissionState::COMPLETE; case PreconditionType::MissionAvailable: - mission = missionComponent->GetMission(value); - - return mission == nullptr || mission->GetMissionState() >= eMissionState::AVAILABLE; + if (missionComponent == nullptr) return false; + return missionComponent->GetMissionState(value) == eMissionState::AVAILABLE || missionComponent->GetMissionState(value) == eMissionState::COMPLETE_AVAILABLE; case PreconditionType::OnMission: - mission = missionComponent->GetMission(value); - - return mission == nullptr || mission->GetMissionState() >= eMissionState::ACTIVE; + if (missionComponent == nullptr) return false; + return missionComponent->GetMissionState(value) == eMissionState::ACTIVE || + missionComponent->GetMissionState(value) == eMissionState::COMPLETE_ACTIVE || + missionComponent->GetMissionState(value) == eMissionState::READY_TO_COMPLETE || + missionComponent->GetMissionState(value) == eMissionState::COMPLETE_READY_TO_COMPLETE; case PreconditionType::MissionComplete: - mission = missionComponent->GetMission(value); - - return mission == nullptr ? false : mission->GetMissionState() >= eMissionState::COMPLETE; + if (missionComponent == nullptr) return false; + return missionComponent->GetMissionState(value) >= eMissionState::COMPLETE; case PreconditionType::PetDeployed: return false; // TODO case PreconditionType::HasFlag: diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index d06201218..c09668974 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -1,2070 +1,145 @@ /* * Darkflame Universe - * Copyright 2018 + * Copyright 2024 */ -#include "SlashCommandHandler.h" - -#include -#include -#include -#include -#include "dZoneManager.h" - -#include /* defines FILENAME_MAX */ -#ifdef _WIN32 -#include -#define GetCurrentDir _getcwd -#else -#include -#define GetCurrentDir getcwd -#endif - -#include "Metrics.hpp" - -#include "User.h" -#include "UserManager.h" -#include "BitStream.h" -#include "dCommonVars.h" -#include "GeneralUtils.h" -#include "Entity.h" -#include "EntityManager.h" -#include "Logger.h" -#include "WorldPackets.h" -#include "GameMessages.h" -#include "CDClientDatabase.h" -#include "ZoneInstanceManager.h" -#include "ControllablePhysicsComponent.h" -#include "NiPoint3.h" -#include "NiQuaternion.h" -#include "ChatPackets.h" -#include "InventoryComponent.h" -#include "Game.h" -#include "CharacterComponent.h" -#include "Database.h" -#include "DestroyableComponent.h" -#include "dServer.h" -#include "MissionComponent.h" -#include "Mail.h" -#include "dpWorld.h" -#include "Item.h" -#include "PropertyManagementComponent.h" -#include "BitStreamUtils.h" -#include "Loot.h" -#include "EntityInfo.h" -#include "LUTriggers.h" -#include "PhantomPhysicsComponent.h" -#include "ProximityMonitorComponent.h" -#include "dpShapeSphere.h" -#include "PossessableComponent.h" -#include "PossessorComponent.h" -#include "HavokVehiclePhysicsComponent.h" -#include "BuffComponent.h" -#include "SkillComponent.h" -#include "VanityUtilities.h" -#include "ScriptedActivityComponent.h" -#include "LevelProgressionComponent.h" -#include "AssetManager.h" -#include "BinaryPathFinder.h" -#include "dConfig.h" -#include "eBubbleType.h" -#include "Amf3.h" -#include "MovingPlatformComponent.h" -#include "eMissionState.h" -#include "TriggerComponent.h" -#include "eServerDisconnectIdentifiers.h" -#include "eObjectBits.h" -#include "eGameMasterLevel.h" -#include "eReplicaComponentType.h" -#include "RenderComponent.h" -#include "eControlScheme.h" -#include "eConnectionType.h" -#include "eChatInternalMessageType.h" -#include "eMasterMessageType.h" -#include "PlayerManager.h" - -#include "CDRewardCodesTable.h" -#include "CDObjectsTable.h" -#include "CDZoneTableTable.h" -#include "ePlayerFlag.h" -#include "dNavMesh.h" - -void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) { - auto commandCopy = command; - // Sanity check that a command was given - if (command.empty() || command.front() != u'/') return; - commandCopy.erase(commandCopy.begin()); - - // Split the command by spaces - std::string chatCommand; - std::vector args; - auto wideCommand = GeneralUtils::SplitString(commandCopy, u' '); - if (wideCommand.empty()) return; - - // Convert the command to lowercase - chatCommand = GeneralUtils::UTF16ToWTF8(wideCommand.front()); - std::transform(chatCommand.begin(), chatCommand.end(), chatCommand.begin(), ::tolower); - wideCommand.erase(wideCommand.begin()); - - // Convert the arguements to not u16strings - for (auto wideArg : wideCommand) args.push_back(GeneralUtils::UTF16ToWTF8(wideArg)); - - User* user = UserManager::Instance()->GetUser(sysAddr); - if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > eGameMasterLevel::CIVILIAN) { - if (args.size() != 1) return; - - const auto level_intermed = GeneralUtils::TryParse(args[0]); - - if (!level_intermed) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid gm level."); - return; - } - eGameMasterLevel level = static_cast(level_intermed.value()); - -#ifndef DEVELOPER_SERVER - if (user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER) { - level = eGameMasterLevel::CIVILIAN; - } -#endif - - if (level > user->GetMaxGMLevel()) { - level = user->GetMaxGMLevel(); - } - - if (level == entity->GetGMLevel()) return; - bool success = user->GetMaxGMLevel() >= level; - - if (success) { - - if (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && level == eGameMasterLevel::CIVILIAN) { - GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); - } else if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN && level > eGameMasterLevel::CIVILIAN) { - GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); - } - - WorldPackets::SendGMLevelChange(sysAddr, success, user->GetMaxGMLevel(), entity->GetGMLevel(), level); - GameMessages::SendChatModeUpdate(entity->GetObjectID(), level); - entity->SetGMLevel(level); - LOG("User %s (%i) has changed their GM level to %i for charID %llu", user->GetUsername().c_str(), user->GetAccountID(), level, entity->GetObjectID()); - } - } - -#ifndef DEVELOPER_SERVER - if ((entity->GetGMLevel() > user->GetMaxGMLevel()) || (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER)) { - WorldPackets::SendGMLevelChange(sysAddr, true, user->GetMaxGMLevel(), entity->GetGMLevel(), eGameMasterLevel::CIVILIAN); - GameMessages::SendChatModeUpdate(entity->GetObjectID(), eGameMasterLevel::CIVILIAN); - entity->SetGMLevel(eGameMasterLevel::CIVILIAN); - - GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); - - ChatPackets::SendSystemMessage(sysAddr, u"Your game master level has been changed, you may not be able to use all commands."); - } -#endif - - if (chatCommand == "togglenameplate" && (Game::config->GetValue("allow_nameplate_off") == "1" || entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER)) { - auto* character = entity->GetCharacter(); - - if (character && character->GetBillboardVisible()) { - character->SetBillboardVisible(false); - ChatPackets::SendSystemMessage(sysAddr, u"Your nameplate has been turned off and is not visible to players currently in this zone."); - } else { - character->SetBillboardVisible(true); - ChatPackets::SendSystemMessage(sysAddr, u"Your nameplate is now on and visible to all players."); - } - return; - } - - if (chatCommand == "toggleskipcinematics" && (Game::config->GetValue("allow_players_to_skip_cinematics") == "1" || entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER)) { - auto* character = entity->GetCharacter(); - if (!character) return; - bool current = character->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS); - character->SetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS, !current); - if (!current) { - ChatPackets::SendSystemMessage(sysAddr, u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now."); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Cinematics will no longer be skipped."); - } - - return; - } - - - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - //HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE! - //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - if (chatCommand == "pvp") { - auto* character = entity->GetComponent(); - - if (character == nullptr) { - LOG("Failed to find character component!"); - return; - } - - character->SetPvpEnabled(!character->GetPvpEnabled()); - Game::entityManager->SerializeEntity(entity); - - std::stringstream message; - message << character->GetName() << " changed their PVP flag to " << std::to_string(character->GetPvpEnabled()) << "!"; - - ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, GeneralUtils::UTF8ToUTF16(message.str()), true); - - return; - } - - if (chatCommand == "who") { - ChatPackets::SendSystemMessage( - sysAddr, - u"Players in this instance: (" + GeneralUtils::to_u16string(PlayerManager::GetAllPlayers().size()) + u")" - ); - - for (auto* player : PlayerManager::GetAllPlayers()) { - const auto& name = player->GetCharacter()->GetName(); - - ChatPackets::SendSystemMessage( - sysAddr, - GeneralUtils::UTF8ToUTF16(player == entity ? name + " (you)" : name) - ); - } - } - - if (chatCommand == "ping") { - if (!args.empty() && args[0] == "-l") { - std::stringstream message; - message << "Your latest ping: " << std::to_string(Game::server->GetLatestPing(sysAddr)) << "ms"; - - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); - } else { - std::stringstream message; - message << "Your average ping: " << std::to_string(Game::server->GetPing(sysAddr)) << "ms"; - - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); - } - return; - } - - if (chatCommand == "fix-stats") { - // Reset skill component and buff component - auto* skillComponent = entity->GetComponent(); - auto* buffComponent = entity->GetComponent(); - auto* destroyableComponent = entity->GetComponent(); - - // If any of the components are nullptr, return - if (skillComponent == nullptr || buffComponent == nullptr || destroyableComponent == nullptr) { - return; - } - - // Reset skill component - skillComponent->Reset(); - - // Reset buff component - buffComponent->Reset(); - - // Fix the destroyable component - destroyableComponent->FixStats(); - } - - if (chatCommand == "credits" || chatCommand == "info") { - const auto& customText = chatCommand == "credits" ? VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/CREDITS.md").string()) : VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/INFO.md").string()); - - { - AMFArrayValue args; - - args.Insert("state", "Story"); - - GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); - } - - entity->AddCallbackTimer(0.5f, [customText, entity]() { - AMFArrayValue args; - - args.Insert("visible", true); - args.Insert("text", customText); - - LOG("Sending %s", customText.c_str()); - - GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", args); - }); - - return; - } - - if (chatCommand == "leave-zone" || chatCommand == "leavezone") { - const auto currentZone = Game::zoneManager->GetZone()->GetZoneID().GetMapID(); - LWOMAPID newZone = 0; - - if (currentZone == 1001 || currentZone % 100 == 0) { - ChatPackets::SendSystemMessage(sysAddr, u"You are not in an instanced zone."); - return; - } else { - newZone = (currentZone / 100) * 100; - } - // If new zone would be inaccessible, then default to Avant Gardens. - if (!Game::zoneManager->CheckIfAccessibleZone(newZone)) newZone = 1100; - - ChatPackets::SendSystemMessage(sysAddr, u"Leaving zone..."); - - const auto objid = entity->GetObjectID(); - - ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, newZone, 0, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - auto* entity = Game::entityManager->GetEntity(objid); - - if (entity == nullptr) { - return; - } - - const auto sysAddr = entity->GetSystemAddress(); - - LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", entity->GetCharacter()->GetName().c_str(), 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->GetCharacter()->SaveXMLToDatabase(); - - WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); - }); - } - - if (chatCommand == "join" && !args.empty()) { - ChatPackets::SendSystemMessage(sysAddr, u"Requesting private map..."); - const auto& password = args[0]; - - ZoneInstanceManager::Instance()->RequestPrivateZone(Game::server, false, password, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - LOG("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->GetCharacter()->SaveXMLToDatabase(); - - WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); - }); - } - - if (user->GetMaxGMLevel() == eGameMasterLevel::CIVILIAN || entity->GetGMLevel() >= eGameMasterLevel::CIVILIAN) { - if (chatCommand == "die") { - entity->Smash(entity->GetObjectID()); - } - - if (chatCommand == "resurrect") { - ScriptedActivityComponent* scriptedActivityComponent = Game::zoneManager->GetZoneControlObject()->GetComponent(); - - if (scriptedActivityComponent) { // check if user is in activity world and if so, they can't resurrect - ChatPackets::SendSystemMessage(sysAddr, u"You cannot resurrect in an activity world."); - return; - } - - GameMessages::SendResurrect(entity); - } - - if (chatCommand == "requestmailcount") { - Mail::HandleNotificationRequest(entity->GetSystemAddress(), entity->GetObjectID()); - } - - if (chatCommand == "instanceinfo") { - const auto zoneId = Game::zoneManager->GetZone()->GetZoneID(); - - ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID()))); - } - - if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) return; - } - - if (chatCommand == "resetmission" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto missionId = GeneralUtils::TryParse(args[0]); - if (!missionId) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission ID."); - return; - } - - auto* missionComponent = entity->GetComponent(); - if (!missionComponent) return; - missionComponent->ResetMission(missionId.value()); - } - - // Log command to database - Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), chatCommand); - - if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { // could break characters so only allow if GM > 0 - const auto minifigItemIdExists = GeneralUtils::TryParse(args[1]); - if (!minifigItemIdExists) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig Item Id ID."); - return; - } - const int32_t minifigItemId = minifigItemIdExists.value(); - Game::entityManager->DestructEntity(entity, sysAddr); - auto* charComp = entity->GetComponent(); - std::string lowerName = args[0]; - if (lowerName.empty()) return; - std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); - if (lowerName == "eyebrows") { - charComp->m_Character->SetEyebrows(minifigItemId); - } else if (lowerName == "eyes") { - charComp->m_Character->SetEyes(minifigItemId); - } else if (lowerName == "haircolor") { - charComp->m_Character->SetHairColor(minifigItemId); - } else if (lowerName == "hairstyle") { - charComp->m_Character->SetHairStyle(minifigItemId); - } else if (lowerName == "pants") { - charComp->m_Character->SetPantsColor(minifigItemId); - } else if (lowerName == "lefthand") { - charComp->m_Character->SetLeftHand(minifigItemId); - } else if (lowerName == "mouth") { - charComp->m_Character->SetMouth(minifigItemId); - } else if (lowerName == "righthand") { - charComp->m_Character->SetRightHand(minifigItemId); - } else if (lowerName == "shirtcolor") { - charComp->m_Character->SetShirtColor(minifigItemId); - } else if (lowerName == "hands") { - charComp->m_Character->SetLeftHand(minifigItemId); - charComp->m_Character->SetRightHand(minifigItemId); - } else { - Game::entityManager->ConstructEntity(entity); - ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig item to change, try one of the following: Eyebrows, Eyes, HairColor, HairStyle, Pants, LeftHand, Mouth, RightHand, Shirt, Hands"); - return; - } - - Game::entityManager->ConstructEntity(entity); - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(lowerName) + u" set to " + (GeneralUtils::to_u16string(minifigItemId))); - - GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); // need to retoggle because it gets reenabled on creation of new character - } - - if ((chatCommand == "playanimation" || chatCommand == "playanim") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - std::u16string anim = GeneralUtils::ASCIIToUTF16(args[0], args[0].size()); - RenderComponent::PlayAnimation(entity, anim); - auto* possessorComponent = entity->GetComponent(); - if (possessorComponent) { - auto* possessedComponent = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); - if (possessedComponent) RenderComponent::PlayAnimation(possessedComponent, anim); - } - } - - if (chatCommand == "list-spawns" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - for (const auto& pair : Game::entityManager->GetSpawnPointEntities()) { - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(pair.first)); - } - - ChatPackets::SendSystemMessage(sysAddr, u"Current: " + GeneralUtils::ASCIIToUTF16(entity->GetCharacter()->GetTargetScene())); - - return; - } - - if (chatCommand == "unlock-emote" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto emoteID = GeneralUtils::TryParse(args.at(0)); - - if (!emoteID) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid emote ID."); - return; - } - - entity->GetCharacter()->UnlockEmote(emoteID.value()); - } - - if (chatCommand == "force-save" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - entity->GetCharacter()->SaveXMLToDatabase(); - } - - if (chatCommand == "kill" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - ChatPackets::SendSystemMessage(sysAddr, u"Brutally murdering that player, if online on this server."); - - auto* player = PlayerManager::GetPlayer(args[0]); - if (player) { - player->Smash(entity->GetObjectID()); - ChatPackets::SendSystemMessage(sysAddr, u"It has been done, do you feel good about yourself now?"); - return; - } - - ChatPackets::SendSystemMessage(sysAddr, u"They were saved from your carnage."); - return; - } - - if (chatCommand == "speedboost" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto boostOptional = GeneralUtils::TryParse(args[0]); - if (!boostOptional) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost."); - return; - } - const float boost = boostOptional.value(); - - auto* controllablePhysicsComponent = entity->GetComponent(); - - if (!controllablePhysicsComponent) return; - controllablePhysicsComponent->SetSpeedMultiplier(boost); - - // speedboost possessables - auto possessor = entity->GetComponent(); - if (possessor) { - auto possessedID = possessor->GetPossessable(); - if (possessedID != LWOOBJID_EMPTY) { - auto possessable = Game::entityManager->GetEntity(possessedID); - if (possessable) { - auto* possessControllablePhysicsComponent = possessable->GetComponent(); - if (possessControllablePhysicsComponent) { - possessControllablePhysicsComponent->SetSpeedMultiplier(boost); - } - } - } - } - - Game::entityManager->SerializeEntity(entity); - } - - if (chatCommand == "freecam" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto state = !entity->GetVar(u"freecam"); - entity->SetVar(u"freecam", state); - - GameMessages::SendSetPlayerControlScheme(entity, static_cast(state ? 9 : 1)); - - ChatPackets::SendSystemMessage(sysAddr, u"Toggled freecam."); - return; - } - - if (chatCommand == "setcontrolscheme" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto scheme = GeneralUtils::TryParse(args[0]); - - if (!scheme) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid control scheme."); - return; - } - - GameMessages::SendSetPlayerControlScheme(entity, static_cast(scheme.value())); - - ChatPackets::SendSystemMessage(sysAddr, u"Switched control scheme."); - return; - } - - if (chatCommand == "approveproperty" && entity->GetGMLevel() >= eGameMasterLevel::LEAD_MODERATOR) { - - if (PropertyManagementComponent::Instance() != nullptr) { - PropertyManagementComponent::Instance()->UpdateApprovedStatus(true); - } - - return; - } - - if (chatCommand == "setuistate" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - AMFArrayValue uiState; - - uiState.Insert("state", args.at(0)); - - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "pushGameState", uiState); - - ChatPackets::SendSystemMessage(sysAddr, u"Switched UI state."); - - return; - } - - if (chatCommand == "toggle" && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - AMFArrayValue amfArgs; - - amfArgs.Insert("visible", true); - - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, args[0], amfArgs); - - ChatPackets::SendSystemMessage(sysAddr, u"Toggled UI state."); - - return; - } - - if ((chatCommand == "setinventorysize" || chatCommand == "setinvsize") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - const auto sizeOptional = GeneralUtils::TryParse(args[0]); - if (!sizeOptional) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid size."); - return; - } - const uint32_t size = sizeOptional.value(); - - eInventoryType selectedInventory = eInventoryType::ITEMS; - - // a possible inventory was provided if we got more than 1 argument - if (args.size() >= 2) { - selectedInventory = GeneralUtils::TryParse(args.at(1)).value_or(eInventoryType::INVALID); - if (selectedInventory == eInventoryType::INVALID) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory."); - return; - } else { - // In this case, we treat the input as a string and try to find it in the reflection list - std::transform(args.at(1).begin(), args.at(1).end(), args.at(1).begin(), ::toupper); - for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { - if (std::string_view(args.at(1)) == std::string_view(InventoryType::InventoryTypeToString(static_cast(index)))) selectedInventory = static_cast(index); - } - } - - ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory " + - GeneralUtils::ASCIIToUTF16(args.at(1)) + - u" to size " + - GeneralUtils::to_u16string(size)); - } else ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory ITEMS to size " + GeneralUtils::to_u16string(size)); - - auto* inventoryComponent = entity->GetComponent(); - if (inventoryComponent) { - auto* inventory = inventoryComponent->GetInventory(selectedInventory); - - inventory->SetSize(size); - } - - return; - } - - if (chatCommand == "runmacro" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - if (args.size() != 1) return; - - // Only process if input does not contain separator charaters - if (args[0].find("/") != std::string::npos) return; - if (args[0].find("\\") != std::string::npos) return; - - auto infile = Game::assetManager->GetFile(("macros/" + args[0] + ".scm").c_str()); - - if (!infile) { - ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); - return; - } - - if (infile.good()) { - std::string line; - while (std::getline(infile, line)) { - // Do this in two separate calls to catch both \n and \r\n - line.erase(std::remove(line.begin(), line.end(), '\n'), line.end()); - line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); - SlashCommandHandler::HandleChatCommand(GeneralUtils::ASCIIToUTF16(line), entity, sysAddr); - } - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); - } - - return; - } - - if (chatCommand == "addmission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - if (args.size() == 0) return; - - const auto missionID = GeneralUtils::TryParse(args.at(0)); - - if (!missionID) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); - return; - } - - auto comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); - if (comp) comp->AcceptMission(missionID.value(), true); - return; - } - - if (chatCommand == "completemission" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - if (args.size() == 0) return; - - const auto missionID = GeneralUtils::TryParse(args.at(0)); - - if (!missionID) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); - return; - } - - auto comp = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); - if (comp) comp->CompleteMission(missionID.value(), true); - return; - } - - if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { - const auto flagId = GeneralUtils::TryParse(args.at(0)); - - if (!flagId) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); - return; - } - - entity->GetCharacter()->SetPlayerFlag(flagId.value(), true); - } - - if (chatCommand == "setflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 2) { - const auto flagId = GeneralUtils::TryParse(args.at(1)); - std::string onOffFlag = args.at(0); - if (!flagId) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); - return; - } - if (onOffFlag != "off" && onOffFlag != "on") { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag type."); - return; - } - entity->GetCharacter()->SetPlayerFlag(flagId.value(), onOffFlag == "on"); - } - if (chatCommand == "clearflag" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { - const auto flagId = GeneralUtils::TryParse(args.at(0)); - - if (!flagId) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); - return; - } - - entity->GetCharacter()->SetPlayerFlag(flagId.value(), false); - } - - if (chatCommand == "playeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { - const auto effectID = GeneralUtils::TryParse(args.at(0)); - - if (!effectID) return; - - // FIXME: use fallible ASCIIToUTF16 conversion, because non-ascii isn't valid anyway - GameMessages::SendPlayFXEffect(entity->GetObjectID(), effectID.value(), GeneralUtils::ASCIIToUTF16(args.at(1)), args.at(2)); - } - - if (chatCommand == "stopeffect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - GameMessages::SendStopFXEffect(entity, true, args[0]); - } - - if (chatCommand == "setanntitle" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - if (args.size() < 0) return; - - std::stringstream ss; - for (auto string : args) - ss << string << " "; - - entity->GetCharacter()->SetAnnouncementTitle(ss.str()); - return; - } - - if (chatCommand == "setannmsg" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - if (args.size() < 0) return; - - std::stringstream ss; - for (auto string : args) - ss << string << " "; - - entity->GetCharacter()->SetAnnouncementMessage(ss.str()); - return; - } - - if (chatCommand == "announce" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - if (entity->GetCharacter()->GetAnnouncementTitle().size() == 0 || entity->GetCharacter()->GetAnnouncementMessage().size() == 0) { - ChatPackets::SendSystemMessage(sysAddr, u"Use /setanntitle & /setannmsg <msg> first!"); - return; - } - - SendAnnouncement(entity->GetCharacter()->GetAnnouncementTitle(), entity->GetCharacter()->GetAnnouncementMessage()); - return; - } - - if (chatCommand == "shutdownuniverse" && entity->GetGMLevel() == eGameMasterLevel::OPERATOR) { - //Tell the master server that we're going to be shutting down whole "universe": - CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN_UNIVERSE); - Game::server->SendToMaster(bitStream); - ChatPackets::SendSystemMessage(sysAddr, u"Sent universe shutdown notification to master."); - - //Tell chat to send an announcement to all servers - SendAnnouncement("Servers Closing Soon!", "DLU servers will close for maintenance in 10 minutes from now."); - return; - } - - if (chatCommand == "getnavmeshheight" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); - if (!control) return; - - float y = dpWorld::GetNavMesh()->GetHeightAtPoint(control->GetPosition()); - std::u16string msg = u"Navmesh height: " + (GeneralUtils::to_u16string(y)); - ChatPackets::SendSystemMessage(sysAddr, msg); - } - - if (chatCommand == "gmadditem" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - if (args.size() == 1) { - const auto itemLOT = GeneralUtils::TryParse<uint32_t>(args.at(0)); - - if (!itemLOT) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); - return; - } - - InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); - - inventory->AddItem(itemLOT.value(), 1, eLootSourceType::MODERATION); - } else if (args.size() == 2) { - const auto itemLOT = GeneralUtils::TryParse<uint32_t>(args.at(0)); - if (!itemLOT) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); - return; - } - - const auto count = GeneralUtils::TryParse<uint32_t>(args.at(1)); - if (!count) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid item count."); - return; - } - - InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); - - inventory->AddItem(itemLOT.value(), count.value(), eLootSourceType::MODERATION); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /gmadditem <lot>"); - } - } - - if (chatCommand == "mailitem" && entity->GetGMLevel() >= eGameMasterLevel::MODERATOR && args.size() >= 2) { - const auto& playerName = args[0]; - - auto playerInfo = Database::Get()->GetCharacterInfo(playerName); - - uint32_t receiverID = 0; - if (!playerInfo) { - ChatPackets::SendSystemMessage(sysAddr, u"Failed to find that player"); - - return; - } - - receiverID = playerInfo->id; - - const auto lot = GeneralUtils::TryParse<LOT>(args.at(1)); - - if (!lot) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid item lot."); - return; - } - - IMail::MailInfo mailInsert; - mailInsert.senderId = entity->GetObjectID(); - mailInsert.senderUsername = "Darkflame Universe"; - mailInsert.receiverId = receiverID; - mailInsert.recipient = playerName; - mailInsert.subject = "Lost item"; - mailInsert.body = "This is a replacement item for one you lost."; - mailInsert.itemID = LWOOBJID_EMPTY; - mailInsert.itemLOT = lot.value(); - mailInsert.itemSubkey = LWOOBJID_EMPTY; - mailInsert.itemCount = 1; - Database::Get()->InsertNewMail(mailInsert); - - ChatPackets::SendSystemMessage(sysAddr, u"Mail sent"); - - return; - } - - if (chatCommand == "setname" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - std::string name = ""; - - for (const auto& arg : args) { - name += arg + " "; - } - - GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); - } - - if (chatCommand == "title" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - std::string name = entity->GetCharacter()->GetName() + " - "; - - for (const auto& arg : args) { - name += arg + " "; - } - - GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); - } - - if ((chatCommand == "teleport" || chatCommand == "tele") && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { - NiPoint3 pos{}; - if (args.size() == 3) { - - const auto x = GeneralUtils::TryParse<float>(args.at(0)); - if (!x) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); - return; - } - - const auto y = GeneralUtils::TryParse<float>(args.at(1)); - if (!y) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid y."); - return; - } - - const auto z = GeneralUtils::TryParse<float>(args.at(2)); - if (!z) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); - return; - } - - pos.SetX(x.value()); - pos.SetY(y.value()); - pos.SetZ(z.value()); - - LOG("Teleporting objectID: %llu to %f, %f, %f", entity->GetObjectID(), pos.x, pos.y, pos.z); - GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); - } else if (args.size() == 2) { - - const auto x = GeneralUtils::TryParse<float>(args.at(0)); - if (!x) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); - return; - } - - const auto z = GeneralUtils::TryParse<float>(args.at(1)); - if (!z) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); - return; - } - - pos.SetX(x.value()); - pos.SetY(0.0f); - pos.SetZ(z.value()); - - LOG("Teleporting objectID: %llu to X: %f, Z: %f", entity->GetObjectID(), pos.x, pos.z); - GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport <x> (<y>) <z> - if no Y given, will teleport to the height of the terrain (or any physics object)."); - } - - - auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - if (possessorComponent) { - auto* possassableEntity = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); - - if (possassableEntity != nullptr) { - auto* havokVehiclePhysicsComponent = possassableEntity->GetComponent<HavokVehiclePhysicsComponent>(); - if (havokVehiclePhysicsComponent) { - havokVehiclePhysicsComponent->SetPosition(pos); - Game::entityManager->SerializeEntity(possassableEntity); - } else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, NiQuaternion(), sysAddr); - } - } - } - - if (chatCommand == "tpall" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto pos = entity->GetPosition(); - - const auto characters = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); - - for (auto* character : characters) { - GameMessages::SendTeleport(character->GetObjectID(), pos, NiQuaternion(), character->GetSystemAddress()); - } - - return; - } - - if (chatCommand == "dismount" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - if (possessorComponent) { - auto possessableId = possessorComponent->GetPossessable(); - if (possessableId != LWOOBJID_EMPTY) { - auto* possessableEntity = Game::entityManager->GetEntity(possessableId); - if (possessableEntity) possessorComponent->Dismount(possessableEntity, true); - } - } - } - - if (chatCommand == "fly" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { - auto* character = entity->GetCharacter(); - - if (character) { - bool isFlying = character->GetIsFlying(); - - if (isFlying) { - GameMessages::SendSetJetPackMode(entity, false); - - character->SetIsFlying(false); - } else { - float speedScale = 1.0f; - - if (args.size() >= 1) { - const auto tempScaleStore = GeneralUtils::TryParse<float>(args.at(0)); - - if (tempScaleStore) { - speedScale = tempScaleStore.value(); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Failed to parse speed scale argument."); - } - } - - float airSpeed = 20 * speedScale; - float maxAirSpeed = 30 * speedScale; - float verticalVelocity = 1.5 * speedScale; - - GameMessages::SendSetJetPackMode(entity, true, true, false, 167, airSpeed, maxAirSpeed, verticalVelocity); - - character->SetIsFlying(true); - } - } - } - - //------- GM COMMANDS TO ACTUALLY MODERATE -------- - - if (chatCommand == "mute" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { - if (args.size() >= 1) { - auto* player = PlayerManager::GetPlayer(args[0]); - - uint32_t accountId = 0; - LWOOBJID characterId = 0; - - if (player == nullptr) { - auto characterInfo = Database::Get()->GetCharacterInfo(args[0]); - - if (characterInfo) { - accountId = characterInfo->accountId; - characterId = characterInfo->id; - - GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER); - GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT); - } - - if (accountId == 0) { - ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0])); - - return; - } - } else { - auto* character = player->GetCharacter(); - auto* user = character != nullptr ? character->GetParentUser() : nullptr; - if (user) accountId = user->GetAccountID(); - characterId = player->GetObjectID(); - } - - time_t expire = 1; // Default to indefinate mute - - if (args.size() >= 2) { - const auto days = GeneralUtils::TryParse<uint32_t>(args[1]); - if (!days) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid days."); - - return; - } - - std::optional<uint32_t> hours; - if (args.size() >= 3) { - hours = GeneralUtils::TryParse<uint32_t>(args[2]); - if (!hours) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid hours."); - - return; - } - } - - expire = time(NULL); - expire += 24 * 60 * 60 * days.value(); - expire += 60 * 60 * hours.value_or(0); - } - - if (accountId != 0) Database::Get()->UpdateAccountUnmuteTime(accountId, expire); - - char buffer[32] = "brought up for review.\0"; - - if (expire != 1) { - std::tm* ptm = std::localtime(&expire); - // Format: Mo, 15.06.2009 20:20:00 - std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm); - } - - const auto timeStr = GeneralUtils::ASCIIToUTF16(std::string(buffer)); - - ChatPackets::SendSystemMessage(sysAddr, u"Muted: " + GeneralUtils::UTF8ToUTF16(args[0]) + u" until " + timeStr); - - //Notify chat about it - CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE); - - bitStream.Write(characterId); - bitStream.Write(expire); - - Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /mute <username> <days (optional)> <hours (optional)>"); - } - } - - if (chatCommand == "kick" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_MODERATOR) { - if (args.size() == 1) { - auto* player = PlayerManager::GetPlayer(args[0]); - - std::u16string username = GeneralUtils::UTF8ToUTF16(args[0]); - if (player == nullptr) { - ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + username); - return; - } - - Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); - - ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /kick <username>"); - } - } - - if (chatCommand == "ban" && entity->GetGMLevel() >= eGameMasterLevel::SENIOR_MODERATOR) { - if (args.size() == 1) { - auto* player = PlayerManager::GetPlayer(args[0]); - - uint32_t accountId = 0; - - if (player == nullptr) { - auto characterInfo = Database::Get()->GetCharacterInfo(args[0]); - - if (characterInfo) { - accountId = characterInfo->accountId; - } - - if (accountId == 0) { - ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(args[0])); - - return; - } - } else { - auto* character = player->GetCharacter(); - auto* user = character != nullptr ? character->GetParentUser() : nullptr; - if (user) accountId = user->GetAccountID(); - } - - if (accountId != 0) Database::Get()->UpdateAccountBan(accountId, true); - - if (player != nullptr) { - Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); - } - - ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(args[0])); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /ban <username>"); - } - } - - //------------------------------------------------- - - if (chatCommand == "buffme" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - if (dest) { - dest->SetHealth(999); - dest->SetMaxHealth(999.0f); - dest->SetArmor(999); - dest->SetMaxArmor(999.0f); - dest->SetImagination(999); - dest->SetMaxImagination(999.0f); - } - Game::entityManager->SerializeEntity(entity); - } - - if (chatCommand == "startcelebration" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { - const auto celebration = GeneralUtils::TryParse<int32_t>(args.at(0)); - - if (!celebration) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid celebration."); - return; - } - - GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration.value()); - } - - if (chatCommand == "buffmed" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - if (dest) { - dest->SetHealth(9); - dest->SetMaxHealth(9.0f); - dest->SetArmor(9); - dest->SetMaxArmor(9.0f); - dest->SetImagination(9); - dest->SetMaxImagination(9.0f); - } - Game::entityManager->SerializeEntity(entity); - } - - if (chatCommand == "refillstats" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - - auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); - if (dest) { - dest->SetHealth(static_cast<int32_t>(dest->GetMaxHealth())); - dest->SetArmor(static_cast<int32_t>(dest->GetMaxArmor())); - dest->SetImagination(static_cast<int32_t>(dest->GetMaxImagination())); - } - - Game::entityManager->SerializeEntity(entity); - } - - if (chatCommand == "lookup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - auto query = CDClientDatabase::CreatePreppedStmt( - "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE ?1 OR `name` LIKE ?1 OR `description` LIKE ?1 LIMIT 50"); - // Concatenate all of the arguments into a single query so a multi word query can be used properly. - std::string conditional = args[0]; - args.erase(args.begin()); - for (auto& argument : args) { - conditional += ' ' + argument; - } - - const std::string query_text = "%" + conditional + "%"; - query.bind(1, query_text.c_str()); - - auto tables = query.execQuery(); - - while (!tables.eof()) { - std::string message = std::to_string(tables.getIntField(0)) + " - " + tables.getStringField(1); - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(message, message.size())); - tables.nextRow(); - } - } - - if (chatCommand == "spawn" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); - if (!comp) return; - - const auto lot = GeneralUtils::TryParse<uint32_t>(args[0]); - - if (!lot) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); - return; - } - - EntityInfo info; - info.lot = lot.value(); - info.pos = comp->GetPosition(); - info.rot = comp->GetRotation(); - info.spawner = nullptr; - info.spawnerID = entity->GetObjectID(); - info.spawnerNodeID = 0; - - Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr); - - if (newEntity == nullptr) { - ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); - return; - } - - Game::entityManager->ConstructEntity(newEntity); - } - - if (chatCommand == "spawngroup" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { - auto controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); - if (!controllablePhysicsComponent) return; - - const auto lot = GeneralUtils::TryParse<LOT>(args[0]); - if (!lot) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); - return; - } - - const auto numberToSpawnOptional = GeneralUtils::TryParse<uint32_t>(args[1]); - if (!numberToSpawnOptional && numberToSpawnOptional.value() > 0) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid number of enemies to spawn."); - return; - } - uint32_t numberToSpawn = numberToSpawnOptional.value(); - - // Must spawn within a radius of at least 0.0f - const auto radiusToSpawnWithinOptional = GeneralUtils::TryParse<float>(args[2]); - if (!radiusToSpawnWithinOptional && radiusToSpawnWithinOptional.value() < 0.0f) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid radius to spawn within."); - return; - } - const float radiusToSpawnWithin = radiusToSpawnWithinOptional.value(); - - EntityInfo info; - info.lot = lot.value(); - info.spawner = nullptr; - info.spawnerID = entity->GetObjectID(); - info.spawnerNodeID = 0; - - auto playerPosition = controllablePhysicsComponent->GetPosition(); - while (numberToSpawn > 0) { - auto randomAngle = GeneralUtils::GenerateRandomNumber<float>(0.0f, 2 * PI); - auto randomRadius = GeneralUtils::GenerateRandomNumber<float>(0.0f, radiusToSpawnWithin); - - // Set the position to the generated random position plus the player position. This will - // spawn the entity in a circle around the player. As you get further from the player, the angle chosen will get less accurate. - info.pos = playerPosition + NiPoint3(cos(randomAngle) * randomRadius, 0.0f, sin(randomAngle) * randomRadius); - info.rot = NiQuaternion(); - - auto newEntity = Game::entityManager->CreateEntity(info); - if (newEntity == nullptr) { - ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); - return; - } - - Game::entityManager->ConstructEntity(newEntity); - numberToSpawn--; - } - } - - if ((chatCommand == "giveuscore") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto uscoreOptional = GeneralUtils::TryParse<int32_t>(args[0]); - if (!uscoreOptional) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid uscore."); - return; - } - const int32_t uscore = uscoreOptional.value(); - - CharacterComponent* character = entity->GetComponent<CharacterComponent>(); - if (character) character->SetUScore(character->GetUScore() + uscore); - // MODERATION should work but it doesn't. Relog to see uscore changes - - eLootSourceType lootType = eLootSourceType::MODERATION; - - if (args.size() >= 2) { - const auto type = GeneralUtils::TryParse<eLootSourceType>(args[1]); - lootType = type.value_or(lootType); - } - - GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType); - } - - if ((chatCommand == "setlevel") && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - // We may be trying to set a specific players level to a level. If so override the entity with the requested players. - std::string requestedPlayerToSetLevelOf = ""; - if (args.size() > 1) { - requestedPlayerToSetLevelOf = args[1]; - - auto requestedPlayer = PlayerManager::GetPlayer(requestedPlayerToSetLevelOf); - - if (!requestedPlayer) { - ChatPackets::SendSystemMessage(sysAddr, u"No player found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); - return; - } - - if (!requestedPlayer->GetOwner()) { - ChatPackets::SendSystemMessage(sysAddr, u"No entity found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); - return; - } - - entity = requestedPlayer->GetOwner(); - } - const auto requestedLevelOptional = GeneralUtils::TryParse<uint32_t>(args[0]); - uint32_t oldLevel; - - // first check the level is valid - if (!requestedLevelOptional) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid level."); - return; - } - uint32_t requestedLevel = requestedLevelOptional.value(); - // query to set our uscore to the correct value for this level - - auto characterComponent = entity->GetComponent<CharacterComponent>(); - if (!characterComponent) return; - auto levelComponent = entity->GetComponent<LevelProgressionComponent>(); - auto query = CDClientDatabase::CreatePreppedStmt("SELECT requiredUScore from LevelProgressionLookup WHERE id = ?;"); - query.bind(1, static_cast<int>(requestedLevel)); - auto result = query.execQuery(); - - if (result.eof()) return; - - // Set the UScore first - oldLevel = levelComponent->GetLevel(); - characterComponent->SetUScore(result.getIntField(0, characterComponent->GetUScore())); - - // handle level up for each level we have passed if we set our level to be higher than the current one. - if (oldLevel < requestedLevel) { - while (oldLevel < requestedLevel) { - oldLevel += 1; - levelComponent->SetLevel(oldLevel); - levelComponent->HandleLevelUp(); - } - } else { - levelComponent->SetLevel(requestedLevel); - } - - if (requestedPlayerToSetLevelOf != "") { - ChatPackets::SendSystemMessage( - sysAddr, u"Set " + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u"'s level to " + GeneralUtils::to_u16string(requestedLevel) + - u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + - u". Relog to see changes."); - } else { - ChatPackets::SendSystemMessage( - sysAddr, u"Set your level to " + GeneralUtils::to_u16string(requestedLevel) + - u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + - u". Relog to see changes."); - } - return; - } - - if (chatCommand == "pos" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto position = entity->GetPosition(); - - ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">"); - - LOG("Position: %f, %f, %f", position.x, position.y, position.z); - } - - if (chatCommand == "rot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto rotation = entity->GetRotation(); - - ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">"); - - LOG("Rotation: %f, %f, %f, %f", rotation.w, rotation.x, rotation.y, rotation.z); - } - - if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto position = entity->GetPosition(); - const auto rotation = entity->GetRotation(); - - LOG("<location x=\"%f\" y=\"%f\" z=\"%f\" rw=\"%f\" rx=\"%f\" ry=\"%f\" rz=\"%f\" />", position.x, position.y, position.z, rotation.w, rotation.x, rotation.y, rotation.z); - } - - if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - GameMessages::SendPlayFXEffect(entity, 7074, u"create", "7074", LWOOBJID_EMPTY, 1.0f, 1.0f, true); - } - - if (chatCommand == "playrebuildfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - GameMessages::SendPlayFXEffect(entity, 230, u"rebuild", "230", LWOOBJID_EMPTY, 1.0f, 1.0f, true); - } - if ((chatCommand == "freemoney" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) && args.size() == 1) { - const auto money = GeneralUtils::TryParse<int64_t>(args[0]); - if (!money) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); - return; - } - - auto* ch = entity->GetCharacter(); - ch->SetCoins(ch->GetCoins() + money.value(), eLootSourceType::MODERATION); - } +#include "SlashCommandHandler.h" - if ((chatCommand == "setcurrency") && args.size() == 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - const auto money = GeneralUtils::TryParse<int64_t>(args[0]); +#include <iomanip> +#include <ranges> - if (!money) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); - return; - } +#include "DEVGMCommands.h" +#include "GMGreaterThanZeroCommands.h" +#include "GMZeroCommands.h" - auto* ch = entity->GetCharacter(); - ch->SetCoins(money.value(), eLootSourceType::MODERATION); - } +#include "Amf3.h" +#include "Database.h" +#include "MessageType/Chat.h" +#include "dServer.h" - // Allow for this on even while not a GM, as it sometimes toggles incorrrectly. - if (chatCommand == "gminvis" && entity->GetCharacter()->GetParentUser()->GetMaxGMLevel() >= eGameMasterLevel::DEVELOPER) { - GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); +namespace { + std::map<std::string, Command> CommandInfos; + std::map<std::string, Command> RegisteredCommands; +} +void SlashCommandHandler::RegisterCommand(Command command) { + if (command.aliases.empty()) { + LOG("Command %s has no aliases! Skipping!", command.help.c_str()); return; } - if (chatCommand == "gmimmune" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - - const auto state = GeneralUtils::TryParse<int32_t>(args[0]); - - if (!state) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); - return; + for (const auto& alias : command.aliases) { + auto [_, success] = RegisteredCommands.try_emplace(alias, command); + // Don't allow duplicate commands + if (!success) { + LOG_DEBUG("Command alias %s is already registered! Skipping!", alias.c_str()); + continue; } - - if (destroyableComponent) destroyableComponent->SetIsGMImmune(state.value()); - return; } + CommandInfos[command.aliases[0]] = command; +} - //Testing basic attack immunity - if (chatCommand == "attackimmune" && args.size() >= 1 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); +void SlashCommandHandler::HandleChatCommand(const std::u16string& chat, Entity* entity, const SystemAddress& sysAddr) { + auto input = GeneralUtils::UTF16ToWTF8(chat); + if (input.empty() || input.front() != '/') return; + const auto pos = input.find(' '); + std::string command = input.substr(1, pos - 1); - const auto state = GeneralUtils::TryParse<int32_t>(args[0]); + std::string args; + // make sure the space exists and isn't the last character + if (pos != std::string::npos && pos != input.size()) args = input.substr(input.find(' ') + 1); + LOG_DEBUG("Handling command \"%s\" with args \"%s\"", command.c_str(), args.c_str()); - if (!state) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); - return; + const auto commandItr = RegisteredCommands.find(command); + std::string error; + if (commandItr != RegisteredCommands.end()) { + auto& [alias, commandHandle] = *commandItr; + if (entity->GetGMLevel() >= commandHandle.requiredLevel) { + if (commandHandle.requiredLevel > eGameMasterLevel::CIVILIAN) Database::Get()->InsertSlashCommandUsage(entity->GetObjectID(), input); + commandHandle.handle(entity, sysAddr, args); + } else if (entity->GetGMLevel() != eGameMasterLevel::CIVILIAN) { + error = "You are not high enough GM level to use \"" + command + "\""; } - - if (destroyableComponent) destroyableComponent->SetIsImmune(state.value()); - return; + } else if (entity->GetGMLevel() == eGameMasterLevel::CIVILIAN) { + error = "Command " + command + " does not exist!"; } - if (chatCommand == "buff" && args.size() >= 2 && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto* buffComponent = entity->GetComponent<BuffComponent>(); - - const auto id = GeneralUtils::TryParse<int32_t>(args[0]); - if (!id) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff id."); - return; - } - - const auto duration = GeneralUtils::TryParse<int32_t>(args[1]); - if (!duration) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff duration."); - return; - } - - if (buffComponent) buffComponent->ApplyBuff(id.value(), duration.value(), entity->GetObjectID()); - return; + if (!error.empty()) { + GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(error)); } +} - if ((chatCommand == "testmap" && args.size() >= 1) && entity->GetGMLevel() >= eGameMasterLevel::FORUM_MODERATOR) { - ChatPackets::SendSystemMessage(sysAddr, u"Requesting map change..."); - LWOCLONEID cloneId = 0; - bool force = false; - - const auto reqZoneOptional = GeneralUtils::TryParse<LWOMAPID>(args[0]); - if (!reqZoneOptional) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); - return; - } - const LWOMAPID reqZone = reqZoneOptional.value(); - - if (args.size() > 1) { - auto index = 1; - - if (args[index] == "force") { - index++; - - force = true; - } - - if (args.size() > index) { - const auto cloneIdOptional = GeneralUtils::TryParse<LWOCLONEID>(args[index]); - if (!cloneIdOptional) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone id."); - return; - } - cloneId = cloneIdOptional.value(); +void GMZeroCommands::Help(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + std::ostringstream feedback; + constexpr size_t pageSize = 10; + + std::string trimmedArgs = args; + trimmedArgs.erase(trimmedArgs.begin(), std::find_if_not(trimmedArgs.begin(), trimmedArgs.end(), [](unsigned char ch) { + return std::isspace(ch); + })); + trimmedArgs.erase(std::find_if_not(trimmedArgs.rbegin(), trimmedArgs.rend(), [](unsigned char ch) { + return std::isspace(ch); + }).base(), trimmedArgs.end()); + + std::optional<uint32_t> parsedPage = GeneralUtils::TryParse<uint32_t>(trimmedArgs); + if (trimmedArgs.empty() || parsedPage.has_value()) { + size_t page = parsedPage.value_or(1); + + std::map<std::string, Command> accessibleCommands; + for (const auto& [commandName, command] : CommandInfos) { + if (command.requiredLevel <= entity->GetGMLevel()) { + accessibleCommands.emplace(commandName, command); } } - const auto objid = entity->GetObjectID(); - - if (force || Game::zoneManager->CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery - - ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { - - auto* entity = Game::entityManager->GetEntity(objid); - if (!entity) return; - - const auto sysAddr = entity->GetSystemAddress(); - - ChatPackets::SendSystemMessage(sysAddr, u"Transfering map..."); - - LOG("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; - }); - } else { - std::string msg = "ZoneID not found or allowed: "; - msg.append(args[0]); // FIXME: unnecessary utf16 re-encoding just for error - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(msg, msg.size())); - } - } - - if (chatCommand == "createprivate" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 3) { - const auto zone = GeneralUtils::TryParse<uint32_t>(args[0]); - if (!zone) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); - return; - } - - const auto clone = GeneralUtils::TryParse<uint32_t>(args[1]); - if (!clone) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone."); - return; - } - - const auto& password = args[2]; - - ZoneInstanceManager::Instance()->CreatePrivateZone(Game::server, zone.value(), clone.value(), password); - - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16("Sent request for private zone with password: " + password)); - - return; - } - - if ((chatCommand == "debugui") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger..."); - AMFArrayValue args; - GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "ToggleUIDebugger;", args); - } - - if ((chatCommand == "boost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - - if (possessorComponent == nullptr) { - return; - } - - auto* vehicle = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + size_t totalPages = (accessibleCommands.size() + pageSize - 1) / pageSize; - if (vehicle == nullptr) { + if (page < 1 || page > totalPages) { + feedback << "Invalid page number. Total pages: " << totalPages; + GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedback.str())); return; } - if (args.size() >= 1) { - const auto time = GeneralUtils::TryParse<float>(args[0]); - - if (!time) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost time."); - return; - } else { - GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - entity->AddCallbackTimer(time.value(), [vehicle]() { - if (!vehicle) return; - GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - }); - } - } else { - GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - } - - } - - if ((chatCommand == "unboost") && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto* possessorComponent = entity->GetComponent<PossessorComponent>(); - - if (possessorComponent == nullptr) return; - auto* vehicle = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); - - if (vehicle == nullptr) return; - GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); - } - - if (chatCommand == "activatespawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - auto spawners = Game::zoneManager->GetSpawnersByName(args[0]); - - for (auto* spawner : spawners) { - spawner->Activate(); - } - - spawners = Game::zoneManager->GetSpawnersInGroup(args[0]); - - for (auto* spawner : spawners) { - spawner->Activate(); - } - } - - if (chatCommand == "spawnphysicsverts" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { - //Go tell physics to spawn all the vertices: - auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PHANTOM_PHYSICS); - for (auto en : entities) { - auto phys = static_cast<PhantomPhysicsComponent*>(en->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); - if (phys) - phys->SpawnVertices(); - } - } - - if (chatCommand == "reportproxphys" && entity->GetGMLevel() >= eGameMasterLevel::JUNIOR_DEVELOPER) { - auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PROXIMITY_MONITOR); - for (auto en : entities) { - auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(eReplicaComponentType::PROXIMITY_MONITOR)); - if (phys) { - for (auto prox : phys->GetProximitiesData()) { - if (!prox.second) continue; - - auto sphere = static_cast<dpShapeSphere*>(prox.second->GetShape()); - auto pos = prox.second->GetPosition(); - LOG("Proximity: %s, r: %f, pos: %f, %f, %f", prox.first.c_str(), sphere->GetRadius(), pos.x, pos.y, pos.z); - } - } - } - } - - if (chatCommand == "triggerspawner" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - auto spawners = Game::zoneManager->GetSpawnersByName(args[0]); - - for (auto* spawner : spawners) { - spawner->Spawn(); - } - - spawners = Game::zoneManager->GetSpawnersInGroup(args[0]); + auto it = accessibleCommands.begin(); + std::advance(it, (page - 1) * pageSize); + size_t endIdx = std::min(page * pageSize, accessibleCommands.size()); - for (auto* spawner : spawners) { - spawner->Spawn(); + feedback << "----- Commands (Page " << page << " of " << totalPages << ") -----"; + for (size_t i = (page - 1) * pageSize; i < endIdx; ++i, ++it) { + feedback << "\n/" << it->first << ": " << it->second.help; } - } - - if (chatCommand == "reforge" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 2) { - const auto baseItem = GeneralUtils::TryParse<LOT>(args[0]); - if (!baseItem) return; - - const auto reforgedItem = GeneralUtils::TryParse<LOT>(args[1]); - if (!reforgedItem) return; - auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); - if (!inventoryComponent) return; - - std::vector<LDFBaseData*> data{}; - data.push_back(new LDFData<int32_t>(u"reforgedLOT", reforgedItem.value())); - - inventoryComponent->AddItem(baseItem.value(), 1, eLootSourceType::MODERATION, eInventoryType::INVALID, data); - } - - if (chatCommand == "crash" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR) { - ChatPackets::SendSystemMessage(sysAddr, u"Crashing..."); - - int* badPtr = nullptr; - *badPtr = 0; - - return; - } - - if (chatCommand == "metrics" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - for (const auto variable : Metrics::GetAllMetrics()) { - auto* metric = Metrics::GetMetric(variable); - - if (metric == nullptr) { - continue; - } - - ChatPackets::SendSystemMessage( - sysAddr, - GeneralUtils::ASCIIToUTF16(Metrics::MetricVariableToString(variable)) + - u": " + - GeneralUtils::to_u16string(Metrics::ToMiliseconds(metric->average)) + - u"ms" - ); + const auto feedbackStr = feedback.str(); + if (!feedbackStr.empty()) { + GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr)); } - - ChatPackets::SendSystemMessage( - sysAddr, - u"Peak RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetPeakRSS()) / 1.024e6)) + - u"MB" - ); - - ChatPackets::SendSystemMessage( - sysAddr, - u"Current RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetCurrentRSS()) / 1.024e6)) + - u"MB" - ); - - ChatPackets::SendSystemMessage( - sysAddr, - u"Process ID: " + GeneralUtils::to_u16string(Metrics::GetProcessID()) - ); - return; } - if (chatCommand == "reloadconfig" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - Game::config->ReloadConfig(); - VanityUtilities::SpawnVanity(); - dpWorld::Reload(); - auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); - for (const auto* const entity : entities) { - auto* const scriptedActivityComponent = entity->GetComponent<ScriptedActivityComponent>(); - if (!scriptedActivityComponent) continue; - - scriptedActivityComponent->ReloadConfig(); - } - Game::server->UpdateMaximumMtuSize(); - Game::server->UpdateBandwidthLimit(); - ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); - } - - if (chatCommand == "rollloot" && entity->GetGMLevel() >= eGameMasterLevel::OPERATOR && args.size() >= 3) { - const auto lootMatrixIndex = GeneralUtils::TryParse<uint32_t>(args[0]); - if (!lootMatrixIndex) return; - - const auto targetLot = GeneralUtils::TryParse<uint32_t>(args[1]); - if (!targetLot) return; - - const auto loops = GeneralUtils::TryParse<uint32_t>(args[2]); - if (!loops) return; - - uint64_t totalRuns = 0; - - for (uint32_t i = 0; i < loops; i++) { - while (true) { - auto lootRoll = Loot::RollLootMatrix(lootMatrixIndex.value()); - totalRuns += 1; - bool doBreak = false; - for (const auto& kv : lootRoll) { - if (static_cast<uint32_t>(kv.first) == targetLot) { - doBreak = true; - } - } - if (doBreak) break; - } - } - - std::u16string message = u"Ran loot drops looking for " - + GeneralUtils::to_u16string(targetLot.value()) - + u", " - + GeneralUtils::to_u16string(loops.value()) - + u" times. It ran " - + GeneralUtils::to_u16string(totalRuns) - + u" times. Averaging out at " - + GeneralUtils::to_u16string(static_cast<float>(totalRuns) / loops.value()); - - ChatPackets::SendSystemMessage(sysAddr, message); - } - - if (chatCommand == "deleteinven" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - eInventoryType inventoryType = eInventoryType::INVALID; - - const auto inventoryTypeOptional = GeneralUtils::TryParse<eInventoryType>(args[0]); - if (!inventoryTypeOptional) { - // In this case, we treat the input as a string and try to find it in the reflection list - std::transform(args[0].begin(), args[0].end(), args[0].begin(), ::toupper); - LOG("looking for inventory %s", args[0].c_str()); - for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { - if (std::string_view(args[0]) == std::string_view(InventoryType::InventoryTypeToString(static_cast<eInventoryType>(index)))) inventoryType = static_cast<eInventoryType>(index); - } - } else { - inventoryType = inventoryTypeOptional.value(); - } - - if (inventoryType == eInventoryType::INVALID || inventoryType >= NUMBER_OF_INVENTORIES) { - ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory provided."); - return; - } - - auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); - if (!inventoryComponent) return; - - auto* inventoryToDelete = inventoryComponent->GetInventory(inventoryType); - if (!inventoryToDelete) return; - - inventoryToDelete->DeleteAllItems(); - LOG("Deleted inventory %s for user %llu", args[0].c_str(), entity->GetObjectID()); - ChatPackets::SendSystemMessage(sysAddr, u"Deleted inventory " + GeneralUtils::UTF8ToUTF16(args[0])); - } - - if (chatCommand == "castskill" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - auto* skillComponent = entity->GetComponent<SkillComponent>(); - if (skillComponent) { - const auto skillId = GeneralUtils::TryParse<uint32_t>(args[0]); - - if (!skillId) { - ChatPackets::SendSystemMessage(sysAddr, u"Error getting skill ID."); - return; - } else { - skillComponent->CastSkill(skillId.value(), entity->GetObjectID(), entity->GetObjectID()); - ChatPackets::SendSystemMessage(sysAddr, u"Cast skill"); - } - } - } - - if (chatCommand == "setskillslot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 2) { - auto* const inventoryComponent = entity->GetComponent<InventoryComponent>(); - if (inventoryComponent) { - const auto slot = GeneralUtils::TryParse<BehaviorSlot>(args[0]); - if (!slot) { - ChatPackets::SendSystemMessage(sysAddr, u"Error getting slot."); - return; - } else { - const auto skillId = GeneralUtils::TryParse<uint32_t>(args[1]); - if (!skillId) { - ChatPackets::SendSystemMessage(sysAddr, u"Error getting skill."); - return; - } else { - if (inventoryComponent->SetSkill(slot.value(), skillId.value())) ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot successfully"); - else ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot failed"); - } - } - } - } - - if (chatCommand == "setfaction" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - if (destroyableComponent) { - const auto faction = GeneralUtils::TryParse<int32_t>(args[0]); - - if (!faction) { - ChatPackets::SendSystemMessage(sysAddr, u"Error getting faction."); - return; - } else { - destroyableComponent->SetFaction(faction.value()); - ChatPackets::SendSystemMessage(sysAddr, u"Set faction and updated enemies list"); - } - } - } - - if (chatCommand == "addfaction" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - if (destroyableComponent) { - const auto faction = GeneralUtils::TryParse<int32_t>(args[0]); - - if (!faction) { - ChatPackets::SendSystemMessage(sysAddr, u"Error getting faction."); - return; - } else { - destroyableComponent->AddFaction(faction.value()); - ChatPackets::SendSystemMessage(sysAddr, u"Added faction and updated enemies list"); - } - } - } - - if (chatCommand == "getfactions" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) { - auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - if (destroyableComponent) { - ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); - for (const auto entry : destroyableComponent->GetFactionIDs()) { - ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); - } + auto it = std::ranges::find_if(CommandInfos, [&trimmedArgs](const auto& pair) { + return std::ranges::find(pair.second.aliases, trimmedArgs) != pair.second.aliases.end(); + }); - ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); - for (const auto entry : destroyableComponent->GetEnemyFactionsIDs()) { - ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + if (it != CommandInfos.end() && entity->GetGMLevel() >= it->second.requiredLevel) { + const auto& command = it->second; + feedback << "----- " << it->first << " Info -----\n"; + feedback << command.info << "\n"; + if (command.aliases.size() > 1) { + feedback << "Aliases: "; + for (size_t i = 0; i < command.aliases.size(); ++i) { + if (i > 0) feedback << ", "; + feedback << command.aliases[i]; } } + } else { + feedback << "Command not found."; } - if (chatCommand == "setrewardcode" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) { - auto* cdrewardCodes = CDClientManager::GetTable<CDRewardCodesTable>(); - - auto id = cdrewardCodes->GetCodeID(args[0]); - if (id != -1) Database::Get()->InsertRewardCode(user->GetAccountID(), id); - } - - if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) { - Entity* closest = nullptr; - - std::u16string ldf; - - bool isLDF = false; - - auto component = GeneralUtils::TryParse<eReplicaComponentType>(args[0]); - if (!component) { - component = eReplicaComponentType::INVALID; - - ldf = GeneralUtils::UTF8ToUTF16(args[0]); - - isLDF = true; - } - - auto reference = entity->GetPosition(); - - auto closestDistance = 0.0f; - - const auto candidates = Game::entityManager->GetEntitiesByComponent(component.value()); - - for (auto* candidate : candidates) { - if (candidate->GetLOT() == 1 || candidate->GetLOT() == 8092) { - continue; - } - - if (isLDF && !candidate->HasVar(ldf)) { - continue; - } - - if (!closest) { - closest = candidate; - - closestDistance = NiPoint3::Distance(candidate->GetPosition(), reference); - - continue; - } - - const auto distance = NiPoint3::Distance(candidate->GetPosition(), reference); - - if (distance < closestDistance) { - closest = candidate; - - closestDistance = distance; - } - } - - if (!closest) return; - - Game::entityManager->SerializeEntity(closest); - - auto* table = CDClientManager::GetTable<CDObjectsTable>(); - - const auto& info = table->GetByID(closest->GetLOT()); - - std::stringstream header; - - header << info.name << " [" << std::to_string(info.id) << "]" << " " << std::to_string(closestDistance) << " " << std::to_string(closest->IsSleeping()); - - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(header.str())); - - for (const auto& pair : closest->GetComponents()) { - auto id = pair.first; - - std::stringstream stream; - - stream << "Component [" << std::to_string(static_cast<uint32_t>(id)) << "]"; - - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(stream.str())); - } - - if (args.size() >= 2) { - if (args[1] == "-m" && args.size() >= 3) { - auto* const movingPlatformComponent = closest->GetComponent<MovingPlatformComponent>(); - - const auto mValue = GeneralUtils::TryParse<int32_t>(args[2]); - - if (!movingPlatformComponent || !mValue) return; - - movingPlatformComponent->SetSerialized(true); - - if (mValue == -1) { - movingPlatformComponent->StopPathing(); - } else { - movingPlatformComponent->GotoWaypoint(mValue.value()); - } - - Game::entityManager->SerializeEntity(closest); - } else if (args[1] == "-a" && args.size() >= 3) { - RenderComponent::PlayAnimation(closest, args.at(2)); - } else if (args[1] == "-s") { - for (auto* entry : closest->GetSettings()) { - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(entry->GetString())); - } - - ChatPackets::SendSystemMessage(sysAddr, u"------"); - ChatPackets::SendSystemMessage(sysAddr, u"Spawner ID: " + GeneralUtils::to_u16string(closest->GetSpawnerID())); - } else if (args[1] == "-p") { - const auto postion = closest->GetPosition(); - - ChatPackets::SendSystemMessage( - sysAddr, - GeneralUtils::ASCIIToUTF16("< " + std::to_string(postion.x) + ", " + std::to_string(postion.y) + ", " + std::to_string(postion.z) + " >") - ); - } else if (args[1] == "-f") { - auto* destuctable = closest->GetComponent<DestroyableComponent>(); - - if (destuctable == nullptr) { - ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); - return; - } - - ChatPackets::SendSystemMessage(sysAddr, u"Smashable: " + (GeneralUtils::to_u16string(destuctable->GetIsSmashable()))); - - ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); - for (const auto entry : destuctable->GetFactionIDs()) { - ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); - } - - ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); - for (const auto entry : destuctable->GetEnemyFactionsIDs()) { - ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); - } - - if (args.size() >= 3) { - const auto faction = GeneralUtils::TryParse<int32_t>(args[2]); - if (!faction) return; - - destuctable->SetFaction(-1); - destuctable->AddFaction(faction.value(), true); - } - } else if (args[1] == "-cf") { - auto* destuctable = entity->GetComponent<DestroyableComponent>(); - if (!destuctable) { - ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); - return; - } - if (destuctable->IsEnemy(closest)) ChatPackets::SendSystemMessage(sysAddr, u"They are our enemy"); - else ChatPackets::SendSystemMessage(sysAddr, u"They are NOT our enemy"); - } else if (args[1] == "-t") { - auto* phantomPhysicsComponent = closest->GetComponent<PhantomPhysicsComponent>(); - - if (phantomPhysicsComponent != nullptr) { - ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(static_cast<uint32_t>(phantomPhysicsComponent->GetEffectType())))); - const auto dir = phantomPhysicsComponent->GetDirection(); - ChatPackets::SendSystemMessage(sysAddr, u"Direction: <" + (GeneralUtils::to_u16string(dir.x)) + u", " + (GeneralUtils::to_u16string(dir.y)) + u", " + (GeneralUtils::to_u16string(dir.z)) + u">"); - ChatPackets::SendSystemMessage(sysAddr, u"Multiplier: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetDirectionalMultiplier()))); - ChatPackets::SendSystemMessage(sysAddr, u"Active: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetPhysicsEffectActive()))); - } - - auto* triggerComponent = closest->GetComponent<TriggerComponent>(); - if (triggerComponent) { - auto trigger = triggerComponent->GetTrigger(); - if (trigger) { - ChatPackets::SendSystemMessage(sysAddr, u"Trigger: " + (GeneralUtils::to_u16string(trigger->id))); - } - } - } - } + const auto feedbackStr = feedback.str(); + if (!feedbackStr.empty()) { + GameMessages::SendSlashCommandFeedbackText(entity, GeneralUtils::ASCIIToUTF16(feedbackStr)); } } @@ -2078,7 +153,7 @@ void SlashCommandHandler::SendAnnouncement(const std::string& title, const std:: //Notify chat about it CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ANNOUNCEMENT); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_ANNOUNCE); bitStream.Write<uint32_t>(title.size()); for (auto character : title) { @@ -2092,3 +167,1272 @@ void SlashCommandHandler::SendAnnouncement(const std::string& title, const std:: Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } + +void SlashCommandHandler::Startup() { + // Register Dev Commands + Command SetGMLevelCommand{ + .help = "Change the GM level of your character", + .info = "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", + .aliases = { "setgmlevel", "makegm", "gmlevel" }, + .handle = DEVGMCommands::SetGMLevel, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(SetGMLevelCommand); + + Command ToggleNameplateCommand{ + .help = "Toggle the visibility of your nameplate. This must be enabled by a server admin to be used.", + .info = "Turns the nameplate above your head that is visible to other players off and on. This must be enabled by a server admin to be used.", + .aliases = { "togglenameplate", "tnp" }, + .handle = DEVGMCommands::ToggleNameplate, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(ToggleNameplateCommand); + + Command ToggleSkipCinematicsCommand{ + .help = "Toggle Skipping Cinematics", + .info = "Skips mission and world load related cinematics", + .aliases = { "toggleskipcinematics", "tsc" }, + .handle = DEVGMCommands::ToggleSkipCinematics, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(ToggleSkipCinematicsCommand); + + Command KillCommand{ + .help = "Smash a user", + .info = "Smashes the character whom the given user is playing", + .aliases = { "kill" }, + .handle = DEVGMCommands::Kill, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(KillCommand); + + Command MetricsCommand{ + .help = "Display server metrics", + .info = "Prints some information about the server's performance", + .aliases = { "metrics" }, + .handle = DEVGMCommands::Metrics, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(MetricsCommand); + + Command AnnounceCommand{ + .help = " Send and announcement", + .info = "Sends an announcement. `/setanntitle` and `/setannmsg` must be called first to configure the announcement.", + .aliases = { "announce" }, + .handle = DEVGMCommands::Announce, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(AnnounceCommand); + + Command SetAnnTitleCommand{ + .help = "Sets the title of an announcement", + .info = "Sets the title of an announcement. Use with `/setannmsg` and `/announce`", + .aliases = { "setanntitle" }, + .handle = DEVGMCommands::SetAnnTitle, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetAnnTitleCommand); + + Command SetAnnMsgCommand{ + .help = "Sets the message of an announcement", + .info = "Sets the message of an announcement. Use with `/setannmtitle` and `/announce`", + .aliases = { "setannmsg" }, + .handle = DEVGMCommands::SetAnnMsg, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetAnnMsgCommand); + + Command ShutdownUniverseCommand{ + .help = "Sends a shutdown message to the master server", + .info = "Sends a shutdown message to the master server. This will send an announcement to all players that the universe will shut down in 10 minutes.", + .aliases = { "shutdownuniverse" }, + .handle = DEVGMCommands::ShutdownUniverse + }; + RegisterCommand(ShutdownUniverseCommand); + + Command SetMinifigCommand{ + .help = "Alters your player's minifig", + .info = "Alters your player's minifig. Body part can be one of \"Eyebrows\", \"Eyes\", \"HairColor\", \"HairStyle\", \"Pants\", \"LeftHand\", \"Mouth\", \"RightHand\", \"Shirt\", or \"Hands\". Changing minifig parts could break the character so this command is limited to GMs.", + .aliases = { "setminifig" }, + .handle = DEVGMCommands::SetMinifig, + .requiredLevel = eGameMasterLevel::FORUM_MODERATOR + }; + RegisterCommand(SetMinifigCommand); + + Command TestMapCommand{ + .help = "Transfers you to the given zone", + .info = "Transfers you to the given zone by id and clone id. Add \"force\" to skip checking if the zone is accessible (this can softlock your character, though, if you e.g. try to teleport to Frostburgh).", + .aliases = { "testmap", "tm" }, + .handle = DEVGMCommands::TestMap, + .requiredLevel = eGameMasterLevel::FORUM_MODERATOR + }; + RegisterCommand(TestMapCommand); + + Command ReportProxPhysCommand{ + .help = "Display proximity sensor info", + .info = "Prints to console the position and radius of proximity sensors.", + .aliases = { "reportproxphys" }, + .handle = DEVGMCommands::ReportProxPhys, + .requiredLevel = eGameMasterLevel::OPERATOR + }; + RegisterCommand(ReportProxPhysCommand); + + Command SpawnPhysicsVertsCommand{ + .help = "Spawns a 1x1 brick at all vertices of phantom physics objects", + .info = "Spawns a 1x1 brick at all vertices of phantom physics objects", + .aliases = { "spawnphysicsverts" }, + .handle = DEVGMCommands::SpawnPhysicsVerts, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SpawnPhysicsVertsCommand); + + Command TeleportCommand{ + .help = "Teleports you", + .info = "Teleports you. If no Y is given, you are teleported to the height of the terrain or physics object at (x, z)", + .aliases = { "teleport", "tele", "tp" }, + .handle = DEVGMCommands::Teleport, + .requiredLevel = eGameMasterLevel::JUNIOR_DEVELOPER + }; + RegisterCommand(TeleportCommand); + + Command ActivateSpawnerCommand{ + .help = "Activates spawner by name", + .info = "Activates spawner by name", + .aliases = { "activatespawner" }, + .handle = DEVGMCommands::ActivateSpawner, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(ActivateSpawnerCommand); + + Command AddMissionCommand{ + .help = "Accepts the mission, adding it to your journal.", + .info = "Accepts the mission, adding it to your journal.", + .aliases = { "addmission" }, + .handle = DEVGMCommands::AddMission, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(AddMissionCommand); + + Command BoostCommand{ + .help = "Adds boost to a vehicle", + .info = "Adds a passive boost action if you are in a vehicle. If time is given it will end after that amount of time", + .aliases = { "boost" }, + .handle = DEVGMCommands::Boost, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(BoostCommand); + + Command UnboostCommand{ + .help = "Removes a passive vehicle boost", + .info = "Removes a passive vehicle boost", + .aliases = { "unboost" }, + .handle = DEVGMCommands::Unboost, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(UnboostCommand); + + Command BuffCommand{ + .help = "Applies a buff", + .info = "Applies a buff with the given id for the given number of seconds", + .aliases = { "buff" }, + .handle = DEVGMCommands::Buff, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(BuffCommand); + + Command BuffMeCommand{ + .help = "Sets health, armor, and imagination to 999", + .info = "Sets health, armor, and imagination to 999", + .aliases = { "buffme" }, + .handle = DEVGMCommands::BuffMe, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(BuffMeCommand); + + Command BuffMedCommand{ + .help = "Sets health, armor, and imagination to 9", + .info = "Sets health, armor, and imagination to 9", + .aliases = { "buffmed" }, + .handle = DEVGMCommands::BuffMed, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(BuffMedCommand); + + Command ClearFlagCommand{ + .help = "Clear a player flag", + .info = "Removes the given health or inventory flag from your player. Equivalent of calling `/setflag off <flag id>`", + .aliases = { "clearflag" }, + .handle = DEVGMCommands::ClearFlag, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(ClearFlagCommand); + + Command CompleteMissionCommand{ + .help = "Completes the mission", + .info = "Completes the mission, removing it from your journal", + .aliases = { "completemission" }, + .handle = DEVGMCommands::CompleteMission, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(CompleteMissionCommand); + + Command CreatePrivateCommand{ + .help = "Creates a private zone with password", + .info = "Creates a private zone with password", + .aliases = { "createprivate" }, + .handle = DEVGMCommands::CreatePrivate, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(CreatePrivateCommand); + + Command DebugUiCommand{ + .help = "Toggle Debug UI", + .info = "Toggle Debug UI", + .aliases = { "debugui" }, + .handle = DEVGMCommands::DebugUi, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(DebugUiCommand); + + Command DismountCommand{ + .help = "Dismounts you from the vehicle or mount", + .info = "Dismounts you from the vehicle or mount", + .aliases = { "dismount" }, + .handle = DEVGMCommands::Dismount, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(DismountCommand); + + Command ReloadConfigCommand{ + .help = "Reload Server configs", + .info = "Reloads the server with the new config values.", + .aliases = { "reloadconfig", "reload-config" }, + .handle = DEVGMCommands::ReloadConfig, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(ReloadConfigCommand); + + Command ForceSaveCommand{ + .help = "Force save your player", + .info = "While saving to database usually happens on regular intervals and when you disconnect from the server, this command saves your player's data to the database", + .aliases = { "forcesave", "force-save" }, + .handle = DEVGMCommands::ForceSave, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(ForceSaveCommand); + + Command FreecamCommand{ + .help = "Toggles freecam mode", + .info = "Toggles freecam mode", + .aliases = { "freecam" }, + .handle = DEVGMCommands::Freecam, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(FreecamCommand); + + Command FreeMoneyCommand{ + .help = "Give yourself coins", + .info = "Give yourself coins", + .aliases = { "freemoney", "givemoney", "money", "givecoins", "coins"}, + .handle = DEVGMCommands::FreeMoney, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(FreeMoneyCommand); + + Command GetNavmeshHeightCommand{ + .help = "Display the navmesh height", + .info = "Display the navmesh height at your current position", + .aliases = { "getnavmeshheight" }, + .handle = DEVGMCommands::GetNavmeshHeight, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(GetNavmeshHeightCommand); + + Command GiveUScoreCommand{ + .help = "Gives uscore", + .info = "Gives uscore", + .aliases = { "giveuscore" }, + .handle = DEVGMCommands::GiveUScore, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(GiveUScoreCommand); + + Command GmAddItemCommand{ + .help = "Give yourseld an item", + .info = "Adds the given item to your inventory by id", + .aliases = { "gmadditem", "give" }, + .handle = DEVGMCommands::GmAddItem, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(GmAddItemCommand); + + Command InspectCommand{ + .help = "Inspect an object", + .info = "Finds the closest entity with the given component or LNV variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has. See detailed usage in the DLU docs", + .aliases = { "inspect" }, + .handle = DEVGMCommands::Inspect, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(InspectCommand); + + Command ListSpawnsCommand{ + .help = "List spawn points for players", + .info = "Lists all the character spawn points in the zone. Additionally, this command will display the current scene that plays when the character lands in the next zone, if there is one.", + .aliases = { "list-spawns", "listspawns" }, + .handle = DEVGMCommands::ListSpawns, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(ListSpawnsCommand); + + Command LocRowCommand{ + .help = "Prints the your current position and rotation information to the console", + .info = "Prints the your current position and rotation information to the console", + .aliases = { "locrow" }, + .handle = DEVGMCommands::LocRow, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(LocRowCommand); + + Command LookupCommand{ + .help = "Lookup an object", + .info = "Searches through the Objects table in the client SQLite database for items whose display name, name, or description contains the query. Query can be multiple words delimited by spaces.", + .aliases = { "lookup" }, + .handle = DEVGMCommands::Lookup, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(LookupCommand); + + Command PlayAnimationCommand{ + .help = "Play an animation with given ID", + .info = "Play an animation with given ID", + .aliases = { "playanimation", "playanim" }, + .handle = DEVGMCommands::PlayAnimation, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(PlayAnimationCommand); + + Command PlayEffectCommand{ + .help = "Plays an effect", + .info = "Plays an effect", + .aliases = { "playeffect" }, + .handle = DEVGMCommands::PlayEffect, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(PlayEffectCommand); + + Command PlayLvlFxCommand{ + .help = "Plays the level up animation on your character", + .info = "Plays the level up animation on your character", + .aliases = { "playlvlfx" }, + .handle = DEVGMCommands::PlayLvlFx, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(PlayLvlFxCommand); + + Command PlayRebuildFxCommand{ + .help = "Plays the quickbuild animation on your character", + .info = "Plays the quickbuild animation on your character", + .aliases = { "playrebuildfx" }, + .handle = DEVGMCommands::PlayRebuildFx, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(PlayRebuildFxCommand); + + Command PosCommand{ + .help = "Displays your current position in chat and in the console", + .info = "Displays your current position in chat and in the console", + .aliases = { "pos" }, + .handle = DEVGMCommands::Pos, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(PosCommand); + + Command RefillStatsCommand{ + .help = "Refills health, armor, and imagination to their maximum level", + .info = "Refills health, armor, and imagination to their maximum level", + .aliases = { "refillstats" }, + .handle = DEVGMCommands::RefillStats, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(RefillStatsCommand); + + Command ReforgeCommand{ + .help = "Reforges an item", + .info = "Reforges an item", + .aliases = { "reforge" }, + .handle = DEVGMCommands::Reforge, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(ReforgeCommand); + + Command ResetMissionCommand{ + .help = "Sets the state of the mission to accepted but not yet started", + .info = "Sets the state of the mission to accepted but not yet started", + .aliases = { "resetmission" }, + .handle = DEVGMCommands::ResetMission, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(ResetMissionCommand); + + Command RotCommand{ + .help = "Displays your current rotation in chat and in the console", + .info = "Displays your current rotation in chat and in the console", + .aliases = { "rot" }, + .handle = DEVGMCommands::Rot, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(RotCommand); + + Command RunMacroCommand{ + .help = "Run a macro", + .info = "Runs any command macro found in `./res/macros/`", + .aliases = { "runmacro" }, + .handle = DEVGMCommands::RunMacro, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(RunMacroCommand); + + Command SetControlSchemeCommand{ + .help = "Sets the character control scheme to the specified number", + .info = "Sets the character control scheme to the specified number", + .aliases = { "setcontrolscheme" }, + .handle = DEVGMCommands::SetControlScheme, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetControlSchemeCommand); + + Command SetCurrencyCommand{ + .help = "Sets your coins", + .info = "Sets your coins", + .aliases = { "setcurrency", "setcoins" }, + .handle = DEVGMCommands::SetCurrency, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetCurrencyCommand); + + Command SetFlagCommand{ + .help = "Set a player flag", + .info = "Sets the given inventory or health flag to the given value, where value can be one of \"on\" or \"off\". If no value is given, by default this adds the flag to your character (equivalent of calling `/setflag on <flag id>`)", + .aliases = { "setflag" }, + .handle = DEVGMCommands::SetFlag, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetFlagCommand); + + Command SetInventorySizeCommand{ + .help = "Set your inventory size", + .info = "Sets your inventory size to the given size. If `inventory` is provided, the number or string will be used to set that inventory to the requested size", + .aliases = { "setinventorysize", "setinvsize", "setinvensize" }, + .handle = DEVGMCommands::SetInventorySize, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetInventorySizeCommand); + + Command SetUiStateCommand{ + .help = "Changes UI state", + .info = "Changes UI state", + .aliases = { "setuistate" }, + .handle = DEVGMCommands::SetUiState, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetUiStateCommand); + + Command SpawnCommand{ + .help = "Spawns an object at your location by id", + .info = "Spawns an object at your location by id", + .aliases = { "spawn" }, + .handle = DEVGMCommands::Spawn, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SpawnCommand); + + Command SpawnGroupCommand{ + .help = "", + .info = "", + .aliases = { "spawngroup" }, + .handle = DEVGMCommands::SpawnGroup, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SpawnGroupCommand); + + Command SpeedBoostCommand{ + .help = "Set the players speed multiplier", + .info = "Sets the speed multiplier to the given amount. `/speedboost 1.5` will set the speed multiplier to 1.5x the normal speed", + .aliases = { "speedboost" }, + .handle = DEVGMCommands::SpeedBoost, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SpeedBoostCommand); + + Command StartCelebrationCommand{ + .help = "Starts a celebration effect on your character", + .info = "Starts a celebration effect on your character", + .aliases = { "startcelebration" }, + .handle = DEVGMCommands::StartCelebration, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(StartCelebrationCommand); + + Command StopEffectCommand{ + .help = "Stops the given effect", + .info = "Stops the given effect", + .aliases = { "stopeffect" }, + .handle = DEVGMCommands::StopEffect, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(StopEffectCommand); + + Command ToggleCommand{ + .help = "Toggles UI state", + .info = "Toggles UI state", + .aliases = { "toggle" }, + .handle = DEVGMCommands::Toggle, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(ToggleCommand); + + Command TpAllCommand{ + .help = "Teleports all characters to your current position", + .info = "Teleports all characters to your current position", + .aliases = { "tpall" }, + .handle = DEVGMCommands::TpAll, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(TpAllCommand); + + Command TriggerSpawnerCommand{ + .help = "Triggers spawner by name", + .info = "Triggers spawner by name", + .aliases = { "triggerspawner" }, + .handle = DEVGMCommands::TriggerSpawner, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(TriggerSpawnerCommand); + + Command UnlockEmoteCommand{ + .help = "Unlocks for your character the emote of the given id", + .info = "Unlocks for your character the emote of the given id", + .aliases = { "unlock-emote", "unlockemote" }, + .handle = DEVGMCommands::UnlockEmote, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(UnlockEmoteCommand); + + Command SetLevelCommand{ + .help = "Set player level", + .info = "Sets the using entities level to the requested level. Takes an optional parameter of an in-game players username to set the level of", + .aliases = { "setlevel" }, + .handle = DEVGMCommands::SetLevel, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetLevelCommand); + + Command SetSkillSlotCommand{ + .help = "Set an action slot to a specific skill", + .info = "Set an action slot to a specific skill", + .aliases = { "setskillslot" }, + .handle = DEVGMCommands::SetSkillSlot, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetSkillSlotCommand); + + Command SetFactionCommand{ + .help = "Set the players faction", + .info = "Clears the users current factions and sets it", + .aliases = { "setfaction" }, + .handle = DEVGMCommands::SetFaction, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetFactionCommand); + + Command AddFactionCommand{ + .help = "Add the faction to the users list of factions", + .info = "Add the faction to the users list of factions", + .aliases = { "addfaction" }, + .handle = DEVGMCommands::AddFaction, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(AddFactionCommand); + + Command GetFactionsCommand{ + .help = "Shows the player's factions", + .info = "Shows the player's factions", + .aliases = { "getfactions" }, + .handle = DEVGMCommands::GetFactions, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(GetFactionsCommand); + + Command SetRewardCodeCommand{ + .help = "Set a reward code for your account", + .info = "Sets the rewardcode for the account you are logged into if it's a valid rewardcode, See cdclient table `RewardCodes`", + .aliases = { "setrewardcode" }, + .handle = DEVGMCommands::SetRewardCode, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetRewardCodeCommand); + + Command CrashCommand{ + .help = "Crash the server", + .info = "Crashes the server", + .aliases = { "crash", "pumpkin" }, + .handle = DEVGMCommands::Crash, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(CrashCommand); + + Command RollLootCommand{ + .help = "Simulate loot rolls", + .info = "Given a `loot matrix index`, look for `item id` in that matrix `amount` times and print to the chat box statistics of rolling that loot matrix.", + .aliases = { "rollloot", "roll-loot" }, + .handle = DEVGMCommands::RollLoot, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(RollLootCommand); + + Command CastSkillCommand{ + .help = "Casts the skill as the player", + .info = "Casts the skill as the player", + .aliases = { "castskill" }, + .handle = DEVGMCommands::CastSkill, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(CastSkillCommand); + + Command DeleteInvenCommand{ + .help = "Delete all items from a specified inventory", + .info = "Delete all items from a specified inventory", + .aliases = { "deleteinven" }, + .handle = DEVGMCommands::DeleteInven, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(DeleteInvenCommand); + + // Register Greater Than Zero Commands + + Command KickCommand{ + .help = "Kicks the player off the server", + .info = "Kicks the player off the server", + .aliases = { "kick" }, + .handle = GMGreaterThanZeroCommands::Kick, + .requiredLevel = eGameMasterLevel::JUNIOR_MODERATOR + }; + RegisterCommand(KickCommand); + + Command MailItemCommand{ + .help = "Mails an item to the given player", + .info = "Mails an item to the given player. The mailed item has predetermined content. The sender name is set to \"Darkflame Universe\". The title of the message is \"Lost item\". The body of the message is \"This is a replacement item for one you lost\".", + .aliases = { "mailitem" }, + .handle = GMGreaterThanZeroCommands::MailItem, + .requiredLevel = eGameMasterLevel::MODERATOR + }; + RegisterCommand(MailItemCommand); + + Command BanCommand{ + .help = "Bans a user from the server", + .info = "Bans a user from the server", + .aliases = { "ban" }, + .handle = GMGreaterThanZeroCommands::Ban, + .requiredLevel = eGameMasterLevel::SENIOR_MODERATOR + }; + RegisterCommand(BanCommand); + + Command ApprovePropertyCommand{ + .help = "Approves a property", + .info = "Approves the property the player is currently visiting", + .aliases = { "approveproperty" }, + .handle = GMGreaterThanZeroCommands::ApproveProperty, + .requiredLevel = eGameMasterLevel::LEAD_MODERATOR + }; + RegisterCommand(ApprovePropertyCommand); + + Command MuteCommand{ + .help = "Mute a player", + .info = "Mute player for the given amount of time. If no time is given, the mute is indefinite.", + .aliases = { "mute" }, + .handle = GMGreaterThanZeroCommands::Mute, + .requiredLevel = eGameMasterLevel::JUNIOR_DEVELOPER + }; + RegisterCommand(MuteCommand); + + Command FlyCommand{ + .help = "Toggle flying", + .info = "Toggles your flying state with an optional parameter for the speed scale.", + .aliases = { "fly" }, + .handle = GMGreaterThanZeroCommands::Fly, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(FlyCommand); + + Command AttackImmuneCommand{ + .help = "Make yourself immune to attacks", + .info = "Sets the character's immunity to basic attacks state, where value can be one of \"1\", to make yourself immune to basic attack damage, or \"0\" to undo", + .aliases = { "attackimmune" }, + .handle = GMGreaterThanZeroCommands::AttackImmune, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(AttackImmuneCommand); + + Command GmImmuneCommand{ + .help = "Sets the character's GMImmune state", + .info = "Sets the character's GMImmune state, where value can be one of \"1\", to make yourself immune to damage, or \"0\" to undo", + .aliases = { "gmimmune" }, + .handle = GMGreaterThanZeroCommands::GmImmune, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(GmImmuneCommand); + + Command GmInvisCommand{ + .help = "Toggles invisibility for the character", + .info = "Toggles invisibility for the character, though it's currently a bit buggy. Requires nonzero GM Level for the character, but the account must have a GM level of 8", + .aliases = { "gminvis" }, + .handle = GMGreaterThanZeroCommands::GmInvis, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(GmInvisCommand); + + Command SetNameCommand{ + + .help = "Sets a temporary name for your player", + .info = "Sets a temporary name for your player. The name resets when you log out", + .aliases = { "setname" }, + .handle = GMGreaterThanZeroCommands::SetName, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(SetNameCommand); + + Command TitleCommand{ + .help = "Give your character a title", + .info = "Temporarily appends your player's name with \" - <title>\". This resets when you log out", + .aliases = { "title" }, + .handle = GMGreaterThanZeroCommands::Title, + .requiredLevel = eGameMasterLevel::DEVELOPER + }; + RegisterCommand(TitleCommand); + + Command ShowAllCommand{ + .help = "Show all online players across World Servers", + .info = "Usage: /showall (displayZoneData: Default 1) (displayIndividualPlayers: Default 1)", + .aliases = { "showall" }, + .handle = GMGreaterThanZeroCommands::ShowAll, + .requiredLevel = eGameMasterLevel::JUNIOR_MODERATOR + }; + RegisterCommand(ShowAllCommand); + + Command FindPlayerCommand{ + .help = "Find the World Server a player is in if they are online", + .info = "Find the World Server a player is in if they are online", + .aliases = { "findplayer" }, + .handle = GMGreaterThanZeroCommands::FindPlayer, + .requiredLevel = eGameMasterLevel::JUNIOR_MODERATOR + }; + RegisterCommand(FindPlayerCommand); + + Command SpectateCommand{ + .help = "Spectate a player", + .info = "Specify a player name to spectate. They must be in the same world as you. Leave blank to stop spectating", + .aliases = { "spectate", "follow" }, + .handle = GMGreaterThanZeroCommands::Spectate, + .requiredLevel = eGameMasterLevel::JUNIOR_MODERATOR + }; + RegisterCommand(SpectateCommand); + + // Register GM Zero Commands + + Command HelpCommand{ + .help = "Display command info", + .info = "If a command is given, display detailed info on that command. Otherwise display a list of commands with short descriptions.", + .aliases = { "help", "h"}, + .handle = GMZeroCommands::Help, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(HelpCommand); + + Command CreditsCommand{ + .help = "Displays DLU Credits", + .info = "Displays the names of the people behind Darkflame Universe.", + .aliases = { "credits" }, + .handle = GMZeroCommands::Credits, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(CreditsCommand); + + Command InfoCommand{ + .help = "Displays server info", + .info = "Displays server info to the user, including where to find the server's source code", + .aliases = { "info" }, + .handle = GMZeroCommands::Info, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(InfoCommand); + + Command DieCommand{ + .help = "Smashes the player", + .info = "Smashes the player as if they were killed by something", + .aliases = { "die" }, + .handle = GMZeroCommands::Die, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(DieCommand); + + Command PingCommand{ + .help = "Displays your average ping.", + .info = "Displays your average ping. If the `-l` flag is used, the latest ping is displayed.", + .aliases = { "ping" }, + .handle = GMZeroCommands::Ping, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(PingCommand); + + Command PvpCommand{ + .help = "Toggle your PVP flag", + .info = "Toggle your PVP flag", + .aliases = { "pvp" }, + .handle = GMZeroCommands::Pvp, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(PvpCommand); + + Command RequestMailCountCommand{ + .help = "Gets the players mail count", + .info = "Sends notification with number of unread messages in the player's mailbox", + .aliases = { "requestmailcount" }, + .handle = GMZeroCommands::RequestMailCount, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(RequestMailCountCommand); + + Command WhoCommand{ + .help = "Displays all players on the instance", + .info = "Displays all players on the instance", + .aliases = { "who" }, + .handle = GMZeroCommands::Who, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(WhoCommand); + + Command FixStatsCommand{ + .help = "Resets skills, buffs, and destroyables", + .info = "Resets skills, buffs, and destroyables", + .aliases = { "fix-stats" }, + .handle = GMZeroCommands::FixStats, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(FixStatsCommand); + + Command JoinCommand{ + .help = "Join a private zone", + .info = "Join a private zone with given password", + .aliases = { "join" }, + .handle = GMZeroCommands::Join, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(JoinCommand); + + Command LeaveZoneCommand{ + .help = "Leave an instanced zone", + .info = "If you are in an instanced zone, transfers you to the closest main world. For example, if you are in an instance of Avant Gardens Survival or the Spider Queen Battle, you are sent to Avant Gardens. If you are in the Battle of Nimbus Station, you are sent to Nimbus Station.", + .aliases = { "leave-zone", "leavezone" }, + .handle = GMZeroCommands::LeaveZone, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(LeaveZoneCommand); + + Command ResurrectCommand{ + .help = "Resurrects the player", + .info = "Resurrects the player", + .aliases = { "resurrect" }, + .handle = GMZeroCommands::Resurrect, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(ResurrectCommand); + + Command InstanceInfoCommand{ + .help = "Display LWOZoneID info for the current zone", + .info = "Display LWOZoneID info for the current zone", + .aliases = { "instanceinfo" }, + .handle = GMZeroCommands::InstanceInfo, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(InstanceInfoCommand); + + //Commands that are handled by the client + + Command faqCommand{ + .help = "Show the LU FAQ Page", + .info = "Show the LU FAQ Page", + .aliases = {"faq","faqs"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(faqCommand); + + Command teamChatCommand{ + .help = "Send a message to your teammates.", + .info = "Send a message to your teammates.", + .aliases = {"team","t"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(teamChatCommand); + + Command showStoreCommand{ + .help = "Show the LEGO shop page.", + .info = "Show the LEGO shop page.", + .aliases = {"shop","store"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(showStoreCommand); + + Command minigamesCommand{ + .help = "Show the LEGO minigames page!", + .info = "Show the LEGO minigames page!", + .aliases = {"minigames"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(minigamesCommand); + + Command forumsCommand{ + .help = "Show the LU Forums!", + .info = "Show the LU Forums!", + .aliases = {"forums"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(forumsCommand); + + Command exitGameCommand{ + .help = "Exit to desktop", + .info = "Exit to desktop", + .aliases = {"exit","quit"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(exitGameCommand); + + Command thumbsUpCommand{ + .help = "Oh, yeah!", + .info = "Oh, yeah!", + .aliases = {"thumb","thumbs","thumbsup"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(thumbsUpCommand); + + Command victoryCommand{ + .help = "Victory!", + .info = "Victory!", + .aliases = {"victory!"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(victoryCommand); + + Command backflipCommand{ + .help = "Do a flip!", + .info = "Do a flip!", + .aliases = {"backflip"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(backflipCommand); + + Command clapCommand{ + .help = "A round of applause!", + .info = "A round of applause!", + .aliases = {"clap"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(clapCommand); + + Command logoutCharacterCommand{ + .help = "Returns you to the character select screen.", + .info = "Returns you to the character select screen.", + .aliases = {"camp","logoutcharacter"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(logoutCharacterCommand); + + Command sayCommand{ + .help = "Say something outloud so that everyone can hear you", + .info = "Say something outloud so that everyone can hear you", + .aliases = {"s","say"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(sayCommand); + + Command whisperCommand{ + .help = "Send a private message to another player.", + .info = "Send a private message to another player.", + .aliases = {"tell","w","whisper"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(whisperCommand); + + Command locationCommand{ + .help = "Output your current location on the map to the chat box.", + .info = "Output your current location on the map to the chat box.", + .aliases = {"loc","locate","location"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(locationCommand); + + Command logoutCommand{ + .help = "Returns you to the login screen.", + .info = "Returns you to the login screen.", + .aliases = {"logout","logoutaccount"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(logoutCommand); + + Command shrugCommand{ + .help = "I dunno...", + .info = "I dunno...", + .aliases = {"shrug"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(shrugCommand); + + Command leaveTeamCommand{ + .help = "Leave your current team.", + .info = "Leave your current team.", + .aliases = {"leave","leaveteam","teamleave","tleave"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(leaveTeamCommand); + + Command teamLootTypeCommand{ + .help = "[rr|ffa] Set the loot for your current team (round-robin/free for all).", + .info = "[rr|ffa] Set the loot for your current team (round-robin/free for all).", + .aliases = {"setloot","teamsetloot","tloot","tsetloot"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(teamLootTypeCommand); + + Command removeFriendCommand{ + .help = "[name] Removes a player from your friends list.", + .info = "[name] Removes a player from your friends list.", + .aliases = {"removefriend"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(removeFriendCommand); + + Command yesCommand{ + .help = "Aye aye, captain!", + .info = "Aye aye, captain!", + .aliases = {"yes"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(yesCommand); + + Command teamInviteCommand{ + .help = "[name] Invite a player to your team.", + .info = "[name] Invite a player to your team.", + .aliases = {"invite","inviteteam","teaminvite","tinvite"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(teamInviteCommand); + + Command danceCommand{ + .help = "Dance 'til you can't dance no more.", + .info = "Dance 'til you can't dance no more.", + .aliases = {"dance"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(danceCommand); + + Command sighCommand{ + .help = "Another day, another brick.", + .info = "Another day, another brick.", + .aliases = {"sigh"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(sighCommand); + + Command recommendedOptionsCommand{ + .help = "Sets the recommended performance options in the cfg file", + .info = "Sets the recommended performance options in the cfg file", + .aliases = {"recommendedperfoptions"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(recommendedOptionsCommand); + + Command setTeamLeaderCommand{ + .help = "[name] Set the leader for your current team.", + .info = "[name] Set the leader for your current team.", + .aliases = {"leader","setleader","teamsetleader","tleader","tsetleader"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(setTeamLeaderCommand); + + Command cringeCommand{ + .help = "I don't even want to talk about it...", + .info = "I don't even want to talk about it...", + .aliases = {"cringe"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(cringeCommand); + + Command talkCommand{ + .help = "Jibber Jabber", + .info = "Jibber Jabber", + .aliases = {"talk"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(talkCommand); + + Command cancelQueueCommand{ + .help = "Cancel Your position in the queue if you are in one.", + .info = "Cancel Your position in the queue if you are in one.", + .aliases = {"cancelqueue"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(cancelQueueCommand); + + Command lowPerformanceCommand{ + .help = "Sets the default low-spec performance options in the cfg file", + .info = "Sets the default low-spec performance options in the cfg file", + .aliases = {"perfoptionslow"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(lowPerformanceCommand); + + Command kickFromTeamCommand{ + .help = "[name] Kick a player from your current team.", + .info = "[name] Kick a player from your current team.", + .aliases = {"kick","kickplayer","teamkickplayer","tkick","tkickplayer"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(kickFromTeamCommand); + + Command thanksCommand{ + .help = "Express your gratitude for another.", + .info = "Express your gratitude for another.", + .aliases = {"thanks"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(thanksCommand); + + Command waveCommand{ + .help = "Wave to other players.", + .info = "Wave to other players.", + .aliases = {"wave"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(waveCommand); + + Command whyCommand{ + .help = "Why|!?!!", + .info = "Why|!?!!", + .aliases = {"why"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(whyCommand); + + Command midPerformanceCommand{ + .help = "Sets the default medium-spec performance options in the cfg file", + .info = "Sets the default medium-spec performance options in the cfg file", + .aliases = {"perfoptionsmid"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(midPerformanceCommand); + + Command highPerformanceCommand{ + .help = "Sets the default high-spec performance options in the cfg file", + .info = "Sets the default high-spec performance options in the cfg file", + .aliases = {"perfoptionshigh"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(highPerformanceCommand); + + Command gaspCommand{ + .help = "Oh my goodness!", + .info = "Oh my goodness!", + .aliases = {"gasp"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(gaspCommand); + + Command ignoreCommand{ + .help = "[name] Add a player to your ignore list.", + .info = "[name] Add a player to your ignore list.", + .aliases = {"addignore"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(ignoreCommand); + + Command addFriendCommand{ + .help = "[name] Add a player to your friends list.", + .info = "[name] Add a player to your friends list.", + .aliases = {"addfriend"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(addFriendCommand); + + Command cryCommand{ + .help = "Show everyone your 'Aw' face.", + .info = "Show everyone your 'Aw' face.", + .aliases = {"cry"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(cryCommand); + + Command giggleCommand{ + .help = "A good little chuckle", + .info = "A good little chuckle", + .aliases = {"giggle"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(giggleCommand); + + Command saluteCommand{ + .help = "For those about to build...", + .info = "For those about to build...", + .aliases = {"salute"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(saluteCommand); + + Command removeIgnoreCommand{ + .help = "[name] Removes a player from your ignore list.", + .info = "[name] Removes a player from your ignore list.", + .aliases = {"removeIgnore"}, + .handle = GMZeroCommands::ClientHandled, + .requiredLevel = eGameMasterLevel::CIVILIAN + }; + RegisterCommand(removeIgnoreCommand); +} diff --git a/dGame/dUtilities/SlashCommandHandler.h b/dGame/dUtilities/SlashCommandHandler.h index 85b7c6976..6a94dd3b1 100644 --- a/dGame/dUtilities/SlashCommandHandler.h +++ b/dGame/dUtilities/SlashCommandHandler.h @@ -7,13 +7,28 @@ #define SLASHCOMMANDHANDLER_H #include "RakNetTypes.h" +#include "eGameMasterLevel.h" #include <string> class Entity; +struct Command { + std::string help; + std::string info; + std::vector<std::string> aliases; + std::function<void(Entity*, const SystemAddress&,const std::string)> handle; + eGameMasterLevel requiredLevel = eGameMasterLevel::OPERATOR; +}; + namespace SlashCommandHandler { void HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr); void SendAnnouncement(const std::string& title, const std::string& message); + void RegisterCommand(Command info); + void Startup(); }; +namespace GMZeroCommands { + void Help(Entity* entity, const SystemAddress& sysAddr, const std::string args); +} + #endif // SLASHCOMMANDHANDLER_H diff --git a/dGame/dUtilities/SlashCommands/CMakeLists.txt b/dGame/dUtilities/SlashCommands/CMakeLists.txt new file mode 100644 index 000000000..999cd0ec0 --- /dev/null +++ b/dGame/dUtilities/SlashCommands/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DGAME_DUTILITIES_SLASHCOMMANDS + "DEVGMCommands.cpp" + "GMGreaterThanZeroCommands.cpp" + "GMZeroCommands.cpp" + PARENT_SCOPE +) diff --git a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp new file mode 100644 index 000000000..37fba9115 --- /dev/null +++ b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp @@ -0,0 +1,1598 @@ +#include "DEVGMCommands.h" + +// Classes +#include "AssetManager.h" +#include "Character.h" +#include "ChatPackets.h" +#include "dConfig.h" +#include "dNavMesh.h" +#include "dpWorld.h" +#include "dServer.h" +#include "dpShapeSphere.h" +#include "dZoneManager.h" +#include "EntityInfo.h" +#include "Metrics.hpp" +#include "PlayerManager.h" +#include "SlashCommandHandler.h" +#include "UserManager.h" +#include "User.h" +#include "VanityUtilities.h" +#include "WorldPackets.h" +#include "ZoneInstanceManager.h" + +// Database +#include "Database.h" +#include "CDObjectsTable.h" +#include "CDRewardCodesTable.h" + +// Components +#include "BuffComponent.h" +#include "CharacterComponent.h" +#include "ControllablePhysicsComponent.h" +#include "DestroyableComponent.h" +#include "HavokVehiclePhysicsComponent.h" +#include "InventoryComponent.h" +#include "LevelProgressionComponent.h" +#include "MissionComponent.h" +#include "MovingPlatformComponent.h" +#include "PossessorComponent.h" +#include "ProximityMonitorComponent.h" +#include "RenderComponent.h" +#include "ScriptedActivityComponent.h" +#include "SkillComponent.h" +#include "TriggerComponent.h" +#include "RigidbodyPhantomPhysicsComponent.h" + +// Enums +#include "eGameMasterLevel.h" +#include "MessageType/Master.h" +#include "eInventoryType.h" +#include "ePlayerFlag.h" + + +namespace DEVGMCommands { + void SetGMLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + User* user = UserManager::Instance()->GetUser(entity->GetSystemAddress()); + + const auto level_intermed = GeneralUtils::TryParse<uint32_t>(args); + if (!level_intermed) { + GameMessages::SendSlashCommandFeedbackText(entity, u"Invalid GM level."); + return; + } + eGameMasterLevel level = static_cast<eGameMasterLevel>(level_intermed.value()); + +#ifndef DEVELOPER_SERVER + if (user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER) { + level = eGameMasterLevel::CIVILIAN; + } +#endif + + if (level > user->GetMaxGMLevel()) level = user->GetMaxGMLevel(); + + if (level == entity->GetGMLevel()) return; + bool success = user->GetMaxGMLevel() >= level; + + if (success) { + WorldPackets::SendGMLevelChange(entity->GetSystemAddress(), success, user->GetMaxGMLevel(), entity->GetGMLevel(), level); + GameMessages::SendChatModeUpdate(entity->GetObjectID(), level); + entity->SetGMLevel(level); + LOG("User %s (%i) has changed their GM level to %i for charID %llu", user->GetUsername().c_str(), user->GetAccountID(), level, entity->GetObjectID()); + } + +#ifndef DEVELOPER_SERVER + if ((entity->GetGMLevel() > user->GetMaxGMLevel()) || (entity->GetGMLevel() > eGameMasterLevel::CIVILIAN && user->GetMaxGMLevel() == eGameMasterLevel::JUNIOR_DEVELOPER)) { + WorldPackets::SendGMLevelChange(entity->GetSystemAddress(), true, user->GetMaxGMLevel(), entity->GetGMLevel(), eGameMasterLevel::CIVILIAN); + GameMessages::SendChatModeUpdate(entity->GetObjectID(), eGameMasterLevel::CIVILIAN); + entity->SetGMLevel(eGameMasterLevel::CIVILIAN); + + GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendSlashCommandFeedbackText(entity, u"Your game master level has been changed, you may not be able to use all commands."); + } +#endif + } + + + void ToggleNameplate(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if ((Game::config->GetValue("allow_nameplate_off") != "1" && entity->GetGMLevel() < eGameMasterLevel::DEVELOPER)) return; + + auto* character = entity->GetCharacter(); + if (character && character->GetBillboardVisible()) { + character->SetBillboardVisible(false); + GameMessages::SendSlashCommandFeedbackText(entity, u"Your nameplate has been turned off and is not visible to players currently in this zone."); + } else { + character->SetBillboardVisible(true); + GameMessages::SendSlashCommandFeedbackText(entity, u"Your nameplate is now on and visible to all players."); + } + } + + void ToggleSkipCinematics(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1" && entity->GetGMLevel() < eGameMasterLevel::DEVELOPER) return; + auto* character = entity->GetCharacter(); + if (!character) return; + bool current = character->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS); + character->SetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS, !current); + if (!current) { + GameMessages::SendSlashCommandFeedbackText(entity, u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now."); + } else { + GameMessages::SendSlashCommandFeedbackText(entity, u"Cinematics will no longer be skipped."); + } + } + + void ResetMission(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto missionId = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!missionId) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission ID."); + return; + } + + auto* missionComponent = entity->GetComponent<MissionComponent>(); + if (!missionComponent) return; + missionComponent->ResetMission(missionId.value()); + } + + void SetMinifig(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + const auto minifigItemIdExists = GeneralUtils::TryParse<int32_t>(splitArgs[1]); + if (!minifigItemIdExists) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig Item Id ID."); + return; + } + const int32_t minifigItemId = minifigItemIdExists.value(); + Game::entityManager->DestructEntity(entity, sysAddr); + auto* charComp = entity->GetComponent<CharacterComponent>(); + std::string lowerName = splitArgs[0]; + if (lowerName.empty()) return; + std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); + if (lowerName == "eyebrows") { + charComp->m_Character->SetEyebrows(minifigItemId); + } else if (lowerName == "eyes") { + charComp->m_Character->SetEyes(minifigItemId); + } else if (lowerName == "haircolor") { + charComp->m_Character->SetHairColor(minifigItemId); + } else if (lowerName == "hairstyle") { + charComp->m_Character->SetHairStyle(minifigItemId); + } else if (lowerName == "pants") { + charComp->m_Character->SetPantsColor(minifigItemId); + } else if (lowerName == "lefthand") { + charComp->m_Character->SetLeftHand(minifigItemId); + } else if (lowerName == "mouth") { + charComp->m_Character->SetMouth(minifigItemId); + } else if (lowerName == "righthand") { + charComp->m_Character->SetRightHand(minifigItemId); + } else if (lowerName == "shirtcolor") { + charComp->m_Character->SetShirtColor(minifigItemId); + } else if (lowerName == "hands") { + charComp->m_Character->SetLeftHand(minifigItemId); + charComp->m_Character->SetRightHand(minifigItemId); + } else { + Game::entityManager->ConstructEntity(entity); + ChatPackets::SendSystemMessage(sysAddr, u"Invalid Minifig item to change, try one of the following: Eyebrows, Eyes, HairColor, HairStyle, Pants, LeftHand, Mouth, RightHand, Shirt, Hands"); + return; + } + + Game::entityManager->ConstructEntity(entity); + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(lowerName) + u" set to " + (GeneralUtils::to_u16string(minifigItemId))); + + GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); // need to retoggle because it gets reenabled on creation of new character + } + + void PlayAnimation(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + std::u16string anim = GeneralUtils::ASCIIToUTF16(splitArgs[0], splitArgs[0].size()); + RenderComponent::PlayAnimation(entity, anim); + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + if (possessorComponent) { + auto* possessedComponent = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + if (possessedComponent) RenderComponent::PlayAnimation(possessedComponent, anim); + } + } + + void ListSpawns(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + for (const auto& pair : Game::entityManager->GetSpawnPointEntities()) { + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(pair.first)); + } + + ChatPackets::SendSystemMessage(sysAddr, u"Current: " + GeneralUtils::ASCIIToUTF16(entity->GetCharacter()->GetTargetScene())); + } + + void UnlockEmote(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto emoteID = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!emoteID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid emote ID."); + return; + } + + entity->GetCharacter()->UnlockEmote(emoteID.value()); + } + + void ForceSave(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + entity->GetCharacter()->SaveXMLToDatabase(); + } + + void Kill(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + ChatPackets::SendSystemMessage(sysAddr, u"Brutally murdering that player, if online on this server."); + + auto* player = PlayerManager::GetPlayer(splitArgs[0]); + if (player) { + player->Smash(entity->GetObjectID()); + ChatPackets::SendSystemMessage(sysAddr, u"It has been done, do you feel good about yourself now?"); + return; + } + + ChatPackets::SendSystemMessage(sysAddr, u"They were saved from your carnage."); + return; + } + + void SpeedBoost(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto boostOptional = GeneralUtils::TryParse<float>(splitArgs[0]); + if (!boostOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost."); + return; + } + const float boost = boostOptional.value(); + + auto* controllablePhysicsComponent = entity->GetComponent<ControllablePhysicsComponent>(); + + if (!controllablePhysicsComponent) return; + controllablePhysicsComponent->SetSpeedMultiplier(boost); + + // speedboost possessables + auto possessor = entity->GetComponent<PossessorComponent>(); + if (possessor) { + auto possessedID = possessor->GetPossessable(); + if (possessedID != LWOOBJID_EMPTY) { + auto possessable = Game::entityManager->GetEntity(possessedID); + if (possessable) { + auto* possessControllablePhysicsComponent = possessable->GetComponent<ControllablePhysicsComponent>(); + if (possessControllablePhysicsComponent) { + possessControllablePhysicsComponent->SetSpeedMultiplier(boost); + } + } + } + } + + Game::entityManager->SerializeEntity(entity); + } + + void Freecam(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto state = !entity->GetVar<bool>(u"freecam"); + entity->SetVar<bool>(u"freecam", state); + + GameMessages::SendSetPlayerControlScheme(entity, static_cast<eControlScheme>(state ? 9 : 1)); + + ChatPackets::SendSystemMessage(sysAddr, u"Toggled freecam."); + } + + void SetControlScheme(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto scheme = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + + if (!scheme) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid control scheme."); + return; + } + + GameMessages::SendSetPlayerControlScheme(entity, static_cast<eControlScheme>(scheme.value())); + + ChatPackets::SendSystemMessage(sysAddr, u"Switched control scheme."); + } + + void SetUiState(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + AMFArrayValue uiState; + + uiState.Insert("state", splitArgs[0]); + + GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, "pushGameState", uiState); + + ChatPackets::SendSystemMessage(sysAddr, u"Switched UI state."); + } + + void Toggle(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + AMFArrayValue amfArgs; + + amfArgs.Insert("visible", true); + + GameMessages::SendUIMessageServerToSingleClient(entity, sysAddr, splitArgs[0], amfArgs); + + ChatPackets::SendSystemMessage(sysAddr, u"Toggled UI state."); + } + + void SetInventorySize(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto sizeOptional = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!sizeOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid size."); + return; + } + const uint32_t size = sizeOptional.value(); + + eInventoryType selectedInventory = eInventoryType::ITEMS; + + // a possible inventory was provided if we got more than 1 argument + if (splitArgs.size() >= 2) { + selectedInventory = GeneralUtils::TryParse<eInventoryType>(splitArgs.at(1)).value_or(eInventoryType::INVALID); + if (selectedInventory == eInventoryType::INVALID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory."); + return; + } else { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(splitArgs.at(1).begin(), splitArgs.at(1).end(), splitArgs.at(1).begin(), ::toupper); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(splitArgs.at(1)) == std::string_view(InventoryType::InventoryTypeToString(static_cast<eInventoryType>(index)))) selectedInventory = static_cast<eInventoryType>(index); + } + } + + ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory " + + GeneralUtils::ASCIIToUTF16(splitArgs.at(1)) + + u" to size " + + GeneralUtils::to_u16string(size)); + } else ChatPackets::SendSystemMessage(sysAddr, u"Setting inventory ITEMS to size " + GeneralUtils::to_u16string(size)); + + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (inventoryComponent) { + auto* inventory = inventoryComponent->GetInventory(selectedInventory); + + inventory->SetSize(size); + } + } + + void RunMacro(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + // Only process if input does not contain separator charaters + if (splitArgs[0].find("/") != std::string::npos) return; + if (splitArgs[0].find("\\") != std::string::npos) return; + + auto infile = Game::assetManager->GetFile(("macros/" + splitArgs[0] + ".scm").c_str()); + + if (!infile) { + ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); + return; + } + + if (infile.good()) { + std::string line; + while (std::getline(infile, line)) { + // Do this in two separate calls to catch both \n and \r\n + line.erase(std::remove(line.begin(), line.end(), '\n'), line.end()); + line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); + SlashCommandHandler::HandleChatCommand(GeneralUtils::ASCIIToUTF16(line), entity, sysAddr); + } + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Unknown macro! Is the filename right?"); + } + } + + void AddMission(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto missionID = GeneralUtils::TryParse<uint32_t>(splitArgs.at(0)); + + if (!missionID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); + return; + } + + auto comp = static_cast<MissionComponent*>(entity->GetComponent(eReplicaComponentType::MISSION)); + if (comp) comp->AcceptMission(missionID.value(), true); + } + + void CompleteMission(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto missionID = GeneralUtils::TryParse<uint32_t>(splitArgs.at(0)); + + if (!missionID) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid mission id."); + return; + } + + auto comp = static_cast<MissionComponent*>(entity->GetComponent(eReplicaComponentType::MISSION)); + if (comp) comp->CompleteMission(missionID.value(), true); + } + + void SetFlag(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() == 1) { + const auto flagId = GeneralUtils::TryParse<int32_t>(splitArgs.at(0)); + + if (!flagId) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); + return; + } + + entity->GetCharacter()->SetPlayerFlag(flagId.value(), true); + } else if (splitArgs.size() >= 2) { + const auto flagId = GeneralUtils::TryParse<int32_t>(splitArgs.at(1)); + std::string onOffFlag = splitArgs.at(0); + if (!flagId) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); + return; + } + + if (onOffFlag != "off" && onOffFlag != "on") { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag type."); + return; + } + + entity->GetCharacter()->SetPlayerFlag(flagId.value(), onOffFlag == "on"); + } + } + + void ClearFlag(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto flagId = GeneralUtils::TryParse<int32_t>(splitArgs.at(0)); + + if (!flagId) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid flag id."); + return; + } + + entity->GetCharacter()->SetPlayerFlag(flagId.value(), false); + } + + void PlayEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 3) return; + + const auto effectID = GeneralUtils::TryParse<int32_t>(splitArgs.at(0)); + + if (!effectID) return; + + // FIXME: use fallible ASCIIToUTF16 conversion, because non-ascii isn't valid anyway + GameMessages::SendPlayFXEffect(entity->GetObjectID(), effectID.value(), GeneralUtils::ASCIIToUTF16(splitArgs.at(1)), splitArgs.at(2)); + } + + void StopEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + GameMessages::SendStopFXEffect(entity, true, splitArgs[0]); + } + + void SetAnnTitle(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + entity->GetCharacter()->SetAnnouncementTitle(args); + } + + void SetAnnMsg(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + entity->GetCharacter()->SetAnnouncementMessage(args); + } + + void Announce(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (entity->GetCharacter()->GetAnnouncementTitle().empty() || entity->GetCharacter()->GetAnnouncementMessage().empty()) { + ChatPackets::SendSystemMessage(sysAddr, u"Use /setanntitle <title> & /setannmsg <msg> first!"); + return; + } + + SlashCommandHandler::SendAnnouncement(entity->GetCharacter()->GetAnnouncementTitle(), entity->GetCharacter()->GetAnnouncementMessage()); + } + + void ShutdownUniverse(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + //Tell the master server that we're going to be shutting down whole "universe": + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::SHUTDOWN_UNIVERSE); + Game::server->SendToMaster(bitStream); + ChatPackets::SendSystemMessage(sysAddr, u"Sent universe shutdown notification to master."); + + //Tell chat to send an announcement to all servers + SlashCommandHandler::SendAnnouncement("Servers Closing Soon!", "DLU servers will close for maintenance in 10 minutes from now."); + } + + void GetNavmeshHeight(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto control = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); + if (!control) return; + + float y = dpWorld::GetNavMesh()->GetHeightAtPoint(control->GetPosition()); + std::u16string msg = u"Navmesh height: " + (GeneralUtils::to_u16string(y)); + ChatPackets::SendSystemMessage(sysAddr, msg); + } + + void GmAddItem(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + if (splitArgs.size() == 1) { + const auto itemLOT = GeneralUtils::TryParse<uint32_t>(splitArgs.at(0)); + + if (!itemLOT) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); + return; + } + + InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); + + inventory->AddItem(itemLOT.value(), 1, eLootSourceType::MODERATION); + } else if (splitArgs.size() == 2) { + const auto itemLOT = GeneralUtils::TryParse<uint32_t>(splitArgs.at(0)); + if (!itemLOT) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item LOT."); + return; + } + + const auto count = GeneralUtils::TryParse<uint32_t>(splitArgs.at(1)); + if (!count) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item count."); + return; + } + + InventoryComponent* inventory = static_cast<InventoryComponent*>(entity->GetComponent(eReplicaComponentType::INVENTORY)); + + inventory->AddItem(itemLOT.value(), count.value(), eLootSourceType::MODERATION); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /gmadditem <lot>"); + } + } + + void Teleport(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + NiPoint3 pos{}; + if (splitArgs.size() == 3) { + + const auto x = GeneralUtils::TryParse<float>(splitArgs.at(0)); + if (!x) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); + return; + } + + const auto y = GeneralUtils::TryParse<float>(splitArgs.at(1)); + if (!y) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid y."); + return; + } + + const auto z = GeneralUtils::TryParse<float>(splitArgs.at(2)); + if (!z) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); + return; + } + + pos.SetX(x.value()); + pos.SetY(y.value()); + pos.SetZ(z.value()); + + LOG("Teleporting objectID: %llu to %f, %f, %f", entity->GetObjectID(), pos.x, pos.y, pos.z); + GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } else if (splitArgs.size() == 2) { + + const auto x = GeneralUtils::TryParse<float>(splitArgs.at(0)); + if (!x) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid x."); + return; + } + + const auto z = GeneralUtils::TryParse<float>(splitArgs.at(1)); + if (!z) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid z."); + return; + } + + pos.SetX(x.value()); + pos.SetY(0.0f); + pos.SetZ(z.value()); + + LOG("Teleporting objectID: %llu to X: %f, Z: %f", entity->GetObjectID(), pos.x, pos.z); + GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport <x> (<y>) <z> - if no Y given, will teleport to the height of the terrain (or any physics object)."); + } + + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + if (possessorComponent) { + auto* possassableEntity = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + + if (possassableEntity != nullptr) { + auto* havokVehiclePhysicsComponent = possassableEntity->GetComponent<HavokVehiclePhysicsComponent>(); + if (havokVehiclePhysicsComponent) { + havokVehiclePhysicsComponent->SetPosition(pos); + Game::entityManager->SerializeEntity(possassableEntity); + } else GameMessages::SendTeleport(possassableEntity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } + } + } + + void TpAll(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto pos = entity->GetPosition(); + + const auto characters = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); + + for (auto* character : characters) { + GameMessages::SendTeleport(character->GetObjectID(), pos, NiQuaternion(), character->GetSystemAddress()); + } + } + + void Dismount(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + if (possessorComponent) { + auto possessableId = possessorComponent->GetPossessable(); + if (possessableId != LWOOBJID_EMPTY) { + auto* possessableEntity = Game::entityManager->GetEntity(possessableId); + if (possessableEntity) possessorComponent->Dismount(possessableEntity, true); + } + } + } + + void BuffMe(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); + if (dest) { + dest->SetHealth(999); + dest->SetMaxHealth(999.0f); + dest->SetArmor(999); + dest->SetMaxArmor(999.0f); + dest->SetImagination(999); + dest->SetMaxImagination(999.0f); + } + Game::entityManager->SerializeEntity(entity); + } + + void StartCelebration(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto celebration = GeneralUtils::TryParse<int32_t>(splitArgs.at(0)); + + if (!celebration) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid celebration."); + return; + } + + GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration.value()); + } + + void BuffMed(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); + if (dest) { + dest->SetHealth(9); + dest->SetMaxHealth(9.0f); + dest->SetArmor(9); + dest->SetMaxArmor(9.0f); + dest->SetImagination(9); + dest->SetMaxImagination(9.0f); + } + Game::entityManager->SerializeEntity(entity); + } + + void RefillStats(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE)); + if (dest) { + dest->SetHealth(static_cast<int32_t>(dest->GetMaxHealth())); + dest->SetArmor(static_cast<int32_t>(dest->GetMaxArmor())); + dest->SetImagination(static_cast<int32_t>(dest->GetMaxImagination())); + } + + Game::entityManager->SerializeEntity(entity); + } + + void Lookup(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE ?1 OR `name` LIKE ?1 OR `description` LIKE ?1 LIMIT 50"); + + const std::string query_text = "%" + args + "%"; + query.bind(1, query_text.c_str()); + + auto tables = query.execQuery(); + + while (!tables.eof()) { + std::string message = std::to_string(tables.getIntField("id")) + " - " + tables.getStringField("name"); + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(message, message.size())); + tables.nextRow(); + } + } + + void Spawn(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + ControllablePhysicsComponent* comp = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS)); + if (!comp) return; + + const auto lot = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + + if (!lot) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); + return; + } + + EntityInfo info; + info.lot = lot.value(); + info.pos = comp->GetPosition(); + info.rot = comp->GetRotation(); + info.spawner = nullptr; + info.spawnerID = entity->GetObjectID(); + info.spawnerNodeID = 0; + + Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr); + + if (newEntity == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); + return; + } + + Game::entityManager->ConstructEntity(newEntity); + } + + void SpawnGroup(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 3) return; + + const auto lot = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!lot) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid lot."); + return; + } + + const auto numberToSpawnOptional = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!numberToSpawnOptional && numberToSpawnOptional.value() > 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid number of enemies to spawn."); + return; + } + uint32_t numberToSpawn = numberToSpawnOptional.value(); + + // Must spawn within a radius of at least 0.0f + const auto radiusToSpawnWithinOptional = GeneralUtils::TryParse<float>(splitArgs[2]); + if (!radiusToSpawnWithinOptional && radiusToSpawnWithinOptional.value() < 0.0f) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid radius to spawn within."); + return; + } + const float radiusToSpawnWithin = radiusToSpawnWithinOptional.value(); + + EntityInfo info; + info.lot = lot.value(); + info.spawner = nullptr; + info.spawnerID = entity->GetObjectID(); + info.spawnerNodeID = 0; + + auto playerPosition = entity->GetPosition(); + while (numberToSpawn > 0) { + auto randomAngle = GeneralUtils::GenerateRandomNumber<float>(0.0f, 2 * PI); + auto randomRadius = GeneralUtils::GenerateRandomNumber<float>(0.0f, radiusToSpawnWithin); + + // Set the position to the generated random position plus the player position. This will + // spawn the entity in a circle around the player. As you get further from the player, the angle chosen will get less accurate. + info.pos = playerPosition + NiPoint3(cos(randomAngle) * randomRadius, 0.0f, sin(randomAngle) * randomRadius); + info.rot = NiQuaternion(); + + auto newEntity = Game::entityManager->CreateEntity(info); + if (newEntity == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to spawn entity."); + return; + } + + Game::entityManager->ConstructEntity(newEntity); + numberToSpawn--; + } + } + + void GiveUScore(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto uscoreOptional = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + if (!uscoreOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid uscore."); + return; + } + const int32_t uscore = uscoreOptional.value(); + + CharacterComponent* character = entity->GetComponent<CharacterComponent>(); + if (character) character->SetUScore(character->GetUScore() + uscore); + // MODERATION should work but it doesn't. Relog to see uscore changes + + eLootSourceType lootType = eLootSourceType::MODERATION; + + if (splitArgs.size() >= 2) { + const auto type = GeneralUtils::TryParse<eLootSourceType>(splitArgs[1]); + lootType = type.value_or(lootType); + } + + GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, lootType); + } + + void SetLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + // We may be trying to set a specific players level to a level. If so override the entity with the requested players. + std::string requestedPlayerToSetLevelOf = ""; + if (splitArgs.size() > 1) { + requestedPlayerToSetLevelOf = splitArgs[1]; + + auto requestedPlayer = PlayerManager::GetPlayer(requestedPlayerToSetLevelOf); + + if (!requestedPlayer) { + ChatPackets::SendSystemMessage(sysAddr, u"No player found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); + return; + } + + if (!requestedPlayer->GetOwner()) { + ChatPackets::SendSystemMessage(sysAddr, u"No entity found with username: (" + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u")."); + return; + } + + entity = requestedPlayer->GetOwner(); + } + const auto requestedLevelOptional = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + uint32_t oldLevel; + + // first check the level is valid + if (!requestedLevelOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid level."); + return; + } + uint32_t requestedLevel = requestedLevelOptional.value(); + // query to set our uscore to the correct value for this level + + auto characterComponent = entity->GetComponent<CharacterComponent>(); + if (!characterComponent) return; + auto levelComponent = entity->GetComponent<LevelProgressionComponent>(); + auto query = CDClientDatabase::CreatePreppedStmt("SELECT requiredUScore from LevelProgressionLookup WHERE id = ?;"); + query.bind(1, static_cast<int>(requestedLevel)); + auto result = query.execQuery(); + + if (result.eof()) return; + + // Set the UScore first + oldLevel = levelComponent->GetLevel(); + characterComponent->SetUScore(result.getIntField(0, characterComponent->GetUScore())); + + // handle level up for each level we have passed if we set our level to be higher than the current one. + if (oldLevel < requestedLevel) { + while (oldLevel < requestedLevel) { + oldLevel += 1; + levelComponent->SetLevel(oldLevel); + levelComponent->HandleLevelUp(); + } + } else { + levelComponent->SetLevel(requestedLevel); + } + + if (requestedPlayerToSetLevelOf != "") { + ChatPackets::SendSystemMessage( + sysAddr, u"Set " + GeneralUtils::UTF8ToUTF16(requestedPlayerToSetLevelOf) + u"'s level to " + GeneralUtils::to_u16string(requestedLevel) + + u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + + u". Relog to see changes."); + } else { + ChatPackets::SendSystemMessage( + sysAddr, u"Set your level to " + GeneralUtils::to_u16string(requestedLevel) + + u" and UScore to " + GeneralUtils::to_u16string(characterComponent->GetUScore()) + + u". Relog to see changes."); + } + } + + void Pos(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto position = entity->GetPosition(); + + ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">"); + + LOG("Position: %f, %f, %f", position.x, position.y, position.z); + } + + void Rot(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto rotation = entity->GetRotation(); + + ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">"); + + LOG("Rotation: %f, %f, %f, %f", rotation.w, rotation.x, rotation.y, rotation.z); + } + + void LocRow(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto position = entity->GetPosition(); + const auto rotation = entity->GetRotation(); + + LOG("<location x=\"%f\" y=\"%f\" z=\"%f\" rw=\"%f\" rx=\"%f\" ry=\"%f\" rz=\"%f\" />", position.x, position.y, position.z, rotation.w, rotation.x, rotation.y, rotation.z); + } + + void PlayLvlFx(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + GameMessages::SendPlayFXEffect(entity, 7074, u"create", "7074", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + } + + void PlayRebuildFx(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + GameMessages::SendPlayFXEffect(entity, 230, u"rebuild", "230", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + } + + void FreeMoney(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto money = GeneralUtils::TryParse<int64_t>(splitArgs[0]); + + if (!money) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); + return; + } + + auto* ch = entity->GetCharacter(); + ch->SetCoins(ch->GetCoins() + money.value(), eLootSourceType::MODERATION); + } + + void SetCurrency(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + const auto money = GeneralUtils::TryParse<int64_t>(splitArgs[0]); + + if (!money) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid money."); + return; + } + + auto* ch = entity->GetCharacter(); + ch->SetCoins(money.value(), eLootSourceType::MODERATION); + } + + void Buff(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + auto* buffComponent = entity->GetComponent<BuffComponent>(); + + const auto id = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + if (!id) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff id."); + return; + } + + const auto duration = GeneralUtils::TryParse<int32_t>(splitArgs[1]); + if (!duration) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid buff duration."); + return; + } + + if (buffComponent) buffComponent->ApplyBuff(id.value(), duration.value(), entity->GetObjectID()); + } + + void TestMap(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + ChatPackets::SendSystemMessage(sysAddr, u"Requesting map change..."); + LWOCLONEID cloneId = 0; + bool force = false; + + const auto reqZoneOptional = GeneralUtils::TryParse<LWOMAPID>(splitArgs[0]); + if (!reqZoneOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); + return; + } + const LWOMAPID reqZone = reqZoneOptional.value(); + + if (splitArgs.size() > 1) { + auto index = 1; + + if (splitArgs[index] == "force") { + index++; + + force = true; + } + + if (splitArgs.size() > index) { + const auto cloneIdOptional = GeneralUtils::TryParse<LWOCLONEID>(splitArgs[index]); + if (!cloneIdOptional) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone id."); + return; + } + cloneId = cloneIdOptional.value(); + } + } + + const auto objid = entity->GetObjectID(); + + if (force || Game::zoneManager->CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + + auto* entity = Game::entityManager->GetEntity(objid); + if (!entity) return; + + const auto sysAddr = entity->GetSystemAddress(); + + ChatPackets::SendSystemMessage(sysAddr, u"Transfering map..."); + + LOG("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; + }); + } else { + std::string msg = "ZoneID not found or allowed: "; + msg.append(splitArgs[0]); // FIXME: unnecessary utf16 re-encoding just for error + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(msg, msg.size())); + } + } + + void CreatePrivate(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 3) return; + + const auto zone = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!zone) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid zone."); + return; + } + + const auto clone = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!clone) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid clone."); + return; + } + + const auto& password = splitArgs[2]; + + ZoneInstanceManager::Instance()->CreatePrivateZone(Game::server, zone.value(), clone.value(), password); + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16("Sent request for private zone with password: " + password)); + } + + void DebugUi(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + ChatPackets::SendSystemMessage(sysAddr, u"Opening UIDebugger..."); + } + + void Boost(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + + if (possessorComponent == nullptr) { + return; + } + + auto* vehicle = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + + if (vehicle == nullptr) { + return; + } + + if (splitArgs.size() >= 1) { + const auto time = GeneralUtils::TryParse<float>(splitArgs[0]); + + if (!time) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid boost time."); + return; + } else { + GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + entity->AddCallbackTimer(time.value(), [vehicle]() { + if (!vehicle) return; + GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + }); + } + } else { + GameMessages::SendVehicleAddPassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + } + } + + void Unboost(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* possessorComponent = entity->GetComponent<PossessorComponent>(); + + if (possessorComponent == nullptr) return; + auto* vehicle = Game::entityManager->GetEntity(possessorComponent->GetPossessable()); + + if (vehicle == nullptr) return; + GameMessages::SendVehicleRemovePassiveBoostAction(vehicle->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS); + } + + void ActivateSpawner(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto spawners = Game::zoneManager->GetSpawnersByName(splitArgs[0]); + + for (auto* spawner : spawners) { + spawner->Activate(); + } + + spawners = Game::zoneManager->GetSpawnersInGroup(splitArgs[0]); + + for (auto* spawner : spawners) { + spawner->Activate(); + } + } + + void SpawnPhysicsVerts(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + //Go tell physics to spawn all the vertices: + auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PHANTOM_PHYSICS); + for (const auto* en : entities) { + const auto* phys = static_cast<PhantomPhysicsComponent*>(en->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); + if (phys) + phys->SpawnVertices(); + } + for (const auto* en : Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS)) { + const auto* phys = en->GetComponent<RigidbodyPhantomPhysicsComponent>(); + if (phys) + phys->SpawnVertices(); + } + } + + void ReportProxPhys(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PROXIMITY_MONITOR); + for (auto en : entities) { + auto phys = static_cast<ProximityMonitorComponent*>(en->GetComponent(eReplicaComponentType::PROXIMITY_MONITOR)); + if (phys) { + for (auto prox : phys->GetProximitiesData()) { + if (!prox.second) continue; + + auto sphere = static_cast<dpShapeSphere*>(prox.second->GetShape()); + auto pos = prox.second->GetPosition(); + LOG("Proximity: %s, r: %f, pos: %f, %f, %f", prox.first.c_str(), sphere->GetRadius(), pos.x, pos.y, pos.z); + } + } + } + } + + void TriggerSpawner(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto spawners = Game::zoneManager->GetSpawnersByName(splitArgs[0]); + + for (auto* spawner : spawners) { + spawner->Spawn(); + } + + spawners = Game::zoneManager->GetSpawnersInGroup(splitArgs[0]); + + for (auto* spawner : spawners) { + spawner->Spawn(); + } + } + + void Reforge(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + const auto baseItem = GeneralUtils::TryParse<LOT>(splitArgs[0]); + if (!baseItem) return; + + const auto reforgedItem = GeneralUtils::TryParse<LOT>(splitArgs[1]); + if (!reforgedItem) return; + + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (!inventoryComponent) return; + + std::vector<LDFBaseData*> data{}; + data.push_back(new LDFData<int32_t>(u"reforgedLOT", reforgedItem.value())); + + inventoryComponent->AddItem(baseItem.value(), 1, eLootSourceType::MODERATION, eInventoryType::INVALID, data); + } + + void Crash(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + ChatPackets::SendSystemMessage(sysAddr, u"Crashing..."); + + int* badPtr = nullptr; + *badPtr = 0; + } + + void Metrics(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + for (const auto variable : Metrics::GetAllMetrics()) { + auto* metric = Metrics::GetMetric(variable); + + if (metric == nullptr) { + continue; + } + + ChatPackets::SendSystemMessage( + sysAddr, + GeneralUtils::ASCIIToUTF16(Metrics::MetricVariableToString(variable)) + + u": " + + GeneralUtils::to_u16string(Metrics::ToMiliseconds(metric->average)) + + u"ms" + ); + } + + ChatPackets::SendSystemMessage( + sysAddr, + u"Peak RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetPeakRSS()) / 1.024e6)) + + u"MB" + ); + + ChatPackets::SendSystemMessage( + sysAddr, + u"Current RSS: " + GeneralUtils::to_u16string(static_cast<float>(static_cast<double>(Metrics::GetCurrentRSS()) / 1.024e6)) + + u"MB" + ); + + ChatPackets::SendSystemMessage( + sysAddr, + u"Process ID: " + GeneralUtils::to_u16string(Metrics::GetProcessID()) + ); + } + + void ReloadConfig(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + Game::config->ReloadConfig(); + VanityUtilities::SpawnVanity(); + dpWorld::Reload(); + auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); + for (const auto* const entity : entities) { + auto* const scriptedActivityComponent = entity->GetComponent<ScriptedActivityComponent>(); + if (!scriptedActivityComponent) continue; + + scriptedActivityComponent->ReloadConfig(); + } + Game::server->UpdateMaximumMtuSize(); + Game::server->UpdateBandwidthLimit(); + ChatPackets::SendSystemMessage(sysAddr, u"Successfully reloaded config for world!"); + } + + void RollLoot(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 3) return; + + const auto lootMatrixIndex = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + if (!lootMatrixIndex) return; + + const auto targetLot = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!targetLot) return; + + const auto loops = GeneralUtils::TryParse<uint32_t>(splitArgs[2]); + if (!loops) return; + + uint64_t totalRuns = 0; + + for (uint32_t i = 0; i < loops; i++) { + while (true) { + auto lootRoll = Loot::RollLootMatrix(lootMatrixIndex.value()); + totalRuns += 1; + bool doBreak = false; + for (const auto& kv : lootRoll) { + if (static_cast<uint32_t>(kv.first) == targetLot) { + doBreak = true; + } + } + if (doBreak) break; + } + } + + std::u16string message = u"Ran loot drops looking for " + + GeneralUtils::to_u16string(targetLot.value()) + + u", " + + GeneralUtils::to_u16string(loops.value()) + + u" times. It ran " + + GeneralUtils::to_u16string(totalRuns) + + u" times. Averaging out at " + + GeneralUtils::to_u16string(static_cast<float>(totalRuns) / loops.value()); + + ChatPackets::SendSystemMessage(sysAddr, message); + } + + void DeleteInven(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + eInventoryType inventoryType = eInventoryType::INVALID; + + const auto inventoryTypeOptional = GeneralUtils::TryParse<eInventoryType>(splitArgs[0]); + if (!inventoryTypeOptional) { + // In this case, we treat the input as a string and try to find it in the reflection list + std::transform(splitArgs[0].begin(), splitArgs[0].end(), splitArgs[0].begin(), ::toupper); + LOG("looking for inventory %s", splitArgs[0].c_str()); + for (uint32_t index = 0; index < NUMBER_OF_INVENTORIES; index++) { + if (std::string_view(splitArgs[0]) == std::string_view(InventoryType::InventoryTypeToString(static_cast<eInventoryType>(index)))) inventoryType = static_cast<eInventoryType>(index); + } + } else { + inventoryType = inventoryTypeOptional.value(); + } + + if (inventoryType == eInventoryType::INVALID || inventoryType >= NUMBER_OF_INVENTORIES) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid inventory provided."); + return; + } + + auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (!inventoryComponent) return; + + auto* inventoryToDelete = inventoryComponent->GetInventory(inventoryType); + if (!inventoryToDelete) return; + + inventoryToDelete->DeleteAllItems(); + LOG("Deleted inventory %s for user %llu", splitArgs[0].c_str(), entity->GetObjectID()); + ChatPackets::SendSystemMessage(sysAddr, u"Deleted inventory " + GeneralUtils::UTF8ToUTF16(splitArgs[0])); + } + + void CastSkill(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* skillComponent = entity->GetComponent<SkillComponent>(); + if (skillComponent) { + const auto skillId = GeneralUtils::TryParse<uint32_t>(splitArgs[0]); + + if (!skillId) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting skill ID."); + return; + } else { + skillComponent->CastSkill(skillId.value(), entity->GetObjectID(), entity->GetObjectID()); + ChatPackets::SendSystemMessage(sysAddr, u"Cast skill"); + } + } + } + + void SetSkillSlot(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + auto* const inventoryComponent = entity->GetComponent<InventoryComponent>(); + if (inventoryComponent) { + const auto slot = GeneralUtils::TryParse<BehaviorSlot>(splitArgs[0]); + if (!slot) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting slot."); + return; + } else { + const auto skillId = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!skillId) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting skill."); + return; + } else { + if (inventoryComponent->SetSkill(slot.value(), skillId.value())) ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot successfully"); + else ChatPackets::SendSystemMessage(sysAddr, u"Set skill to slot failed"); + } + } + } + } + + void SetFaction(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + const auto faction = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!faction) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting faction."); + return; + } else { + destroyableComponent->SetFaction(faction.value()); + ChatPackets::SendSystemMessage(sysAddr, u"Set faction and updated enemies list"); + } + } + } + + void AddFaction(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + const auto faction = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!faction) { + ChatPackets::SendSystemMessage(sysAddr, u"Error getting faction."); + return; + } else { + destroyableComponent->AddFaction(faction.value()); + ChatPackets::SendSystemMessage(sysAddr, u"Added faction and updated enemies list"); + } + } + } + + void GetFactions(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + if (destroyableComponent) { + ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); + for (const auto entry : destroyableComponent->GetFactionIDs()) { + ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + } + + ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); + for (const auto entry : destroyableComponent->GetEnemyFactionsIDs()) { + ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + } + } + } + + void SetRewardCode(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* character = entity->GetCharacter(); + if (!character) return; + auto* user = character->GetParentUser(); + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + auto* cdrewardCodes = CDClientManager::GetTable<CDRewardCodesTable>(); + + auto id = cdrewardCodes->GetCodeID(splitArgs[0]); + if (id != -1) Database::Get()->InsertRewardCode(user->GetAccountID(), id); + } + + void Inspect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + Entity* closest = nullptr; + + std::u16string ldf; + + bool isLDF = false; + + auto component = GeneralUtils::TryParse<eReplicaComponentType>(splitArgs[0]); + if (!component) { + component = eReplicaComponentType::INVALID; + + ldf = GeneralUtils::UTF8ToUTF16(splitArgs[0]); + + isLDF = true; + } + + auto reference = entity->GetPosition(); + + auto closestDistance = 0.0f; + + const auto candidates = Game::entityManager->GetEntitiesByComponent(component.value()); + + for (auto* candidate : candidates) { + if (candidate->GetLOT() == 1 || candidate->GetLOT() == 8092) { + continue; + } + + if (isLDF && !candidate->HasVar(ldf)) { + continue; + } + + if (!closest) { + closest = candidate; + + closestDistance = NiPoint3::Distance(candidate->GetPosition(), reference); + + continue; + } + + const auto distance = NiPoint3::Distance(candidate->GetPosition(), reference); + + if (distance < closestDistance) { + closest = candidate; + + closestDistance = distance; + } + } + + if (!closest) return; + + Game::entityManager->SerializeEntity(closest); + + auto* table = CDClientManager::GetTable<CDObjectsTable>(); + + const auto& info = table->GetByID(closest->GetLOT()); + + std::stringstream header; + + header << info.name << " [" << std::to_string(info.id) << "]" << " " << std::to_string(closestDistance) << " " << std::to_string(closest->IsSleeping()); + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(header.str())); + + for (const auto& pair : closest->GetComponents()) { + auto id = pair.first; + + std::stringstream stream; + + stream << "Component [" << std::to_string(static_cast<uint32_t>(id)) << "]"; + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(stream.str())); + } + + if (splitArgs.size() >= 2) { + if (splitArgs[1] == "-m" && splitArgs.size() >= 3) { + auto* const movingPlatformComponent = closest->GetComponent<MovingPlatformComponent>(); + + const auto mValue = GeneralUtils::TryParse<int32_t>(splitArgs[2]); + + if (!movingPlatformComponent || !mValue) return; + + movingPlatformComponent->SetSerialized(true); + + if (mValue == -1) { + movingPlatformComponent->StopPathing(); + } else { + movingPlatformComponent->GotoWaypoint(mValue.value()); + } + + Game::entityManager->SerializeEntity(closest); + } else if (splitArgs[1] == "-a" && splitArgs.size() >= 3) { + RenderComponent::PlayAnimation(closest, splitArgs.at(2)); + } else if (splitArgs[1] == "-s") { + for (auto* entry : closest->GetSettings()) { + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(entry->GetString())); + } + + ChatPackets::SendSystemMessage(sysAddr, u"------"); + ChatPackets::SendSystemMessage(sysAddr, u"Spawner ID: " + GeneralUtils::to_u16string(closest->GetSpawnerID())); + } else if (splitArgs[1] == "-p") { + const auto postion = closest->GetPosition(); + + ChatPackets::SendSystemMessage( + sysAddr, + GeneralUtils::ASCIIToUTF16("< " + std::to_string(postion.x) + ", " + std::to_string(postion.y) + ", " + std::to_string(postion.z) + " >") + ); + } else if (splitArgs[1] == "-f") { + auto* destuctable = closest->GetComponent<DestroyableComponent>(); + + if (destuctable == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); + return; + } + + ChatPackets::SendSystemMessage(sysAddr, u"Smashable: " + (GeneralUtils::to_u16string(destuctable->GetIsSmashable()))); + + ChatPackets::SendSystemMessage(sysAddr, u"Friendly factions:"); + for (const auto entry : destuctable->GetFactionIDs()) { + ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + } + + ChatPackets::SendSystemMessage(sysAddr, u"Enemy factions:"); + for (const auto entry : destuctable->GetEnemyFactionsIDs()) { + ChatPackets::SendSystemMessage(sysAddr, (GeneralUtils::to_u16string(entry))); + } + + if (splitArgs.size() >= 3) { + const auto faction = GeneralUtils::TryParse<int32_t>(splitArgs[2]); + if (!faction) return; + + destuctable->SetFaction(-1); + destuctable->AddFaction(faction.value(), true); + } + } else if (splitArgs[1] == "-cf") { + auto* destuctable = entity->GetComponent<DestroyableComponent>(); + if (!destuctable) { + ChatPackets::SendSystemMessage(sysAddr, u"No destroyable component on this entity!"); + return; + } + if (destuctable->IsEnemy(closest)) ChatPackets::SendSystemMessage(sysAddr, u"They are our enemy"); + else ChatPackets::SendSystemMessage(sysAddr, u"They are NOT our enemy"); + } else if (splitArgs[1] == "-t") { + auto* phantomPhysicsComponent = closest->GetComponent<PhantomPhysicsComponent>(); + + if (phantomPhysicsComponent != nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(static_cast<uint32_t>(phantomPhysicsComponent->GetEffectType())))); + const auto dir = phantomPhysicsComponent->GetDirection(); + ChatPackets::SendSystemMessage(sysAddr, u"Direction: <" + (GeneralUtils::to_u16string(dir.x)) + u", " + (GeneralUtils::to_u16string(dir.y)) + u", " + (GeneralUtils::to_u16string(dir.z)) + u">"); + ChatPackets::SendSystemMessage(sysAddr, u"Multiplier: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetDirectionalMultiplier()))); + ChatPackets::SendSystemMessage(sysAddr, u"Active: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetPhysicsEffectActive()))); + } + + auto* triggerComponent = closest->GetComponent<TriggerComponent>(); + if (triggerComponent) { + auto trigger = triggerComponent->GetTrigger(); + if (trigger) { + ChatPackets::SendSystemMessage(sysAddr, u"Trigger: " + (GeneralUtils::to_u16string(trigger->id))); + } + } + } + } + } +}; diff --git a/dGame/dUtilities/SlashCommands/DEVGMCommands.h b/dGame/dUtilities/SlashCommands/DEVGMCommands.h new file mode 100644 index 000000000..e03fd4dee --- /dev/null +++ b/dGame/dUtilities/SlashCommands/DEVGMCommands.h @@ -0,0 +1,78 @@ +#ifndef DEVGMCOMMANDS_H +#define DEVGMCOMMANDS_H + +namespace DEVGMCommands { + void SetGMLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ToggleNameplate(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ToggleSkipCinematics(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Kill(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Metrics(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Announce(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetAnnTitle(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetAnnMsg(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ShutdownUniverse(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetMinifig(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void TestMap(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ReportProxPhys(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SpawnPhysicsVerts(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Teleport(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ActivateSpawner(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void AddMission(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Boost(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Unboost(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Buff(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void BuffMe(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void BuffMed(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ClearFlag(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void CompleteMission(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void CreatePrivate(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void DebugUi(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Dismount(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ReloadConfig(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ForceSave(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Freecam(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void FreeMoney(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GetNavmeshHeight(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GiveUScore(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GmAddItem(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Inspect(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ListSpawns(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void LocRow(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Lookup(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PlayAnimation(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PlayEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PlayLvlFx(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void PlayRebuildFx(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Pos(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void RefillStats(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Reforge(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ResetMission(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Rot(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void RunMacro(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetControlScheme(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetCurrency(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetFlag(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetInventorySize(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetUiState(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Spawn(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SpawnGroup(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SpeedBoost(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void StartCelebration(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void StopEffect(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Toggle(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void TpAll(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void TriggerSpawner(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void UnlockEmote(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetLevel(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetSkillSlot(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetFaction(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void AddFaction(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GetFactions(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetRewardCode(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Crash(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void RollLoot(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void CastSkill(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void DeleteInven(Entity* entity, const SystemAddress& sysAddr, const std::string args); +} + +#endif //!DEVGMCOMMANDS_H diff --git a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp new file mode 100644 index 000000000..3032a33bc --- /dev/null +++ b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.cpp @@ -0,0 +1,340 @@ +#include "GMGreaterThanZeroCommands.h" + +// Classes +#include "Character.h" +#include "ChatPackets.h" +#include "dServer.h" +#include "PlayerManager.h" +#include "User.h" + +// Database +#include "Database.h" + +// Components +#include "DestroyableComponent.h" +#include "PropertyManagementComponent.h" + +// Enums +#include "MessageType/Chat.h" +#include "eServerDisconnectIdentifiers.h" +#include "eObjectBits.h" + +namespace GMGreaterThanZeroCommands { + + void Kick(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() == 1) { + auto* player = PlayerManager::GetPlayer(splitArgs[0]); + + std::u16string username = GeneralUtils::UTF8ToUTF16(splitArgs[0]); + if (player == nullptr) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + username); + return; + } + + Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::KICK); + + ChatPackets::SendSystemMessage(sysAddr, u"Kicked: " + username); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /kick <username>"); + } + } + + void Ban(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + if (splitArgs.size() == 1) { + auto* player = PlayerManager::GetPlayer(splitArgs[0]); + + uint32_t accountId = 0; + + if (player == nullptr) { + auto characterInfo = Database::Get()->GetCharacterInfo(splitArgs[0]); + + if (characterInfo) { + accountId = characterInfo->accountId; + } + + if (accountId == 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(splitArgs[0])); + + return; + } + } else { + auto* character = player->GetCharacter(); + auto* user = character != nullptr ? character->GetParentUser() : nullptr; + if (user) accountId = user->GetAccountID(); + } + + if (accountId != 0) Database::Get()->UpdateAccountBan(accountId, true); + + if (player != nullptr) { + Game::server->Disconnect(player->GetSystemAddress(), eServerDisconnectIdentifiers::FREE_TRIAL_EXPIRED); + } + + ChatPackets::SendSystemMessage(sysAddr, u"Banned: " + GeneralUtils::ASCIIToUTF16(splitArgs[0])); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /ban <username>"); + } + } + + void MailItem(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.size() < 2) return; + + const auto& playerName = splitArgs[0]; + + auto playerInfo = Database::Get()->GetCharacterInfo(playerName); + + uint32_t receiverID = 0; + if (!playerInfo) { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to find that player"); + + return; + } + + receiverID = playerInfo->id; + + const auto lot = GeneralUtils::TryParse<LOT>(splitArgs.at(1)); + + if (!lot) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid item lot."); + return; + } + + IMail::MailInfo mailInsert; + mailInsert.senderId = entity->GetObjectID(); + mailInsert.senderUsername = "Darkflame Universe"; + mailInsert.receiverId = receiverID; + mailInsert.recipient = playerName; + mailInsert.subject = "Lost item"; + mailInsert.body = "This is a replacement item for one you lost."; + mailInsert.itemID = LWOOBJID_EMPTY; + mailInsert.itemLOT = lot.value(); + mailInsert.itemSubkey = LWOOBJID_EMPTY; + mailInsert.itemCount = 1; + Database::Get()->InsertNewMail(mailInsert); + + ChatPackets::SendSystemMessage(sysAddr, u"Mail sent"); + } + + void ApproveProperty(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (PropertyManagementComponent::Instance() != nullptr) { + PropertyManagementComponent::Instance()->UpdateApprovedStatus(true); + } + } + + void Mute(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + if (splitArgs.size() >= 1) { + auto* player = PlayerManager::GetPlayer(splitArgs[0]); + + uint32_t accountId = 0; + LWOOBJID characterId = 0; + + if (player == nullptr) { + auto characterInfo = Database::Get()->GetCharacterInfo(splitArgs[0]); + + if (characterInfo) { + accountId = characterInfo->accountId; + characterId = characterInfo->id; + + GeneralUtils::SetBit(characterId, eObjectBits::CHARACTER); + GeneralUtils::SetBit(characterId, eObjectBits::PERSISTENT); + } + + if (accountId == 0) { + ChatPackets::SendSystemMessage(sysAddr, u"Count not find player of name: " + GeneralUtils::UTF8ToUTF16(splitArgs[0])); + + return; + } + } else { + auto* character = player->GetCharacter(); + auto* user = character != nullptr ? character->GetParentUser() : nullptr; + if (user) accountId = user->GetAccountID(); + characterId = player->GetObjectID(); + } + + time_t expire = 1; // Default to indefinate mute + + if (splitArgs.size() >= 2) { + const auto days = GeneralUtils::TryParse<uint32_t>(splitArgs[1]); + if (!days) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid days."); + + return; + } + + std::optional<uint32_t> hours; + if (splitArgs.size() >= 3) { + hours = GeneralUtils::TryParse<uint32_t>(splitArgs[2]); + if (!hours) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid hours."); + + return; + } + } + + expire = time(NULL); + expire += 24 * 60 * 60 * days.value(); + expire += 60 * 60 * hours.value_or(0); + } + + if (accountId != 0) Database::Get()->UpdateAccountUnmuteTime(accountId, expire); + + char buffer[32] = "brought up for review.\0"; + + if (expire != 1) { + std::tm* ptm = std::localtime(&expire); + // Format: Mo, 15.06.2009 20:20:00 + std::strftime(buffer, 32, "%a, %d.%m.%Y %H:%M:%S", ptm); + } + + const auto timeStr = GeneralUtils::ASCIIToUTF16(std::string(buffer)); + + ChatPackets::SendSystemMessage(sysAddr, u"Muted: " + GeneralUtils::UTF8ToUTF16(splitArgs[0]) + u" until " + timeStr); + + //Notify chat about it + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GM_MUTE); + + bitStream.Write(characterId); + bitStream.Write(expire); + + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /mute <username> <days (optional)> <hours (optional)>"); + } + } + + void Fly(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + auto* character = entity->GetCharacter(); + + if (character) { + bool isFlying = character->GetIsFlying(); + + if (isFlying) { + GameMessages::SendSetJetPackMode(entity, false); + + character->SetIsFlying(false); + } else { + float speedScale = 1.0f; + + if (splitArgs.size() >= 1) { + const auto tempScaleStore = GeneralUtils::TryParse<float>(splitArgs.at(0)); + + if (tempScaleStore) { + speedScale = tempScaleStore.value(); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Failed to parse speed scale argument."); + } + } + + float airSpeed = 20 * speedScale; + float maxAirSpeed = 30 * speedScale; + float verticalVelocity = 1.5 * speedScale; + + GameMessages::SendSetJetPackMode(entity, true, true, false, 167, airSpeed, maxAirSpeed, verticalVelocity); + + character->SetIsFlying(true); + } + } + } + + void AttackImmune(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + + const auto state = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!state) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); + return; + } + + if (destroyableComponent) destroyableComponent->SetIsImmune(state.value()); + } + + void GmImmune(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + + const auto state = GeneralUtils::TryParse<int32_t>(splitArgs[0]); + + if (!state) { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid state."); + return; + } + + if (destroyableComponent) destroyableComponent->SetIsGMImmune(state.value()); + } + + void GmInvis(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + GameMessages::SendToggleGMInvis(entity->GetObjectID(), true, UNASSIGNED_SYSTEM_ADDRESS); + } + + void SetName(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(args), UNASSIGNED_SYSTEM_ADDRESS); + } + + void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + std::string name = entity->GetCharacter()->GetName() + " - " + args; + GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS); + } + + void ShowAll(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + bool displayZoneData = true; + bool displayIndividualPlayers = true; + const auto splitArgs = GeneralUtils::SplitString(args, ' '); + + if (!splitArgs.empty() && !splitArgs.at(0).empty()) displayZoneData = splitArgs.at(0) == "1"; + if (splitArgs.size() > 1) displayIndividualPlayers = splitArgs.at(1) == "1"; + + ShowAllRequest request { + .requestor = entity->GetObjectID(), + .displayZoneData = displayZoneData, + .displayIndividualPlayers = displayIndividualPlayers + }; + + CBITSTREAM; + request.Serialize(bitStream); + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } + + void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (args.empty()) { + GameMessages::SendSlashCommandFeedbackText(entity, u"No player Given"); + return; + } + + FindPlayerRequest request { + .requestor = entity->GetObjectID(), + .playerName = LUWString(args) + }; + + CBITSTREAM; + request.Serialize(bitStream); + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } + + void Spectate(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (args.empty()) { + GameMessages::SendForceCameraTargetCycle(entity, false, eCameraTargetCyclingMode::DISALLOW_CYCLING, entity->GetObjectID()); + return; + } + + auto player = PlayerManager::GetPlayer(args); + if (!player) { + GameMessages::SendSlashCommandFeedbackText(entity, u"Player not found"); + return; + } + GameMessages::SendSlashCommandFeedbackText(entity, u"Spectating Player"); + GameMessages::SendForceCameraTargetCycle(entity, false, eCameraTargetCyclingMode::DISALLOW_CYCLING, player->GetObjectID()); + } +} diff --git a/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.h b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.h new file mode 100644 index 000000000..c278fc0a7 --- /dev/null +++ b/dGame/dUtilities/SlashCommands/GMGreaterThanZeroCommands.h @@ -0,0 +1,21 @@ +#ifndef GMGREATERTHANZEROCOMMANDS_H +#define GMGREATERTHANZEROCOMMANDS_H + +namespace GMGreaterThanZeroCommands { + void Kick(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void MailItem(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Ban(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ApproveProperty(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Mute(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Fly(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void AttackImmune(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GmImmune(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void GmInvis(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void SetName(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ShowAll(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Spectate(Entity* entity, const SystemAddress& sysAddr, const std::string args); +} + +#endif //!GMGREATERTHANZEROCOMMANDS_H diff --git a/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp b/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp new file mode 100644 index 000000000..6c9811c24 --- /dev/null +++ b/dGame/dUtilities/SlashCommands/GMZeroCommands.cpp @@ -0,0 +1,232 @@ +#include "GMZeroCommands.h" + +// Classes +#include "Amf3.h" +#include "BinaryPathFinder.h" +#include "ChatPackets.h" +#include "dServer.h" +#include "dZoneManager.h" +#include "Mail.h" +#include "PlayerManager.h" +#include "SlashCommandHandler.h" +#include "VanityUtilities.h" +#include "WorldPackets.h" +#include "ZoneInstanceManager.h" + +// Components +#include "BuffComponent.h" +#include "CharacterComponent.h" +#include "DestroyableComponent.h" +#include "ScriptedActivityComponent.h" +#include "SkillComponent.h" + +// Emuns +#include "eGameMasterLevel.h" + +namespace GMZeroCommands { + void Pvp(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto* character = entity->GetComponent<CharacterComponent>(); + + if (character == nullptr) { + LOG("Failed to find character component!"); + return; + } + + character->SetPvpEnabled(!character->GetPvpEnabled()); + Game::entityManager->SerializeEntity(entity); + + std::stringstream message; + message << character->GetName() << " changed their PVP flag to " << std::to_string(character->GetPvpEnabled()) << "!"; + + ChatPackets::SendSystemMessage(UNASSIGNED_SYSTEM_ADDRESS, GeneralUtils::UTF8ToUTF16(message.str()), true); + } + + void Who(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + ChatPackets::SendSystemMessage( + sysAddr, + u"Players in this instance: (" + GeneralUtils::to_u16string(PlayerManager::GetAllPlayers().size()) + u")" + ); + + for (auto* player : PlayerManager::GetAllPlayers()) { + const auto& name = player->GetCharacter()->GetName(); + + ChatPackets::SendSystemMessage( + sysAddr, + GeneralUtils::UTF8ToUTF16(player == entity ? name + " (you)" : name) + ); + } + } + + void Ping(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + if (!args.empty() && args.starts_with("-l")) { + std::stringstream message; + message << "Your latest ping: " << std::to_string(Game::server->GetLatestPing(sysAddr)) << "ms"; + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); + } else { + std::stringstream message; + message << "Your average ping: " << std::to_string(Game::server->GetPing(sysAddr)) << "ms"; + + ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message.str())); + } + } + + void FixStats(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + // Reset skill component and buff component + auto* skillComponent = entity->GetComponent<SkillComponent>(); + auto* buffComponent = entity->GetComponent<BuffComponent>(); + auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); + + // If any of the components are nullptr, return + if (skillComponent == nullptr || buffComponent == nullptr || destroyableComponent == nullptr) { + return; + } + + // Reset skill component + skillComponent->Reset(); + + // Reset buff component + buffComponent->Reset(); + + // Fix the destroyable component + destroyableComponent->FixStats(); + } + + void Credits(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto& customText = VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/CREDITS.md").string()); + + { + AMFArrayValue args; + + args.Insert("state", "Story"); + + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); + } + + entity->AddCallbackTimer(0.5f, [customText, entity]() { + AMFArrayValue args; + + args.Insert("visible", true); + args.Insert("text", customText); + + LOG("Sending %s", customText.c_str()); + + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", args); + }); + } + + void Info(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto& customText = VanityUtilities::ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/INFO.md").string()); + + { + AMFArrayValue args; + + args.Insert("state", "Story"); + + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args); + } + + entity->AddCallbackTimer(0.5f, [customText, entity]() { + AMFArrayValue args; + + args.Insert("visible", true); + args.Insert("text", customText); + + LOG("Sending %s", customText.c_str()); + + GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "ToggleStoryBox", args); + }); + } + + void LeaveZone(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto currentZone = Game::zoneManager->GetZone()->GetZoneID().GetMapID(); + LWOMAPID newZone = 0; + + if (currentZone == 1001 || currentZone % 100 == 0) { + ChatPackets::SendSystemMessage(sysAddr, u"You are not in an instanced zone."); + return; + } else { + newZone = (currentZone / 100) * 100; + } + // If new zone would be inaccessible, then default to Avant Gardens. + if (!Game::zoneManager->CheckIfAccessibleZone(newZone)) newZone = 1100; + + ChatPackets::SendSystemMessage(sysAddr, u"Leaving zone..."); + + const auto objid = entity->GetObjectID(); + + ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, newZone, 0, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + auto* entity = Game::entityManager->GetEntity(objid); + + if (entity == nullptr) { + return; + } + + const auto sysAddr = entity->GetSystemAddress(); + + LOG("Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i", entity->GetCharacter()->GetName().c_str(), 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->GetCharacter()->SaveXMLToDatabase(); + + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + }); + } + + void Join(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + auto splitArgs = GeneralUtils::SplitString(args, ' '); + if (splitArgs.empty()) return; + + ChatPackets::SendSystemMessage(sysAddr, u"Requesting private map..."); + const auto& password = splitArgs[0]; + + ZoneInstanceManager::Instance()->RequestPrivateZone(Game::server, false, password, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { + LOG("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->GetCharacter()->SaveXMLToDatabase(); + + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); + }); + } + + void Die(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + entity->Smash(entity->GetObjectID()); + } + + void Resurrect(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + ScriptedActivityComponent* scriptedActivityComponent = Game::zoneManager->GetZoneControlObject()->GetComponent<ScriptedActivityComponent>(); + + if (scriptedActivityComponent) { // check if user is in activity world and if so, they can't resurrect + ChatPackets::SendSystemMessage(sysAddr, u"You cannot resurrect in an activity world."); + return; + } + + GameMessages::SendResurrect(entity); + } + + void RequestMailCount(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + Mail::HandleNotificationRequest(entity->GetSystemAddress(), entity->GetObjectID()); + } + + void InstanceInfo(Entity* entity, const SystemAddress& sysAddr, const std::string args) { + const auto zoneId = Game::zoneManager->GetZone()->GetZoneID(); + + ChatPackets::SendSystemMessage(sysAddr, u"Map: " + (GeneralUtils::to_u16string(zoneId.GetMapID())) + u"\nClone: " + (GeneralUtils::to_u16string(zoneId.GetCloneID())) + u"\nInstance: " + (GeneralUtils::to_u16string(zoneId.GetInstanceID()))); + } + + //For client side commands + void ClientHandled(Entity* entity, const SystemAddress& sysAddr, const std::string args) {} + +}; + diff --git a/dGame/dUtilities/SlashCommands/GMZeroCommands.h b/dGame/dUtilities/SlashCommands/GMZeroCommands.h new file mode 100644 index 000000000..d3f6753d0 --- /dev/null +++ b/dGame/dUtilities/SlashCommands/GMZeroCommands.h @@ -0,0 +1,21 @@ +#ifndef GMZEROCOMMANDS_H +#define GMZEROCOMMANDS_H + +namespace GMZeroCommands { + void Help(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Credits(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Info(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Die(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Ping(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Pvp(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void RequestMailCount(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Who(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void FixStats(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Join(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void LeaveZone(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void Resurrect(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void InstanceInfo(Entity* entity, const SystemAddress& sysAddr, const std::string args); + void ClientHandled(Entity* entity, const SystemAddress& sysAddr, const std::string args); +} + +#endif //!GMZEROCOMMANDS_H diff --git a/dGame/dUtilities/VanityUtilities.cpp b/dGame/dUtilities/VanityUtilities.cpp index 3e93f830f..8ae9246df 100644 --- a/dGame/dUtilities/VanityUtilities.cpp +++ b/dGame/dUtilities/VanityUtilities.cpp @@ -22,9 +22,18 @@ #include <fstream> -std::vector<VanityObject> VanityUtilities::m_Objects = {}; -std::set<std::string> VanityUtilities::m_LoadedFiles = {}; +namespace { + std::vector<VanityObject> objects; + std::set<std::string> loadedFiles; +} + +void SetupNPCTalk(Entity* npc); +void NPCTalk(Entity* npc); +void ParseXml(const std::string& file); +LWOOBJID SpawnSpawner(const VanityObject& object, const VanityObjectLocation& location); +Entity* SpawnObject(const VanityObject& object, const VanityObjectLocation& location); +VanityObject* GetObject(const std::string& name); void VanityUtilities::SpawnVanity() { const uint32_t zoneID = Game::server->GetZoneID(); @@ -36,21 +45,19 @@ void VanityUtilities::SpawnVanity() { info.pos = { 259.5f, 246.4f, -705.2f }; info.rot = { 0.0f, 0.0f, 1.0f, 0.0f }; info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID(); - - info.settings = { new LDFData<bool>(u"hasCustomText", true), - new LDFData<std::string>(u"customText", ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/TESTAMENT.md").string())) }; + info.settings = { + new LDFData<bool>(u"hasCustomText", true), + new LDFData<std::string>(u"customText", ParseMarkdown((BinaryPathFinder::GetBinaryDir() / "vanity/TESTAMENT.md").string())) + }; auto* entity = Game::entityManager->CreateEntity(info); - Game::entityManager->ConstructEntity(entity); } } - if (Game::config->GetValue("disable_vanity") == "1") { - return; - } + if (Game::config->GetValue("disable_vanity") == "1") return; - for (const auto& npc : m_Objects) { + for (const auto& npc : objects) { if (npc.m_ID == LWOOBJID_EMPTY) continue; if (npc.m_LOT == 176){ Game::zoneManager->RemoveSpawner(npc.m_ID); @@ -61,13 +68,13 @@ void VanityUtilities::SpawnVanity() { } } - m_Objects.clear(); - m_LoadedFiles.clear(); + objects.clear(); + loadedFiles.clear(); - ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity/root.xml").string()); + ParseXml((BinaryPathFinder::GetBinaryDir() / "vanity/root.xml").string()); // Loop through all objects - for (auto& object : m_Objects) { + for (auto& object : objects) { if (object.m_Locations.find(Game::server->GetZoneID()) == object.m_Locations.end()) continue; const std::vector<VanityObjectLocation>& locations = object.m_Locations.at(Game::server->GetZoneID()); @@ -79,12 +86,6 @@ void VanityUtilities::SpawnVanity() { float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); if (location.m_Chance < rate) continue; - if (object.m_Config.empty()) { - object.m_Config = { - new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }), - new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") - }; - } if (object.m_LOT == 176){ object.m_ID = SpawnSpawner(object, location); } else { @@ -94,21 +95,14 @@ void VanityUtilities::SpawnVanity() { object.m_ID = objectEntity->GetObjectID(); if (!object.m_Phrases.empty()){ objectEntity->SetVar<std::vector<std::string>>(u"chats", object.m_Phrases); - - auto* scriptComponent = objectEntity->GetComponent<ScriptComponent>(); - - if (scriptComponent && !object.m_Script.empty()) { - scriptComponent->SetScript(object.m_Script); - scriptComponent->SetSerialized(false); - } SetupNPCTalk(objectEntity); } } } } -LWOOBJID VanityUtilities::SpawnSpawner(const VanityObject& object, const VanityObjectLocation& location) { - SceneObject obj; +LWOOBJID SpawnSpawner(const VanityObject& object, const VanityObjectLocation& location) { + SceneObject obj{}; obj.lot = object.m_LOT; // guratantee we have no collisions do { @@ -121,7 +115,7 @@ LWOOBJID VanityUtilities::SpawnSpawner(const VanityObject& object, const VanityO return obj.id; } -Entity* VanityUtilities::SpawnObject(const VanityObject& object, const VanityObjectLocation& location) { +Entity* SpawnObject(const VanityObject& object, const VanityObjectLocation& location) { EntityInfo info; info.lot = object.m_LOT; info.pos = location.m_Position; @@ -131,18 +125,16 @@ Entity* VanityUtilities::SpawnObject(const VanityObject& object, const VanityObj info.settings = object.m_Config; auto* entity = Game::entityManager->CreateEntity(info); - entity->SetVar(u"npcName", object.m_Name); + if (!object.m_Name.empty()) entity->SetVar(u"npcName", object.m_Name); if (entity->GetVar<bool>(u"noGhosting")) entity->SetIsGhostingCandidate(false); auto* inventoryComponent = entity->GetComponent<InventoryComponent>(); - if (inventoryComponent && !object.m_Equipment.empty()) { inventoryComponent->SetNPCItems(object.m_Equipment); } auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); - - if (destroyableComponent != nullptr) { + if (destroyableComponent) { destroyableComponent->SetIsGMImmune(true); destroyableComponent->SetMaxHealth(0); destroyableComponent->SetHealth(0); @@ -153,12 +145,12 @@ Entity* VanityUtilities::SpawnObject(const VanityObject& object, const VanityObj return entity; } -void VanityUtilities::ParseXML(const std::string& file) { - if (m_LoadedFiles.contains(file)){ +void ParseXml(const std::string& file) { + if (loadedFiles.contains(file)){ LOG("Trying to load vanity file %s twice!!!", file.c_str()); return; } - m_LoadedFiles.insert(file); + loadedFiles.insert(file); // Read the entire file std::ifstream xmlFile(file); std::string xml((std::istreambuf_iterator<char>(xmlFile)), std::istreambuf_iterator<char>()); @@ -176,24 +168,26 @@ void VanityUtilities::ParseXML(const std::string& file) { if (enabled != "1") { continue; } - ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity" / filename).string()); + ParseXml((BinaryPathFinder::GetBinaryDir() / "vanity" / filename).string()); } } // Read the objects - auto* objects = doc.FirstChildElement("objects"); - - if (objects) { - for (auto* object = objects->FirstChildElement("object"); object != nullptr; object = object->NextSiblingElement("object")) { + auto* objectsElement = doc.FirstChildElement("objects"); + const uint32_t currentZoneID = Game::server->GetZoneID(); + if (objectsElement) { + for (auto* object = objectsElement->FirstChildElement("object"); object != nullptr; object = object->NextSiblingElement("object")) { + // for use later when adding to the vector of VanityObjects + bool useLocationsAsRandomSpawnPoint = false; // Get the NPC name auto* name = object->Attribute("name"); if (!name) name = ""; // Get the NPC lot - auto* lot = object->Attribute("lot"); + auto lot = GeneralUtils::TryParse<LOT>(object->Attribute("lot")).value_or(LOT_NULL); - if (lot == nullptr) { + if (lot == LOT_NULL) { LOG("Failed to parse object lot"); continue; } @@ -211,17 +205,17 @@ void VanityUtilities::ParseXML(const std::string& file) { std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ','); for (auto& item : splitEquipment) { - inventory.push_back(std::stoi(item)); + // remove spaces for tryParse to work + item.erase(remove_if(item.begin(), item.end(), isspace), item.end()); + auto itemInt = GeneralUtils::TryParse<uint32_t>(item); + if (itemInt) inventory.push_back(itemInt.value()); } } } - // Get the phrases auto* phrases = object->FirstChildElement("phrases"); - std::vector<std::string> phraseList = {}; - if (phrases) { for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr; phrase = phrase->NextSiblingElement("phrase")) { @@ -235,41 +229,34 @@ void VanityUtilities::ParseXML(const std::string& file) { } } - // Get the script - auto* scriptElement = object->FirstChildElement("script"); - - std::string scriptName = ""; - - if (scriptElement != nullptr) { - auto* scriptNameAttribute = scriptElement->Attribute("name"); - if (scriptNameAttribute) scriptName = scriptNameAttribute; - } - auto* configElement = object->FirstChildElement("config"); std::vector<std::u16string> keys = {}; - std::vector<LDFBaseData*> config = {}; if(configElement) { for (auto* key = configElement->FirstChildElement("key"); key != nullptr; key = key->NextSiblingElement("key")) { // Get the config data - auto* data = key->Attribute("data"); + auto* data = key->GetText(); if (!data) continue; LDFBaseData* configData = LDFBaseData::DataFromString(data); + if (configData->GetKey() == u"useLocationsAsRandomSpawnPoint" && configData->GetValueType() == eLDFType::LDF_TYPE_BOOLEAN){ + useLocationsAsRandomSpawnPoint = static_cast<bool>(configData); + continue; + } keys.push_back(configData->GetKey()); config.push_back(configData); } } if (!keys.empty()) config.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys)); - VanityObject objectData; - objectData.m_Name = name; - objectData.m_LOT = std::stoi(lot); - objectData.m_Equipment = inventory; - objectData.m_Phrases = phraseList; - objectData.m_Script = scriptName; - objectData.m_Config = config; + VanityObject objectData { + .m_Name = name, + .m_LOT = lot, + .m_Equipment = inventory, + .m_Phrases = phraseList, + .m_Config = config + }; // Get the locations auto* locations = object->FirstChildElement("locations"); @@ -281,66 +268,68 @@ void VanityUtilities::ParseXML(const std::string& file) { for (auto* location = locations->FirstChildElement("location"); location != nullptr; location = location->NextSiblingElement("location")) { - + // Get the location data - auto* zoneID = location->Attribute("zone"); - auto* x = location->Attribute("x"); - auto* y = location->Attribute("y"); - auto* z = location->Attribute("z"); - auto* rw = location->Attribute("rw"); - auto* rx = location->Attribute("rx"); - auto* ry = location->Attribute("ry"); - auto* rz = location->Attribute("rz"); - - if (zoneID == nullptr || x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr - || rz == nullptr) { + auto zoneID = GeneralUtils::TryParse<uint32_t>(location->Attribute("zone")); + auto x = GeneralUtils::TryParse<float>(location->Attribute("x")); + auto y = GeneralUtils::TryParse<float>(location->Attribute("y")); + auto z = GeneralUtils::TryParse<float>(location->Attribute("z")); + auto rw = GeneralUtils::TryParse<float>(location->Attribute("rw")); + auto rx = GeneralUtils::TryParse<float>(location->Attribute("rx")); + auto ry = GeneralUtils::TryParse<float>(location->Attribute("ry")); + auto rz = GeneralUtils::TryParse<float>(location->Attribute("rz")); + + if (!zoneID || !x || !y || !z || !rw || !rx || !ry || !rz) { LOG("Failed to parse NPC location data"); continue; } - VanityObjectLocation locationData; - locationData.m_Position = { std::stof(x), std::stof(y), std::stof(z) }; - locationData.m_Rotation = { std::stof(rw), std::stof(rx), std::stof(ry), std::stof(rz) }; - locationData.m_Chance = 1.0f; + if (zoneID.value() != currentZoneID) { + continue; + } + + VanityObjectLocation locationData { + .m_Position = { x.value(), y.value(), z.value() }, + .m_Rotation = { rw.value(), rx.value(), ry.value(), rz.value() }, + }; if (location->Attribute("chance")) { - locationData.m_Chance = std::stof(location->Attribute("chance")); + locationData.m_Chance = GeneralUtils::TryParse<float>(location->Attribute("chance")).value_or(1.0f); } if (location->Attribute("scale")) { - locationData.m_Scale = std::stof(location->Attribute("scale")); + locationData.m_Scale = GeneralUtils::TryParse<float>(location->Attribute("scale")).value_or(1.0f); } - - const auto& it = objectData.m_Locations.find(std::stoi(zoneID)); + const auto& it = objectData.m_Locations.find(zoneID.value()); if (it != objectData.m_Locations.end()) { it->second.push_back(locationData); } else { std::vector<VanityObjectLocation> locations; locations.push_back(locationData); - objectData.m_Locations.insert(std::make_pair(std::stoi(zoneID), locations)); + objectData.m_Locations.insert(std::make_pair(zoneID.value(), locations)); } - if (!(std::find(keys.begin(), keys.end(), u"teleport") != keys.end())) { - m_Objects.push_back(objectData); + if (!useLocationsAsRandomSpawnPoint) { + objects.push_back(objectData); objectData.m_Locations.clear(); } } - if (std::find(keys.begin(), keys.end(), u"teleport") != keys.end()) { - m_Objects.push_back(objectData); - } + + if (useLocationsAsRandomSpawnPoint && !objectData.m_Locations.empty()) { + objects.push_back(objectData); + } } } } VanityObject* VanityUtilities::GetObject(const std::string& name) { - for (size_t i = 0; i < m_Objects.size(); i++) { - if (m_Objects[i].m_Name == name) { - return &m_Objects[i]; + for (size_t i = 0; i < objects.size(); i++) { + if (objects[i].m_Name == name) { + return &objects[i]; } } - return nullptr; } @@ -350,7 +339,7 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) { // Read the file into a string std::ifstream t(file); std::stringstream output; - // If the file does not exist, return an empty string. + // If the file does not exist, return a useful error. if (!t.good()) { output << "File "; output << file.substr(file.rfind("/") + 1); @@ -408,13 +397,13 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) { return output.str(); } -void VanityUtilities::SetupNPCTalk(Entity* npc) { +void SetupNPCTalk(Entity* npc) { npc->AddCallbackTimer(15.0f, [npc]() { NPCTalk(npc); }); npc->SetProximityRadius(20.0f, "talk"); } -void VanityUtilities::NPCTalk(Entity* npc) { +void NPCTalk(Entity* npc) { auto* proximityMonitorComponent = npc->GetComponent<ProximityMonitorComponent>(); if (!proximityMonitorComponent->GetProximityObjects("talk").empty()) { diff --git a/dGame/dUtilities/VanityUtilities.h b/dGame/dUtilities/VanityUtilities.h index 49bd23ab0..a1d005015 100644 --- a/dGame/dUtilities/VanityUtilities.h +++ b/dGame/dUtilities/VanityUtilities.h @@ -5,58 +5,30 @@ #include <map> #include <set> -struct VanityObjectLocation -{ +struct VanityObjectLocation { float m_Chance = 1.0f; NiPoint3 m_Position; NiQuaternion m_Rotation; float m_Scale = 1.0f; }; -struct VanityObject -{ +struct VanityObject { LWOOBJID m_ID = LWOOBJID_EMPTY; std::string m_Name; - LOT m_LOT; + LOT m_LOT = LOT_NULL; std::vector<LOT> m_Equipment; std::vector<std::string> m_Phrases; - std::string m_Script; std::map<uint32_t, std::vector<VanityObjectLocation>> m_Locations; std::vector<LDFBaseData*> m_Config; }; -class VanityUtilities -{ -public: - static void SpawnVanity(); +namespace VanityUtilities { + void SpawnVanity(); - static Entity* SpawnObject( - const VanityObject& object, - const VanityObjectLocation& location - ); - - static LWOOBJID SpawnSpawner( - const VanityObject& object, - const VanityObjectLocation& location - ); - - static std::string ParseMarkdown( - const std::string& file - ); + VanityObject* GetObject(const std::string& name); - static void ParseXML( + std::string ParseMarkdown( const std::string& file ); - - static VanityObject* GetObject(const std::string& name); - -private: - static void SetupNPCTalk(Entity* npc); - - static void NPCTalk(Entity* npc); - - static std::vector<VanityObject> m_Objects; - - static std::set<std::string> m_LoadedFiles; }; diff --git a/dMasterServer/CMakeLists.txt b/dMasterServer/CMakeLists.txt index 32a7b1eca..2e2b4dd9d 100644 --- a/dMasterServer/CMakeLists.txt +++ b/dMasterServer/CMakeLists.txt @@ -6,11 +6,14 @@ set(DMASTERSERVER_SOURCES add_library(dMasterServer ${DMASTERSERVER_SOURCES}) add_executable(MasterServer "MasterServer.cpp") -add_compile_definitions(MasterServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"") +target_compile_definitions(MasterServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"") +target_include_directories(dMasterServer PUBLIC "." + "${PROJECT_SOURCE_DIR}/dZoneManager" # InstanceManager.h uses dZMCommon.h + ${PROJECT_SOURCE_DIR}/dServer/ # BinaryPathFinder.h +) target_link_libraries(dMasterServer ${COMMON_LIBRARIES}) -target_link_libraries(MasterServer ${COMMON_LIBRARIES} dMasterServer dServer) -target_include_directories(dMasterServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer) +target_link_libraries(MasterServer ${COMMON_LIBRARIES} bcrypt dMasterServer dServer) if(WIN32) add_dependencies(MasterServer WorldServer AuthServer ChatServer) diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 3ec42634b..5f2672e05 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -10,7 +10,7 @@ #include "MasterPackets.h" #include "BitStreamUtils.h" #include "eConnectionType.h" -#include "eMasterMessageType.h" +#include "MessageType/Master.h" #include "Start.h" @@ -177,7 +177,7 @@ void InstanceManager::RequestAffirmation(Instance* instance, const PendingInstan CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::AFFIRM_TRANSFER_REQUEST); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::AFFIRM_TRANSFER_REQUEST); bitStream.Write(request.id); @@ -359,7 +359,7 @@ bool Instance::GetShutdownComplete() const { void Instance::Shutdown() { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::SHUTDOWN); Game::server->Send(bitStream, this->m_SysAddr, false); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 4104f5ea8..7edcaced2 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -24,7 +24,7 @@ #include "AssetManager.h" #include "BinaryPathFinder.h" #include "eConnectionType.h" -#include "eMasterMessageType.h" +#include "MessageType/Master.h" //RakNet includes: #include "RakNetDefines.h" @@ -40,6 +40,8 @@ #include "BitStreamUtils.h" #include "Start.h" #include "Server.h" +#include "CDZoneTableTable.h" +#include "eGameMasterLevel.h" namespace Game { Logger* logger = nullptr; @@ -186,15 +188,20 @@ int main(int argc, char** argv) { std::cout << "Enter a username: "; std::cin >> username; + const auto checkIsAdmin = []() { + std::string admin; + std::cout << "What level of privilege should this account have? Please enter a number between 0 (Player) and 9 (Admin) inclusive. No entry will default to 0." << std::endl; + std::cin >> admin; + return admin; + }; + auto accountId = Database::Get()->GetAccountInfo(username); - if (accountId) { + if (accountId && accountId->id != 0) { LOG("Account with name \"%s\" already exists", username.c_str()); std::cout << "Do you want to change the password of that account? [y/n]?"; std::string prompt = ""; std::cin >> prompt; if (prompt == "y" || prompt == "yes") { - if (accountId->id == 0) return EXIT_FAILURE; - //Read the password from the console without echoing it. #ifdef __linux__ //This function is obsolete, but it only meant to be used by the @@ -219,6 +226,20 @@ int main(int argc, char** argv) { } else { LOG("Account \"%s\" was not updated.", username.c_str()); } + + std::cout << "Update admin privileges? [y/n]? "; + std::string admin; + std::cin >> admin; + bool updateAdmin = admin == "y" || admin == "yes"; + if (updateAdmin) { + auto gmLevel = GeneralUtils::TryParse<int32_t>(checkIsAdmin()).value_or(0); + if (gmLevel > 9 || gmLevel < 0) { + LOG("Invalid admin level. Defaulting to 0"); + gmLevel = 0; + } + Database::Get()->UpdateAccountGmLevel(accountId->id, static_cast<eGameMasterLevel>(gmLevel)); + } + return EXIT_SUCCESS; } @@ -249,6 +270,17 @@ int main(int argc, char** argv) { } LOG("Account created successfully!"); + + accountId = Database::Get()->GetAccountInfo(username); + if (accountId) { + auto gmLevel = GeneralUtils::TryParse<int32_t>(checkIsAdmin()).value_or(0); + if (gmLevel > 9 || gmLevel < 0) { + LOG("Invalid admin level. Defaulting to 0"); + gmLevel = 0; + } + Database::Get()->UpdateAccountGmLevel(accountId->id, static_cast<eGameMasterLevel>(gmLevel)); + } + return EXIT_SUCCESS; } @@ -277,6 +309,17 @@ int main(int argc, char** argv) { PersistentIDManager::Initialize(); Game::im = new InstanceManager(Game::logger, Game::server->GetIP()); + //Get CDClient initial information + try { + CDClientManager::LoadValuesFromDatabase(); + } catch (CppSQLite3Exception& e) { + LOG("Failed to initialize CDServer SQLite Database"); + LOG("May be caused by corrupted file: %s", (Game::assetManager->GetResPath() / "CDServer.sqlite").string().c_str()); + LOG("Error: %s", e.errorMessage()); + LOG("Error Code: %i", e.errorCode()); + return EXIT_FAILURE; + } + //Depending on the config, start up servers: if (Game::config->GetValue("prestart_servers") != "0") { StartChatServer(); @@ -382,6 +425,7 @@ int main(int argc, char** argv) { } void HandlePacket(Packet* packet) { + if (packet->length < 1) return; if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION) { LOG("A server has disconnected"); @@ -429,8 +473,8 @@ void HandlePacket(Packet* packet) { if (packet->length < 4) return; if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::MASTER) { - switch (static_cast<eMasterMessageType>(packet->data[3])) { - case eMasterMessageType::REQUEST_PERSISTENT_ID: { + switch (static_cast<MessageType::Master>(packet->data[3])) { + case MessageType::Master::REQUEST_PERSISTENT_ID: { LOG("A persistent ID req"); RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -442,7 +486,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::REQUEST_ZONE_TRANSFER: { + case MessageType::Master::REQUEST_ZONE_TRANSFER: { LOG("Received zone transfer req"); RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -478,7 +522,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::SERVER_INFO: { + case MessageType::Master::SERVER_INFO: { //MasterPackets::HandleServerInfo(packet); //This is here because otherwise we'd have to include IM in @@ -539,19 +583,19 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::SET_SESSION_KEY: { + case MessageType::Master::SET_SESSION_KEY: { CINSTREAM_SKIP_HEADER; uint32_t sessionKey = 0; inStream.Read(sessionKey); LUString username; inStream.Read(username); - + for (auto it : activeSessions) { if (it.second == username.string) { activeSessions.erase(it.first); CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::NEW_SESSION_ALERT); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::NEW_SESSION_ALERT); bitStream.Write(sessionKey); bitStream.Write(username); SEND_PACKET_BROADCAST; @@ -565,7 +609,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::REQUEST_SESSION_KEY: { + case MessageType::Master::REQUEST_SESSION_KEY: { CINSTREAM_SKIP_HEADER; LUWString username; inStream.Read(username); @@ -573,7 +617,7 @@ void HandlePacket(Packet* packet) { for (auto key : activeSessions) { if (key.second == username.GetAsString()) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SESSION_KEY_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::SESSION_KEY_RESPONSE); bitStream.Write(key.first); bitStream.Write(username); Game::server->Send(bitStream, packet->systemAddress, false); @@ -583,7 +627,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::PLAYER_ADDED: { + case MessageType::Master::PLAYER_ADDED: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -603,7 +647,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::PLAYER_REMOVED: { + case MessageType::Master::PLAYER_REMOVED: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -621,7 +665,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::CREATE_PRIVATE_ZONE: { + case MessageType::Master::CREATE_PRIVATE_ZONE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -645,7 +689,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::REQUEST_PRIVATE_ZONE: { + case MessageType::Master::REQUEST_PRIVATE_ZONE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -675,12 +719,12 @@ void HandlePacket(Packet* packet) { const auto& zone = instance->GetZoneID(); - MasterPackets::SendZoneTransferResponse(Game::server, packet->systemAddress, requestID, (bool)mythranShift, zone.GetMapID(), instance->GetInstanceID(), zone.GetCloneID(), instance->GetIP(), instance->GetPort()); + MasterPackets::SendZoneTransferResponse(Game::server, packet->systemAddress, requestID, static_cast<bool>(mythranShift), zone.GetMapID(), instance->GetInstanceID(), zone.GetCloneID(), instance->GetIP(), instance->GetPort()); break; } - case eMasterMessageType::WORLD_READY: { + case MessageType::Master::WORLD_READY: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -704,7 +748,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::PREP_ZONE: { + case MessageType::Master::PREP_ZONE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -720,7 +764,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::AFFIRM_TRANSFER_RESPONSE: { + case MessageType::Master::AFFIRM_TRANSFER_RESPONSE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -740,7 +784,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::SHUTDOWN_RESPONSE: { + case MessageType::Master::SHUTDOWN_RESPONSE: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -755,7 +799,7 @@ void HandlePacket(Packet* packet) { break; } - case eMasterMessageType::SHUTDOWN_UNIVERSE: { + case MessageType::Master::SHUTDOWN_UNIVERSE: { LOG("Received shutdown universe command, shutting down in 10 minutes."); Game::universeShutdownRequested = true; break; @@ -785,7 +829,7 @@ int ShutdownSequence(int32_t signal) { { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::SHUTDOWN); Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); LOG("Triggered master shutdown"); } diff --git a/dNavigation/CMakeLists.txt b/dNavigation/CMakeLists.txt index 4c03d24b2..e2a1c6ef3 100644 --- a/dNavigation/CMakeLists.txt +++ b/dNavigation/CMakeLists.txt @@ -6,5 +6,12 @@ foreach(file ${DNAVIGATIONS_DTERRAIN_SOURCES}) set(DNAVIGATION_SOURCES ${DNAVIGATION_SOURCES} "dTerrain/${file}") endforeach() -add_library(dNavigation STATIC ${DNAVIGATION_SOURCES}) -target_link_libraries(dNavigation Detour Recast) +add_library(dNavigation OBJECT ${DNAVIGATION_SOURCES}) +target_include_directories(dNavigation PUBLIC "." + PRIVATE + "${PROJECT_SOURCE_DIR}/dZoneManager" + "${PROJECT_SOURCE_DIR}/dGame" + "${PROJECT_SOURCE_DIR}/dGame/dEntity" + "${PROJECT_SOURCE_DIR}/dNavigation/dTerrain" # via dNavMesh.cpp +) +target_link_libraries(dNavigation PRIVATE Detour Recast dCommon) diff --git a/dNavigation/dNavMesh.cpp b/dNavigation/dNavMesh.cpp index f49dd31e5..d9584b00c 100644 --- a/dNavigation/dNavMesh.cpp +++ b/dNavigation/dNavMesh.cpp @@ -112,6 +112,31 @@ void dNavMesh::LoadNavmesh() { m_NavMesh = mesh; } +NiPoint3 dNavMesh::NearestPoint(const NiPoint3& location, const float halfExtent) const { + NiPoint3 toReturn = location; + if (m_NavMesh != nullptr) { + float pos[3]; + pos[0] = location.x; + pos[1] = location.y; + pos[2] = location.z; + + dtPolyRef nearestRef = 0; + float polyPickExt[3] = { halfExtent, halfExtent, halfExtent }; + float nearestPoint[3] = { 0.0f, 0.0f, 0.0f }; + dtQueryFilter filter{}; + + auto hasPoly = m_NavQuery->findNearestPoly(pos, polyPickExt, &filter, &nearestRef, nearestPoint); + if (hasPoly != DT_SUCCESS) { + toReturn = location; + } else { + toReturn.x = nearestPoint[0]; + toReturn.y = nearestPoint[1]; + toReturn.z = nearestPoint[2]; + } + } + return toReturn; +} + float dNavMesh::GetHeightAtPoint(const NiPoint3& location, const float halfExtentsHeight) const { if (m_NavMesh == nullptr) { return location.y; diff --git a/dNavigation/dNavMesh.h b/dNavigation/dNavMesh.h index 8a55c6497..60e07e7c2 100644 --- a/dNavigation/dNavMesh.h +++ b/dNavigation/dNavMesh.h @@ -21,7 +21,7 @@ class dNavMesh { /** * Get the height at a point - * + * * @param location The location to check for height at. This is the center of the search area. * @param halfExtentsHeight The half extents height of the search area. This is the distance from the center to the top and bottom of the search area. * The larger the value of halfExtentsHeight is, the larger the performance cost of the query. @@ -29,7 +29,7 @@ class dNavMesh { */ float GetHeightAtPoint(const NiPoint3& location, const float halfExtentsHeight = 32.0f) const; std::vector<NiPoint3> GetPath(const NiPoint3& startPos, const NiPoint3& endPos, float speed = 10.0f); - + NiPoint3 NearestPoint(const NiPoint3& location, const float halfExtent = 32.0f) const; bool IsNavmeshLoaded() { return m_NavMesh != nullptr; } private: diff --git a/dNet/AuthPackets.cpp b/dNet/AuthPackets.cpp index 2ba33ab5e..561f78e0b 100644 --- a/dNet/AuthPackets.cpp +++ b/dNet/AuthPackets.cpp @@ -8,7 +8,7 @@ #include "ZoneInstanceManager.h" #include "MD5.h" #include "GeneralUtils.h" -#include "ClientVersion.h" +#include "dClient/ClientVersion.h" #include <bcrypt/BCrypt.hpp> @@ -20,8 +20,8 @@ #include "eServerDisconnectIdentifiers.h" #include "eLoginResponse.h" #include "eConnectionType.h" -#include "eServerMessageType.h" -#include "eMasterMessageType.h" +#include "MessageType/Server.h" +#include "MessageType/Master.h" #include "eGameMasterLevel.h" #include "StringifiedEnum.h" namespace { @@ -63,7 +63,7 @@ void AuthPackets::HandleHandshake(dServer* server, Packet* packet) { if (port != packet->systemAddress.port) LOG("WARNING: Port written in packet does not match the port the client is connecting over!"); inStream.IgnoreBytes(33); - + LOG_DEBUG("Client Data [Version: %i, Service: %s, Process: %u, Port: %u, Sysaddr Port: %u]", clientVersion, StringifiedEnum::ToString(serviceId).data(), processID, port, packet->systemAddress.port); SendHandshake(server, packet->systemAddress, server->GetIP(), server->GetPort(), server->GetServerType()); @@ -71,8 +71,8 @@ void AuthPackets::HandleHandshake(dServer* server, Packet* packet) { void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, const std::string& nextServerIP, uint16_t nextServerPort, const ServerType serverType) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::SERVER, eServerMessageType::VERSION_CONFIRM); - + BitStreamUtils::WriteHeader(bitStream, eConnectionType::SERVER, MessageType::Server::VERSION_CONFIRM); + const auto clientNetVersionString = Game::config->GetValue("client_net_version"); const uint32_t clientNetVersion = GeneralUtils::TryParse<uint32_t>(clientNetVersionString).value_or(171022); @@ -82,7 +82,7 @@ void AuthPackets::SendHandshake(dServer* server, const SystemAddress& sysAddr, c if (serverType == ServerType::Auth) bitStream.Write(ServiceId::Auth); else if (serverType == ServerType::World) bitStream.Write(ServiceId::World); else bitStream.Write(ServiceId::General); - bitStream.Write<uint64_t>(215523405360); + bitStream.Write<uint64_t>(215523470896); server->Send(bitStream, sysAddr, false); } @@ -227,9 +227,9 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username, std::vector<Stamp>& stamps) { stamps.emplace_back(eStamps::PASSPORT_AUTH_IM_LOGIN_START, 1); RakNet::BitStream loginResponse; - BitStreamUtils::WriteHeader(loginResponse, eConnectionType::CLIENT, eClientMessageType::LOGIN_RESPONSE); + BitStreamUtils::WriteHeader(loginResponse, eConnectionType::CLIENT, MessageType::Client::LOGIN_RESPONSE); - loginResponse.Write<uint8_t>(GeneralUtils::CastUnderlyingType(responseCode)); + loginResponse.Write(responseCode); // Event Gating loginResponse.Write(LUString(Game::config->GetValue("event_1"))); @@ -297,7 +297,7 @@ void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAdd //Inform the master server that we've created a session for this user: if (responseCode == eLoginResponse::SUCCESS) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SET_SESSION_KEY); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::SET_SESSION_KEY); bitStream.Write(sessionKey); bitStream.Write(LUString(username)); server->SendToMaster(bitStream); diff --git a/dNet/BitStreamUtils.h b/dNet/BitStreamUtils.h index 1322ec955..33fde5642 100644 --- a/dNet/BitStreamUtils.h +++ b/dNet/BitStreamUtils.h @@ -5,6 +5,7 @@ #include "MessageIdentifiers.h" #include "BitStream.h" #include <string> +#include <algorithm> enum class eConnectionType : uint16_t; diff --git a/dNet/CMakeLists.txt b/dNet/CMakeLists.txt index 68de8eb11..15cdda42b 100644 --- a/dNet/CMakeLists.txt +++ b/dNet/CMakeLists.txt @@ -8,5 +8,24 @@ set(DNET_SOURCES "AuthPackets.cpp" "ZoneInstanceManager.cpp") add_library(dNet STATIC ${DNET_SOURCES}) +target_link_libraries(dNet PRIVATE bcrypt MD5) +target_include_directories(dNet PRIVATE + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" -target_link_libraries(dNet PUBLIC dCommon) + "${PROJECT_SOURCE_DIR}/dZoneManager" + + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/CDClientDatabase/CDClientTables" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase" + "${PROJECT_SOURCE_DIR}/dDatabase/GameDatabase/ITables" + "${PROJECT_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/include" + + "${PROJECT_SOURCE_DIR}/dGame" # UserManager.h + "${PROJECT_SOURCE_DIR}/dGame/dComponents" + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # via dZoneManager + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # GameMessages.h + "${PROJECT_SOURCE_DIR}/dGame/dInventory" # via PossessableComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" # via Item.h + "${PROJECT_SOURCE_DIR}/dScripts" # transitive through components +) diff --git a/dNet/ChatPackets.cpp b/dNet/ChatPackets.cpp index d03546597..bf3c9d62d 100644 --- a/dNet/ChatPackets.cpp +++ b/dNet/ChatPackets.cpp @@ -10,11 +10,35 @@ #include "BitStreamUtils.h" #include "dServer.h" #include "eConnectionType.h" -#include "eChatMessageType.h" +#include "MessageType/Chat.h" + +void ShowAllRequest::Serialize(RakNet::BitStream& bitStream) { + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::SHOW_ALL); + bitStream.Write(this->requestor); + bitStream.Write(this->displayZoneData); + bitStream.Write(this->displayIndividualPlayers); +} + +void ShowAllRequest::Deserialize(RakNet::BitStream& inStream) { + inStream.Read(this->requestor); + inStream.Read(this->displayZoneData); + inStream.Read(this->displayIndividualPlayers); +} + +void FindPlayerRequest::Serialize(RakNet::BitStream& bitStream) { + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::WHO); + bitStream.Write(this->requestor); + bitStream.Write(this->playerName); +} + +void FindPlayerRequest::Deserialize(RakNet::BitStream& inStream) { + inStream.Read(this->requestor); + inStream.Read(this->playerName); +} void ChatPackets::SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GENERAL_CHAT_MESSAGE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GENERAL_CHAT_MESSAGE); bitStream.Write<uint64_t>(0); bitStream.Write(chatChannel); @@ -36,7 +60,7 @@ void ChatPackets::SendChatMessage(const SystemAddress& sysAddr, char chatChannel void ChatPackets::SendSystemMessage(const SystemAddress& sysAddr, const std::u16string& message, const bool broadcast) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GENERAL_CHAT_MESSAGE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::GENERAL_CHAT_MESSAGE); bitStream.Write<uint64_t>(0); bitStream.Write<char>(4); @@ -68,7 +92,7 @@ void ChatPackets::SendMessageFail(const SystemAddress& sysAddr) { //0x01 - "Upgrade to a full LEGO Universe Membership to chat with other players." CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::SEND_CANNED_TEXT); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::SEND_CANNED_TEXT); bitStream.Write<uint8_t>(0); //response type, options above ^ //docs say there's a wstring here-- no idea what it's for, or if it's even needed so leaving it as is for now. SEND_PACKET; diff --git a/dNet/ChatPackets.h b/dNet/ChatPackets.h index 8f6de175f..c33d00dde 100644 --- a/dNet/ChatPackets.h +++ b/dNet/ChatPackets.h @@ -11,6 +11,21 @@ struct SystemAddress; #include <string> #include "dCommonVars.h" +struct ShowAllRequest{ + LWOOBJID requestor = LWOOBJID_EMPTY; + bool displayZoneData = true; + bool displayIndividualPlayers = true; + void Serialize(RakNet::BitStream& bitStream); + void Deserialize(RakNet::BitStream& inStream); +}; + +struct FindPlayerRequest{ + LWOOBJID requestor = LWOOBJID_EMPTY; + LUWString playerName; + void Serialize(RakNet::BitStream& bitStream); + void Deserialize(RakNet::BitStream& inStream); +}; + namespace ChatPackets { void SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message); void SendSystemMessage(const SystemAddress& sysAddr, const std::u16string& message, bool broadcast = false); diff --git a/dNet/MasterPackets.cpp b/dNet/MasterPackets.cpp index 7bd8f4a59..e15cab67e 100644 --- a/dNet/MasterPackets.cpp +++ b/dNet/MasterPackets.cpp @@ -3,21 +3,21 @@ #include "dCommonVars.h" #include "dServer.h" #include "eConnectionType.h" -#include "eMasterMessageType.h" +#include "MessageType/Master.h" #include "BitStreamUtils.h" #include <string> void MasterPackets::SendPersistentIDRequest(dServer* server, uint64_t requestID) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_PERSISTENT_ID); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::REQUEST_PERSISTENT_ID); bitStream.Write(requestID); server->SendToMaster(bitStream); } void MasterPackets::SendPersistentIDResponse(dServer* server, const SystemAddress& sysAddr, uint64_t requestID, uint32_t objID) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_PERSISTENT_ID_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::REQUEST_PERSISTENT_ID_RESPONSE); bitStream.Write(requestID); bitStream.Write(objID); @@ -27,7 +27,7 @@ void MasterPackets::SendPersistentIDResponse(dServer* server, const SystemAddres void MasterPackets::SendZoneTransferRequest(dServer* server, uint64_t requestID, bool mythranShift, uint32_t zoneID, uint32_t cloneID) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_ZONE_TRANSFER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::REQUEST_ZONE_TRANSFER); bitStream.Write(requestID); bitStream.Write<uint8_t>(mythranShift); @@ -39,7 +39,7 @@ void MasterPackets::SendZoneTransferRequest(dServer* server, uint64_t requestID, void MasterPackets::SendZoneCreatePrivate(dServer* server, uint32_t zoneID, uint32_t cloneID, const std::string& password) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::CREATE_PRIVATE_ZONE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::CREATE_PRIVATE_ZONE); bitStream.Write(zoneID); bitStream.Write(cloneID); @@ -54,7 +54,7 @@ void MasterPackets::SendZoneCreatePrivate(dServer* server, uint32_t zoneID, uint void MasterPackets::SendZoneRequestPrivate(dServer* server, uint64_t requestID, bool mythranShift, const std::string& password) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_PRIVATE_ZONE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::REQUEST_PRIVATE_ZONE); bitStream.Write(requestID); bitStream.Write<uint8_t>(mythranShift); @@ -69,7 +69,7 @@ void MasterPackets::SendZoneRequestPrivate(dServer* server, uint64_t requestID, void MasterPackets::SendWorldReady(dServer* server, LWOMAPID zoneId, LWOINSTANCEID instanceId) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::WORLD_READY); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::WORLD_READY); bitStream.Write(zoneId); bitStream.Write(instanceId); @@ -79,7 +79,7 @@ void MasterPackets::SendWorldReady(dServer* server, LWOMAPID zoneId, LWOINSTANCE void MasterPackets::SendZoneTransferResponse(dServer* server, const SystemAddress& sysAddr, uint64_t requestID, bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, const std::string& serverIP, uint32_t serverPort) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_ZONE_TRANSFER_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::REQUEST_ZONE_TRANSFER_RESPONSE); bitStream.Write(requestID); bitStream.Write<uint8_t>(mythranShift); @@ -111,7 +111,7 @@ void MasterPackets::HandleServerInfo(Packet* packet) { void MasterPackets::SendServerInfo(dServer* server, Packet* packet) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SERVER_INFO); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::SERVER_INFO); bitStream.Write(server->GetPort()); bitStream.Write(server->GetZoneID()); diff --git a/dNet/WorldPackets.cpp b/dNet/WorldPackets.cpp index 1c2b8dec3..ddd16c3e5 100644 --- a/dNet/WorldPackets.cpp +++ b/dNet/WorldPackets.cpp @@ -12,9 +12,18 @@ #include <iostream> +void HTTPMonitorInfo::Serialize(RakNet::BitStream &bitStream) const { + bitStream.Write(port); + bitStream.Write<uint8_t>(openWeb); + bitStream.Write<uint8_t>(supportsSum); + bitStream.Write<uint8_t>(supportsDetail); + bitStream.Write<uint8_t>(supportsWho); + bitStream.Write<uint8_t>(supportsObjects); +} + void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::LOAD_STATIC_ZONE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::LOAD_STATIC_ZONE); bitStream.Write<uint16_t>(zone.GetMapID()); bitStream.Write<uint16_t>(zone.GetInstanceID()); @@ -35,28 +44,28 @@ void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, flo void WorldPackets::SendCharacterCreationResponse(const SystemAddress& sysAddr, eCharacterCreationResponse response) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_CREATE_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::CHARACTER_CREATE_RESPONSE); bitStream.Write(response); SEND_PACKET; } void WorldPackets::SendCharacterRenameResponse(const SystemAddress& sysAddr, eRenameResponse response) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHARACTER_RENAME_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::CHARACTER_RENAME_RESPONSE); bitStream.Write(response); SEND_PACKET; } void WorldPackets::SendCharacterDeleteResponse(const SystemAddress& sysAddr, bool response) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::DELETE_CHARACTER_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::DELETE_CHARACTER_RESPONSE); bitStream.Write<uint8_t>(response); SEND_PACKET; } void WorldPackets::SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TRANSFER_TO_WORLD); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::TRANSFER_TO_WORLD); bitStream.Write(LUString(serverIP)); bitStream.Write<uint16_t>(serverPort); @@ -67,14 +76,14 @@ void WorldPackets::SendTransferToWorld(const SystemAddress& sysAddr, const std:: void WorldPackets::SendServerState(const SystemAddress& sysAddr) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::SERVER_STATES); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::SERVER_STATES); bitStream.Write<uint8_t>(1); //If the server is receiving this request, it probably is ready anyway. SEND_PACKET; } void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CREATE_CHARACTER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::CREATE_CHARACTER); RakNet::BitStream data; data.Write<uint32_t>(7); //LDF key count @@ -127,7 +136,7 @@ void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, int64_t rep void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::CHAT_MODERATION_STRING); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::CHAT_MODERATION_STRING); bitStream.Write<uint8_t>(unacceptedItems.empty()); // Is sentence ok? bitStream.Write<uint16_t>(0x16); // Source ID, unknown @@ -151,7 +160,7 @@ void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAKE_GM_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::MAKE_GM_RESPONSE); bitStream.Write<uint8_t>(success); bitStream.Write(static_cast<uint16_t>(highestLevel)); @@ -160,3 +169,18 @@ void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, SEND_PACKET; } + +void WorldPackets::SendHTTPMonitorInfo(const SystemAddress& sysAddr, const HTTPMonitorInfo& info) { + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::HTTP_MONITOR_INFO_RESPONSE); + info.Serialize(bitStream); + SEND_PACKET; +} + +void WorldPackets::SendDebugOuput(const SystemAddress& sysAddr, const std::string& data){ + CBITSTREAM; + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::DEBUG_OUTPUT); + bitStream.Write<uint32_t>(data.size()); + bitStream.Write(data); + SEND_PACKET; +} diff --git a/dNet/WorldPackets.h b/dNet/WorldPackets.h index 0d5de0798..0081623ec 100644 --- a/dNet/WorldPackets.h +++ b/dNet/WorldPackets.h @@ -10,6 +10,19 @@ struct SystemAddress; enum class eGameMasterLevel : uint8_t; enum class eCharacterCreationResponse : uint8_t; enum class eRenameResponse : uint8_t; +namespace RakNet { + class BitStream; +}; + +struct HTTPMonitorInfo { + uint16_t port = 80; + bool openWeb = false; + bool supportsSum = false; + bool supportsDetail = false; + bool supportsWho = false; + bool supportsObjects = false; + void Serialize(RakNet::BitStream &bitstream) const; +}; namespace WorldPackets { void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone); @@ -21,6 +34,8 @@ namespace WorldPackets { void SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm); void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems); void SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel); + void SendHTTPMonitorInfo(const SystemAddress& sysAddr, const HTTPMonitorInfo& info); + void SendDebugOuput(const SystemAddress& sysAddr, const std::string& data); } #endif // WORLDPACKETS_H diff --git a/dNet/dServer.cpp b/dNet/dServer.cpp index e504a9856..20a21d499 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -7,8 +7,8 @@ #include "RakNetworkFactory.h" #include "MessageIdentifiers.h" #include "eConnectionType.h" -#include "eServerMessageType.h" -#include "eMasterMessageType.h" +#include "MessageType/Server.h" +#include "MessageType/Master.h" #include "BitStreamUtils.h" #include "MasterPackets.h" @@ -124,12 +124,12 @@ Packet* dServer::ReceiveFromMaster() { if (packet->data[0] == ID_USER_PACKET_ENUM) { if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::MASTER) { - switch (static_cast<eMasterMessageType>(packet->data[3])) { - case eMasterMessageType::REQUEST_ZONE_TRANSFER_RESPONSE: { + switch (static_cast<MessageType::Master>(packet->data[3])) { + case MessageType::Master::REQUEST_ZONE_TRANSFER_RESPONSE: { ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(packet); break; } - case eMasterMessageType::SHUTDOWN: + case MessageType::Master::SHUTDOWN: *mShouldShutdown = -2; break; @@ -170,7 +170,7 @@ void dServer::SendToMaster(RakNet::BitStream& bitStream) { void dServer::Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID) { RakNet::BitStream bitStream; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::SERVER, eServerMessageType::DISCONNECT_NOTIFY); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::SERVER, MessageType::Server::DISCONNECT_NOTIFY); bitStream.Write(disconNotifyID); mPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, sysAddr, false); diff --git a/dNet/dServer.h b/dNet/dServer.h index 40f606f15..f958fc408 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -86,7 +86,7 @@ class dServer { void SetupForMasterConnection(); bool ConnectToMaster(); -private: +protected: Logger* mLogger = nullptr; dConfig* mConfig = nullptr; RakPeerInterface* mPeer = nullptr; diff --git a/dPhysics/CMakeLists.txt b/dPhysics/CMakeLists.txt index 340e4c3c3..65588b4b9 100644 --- a/dPhysics/CMakeLists.txt +++ b/dPhysics/CMakeLists.txt @@ -7,6 +7,10 @@ set(DPHYSICS_SOURCES "dpCollisionChecks.cpp" "dpWorld.cpp") add_library(dPhysics STATIC ${DPHYSICS_SOURCES}) +target_include_directories(dPhysics PUBLIC "." + "${PROJECT_SOURCE_DIR}/dCommon" + "${PROJECT_SOURCE_DIR}/dCommon/dEnums" +) target_link_libraries(dPhysics PUBLIC Recast Detour - INTERFACE dNavigation) + INTERFACE dNavigation dCommon) diff --git a/dPhysics/dpEntity.cpp b/dPhysics/dpEntity.cpp index cbe3f5e8c..6fc404525 100644 --- a/dPhysics/dpEntity.cpp +++ b/dPhysics/dpEntity.cpp @@ -3,8 +3,6 @@ #include "dpShapeBox.h" #include "dpGrid.h" -#include <iostream> - dpEntity::dpEntity(const LWOOBJID& objectID, dpShapeType shapeType, bool isStatic) { m_ObjectID = objectID; m_IsStatic = isStatic; @@ -76,16 +74,17 @@ void dpEntity::CheckCollision(dpEntity* other) { return; } - bool wasFound = m_CurrentlyCollidingObjects.contains(other->GetObjectID()); - - bool isColliding = m_CollisionShape->IsColliding(other->GetShape()); + const auto objId = other->GetObjectID(); + const auto objItr = m_CurrentlyCollidingObjects.find(objId); + const bool wasFound = objItr != m_CurrentlyCollidingObjects.cend(); + const bool isColliding = m_CollisionShape->IsColliding(other->GetShape()); if (isColliding && !wasFound) { - m_CurrentlyCollidingObjects.emplace(other->GetObjectID(), other); - m_NewObjects.push_back(other); + m_CurrentlyCollidingObjects.emplace(objId); + m_NewObjects.push_back(objId); } else if (!isColliding && wasFound) { - m_CurrentlyCollidingObjects.erase(other->GetObjectID()); - m_RemovedObjects.push_back(other); + m_CurrentlyCollidingObjects.erase(objItr); + m_RemovedObjects.push_back(objId); } } diff --git a/dPhysics/dpEntity.h b/dPhysics/dpEntity.h index ea7a49b2f..cc47d7187 100644 --- a/dPhysics/dpEntity.h +++ b/dPhysics/dpEntity.h @@ -2,7 +2,8 @@ #include "NiPoint3.h" #include "NiQuaternion.h" #include <vector> -#include <map> +#include <unordered_set> +#include <span> #include "dCommonVars.h" #include "dpCommon.h" @@ -49,9 +50,9 @@ class dpEntity { bool GetSleeping() const { return m_Sleeping; } void SetSleeping(bool value) { m_Sleeping = value; } - const std::vector<dpEntity*>& GetNewObjects() const { return m_NewObjects; } - const std::vector<dpEntity*>& GetRemovedObjects() const { return m_RemovedObjects; } - const std::map<LWOOBJID, dpEntity*>& GetCurrentlyCollidingObjects() const { return m_CurrentlyCollidingObjects; } + std::span<const LWOOBJID> GetNewObjects() const { return m_NewObjects; } + std::span<const LWOOBJID> GetRemovedObjects() const { return m_RemovedObjects; } + const std::unordered_set<LWOOBJID>& GetCurrentlyCollidingObjects() const { return m_CurrentlyCollidingObjects; } void PreUpdate() { m_NewObjects.clear(); m_RemovedObjects.clear(); } @@ -80,7 +81,7 @@ class dpEntity { bool m_IsGargantuan = false; - std::vector<dpEntity*> m_NewObjects; - std::vector<dpEntity*> m_RemovedObjects; - std::map<LWOOBJID, dpEntity*> m_CurrentlyCollidingObjects; + std::vector<LWOOBJID> m_NewObjects; + std::vector<LWOOBJID> m_RemovedObjects; + std::unordered_set<LWOOBJID> m_CurrentlyCollidingObjects; }; diff --git a/dPhysics/dpGrid.cpp b/dPhysics/dpGrid.cpp index 8ec944fdd..7a0db1f88 100644 --- a/dPhysics/dpGrid.cpp +++ b/dPhysics/dpGrid.cpp @@ -26,8 +26,8 @@ dpGrid::~dpGrid() { void dpGrid::Add(dpEntity* entity) { //Determine which grid cell it's in. - int cellX = (int)std::round(entity->m_Position.x) / dpGrid::CELL_SIZE + NUM_CELLS / 2; - int cellZ = (int)std::round(entity->m_Position.z) / dpGrid::CELL_SIZE + NUM_CELLS / 2; + int cellX = static_cast<int>(std::round(entity->m_Position.x)) / dpGrid::CELL_SIZE + NUM_CELLS / 2; + int cellZ = static_cast<int>(std::round(entity->m_Position.z)) / dpGrid::CELL_SIZE + NUM_CELLS / 2; // Clamp values to the range [0, NUM_CELLS - 1] cellX = std::clamp(cellX, 0, NUM_CELLS - 1); @@ -42,11 +42,11 @@ void dpGrid::Add(dpEntity* entity) { } void dpGrid::Move(dpEntity* entity, float x, float z) { - int oldCellX = (int)std::round(entity->m_Position.x) / dpGrid::CELL_SIZE + NUM_CELLS / 2; - int oldCellZ = (int)std::round(entity->m_Position.z) / dpGrid::CELL_SIZE + NUM_CELLS / 2; + int oldCellX = static_cast<int>(std::round(entity->m_Position.x)) / dpGrid::CELL_SIZE + NUM_CELLS / 2; + int oldCellZ = static_cast<int>(std::round(entity->m_Position.z)) / dpGrid::CELL_SIZE + NUM_CELLS / 2; - int cellX = (int)std::round(x) / dpGrid::CELL_SIZE + NUM_CELLS / 2; - int cellZ = (int)std::round(z) / dpGrid::CELL_SIZE + NUM_CELLS / 2; + int cellX = static_cast<int>(std::round(x)) / dpGrid::CELL_SIZE + NUM_CELLS / 2; + int cellZ = static_cast<int>(std::round(z)) / dpGrid::CELL_SIZE + NUM_CELLS / 2; // Clamp values to the range [0, NUM_CELLS - 1] cellX = std::clamp(cellX, 0, NUM_CELLS - 1); @@ -73,8 +73,8 @@ void dpGrid::Move(dpEntity* entity, float x, float z) { void dpGrid::Delete(dpEntity* entity) { if (!entity) return; - int oldCellX = (int)std::round(entity->m_Position.x) / dpGrid::CELL_SIZE + NUM_CELLS / 2; - int oldCellZ = (int)std::round(entity->m_Position.z) / dpGrid::CELL_SIZE + NUM_CELLS / 2; + int oldCellX = static_cast<int>(std::round(entity->m_Position.x)) / dpGrid::CELL_SIZE + NUM_CELLS / 2; + int oldCellZ = static_cast<int>(std::round(entity->m_Position.z)) / dpGrid::CELL_SIZE + NUM_CELLS / 2; // Clamp values to the range [0, NUM_CELLS - 1] oldCellX = std::clamp(oldCellX, 0, NUM_CELLS - 1); diff --git a/dScripts/02_server/CMakeLists.txt b/dScripts/02_server/CMakeLists.txt index 51eb24c8a..8114b2267 100644 --- a/dScripts/02_server/CMakeLists.txt +++ b/dScripts/02_server/CMakeLists.txt @@ -30,15 +30,28 @@ endforeach() add_subdirectory(Pets) -add_library(dScriptsServer STATIC ${DSCRIPTS_SOURCES_02_SERVER}) -target_include_directories(dScriptsServer PUBLIC "." +add_library(dScriptsServerBase OBJECT ${DSCRIPTS_SOURCES_02_SERVER}) +target_include_directories(dScriptsServerBase PUBLIC "." "DLU" "Equipment" "Minigame" "Minigame/General" "Objects" - "Pets") +) +target_precompile_headers(dScriptsServerBase REUSE_FROM dScriptsBase) + +add_library(dScriptsServer INTERFACE) +target_sources(dScriptsServer INTERFACE + $<TARGET_OBJECTS:dScriptsServerBase> + $<TARGET_OBJECTS:dScriptsServerEnemy> + $<TARGET_OBJECTS:dScriptsServerPets> +) target_link_libraries(dScriptsServer INTERFACE - dScriptsServerEnemy - dScriptsServerMap) -target_precompile_headers(dScriptsServer REUSE_FROM dScriptsBase) + dScriptsServerMap +) +target_include_directories(dScriptsServer INTERFACE + $<TARGET_PROPERTY:dScriptsServerBase,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerEnemy,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMap,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerPets,INTERFACE_INCLUDE_DIRECTORIES> +) diff --git a/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp b/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp index 8aff19952..60d2d7154 100644 --- a/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp +++ b/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp @@ -5,20 +5,17 @@ #include "RenderComponent.h" void DLUVanityTeleportingObject::OnStartup(Entity* self) { - if (!self->HasVar(u"npcName") || !self->HasVar(u"teleport")) return; - m_Object = VanityUtilities::GetObject(self->GetVarAsString(u"npcName")); + if (!self->HasVar(u"npcName")) return; + m_Object = VanityUtilities::GetObject(self->GetVarAsString(u"npcName")); if (!m_Object) return; if (self->HasVar(u"teleportInterval")) m_TeleportInterval = self->GetVar<float>(u"teleportInterval"); - if (self->GetVar<bool>(u"teleport")) { - self->AddTimer("setupTeleport", m_TeleportInterval); - } + self->AddTimer("setupTeleport", m_TeleportInterval); } void DLUVanityTeleportingObject::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "setupTeleport") { - RenderComponent::PlayAnimation(self, u"interact"); GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); @@ -40,7 +37,6 @@ void DLUVanityTeleportingObject::OnTimerDone(Entity* self, std::string timerName self->SetPosition(newLocation.m_Position); self->SetRotation(newLocation.m_Rotation); - self->SetScale(newLocation.m_Scale); GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); self->AddTimer("stopFX", 2.0f); diff --git a/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp index 40b248f55..b64bb7a86 100644 --- a/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp +++ b/dScripts/02_server/Enemy/AG/BossSpiderQueenEnemyServer.cpp @@ -15,6 +15,7 @@ #include "SkillComponent.h" #include "eReplicaComponentType.h" #include "RenderComponent.h" +#include "PlayerManager.h" #include <vector> @@ -53,11 +54,13 @@ void BossSpiderQueenEnemyServer::OnStartup(Entity* self) { void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) { if (Game::zoneManager->GetZoneID().GetMapID() == instanceZoneID && killer) { - auto* missionComponent = killer->GetComponent<MissionComponent>(); - if (missionComponent == nullptr) - return; + for (const auto& player : PlayerManager::GetAllPlayers()) { + auto* missionComponent = player->GetComponent<MissionComponent>(); + if (missionComponent == nullptr) + return; - missionComponent->CompleteMission(instanceMissionID); + missionComponent->CompleteMission(instanceMissionID); + } } // There is suppose to be a 0.1 second delay here but that may be admitted? diff --git a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp index 9895395ce..dd3e0bd4c 100644 --- a/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp +++ b/dScripts/02_server/Enemy/AM/AmDarklingDragon.cpp @@ -6,7 +6,7 @@ #include "SkillComponent.h" #include "BaseCombatAIComponent.h" #include "EntityInfo.h" -#include "eAninmationFlags.h" +#include "eAnimationFlags.h" #include "RenderComponent.h" void AmDarklingDragon::OnStartup(Entity* self) { diff --git a/dScripts/02_server/Enemy/CMakeLists.txt b/dScripts/02_server/Enemy/CMakeLists.txt index 62f617728..3c39721ce 100644 --- a/dScripts/02_server/Enemy/CMakeLists.txt +++ b/dScripts/02_server/Enemy/CMakeLists.txt @@ -42,7 +42,7 @@ foreach(file ${DSCRIPTS_SOURCES_02_SERVER_ENEMY_WAVES}) set(DSCRIPTS_SOURCES_02_SERVER_ENEMY ${DSCRIPTS_SOURCES_02_SERVER_ENEMY} "Waves/${file}") endforeach() -add_library(dScriptsServerEnemy STATIC ${DSCRIPTS_SOURCES_02_SERVER_ENEMY}) +add_library(dScriptsServerEnemy OBJECT ${DSCRIPTS_SOURCES_02_SERVER_ENEMY}) target_link_libraries(dScriptsServerEnemy dScriptsBase) target_include_directories(dScriptsServerEnemy PUBLIC "." "AG" diff --git a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp index d2b3c7376..6d80b3ff8 100644 --- a/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp +++ b/dScripts/02_server/Enemy/FV/FvMaelstromDragon.cpp @@ -3,7 +3,7 @@ #include "SkillComponent.h" #include "BaseCombatAIComponent.h" #include "DestroyableComponent.h" -#include "eAninmationFlags.h" +#include "eAnimationFlags.h" #include "EntityInfo.h" #include "RenderComponent.h" diff --git a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp index 072212481..d0f73bd13 100644 --- a/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp +++ b/dScripts/02_server/Enemy/General/BaseEnemyApe.cpp @@ -5,7 +5,7 @@ #include "EntityManager.h" #include "EntityInfo.h" #include "SkillComponent.h" -#include "eAninmationFlags.h" +#include "eAnimationFlags.h" #include "RenderComponent.h" #include "eStateChangeType.h" diff --git a/dScripts/02_server/Map/AG/CMakeLists.txt b/dScripts/02_server/Map/AG/CMakeLists.txt index a8315398e..e13fd26ac 100644 --- a/dScripts/02_server/Map/AG/CMakeLists.txt +++ b/dScripts/02_server/Map/AG/CMakeLists.txt @@ -14,6 +14,6 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_AG "NpcCowboyServer.cpp" "NpcPirateServer.cpp") -add_library(dScriptsServerMapAG ${DSCRIPTS_SOURCES_02_SERVER_MAP_AG}) +add_library(dScriptsServerMapAG OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_AG}) target_include_directories(dScriptsServerMapAG PUBLIC ".") target_precompile_headers(dScriptsServerMapAG REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/AG_Spider_Queen/CMakeLists.txt b/dScripts/02_server/Map/AG_Spider_Queen/CMakeLists.txt index 65019afe5..30d09debb 100644 --- a/dScripts/02_server/Map/AG_Spider_Queen/CMakeLists.txt +++ b/dScripts/02_server/Map/AG_Spider_Queen/CMakeLists.txt @@ -2,7 +2,7 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_AG_SPIDER_QUEEN "ZoneAgSpiderQueen.cpp" "SpiderBossTreasureChestServer.cpp") -add_library(dScriptsServerMapAGSpiderQueen ${DSCRIPTS_SOURCES_02_SERVER_MAP_AG_SPIDER_QUEEN}) +add_library(dScriptsServerMapAGSpiderQueen OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_AG_SPIDER_QUEEN}) target_include_directories(dScriptsServerMapAGSpiderQueen PUBLIC ".") target_link_libraries(dScriptsServerMapAGSpiderQueen dScriptsServerMapProperty) target_precompile_headers(dScriptsServerMapAGSpiderQueen REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/AM/CMakeLists.txt b/dScripts/02_server/Map/AM/CMakeLists.txt index 177b3c455..81a37548d 100644 --- a/dScripts/02_server/Map/AM/CMakeLists.txt +++ b/dScripts/02_server/Map/AM/CMakeLists.txt @@ -15,8 +15,10 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_AM "AmSkullkinDrillStand.cpp" "AmSkullkinTower.cpp" "AmBlueX.cpp" - "AmTeapotServer.cpp") + "AmTeapotServer.cpp" + "WanderingVendor.cpp" + ) -add_library(dScriptsServerMapAM ${DSCRIPTS_SOURCES_02_SERVER_MAP_AM}) +add_library(dScriptsServerMapAM OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_AM}) target_include_directories(dScriptsServerMapAM PUBLIC ".") target_precompile_headers(dScriptsServerMapAM REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/AM/WanderingVendor.cpp b/dScripts/02_server/Map/AM/WanderingVendor.cpp new file mode 100644 index 000000000..d6bb32475 --- /dev/null +++ b/dScripts/02_server/Map/AM/WanderingVendor.cpp @@ -0,0 +1,42 @@ +#include "WanderingVendor.h" +#include "MovementAIComponent.h" +#include "ProximityMonitorComponent.h" +#include <ranges> + +void WanderingVendor::OnStartup(Entity* self) { + auto movementAIComponent = self->GetComponent<MovementAIComponent>(); + if (!movementAIComponent) return; + self->SetProximityRadius(10, "playermonitor"); +} + +void WanderingVendor::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + if (status == "ENTER" && entering->IsPlayer()) { + auto movementAIComponent = self->GetComponent<MovementAIComponent>(); + if (!movementAIComponent) return; + movementAIComponent->Pause(); + self->CancelTimer("startWalking"); + } else if (status == "LEAVE") { + auto* proximityMonitorComponent = self->GetComponent<ProximityMonitorComponent>(); + if (!proximityMonitorComponent) self->AddComponent<ProximityMonitorComponent>(); + + const auto proxObjs = proximityMonitorComponent->GetProximityObjects("playermonitor"); + bool foundPlayer = false; + for (const auto id : proxObjs) { + auto* entity = Game::entityManager->GetEntity(id); + if (entity && entity->IsPlayer()) { + foundPlayer = true; + break; + } + } + + if (!foundPlayer) self->AddTimer("startWalking", 1.5); + } +} + +void WanderingVendor::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "startWalking") { + auto movementAIComponent = self->GetComponent<MovementAIComponent>(); + if (!movementAIComponent) return; + movementAIComponent->Resume(); + } +} diff --git a/dScripts/02_server/Map/AM/WanderingVendor.h b/dScripts/02_server/Map/AM/WanderingVendor.h new file mode 100644 index 000000000..e0cb16452 --- /dev/null +++ b/dScripts/02_server/Map/AM/WanderingVendor.h @@ -0,0 +1,13 @@ +#ifndef __WANDERINGVENDOR__H__ +#define __WANDERINGVENDOR__H__ + +#include "CppScripts.h" + +class WanderingVendor : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnTimerDone(Entity* self, std::string timerName) override; +}; + +#endif //!__WANDERINGVENDOR__H__ diff --git a/dScripts/02_server/Map/CMakeLists.txt b/dScripts/02_server/Map/CMakeLists.txt index a5fb5b031..33bd9bd4c 100644 --- a/dScripts/02_server/Map/CMakeLists.txt +++ b/dScripts/02_server/Map/CMakeLists.txt @@ -13,17 +13,33 @@ add_subdirectory(SS) add_subdirectory(VE) add_library(dScriptsServerMap INTERFACE) -target_link_libraries(dScriptsServerMap INTERFACE - dScriptsServerMapAG - dScriptsServerMapAGSpiderQueen - dScriptsServerMapAM - dScriptsServerMapFV - dScriptsServerMapGeneral - dScriptsServerMapGF - dScriptsServerMapNJHub - dScriptsServerMapNS - dScriptsServerMapNT - dScriptsServerMapPR - dScriptsServerMapProperty - dScriptsServerMapSS - dScriptsServerMapVE) +target_sources(dScriptsServerMap INTERFACE + $<TARGET_OBJECTS:dScriptsServerMapAG> + $<TARGET_OBJECTS:dScriptsServerMapAGSpiderQueen> + $<TARGET_OBJECTS:dScriptsServerMapAM> + $<TARGET_OBJECTS:dScriptsServerMapFV> + $<TARGET_OBJECTS:dScriptsServerMapGeneral> + $<TARGET_OBJECTS:dScriptsServerMapGF> + $<TARGET_OBJECTS:dScriptsServerMapNJHub> + $<TARGET_OBJECTS:dScriptsServerMapNS> + $<TARGET_OBJECTS:dScriptsServerMapNT> + $<TARGET_OBJECTS:dScriptsServerMapPR> + $<TARGET_OBJECTS:dScriptsServerMapProperty> + $<TARGET_OBJECTS:dScriptsServerMapSS> + $<TARGET_OBJECTS:dScriptsServerMapVE> +) +target_include_directories(dScriptsServerMap INTERFACE + $<TARGET_PROPERTY:dScriptsServerMapAG,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapAGSpiderQueen,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapAM,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapFV,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapGeneral,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapGF,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapNJHub,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapNS,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapNT,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapPR,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapProperty,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapSS,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServerMapVE,INTERFACE_INCLUDE_DIRECTORIES> +) diff --git a/dScripts/02_server/Map/FV/CMakeLists.txt b/dScripts/02_server/Map/FV/CMakeLists.txt index 6f774c987..9746a5dd5 100644 --- a/dScripts/02_server/Map/FV/CMakeLists.txt +++ b/dScripts/02_server/Map/FV/CMakeLists.txt @@ -11,6 +11,6 @@ foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_FV_RACING}) set(DSCRIPTS_SOURCES_02_SERVER_MAP_FV ${DSCRIPTS_SOURCES_02_SERVER_MAP_FV} "Racing/${file}") endforeach() -add_library(dScriptsServerMapFV ${DSCRIPTS_SOURCES_02_SERVER_MAP_FV}) +add_library(dScriptsServerMapFV OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_FV}) target_include_directories(dScriptsServerMapFV PUBLIC "." "Racing") target_precompile_headers(dScriptsServerMapFV REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/FV/Racing/CMakeLists.txt b/dScripts/02_server/Map/FV/Racing/CMakeLists.txt index 89536b679..9b2108c8d 100644 --- a/dScripts/02_server/Map/FV/Racing/CMakeLists.txt +++ b/dScripts/02_server/Map/FV/Racing/CMakeLists.txt @@ -1,3 +1,6 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_FV_RACING + "RaceFireballs.cpp" "RaceMaelstromGeiser.cpp" + "RaceShipLapColumnsServer.cpp" + "FvRacingColumns.cpp" PARENT_SCOPE) diff --git a/dScripts/02_server/Map/FV/Racing/FvRacingColumns.cpp b/dScripts/02_server/Map/FV/Racing/FvRacingColumns.cpp new file mode 100644 index 000000000..a3e3dd4a8 --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/FvRacingColumns.cpp @@ -0,0 +1,15 @@ +#include "FvRacingColumns.h" +#include "MovingPlatformComponent.h" + +void FvRacingColumns::OnStartup(Entity* self) { + auto* movingPlatformComponent = self->GetComponent<MovingPlatformComponent>(); + if (!movingPlatformComponent) return; + + movingPlatformComponent->StopPathing(); + movingPlatformComponent->SetSerialized(true); + int32_t pathStart = 0; + if (self->HasVar(u"attached_path_start")) { + pathStart = self->GetVar<uint32_t>(u"attached_path_start"); + } + movingPlatformComponent->WarpToWaypoint(pathStart); +} diff --git a/dScripts/02_server/Map/FV/Racing/FvRacingColumns.h b/dScripts/02_server/Map/FV/Racing/FvRacingColumns.h new file mode 100644 index 000000000..f4555693c --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/FvRacingColumns.h @@ -0,0 +1,6 @@ +#include "CppScripts.h" + +class FvRacingColumns : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; +}; diff --git a/dScripts/02_server/Map/FV/Racing/RaceFireballs.cpp b/dScripts/02_server/Map/FV/Racing/RaceFireballs.cpp new file mode 100644 index 000000000..fb0f12725 --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceFireballs.cpp @@ -0,0 +1,15 @@ +#include "RaceFireballs.h" +#include "SkillComponent.h" + +void RaceFireballs::OnStartup(Entity* self) { + self->AddTimer("fire", GeneralUtils::GenerateRandomNumber<float>(3.0f, 10.0f)); +} + +void RaceFireballs::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "fire") { + auto* skillComponent = self->GetComponent<SkillComponent>(); + if (skillComponent) skillComponent->CastSkill(894); + self->AddTimer("fire", GeneralUtils::GenerateRandomNumber<float>(3.0f, 10.0f)); + + } +} diff --git a/dScripts/02_server/Map/FV/Racing/RaceFireballs.h b/dScripts/02_server/Map/FV/Racing/RaceFireballs.h new file mode 100644 index 000000000..e96286ae0 --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceFireballs.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class RaceFireballs : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; +}; diff --git a/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.cpp b/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.cpp new file mode 100644 index 000000000..c0112b6ac --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.cpp @@ -0,0 +1,47 @@ +#include "RaceShipLapColumnsServer.h" + +#include "RacingControlComponent.h" +#include "MovingPlatformComponent.h" + +void RaceShipLapColumnsServer::OnStartup(Entity* self) { + self->SetVar(u"Lap2Complete", false); + self->SetVar(u"Lap3Complete", false); +} + +void SetMovingToWaypoint(const int32_t waypointIndex, const std::string group) { + const auto entities = Game::entityManager->GetEntitiesInGroup(group); + if (entities.empty()) return; + + auto* entity = entities[0]; + entity->SetIsGhostingCandidate(false); + + auto* movingPlatfromComponent = entity->GetComponent<MovingPlatformComponent>(); + if (!movingPlatfromComponent) return; + + movingPlatfromComponent->SetSerialized(true); + movingPlatfromComponent->GotoWaypoint(waypointIndex); + Game::entityManager->SerializeEntity(entity); +} + +void RaceShipLapColumnsServer::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + if (racingControllers.empty()) return; + + auto* racingControlComponent = racingControllers[0]->GetComponent<RacingControlComponent>(); + if (!racingControlComponent) return; + + const auto* player = racingControlComponent->GetPlayerData(target->GetObjectID()); + if (!player) return; + + if (player->lap == 1 && !self->GetVar<bool>(u"Lap2Complete")) { + self->SetVar(u"Lap2Complete", true); + SetMovingToWaypoint(1, "Lap2Column"); + SetMovingToWaypoint(0, "Lap2Ramp"); + } else if (player->lap == 2 && !self->GetVar<bool>(u"Lap3Complete")) { + self->SetVar(u"Lap3Complete", true); + SetMovingToWaypoint(1, "Lap3Column"); + SetMovingToWaypoint(0, "Lap3Ramp"); + } +} diff --git a/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.h b/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.h new file mode 100644 index 000000000..b8a268256 --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class RaceShipLapColumnsServer : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; +}; diff --git a/dScripts/02_server/Map/GF/CMakeLists.txt b/dScripts/02_server/Map/GF/CMakeLists.txt index 45ec871a3..c6a953006 100644 --- a/dScripts/02_server/Map/GF/CMakeLists.txt +++ b/dScripts/02_server/Map/GF/CMakeLists.txt @@ -4,6 +4,6 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_GF "MastTeleport.cpp" "SpawnLionServer.cpp") -add_library(dScriptsServerMapGF ${DSCRIPTS_SOURCES_02_SERVER_MAP_GF}) +add_library(dScriptsServerMapGF OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_GF}) target_include_directories(dScriptsServerMapGF PUBLIC ".") target_precompile_headers(dScriptsServerMapGF REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/General/CMakeLists.txt b/dScripts/02_server/Map/General/CMakeLists.txt index 4fe5aae89..3379e5b00 100644 --- a/dScripts/02_server/Map/General/CMakeLists.txt +++ b/dScripts/02_server/Map/General/CMakeLists.txt @@ -27,6 +27,6 @@ foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL_NINJAGO}) set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL} "Ninjago/${file}") endforeach() -add_library(dScriptsServerMapGeneral ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL}) +add_library(dScriptsServerMapGeneral OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL}) target_include_directories(dScriptsServerMapGeneral PUBLIC "." "Ninjago") target_precompile_headers(dScriptsServerMapGeneral REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/General/PetDigServer.cpp b/dScripts/02_server/Map/General/PetDigServer.cpp index a55c2f291..77a50e5af 100644 --- a/dScripts/02_server/Map/General/PetDigServer.cpp +++ b/dScripts/02_server/Map/General/PetDigServer.cpp @@ -215,20 +215,20 @@ void PetDigServer::SpawnPet(Entity* self, const Entity* owner, const DigInfo dig Game::entityManager->ConstructEntity(spawnedPet); } -Entity* PetDigServer::GetClosestTresure(NiPoint3 position) { +Entity* PetDigServer::GetClosestTreasure(NiPoint3 position) { float closestDistance = 0; Entity* closest = nullptr; - for (const auto tresureId : treasures) { - auto* tresure = Game::entityManager->GetEntity(tresureId); + for (const auto treasureId : treasures) { + auto* treasure = Game::entityManager->GetEntity(treasureId); - if (tresure == nullptr) continue; + if (treasure == nullptr) continue; - float distance = Vector3::DistanceSquared(tresure->GetPosition(), position); + float distance = Vector3::DistanceSquared(treasure->GetPosition(), position); if (closest == nullptr || distance < closestDistance) { closestDistance = distance; - closest = tresure; + closest = treasure; } } diff --git a/dScripts/02_server/Map/General/PetDigServer.h b/dScripts/02_server/Map/General/PetDigServer.h index 1122517b0..4091b1658 100644 --- a/dScripts/02_server/Map/General/PetDigServer.h +++ b/dScripts/02_server/Map/General/PetDigServer.h @@ -17,7 +17,7 @@ class PetDigServer : public CppScripts::Script void OnStartup(Entity* self) override; void OnDie(Entity* self, Entity* killer) override; - static Entity* GetClosestTresure(NiPoint3 position); + static Entity* GetClosestTreasure(NiPoint3 position); private: static void ProgressPetDigMissions(const Entity* owner, const Entity* chest); diff --git a/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp b/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp index 9a1a4908b..4ad78d6ab 100644 --- a/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp +++ b/dScripts/02_server/Map/General/StoryBoxInteractServer.cpp @@ -6,7 +6,7 @@ #include "Entity.h" void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) { - if (self->GetVar<bool>(u"hasCustomText")) { + if (self->HasVar(u"customText")) { const auto& customText = self->GetVar<std::string>(u"customText"); { @@ -29,15 +29,19 @@ void StoryBoxInteractServer::OnUse(Entity* self, Entity* user) { return; } + if (!self->HasVar(u"storyText")) return; const auto storyText = self->GetVarAsString(u"storyText"); + if (storyText.length() > 2) { + auto storyValue = GeneralUtils::TryParse<uint32_t>(storyText.substr(storyText.length() - 2)); + if(!storyValue) return; + int32_t boxFlag = self->GetVar<int32_t>(u"altFlagID"); + if (boxFlag <= 0) { + boxFlag = (10000 + Game::server->GetZoneID() + storyValue.value()); + } - int32_t boxFlag = self->GetVar<int32_t>(u"altFlagID"); - if (boxFlag <= 0) { - boxFlag = (10000 + Game::server->GetZoneID() + std::stoi(storyText.substr(storyText.length() - 2))); - } - - if (user->GetCharacter()->GetPlayerFlag(boxFlag) == false) { - user->GetCharacter()->SetPlayerFlag(boxFlag, true); - GameMessages::SendFireEventClientSide(self->GetObjectID(), user->GetSystemAddress(), u"achieve", LWOOBJID_EMPTY, 0, -1, LWOOBJID_EMPTY); + if (user->GetCharacter()->GetPlayerFlag(boxFlag) == false) { + user->GetCharacter()->SetPlayerFlag(boxFlag, true); + GameMessages::SendFireEventClientSide(self->GetObjectID(), user->GetSystemAddress(), u"achieve", LWOOBJID_EMPTY, 0, -1, LWOOBJID_EMPTY); + } } } diff --git a/dScripts/02_server/Map/General/TokenConsoleServer.cpp b/dScripts/02_server/Map/General/TokenConsoleServer.cpp index e13011cb9..0a1f679cd 100644 --- a/dScripts/02_server/Map/General/TokenConsoleServer.cpp +++ b/dScripts/02_server/Map/General/TokenConsoleServer.cpp @@ -17,7 +17,9 @@ void TokenConsoleServer::OnUse(Entity* self, Entity* user) { inv->RemoveItem(6194, bricksToTake); //play sound - GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), "947d0d52-c7f8-4516-8dee-e1593a7fd1d1"); + if (self->HasVar(u"sound1")) { + GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), self->GetVarAsString(u"sound1")); + } //figure out which faction the player belongs to: auto character = user->GetCharacter(); diff --git a/dScripts/02_server/Map/NS/CMakeLists.txt b/dScripts/02_server/Map/NS/CMakeLists.txt index 4927f0c87..6be99dab7 100644 --- a/dScripts/02_server/Map/NS/CMakeLists.txt +++ b/dScripts/02_server/Map/NS/CMakeLists.txt @@ -10,6 +10,6 @@ foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_NS_WAVES}) set(DSCRIPTS_SOURCES_02_SERVER_MAP_NS ${DSCRIPTS_SOURCES_02_SERVER_MAP_NS} "Waves/${file}") endforeach() -add_library(dScriptsServerMapNS ${DSCRIPTS_SOURCES_02_SERVER_MAP_NS}) +add_library(dScriptsServerMapNS OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_NS}) target_include_directories(dScriptsServerMapNS PUBLIC "." "Waves") target_precompile_headers(dScriptsServerMapNS REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp b/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp index 74542f9fc..7d8258280 100644 --- a/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp +++ b/dScripts/02_server/Map/NS/NsTokenConsoleServer.cpp @@ -39,7 +39,7 @@ void NsTokenConsoleServer::OnUse(Entity* self, Entity* user) { const auto useSound = self->GetVar<std::string>(u"sound1"); if (!useSound.empty()) { - GameMessages::SendPlayNDAudioEmitter(self, UNASSIGNED_SYSTEM_ADDRESS, useSound); + GameMessages::SendPlayNDAudioEmitter(self, user->GetSystemAddress(), useSound); } // Player must be in faction to interact with this entity. diff --git a/dScripts/02_server/Map/NT/CMakeLists.txt b/dScripts/02_server/Map/NT/CMakeLists.txt index 49c6a5aea..5ab3307cf 100644 --- a/dScripts/02_server/Map/NT/CMakeLists.txt +++ b/dScripts/02_server/Map/NT/CMakeLists.txt @@ -27,6 +27,6 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_NT "NtBcSubmitServer.cpp" "NtNaomiBreadcrumbServer.cpp") -add_library(dScriptsServerMapNT ${DSCRIPTS_SOURCES_02_SERVER_MAP_NT}) +add_library(dScriptsServerMapNT OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_NT}) target_include_directories(dScriptsServerMapNT PUBLIC ".") target_precompile_headers(dScriptsServerMapNT REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeDummy.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeDummy.cpp index 5be5a9b3d..13dd73c8a 100644 --- a/dScripts/02_server/Map/NT/NtCombatChallengeDummy.cpp +++ b/dScripts/02_server/Map/NT/NtCombatChallengeDummy.cpp @@ -1,5 +1,6 @@ #include "NtCombatChallengeDummy.h" #include "EntityManager.h" +#include "Entity.h" void NtCombatChallengeDummy::OnDie(Entity* self, Entity* killer) { const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID"); @@ -7,9 +8,7 @@ void NtCombatChallengeDummy::OnDie(Entity* self, Entity* killer) { auto* challengeObject = Game::entityManager->GetEntity(challengeObjectID); if (challengeObject != nullptr) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) { - script->OnDie(challengeObject, killer); - } + challengeObject->GetScript()->OnDie(challengeObject, killer); } } @@ -19,8 +18,6 @@ void NtCombatChallengeDummy::OnHitOrHealResult(Entity* self, Entity* attacker, i auto* challengeObject = Game::entityManager->GetEntity(challengeObjectID); if (challengeObject != nullptr) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) { - script->OnHitOrHealResult(challengeObject, attacker, damage); - } + challengeObject->GetScript()->OnHitOrHealResult(challengeObject, attacker, damage); } } diff --git a/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp b/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp index 4ae2b3354..c384b26d5 100644 --- a/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp +++ b/dScripts/02_server/Map/NT/NtCombatChallengeExplodingDummy.cpp @@ -9,9 +9,7 @@ void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) { auto* challengeObject = Game::entityManager->GetEntity(challengeObjectID); if (challengeObject != nullptr) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) { - script->OnDie(challengeObject, killer); - } + challengeObject->GetScript()->OnDie(challengeObject, killer); } } @@ -32,9 +30,7 @@ void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* at auto* challengeObject = Game::entityManager->GetEntity(challengeObjectID); if (challengeObject != nullptr) { - for (CppScripts::Script* script : CppScripts::GetEntityScripts(challengeObject)) { - script->OnHitOrHealResult(challengeObject, attacker, damage); - } + challengeObject->GetScript()->OnHitOrHealResult(challengeObject, attacker, damage); } auto skillComponent = self->GetComponent<SkillComponent>(); if (skillComponent != nullptr) { diff --git a/dScripts/02_server/Map/PR/CMakeLists.txt b/dScripts/02_server/Map/PR/CMakeLists.txt index 13b3fd35e..8de0e71df 100644 --- a/dScripts/02_server/Map/PR/CMakeLists.txt +++ b/dScripts/02_server/Map/PR/CMakeLists.txt @@ -3,6 +3,6 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_PR "PrSeagullFly.cpp" "SpawnGryphonServer.cpp") -add_library(dScriptsServerMapPR ${DSCRIPTS_SOURCES_02_SERVER_MAP_PR}) +add_library(dScriptsServerMapPR OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_PR}) target_include_directories(dScriptsServerMapPR PUBLIC ".") target_precompile_headers(dScriptsServerMapPR REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/Property/CMakeLists.txt b/dScripts/02_server/Map/Property/CMakeLists.txt index 52b91d0bf..b4085cfb9 100644 --- a/dScripts/02_server/Map/Property/CMakeLists.txt +++ b/dScripts/02_server/Map/Property/CMakeLists.txt @@ -19,7 +19,7 @@ foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY_NS_MED}) set(DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY} "NS_Med/${file}") endforeach() -add_library(dScriptsServerMapProperty ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY}) +add_library(dScriptsServerMapProperty OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_PROPERTY}) target_precompile_headers(dScriptsServerMapProperty REUSE_FROM dScriptsBase) target_include_directories(dScriptsServerMapProperty PUBLIC "." "AG_Med" diff --git a/dScripts/02_server/Map/SS/CMakeLists.txt b/dScripts/02_server/Map/SS/CMakeLists.txt index ed6a7596f..894d4ece5 100644 --- a/dScripts/02_server/Map/SS/CMakeLists.txt +++ b/dScripts/02_server/Map/SS/CMakeLists.txt @@ -1,6 +1,6 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_SS "SsModularBuildServer.cpp") -add_library(dScriptsServerMapSS ${DSCRIPTS_SOURCES_02_SERVER_MAP_SS}) +add_library(dScriptsServerMapSS OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_SS}) target_include_directories(dScriptsServerMapSS PUBLIC ".") target_precompile_headers(dScriptsServerMapSS REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/VE/CMakeLists.txt b/dScripts/02_server/Map/VE/CMakeLists.txt index 2dbcaaffe..8be55c9f9 100644 --- a/dScripts/02_server/Map/VE/CMakeLists.txt +++ b/dScripts/02_server/Map/VE/CMakeLists.txt @@ -3,6 +3,6 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_VE "VeEpsilonServer.cpp" "VeBricksampleServer.cpp") -add_library(dScriptsServerMapVE ${DSCRIPTS_SOURCES_02_SERVER_MAP_VE}) +add_library(dScriptsServerMapVE OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_VE}) target_include_directories(dScriptsServerMapVE PUBLIC ".") target_precompile_headers(dScriptsServerMapVE REUSE_FROM dScriptsBase) diff --git a/dScripts/02_server/Map/njhub/CMakeLists.txt b/dScripts/02_server/Map/njhub/CMakeLists.txt index 0f287ce32..94d99867c 100644 --- a/dScripts/02_server/Map/njhub/CMakeLists.txt +++ b/dScripts/02_server/Map/njhub/CMakeLists.txt @@ -28,7 +28,7 @@ foreach(file ${DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB_BOSS_INSTANCE}) set(DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB ${DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB} "boss_instance/${file}") endforeach() -add_library(dScriptsServerMapNJHub ${DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB}) +add_library(dScriptsServerMapNJHub OBJECT ${DSCRIPTS_SOURCES_02_SERVER_MAP_NJHUB}) target_include_directories(dScriptsServerMapNJHub PUBLIC "." "boss_instance") target_link_libraries(dScriptsServerMapNJHub dScriptsServerPets diff --git a/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp b/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp index 04d9711c9..1a7cac11a 100644 --- a/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp +++ b/dScripts/02_server/Objects/AgSurvivalBuffStation.cpp @@ -56,10 +56,6 @@ void AgSurvivalBuffStation::OnTimerDone(Entity* self, std::string timerName) { auto member = Game::entityManager->GetEntity(memberID); if (member != nullptr && !member->GetIsDead()) { GameMessages::SendDropClientLoot(member, self->GetObjectID(), powerupToDrop, 0, self->GetPosition()); - } else { - // If player left the team or left early erase them from the team variable. - team.erase(std::find(team.begin(), team.end(), memberID)); - self->SetVar<std::vector<LWOOBJID>>(u"BuilderTeam", team); } } } diff --git a/dScripts/02_server/Pets/CMakeLists.txt b/dScripts/02_server/Pets/CMakeLists.txt index 79123ebec..aa1d0e3f0 100644 --- a/dScripts/02_server/Pets/CMakeLists.txt +++ b/dScripts/02_server/Pets/CMakeLists.txt @@ -3,7 +3,7 @@ set(DSCRIPTS_SOURCES_02_SERVER_PETS "PetFromObjectServer.cpp" "DamagingPets.cpp") -add_library(dScriptsServerPets STATIC ${DSCRIPTS_SOURCES_02_SERVER_PETS}) +add_library(dScriptsServerPets OBJECT ${DSCRIPTS_SOURCES_02_SERVER_PETS}) target_include_directories(dScriptsServerPets PUBLIC ".") target_precompile_headers(dScriptsServerPets REUSE_FROM dScriptsBase) diff --git a/dScripts/CMakeLists.txt b/dScripts/CMakeLists.txt index b3fb7d447..29f04be32 100644 --- a/dScripts/CMakeLists.txt +++ b/dScripts/CMakeLists.txt @@ -11,24 +11,27 @@ set(DSCRIPTS_SOURCES "InvalidScript.cpp" "NPCAddRemoveItem.cpp" "NtFactionSpyServer.cpp" - "ScriptComponent.cpp" "ScriptedPowerupSpawner.cpp" "SpawnPetBaseServer.cpp") link_libraries(dDatabase dPhysics) -add_library(dScriptsBase STATIC ${DSCRIPTS_SOURCES}) -target_include_directories(dScriptsBase PUBLIC .) -target_link_libraries(dScriptsBase - INTERFACE dGameBase) +add_library(dScriptsBase OBJECT ${DSCRIPTS_SOURCES}) +target_link_libraries(dScriptsBase INTERFACE dGameBase dComponents) target_precompile_headers(dScriptsBase PRIVATE ${HEADERS_DGAME}) include_directories( - ${PROJECT_SOURCE_DIR}/dScripts - ${PROJECT_SOURCE_DIR}/dGame + "${PROJECT_SOURCE_DIR}/dScripts" + "${PROJECT_SOURCE_DIR}/dGame" + "${PROJECT_SOURCE_DIR}/dGame/dComponents" # e.g. ScriptedActivityComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" # e.g. direct ActivityManager + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" # e.g. direct ActivityManager + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # via dZoneManager.h + "${PROJECT_SOURCE_DIR}/dGame/dMission" # via MissionComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dBehaviors" # viaInventoryComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dInventory" # via InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dZoneManager" ) -link_libraries(dScriptsBase) -# dComponents add_subdirectory(02_server) add_subdirectory(ai) @@ -37,14 +40,22 @@ add_subdirectory(EquipmentScripts) add_subdirectory(EquipmentTriggers) add_subdirectory(zone) -add_library(dScripts STATIC "CppScripts.cpp") +add_library(dScripts STATIC + $<TARGET_OBJECTS:dScriptsBase> + $<TARGET_OBJECTS:dScriptsClient> + $<TARGET_OBJECTS:dScriptsEquipmentScripts> + $<TARGET_OBJECTS:dScriptsEquipmentTriggers> + $<TARGET_OBJECTS:dScriptsZone> + "CppScripts.cpp" +) +target_link_libraries(dScripts PRIVATE dScriptsAI dScriptsServer) +target_include_directories(dScripts PRIVATE + $<TARGET_PROPERTY:dScriptsBase,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsServer,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAI,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsClient,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsEquipmentScripts,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsEquipmentTriggers,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsZone,INTERFACE_INCLUDE_DIRECTORIES> +) target_precompile_headers(dScripts REUSE_FROM dScriptsBase) -target_include_directories(dScripts PUBLIC ".") -target_link_libraries(dScripts - dScriptsBase - dScriptsServer - dScriptsAI - dScriptsClient - dScriptsEquipmentScripts - dScriptsEquipmentTriggers - dScriptsZone) diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index 7cb853e62..ed0de2ba3 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -14,6 +14,7 @@ #include "AgShipPlayerDeathTrigger.h" #include "AgShipPlayerShockServer.h" #include "AgSpaceStuff.h" +#include "AgShipShake.h" #include "AgImagSmashable.h" #include "NpcNpSpacemanBob.h" #include "StoryBoxInteractServer.h" @@ -154,6 +155,11 @@ #include "FvBounceOverWall.h" #include "FvFong.h" #include "FvMaelstromGeyser.h" +#include "FvRaceDragon.h" +#include "FvRacePillarABCServer.h" +#include "FvRacePillarDServer.h" +#include "RaceFireballs.h" +#include "RaceShipLapColumnsServer.h" // FB Scripts #include "AgJetEffectServer.h" @@ -179,6 +185,7 @@ #include "RaceMaelstromGeiser.h" #include "FvRaceSmashEggImagineServer.h" #include "RaceSmashServer.h" +#include "FvRacingColumns.h" // NT Scripts #include "NtSentinelWalkwayServer.h" @@ -240,6 +247,7 @@ #include "AmDarklingDragon.h" #include "AmBlueX.h" #include "AmTeapotServer.h" +#include "WanderingVendor.h" // NJ Scripts #include "NjGarmadonCelebration.h" @@ -317,650 +325,394 @@ #include "WildNinjaSensei.h" #include "WildNinjaBricks.h" #include "VisToggleNotifierServer.h" +#include "LupGenericInteract.h" +#include "WblRobotCitizen.h" + +#include <map> +#include <string> +#include <functional> namespace { - InvalidScript* invalidToReturn = new InvalidScript(); - std::map<std::string, CppScripts::Script*> m_Scripts; + // This is in the translation unit instead of the header to prevent weird linker errors + InvalidScript InvalidToReturn; + std::map<std::string, CppScripts::Script*> g_Scripts; + std::map<std::string, std::function<CppScripts::Script* ()>> scriptLoader = { + + //VE / AG + { "scripts\\ai\\AG\\L_AG_SHIP_PLAYER_DEATH_TRIGGER.lua", []() { return new AgShipPlayerDeathTrigger(); } }, + {"scripts\\ai\\NP\\L_NPC_NP_SPACEMAN_BOB.lua", []() { return new NpcNpSpacemanBob(); } }, + {"scripts\\ai\\AG\\L_AG_SPACE_STUFF.lua", []() { return new AgSpaceStuff();} }, + {"scripts\\ai\\AG\\L_AG_SHIP_SHAKE.lua", []() { return new AgShipShake();}}, + {"scripts\\ai\\AG\\L_AG_SHIP_PLAYER_SHOCK_SERVER.lua", []() { return new AgShipPlayerShockServer();} }, + {"scripts\\ai\\AG\\L_AG_IMAG_SMASHABLE.lua", []() { return new AgImagSmashable();} }, + {"scripts\\02_server\\Map\\General\\L_STORY_BOX_INTERACT_SERVER.lua", []() { return new StoryBoxInteractServer();} }, + {"scripts\\02_server\\Map\\General\\L_BINOCULARS.lua", []() { return new Binoculars();} }, + {"scripts\\ai\\WILD\\L_ALL_CRATE_CHICKEN.lua", []() { return new AllCrateChicken();} }, + // Broken? (below) + {"scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_SMASHABLE.lua", []() { return new RockHydrantSmashable();} }, + {"scripts\\02_server\\Map\\SS\\L_SS_MODULAR_BUILD_SERVER.lua", []() { return new SsModularBuildServer();} }, + {"scripts\\02_server\\Map\\Property\\AG_Small\\L_ZONE_AG_PROPERTY.lua", []() { return new ZoneAgProperty();} }, + // this is done in Entity.cpp, not needed for our implementation (below) + {"scripts\\02_server\\Map\\General\\L_POI_MISSION.lua", []() { return new InvalidScript();} }, + {"scripts\\02_server\\Map\\General\\L_TOUCH_MISSION_UPDATE_SERVER.lua", []() { return new TouchMissionUpdateServer();} }, + {"scripts\\ai\\AG\\L_ACT_SHARK_PLAYER_DEATH_TRIGGER.lua", []() { return new ActSharkPlayerDeathTrigger();} }, + {"scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_MECH.lua", []() { return new BaseEnemyMech();} }, + {"scripts\\zone\\AG\\L_ZONE_AG_SURVIVAL.lua", []() { return new ZoneAgSurvival();} }, + {"scripts\\02_server\\Objects\\L_BUFF_STATION_SERVER.lua", []() { return new AgSurvivalBuffStation();} }, + {"scripts\\ai\\AG\\L_AG_BUS_DOOR.lua", []() { return new AgBusDoor();} }, + {"scripts\\02_server\\Equipment\\L_MAESTROM_EXTRACTICATOR_SERVER.lua", []() { return new MaestromExtracticatorServer();} }, + {"scripts\\02_server\\Map\\AG\\L_AG_CAGED_BRICKS_SERVER.lua", []() { return new AgCagedBricksServer();} }, + {"scripts\\02_server\\Map\\AG\\L_NPC_WISP_SERVER.lua", []() { return new NpcWispServer();} }, + {"scripts\\02_server\\Map\\AG\\L_NPC_EPSILON_SERVER.lua", []() { return new NpcEpsilonServer();} }, + {"scripts\\ai\\AG\\L_AG_TURRET.lua", []() {return new AgTurret();}}, + {"scripts\\ai\\AG\\L_AG_TURRET_FOR_SHIP.lua", []() { return new AgTurret();}}, + {"scripts\\02_server\\Map\\AG\\L_AG_LASER_SENSOR_SERVER.lua", []() {return new AgLaserSensorServer();}}, + {"scripts\\02_server\\Map\\AG\\L_AG_MONUMENT_LASER_SERVER.lua", []() {return new AgMonumentLaserServer();}}, + {"scripts\\ai\\AG\\L_AG_FANS.lua", []() {return new AgFans();}}, + {"scripts\\02_server\\Map\\AG\\L_AG_MONUMENT_BIRDS.lua", []() {return new AgMonumentBirds();}}, + {"scripts\\02_server\\Map\\AG\\L_REMOVE_RENTAL_GEAR.lua", []() {return new RemoveRentalGear();}}, + {"scripts\\02_server\\Map\\AG\\L_NPC_NJ_ASSISTANT_SERVER.lua", []() {return new NpcNjAssistantServer();}}, + {"scripts\\ai\\AG\\L_AG_SALUTING_NPCS.lua", []() {return new AgSalutingNpcs();}}, + {"scripts\\ai\\AG\\L_AG_JET_EFFECT_SERVER.lua", []() {return new AgJetEffectServer();}}, + {"scripts\\02_server\\Enemy\\AG\\L_BOSS_SPIDER_QUEEN_ENEMY_SERVER.lua", []() {return new BossSpiderQueenEnemyServer();}}, + {"scripts\\02_server\\Map\\Property\\AG_Small\\L_ENEMY_SPIDER_SPAWNER.lua", []() {return new EnemySpiderSpawner();}}, + {"scripts/02_server/Map/Property/AG_Small/L_ENEMY_SPIDER_SPAWNER.lua", []() {return new EnemySpiderSpawner();}}, + {"scripts\\ai\\AG\\L_AG_QB_Elevator.lua", []() {return new AgQbElevator();}}, + {"scripts\\ai\\PROPERTY\\AG\\L_AG_PROP_GUARD.lua", []() {return new AgPropGuard();}}, + {"scripts\\02_server\\Map\\AG\\L_AG_BUGSPRAYER.lua", []() {return new AgBugsprayer();}}, + {"scripts\\02_server\\Map\\AG\\L_NPC_AG_COURSE_STARTER.lua", []() {return new NpcAgCourseStarter();}}, + {"scripts\\02_server\\Map\\AG\\L__AG_MONUMENT_RACE_GOAL.lua", []() {return new AgMonumentRaceGoal();}}, + {"scripts\\02_server\\Map\\AG\\L__AG_MONUMENT_RACE_CANCEL.lua", []() {return new AgMonumentRaceCancel();}}, + {"scripts\\02_server\\Map\\AG_Spider_Queen\\L_ZONE_AG_SPIDER_QUEEN.lua", []() {return new ZoneAgSpiderQueen();}}, + {"scripts\\02_server\\Map\\AG_Spider_Queen\\L_SPIDER_BOSS_TREASURE_CHEST_SERVER.lua", []() {return new SpiderBossTreasureChestServer();}}, + {"scripts\\02_server\\Map\\AG\\L_NPC_COWBOY_SERVER.lua", []() {return new NpcCowboyServer();}}, + {"scripts\\02_server\\Map\\Property\\AG_Med\\L_ZONE_AG_MED_PROPERTY.lua", []() {return new ZoneAgMedProperty();}}, + {"scripts\\ai\\AG\\L_AG_STROMBIE_PROPERTY.lua", []() {return new AgStromlingProperty();}}, + {"scripts\\ai\\AG\\L_AG_DARKLING_MECH.lua", []() {return new BaseEnemyMech();}}, + {"scripts\\ai\\AG\\L_AG_DARK_SPIDERLING.lua", []() {return new AgDarkSpiderling();}}, + {"scripts\\ai\\PROPERTY\\L_PROP_GUARDS.lua", []() {return new AgPropguards();}}, + {"scripts\\ai\\PROPERTY\\L_PROPERTY_FX_DAMAGE.lua", []() {return new PropertyFXDamage();}}, + {"scripts\\02_server\\Map\\AG\\L_NPC_PIRATE_SERVER.lua", []() {return new NpcPirateServer();}}, + {"scripts\\ai\\AG\\L_AG_PICNIC_BLANKET.lua", []() {return new AgPicnicBlanket();}}, + {"scripts\\02_server\\Map\\Property\\L_PROPERTY_BANK_INTERACT_SERVER.lua", []() {return new PropertyBankInteract();}}, + {"scripts\\02_server\\Enemy\\VE\\L_VE_MECH.lua", []() {return new VeMech();}}, + {"scripts\\02_server\\Map\\VE\\L_MISSION_CONSOLE_SERVER.lua", []() {return new VeMissionConsole();}}, + {"scripts\\02_server\\Map\\VE\\L_EPSILON_SERVER.lua", []() {return new VeEpsilonServer();}}, + + //NS + {"scripts\\ai\\NS\\L_NS_MODULAR_BUILD.lua", []() {return new NsModularBuild();}}, + {"scripts\\ai\\NS\\L_NS_GET_FACTION_MISSION_SERVER.lua", []() {return new NsGetFactionMissionServer();}}, + {"scripts\\ai\\NS\\L_NS_QB_IMAGINATION_STATUE.lua", []() {return new NsQbImaginationStatue();}}, + {"scripts\\02_server\\Map\\NS\\CONCERT_CHOICEBUILD_MANAGER_SERVER.lua", []() {return new NsConcertChoiceBuildManager();}}, + {"scripts\\ai\\NS\\L_NS_CONCERT_CHOICEBUILD.lua", []() {return new NsConcertChoiceBuild();}}, + {"scripts\\ai\\NS\\L_NS_CONCERT_QUICKBUILD.lua", []() {return new NsConcertQuickBuild();}}, + {"scripts\\ai\\AG\\L_AG_STAGE_PLATFORMS.lua", []() {return new AgStagePlatforms();}}, + {"scripts\\ai\\NS\\L_NS_CONCERT_INSTRUMENT_QB.lua", []() {return new NsConcertInstrument();}}, + {"scripts\\ai\\NS\\L_NS_JONNY_FLAG_MISSION_SERVER.lua", []() {return new NsJohnnyMissionServer();}}, + {"scripts\\02_server\\Objects\\L_STINKY_FISH_TARGET.lua", []() {return new StinkyFishTarget();}}, + {"scripts\\zone\\PROPERTY\\NS\\L_ZONE_NS_PROPERTY.lua", []() {return new ZoneNsProperty();}}, + {"scripts\\02_server\\Map\\Property\\NS_Med\\L_ZONE_NS_MED_PROPERTY.lua", []() {return new ZoneNsMedProperty();}}, + {"scripts\\02_server\\Map\\NS\\L_NS_TOKEN_CONSOLE_SERVER.lua", []() {return new NsTokenConsoleServer();}}, + {"scripts\\02_server\\Map\\NS\\L_NS_LUP_TELEPORT.lua", []() {return new NsLupTeleport();}}, + {"scripts\\02_server\\Map\\NS\\Waves\\L_ZONE_NS_WAVES.lua", []() {return new ZoneNsWaves();}}, + {"scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_HAMMERLING_ENEMY_SERVER.lua", []() {return new WaveBossHammerling();}}, + {"scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_APE_ENEMY_SERVER.lua", []() {return new WaveBossApe();}}, + {"scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_DARK_SPIDERLING_ENEMY_SERVER.lua", []() {return new WaveBossSpiderling();}}, + {"scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_HORESEMEN_ENEMY_SERVER.lua", []() {return new WaveBossHorsemen();}}, + {"scripts\\02_server\\Minigame\\General\\L_MINIGAME_TREASURE_CHEST_SERVER.lua", []() {return new MinigameTreasureChestServer();}}, + {"scripts\\02_server\\Map\\NS\\L_NS_LEGO_CLUB_DOOR.lua", []() {return new NsLegoClubDoor();}}, + {"scripts/ai/NS/L_CL_RING.lua", []() {return new ClRing();}}, + {"scripts\\ai\\WILD\\L_WILD_AMBIENTS.lua", []() {return new WildAmbients();}}, + {"scripts\\ai\\NS\\NS_PP_01\\L_NS_PP_01_TELEPORT.lua", []() {return new PropertyDeathPlane();}}, + {"scripts\\02_server\\Map\\General\\L_QB_SPAWNER.lua", []() {return new QbSpawner();}}, + {"scripts\\ai\\AG\\L_AG_QB_Wall.lua", []() {return new AgQbWall();}}, + + //GF + {"scripts\\02_server\\Map\\GF\\L_GF_TORCH.lua", []() {return new GfTikiTorch();}}, + {"scripts\\ai\\GF\\L_SPECIAL_FIREPIT.lua", []() {return new GfCampfire();}}, + {"scripts\\ai\\GF\\L_GF_ORGAN.lua", []() {return new GfOrgan();}}, + {"scripts\\ai\\GF\\L_GF_BANANA.lua", []() {return new GfBanana();}}, + {"scripts\\ai\\GF\\L_GF_BANANA_CLUSTER.lua", []() {return new GfBananaCluster();}}, + {"scripts/ai/GF/L_GF_JAILKEEP_MISSION.lua", []() {return new GfJailkeepMission();}}, + {"scripts\\ai\\GF\\L_TRIGGER_AMBUSH.lua", []() {return new TriggerAmbush();}}, + {"scripts\\02_server\\Map\\GF\\L_GF_CAPTAINS_CANNON.lua", []() {return new GfCaptainsCannon();}}, + {"scripts\\02_server\\Map\\GF\\L_MAST_TELEPORT.lua", []() {return new MastTeleport();}}, + {"scripts\\ai\\GF\\L_GF_JAIL_WALLS.lua", []() {return new GfJailWalls();}}, + {"scripts\\02_server\\Map\\General\\L_QB_ENEMY_STUNNER.lua", []() {return new QbEnemyStunner();}}, + //Technically also used once in AG (below) + {"scripts\\ai\\GF\\L_GF_PET_DIG_BUILD.lua", []() {return new PetDigBuild();}}, + {"scripts\\02_server\\Map\\GF\\L_SPAWN_LION_SERVER.lua", []() {return new SpawnLionServer();}}, + {"scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_APE.lua", []() {return new BaseEnemyApe();}}, + {"scripts\\02_server\\Enemy\\General\\L_GF_APE_SMASHING_QB.lua", []() {return new GfApeSmashingQB();}}, + {"scripts\\zone\\PROPERTY\\GF\\L_ZONE_GF_PROPERTY.lua", []() {return new ZoneGfProperty();}}, + {"scripts\\ai\\GF\\L_GF_ARCHWAY.lua", []() {return new GfArchway();}}, + {"scripts\\ai\\GF\\L_GF_MAELSTROM_GEYSER.lua", []() {return new GfMaelstromGeyser();}}, + {"scripts\\ai\\GF\\L_PIRATE_REP.lua", []() {return new PirateRep();}}, + {"scripts\\ai\\GF\\L_GF_PARROT_CRASH.lua", []() {return new GfParrotCrash();}}, + + //SG + {"scripts\\ai\\MINIGAME\\SG_GF\\SERVER\\SG_CANNON.lua", []() {return new SGCannon();}}, + {"scripts\\ai\\MINIGAME\\SG_GF\\L_ZONE_SG_SERVER.lua", []() {return new ZoneSGServer();}}, + + //PR + {"scripts\\client\\ai\\PR\\L_PR_WHISTLE.lua", []() {return new PrWhistle();}}, + {"scripts\\02_server\\Map\\PR\\L_PR_SEAGULL_FLY.lua", []() {return new PrSeagullFly();}}, + {"scripts\\ai\\PETS\\L_HYDRANT_SMASHABLE.lua", []() {return new HydrantSmashable();}}, + {"scripts\\02_server\\map\\PR\\L_HYDRANT_BROKEN.lua", []() {return new HydrantBroken();}}, + {"scripts\\02_server\\Map\\General\\PET_DIG_SERVER.lua", []() {return new PetDigServer();}}, + {"scripts\\02_server\\Map\\AM\\L_SKELETON_DRAGON_PET_DIG_SERVER.lua", []() {return new PetDigServer();}}, + //{"scripts\\02_server\\Map\\AM\\L_SKELETON_DRAGON_PET_DIG_SERVER.lua", [](){return new PetDigServer();}}, + {"scripts\\client\\ai\\PR\\L_CRAB_SERVER.lua", []() {return new CrabServer();}}, + {"scripts\\02_server\\Pets\\L_PET_FROM_DIG_SERVER.lua", []() {return new PetFromDigServer();}}, + {"scripts\\02_server\\Pets\\L_PET_FROM_OBJECT_SERVER.lua", []() {return new PetFromObjectServer();}}, + {"scripts\\02_server\\Pets\\L_DAMAGING_PET.lua", []() {return new DamagingPets();}}, + {"scripts\\02_server\\Map\\PR\\L_SPAWN_GRYPHON_SERVER.lua", []() {return new SpawnGryphonServer();}}, + + //FV + {"scripts\\02_server\\Map\\FV\\L_ACT_CANDLE.lua", []() {return new FvCandle();}}, + {"scripts\\02_server\\Map\\FV\\L_ENEMY_RONIN_SPAWNER.lua", []() {return new EnemyRoninSpawner();}}, + {"scripts\\02_server\\Enemy\\FV\\L_FV_MAELSTROM_CAVALRY.lua", []() {return new FvMaelstromCavalry();}}, + {"scripts\\ai\\FV\\L_ACT_NINJA_TURRET_1.lua", []() {return new ActNinjaTurret();}}, + {"scripts\\02_server\\Map\\FV\\L_FV_HORSEMEN_TRIGGER.lua", []() {return new FvHorsemenTrigger();}}, + {"scripts\\ai\\FV\\L_FV_FLYING_CREVICE_DRAGON.lua", []() {return new FvFlyingCreviceDragon();}}, + {"scripts\\02_server\\Enemy\\FV\\L_FV_MAELSTROM_DRAGON.lua", []() {return new FvMaelstromDragon();}}, + {"scripts\\ai\\FV\\L_FV_DRAGON_SMASHING_GOLEM_QB.lua", []() {return new FvDragonSmashingGolemQb();}}, + {"scripts\\02_server\\Enemy\\General\\L_TREASURE_CHEST_DRAGON_SERVER.lua", []() {return new TreasureChestDragonServer();}}, + {"scripts\\ai\\GENERAL\\L_INSTANCE_EXIT_TRANSFER_PLAYER_TO_LAST_NON_INSTANCE.lua", []() {return new InstanceExitTransferPlayerToLastNonInstance();}}, + {"scripts\\ai\\FV\\L_NPC_FREE_GF_NINJAS.lua", []() {return new FvFreeGfNinjas();}}, + {"scripts\\ai\\FV\\L_FV_PANDA_SPAWNER_SERVER.lua", []() {return new FvPandaSpawnerServer();}}, + {"scripts\\ai\\FV\\L_FV_PANDA_SERVER.lua", []() {return new FvPandaServer();}}, + {"scripts\\zone\\PROPERTY\\FV\\L_ZONE_FV_PROPERTY.lua", []() {return new ZoneFvProperty();}}, + {"scripts\\ai\\FV\\L_FV_BRICK_PUZZLE_SERVER.lua", []() {return new FvBrickPuzzleServer();}}, + {"scripts\\ai\\FV\\L_FV_CONSOLE_LEFT_QUICKBUILD.lua", []() {return new FvConsoleLeftQuickbuild();}}, + {"scripts\\ai\\FV\\L_FV_CONSOLE_RIGHT_QUICKBUILD.lua", []() {return new FvConsoleRightQuickbuild();}}, + {"scripts\\ai\\FV\\L_FV_FACILITY_BRICK.lua", []() {return new FvFacilityBrick();}}, + {"scripts\\ai\\FV\\L_FV_FACILITY_PIPES.lua", []() {return new FvFacilityPipes();}}, + {"scripts\\02_server\\Map\\FV\\L_IMG_BRICK_CONSOLE_QB.lua", []() {return new ImgBrickConsoleQB();}}, + {"scripts\\ai\\FV\\L_ACT_PARADOX_PIPE_FIX.lua", []() {return new ActParadoxPipeFix();}}, + {"scripts\\ai\\FV\\L_FV_NINJA_GUARDS.lua", []() {return new FvNinjaGuard();}}, + {"scripts\\ai\\FV\\L_ACT_PASS_THROUGH_WALL.lua", []() {return new FvPassThroughWall();}}, + {"scripts\\ai\\FV\\L_ACT_BOUNCE_OVER_WALL.lua", []() {return new FvBounceOverWall();}}, + {"scripts\\02_server\\Map\\FV\\L_NPC_FONG.lua", []() {return new FvFong();}}, + {"scripts\\ai\\FV\\L_FV_MAELSTROM_GEYSER.lua", []() {return new FvMaelstromGeyser();}}, + {"scripts\\02_server\\Map\\FV\\Racing\\RACE_SHIP_LAP_COLUMNS_SERVER.lua", []() {return new RaceShipLapColumnsServer();}}, + + //yes we know the lap numbers dont match the file name or anim. Thats what they desgined it as. + {"scripts\\ai\\RACING\\OBJECTS\\FV_RACE_DRAGON_LAP1_SERVER.lua", []() {return new FvRaceDragon("lap_01", 2);}}, + {"scripts\\ai\\RACING\\OBJECTS\\FV_RACE_DRAGON_LAP2_SERVER.lua", []() {return new FvRaceDragon("lap_02", 0);}}, + {"scripts\\ai\\RACING\\OBJECTS\\FV_RACE_DRAGON_LAP3_SERVER.lua", []() {return new FvRaceDragon("lap_03", 1);}}, + {"scripts\\ai\\RACING\\OBJECTS\\FV_RACE_PILLAR_ABC_SERVER.lua", []() {return new FvRacePillarABCServer();}}, + {"scripts\\ai\\RACING\\OBJECTS\\FV_RACE_PILLAR_D_SERVER.lua", []() {return new FvRacePillarDServer();}}, + {"scripts\\02_server\\Map\\FV\\Racing\\RACE_FIREBALLS.lua", []() {return new RaceFireballs();}}, + + //Misc. + {"scripts\\02_server\\Map\\General\\L_EXPLODING_ASSET.lua", []() {return new ExplodingAsset();}}, + {"scripts\\02_server\\Map\\General\\L_WISHING_WELL_SERVER.lua", []() {return new WishingWellServer();}}, + {"scripts\\ai\\ACT\\L_ACT_PLAYER_DEATH_TRIGGER.lua", []() {return new ActPlayerDeathTrigger();}}, + {"scripts\\02_server\\Map\\General\\L_GROWING_FLOWER_SERVER.lua", []() {return new GrowingFlower();}}, + {"scripts\\02_server\\Map\\General\\L_TOKEN_CONSOLE_SERVER.lua", []() {return new TokenConsoleServer();}}, + {"scripts\\ai\\ACT\\FootRace\\L_ACT_BASE_FOOT_RACE.lua", []() {return new BaseFootRaceManager();}}, + {"scripts\\02_server\\Map\\General\\L_PROP_PLATFORM.lua", []() {return new PropertyPlatform();}}, + {"scripts\\02_server\\Map\\VE\\L_VE_BRICKSAMPLE_SERVER.lua", []() {return new VeBricksampleServer();}}, + {"scripts\\02_server\\Map\\General\\L_MAIL_BOX_SERVER.lua", []() {return new MailBoxServer();}}, + {"scripts\\ai\\ACT\\L_ACT_MINE.lua", []() {return new ActMine();}}, + {"scripts\\02_server\\Map\\AM\\L_WANDERING_VENDOR.lua", []() {return new WanderingVendor();}}, + + //Racing + {"scripts\\ai\\RACING\\OBJECTS\\RACE_IMAGINE_CRATE_SERVER.lua", []() {return new RaceImagineCrateServer();}}, + {"scripts\\ai\\ACT\\L_ACT_VEHICLE_DEATH_TRIGGER.lua", []() {return new ActVehicleDeathTrigger();}}, + {"scripts\\ai\\RACING\\OBJECTS\\RACE_IMAGINE_POWERUP.lua", []() {return new RaceImaginePowerup();}}, + {"scripts\\02_server\\Map\\FV\\Racing\\RACE_MAELSTROM_GEISER.lua", []() {return new RaceMaelstromGeiser();}}, + {"scripts\\ai\\RACING\\OBJECTS\\FV_RACE_SMASH_EGG_IMAGINE_SERVER.lua", []() {return new FvRaceSmashEggImagineServer();}}, + {"scripts\\02_server\\Map\\FV\\Racing\\FV_RACING_COLUMNS.lua", []() {return new FvRacingColumns();}}, + {"scripts\\ai\\RACING\\OBJECTS\\RACE_SMASH_SERVER.lua", []() {return new RaceSmashServer();}}, + + //NT + {"scripts\\02_server\\Map\\NT\\L_NT_SENTINELWALKWAY_SERVER.lua", []() {return new NtSentinelWalkwayServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_PARADOXTELE_SERVER.lua", []() {return new NtParadoxTeleServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_DARKITECT_REVEAL_SERVER.lua", []() {return new NtDarkitectRevealServer();}}, + {"scripts\\02_server\\Map\\General\\L_BANK_INTERACT_SERVER.lua", []() {return new BankInteractServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_VENTURESPEEDPAD_SERVER.lua", []() {return new NtVentureSpeedPadServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_VENTURE_CANNON_SERVER.lua", []() {return new NtVentureCannonServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_COMBAT_CHALLENGE_SERVER.lua", []() {return new NtCombatChallengeServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_COMBAT_CHALLENGE_DUMMY.lua", []() {return new NtCombatChallengeDummy();}}, + {"scripts\\02_server\\Map\\NT\\\\L_NT_COMBAT_EXPLODING_TARGET.lua", []() {return new NtCombatChallengeExplodingDummy();}}, + {"scripts\\02_server\\Map\\General\\L_BASE_INTERACT_DROP_LOOT_SERVER.lua", []() {return new BaseInteractDropLootServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_ASSEMBLYTUBE_SERVER.lua", []() {return new NtAssemblyTubeServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_PARADOX_PANEL_SERVER.lua", []() {return new NtParadoxPanelServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_IMAG_BEAM_BUFFER.lua", []() {return new NtImagBeamBuffer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_BEAM_IMAGINATION_COLLECTORS.lua", []() {return new NtBeamImaginationCollectors();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_DIRT_CLOUD_SERVER.lua", []() {return new NtDirtCloudServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_CONSOLE_TELEPORT_SERVER.lua", []() {return new NtConsoleTeleportServer();}}, + {"scripts\\02_server\\Map\\NT\\L_SPAWN_STEGO_SERVER.lua", []() {return new SpawnStegoServer();}}, + {"scripts\\02_server\\Map\\NT\\L_SPAWN_SABERCAT_SERVER.lua", []() {return new SpawnSaberCatServer();}}, + {"scripts\\02_server\\Map\\NT\\L_SPAWN_SHRAKE_SERVER.lua", []() {return new SpawnShrakeServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_DUKE_SERVER.lua", []() {return new NtDukeServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_HAEL_SERVER.lua", []() {return new NtHaelServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_FACTION_SPY_SERVER.lua", []() {return new NtFactionSpyServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_OVERBUILD_SERVER.lua", []() {return new NtOverbuildServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_VANDA_SERVER.lua", []() {return new NtVandaServer();}}, + {"scripts\\02_server\\Map\\General\\L_FORCE_VOLUME_SERVER.lua", []() {return new ForceVolumeServer();}}, + {"scripts\\02_server\\Map\\General\\L_FRICTION_VOLUME_SERVER.lua", []() {return new FrictionVolumeServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_XRAY_SERVER.lua", []() {return new NtXRayServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_SLEEPING_GUARD.lua", []() {return new NtSleepingGuard();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_IMAGIMETER_VISIBILITY_SERVER.lua", []() {return new NTImagimeterVisibility();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_PIPE_VISIBILITY_SERVER.lua", []() {return new NTPipeVisibilityServer();}}, + {"scripts\\ai\\MINIGAME\\Objects\\MINIGAME_BLUE_MARK.lua", []() {return new MinigameBlueMark();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_NAOMI_BREADCRUMB_SERVER.lua", []() {return new NtNaomiBreadcrumbServer();}}, + {"scripts\\02_server\\Map\\NT\\L_NT_NAOMI_DIRT_SERVER.lua", []() {return new NTNaomiDirtServer();}}, + + //AM Crux + {"scripts\\02_server\\Map\\AM\\L_AM_CONSOLE_TELEPORT_SERVER.lua", []() {return new AmConsoleTeleportServer();}}, + {"scripts\\02_server\\Map\\AM\\L_RANDOM_SPAWNER_FIN.lua", []() {return new RandomSpawnerFin();}}, + {"scripts\\02_server\\Map\\AM\\L_RANDOM_SPAWNER_PIT.lua", []() {return new RandomSpawnerPit();}}, + {"scripts\\02_server\\Map\\AM\\L_RANDOM_SPAWNER_STR.lua", []() {return new RandomSpawnerStr();}}, + {"scripts\\02_server\\Map\\AM\\L_RANDOM_SPAWNER_ZIP.lua", []() {return new RandomSpawnerZip();}}, + {"scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_MECH.lua", []() {return new AmDarklingMech();}}, + {"scripts\\02_server\\Map\\AM\\L_BRIDGE.lua", []() {return new AmBridge();}}, + {"scripts\\02_server\\Map\\AM\\L_DRAW_BRIDGE.lua", []() {return new AmDrawBridge();}}, + {"scripts\\02_server\\Map\\AM\\L_SHIELD_GENERATOR.lua", []() {return new AmShieldGenerator();}}, + {"scripts\\02_server\\Map\\AM\\L_SHIELD_GENERATOR_QUICKBUILD.lua", []() {return new AmShieldGeneratorQuickbuild();}}, + {"scripts\\02_server\\Map\\AM\\L_DROPSHIP_COMPUTER.lua", []() {return new AmDropshipComputer();}}, + {"scripts\\02_server\\Map\\AM\\L_SCROLL_READER_SERVER.lua", []() {return new AmScrollReaderServer();}}, + {"scripts\\02_server\\Map\\AM\\L_TEMPLE_SKILL_VOLUME.lua", []() {return new AmTemplateSkillVolume();}}, + {"scripts\\02_server\\Enemy\\General\\L_ENEMY_NJ_BUFF.lua", []() {return new EnemyNjBuff();}}, + {"scripts\\02_server\\Enemy\\AM\\L_AM_SKELETON_ENGINEER.lua", []() {return new AmSkeletonEngineer();}}, + {"scripts\\02_server\\Map\\AM\\L_SKULLKIN_DRILL.lua", []() {return new AmSkullkinDrill();}}, + {"scripts\\02_server\\Map\\AM\\L_SKULLKIN_DRILL_STAND.lua", []() {return new AmSkullkinDrillStand();}}, + {"scripts\\02_server\\Map\\AM\\L_SKULLKIN_TOWER.lua", []() {return new AmSkullkinTower();}}, + {"scripts\\02_server\\Enemy\\AM\\L_AM_NAMED_DARKLING_DRAGON.lua", []() {return new AmDarklingDragon();}}, + {"scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_DRAGON.lua", []() {return new AmDarklingDragon();}}, + {"scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_APE.lua", []() {return new BaseEnemyApe();}}, + {"scripts\\02_server\\Map\\AM\\L_BLUE_X.lua", []() {return new AmBlueX();}}, + {"scripts\\02_server\\Map\\AM\\L_TEAPOT_SERVER.lua", []() {return new AmTeapotServer();}}, + + //Ninjago + {"scripts\\02_server\\Map\\njhub\\L_GARMADON_CELEBRATION_SERVER.lua", []() {return new NjGarmadonCelebration();}}, + {"scripts\\02_server\\Map\\njhub\\L_WU_NPC.lua", []() {return new NjWuNPC();}}, + {"scripts\\02_server\\Map\\njhub\\L_SCROLL_CHEST_SERVER.lua", []() {return new NjScrollChestServer();}}, + {"scripts\\02_server\\Map\\njhub\\L_COLE_NPC.lua", []() {return new NjColeNPC();}}, + {"scripts\\02_server\\Map\\njhub\\L_JAY_MISSION_ITEMS.lua", []() {return new NjJayMissionItems();}}, + {"scripts\\02_server\\Map\\njhub\\L_NPC_MISSION_SPINJITZU_SERVER.lua", []() {return new NjNPCMissionSpinjitzuServer();}}, + {"scripts\\02_server\\Map\\njhub\\L_ENEMY_SKELETON_SPAWNER.lua", []() {return new EnemySkeletonSpawner();}}, + {"scripts\\02_server\\Map\\General\\L_NJ_RAIL_SWITCH.lua", []() {return new NjRailSwitch();}}, + {"scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_ACTIVATORS_SERVER.lua", []() {return new NjRailActivatorsServer();}}, + {"scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_POST_SERVER.lua", []() {return new NjRailPostServer();}}, + {"scripts\\02_server\\Map\\General\\Ninjago\\L_ICE_RAIL_ACTIVATOR_SERVER.lua", []() {return new NjIceRailActivator();}}, + {"scripts\\02_server\\Map\\njhub\\L_FALLING_TILE.lua", []() {return new FallingTile();}}, + {"scripts\\02_server\\Enemy\\General\\L_ENEMY_NJ_BUFF_STUN_IMMUNITY.lua", []() {return new EnemyNjBuff();}}, + {"scripts\\02_server\\Map\\njhub\\L_IMAGINATION_SHRINE_SERVER.lua", []() {return new ImaginationShrineServer();}}, + {"scripts\\02_server\\Map\\njhub\\L_LIEUTENANT.lua", []() {return new Lieutenant();}}, + {"scripts\\02_server\\Map\\njhub\\L_RAIN_OF_ARROWS.lua", []() {return new RainOfArrows();}}, + {"scripts\\02_server\\Map\\njhub\\L_CAVE_PRISON_CAGE.lua", []() {return new CavePrisonCage();}}, + {"scripts\\02_server\\Map\\njhub\\boss_instance\\L_MONASTERY_BOSS_INSTANCE_SERVER.lua", []() {return new NjMonastryBossInstance();}}, + {"scripts\\02_server\\Map\\njhub\\L_CATAPULT_BOUNCER_SERVER.lua", []() {return new CatapultBouncerServer();}}, + {"scripts\\02_server\\Map\\njhub\\L_CATAPULT_BASE_SERVER.lua", []() {return new CatapultBaseServer();}}, + {"scripts\\02_server\\Map\\General\\Ninjago\\L_NJHUB_LAVA_PLAYER_DEATH_TRIGGER.lua", []() {return new NjhubLavaPlayerDeathTrigger();}}, + {"scripts\\02_server\\Map\\njhub\\L_MON_CORE_NOOK_DOORS.lua", []() {return new MonCoreNookDoors();}}, + {"scripts\\02_server\\Map\\njhub\\L_MON_CORE_SMASHABLE_DOORS.lua", []() {return new MonCoreSmashableDoors();}}, + {"scripts\\02_server\\Map\\njhub\\L_MON_CORE_SMASHABLE_DOORS.lua", []() {return new MonCoreSmashableDoors();}}, + {"scripts\\02_server\\Map\\njhub\\L_FLAME_JET_SERVER.lua", []() {return new FlameJetServer();}}, + {"scripts\\02_server\\Map\\njhub\\L_BURNING_TILE.lua", []() {return new BurningTile();}}, + {"scripts\\02_server\\Map\\njhub\\L_SPAWN_EARTH_PET_SERVER.lua", []() {return new NjEarthDragonPetServer();}}, + {"scripts\\02_server\\Map\\njhub\\L_EARTH_PET_SERVER.lua", []() {return new NjEarthPetServer();}}, + {"scripts\\02_server\\Map\\njhub\\L_DRAGON_EMBLEM_CHEST_SERVER.lua", []() {return new NjDragonEmblemChestServer();}}, + {"scripts\\02_server\\Map\\njhub\\L_NYA_MISSION_ITEMS.lua", []() {return new NjNyaMissionitems();}}, + + //DLU + {"scripts\\02_server\\DLU\\DLUVanityTeleportingObject.lua", []() {return new DLUVanityTeleportingObject();}}, + + //Survival Minigame + {"scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_STROMBIE.lua", []() {return new AgSurvivalStromling();}}, + {"scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_DARKLING_MECH.lua", []() {return new AgSurvivalMech();}}, + {"scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_DARK_SPIDERLING.lua", []() {return new AgSurvivalSpiderling();}}, + + //Scripted Equipment + {"scripts\\EquipmentScripts\\Sunflower.lua", []() {return new Sunflower();}}, + {"scripts/EquipmentScripts/AnvilOfArmor.lua", []() {return new AnvilOfArmor();}}, + {"scripts/EquipmentScripts/FountainOfImagination.lua", []() {return new FountainOfImagination();}}, + {"scripts/EquipmentScripts/CauldronOfLife.lua", []() {return new CauldronOfLife();}}, + {"scripts\\02_server\\Equipment\\L_BOOTYDIG_SERVER.lua", []() {return new BootyDigServer();}}, + {"scripts\\EquipmentScripts\\PersonalFortress.lua", []() {return new PersonalFortress();}}, + {"scripts\\02_server\\Map\\General\\L_PROPERTY_DEVICE.lua", []() {return new PropertyDevice();}}, + {"scripts\\02_server\\Map\\General\\L_IMAG_BACKPACK_HEALS_SERVER.lua", []() {return new ImaginationBackpackHealServer();}}, + {"scripts\\ai\\GENERAL\\L_LEGO_DIE_ROLL.lua", []() {return new LegoDieRoll();}}, + {"scripts\\EquipmentScripts\\BuccaneerValiantShip.lua", []() {return new BuccaneerValiantShip();}}, + {"scripts\\EquipmentScripts\\FireFirstSkillonStartup.lua", []() {return new FireFirstSkillonStartup();}}, + {"scripts\\equipmenttriggers\\gempack.lua", []() {return new GemPack();}}, + {"scripts\\equipmenttriggers\\shardarmor.lua", []() {return new ShardArmor();}}, + {"scripts\\equipmenttriggers\\coilbackpack.lua", []() {return new TeslaPack();}}, + {"scripts\\EquipmentScripts\\stunImmunity.lua", []() {return new StunImmunity();}}, + + //FB + {"scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_BROKEN.lua", []() {return new RockHydrantBroken();}}, + {"scripts\\ai\\NS\\L_NS_WH_FANS.lua", []() {return new WhFans();}}, + + //WBL + {"scripts\\zone\\LUPs\\WBL_generic_zone.lua", []() {return new WblGenericZone();}}, + + //Alpha + {"scripts\\ai\\FV\\L_TRIGGER_GAS.lua", []() {return new TriggerGas();}}, + {"scripts\\ai\\FV\\L_ACT_NINJA_SENSEI.lua", []() {return new ActNinjaSensei();}}, + + //Pickups + {"scripts\\ai\\SPEC\\L_SPECIAL_1_BRONZE-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(1);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_1_GOLD-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(10000);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_1_SILVER-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(100);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_10_BRONZE-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(10);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_10_GOLD-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(100000);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_10_SILVER-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(1000);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_25_BRONZE-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(25);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_25_GOLD-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(250000);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_25_SILVER-COIN-SPAWNER.lua", []() {return new SpecialCoinSpawner(2500);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_IMAGINE-POWERUP-SPAWNER.lua", []() {return new SpecialPowerupSpawner(13);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_IMAGINE-POWERUP-SPAWNER-2PT.lua", []() {return new SpecialPowerupSpawner(129);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_LIFE-POWERUP-SPAWNER.lua", []() {return new SpecialPowerupSpawner(5);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_ARMOR-POWERUP-SPAWNER.lua", []() {return new SpecialPowerupSpawner(747);}}, + {"scripts\\ai\\SPEC\\L_SPECIAL_SPEED_BUFF_SPAWNER.lua", []() {return new SpecialSpeedBuffSpawner();}}, + + //Wild + {"scripts\\ai\\WILD\\L_WILD_GF_RAT.lua", []() {return new WildAndScared();}}, + {"scripts\\ai\\WILD\\L_WILD_GF_SNAIL.lua", []() {return new WildAndScared();}}, + {"scripts\\ai\\WILD\\L_WILD_GF_GLOWBUG.lua", []() {return new WildGfGlowbug();}}, + {"scripts\\ai\\WILD\\L_WILD_AMBIENT_CRAB.lua", []() {return new WildAmbientCrab();}}, + {"scripts\\ai\\WILD\\L_WILD_PANTS.lua", []() {return new WildPants();}}, + {"scripts\\ai\\WILD\\L_WILD_NINJA_BRICKS.lua", []() {return new WildNinjaBricks();}}, + {"scripts\\ai\\WILD\\L_WILD_NINJA_STUDENT.lua", []() {return new WildNinjaStudent();}}, + {"scripts\\ai\\WILD\\L_WILD_NINJA_SENSEI.lua", []() {return new WildNinjaSensei();}}, + {"scripts\\ai\\WILD\\L_LUP_generic_interact.lua", []() {return new LupGenericInteract();}}, + {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenBlue.lua", []() {return new WblRobotCitizen();}}, + {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenGreen.lua", []() {return new WblRobotCitizen();}}, + {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenOrange.lua", []() {return new WblRobotCitizen();}}, + {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenRed.lua", []() {return new WblRobotCitizen();}}, + {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenYellow.lua", []() {return new WblRobotCitizen();}}, + + }; }; -CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scriptName) { - if (m_Scripts.find(scriptName) != m_Scripts.end()) { - return m_Scripts[scriptName]; +CppScripts::Script* const CppScripts::GetScript(Entity* parent, const std::string& scriptName) { + auto itr = g_Scripts.find(scriptName); + if (itr != g_Scripts.end()) { + return itr->second; } - Script* script = invalidToReturn; - - //VE / AG: - if (scriptName == "scripts\\ai\\AG\\L_AG_SHIP_PLAYER_DEATH_TRIGGER.lua") - script = new AgShipPlayerDeathTrigger(); - else if (scriptName == "scripts\\ai\\NP\\L_NPC_NP_SPACEMAN_BOB.lua") - script = new NpcNpSpacemanBob(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_SPACE_STUFF.lua") // Broken, will (sometimes) display all animations at once on initial login - script = new AgSpaceStuff(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_SHIP_PLAYER_SHOCK_SERVER.lua") - script = new AgShipPlayerShockServer(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_IMAG_SMASHABLE.lua") - script = new AgImagSmashable(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_STORY_BOX_INTERACT_SERVER.lua") - script = new StoryBoxInteractServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_BINOCULARS.lua") - script = new Binoculars(); - else if (scriptName == "scripts\\ai\\WILD\\L_ALL_CRATE_CHICKEN.lua") - script = new AllCrateChicken(); - else if (scriptName == "scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_SMASHABLE.lua") - script = new RockHydrantSmashable(); // Broken? - else if (scriptName == "scripts\\02_server\\Map\\SS\\L_SS_MODULAR_BUILD_SERVER.lua") - script = new SsModularBuildServer(); - else if (scriptName == "scripts\\02_server\\Map\\Property\\AG_Small\\L_ZONE_AG_PROPERTY.lua") - script = new ZoneAgProperty(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_POI_MISSION.lua") - script = new InvalidScript(); // this is done in Entity.cpp, not needed for our implementation - else if (scriptName == "scripts\\02_server\\Map\\General\\L_TOUCH_MISSION_UPDATE_SERVER.lua") - script = new TouchMissionUpdateServer(); - else if (scriptName == "scripts\\ai\\AG\\L_ACT_SHARK_PLAYER_DEATH_TRIGGER.lua") - script = new ActSharkPlayerDeathTrigger(); - else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_MECH.lua") - script = new BaseEnemyMech(); - else if (scriptName == "scripts\\zone\\AG\\L_ZONE_AG_SURVIVAL.lua") - script = new ZoneAgSurvival(); - else if (scriptName == "scripts\\02_server\\Objects\\L_BUFF_STATION_SERVER.lua") - script = new AgSurvivalBuffStation(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_BUS_DOOR.lua") - script = new AgBusDoor(); - else if (scriptName == "scripts\\02_server\\Equipment\\L_MAESTROM_EXTRACTICATOR_SERVER.lua") - script = new MaestromExtracticatorServer(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_AG_CAGED_BRICKS_SERVER.lua") - script = new AgCagedBricksServer(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_WISP_SERVER.lua") - script = new NpcWispServer(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_EPSILON_SERVER.lua") - script = new NpcEpsilonServer(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_TURRET.lua" || scriptName == "scripts\\ai\\AG\\L_AG_TURRET_FOR_SHIP.lua") - script = new AgTurret(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_AG_LASER_SENSOR_SERVER.lua") - script = new AgLaserSensorServer(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_AG_MONUMENT_LASER_SERVER.lua") - script = new AgMonumentLaserServer(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_FANS.lua") - script = new AgFans(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_AG_MONUMENT_BIRDS.lua") - script = new AgMonumentBirds(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_REMOVE_RENTAL_GEAR.lua") - script = new RemoveRentalGear(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_NJ_ASSISTANT_SERVER.lua") - script = new NpcNjAssistantServer(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_SALUTING_NPCS.lua") - script = new AgSalutingNpcs(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_JET_EFFECT_SERVER.lua") - script = new AgJetEffectServer(); - else if (scriptName == "scripts\\02_server\\Enemy\\AG\\L_BOSS_SPIDER_QUEEN_ENEMY_SERVER.lua") - script = new BossSpiderQueenEnemyServer(); - else if (scriptName == "scripts\\02_server\\Map\\Property\\AG_Small\\L_ENEMY_SPIDER_SPAWNER.lua") - script = new EnemySpiderSpawner(); - else if (scriptName == "scripts/02_server/Map/Property/AG_Small/L_ENEMY_SPIDER_SPAWNER.lua") - script = new EnemySpiderSpawner(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_QB_Elevator.lua") - script = new AgQbElevator(); - else if (scriptName == "scripts\\ai\\PROPERTY\\AG\\L_AG_PROP_GUARD.lua") - script = new AgPropGuard(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_AG_BUGSPRAYER.lua") - script = new AgBugsprayer(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_AG_COURSE_STARTER.lua") - script = new NpcAgCourseStarter(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L__AG_MONUMENT_RACE_GOAL.lua") - script = new AgMonumentRaceGoal(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L__AG_MONUMENT_RACE_CANCEL.lua") - script = new AgMonumentRaceCancel(); - else if (scriptName == "scripts\\02_server\\Map\\AG_Spider_Queen\\L_ZONE_AG_SPIDER_QUEEN.lua") - script = new ZoneAgSpiderQueen(); - else if (scriptName == "scripts\\02_server\\Map\\AG_Spider_Queen\\L_SPIDER_BOSS_TREASURE_CHEST_SERVER.lua") - script = new SpiderBossTreasureChestServer(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_COWBOY_SERVER.lua") - script = new NpcCowboyServer(); - else if (scriptName == "scripts\\02_server\\Map\\Property\\AG_Med\\L_ZONE_AG_MED_PROPERTY.lua") - script = new ZoneAgMedProperty(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_STROMBIE_PROPERTY.lua") - script = new AgStromlingProperty(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_DARKLING_MECH.lua") - script = new BaseEnemyMech(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_DARK_SPIDERLING.lua") - script = new AgDarkSpiderling(); - else if (scriptName == "scripts\\ai\\PROPERTY\\L_PROP_GUARDS.lua") - script = new AgPropguards(); - else if (scriptName == "scripts\\ai\\PROPERTY\\L_PROPERTY_FX_DAMAGE.lua") - script = new PropertyFXDamage(); - else if (scriptName == "scripts\\02_server\\Map\\AG\\L_NPC_PIRATE_SERVER.lua") - script = new NpcPirateServer(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_PICNIC_BLANKET.lua") - script = new AgPicnicBlanket(); - else if (scriptName == "scripts\\02_server\\Map\\Property\\L_PROPERTY_BANK_INTERACT_SERVER.lua") - script = new PropertyBankInteract(); - else if (scriptName == "scripts\\02_server\\Enemy\\VE\\L_VE_MECH.lua") - script = new VeMech(); - else if (scriptName == "scripts\\02_server\\Map\\VE\\L_MISSION_CONSOLE_SERVER.lua") - script = new VeMissionConsole(); - else if (scriptName == "scripts\\02_server\\Map\\VE\\L_EPSILON_SERVER.lua") - script = new VeEpsilonServer(); - // Win32 thinks this if chain is too long, let's cut it up and serve it as a three course meal - //NS: - if (scriptName == "scripts\\ai\\NS\\L_NS_MODULAR_BUILD.lua") - script = new NsModularBuild(); - else if (scriptName == "scripts\\ai\\NS\\L_NS_GET_FACTION_MISSION_SERVER.lua") - script = new NsGetFactionMissionServer(); - else if (scriptName == "scripts\\ai\\NS\\L_NS_QB_IMAGINATION_STATUE.lua") - script = new NsQbImaginationStatue(); - else if (scriptName == "scripts\\02_server\\Map\\NS\\CONCERT_CHOICEBUILD_MANAGER_SERVER.lua") - script = new NsConcertChoiceBuildManager(); - else if (scriptName == "scripts\\ai\\NS\\L_NS_CONCERT_CHOICEBUILD.lua") - script = new NsConcertChoiceBuild(); - else if (scriptName == "scripts\\ai\\NS\\L_NS_CONCERT_QUICKBUILD.lua") - script = new NsConcertQuickBuild(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_STAGE_PLATFORMS.lua") - script = new AgStagePlatforms(); - else if (scriptName == "scripts\\ai\\NS\\L_NS_CONCERT_INSTRUMENT_QB.lua") - script = new NsConcertInstrument(); - else if (scriptName == "scripts\\ai\\NS\\L_NS_JONNY_FLAG_MISSION_SERVER.lua") - script = new NsJohnnyMissionServer(); - else if (scriptName == "scripts\\02_server\\Objects\\L_STINKY_FISH_TARGET.lua") - script = new StinkyFishTarget(); - else if (scriptName == "scripts\\zone\\PROPERTY\\NS\\L_ZONE_NS_PROPERTY.lua") - script = new ZoneNsProperty(); - else if (scriptName == "scripts\\02_server\\Map\\Property\\NS_Med\\L_ZONE_NS_MED_PROPERTY.lua") - script = new ZoneNsMedProperty(); - else if (scriptName == "scripts\\02_server\\Map\\NS\\L_NS_TOKEN_CONSOLE_SERVER.lua") - script = new NsTokenConsoleServer(); - else if (scriptName == "scripts\\02_server\\Map\\NS\\L_NS_LUP_TELEPORT.lua") - script = new NsLupTeleport(); - else if (scriptName == "scripts\\02_server\\Map\\NS\\Waves\\L_ZONE_NS_WAVES.lua") - script = new ZoneNsWaves(); - else if (scriptName == "scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_HAMMERLING_ENEMY_SERVER.lua") - script = new WaveBossHammerling(); - else if (scriptName == "scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_APE_ENEMY_SERVER.lua") - script = new WaveBossApe(); - else if (scriptName == "scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_DARK_SPIDERLING_ENEMY_SERVER.lua") - script = new WaveBossSpiderling(); - else if (scriptName == "scripts\\02_server\\Enemy\\Waves\\L_WAVES_BOSS_HORESEMEN_ENEMY_SERVER.lua") - script = new WaveBossHorsemen(); - else if (scriptName == "scripts\\02_server\\Minigame\\General\\L_MINIGAME_TREASURE_CHEST_SERVER.lua") - script = new MinigameTreasureChestServer(); - else if (scriptName == "scripts\\02_server\\Map\\NS\\L_NS_LEGO_CLUB_DOOR.lua") - script = new NsLegoClubDoor(); - else if (scriptName == "scripts/ai/NS/L_CL_RING.lua") - script = new ClRing(); - else if (scriptName == "scripts\\ai\\WILD\\L_WILD_AMBIENTS.lua") - script = new WildAmbients(); - else if (scriptName == "scripts\\ai\\NS\\NS_PP_01\\L_NS_PP_01_TELEPORT.lua") - script = new PropertyDeathPlane(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_QB_SPAWNER.lua") - script = new QbSpawner(); - else if (scriptName == "scripts\\ai\\AG\\L_AG_QB_Wall.lua") - script = new AgQbWall(); - - //GF: - else if (scriptName == "scripts\\02_server\\Map\\GF\\L_GF_TORCH.lua") - script = new GfTikiTorch(); - else if (scriptName == "scripts\\ai\\GF\\L_SPECIAL_FIREPIT.lua") - script = new GfCampfire(); - else if (scriptName == "scripts\\ai\\GF\\L_GF_ORGAN.lua") - script = new GfOrgan(); - else if (scriptName == "scripts\\ai\\GF\\L_GF_BANANA.lua") - script = new GfBanana(); - else if (scriptName == "scripts\\ai\\GF\\L_GF_BANANA_CLUSTER.lua") - script = new GfBananaCluster(); - else if (scriptName == "scripts/ai/GF/L_GF_JAILKEEP_MISSION.lua") - script = new GfJailkeepMission(); - else if (scriptName == "scripts\\ai\\GF\\L_TRIGGER_AMBUSH.lua") - script = new TriggerAmbush(); - else if (scriptName == "scripts\\02_server\\Map\\GF\\L_GF_CAPTAINS_CANNON.lua") - script = new GfCaptainsCannon(); - else if (scriptName == "scripts\\02_server\\Map\\GF\\L_MAST_TELEPORT.lua") - script = new MastTeleport(); - else if (scriptName == "scripts\\ai\\GF\\L_GF_JAIL_WALLS.lua") - script = new GfJailWalls(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_QB_ENEMY_STUNNER.lua") - script = new QbEnemyStunner(); - else if (scriptName == "scripts\\ai\\GF\\L_GF_PET_DIG_BUILD.lua") - script = new PetDigBuild(); // Technically also used once in AG - else if (scriptName == "scripts\\02_server\\Map\\GF\\L_SPAWN_LION_SERVER.lua") - script = new SpawnLionServer(); - else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_APE.lua") - script = new BaseEnemyApe(); - else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_GF_APE_SMASHING_QB.lua") - script = new GfApeSmashingQB(); - else if (scriptName == "scripts\\zone\\PROPERTY\\GF\\L_ZONE_GF_PROPERTY.lua") - script = new ZoneGfProperty(); - else if (scriptName == "scripts\\ai\\GF\\L_GF_ARCHWAY.lua") - script = new GfArchway(); - else if (scriptName == "scripts\\ai\\GF\\L_GF_MAELSTROM_GEYSER.lua") - script = new GfMaelstromGeyser(); - else if (scriptName == "scripts\\ai\\GF\\L_PIRATE_REP.lua") - script = new PirateRep(); - else if (scriptName == "scripts\\ai\\GF\\L_GF_PARROT_CRASH.lua") - script = new GfParrotCrash(); - - // SG - else if (scriptName == "scripts\\ai\\MINIGAME\\SG_GF\\SERVER\\SG_CANNON.lua") - script = new SGCannon(); - else if (scriptName == "scripts\\ai\\MINIGAME\\SG_GF\\L_ZONE_SG_SERVER.lua") - script = new ZoneSGServer(); - - //PR: - else if (scriptName == "scripts\\client\\ai\\PR\\L_PR_WHISTLE.lua") - script = new PrWhistle(); - else if (scriptName == "scripts\\02_server\\Map\\PR\\L_PR_SEAGULL_FLY.lua") - script = new PrSeagullFly(); - else if (scriptName == "scripts\\ai\\PETS\\L_HYDRANT_SMASHABLE.lua") - script = new HydrantSmashable(); - else if (scriptName == "scripts\\02_server\\map\\PR\\L_HYDRANT_BROKEN.lua") - script = new HydrantBroken(); - else if (scriptName == "scripts\\02_server\\Map\\General\\PET_DIG_SERVER.lua" || scriptName == "scripts\\02_server\\Map\\AM\\L_SKELETON_DRAGON_PET_DIG_SERVER.lua") - script = new PetDigServer(); - else if (scriptName == "scripts\\client\\ai\\PR\\L_CRAB_SERVER.lua") - script = new CrabServer(); - else if (scriptName == "scripts\\02_server\\Pets\\L_PET_FROM_DIG_SERVER.lua") - script = new PetFromDigServer(); - else if (scriptName == "scripts\\02_server\\Pets\\L_PET_FROM_OBJECT_SERVER.lua") - script = new PetFromObjectServer(); - else if (scriptName == "scripts\\02_server\\Pets\\L_DAMAGING_PET.lua") - script = new DamagingPets(); - else if (scriptName == "scripts\\02_server\\Map\\PR\\L_SPAWN_GRYPHON_SERVER.lua") - script = new SpawnGryphonServer(); - - //FV Scripts: - else if (scriptName == "scripts\\02_server\\Map\\FV\\L_ACT_CANDLE.lua") - script = new FvCandle(); - else if (scriptName == "scripts\\02_server\\Map\\FV\\L_ENEMY_RONIN_SPAWNER.lua") - script = new EnemyRoninSpawner(); - else if (scriptName == "scripts\\02_server\\Enemy\\FV\\L_FV_MAELSTROM_CAVALRY.lua") - script = new FvMaelstromCavalry(); - else if (scriptName == "scripts\\ai\\FV\\L_ACT_NINJA_TURRET_1.lua") - script = new ActNinjaTurret(); - else if (scriptName == "scripts\\02_server\\Map\\FV\\L_FV_HORSEMEN_TRIGGER.lua") - script = new FvHorsemenTrigger(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_FLYING_CREVICE_DRAGON.lua") - script = new FvFlyingCreviceDragon(); - else if (scriptName == "scripts\\02_server\\Enemy\\FV\\L_FV_MAELSTROM_DRAGON.lua") - script = new FvMaelstromDragon(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_DRAGON_SMASHING_GOLEM_QB.lua") - script = new FvDragonSmashingGolemQb(); - else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_TREASURE_CHEST_DRAGON_SERVER.lua") - script = new TreasureChestDragonServer(); - else if (scriptName == "scripts\\ai\\GENERAL\\L_INSTANCE_EXIT_TRANSFER_PLAYER_TO_LAST_NON_INSTANCE.lua") - script = new InstanceExitTransferPlayerToLastNonInstance(); - else if (scriptName == "scripts\\ai\\FV\\L_NPC_FREE_GF_NINJAS.lua") - script = new FvFreeGfNinjas(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_PANDA_SPAWNER_SERVER.lua") - script = new FvPandaSpawnerServer(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_PANDA_SERVER.lua") - script = new FvPandaServer(); - else if (scriptName == "scripts\\zone\\PROPERTY\\FV\\L_ZONE_FV_PROPERTY.lua") - script = new ZoneFvProperty(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_BRICK_PUZZLE_SERVER.lua") - script = new FvBrickPuzzleServer(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_CONSOLE_LEFT_QUICKBUILD.lua") - script = new FvConsoleLeftQuickbuild(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_CONSOLE_RIGHT_QUICKBUILD.lua") - script = new FvConsoleRightQuickbuild(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_FACILITY_BRICK.lua") - script = new FvFacilityBrick(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_FACILITY_PIPES.lua") - script = new FvFacilityPipes(); - else if (scriptName == "scripts\\02_server\\Map\\FV\\L_IMG_BRICK_CONSOLE_QB.lua") - script = new ImgBrickConsoleQB(); - else if (scriptName == "scripts\\ai\\FV\\L_ACT_PARADOX_PIPE_FIX.lua") - script = new ActParadoxPipeFix(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_NINJA_GUARDS.lua") - script = new FvNinjaGuard(); - else if (scriptName == "scripts\\ai\\FV\\L_ACT_PASS_THROUGH_WALL.lua") - script = new FvPassThroughWall(); - else if (scriptName == "scripts\\ai\\FV\\L_ACT_BOUNCE_OVER_WALL.lua") - script = new FvBounceOverWall(); - else if (scriptName == "scripts\\02_server\\Map\\FV\\L_NPC_FONG.lua") - script = new FvFong(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_MAELSTROM_GEYSER.lua") { - script = new FvMaelstromGeyser(); - } + const auto itrTernary = scriptLoader.find(scriptName); + Script* script = itrTernary != scriptLoader.cend() ? itrTernary->second() : &InvalidToReturn; - //Misc: - if (scriptName == "scripts\\02_server\\Map\\General\\L_EXPLODING_ASSET.lua") - script = new ExplodingAsset(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_WISHING_WELL_SERVER.lua") - script = new WishingWellServer(); - else if (scriptName == "scripts\\ai\\ACT\\L_ACT_PLAYER_DEATH_TRIGGER.lua") - script = new ActPlayerDeathTrigger(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_GROWING_FLOWER_SERVER.lua") - script = new GrowingFlower(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_TOKEN_CONSOLE_SERVER.lua") - script = new TokenConsoleServer(); - else if (scriptName == "scripts\\ai\\ACT\\FootRace\\L_ACT_BASE_FOOT_RACE.lua") - script = new BaseFootRaceManager(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_PROP_PLATFORM.lua") - script = new PropertyPlatform(); - else if (scriptName == "scripts\\02_server\\Map\\VE\\L_VE_BRICKSAMPLE_SERVER.lua") - script = new VeBricksampleServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_MAIL_BOX_SERVER.lua") - script = new MailBoxServer(); - else if (scriptName == "scripts\\ai\\ACT\\L_ACT_MINE.lua") - script = new ActMine(); - - //Racing: - else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\RACE_IMAGINE_CRATE_SERVER.lua") - script = new RaceImagineCrateServer(); - else if (scriptName == "scripts\\ai\\ACT\\L_ACT_VEHICLE_DEATH_TRIGGER.lua") - script = new ActVehicleDeathTrigger(); - else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\RACE_IMAGINE_POWERUP.lua") - script = new RaceImaginePowerup(); - else if (scriptName == "scripts\\02_server\\Map\\FV\\Racing\\RACE_MAELSTROM_GEISER.lua") - script = new RaceMaelstromGeiser(); - else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\FV_RACE_SMASH_EGG_IMAGINE_SERVER.lua") - script = new FvRaceSmashEggImagineServer(); - else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\RACE_SMASH_SERVER.lua") - script = new RaceSmashServer(); - - //NT: - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_SENTINELWALKWAY_SERVER.lua") - script = new NtSentinelWalkwayServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_PARADOXTELE_SERVER.lua") - script = new NtParadoxTeleServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_DARKITECT_REVEAL_SERVER.lua") - script = new NtDarkitectRevealServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_BANK_INTERACT_SERVER.lua") - script = new BankInteractServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_VENTURESPEEDPAD_SERVER.lua") - script = new NtVentureSpeedPadServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_VENTURE_CANNON_SERVER.lua") - script = new NtVentureCannonServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_COMBAT_CHALLENGE_SERVER.lua") - script = new NtCombatChallengeServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_COMBAT_CHALLENGE_DUMMY.lua") - script = new NtCombatChallengeDummy(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\\\L_NT_COMBAT_EXPLODING_TARGET.lua") - script = new NtCombatChallengeExplodingDummy(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_BASE_INTERACT_DROP_LOOT_SERVER.lua") - script = new BaseInteractDropLootServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_ASSEMBLYTUBE_SERVER.lua") - script = new NtAssemblyTubeServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_PARADOX_PANEL_SERVER.lua") - script = new NtParadoxPanelServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_IMAG_BEAM_BUFFER.lua") - script = new NtImagBeamBuffer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_BEAM_IMAGINATION_COLLECTORS.lua") - script = new NtBeamImaginationCollectors(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_DIRT_CLOUD_SERVER.lua") - script = new NtDirtCloudServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_CONSOLE_TELEPORT_SERVER.lua") - script = new NtConsoleTeleportServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_SPAWN_STEGO_SERVER.lua") - script = new SpawnStegoServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_SPAWN_SABERCAT_SERVER.lua") - script = new SpawnSaberCatServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_SPAWN_SHRAKE_SERVER.lua") - script = new SpawnShrakeServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_DUKE_SERVER.lua") - script = new NtDukeServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_HAEL_SERVER.lua") - script = new NtHaelServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_FACTION_SPY_SERVER.lua") - script = new NtFactionSpyServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_OVERBUILD_SERVER.lua") - script = new NtOverbuildServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_VANDA_SERVER.lua") - script = new NtVandaServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_FORCE_VOLUME_SERVER.lua") - script = new ForceVolumeServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_FRICTION_VOLUME_SERVER.lua") - script = new FrictionVolumeServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_XRAY_SERVER.lua") - script = new NtXRayServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_SLEEPING_GUARD.lua") - script = new NtSleepingGuard(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_IMAGIMETER_VISIBILITY_SERVER.lua") - script = new NTImagimeterVisibility(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_PIPE_VISIBILITY_SERVER.lua") - script = new NTPipeVisibilityServer(); - else if (scriptName == "scripts\\ai\\MINIGAME\\Objects\\MINIGAME_BLUE_MARK.lua") - script = new MinigameBlueMark(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_NAOMI_BREADCRUMB_SERVER.lua") - script = new NtNaomiBreadcrumbServer(); - else if (scriptName == "scripts\\02_server\\Map\\NT\\L_NT_NAOMI_DIRT_SERVER.lua") - script = new NTNaomiDirtServer(); - - //AM: - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_AM_CONSOLE_TELEPORT_SERVER.lua") - script = new AmConsoleTeleportServer(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_RANDOM_SPAWNER_FIN.lua") - script = new RandomSpawnerFin(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_RANDOM_SPAWNER_PIT.lua") - script = new RandomSpawnerPit(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_RANDOM_SPAWNER_STR.lua") - script = new RandomSpawnerStr(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_RANDOM_SPAWNER_ZIP.lua") - script = new RandomSpawnerZip(); - else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_MECH.lua") - script = new AmDarklingMech(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_BRIDGE.lua") - script = new AmBridge(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_DRAW_BRIDGE.lua") - script = new AmDrawBridge(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_SHIELD_GENERATOR.lua") - script = new AmShieldGenerator(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_SHIELD_GENERATOR_QUICKBUILD.lua") - script = new AmShieldGeneratorQuickbuild(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_DROPSHIP_COMPUTER.lua") - script = new AmDropshipComputer(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_SCROLL_READER_SERVER.lua") - script = new AmScrollReaderServer(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_TEMPLE_SKILL_VOLUME.lua") - script = new AmTemplateSkillVolume(); - else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_ENEMY_NJ_BUFF.lua") - script = new EnemyNjBuff(); - else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_SKELETON_ENGINEER.lua") - script = new AmSkeletonEngineer(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_SKULLKIN_DRILL.lua") - script = new AmSkullkinDrill(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_SKULLKIN_DRILL_STAND.lua") - script = new AmSkullkinDrillStand(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_SKULLKIN_TOWER.lua") - script = new AmSkullkinTower(); - else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_NAMED_DARKLING_DRAGON.lua") - script = new AmDarklingDragon(); - else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_DRAGON.lua") - script = new AmDarklingDragon(); - else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_APE.lua") - script = new BaseEnemyApe(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_BLUE_X.lua") - script = new AmBlueX(); - else if (scriptName == "scripts\\02_server\\Map\\AM\\L_TEAPOT_SERVER.lua") - script = new AmTeapotServer(); - - // Ninjago - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_GARMADON_CELEBRATION_SERVER.lua") - script = new NjGarmadonCelebration(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_WU_NPC.lua") - script = new NjWuNPC(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_SCROLL_CHEST_SERVER.lua") - script = new NjScrollChestServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_COLE_NPC.lua") - script = new NjColeNPC(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_JAY_MISSION_ITEMS.lua") - script = new NjJayMissionItems(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_NPC_MISSION_SPINJITZU_SERVER.lua") - script = new NjNPCMissionSpinjitzuServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_ENEMY_SKELETON_SPAWNER.lua") - script = new EnemySkeletonSpawner(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_NJ_RAIL_SWITCH.lua") - script = new NjRailSwitch(); - else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_ACTIVATORS_SERVER.lua") - script = new NjRailActivatorsServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_POST_SERVER.lua") - script = new NjRailPostServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_ICE_RAIL_ACTIVATOR_SERVER.lua") - script = new NjIceRailActivator(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_FALLING_TILE.lua") - script = new FallingTile(); - else if (scriptName == "scripts\\02_server\\Enemy\\General\\L_ENEMY_NJ_BUFF_STUN_IMMUNITY.lua") - script = new EnemyNjBuff(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_IMAGINATION_SHRINE_SERVER.lua") - script = new ImaginationShrineServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_LIEUTENANT.lua") - script = new Lieutenant(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_RAIN_OF_ARROWS.lua") - script = new RainOfArrows(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_CAVE_PRISON_CAGE.lua") - script = new CavePrisonCage(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\boss_instance\\L_MONASTERY_BOSS_INSTANCE_SERVER.lua") - script = new NjMonastryBossInstance(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_CATAPULT_BOUNCER_SERVER.lua") - script = new CatapultBouncerServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_CATAPULT_BASE_SERVER.lua") - script = new CatapultBaseServer(); - else if (scriptName == "scripts\\02_server\\Map\\General\\Ninjago\\L_NJHUB_LAVA_PLAYER_DEATH_TRIGGER.lua") - script = new NjhubLavaPlayerDeathTrigger(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_MON_CORE_NOOK_DOORS.lua") - script = new MonCoreNookDoors(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_MON_CORE_SMASHABLE_DOORS.lua") - script = new MonCoreSmashableDoors(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_FLAME_JET_SERVER.lua") - script = new FlameJetServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_BURNING_TILE.lua") - script = new BurningTile(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_SPAWN_EARTH_PET_SERVER.lua") - script = new NjEarthDragonPetServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_EARTH_PET_SERVER.lua") - script = new NjEarthPetServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_DRAGON_EMBLEM_CHEST_SERVER.lua") - script = new NjDragonEmblemChestServer(); - else if (scriptName == "scripts\\02_server\\Map\\njhub\\L_NYA_MISSION_ITEMS.lua") - script = new NjNyaMissionitems(); - - //DLU: - else if (scriptName == "scripts\\02_server\\DLU\\DLUVanityTeleportingObject.lua") - script = new DLUVanityTeleportingObject(); - - // Survival minigame - else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_STROMBIE.lua") - script = new AgSurvivalStromling(); - else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_DARKLING_MECH.lua") - script = new AgSurvivalMech(); - else if (scriptName == "scripts\\02_server\\Enemy\\Survival\\L_AG_SURVIVAL_DARK_SPIDERLING.lua") - script = new AgSurvivalSpiderling(); - - // Scripted equipment - else if (scriptName == "scripts\\EquipmentScripts\\Sunflower.lua") - script = new Sunflower(); - else if (scriptName == "scripts/EquipmentScripts/AnvilOfArmor.lua") - script = new AnvilOfArmor(); - else if (scriptName == "scripts/EquipmentScripts/FountainOfImagination.lua") - script = new FountainOfImagination(); - else if (scriptName == "scripts/EquipmentScripts/CauldronOfLife.lua") - script = new CauldronOfLife(); - else if (scriptName == "scripts\\02_server\\Equipment\\L_BOOTYDIG_SERVER.lua") - script = new BootyDigServer(); - else if (scriptName == "scripts\\EquipmentScripts\\PersonalFortress.lua") - script = new PersonalFortress(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_PROPERTY_DEVICE.lua") - script = new PropertyDevice(); - else if (scriptName == "scripts\\02_server\\Map\\General\\L_IMAG_BACKPACK_HEALS_SERVER.lua") - script = new ImaginationBackpackHealServer(); - else if (scriptName == "scripts\\ai\\GENERAL\\L_LEGO_DIE_ROLL.lua") - script = new LegoDieRoll(); - else if (scriptName == "scripts\\EquipmentScripts\\BuccaneerValiantShip.lua") - script = new BuccaneerValiantShip(); - else if (scriptName == "scripts\\EquipmentScripts\\FireFirstSkillonStartup.lua") - script = new FireFirstSkillonStartup(); - else if (scriptName == "scripts\\equipmenttriggers\\gempack.lua") - script = new GemPack(); - else if (scriptName == "scripts\\equipmenttriggers\\shardarmor.lua") - script = new ShardArmor(); - else if (scriptName == "scripts\\equipmenttriggers\\coilbackpack.lua") - script = new TeslaPack(); - else if (scriptName == "scripts\\EquipmentScripts\\stunImmunity.lua") - script = new StunImmunity(); - - // FB - else if (scriptName == "scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_BROKEN.lua") - script = new RockHydrantBroken(); - else if (scriptName == "scripts\\ai\\NS\\L_NS_WH_FANS.lua") - script = new WhFans(); - - // WBL - else if (scriptName == "scripts\\zone\\LUPs\\WBL_generic_zone.lua") - script = new WblGenericZone(); - - // Alpha - if (scriptName == "scripts\\ai\\FV\\L_TRIGGER_GAS.lua") - script = new TriggerGas(); - else if (scriptName == "scripts\\ai\\FV\\L_ACT_NINJA_SENSEI.lua") - script = new ActNinjaSensei(); - - // pickups - if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_1_BRONZE-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(1); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_1_GOLD-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(10000); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_1_SILVER-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(100); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_10_BRONZE-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(10); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_10_GOLD-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(100000); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_10_SILVER-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(1000); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_25_BRONZE-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(25); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_25_GOLD-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(250000); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_25_SILVER-COIN-SPAWNER.lua") - script = new SpecialCoinSpawner(2500); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_IMAGINE-POWERUP-SPAWNER.lua") - script = new SpecialPowerupSpawner(13); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_IMAGINE-POWERUP-SPAWNER-2PT.lua") - script = new SpecialPowerupSpawner(129); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_LIFE-POWERUP-SPAWNER.lua") - script = new SpecialPowerupSpawner(5); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_ARMOR-POWERUP-SPAWNER.lua") - script = new SpecialPowerupSpawner(747); - else if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_SPEED_BUFF_SPAWNER.lua") - script = new SpecialSpeedBuffSpawner(); - - // Wild - if (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_RAT.lua" || scriptName == "scripts\\ai\\WILD\\L_WILD_GF_SNAIL.lua") - script = new WildAndScared(); - else if (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_GLOWBUG.lua") - script = new WildGfGlowbug(); - else if (scriptName == "scripts\\ai\\WILD\\L_WILD_AMBIENT_CRAB.lua") - script = new WildAmbientCrab(); - else if (scriptName == "scripts\\ai\\WILD\\L_WILD_PANTS.lua") - script = new WildPants(); - else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_BRICKS.lua") - script = new WildNinjaBricks(); - else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_STUDENT.lua") - script = new WildNinjaStudent(); - else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_SENSEI.lua") - script = new WildNinjaSensei(); - - // handle invalid script reporting if the path is greater than zero and it's not an ignored script - // information not really needed for sys admins but is for developers - else if (script == invalidToReturn) { + if (script == &InvalidToReturn) { if ((scriptName.length() > 0) && !((scriptName == "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua") || (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua") || - (scriptName =="scripts\\ai\\FV\\L_ACT_NINJA_STUDENT.lua") || + (scriptName == "scripts\\ai\\FV\\L_ACT_NINJA_STUDENT.lua") || (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_FROG.lua") || - (scriptName == "scripts\\empty.lua") + (scriptName == "scripts\\empty.lua") || + (scriptName == "scripts\\ai\\AG\\L_AG_SENTINEL_GUARD.lua") )) LOG_DEBUG("LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str()); } - m_Scripts[scriptName] = script; + g_Scripts[scriptName] = script; return script; } -std::vector<CppScripts::Script*> CppScripts::GetEntityScripts(Entity* entity) { - std::vector<CppScripts::Script*> scripts; - std::vector<ScriptComponent*> comps = entity->GetScriptComponents(); - for (ScriptComponent* scriptComp : comps) { - if (scriptComp != nullptr) { - scripts.push_back(scriptComp->GetScript()); - } - } - return scripts; +CppScripts::Script* const CppScripts::GetInvalidScript() { + return &InvalidToReturn; } diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index d005a14a6..8d3b3b5d8 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -357,6 +357,10 @@ namespace CppScripts { virtual void OnRequestActivityExit(Entity* sender, LWOOBJID player, bool canceled){}; }; - Script* GetScript(Entity* parent, const std::string& scriptName); - std::vector<Script*> GetEntityScripts(Entity* entity); + Script* const GetScript(Entity* parent, const std::string& scriptName); + + // Get the invalid script. Would be a static variable of the namespace, but that would be + // more cluttery to use. Also this allows us to control where this invalid script is defined and initialized + // since we dont want anyone externally modifying it. + Script* const GetInvalidScript(); }; diff --git a/dScripts/EquipmentScripts/CMakeLists.txt b/dScripts/EquipmentScripts/CMakeLists.txt index 08966e08f..60f315035 100644 --- a/dScripts/EquipmentScripts/CMakeLists.txt +++ b/dScripts/EquipmentScripts/CMakeLists.txt @@ -8,6 +8,6 @@ set(DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS "FireFirstSkillonStartup.cpp" "StunImmunity.cpp") -add_library(dScriptsEquipmentScripts STATIC ${DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS}) +add_library(dScriptsEquipmentScripts OBJECT ${DSCRIPTS_SOURCES_EQUIPMENTSCRIPTS}) target_include_directories(dScriptsEquipmentScripts PUBLIC ".") target_precompile_headers(dScriptsEquipmentScripts REUSE_FROM dScriptsBase) diff --git a/dScripts/EquipmentTriggers/CMakeLists.txt b/dScripts/EquipmentTriggers/CMakeLists.txt index cb6e81a86..af0a1425a 100644 --- a/dScripts/EquipmentTriggers/CMakeLists.txt +++ b/dScripts/EquipmentTriggers/CMakeLists.txt @@ -1,6 +1,6 @@ set(DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS "CoilBackpackBase.cpp") -add_library(dScriptsEquipmentTriggers STATIC ${DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS}) +add_library(dScriptsEquipmentTriggers OBJECT ${DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS}) target_include_directories(dScriptsEquipmentTriggers PUBLIC ".") target_precompile_headers(dScriptsEquipmentTriggers REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/ACT/CMakeLists.txt b/dScripts/ai/ACT/CMakeLists.txt index 5071afa0e..680c5e4cd 100644 --- a/dScripts/ai/ACT/CMakeLists.txt +++ b/dScripts/ai/ACT/CMakeLists.txt @@ -9,6 +9,6 @@ foreach(file ${DSCRIPTS_SOURCES_AI_ACT_FOOTRACE}) set(DSCRIPTS_SOURCES_AI_ACT ${DSCRIPTS_SOURCES_AI_ACT} "FootRace/${file}") endforeach() -add_library(dScriptsAiAct STATIC ${DSCRIPTS_SOURCES_AI_ACT}) +add_library(dScriptsAiAct OBJECT ${DSCRIPTS_SOURCES_AI_ACT}) target_include_directories(dScriptsAiAct PUBLIC "." "FootRace") target_precompile_headers(dScriptsAiAct REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/AG/AgBusDoor.cpp b/dScripts/ai/AG/AgBusDoor.cpp index fd6c272ed..a4106aaf5 100644 --- a/dScripts/ai/AG/AgBusDoor.cpp +++ b/dScripts/ai/AG/AgBusDoor.cpp @@ -23,13 +23,13 @@ void AgBusDoor::OnProximityUpdate(Entity* self, Entity* entering, std::string na m_Counter = 0; m_OuterCounter = 0; - for (const auto& pair : proximityMonitorComponent->GetProximityObjects("busDoor")) { - auto* entity = Game::entityManager->GetEntity(pair.first); + for (const auto id : proximityMonitorComponent->GetProximityObjects("busDoor")) { + const auto* const entity = Game::entityManager->GetEntity(id); if (entity != nullptr && entity->IsPlayer()) m_Counter++; } - for (const auto& pair : proximityMonitorComponent->GetProximityObjects("busDoorOuter")) { - auto* entity = Game::entityManager->GetEntity(pair.first); + for (const auto id : proximityMonitorComponent->GetProximityObjects("busDoorOuter")) { + const auto* const entity = Game::entityManager->GetEntity(id); if (entity != nullptr && entity->IsPlayer()) m_OuterCounter++; } diff --git a/dScripts/ai/AG/AgShipShake.cpp b/dScripts/ai/AG/AgShipShake.cpp new file mode 100644 index 000000000..7dd2323a7 --- /dev/null +++ b/dScripts/ai/AG/AgShipShake.cpp @@ -0,0 +1,81 @@ +#include "AgShipShake.h" +#include "EntityInfo.h" +#include "GeneralUtils.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "RenderComponent.h" +#include "Entity.h" + +void AgShipShake::OnStartup(Entity* self) { + EntityInfo info{}; + + info.pos = { -418, 585, -30 }; + info.lot = 33; + info.spawnerID = self->GetObjectID(); + + auto* ref = Game::entityManager->CreateEntity(info); + + Game::entityManager->ConstructEntity(ref); + + self->SetVar(u"ShakeObject", ref->GetObjectID()); + + self->AddTimer("ShipShakeIdle", 2.0f); + self->SetVar(u"RandomTime", 10); +} + +void AgShipShake::OnTimerDone(Entity* self, std::string timerName) { + auto* shipFxObject = GetEntityInGroup(ShipFX); + auto* shipFxObject2 = GetEntityInGroup(ShipFX2); + auto* debrisObject = GetEntityInGroup(DebrisFX); + if (timerName == "ShipShakeIdle") { + auto* ref = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"ShakeObject")); + + const auto randomTime = self->GetVar<int>(u"RandomTime"); + auto time = GeneralUtils::GenerateRandomNumber<int>(0, randomTime + 1); + + if (time < randomTime / 2) { + time += randomTime / 2; + } + + self->AddTimer("ShipShakeIdle", static_cast<float>(time)); + + if (ref) + GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(ref, FXName, ref->GetObjectID(), 500.0f); + + + if (debrisObject) + GameMessages::SendPlayFXEffect(debrisObject, -1, u"DebrisFall", "Debris", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + + const auto randomFx = GeneralUtils::GenerateRandomNumber<int>(0, 3); + + if (shipFxObject) { + std::string effectType = "shipboom" + std::to_string(randomFx); + GameMessages::SendPlayFXEffect(shipFxObject, 559, GeneralUtils::ASCIIToUTF16(effectType), "FX", LWOOBJID_EMPTY, 1.0f, 1.0f, true); + } + + self->AddTimer("ShipShakeExplode", 5.0f); + + if (shipFxObject2) + RenderComponent::PlayAnimation(shipFxObject2, u"explosion"); + } else if (timerName == "ShipShakeExplode") { + if (shipFxObject) + RenderComponent::PlayAnimation(shipFxObject, u"idle"); + if (shipFxObject2) + RenderComponent::PlayAnimation(shipFxObject2, u"idle"); + } +} + +Entity* AgShipShake::GetEntityInGroup(const std::string& group) { + auto entities = Game::entityManager->GetEntitiesInGroup(group); + Entity* en = nullptr; + + for (auto entity : entities) { + if (entity) { + en = entity; + break; + } + } + + return en; +} + diff --git a/dScripts/ai/AG/AgShipShake.h b/dScripts/ai/AG/AgShipShake.h new file mode 100644 index 000000000..4cc26f960 --- /dev/null +++ b/dScripts/ai/AG/AgShipShake.h @@ -0,0 +1,16 @@ +#pragma once +#include "CppScripts.h" + +class AgShipShake : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + + std::string DebrisFX = "DebrisFX"; + std::string ShipFX = "ShipFX"; + std::string ShipFX2 = "ShipFX2"; + std::u16string FXName = u"camshake-bridge"; + +private: + Entity* GetEntityInGroup(const std::string& group); +}; diff --git a/dScripts/ai/AG/AgSpaceStuff.cpp b/dScripts/ai/AG/AgSpaceStuff.cpp index 130d43540..dedbd08cd 100644 --- a/dScripts/ai/AG/AgSpaceStuff.cpp +++ b/dScripts/ai/AG/AgSpaceStuff.cpp @@ -8,21 +8,6 @@ void AgSpaceStuff::OnStartup(Entity* self) { self->AddTimer("FloaterScale", 5.0f); - - EntityInfo info{}; - - info.pos = { -418, 585, -30 }; - info.lot = 33; - info.spawnerID = self->GetObjectID(); - - auto* ref = Game::entityManager->CreateEntity(info); - - Game::entityManager->ConstructEntity(ref); - - self->SetVar(u"ShakeObject", ref->GetObjectID()); - - self->AddTimer("ShipShakeIdle", 2.0f); - self->SetVar(u"RandomTime", 10); } void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) { @@ -37,70 +22,5 @@ void AgSpaceStuff::OnTimerDone(Entity* self, std::string timerName) { RenderComponent::PlayAnimation(self, u"path_0" + (GeneralUtils::to_u16string(pathType))); self->AddTimer("FloaterScale", randTime); - } else if (timerName == "ShipShakeExplode") { - DoShake(self, true); - } else if (timerName == "ShipShakeIdle") { - DoShake(self, false); } } - -void AgSpaceStuff::DoShake(Entity* self, bool explodeIdle) { - - if (!explodeIdle) { - auto* ref = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"ShakeObject")); - - const auto randomTime = self->GetVar<int>(u"RandomTime"); - auto time = GeneralUtils::GenerateRandomNumber<int>(0, randomTime + 1); - - if (time < randomTime / 2) { - time += randomTime / 2; - } - - self->AddTimer("ShipShakeIdle", static_cast<float>(time)); - - if (ref) - GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(ref, FXName, ref->GetObjectID(), 500.0f); - - auto* debrisObject = GetEntityInGroup(DebrisFX); - - if (debrisObject) - GameMessages::SendPlayFXEffect(debrisObject, -1, u"DebrisFall", "Debris", LWOOBJID_EMPTY, 1.0f, 1.0f, true); - - const auto randomFx = GeneralUtils::GenerateRandomNumber<int>(0, 3); - - auto* shipFxObject = GetEntityInGroup(ShipFX); - if (shipFxObject) { - std::string effectType = "shipboom" + std::to_string(randomFx); - GameMessages::SendPlayFXEffect(shipFxObject, 559, GeneralUtils::ASCIIToUTF16(effectType), "FX", LWOOBJID_EMPTY, 1.0f, 1.0f, true); - } - - self->AddTimer("ShipShakeExplode", 5.0f); - - auto* shipFxObject2 = GetEntityInGroup(ShipFX2); - if (shipFxObject2) - RenderComponent::PlayAnimation(shipFxObject2, u"explosion"); - } else { - auto* shipFxObject = GetEntityInGroup(ShipFX); - auto* shipFxObject2 = GetEntityInGroup(ShipFX2); - - if (shipFxObject) - RenderComponent::PlayAnimation(shipFxObject, u"idle"); - - if (shipFxObject2) - RenderComponent::PlayAnimation(shipFxObject2, u"idle"); - } -} - -Entity* AgSpaceStuff::GetEntityInGroup(const std::string& group) { - auto entities = Game::entityManager->GetEntitiesInGroup(group); - Entity* en = nullptr; - - for (auto entity : entities) { - if (entity) { - en = entity; - break; - } - } - - return en; -} diff --git a/dScripts/ai/AG/AgSpaceStuff.h b/dScripts/ai/AG/AgSpaceStuff.h index 8d8166912..568f2baf7 100644 --- a/dScripts/ai/AG/AgSpaceStuff.h +++ b/dScripts/ai/AG/AgSpaceStuff.h @@ -5,14 +5,5 @@ class AgSpaceStuff : public CppScripts::Script { public: void OnStartup(Entity* self); void OnTimerDone(Entity* self, std::string timerName); - void DoShake(Entity* self, bool explodeIdle); - - std::string DebrisFX = "DebrisFX"; - std::string ShipFX = "ShipFX"; - std::string ShipFX2 = "ShipFX2"; - std::u16string FXName = u"camshake-bridge"; - -private: - Entity* GetEntityInGroup(const std::string& group); }; diff --git a/dScripts/ai/AG/CMakeLists.txt b/dScripts/ai/AG/CMakeLists.txt index e031e386d..101f86fd5 100644 --- a/dScripts/ai/AG/CMakeLists.txt +++ b/dScripts/ai/AG/CMakeLists.txt @@ -1,6 +1,7 @@ set(DSCRIPTS_SOURCES_AI_AG "AgShipPlayerDeathTrigger.cpp" "AgSpaceStuff.cpp" + "AgShipShake.cpp" "AgShipPlayerShockServer.cpp" "AgImagSmashable.cpp" "ActSharkPlayerDeathTrigger.cpp" @@ -16,6 +17,6 @@ set(DSCRIPTS_SOURCES_AI_AG "AgStagePlatforms.cpp" "AgQbWall.cpp") -add_library(dScriptsAiAG STATIC ${DSCRIPTS_SOURCES_AI_AG}) +add_library(dScriptsAiAG OBJECT ${DSCRIPTS_SOURCES_AI_AG}) target_include_directories(dScriptsAiAG PUBLIC ".") target_precompile_headers(dScriptsAiAG REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/CMakeLists.txt b/dScripts/ai/CMakeLists.txt index 7e94cd349..354bda21c 100644 --- a/dScripts/ai/CMakeLists.txt +++ b/dScripts/ai/CMakeLists.txt @@ -15,18 +15,34 @@ add_subdirectory(SPEC) add_subdirectory(WILD) add_library(dScriptsAI INTERFACE) -target_link_libraries(dScriptsAI INTERFACE - dScriptsAiAct - dScriptsAiAG - dScriptsAiFV - dScriptsAiGeneral - dScriptsAiGF - dScriptsAiMinigame - dScriptsAiNP - dScriptsAiNS - dScriptsAiPets - dScriptsAiProperty - dScriptsAiRacing - dScriptsAiSpec - dScriptsAiWild +target_sources(dScriptsAI INTERFACE + $<TARGET_OBJECTS:dScriptsAiAct> + $<TARGET_OBJECTS:dScriptsAiAG> + $<TARGET_OBJECTS:dScriptsAiFV> + $<TARGET_OBJECTS:dScriptsAiGeneral> + $<TARGET_OBJECTS:dScriptsAiGF> + $<TARGET_OBJECTS:dScriptsAiMinigame> + $<TARGET_OBJECTS:dScriptsAiNP> + $<TARGET_OBJECTS:dScriptsAiNS> + $<TARGET_OBJECTS:dScriptsAiPets> + $<TARGET_OBJECTS:dScriptsAiProperty> + $<TARGET_OBJECTS:dScriptsAiRacing> + $<TARGET_OBJECTS:dScriptsAiSpec> + $<TARGET_OBJECTS:dScriptsAiWild> +) + +target_include_directories(dScriptsAI INTERFACE + $<TARGET_PROPERTY:dScriptsAiAct,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiAG,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiFV,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiGeneral,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiGF,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiMinigame,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiNP,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiNS,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiPets,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiProperty,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiRacing,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiSpec,INTERFACE_INCLUDE_DIRECTORIES> + $<TARGET_PROPERTY:dScriptsAiWild,INTERFACE_INCLUDE_DIRECTORIES> ) diff --git a/dScripts/ai/FV/CMakeLists.txt b/dScripts/ai/FV/CMakeLists.txt index 55c68a270..535a02a66 100644 --- a/dScripts/ai/FV/CMakeLists.txt +++ b/dScripts/ai/FV/CMakeLists.txt @@ -18,7 +18,7 @@ set(DSCRIPTS_SOURCES_AI_FV "FvMaelstromGeyser.cpp" "TriggerGas.cpp") -add_library(dScriptsAiFV STATIC ${DSCRIPTS_SOURCES_AI_FV}) +add_library(dScriptsAiFV OBJECT ${DSCRIPTS_SOURCES_AI_FV}) target_include_directories(dScriptsAiFV PUBLIC ".") target_precompile_headers(dScriptsAiFV REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/GENERAL/CMakeLists.txt b/dScripts/ai/GENERAL/CMakeLists.txt index 9b7f2a2ab..77441b4ac 100644 --- a/dScripts/ai/GENERAL/CMakeLists.txt +++ b/dScripts/ai/GENERAL/CMakeLists.txt @@ -2,7 +2,7 @@ set(DSCRIPTS_SOURCES_AI_GENERAL "InstanceExitTransferPlayerToLastNonInstance.cpp" "LegoDieRoll.cpp") -add_library(dScriptsAiGeneral STATIC ${DSCRIPTS_SOURCES_AI_GENERAL}) +add_library(dScriptsAiGeneral OBJECT ${DSCRIPTS_SOURCES_AI_GENERAL}) target_include_directories(dScriptsAiGeneral PUBLIC ".") target_precompile_headers(dScriptsAiGeneral REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/GF/CMakeLists.txt b/dScripts/ai/GF/CMakeLists.txt index 7a7a17235..d28b04f1b 100644 --- a/dScripts/ai/GF/CMakeLists.txt +++ b/dScripts/ai/GF/CMakeLists.txt @@ -12,6 +12,6 @@ set(DSCRIPTS_SOURCES_AI_GF "PirateRep.cpp" "GfParrotCrash.cpp") -add_library(dScriptsAiGF STATIC ${DSCRIPTS_SOURCES_AI_GF}) +add_library(dScriptsAiGF OBJECT ${DSCRIPTS_SOURCES_AI_GF}) target_include_directories(dScriptsAiGF PUBLIC ".") target_precompile_headers(dScriptsAiGF REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/MINIGAME/CMakeLists.txt b/dScripts/ai/MINIGAME/CMakeLists.txt index 0e07d526a..5598110b1 100644 --- a/dScripts/ai/MINIGAME/CMakeLists.txt +++ b/dScripts/ai/MINIGAME/CMakeLists.txt @@ -12,6 +12,6 @@ foreach(file ${DSCRIPTS_SOURCES_AI_MINIGAME_OBJECTS}) set(DSCRIPTS_SOURCES_AI_MINIGAME ${DSCRIPTS_SOURCES_AI_MINIGAME} "Objects/${file}") endforeach() -add_library(dScriptsAiMinigame STATIC ${DSCRIPTS_SOURCES_AI_MINIGAME}) +add_library(dScriptsAiMinigame OBJECT ${DSCRIPTS_SOURCES_AI_MINIGAME}) target_include_directories(dScriptsAiMinigame PUBLIC "." "Objects" "SG_GF" "SG_GF/SERVER") target_precompile_headers(dScriptsAiMinigame REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp index 1952831a3..5b178e06f 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -61,6 +61,7 @@ void SGCannon::OnStartup(Entity* self) { if (simplePhysicsComponent != nullptr) { simplePhysicsComponent->SetPhysicsMotionState(5); } + Game::entityManager->SerializeEntity(self); } void SGCannon::OnPlayerLoaded(Entity* self, Entity* player) { @@ -307,11 +308,7 @@ void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) { movementAI->SetCurrentSpeed(toSpawn.initialSpeed); movementAI->SetHaltDistance(0.0f); - std::vector<NiPoint3> pathWaypoints; - - for (const auto& waypoint : path->pathWaypoints) { - pathWaypoints.push_back(waypoint.position); - } + std::vector<PathWaypoint> pathWaypoints = path->pathWaypoints; if (GeneralUtils::GenerateRandomNumber<float_t>(0, 1) < 0.5f) { std::reverse(pathWaypoints.begin(), pathWaypoints.end()); diff --git a/dScripts/ai/NP/CMakeLists.txt b/dScripts/ai/NP/CMakeLists.txt index 9f3f6a651..b71bd1f8b 100644 --- a/dScripts/ai/NP/CMakeLists.txt +++ b/dScripts/ai/NP/CMakeLists.txt @@ -1,6 +1,6 @@ set(DSCRIPTS_SOURCES_AI_NP "NpcNpSpacemanBob.cpp") -add_library(dScriptsAiNP STATIC ${DSCRIPTS_SOURCES_AI_NP}) +add_library(dScriptsAiNP OBJECT ${DSCRIPTS_SOURCES_AI_NP}) target_include_directories(dScriptsAiNP PUBLIC ".") target_precompile_headers(dScriptsAiNP REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/NS/CMakeLists.txt b/dScripts/ai/NS/CMakeLists.txt index 0f0aa0c78..750ee67a9 100644 --- a/dScripts/ai/NS/CMakeLists.txt +++ b/dScripts/ai/NS/CMakeLists.txt @@ -21,7 +21,7 @@ foreach(file ${DSCRIPTS_SOURCES_AI_NS_WH}) set(DSCRIPTS_SOURCES_AI_NS ${DSCRIPTS_SOURCES_AI_NS} "WH/${file}") endforeach() -add_library(dScriptsAiNS STATIC ${DSCRIPTS_SOURCES_AI_NS}) +add_library(dScriptsAiNS OBJECT ${DSCRIPTS_SOURCES_AI_NS}) target_include_directories(dScriptsAiNS PUBLIC "." "NS_PP_01" "WH" PRIVATE ${PROJECT_SOURCE_DIR}/dScripts/02_server/Map/NS) # NsConcertChoiceBuildManager.h diff --git a/dScripts/ai/PETS/CMakeLists.txt b/dScripts/ai/PETS/CMakeLists.txt index 8bd8630c3..b7ae20334 100644 --- a/dScripts/ai/PETS/CMakeLists.txt +++ b/dScripts/ai/PETS/CMakeLists.txt @@ -1,6 +1,6 @@ set(DSCRIPTS_SOURCES_AI_PETS "HydrantSmashable.cpp") -add_library(dScriptsAiPets STATIC ${DSCRIPTS_SOURCES_AI_PETS}) +add_library(dScriptsAiPets OBJECT ${DSCRIPTS_SOURCES_AI_PETS}) target_include_directories(dScriptsAiPets PUBLIC "." "NS_PP_01" "WH") target_precompile_headers(dScriptsAiPets REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/PROPERTY/CMakeLists.txt b/dScripts/ai/PROPERTY/CMakeLists.txt index a31b9257e..07c528f72 100644 --- a/dScripts/ai/PROPERTY/CMakeLists.txt +++ b/dScripts/ai/PROPERTY/CMakeLists.txt @@ -8,6 +8,6 @@ foreach(file ${DSCRIPTS_SOURCES_AI_PROPERTY_AG}) set(DSCRIPTS_SOURCES_AI_PROPERTY ${DSCRIPTS_SOURCES_AI_PROPERTY} "AG/${file}") endforeach() -add_library(dScriptsAiProperty STATIC ${DSCRIPTS_SOURCES_AI_PROPERTY}) +add_library(dScriptsAiProperty OBJECT ${DSCRIPTS_SOURCES_AI_PROPERTY}) target_include_directories(dScriptsAiProperty PUBLIC "." "AG") target_precompile_headers(dScriptsAiProperty REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/RACING/CMakeLists.txt b/dScripts/ai/RACING/CMakeLists.txt index b7343c61b..a803b051c 100644 --- a/dScripts/ai/RACING/CMakeLists.txt +++ b/dScripts/ai/RACING/CMakeLists.txt @@ -6,6 +6,6 @@ foreach(file ${DSCRIPTS_SOURCES_AI_RACING_OBJECTS}) set(DSCRIPTS_SOURCES_AI_RACING ${DSCRIPTS_SOURCES_AI_RACING} "OBJECTS/${file}") endforeach() -add_library(dScriptsAiRacing STATIC ${DSCRIPTS_SOURCES_AI_RACING}) +add_library(dScriptsAiRacing OBJECT ${DSCRIPTS_SOURCES_AI_RACING}) target_include_directories(dScriptsAiRacing PUBLIC "." "OBJECTS") target_precompile_headers(dScriptsAiRacing REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/RACING/OBJECTS/CMakeLists.txt b/dScripts/ai/RACING/OBJECTS/CMakeLists.txt index 4ef427d58..83f4b8b32 100644 --- a/dScripts/ai/RACING/OBJECTS/CMakeLists.txt +++ b/dScripts/ai/RACING/OBJECTS/CMakeLists.txt @@ -1,6 +1,10 @@ set(DSCRIPTS_SOURCES_AI_RACING_OBJECTS "RaceImagineCrateServer.cpp" "RaceImaginePowerup.cpp" + "FvRaceDragon.cpp" + "FvRacePillarServer.cpp" + "FvRacePillarABCServer.cpp" + "FvRacePillarDServer.cpp" "FvRaceSmashEggImagineServer.cpp" "RaceSmashServer.cpp" PARENT_SCOPE) diff --git a/dScripts/ai/RACING/OBJECTS/FvRaceDragon.cpp b/dScripts/ai/RACING/OBJECTS/FvRaceDragon.cpp new file mode 100644 index 000000000..cde7b8099 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRaceDragon.cpp @@ -0,0 +1,30 @@ +#include "FvRaceDragon.h" +#include "RenderComponent.h" +#include "RacingControlComponent.h" + +void FvRaceDragon::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + if (racingControllers.empty()) return; + + auto* racingControlComponent = racingControllers[0]->GetComponent<RacingControlComponent>(); + if (!racingControlComponent) return; + + const auto* player = racingControlComponent->GetPlayerData(target->GetObjectID()); + if (!player) return; + + if (player->lap != m_Lap) return; + + const auto dragons = Game::entityManager->GetEntitiesInGroup("dragon"); + for (const auto& dragon : dragons) { + if (!dragon || dragon->GetLOT() != this->m_Dragon) continue; + + auto* renderComponent = dragon->GetComponent<RenderComponent>(); + if (!renderComponent) continue; + + renderComponent->PlayAnimation(dragon, m_LapAnimName); + + } + Game::entityManager->DestroyEntity(self); +} diff --git a/dScripts/ai/RACING/OBJECTS/FvRaceDragon.h b/dScripts/ai/RACING/OBJECTS/FvRaceDragon.h new file mode 100644 index 000000000..0a0320c32 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRaceDragon.h @@ -0,0 +1,15 @@ +#pragma once +#include "CppScripts.h" + +#include <string> +#include <string_view> + +class FvRaceDragon : public CppScripts::Script { +public: + FvRaceDragon(const std::string_view lapAnimName, const int32_t lap) : m_LapAnimName(lapAnimName), m_Lap(lap) {} +private: + void OnCollisionPhantom(Entity* self, Entity* target) override; + const std::string m_LapAnimName; + const int32_t m_Lap; + const LOT m_Dragon = 11898; +}; diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.cpp b/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.cpp new file mode 100644 index 000000000..7023fecca --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.cpp @@ -0,0 +1,34 @@ +#include "FvRacePillarABCServer.h" +#include "RenderComponent.h" +#include "RacingControlComponent.h" + +void FvRacePillarABCServer::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + if (racingControllers.empty()) return; + + auto* racingControlComponent = racingControllers[0]->GetComponent<RacingControlComponent>(); + if (!racingControlComponent) return; + + const auto* player = racingControlComponent->GetPlayerData(target->GetObjectID()); + if (!player || player->lap != 1) return; + + PlayAnimation("crumble", "pillars", m_PillarA); + PlayAnimation("roar", "dragon", m_Dragon); + + self->AddTimer("PillarBFall", 2.5f); + self->AddTimer("PillarCFall", 3.7f); + self->AddTimer("DeleteObject", 3.8f); +} + +void FvRacePillarABCServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "PillarBFall") { + PlayAnimation("crumble", "pillars", m_PillarB); + } else if (timerName == "PillarCFall") { + PlayAnimation("crumble", "pillars", m_PillarC); + } else if (timerName == "DeleteObject") { + Game::entityManager->DestroyEntity(self); + } +} + diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.h b/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.h new file mode 100644 index 000000000..9059fbeb9 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" +#include "FvRacePillarServer.h" + +class FvRacePillarABCServer : public FvRacePillarServer { + void OnCollisionPhantom(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + const LOT m_PillarA = 11946; + const LOT m_PillarB = 11947; + const LOT m_PillarC = 11948; + const LOT m_Dragon = 11898; +}; diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.cpp b/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.cpp new file mode 100644 index 000000000..b119352eb --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.cpp @@ -0,0 +1,21 @@ +#include "FvRacePillarDServer.h" +#include "RenderComponent.h" +#include "RacingControlComponent.h" + +void FvRacePillarDServer::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + if (racingControllers.empty()) return; + + auto* racingControlComponent = racingControllers[0]->GetComponent<RacingControlComponent>(); + if (!racingControlComponent) return; + + const auto* player = racingControlComponent->GetPlayerData(target->GetObjectID()); + if (!player) return; + + if (player->lap == 2) { + PlayAnimation("crumble", "pillars", m_PillarD); + PlayAnimation("roar", "dragon", m_Dragon); + } +} diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.h b/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.h new file mode 100644 index 000000000..e8d215674 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" +#include "FvRacePillarServer.h" + +class FvRacePillarDServer : public FvRacePillarServer { + void OnCollisionPhantom(Entity* self, Entity* target) override; +private: + const LOT m_PillarD = 11949; + const LOT m_Dragon = 11898; +}; diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.cpp b/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.cpp new file mode 100644 index 000000000..c89cf2a22 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.cpp @@ -0,0 +1,15 @@ +#include "FvRacePillarServer.h" + +#include "Game.h" +#include "EntityManager.h" +#include "RenderComponent.h" + +void FvRacePillarServer::PlayAnimation(const std::string animName, const std::string group, const LOT lot) { + const auto entities = Game::entityManager->GetEntitiesInGroup(group); + for (const auto& entity : entities) { + if (!entity || entity->GetLOT() != lot) continue; + auto* renderComponent = entity->GetComponent<RenderComponent>(); + if (!renderComponent) continue; + renderComponent->PlayAnimation(entity, animName); + } +} diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.h b/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.h new file mode 100644 index 000000000..9249177a6 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.h @@ -0,0 +1,12 @@ +#ifndef FVRACEPILLARSERVER__H +#define FVRACEPILLARSERVER__H + +#include "CppScripts.h" + +class FvRacePillarServer : public virtual CppScripts::Script { +protected: + // Plays an animation on all entities in a group with a specific LOT + void PlayAnimation(const std::string animName, const std::string group, const LOT lot); +}; + +#endif // FVRACEPILLARSERVER__H diff --git a/dScripts/ai/SPEC/CMakeLists.txt b/dScripts/ai/SPEC/CMakeLists.txt index c60372ac1..29a781eb2 100644 --- a/dScripts/ai/SPEC/CMakeLists.txt +++ b/dScripts/ai/SPEC/CMakeLists.txt @@ -3,6 +3,6 @@ set(DSCRIPTS_SOURCES_AI_SPEC "SpecialPowerupSpawner.cpp" "SpecialSpeedBuffSpawner.cpp") -add_library(dScriptsAiSpec STATIC ${DSCRIPTS_SOURCES_AI_SPEC}) +add_library(dScriptsAiSpec OBJECT ${DSCRIPTS_SOURCES_AI_SPEC}) target_include_directories(dScriptsAiSpec PUBLIC ".") target_precompile_headers(dScriptsAiSpec REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/WILD/CMakeLists.txt b/dScripts/ai/WILD/CMakeLists.txt index 418ffb5f4..5d4f43c31 100644 --- a/dScripts/ai/WILD/CMakeLists.txt +++ b/dScripts/ai/WILD/CMakeLists.txt @@ -1,5 +1,6 @@ set(DSCRIPTS_SOURCES_AI_WILD "AllCrateChicken.cpp" + "LupGenericInteract.cpp" "WildAmbients.cpp" "WildAmbientCrab.cpp" "WildAndScared.cpp" @@ -9,6 +10,6 @@ set(DSCRIPTS_SOURCES_AI_WILD "WildNinjaSensei.cpp" "WildPants.cpp") -add_library(dScriptsAiWild STATIC ${DSCRIPTS_SOURCES_AI_WILD}) +add_library(dScriptsAiWild OBJECT ${DSCRIPTS_SOURCES_AI_WILD}) target_include_directories(dScriptsAiWild PUBLIC ".") target_precompile_headers(dScriptsAiWild REUSE_FROM dScriptsBase) diff --git a/dScripts/ai/WILD/LupGenericInteract.cpp b/dScripts/ai/WILD/LupGenericInteract.cpp new file mode 100644 index 000000000..95eb7a96f --- /dev/null +++ b/dScripts/ai/WILD/LupGenericInteract.cpp @@ -0,0 +1,6 @@ +#include "LupGenericInteract.h" +#include "GameMessages.h" + +void LupGenericInteract::OnUse(Entity* self, Entity* user) { + GameMessages::SendPlayAnimation(self, u"interact"); +} diff --git a/dScripts/ai/WILD/LupGenericInteract.h b/dScripts/ai/WILD/LupGenericInteract.h new file mode 100644 index 000000000..68949bbf7 --- /dev/null +++ b/dScripts/ai/WILD/LupGenericInteract.h @@ -0,0 +1,12 @@ +#ifndef __LUCGENERICINTERACT__H__ +#define __LUCGENERICINTERACT__H__ + +#include "CppScripts.h" + +class LupGenericInteract : public CppScripts::Script { +public: + void OnUse(Entity* self, Entity* user) override; +}; + +#endif //!__LUCGENERICINTERACT__H__ + diff --git a/dScripts/client/CMakeLists.txt b/dScripts/client/CMakeLists.txt index b3ad08fbd..f6760006b 100644 --- a/dScripts/client/CMakeLists.txt +++ b/dScripts/client/CMakeLists.txt @@ -6,6 +6,6 @@ foreach(file ${DSCRIPTS_SOURCES_CLIENT_AI}) set(DSCRIPTS_SOURCES_CLIENT ${DSCRIPTS_SOURCES_CLIENT} "ai/${file}") endforeach() -add_library(dScriptsClient STATIC ${DSCRIPTS_SOURCES_CLIENT}) +add_library(dScriptsClient OBJECT ${DSCRIPTS_SOURCES_CLIENT}) target_include_directories(dScriptsClient PUBLIC "." "ai" "ai/PR") target_precompile_headers(dScriptsClient REUSE_FROM dScriptsBase) diff --git a/dScripts/zone/CMakeLists.txt b/dScripts/zone/CMakeLists.txt index 93ea70ca7..fe919cd4f 100644 --- a/dScripts/zone/CMakeLists.txt +++ b/dScripts/zone/CMakeLists.txt @@ -18,10 +18,11 @@ foreach(file ${DSCRIPTS_SOURCES_ZONE_PROPERTY}) set(DSCRIPTS_SOURCES_ZONE ${DSCRIPTS_SOURCES_ZONE} "PROPERTY/${file}") endforeach() -add_library(dScriptsZone STATIC ${DSCRIPTS_SOURCES_ZONE}) +add_library(dScriptsZone OBJECT ${DSCRIPTS_SOURCES_ZONE}) target_include_directories(dScriptsZone PUBLIC "." "AG" "LUPs" + "LUPs/RobotCity_Intro" "PROPERTY" "PROPERTY/FV" "PROPERTY/GF" diff --git a/dScripts/zone/LUPs/CMakeLists.txt b/dScripts/zone/LUPs/CMakeLists.txt index b3b55ad61..7ce84fcc0 100644 --- a/dScripts/zone/LUPs/CMakeLists.txt +++ b/dScripts/zone/LUPs/CMakeLists.txt @@ -1,3 +1,11 @@ -set(DSCRIPTS_SOURCES_ZONE_LUPS +set(DSCRIPTS_SOURCES_ZONE_LUPS "WblGenericZone.cpp" - PARENT_SCOPE) +) + +add_subdirectory(RobotCity_Intro) + +foreach(file ${DSCRIPTS_SOURCES_ZONE_LUPS_ROBOTCITYINTRO}) + set(DSCRIPTS_SOURCES_ZONE_LUPS ${DSCRIPTS_SOURCES_ZONE_LUPS} "RobotCity_Intro/${file}") +endforeach() + +set(DSCRIPTS_SOURCES_ZONE_LUPS ${DSCRIPTS_SOURCES_ZONE_LUPS} PARENT_SCOPE) diff --git a/dScripts/zone/LUPs/RobotCity_Intro/CMakeLists.txt b/dScripts/zone/LUPs/RobotCity_Intro/CMakeLists.txt new file mode 100644 index 000000000..fae8793ba --- /dev/null +++ b/dScripts/zone/LUPs/RobotCity_Intro/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DSCRIPTS_SOURCES_ZONE_LUPS_ROBOTCITYINTRO + "WblRobotCitizen.cpp" + PARENT_SCOPE) diff --git a/dScripts/zone/LUPs/RobotCity_Intro/WblRobotCitizen.cpp b/dScripts/zone/LUPs/RobotCity_Intro/WblRobotCitizen.cpp new file mode 100644 index 000000000..8ad303a60 --- /dev/null +++ b/dScripts/zone/LUPs/RobotCity_Intro/WblRobotCitizen.cpp @@ -0,0 +1,23 @@ +#include "WblRobotCitizen.h" +#include "MovementAIComponent.h" +#include "RenderComponent.h" + +void WblRobotCitizen::OnStartup(Entity* self) { + auto movementAIComponent = self->GetComponent<MovementAIComponent>(); + if (!movementAIComponent) return; +} + +void WblRobotCitizen::OnUse(Entity* self, Entity* user) { + auto movementAIComponent = self->GetComponent<MovementAIComponent>(); + if (movementAIComponent) movementAIComponent->Pause(); + auto face = NiQuaternion::LookAt(self->GetPosition(), user->GetPosition()); + self->SetRotation(face); + auto timer = RenderComponent::PlayAnimation(self, "wave", 0.4f); + self->AddTimer("animation time", timer); +} + +void WblRobotCitizen::OnTimerDone(Entity* self, std::string timerName) { + auto movementAIComponent = self->GetComponent<MovementAIComponent>(); + if (!movementAIComponent) return; + movementAIComponent->Resume(); +} diff --git a/dScripts/zone/LUPs/RobotCity_Intro/WblRobotCitizen.h b/dScripts/zone/LUPs/RobotCity_Intro/WblRobotCitizen.h new file mode 100644 index 000000000..2f720764c --- /dev/null +++ b/dScripts/zone/LUPs/RobotCity_Intro/WblRobotCitizen.h @@ -0,0 +1,13 @@ +#ifndef __WBLROBOTCITIZEN__H__ +#define __WBLROBOTCITIZEN__H__ + +#include "CppScripts.h" + +class WblRobotCitizen : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnUse(Entity* self, Entity* user) override; + void OnTimerDone(Entity* self, std::string timerName) override; +}; + +#endif //!__WBLROBOTCITIZEN__H__ diff --git a/dServer/CMakeLists.txt b/dServer/CMakeLists.txt index 356e55b7b..ca4e61984 100644 --- a/dServer/CMakeLists.txt +++ b/dServer/CMakeLists.txt @@ -4,3 +4,7 @@ set(DSERVER_SOURCES add_library(dServer STATIC ${DSERVER_SOURCES}) target_include_directories(dServer PUBLIC ".") + +target_include_directories(dServer PRIVATE + "${PROJECT_SOURCE_DIR}/dCommon/" # BinaryPathFinder.h +) diff --git a/dWorldServer/CMakeLists.txt b/dWorldServer/CMakeLists.txt index 41cba0e27..62a3767aa 100644 --- a/dWorldServer/CMakeLists.txt +++ b/dWorldServer/CMakeLists.txt @@ -2,11 +2,22 @@ set(DWORLDSERVER_SOURCES "PerformanceManager.cpp" ) -add_library(dWorldServer ${DWORLDSERVER_SOURCES}) +add_library(dWorldServer OBJECT ${DWORLDSERVER_SOURCES}) +target_link_libraries(dWorldServer PUBLIC dGameBase dCommon) + add_executable(WorldServer "WorldServer.cpp") +target_include_directories(WorldServer PRIVATE "${PROJECT_SOURCE_DIR}/dChatFilter") add_compile_definitions(WorldServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"") -target_link_libraries(dWorldServer ${COMMON_LIBRARIES}) -target_link_libraries(WorldServer ${COMMON_LIBRARIES} dChatFilter dGame dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dNavigation dServer) -target_include_directories(WorldServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer) +target_include_directories(WorldServer PRIVATE + "${PROJECT_SOURCE_DIR}/dServer" # BinaryPathFinder.h +) +target_link_libraries(WorldServer ${COMMON_LIBRARIES} + dScripts + dGameBase + dComponents + dUtilities + dGameMessages + dInventory + dGame dChatFilter dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dNavigation dServer) diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index fde5a2a6a..c723a01ef 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -65,11 +65,11 @@ #include "eServerDisconnectIdentifiers.h" #include "eObjectBits.h" #include "eConnectionType.h" -#include "eServerMessageType.h" -#include "eChatInternalMessageType.h" -#include "eWorldMessageType.h" -#include "eMasterMessageType.h" -#include "eGameMessageType.h" +#include "MessageType/Server.h" +#include "MessageType/Chat.h" +#include "MessageType/World.h" +#include "MessageType/Master.h" +#include "MessageType/Game.h" #include "ZCompression.h" #include "EntityManager.h" #include "CheatDetection.h" @@ -79,6 +79,9 @@ #include "PositionUpdate.h" #include "PlayerManager.h" #include "eLoginResponse.h" +#include "MissionComponent.h" +#include "SlashCommandHandler.h" +#include "InventoryComponent.h" namespace Game { Logger* logger = nullptr; @@ -281,24 +284,22 @@ int main(int argc, char** argv) { } const int32_t bufferSize = 1024; - MD5* md5 = new MD5(); + MD5 md5; char fileStreamBuffer[1024] = {}; while (!fileStream.eof()) { memset(fileStreamBuffer, 0, bufferSize); fileStream.read(fileStreamBuffer, bufferSize); - md5->update(fileStreamBuffer, fileStream.gcount()); + md5.update(fileStreamBuffer, fileStream.gcount()); } fileStream.close(); const char* nullTerminateBuffer = "\0"; - md5->update(nullTerminateBuffer, 1); // null terminate the data - md5->finalize(); - databaseChecksum = md5->hexdigest(); - - delete md5; + md5.update(nullTerminateBuffer, 1); // null terminate the data + md5.finalize(); + databaseChecksum = md5.hexdigest(); LOG("FDB Checksum calculated as: %s", databaseChecksum.c_str()); } @@ -313,6 +314,9 @@ int main(int argc, char** argv) { uint32_t sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames uint32_t emptyShutdownTime = (cloneID == 0 ? 30 : 5) * 60 * currentFramerate; // 30 minutes for main worlds, 5 for all others. + // Register slash commands if not in zone 0 + if (zoneID != 0) SlashCommandHandler::Startup(); + Game::logger->Flush(); // once immediately before the main loop while (true) { Metrics::StartMeasurement(MetricVariable::Frame); @@ -335,7 +339,7 @@ int main(int argc, char** argv) { // Update to the new framerate and scale all timings to said new framerate if (newFrameDelta != currentFrameDelta) { - float_t ratioBeforeToAfter = (float)currentFrameDelta / (float)newFrameDelta; + float_t ratioBeforeToAfter = static_cast<float>(currentFrameDelta) / static_cast<float>(newFrameDelta); currentFrameDelta = newFrameDelta; currentFramerate = MS_TO_FRAMES(newFrameDelta); LOG_DEBUG("Framerate for zone/instance/clone %i/%i/%i is now %i", zoneID, instanceID, cloneID, currentFramerate); @@ -357,7 +361,7 @@ int main(int argc, char** argv) { //Warning if we ran slow if (deltaTime > currentFrameDelta) { - LOG("We're running behind, dT: %f > %f (framerate %i)", deltaTime, currentFrameDelta, currentFramerate); + LOG("We're running behind, dT: %f > %i (framerate %i)", deltaTime, currentFrameDelta, currentFramerate); } //Check if we're still connected to master: @@ -384,14 +388,14 @@ int main(int argc, char** argv) { //In world we'd update our other systems here. if (zoneID != 0 && deltaTime > 0.0f) { - Metrics::StartMeasurement(MetricVariable::Physics); - dpWorld::StepWorld(deltaTime); - Metrics::EndMeasurement(MetricVariable::Physics); - Metrics::StartMeasurement(MetricVariable::UpdateEntities); Game::entityManager->UpdateEntities(deltaTime); Metrics::EndMeasurement(MetricVariable::UpdateEntities); + Metrics::StartMeasurement(MetricVariable::Physics); + dpWorld::StepWorld(deltaTime); + Metrics::EndMeasurement(MetricVariable::Physics); + Metrics::StartMeasurement(MetricVariable::Ghosting); if (std::chrono::duration<float>(currentTime - ghostingLastTime).count() >= 1.0f) { Game::entityManager->UpdateGhosting(); @@ -527,6 +531,7 @@ int main(int argc, char** argv) { } void HandlePacketChat(Packet* packet) { + if (packet->length < 1) return; if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { LOG("Lost our connection to chat, zone(%i), instance(%i)", Game::server->GetZoneID(), Game::server->GetInstanceID()); @@ -540,129 +545,128 @@ void HandlePacketChat(Packet* packet) { chatConnected = true; } - if (packet->data[0] == ID_USER_PACKET_ENUM) { - if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) { - switch (static_cast<eChatInternalMessageType>(packet->data[3])) { - case eChatInternalMessageType::ROUTE_TO_PLAYER: { - CINSTREAM_SKIP_HEADER; - LWOOBJID playerID; - inStream.Read(playerID); + if (packet->data[0] == ID_USER_PACKET_ENUM && packet->length >= 4) { + if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT) { + switch (static_cast<MessageType::Chat>(packet->data[3])) { + case MessageType::Chat::WORLD_ROUTE_PACKET: { + CINSTREAM_SKIP_HEADER; + LWOOBJID playerID; + inStream.Read(playerID); - auto player = Game::entityManager->GetEntity(playerID); - if (!player) return; + auto player = Game::entityManager->GetEntity(playerID); + if (!player) return; - auto sysAddr = player->GetSystemAddress(); + auto sysAddr = player->GetSystemAddress(); - //Write our stream outwards: - CBITSTREAM; - for (BitSize_t i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { - bitStream.Write(packet->data[i + 16]); //16 bytes == header + playerID to skip + //Write our stream outwards: + CBITSTREAM; + unsigned char data; + while (inStream.Read(data)) { + bitStream.Write(data); + } + + SEND_PACKET; //send routed packet to player + break; } - SEND_PACKET; //send routed packet to player + case MessageType::Chat::GM_ANNOUNCE: { + CINSTREAM_SKIP_HEADER; - break; - } + std::string title; + std::string msg; - case eChatInternalMessageType::ANNOUNCEMENT: { - CINSTREAM_SKIP_HEADER; + uint32_t len; + inStream.Read<uint32_t>(len); + for (uint32_t i = 0; len > i; i++) { + char character; + inStream.Read<char>(character); + title += character; + } - std::string title; - std::string msg; + len = 0; + inStream.Read<uint32_t>(len); + for (uint32_t i = 0; len > i; i++) { + char character; + inStream.Read<char>(character); + msg += character; + } - uint32_t len; - inStream.Read<uint32_t>(len); - for (uint32_t i = 0; len > i; i++) { - char character; - inStream.Read<char>(character); - title += character; - } + //Send to our clients: + AMFArrayValue args; - len = 0; - inStream.Read<uint32_t>(len); - for (uint32_t i = 0; len > i; i++) { - char character; - inStream.Read<char>(character); - msg += character; - } + args.Insert("title", title); + args.Insert("message", msg); - //Send to our clients: - AMFArrayValue args; + GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); - args.Insert("title", title); - args.Insert("message", msg); + break; + } - GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); + case MessageType::Chat::GM_MUTE: { + CINSTREAM_SKIP_HEADER; + LWOOBJID playerId; + time_t expire = 0; + inStream.Read(playerId); + inStream.Read(expire); - break; - } - - case eChatInternalMessageType::MUTE_UPDATE: { - CINSTREAM_SKIP_HEADER; - LWOOBJID playerId; - time_t expire = 0; - inStream.Read(playerId); - inStream.Read(expire); + auto* entity = Game::entityManager->GetEntity(playerId); + auto* character = entity != nullptr ? entity->GetCharacter() : nullptr; + auto* user = character != nullptr ? character->GetParentUser() : nullptr; + if (user) { + user->SetMuteExpire(expire); - auto* entity = Game::entityManager->GetEntity(playerId); - auto* character = entity != nullptr ? entity->GetCharacter() : nullptr; - auto* user = character != nullptr ? character->GetParentUser() : nullptr; - if (user) { - user->SetMuteExpire(expire); + entity->GetCharacter()->SendMuteNotice(); + } - entity->GetCharacter()->SendMuteNotice(); + break; } - break; - } - - case eChatInternalMessageType::TEAM_UPDATE: { - CINSTREAM_SKIP_HEADER; + case MessageType::Chat::TEAM_GET_STATUS: { + CINSTREAM_SKIP_HEADER; - LWOOBJID teamID = 0; - char lootOption = 0; - char memberCount = 0; - std::vector<LWOOBJID> members; + LWOOBJID teamID = 0; + char lootOption = 0; + char memberCount = 0; + std::vector<LWOOBJID> members; - inStream.Read(teamID); - bool deleteTeam = inStream.ReadBit(); + inStream.Read(teamID); + bool deleteTeam = inStream.ReadBit(); - if (deleteTeam) { - TeamManager::Instance()->DeleteTeam(teamID); + if (deleteTeam) { + TeamManager::Instance()->DeleteTeam(teamID); - LOG("Deleting team (%llu)", teamID); - - break; - } + LOG("Deleting team (%llu)", teamID); - inStream.Read(lootOption); - inStream.Read(memberCount); - LOG("Updating team (%llu), (%i), (%i)", teamID, lootOption, memberCount); - for (char i = 0; i < memberCount; i++) { - LWOOBJID member = LWOOBJID_EMPTY; - inStream.Read(member); - members.push_back(member); + break; + } - LOG("Updating team member (%llu)", member); - } + inStream.Read(lootOption); + inStream.Read(memberCount); + LOG("Updating team (%llu), (%i), (%i)", teamID, lootOption, memberCount); + for (char i = 0; i < memberCount; i++) { + LWOOBJID member = LWOOBJID_EMPTY; + inStream.Read(member); + members.push_back(member); - TeamManager::Instance()->UpdateTeam(teamID, lootOption, members); + LOG("Updating team member (%llu)", member); + } - break; - } + TeamManager::Instance()->UpdateTeam(teamID, lootOption, members); - default: - LOG("Received an unknown chat internal: %i", int(packet->data[3])); + break; + } + default: + LOG("Received an unknown chat: %i", int(packet->data[3])); } } } } void HandleMasterPacket(Packet* packet) { - + if (packet->length < 2) return; if (static_cast<eConnectionType>(packet->data[1]) != eConnectionType::MASTER || packet->length < 4) return; - switch (static_cast<eMasterMessageType>(packet->data[3])) { - case eMasterMessageType::REQUEST_PERSISTENT_ID_RESPONSE: { + switch (static_cast<MessageType::Master>(packet->data[3])) { + case MessageType::Master::REQUEST_PERSISTENT_ID_RESPONSE: { CINSTREAM_SKIP_HEADER; uint64_t requestID; inStream.Read(requestID); @@ -672,7 +676,7 @@ void HandleMasterPacket(Packet* packet) { break; } - case eMasterMessageType::SESSION_KEY_RESPONSE: { + case MessageType::Master::SESSION_KEY_RESPONSE: { //Read our session key and to which user it belongs: CINSTREAM_SKIP_HEADER; uint32_t sessionKey = 0; @@ -727,16 +731,16 @@ void HandleMasterPacket(Packet* packet) { //Notify master: { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PLAYER_ADDED); - bitStream.Write((LWOMAPID)Game::server->GetZoneID()); - bitStream.Write((LWOINSTANCEID)instanceID); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::PLAYER_ADDED); + bitStream.Write<LWOMAPID>(Game::server->GetZoneID()); + bitStream.Write<LWOINSTANCEID>(instanceID); Game::server->SendToMaster(bitStream); } } break; } - case eMasterMessageType::AFFIRM_TRANSFER_REQUEST: { + case MessageType::Master::AFFIRM_TRANSFER_REQUEST: { CINSTREAM_SKIP_HEADER; uint64_t requestID; inStream.Read(requestID); @@ -744,20 +748,20 @@ void HandleMasterPacket(Packet* packet) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::AFFIRM_TRANSFER_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::AFFIRM_TRANSFER_RESPONSE); bitStream.Write(requestID); Game::server->SendToMaster(bitStream); break; } - case eMasterMessageType::SHUTDOWN: { + case MessageType::Master::SHUTDOWN: { Game::lastSignal = -1; LOG("Got shutdown request from master, zone (%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID()); break; } - case eMasterMessageType::NEW_SESSION_ALERT: { + case MessageType::Master::NEW_SESSION_ALERT: { CINSTREAM_SKIP_HEADER; uint32_t sessionKey = inStream.Read(sessionKey); @@ -785,6 +789,7 @@ void HandleMasterPacket(Packet* packet) { } void HandlePacket(Packet* packet) { + if (packet->length < 1) return; if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) { auto user = UserManager::Instance()->GetUser(packet->systemAddress); if (!user) return; @@ -817,7 +822,7 @@ void HandlePacket(Packet* packet) { { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::UNEXPECTED_DISCONNECT); bitStream.Write(user->GetLoggedInChar()); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } @@ -829,23 +834,23 @@ void HandlePacket(Packet* packet) { } CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PLAYER_REMOVED); - bitStream.Write((LWOMAPID)Game::server->GetZoneID()); - bitStream.Write((LWOINSTANCEID)instanceID); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::PLAYER_REMOVED); + bitStream.Write<LWOMAPID>(Game::server->GetZoneID()); + bitStream.Write<LWOINSTANCEID>(instanceID); Game::server->SendToMaster(bitStream); } if (packet->data[0] != ID_USER_PACKET_ENUM || packet->length < 4) return; if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) { - if (static_cast<eServerMessageType>(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) { + if (static_cast<MessageType::Server>(packet->data[3]) == MessageType::Server::VERSION_CONFIRM) { AuthPackets::HandleHandshake(Game::server, packet); } } if (static_cast<eConnectionType>(packet->data[1]) != eConnectionType::WORLD) return; - switch (static_cast<eWorldMessageType>(packet->data[3])) { - case eWorldMessageType::VALIDATION: { + switch (static_cast<MessageType::World>(packet->data[3])) { + case MessageType::World::VALIDATION: { CINSTREAM_SKIP_HEADER; LUWString username; inStream.Read(username); @@ -893,7 +898,7 @@ void HandlePacket(Packet* packet) { //Request the session info from Master: CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_SESSION_KEY); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::REQUEST_SESSION_KEY); bitStream.Write(username); Game::server->SendToMaster(bitStream); @@ -906,7 +911,7 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::CHARACTER_LIST_REQUEST: { + case MessageType::World::CHARACTER_LIST_REQUEST: { //We need to delete the entity first, otherwise the char list could delete it while it exists in the world! if (Game::server->GetZoneID() != 0) { auto user = UserManager::Instance()->GetUser(packet->systemAddress); @@ -928,12 +933,12 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::GAME_MSG: { + case MessageType::World::GAME_MSG: { RakNet::BitStream bitStream(packet->data, packet->length, false); uint64_t header; LWOOBJID objectID; - eGameMessageType messageID; + MessageType::Game messageID; bitStream.Read(header); bitStream.Read(objectID); @@ -954,12 +959,12 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::CHARACTER_CREATE_REQUEST: { + case MessageType::World::CHARACTER_CREATE_REQUEST: { UserManager::Instance()->CreateCharacter(packet->systemAddress, packet); break; } - case eWorldMessageType::LOGIN_REQUEST: { + case MessageType::World::LOGIN_REQUEST: { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); @@ -986,7 +991,7 @@ void HandlePacket(Packet* packet) { // This means we swapped characters and we need to remove the previous player from the container. if (static_cast<uint32_t>(lastCharacter) != playerID) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::UNEXPECTED_DISCONNECT); bitStream.Write(lastCharacter); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } @@ -996,18 +1001,17 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::CHARACTER_DELETE_REQUEST: { + case MessageType::World::CHARACTER_DELETE_REQUEST: { UserManager::Instance()->DeleteCharacter(packet->systemAddress, packet); - UserManager::Instance()->RequestCharacterList(packet->systemAddress); break; } - case eWorldMessageType::CHARACTER_RENAME_REQUEST: { + case MessageType::World::CHARACTER_RENAME_REQUEST: { UserManager::Instance()->RenameCharacter(packet->systemAddress, packet); break; } - case eWorldMessageType::LEVEL_LOAD_COMPLETE: { + case MessageType::World::LEVEL_LOAD_COMPLETE: { LOG("Received level load complete from user."); User* user = UserManager::Instance()->GetUser(packet->systemAddress); if (user) { @@ -1040,7 +1044,9 @@ void HandlePacket(Packet* packet) { // Do charxml fixes here auto* levelComponent = player->GetComponent<LevelProgressionComponent>(); - if (!levelComponent) return; + auto* const inventoryComponent = player->GetComponent<InventoryComponent>(); + const auto* const missionComponent = player->GetComponent<MissionComponent>(); + if (!levelComponent || !missionComponent || !inventoryComponent) return; auto version = levelComponent->GetCharacterVersion(); switch (version) { @@ -1057,7 +1063,23 @@ void HandlePacket(Packet* packet) { case eCharacterVersion::VAULT_SIZE: LOG("Updaing Speedbase"); levelComponent->SetRetroactiveBaseSpeed(); + levelComponent->SetCharacterVersion(eCharacterVersion::SPEED_BASE); + case eCharacterVersion::SPEED_BASE: { + LOG("Removing lots from NJ Jay missions bugged at foss"); + // https://explorer.lu/missions/1789 + const auto* mission = missionComponent->GetMission(1789); + if (mission && mission->IsComplete()) { + inventoryComponent->RemoveItem(14474, 1, eInventoryType::ITEMS); + inventoryComponent->RemoveItem(14474, 1, eInventoryType::VAULT_ITEMS); + } + // https://explorer.lu/missions/1927 + mission = missionComponent->GetMission(1927); + if (mission && mission->IsComplete()) { + inventoryComponent->RemoveItem(14493, 1, eInventoryType::ITEMS); + inventoryComponent->RemoveItem(14493, 1, eInventoryType::VAULT_ITEMS); + } levelComponent->SetCharacterVersion(eCharacterVersion::UP_TO_DATE); + } case eCharacterVersion::UP_TO_DATE: break; } @@ -1100,7 +1122,7 @@ void HandlePacket(Packet* packet) { GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT); CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, MessageType::Client::BLUEPRINT_SAVE_RESPONSE); bitStream.Write<LWOOBJID>(LWOOBJID_EMPTY); //always zero so that a check on the client passes bitStream.Write(eBlueprintSaveResponseType::EverythingWorked); bitStream.Write<uint32_t>(1); @@ -1132,7 +1154,7 @@ void HandlePacket(Packet* packet) { const auto& playerName = character->GetName(); CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, MessageType::Chat::LOGIN_SESSION_NOTIFY); bitStream.Write(player->GetObjectID()); bitStream.Write<uint32_t>(playerName.size()); for (size_t i = 0; i < playerName.size(); i++) { @@ -1158,7 +1180,7 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::POSITION_UPDATE: { + case MessageType::World::POSITION_UPDATE: { auto positionUpdate = ClientPackets::HandleClientPositionUpdate(packet); User* user = UserManager::Instance()->GetUser(packet->systemAddress); @@ -1172,7 +1194,7 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::MAIL: { + case MessageType::World::MAIL: { RakNet::BitStream bitStream(packet->data, packet->length, false); // FIXME: Change this to the macro to skip the header... LWOOBJID space; @@ -1181,7 +1203,7 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::ROUTE_PACKET: { + case MessageType::World::ROUTE_PACKET: { //Yeet to chat CINSTREAM_SKIP_HEADER; uint32_t size = 0; @@ -1207,15 +1229,15 @@ void HandlePacket(Packet* packet) { //Now write the rest of the data: auto data = inStream.GetData(); - for (uint32_t i = 0; i < size; ++i) { - bitStream.Write(data[i + 23]); + for (uint32_t i = 23; i - 23 < size && i < packet->length; ++i) { + bitStream.Write(data[i]); } Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, Game::chatSysAddr, false); break; } - case eWorldMessageType::STRING_CHECK: { + case MessageType::World::STRING_CHECK: { auto request = ClientPackets::HandleChatModerationRequest(packet); // TODO: Find a good home for the logic in this case. @@ -1287,7 +1309,7 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::GENERAL_CHAT_MESSAGE: { + case MessageType::World::GENERAL_CHAT_MESSAGE: { if (chatDisabled) { ChatPackets::SendMessageFail(packet->systemAddress); } else { @@ -1319,7 +1341,7 @@ void HandlePacket(Packet* packet) { break; } - case eWorldMessageType::HANDLE_FUNNESS: { + case MessageType::World::HANDLE_FUNNESS: { //This means the client is running slower or faster than it should. //Could be insane lag, but I'mma just YEET them as it's usually speedhacking. //This is updated to now count the amount of times we've been caught "speedhacking" to kick with a delay @@ -1338,7 +1360,7 @@ void HandlePacket(Packet* packet) { } - case eWorldMessageType::UI_HELP_TOP_5: { + case MessageType::World::UI_HELP_TOP_5: { auto language = ClientPackets::SendTop5HelpIssues(packet); // TODO: Handle different languages in a nice way // 0: en_US @@ -1374,7 +1396,7 @@ void HandlePacket(Packet* packet) { } default: - const auto messageId = *reinterpret_cast<eWorldMessageType*>(&packet->data[3]); + const auto messageId = *reinterpret_cast<MessageType::World*>(&packet->data[3]); const std::string_view messageIdString = StringifiedEnum::ToString(messageId); LOG("Unknown world packet received: %4i, %s", messageId, messageIdString.data()); } @@ -1460,6 +1482,6 @@ void FinalizeShutdown() { void SendShutdownMessageToMaster() { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN_RESPONSE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, MessageType::Master::SHUTDOWN_RESPONSE); Game::server->SendToMaster(bitStream); } diff --git a/dZoneManager/CMakeLists.txt b/dZoneManager/CMakeLists.txt index e73823678..544a01d9e 100644 --- a/dZoneManager/CMakeLists.txt +++ b/dZoneManager/CMakeLists.txt @@ -3,7 +3,20 @@ set(DZONEMANAGER_SOURCES "dZoneManager.cpp" "Spawner.cpp" "Zone.cpp") -add_library(dZoneManager STATIC ${DZONEMANAGER_SOURCES}) +add_library(dZoneManager OBJECT ${DZONEMANAGER_SOURCES}) target_link_libraries(dZoneManager - PUBLIC dPhysics - INTERFACE dWorldServer) + PRIVATE dDatabaseCDClient + PUBLIC dPhysics) + +#set_property(TARGET dZoneManager APPEND PROPERTY INTERFACE_LINK_LIBRARIES dWorldServer) + +target_include_directories(dZoneManager PUBLIC "." + "${PROJECT_SOURCE_DIR}/dGame" # Entity.h + "${PROJECT_SOURCE_DIR}/dGame/dEntity" # EntityInfo.h + PRIVATE + "${PROJECT_SOURCE_DIR}/dGame/dComponents" #InventoryComponent.h + "${PROJECT_SOURCE_DIR}/dGame/dInventory" #InventoryComponent.h (transitive) + "${PROJECT_SOURCE_DIR}/dGame/dBehaviors" #BehaviorSlot.h + "${PROJECT_SOURCE_DIR}/dGame/dGameMessages" #GameMessages.h + "${PROJECT_SOURCE_DIR}/dGame/dUtilities" #VanityUtilities.h +) diff --git a/dZoneManager/Zone.cpp b/dZoneManager/Zone.cpp index 42ce12152..44532fc9d 100644 --- a/dZoneManager/Zone.cpp +++ b/dZoneManager/Zone.cpp @@ -17,6 +17,7 @@ #include "eTriggerCommandType.h" #include "eTriggerEventType.h" +#include "eWaypointCommandType.h" #include "dNavMesh.h" Zone::Zone(const LWOMAPID& mapID, const LWOINSTANCEID& instanceID, const LWOCLONEID& cloneID) : @@ -419,7 +420,7 @@ void Zone::LoadPath(std::istream& file) { if (path.pathType == PathType::MovingPlatform) { BinaryIO::BinaryRead(file, waypoint.movingPlatform.lockPlayer); - BinaryIO::BinaryRead(file, waypoint.movingPlatform.speed); + BinaryIO::BinaryRead(file, waypoint.speed); BinaryIO::BinaryRead(file, waypoint.movingPlatform.wait); if (path.pathVersion >= 13) { BinaryIO::ReadString<uint8_t>(file, waypoint.movingPlatform.departSound, BinaryIO::ReadType::WideString); @@ -438,7 +439,7 @@ void Zone::LoadPath(std::istream& file) { BinaryIO::BinaryRead(file, waypoint.racing.planeHeight); BinaryIO::BinaryRead(file, waypoint.racing.shortestDistanceToEnd); } else if (path.pathType == PathType::Rail) { - if (path.pathVersion > 16) BinaryIO::BinaryRead(file, waypoint.rail.speed); + if (path.pathVersion > 16) BinaryIO::BinaryRead(file, waypoint.speed); } // object LDF configs @@ -452,15 +453,23 @@ void Zone::LoadPath(std::istream& file) { std::string value; BinaryIO::ReadString<uint8_t>(file, value, BinaryIO::ReadType::WideString); - LDFBaseData* ldfConfig = nullptr; if (path.pathType == PathType::Movement || path.pathType == PathType::Rail) { - ldfConfig = LDFBaseData::DataFromString(parameter + "=0:" + value); + // cause NetDevil puts spaces in things that don't need spaces + parameter.erase(std::remove_if(parameter.begin(), parameter.end(), ::isspace), parameter.end()); + auto waypointCommand = WaypointCommandType::StringToWaypointCommandType(parameter); + if (waypointCommand == eWaypointCommandType::DELAY) value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end()); + if (waypointCommand != eWaypointCommandType::INVALID) { + auto& command = waypoint.commands.emplace_back(); + command.command = waypointCommand; + command.data = value; + } else LOG("Tried to load invalid waypoint command '%s'", parameter.c_str()); } else { - ldfConfig = LDFBaseData::DataFromString(parameter + "=" + value); + waypoint.config.emplace_back(LDFBaseData::DataFromString(parameter + "=" + value)); } - if (ldfConfig) waypoint.config.push_back(ldfConfig); + } } + // We verify the waypoint heights against the navmesh because in many movement paths, // the waypoint is located near 0 height, if (path.pathType == PathType::Movement) { diff --git a/dZoneManager/Zone.h b/dZoneManager/Zone.h index a62a81edc..299d675b0 100644 --- a/dZoneManager/Zone.h +++ b/dZoneManager/Zone.h @@ -13,57 +13,60 @@ namespace LUTriggers { class Level; +enum class eWaypointCommandType : uint32_t; + +struct WaypointCommand { + eWaypointCommandType command{}; + std::string data; +}; + + struct SceneRef { std::string filename; - uint32_t id; - uint32_t sceneType; //0 = general, 1 = audio? + uint32_t id{}; + uint32_t sceneType{}; //0 = general, 1 = audio? std::string name; NiPoint3 unknown1; - float unknown2; - uint8_t color_r; - uint8_t color_g; - uint8_t color_b; + float unknown2{}; + uint8_t color_r{}; + uint8_t color_g{}; + uint8_t color_b{}; Level* level; std::map<uint32_t, LUTriggers::Trigger*> triggers; }; struct SceneTransitionInfo { - uint64_t sceneID; //id of the scene being transitioned to. + uint64_t sceneID{}; //id of the scene being transitioned to. NiPoint3 position; }; struct SceneTransition { std::string name; std::vector<SceneTransitionInfo> points; - float width; + float width{}; }; struct MovingPlatformPathWaypoint { - uint8_t lockPlayer; - float speed; - float wait; + uint8_t lockPlayer{}; + float wait{}; std::string departSound; std::string arriveSound; }; struct CameraPathWaypoint { - float time; - float fov; - float tension; - float continuity; - float bias; + float time{}; + float fov{}; + float tension{}; + float continuity{}; + float bias{}; }; struct RacingPathWaypoint { - uint8_t isResetNode; - uint8_t isNonHorizontalCamera; - float planeWidth; - float planeHeight; - float shortestDistanceToEnd; -}; - -struct RailPathWaypoint { - float speed; + uint8_t isResetNode{}; + uint8_t isNonHorizontalCamera{}; + float planeWidth{}; + float planeHeight{}; + float shortestDistanceToEnd{}; }; struct PathWaypoint { @@ -72,8 +75,9 @@ struct PathWaypoint { MovingPlatformPathWaypoint movingPlatform; CameraPathWaypoint camera; RacingPathWaypoint racing; - RailPathWaypoint rail; + float speed{}; std::vector<LDFBaseData*> config; + std::vector<WaypointCommand> commands; }; enum class PathType : uint32_t { @@ -133,49 +137,49 @@ enum class PropertyAchievmentRequired : uint32_t { struct MovingPlatformPath { std::string platformTravelSound; - uint8_t timeBasedMovement; + uint8_t timeBasedMovement{}; }; struct PropertyPath { - PropertyPathType pathType; - int32_t price; - uint32_t rentalTime; - uint64_t associatedZone; + PropertyPathType pathType{}; + int32_t price{}; + uint32_t rentalTime{}; + uint64_t associatedZone{}; std::string displayName; std::string displayDesc; - PropertyType type; - uint32_t cloneLimit; - float repMultiplier; - PropertyRentalPeriod rentalPeriod; - PropertyAchievmentRequired achievementRequired; + PropertyType type{}; + uint32_t cloneLimit{}; + float repMultiplier{}; + PropertyRentalPeriod rentalPeriod{}; + PropertyAchievmentRequired achievementRequired{}; // Player respawn coordinates in the main zone (not the property zone) NiPoint3 playerZoneCoords; - float maxBuildHeight; + float maxBuildHeight{}; }; struct CameraPath { std::string nextPath; - uint8_t rotatePlayer; + uint8_t rotatePlayer{}; }; struct SpawnerPath { - LOT spawnedLOT; - uint32_t respawnTime; - int32_t maxToSpawn; - uint32_t amountMaintained; + LOT spawnedLOT{}; + uint32_t respawnTime{}; + int32_t maxToSpawn{}; + uint32_t amountMaintained{}; LWOOBJID spawnerObjID; - uint8_t spawnerNetActive; + uint8_t spawnerNetActive{}; }; struct Path { - uint32_t pathVersion; + uint32_t pathVersion{}; PathType pathType; std::string pathName; - uint32_t flags; + uint32_t flags{}; PathBehavior pathBehavior; - uint32_t waypointCount; + uint32_t waypointCount{}; std::vector<PathWaypoint> pathWaypoints; SpawnerPath spawner; MovingPlatformPath movingPlatform; diff --git a/docker-compose.yml b/docker-compose.yml index a79547184..8f5a3d09c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: - darkflame image: mariadb:latest volumes: - - ${DB_DATA_DIR:-./db/data}:/var/lib/mysql + - ${DB_DATA_DIR:-db-data}:/var/lib/mysql environment: - MARIADB_RANDOM_ROOT_PASSWORD=1 - MARIADB_USER=${MARIADB_USER:-darkflame} @@ -79,3 +79,6 @@ services: networks: darkflame: + +volumes: + db-data: diff --git a/docs/Vanity.md b/docs/Vanity.md new file mode 100644 index 000000000..ac2c42630 --- /dev/null +++ b/docs/Vanity.md @@ -0,0 +1,170 @@ +# DLU Vanity System + +Darkflame Universe Vanity System is a method of defined objects to be spawned serverside and communicated to the client without modifying the game's assets. + +You can check out the different `xml` files in `vanity/` and use `vanity/demo.xml` to follow along with this tutorial and documentation of thew various features, cabapilities, and limitations of this system. + +## `vanity/root.xml` +`root.xml` is the only file the server will load in by default. + +To load other files, you can do so like this: +```xml +<files> + <file name="dev-tribute.xml" enabled="1"/> + <file name="atm.xml" enabled="0"/> + <file name="demo.xml" enabled="0"/> +</files> +``` + +`name` is the name of the file relative to the vanity folder. +Ex: you have a folder like `vanity/events/` with a file called `halloween.xml` in it, you will include it as such: + +`<file name="events/halloween.xml" enabled="1"/>` + +`enabled` tells if that file should be loaded. +files will only be loaded in, if `enabled="1"` + +There cannot be multiple `<files></files>` per xml file, only the first one will be read, but you can have as many `<files/>` in it as you wish. + +## `vanity/demo.xml` + +This demo file covers most of the features of defining objects to spawn server side and will go over them one by one. + +The minimun data needed to define and ojbect to spawn is as follows: +```xml +<objects> + <object lot="1"> + <locations> + <location zone="1200" x="0" y="0" z="0" rw="0" rx="0" ry="0" rz="0" /> + </locations> + </object> +</objects> +``` + + * `lot` the LEGO Object Template to be spawned + + * `<location/>` must have `zone`, `x`, `y`, `z` `rw`, `rx`, `ry`, and `rz` and one `location` must in exist in `locations` for it to be spawned + +Everything else is is optional. + +* LEGO Name Value (LNV) configs can control almost all functionality of the objects in the game, they are defined like `name=type:value`. types can be found in `dCommon/LDFFromat.h` + +```xml +<config> + <key>bool=7:1</key> +</config> +``` + +### Story Plaque with custom text + +lot 8193 is the story plaque that is used in game to give the game lore to the player. + +DLU Vanity has the capability to provide custom text to it via a LNV config + +From `demo.xml` +```xml + <object lot="8139"> + <config> + <key>customText=13:This story plaque has custom text that is defined by DLU's vanity system. Check out <font color="#000000" >vanity/demo.xml</font> to see how this works!</key> + </config> + <locations> + <location zone="1200" x="-26.281" y="288.896" z="-77.484" rw="0.997534" rx="0.00" ry="-0.070190" rz="0.00" /> + </locations> + </object> +``` + + * The `customText` config must be a type of `13` (wstring) + * HTML like formatting can be used for font color, but `<` must be reaplaced withh `>`, and `>` replaced with `<` + +### Object with multiple locations and scale + +```xml + <object lot="3248"> + <locations> + <location zone="1200" x="-15.0" y="288.8" z="-167.0" rw="0.984321" rx="0.00" ry="0.176388" rz="0.00" /> + <location zone="1200" x="15.0" y="288.8" z="-158.0" rw="0.724628" rx="0.00" ry="-0.689141" rz="0.00" scale="0.30" /> + </locations> + </object> +``` +#### Multiple locations +Multiple location elements can be defined for an object. +For every location that object will spawn: +This will spawn two trees, one at each specified location. + +#### Scale +Each location can specify a `scale` which defaults to `1`. The object will be scaled by this attribute in the location when defined. + +### Object with multiple random locations and chance + +```xml + <object lot="10141"> + <config> + <key>useLocationsAsRandomSpawnPoint=7:1</key> + </config> + <locations> + <location zone="1200" x="31.819" y="288.896" z="-117.095" rw="0.630659" rx="0.00" ry="-0.776060" rz="0.00" chance="0.50"/> + <location zone="1200" x="42.755" y="291.897" z="-144.385" rw="0.855306" rx="0.00" ry="-0.518124" rz="0.00" chance="0.50"/> + <location zone="1200" x="3.984" y="288.896" z="-165.947" rw="0.978508" rx="0.00" ry="-0.206210" rz="0.00" chance="0.50"/> + </locations> + </object> +``` +#### Random Spawn Point +If the LNV config `useLocationsAsRandomSpawnPoint=7:1` is defined and is set to `1`, instead of spawning the object at every location, it will randomly choose between all locations in the current zone to spawn one instance of the object. +If a location is not in the current zone, it will not be considered. + +#### Chance +Each location can specify a `chance` attribute. This defines a chance from, `0` to `1` that the object will spawn, with `0` being never spawn, and `1` being always spawn. A `chance="0.8"` will have an 80% chance for the object to spawn at that location. + +`useLocationsAsRandomSpawnPoint` and `chance` are independent of each other and be used separately + +### Custom vendor with custom name and gear + +```xml + <object name="Demo Fella - GM Items Vendor" lot="1867"> + <equipment>7630, 1727, 7453, 7521</equipment> + <config> + <key>vendorInvOverride=0:1727,7292,16553,2243,14535,14538,14531,6730</key> + </config> + <locations> + <location zone="1200" x="35.935" y="288.896" z="-128.213" rw="0.882977" rx="0.00" ry="-0.469416" rz="0.00" /> + </locations> + </object> +``` +#### Custom vendor + +For a custom vendor to work, you must use a LOT that already has a vendor compoenet attached to it. + +Without an LNV keys, it will give it's normal inventory +You muse define `vendorInvOverride=0:` and then a list of LOTs that the vendor will sell. This will override all items the vendor was selling and use the list of LOTs provided. + +LOTs must have an item component in order to be sold by a vendor. + +#### Custom Name + +The `name` attribute will give or override the name displayed for an object, if it displays one. +Using a ` - ` will allow you to define a title that will display under their name on their nametag (formally called a billboard). + +#### Custom Gear + +The `equipment` element is a lis of comma separated lots that will defind the geat an object will attempt to equip. + +LOTs must have an inventory component in order to equipe custom gear. + +### Creating Spawners +```xml + <object lot="176"> + <config> + ... + <key>spawntemplate=1:2295</key> + ... + </config> + <locations> + <location zone="1200" x="4.232" y="288.895" z="-85.846" rw="-0.205988" rx="0.00" ry="0.978555" rz="0.00" /> + </locations> + </object> +</objects> +``` + +LOT `167` is a spawner. The spawner config in the `demo.xml` was copied from an existing object via lcdr's luzviewer. + +The main config to care about is `spawntemplate` as that controls what the spawner spawns. diff --git a/migrations/dlu/15_behavior_owner.sql b/migrations/dlu/15_behavior_owner.sql new file mode 100644 index 000000000..53e76f82f --- /dev/null +++ b/migrations/dlu/15_behavior_owner.sql @@ -0,0 +1,3 @@ +ALTER TABLE behaviors ADD COLUMN character_id BIGINT NOT NULL DEFAULT 0; +ALTER TABLE behaviors ADD COLUMN behavior_id BIGINT NOT NULL PRIMARY KEY; +ALTER TABLE behaviors DROP COLUMN id; diff --git a/migrations/dlu/16_big_behaviors.sql b/migrations/dlu/16_big_behaviors.sql new file mode 100644 index 000000000..12edc0bc8 --- /dev/null +++ b/migrations/dlu/16_big_behaviors.sql @@ -0,0 +1 @@ +ALTER TABLE behaviors MODIFY behavior_info LONGTEXT DEFAULT NULL; diff --git a/migrations/dlu/9_Update_Leaderboard_Storage.sql b/migrations/dlu/9_Update_Leaderboard_Storage.sql index c87e3501f..9b5098ebd 100644 --- a/migrations/dlu/9_Update_Leaderboard_Storage.sql +++ b/migrations/dlu/9_Update_Leaderboard_Storage.sql @@ -11,7 +11,7 @@ ALTER TABLE leaderboard CHANGE time secondaryScore FLOAT NOT NULL DEFAULT 0 AFTE /* A bit messy, but better than going through a bunch of code fixes all to be run once. */ UPDATE leaderboard SET primaryScore = secondaryScore, - secondaryScore = 0 WHERE game_id IN (1, 44, 46, 47, 48, 49, 53, 103, 104, 108, 1901); + secondaryScore = 0 WHERE game_id IN (1, 44, 46, 47, 48, 49, 53, 103, 104, 108, 1901) AND secondaryScore > 0; /* Do this last so we dont update entry times erroneously */ ALTER TABLE leaderboard diff --git a/resources/blacklist.dcf b/resources/blocklist.dcf similarity index 100% rename from resources/blacklist.dcf rename to resources/blocklist.dcf diff --git a/resources/navmeshes.zip b/resources/navmeshes.zip index 95948656e..cfa6539b0 100644 Binary files a/resources/navmeshes.zip and b/resources/navmeshes.zip differ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ba75a2f1..24adec61d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,20 +1,17 @@ -message (STATUS "Testing is enabled. Fetching gtest...") +message (STATUS "Testing is enabled.") enable_testing() -include(FetchContent) -FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG release-1.12.1 -) - -# For Windows: Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) - -FetchContent_MakeAvailable(GoogleTest) +find_package(GoogleTest REQUIRED) include(GoogleTest) -message(STATUS "gtest fetched and is now ready.") +if(APPLE) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH True) + set(CMAKE_BUILD_WITH_INSTALL_RPATH True) + set(CMAKE_INSTALL_RPATH "@executable_path") +endif() + +add_custom_target(conncpp_tests + ${CMAKE_COMMAND} -E copy $<TARGET_FILE:MariaDB::ConnCpp> ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) # Add the subdirectories add_subdirectory(dCommonTests) diff --git a/tests/dCommonTests/AMFDeserializeTests.cpp b/tests/dCommonTests/AMFDeserializeTests.cpp index fb1946c5d..0a8c0ac76 100644 --- a/tests/dCommonTests/AMFDeserializeTests.cpp +++ b/tests/dCommonTests/AMFDeserializeTests.cpp @@ -175,7 +175,7 @@ TEST(dCommonTests, AMFDeserializeAMFArrayTest) { /** * @brief This test checks that if we recieve an unimplemented eAmf * we correctly throw an error and can actch it. - * Yes this leaks memory. + * Yes this leaks memory. */ TEST(dCommonTests, AMFDeserializeUnimplementedValuesTest) { std::vector<eAmf> unimplementedValues = { @@ -362,7 +362,7 @@ TEST(dCommonTests, AMFBadConversionTest) { ASSERT_EQ(result->Get<double>("BehaviorID"), nullptr); // Does not exist in the associative portion - ASSERT_EQ(result->Get<nullptr_t>("DOES_NOT_EXIST"), nullptr); + ASSERT_EQ(result->Get<std::nullptr_t>("DOES_NOT_EXIST"), nullptr); result->Push(true); diff --git a/tests/dCommonTests/Amf3Tests.cpp b/tests/dCommonTests/Amf3Tests.cpp index 5b52cf277..79d0d496d 100644 --- a/tests/dCommonTests/Amf3Tests.cpp +++ b/tests/dCommonTests/Amf3Tests.cpp @@ -78,7 +78,7 @@ TEST(dCommonTests, AMF3InsertionAssociativeTest) { ASSERT_EQ(array.Get<int32_t>("Integer")->GetValueType(), eAmf::Integer); ASSERT_EQ(array.Get<double>("Double")->GetValueType(), eAmf::Double); ASSERT_EQ(array.GetArray("Array")->GetValueType(), eAmf::Array); - ASSERT_EQ(array.Get<nullptr_t>("Null")->GetValueType(), eAmf::Null); + ASSERT_EQ(array.Get<std::nullptr_t>("Null")->GetValueType(), eAmf::Null); ASSERT_EQ(array.Get<std::vector<uint32_t>>("Undefined")->GetValueType(), eAmf::Undefined); } @@ -101,6 +101,6 @@ TEST(dCommonTests, AMF3InsertionDenseTest) { ASSERT_EQ(array.Get<int32_t>(4)->GetValueType(), eAmf::Integer); ASSERT_EQ(array.Get<double>(5)->GetValueType(), eAmf::Double); ASSERT_EQ(array.GetArray(6)->GetValueType(), eAmf::Array); - ASSERT_EQ(array.Get<nullptr_t>(7)->GetValueType(), eAmf::Null); + ASSERT_EQ(array.Get<std::nullptr_t>(7)->GetValueType(), eAmf::Null); ASSERT_EQ(array.Get<std::vector<uint32_t>>(8)->GetValueType(), eAmf::Undefined); } diff --git a/tests/dCommonTests/CMakeLists.txt b/tests/dCommonTests/CMakeLists.txt index be23d8665..ef7c4cba9 100644 --- a/tests/dCommonTests/CMakeLists.txt +++ b/tests/dCommonTests/CMakeLists.txt @@ -1,7 +1,7 @@ set(DCOMMONTEST_SOURCES "AMFDeserializeTests.cpp" "Amf3Tests.cpp" - "CastUnderlyingTypeTests.cpp" + "ToUnderlyingTests.cpp" "HeaderSkipTest.cpp" "TestCDFeatureGatingTable.cpp" "TestLDFFormat.cpp" @@ -17,6 +17,19 @@ list(APPEND DCOMMONTEST_SOURCES ${DENUMS_TESTS}) # Set our executable add_executable(dCommonTests ${DCOMMONTEST_SOURCES}) +add_dependencies(dCommonTests conncpp_tests) + +# Apple needs some special linkage for the mariadb connector for tests. +if(APPLE) +add_custom_command(TARGET dCommonTests POST_BUILD + COMMAND otool ARGS -l dCommonTests + COMMAND otool ARGS -L dCommonTests + COMMAND ls + COMMAND otool ARGS -D libmariadbcpp.dylib + COMMAND install_name_tool ARGS -change libmariadbcpp.dylib @rpath/libmariadbcpp.dylib dCommonTests + COMMAND otool ARGS -L dCommonTests + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() # Link needed libraries target_link_libraries(dCommonTests ${COMMON_LIBRARIES} GTest::gtest_main) diff --git a/tests/dCommonTests/CastUnderlyingTypeTests.cpp b/tests/dCommonTests/CastUnderlyingTypeTests.cpp deleted file mode 100644 index 9cdfcdd3d..000000000 --- a/tests/dCommonTests/CastUnderlyingTypeTests.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include <gtest/gtest.h> - -#include "GeneralUtils.h" - -#include "eGameMasterLevel.h" -#include "eGameMessageType.h" -#include "eWorldMessageType.h" - -#define ASSERT_TYPE_EQ(TYPE, ENUM)\ - ASSERT_TRUE(typeid(TYPE) == typeid(GeneralUtils::CastUnderlyingType(static_cast<ENUM>(0)))); - -#define ASSERT_TYPE_NE(TYPE, ENUM)\ - ASSERT_FALSE(typeid(TYPE) == typeid(GeneralUtils::CastUnderlyingType(static_cast<ENUM>(0)))); - -// Verify that the underlying enum types are being cast correctly -TEST(CastUnderlyingTypeTests, VerifyCastUnderlyingType) { - ASSERT_TYPE_EQ(uint8_t, eGameMasterLevel); - ASSERT_TYPE_EQ(uint16_t, eGameMessageType); - ASSERT_TYPE_EQ(uint32_t, eWorldMessageType) - - ASSERT_TYPE_NE(void, eGameMasterLevel); - ASSERT_TYPE_NE(void, eGameMessageType); - ASSERT_TYPE_NE(void, eWorldMessageType) -} diff --git a/tests/dCommonTests/TestEncoding.cpp b/tests/dCommonTests/TestEncoding.cpp index 54ae03d3f..0286d2840 100644 --- a/tests/dCommonTests/TestEncoding.cpp +++ b/tests/dCommonTests/TestEncoding.cpp @@ -15,12 +15,12 @@ TEST_F(EncodingTest, TestEncodingHello) { originalWord = "Hello World!"; originalWordSv = originalWord; - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'H'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'e'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'o'); - EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), true); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'H'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'e'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'o'); + EXPECT_EQ(GeneralUtils::details::_NextUTF8Char(originalWordSv, out), true); EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Hello World!"), u"Hello World!"); }; @@ -29,15 +29,15 @@ TEST_F(EncodingTest, TestEncodingUmlaut) { originalWord = reinterpret_cast<const char*>(u8"Frühling"); originalWordSv = originalWord; - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'F'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'r'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'ü'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'h'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'l'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'i'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'n'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'g'); - EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'F'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'r'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'ü'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'h'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'l'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'i'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'n'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'g'); + EXPECT_EQ(GeneralUtils::details::_NextUTF8Char(originalWordSv, out), false); EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Frühling"), u"Frühling"); }; @@ -46,10 +46,10 @@ TEST_F(EncodingTest, TestEncodingChinese) { originalWord = "中文字"; originalWordSv = originalWord; - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'中'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'文'); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'字'); - EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'中'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'文'); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'字'); + EXPECT_EQ(GeneralUtils::details::_NextUTF8Char(originalWordSv, out), false); EXPECT_EQ(GeneralUtils::UTF8ToUTF16("中文字"), u"中文字"); }; @@ -58,11 +58,11 @@ TEST_F(EncodingTest, TestEncodingEmoji) { originalWord = "👨‍⚖️"; originalWordSv = originalWord; - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x1F468); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x200D); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x2696); - GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0xFE0F); - EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x1F468); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x200D); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x2696); + GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0xFE0F); + EXPECT_EQ(GeneralUtils::details::_NextUTF8Char(originalWordSv, out), false); EXPECT_EQ(GeneralUtils::UTF8ToUTF16("👨‍⚖️"), u"👨‍⚖️"); }; diff --git a/tests/dCommonTests/TestLDFFormat.cpp b/tests/dCommonTests/TestLDFFormat.cpp index 7baa5a0b2..b761096c1 100644 --- a/tests/dCommonTests/TestLDFFormat.cpp +++ b/tests/dCommonTests/TestLDFFormat.cpp @@ -27,7 +27,7 @@ TEST_F(LDFTests, LDFUTF16Test) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<std::u16string>*)data.get())->GetValue(), u"IAmA weird string with :::: and spac,./;'][\\es that I expect to be parsed correctly...; "); + ASSERT_EQ((static_cast<LDFData<std::u16string>*>(data.get()))->GetValue(), u"IAmA weird string with :::: and spac,./;'][\\es that I expect to be parsed correctly...; "); ASSERT_EQ(data->GetString(), testWord); } @@ -37,7 +37,7 @@ TEST_F(LDFTests, LDFUTF16EmptyTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<std::u16string>*)data.get())->GetValue(), u""); + ASSERT_EQ(static_cast<LDFData<std::u16string>*>(data.get())->GetValue(), u""); ASSERT_EQ(data->GetString(), testWord); } @@ -47,7 +47,7 @@ TEST_F(LDFTests, LDFUTF16ColonTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<std::u16string>*)data.get())->GetValue(), u"::"); + ASSERT_EQ(static_cast<LDFData<std::u16string>*>(data.get())->GetValue(), u"::"); ASSERT_EQ(data->GetString(), testWord); } @@ -57,7 +57,7 @@ TEST_F(LDFTests, LDFUTF16EqualsTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_16); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<std::u16string>*)data.get())->GetValue(), u"=="); + ASSERT_EQ(static_cast<LDFData<std::u16string>*>(data.get())->GetValue(), u"=="); ASSERT_EQ(data->GetString(), testWord); } @@ -66,7 +66,7 @@ TEST_F(LDFTests, LDFS32Test) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_S32); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<int32_t>*)data.get())->GetValue(), -15); + ASSERT_EQ(static_cast<LDFData<int32_t>*>(data.get())->GetValue(), -15); ASSERT_EQ(data->GetString(), "KEY=1:-15"); } TEST_F(LDFTests, LDFU32Test) { @@ -74,7 +74,7 @@ TEST_F(LDFTests, LDFU32Test) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_U32); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<uint32_t>*)data.get())->GetValue(), 15); + ASSERT_EQ(static_cast<LDFData<uint32_t>*>(data.get())->GetValue(), 15); ASSERT_EQ(data->GetString(), "KEY=5:15"); } @@ -83,7 +83,7 @@ TEST_F(LDFTests, LDFU32TrueTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_U32); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<uint32_t>*)data.get())->GetValue(), 1); + ASSERT_EQ(static_cast<LDFData<uint32_t>*>(data.get())->GetValue(), 1); ASSERT_EQ(data->GetString(), "KEY=5:1"); } @@ -92,7 +92,7 @@ TEST_F(LDFTests, LDFU32FalseTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_U32); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<uint32_t>*)data.get())->GetValue(), 0); + ASSERT_EQ(static_cast<LDFData<uint32_t>*>(data.get())->GetValue(), 0); ASSERT_EQ(data->GetString(), "KEY=5:0"); } @@ -103,7 +103,7 @@ TEST_F(LDFTests, LDFFloatTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_FLOAT); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<float>*)data.get())->GetValue(), 15.5f); + ASSERT_EQ(static_cast<LDFData<float>*>(data.get())->GetValue(), 15.5f); ASSERT_EQ(data->GetString().find("KEY=3:15.5"), 0); } @@ -112,7 +112,7 @@ TEST_F(LDFTests, LDFDoubleTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_DOUBLE); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<double>*)data.get())->GetValue(), 15.5); + ASSERT_EQ(static_cast<LDFData<double>*>(data.get())->GetValue(), 15.5); ASSERT_EQ(data->GetString().find("KEY=4:15.5"), 0); } @@ -122,7 +122,7 @@ TEST_F(LDFTests, LDFBoolTrueTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_BOOLEAN); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<bool>*)data.get())->GetValue(), true); + ASSERT_EQ(static_cast<LDFData<bool>*>(data.get())->GetValue(), true); ASSERT_EQ(data->GetString(), "KEY=7:1"); } @@ -131,7 +131,7 @@ TEST_F(LDFTests, LDFBoolFalseTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_BOOLEAN); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<bool>*)data.get())->GetValue(), false); + ASSERT_EQ(static_cast<LDFData<bool>*>(data.get())->GetValue(), false); ASSERT_EQ(data->GetString(), "KEY=7:0"); } @@ -140,7 +140,7 @@ TEST_F(LDFTests, LDFBoolIntTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_BOOLEAN); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<bool>*)data.get())->GetValue(), true); + ASSERT_EQ(static_cast<LDFData<bool>*>(data.get())->GetValue(), true); ASSERT_EQ(data->GetString(), "KEY=7:1"); } @@ -149,7 +149,7 @@ TEST_F(LDFTests, LDFU64Test) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_U64); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<uint64_t>*)data.get())->GetValue(), 15); + ASSERT_EQ(static_cast<LDFData<uint64_t>*>(data.get())->GetValue(), 15); ASSERT_EQ(data->GetString(), "KEY=8:15"); } @@ -158,7 +158,7 @@ TEST_F(LDFTests, LDFLWOOBJIDTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_OBJID); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<uint64_t>*)data.get())->GetValue(), 15); + ASSERT_EQ(static_cast<LDFData<uint64_t>*>(data.get())->GetValue(), 15); ASSERT_EQ(data->GetString(), "KEY=9:15"); } @@ -168,7 +168,7 @@ TEST_F(LDFTests, LDFUTF8Test) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_8); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<std::string>*)data.get())->GetValue(), "IAmA weird string with :::: and spac,./;'][\\es that I expect to be parsed correctly...; "); + ASSERT_EQ(static_cast<LDFData<std::string>*>(data.get())->GetValue(), "IAmA weird string with :::: and spac,./;'][\\es that I expect to be parsed correctly...; "); ASSERT_EQ(data->GetString(), testWord); } @@ -178,7 +178,7 @@ TEST_F(LDFTests, LDFUTF8EmptyTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_8); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<std::string>*)data.get())->GetValue(), ""); + ASSERT_EQ(static_cast<LDFData<std::string>*>(data.get())->GetValue(), ""); ASSERT_EQ(data->GetString(), testWord); } @@ -188,7 +188,7 @@ TEST_F(LDFTests, LDFUTF8ColonsTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_8); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<std::string>*)data.get())->GetValue(), "::"); + ASSERT_EQ(static_cast<LDFData<std::string>*>(data.get())->GetValue(), "::"); ASSERT_EQ(data->GetString(), testWord); } TEST_F(LDFTests, LDFUTF8EqualsTest) { @@ -197,7 +197,7 @@ TEST_F(LDFTests, LDFUTF8EqualsTest) { ASSERT_NE(data, nullptr); ASSERT_EQ(data->GetValueType(), eLDFType::LDF_TYPE_UTF_8); ASSERT_EQ(data->GetKey(), u"KEY"); - ASSERT_EQ(((LDFData<std::string>*)data.get())->GetValue(), "=="); + ASSERT_EQ(static_cast<LDFData<std::string>*>(data.get())->GetValue(), "=="); ASSERT_EQ(data->GetString(), testWord); } diff --git a/tests/dCommonTests/ToUnderlyingTests.cpp b/tests/dCommonTests/ToUnderlyingTests.cpp new file mode 100644 index 000000000..c062ff789 --- /dev/null +++ b/tests/dCommonTests/ToUnderlyingTests.cpp @@ -0,0 +1,24 @@ +#include <gtest/gtest.h> + +#include "GeneralUtils.h" + +#include "eGameMasterLevel.h" +#include "MessageType/Game.h" +#include "MessageType/World.h" + +#define ASSERT_TYPE_EQ(TYPE, ENUM)\ + ASSERT_TRUE(typeid(TYPE) == typeid(GeneralUtils::ToUnderlying(static_cast<ENUM>(0)))); + +#define ASSERT_TYPE_NE(TYPE, ENUM)\ + ASSERT_FALSE(typeid(TYPE) == typeid(GeneralUtils::ToUnderlying(static_cast<ENUM>(0)))); + +// Verify that the underlying enum types are being cast correctly +TEST(ToUnderlyingTests, VerifyToUnderlying) { + ASSERT_TYPE_EQ(uint8_t, eGameMasterLevel); + ASSERT_TYPE_EQ(uint16_t, MessageType::Game); + ASSERT_TYPE_EQ(uint32_t, MessageType::World) + + ASSERT_TYPE_NE(void, eGameMasterLevel); + ASSERT_TYPE_NE(void, MessageType::Game); + ASSERT_TYPE_NE(void, MessageType::World) +} diff --git a/tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp b/tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp index 0ca2e2ea9..fcd517f1f 100644 --- a/tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp +++ b/tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp @@ -6,8 +6,8 @@ #include "StringifiedEnum.h" #include "Logger.h" #include "Game.h" -#include "eGameMessageType.h" -#include "eWorldMessageType.h" +#include "MessageType/Game.h" +#include "MessageType/World.h" #include "magic_enum.hpp" #define ENUM_EQ(e, y, z)\ @@ -21,47 +21,47 @@ TEST(MagicEnumTest, eWorldMessageTypeTest) { Game::logger = new Logger("./MagicEnumTest_eWorldMessageTypeTest.log", true, true); - ENUM_EQ(eWorldMessageType, 1, VALIDATION); - ENUM_EQ(eWorldMessageType, 2, CHARACTER_LIST_REQUEST); - ENUM_EQ(eWorldMessageType, 3, CHARACTER_CREATE_REQUEST); - ENUM_EQ(eWorldMessageType, 4, LOGIN_REQUEST); - ENUM_EQ(eWorldMessageType, 5, GAME_MSG); - ENUM_EQ(eWorldMessageType, 6, CHARACTER_DELETE_REQUEST); - ENUM_EQ(eWorldMessageType, 7, CHARACTER_RENAME_REQUEST); - ENUM_EQ(eWorldMessageType, 8, HAPPY_FLOWER_MODE_NOTIFY); - ENUM_EQ(eWorldMessageType, 9, SLASH_RELOAD_MAP); - ENUM_EQ(eWorldMessageType, 10, SLASH_PUSH_MAP_REQUEST); - ENUM_EQ(eWorldMessageType, 11, SLASH_PUSH_MAP); - ENUM_EQ(eWorldMessageType, 12, SLASH_PULL_MAP); - ENUM_EQ(eWorldMessageType, 13, LOCK_MAP_REQUEST); - ENUM_EQ(eWorldMessageType, 14, GENERAL_CHAT_MESSAGE); - ENUM_EQ(eWorldMessageType, 15, HTTP_MONITOR_INFO_REQUEST); - ENUM_EQ(eWorldMessageType, 16, SLASH_DEBUG_SCRIPTS); - ENUM_EQ(eWorldMessageType, 17, MODELS_CLEAR); - ENUM_EQ(eWorldMessageType, 18, EXHIBIT_INSERT_MODEL); - ENUM_EQ(eWorldMessageType, 19, LEVEL_LOAD_COMPLETE); - ENUM_EQ(eWorldMessageType, 20, TMP_GUILD_CREATE); - ENUM_EQ(eWorldMessageType, 21, ROUTE_PACKET); - ENUM_EQ(eWorldMessageType, 22, POSITION_UPDATE); - ENUM_EQ(eWorldMessageType, 23, MAIL); - ENUM_EQ(eWorldMessageType, 24, WORD_CHECK); - ENUM_EQ(eWorldMessageType, 25, STRING_CHECK); - ENUM_EQ(eWorldMessageType, 26, GET_PLAYERS_IN_ZONE); - ENUM_EQ(eWorldMessageType, 27, REQUEST_UGC_MANIFEST_INFO); - ENUM_EQ(eWorldMessageType, 28, BLUEPRINT_GET_ALL_DATA_REQUEST); - ENUM_EQ(eWorldMessageType, 29, CANCEL_MAP_QUEUE); - ENUM_EQ(eWorldMessageType, 30, HANDLE_FUNNESS); - ENUM_EQ(eWorldMessageType, 31, FAKE_PRG_CSR_MESSAGE); - ENUM_EQ(eWorldMessageType, 32, REQUEST_FREE_TRIAL_REFRESH); - ENUM_EQ(eWorldMessageType, 33, GM_SET_FREE_TRIAL_STATUS); - ENUM_EQ(eWorldMessageType, 91, UI_HELP_TOP_5); - ENUM_NE(eWorldMessageType, 37); - ENUM_NE(eWorldMessageType, 123); + ENUM_EQ(MessageType::World, 1, VALIDATION); + ENUM_EQ(MessageType::World, 2, CHARACTER_LIST_REQUEST); + ENUM_EQ(MessageType::World, 3, CHARACTER_CREATE_REQUEST); + ENUM_EQ(MessageType::World, 4, LOGIN_REQUEST); + ENUM_EQ(MessageType::World, 5, GAME_MSG); + ENUM_EQ(MessageType::World, 6, CHARACTER_DELETE_REQUEST); + ENUM_EQ(MessageType::World, 7, CHARACTER_RENAME_REQUEST); + ENUM_EQ(MessageType::World, 8, HAPPY_FLOWER_MODE_NOTIFY); + ENUM_EQ(MessageType::World, 9, SLASH_RELOAD_MAP); + ENUM_EQ(MessageType::World, 10, SLASH_PUSH_MAP_REQUEST); + ENUM_EQ(MessageType::World, 11, SLASH_PUSH_MAP); + ENUM_EQ(MessageType::World, 12, SLASH_PULL_MAP); + ENUM_EQ(MessageType::World, 13, LOCK_MAP_REQUEST); + ENUM_EQ(MessageType::World, 14, GENERAL_CHAT_MESSAGE); + ENUM_EQ(MessageType::World, 15, HTTP_MONITOR_INFO_REQUEST); + ENUM_EQ(MessageType::World, 16, SLASH_DEBUG_SCRIPTS); + ENUM_EQ(MessageType::World, 17, MODELS_CLEAR); + ENUM_EQ(MessageType::World, 18, EXHIBIT_INSERT_MODEL); + ENUM_EQ(MessageType::World, 19, LEVEL_LOAD_COMPLETE); + ENUM_EQ(MessageType::World, 20, TMP_GUILD_CREATE); + ENUM_EQ(MessageType::World, 21, ROUTE_PACKET); + ENUM_EQ(MessageType::World, 22, POSITION_UPDATE); + ENUM_EQ(MessageType::World, 23, MAIL); + ENUM_EQ(MessageType::World, 24, WORD_CHECK); + ENUM_EQ(MessageType::World, 25, STRING_CHECK); + ENUM_EQ(MessageType::World, 26, GET_PLAYERS_IN_ZONE); + ENUM_EQ(MessageType::World, 27, REQUEST_UGC_MANIFEST_INFO); + ENUM_EQ(MessageType::World, 28, BLUEPRINT_GET_ALL_DATA_REQUEST); + ENUM_EQ(MessageType::World, 29, CANCEL_MAP_QUEUE); + ENUM_EQ(MessageType::World, 30, HANDLE_FUNNESS); + ENUM_EQ(MessageType::World, 31, FAKE_PRG_CSR_MESSAGE); + ENUM_EQ(MessageType::World, 32, REQUEST_FREE_TRIAL_REFRESH); + ENUM_EQ(MessageType::World, 33, GM_SET_FREE_TRIAL_STATUS); + ENUM_EQ(MessageType::World, 91, UI_HELP_TOP_5); + ENUM_NE(MessageType::World, 37); + ENUM_NE(MessageType::World, 123); srand(time(NULL)); auto begin = std::chrono::high_resolution_clock::now(); for (int i = 0; i < 10000000; ++i) { - volatile auto f = StringifiedEnum::ToString(static_cast<eWorldMessageType>(i)).data(); + volatile auto f = StringifiedEnum::ToString(static_cast<MessageType::World>(i)).data(); // To ensure the compiler doesn't optimize out the call, I print it at random intervals if (rand() % 100000 == 0) LOG("%i, %s", i, f); @@ -78,34 +78,34 @@ TEST(MagicEnumTest, eGameMessageTypeTest) { Game::logger = new Logger("./MagicEnumTest_eGameMessageTypeTest.log", true, true); // Only doing the first and last 10 for the sake of my sanity - ENUM_EQ(eGameMessageType, 0, GET_POSITION); - ENUM_EQ(eGameMessageType, 1, GET_ROTATION); - ENUM_EQ(eGameMessageType, 2, GET_LINEAR_VELOCITY); - ENUM_EQ(eGameMessageType, 3, GET_ANGULAR_VELOCITY); - ENUM_EQ(eGameMessageType, 4, GET_FORWARD_VELOCITY); - ENUM_EQ(eGameMessageType, 5, GET_PLAYER_FORWARD); - ENUM_EQ(eGameMessageType, 6, GET_FORWARD_VECTOR); - ENUM_EQ(eGameMessageType, 7, SET_POSITION); - ENUM_EQ(eGameMessageType, 8, SET_LOCAL_POSITION); - ENUM_EQ(eGameMessageType, 9, SET_ROTATION); - ENUM_EQ(eGameMessageType, 10, SET_LINEAR_VELOCITY); - ENUM_EQ(eGameMessageType, 1762, USE_SKILL_SET); - ENUM_EQ(eGameMessageType, 1763, SET_SKILL_SET_POSSESSOR); - ENUM_EQ(eGameMessageType, 1764, POPULATE_ACTION_BAR); - ENUM_EQ(eGameMessageType, 1765, GET_COMPONENT_TEMPLATE_ID); - ENUM_EQ(eGameMessageType, 1766, GET_POSSESSABLE_SKILL_SET); - ENUM_EQ(eGameMessageType, 1767, MARK_INVENTORY_ITEM_AS_ACTIVE); - ENUM_EQ(eGameMessageType, 1768, UPDATE_FORGED_ITEM); - ENUM_EQ(eGameMessageType, 1769, CAN_ITEMS_BE_REFORGED); - ENUM_EQ(eGameMessageType, 1771, NOTIFY_CLIENT_RAIL_START_FAILED); - ENUM_EQ(eGameMessageType, 1772, GET_IS_ON_RAIL); - ENUM_NE(eGameMessageType, 32); - ENUM_NE(eGameMessageType, 1776); + ENUM_EQ(MessageType::Game, 0, GET_POSITION); + ENUM_EQ(MessageType::Game, 1, GET_ROTATION); + ENUM_EQ(MessageType::Game, 2, GET_LINEAR_VELOCITY); + ENUM_EQ(MessageType::Game, 3, GET_ANGULAR_VELOCITY); + ENUM_EQ(MessageType::Game, 4, GET_FORWARD_VELOCITY); + ENUM_EQ(MessageType::Game, 5, GET_PLAYER_FORWARD); + ENUM_EQ(MessageType::Game, 6, GET_FORWARD_VECTOR); + ENUM_EQ(MessageType::Game, 7, SET_POSITION); + ENUM_EQ(MessageType::Game, 8, SET_LOCAL_POSITION); + ENUM_EQ(MessageType::Game, 9, SET_ROTATION); + ENUM_EQ(MessageType::Game, 10, SET_LINEAR_VELOCITY); + ENUM_EQ(MessageType::Game, 1762, USE_SKILL_SET); + ENUM_EQ(MessageType::Game, 1763, SET_SKILL_SET_POSSESSOR); + ENUM_EQ(MessageType::Game, 1764, POPULATE_ACTION_BAR); + ENUM_EQ(MessageType::Game, 1765, GET_COMPONENT_TEMPLATE_ID); + ENUM_EQ(MessageType::Game, 1766, GET_POSSESSABLE_SKILL_SET); + ENUM_EQ(MessageType::Game, 1767, MARK_INVENTORY_ITEM_AS_ACTIVE); + ENUM_EQ(MessageType::Game, 1768, UPDATE_FORGED_ITEM); + ENUM_EQ(MessageType::Game, 1769, CAN_ITEMS_BE_REFORGED); + ENUM_EQ(MessageType::Game, 1771, NOTIFY_CLIENT_RAIL_START_FAILED); + ENUM_EQ(MessageType::Game, 1772, GET_IS_ON_RAIL); + ENUM_NE(MessageType::Game, 32); + ENUM_NE(MessageType::Game, 1776); srand(time(NULL)); auto begin = std::chrono::high_resolution_clock::now(); for (int i = 0; i < 10000000; ++i) { - volatile auto f = StringifiedEnum::ToString(static_cast<eGameMessageType>(i)).data(); + volatile auto f = StringifiedEnum::ToString(static_cast<MessageType::Game>(i)).data(); // To ensure the compiler doesn't optimize out the call, I print it at random intervals if (rand() % 100000 == 0) LOG("%i, %s", i, f); @@ -121,7 +121,7 @@ TEST(MagicEnumTest, eGameMessageTypeTest) { namespace { template <typename T> void AssertEnumArraySorted(const T& eArray) { - for (int i = 0; i < eArray->size(); ++i) { + for (int i = 0; i < eArray->size() - 1; ++i) { const auto entryCurr = eArray->at(i).first; LOG_EARRAY(eArray, i, entryCurr); const auto entryNext = eArray->at(++i).first; @@ -135,10 +135,10 @@ namespace { TEST(MagicEnumTest, ArraysAreSorted) { Game::logger = new Logger("./MagicEnumTest_ArraysAreSorted.log", true, true); - constexpr auto wmArray = &magic_enum::enum_entries<eWorldMessageType>(); + constexpr auto wmArray = &magic_enum::enum_entries<MessageType::World>(); AssertEnumArraySorted(wmArray); - constexpr auto gmArray = &magic_enum::enum_entries<eGameMessageType>(); + constexpr auto gmArray = &magic_enum::enum_entries<MessageType::Game>(); AssertEnumArraySorted(gmArray); delete Game::logger; diff --git a/tests/dGameTests/CMakeLists.txt b/tests/dGameTests/CMakeLists.txt index b1fdaa070..e1c294331 100644 --- a/tests/dGameTests/CMakeLists.txt +++ b/tests/dGameTests/CMakeLists.txt @@ -9,11 +9,22 @@ add_subdirectory(dGameMessagesTests) list(APPEND DGAMETEST_SOURCES ${DGAMEMESSAGES_TESTS}) file(COPY ${GAMEMESSAGE_TESTBITSTREAMS} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +file(COPY ${COMPONENT_TEST_DATA} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) # Add the executable. Remember to add all tests above this! add_executable(dGameTests ${DGAMETEST_SOURCES}) +add_dependencies(dGameTests conncpp_tests) -target_link_libraries(dGameTests ${COMMON_LIBRARIES} GTest::gtest_main dGame dZoneManager dPhysics Detour Recast tinyxml2 dWorldServer dChatFilter dNavigation) +# Apple needs some special linkage for the mariadb connector for tests. +if(APPLE) +add_custom_command(TARGET dGameTests POST_BUILD + COMMAND install_name_tool ARGS -change libmariadbcpp.dylib @rpath/libmariadbcpp.dylib dGameTests + COMMAND otool ARGS -L dGameTests + WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +endif() + +target_link_libraries(dGameTests ${COMMON_LIBRARIES} GTest::gtest_main + dGame dScripts dPhysics Detour Recast tinyxml2 dWorldServer dZoneManager dChatFilter dNavigation) # Discover the tests gtest_discover_tests(dGameTests) diff --git a/tests/dGameTests/GameDependencies.h b/tests/dGameTests/GameDependencies.h index 52e3919af..9f8dbb2b5 100644 --- a/tests/dGameTests/GameDependencies.h +++ b/tests/dGameTests/GameDependencies.h @@ -8,6 +8,9 @@ #include "EntityInfo.h" #include "EntityManager.h" #include "dConfig.h" +#include "dZoneManager.h" +#include "GameDatabase/TestSQL/TestSQLDatabase.h" +#include "Database.h" #include <gtest/gtest.h> class dZoneManager; @@ -20,6 +23,7 @@ class dServerMock : public dServer { ~dServerMock() {}; RakNet::BitStream* GetMostRecentBitStream() { return sentBitStream; }; void Send(RakNet::BitStream& bitStream, const SystemAddress& sysAddr, bool broadcast) override { sentBitStream = &bitStream; }; + void SetZoneId(unsigned int zoneId) { mZoneID = zoneId; } }; class GameDependenciesTest : public ::testing::Test { @@ -34,6 +38,9 @@ class GameDependenciesTest : public ::testing::Test { Game::server = new dServerMock(); Game::config = new dConfig("worldconfig.ini"); Game::entityManager = new EntityManager(); + Game::zoneManager = new dZoneManager(); + Game::zoneManager->LoadZone(LWOZONEID(1, 0, 0)); + Database::_setDatabase(new TestSQLDatabase()); // this new is managed by the Database // Create a CDClientManager instance and load from defaults CDClientManager::LoadValuesFromDefaults(); @@ -42,6 +49,7 @@ class GameDependenciesTest : public ::testing::Test { void TearDownDependencies() { if (Game::server) delete Game::server; if (Game::entityManager) delete Game::entityManager; + if (Game::zoneManager) delete Game::zoneManager; if (Game::logger) { Game::logger->Flush(); delete Game::logger; diff --git a/tests/dGameTests/dComponentsTests/CMakeLists.txt b/tests/dGameTests/dComponentsTests/CMakeLists.txt index 374095af0..f73f1214c 100644 --- a/tests/dGameTests/dComponentsTests/CMakeLists.txt +++ b/tests/dGameTests/dComponentsTests/CMakeLists.txt @@ -2,6 +2,7 @@ set(DCOMPONENTS_TESTS "DestroyableComponentTests.cpp" "PetComponentTests.cpp" "SimplePhysicsComponentTests.cpp" + "SavingTests.cpp" ) # Get the folder name and prepend it to the files above @@ -10,3 +11,8 @@ list(TRANSFORM DCOMPONENTS_TESTS PREPEND "${thisFolderName}/") # Export to parent scope set(DCOMPONENTS_TESTS ${DCOMPONENTS_TESTS} PARENT_SCOPE) + +# Copy test files to testing directory +add_subdirectory(TestData) +list(TRANSFORM COMPONENT_TEST_DATA PREPEND "${thisFolderName}/") +set(COMPONENT_TEST_DATA ${COMPONENT_TEST_DATA} PARENT_SCOPE) diff --git a/tests/dGameTests/dComponentsTests/SavingTests.cpp b/tests/dGameTests/dComponentsTests/SavingTests.cpp new file mode 100644 index 000000000..7123b6986 --- /dev/null +++ b/tests/dGameTests/dComponentsTests/SavingTests.cpp @@ -0,0 +1,103 @@ +#include "GameDependencies.h" +#include "Character.h" +#include "Entity.h" +#include "tinyxml2.h" +#include "BuffComponent.h" +#include "CharacterComponent.h" + +class SavingTest : public GameDependenciesTest { +protected: + std::unique_ptr<Entity> entity; + std::unique_ptr<Character> character; + tinyxml2::XMLDocument doc; + tinyxml2::XMLPrinter printer{ 0, true, 0 }; + + void SetUp() override { + SetUpDependencies(); + Game::zoneManager->LoadZone(LWOZONEID(1800, 2, 0)); + static_cast<dServerMock*>(Game::server)->SetZoneId(1800); + + entity = std::make_unique<Entity>(1, GameDependenciesTest::info); + character = std::make_unique<Character>(1, nullptr); + + doc.LoadFile("./test_xml_data.xml"); + + entity->SetCharacter(character.get()); + character->SetEntity(entity.get()); + + doc.Print(&printer); + character->_setXmlData(printer.CStr()); + printer.ClearBuffer(); + + character->_doQuickXMLDataParse(); + character->LoadXmlRespawnCheckpoints(); + + entity->AddComponent<CharacterComponent>(character.get(), UNASSIGNED_SYSTEM_ADDRESS)->LoadFromXml(entity->GetCharacter()->GetXMLDoc()); + } + + void TearDown() override { + entity->SetCharacter(nullptr); + + entity.reset(); + character.reset(); + + TearDownDependencies(); + } +}; + +TEST_F(SavingTest, CharacterComponentTest) { + // Print the original XML data + // character->GetXMLDoc().Print(&printer); + // std::string xmlDataOriginal(printer.CStr()); + // printer.ClearBuffer(); + // std::ofstream oldXml("./test_xml_data_original.xml"); + // oldXml << xmlDataOriginal; + + auto* characterComponent = entity->GetComponent<CharacterComponent>(); + + // Update the xml document so its been run through the saver + character->SaveXMLToDatabase(); + + // Reload the component and character from the now updated xml data + const auto prevTotalTime = characterComponent->GetTotalTimePlayed(); + character->_doQuickXMLDataParse(); + entity->AddComponent<CharacterComponent>(character.get(), UNASSIGNED_SYSTEM_ADDRESS); + characterComponent->LoadFromXml(entity->GetCharacter()->GetXMLDoc()); + + // Check that the buff component is the same as before which means resaving data and loading it back in didn't change anything + ASSERT_EQ("32114;69;343;13;163;2;181;2;388;252;146;24451;25;9022;41898;42186;42524;4404;0;0;0;0;0;0;0;0;0;", characterComponent->StatisticsToString()); + + // need a variable because the macros do not support {} + constexpr std::array<uint64_t, 4> correctCodes = { 1073741968, 0, 0, 0 }; + ASSERT_EQ(correctCodes, characterComponent->GetClaimCodes()); + ASSERT_EQ(1, characterComponent->m_Character->GetEyebrows()); + ASSERT_EQ(2, characterComponent->m_Character->GetEyes()); + ASSERT_EQ(9, characterComponent->m_Character->GetHairColor()); + ASSERT_EQ(8, characterComponent->m_Character->GetHairStyle()); + ASSERT_EQ(3, characterComponent->m_Character->GetPantsColor()); + ASSERT_EQ(27634704, characterComponent->m_Character->GetLeftHand()); + ASSERT_EQ(3, characterComponent->m_Character->GetMouth()); + ASSERT_EQ(27187396, characterComponent->m_Character->GetRightHand()); + ASSERT_EQ(13, characterComponent->m_Character->GetShirtColor()); + ASSERT_EQ(7510, characterComponent->GetUScore()); + ASSERT_EQ(300, characterComponent->GetReputation()); + ASSERT_EQ(u"0:1:4719+1:4720+1:4721", characterComponent->GetLastRocketConfig()); + ASSERT_EQ(prevTotalTime, characterComponent->GetTotalTimePlayed()); + + const std::map<LWOMAPID, ZoneStatistics> correctZoneStats = + { + { 1000, { .m_AchievementsCollected = 0, .m_BricksCollected = 0, .m_CoinsCollected = 4, .m_EnemiesSmashed = 0, .m_QuickBuildsCompleted = 0 } }, + { 1100, { .m_AchievementsCollected = 1, .m_BricksCollected = 54, .m_CoinsCollected = 584, .m_EnemiesSmashed = 34, .m_QuickBuildsCompleted = 0 } }, + { 1101, { .m_AchievementsCollected = 7, .m_BricksCollected = 0, .m_CoinsCollected = 750, .m_EnemiesSmashed = 100, .m_QuickBuildsCompleted = 7 } }, + { 1200, { .m_AchievementsCollected = 51, .m_BricksCollected = 9, .m_CoinsCollected = 26724, .m_EnemiesSmashed = 0, .m_QuickBuildsCompleted = 3 } }, + { 1250, { .m_AchievementsCollected = 1, .m_BricksCollected = 1, .m_CoinsCollected = 158, .m_EnemiesSmashed = 15, .m_QuickBuildsCompleted = 1 } }, + { 1800, { .m_AchievementsCollected = 4, .m_BricksCollected = 5, .m_CoinsCollected = 3894, .m_EnemiesSmashed = 14, .m_QuickBuildsCompleted = 2 } }, + }; + + ASSERT_EQ(correctZoneStats, characterComponent->GetZoneStatistics()); + + // Fails currently due to not reading style from xml + // Should the value be fixed, this test will fail and will match the above + // only then will this comment be removed. + ASSERT_NE(27, characterComponent->m_Character->GetShirtStyle()); +} diff --git a/tests/dGameTests/dComponentsTests/TestData/CMakeLists.txt b/tests/dGameTests/dComponentsTests/TestData/CMakeLists.txt new file mode 100644 index 000000000..31e925420 --- /dev/null +++ b/tests/dGameTests/dComponentsTests/TestData/CMakeLists.txt @@ -0,0 +1,10 @@ +set(COMPONENT_TEST_DATA + "test_xml_data.xml" +) + +# Get the folder name and prepend it to the files above +get_filename_component(thisFolderName ${CMAKE_CURRENT_SOURCE_DIR} NAME) +list(TRANSFORM COMPONENT_TEST_DATA PREPEND "${thisFolderName}/") + +# Export our list of files +set(COMPONENT_TEST_DATA ${COMPONENT_TEST_DATA} PARENT_SCOPE) diff --git a/tests/dGameTests/dComponentsTests/TestData/test_xml_data.xml b/tests/dGameTests/dComponentsTests/TestData/test_xml_data.xml new file mode 100644 index 000000000..431c12c93 --- /dev/null +++ b/tests/dGameTests/dComponentsTests/TestData/test_xml_data.xml @@ -0,0 +1 @@ +<obj v="1"><mf hc="9" hs="8" hd="0" t="13" l="3" hdc="0" cd="27" lh="27634704" rh="27187396" es="1" ess="2" ms="3"/><char acct="628" cc="30046" gm="9" ft="0" llog="1716697644" ls="7510" lzx="-60.869003" lzy="76.865089" lzz="224.79057" lzrx="0" lzry="-0.85140967" lzrz="0" lzrw="0.5245012" stt="32114;69;343;13;163;2;181;2;388;252;146;24451;25;9022;41898;42186;42524;4404;0;0;0;0;0;0;0;0;0;" lzid="132872" lnzid="0" lwid="1800" tscene="" co="1073741968" rpt="300" lrid="1152921509279923587" lcbp="0:1:4719+1:4720+1:4721" time="24062"><ue><e id="115"/><e id="383"/><e id="377"/><e id="385"/><e id="207"/><e id="209"/><e id="384"/><e id="356"/><e id="178"/><e id="208"/></ue><zs><s map="1000" ac="0" bc="0" cc="4" es="0" qbc="0"/><s map="1100" ac="1" bc="54" cc="584" es="34" qbc="0"/><s map="1101" ac="7" bc="0" cc="750" es="100" qbc="7"/><s map="1200" ac="51" bc="9" cc="26724" es="0" qbc="3"/><s map="1250" ac="1" bc="1" cc="158" es="15" qbc="1"/><s map="1800" ac="4" bc="5" cc="3894" es="14" qbc="2"/></zs></char><dest hm="5" hc="5" im="10" ic="8" am="4" ac="4" d="0"><buff/></dest><inv csl="-1"><bag><b t="0" m="2032"/><b t="1" m="40"/><b t="2" m="240"/><b t="4" m="240"/><b t="5" m="240"/><b t="6" m="240"/><b t="7" m="240"/><b t="12" m="240"/><b t="14" m="40"/><b t="15" m="240"/></bag><items><in t="0"><i l="7794" id="1152921508920713320" s="63" c="1" b="true" eq="false" sk="0" parent="0"/><i l="3292" id="1152921508927576659" s="44" c="1" b="true" eq="false" sk="0" parent="0"/><i l="2620" id="1152921508954303322" s="100" c="3" b="false" eq="false" sk="0" parent="0"/><i l="6199" id="1152921508964317723" s="97" c="1" b="true" eq="false" sk="0" parent="0"/><i l="3010" id="1152921508984382191" s="92" c="1" b="true" eq="false" sk="0" parent="0"/><i l="2198" id="1152921508997945710" s="21" c="3" b="false" eq="false" sk="0" parent="0"/><i l="8530" id="1152921509026332959" s="104" c="1" b="true" eq="false" sk="0" parent="0"/><i l="2945" id="1152921509029155394" s="114" c="1" b="true" eq="false" sk="0" parent="0"/><i l="13604" id="1152921509085846784" s="108" c="1" b="false" eq="false" sk="0" parent="0"/><i l="2943" id="1152921509092391378" s="62" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6232" id="1152921509111798972" s="110" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10396" id="1152921509126949920" s="83" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8027" id="1152921509141654496" s="37" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14359" id="1152921509158585047" s="77" c="1" b="true" eq="false" sk="0" parent="0"/><i l="5832" id="1152921509169724111" s="59" c="5" b="false" eq="false" sk="0" parent="0"/><i l="12809" id="1152921509180231955" s="9" c="1" b="true" eq="true" sk="0" parent="0"/><i l="13110" id="1152921509185089610" s="107" c="1" b="false" eq="false" sk="0" parent="0"/><i l="4883" id="1152921509189172724" s="72" c="1" b="true" eq="false" sk="0" parent="0"/><i l="4881" id="1152921509212887577" s="71" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6086" id="1152921509226361095" s="112" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6865" id="1152921509237848167" s="12" c="1" b="false" eq="false" sk="0" parent="0"/><i l="7850" id="1152921509277123194" s="64" c="1" b="true" eq="false" sk="0" parent="0"/><i l="2515" id="1152921509364441086" s="1" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8032" id="1152921509367735487" s="29" c="1" b="true" eq="false" sk="0" parent="0"/><i l="4880" id="1152921509378831114" s="70" c="1" b="true" eq="false" sk="0" parent="0"/><i l="2944" id="1152921509395664079" s="65" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9721" id="1152921509411663752" s="82" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6200" id="1152921509412971616" s="111" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14315" id="1152921509417121429" s="80" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6197" id="1152921509447546613" s="99" c="1" b="true" eq="false" sk="0" parent="0"/><i l="1966" id="1152921509478559581" s="17" c="4" b="false" eq="false" sk="0" parent="0"/><i l="14553" id="1152921509509803723" s="76" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9726" id="1152921509515105138" s="102" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10401" id="1152921509549395474" s="103" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10121" id="1152921509550775173" s="46" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7727" id="1152921509555753924" s="105" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10397" id="1152921509575952396" s="85" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8034" id="1152921509585202997" s="30" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8600" id="1152921509597168815" s="8" c="1" b="true" eq="true" sk="0" parent="0"/><i l="7781" id="1152921509649675131" s="58" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10398" id="1152921509663938461" s="87" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8541" id="1152921509672829053" s="23" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7741" id="1152921509743573746" s="16" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6230" id="1152921509743622304" s="109" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8031" id="1152921509765940473" s="27" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6194" id="1152921509786448538" s="4" c="9" b="true" eq="false" sk="0" parent="0"/><i l="8028" id="1152921509804752356" s="36" c="1" b="true" eq="false" sk="0" parent="0"/><i l="2986" id="1152921509830041581" s="67" c="1" b="true" eq="false" sk="0" parent="0"/><i l="2994" id="1152921509842715529" s="15" c="2" b="false" eq="false" sk="0" parent="0"/><i l="14359" id="1152921509877252555" s="88" c="1" b="true" eq="false" sk="0" parent="0"/><i l="2946" id="1152921509880223681" s="61" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10399" id="1152921509935987204" s="94" c="1" b="true" eq="false" sk="0" parent="0"/><i l="4977" id="1152921509984266242" s="106" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7851" id="1152921509989879303" s="66" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8375" id="1152921509992503200" s="18" c="2" b="false" eq="false" sk="0" parent="0"/><i l="2998" id="1152921510013576010" s="6" c="7" b="false" eq="false" sk="0" parent="0"/><i l="12764" id="1152921510017128054" s="13" c="2" b="false" eq="false" sk="0" parent="0"/><i l="5835" id="1152921510023526076" s="113" c="1" b="false" eq="false" sk="0" parent="0"/><i l="3206" id="1152921510023644642" s="14" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10400" id="1152921510023977735" s="96" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14321" id="1152921510075755907" s="78" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6207" id="1152921510089473412" s="75" c="1" b="false" eq="false" sk="0" parent="0"/><i l="2998" id="1152921510104551252" s="5" c="10" b="false" eq="false" sk="0" parent="0"/><i l="6928" id="1152921510122179214" s="117" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14315" id="1152921510132673403" s="91" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9725" id="1152921510156708516" s="95" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8642" id="1152921510245754723" s="47" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7591" id="1152921510266847048" s="25" c="1" b="true" eq="false" sk="0" parent="0"/><i l="11298" id="1152921510269106232" s="51" c="1" b="true" eq="false" sk="0" parent="0"/><i l="5833" id="1152921510273715296" s="60" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8548" id="1152921510293088757" s="101" c="1" b="true" eq="false" sk="0" parent="0"/><i l="3291" id="1152921510306034768" s="43" c="1" b="true" eq="false" sk="0" parent="0"/><i l="12891" id="1152921510306317362" s="56" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10128" id="1152921510323527647" s="42" c="1" b="true" eq="false" sk="0" parent="0"/><i l="1726" id="1152921510327741676" s="73" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9775" id="1152921510356108968" s="116" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9595" id="1152921510357440949" s="45" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10131" id="1152921510369968013" s="34" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14816" id="1152921510376734193" s="69" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6866" id="1152921510388993454" s="11" c="2" b="false" eq="false" sk="0" parent="0"/><i l="9723" id="1152921510411010897" s="86" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14126" id="1152921510411320020" s="53" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9468" id="1152921510438793358" s="50" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8029" id="1152921510446828549" s="32" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7590" id="1152921510451754174" s="35" c="1" b="true" eq="false" sk="0" parent="0"/><i l="4449" id="1152921510455062254" s="0" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6198" id="1152921510460000458" s="98" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10123" id="1152921510468452592" s="38" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14353" id="1152921510491998217" s="79" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8033" id="1152921510495630138" s="26" c="1" b="true" eq="false" sk="0" parent="0"/><i l="5842" id="1152921510496178236" s="74" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9467" id="1152921510504490675" s="49" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10165" id="1152921510540139669" s="39" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7797" id="1152921510561704272" s="68" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14592" id="1152921510581689762" s="22" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7044" id="1152921510582541838" s="24" c="1" b="true" eq="false" sk="0" parent="0"/><i l="12889" id="1152921510595283420" s="54" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8030" id="1152921510624605329" s="33" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7779" id="1152921510633430898" s="19" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8597" id="1152921510650260332" s="81" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7778" id="1152921510651577746" s="115" c="5" b="false" eq="false" sk="0" parent="0"/><i l="3100" id="1152921510672913850" s="10" c="2" b="false" eq="false" sk="0" parent="0"/><i l="7586" id="1152921510727803798" s="28" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9466" id="1152921510745549481" s="48" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6936" id="1152921510772769862" s="118" c="1" b="true" eq="false" sk="0" parent="0"/><i l="4977" id="1152921510817922687" s="3" c="1" b="true" eq="false" sk="0" parent="0"/><i l="14353" id="1152921510818370355" s="90" c="1" b="true" eq="false" sk="0" parent="0"/><i l="12781" id="1152921510825365922" s="2" c="1" b="true" eq="true" sk="0" parent="0"/><i l="13073" id="1152921510834293637" s="57" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7792" id="1152921510846805952" s="20" c="1" b="true" eq="false" sk="0" parent="0"/><i l="12424" id="1152921510870329108" s="40" c="1" b="true" eq="false" sk="0" parent="0"/><i l="11291" id="1152921510883860603" s="52" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10096" id="1152921510901282012" s="41" c="2" b="true" eq="false" sk="0" parent="0"/><i l="14321" id="1152921510924971804" s="89" c="1" b="true" eq="false" sk="0" parent="0"/><i l="12890" id="1152921510964199450" s="55" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7589" id="1152921510985440500" s="31" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9722" id="1152921510986541148" s="84" c="1" b="true" eq="false" sk="0" parent="0"/><i l="12220" id="1152921511039776013" s="7" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9724" id="1152921511045784551" s="93" c="1" b="true" eq="false" sk="0" parent="0"/></in><in t="1"/><in t="2"><i l="31" id="1152921509136277529" s="14" c="4" b="false" eq="false" sk="0" parent="0"/><i l="41" id="1152921509208381889" s="17" c="4" b="false" eq="false" sk="0" parent="0"/><i l="365" id="1152921509209617259" s="21" c="1" b="false" eq="false" sk="0" parent="0"/><i l="724" id="1152921509228294511" s="23" c="4" b="false" eq="false" sk="0" parent="0"/><i l="9201" id="1152921509299794444" s="24" c="1" b="false" eq="false" sk="0" parent="0"/><i l="60" id="1152921509347039686" s="11" c="2" b="false" eq="false" sk="0" parent="0"/><i l="38" id="1152921509414891282" s="12" c="1" b="false" eq="false" sk="0" parent="0"/><i l="32" id="1152921509591459525" s="0" c="3" b="false" eq="false" sk="0" parent="0"/><i l="30" id="1152921509592302285" s="16" c="3" b="false" eq="false" sk="0" parent="0"/><i l="103" id="1152921509672626115" s="22" c="2" b="false" eq="false" sk="0" parent="0"/><i l="39" id="1152921509717737184" s="2" c="4" b="false" eq="false" sk="0" parent="0"/><i l="143" id="1152921509924347982" s="9" c="1" b="false" eq="false" sk="0" parent="0"/><i l="37" id="1152921510035076473" s="13" c="2" b="false" eq="false" sk="0" parent="0"/><i l="40" id="1152921510088264990" s="4" c="4" b="false" eq="false" sk="0" parent="0"/><i l="144" id="1152921510158428301" s="8" c="1" b="false" eq="false" sk="0" parent="0"/><i l="58" id="1152921510175358063" s="3" c="1" b="false" eq="false" sk="0" parent="0"/><i l="869" id="1152921510252792257" s="20" c="2" b="false" eq="false" sk="0" parent="0"/><i l="98" id="1152921510332640892" s="6" c="5" b="false" eq="false" sk="0" parent="0"/><i l="33" id="1152921510369758653" s="7" c="3" b="false" eq="false" sk="0" parent="0"/><i l="59" id="1152921510655910288" s="15" c="2" b="false" eq="false" sk="0" parent="0"/><i l="29" id="1152921510657034316" s="5" c="4" b="false" eq="false" sk="0" parent="0"/><i l="35" id="1152921510675425704" s="10" c="2" b="false" eq="false" sk="0" parent="0"/><i l="62" id="1152921510735659034" s="1" c="6" b="false" eq="false" sk="0" parent="0"/><i l="42" id="1152921510877741845" s="18" c="3" b="false" eq="false" sk="0" parent="0"/><i l="66" id="1152921510961573144" s="19" c="4" b="false" eq="false" sk="0" parent="0"/></in><in t="4"><i l="4992" id="1152921510949967196" s="0" c="1" b="true" eq="false" sk="0" parent="0"/></in><in t="5"><i l="5637" id="1152921509035471592" s="22" c="1" b="true" eq="false" sk="1152921510439550141" parent="0"/><i l="6416" id="1152921509279923587" s="21" c="1" b="true" eq="false" sk="1152921504606900560" parent="0"><x ma="0:1:4719+1:4720+1:4721"/></i><i l="8077" id="1152921509405250679" s="3" c="2" b="false" eq="false" sk="0" parent="0"/><i l="16248" id="1152921509500518051" s="15" c="1" b="false" eq="false" sk="0" parent="0"/><i l="16247" id="1152921509534779887" s="14" c="1" b="false" eq="false" sk="0" parent="0"/><i l="5637" id="1152921509589299202" s="7" c="1" b="true" eq="false" sk="1152921510433975245" parent="0"/><i l="9518" id="1152921509746124829" s="10" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8069" id="1152921509756596102" s="0" c="2" b="false" eq="false" sk="0" parent="0"/><i l="16250" id="1152921509791098270" s="17" c="1" b="false" eq="false" sk="0" parent="0"/><i l="6870" id="1152921509797082915" s="11" c="1" b="true" eq="false" sk="0" parent="0"/><i l="8068" id="1152921509978963451" s="1" c="1" b="false" eq="false" sk="0" parent="0"/><i l="16249" id="1152921509981992435" s="16" c="1" b="false" eq="false" sk="0" parent="0"/><i l="4717" id="1152921509989262993" s="19" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9516" id="1152921510005396812" s="8" c="1" b="true" eq="false" sk="0" parent="0"/><i l="4716" id="1152921510029464704" s="18" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9325" id="1152921510148144752" s="12" c="1" b="false" eq="false" sk="0" parent="0"/><i l="4714" id="1152921510211817125" s="23" c="1" b="true" eq="false" sk="0" parent="0"/><i l="9394" id="1152921510340921444" s="13" c="1" b="false" eq="false" sk="0" parent="0"/><i l="9517" id="1152921510615990012" s="9" c="1" b="true" eq="false" sk="0" parent="0"/><i l="4718" id="1152921510630642881" s="20" c="1" b="true" eq="false" sk="0" parent="0"/><i l="12495" id="1152921510799243558" s="5" c="1" b="false" eq="false" sk="0" parent="0"/><i l="7759" id="1152921510809831059" s="2" c="1" b="false" eq="false" sk="0" parent="0"/><i l="7770" id="1152921510857599662" s="24" c="1" b="false" eq="false" sk="0" parent="0"/><i l="12496" id="1152921510864599234" s="4" c="1" b="false" eq="false" sk="0" parent="0"/><i l="12497" id="1152921510997101806" s="6" c="1" b="false" eq="false" sk="0" parent="0"/></in><in t="6"/><in t="7"><i l="10448" id="1152921509279267399" s="6" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10996" id="1152921509319886942" s="3" c="1" b="true" eq="false" sk="0" parent="0"/><i l="11033" id="1152921509600825326" s="0" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10449" id="1152921509766284429" s="7" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10997" id="1152921510033136873" s="2" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10446" id="1152921510619422428" s="4" c="1" b="true" eq="false" sk="0" parent="0"/><i l="11030" id="1152921510903410334" s="1" c="1" b="true" eq="false" sk="0" parent="0"/><i l="10447" id="1152921510924928258" s="5" c="1" b="true" eq="false" sk="0" parent="0"/></in><in t="12"><i l="7092" id="1152921508958136194" s="7" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7091" id="1152921509468388221" s="0" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6979" id="1152921509479321842" s="4" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6981" id="1152921509846970455" s="3" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7093" id="1152921509913056742" s="6" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6980" id="1152921510461832315" s="5" c="1" b="true" eq="false" sk="0" parent="0"/><i l="6978" id="1152921510646559867" s="2" c="1" b="true" eq="false" sk="0" parent="0"/><i l="7090" id="1152921510762462193" s="1" c="1" b="true" eq="false" sk="0" parent="0"/></in><in t="14"/><in t="15"><i l="13285" id="1152921509974584478" s="0" c="1" b="true" eq="true" sk="0" parent="1152921509180231955"/></in></items></inv><lvl l="15" cv="4" sb="500"/><flag><f id="12" v="1125899906842624"/><f id="175" v="56"/><f id="0" v="18038872311117888"/><f id="1" v="1125912817434656"/></flag><res><r w="1000" x="-414.60861" y="592.07843" z="-30.009001"/><r w="1100" x="-122.5409" y="359.34299" z="-275.823"/><r w="1101" x="34.869747" y="365.76721" z="-194.87486"/><r w="1200" x="45.8661" y="301.293" z="21.839399"/><r w="1250" x="-17.475601" y="440.20929" z="30.503101"/><r w="1800" x="-12.18811" y="81.837692" z="49.067474"/></res><mis><done><m state="8" id="872" cct="1" cts="1716977431"/><m state="8" id="618" cct="1" cts="1716977483"/><m state="8" id="110" cct="1" cts="1716977379"/><m state="8" id="881" cct="1" cts="1716977431"/><m state="8" id="500" cct="1" cts="1716977432"/><m state="8" id="1152" cct="1" cts="1716977483"/><m state="8" id="680" cct="1" cts="1716977483"/><m state="8" id="1950" cct="1" cts="1716977481"/><m state="8" id="1249" cct="1" cts="1716977433"/><m state="8" id="478" cct="1" cts="1716977429"/><m state="8" id="777" cct="1" cts="1716977432"/><m state="8" id="236" cct="1" cts="1716977432"/><m state="8" id="871" cct="1" cts="1716977482"/><m state="8" id="175" cct="1" cts="1716977432"/><m state="8" id="470" cct="1" cts="1716977483"/><m state="8" id="1869" cct="1" cts="1716977480"/><m state="8" id="878" cct="1" cts="1716977431"/><m state="8" id="377" cct="1" cts="1716977481"/><m state="8" id="891" cct="1" cts="1716977482"/><m state="8" id="318" cct="1" cts="1716977481"/><m state="8" id="859" cct="1" cts="1716977431"/><m state="8" id="602" cct="1" cts="1716977435"/><m state="8" id="311" cct="1" cts="1716977479"/><m state="8" id="1853" cct="1" cts="1716977481"/><m state="8" id="230" cct="1" cts="1716977432"/><m state="8" id="1246" cct="1" cts="1716977433"/><m state="8" id="475" cct="1" cts="1716977429"/><m state="8" id="755" cct="1" cts="1716977479"/><m state="8" id="536" cct="1" cts="1716977434"/><m state="8" id="302" cct="1" cts="1716977435"/><m state="8" id="843" cct="1" cts="1716977379"/><m state="8" id="589" cct="1" cts="1716977430"/><m state="8" id="595" cct="1" cts="1716977435"/><m state="8" id="477" cct="1" cts="1716977429"/><m state="8" id="1248" cct="1" cts="1716977433"/><m state="8" id="1935" cct="1" cts="1716977481"/><m state="8" id="312" cct="1" cts="1716977480"/><m state="8" id="1854" cct="1" cts="1716977481"/><m state="8" id="566" cct="1" cts="1716977429"/><m state="8" id="1851" cct="1" cts="1716977480"/><m state="8" id="835" cct="1" cts="1716977433"/><m state="8" id="893" cct="1" cts="1716977435"/><m state="8" id="379" cct="1" cts="1716977432"/><m state="8" id="506" cct="1" cts="1716977379"/><m state="8" id="176" cct="1" cts="1716977432"/><m state="8" id="879" cct="1" cts="1716977432"/><m state="8" id="81" cct="1" cts="1717033274"/><m state="8" id="622" cct="1" cts="1716977433"/><m state="8" id="876" cct="1" cts="1716977430"/><m state="8" id="619" cct="1" cts="1716977483"/><m state="8" id="1153" cct="1" cts="1716977483"/><m state="8" id="681" cct="1" cts="1716977380"/><m state="8" id="1852" cct="1" cts="1716977481"/><m state="8" id="229" cct="1" cts="1716977429"/><m state="8" id="1753" cct="1" cts="1716977433"/><m state="8" id="483" cct="1" cts="1716977483"/><m state="8" id="356" cct="1" cts="1716977484"/><m state="8" id="870" cct="1" cts="1716977482"/><m state="8" id="261" cct="1" cts="1716977482"/><m state="8" id="775" cct="1" cts="1716977432"/><m state="8" id="1293" cct="1" cts="1716977483"/><m state="8" id="522" cct="1" cts="1716977390"/><m state="8" id="779" cct="1" cts="1716977430"/><m state="8" id="525" cct="1" cts="1717029904"/><m state="8" id="476" cct="1" cts="1716977428"/><m state="8" id="733" cct="1" cts="1716977480"/><m state="8" id="1247" cct="1" cts="1716977433"/><m state="8" id="502" cct="1" cts="1716977380"/><m state="8" id="759" cct="1" cts="1716977434"/><m state="8" id="510" cct="1" cts="1716977380"/><m state="8" id="313" cct="1" cts="1716977481"/><m state="8" id="1855" cct="1" cts="1716977481"/><m state="8" id="773" cct="1" cts="1716977432"/><m state="8" id="516" cct="1" cts="1716977484"/><m state="8" id="259" cct="1" cts="1716977480"/><m state="8" id="948" cct="1" cts="1716977832"/><m state="8" id="1151" cct="1" cts="1716977480"/><m state="8" id="590" cct="1" cts="1716977430"/><m state="8" id="593" cct="1" cts="1716977434"/><m state="8" id="511" cct="1" cts="1716977434"/><m state="8" id="688" cct="1" cts="1716977379"/><m state="8" id="815" cct="1" cts="1716977430"/><m state="8" id="942" cct="1" cts="1716977433"/><m state="8" id="685" cct="1" cts="1716944460"/><m state="8" id="287" cct="1" cts="1717029956"/><m state="8" id="544" cct="1" cts="1716977429"/><m state="8" id="877" cct="1" cts="1716977430"/><m state="8" id="1054" cct="1" cts="1716710961"/><m state="8" id="283" cct="1" cts="1716977434"/><m state="8" id="482" cct="1" cts="1716977429"/><m state="8" id="996" cct="1" cts="1716711173"/><m state="8" id="812" cct="1" cts="1716977430"/><m state="8" id="833" cct="1" cts="1716977432"/><m state="8" id="767" cct="1" cts="1716977430"/><m state="8" id="1849" cct="1" cts="1716977480"/><m state="8" id="813" cct="1" cts="1716977430"/><m state="8" id="1847" cct="1" cts="1716977480"/><m state="8" id="577" cct="1" cts="1716977429"/><m state="8" id="1862" cct="1" cts="1716977484"/><m state="8" id="320" cct="1" cts="1716977483"/><m state="8" id="834" cct="1" cts="1716977432"/><m state="8" id="588" cct="1" cts="1716977429"/><m state="8" id="842" cct="1" cts="1716977379"/><m state="8" id="591" cct="1" cts="1716977430"/><m state="8" id="1055" cct="1" cts="1716711087"/><m state="8" id="889" cct="1" cts="1716977431"/><m state="8" id="762" cct="1" cts="1716977380"/><m state="8" id="505" cct="1" cts="1716977380"/><m state="8" id="467" cct="1" cts="1717036052"/><m state="8" id="526" cct="1" cts="1717036047"/><m state="8" id="1133" cct="1" cts="1716711173"/><m state="8" id="592" cct="1" cts="1716977435"/><m state="8" id="254" cct="1" cts="1716977435"/><m state="8" id="1877" cct="1" cts="1716977483"/><m state="8" id="474" cct="1" cts="1716977432"/><m state="8" id="260" cct="1" cts="1716977481"/><m state="8" id="111" cct="1" cts="1716977379"/><m state="8" id="1381" cct="1" cts="1716977432"/><m state="8" id="353" cct="1" cts="1716977484"/><m state="8" id="867" cct="1" cts="1716977430"/><m state="8" id="778" cct="1" cts="1716977431"/><m state="8" id="521" cct="1" cts="1716977390"/><m state="8" id="479" cct="1" cts="1716977480"/><m state="8" id="993" cct="1" cts="1716977434"/><m state="8" id="325" cct="1" cts="1716977483"/><m state="8" id="866" cct="1" cts="1716977430"/><m state="8" id="865" cct="1" cts="1716977430"/><m state="8" id="324" cct="1" cts="1716977484"/><m state="8" id="1848" cct="1" cts="1716977480"/><m state="8" id="268" cct="1" cts="1716977431"/><m state="8" id="809" cct="1" cts="1716977429"/><m state="8" id="633" cct="1" cts="1716977481"/><m state="8" id="781" cct="1" cts="1716977430"/><m state="8" id="1322" cct="1" cts="1716977432"/><m state="8" id="814" cct="1" cts="1716977430"/><m state="8" id="1071" cct="1" cts="1716977484"/><m state="8" id="687" cct="1" cts="1716977434"/><m state="8" id="944" cct="1" cts="1716977433"/><m state="8" id="961" cct="1" cts="1716977431"/><m state="8" id="1732" cct="1" cts="1716977479"/><m state="8" id="768" cct="1" cts="1716977482"/><m state="8" id="1850" cct="1" cts="1716977480"/><m state="8" id="555" cct="1" cts="1716977429"/><m state="8" id="14" cct="1" cts="1716705020"/><m state="8" id="943" cct="1" cts="1716977433"/><m state="8" id="686" cct="1" cts="1716977356"/><m state="8" id="172" cct="1" cts="1716977379"/><m state="8" id="1728" cct="1" cts="1716977483"/><m state="8" id="957" cct="1" cts="1716977483"/><m state="8" id="256" cct="1" cts="1716977434"/><m state="8" id="247" cct="1" cts="1716977434"/><m state="8" id="880" cct="1" cts="1716977483"/><m state="8" id="1324" cct="1" cts="1716977434"/><m state="8" id="242" cct="1" cts="1716977434"/><m state="8" id="537" cct="1" cts="1716977434"/><m state="8" id="598" cct="1" cts="1716977434"/><m state="8" id="684" cct="1" cts="1716977434"/><m state="8" id="939" cct="1" cts="1716977480"/><m state="8" id="207" cct="1" cts="1716977379"/><m state="8" id="355" cct="1" cts="1716977484"/><m state="8" id="142" cct="1" cts="1716977434"/><m state="8" id="399" cct="1" cts="1717036050"/><m state="8" id="940" cct="1" cts="1716977480"/><m state="8" id="40" cct="1" cts="1716977434"/><m state="8" id="776" cct="1" cts="1716977432"/><m state="8" id="317" cct="1" cts="1716977481"/><m state="8" id="858" cct="1" cts="1716977431"/><m state="8" id="316" cct="1" cts="1716977480"/><m state="8" id="857" cct="1" cts="1716977431"/><m state="8" id="315" cct="1" cts="1716977480"/><m state="8" id="314" cct="1" cts="1716977480"/><m state="8" id="774" cct="1" cts="1716977432"/><m state="8" id="1856" cct="1" cts="1716977481"/><m state="8" id="322" cct="1" cts="1716977483"/><m state="8" id="863" cct="1" cts="1716977433"/><m state="8" id="1158" cct="1" cts="1716977484"/><m state="8" id="617" cct="1" cts="1716977433"/><m state="8" id="319" cct="1" cts="1716977483"/><m state="8" id="860" cct="1" cts="1716977431"/><m state="8" id="16" cct="1" cts="1717029764"/><m state="8" id="184" cct="1" cts="1717032860"/></done><cur><m state="2" id="17"><sv v="29"/></m><m state="2" id="421"><sv v="5"/></m><m state="2" id="2044"><sv v="0"/></m><m state="2" id="796"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="282"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1482"><sv v="0"/></m><m state="2" id="454"><sv v="0"/><sv v="5"/><sv v="0"/></m><m state="2" id="1705"><sv v="0"/></m><m state="2" id="82"><sv v="1"/></m><m state="2" id="1164"><sv v="0"/></m><m state="2" id="435"><sv v="0"/></m><m state="2" id="692"><sv v="146"/></m><m state="2" id="1473"><sv v="0"/></m><m state="2" id="543"><sv v="0"/></m><m state="2" id="1928"><sv v="0"/></m><m state="2" id="643"><sv v="0"/></m><m state="2" id="1725"><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1056"><sv v="0"/></m><m state="2" id="1478"><sv v="0"/></m><m state="2" id="937"><sv v="2"/></m><m state="2" id="354"><sv v="0"/><sv v="1"/><sv v="0"/></m><m state="2" id="895"><sv v="0"/></m><m state="2" id="1268"><sv v="0"/></m><m state="2" id="1141"><sv v="6"/></m><m state="2" id="600"><sv v="0"/></m><m state="2" id="616"><sv v="0"/><sv v="0"/><sv v="1"/><sv v="0"/></m><m state="2" id="751"><sv v="0"/></m><m state="2" id="529"><sv v="3"/></m><m state="2" id="251"><sv v="0"/></m><m state="2" id="1488"><sv v="0"/></m><m state="2" id="753"><sv v="0"/></m><m state="2" id="1267"><sv v="0"/></m><m state="2" id="185"><sv v="48"/></m><m state="2" id="2051"><sv v="0"/></m><m state="2" id="1702"><sv v="0"/></m><m state="2" id="620"><sv v="12"/></m><m state="2" id="599"><sv v="0"/></m><m state="2" id="439"><sv v="0"/><sv v="0"/></m><m state="2" id="535"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="789"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="864"><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="448"><sv v="2"/></m><m state="2" id="270"><sv v="300"/></m><m state="2" id="1060"><sv v="2"/></m><m state="2" id="546"><sv v="0"/></m><m state="2" id="597"><sv v="0"/></m><m state="2" id="1138"><sv v="0"/></m><m state="2" id="404"><sv v="56"/></m><m state="2" id="1486"><sv v="0"/></m><m state="2" id="1497"><sv v="0"/></m><m state="2" id="415"><sv v="0"/></m><m state="2" id="405"><sv v="7"/></m><m state="2" id="1487"><sv v="0"/></m><m state="2" id="1230"><sv v="0"/></m><m state="2" id="1470"><sv v="0"/></m><m o="746" state="2" id="1727"><sv v="0"/></m><m state="2" id="645"><sv v="0"/></m><m state="2" id="1930"><sv v="0"/></m><m state="2" id="952"><sv v="0"/></m><m state="2" id="1493"><sv v="0"/></m><m state="2" id="1750"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="647"><sv v="0"/></m><m state="2" id="1469"><sv v="0"/></m><m state="2" id="1114"><sv v="0"/></m><m state="2" id="1344"><sv v="0"/></m><m state="2" id="1088"><sv v="3"/></m><m state="2" id="574"><sv v="0"/></m><m state="2" id="1711"><sv v="0"/></m><m o="813" state="2" id="1196"><sv v="1"/><sv v="1860638409"/></m><m state="2" id="1214"><sv v="0"/></m><m state="2" id="2070"><sv v="0"/></m><m state="2" id="1708"><sv v="0"/></m><m state="2" id="665"><sv v="0"/></m><m state="2" id="568"><sv v="0"/></m><m state="2" id="2068"><sv v="0"/></m><m state="2" id="1040"><sv v="0"/></m><m state="2" id="1271"><sv v="0"/></m><m state="2" id="2067"><sv v="0"/></m><m state="2" id="1058"><sv v="0"/></m><m state="2" id="517"><sv v="1"/></m><m state="2" id="1716"><sv v="11"/></m><m state="2" id="2052"><sv v="0"/></m><m state="2" id="1323"><sv v="0"/></m><m state="2" id="552"><sv v="0"/></m><m state="2" id="1713"><sv v="0"/></m><m state="2" id="1273"><sv v="0"/></m><m state="2" id="1146"><sv v="0"/></m><m state="2" id="638"><sv v="0"/></m><m state="2" id="1372"><sv v="0"/></m><m state="2" id="408"><sv v="0"/></m><m state="2" id="1490"><sv v="0"/></m><m state="2" id="462"><sv v="0"/></m><m state="2" id="2004"><sv v="0"/></m><m state="2" id="205"><sv v="0"/></m><m state="2" id="883"><sv v="0"/></m><m state="2" id="563"><sv v="0"/></m><m state="2" id="1104"><sv v="0"/></m><m state="2" id="955"><sv v="0"/></m><m state="2" id="414"><sv v="0"/></m><m state="2" id="1496"><sv v="0"/></m><m state="2" id="1154"><sv v="9"/></m><m state="2" id="83"><sv v="0"/></m><m state="2" id="1706"><sv v="0"/></m><m state="2" id="2007"><sv v="0"/></m><m state="2" id="1466"><sv v="0"/></m><m state="2" id="849"><sv v="0"/><sv v="0"/></m><m state="2" id="1272"><sv v="0"/></m><m state="2" id="1710"><sv v="0"/></m><m state="2" id="1034"><sv v="0"/></m><m state="2" id="12"><sv v="0"/></m><m state="2" id="1094"><sv v="0"/></m><m state="2" id="934"><sv v="2"/></m><m state="2" id="1475"><sv v="0"/></m><m state="2" id="1703"><sv v="0"/></m><m state="2" id="1148"><sv v="0"/></m><m state="2" id="1479"><sv v="0"/></m><m state="2" id="1168"><sv v="0"/></m><m state="2" id="1709"><sv v="0"/></m><m state="2" id="640"><sv v="0"/></m><m state="2" id="1722"><sv v="0"/></m><m state="2" id="1468"><sv v="0"/></m><m state="2" id="1137"><sv v="0"/></m><m state="2" id="1234"><sv v="0"/></m><m state="2" id="2005"><sv v="0"/></m><m state="2" id="1491"><sv v="0"/></m><m state="2" id="747"><sv v="0"/></m><m state="2" id="206"><sv v="0"/></m><m state="2" id="1110"><sv v="0"/></m><m state="2" id="1373"><sv v="0"/></m><m state="2" id="2049"><sv v="0"/></m><m state="2" id="250"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="885"><sv v="0"/></m><m state="2" id="2046"><sv v="0"/></m><m state="2" id="582"><sv v="0"/></m><m state="2" id="1123"><sv v="0"/></m><m state="2" id="2003"><sv v="0"/></m><m state="2" id="691"><sv v="388"/></m><m state="2" id="1232"><sv v="0"/></m><m state="2" id="1944"><sv v="0"/></m><m state="2" id="1082"><sv v="0"/></m><m state="2" id="639"><sv v="0"/></m><m state="2" id="875"><sv v="0"/></m><m state="2" id="690"><sv v="252"/></m><m state="2" id="433"><sv v="0"/></m><m state="2" id="1269"><sv v="0"/></m><m state="2" id="2048"><sv v="0"/></m><m state="2" id="468"><sv v="0"/></m><m state="2" id="1100"><sv v="5"/></m><m state="2" id="1080"><sv v="0"/></m><m state="2" id="1700"><sv v="0"/></m><m state="2" id="708"><sv v="0"/></m><m state="2" id="1934"><sv v="0"/></m><m state="2" id="1312"><sv v="0"/><sv v="0"/></m><m state="2" id="707"><sv v="0"/></m><m state="2" id="1313"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1107"><sv v="1"/></m><m state="2" id="1704"><sv v="0"/></m><m state="2" id="1701"><sv v="0"/></m><m state="2" id="1311"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="897"><sv v="0"/></m><m state="2" id="1316"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="752"><sv v="0"/></m><m state="2" id="2064"><sv v="0"/></m><m state="2" id="1274"><sv v="0"/></m><m state="2" id="706"><sv v="0"/></m><m state="2" id="1314"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1057"><sv v="0"/></m><m state="2" id="1489"><sv v="0"/></m><m state="2" id="1134"><sv v="1"/></m><m state="2" id="1483"><sv v="0"/></m><m state="2" id="1199"><sv v="1"/><sv v="1860638409"/></m><m state="2" id="1369"><sv v="1"/></m><m state="2" id="1374"><sv v="0"/></m><m state="2" id="1915"><sv v="0"/></m><m state="2" id="1943"><sv v="0"/></m><m state="2" id="861"><sv v="0"/></m><m state="2" id="293"><sv v="25"/><sv v="25"/><sv v="3"/></m><m state="2" id="2047"><sv v="0"/></m><m state="2" id="1752"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="882"><sv v="0"/></m><m state="2" id="894"><sv v="0"/></m><m state="2" id="1350"><sv v="2"/></m><m state="2" id="1147"><sv v="0"/></m><m state="2" id="2066"><sv v="0"/></m><m state="2" id="1038"><sv v="0"/></m><m state="2" id="1485"><sv v="0"/></m><m state="2" id="403"><sv v="3"/></m><m state="2" id="2043"><sv v="0"/></m><m state="2" id="1191"><sv v="0"/></m><m state="2" id="1484"><sv v="0"/></m><m state="2" id="402"><sv v="41"/></m><m state="2" id="646"><sv v="0"/></m><m state="2" id="416"><sv v="0"/></m><m state="2" id="1498"><sv v="0"/></m><m state="2" id="2012"><sv v="0"/></m><m state="2" id="1471"><sv v="0"/></m><m state="2" id="788"><sv v="0"/><sv v="0"/></m><m state="2" id="1329"><sv v="0"/></m><m state="2" id="1270"><sv v="0"/></m><m state="2" id="2041"><sv v="0"/></m><m state="2" id="1139"><sv v="0"/></m><m state="2" id="1969"><sv v="0"/></m><m state="2" id="1712"><sv v="0"/></m><m state="2" id="1480"><sv v="0"/></m><m state="2" id="748"><sv v="0"/></m><m state="2" id="896"><sv v="0"/></m><m state="2" id="683"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1481"><sv v="0"/></m><m state="2" id="1317"><sv v="0"/><sv v="0"/></m><m state="2" id="1940"><sv v="0"/></m><m state="2" id="1939"><sv v="0"/></m><m state="2" id="1938"><sv v="0"/></m><m state="2" id="856"><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1937"><sv v="0"/></m><m state="2" id="233"><sv v="0"/></m><m state="2" id="1315"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1945"><sv v="0"/></m><m state="2" id="579"><sv v="0"/></m><m state="2" id="1120"><sv v="6"/></m><m state="2" id="1972"><sv v="0"/></m><m state="2" id="349"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="847"><sv v="0"/></m><m state="2" id="1929"><sv v="0"/></m><m state="2" id="1699"><sv v="0"/></m><m state="2" id="360"><sv v="0"/></m><m state="2" id="1942"><sv v="0"/></m><m state="2" id="1117"><sv v="1"/></m><m state="2" id="557"><sv v="0"/></m><m state="2" id="644"><sv v="0"/></m><m state="2" id="1726"><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="790"><sv v="1"/></m><m state="2" id="1933"><sv v="0"/></m><m state="2" id="851"><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1178"><sv v="0"/></m><m state="2" id="1166"><sv v="0"/></m><m state="2" id="1707"><sv v="0"/></m><m state="2" id="892"><sv v="0"/></m><m state="2" id="806"><sv v="0"/></m><m state="2" id="2065"><sv v="0"/></m><m state="2" id="669"><sv v="0"/></m><m state="2" id="1751"><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="750"><sv v="0"/></m><m state="2" id="209"><sv v="2"/></m><m state="2" id="412"><sv v="0"/></m><m state="2" id="1494"><sv v="0"/></m><m state="2" id="953"><sv v="0"/></m><m state="2" id="1467"><sv v="0"/></m><m state="2" id="1472"><sv v="0"/></m><m state="2" id="958"><sv v="0"/></m><m state="2" id="417"><sv v="0"/></m><m state="2" id="1495"><sv v="0"/></m><m state="2" id="413"><sv v="0"/></m><m state="2" id="954"><sv v="0"/></m><m state="2" id="1492"><sv v="0"/></m><m state="2" id="410"><sv v="0"/></m><m state="2" id="666"><sv v="0"/></m><m state="2" id="1748"><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="1724"><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="642"><sv v="0"/></m><m state="2" id="936"><sv v="0"/></m><m state="2" id="1477"><sv v="0"/></m><m state="2" id="641"><sv v="0"/></m><m state="2" id="1723"><sv v="0"/><sv v="0"/><sv v="0"/><sv v="0"/></m><m state="2" id="933"><sv v="2"/></m><m state="2" id="1474"><sv v="0"/></m><m state="2" id="2042"><sv v="0"/></m><m state="2" id="419"><sv v="0"/></m><m state="2" id="960"><sv v="0"/></m><m state="2" id="709"><sv v="0"/></m><m state="2" id="1476"><sv v="0"/></m><m state="2" id="935"><sv v="2"/></m><m state="2" id="427"><sv v="0"/></m><m state="2" id="2050"><sv v="0"/></m><m state="2" id="1059"><sv v="0"/></m><m state="2" id="2045"><sv v="0"/></m><m state="2" id="1290"><sv v="0"/></m><m state="2" id="749"><sv v="0"/></m><m state="2" id="208"><sv v="0"/></m><m state="2" id="1005"><sv v="0"/></m><m state="2" id="244"><sv v="32"/></m><m state="2" id="13"><sv v="0"/></m><m state="2" id="527"><sv v="8"/></m></cur></mis><pet><p id="1152921510439550141" l="5637" m="1" n="" t="0"/><p id="1152921510433975245" l="5637" m="1" n="" t="0"/></pet></obj> diff --git a/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp index e62c6d179..528136e17 100644 --- a/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp +++ b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp @@ -87,9 +87,8 @@ TEST_F(GameMessageTests, SendBlueprintLoadItemResponse) { TEST_F(GameMessageTests, ControlBehaviorAddStrip) { auto data = ReadFromFile("addStrip"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - AddStripMessage addStrip(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + AddStripMessage addStrip(ReadArrayFromBitStream(inStream)); ASSERT_FLOAT_EQ(addStrip.GetPosition().GetX(), 50.65); ASSERT_FLOAT_EQ(addStrip.GetPosition().GetY(), 178.05); ASSERT_EQ(addStrip.GetActionContext().GetStripId(), 0); @@ -103,9 +102,8 @@ TEST_F(GameMessageTests, ControlBehaviorAddStrip) { TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) { auto data = ReadFromFile("removeStrip"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - RemoveStripMessage removeStrip(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + RemoveStripMessage removeStrip(ReadArrayFromBitStream(inStream)); ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStripId()), 1); ASSERT_EQ(static_cast<int32_t>(removeStrip.GetActionContext().GetStateId()), 0); ASSERT_EQ(removeStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); @@ -113,9 +111,8 @@ TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) { TEST_F(GameMessageTests, ControlBehaviorMergeStrips) { auto data = ReadFromFile("mergeStrips"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - MergeStripsMessage mergeStrips(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + MergeStripsMessage mergeStrips(ReadArrayFromBitStream(inStream)); ASSERT_EQ(mergeStrips.GetSourceActionContext().GetStripId(), 2); ASSERT_EQ(mergeStrips.GetDestinationActionContext().GetStripId(), 0); ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetSourceActionContext().GetStateId()), 0); @@ -126,10 +123,9 @@ TEST_F(GameMessageTests, ControlBehaviorMergeStrips) { TEST_F(GameMessageTests, ControlBehaviorSplitStrip) { auto data = ReadFromFile("splitStrip"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - SplitStripMessage splitStrip(*msg); - ASSERT_EQ(splitStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + SplitStripMessage splitStrip(ReadArrayFromBitStream(inStream)); + ASSERT_EQ(splitStrip.GetBehaviorId(), -1); ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetX(), 275.65); ASSERT_FLOAT_EQ(splitStrip.GetPosition().GetY(), 28.7); @@ -142,9 +138,8 @@ TEST_F(GameMessageTests, ControlBehaviorSplitStrip) { TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) { auto data = ReadFromFile("updateStripUI"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - UpdateStripUiMessage updateStripUi(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + UpdateStripUiMessage updateStripUi(ReadArrayFromBitStream(inStream)); ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetX(), 116.65); ASSERT_FLOAT_EQ(updateStripUi.GetPosition().GetY(), 35.35); ASSERT_EQ(updateStripUi.GetActionContext().GetStripId(), 0); @@ -154,9 +149,8 @@ TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) { TEST_F(GameMessageTests, ControlBehaviorAddAction) { auto data = ReadFromFile("addAction"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - AddActionMessage addAction{ *msg }; + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + AddActionMessage addAction(ReadArrayFromBitStream(inStream)); ASSERT_EQ(addAction.GetActionIndex(), 3); ASSERT_EQ(addAction.GetActionContext().GetStripId(), 0); ASSERT_EQ(static_cast<uint32_t>(addAction.GetActionContext().GetStateId()), 0); @@ -169,9 +163,8 @@ TEST_F(GameMessageTests, ControlBehaviorAddAction) { TEST_F(GameMessageTests, ControlBehaviorMigrateActions) { auto data = ReadFromFile("migrateActions"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - MigrateActionsMessage migrateActions(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + MigrateActionsMessage migrateActions(ReadArrayFromBitStream(inStream)); ASSERT_EQ(migrateActions.GetSrcActionIndex(), 1); ASSERT_EQ(migrateActions.GetDstActionIndex(), 2); ASSERT_EQ(migrateActions.GetSourceActionContext().GetStripId(), 1); @@ -183,9 +176,8 @@ TEST_F(GameMessageTests, ControlBehaviorMigrateActions) { TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) { auto data = ReadFromFile("rearrangeStrip"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - RearrangeStripMessage rearrangeStrip(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + RearrangeStripMessage rearrangeStrip(ReadArrayFromBitStream(inStream)); ASSERT_EQ(rearrangeStrip.GetSrcActionIndex(), 2); ASSERT_EQ(rearrangeStrip.GetDstActionIndex(), 1); ASSERT_EQ(rearrangeStrip.GetActionContext().GetStripId(), 0); @@ -195,18 +187,16 @@ TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) { TEST_F(GameMessageTests, ControlBehaviorAdd) { auto data = ReadFromFile("add"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - AddMessage add(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + AddMessage add(ReadArrayFromBitStream(inStream)); ASSERT_EQ(add.GetBehaviorId(), 10446); ASSERT_EQ(add.GetBehaviorIndex(), 0); } TEST_F(GameMessageTests, ControlBehaviorRemoveActions) { auto data = ReadFromFile("removeActions"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - RemoveActionsMessage removeActions(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + RemoveActionsMessage removeActions(ReadArrayFromBitStream(inStream)); ASSERT_EQ(removeActions.GetBehaviorId(), -1); ASSERT_EQ(removeActions.GetActionIndex(), 1); ASSERT_EQ(removeActions.GetActionContext().GetStripId(), 0); @@ -215,18 +205,16 @@ TEST_F(GameMessageTests, ControlBehaviorRemoveActions) { TEST_F(GameMessageTests, ControlBehaviorRename) { auto data = ReadFromFile("rename"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - RenameMessage rename(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + RenameMessage rename(ReadArrayFromBitStream(inStream)); ASSERT_EQ(rename.GetName(), "test"); ASSERT_EQ(rename.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); } TEST_F(GameMessageTests, ControlBehaviorUpdateAction) { auto data = ReadFromFile("updateAction"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - auto msg = ReadArrayFromBitStream(inStream); - UpdateActionMessage updateAction(*msg); + RakNet::BitStream inStream(reinterpret_cast<unsigned char*>(&data[0]), data.length(), true); + UpdateActionMessage updateAction(ReadArrayFromBitStream(inStream)); ASSERT_EQ(updateAction.GetAction().GetType(), "FlyDown"); ASSERT_EQ(updateAction.GetAction().GetValueParameterName(), "Distance"); ASSERT_EQ(updateAction.GetAction().GetValueParameterString(), ""); diff --git a/tests/dGameTests/dGameMessagesTests/LegacyGameMessageTests.cpp b/tests/dGameTests/dGameMessagesTests/LegacyGameMessageTests.cpp index 0226b0adb..a1f4bf856 100644 --- a/tests/dGameTests/dGameMessagesTests/LegacyGameMessageTests.cpp +++ b/tests/dGameTests/dGameMessagesTests/LegacyGameMessageTests.cpp @@ -1,298 +1,298 @@ #include <gtest/gtest.h> -#include "eGameMessageType.h" +#include "MessageType/Game.h" TEST(LegacyGameMessageTests, AssertLegacyGmValues) { - EXPECT_EQ(eGameMessageType::TELEPORT, (eGameMessageType)19); - EXPECT_EQ(eGameMessageType::SET_PLAYER_CONTROL_SCHEME, (eGameMessageType)26); - EXPECT_EQ(eGameMessageType::DROP_CLIENT_LOOT, (eGameMessageType)30); - EXPECT_EQ(eGameMessageType::DIE, (eGameMessageType)37); - EXPECT_EQ(eGameMessageType::REQUEST_DIE, (eGameMessageType)38); - EXPECT_EQ(eGameMessageType::PLAY_EMOTE, (eGameMessageType)41); - EXPECT_EQ(eGameMessageType::PLAY_ANIMATION, (eGameMessageType)43); - EXPECT_EQ(eGameMessageType::CONTROL_BEHAVIORS, (eGameMessageType)48); - EXPECT_EQ(eGameMessageType::SET_NAME, (eGameMessageType)72); - EXPECT_EQ(eGameMessageType::ECHO_START_SKILL, (eGameMessageType)118); - EXPECT_EQ(eGameMessageType::START_SKILL, (eGameMessageType)119); - EXPECT_EQ(eGameMessageType::VERIFY_ACK, (eGameMessageType)121); - EXPECT_EQ(eGameMessageType::ADD_SKILL, (eGameMessageType)127); - EXPECT_EQ(eGameMessageType::REMOVE_SKILL, (eGameMessageType)128); - EXPECT_EQ(eGameMessageType::SET_CURRENCY, (eGameMessageType)133); - EXPECT_EQ(eGameMessageType::PICKUP_CURRENCY, (eGameMessageType)137); - EXPECT_EQ(eGameMessageType::PICKUP_ITEM, (eGameMessageType)139); - EXPECT_EQ(eGameMessageType::TEAM_PICKUP_ITEM, (eGameMessageType)140); - EXPECT_EQ(eGameMessageType::PLAY_FX_EFFECT, (eGameMessageType)154); - EXPECT_EQ(eGameMessageType::STOP_FX_EFFECT, (eGameMessageType)155); - EXPECT_EQ(eGameMessageType::REQUEST_RESURRECT, (eGameMessageType)159); - EXPECT_EQ(eGameMessageType::RESURRECT, (eGameMessageType)160); - EXPECT_EQ(eGameMessageType::PUSH_EQUIPPED_ITEMS_STATE, (eGameMessageType)191); - EXPECT_EQ(eGameMessageType::POP_EQUIPPED_ITEMS_STATE, (eGameMessageType)192); - EXPECT_EQ(eGameMessageType::SET_GM_LEVEL, (eGameMessageType)193); - EXPECT_EQ(eGameMessageType::SET_STUNNED, (eGameMessageType)198); - EXPECT_EQ(eGameMessageType::SET_STUN_IMMUNITY, (eGameMessageType)200); - EXPECT_EQ(eGameMessageType::KNOCKBACK, (eGameMessageType)202); - EXPECT_EQ(eGameMessageType::REBUILD_CANCEL, (eGameMessageType)209); - EXPECT_EQ(eGameMessageType::ENABLE_REBUILD, (eGameMessageType)213); - EXPECT_EQ(eGameMessageType::MOVE_ITEM_IN_INVENTORY, (eGameMessageType)224); - EXPECT_EQ(eGameMessageType::ADD_ITEM_TO_INVENTORY_CLIENT_SYNC, (eGameMessageType)227); - EXPECT_EQ(eGameMessageType::REMOVE_ITEM_FROM_INVENTORY, (eGameMessageType)230); - EXPECT_EQ(eGameMessageType::EQUIP_INVENTORY, (eGameMessageType)231); - EXPECT_EQ(eGameMessageType::UN_EQUIP_INVENTORY, (eGameMessageType)233); - EXPECT_EQ(eGameMessageType::OFFER_MISSION, (eGameMessageType)248); - EXPECT_EQ(eGameMessageType::RESPOND_TO_MISSION, (eGameMessageType)249); - EXPECT_EQ(eGameMessageType::NOTIFY_MISSION, (eGameMessageType)254); - EXPECT_EQ(eGameMessageType::NOTIFY_MISSION_TASK, (eGameMessageType)255); - EXPECT_EQ(eGameMessageType::REBUILD_NOTIFY_STATE, (eGameMessageType)336); - EXPECT_EQ(eGameMessageType::TERMINATE_INTERACTION, (eGameMessageType)357); - EXPECT_EQ(eGameMessageType::SERVER_TERMINATE_INTERACTION, (eGameMessageType)358); - EXPECT_EQ(eGameMessageType::REQUEST_USE, (eGameMessageType)364); - EXPECT_EQ(eGameMessageType::VENDOR_OPEN_WINDOW, (eGameMessageType)369); - EXPECT_EQ(eGameMessageType::BUY_FROM_VENDOR, (eGameMessageType)373); - EXPECT_EQ(eGameMessageType::SELL_TO_VENDOR, (eGameMessageType)374); - EXPECT_EQ(eGameMessageType::TEAM_SET_OFF_WORLD_FLAG, (eGameMessageType)383); - EXPECT_EQ(eGameMessageType::SET_INVENTORY_SIZE, (eGameMessageType)389); - EXPECT_EQ(eGameMessageType::ACKNOWLEDGE_POSSESSION, (eGameMessageType)391); - EXPECT_EQ(eGameMessageType::SET_SHOOTING_GALLERY_PARAMS, (eGameMessageType)400); - EXPECT_EQ(eGameMessageType::REQUEST_ACTIVITY_START_STOP, (eGameMessageType)402); - EXPECT_EQ(eGameMessageType::REQUEST_ACTIVITY_ENTER, (eGameMessageType)403); - EXPECT_EQ(eGameMessageType::REQUEST_ACTIVITY_EXIT, (eGameMessageType)404); - EXPECT_EQ(eGameMessageType::ACTIVITY_ENTER, (eGameMessageType)405); - EXPECT_EQ(eGameMessageType::ACTIVITY_EXIT, (eGameMessageType)406); - EXPECT_EQ(eGameMessageType::ACTIVITY_START, (eGameMessageType)407); - EXPECT_EQ(eGameMessageType::ACTIVITY_STOP, (eGameMessageType)408); - EXPECT_EQ(eGameMessageType::SHOOTING_GALLERY_CLIENT_AIM_UPDATE, (eGameMessageType)409); - EXPECT_EQ(eGameMessageType::SHOOTING_GALLERY_FIRE, (eGameMessageType)411); - EXPECT_EQ(eGameMessageType::REQUEST_VENDOR_STATUS_UPDATE, (eGameMessageType)416); - EXPECT_EQ(eGameMessageType::VENDOR_STATUS_UPDATE, (eGameMessageType)417); - EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE, (eGameMessageType)425); - EXPECT_EQ(eGameMessageType::CONSUME_CLIENT_ITEM, (eGameMessageType)427); - EXPECT_EQ(eGameMessageType::CLIENT_ITEM_CONSUMED, (eGameMessageType)428); - EXPECT_EQ(eGameMessageType::UPDATE_SHOOTING_GALLERY_ROTATION, (eGameMessageType)448); - EXPECT_EQ(eGameMessageType::SET_FLAG, (eGameMessageType)471); - EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_FLAG_CHANGE, (eGameMessageType)472); - EXPECT_EQ(eGameMessageType::VENDOR_TRANSACTION_RESULT, (eGameMessageType)476); - EXPECT_EQ(eGameMessageType::HAS_BEEN_COLLECTED, (eGameMessageType)486); - EXPECT_EQ(eGameMessageType::DISPLAY_CHAT_BUBBLE, (eGameMessageType)495); - EXPECT_EQ(eGameMessageType::SPAWN_PET, (eGameMessageType)498); - EXPECT_EQ(eGameMessageType::DESPAWN_PET, (eGameMessageType)499); - EXPECT_EQ(eGameMessageType::PLAYER_LOADED, (eGameMessageType)505); - EXPECT_EQ(eGameMessageType::PLAYER_READY, (eGameMessageType)509); - EXPECT_EQ(eGameMessageType::REQUEST_LINKED_MISSION, (eGameMessageType)515); - EXPECT_EQ(eGameMessageType::INVALID_ZONE_TRANSFER_LIST, (eGameMessageType)519); - EXPECT_EQ(eGameMessageType::MISSION_DIALOGUE_OK, (eGameMessageType)520); - EXPECT_EQ(eGameMessageType::DISPLAY_MESSAGE_BOX, (eGameMessageType)529); - EXPECT_EQ(eGameMessageType::MESSAGE_BOX_RESPOND, (eGameMessageType)530); - EXPECT_EQ(eGameMessageType::CHOICE_BOX_RESPOND, (eGameMessageType)531); - EXPECT_EQ(eGameMessageType::SMASH, (eGameMessageType)537); - EXPECT_EQ(eGameMessageType::UN_SMASH, (eGameMessageType)538); - EXPECT_EQ(eGameMessageType::PLACE_MODEL_RESPONSE, (eGameMessageType)547); - EXPECT_EQ(eGameMessageType::SET_SHOOTING_GALLERY_RETICULE_EFFECT, (eGameMessageType)546); - EXPECT_EQ(eGameMessageType::SET_JET_PACK_MODE, (eGameMessageType)561); - EXPECT_EQ(eGameMessageType::REGISTER_PET_ID, (eGameMessageType)565); - EXPECT_EQ(eGameMessageType::REGISTER_PET_DBID, (eGameMessageType)566); - EXPECT_EQ(eGameMessageType::SHOW_ACTIVITY_COUNTDOWN, (eGameMessageType)568); - EXPECT_EQ(eGameMessageType::START_ACTIVITY_TIME, (eGameMessageType)576); - EXPECT_EQ(eGameMessageType::ACTIVITY_PAUSE, (eGameMessageType)602); - EXPECT_EQ(eGameMessageType::USE_NON_EQUIPMENT_ITEM, (eGameMessageType)603); - EXPECT_EQ(eGameMessageType::USE_ITEM_RESULT, (eGameMessageType)607); - EXPECT_EQ(eGameMessageType::COMMAND_PET, (eGameMessageType)640); - EXPECT_EQ(eGameMessageType::PET_RESPONSE, (eGameMessageType)641); - EXPECT_EQ(eGameMessageType::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA, (eGameMessageType)648); - EXPECT_EQ(eGameMessageType::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA, (eGameMessageType)649); - EXPECT_EQ(eGameMessageType::NOTIFY_OBJECT, (eGameMessageType)656); - EXPECT_EQ(eGameMessageType::CLIENT_NOTIFY_PET, (eGameMessageType)659); - EXPECT_EQ(eGameMessageType::NOTIFY_PET, (eGameMessageType)660); - EXPECT_EQ(eGameMessageType::NOTIFY_PET_TAMING_MINIGAME, (eGameMessageType)661); - EXPECT_EQ(eGameMessageType::START_SERVER_PET_MINIGAME_TIMER, (eGameMessageType)662); - EXPECT_EQ(eGameMessageType::CLIENT_EXIT_TAMING_MINIGAME, (eGameMessageType)663); - EXPECT_EQ(eGameMessageType::PET_NAME_CHANGED, (eGameMessageType)686); - EXPECT_EQ(eGameMessageType::PET_TAMING_MINIGAME_RESULT, (eGameMessageType)667); - EXPECT_EQ(eGameMessageType::PET_TAMING_TRY_BUILD_RESULT, (eGameMessageType)668); - EXPECT_EQ(eGameMessageType::NOTIFY_TAMING_BUILD_SUCCESS, (eGameMessageType)673); - EXPECT_EQ(eGameMessageType::NOTIFY_TAMING_MODEL_LOADED_ON_SERVER, (eGameMessageType)674); - EXPECT_EQ(eGameMessageType::ACTIVATE_BUBBLE_BUFF, (eGameMessageType)678); - EXPECT_EQ(eGameMessageType::DECTIVATE_BUBBLE_BUFF, (eGameMessageType)679); - EXPECT_EQ(eGameMessageType::ADD_PET_TO_PLAYER, (eGameMessageType)681); - EXPECT_EQ(eGameMessageType::REQUEST_SET_PET_NAME, (eGameMessageType)683); - EXPECT_EQ(eGameMessageType::SET_PET_NAME, (eGameMessageType)684); - EXPECT_EQ(eGameMessageType::NOTIFY_TAMING_PUZZLE_SELECTED, (eGameMessageType)675); - EXPECT_EQ(eGameMessageType::SHOW_PET_ACTION_BUTTON, (eGameMessageType)692); - EXPECT_EQ(eGameMessageType::SET_EMOTE_LOCK_STATE, (eGameMessageType)693); - EXPECT_EQ(eGameMessageType::USE_ITEM_REQUIREMENTS_RESPONSE, (eGameMessageType)703); - EXPECT_EQ(eGameMessageType::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT, (eGameMessageType)713); - EXPECT_EQ(eGameMessageType::DOWNLOAD_PROPERTY_DATA, (eGameMessageType)716); - EXPECT_EQ(eGameMessageType::QUERY_PROPERTY_DATA, (eGameMessageType)717); - EXPECT_EQ(eGameMessageType::PROPERTY_EDITOR_BEGIN, (eGameMessageType)724); - EXPECT_EQ(eGameMessageType::PROPERTY_EDITOR_END, (eGameMessageType)725); - EXPECT_EQ(eGameMessageType::IS_MINIFIG_IN_A_BUBBLE, (eGameMessageType)729); - EXPECT_EQ(eGameMessageType::START_PATHING, (eGameMessageType)733); - EXPECT_EQ(eGameMessageType::ACTIVATE_BUBBLE_BUFF_FROM_SERVER, (eGameMessageType)734); - EXPECT_EQ(eGameMessageType::DEACTIVATE_BUBBLE_BUFF_FROM_SERVER, (eGameMessageType)735); - EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_ZONE_OBJECT, (eGameMessageType)737); - EXPECT_EQ(eGameMessageType::UPDATE_REPUTATION, (eGameMessageType)746); - EXPECT_EQ(eGameMessageType::PROPERTY_RENTAL_RESPONSE, (eGameMessageType)750); - EXPECT_EQ(eGameMessageType::REQUEST_PLATFORM_RESYNC, (eGameMessageType)760); - EXPECT_EQ(eGameMessageType::PLATFORM_RESYNC, (eGameMessageType)761); - EXPECT_EQ(eGameMessageType::PLAY_CINEMATIC, (eGameMessageType)762); - EXPECT_EQ(eGameMessageType::END_CINEMATIC, (eGameMessageType)763); - EXPECT_EQ(eGameMessageType::CINEMATIC_UPDATE, (eGameMessageType)764); - EXPECT_EQ(eGameMessageType::TOGGLE_GHOST_REFERENCE_OVERRIDE, (eGameMessageType)767); - EXPECT_EQ(eGameMessageType::SET_GHOST_REFERENCE_POSITION, (eGameMessageType)768); - EXPECT_EQ(eGameMessageType::FIRE_EVENT_SERVER_SIDE, (eGameMessageType)770); - EXPECT_EQ(eGameMessageType::SCRIPT_NETWORK_VAR_UPDATE, (eGameMessageType)781); - EXPECT_EQ(eGameMessageType::UPDATE_MODEL_FROM_CLIENT, (eGameMessageType)793); - EXPECT_EQ(eGameMessageType::DELETE_MODEL_FROM_CLIENT, (eGameMessageType)794); - EXPECT_EQ(eGameMessageType::PLAY_ND_AUDIO_EMITTER, (eGameMessageType)821); - EXPECT_EQ(eGameMessageType::PLAY2_D_AMBIENT_SOUND, (eGameMessageType)831); - EXPECT_EQ(eGameMessageType::ENTER_PROPERTY1, (eGameMessageType)840); - EXPECT_EQ(eGameMessageType::ENTER_PROPERTY2, (eGameMessageType)841); - EXPECT_EQ(eGameMessageType::PROPERTY_ENTRANCE_SYNC, (eGameMessageType)842); - EXPECT_EQ(eGameMessageType::PROPERTY_SELECT_QUERY, (eGameMessageType)845); - EXPECT_EQ(eGameMessageType::PARSE_CHAT_MESSAGE, (eGameMessageType)850); - EXPECT_EQ(eGameMessageType::BROADCAST_TEXT_TO_CHATBOX, (eGameMessageType)858); - EXPECT_EQ(eGameMessageType::OPEN_PROPERTY_MANAGEMENT, (eGameMessageType)860); - EXPECT_EQ(eGameMessageType::OPEN_PROPERTY_VENDOR, (eGameMessageType)861); - EXPECT_EQ(eGameMessageType::UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK, (eGameMessageType)863); - EXPECT_EQ(eGameMessageType::CLIENT_TRADE_REQUEST, (eGameMessageType)868); - EXPECT_EQ(eGameMessageType::SERVER_TRADE_REQUEST, (eGameMessageType)869); - EXPECT_EQ(eGameMessageType::SERVER_TRADE_INVITE, (eGameMessageType)870); - EXPECT_EQ(eGameMessageType::CLIENT_TRADE_REPLY, (eGameMessageType)871); - EXPECT_EQ(eGameMessageType::SERVER_TRADE_REPLY, (eGameMessageType)872); - EXPECT_EQ(eGameMessageType::SERVER_TRADE_INITIAL_REPLY, (eGameMessageType)873); - EXPECT_EQ(eGameMessageType::SERVER_TRADE_FINAL_REPLY, (eGameMessageType)874); - EXPECT_EQ(eGameMessageType::CLIENT_TRADE_UPDATE, (eGameMessageType)875); - EXPECT_EQ(eGameMessageType::SERVER_SIDE_TRADE_UPDATE, (eGameMessageType)876); - EXPECT_EQ(eGameMessageType::SERVER_TRADE_UPDATE, (eGameMessageType)877); - EXPECT_EQ(eGameMessageType::CLIENT_TRADE_CANCEL, (eGameMessageType)878); - EXPECT_EQ(eGameMessageType::CLIENT_SIDE_TRADE_CANCEL, (eGameMessageType)879); - EXPECT_EQ(eGameMessageType::CLIENT_TRADE_ACCEPT, (eGameMessageType)880); - EXPECT_EQ(eGameMessageType::SERVER_SIDE_TRADE_ACCEPT, (eGameMessageType)881); - EXPECT_EQ(eGameMessageType::SERVER_SIDE_TRADE_CANCEL, (eGameMessageType)882); - EXPECT_EQ(eGameMessageType::SERVER_TRADE_CANCEL, (eGameMessageType)883); - EXPECT_EQ(eGameMessageType::SERVER_TRADE_ACCEPT, (eGameMessageType)884); - EXPECT_EQ(eGameMessageType::READY_FOR_UPDATES, (eGameMessageType)888); - EXPECT_EQ(eGameMessageType::ORIENT_TO_OBJECT, (eGameMessageType)905); - EXPECT_EQ(eGameMessageType::ORIENT_TO_POSITION, (eGameMessageType)906); - EXPECT_EQ(eGameMessageType::ORIENT_TO_ANGLE, (eGameMessageType)907); - EXPECT_EQ(eGameMessageType::BOUNCER_ACTIVE_STATUS, (eGameMessageType)942); - EXPECT_EQ(eGameMessageType::UN_USE_BBB_MODEL, (eGameMessageType)999); - EXPECT_EQ(eGameMessageType::BBB_LOAD_ITEM_REQUEST, (eGameMessageType)1000); - EXPECT_EQ(eGameMessageType::BBB_SAVE_REQUEST, (eGameMessageType)1001); - EXPECT_EQ(eGameMessageType::BBB_SAVE_RESPONSE, (eGameMessageType)1005); - EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_OBJECT, (eGameMessageType)1042); - EXPECT_EQ(eGameMessageType::DISPLAY_ZONE_SUMMARY, (eGameMessageType)1043); - EXPECT_EQ(eGameMessageType::ZONE_SUMMARY_DISMISSED, (eGameMessageType)1044); - EXPECT_EQ(eGameMessageType::ACTIVITY_STATE_CHANGE_REQUEST, (eGameMessageType)1053); - EXPECT_EQ(eGameMessageType::MODIFY_PLAYER_ZONE_STATISTIC, (eGameMessageType)1046); - EXPECT_EQ(eGameMessageType::START_BUILDING_WITH_ITEM, (eGameMessageType)1057); - EXPECT_EQ(eGameMessageType::START_ARRANGING_WITH_ITEM, (eGameMessageType)1061); - EXPECT_EQ(eGameMessageType::FINISH_ARRANGING_WITH_ITEM, (eGameMessageType)1062); - EXPECT_EQ(eGameMessageType::DONE_ARRANGING_WITH_ITEM, (eGameMessageType)1063); - EXPECT_EQ(eGameMessageType::SET_BUILD_MODE, (eGameMessageType)1068); - EXPECT_EQ(eGameMessageType::BUILD_MODE_SET, (eGameMessageType)1069); - EXPECT_EQ(eGameMessageType::SET_BUILD_MODE_CONFIRMED, (eGameMessageType)1073); - EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_FAILED_PRECONDITION, (eGameMessageType)1081); - EXPECT_EQ(eGameMessageType::MOVE_ITEM_BETWEEN_INVENTORY_TYPES, (eGameMessageType)1093); - EXPECT_EQ(eGameMessageType::MODULAR_BUILD_BEGIN, (eGameMessageType)1094); - EXPECT_EQ(eGameMessageType::MODULAR_BUILD_END, (eGameMessageType)1095); - EXPECT_EQ(eGameMessageType::MODULAR_BUILD_MOVE_AND_EQUIP, (eGameMessageType)1096); - EXPECT_EQ(eGameMessageType::MODULAR_BUILD_FINISH, (eGameMessageType)1097); - EXPECT_EQ(eGameMessageType::REPORT_BUG, (eGameMessageType)1198); - EXPECT_EQ(eGameMessageType::MISSION_DIALOGUE_CANCELLED, (eGameMessageType)1129); - EXPECT_EQ(eGameMessageType::ECHO_SYNC_SKILL, (eGameMessageType)1144); - EXPECT_EQ(eGameMessageType::SYNC_SKILL, (eGameMessageType)1145); - EXPECT_EQ(eGameMessageType::REQUEST_SERVER_PROJECTILE_IMPACT, (eGameMessageType)1148); - EXPECT_EQ(eGameMessageType::DO_CLIENT_PROJECTILE_IMPACT, (eGameMessageType)1151); - EXPECT_EQ(eGameMessageType::MODULAR_BUILD_CONVERT_MODEL, (eGameMessageType)1155); - EXPECT_EQ(eGameMessageType::SET_PLAYER_ALLOWED_RESPAWN, (eGameMessageType)1165); - EXPECT_EQ(eGameMessageType::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT, (eGameMessageType)1184); - EXPECT_EQ(eGameMessageType::UI_MESSAGE_SERVER_TO_ALL_CLIENTS, (eGameMessageType)1185); - EXPECT_EQ(eGameMessageType::PET_TAMING_TRY_BUILD, (eGameMessageType)1197); - EXPECT_EQ(eGameMessageType::REQUEST_SMASH_PLAYER, (eGameMessageType)1202); - EXPECT_EQ(eGameMessageType::FIRE_EVENT_CLIENT_SIDE, (eGameMessageType)1213); - EXPECT_EQ(eGameMessageType::TOGGLE_GM_INVIS, (eGameMessageType)1218); - EXPECT_EQ(eGameMessageType::CHANGE_OBJECT_WORLD_STATE, (eGameMessageType)1223); - EXPECT_EQ(eGameMessageType::VEHICLE_LOCK_INPUT, (eGameMessageType)1230); - EXPECT_EQ(eGameMessageType::VEHICLE_UNLOCK_INPUT, (eGameMessageType)1231); - EXPECT_EQ(eGameMessageType::RACING_RESET_PLAYER_TO_LAST_RESET, (eGameMessageType)1252); - EXPECT_EQ(eGameMessageType::RACING_SERVER_SET_PLAYER_LAP_AND_PLANE, (eGameMessageType)1253); - EXPECT_EQ(eGameMessageType::RACING_SET_PLAYER_RESET_INFO, (eGameMessageType)1254); - EXPECT_EQ(eGameMessageType::RACING_PLAYER_INFO_RESET_FINISHED, (eGameMessageType)1255); - EXPECT_EQ(eGameMessageType::LOCK_NODE_ROTATION, (eGameMessageType)1260); - EXPECT_EQ(eGameMessageType::VEHICLE_SET_WHEEL_LOCK_STATE, (eGameMessageType)1273); - EXPECT_EQ(eGameMessageType::NOTIFY_VEHICLE_OF_RACING_OBJECT, (eGameMessageType)1276); - EXPECT_EQ(eGameMessageType::SET_NAME_BILLBOARD_STATE, (eGameMessageType)1284); - EXPECT_EQ(eGameMessageType::PLAYER_REACHED_RESPAWN_CHECKPOINT, (eGameMessageType)1296); - EXPECT_EQ(eGameMessageType::HANDLE_UGC_POST_DELETE_BASED_ON_EDIT_MODE, (eGameMessageType)1300); - EXPECT_EQ(eGameMessageType::HANDLE_UGC_POST_CREATE_BASED_ON_EDIT_MODE, (eGameMessageType)1301); - EXPECT_EQ(eGameMessageType::PROPERTY_CONTENTS_FROM_CLIENT, (eGameMessageType)1305); - EXPECT_EQ(eGameMessageType::GET_MODELS_ON_PROPERTY, (eGameMessageType)1306); - EXPECT_EQ(eGameMessageType::MATCH_REQUEST, (eGameMessageType)1308); - EXPECT_EQ(eGameMessageType::MATCH_RESPONSE, (eGameMessageType)1309); - EXPECT_EQ(eGameMessageType::MATCH_UPDATE, (eGameMessageType)1310); - EXPECT_EQ(eGameMessageType::MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT, (eGameMessageType)1131); - EXPECT_EQ(eGameMessageType::MODULE_ASSEMBLY_QUERY_DATA, (eGameMessageType)1132); - EXPECT_EQ(eGameMessageType::SHOW_BILLBOARD_INTERACT_ICON, (eGameMessageType)1337); - EXPECT_EQ(eGameMessageType::CHANGE_IDLE_FLAGS, (eGameMessageType)1338); - EXPECT_EQ(eGameMessageType::VEHICLE_ADD_PASSIVE_BOOST_ACTION, (eGameMessageType)1340); - EXPECT_EQ(eGameMessageType::VEHICLE_REMOVE_PASSIVE_BOOST_ACTION, (eGameMessageType)1341); - EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_VEHICLE_ADD_PASSIVE_BOOST_ACTION, (eGameMessageType)1342); - EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION, (eGameMessageType)1343); - EXPECT_EQ(eGameMessageType::VEHICLE_ADD_SLOWDOWN_ACTION, (eGameMessageType)1344); - EXPECT_EQ(eGameMessageType::VEHICLE_REMOVE_SLOWDOWN_ACTION, (eGameMessageType)1345); - EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_VEHICLE_ADD_SLOWDOWN_ACTION, (eGameMessageType)1346); - EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_VEHICLE_REMOVE_SLOWDOWN_ACTION, (eGameMessageType)1347); - EXPECT_EQ(eGameMessageType::BUYBACK_FROM_VENDOR, (eGameMessageType)1350); - EXPECT_EQ(eGameMessageType::SET_PROPERTY_ACCESS, (eGameMessageType)1366); - EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_PLACED, (eGameMessageType)1369); - EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_ROTATED, (eGameMessageType)1370); - EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_REMOVED_WHILE_EQUIPPED, (eGameMessageType)1371); - EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_EQUIPPED, (eGameMessageType)1372); - EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_PICKED_UP, (eGameMessageType)1373); - EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_REMOVED, (eGameMessageType)1374); - EXPECT_EQ(eGameMessageType::NOTIFY_RACING_CLIENT, (eGameMessageType)1390); - EXPECT_EQ(eGameMessageType::RACING_PLAYER_HACK_CAR, (eGameMessageType)1391); - EXPECT_EQ(eGameMessageType::RACING_PLAYER_LOADED, (eGameMessageType)1392); - EXPECT_EQ(eGameMessageType::RACING_CLIENT_READY, (eGameMessageType)1393); - EXPECT_EQ(eGameMessageType::UPDATE_CHAT_MODE, (eGameMessageType)1395); - EXPECT_EQ(eGameMessageType::VEHICLE_NOTIFY_FINISHED_RACE, (eGameMessageType)1396); - EXPECT_EQ(eGameMessageType::SET_CONSUMABLE_ITEM, (eGameMessageType)1409); - EXPECT_EQ(eGameMessageType::SET_STATUS_IMMUNITY, (eGameMessageType)1435); - EXPECT_EQ(eGameMessageType::SET_PET_NAME_MODERATED, (eGameMessageType)1448); - EXPECT_EQ(eGameMessageType::MODIFY_LEGO_SCORE, (eGameMessageType)1459); - EXPECT_EQ(eGameMessageType::RESTORE_TO_POST_LOAD_STATS, (eGameMessageType)1468); - EXPECT_EQ(eGameMessageType::SET_RAIL_MOVEMENT, (eGameMessageType)1471); - EXPECT_EQ(eGameMessageType::START_RAIL_MOVEMENT, (eGameMessageType)1472); - EXPECT_EQ(eGameMessageType::CANCEL_RAIL_MOVEMENT, (eGameMessageType)1474); - EXPECT_EQ(eGameMessageType::CLIENT_RAIL_MOVEMENT_READY, (eGameMessageType)1476); - EXPECT_EQ(eGameMessageType::PLAYER_RAIL_ARRIVED_NOTIFICATION, (eGameMessageType)1477); - EXPECT_EQ(eGameMessageType::UPDATE_PLAYER_STATISTIC, (eGameMessageType)1481); - EXPECT_EQ(eGameMessageType::MODULAR_ASSEMBLY_NIF_COMPLETED, (eGameMessageType)1498); - EXPECT_EQ(eGameMessageType::NOTIFY_NOT_ENOUGH_INV_SPACE, (eGameMessageType)1516); - EXPECT_EQ(eGameMessageType::TEAM_SET_LEADER, (eGameMessageType)1557); - EXPECT_EQ(eGameMessageType::TEAM_INVITE_CONFIRM, (eGameMessageType)1558); - EXPECT_EQ(eGameMessageType::TEAM_GET_STATUS_RESPONSE, (eGameMessageType)1559); - EXPECT_EQ(eGameMessageType::TEAM_ADD_PLAYER, (eGameMessageType)1562); - EXPECT_EQ(eGameMessageType::TEAM_REMOVE_PLAYER, (eGameMessageType)1563); - EXPECT_EQ(eGameMessageType::START_CELEBRATION_EFFECT, (eGameMessageType)1618); - EXPECT_EQ(eGameMessageType::ADD_BUFF, (eGameMessageType)1647); - EXPECT_EQ(eGameMessageType::SERVER_DONE_LOADING_ALL_OBJECTS, (eGameMessageType)1642); - EXPECT_EQ(eGameMessageType::PLACE_PROPERTY_MODEL, (eGameMessageType)1170); - EXPECT_EQ(eGameMessageType::VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER, (eGameMessageType)1606); - EXPECT_EQ(eGameMessageType::ADD_RUN_SPEED_MODIFIER, (eGameMessageType)1505); - EXPECT_EQ(eGameMessageType::GET_HOT_PROPERTY_DATA, (eGameMessageType)1511); - EXPECT_EQ(eGameMessageType::SEND_HOT_PROPERTY_DATA, (eGameMessageType)1510); - EXPECT_EQ(eGameMessageType::REMOVE_RUN_SPEED_MODIFIER, (eGameMessageType)1506); - EXPECT_EQ(eGameMessageType::UPDATE_PROPERTY_PERFORMANCE_COST, (eGameMessageType)1547); - EXPECT_EQ(eGameMessageType::PROPERTY_ENTRANCE_BEGIN, (eGameMessageType)1553); - EXPECT_EQ(eGameMessageType::SET_RESURRECT_RESTORE_VALUES, (eGameMessageType)1591); - EXPECT_EQ(eGameMessageType::VEHICLE_STOP_BOOST, (eGameMessageType)1617); - EXPECT_EQ(eGameMessageType::REMOVE_BUFF, (eGameMessageType)1648); - EXPECT_EQ(eGameMessageType::REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES, (eGameMessageType)1666); - EXPECT_EQ(eGameMessageType::RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES, (eGameMessageType)1667); - EXPECT_EQ(eGameMessageType::PLAYER_SET_CAMERA_CYCLING_MODE, (eGameMessageType)1676); - EXPECT_EQ(eGameMessageType::SET_MOUNT_INVENTORY_ID, (eGameMessageType)1727); - EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE, (eGameMessageType)1734); - EXPECT_EQ(eGameMessageType::NOTIFY_LEVEL_REWARDS, (eGameMessageType)1735); - EXPECT_EQ(eGameMessageType::DISMOUNT_COMPLETE, (eGameMessageType)1756); - EXPECT_EQ(eGameMessageType::MARK_INVENTORY_ITEM_AS_ACTIVE, (eGameMessageType)1767); + EXPECT_EQ(MessageType::Game::TELEPORT, static_cast<MessageType::Game>(19)); + EXPECT_EQ(MessageType::Game::SET_PLAYER_CONTROL_SCHEME, static_cast<MessageType::Game>(26)); + EXPECT_EQ(MessageType::Game::DROP_CLIENT_LOOT, static_cast<MessageType::Game>(30)); + EXPECT_EQ(MessageType::Game::DIE, static_cast<MessageType::Game>(37)); + EXPECT_EQ(MessageType::Game::REQUEST_DIE, static_cast<MessageType::Game>(38)); + EXPECT_EQ(MessageType::Game::PLAY_EMOTE, static_cast<MessageType::Game>(41)); + EXPECT_EQ(MessageType::Game::PLAY_ANIMATION, static_cast<MessageType::Game>(43)); + EXPECT_EQ(MessageType::Game::CONTROL_BEHAVIORS, static_cast<MessageType::Game>(48)); + EXPECT_EQ(MessageType::Game::SET_NAME, static_cast<MessageType::Game>(72)); + EXPECT_EQ(MessageType::Game::ECHO_START_SKILL, static_cast<MessageType::Game>(118)); + EXPECT_EQ(MessageType::Game::START_SKILL, static_cast<MessageType::Game>(119)); + EXPECT_EQ(MessageType::Game::VERIFY_ACK, static_cast<MessageType::Game>(121)); + EXPECT_EQ(MessageType::Game::ADD_SKILL, static_cast<MessageType::Game>(127)); + EXPECT_EQ(MessageType::Game::REMOVE_SKILL, static_cast<MessageType::Game>(128)); + EXPECT_EQ(MessageType::Game::SET_CURRENCY, static_cast<MessageType::Game>(133)); + EXPECT_EQ(MessageType::Game::PICKUP_CURRENCY, static_cast<MessageType::Game>(137)); + EXPECT_EQ(MessageType::Game::PICKUP_ITEM, static_cast<MessageType::Game>(139)); + EXPECT_EQ(MessageType::Game::TEAM_PICKUP_ITEM, static_cast<MessageType::Game>(140)); + EXPECT_EQ(MessageType::Game::PLAY_FX_EFFECT, static_cast<MessageType::Game>(154)); + EXPECT_EQ(MessageType::Game::STOP_FX_EFFECT, static_cast<MessageType::Game>(155)); + EXPECT_EQ(MessageType::Game::REQUEST_RESURRECT, static_cast<MessageType::Game>(159)); + EXPECT_EQ(MessageType::Game::RESURRECT, static_cast<MessageType::Game>(160)); + EXPECT_EQ(MessageType::Game::PUSH_EQUIPPED_ITEMS_STATE, static_cast<MessageType::Game>(191)); + EXPECT_EQ(MessageType::Game::POP_EQUIPPED_ITEMS_STATE, static_cast<MessageType::Game>(192)); + EXPECT_EQ(MessageType::Game::SET_GM_LEVEL, static_cast<MessageType::Game>(193)); + EXPECT_EQ(MessageType::Game::SET_STUNNED, static_cast<MessageType::Game>(198)); + EXPECT_EQ(MessageType::Game::SET_STUN_IMMUNITY, static_cast<MessageType::Game>(200)); + EXPECT_EQ(MessageType::Game::KNOCKBACK, static_cast<MessageType::Game>(202)); + EXPECT_EQ(MessageType::Game::REBUILD_CANCEL, static_cast<MessageType::Game>(209)); + EXPECT_EQ(MessageType::Game::ENABLE_REBUILD, static_cast<MessageType::Game>(213)); + EXPECT_EQ(MessageType::Game::MOVE_ITEM_IN_INVENTORY, static_cast<MessageType::Game>(224)); + EXPECT_EQ(MessageType::Game::ADD_ITEM_TO_INVENTORY_CLIENT_SYNC, static_cast<MessageType::Game>(227)); + EXPECT_EQ(MessageType::Game::REMOVE_ITEM_FROM_INVENTORY, static_cast<MessageType::Game>(230)); + EXPECT_EQ(MessageType::Game::EQUIP_INVENTORY, static_cast<MessageType::Game>(231)); + EXPECT_EQ(MessageType::Game::UN_EQUIP_INVENTORY, static_cast<MessageType::Game>(233)); + EXPECT_EQ(MessageType::Game::OFFER_MISSION, static_cast<MessageType::Game>(248)); + EXPECT_EQ(MessageType::Game::RESPOND_TO_MISSION, static_cast<MessageType::Game>(249)); + EXPECT_EQ(MessageType::Game::NOTIFY_MISSION, static_cast<MessageType::Game>(254)); + EXPECT_EQ(MessageType::Game::NOTIFY_MISSION_TASK, static_cast<MessageType::Game>(255)); + EXPECT_EQ(MessageType::Game::REBUILD_NOTIFY_STATE, static_cast<MessageType::Game>(336)); + EXPECT_EQ(MessageType::Game::TERMINATE_INTERACTION, static_cast<MessageType::Game>(357)); + EXPECT_EQ(MessageType::Game::SERVER_TERMINATE_INTERACTION, static_cast<MessageType::Game>(358)); + EXPECT_EQ(MessageType::Game::REQUEST_USE, static_cast<MessageType::Game>(364)); + EXPECT_EQ(MessageType::Game::VENDOR_OPEN_WINDOW, static_cast<MessageType::Game>(369)); + EXPECT_EQ(MessageType::Game::BUY_FROM_VENDOR, static_cast<MessageType::Game>(373)); + EXPECT_EQ(MessageType::Game::SELL_TO_VENDOR, static_cast<MessageType::Game>(374)); + EXPECT_EQ(MessageType::Game::TEAM_SET_OFF_WORLD_FLAG, static_cast<MessageType::Game>(383)); + EXPECT_EQ(MessageType::Game::SET_INVENTORY_SIZE, static_cast<MessageType::Game>(389)); + EXPECT_EQ(MessageType::Game::ACKNOWLEDGE_POSSESSION, static_cast<MessageType::Game>(391)); + EXPECT_EQ(MessageType::Game::SET_SHOOTING_GALLERY_PARAMS, static_cast<MessageType::Game>(400)); + EXPECT_EQ(MessageType::Game::REQUEST_ACTIVITY_START_STOP, static_cast<MessageType::Game>(402)); + EXPECT_EQ(MessageType::Game::REQUEST_ACTIVITY_ENTER, static_cast<MessageType::Game>(403)); + EXPECT_EQ(MessageType::Game::REQUEST_ACTIVITY_EXIT, static_cast<MessageType::Game>(404)); + EXPECT_EQ(MessageType::Game::ACTIVITY_ENTER, static_cast<MessageType::Game>(405)); + EXPECT_EQ(MessageType::Game::ACTIVITY_EXIT, static_cast<MessageType::Game>(406)); + EXPECT_EQ(MessageType::Game::ACTIVITY_START, static_cast<MessageType::Game>(407)); + EXPECT_EQ(MessageType::Game::ACTIVITY_STOP, static_cast<MessageType::Game>(408)); + EXPECT_EQ(MessageType::Game::SHOOTING_GALLERY_CLIENT_AIM_UPDATE, static_cast<MessageType::Game>(409)); + EXPECT_EQ(MessageType::Game::SHOOTING_GALLERY_FIRE, static_cast<MessageType::Game>(411)); + EXPECT_EQ(MessageType::Game::REQUEST_VENDOR_STATUS_UPDATE, static_cast<MessageType::Game>(416)); + EXPECT_EQ(MessageType::Game::VENDOR_STATUS_UPDATE, static_cast<MessageType::Game>(417)); + EXPECT_EQ(MessageType::Game::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE, static_cast<MessageType::Game>(425)); + EXPECT_EQ(MessageType::Game::CONSUME_CLIENT_ITEM, static_cast<MessageType::Game>(427)); + EXPECT_EQ(MessageType::Game::CLIENT_ITEM_CONSUMED, static_cast<MessageType::Game>(428)); + EXPECT_EQ(MessageType::Game::UPDATE_SHOOTING_GALLERY_ROTATION, static_cast<MessageType::Game>(448)); + EXPECT_EQ(MessageType::Game::SET_FLAG, static_cast<MessageType::Game>(471)); + EXPECT_EQ(MessageType::Game::NOTIFY_CLIENT_FLAG_CHANGE, static_cast<MessageType::Game>(472)); + EXPECT_EQ(MessageType::Game::VENDOR_TRANSACTION_RESULT, static_cast<MessageType::Game>(476)); + EXPECT_EQ(MessageType::Game::HAS_BEEN_COLLECTED, static_cast<MessageType::Game>(486)); + EXPECT_EQ(MessageType::Game::DISPLAY_CHAT_BUBBLE, static_cast<MessageType::Game>(495)); + EXPECT_EQ(MessageType::Game::SPAWN_PET, static_cast<MessageType::Game>(498)); + EXPECT_EQ(MessageType::Game::DESPAWN_PET, static_cast<MessageType::Game>(499)); + EXPECT_EQ(MessageType::Game::PLAYER_LOADED, static_cast<MessageType::Game>(505)); + EXPECT_EQ(MessageType::Game::PLAYER_READY, static_cast<MessageType::Game>(509)); + EXPECT_EQ(MessageType::Game::REQUEST_LINKED_MISSION, static_cast<MessageType::Game>(515)); + EXPECT_EQ(MessageType::Game::INVALID_ZONE_TRANSFER_LIST, static_cast<MessageType::Game>(519)); + EXPECT_EQ(MessageType::Game::MISSION_DIALOGUE_OK, static_cast<MessageType::Game>(520)); + EXPECT_EQ(MessageType::Game::DISPLAY_MESSAGE_BOX, static_cast<MessageType::Game>(529)); + EXPECT_EQ(MessageType::Game::MESSAGE_BOX_RESPOND, static_cast<MessageType::Game>(530)); + EXPECT_EQ(MessageType::Game::CHOICE_BOX_RESPOND, static_cast<MessageType::Game>(531)); + EXPECT_EQ(MessageType::Game::SMASH, static_cast<MessageType::Game>(537)); + EXPECT_EQ(MessageType::Game::UN_SMASH, static_cast<MessageType::Game>(538)); + EXPECT_EQ(MessageType::Game::PLACE_MODEL_RESPONSE, static_cast<MessageType::Game>(547)); + EXPECT_EQ(MessageType::Game::SET_SHOOTING_GALLERY_RETICULE_EFFECT, static_cast<MessageType::Game>(546)); + EXPECT_EQ(MessageType::Game::SET_JET_PACK_MODE, static_cast<MessageType::Game>(561)); + EXPECT_EQ(MessageType::Game::REGISTER_PET_ID, static_cast<MessageType::Game>(565)); + EXPECT_EQ(MessageType::Game::REGISTER_PET_DBID, static_cast<MessageType::Game>(566)); + EXPECT_EQ(MessageType::Game::SHOW_ACTIVITY_COUNTDOWN, static_cast<MessageType::Game>(568)); + EXPECT_EQ(MessageType::Game::START_ACTIVITY_TIME, static_cast<MessageType::Game>(576)); + EXPECT_EQ(MessageType::Game::ACTIVITY_PAUSE, static_cast<MessageType::Game>(602)); + EXPECT_EQ(MessageType::Game::USE_NON_EQUIPMENT_ITEM, static_cast<MessageType::Game>(603)); + EXPECT_EQ(MessageType::Game::USE_ITEM_RESULT, static_cast<MessageType::Game>(607)); + EXPECT_EQ(MessageType::Game::COMMAND_PET, static_cast<MessageType::Game>(640)); + EXPECT_EQ(MessageType::Game::PET_RESPONSE, static_cast<MessageType::Game>(641)); + EXPECT_EQ(MessageType::Game::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA, static_cast<MessageType::Game>(648)); + EXPECT_EQ(MessageType::Game::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA, static_cast<MessageType::Game>(649)); + EXPECT_EQ(MessageType::Game::NOTIFY_OBJECT, static_cast<MessageType::Game>(656)); + EXPECT_EQ(MessageType::Game::CLIENT_NOTIFY_PET, static_cast<MessageType::Game>(659)); + EXPECT_EQ(MessageType::Game::NOTIFY_PET, static_cast<MessageType::Game>(660)); + EXPECT_EQ(MessageType::Game::NOTIFY_PET_TAMING_MINIGAME, static_cast<MessageType::Game>(661)); + EXPECT_EQ(MessageType::Game::START_SERVER_PET_MINIGAME_TIMER, static_cast<MessageType::Game>(662)); + EXPECT_EQ(MessageType::Game::CLIENT_EXIT_TAMING_MINIGAME, static_cast<MessageType::Game>(663)); + EXPECT_EQ(MessageType::Game::PET_NAME_CHANGED, static_cast<MessageType::Game>(686)); + EXPECT_EQ(MessageType::Game::PET_TAMING_MINIGAME_RESULT, static_cast<MessageType::Game>(667)); + EXPECT_EQ(MessageType::Game::PET_TAMING_TRY_BUILD_RESULT, static_cast<MessageType::Game>(668)); + EXPECT_EQ(MessageType::Game::NOTIFY_TAMING_BUILD_SUCCESS, static_cast<MessageType::Game>(673)); + EXPECT_EQ(MessageType::Game::NOTIFY_TAMING_MODEL_LOADED_ON_SERVER, static_cast<MessageType::Game>(674)); + EXPECT_EQ(MessageType::Game::ACTIVATE_BUBBLE_BUFF, static_cast<MessageType::Game>(678)); + EXPECT_EQ(MessageType::Game::DECTIVATE_BUBBLE_BUFF, static_cast<MessageType::Game>(679)); + EXPECT_EQ(MessageType::Game::ADD_PET_TO_PLAYER, static_cast<MessageType::Game>(681)); + EXPECT_EQ(MessageType::Game::REQUEST_SET_PET_NAME, static_cast<MessageType::Game>(683)); + EXPECT_EQ(MessageType::Game::SET_PET_NAME, static_cast<MessageType::Game>(684)); + EXPECT_EQ(MessageType::Game::NOTIFY_TAMING_PUZZLE_SELECTED, static_cast<MessageType::Game>(675)); + EXPECT_EQ(MessageType::Game::SHOW_PET_ACTION_BUTTON, static_cast<MessageType::Game>(692)); + EXPECT_EQ(MessageType::Game::SET_EMOTE_LOCK_STATE, static_cast<MessageType::Game>(693)); + EXPECT_EQ(MessageType::Game::USE_ITEM_REQUIREMENTS_RESPONSE, static_cast<MessageType::Game>(703)); + EXPECT_EQ(MessageType::Game::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT, static_cast<MessageType::Game>(713)); + EXPECT_EQ(MessageType::Game::DOWNLOAD_PROPERTY_DATA, static_cast<MessageType::Game>(716)); + EXPECT_EQ(MessageType::Game::QUERY_PROPERTY_DATA, static_cast<MessageType::Game>(717)); + EXPECT_EQ(MessageType::Game::PROPERTY_EDITOR_BEGIN, static_cast<MessageType::Game>(724)); + EXPECT_EQ(MessageType::Game::PROPERTY_EDITOR_END, static_cast<MessageType::Game>(725)); + EXPECT_EQ(MessageType::Game::IS_MINIFIG_IN_A_BUBBLE, static_cast<MessageType::Game>(729)); + EXPECT_EQ(MessageType::Game::START_PATHING, static_cast<MessageType::Game>(733)); + EXPECT_EQ(MessageType::Game::ACTIVATE_BUBBLE_BUFF_FROM_SERVER, static_cast<MessageType::Game>(734)); + EXPECT_EQ(MessageType::Game::DEACTIVATE_BUBBLE_BUFF_FROM_SERVER, static_cast<MessageType::Game>(735)); + EXPECT_EQ(MessageType::Game::NOTIFY_CLIENT_ZONE_OBJECT, static_cast<MessageType::Game>(737)); + EXPECT_EQ(MessageType::Game::UPDATE_REPUTATION, static_cast<MessageType::Game>(746)); + EXPECT_EQ(MessageType::Game::PROPERTY_RENTAL_RESPONSE, static_cast<MessageType::Game>(750)); + EXPECT_EQ(MessageType::Game::REQUEST_PLATFORM_RESYNC, static_cast<MessageType::Game>(760)); + EXPECT_EQ(MessageType::Game::PLATFORM_RESYNC, static_cast<MessageType::Game>(761)); + EXPECT_EQ(MessageType::Game::PLAY_CINEMATIC, static_cast<MessageType::Game>(762)); + EXPECT_EQ(MessageType::Game::END_CINEMATIC, static_cast<MessageType::Game>(763)); + EXPECT_EQ(MessageType::Game::CINEMATIC_UPDATE, static_cast<MessageType::Game>(764)); + EXPECT_EQ(MessageType::Game::TOGGLE_GHOST_REFERENCE_OVERRIDE, static_cast<MessageType::Game>(767)); + EXPECT_EQ(MessageType::Game::SET_GHOST_REFERENCE_POSITION, static_cast<MessageType::Game>(768)); + EXPECT_EQ(MessageType::Game::FIRE_EVENT_SERVER_SIDE, static_cast<MessageType::Game>(770)); + EXPECT_EQ(MessageType::Game::SCRIPT_NETWORK_VAR_UPDATE, static_cast<MessageType::Game>(781)); + EXPECT_EQ(MessageType::Game::UPDATE_MODEL_FROM_CLIENT, static_cast<MessageType::Game>(793)); + EXPECT_EQ(MessageType::Game::DELETE_MODEL_FROM_CLIENT, static_cast<MessageType::Game>(794)); + EXPECT_EQ(MessageType::Game::PLAY_ND_AUDIO_EMITTER, static_cast<MessageType::Game>(821)); + EXPECT_EQ(MessageType::Game::PLAY2_D_AMBIENT_SOUND, static_cast<MessageType::Game>(831)); + EXPECT_EQ(MessageType::Game::ENTER_PROPERTY1, static_cast<MessageType::Game>(840)); + EXPECT_EQ(MessageType::Game::ENTER_PROPERTY2, static_cast<MessageType::Game>(841)); + EXPECT_EQ(MessageType::Game::PROPERTY_ENTRANCE_SYNC, static_cast<MessageType::Game>(842)); + EXPECT_EQ(MessageType::Game::PROPERTY_SELECT_QUERY, static_cast<MessageType::Game>(845)); + EXPECT_EQ(MessageType::Game::PARSE_CHAT_MESSAGE, static_cast<MessageType::Game>(850)); + EXPECT_EQ(MessageType::Game::BROADCAST_TEXT_TO_CHATBOX, static_cast<MessageType::Game>(858)); + EXPECT_EQ(MessageType::Game::OPEN_PROPERTY_MANAGEMENT, static_cast<MessageType::Game>(860)); + EXPECT_EQ(MessageType::Game::OPEN_PROPERTY_VENDOR, static_cast<MessageType::Game>(861)); + EXPECT_EQ(MessageType::Game::UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK, static_cast<MessageType::Game>(863)); + EXPECT_EQ(MessageType::Game::CLIENT_TRADE_REQUEST, static_cast<MessageType::Game>(868)); + EXPECT_EQ(MessageType::Game::SERVER_TRADE_REQUEST, static_cast<MessageType::Game>(869)); + EXPECT_EQ(MessageType::Game::SERVER_TRADE_INVITE, static_cast<MessageType::Game>(870)); + EXPECT_EQ(MessageType::Game::CLIENT_TRADE_REPLY, static_cast<MessageType::Game>(871)); + EXPECT_EQ(MessageType::Game::SERVER_TRADE_REPLY, static_cast<MessageType::Game>(872)); + EXPECT_EQ(MessageType::Game::SERVER_TRADE_INITIAL_REPLY, static_cast<MessageType::Game>(873)); + EXPECT_EQ(MessageType::Game::SERVER_TRADE_FINAL_REPLY, static_cast<MessageType::Game>(874)); + EXPECT_EQ(MessageType::Game::CLIENT_TRADE_UPDATE, static_cast<MessageType::Game>(875)); + EXPECT_EQ(MessageType::Game::SERVER_SIDE_TRADE_UPDATE, static_cast<MessageType::Game>(876)); + EXPECT_EQ(MessageType::Game::SERVER_TRADE_UPDATE, static_cast<MessageType::Game>(877)); + EXPECT_EQ(MessageType::Game::CLIENT_TRADE_CANCEL, static_cast<MessageType::Game>(878)); + EXPECT_EQ(MessageType::Game::CLIENT_SIDE_TRADE_CANCEL, static_cast<MessageType::Game>(879)); + EXPECT_EQ(MessageType::Game::CLIENT_TRADE_ACCEPT, static_cast<MessageType::Game>(880)); + EXPECT_EQ(MessageType::Game::SERVER_SIDE_TRADE_ACCEPT, static_cast<MessageType::Game>(881)); + EXPECT_EQ(MessageType::Game::SERVER_SIDE_TRADE_CANCEL, static_cast<MessageType::Game>(882)); + EXPECT_EQ(MessageType::Game::SERVER_TRADE_CANCEL, static_cast<MessageType::Game>(883)); + EXPECT_EQ(MessageType::Game::SERVER_TRADE_ACCEPT, static_cast<MessageType::Game>(884)); + EXPECT_EQ(MessageType::Game::READY_FOR_UPDATES, static_cast<MessageType::Game>(888)); + EXPECT_EQ(MessageType::Game::ORIENT_TO_OBJECT, static_cast<MessageType::Game>(905)); + EXPECT_EQ(MessageType::Game::ORIENT_TO_POSITION, static_cast<MessageType::Game>(906)); + EXPECT_EQ(MessageType::Game::ORIENT_TO_ANGLE, static_cast<MessageType::Game>(907)); + EXPECT_EQ(MessageType::Game::BOUNCER_ACTIVE_STATUS, static_cast<MessageType::Game>(942)); + EXPECT_EQ(MessageType::Game::UN_USE_BBB_MODEL, static_cast<MessageType::Game>(999)); + EXPECT_EQ(MessageType::Game::BBB_LOAD_ITEM_REQUEST, static_cast<MessageType::Game>(1000)); + EXPECT_EQ(MessageType::Game::BBB_SAVE_REQUEST, static_cast<MessageType::Game>(1001)); + EXPECT_EQ(MessageType::Game::BBB_SAVE_RESPONSE, static_cast<MessageType::Game>(1005)); + EXPECT_EQ(MessageType::Game::NOTIFY_CLIENT_OBJECT, static_cast<MessageType::Game>(1042)); + EXPECT_EQ(MessageType::Game::DISPLAY_ZONE_SUMMARY, static_cast<MessageType::Game>(1043)); + EXPECT_EQ(MessageType::Game::ZONE_SUMMARY_DISMISSED, static_cast<MessageType::Game>(1044)); + EXPECT_EQ(MessageType::Game::ACTIVITY_STATE_CHANGE_REQUEST, static_cast<MessageType::Game>(1053)); + EXPECT_EQ(MessageType::Game::MODIFY_PLAYER_ZONE_STATISTIC, static_cast<MessageType::Game>(1046)); + EXPECT_EQ(MessageType::Game::START_BUILDING_WITH_ITEM, static_cast<MessageType::Game>(1057)); + EXPECT_EQ(MessageType::Game::START_ARRANGING_WITH_ITEM, static_cast<MessageType::Game>(1061)); + EXPECT_EQ(MessageType::Game::FINISH_ARRANGING_WITH_ITEM, static_cast<MessageType::Game>(1062)); + EXPECT_EQ(MessageType::Game::DONE_ARRANGING_WITH_ITEM, static_cast<MessageType::Game>(1063)); + EXPECT_EQ(MessageType::Game::SET_BUILD_MODE, static_cast<MessageType::Game>(1068)); + EXPECT_EQ(MessageType::Game::BUILD_MODE_SET, static_cast<MessageType::Game>(1069)); + EXPECT_EQ(MessageType::Game::SET_BUILD_MODE_CONFIRMED, static_cast<MessageType::Game>(1073)); + EXPECT_EQ(MessageType::Game::NOTIFY_CLIENT_FAILED_PRECONDITION, static_cast<MessageType::Game>(1081)); + EXPECT_EQ(MessageType::Game::MOVE_ITEM_BETWEEN_INVENTORY_TYPES, static_cast<MessageType::Game>(1093)); + EXPECT_EQ(MessageType::Game::MODULAR_BUILD_BEGIN, static_cast<MessageType::Game>(1094)); + EXPECT_EQ(MessageType::Game::MODULAR_BUILD_END, static_cast<MessageType::Game>(1095)); + EXPECT_EQ(MessageType::Game::MODULAR_BUILD_MOVE_AND_EQUIP, static_cast<MessageType::Game>(1096)); + EXPECT_EQ(MessageType::Game::MODULAR_BUILD_FINISH, static_cast<MessageType::Game>(1097)); + EXPECT_EQ(MessageType::Game::REPORT_BUG, static_cast<MessageType::Game>(1198)); + EXPECT_EQ(MessageType::Game::MISSION_DIALOGUE_CANCELLED, static_cast<MessageType::Game>(1129)); + EXPECT_EQ(MessageType::Game::ECHO_SYNC_SKILL, static_cast<MessageType::Game>(1144)); + EXPECT_EQ(MessageType::Game::SYNC_SKILL, static_cast<MessageType::Game>(1145)); + EXPECT_EQ(MessageType::Game::REQUEST_SERVER_PROJECTILE_IMPACT, static_cast<MessageType::Game>(1148)); + EXPECT_EQ(MessageType::Game::DO_CLIENT_PROJECTILE_IMPACT, static_cast<MessageType::Game>(1151)); + EXPECT_EQ(MessageType::Game::MODULAR_BUILD_CONVERT_MODEL, static_cast<MessageType::Game>(1155)); + EXPECT_EQ(MessageType::Game::SET_PLAYER_ALLOWED_RESPAWN, static_cast<MessageType::Game>(1165)); + EXPECT_EQ(MessageType::Game::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT, static_cast<MessageType::Game>(1184)); + EXPECT_EQ(MessageType::Game::UI_MESSAGE_SERVER_TO_ALL_CLIENTS, static_cast<MessageType::Game>(1185)); + EXPECT_EQ(MessageType::Game::PET_TAMING_TRY_BUILD, static_cast<MessageType::Game>(1197)); + EXPECT_EQ(MessageType::Game::REQUEST_SMASH_PLAYER, static_cast<MessageType::Game>(1202)); + EXPECT_EQ(MessageType::Game::FIRE_EVENT_CLIENT_SIDE, static_cast<MessageType::Game>(1213)); + EXPECT_EQ(MessageType::Game::TOGGLE_GM_INVIS, static_cast<MessageType::Game>(1218)); + EXPECT_EQ(MessageType::Game::CHANGE_OBJECT_WORLD_STATE, static_cast<MessageType::Game>(1223)); + EXPECT_EQ(MessageType::Game::VEHICLE_LOCK_INPUT, static_cast<MessageType::Game>(1230)); + EXPECT_EQ(MessageType::Game::VEHICLE_UNLOCK_INPUT, static_cast<MessageType::Game>(1231)); + EXPECT_EQ(MessageType::Game::RACING_RESET_PLAYER_TO_LAST_RESET, static_cast<MessageType::Game>(1252)); + EXPECT_EQ(MessageType::Game::RACING_SERVER_SET_PLAYER_LAP_AND_PLANE, static_cast<MessageType::Game>(1253)); + EXPECT_EQ(MessageType::Game::RACING_SET_PLAYER_RESET_INFO, static_cast<MessageType::Game>(1254)); + EXPECT_EQ(MessageType::Game::RACING_PLAYER_INFO_RESET_FINISHED, static_cast<MessageType::Game>(1255)); + EXPECT_EQ(MessageType::Game::LOCK_NODE_ROTATION, static_cast<MessageType::Game>(1260)); + EXPECT_EQ(MessageType::Game::VEHICLE_SET_WHEEL_LOCK_STATE, static_cast<MessageType::Game>(1273)); + EXPECT_EQ(MessageType::Game::NOTIFY_VEHICLE_OF_RACING_OBJECT, static_cast<MessageType::Game>(1276)); + EXPECT_EQ(MessageType::Game::SET_NAME_BILLBOARD_STATE, static_cast<MessageType::Game>(1284)); + EXPECT_EQ(MessageType::Game::PLAYER_REACHED_RESPAWN_CHECKPOINT, static_cast<MessageType::Game>(1296)); + EXPECT_EQ(MessageType::Game::HANDLE_UGC_POST_DELETE_BASED_ON_EDIT_MODE, static_cast<MessageType::Game>(1300)); + EXPECT_EQ(MessageType::Game::HANDLE_UGC_POST_CREATE_BASED_ON_EDIT_MODE, static_cast<MessageType::Game>(1301)); + EXPECT_EQ(MessageType::Game::PROPERTY_CONTENTS_FROM_CLIENT, static_cast<MessageType::Game>(1305)); + EXPECT_EQ(MessageType::Game::GET_MODELS_ON_PROPERTY, static_cast<MessageType::Game>(1306)); + EXPECT_EQ(MessageType::Game::MATCH_REQUEST, static_cast<MessageType::Game>(1308)); + EXPECT_EQ(MessageType::Game::MATCH_RESPONSE, static_cast<MessageType::Game>(1309)); + EXPECT_EQ(MessageType::Game::MATCH_UPDATE, static_cast<MessageType::Game>(1310)); + EXPECT_EQ(MessageType::Game::MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT, static_cast<MessageType::Game>(1131)); + EXPECT_EQ(MessageType::Game::MODULE_ASSEMBLY_QUERY_DATA, static_cast<MessageType::Game>(1132)); + EXPECT_EQ(MessageType::Game::SHOW_BILLBOARD_INTERACT_ICON, static_cast<MessageType::Game>(1337)); + EXPECT_EQ(MessageType::Game::CHANGE_IDLE_FLAGS, static_cast<MessageType::Game>(1338)); + EXPECT_EQ(MessageType::Game::VEHICLE_ADD_PASSIVE_BOOST_ACTION, static_cast<MessageType::Game>(1340)); + EXPECT_EQ(MessageType::Game::VEHICLE_REMOVE_PASSIVE_BOOST_ACTION, static_cast<MessageType::Game>(1341)); + EXPECT_EQ(MessageType::Game::NOTIFY_SERVER_VEHICLE_ADD_PASSIVE_BOOST_ACTION, static_cast<MessageType::Game>(1342)); + EXPECT_EQ(MessageType::Game::NOTIFY_SERVER_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION, static_cast<MessageType::Game>(1343)); + EXPECT_EQ(MessageType::Game::VEHICLE_ADD_SLOWDOWN_ACTION, static_cast<MessageType::Game>(1344)); + EXPECT_EQ(MessageType::Game::VEHICLE_REMOVE_SLOWDOWN_ACTION, static_cast<MessageType::Game>(1345)); + EXPECT_EQ(MessageType::Game::NOTIFY_SERVER_VEHICLE_ADD_SLOWDOWN_ACTION, static_cast<MessageType::Game>(1346)); + EXPECT_EQ(MessageType::Game::NOTIFY_SERVER_VEHICLE_REMOVE_SLOWDOWN_ACTION, static_cast<MessageType::Game>(1347)); + EXPECT_EQ(MessageType::Game::BUYBACK_FROM_VENDOR, static_cast<MessageType::Game>(1350)); + EXPECT_EQ(MessageType::Game::SET_PROPERTY_ACCESS, static_cast<MessageType::Game>(1366)); + EXPECT_EQ(MessageType::Game::ZONE_PROPERTY_MODEL_PLACED, static_cast<MessageType::Game>(1369)); + EXPECT_EQ(MessageType::Game::ZONE_PROPERTY_MODEL_ROTATED, static_cast<MessageType::Game>(1370)); + EXPECT_EQ(MessageType::Game::ZONE_PROPERTY_MODEL_REMOVED_WHILE_EQUIPPED, static_cast<MessageType::Game>(1371)); + EXPECT_EQ(MessageType::Game::ZONE_PROPERTY_MODEL_EQUIPPED, static_cast<MessageType::Game>(1372)); + EXPECT_EQ(MessageType::Game::ZONE_PROPERTY_MODEL_PICKED_UP, static_cast<MessageType::Game>(1373)); + EXPECT_EQ(MessageType::Game::ZONE_PROPERTY_MODEL_REMOVED, static_cast<MessageType::Game>(1374)); + EXPECT_EQ(MessageType::Game::NOTIFY_RACING_CLIENT, static_cast<MessageType::Game>(1390)); + EXPECT_EQ(MessageType::Game::RACING_PLAYER_HACK_CAR, static_cast<MessageType::Game>(1391)); + EXPECT_EQ(MessageType::Game::RACING_PLAYER_LOADED, static_cast<MessageType::Game>(1392)); + EXPECT_EQ(MessageType::Game::RACING_CLIENT_READY, static_cast<MessageType::Game>(1393)); + EXPECT_EQ(MessageType::Game::UPDATE_CHAT_MODE, static_cast<MessageType::Game>(1395)); + EXPECT_EQ(MessageType::Game::VEHICLE_NOTIFY_FINISHED_RACE, static_cast<MessageType::Game>(1396)); + EXPECT_EQ(MessageType::Game::SET_CONSUMABLE_ITEM, static_cast<MessageType::Game>(1409)); + EXPECT_EQ(MessageType::Game::SET_STATUS_IMMUNITY, static_cast<MessageType::Game>(1435)); + EXPECT_EQ(MessageType::Game::SET_PET_NAME_MODERATED, static_cast<MessageType::Game>(1448)); + EXPECT_EQ(MessageType::Game::MODIFY_LEGO_SCORE, static_cast<MessageType::Game>(1459)); + EXPECT_EQ(MessageType::Game::RESTORE_TO_POST_LOAD_STATS, static_cast<MessageType::Game>(1468)); + EXPECT_EQ(MessageType::Game::SET_RAIL_MOVEMENT, static_cast<MessageType::Game>(1471)); + EXPECT_EQ(MessageType::Game::START_RAIL_MOVEMENT, static_cast<MessageType::Game>(1472)); + EXPECT_EQ(MessageType::Game::CANCEL_RAIL_MOVEMENT, static_cast<MessageType::Game>(1474)); + EXPECT_EQ(MessageType::Game::CLIENT_RAIL_MOVEMENT_READY, static_cast<MessageType::Game>(1476)); + EXPECT_EQ(MessageType::Game::PLAYER_RAIL_ARRIVED_NOTIFICATION, static_cast<MessageType::Game>(1477)); + EXPECT_EQ(MessageType::Game::UPDATE_PLAYER_STATISTIC, static_cast<MessageType::Game>(1481)); + EXPECT_EQ(MessageType::Game::MODULAR_ASSEMBLY_NIF_COMPLETED, static_cast<MessageType::Game>(1498)); + EXPECT_EQ(MessageType::Game::NOTIFY_NOT_ENOUGH_INV_SPACE, static_cast<MessageType::Game>(1516)); + EXPECT_EQ(MessageType::Game::TEAM_SET_LEADER, static_cast<MessageType::Game>(1557)); + EXPECT_EQ(MessageType::Game::TEAM_INVITE_CONFIRM, static_cast<MessageType::Game>(1558)); + EXPECT_EQ(MessageType::Game::TEAM_GET_STATUS_RESPONSE, static_cast<MessageType::Game>(1559)); + EXPECT_EQ(MessageType::Game::TEAM_ADD_PLAYER, static_cast<MessageType::Game>(1562)); + EXPECT_EQ(MessageType::Game::TEAM_REMOVE_PLAYER, static_cast<MessageType::Game>(1563)); + EXPECT_EQ(MessageType::Game::START_CELEBRATION_EFFECT, static_cast<MessageType::Game>(1618)); + EXPECT_EQ(MessageType::Game::ADD_BUFF, static_cast<MessageType::Game>(1647)); + EXPECT_EQ(MessageType::Game::SERVER_DONE_LOADING_ALL_OBJECTS, static_cast<MessageType::Game>(1642)); + EXPECT_EQ(MessageType::Game::PLACE_PROPERTY_MODEL, static_cast<MessageType::Game>(1170)); + EXPECT_EQ(MessageType::Game::VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER, static_cast<MessageType::Game>(1606)); + EXPECT_EQ(MessageType::Game::ADD_RUN_SPEED_MODIFIER, static_cast<MessageType::Game>(1505)); + EXPECT_EQ(MessageType::Game::GET_HOT_PROPERTY_DATA, static_cast<MessageType::Game>(1511)); + EXPECT_EQ(MessageType::Game::SEND_HOT_PROPERTY_DATA, static_cast<MessageType::Game>(1510)); + EXPECT_EQ(MessageType::Game::REMOVE_RUN_SPEED_MODIFIER, static_cast<MessageType::Game>(1506)); + EXPECT_EQ(MessageType::Game::UPDATE_PROPERTY_PERFORMANCE_COST, static_cast<MessageType::Game>(1547)); + EXPECT_EQ(MessageType::Game::PROPERTY_ENTRANCE_BEGIN, static_cast<MessageType::Game>(1553)); + EXPECT_EQ(MessageType::Game::SET_RESURRECT_RESTORE_VALUES, static_cast<MessageType::Game>(1591)); + EXPECT_EQ(MessageType::Game::VEHICLE_STOP_BOOST, static_cast<MessageType::Game>(1617)); + EXPECT_EQ(MessageType::Game::REMOVE_BUFF, static_cast<MessageType::Game>(1648)); + EXPECT_EQ(MessageType::Game::REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES, static_cast<MessageType::Game>(1666)); + EXPECT_EQ(MessageType::Game::RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES, static_cast<MessageType::Game>(1667)); + EXPECT_EQ(MessageType::Game::PLAYER_SET_CAMERA_CYCLING_MODE, static_cast<MessageType::Game>(1676)); + EXPECT_EQ(MessageType::Game::SET_MOUNT_INVENTORY_ID, static_cast<MessageType::Game>(1727)); + EXPECT_EQ(MessageType::Game::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE, static_cast<MessageType::Game>(1734)); + EXPECT_EQ(MessageType::Game::NOTIFY_LEVEL_REWARDS, static_cast<MessageType::Game>(1735)); + EXPECT_EQ(MessageType::Game::DISMOUNT_COMPLETE, static_cast<MessageType::Game>(1756)); + EXPECT_EQ(MessageType::Game::MARK_INVENTORY_ITEM_AS_ACTIVE, static_cast<MessageType::Game>(1767)); } diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 40c81544a..79863a53b 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -19,7 +19,16 @@ add_library(bcrypt ${SOURCES_LIBBCRYPT}) # Because we are not using the libbcrypt CMakeLists.txt, we need to include these headers for the library to use. # fortunately they are only needed for building the libbcrypt directory and nothing else, so these are marked private. -target_include_directories(bcrypt PRIVATE "libbcrypt/include") +if(NOT WIN32) + target_include_directories(bcrypt PRIVATE "libbcrypt/include/bcrypt") +endif() + +# Need to define this on Clang and GNU for 'strdup' support +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_compile_definitions(bcrypt PRIVATE "_POSIX_C_SOURCE=200809L") +endif() + +target_include_directories(bcrypt INTERFACE "libbcrypt/include") target_include_directories(bcrypt PRIVATE "libbcrypt/src") # Source code for sqlite @@ -28,9 +37,6 @@ add_subdirectory(SQLite) # Source code for magic_enum add_subdirectory(magic_enum) -# MariaDB C++ Connector -include(CMakeMariaDBLists.txt) - # Create our third party library objects add_subdirectory(raknet) diff --git a/thirdparty/SQLite/CMakeLists.txt b/thirdparty/SQLite/CMakeLists.txt index 3aa066a42..e745c46aa 100644 --- a/thirdparty/SQLite/CMakeLists.txt +++ b/thirdparty/SQLite/CMakeLists.txt @@ -11,7 +11,7 @@ if(UNIX) # -Wno-unused-result -Wno-unknown-pragmas -fpermissive target_compile_options(sqlite3 PRIVATE) - if(NOT APPLE) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") target_compile_options(sqlite3 PRIVATE "-Wno-return-local-addr" "-Wno-maybe-uninitialized") else() target_compile_options(sqlite3 PRIVATE "-Wno-return-stack-address" "-Wno-uninitialized" "-Wno-deprecated-declarations") diff --git a/thirdparty/SQLite/CppSQLite3.h b/thirdparty/SQLite/CppSQLite3.h index 7ae8a8b7f..70c4b8e8d 100644 --- a/thirdparty/SQLite/CppSQLite3.h +++ b/thirdparty/SQLite/CppSQLite3.h @@ -36,10 +36,11 @@ #include "sqlite3.h" #include <cstdio> #include <cstring> +#include <exception> #define CPPSQLITE_ERROR 1000 -class CppSQLite3Exception +class CppSQLite3Exception : public std::exception { public: @@ -54,6 +55,8 @@ class CppSQLite3Exception const int errorCode() { return mnErrCode; } const char* errorMessage() { return mpszErrMess; } + + const char* what() const noexcept override { return mpszErrMess; } static const char* errorCodeAsString(int nErrCode); diff --git a/thirdparty/mariadb-connector-cpp b/thirdparty/mariadb-connector-cpp index 8641b1453..ef0873998 160000 --- a/thirdparty/mariadb-connector-cpp +++ b/thirdparty/mariadb-connector-cpp @@ -1 +1 @@ -Subproject commit 8641b1453ae3ce5a70f78248a1f7fc20a048cb88 +Subproject commit ef0873998b3f94a4f76a485fb90b14866fbb99d4 diff --git a/vanity/atm.xml b/vanity/atm.xml index 96ed1a2b7..c03a59ce6 100644 --- a/vanity/atm.xml +++ b/vanity/atm.xml @@ -1,23 +1,42 @@ <objects> - <object lot="13538"> - <config> - <key data="CheckPrecondition=0:168"/> - </config> - <locations> - <location zone="1100" x="248.792" y="381.869" z="-181.114" rw="0.782761" rx="0.00" ry="-0.622322" rz="0.00" /> - <location zone="1100" x="471.545" y="413.979" z="27.176" rw="0.874378" rx="0.00" ry="-0.485246" rz="0.00" /> - <location zone="1200" x="51.663" y="291.371" z="-74.650" rw="-0.446235" rx="0.00" ry="0.894916" rz="0.00" /> - <location zone="1200" x="203.348" y="259.136" z="-543.400" rw="0.481554" rx="0.00" ry="0.876416" rz="0.00" /> - <location zone="1201" x="46.537" y="233.137" z="-311.395" rw="0.780747" rx="0.00" ry="-0.624847" rz="0.00" /> - <location zone="1260" x="-255.991" y="535.731" z="322.299" rw="0.683777" rx="0.00" ry="-0.729691" rz="0.00" /> - <location zone="1600" x="85.210" y="1526.810" z="314.816" rw="-0.159486" rx="0.00" ry="0.987200" rz="0.00" /> - <location zone="1700" x="-256.293" y="1035.092" z="109.761" rw="0.00" rx="0.00" ry="1" rz="0.00" /> - <location zone="1300" x="-199.258" y="246.874" z="-101.174" rw="-0.219711" rx="0.00" ry="0.975565" rz="0.00" /> - <location zone="1300" x="51.848" y="329.0" z="561.114" rw="-0.277656" rx="0.00" ry="0.960681" rz="0.00" /> - <location zone="1300" x="363.259" y="259.367" z="-210.834" rw="0.961918" rx="0.00" ry="-0.273340" rz="0.00" /> - <location zone="1400" x="-194.288" y="381.275" z="-93.292" rw="0.935135" rx="0.00" ry="0.354292" rz="0.00" /> - <location zone="1400" x="-696.957" y="-3.206" z="-452.441" rw="0.884105" rx="0.00" ry="0.467288" rz="0.00" /> - <location zone="1800" x="-222.634" y="92.693" z="568.392" rw="-0.435024" rx="0.00" ry="0.900419" rz="0.00" /> - </locations> - </object> + <object lot="13538"> + <config> + <!--Precondition 168 means the player must complete mission 1203 before being able to use an ATM--> + <key>CheckPrecondition=0:168</key> + </config> + <locations> + <!--AG Sentinel Base Camp--> + <location zone="1100" x="248.792" y="381.781" z="-181.114" rw="0.782761" rx="0.00" ry="-0.622322" rz="0.00" /> + <!--AG Picnic Area--> + <location zone="1100" x="471.545" y="413.719" z="27.176" rw="0.874378" rx="0.00" ry="-0.485246" rz="0.00" /> + <!--NS Nimbus Plaza--> + <location zone="1200" x="51.663" y="291.371" z="-74.650" rw="-0.446235" rx="0.00" ry="0.894916" rz="0.00" /> + <!--NS Red Blocks--> + <location zone="1200" x="203.348" y="259.0" z="-543.400" rw="0.481554" rx="0.00" ry="0.876416" rz="0.00" /> + <!--PC by Lighthouse--> + <location zone="1201" x="46.537" y="232.958" z="-311.395" rw="0.780747" rx="0.00" ry="-0.624847" rz="0.00" /> + <!--Frostburgh--> + <location zone="1260" x="-255.991" y="535.731" z="322.299" rw="0.683777" rx="0.00" ry="-0.729691" rz="0.00" /> + <!--Starbase 3001--> + <location zone="1600" x="93.572" y="1526.970" z="311.905" rw="-0.159486" rx="0.00" ry="0.987200" rz="0.00" /> + <!--LEGO Club--> + <location zone="1700" x="-256.293" y="1035.092" z="109.761" rw="0.00" rx="0.00" ry="1" rz="0.00" /> + <!--GF Ravine--> + <location zone="1300" x="-199.258" y="246.874" z="-101.174" rw="-0.219711" rx="0.00" ry="0.975565" rz="0.00" /> + <!--GF Race Place--> + <location zone="1300" x="51.848" y="329.0" z="561.114" rw="-0.277656" rx="0.00" ry="0.960681" rz="0.00" /> + <!--GF Pirate Camp--> + <location zone="1300" x="363.259" y="259.367" z="-210.834" rw="0.961918" rx="0.00" ry="-0.273340" rz="0.00" /> + <!--FV Race Place--> + <location zone="1400" x="746.784" y="237.957" z="495.015" rw="-0.036648" rx="0.00" ry="0.999328" rz="0.00" /> + <!--FV Great Tree--> + <location zone="1400" x="-194.288" y="381.275" z="-93.292" rw="0.935135" rx="0.00" ry="0.354292" rz="0.00" /> + <!--FV Paradox Refinery--> + <location zone="1400" x="-696.957" y="-3.206" z="-452.441" rw="0.884105" rx="0.00" ry="0.467288" rz="0.00" /> + <!--CP Sentinel Point Zeta--> + <location zone="1800" x="-222.634" y="92.373" z="568.392" rw="-0.435024" rx="0.00" ry="0.900419" rz="0.00" /> + <!--NJ Monastery Courtyard--> + <location zone="2000" x="-63.487" y="208.270" z="379.195" rw="0.00" rx="0.00" ry="1" rz="0.00" /> + </locations> + </object> </objects> diff --git a/vanity/demo.xml b/vanity/demo.xml new file mode 100644 index 000000000..31c80d8c3 --- /dev/null +++ b/vanity/demo.xml @@ -0,0 +1,143 @@ +<objects> + <!--A story plaque with custom text--> + <!--Font color can be set but you must encode the `<` as < and `>` as > >--> + <object lot="8139"> + <config> + <key>customText=13:This story plaque has custom text that is defined by DLU's vanity system. Check out <font color="#000000" >vanity/demo.xml</font> to see how this works!</key> + </config> + <locations> + <location zone="1200" x="-26.281" y="288.896" z="-77.484" rw="0.997534" rx="0.00" ry="-0.070190" rz="0.00" /> + </locations> + </object> + + <!--A tree spawned at two locations with different positions, rotations, and scales--> + <!--Positions and rotations are easily gotten by typing /loc or /pos, and /rot into the in-game chat--> + <object lot="3248"> + <locations> + <location zone="1200" x="-15.0" y="288.8" z="-167.0" rw="0.984321" rx="0.00" ry="0.176388" rz="0.00" /> + <location zone="1200" x="15.0" y="288.8" z="-158.0" rw="0.724628" rx="0.00" ry="-0.689141" rz="0.00" scale="0.30" /> + </locations> + </object> + + <!--A vendor who we will give GM-only items--> + <object name="Demo Fella - GM Items Vendor" lot="1867"> + <equipment>7630, 1727, 7453, 7521</equipment> + <config> + <key>vendorInvOverride=0:1727,7292,16553,2243,14535,14538,14531,6730</key> + </config> + <locations> + <location zone="1200" x="35.935" y="288.896" z="-128.213" rw="0.882977" rx="0.00" ry="-0.469416" rz="0.00" /> + </locations> + </object> + + <!--Friendly Felix will choose one of the 3 locations, then have a 50% chance to spawn at one of them on world server startup--> + <object lot="10141"> + <config> + <key>useLocationsAsRandomSpawnPoint=7:1</key> + </config> + <locations> + <location zone="1200" x="31.819" y="288.896" z="-117.095" rw="0.630659" rx="0.00" ry="-0.776060" rz="0.00" chance="0.50"/> + <location zone="1200" x="42.755" y="291.897" z="-144.385" rw="0.855306" rx="0.00" ry="-0.518124" rz="0.00" chance="0.50"/> + <location zone="1200" x="3.984" y="288.896" z="-165.947" rw="0.978508" rx="0.00" ry="-0.206210" rz="0.00" chance="0.50"/> + </locations> + </object> + + <!--Spawner(s) for enemies, largely copy-pasted from Portabello in this case--> + <object lot="176"> + <config> + <key>CheckPrecondition=0:</key> + <key>SmashableDoesNotCutNavmesh=7:0</key> + <key>add_to_navmesh=7:1</key> + <key>aggroRadius=3:15</key> + <key>camGradSnap=7:0</key> + <key>camPrefersToFadeObject=7:1</key> + <key>carver_only=7:0</key> + <key>create_physics=7:1</key> + <key>currency=5:0</key> + <key>custom_config_names=0:</key> + <key>explode_factor=3:1</key> + <key>fxpriority=1:0</key> + <key>gravFactor=3:1</key> + <key>grpNameQBShowBricks=0:</key> + <key>ignoreCameraCollision=7:0</key> + <key>interaction_distance=3:16</key> + <key>is_smashable=7:1</key> + <key>loadOnClientOnly=7:0</key> + <key>loadSrvrOnly=7:0</key> + <key>max_to_spawn=1:-1</key> + <key>navmesh_carver=7:0</key> + <key>no_auto_spawn=7:1</key> + <key>no_timed_spawn=7:1</key> + <key>override_faction=7:0</key> + <key>radius=3:0</key> + <key>renderAnimLODSkew=3:1</key> + <key>renderCullingGroup=5:0</key> + <key>renderOffscreenAnimEnabled=7:0</key> + <key>respawn=3:20</key> + <key>sceneIDOverride=1:255</key> + <key>sceneIDOverrideEnabled=7:0</key> + <key>sceneLayerIDOverride=5:0</key> + <key>set_faction=13:4</key> + <key>smashable_loot_matrix=1:486</key> + <key>smashable_loot_matrix_set=7:0</key> + <key>softtetherRadius=3:15</key> + <key>spawner_active_on_load=7:1</key> + <key>spawntemplate=1:12379</key> + <key>startsQBActivator=7:0</key> + <key>template=1:-1</key> + <key>tetherRadius=3:15</key> + <key>usetetherdb=7:0</key> + <key>usewanderdb=7:0</key> + <key>wanderRadius=3:15</key> + </config> + <locations> + <location zone="1200" x="-16.749" y="291.841" z="-122.349" rw="1.00" rx="0.00" ry="0.00" rz="0.00" /> + <location zone="1200" x="-15.696" y="291.608" z="-136.902" rw="1.00" rx="0.00" ry="0.00" rz="0.00" /> + </locations> + </object> + + <!--Spawner for a crate--> + <object lot="176"> + <config> + <key>CheckPrecondition=0:</key> + <key>SmashableDoesNotCutNavmesh=7:0</key> + <key>add_to_navmesh=7:1</key> + <key>bounding_radius_override=3:0</key> + <key>camGradSnap=7:0</key> + <key>camPrefersToFadeObject=7:1</key> + <key>carver_only=7:0</key> + <key>create_physics=7:1</key> + <key>custom_config_names=0:</key> + <key>explode_factor=3:1</key> + <key>friction=3:1.5</key> + <key>fxpriority=1:0</key> + <key>gravFactor=3:1</key> + <key>grpNameQBShowBricks=0:</key> + <key>ignoreCameraCollision=7:0</key> + <key>interaction_distance=3:16</key> + <key>is_smashable=7:1</key> + <key>loadOnClientOnly=7:0</key> + <key>max_to_spawn=1:-1</key> + <key>navmesh_carver=7:0</key> + <key>no_auto_spawn=7:1</key> + <key>no_timed_spawn=7:1</key> + <key>override_faction=7:0</key> + <key>radius=3:0</key> + <key>renderCullingGroup=5:0</key> + <key>respawn=5:20000</key> + <key>sceneIDOverride=1:255</key> + <key>sceneIDOverrideEnabled=7:0</key> + <key>sceneLayerIDOverride=5:0</key> + <key>set_faction=13:6 </key> + <key>smashable_loot_matrix=1:227</key> + <key>smashable_loot_matrix_set=7:0</key> + <key>spawner_active_on_load=7:1</key> + <key>spawntemplate=1:2295</key> + <key>startsQBActivator=7:0</key> + <key>template=1:-1</key> + </config> + <locations> + <location zone="1200" x="4.232" y="288.895" z="-85.846" rw="-0.205988" rx="0.00" ry="0.978555" rz="0.00" /> + </locations> + </object> +</objects> diff --git a/vanity/dev-tribute.xml b/vanity/dev-tribute.xml index d20e31a68..a3d4e7ebf 100644 --- a/vanity/dev-tribute.xml +++ b/vanity/dev-tribute.xml @@ -1,378 +1,439 @@ <objects> - <object name="Wincent - Developer" lot="2279"> - <equipment>6802, 2519, 2623, 14806</equipment> - <phrases> - <phrase>Sorry for the mess.</phrase> - <phrase>To future endeavours!</phrase> - <phrase>What could imagination bring to light?</phrase> - <phrase>Vroom vroom...</phrase> - <phrase>Take care to preserve the universe.</phrase> - <phrase>Builders of the world, unite!</phrase> - <phrase>Everything is awesome!</phrase> - <phrase>I hope my behaviors are behaving themselves.</phrase> - </phrases> - <locations> - <location zone="1200" x="-352.5" y="287.6" z="217.7" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" /> - </locations> - </object> - <object name="EmosewaMC - Quickbuilder" lot="6738"> - <equipment>12947, 12949, 12962, 12963</equipment> - <phrases> - <phrase>I hope quickbulds are still working!</phrase> - <phrase>Be careful crossing the gap!</phrase> - <phrase>Have The Maelstrom stopped going invisible?</phrase> - </phrases> - <locations> - <location zone="1800" x="745.756" y="75.262" z="-207.989" rw="0.838565" rx="0.0" ry="0.544801" rz="0.0" /> - </locations> - </object> - <object name="Neal - Paradox Scout" lot="6738"> - <equipment>9950, 9944, 14102, 14092</equipment> - <phrases> - <phrase>Hello Explorer! It's great to see you made it!</phrase> - <phrase>Have you heard about Darkflame?</phrase> - <phrase>I've traveled across this entire system, but nothing beats the view here.</phrase> - </phrases> - <locations> - <location zone="1200" x="163.835" y="330.756" z="-141.933" rw="0.774887" rx="0.0" ry="-0.6321" rz="0.0" /> - </locations> - </object> - <object name="averysumner - Destroyer of Worlds" lot="11235"> - <equipment></equipment> - <phrases> - <phrase>cmerw[acowipaejio;fawjioefasdl;kfjm;</phrase> - <phrase>I, for one, welcome our new robot overlords.</phrase> - <phrase>zxnpoasdfiopwemsadf'kawpfo[ekasdf;'s</phrase> - <phrase>*teleports behind you*</phrase> - </phrases> - <script name="scripts\02_server\DLU\DLUVanityTeleportingObject.lua" /> - <config> - <key data="teleport=7:1" /> - <key data="teleportInterval=3:3.0" /> - </config> - <locations> - <location zone="1200" x="-361.583" y="285.541" z="64.4695" rw="0.785518" rx="0.0" ry="0.618838" rz="0.0" /> - <location zone="1200" x="178.188" y="354.528" z="-173.932" rw="0.734375" rx="0.0" ry="-0.678744" rz="0.0" /> - <location zone="1200" x="389.093" y="295.119" z="-647.583" rw="0.851229" rx="0.0" ry="-0.524795" rz="0.0" /> - </locations> - </object> - <object name="NinjaOfLU - Resident Physicist" lot="12260"> - <equipment>4360, 2523, 5659, 10067</equipment> - <phrases> - <phrase>Congratulations! I don't see too many people around here!</phrase> - <phrase>Got any spring shoes?</phrase> - <phrase>I miss the quip!</phrase> - <phrase>Want to talk about physics?</phrase> - <phrase>Hang on, this isn't the DLU forums!</phrase> - <phrase>What if we're all just Boltzmann brains?</phrase> - <phrase>Hahaha! The universe? A computer program? How unlikely!</phrase> - <phrase>I have been idle for 10 minutes, and will be returned to the login screen in 5 minutes.</phrase> - <phrase>Of what has one to be proud, if dnot one's friends?</phrase> - </phrases> - <locations> - <location zone="1100" x="287" y="451" z="-98" rw="-0.320221" rx="0" ry="0.947343" rz="0" /> - </locations> - <locations> - <location zone="1800" x="798" y="93" z="325" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" /> - </locations> - </object> - <object name="BlasterBuilder - Race Ace" lot="8205"> - <equipment>14098, 8539, 14096, 14092</equipment> - <phrases> - <phrase>LEGO Universe... LEGO Universe... LEGO Universe... LEGO Universe...</phrase> - <phrase>So, they say the Maelstrom is chaos, but isn't Imagination also chaos?</phrase> - <phrase>The Sentinels have always given me cop vibes...</phrase> - <phrase>Where's Bob, you ask? Yeah, I dunno.</phrase> - <phrase>Bob's supposed to meet me here. I wonder where he is.</phrase> - <phrase>Hhhh... Fantastic.</phrase> - <phrase>Quicksicles are really nice, except for the 5 seconds of withdrawal.</phrase> - <phrase>Vroom vroom.</phrase> - <phrase>VROOM VROOM!</phrase> - <phrase>So I've been thinking: shouldn't every game have mood bars and randomized weather?</phrase> - <phrase>If there are two things I hate more than anything else, it's gender and Maelstrom.</phrase> - <phrase>Ah, sunny day. Unless you haven't defeated the Spider Queen yet, in which case, wow, it's raining ash.</phrase> - <phrase>I've been given the power to add to the game's canon: gender is over.</phrase> - <phrase>Wisdom is a circle. What you receive, you must give back.</phrase> - <phrase>AAAAAAAAAAAGHHH!</phrase> - <phrase>I kind of liked the atmosphere better when it was raining ash, but this is fine too I guess.</phrase> - <phrase>The current temperature in Avant Gardens is 112 degrees Fahrenheit!</phrase> - <phrase>The current temperature in Avant Gardens is 38 degrees Fahrenheit!</phrase> - <phrase>Gather uh banana</phrase> - <phrase>I've done nothing all day. Why am I here?</phrase> - </phrases> - <locations> - <location zone="1100" x="444.318" y="421.154" z="54.4241" rw="0.877539" rx="0.0" ry="0.479506" rz="0.0" /> - </locations> - </object> - <!-- Mick - Brick Market Broker --> - <object name="Mick - Brick Market Broker" lot="6876"> - <equipment>2519, 4091, 5128, 7990</equipment> - <phrases> - <phrase>Still can't believe we made it through that 2012 recession.</phrase> - <phrase>What's your market on Red Parrots?</phrase> - <phrase>Heard the news? Prices for brick #14451 are going to the moon!</phrase> - <phrase>Heard the news? Prices for brick #13191 are going to the moon!</phrase> - <phrase>Heard the news? Prices for brick #4718 are going to the moon!</phrase> - <phrase>Invest in grey kepis while you still can, they're a steal right now!</phrase> - <phrase>I really need to get rid of these Maelstrom Bricks, how about 80 cents on the dollar?</phrase> - <phrase>Don't buy at Darby's, the prices might seem good but the fees are outrageous.</phrase> - <phrase>I know a guy that sells jetpacks, it ain't cheap but everything has a price.</phrase> - <phrase>You know Dr. Overbuild? He keeps ignoring my calls.</phrase> - </phrases> - <locations> - <location zone="1100" x="449.725" y="414.926" z="180.539" rw="0.180645" rx="0.0" ry="0.983548" rz="0.0" /> - </locations> - </object> - <!-- Knightoffaith - Sage of Wanderlust --> - <object name="Knightoffaith - Sage of Wanderlust" lot="12260"> - <equipment>7359, 7368, 7380, 7392, 7403, 8456</equipment> - <phrases> - <phrase>Come and join me - take a look at the beauty that still remains even amidst the chaos</phrase> - <phrase>If it's a bit scuffed, you're doing it right</phrase> - <phrase>Always have things - and people - you care about</phrase> - <phrase>Careful, you get me talking and you might not be home in time for dinner!</phrase> - <phrase>If all else fails, try changing the long to a long long</phrase> - <phrase>If you do one thing - let it be to always hold respect for everyone</phrase> - <phrase>Never settle for mediocraty - seek excellence in all things</phrase> - <phrase>You ever heard the one about the octapus, the shark, and the - oh, nevermind</phrase> - <phrase>To imagination! May its spark never be extinguished.</phrase> - <phrase>Don't look at me, it was Sam's turn to look after Burno!</phrase> - <phrase>The Universe is beautiful - take some time to enjoy it</phrase> - </phrases> - <locations> - <location zone="1100" x="-381.053" y="367.787" z="-60.1185" rw="-0.14307" rx="0" ry="0.989713" rz="0" /> - </locations> - </object> - <object name="Snifflegully - DLU Alpha Tester" lot="2281"> - <equipment>15975, 7492, 12690, 12472</equipment> - <phrases> - <phrase>Praise the cube!</phrase> - <phrase>Congratulations, you have finished the 'Talk to Snifflegully any%' speedrun!</phrase> - <phrase>Fun fact: you can find R2-D2 bricks sold in Nexus Tower.</phrase> - <phrase>Have you found my other friends across the Nimbus System?</phrase> - <phrase>This game is fun.</phrase> - <phrase>Embrace the Sentinel meta!</phrase> - <phrase>Hope you enjoy DLU as much as I have, explorer!</phrase> - <phrase>There are many more memories still to be made.</phrase> - </phrases> - <locations> - <location zone="1200" x="-429.296" y="291.058" z="212.918" rw="0.339487" rx="0" ry="0.940611" rz="0" /> - </locations> - </object> - <object name="Hollis - Master Builder" lot="9893"> - <equipment>4465, 2517, 6855, 8532, 9615</equipment> - <phrases> - <phrase>Visit Starbase 3001 and blast off to the awesome worlds built by the World Builder League!</phrase> - <phrase>I single-handedly built everything you see around you. Well, maybe half of it. Ok, none of it. But I once built a pretty cool house on Nimbus Rock!</phrase> - <phrase>I once was told there was an elusive wizard living in the outskirts of Nimbus Station who will give you magical wizard powers if you catch him. I never did find that guy.</phrase> - <phrase>I checked the forecast for today, and the gravity on Moonbase will be perfect for jumping around! Which is the same as every day, but still.</phrase> - <phrase>There are many amazing properties to explore across the universe. You can visit some of them from the launchpads right here in Brick Annex.</phrase> - <phrase>Don't stop believing! Uhh, I mean building. Don't stop building!</phrase> - </phrases> - <locations> - <location zone="1200" x="-317.509" y="287.652" z="191.86" rw="0.57124" rx="0" ry="-0.820783" rz="0" /> - </locations> - </object> - <object name="Xiphoseer - Database Scout" lot="12260"> - <equipment>2632, 12754, 8645, 8468</equipment> - <phrases> - <phrase>Oh no, not that old list again</phrase> - <phrase>Have you seen this new thing I added?</phrase> - <phrase>This soundtrack is great!</phrase> - <phrase>lu:explorer</phrase> - <phrase>I've been to the plains of Avant Gardens!</phrase> - <phrase>It's a hash map, duh</phrase> - <phrase>Look at that view!</phrase> - <phrase>Oxidize!</phrase> - </phrases> - <locations> - <location zone="1300" x="283.986" y="261.208" z="-128.466" rw="0.70207" rx="0" ry="0.712108" rz="0" /> - </locations> - </object> - <object name="Simon - External Archeologist" lot="7128"> - <equipment>7363, 7371, 7383, 7395, 7405, 8462</equipment> - <phrases> - <phrase>I want to build a castle, but first I need to build the bricks.</phrase> - <phrase>Why make it easy when you can do it complicated</phrase> - <phrase>When you do extra steps, you can always customize the steps without redoing the whole staircase</phrase> - <phrase>Who needs lamps, when you have Tiki Torches</phrase> - </phrases> - <locations> - <location zone="1300" x="204.93" y="294.784" z="471.537" rw="0.85015" rx="0" ry="-0.52654" rz="0" /> - </locations> - </object> - <object name="Bricknave - Treasure Hunter" lot="2279"> - <equipment>7486, 7510, 7462, 8539</equipment> - <phrases> - <phrase>During my very first expedition, Stromlings were called Darklings, and they dropped entire treasure chests!</phrase> - <phrase>Legend has it that building a mysterious idol was the key to Gnarled Forest survival.</phrase> - <phrase>I was a member of an Inner Circle during the original Alpha Test expedition.</phrase> - <phrase>Did Johnny Thunder send you? A pal of Thunder is a pal of mine!</phrase> - <phrase>Did you know that some guy with green pants, a gray jacket, sunglasses, and a laser whip once impersonated Johnny Thunder?</phrase> - <phrase>Every time you build, you discover a piece of yourself.</phrase> - <phrase>There's treasure inside of all of us. It's called Imagination.</phrase> - <phrase>Stromlings! Why did it have to be Stromlings?</phrase> - </phrases> - <locations> - <location zone="1300" x="-47.6296" y="322.527" z="533.5" rw="0.145135" rx="0" ry="0.989412" rz="0" /> - </locations> - </object> - <object name="Jamie - Shenanigans Enthusiast" lot="9893"> - <equipment>12915, 9683, 10476, 13342, 14166</equipment> - <phrases> - <phrase>sup lol</phrase> - <phrase>How long have I been standing here?</phrase> - <phrase>Wait, did the game close yet?</phrase> - <phrase>... What year is it?</phrase> - </phrases> - <locations> - <location zone="1400" x="-490.608" y="51.9449" z="-347.747" rw="0.594978" rx="0" ry="-0.803742" rz="0" /> - </locations> - </object> - <object name="Wicked" lot="7412"> - <equipment>8287, 2957, 7523, 16613</equipment> - <phrases></phrases> - <locations> - <location zone="1400" x="264.506" y="339.931" z="54.1201" rw="0.715223" rx="0" ry="0.698896" rz="0" /> - </locations> - </object> - <object name="Krysto - Sentinal Veteran" lot="12260"> - <equipment>12651, 12648, 10158, 5694, 16619, 9681, 8286</equipment> - <phrases> - <phrase>Need a pick me up? Interact with the consoles here to restore your health and armor!</phrase> - <phrase>Did I ever tell you about that one time I broke the mail?</phrase> - <phrase>Can I interest you in a surprise model pack? No? Ok...</phrase> - <phrase>Headed to Forbidden Valley? Watch out for flying Ronin!</phrase> - <phrase>If you run into Sensei Wu, tell him he still owes me that red kabuto.</phrase> - <phrase>If you see another me running around, please inform Wisp Lee immediately.</phrase> - <phrase>What do you mean my title is misspelled?</phrase> - <phrase>When I was your age, numbers were illegal.</phrase> - </phrases> - <locations> - <location zone="1900" x="-493.724" y="1124.05" z="-76.6355" rw="0.1719" rx="0" ry="0.985114" rz="0" /> - </locations> - </object> - 12651 - <object name="Matthew - ?????" lot="2279"> - <equipment>9856, 7793, 6928, 6927</equipment> - <phrases> - <phrase>I think I have a migraine from staring at this for so long</phrase> - <phrase>Anything but Portabello</phrase> - </phrases> - <locations> - <location zone="1900" x="-227.621" y="1188.28" z="145.734" rw="-0.254353" rx="0" ry="0.967111" rz="0" /> - </locations> - </object> - <object name="Raine" lot="9893"> - <equipment>13342, 7370, 7382</equipment> - <phrases> - <phrase>Per Aspera ad Astra</phrase> - </phrases> - <locations> - <location zone="1900" x="-190.673" y="1218.34" z="221.6" rw="0.972371" rx="0" ry="-0.233441" rz="0" /> - </locations> - </object> - <object name="Brickgirl - Explorer" lot="12260"> - <equipment>12781, 12686, 13000, 12802, 12678, 12095</equipment> - <phrases> - <phrase>Imagination will often carry us to worlds that never were, but without it we go nowhere.</phrase> - <phrase>I love this view over to Butterscorch. Look at it for a while and admire the changing stars in the sky.</phrase> - <phrase>Have you tried those buttery croissants from “Farnham Spoon” they are delicious! I might just go and have another</phrase> - <phrase>Have fun!</phrase> - </phrases> - <locations> - <location zone="1800" x="-39.2259" y="96.8605" z="-550.077" rw="0.815145" rx="0" ry="-0.579257" rz="0" /> - </locations> - </object> - <object name="Sam - The Avianite" lot="2281"> - <equipment>12563, 12565, 12567, 12949, 12947, 7570</equipment> - <phrases> - <phrase>Nice finding me! Now take a moment to take a deep breath, in... And out... NOW GET BACK TO YOUR QUEST!</phrase> - <phrase>Wu once told me, "The path we seek is never a straight line"."</phrase> - <phrase>Stop! I'm from the future to warn you that there will be snakes, ninja robots! More snakes, ghosts, sky pirates, snakes that make snakes! Bikers, dragon hunters... Wait what do you mean it hasn't happened yet?</phrase> - </phrases> - <locations> - <location zone="2000" x="-119.269" y="230.372" z="226.63" rw="0.381416" rx="0" ry="0.924404" rz="0" /> - </locations> - </object> - <object name="lcdr - Dab Specialist" lot="8657"> - <equipment>15931, 4298, 2526</equipment> - <phrases> - <phrase>Hello there.</phrase> - <phrase>May the Bodge be with you.</phrase> - <phrase>The Bodge is what gives a programmer his power. It's an energy field created by all sketchy programs. It surrounds us and penetrates us. It binds the program together.</phrase> - <phrase>LEGO Universe truly is the Dark Souls of LEGO games.</phrase> - <phrase>I'm gonna get DLU to compile on my machine one day, I swear.</phrase> - <phrase>Hold on, I need to reconfigure my input bindings - my foot pedals aren't mapped yet.</phrase> - <phrase>If you're having trouble playing, make sure your input piano has at least two octaves available.</phrase> - <phrase>Finally, unsigned bool.</phrase> - <phrase>If you find a stray PC on the side of the road, give it shelter.</phrase> - <phrase>Place Nate on your Property. Do it now.</phrase> - <phrase>Playpen balls are legos.</phrase> - <phrase>Gonk.</phrase> - <phrase>There is a theory which states that if ever anyone discovers exactly what the Universe is for and why it is here, it will instantly disappear and be replaced by something even more bizarre and inexplicable. There is another theory, which states that this has already happened.</phrase> - </phrases> - <locations> - <location zone="1200" x="197.549" y="259.137" z="-587.759" rw="0.873694" rx="0" ry="0.486475" rz="0" /> - </locations> - </object> - <object name="zaop - Assembly Scientist" lot="2279"> - <equipment>12099, 3010, 10067, 7503</equipment> - <phrases> - <phrase>Hi!</phrase> - <phrase>If you get in trouble, just go back in time.</phrase> - <phrase>Hello!</phrase> - <phrase>Particles were not supposed to be looked at!</phrase> - <phrase>Direction and magnitude!</phrase> - <phrase>Good to see you here!</phrase> - <phrase>Oh, that's not a bug, it's a surprise feature.</phrase> - <phrase>Hello again, it's been a while!</phrase> - <phrase>What on earth is a Boltzmann brain?</phrase> - <phrase>Thanks for stopping by!</phrase> - <phrase>Where have you been? We've been looking for you since 2012!</phrase> - <phrase>Careful now with that shovel!</phrase> - <phrase>Go find my friends scattered across the rest of the Universe!</phrase> - <phrase>Excuse me, do you know the way to Frostburgh?</phrase> - <phrase>What are those Paradox scientists up to these days?</phrase> - </phrases> - <locations> - <location zone="1100" x="436.949" y="415.264" z="151.381" rw="0.528425" rx="0" ry="0.84898" rz="0" /> - </locations> - </object> - <object name="Ben" lot="2279"> - <equipment>8664, 4065, 2587</equipment> - <phrases></phrases> - <locations> - <location zone="1200" x="284.538" y="260.627" z="-506.692" rw="0.819721" rx="0" ry="0.572763" rz="0" /> - </locations> - </object> - <object name="HappyAngryCatfish - Explorer" lot="2279"> - <equipment>8613, 13000, 7570</equipment> - <phrases> - <phrase>The red parrot can be very difficult to find!</phrase> - <phrase>Some say there are elephants in this forest.</phrase> - <phrase>I think I may be lost...</phrase> - <phrase>I'm feeling a bit emotionally conflicted right now</phrase> - </phrases> - <locations> - <location zone="1300" x="-171.217" y="246.482" z="-147.05" rw="-0.203118" rx="0" ry="0.979154" rz="0" /> - </locations> - </object> + <object name="Wincent - Developer" lot="2279"> + <equipment>6802, 2519, 2623, 14806</equipment> + <phrases> + <phrase>Sorry for the mess.</phrase> + <phrase>To future endeavours!</phrase> + <phrase>What could imagination bring to light?</phrase> + <phrase>Vroom vroom...</phrase> + <phrase>Take care to preserve the universe.</phrase> + <phrase>Builders of the world, unite!</phrase> + <phrase>Everything is awesome!</phrase> + <phrase>I hope my behaviors are behaving themselves.</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1200" x="-352.5" y="287.6" z="217.7" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" /> + </locations> + </object> + <object name="EmosewaMC - Quickbuilder" lot="6738"> + <equipment>12947, 12949, 12962, 12963</equipment> + <phrases> + <phrase>I hope quickbulds are still working!</phrase> + <phrase>Be careful crossing the gap!</phrase> + <phrase>Have The Maelstrom stopped going invisible?</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1800" x="745.756" y="75.262" z="-207.989" rw="0.838565" rx="0.0" ry="0.544801" rz="0.0" /> + </locations> + </object> + <object name="Neal - Paradox Scout" lot="6738"> + <equipment>9950, 9944, 14102, 14092</equipment> + <phrases> + <phrase>Hello Explorer! It's great to see you made it!</phrase> + <phrase>Have you heard about Darkflame?</phrase> + <phrase>I've traveled across this entire system, but nothing beats the view here.</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1200" x="163.835" y="330.756" z="-141.933" rw="0.774887" rx="0.0" ry="-0.6321" rz="0.0" /> + </locations> + </object> + <object name="averysumner - Destroyer of Worlds" lot="11235"> + <phrases> + <phrase>cmerw[acowipaejio;fawjioefasdl;kfjm;</phrase> + <phrase>I, for one, welcome our new robot overlords.</phrase> + <phrase>zxnpoasdfiopwemsadf'kawpfo[ekasdf;'s</phrase> + <phrase>*teleports behind you*</phrase> + </phrases> + <config> + <key>useLocationsAsRandomSpawnPoint=7:1</key> + <key>teleportInterval=3:15.0</key> + <key>custom_script_server=0:scripts\02_server\DLU\DLUVanityTeleportingObject.lua</key> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1200" x="-361.583" y="285.541" z="64.4695" rw="0.785518" rx="0.0" ry="0.618838" rz="0.0" /> + <location zone="1200" x="178.188" y="354.528" z="-173.932" rw="0.734375" rx="0.0" ry="-0.678744" rz="0.0" /> + <location zone="1200" x="-318.569" y="287.637695" z="226.728" rw="-0.289502" rx="0.0" ry="0.957178" rz="0.0" /> + <location zone="1200" x="389.093" y="295.119" z="-647.583" rw="0.851229" rx="0.0" ry="-0.524795" rz="0.0" /> + </locations> + </object> + <object name="NinjaOfLU - Resident Physicist" lot="12260"> + <equipment>4360, 2523, 5659, 10067</equipment> + <phrases> + <phrase>Congratulations! I don't see too many people around here!</phrase> + <phrase>Got any spring shoes?</phrase> + <phrase>I miss the quip!</phrase> + <phrase>Want to talk about physics?</phrase> + <phrase>Hang on, this isn't the DLU forums!</phrase> + <phrase>What if we're all just Boltzmann brains?</phrase> + <phrase>Hahaha! The universe? A computer program? How unlikely!</phrase> + <phrase>I have been idle for 10 minutes, and will be returned to the login screen in 5 minutes.</phrase> + <phrase>Of what has one to be proud, if dnot one's friends?</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1100" x="287" y="451" z="-98" rw="-0.320221" rx="0" ry="0.947343" rz="0" /> + <location zone="1800" x="798" y="93" z="325" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" /> + </locations> + </object> + <object name="BlasterBuilder - Race Ace" lot="8205"> + <equipment>14098, 8539, 14096, 14092</equipment> + <phrases> + <phrase>LEGO Universe... LEGO Universe... LEGO Universe... LEGO Universe...</phrase> + <phrase>So, they say the Maelstrom is chaos, but isn't Imagination also chaos?</phrase> + <phrase>The Sentinels have always given me cop vibes...</phrase> + <phrase>Where's Bob, you ask? Yeah, I dunno.</phrase> + <phrase>Bob's supposed to meet me here. I wonder where he is.</phrase> + <phrase>Hhhh... Fantastic.</phrase> + <phrase>Quicksicles are really nice, except for the 5 seconds of withdrawal.</phrase> + <phrase>Vroom vroom.</phrase> + <phrase>VROOM VROOM!</phrase> + <phrase>So I've been thinking: shouldn't every game have mood bars and randomized weather?</phrase> + <phrase>If there are two things I hate more than anything else, it's gender and Maelstrom.</phrase> + <phrase>Ah, sunny day. Unless you haven't defeated the Spider Queen yet, in which case, wow, it's raining ash.</phrase> + <phrase>I've been given the power to add to the game's canon: gender is over.</phrase> + <phrase>Wisdom is a circle. What you receive, you must give back.</phrase> + <phrase>AAAAAAAAAAAGHHH!</phrase> + <phrase>I kind of liked the atmosphere better when it was raining ash, but this is fine too I guess.</phrase> + <phrase>The current temperature in Avant Gardens is 112 degrees Fahrenheit!</phrase> + <phrase>The current temperature in Avant Gardens is 38 degrees Fahrenheit!</phrase> + <phrase>Gather uh banana</phrase> + <phrase>I've done nothing all day. Why am I here?</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1100" x="444.318" y="421.154" z="54.4241" rw="0.877539" rx="0.0" ry="0.479506" rz="0.0" /> + </locations> + </object> + <object name="Mick - Brick Market Broker" lot="6876"> + <equipment>2519, 4091, 5128, 7990</equipment> + <phrases> + <phrase>Still can't believe we made it through that 2012 recession.</phrase> + <phrase>What's your market on Red Parrots?</phrase> + <phrase>Heard the news? Prices for brick #14451 are going to the moon!</phrase> + <phrase>Heard the news? Prices for brick #13191 are going to the moon!</phrase> + <phrase>Heard the news? Prices for brick #4718 are going to the moon!</phrase> + <phrase>Invest in grey kepis while you still can, they're a steal right now!</phrase> + <phrase>I really need to get rid of these Maelstrom Bricks, how about 80 cents on the dollar?</phrase> + <phrase>Don't buy at Darby's, the prices might seem good but the fees are outrageous.</phrase> + <phrase>I know a guy that sells jetpacks, it ain't cheap but everything has a price.</phrase> + <phrase>You know Dr. Overbuild? He keeps ignoring my calls.</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1100" x="449.725" y="414.926" z="180.539" rw="0.180645" rx="0.0" ry="0.983548" rz="0.0" /> + </locations> + </object> + <object name="Knightoffaith - Sage of Wanderlust" lot="12260"> + <equipment>7359, 7368, 7380, 7392, 7403, 8456</equipment> + <phrases> + <phrase>Come and join me - take a look at the beauty that still remains even amidst the chaos</phrase> + <phrase>If it's a bit scuffed, you're doing it right</phrase> + <phrase>Always have things - and people - you care about</phrase> + <phrase>Careful, you get me talking and you might not be home in time for dinner!</phrase> + <phrase>If all else fails, try changing the long to a long long</phrase> + <phrase>If you do one thing - let it be to always hold respect for everyone</phrase> + <phrase>Never settle for mediocraty - seek excellence in all things</phrase> + <phrase>You ever heard the one about the octapus, the shark, and the - oh, nevermind</phrase> + <phrase>To imagination! May its spark never be extinguished.</phrase> + <phrase>Don't look at me, it was Sam's turn to look after Burno!</phrase> + <phrase>The Universe is beautiful - take some time to enjoy it</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1100" x="-381.053" y="367.787" z="-60.1185" rw="-0.14307" rx="0" ry="0.989713" rz="0" /> + </locations> + </object> + <object name="Snifflegully - DLU Alpha Tester" lot="2281"> + <equipment>15975, 7492, 12690, 12472</equipment> + <phrases> + <phrase>Praise the cube!</phrase> + <phrase>Congratulations, you have finished the 'Talk to Snifflegully any%' speedrun!</phrase> + <phrase>Fun fact: you can find R2-D2 bricks sold in Nexus Tower.</phrase> + <phrase>Have you found my other friends across the Nimbus System?</phrase> + <phrase>This game is fun.</phrase> + <phrase>Embrace the Sentinel meta!</phrase> + <phrase>Hope you enjoy DLU as much as I have, explorer!</phrase> + <phrase>There are many more memories still to be made.</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1200" x="-429.296" y="291.058" z="212.918" rw="0.339487" rx="0" ry="0.940611" rz="0" /> + </locations> + </object> + <object name="Hollis - Master Builder" lot="9893"> + <equipment>4465, 2517, 6855, 8532, 9615</equipment> + <phrases> + <phrase>Visit Starbase 3001 and blast off to the awesome worlds built by the World Builder League!</phrase> + <phrase>I single-handedly built everything you see around you. Well, maybe half of it. Ok, none of it. But I once built a pretty cool house on Nimbus Rock!</phrase> + <phrase>I once was told there was an elusive wizard living in the outskirts of Nimbus Station who will give you magical wizard powers if you catch him. I never did find that guy.</phrase> + <phrase>I checked the forecast for today, and the gravity on Moonbase will be perfect for jumping around! Which is the same as every day, but still.</phrase> + <phrase>There are many amazing properties to explore across the universe. You can visit some of them from the launchpads right here in Brick Annex.</phrase> + <phrase>Don't stop believing! Uhh, I mean building. Don't stop building!</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1200" x="-317.509" y="287.652" z="191.86" rw="0.57124" rx="0" ry="-0.820783" rz="0" /> + </locations> + </object> + <object name="Xiphoseer - Database Scout" lot="12260"> + <equipment>2632, 12754, 8645, 8468</equipment> + <phrases> + <phrase>Oh no, not that old list again</phrase> + <phrase>Have you seen this new thing I added?</phrase> + <phrase>This soundtrack is great!</phrase> + <phrase>lu:explorer</phrase> + <phrase>I've been to the plains of Avant Gardens!</phrase> + <phrase>It's a hash map, duh</phrase> + <phrase>Look at that view!</phrase> + <phrase>Oxidize!</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1300" x="283.986" y="261.208" z="-128.466" rw="0.70207" rx="0" ry="0.712108" rz="0" /> + </locations> + </object> + <object name="Simon - External Archeologist" lot="7128"> + <equipment>7363, 7371, 7383, 7395, 7405, 8462</equipment> + <phrases> + <phrase>I want to build a castle, but first I need to build the bricks.</phrase> + <phrase>Why make it easy when you can do it complicated</phrase> + <phrase>When you do extra steps, you can always customize the steps without redoing the whole staircase</phrase> + <phrase>Who needs lamps, when you have Tiki Torches</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1300" x="204.93" y="294.784" z="471.537" rw="0.85015" rx="0" ry="-0.52654" rz="0" /> + </locations> + </object> + <object name="Bricknave - Treasure Hunter" lot="2279"> + <equipment>7486, 7510, 7462, 8539</equipment> + <phrases> + <phrase>During my very first expedition, Stromlings were called Darklings, and they dropped entire treasure chests!</phrase> + <phrase>Legend has it that building a mysterious idol was the key to Gnarled Forest survival.</phrase> + <phrase>I was a member of an Inner Circle during the original Alpha Test expedition.</phrase> + <phrase>Did Johnny Thunder send you? A pal of Thunder is a pal of mine!</phrase> + <phrase>Did you know that some guy with green pants, a gray jacket, sunglasses, and a laser whip once impersonated Johnny Thunder?</phrase> + <phrase>Every time you build, you discover a piece of yourself.</phrase> + <phrase>There's treasure inside of all of us. It's called Imagination.</phrase> + <phrase>Stromlings! Why did it have to be Stromlings?</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1300" x="-47.6296" y="322.527" z="533.5" rw="0.145135" rx="0" ry="0.989412" rz="0" /> + </locations> + </object> + <object name="Jamie - Shenanigans Enthusiast" lot="9893"> + <equipment>12915, 9683, 10476, 13342, 14166</equipment> + <phrases> + <phrase>sup lol</phrase> + <phrase>How long have I been standing here?</phrase> + <phrase>Wait, did the game close yet?</phrase> + <phrase>... What year is it?</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1400" x="-490.608" y="51.9449" z="-347.747" rw="0.594978" rx="0" ry="-0.803742" rz="0" /> + </locations> + </object> + <object name="Wicked" lot="7412"> + <equipment>8287, 2957, 7523, 16613</equipment> + <locations> + <location zone="1400" x="264.506" y="339.931" z="54.1201" rw="0.715223" rx="0" ry="0.698896" rz="0" /> + </locations> + </object> + <object name="Krysto - Sentinal Veteran" lot="12260"> + <equipment>12651, 12648, 10158, 5694, 16619, 9681, 8286</equipment> + <phrases> + <phrase>Need a pick me up? Interact with the consoles here to restore your health and armor!</phrase> + <phrase>Did I ever tell you about that one time I broke the mail?</phrase> + <phrase>Can I interest you in a surprise model pack? No? Ok...</phrase> + <phrase>Headed to Forbidden Valley? Watch out for flying Ronin!</phrase> + <phrase>If you run into Sensei Wu, tell him he still owes me that red kabuto.</phrase> + <phrase>If you see another me running around, please inform Wisp Lee immediately.</phrase> + <phrase>What do you mean my title is misspelled?</phrase> + <phrase>When I was your age, numbers were illegal.</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1900" x="-493.724" y="1124.05" z="-76.6355" rw="0.1719" rx="0" ry="0.985114" rz="0" /> + </locations> + </object> + <object name="Matthew - ?????" lot="2279"> + <equipment>9856, 7793, 6928, 6927</equipment> + <phrases> + <phrase>I think I have a migraine from staring at this for so long</phrase> + <phrase>Anything but Portabello</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1900" x="-227.621" y="1188.28" z="145.734" rw="-0.254353" rx="0" ry="0.967111" rz="0" /> + </locations> + </object> + <object name="Raine" lot="9893"> + <equipment>13342, 7370, 7382</equipment> + <phrases> + <phrase>Per Aspera ad Astra</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1900" x="-190.673" y="1218.34" z="221.6" rw="0.972371" rx="0" ry="-0.233441" rz="0" /> + </locations> + </object> + <object name="Brickgirl - Explorer" lot="12260"> + <equipment>12781, 12686, 13000, 12802, 12678, 12095</equipment> + <phrases> + <phrase>Imagination will often carry us to worlds that never were, but without it we go nowhere.</phrase> + <phrase>I love this view over to Butterscorch. Look at it for a while and admire the changing stars in the sky.</phrase> + <phrase>Have you tried those buttery croissants from “Farnham Spoon” they are delicious! I might just go and have another</phrase> + <phrase>Have fun!</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1800" x="-39.2259" y="96.8605" z="-550.077" rw="0.815145" rx="0" ry="-0.579257" rz="0" /> + </locations> + </object> + <object name="Sam - The Avianite" lot="2281"> + <equipment>12563, 12565, 12567, 12949, 12947, 7570</equipment> + <phrases> + <phrase>Nice finding me! Now take a moment to take a deep breath, in... And out... NOW GET BACK TO YOUR QUEST!</phrase> + <phrase>Wu once told me, "The path we seek is never a straight line"."</phrase> + <phrase>Stop! I'm from the future to warn you that there will be snakes, ninja robots! More snakes, ghosts, sky pirates, snakes that make snakes! Bikers, dragon hunters... Wait what do you mean it hasn't happened yet?</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="2000" x="-119.269" y="230.372" z="226.63" rw="0.381416" rx="0" ry="0.924404" rz="0" /> + </locations> + </object> + <object name="lcdr - Dab Specialist" lot="8657"> + <equipment>15931, 4298, 2526</equipment> + <phrases> + <phrase>Hello there.</phrase> + <phrase>May the Bodge be with you.</phrase> + <phrase>The Bodge is what gives a programmer his power. It's an energy field created by all sketchy programs. It surrounds us and penetrates us. It binds the program together.</phrase> + <phrase>LEGO Universe truly is the Dark Souls of LEGO games.</phrase> + <phrase>I'm gonna get DLU to compile on my machine one day, I swear.</phrase> + <phrase>Hold on, I need to reconfigure my input bindings - my foot pedals aren't mapped yet.</phrase> + <phrase>If you're having trouble playing, make sure your input piano has at least two octaves available.</phrase> + <phrase>Finally, unsigned bool.</phrase> + <phrase>If you find a stray PC on the side of the road, give it shelter.</phrase> + <phrase>Place Nate on your Property. Do it now.</phrase> + <phrase>Playpen balls are legos.</phrase> + <phrase>Gonk.</phrase> + <phrase>There is a theory which states that if ever anyone discovers exactly what the Universe is for and why it is here, it will instantly disappear and be replaced by something even more bizarre and inexplicable. There is another theory, which states that this has already happened.</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1200" x="197.549" y="259.137" z="-587.759" rw="0.873694" rx="0" ry="0.486475" rz="0" /> + </locations> + </object> + <object name="zaop - Assembly Scientist" lot="2279"> + <equipment>12099, 3010, 10067, 7503</equipment> + <phrases> + <phrase>Hi!</phrase> + <phrase>If you get in trouble, just go back in time.</phrase> + <phrase>Hello!</phrase> + <phrase>Particles were not supposed to be looked at!</phrase> + <phrase>Direction and magnitude!</phrase> + <phrase>Good to see you here!</phrase> + <phrase>Oh, that's not a bug, it's a surprise feature.</phrase> + <phrase>Hello again, it's been a while!</phrase> + <phrase>What on earth is a Boltzmann brain?</phrase> + <phrase>Thanks for stopping by!</phrase> + <phrase>Where have you been? We've been looking for you since 2012!</phrase> + <phrase>Careful now with that shovel!</phrase> + <phrase>Go find my friends scattered across the rest of the Universe!</phrase> + <phrase>Excuse me, do you know the way to Frostburgh?</phrase> + <phrase>What are those Paradox scientists up to these days?</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1100" x="436.949" y="415.264" z="151.381" rw="0.528425" rx="0" ry="0.84898" rz="0" /> + </locations> + </object> + <object name="Ben" lot="2279"> + <equipment>8664, 4065, 2587</equipment> + <locations> + <location zone="1200" x="284.538" y="260.627" z="-506.692" rw="0.819721" rx="0" ry="0.572763" rz="0" /> + </locations> + </object> + <object name="HappyAngryCatfish - Explorer" lot="2279"> + <equipment>8613, 13000, 7570</equipment> + <phrases> + <phrase>The red parrot can be very difficult to find!</phrase> + <phrase>Some say there are elephants in this forest.</phrase> + <phrase>I think I may be lost...</phrase> + <phrase>I'm feeling a bit emotionally conflicted right now</phrase> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + </config> + <locations> + <location zone="1300" x="-171.217" y="246.482" z="-147.05" rw="-0.203118" rx="0" ry="0.979154" rz="0" /> + </locations> + </object> <object name="Max - Developer" lot="9749"> - <equipment>4523, 2517, 11909</equipment> - <phrases> - <phrase>Some people know me as "Darwin"; but that's been a while!</phrase> - <phrase>Per aspera ad astra!</phrase> - <phrase>Oh, hi there!</phrase> - <phrase>If you see a certain wizard, say hi to him for me!</phrase> - <phrase>Persue your goals, I believe in you!</phrase> - <phrase>Something to think about: "I like red shirts. Some people don't, but that's okay. It's for me, not them."</phrase> - <phrase>Working as intended</phrase> - <phrase>I love cats, little meow meows</phrase> + <equipment>4523, 2517, 11909</equipment> + <phrases> + <phrase>Some people know me as "Darwin"; but that's been a while!</phrase> + <phrase>Per aspera ad astra!</phrase> + <phrase>Oh, hi there!</phrase> + <phrase>If you see a certain wizard, say hi to him for me!</phrase> + <phrase>Persue your goals, I believe in you!</phrase> + <phrase>Something to think about: "I like red shirts. Some people don't, but that's okay. It's for me, not them."</phrase> + <phrase>Working as intended</phrase> + <phrase>I love cats, little meow meows</phrase> <phrase>It's not perfect, but it works!</phrase> - </phrases> - <locations> - <location zone="1201" x="197.709" y="179.335" z="-8.05284" rw="0.544424" rx="0" ry="-0.83881" rz="0" /> - </locations> - </object> + </phrases> + <config> + <key>custom_script_client=0:scripts\ai\SPEC\MISSION_MINIGAME_CLIENT.lua</key> + <key>vendorInvOverride=0:11909,7785,12764,12241</key> + </config> + <locations> + <location zone="1201" x="197.709" y="179.335" z="-8.05284" rw="0.544424" rx="0" ry="-0.83881" rz="0" /> + </locations> + </object> </objects> diff --git a/vanity/root.xml b/vanity/root.xml index dbbcff512..dcb89217a 100644 --- a/vanity/root.xml +++ b/vanity/root.xml @@ -1,4 +1,5 @@ <files> - <file name="dev-tribute.xml" enabled="1"/> - <file name="atm.xml" enabled="0"/> + <file name="dev-tribute.xml" enabled="1"/> + <file name="atm.xml" enabled="0"/> + <file name="demo.xml" enabled="0"/> </files> diff --git a/versions.txt b/versions.txt index 1dc48d9c6..fa7ea86c8 100644 --- a/versions.txt +++ b/versions.txt @@ -1,3 +1,7 @@ +2.3 - Dragonmaw functional, new slash command system, vanity system overhaul +2.2 - Code cleanup and QoL fixes +2.1 - Bug and crash fixes +2.0 - Whole lot of fixed bugs and implemented features 1.0 - Final cleanup and bug fixing for public release 0.9 - Includes BBB without the need for a UGC server, cannon cove minigame, and bug fixes. 0.8 - Added Ninjago! and it's various features + frakjaw minigame. AG survival now works. @@ -7,4 +11,4 @@ 0.4 - Added Havok to replace Bullet, Instancing, Quickbuilds, rockets, and a ton more fixes and additions. 0.3 - FrostBurgh, Snowdrift and Snowman's Land testing version. Includes bodged systems. 0.2 - Transfer to VS2019 & Bullet -0.1 - Initial transfer from NixLU, up until BehaviorManager inclusion \ No newline at end of file +0.1 - Initial transfer from NixLU, up until BehaviorManager inclusion