diff --git a/CMakeLists.txt b/CMakeLists.txt index e085bfe71..5f8dbaf5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,18 @@ -cmake_minimum_required(VERSION 3.18) +cmake_minimum_required(VERSION 3.25) project(Darkflame) + +# 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_CXX_STANDARD 20) set(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 @@ -70,13 +79,15 @@ if(UNIX) 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") 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_RELWITHDEBINFO ${CMAKE_BINARY_DIR}) @@ -90,6 +101,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +find_package(MariaDB) + # Create a /resServer directory make_directory(${CMAKE_BINARY_DIR}/resServer) @@ -97,7 +110,7 @@ make_directory(${CMAKE_BINARY_DIR}/resServer) make_directory(${CMAKE_BINARY_DIR}/logs) # Copy resource files on first build -set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf") +set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blocklist.dcf") message(STATUS "Checking resource file integrity") include(Utils) @@ -179,7 +192,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" "NPC.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,91 +215,47 @@ 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" - "thirdparty/magic_enum/include/magic_enum" - "thirdparty/raknet/Source" - "thirdparty/tinyxml2" - "thirdparty/recastnavigation" - "thirdparty/SQLite" - "thirdparty/cpplinq" - "thirdparty/cpp-httplib" - "thirdparty/MD5" - "tests" "tests/dCommonTests" "tests/dGameTests" "tests/dGameTests/dComponentsTests" + + SYSTEM "thirdparty/magic_enum/include/magic_enum" + SYSTEM "thirdparty/raknet/Source" + SYSTEM "thirdparty/tinyxml2" + SYSTEM "thirdparty/recastnavigation" + SYSTEM "thirdparty/SQLite" + SYSTEM "thirdparty/cpplinq" + SYSTEM "thirdparty/cpp-httplib" + SYSTEM "thirdparty/MD5" ) # 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") -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") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast -Werror") # Warning flags 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 +290,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 +312,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/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/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/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 d77eeeed0..6dfbd7fc1 100644 --- a/dChatServer/ChatIgnoreList.cpp +++ b/dChatServer/ChatIgnoreList.cpp @@ -1,6 +1,6 @@ #include "ChatIgnoreList.h" #include "PlayerContainer.h" -#include "eChatInternalMessageType.h" +#include "eChatMessageType.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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receivingPlayer); //portion that will get routed: @@ -59,7 +59,7 @@ void ChatIgnoreList::GetIgnoreList(Packet* packet) { bitStream.Write(LUWString(ignoredPlayer.playerName, 36)); } - Game::server->Send(&bitStream, packet->systemAddress, false); + Game::server->Send(bitStream, packet->systemAddress, false); } void ChatIgnoreList::AddIgnore(Packet* packet) { @@ -131,7 +131,7 @@ void ChatIgnoreList::AddIgnore(Packet* packet) { bitStream.Write(playerNameSend); bitStream.Write(ignoredPlayerId); - Game::server->Send(&bitStream, packet->systemAddress, false); + Game::server->Send(bitStream, packet->systemAddress, false); } void ChatIgnoreList::RemoveIgnore(Packet* packet) { @@ -167,5 +167,5 @@ void ChatIgnoreList::RemoveIgnore(Packet* packet) { LUWString playerNameSend(removedIgnoreStr, 33); bitStream.Write(playerNameSend); - Game::server->Send(&bitStream, packet->systemAddress, false); + Game::server->Send(bitStream, packet->systemAddress, false); } diff --git a/dChatServer/ChatPacketHandler.cpp b/dChatServer/ChatPacketHandler.cpp index 5e2e58d7d..82cea018b 100644 --- a/dChatServer/ChatPacketHandler.cpp +++ b/dChatServer/ChatPacketHandler.cpp @@ -14,11 +14,11 @@ #include "eObjectBits.h" #include "eConnectionType.h" #include "eChatMessageType.h" -#include "eChatInternalMessageType.h" #include "eClientMessageType.h" #include "eGameMessageType.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,7 +60,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(playerID); //portion that will get routed: @@ -355,6 +355,67 @@ void ChatPacketHandler::HandleGMLevelUpdate(Packet* packet) { inStream.Read(player.gmLevel); } + +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, eChatMessageType::WORLD_ROUTE_PACKET); + bitStream.Write(request.requestor); + + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::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, eChatMessageType::WORLD_ROUTE_PACKET); + bitStream.Write(request.requestor); + + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::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) { @@ -454,7 +515,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(routeTo.playerID); BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE); @@ -696,7 +757,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: @@ -711,7 +772,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: @@ -738,7 +799,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: @@ -763,7 +824,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: @@ -780,7 +841,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: @@ -809,7 +870,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: @@ -835,7 +896,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: @@ -869,7 +930,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(friendData.playerID); //portion that will get routed: @@ -906,7 +967,7 @@ void ChatPacketHandler::SendFriendRequest(const PlayerData& receiver, const Play } CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: @@ -920,7 +981,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); // Portion that will get routed: @@ -943,7 +1004,7 @@ 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, eChatMessageType::WORLD_ROUTE_PACKET); bitStream.Write(receiver.playerID); //portion that will get routed: 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 449570421..d6e99230e 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -17,7 +17,6 @@ #include "PlayerContainer.h" #include "ChatPacketHandler.h" #include "eChatMessageType.h" -#include "eChatInternalMessageType.h" #include "eWorldMessageType.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; @@ -180,49 +179,32 @@ 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. - - 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; + CINSTREAM; + inStream.SetReadOffset(BYTES_TO_BITS(1)); - case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION: - Game::playerContainer.RemovePlayer(packet); - break; + eConnectionType connection; + eChatMessageType chatMessageID; - case eChatInternalMessageType::MUTE_UPDATE: + inStream.Read(connection); + if (connection != eConnectionType::CHAT) return; + inStream.Read(chatMessageID); + + switch (chatMessageID) { + case eChatMessageType::GM_MUTE: Game::playerContainer.MuteUpdate(packet); break; - case eChatInternalMessageType::CREATE_TEAM: + case eChatMessageType::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: ChatPacketHandler::HandleFriendlistRequest(packet); break; @@ -296,6 +278,23 @@ void HandlePacket(Packet* packet) { ChatPacketHandler::HandleGMLevelUpdate(packet); break; case eChatMessageType::LOGIN_SESSION_NOTIFY: + Game::playerContainer.InsertPlayer(packet); + break; + case eChatMessageType::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 eChatMessageType::UNEXPECTED_DISCONNECT: + Game::playerContainer.RemovePlayer(packet); + break; + case eChatMessageType::WHO: + ChatPacketHandler::HandleWho(packet); + break; + case eChatMessageType::SHOW_ALL: + ChatPacketHandler::HandleShowAll(packet); + break; case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE: case eChatMessageType::WORLD_DISCONNECT_REQUEST: case eChatMessageType::WORLD_PROXIMITY_RESPONSE: @@ -308,7 +307,6 @@ void HandlePacket(Packet* packet) { 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: @@ -323,7 +321,6 @@ void HandlePacket(Packet* packet) { 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: @@ -332,33 +329,18 @@ void HandlePacket(Packet* packet) { 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); + LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chatMessageID).data(), chatMessageID); 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"); - 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 dbbaeb9e6..17e2cd1a8 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 "eChatMessageType.h" void PlayerContainer::Initialize() { m_MaxNumberOfBestFriends = @@ -49,6 +49,7 @@ void PlayerContainer::InsertPlayer(Packet* packet) { 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 +88,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) { } } + m_PlayerCount--; LOG("Removed user: %llu", playerID); m_Players.erase(playerID); @@ -145,12 +147,12 @@ void PlayerContainer::CreateTeamServer(Packet* packet) { void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GM_MUTE); bitStream.Write(player); bitStream.Write(time); - Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); } TeamData* PlayerContainer::CreateLocalTeam(std::vector members) { @@ -352,7 +354,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, eChatMessageType::TEAM_GET_STATUS); bitStream.Write(team->teamID); bitStream.Write(deleteTeam); @@ -365,7 +367,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) { } } - Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); } std::u16string PlayerContainer::GetName(LWOOBJID playerID) { @@ -390,7 +392,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/AMFDeserialize.cpp b/dCommon/AMFDeserialize.cpp index 648d1ed11..130ebc4a9 100644 --- a/dCommon/AMFDeserialize.cpp +++ b/dCommon/AMFDeserialize.cpp @@ -9,12 +9,11 @@ * AMF3 Deserializer written by EmosewaMC */ -AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) { - if (!inStream) return nullptr; +AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream& inStream) { AMFBaseValue* returnValue = nullptr; // Read in the value type from the bitStream eAmf marker; - inStream->Read(marker); + inStream.Read(marker); // Based on the typing, create the value associated with that and return the base value class switch (marker) { case eAmf::Undefined: { @@ -79,13 +78,13 @@ AMFBaseValue* AMFDeserialize::Read(RakNet::BitStream* inStream) { return returnValue; } -uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) { +uint32_t AMFDeserialize::ReadU29(RakNet::BitStream& inStream) { bool byteFlag = true; uint32_t actualNumber{}; uint8_t numberOfBytesRead{}; while (byteFlag && numberOfBytesRead < 4) { uint8_t byte{}; - inStream->Read(byte); + inStream.Read(byte); // Parse the byte if (numberOfBytesRead < 3) { byteFlag = byte & static_cast(1 << 7); @@ -101,7 +100,7 @@ uint32_t AMFDeserialize::ReadU29(RakNet::BitStream* inStream) { return actualNumber; } -const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) { +const std::string AMFDeserialize::ReadString(RakNet::BitStream& inStream) { auto length = ReadU29(inStream); // Check if this is a reference bool isReference = length % 2 == 1; @@ -109,7 +108,7 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) { length = length >> 1; if (isReference) { std::string value(length, 0); - inStream->Read(&value[0], length); + inStream.Read(&value[0], length); // Empty strings are never sent by reference if (!value.empty()) accessedElements.push_back(value); return value; @@ -119,20 +118,20 @@ const std::string AMFDeserialize::ReadString(RakNet::BitStream* inStream) { } } -AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream* inStream) { +AMFBaseValue* AMFDeserialize::ReadAmfDouble(RakNet::BitStream& inStream) { double value; - inStream->Read(value); + inStream.Read(value); return new AMFDoubleValue(value); } -AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) { +AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream& inStream) { auto arrayValue = new AMFArrayValue(); // Read size of dense array - auto sizeOfDenseArray = (ReadU29(inStream) >> 1); + const auto sizeOfDenseArray = (ReadU29(inStream) >> 1); // Then read associative portion while (true) { - auto key = ReadString(inStream); + const auto key = ReadString(inStream); // No more associative values when we encounter an empty string key if (key.size() == 0) break; arrayValue->Insert(key, Read(inStream)); @@ -144,10 +143,10 @@ AMFBaseValue* AMFDeserialize::ReadAmfArray(RakNet::BitStream* inStream) { return arrayValue; } -AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream* inStream) { +AMFBaseValue* AMFDeserialize::ReadAmfString(RakNet::BitStream& inStream) { return new AMFStringValue(ReadString(inStream)); } -AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream* inStream) { +AMFBaseValue* AMFDeserialize::ReadAmfInteger(RakNet::BitStream& inStream) { return new AMFIntValue(ReadU29(inStream)); } diff --git a/dCommon/AMFDeserialize.h b/dCommon/AMFDeserialize.h index 5e2729eb4..e204976d3 100644 --- a/dCommon/AMFDeserialize.h +++ b/dCommon/AMFDeserialize.h @@ -15,7 +15,7 @@ class AMFDeserialize { * @param inStream inStream to read value from. * @return Returns an AMFValue with all the information from the bitStream in it. */ - AMFBaseValue* Read(RakNet::BitStream* inStream); + AMFBaseValue* Read(RakNet::BitStream& inStream); private: /** * @brief Private method to read a U29 integer from a bitstream @@ -23,7 +23,7 @@ class AMFDeserialize { * @param inStream bitstream to read data from * @return The number as an unsigned 29 bit integer */ - uint32_t ReadU29(RakNet::BitStream* inStream); + static uint32_t ReadU29(RakNet::BitStream& inStream); /** * @brief Reads a string from a bitstream @@ -31,7 +31,7 @@ class AMFDeserialize { * @param inStream bitStream to read data from * @return The read string */ - const std::string ReadString(RakNet::BitStream* inStream); + const std::string ReadString(RakNet::BitStream& inStream); /** * @brief Read an AMFDouble value from a bitStream @@ -39,7 +39,7 @@ class AMFDeserialize { * @param inStream bitStream to read data from * @return Double value represented as an AMFValue */ - AMFBaseValue* ReadAmfDouble(RakNet::BitStream* inStream); + AMFBaseValue* ReadAmfDouble(RakNet::BitStream& inStream); /** * @brief Read an AMFArray from a bitStream @@ -47,7 +47,7 @@ class AMFDeserialize { * @param inStream bitStream to read data from * @return Array value represented as an AMFValue */ - AMFBaseValue* ReadAmfArray(RakNet::BitStream* inStream); + AMFBaseValue* ReadAmfArray(RakNet::BitStream& inStream); /** * @brief Read an AMFString from a bitStream @@ -55,7 +55,7 @@ class AMFDeserialize { * @param inStream bitStream to read data from * @return String value represented as an AMFValue */ - AMFBaseValue* ReadAmfString(RakNet::BitStream* inStream); + AMFBaseValue* ReadAmfString(RakNet::BitStream& inStream); /** * @brief Read an AMFInteger from a bitStream @@ -63,7 +63,7 @@ class AMFDeserialize { * @param inStream bitStream to read data from * @return Integer value represented as an AMFValue */ - AMFBaseValue* ReadAmfInteger(RakNet::BitStream* inStream); + AMFBaseValue* ReadAmfInteger(RakNet::BitStream& inStream); /** * List of strings read so far saved to be read by reference. diff --git a/dCommon/Amf3.h b/dCommon/Amf3.h index dbafba1fe..9fe728c06 100644 --- a/dCommon/Amf3.h +++ b/dCommon/Amf3.h @@ -41,12 +41,14 @@ template class AMFValue : public AMFBaseValue { public: AMFValue() = default; - AMFValue(const ValueType value) { m_Data = value; } + AMFValue(const ValueType value) : m_Data{ value } {} + virtual ~AMFValue() override = default; [[nodiscard]] constexpr eAmf GetValueType() const noexcept override; [[nodiscard]] const ValueType& GetValue() const { return m_Data; } + void SetValue(const ValueType value) { m_Data = value; } protected: @@ -54,7 +56,7 @@ class AMFValue : public AMFBaseValue { }; // Explicit template class instantiations -template class AMFValue; +template class AMFValue; template class AMFValue; template class AMFValue; template class AMFValue; @@ -110,7 +112,7 @@ class AMFArrayValue : public AMFBaseValue { [[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::Array; } ~AMFArrayValue() override { - for (auto valueToDelete : GetDense()) { + for (const auto* valueToDelete : GetDense()) { if (valueToDelete) { delete valueToDelete; valueToDelete = nullptr; @@ -127,12 +129,12 @@ class AMFArrayValue : public AMFBaseValue { /** * Returns the Associative portion of the object */ - [[nodiscard]] inline AMFAssociative& GetAssociative() noexcept { return this->associative; } + [[nodiscard]] inline const AMFAssociative& GetAssociative() const noexcept { return m_Associative; } /** * Returns the dense portion of the object */ - [[nodiscard]] inline AMFDense& GetDense() noexcept { return this->dense; } + [[nodiscard]] inline const AMFDense& GetDense() const noexcept { return m_Dense; } /** * Inserts an AMFValue into the associative portion with the given key. @@ -150,12 +152,12 @@ class AMFArrayValue : public AMFBaseValue { */ template [[maybe_unused]] std::pair*, bool> Insert(const std::string& key, const ValueType value) { - auto element = associative.find(key); + const auto element = m_Associative.find(key); AMFValue* val = nullptr; bool found = true; - if (element == associative.end()) { + if (element == m_Associative.cend()) { val = new AMFValue(value); - associative.insert(std::make_pair(key, val)); + m_Associative.emplace(key, val); } else { val = dynamic_cast*>(element->second); found = false; @@ -165,12 +167,12 @@ class AMFArrayValue : public AMFBaseValue { // Associates an array with a string key [[maybe_unused]] std::pair Insert(const std::string& key) { - auto element = associative.find(key); + const auto element = m_Associative.find(key); AMFArrayValue* val = nullptr; bool found = true; - if (element == associative.end()) { + if (element == m_Associative.cend()) { val = new AMFArrayValue(); - associative.insert(std::make_pair(key, val)); + m_Associative.emplace(key, val); } else { val = dynamic_cast(element->second); found = false; @@ -182,13 +184,13 @@ class AMFArrayValue : public AMFBaseValue { [[maybe_unused]] std::pair Insert(const size_t index) { AMFArrayValue* val = nullptr; bool inserted = false; - if (index >= dense.size()) { - dense.resize(index + 1); + if (index >= m_Dense.size()) { + m_Dense.resize(index + 1); val = new AMFArrayValue(); - dense.at(index) = val; + m_Dense.at(index) = val; inserted = true; } - return std::make_pair(dynamic_cast(dense.at(index)), inserted); + return std::make_pair(dynamic_cast(m_Dense.at(index)), inserted); } /** @@ -205,13 +207,13 @@ class AMFArrayValue : public AMFBaseValue { [[maybe_unused]] std::pair*, bool> Insert(const size_t index, const ValueType value) { AMFValue* val = nullptr; bool inserted = false; - if (index >= this->dense.size()) { - this->dense.resize(index + 1); + if (index >= m_Dense.size()) { + m_Dense.resize(index + 1); val = new AMFValue(value); - this->dense.at(index) = val; + m_Dense.at(index) = val; inserted = true; } - return std::make_pair(dynamic_cast*>(this->dense.at(index)), inserted); + return std::make_pair(dynamic_cast*>(m_Dense.at(index)), inserted); } /** @@ -224,12 +226,12 @@ class AMFArrayValue : public AMFBaseValue { * @param value The value to insert */ void Insert(const std::string& key, AMFBaseValue* const value) { - auto element = associative.find(key); - if (element != associative.end() && element->second) { + const auto element = m_Associative.find(key); + if (element != m_Associative.cend() && element->second) { delete element->second; element->second = value; } else { - associative.insert(std::make_pair(key, value)); + m_Associative.emplace(key, value); } } @@ -243,13 +245,13 @@ class AMFArrayValue : public AMFBaseValue { * @param value The value to insert */ void Insert(const size_t index, AMFBaseValue* const value) { - if (index < dense.size()) { - AMFDense::iterator itr = dense.begin() + index; - if (*itr) delete dense.at(index); + if (index < m_Dense.size()) { + const AMFDense::const_iterator itr = m_Dense.cbegin() + index; + if (*itr) delete m_Dense.at(index); } else { - dense.resize(index + 1); + m_Dense.resize(index + 1); } - dense.at(index) = value; + m_Dense.at(index) = value; } /** @@ -264,7 +266,7 @@ class AMFArrayValue : public AMFBaseValue { */ template [[maybe_unused]] inline AMFValue* Push(const ValueType value) { - return Insert(this->dense.size(), value).first; + return Insert(m_Dense.size(), value).first; } /** @@ -275,10 +277,10 @@ class AMFArrayValue : public AMFBaseValue { * @param key The key to remove from the associative portion */ void Remove(const std::string& key, const bool deleteValue = true) { - AMFAssociative::iterator it = this->associative.find(key); - if (it != this->associative.end()) { + const AMFAssociative::const_iterator it = m_Associative.find(key); + if (it != m_Associative.cend()) { if (deleteValue) delete it->second; - this->associative.erase(it); + m_Associative.erase(it); } } @@ -286,27 +288,24 @@ class AMFArrayValue : public AMFBaseValue { * Pops the last element in the dense portion, deleting it in the process. */ void Remove(const size_t index) { - if (!this->dense.empty() && index < this->dense.size()) { - auto itr = this->dense.begin() + index; + if (!m_Dense.empty() && index < m_Dense.size()) { + const auto itr = m_Dense.cbegin() + index; if (*itr) delete (*itr); - this->dense.erase(itr); + m_Dense.erase(itr); } } void Pop() { - if (!this->dense.empty()) Remove(this->dense.size() - 1); + if (!m_Dense.empty()) Remove(m_Dense.size() - 1); } - [[nodiscard]] AMFArrayValue* GetArray(const std::string& key) { - AMFAssociative::const_iterator it = this->associative.find(key); - if (it != this->associative.end()) { - return dynamic_cast(it->second); - } - return nullptr; + [[nodiscard]] AMFArrayValue* GetArray(const std::string& key) const { + const AMFAssociative::const_iterator it = m_Associative.find(key); + return it != m_Associative.cend() ? dynamic_cast(it->second) : nullptr; } - [[nodiscard]] AMFArrayValue* GetArray(const size_t index) { - return index >= this->dense.size() ? nullptr : dynamic_cast(this->dense.at(index)); + [[nodiscard]] AMFArrayValue* GetArray(const size_t index) const { + return index < m_Dense.size() ? dynamic_cast(m_Dense.at(index)) : nullptr; } [[maybe_unused]] inline AMFArrayValue* InsertArray(const std::string& key) { @@ -318,7 +317,7 @@ class AMFArrayValue : public AMFBaseValue { } [[maybe_unused]] inline AMFArrayValue* PushArray() { - return static_cast(Insert(this->dense.size()).first); + return static_cast(Insert(m_Dense.size()).first); } /** @@ -332,16 +331,16 @@ class AMFArrayValue : public AMFBaseValue { */ template [[nodiscard]] AMFValue* Get(const std::string& key) const { - AMFAssociative::const_iterator it = this->associative.find(key); - return it != this->associative.end() ? + const AMFAssociative::const_iterator it = m_Associative.find(key); + return it != m_Associative.cend() ? dynamic_cast*>(it->second) : nullptr; } // Get from the array but dont cast it [[nodiscard]] AMFBaseValue* Get(const std::string& key) const { - AMFAssociative::const_iterator it = this->associative.find(key); - return it != this->associative.end() ? it->second : nullptr; + const AMFAssociative::const_iterator it = m_Associative.find(key); + return it != m_Associative.cend() ? it->second : nullptr; } /** @@ -355,27 +354,27 @@ class AMFArrayValue : public AMFBaseValue { */ template [[nodiscard]] AMFValue* Get(const size_t index) const { - return index < this->dense.size() ? - dynamic_cast*>(this->dense.at(index)) : + return index < m_Dense.size() ? + dynamic_cast*>(m_Dense.at(index)) : nullptr; } // Get from the dense but dont cast it [[nodiscard]] AMFBaseValue* Get(const size_t index) const { - return index < this->dense.size() ? this->dense.at(index) : nullptr; + return index < m_Dense.size() ? m_Dense.at(index) : nullptr; } private: /** * The associative portion. These values are key'd with strings to an AMFValue. */ - AMFAssociative associative; + AMFAssociative m_Associative; /** * The dense portion. These AMFValue's are stored one after * another with the most recent addition being at the back. */ - AMFDense dense; + AMFDense m_Dense; }; #endif //!__AMF3__H__ diff --git a/dCommon/AmfSerialize.cpp b/dCommon/AmfSerialize.cpp index 3072b8e15..e11ae1de4 100644 --- a/dCommon/AmfSerialize.cpp +++ b/dCommon/AmfSerialize.cpp @@ -53,7 +53,7 @@ void RakNet::BitStream::Write(AMFBaseValue& value) { * A private function to write an value to a RakNet::BitStream * RakNet writes in the correct byte order - do not reverse this. */ -void WriteUInt29(RakNet::BitStream* bs, uint32_t v) { +void WriteUInt29(RakNet::BitStream& bs, uint32_t v) { unsigned char b4 = static_cast(v); if (v < 0x00200000) { b4 = b4 & 0x7F; @@ -65,10 +65,10 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) { unsigned char b2; v = v >> 7; b2 = static_cast(v) | 0x80; - bs->Write(b2); + bs.Write(b2); } - bs->Write(b3); + bs.Write(b3); } } else { unsigned char b1; @@ -82,19 +82,19 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) { v = v >> 7; b1 = static_cast(v) | 0x80; - bs->Write(b1); - bs->Write(b2); - bs->Write(b3); + bs.Write(b1); + bs.Write(b2); + bs.Write(b3); } - bs->Write(b4); + bs.Write(b4); } /** * Writes a flag number to a RakNet::BitStream * RakNet writes in the correct byte order - do not reverse this. */ -void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) { +void WriteFlagNumber(RakNet::BitStream& bs, uint32_t v) { v = (v << 1) | 0x01; WriteUInt29(bs, v); } @@ -104,9 +104,9 @@ void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) { * * RakNet writes in the correct byte order - do not reverse this. */ -void WriteAMFString(RakNet::BitStream* bs, const std::string& str) { +void WriteAMFString(RakNet::BitStream& bs, const std::string& str) { WriteFlagNumber(bs, static_cast(str.size())); - bs->Write(str.c_str(), static_cast(str.size())); + bs.Write(str.c_str(), static_cast(str.size())); } /** @@ -114,8 +114,8 @@ void WriteAMFString(RakNet::BitStream* bs, const std::string& str) { * * RakNet writes in the correct byte order - do not reverse this. */ -void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) { - bs->Write(value); +void WriteAMFU16(RakNet::BitStream& bs, uint16_t value) { + bs.Write(value); } /** @@ -123,8 +123,8 @@ void WriteAMFU16(RakNet::BitStream* bs, uint16_t value) { * * RakNet writes in the correct byte order - do not reverse this. */ -void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) { - bs->Write(value); +void WriteAMFU32(RakNet::BitStream& bs, uint32_t value) { + bs.Write(value); } /** @@ -132,40 +132,40 @@ void WriteAMFU32(RakNet::BitStream* bs, uint32_t value) { * * RakNet writes in the correct byte order - do not reverse this. */ -void WriteAMFU64(RakNet::BitStream* bs, uint64_t value) { - bs->Write(value); +void WriteAMFU64(RakNet::BitStream& bs, uint64_t value) { + bs.Write(value); } // Writes an AMFIntegerValue to BitStream template<> void RakNet::BitStream::Write(AMFIntValue& value) { - WriteUInt29(this, value.GetValue()); + WriteUInt29(*this, value.GetValue()); } // Writes an AMFDoubleValue to BitStream template<> void RakNet::BitStream::Write(AMFDoubleValue& value) { double d = value.GetValue(); - WriteAMFU64(this, *reinterpret_cast(&d)); + WriteAMFU64(*this, *reinterpret_cast(&d)); } // Writes an AMFStringValue to BitStream template<> void RakNet::BitStream::Write(AMFStringValue& value) { - WriteAMFString(this, value.GetValue()); + WriteAMFString(*this, value.GetValue()); } // Writes an AMFArrayValue to BitStream template<> void RakNet::BitStream::Write(AMFArrayValue& value) { uint32_t denseSize = value.GetDense().size(); - WriteFlagNumber(this, denseSize); + WriteFlagNumber(*this, denseSize); auto it = value.GetAssociative().begin(); auto end = value.GetAssociative().end(); while (it != end) { - WriteAMFString(this, it->first); + WriteAMFString(*this, it->first); this->Write(*it->second); it++; } 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 78cf4f485..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,49 +271,70 @@ std::vector GeneralUtils::SplitString(const std::string& str, char } } - vector.push_back(current); - + vector.push_back(std::move(current)); return vector; } -std::u16string GeneralUtils::ReadWString(RakNet::BitStream* inStream) { +std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) { uint32_t length; - inStream->Read(length); + 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); + inStream.Read(c); string.push_back(c); } 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)) { + for (const 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)); + 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(); - while (!filenames.empty()) { - if (fileIterator == filenames.end()) { - sortedFiles.push_back(oldest->second); - filenames.erase(oldest); - fileIterator = filenames.begin(); - oldest = filenames.begin(); - continue; + auto fileIterator = filenames.cbegin(); + auto oldest = filenames.cbegin(); + while (!filenames.empty()) { + if (fileIterator == filenames.cend()) { + sortedFiles.push_back(oldest->second); + filenames.erase(oldest); + fileIterator = filenames.cbegin(); + oldest = filenames.cbegin(); + continue; } - if (oldest->first > fileIterator->first) oldest = fileIterator; - fileIterator++; + if (oldest->first > fileIterator->first) oldest = fileIterator; + ++fileIterator; } return sortedFiles; } + +#if !(__GNUC__ >= 11 || _MSC_VER >= 1924) + +// MacOS floating-point parse function specializations +namespace GeneralUtils::details { + template <> + [[nodiscard]] float _parse(const std::string_view str, size_t& parseNum) { + return std::stof(std::string{ str }, &parseNum); + } + + template <> + [[nodiscard]] double _parse(const std::string_view str, size_t& parseNum) { + return std::stod(std::string{ str }, &parseNum); + } + + template <> + [[nodiscard]] long double _parse(const std::string_view str, size_t& parseNum) { + return std::stold(std::string{ str }, &parseNum); + } +} + +#endif diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index 15659912b..0a8d15c13 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::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); // Concept constraining to enum types template @@ -144,7 +147,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 @@ -156,8 +159,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); @@ -166,27 +170,12 @@ namespace GeneralUtils { return isParsed ? static_cast(result) : std::optional{}; } -#ifdef DARKFLAME_PLATFORM_MACOS +#if !(__GNUC__ >= 11 || _MSC_VER >= 1924) - // Anonymous namespace containing MacOS floating-point parse function specializations - namespace { + // MacOS floating-point parse helper function specializations + namespace details { template - [[nodiscard]] T Parse(const std::string_view str, size_t* parseNum); - - template <> - [[nodiscard]] float Parse(const std::string_view str, size_t* parseNum) { - return std::stof(std::string{ str }, parseNum); - } - - template <> - [[nodiscard]] double Parse(const std::string_view str, size_t* parseNum) { - return std::stod(std::string{ str }, parseNum); - } - - template <> - [[nodiscard]] long double Parse(const std::string_view str, size_t* parseNum) { - return std::stold(std::string{ str }, parseNum); - } + [[nodiscard]] T _parse(const std::string_view str, size_t& parseNum); } /** @@ -196,9 +185,12 @@ 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 try { + [[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 = Parse(str, &parseNum); + const T result = details::_parse(str, parseNum); const bool isParsed = str.length() == parseNum; return isParsed ? result : std::optional{}; @@ -216,7 +208,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; @@ -228,17 +220,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)); } @@ -257,7 +249,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"); @@ -278,16 +270,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/LDFFormat.h b/dCommon/LDFFormat.h index 3a4f2ea7e..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,17 +62,17 @@ class LDFData: public LDFBaseData { T value; //! Writes the key to the packet - void WriteKey(RakNet::BitStream* packet) { - packet->Write(this->key.length() * sizeof(uint16_t)); + 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]); + packet.Write(this->key[i]); } } //! Writes the value to the packet - void WriteValue(RakNet::BitStream* packet) { - packet->Write(this->GetValueType()); - packet->Write(this->value); + void WriteValue(RakNet::BitStream& packet) const { + packet.Write(this->GetValueType()); + packet.Write(this->value); } public: @@ -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,58 +166,58 @@ 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) { - packet->Write(this->GetValueType()); +inline void LDFData::WriteValue(RakNet::BitStream& packet) const { + packet.Write(this->GetValueType()); - packet->Write(this->value.length()); + packet.Write(this->value.length()); for (uint32_t i = 0; i < this->value.length(); ++i) { - packet->Write(this->value[i]); + packet.Write(this->value[i]); } } // The specialized version for bool template<> -inline void LDFData::WriteValue(RakNet::BitStream* packet) { - packet->Write(this->GetValueType()); +inline void LDFData::WriteValue(RakNet::BitStream& packet) const { + packet.Write(this->GetValueType()); - packet->Write(this->value); + packet.Write(this->value); } // The specialized version for std::string (UTF-8) template<> -inline void LDFData::WriteValue(RakNet::BitStream* packet) { - packet->Write(this->GetValueType()); +inline void LDFData::WriteValue(RakNet::BitStream& packet) const { + packet.Write(this->GetValueType()); - packet->Write(this->value.length()); + packet.Write(this->value.length()); for (uint32_t i = 0; i < this->value.length(); ++i) { - packet->Write(this->value[i]); + packet.Write(this->value[i]); } } -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/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/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index d871e2672..7cdbfdb6a 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -34,8 +34,8 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate); #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 SEND_PACKET Game::server->Send(&bitStream, sysAddr, false); -#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); +#define SEND_PACKET Game::server->Send(bitStream, sysAddr, false); +#define SEND_PACKET_BROADCAST Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); //=========== TYPEDEFS ========== 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 index 52895ba3e..38cd86de1 100644 --- a/dCommon/dEnums/eChatMessageType.h +++ b/dCommon/dEnums/eChatMessageType.h @@ -72,7 +72,9 @@ enum class eChatMessageType :uint32_t { UPDATE_DONATION, PRG_CSR_COMMAND, HEARTBEAT_REQUEST_FROM_WORLD, - UPDATE_FREE_TRIAL_STATUS + UPDATE_FREE_TRIAL_STATUS, + // CUSTOM DLU MESSAGE ID FOR INTERNAL USE + CREATE_TEAM, }; #endif //!__ECHATMESSAGETYPE__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 index e3fc22b6b..8e6980d6b 100644 --- a/dCommon/dEnums/eGameMessageType.h +++ b/dCommon/dEnums/eGameMessageType.h @@ -790,9 +790,10 @@ enum class eGameMessageType : uint16_t { GET_MISSION_TYPE_STATES = 853, GET_TIME_PLAYED = 854, SET_MISSION_VIEWED = 855, - SLASH_COMMAND_TEXT_FEEDBACK = 856, - HANDLE_SLASH_COMMAND_KORE_DEBUGGER = 857, + 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, diff --git a/dCommon/dEnums/eReplicaComponentType.h b/dCommon/dEnums/eReplicaComponentType.h index 83acbf897..2b991dfbf 100644 --- a/dCommon/dEnums/eReplicaComponentType.h +++ b/dCommon/dEnums/eReplicaComponentType.h @@ -106,7 +106,7 @@ enum class eReplicaComponentType : uint32_t { INTERACTION_MANAGER, DONATION_VENDOR, COMBAT_MEDIATOR, - COMMENDATION_VENDOR, + ACHIEVEMENT_VENDOR, GATE_RUSH_CONTROL, RAIL_ACTIVATOR, ROLLER, 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/eVendorTransactionResult.h b/dCommon/dEnums/eVendorTransactionResult.h new file mode 100644 index 000000000..e61ee0ee2 --- /dev/null +++ b/dCommon/dEnums/eVendorTransactionResult.h @@ -0,0 +1,15 @@ +#ifndef __EVENDORTRANSACTIONRESULT__ +#define __EVENDORTRANSACTIONRESULT__ + +#include + +enum class eVendorTransactionResult : uint32_t { + SELL_SUCCESS = 0, + SELL_FAIL, + PURCHASE_SUCCESS, + PURCHASE_FAIL, + DONATION_FAIL, + DONATION_FULL +}; + +#endif // !__EVENDORTRANSACTIONRESULT__ 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 index bfaa110bb..920810550 100644 --- a/dCommon/dEnums/eWorldMessageType.h +++ b/dCommon/dEnums/eWorldMessageType.h @@ -29,8 +29,8 @@ enum class eWorldMessageType : uint32_t { ROUTE_PACKET, // Social? POSITION_UPDATE, MAIL, - WORD_CHECK, // Whitelist word check - STRING_CHECK, // Whitelist string check + WORD_CHECK, // AllowList word check + STRING_CHECK, // AllowList string check GET_PLAYERS_IN_ZONE, REQUEST_UGC_MANIFEST_INFO, BLUEPRINT_GET_ALL_DATA_REQUEST, 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 8862b1dba..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,10 +76,8 @@ 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(); Default.id = -1; @@ -118,3 +116,12 @@ const CDMissions& CDMissionsTable::GetByMissionID(uint32_t missionID, bool& foun return Default; } +const std::set CDMissionsTable::GetMissionsForReward(LOT lot) { + std::set toReturn {}; + for (const auto& entry : GetEntries()) { + if (lot == entry.reward_item1 || lot == entry.reward_item2 || lot == entry.reward_item3 || lot == entry.reward_item4) { + toReturn.insert(entry.id); + } + } + return toReturn; +} diff --git a/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h b/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h index 6ba7b19e9..c5ae0e88c 100644 --- a/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h +++ b/dDatabase/CDClientDatabase/CDClientTables/CDMissionsTable.h @@ -70,6 +70,8 @@ class CDMissionsTable : public CDTable> const CDMissions& GetByMissionID(uint32_t missionID, bool& found) const; + const std::set GetMissionsForReward(LOT lot); + + 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..09ca7251e 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,25 @@ 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_library(dDatabaseGame STATIC ${DDATABASE_GAMEDATABASE_SOURCES}) +target_include_directories(dDatabaseGame PUBLIC "." + "ITables" PRIVATE "MySQL" + "${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/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..3f27dda6b 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; 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.h b/dDatabase/GameDatabase/MySQL/MySQLDatabase.h index 836ab56c4..689622d05 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,9 @@ 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; private: // Generic query functions that can be used for any query. 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/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..57a951d9b 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; } @@ -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,18 +67,13 @@ 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!"); @@ -89,7 +81,7 @@ void Character::DoQuickXMLDataParse() { 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..7a83325b0 100644 --- a/dGame/Character.h +++ b/dGame/Character.h @@ -37,7 +37,7 @@ 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; } /** * Out of abundance of safety and clarity of what this saves, this is its own function. @@ -464,22 +464,22 @@ class Character { /** * 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 +506,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 +583,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 +613,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 +623,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 269b4cc44..6699c5959 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -82,6 +82,7 @@ #include "CollectibleComponent.h" #include "ItemComponent.h" #include "GhostComponent.h" +#include "AchievementVendorComponent.h" // Table includes #include "CDComponentsRegistryTable.h" @@ -145,17 +146,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); } } } @@ -226,7 +225,7 @@ void Entity::Initialize() { AddComponent(simplePhysicsComponentID); - AddComponent(); + AddComponent()->LoadBehaviors(); AddComponent(); @@ -477,8 +476,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) { @@ -615,6 +613,8 @@ void Entity::Initialize() { AddComponent(); } else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) { AddComponent(); + } else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ACHIEVEMENT_VENDOR, -1) != -1)) { + AddComponent(); } if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) { @@ -649,7 +649,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); @@ -730,15 +730,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); @@ -759,9 +765,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()) { @@ -836,17 +840,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(); @@ -896,34 +889,34 @@ void Entity::SetGMLevel(eGameMasterLevel value) { } } -void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType) { +void Entity::WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacketType packetType) { if (packetType == eReplicaPacketType::CONSTRUCTION) { - outBitStream->Write(m_ObjectID); - outBitStream->Write(m_TemplateID); + outBitStream.Write(m_ObjectID); + outBitStream.Write(m_TemplateID); if (IsPlayer()) { std::string name = m_Character != nullptr ? m_Character->GetName() : "Invalid"; - outBitStream->Write(uint8_t(name.size())); + outBitStream.Write(uint8_t(name.size())); for (size_t i = 0; i < name.size(); ++i) { - outBitStream->Write(name[i]); + outBitStream.Write(name[i]); } } else { const auto& name = GetVar(u"npcName"); - outBitStream->Write(uint8_t(name.size())); + outBitStream.Write(uint8_t(name.size())); for (size_t i = 0; i < name.size(); ++i) { - outBitStream->Write(name[i]); + outBitStream.Write(name[i]); } } - outBitStream->Write(0); //Time since created on server + outBitStream.Write(0); //Time since created on server const auto& syncLDF = GetVar>(u"syncLDF"); // Only sync for models. if (m_Settings.size() > 0 && (GetComponent() && !GetComponent())) { - outBitStream->Write1(); //ldf data + outBitStream.Write1(); //ldf data RakNet::BitStream settingStream; int32_t numberOfValidKeys = m_Settings.size(); @@ -940,13 +933,13 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke for (LDFBaseData* data : m_Settings) { if (data && data->GetValueType() != eLDFType::LDF_TYPE_UNKNOWN) { - data->WriteToPacket(&settingStream); + data->WriteToPacket(settingStream); } } - outBitStream->Write(settingStream.GetNumberOfBytesUsed() + 1); - outBitStream->Write(0); //no compression used - outBitStream->Write(settingStream); + outBitStream.Write(settingStream.GetNumberOfBytesUsed() + 1); + outBitStream.Write(0); //no compression used + outBitStream.Write(settingStream); } else if (!syncLDF.empty()) { std::vector ldfData; @@ -954,79 +947,79 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke ldfData.push_back(GetVarData(data)); } - outBitStream->Write1(); //ldf data + outBitStream.Write1(); //ldf data RakNet::BitStream settingStream; settingStream.Write(ldfData.size()); for (LDFBaseData* data : ldfData) { if (data) { - data->WriteToPacket(&settingStream); + data->WriteToPacket(settingStream); } } - outBitStream->Write(settingStream.GetNumberOfBytesUsed() + 1); - outBitStream->Write(0); //no compression used - outBitStream->Write(settingStream); + outBitStream.Write(settingStream.GetNumberOfBytesUsed() + 1); + outBitStream.Write(0); //no compression used + outBitStream.Write(settingStream); } else { - outBitStream->Write0(); //No ldf data + outBitStream.Write0(); //No ldf data } TriggerComponent* triggerComponent; if (TryGetComponent(eReplicaComponentType::TRIGGER, triggerComponent)) { // has trigger component, check to see if we have events to handle auto* trigger = triggerComponent->GetTrigger(); - outBitStream->Write(trigger && trigger->events.size() > 0); + outBitStream.Write(trigger && trigger->events.size() > 0); } else { // no trigger componenet, so definitely no triggers - outBitStream->Write0(); + outBitStream.Write0(); } if (m_ParentEntity != nullptr || m_SpawnerID != 0) { - outBitStream->Write1(); - if (m_ParentEntity != nullptr) outBitStream->Write(GeneralUtils::SetBit(m_ParentEntity->GetObjectID(), static_cast(eObjectBits::CLIENT))); - else if (m_Spawner != nullptr && m_Spawner->m_Info.isNetwork) outBitStream->Write(m_SpawnerID); - else outBitStream->Write(GeneralUtils::SetBit(m_SpawnerID, static_cast(eObjectBits::CLIENT))); - } else outBitStream->Write0(); + outBitStream.Write1(); + if (m_ParentEntity != nullptr) outBitStream.Write(GeneralUtils::SetBit(m_ParentEntity->GetObjectID(), static_cast(eObjectBits::CLIENT))); + else if (m_Spawner != nullptr && m_Spawner->m_Info.isNetwork) outBitStream.Write(m_SpawnerID); + else outBitStream.Write(GeneralUtils::SetBit(m_SpawnerID, static_cast(eObjectBits::CLIENT))); + } else outBitStream.Write0(); - outBitStream->Write(m_HasSpawnerNodeID); - if (m_HasSpawnerNodeID) outBitStream->Write(m_SpawnerNodeID); + outBitStream.Write(m_HasSpawnerNodeID); + if (m_HasSpawnerNodeID) outBitStream.Write(m_SpawnerNodeID); - //outBitStream->Write0(); //Spawner node id + //outBitStream.Write0(); //Spawner node id - if (m_Scale == 1.0f || m_Scale == 0.0f) outBitStream->Write0(); + if (m_Scale == 1.0f || m_Scale == 0.0f) outBitStream.Write0(); else { - outBitStream->Write1(); - outBitStream->Write(m_Scale); + outBitStream.Write1(); + outBitStream.Write(m_Scale); } - outBitStream->Write0(); //ObjectWorldState + outBitStream.Write0(); //ObjectWorldState if (m_GMLevel != eGameMasterLevel::CIVILIAN) { - outBitStream->Write1(); - outBitStream->Write(m_GMLevel); - } else outBitStream->Write0(); //No GM Level + outBitStream.Write1(); + outBitStream.Write(m_GMLevel); + } else outBitStream.Write0(); //No GM Level } // Only serialize parent / child info should the info be dirty (changed) or if this is the construction of the entity. - outBitStream->Write(m_IsParentChildDirty || packetType == eReplicaPacketType::CONSTRUCTION); + outBitStream.Write(m_IsParentChildDirty || packetType == eReplicaPacketType::CONSTRUCTION); if (m_IsParentChildDirty || packetType == eReplicaPacketType::CONSTRUCTION) { m_IsParentChildDirty = false; - outBitStream->Write(m_ParentEntity != nullptr); + outBitStream.Write(m_ParentEntity != nullptr); if (m_ParentEntity) { - outBitStream->Write(m_ParentEntity->GetObjectID()); - outBitStream->Write0(); + outBitStream.Write(m_ParentEntity->GetObjectID()); + outBitStream.Write0(); } - outBitStream->Write(m_ChildEntities.size() > 0); + outBitStream.Write(m_ChildEntities.size() > 0); if (m_ChildEntities.size() > 0) { - outBitStream->Write(m_ChildEntities.size()); + outBitStream.Write(m_ChildEntities.size()); for (Entity* child : m_ChildEntities) { - outBitStream->Write(child->GetObjectID()); + outBitStream.Write(child->GetObjectID()); } } } } -void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType packetType) { +void Entity::WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType packetType) { /** * This has to be done in a specific order. @@ -1114,7 +1107,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType possessorComponent->Serialize(outBitStream, bIsInitialUpdate); } else { // Should never happen, but just to be safe - outBitStream->Write0(); + outBitStream.Write0(); } LevelProgressionComponent* levelProgressionComponent; @@ -1122,7 +1115,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType levelProgressionComponent->Serialize(outBitStream, bIsInitialUpdate); } else { // Should never happen, but just to be safe - outBitStream->Write0(); + outBitStream.Write0(); } PlayerForcedMovementComponent* playerForcedMovementComponent; @@ -1130,7 +1123,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType playerForcedMovementComponent->Serialize(outBitStream, bIsInitialUpdate); } else { // Should never happen, but just to be safe - outBitStream->Write0(); + outBitStream.Write0(); } characterComponent->Serialize(outBitStream, bIsInitialUpdate); @@ -1191,6 +1184,11 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType donationVendorComponent->Serialize(outBitStream, bIsInitialUpdate); } + AchievementVendorComponent* achievementVendorComponent; + if (TryGetComponent(eReplicaComponentType::ACHIEVEMENT_VENDOR, achievementVendorComponent)) { + achievementVendorComponent->Serialize(outBitStream, bIsInitialUpdate); + } + BouncerComponent* bouncerComponent; if (TryGetComponent(eReplicaComponentType::BOUNCER, bouncerComponent)) { bouncerComponent->Serialize(outBitStream, bIsInitialUpdate); @@ -1242,10 +1240,10 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType // BBB Component, unused currently // Need to to write0 so that is serialized correctly // TODO: Implement BBB Component - outBitStream->Write0(); + 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. @@ -1270,9 +1268,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 { @@ -1318,9 +1314,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; @@ -1337,9 +1331,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; @@ -1351,9 +1343,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); @@ -1392,9 +1382,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); @@ -1411,46 +1399,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; @@ -1460,82 +1434,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) { @@ -1568,9 +1523,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); @@ -1581,7 +1534,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! @@ -1681,10 +1634,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(); @@ -1889,6 +1840,12 @@ const NiPoint3& Entity::GetPosition() const { return vehicel->GetPosition(); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + return rigidBodyPhantomPhysicsComponent->GetPosition(); + } + return NiPoint3Constant::ZERO; } @@ -1917,6 +1874,12 @@ const NiQuaternion& Entity::GetRotation() const { return vehicel->GetRotation(); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + return rigidBodyPhantomPhysicsComponent->GetRotation(); + } + return NiQuaternionConstant::IDENTITY; } @@ -1945,6 +1908,12 @@ void Entity::SetPosition(const NiPoint3& position) { vehicel->SetPosition(position); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + rigidBodyPhantomPhysicsComponent->SetPosition(position); + } + Game::entityManager->SerializeEntity(this); } @@ -1973,6 +1942,12 @@ void Entity::SetRotation(const NiQuaternion& rotation) { vehicel->SetRotation(rotation); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + rigidBodyPhantomPhysicsComponent->SetRotation(rotation); + } + Game::entityManager->SerializeEntity(this); } @@ -2118,9 +2093,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 @@ -2131,9 +2104,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); } @@ -2155,9 +2126,7 @@ 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); diff --git a/dGame/Entity.h b/dGame/Entity.h index 6546e458f..ffdcb7130 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -146,7 +146,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); @@ -171,9 +172,9 @@ class Entity { std::unordered_map& GetComponents() { return m_Components; } // TODO: Remove - void WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType); - void WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType packetType); - void UpdateXMLDoc(tinyxml2::XMLDocument* doc); + void WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacketType packetType); + void WriteComponents(RakNet::BitStream& outBitStream, eReplicaPacketType packetType); + void UpdateXMLDoc(tinyxml2::XMLDocument& doc); void Update(float deltaTime); // Events @@ -295,6 +296,9 @@ class Entity { void ProcessPositionUpdate(PositionUpdate& update); + // Scale will only be communicated to the client when the construction packet is sent + void SetScale(const float scale) { m_Scale = scale; }; + protected: LWOOBJID m_ObjectID; diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index fc9fa0f07..c95af3d7f 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -178,18 +178,18 @@ void EntityManager::SerializeEntities() { stream.Write(ID_REPLICA_MANAGER_SERIALIZE); stream.Write(entity->GetNetworkId()); - entity->WriteBaseReplicaData(&stream, eReplicaPacketType::SERIALIZATION); - entity->WriteComponents(&stream, eReplicaPacketType::SERIALIZATION); + entity->WriteBaseReplicaData(stream, eReplicaPacketType::SERIALIZATION); + entity->WriteComponents(stream, eReplicaPacketType::SERIALIZATION); if (entity->GetIsGhostingCandidate()) { for (auto* player : PlayerManager::GetAllPlayers()) { auto* ghostComponent = player->GetComponent(); if (ghostComponent && ghostComponent->IsObserved(toSerialize)) { - Game::server->Send(&stream, player->GetSystemAddress(), false); + Game::server->Send(stream, player->GetSystemAddress(), false); } } } else { - Game::server->Send(&stream, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::server->Send(stream, UNASSIGNED_SYSTEM_ADDRESS, true); } } m_EntitiesToSerialize.clear(); @@ -359,16 +359,16 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr stream.Write(true); stream.Write(entity->GetNetworkId()); - entity->WriteBaseReplicaData(&stream, eReplicaPacketType::CONSTRUCTION); - entity->WriteComponents(&stream, eReplicaPacketType::CONSTRUCTION); + entity->WriteBaseReplicaData(stream, eReplicaPacketType::CONSTRUCTION); + entity->WriteComponents(stream, eReplicaPacketType::CONSTRUCTION); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) { if (skipChecks) { - Game::server->Send(&stream, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::server->Send(stream, UNASSIGNED_SYSTEM_ADDRESS, true); } else { for (auto* player : PlayerManager::GetAllPlayers()) { if (player->GetPlayerReadyForUpdates()) { - Game::server->Send(&stream, player->GetSystemAddress(), false); + Game::server->Send(stream, player->GetSystemAddress(), false); } else { auto* ghostComponent = player->GetComponent(); if (ghostComponent) ghostComponent->AddLimboConstruction(entity->GetObjectID()); @@ -376,7 +376,7 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr } } } else { - Game::server->Send(&stream, sysAddr, false); + Game::server->Send(stream, sysAddr, false); } if (entity->IsPlayer()) { @@ -407,7 +407,7 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) stream.Write(ID_REPLICA_MANAGER_DESTRUCTION); stream.Write(entity->GetNetworkId()); - Game::server->Send(&stream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); + Game::server->Send(stream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); for (auto* player : PlayerManager::GetAllPlayers()) { if (!player->GetPlayerReadyForUpdates()) { @@ -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()); } } @@ -575,13 +581,13 @@ void EntityManager::ScheduleForKill(Entity* entity) { const auto objectId = entity->GetObjectID(); - if (std::find(m_EntitiesToKill.begin(), m_EntitiesToKill.end(), objectId) != m_EntitiesToKill.end()) { + if (std::find(m_EntitiesToKill.begin(), m_EntitiesToKill.end(), objectId) == m_EntitiesToKill.end()) { m_EntitiesToKill.push_back(objectId); } } void EntityManager::ScheduleForDeletion(LWOOBJID entity) { - if (std::find(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), entity) != m_EntitiesToDelete.end()) { + if (std::find(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), entity) == m_EntitiesToDelete.end()) { m_EntitiesToDelete.push_back(entity); } } 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/LeaderboardManager.cpp b/dGame/LeaderboardManager.cpp index ba9055a74..347bd68e9 100644 --- a/dGame/LeaderboardManager.cpp +++ b/dGame/LeaderboardManager.cpp @@ -43,9 +43,9 @@ inline void WriteLeaderboardRow(std::ostringstream& leaderboard, const uint32_t& leaderboard << "\nResult[0].Row[" << index << "]." << data->GetString(); } -void Leaderboard::Serialize(RakNet::BitStream* bitStream) const { - bitStream->Write(gameID); - bitStream->Write(infoType); +void Leaderboard::Serialize(RakNet::BitStream& bitStream) const { + bitStream.Write(gameID); + bitStream.Write(infoType); std::ostringstream leaderboard; @@ -64,12 +64,12 @@ void Leaderboard::Serialize(RakNet::BitStream* bitStream) const { // Serialize the thing to a BitStream uint32_t leaderboardSize = leaderboard.tellp(); - bitStream->Write(leaderboardSize); + bitStream.Write(leaderboardSize); // Doing this all in 1 call so there is no possbility of a dangling pointer. - bitStream->WriteAlignedBytes(reinterpret_cast(GeneralUtils::ASCIIToUTF16(leaderboard.str()).c_str()), leaderboardSize * sizeof(char16_t)); - if (leaderboardSize > 0) bitStream->Write(0); - bitStream->Write0(); - bitStream->Write0(); + bitStream.WriteAlignedBytes(reinterpret_cast(GeneralUtils::ASCIIToUTF16(leaderboard.str()).c_str()), leaderboardSize * sizeof(char16_t)); + if (leaderboardSize > 0) bitStream.Write(0); + bitStream.Write0(); + bitStream.Write0(); } void Leaderboard::QueryToLdf(std::unique_ptr& rows) { diff --git a/dGame/LeaderboardManager.h b/dGame/LeaderboardManager.h index 89537ba05..527ae02d7 100644 --- a/dGame/LeaderboardManager.h +++ b/dGame/LeaderboardManager.h @@ -88,7 +88,7 @@ class Leaderboard { * * Expensive! Leaderboards are very string intensive so be wary of performatnce calling this method. */ - void Serialize(RakNet::BitStream* bitStream) const; + void Serialize(RakNet::BitStream& bitStream) const; /** * Builds the leaderboard from the database based on the associated gameID 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..8579d8829 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 "eChatMessageType.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')) { @@ -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, eChatMessageType::UNEXPECTED_DISCONNECT); bitStream.Write(objectID); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); @@ -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/AirMovementBehavior.cpp b/dGame/dBehaviors/AirMovementBehavior.cpp index 8a3f894c0..46d186806 100644 --- a/dGame/dBehaviors/AirMovementBehavior.cpp +++ b/dGame/dBehaviors/AirMovementBehavior.cpp @@ -5,35 +5,35 @@ #include "Game.h" #include "Logger.h" -void AirMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void AirMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { uint32_t handle{}; - if (!bitStream->Read(handle)) { - LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(handle)) { + LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; } context->RegisterSyncBehavior(handle, this, branch, this->m_Timeout); } -void AirMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void AirMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { const auto handle = context->GetUniqueSkillId(); - bitStream->Write(handle); + bitStream.Write(handle); } -void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { uint32_t behaviorId{}; - if (!bitStream->Read(behaviorId)) { - LOG("Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(behaviorId)) { + LOG("Unable to read behaviorId from bitStream, aborting Sync! %i", bitStream.GetNumberOfUnreadBits()); return; } LWOOBJID target{}; - if (!bitStream->Read(target)) { - LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(target)) { + LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream.GetNumberOfUnreadBits()); return; } diff --git a/dGame/dBehaviors/AirMovementBehavior.h b/dGame/dBehaviors/AirMovementBehavior.h index 9d51ef032..0edb1a764 100644 --- a/dGame/dBehaviors/AirMovementBehavior.h +++ b/dGame/dBehaviors/AirMovementBehavior.h @@ -6,11 +6,11 @@ class AirMovementBehavior final : public Behavior public: explicit AirMovementBehavior(const uint32_t behavior_id) : Behavior(behavior_id) {} - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: diff --git a/dGame/dBehaviors/AndBehavior.cpp b/dGame/dBehaviors/AndBehavior.cpp index 574932481..ad986e37c 100644 --- a/dGame/dBehaviors/AndBehavior.cpp +++ b/dGame/dBehaviors/AndBehavior.cpp @@ -3,13 +3,13 @@ #include "Game.h" #include "Logger.h" -void AndBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void AndBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { for (auto* behavior : this->m_behaviors) { behavior->Handle(context, bitStream, branch); } } -void AndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void AndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { for (auto* behavior : this->m_behaviors) { behavior->Calculate(context, bitStream, branch); } diff --git a/dGame/dBehaviors/AndBehavior.h b/dGame/dBehaviors/AndBehavior.h index 0ef7c0fda..76bd39562 100644 --- a/dGame/dBehaviors/AndBehavior.h +++ b/dGame/dBehaviors/AndBehavior.h @@ -15,9 +15,9 @@ class AndBehavior final : public Behavior explicit AndBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/ApplyBuffBehavior.cpp b/dGame/dBehaviors/ApplyBuffBehavior.cpp index 26b3da841..9ee48375d 100644 --- a/dGame/dBehaviors/ApplyBuffBehavior.cpp +++ b/dGame/dBehaviors/ApplyBuffBehavior.cpp @@ -5,7 +5,7 @@ #include "BuffComponent.h" -void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* entity = Game::entityManager->GetEntity(branch.target == LWOOBJID_EMPTY ? context->originator : branch.target); if (entity == nullptr) return; @@ -30,7 +30,7 @@ void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext b buffComponent->RemoveBuff(m_BuffId); } -void ApplyBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ApplyBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/ApplyBuffBehavior.h b/dGame/dBehaviors/ApplyBuffBehavior.h index e01a238ea..4acc65500 100644 --- a/dGame/dBehaviors/ApplyBuffBehavior.h +++ b/dGame/dBehaviors/ApplyBuffBehavior.h @@ -24,11 +24,11 @@ class ApplyBuffBehavior final : public Behavior explicit ApplyBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: diff --git a/dGame/dBehaviors/AreaOfEffectBehavior.cpp b/dGame/dBehaviors/AreaOfEffectBehavior.cpp index 2a7e97548..ce41785f4 100644 --- a/dGame/dBehaviors/AreaOfEffectBehavior.cpp +++ b/dGame/dBehaviors/AreaOfEffectBehavior.cpp @@ -12,11 +12,11 @@ #include "Game.h" #include "Logger.h" -void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { uint32_t targetCount{}; - if (!bitStream->Read(targetCount)) { - LOG("Unable to read targetCount from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(targetCount)) { + LOG("Unable to read targetCount from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; } @@ -40,7 +40,7 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b for (auto i = 0u; i < targetCount; ++i) { LWOOBJID target{}; - if (!bitStream->Read(target)) { + if (!bitStream.Read(target)) { LOG("failed to read in target %i from bitStream, aborting target Handle!", i); }; targets.push_back(target); @@ -54,7 +54,7 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b PlayFx(u"cast", context->originator); } -void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* caster = Game::entityManager->GetEntity(context->caster); if (!caster) return; @@ -83,7 +83,7 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream // resize if we have more than max targets allows if (targets.size() > this->m_maxTargets) targets.resize(this->m_maxTargets); - bitStream->Write(targets.size()); + bitStream.Write(targets.size()); if (targets.size() == 0) { PlayFx(u"miss", context->originator); @@ -92,7 +92,7 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream context->foundTarget = true; // write all the targets to the bitstream for (auto* target : targets) { - bitStream->Write(target->GetObjectID()); + bitStream.Write(target->GetObjectID()); } // then cast all the actions diff --git a/dGame/dBehaviors/AreaOfEffectBehavior.h b/dGame/dBehaviors/AreaOfEffectBehavior.h index f0fbb18d3..5ce200033 100644 --- a/dGame/dBehaviors/AreaOfEffectBehavior.h +++ b/dGame/dBehaviors/AreaOfEffectBehavior.h @@ -6,8 +6,8 @@ class AreaOfEffectBehavior final : public Behavior { public: explicit AreaOfEffectBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: Behavior* m_action; diff --git a/dGame/dBehaviors/AttackDelayBehavior.cpp b/dGame/dBehaviors/AttackDelayBehavior.cpp index 1bf1048af..105a13271 100644 --- a/dGame/dBehaviors/AttackDelayBehavior.cpp +++ b/dGame/dBehaviors/AttackDelayBehavior.cpp @@ -4,11 +4,11 @@ #include "Game.h" #include "Logger.h" -void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { uint32_t handle{}; - if (!bitStream->Read(handle)) { - LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(handle)) { + LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -17,10 +17,10 @@ void AttackDelayBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi } } -void AttackDelayBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void AttackDelayBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { const auto handle = context->GetUniqueSkillId(); - bitStream->Write(handle); + bitStream.Write(handle); context->foundTarget = true; @@ -31,11 +31,11 @@ void AttackDelayBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* } } -void AttackDelayBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void AttackDelayBehavior::Sync(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { this->m_action->Handle(context, bitStream, branch); } -void AttackDelayBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void AttackDelayBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { PlayFx(u"cast", context->originator); this->m_action->Calculate(context, bitStream, branch); diff --git a/dGame/dBehaviors/AttackDelayBehavior.h b/dGame/dBehaviors/AttackDelayBehavior.h index 64271ba53..173b0a0d1 100644 --- a/dGame/dBehaviors/AttackDelayBehavior.h +++ b/dGame/dBehaviors/AttackDelayBehavior.h @@ -19,13 +19,13 @@ class AttackDelayBehavior final : public Behavior explicit AttackDelayBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void SyncCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/BasicAttackBehavior.cpp b/dGame/dBehaviors/BasicAttackBehavior.cpp index 914e67a57..97ceb846d 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.cpp +++ b/dGame/dBehaviors/BasicAttackBehavior.cpp @@ -9,7 +9,7 @@ #include "BehaviorContext.h" #include "eBasicAttackSuccessTypes.h" -void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { if (context->unmanaged) { auto* entity = Game::entityManager->GetEntity(branch.target); @@ -30,22 +30,22 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi return; } - bitStream->AlignReadToByteBoundary(); + bitStream.AlignReadToByteBoundary(); uint16_t allocatedBits{}; - if (!bitStream->Read(allocatedBits) || allocatedBits == 0) { + if (!bitStream.Read(allocatedBits) || allocatedBits == 0) { LOG_DEBUG("No allocated bits"); return; } LOG_DEBUG("Number of allocated bits %i", allocatedBits); - const auto baseAddress = bitStream->GetReadOffset(); + const auto baseAddress = bitStream.GetReadOffset(); DoHandleBehavior(context, bitStream, branch); - bitStream->SetReadOffset(baseAddress + allocatedBits); + bitStream.SetReadOffset(baseAddress + allocatedBits); } -void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* targetEntity = Game::entityManager->GetEntity(branch.target); if (!targetEntity) { LOG("Target targetEntity %llu not found.", branch.target); @@ -62,7 +62,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit bool isImmune{}; bool isSuccess{}; - if (!bitStream->Read(isBlocked)) { + if (!bitStream.Read(isBlocked)) { LOG("Unable to read isBlocked"); return; } @@ -74,7 +74,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit return; } - if (!bitStream->Read(isImmune)) { + if (!bitStream.Read(isImmune)) { LOG("Unable to read isImmune"); return; } @@ -85,20 +85,20 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit return; } - if (!bitStream->Read(isSuccess)) { + if (!bitStream.Read(isSuccess)) { LOG("failed to read success from bitstream"); return; } if (isSuccess) { uint32_t armorDamageDealt{}; - if (!bitStream->Read(armorDamageDealt)) { + if (!bitStream.Read(armorDamageDealt)) { LOG("Unable to read armorDamageDealt"); return; } uint32_t healthDamageDealt{}; - if (!bitStream->Read(healthDamageDealt)) { + if (!bitStream.Read(healthDamageDealt)) { LOG("Unable to read healthDamageDealt"); return; } @@ -111,7 +111,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit } bool died{}; - if (!bitStream->Read(died)) { + if (!bitStream.Read(died)) { LOG("Unable to read died"); return; } @@ -122,7 +122,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit } uint8_t successState{}; - if (!bitStream->Read(successState)) { + if (!bitStream.Read(successState)) { LOG("Unable to read success state"); return; } @@ -144,26 +144,26 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit } } -void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - bitStream->AlignWriteToByteBoundary(); +void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { + bitStream.AlignWriteToByteBoundary(); - const auto allocatedAddress = bitStream->GetWriteOffset(); + const auto allocatedAddress = bitStream.GetWriteOffset(); - bitStream->Write(0); + bitStream.Write(0); - const auto startAddress = bitStream->GetWriteOffset(); + const auto startAddress = bitStream.GetWriteOffset(); DoBehaviorCalculation(context, bitStream, branch); - const auto endAddress = bitStream->GetWriteOffset(); + const auto endAddress = bitStream.GetWriteOffset(); const uint16_t allocate = endAddress - startAddress; - bitStream->SetWriteOffset(allocatedAddress); - bitStream->Write(allocate); - bitStream->SetWriteOffset(startAddress + allocate); + bitStream.SetWriteOffset(allocatedAddress); + bitStream.Write(allocate); + bitStream.SetWriteOffset(startAddress + allocate); } -void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* targetEntity = Game::entityManager->GetEntity(branch.target); if (!targetEntity) { LOG("Target entity %llu is null!", branch.target); @@ -178,7 +178,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet const bool isBlocking = destroyableComponent->GetAttacksToBlock() > 0; - bitStream->Write(isBlocking); + bitStream.Write(isBlocking); if (isBlocking) { destroyableComponent->SetAttacksToBlock(destroyableComponent->GetAttacksToBlock() - 1); @@ -188,7 +188,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet } const bool isImmune = destroyableComponent->IsImmune() || destroyableComponent->IsCooldownImmune(); - bitStream->Write(isImmune); + bitStream.Write(isImmune); if (isImmune) { LOG_DEBUG("Target targetEntity %llu is immune!", branch.target); @@ -210,7 +210,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet const uint32_t healthDamageDealt = previousHealth - destroyableComponent->GetHealth(); isSuccess = armorDamageDealt > 0 || healthDamageDealt > 0 || (armorDamageDealt + healthDamageDealt) > 0; - bitStream->Write(isSuccess); + bitStream.Write(isSuccess); //Handle player damage cooldown if (isSuccess && targetEntity->IsPlayer() && !this->m_DontApplyImmune) { @@ -222,15 +222,15 @@ 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); - bitStream->Write(healthDamageDealt); - bitStream->Write(targetEntity->GetIsDead()); + bitStream.Write(armorDamageDealt); + bitStream.Write(healthDamageDealt); + bitStream.Write(targetEntity->GetIsDead()); } - bitStream->Write(successState); + bitStream.Write(successState); switch (static_cast(successState)) { case eBasicAttackSuccessTypes::SUCCESS: diff --git a/dGame/dBehaviors/BasicAttackBehavior.h b/dGame/dBehaviors/BasicAttackBehavior.h index 6525c3431..3cde23fde 100644 --- a/dGame/dBehaviors/BasicAttackBehavior.h +++ b/dGame/dBehaviors/BasicAttackBehavior.h @@ -12,7 +12,7 @@ class BasicAttackBehavior final : public Behavior * is then offset to after the allocated bits for this stream. * */ - void DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + void DoHandleBehavior(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch); /** * @brief Handles a client initialized Basic Attack Behavior cast to be deserialized and verified on the server. @@ -22,14 +22,14 @@ class BasicAttackBehavior final : public Behavior * and will fail gracefully if an overread is detected. * @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down. */ - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; /** * @brief Writes a 16bit short to the bitStream and when the actual behavior calculation finishes with all of its branches, the number * of bits used is then written to where the 16bit short initially was. * */ - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; /** * @brief Calculates a server initialized Basic Attack Behavior cast to be serialized to the client @@ -38,7 +38,7 @@ class BasicAttackBehavior final : public Behavior * @param bitStream The bitStream to serialize to. * @param branch The context of this specific branch of the Skill Behavior. Changes based on which branch you are going down. */ - void DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + void DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch); /** * @brief Loads this Behaviors parameters from the database. For this behavior specifically: diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index 64bb03f54..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; } @@ -487,10 +481,10 @@ std::map Behavior::GetParameterNames() const { void Behavior::Load() { } -void Behavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void Behavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { } -void Behavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void Behavior::Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { } void Behavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { @@ -502,14 +496,8 @@ void Behavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWO void Behavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { } -void Behavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { -} - -void Behavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void Behavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { } -Behavior::~Behavior() { - delete m_effectNames; - delete m_effectType; - delete m_effectHandle; +void Behavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { } diff --git a/dGame/dBehaviors/Behavior.h b/dGame/dBehaviors/Behavior.h index ca1c23e5a..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 @@ -68,9 +68,9 @@ class Behavior virtual void Load(); // Player side - virtual void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + virtual void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch); - virtual void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + virtual void Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch); virtual void UnCast(BehaviorContext* context, BehaviorBranchContext branch); @@ -79,14 +79,20 @@ class Behavior virtual void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second); // Npc side - virtual void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + virtual void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch); - virtual void SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch); + virtual void SyncCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch); /* * Creations/destruction */ 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 e4f3011ca..abba74bee 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; } @@ -224,6 +225,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; @@ -243,27 +254,25 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) { echo.uiBehaviorHandle = entry.handle; echo.uiSkillHandle = this->skillUId; - auto* bitStream = new RakNet::BitStream(); + RakNet::BitStream bitStream{}; // Calculate sync entry.behavior->SyncCalculation(this, bitStream, entry.branchContext); if (!clientInitalized) { - echo.sBitStream.assign(reinterpret_cast(bitStream->GetData()), bitStream->GetNumberOfBytesUsed()); + echo.sBitStream.assign(reinterpret_cast(bitStream.GetData()), bitStream.GetNumberOfBytesUsed()); // Write message RakNet::BitStream message; BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); message.Write(this->originator); - echo.Serialize(&message); + echo.Serialize(message); - Game::server->Send(&message, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::server->Send(message, UNASSIGNED_SYSTEM_ADDRESS, true); } ExecuteUpdates(); - - delete bitStream; } std::vector valid; @@ -335,7 +344,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++; @@ -358,24 +367,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; } @@ -421,8 +430,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 333dc9a8d..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/BlockBehavior.cpp b/dGame/dBehaviors/BlockBehavior.cpp index 88c6bb0b8..0d3e164b0 100644 --- a/dGame/dBehaviors/BlockBehavior.cpp +++ b/dGame/dBehaviors/BlockBehavior.cpp @@ -7,7 +7,7 @@ #include "Logger.h" #include "DestroyableComponent.h" -void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { const auto target = context->originator; auto* entity = Game::entityManager->GetEntity(target); @@ -33,7 +33,7 @@ void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea } } -void BlockBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void BlockBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/BlockBehavior.h b/dGame/dBehaviors/BlockBehavior.h index e0d639ed2..9f4d696d4 100644 --- a/dGame/dBehaviors/BlockBehavior.h +++ b/dGame/dBehaviors/BlockBehavior.h @@ -13,9 +13,9 @@ class BlockBehavior final : public Behavior explicit BlockBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/BuffBehavior.cpp b/dGame/dBehaviors/BuffBehavior.cpp index 7ac8b352e..e20bf8206 100644 --- a/dGame/dBehaviors/BuffBehavior.cpp +++ b/dGame/dBehaviors/BuffBehavior.cpp @@ -7,7 +7,7 @@ #include "Logger.h" #include "DestroyableComponent.h" -void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; auto* entity = Game::entityManager->GetEntity(target); diff --git a/dGame/dBehaviors/BuffBehavior.h b/dGame/dBehaviors/BuffBehavior.h index b7c805b3e..d057758a9 100644 --- a/dGame/dBehaviors/BuffBehavior.h +++ b/dGame/dBehaviors/BuffBehavior.h @@ -16,7 +16,7 @@ class BuffBehavior final : public Behavior explicit BuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; 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/CarBoostBehavior.cpp b/dGame/dBehaviors/CarBoostBehavior.cpp index eb22cb09b..fdbcba714 100644 --- a/dGame/dBehaviors/CarBoostBehavior.cpp +++ b/dGame/dBehaviors/CarBoostBehavior.cpp @@ -8,7 +8,7 @@ #include "Logger.h" #include "PossessableComponent.h" -void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { GameMessages::SendVehicleAddPassiveBoostAction(branch.target, UNASSIGNED_SYSTEM_ADDRESS); auto* entity = Game::entityManager->GetEntity(context->originator); diff --git a/dGame/dBehaviors/CarBoostBehavior.h b/dGame/dBehaviors/CarBoostBehavior.h index 3f4265b92..5e629421c 100644 --- a/dGame/dBehaviors/CarBoostBehavior.h +++ b/dGame/dBehaviors/CarBoostBehavior.h @@ -17,7 +17,7 @@ class CarBoostBehavior final : public Behavior explicit CarBoostBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/ChainBehavior.cpp b/dGame/dBehaviors/ChainBehavior.cpp index 4a20c151a..feb27988d 100644 --- a/dGame/dBehaviors/ChainBehavior.cpp +++ b/dGame/dBehaviors/ChainBehavior.cpp @@ -3,11 +3,11 @@ #include "Game.h" #include "Logger.h" -void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { uint32_t chainIndex{}; - if (!bitStream->Read(chainIndex)) { - LOG("Unable to read chainIndex from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(chainIndex)) { + LOG("Unable to read chainIndex from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; } @@ -16,12 +16,12 @@ void ChainBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea if (chainIndex < this->m_behaviors.size()) { this->m_behaviors.at(chainIndex)->Handle(context, bitStream, branch); } else { - LOG("chainIndex out of bounds, aborting handle of chain %i bits unread %i", chainIndex, bitStream->GetNumberOfUnreadBits()); + LOG("chainIndex out of bounds, aborting handle of chain %i bits unread %i", chainIndex, bitStream.GetNumberOfUnreadBits()); } } -void ChainBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - bitStream->Write(1); +void ChainBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { + bitStream.Write(1); this->m_behaviors.at(0)->Calculate(context, bitStream, branch); } diff --git a/dGame/dBehaviors/ChainBehavior.h b/dGame/dBehaviors/ChainBehavior.h index c31d53580..174326df7 100644 --- a/dGame/dBehaviors/ChainBehavior.h +++ b/dGame/dBehaviors/ChainBehavior.h @@ -16,9 +16,9 @@ class ChainBehavior final : public Behavior explicit ChainBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp index 06a79fa72..b7c6b80a2 100644 --- a/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.cpp @@ -3,7 +3,7 @@ #include "BehaviorContext.h" #include "BehaviorBranchContext.h" -void ChangeIdleFlagsBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ChangeIdleFlagsBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; if (!target) return; @@ -16,7 +16,7 @@ void ChangeIdleFlagsBehavior::Handle(BehaviorContext* context, RakNet::BitStream } } -void ChangeIdleFlagsBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ChangeIdleFlagsBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/ChangeIdleFlagsBehavior.h b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h index 91f802f4b..e40af3ccf 100644 --- a/dGame/dBehaviors/ChangeIdleFlagsBehavior.h +++ b/dGame/dBehaviors/ChangeIdleFlagsBehavior.h @@ -11,8 +11,8 @@ class ChangeIdleFlagsBehavior final : public Behavior { */ explicit ChangeIdleFlagsBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void Load() override; diff --git a/dGame/dBehaviors/ChangeOrientationBehavior.cpp b/dGame/dBehaviors/ChangeOrientationBehavior.cpp index 445c76dfe..f8a34fb89 100644 --- a/dGame/dBehaviors/ChangeOrientationBehavior.cpp +++ b/dGame/dBehaviors/ChangeOrientationBehavior.cpp @@ -3,7 +3,7 @@ #include "BehaviorContext.h" #include "EntityManager.h" -void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Entity* sourceEntity; if (this->m_orientCaster) sourceEntity = Game::entityManager->GetEntity(context->originator); else sourceEntity = Game::entityManager->GetEntity(branch.target); diff --git a/dGame/dBehaviors/ChangeOrientationBehavior.h b/dGame/dBehaviors/ChangeOrientationBehavior.h index 22c92bb85..62c47d5ca 100644 --- a/dGame/dBehaviors/ChangeOrientationBehavior.h +++ b/dGame/dBehaviors/ChangeOrientationBehavior.h @@ -5,7 +5,7 @@ class ChangeOrientationBehavior final : public Behavior { public: explicit ChangeOrientationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: bool m_orientCaster; diff --git a/dGame/dBehaviors/ChargeUpBehavior.cpp b/dGame/dBehaviors/ChargeUpBehavior.cpp index cf737e19a..dd6293db2 100644 --- a/dGame/dBehaviors/ChargeUpBehavior.cpp +++ b/dGame/dBehaviors/ChargeUpBehavior.cpp @@ -4,10 +4,10 @@ #include "Game.h" #include "Logger.h" -void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { uint32_t handle{}; - if (!bitStream->Read(handle)) { + if (!bitStream.Read(handle)) { LOG("Unable to read handle from bitStream, aborting Handle! variable_type"); return; }; @@ -15,10 +15,10 @@ void ChargeUpBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt context->RegisterSyncBehavior(handle, this, branch, this->m_MaxDuration); } -void ChargeUpBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ChargeUpBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { } -void ChargeUpBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void ChargeUpBehavior::Sync(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { this->m_action->Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/ChargeUpBehavior.h b/dGame/dBehaviors/ChargeUpBehavior.h index ceb40f6c4..2ded1eb60 100644 --- a/dGame/dBehaviors/ChargeUpBehavior.h +++ b/dGame/dBehaviors/ChargeUpBehavior.h @@ -6,11 +6,11 @@ class ChargeUpBehavior final : public Behavior public: explicit ChargeUpBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: diff --git a/dGame/dBehaviors/ClearTargetBehavior.cpp b/dGame/dBehaviors/ClearTargetBehavior.cpp index ec0c0db62..40ae9b010 100644 --- a/dGame/dBehaviors/ClearTargetBehavior.cpp +++ b/dGame/dBehaviors/ClearTargetBehavior.cpp @@ -3,13 +3,13 @@ #include "BehaviorContext.h" -void ClearTargetBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ClearTargetBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { branch.target = LWOOBJID_EMPTY; this->m_action->Handle(context, bitStream, branch); } -void ClearTargetBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ClearTargetBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { branch.target = LWOOBJID_EMPTY; this->m_action->Calculate(context, bitStream, branch); diff --git a/dGame/dBehaviors/ClearTargetBehavior.h b/dGame/dBehaviors/ClearTargetBehavior.h index 0ed57fb45..d950c8f54 100644 --- a/dGame/dBehaviors/ClearTargetBehavior.h +++ b/dGame/dBehaviors/ClearTargetBehavior.h @@ -14,9 +14,9 @@ class ClearTargetBehavior final : public Behavior explicit ClearTargetBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/ConsumeItemBehavior.cpp b/dGame/dBehaviors/ConsumeItemBehavior.cpp index c3b76fcbc..440a641ba 100644 --- a/dGame/dBehaviors/ConsumeItemBehavior.cpp +++ b/dGame/dBehaviors/ConsumeItemBehavior.cpp @@ -3,7 +3,7 @@ #include "BehaviorBranchContext.h" #include "InventoryComponent.h" -void ConsumeItemBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ConsumeItemBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto action_to_cast = m_ActionNotConsumed; if (this->m_ConsumeLOT != -1) { auto caster = Game::entityManager->GetEntity(context->caster); @@ -19,7 +19,7 @@ void ConsumeItemBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi if(action_to_cast) action_to_cast->Handle(context, bitStream, branch); } -void ConsumeItemBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ConsumeItemBehavior::Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/ConsumeItemBehavior.h b/dGame/dBehaviors/ConsumeItemBehavior.h index f3eeb3308..c2fe357c4 100644 --- a/dGame/dBehaviors/ConsumeItemBehavior.h +++ b/dGame/dBehaviors/ConsumeItemBehavior.h @@ -5,8 +5,8 @@ class ConsumeItemBehavior final : public Behavior { public: explicit ConsumeItemBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; + void Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: diff --git a/dGame/dBehaviors/DamageAbsorptionBehavior.cpp b/dGame/dBehaviors/DamageAbsorptionBehavior.cpp index 880550e3e..f657c8fd0 100644 --- a/dGame/dBehaviors/DamageAbsorptionBehavior.cpp +++ b/dGame/dBehaviors/DamageAbsorptionBehavior.cpp @@ -7,7 +7,7 @@ #include "Logger.h" #include "DestroyableComponent.h" -void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); if (target == nullptr) { @@ -29,7 +29,7 @@ void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStrea context->RegisterTimerBehavior(this, branch, target->GetObjectID()); } -void DamageAbsorptionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void DamageAbsorptionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/DamageAbsorptionBehavior.h b/dGame/dBehaviors/DamageAbsorptionBehavior.h index 1b865e874..6e26bda13 100644 --- a/dGame/dBehaviors/DamageAbsorptionBehavior.h +++ b/dGame/dBehaviors/DamageAbsorptionBehavior.h @@ -13,9 +13,9 @@ class DamageAbsorptionBehavior final : public Behavior explicit DamageAbsorptionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; diff --git a/dGame/dBehaviors/DamageReductionBehavior.cpp b/dGame/dBehaviors/DamageReductionBehavior.cpp index bf32360e0..62b70a52b 100644 --- a/dGame/dBehaviors/DamageReductionBehavior.cpp +++ b/dGame/dBehaviors/DamageReductionBehavior.cpp @@ -7,7 +7,7 @@ #include "Logger.h" #include "DestroyableComponent.h" -void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); if (target == nullptr) { @@ -27,7 +27,7 @@ void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream context->RegisterTimerBehavior(this, branch, target->GetObjectID()); } -void DamageReductionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void DamageReductionBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/DamageReductionBehavior.h b/dGame/dBehaviors/DamageReductionBehavior.h index bddd31fbe..7a9aa4f50 100644 --- a/dGame/dBehaviors/DamageReductionBehavior.h +++ b/dGame/dBehaviors/DamageReductionBehavior.h @@ -13,9 +13,9 @@ class DamageReductionBehavior final : public Behavior explicit DamageReductionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; diff --git a/dGame/dBehaviors/DarkInspirationBehavior.cpp b/dGame/dBehaviors/DarkInspirationBehavior.cpp index 27a7c6346..367f9d5a4 100644 --- a/dGame/dBehaviors/DarkInspirationBehavior.cpp +++ b/dGame/dBehaviors/DarkInspirationBehavior.cpp @@ -6,7 +6,7 @@ #include "EntityManager.h" #include "BehaviorContext.h" -void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); if (target == nullptr) { @@ -25,7 +25,7 @@ void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream } } -void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); if (target == nullptr) { diff --git a/dGame/dBehaviors/DarkInspirationBehavior.h b/dGame/dBehaviors/DarkInspirationBehavior.h index f82987420..5fe02c5e7 100644 --- a/dGame/dBehaviors/DarkInspirationBehavior.h +++ b/dGame/dBehaviors/DarkInspirationBehavior.h @@ -11,9 +11,9 @@ class DarkInspirationBehavior final : public Behavior explicit DarkInspirationBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: diff --git a/dGame/dBehaviors/DurationBehavior.cpp b/dGame/dBehaviors/DurationBehavior.cpp index c0bc5585e..3544dc526 100644 --- a/dGame/dBehaviors/DurationBehavior.cpp +++ b/dGame/dBehaviors/DurationBehavior.cpp @@ -2,13 +2,13 @@ #include "BehaviorBranchContext.h" #include "BehaviorContext.h" -void DurationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void DurationBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { branch.duration = this->m_duration; this->m_action->Handle(context, bitStream, branch); } -void DurationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void DurationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { branch.duration = this->m_duration; this->m_action->Calculate(context, bitStream, branch); diff --git a/dGame/dBehaviors/DurationBehavior.h b/dGame/dBehaviors/DurationBehavior.h index 164754b10..5ea6abb95 100644 --- a/dGame/dBehaviors/DurationBehavior.h +++ b/dGame/dBehaviors/DurationBehavior.h @@ -11,9 +11,9 @@ class DurationBehavior final : public Behavior explicit DurationBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: 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/EndBehavior.cpp b/dGame/dBehaviors/EndBehavior.cpp index c67f3215e..804a31b73 100644 --- a/dGame/dBehaviors/EndBehavior.cpp +++ b/dGame/dBehaviors/EndBehavior.cpp @@ -3,11 +3,11 @@ #include "BehaviorContext.h" #include "BehaviorBranchContext.h" -void EndBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void EndBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { context->InvokeEnd(this->m_startBehavior); } -void EndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void EndBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { context->InvokeEnd(this->m_startBehavior); } diff --git a/dGame/dBehaviors/EndBehavior.h b/dGame/dBehaviors/EndBehavior.h index e1c06068e..26a6f2d5a 100644 --- a/dGame/dBehaviors/EndBehavior.h +++ b/dGame/dBehaviors/EndBehavior.h @@ -13,9 +13,9 @@ class EndBehavior final : public Behavior explicit EndBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/FallSpeedBehavior.cpp b/dGame/dBehaviors/FallSpeedBehavior.cpp index dfbdec2a3..9a376cec3 100644 --- a/dGame/dBehaviors/FallSpeedBehavior.cpp +++ b/dGame/dBehaviors/FallSpeedBehavior.cpp @@ -5,7 +5,7 @@ #include "BehaviorBranchContext.h" -void FallSpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void FallSpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { // make sure required parameter has non-default value if (m_PercentSlowed == 0.0f) return; auto* target = Game::entityManager->GetEntity(branch.target); @@ -23,7 +23,7 @@ void FallSpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS } } -void FallSpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void FallSpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/FallSpeedBehavior.h b/dGame/dBehaviors/FallSpeedBehavior.h index 01f0143f3..f53c17e2d 100644 --- a/dGame/dBehaviors/FallSpeedBehavior.h +++ b/dGame/dBehaviors/FallSpeedBehavior.h @@ -6,8 +6,8 @@ class FallSpeedBehavior final : public Behavior public: explicit FallSpeedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/ForceMovementBehavior.cpp b/dGame/dBehaviors/ForceMovementBehavior.cpp index 2ba3f2e19..04dad7150 100644 --- a/dGame/dBehaviors/ForceMovementBehavior.cpp +++ b/dGame/dBehaviors/ForceMovementBehavior.cpp @@ -6,29 +6,29 @@ #include "Game.h" #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) { +void ForceMovementBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { + if (this->m_hitAction->m_templateId == BehaviorTemplate::EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplate::EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplate::EMPTY) { return; } uint32_t handle{}; - if (!bitStream->Read(handle)) { - LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(handle)) { + LOG("Unable to read handle from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; } context->RegisterSyncBehavior(handle, this, branch, this->m_Duration); } -void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { uint32_t next{}; - if (!bitStream->Read(next)) { - LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(next)) { + LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream.GetNumberOfUnreadBits()); return; } LWOOBJID target{}; - if (!bitStream->Read(target)) { - LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(target)) { + LOG("Unable to read target from bitStream, aborting Sync! %i", bitStream.GetNumberOfUnreadBits()); return; } @@ -37,8 +37,8 @@ void ForceMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bi behavior->Handle(context, bitStream, branch); } -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) { +void ForceMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { + if (this->m_hitAction->m_templateId == BehaviorTemplate::EMPTY && this->m_hitEnemyAction->m_templateId == BehaviorTemplate::EMPTY && this->m_hitFactionAction->m_templateId == BehaviorTemplate::EMPTY) { return; } @@ -56,7 +56,7 @@ void ForceMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStrea } const auto skillHandle = context->GetUniqueSkillId(); - bitStream->Write(skillHandle); + bitStream.Write(skillHandle); context->SyncCalculation(skillHandle, this->m_Duration, this, branch); } @@ -71,7 +71,7 @@ void ForceMovementBehavior::Load() { this->m_Yaw = GetFloat("yaw"); } -void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* casterEntity = Game::entityManager->GetEntity(context->caster); if (casterEntity != nullptr) { auto* controllablePhysicsComponent = casterEntity->GetComponent(); diff --git a/dGame/dBehaviors/ForceMovementBehavior.h b/dGame/dBehaviors/ForceMovementBehavior.h index 8d5fd9f46..ffcea0f4c 100644 --- a/dGame/dBehaviors/ForceMovementBehavior.h +++ b/dGame/dBehaviors/ForceMovementBehavior.h @@ -22,13 +22,13 @@ class ForceMovementBehavior final : public Behavior explicit ForceMovementBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void SyncCalculation(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Sync(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Sync(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/HealBehavior.cpp b/dGame/dBehaviors/HealBehavior.cpp index 3eb4928cc..e2553671d 100644 --- a/dGame/dBehaviors/HealBehavior.cpp +++ b/dGame/dBehaviors/HealBehavior.cpp @@ -7,7 +7,7 @@ #include "eReplicaComponentType.h" -void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { +void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, const BehaviorBranchContext branch) { auto* entity = Game::entityManager->GetEntity(branch.target); if (entity == nullptr) { @@ -28,7 +28,7 @@ void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_strea } -void HealBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { +void HealBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, const BehaviorBranchContext branch) { Handle(context, bit_stream, branch); } diff --git a/dGame/dBehaviors/HealBehavior.h b/dGame/dBehaviors/HealBehavior.h index e967135aa..9ce678a47 100644 --- a/dGame/dBehaviors/HealBehavior.h +++ b/dGame/dBehaviors/HealBehavior.h @@ -13,9 +13,9 @@ class HealBehavior final : public Behavior explicit HealBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/ImaginationBehavior.cpp b/dGame/dBehaviors/ImaginationBehavior.cpp index c57fd0c74..be426e447 100644 --- a/dGame/dBehaviors/ImaginationBehavior.cpp +++ b/dGame/dBehaviors/ImaginationBehavior.cpp @@ -6,7 +6,7 @@ #include "Logger.h" -void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { +void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, const BehaviorBranchContext branch) { auto* entity = Game::entityManager->GetEntity(branch.target); if (entity == nullptr) { @@ -23,7 +23,7 @@ void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi } -void ImaginationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { +void ImaginationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, const BehaviorBranchContext branch) { Handle(context, bit_stream, branch); } diff --git a/dGame/dBehaviors/ImaginationBehavior.h b/dGame/dBehaviors/ImaginationBehavior.h index a35c2ddd1..ccebccc28 100644 --- a/dGame/dBehaviors/ImaginationBehavior.h +++ b/dGame/dBehaviors/ImaginationBehavior.h @@ -13,9 +13,9 @@ class ImaginationBehavior final : public Behavior explicit ImaginationBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/ImmunityBehavior.cpp b/dGame/dBehaviors/ImmunityBehavior.cpp index 9824c4797..77d438342 100644 --- a/dGame/dBehaviors/ImmunityBehavior.cpp +++ b/dGame/dBehaviors/ImmunityBehavior.cpp @@ -9,7 +9,7 @@ #include "ControllablePhysicsComponent.h" #include "eStateChangeType.h" -void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); if (!target) { @@ -51,7 +51,7 @@ void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt context->RegisterTimerBehavior(this, branch, target->GetObjectID()); } -void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/ImmunityBehavior.h b/dGame/dBehaviors/ImmunityBehavior.h index 02cc0faea..d2f28b959 100644 --- a/dGame/dBehaviors/ImmunityBehavior.h +++ b/dGame/dBehaviors/ImmunityBehavior.h @@ -11,9 +11,9 @@ class ImmunityBehavior final : public Behavior explicit ImmunityBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; diff --git a/dGame/dBehaviors/InterruptBehavior.cpp b/dGame/dBehaviors/InterruptBehavior.cpp index bd3f0c4a5..c2f2fe707 100644 --- a/dGame/dBehaviors/InterruptBehavior.cpp +++ b/dGame/dBehaviors/InterruptBehavior.cpp @@ -7,37 +7,51 @@ #include "SkillComponent.h" -void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - if (branch.target != context->originator) { - bool unknown = false; +void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { + 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; @@ -54,16 +68,17 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS } -void InterruptBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - if (branch.target != context->originator) { - bitStream->Write(false); +void InterruptBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { + LWOOBJID usedTarget = m_target ? branch.target : context->originator; + if (usedTarget != context->originator) { + bitStream.Write(false); } if (!this->m_interruptBlock) { - bitStream->Write(false); + bitStream.Write(false); } - bitStream->Write(false); + bitStream.Write(false); if (branch.target == context->originator) return; diff --git a/dGame/dBehaviors/InterruptBehavior.h b/dGame/dBehaviors/InterruptBehavior.h index 9ba272c79..440bc5592 100644 --- a/dGame/dBehaviors/InterruptBehavior.h +++ b/dGame/dBehaviors/InterruptBehavior.h @@ -15,9 +15,9 @@ class InterruptBehavior final : public Behavior explicit InterruptBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/JetPackBehavior.cpp b/dGame/dBehaviors/JetPackBehavior.cpp index 7fcd78b0e..8cfb87da8 100644 --- a/dGame/dBehaviors/JetPackBehavior.cpp +++ b/dGame/dBehaviors/JetPackBehavior.cpp @@ -5,7 +5,7 @@ #include "Character.h" -void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { +void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, const BehaviorBranchContext branch) { auto* entity = Game::entityManager->GetEntity(branch.target); GameMessages::SendSetJetPackMode(entity, true, this->m_BypassChecks, this->m_EnableHover, this->m_effectId, this->m_Airspeed, this->m_MaxAirspeed, this->m_VerticalVelocity, this->m_WarningEffectID); @@ -33,7 +33,7 @@ void JetPackBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext bra } } -void JetPackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { +void JetPackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, const BehaviorBranchContext branch) { Handle(context, bit_stream, branch); } diff --git a/dGame/dBehaviors/JetPackBehavior.h b/dGame/dBehaviors/JetPackBehavior.h index 0cc6c3995..bc82d5d2d 100644 --- a/dGame/dBehaviors/JetPackBehavior.h +++ b/dGame/dBehaviors/JetPackBehavior.h @@ -18,11 +18,11 @@ class JetPackBehavior final : public Behavior explicit JetPackBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/KnockbackBehavior.cpp b/dGame/dBehaviors/KnockbackBehavior.cpp index d0f865971..4d7bf2ead 100644 --- a/dGame/dBehaviors/KnockbackBehavior.cpp +++ b/dGame/dBehaviors/KnockbackBehavior.cpp @@ -9,16 +9,16 @@ #include "Game.h" #include "Logger.h" -void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { bool unknown{}; - if (!bitStream->Read(unknown)) { - LOG("Unable to read unknown from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(unknown)) { + LOG("Unable to read unknown from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; } -void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { bool blocked = false; auto* target = Game::entityManager->GetEntity(branch.target); @@ -31,7 +31,7 @@ void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* b } } - bitStream->Write(blocked); + bitStream.Write(blocked); } void KnockbackBehavior::Load() { diff --git a/dGame/dBehaviors/KnockbackBehavior.h b/dGame/dBehaviors/KnockbackBehavior.h index c952bb412..89777a6d8 100644 --- a/dGame/dBehaviors/KnockbackBehavior.h +++ b/dGame/dBehaviors/KnockbackBehavior.h @@ -17,9 +17,9 @@ class KnockbackBehavior final : public Behavior explicit KnockbackBehavior(const uint32_t behaviorID) : Behavior(behaviorID) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/LootBuffBehavior.cpp b/dGame/dBehaviors/LootBuffBehavior.cpp index c7a6b36aa..65b734228 100644 --- a/dGame/dBehaviors/LootBuffBehavior.cpp +++ b/dGame/dBehaviors/LootBuffBehavior.cpp @@ -1,6 +1,6 @@ #include "LootBuffBehavior.h" -void LootBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void LootBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto target = Game::entityManager->GetEntity(context->caster); if (!target) return; @@ -14,7 +14,7 @@ void LootBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt } -void LootBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void LootBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/LootBuffBehavior.h b/dGame/dBehaviors/LootBuffBehavior.h index b6f700ca1..dba82d756 100644 --- a/dGame/dBehaviors/LootBuffBehavior.h +++ b/dGame/dBehaviors/LootBuffBehavior.h @@ -20,9 +20,9 @@ class LootBuffBehavior final : public Behavior explicit LootBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {} - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/MovementSwitchBehavior.cpp b/dGame/dBehaviors/MovementSwitchBehavior.cpp index cddeeea93..7d7d3a178 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.cpp +++ b/dGame/dBehaviors/MovementSwitchBehavior.cpp @@ -3,19 +3,19 @@ #include "Game.h" #include "Logger.h" -void MovementSwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +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 (!bitStream.Read(movementType)) { + 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()); + LOG("Unable to read movementType from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -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/MovementSwitchBehavior.h b/dGame/dBehaviors/MovementSwitchBehavior.h index e6ff96f64..75b13b547 100644 --- a/dGame/dBehaviors/MovementSwitchBehavior.h +++ b/dGame/dBehaviors/MovementSwitchBehavior.h @@ -36,7 +36,7 @@ class MovementSwitchBehavior final : public Behavior explicit MovementSwitchBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/NpcCombatSkillBehavior.cpp b/dGame/dBehaviors/NpcCombatSkillBehavior.cpp index 5a8d03cf4..69a6ea9dc 100644 --- a/dGame/dBehaviors/NpcCombatSkillBehavior.cpp +++ b/dGame/dBehaviors/NpcCombatSkillBehavior.cpp @@ -3,7 +3,7 @@ #include "BehaviorContext.h" -void NpcCombatSkillBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { +void NpcCombatSkillBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) { context->skillTime = this->m_npcSkillTime; for (auto* behavior : this->m_behaviors) { diff --git a/dGame/dBehaviors/NpcCombatSkillBehavior.h b/dGame/dBehaviors/NpcCombatSkillBehavior.h index 19ff34830..07826f487 100644 --- a/dGame/dBehaviors/NpcCombatSkillBehavior.h +++ b/dGame/dBehaviors/NpcCombatSkillBehavior.h @@ -15,7 +15,7 @@ class NpcCombatSkillBehavior final : public Behavior explicit NpcCombatSkillBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/OverTimeBehavior.cpp b/dGame/dBehaviors/OverTimeBehavior.cpp index f66a5253f..5a42993fe 100644 --- a/dGame/dBehaviors/OverTimeBehavior.cpp +++ b/dGame/dBehaviors/OverTimeBehavior.cpp @@ -11,7 +11,7 @@ #include "CDSkillBehaviorTable.h" -void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { const auto originator = context->originator; auto* entity = Game::entityManager->GetEntity(originator); @@ -33,7 +33,7 @@ void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt } } -void OverTimeBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void OverTimeBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { } diff --git a/dGame/dBehaviors/OverTimeBehavior.h b/dGame/dBehaviors/OverTimeBehavior.h index 73a07865d..78d9388bd 100644 --- a/dGame/dBehaviors/OverTimeBehavior.h +++ b/dGame/dBehaviors/OverTimeBehavior.h @@ -16,9 +16,9 @@ class OverTimeBehavior final : public Behavior explicit OverTimeBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/PlayEffectBehavior.cpp b/dGame/dBehaviors/PlayEffectBehavior.cpp index acd606a9a..451c52def 100644 --- a/dGame/dBehaviors/PlayEffectBehavior.cpp +++ b/dGame/dBehaviors/PlayEffectBehavior.cpp @@ -3,7 +3,7 @@ #include "BehaviorContext.h" #include "BehaviorBranchContext.h" -void PlayEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void PlayEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { // On managed behaviors this is handled by the client if (!context->unmanaged) return; @@ -13,7 +13,7 @@ void PlayEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit PlayFx(u"", target); } -void PlayEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void PlayEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { const auto& target = branch.target == LWOOBJID_EMPTY ? context->originator : branch.target; //PlayFx(u"", target); diff --git a/dGame/dBehaviors/PlayEffectBehavior.h b/dGame/dBehaviors/PlayEffectBehavior.h index 5ef491616..c112579b1 100644 --- a/dGame/dBehaviors/PlayEffectBehavior.h +++ b/dGame/dBehaviors/PlayEffectBehavior.h @@ -10,9 +10,9 @@ class PlayEffectBehavior final : public Behavior explicit PlayEffectBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.cpp b/dGame/dBehaviors/ProjectileAttackBehavior.cpp index 504afc690..3e5118f70 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.cpp +++ b/dGame/dBehaviors/ProjectileAttackBehavior.cpp @@ -8,11 +8,11 @@ #include "ObjectIDManager.h" #include "eObjectBits.h" -void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { LWOOBJID target{}; - if (!bitStream->Read(target)) { - LOG("Unable to read target from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(target)) { + LOG("Unable to read target from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -34,8 +34,8 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea if (m_useMouseposit && !branch.isSync) { NiPoint3 targetPosition = NiPoint3Constant::ZERO; - if (!bitStream->Read(targetPosition)) { - LOG("Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(targetPosition)) { + LOG("Unable to read targetPosition from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; } @@ -45,8 +45,8 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea for (auto i = 0u; i < this->m_projectileCount; ++i) { LWOOBJID projectileId{}; - if (!bitStream->Read(projectileId)) { - LOG("Unable to read projectileId from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(projectileId)) { + LOG("Unable to read projectileId from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -58,8 +58,8 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea } } -void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - bitStream->Write(branch.target); +void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { + bitStream.Write(branch.target); auto* entity = Game::entityManager->GetEntity(context->originator); @@ -110,7 +110,7 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt GeneralUtils::SetBit(id, eObjectBits::SPAWNED); - bitStream->Write(id); + bitStream.Write(id); auto eulerAngles = rotation.GetEulerAngles(); diff --git a/dGame/dBehaviors/ProjectileAttackBehavior.h b/dGame/dBehaviors/ProjectileAttackBehavior.h index b307e66ca..fee3a5c25 100644 --- a/dGame/dBehaviors/ProjectileAttackBehavior.h +++ b/dGame/dBehaviors/ProjectileAttackBehavior.h @@ -32,9 +32,9 @@ class ProjectileAttackBehavior final : public Behavior explicit ProjectileAttackBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.cpp b/dGame/dBehaviors/PropertyTeleportBehavior.cpp index 939568f68..7e9ecee01 100644 --- a/dGame/dBehaviors/PropertyTeleportBehavior.cpp +++ b/dGame/dBehaviors/PropertyTeleportBehavior.cpp @@ -11,7 +11,7 @@ #include "ZoneInstanceManager.h" #include "dZoneManager.h" -void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* caster = Game::entityManager->GetEntity(context->caster); if (!caster) return; diff --git a/dGame/dBehaviors/PropertyTeleportBehavior.h b/dGame/dBehaviors/PropertyTeleportBehavior.h index 74eed03b3..7dbec84cb 100644 --- a/dGame/dBehaviors/PropertyTeleportBehavior.h +++ b/dGame/dBehaviors/PropertyTeleportBehavior.h @@ -11,7 +11,7 @@ class PropertyTeleportBehavior final : public Behavior explicit PropertyTeleportBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/PullToPointBehavior.cpp b/dGame/dBehaviors/PullToPointBehavior.cpp index e18443f75..f776298f6 100644 --- a/dGame/dBehaviors/PullToPointBehavior.cpp +++ b/dGame/dBehaviors/PullToPointBehavior.cpp @@ -5,7 +5,7 @@ #include "EntityManager.h" #include "MovementAIComponent.h" -void PullToPointBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void PullToPointBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* entity = Game::entityManager->GetEntity(context->originator); auto* target = Game::entityManager->GetEntity(branch.target); @@ -25,7 +25,7 @@ void PullToPointBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi movement->PullToPoint(position); } -void PullToPointBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void PullToPointBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/PullToPointBehavior.h b/dGame/dBehaviors/PullToPointBehavior.h index d448ad8d4..83c8a9448 100644 --- a/dGame/dBehaviors/PullToPointBehavior.h +++ b/dGame/dBehaviors/PullToPointBehavior.h @@ -12,9 +12,9 @@ class PullToPointBehavior final : public Behavior explicit PullToPointBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/RemoveBuffBehavior.cpp b/dGame/dBehaviors/RemoveBuffBehavior.cpp index c6d2c9c90..ec2c15d41 100644 --- a/dGame/dBehaviors/RemoveBuffBehavior.cpp +++ b/dGame/dBehaviors/RemoveBuffBehavior.cpp @@ -5,7 +5,7 @@ #include "EntityManager.h" #include "BuffComponent.h" -void RemoveBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void RemoveBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* entity = Game::entityManager->GetEntity(context->caster); if (!entity) return; diff --git a/dGame/dBehaviors/RemoveBuffBehavior.h b/dGame/dBehaviors/RemoveBuffBehavior.h index f2d8547b1..5e08ea7f1 100644 --- a/dGame/dBehaviors/RemoveBuffBehavior.h +++ b/dGame/dBehaviors/RemoveBuffBehavior.h @@ -12,7 +12,7 @@ class RemoveBuffBehavior final : public Behavior explicit RemoveBuffBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; diff --git a/dGame/dBehaviors/RepairBehavior.cpp b/dGame/dBehaviors/RepairBehavior.cpp index d0ce3fe84..95b8ed895 100644 --- a/dGame/dBehaviors/RepairBehavior.cpp +++ b/dGame/dBehaviors/RepairBehavior.cpp @@ -7,7 +7,7 @@ #include "Game.h" #include "eReplicaComponentType.h" -void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { +void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, const BehaviorBranchContext branch) { auto* entity = Game::entityManager->GetEntity(branch.target); if (entity == nullptr) { @@ -27,7 +27,7 @@ void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_str destroyable->Repair(this->m_armor); } -void RepairBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { +void RepairBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, const BehaviorBranchContext branch) { Handle(context, bit_stream, branch); } diff --git a/dGame/dBehaviors/RepairBehavior.h b/dGame/dBehaviors/RepairBehavior.h index 8d2f14e44..61b96543b 100644 --- a/dGame/dBehaviors/RepairBehavior.h +++ b/dGame/dBehaviors/RepairBehavior.h @@ -13,9 +13,9 @@ class RepairBehavior final : public Behavior explicit RepairBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/SkillCastFailedBehavior.cpp b/dGame/dBehaviors/SkillCastFailedBehavior.cpp index a663e7095..a9babe610 100644 --- a/dGame/dBehaviors/SkillCastFailedBehavior.cpp +++ b/dGame/dBehaviors/SkillCastFailedBehavior.cpp @@ -3,11 +3,11 @@ #include "BehaviorContext.h" #include "BehaviorBranchContext.h" -void SkillCastFailedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SkillCastFailedBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { context->failed = true; } -void SkillCastFailedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SkillCastFailedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { context->failed = true; } diff --git a/dGame/dBehaviors/SkillCastFailedBehavior.h b/dGame/dBehaviors/SkillCastFailedBehavior.h index 5359cb42b..5ccb12b20 100644 --- a/dGame/dBehaviors/SkillCastFailedBehavior.h +++ b/dGame/dBehaviors/SkillCastFailedBehavior.h @@ -11,9 +11,9 @@ class SkillCastFailedBehavior final : public Behavior explicit SkillCastFailedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/SkillEventBehavior.cpp b/dGame/dBehaviors/SkillEventBehavior.cpp index 4205c28bd..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) { +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/SkillEventBehavior.h b/dGame/dBehaviors/SkillEventBehavior.h index 540f6d4a1..6a334d908 100644 --- a/dGame/dBehaviors/SkillEventBehavior.h +++ b/dGame/dBehaviors/SkillEventBehavior.h @@ -9,7 +9,7 @@ class SkillEventBehavior final : public Behavior { explicit SkillEventBehavior(const uint32_t behaviorID) : Behavior(behaviorID) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; }; diff --git a/dGame/dBehaviors/SpawnBehavior.cpp b/dGame/dBehaviors/SpawnBehavior.cpp index dd45fb1b6..e033d368d 100644 --- a/dGame/dBehaviors/SpawnBehavior.cpp +++ b/dGame/dBehaviors/SpawnBehavior.cpp @@ -11,7 +11,7 @@ #include "EntityInfo.h" #include "eReplicaComponentType.h" -void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* origin = Game::entityManager->GetEntity(context->originator); if (origin == nullptr) { @@ -74,7 +74,7 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea }); } -void SpawnBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SpawnBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/SpawnBehavior.h b/dGame/dBehaviors/SpawnBehavior.h index 875e0a2bf..fad576042 100644 --- a/dGame/dBehaviors/SpawnBehavior.h +++ b/dGame/dBehaviors/SpawnBehavior.h @@ -13,9 +13,9 @@ class SpawnBehavior final : public Behavior explicit SpawnBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; diff --git a/dGame/dBehaviors/SpawnQuickbuildBehavior.cpp b/dGame/dBehaviors/SpawnQuickbuildBehavior.cpp index 514ae27a8..a76ce9806 100644 --- a/dGame/dBehaviors/SpawnQuickbuildBehavior.cpp +++ b/dGame/dBehaviors/SpawnQuickbuildBehavior.cpp @@ -3,7 +3,7 @@ #include "BehaviorBranchContext.h" #include "BehaviorContext.h" -void SpawnQuickbuildBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SpawnQuickbuildBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { } void SpawnQuickbuildBehavior::Load() { diff --git a/dGame/dBehaviors/SpawnQuickbuildBehavior.h b/dGame/dBehaviors/SpawnQuickbuildBehavior.h index 653c60e89..a5700cc58 100644 --- a/dGame/dBehaviors/SpawnQuickbuildBehavior.h +++ b/dGame/dBehaviors/SpawnQuickbuildBehavior.h @@ -11,7 +11,7 @@ class SpawnQuickbuildBehavior final : public Behavior explicit SpawnQuickbuildBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/SpeedBehavior.cpp b/dGame/dBehaviors/SpeedBehavior.cpp index f21fda7ef..c9c99bedd 100644 --- a/dGame/dBehaviors/SpeedBehavior.cpp +++ b/dGame/dBehaviors/SpeedBehavior.cpp @@ -6,7 +6,7 @@ #include "Logger.h" -void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { if (m_AffectsCaster) branch.target = context->caster; auto* target = Game::entityManager->GetEntity(branch.target); @@ -25,7 +25,7 @@ void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea } } -void SpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { Handle(context, bitStream, branch); } diff --git a/dGame/dBehaviors/SpeedBehavior.h b/dGame/dBehaviors/SpeedBehavior.h index 88b858209..f122fde76 100644 --- a/dGame/dBehaviors/SpeedBehavior.h +++ b/dGame/dBehaviors/SpeedBehavior.h @@ -11,9 +11,9 @@ class SpeedBehavior final : public Behavior explicit SpeedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/StartBehavior.cpp b/dGame/dBehaviors/StartBehavior.cpp index 2bcaf3251..cb23e31f0 100644 --- a/dGame/dBehaviors/StartBehavior.cpp +++ b/dGame/dBehaviors/StartBehavior.cpp @@ -1,13 +1,13 @@ #include "StartBehavior.h" #include "BehaviorBranchContext.h" -void StartBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { +void StartBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) { branch.start = this->m_behaviorId; this->m_action->Handle(context, bit_stream, branch); } -void StartBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { +void StartBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) { branch.start = this->m_behaviorId; this->m_action->Calculate(context, bit_stream, branch); diff --git a/dGame/dBehaviors/StartBehavior.h b/dGame/dBehaviors/StartBehavior.h index 384fe64a9..7d708d0a8 100644 --- a/dGame/dBehaviors/StartBehavior.h +++ b/dGame/dBehaviors/StartBehavior.h @@ -13,9 +13,9 @@ class StartBehavior final : public Behavior explicit StartBehavior(const uint32_t behaviorID) : Behavior(behaviorID) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/StunBehavior.cpp b/dGame/dBehaviors/StunBehavior.cpp index 02144f694..bec6f409f 100644 --- a/dGame/dBehaviors/StunBehavior.cpp +++ b/dGame/dBehaviors/StunBehavior.cpp @@ -10,14 +10,14 @@ #include "eReplicaComponentType.h" -void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { if (this->m_stunCaster || branch.target == context->originator) { return; } bool blocked{}; - if (!bitStream->Read(blocked)) { - LOG("Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(blocked)) { + LOG("Unable to read blocked from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -42,7 +42,7 @@ void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream combatAiComponent->Stun(branch.duration); } -void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { +void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { if (this->m_stunCaster || branch.target == context->originator) { auto* self = Game::entityManager->GetEntity(context->originator); @@ -79,7 +79,7 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr } } - bitStream->Write(blocked); + bitStream.Write(blocked); if (target == nullptr) { LOG("Failed to find target (%llu)!", branch.target); diff --git a/dGame/dBehaviors/StunBehavior.h b/dGame/dBehaviors/StunBehavior.h index f4851b472..18ca31f46 100644 --- a/dGame/dBehaviors/StunBehavior.h +++ b/dGame/dBehaviors/StunBehavior.h @@ -12,9 +12,9 @@ class StunBehavior final : public Behavior explicit StunBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/SwitchBehavior.cpp b/dGame/dBehaviors/SwitchBehavior.cpp index db04650df..a53b00010 100644 --- a/dGame/dBehaviors/SwitchBehavior.cpp +++ b/dGame/dBehaviors/SwitchBehavior.cpp @@ -6,61 +6,71 @@ #include "BehaviorContext.h" #include "BuffComponent.h" -void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { - auto state = true; +void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, const BehaviorBranchContext branch) { + bool state = true; - if (this->m_imagination > 0 || !this->m_isEnemyFaction) { - if (!bitStream->Read(state)) { - LOG("Unable to read state from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + 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; }; } 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()); } -} -void SwitchBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { - auto state = true; + auto* behaviorToCall = state ? m_actionTrue : m_actionFalse; + behaviorToCall->Handle(context, bitStream, branch); +} - if (this->m_imagination > 0 || !this->m_isEnemyFaction) { +void SwitchBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { + 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); + 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 5e40d6594..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 */ @@ -21,9 +23,9 @@ class SwitchBehavior final : public Behavior explicit SwitchBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/SwitchMultipleBehavior.cpp b/dGame/dBehaviors/SwitchMultipleBehavior.cpp index faaa0d232..00d639d56 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.cpp +++ b/dGame/dBehaviors/SwitchMultipleBehavior.cpp @@ -9,11 +9,11 @@ #include "EntityManager.h" -void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { float value{}; - if (!bitStream->Read(value)) { - LOG("Unable to read value from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(value)) { + LOG("Unable to read value from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -32,7 +32,7 @@ void SwitchMultipleBehavior::Handle(BehaviorContext* context, RakNet::BitStream* behavior->Handle(context, bitStream, branch); } -void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { // TODO } @@ -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/dBehaviors/SwitchMultipleBehavior.h b/dGame/dBehaviors/SwitchMultipleBehavior.h index 1e3dfe64c..9f9754b89 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.h +++ b/dGame/dBehaviors/SwitchMultipleBehavior.h @@ -15,9 +15,9 @@ class SwitchMultipleBehavior final : public Behavior explicit SwitchMultipleBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/TacArcBehavior.cpp b/dGame/dBehaviors/TacArcBehavior.cpp index 0cea82136..cb3430c8a 100644 --- a/dGame/dBehaviors/TacArcBehavior.cpp +++ b/dGame/dBehaviors/TacArcBehavior.cpp @@ -11,7 +11,7 @@ #include -void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { std::vector targets = {}; if (this->m_usePickedTarget && branch.target != LWOOBJID_EMPTY) { @@ -28,16 +28,16 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre } bool hasTargets = false; - if (!bitStream->Read(hasTargets)) { - LOG("Unable to read hasTargets from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(hasTargets)) { + LOG("Unable to read hasTargets from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; if (this->m_checkEnv) { bool blocked = false; - if (!bitStream->Read(blocked)) { - LOG("Unable to read blocked from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(blocked)) { + LOG("Unable to read blocked from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -49,8 +49,8 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre if (hasTargets) { uint32_t count = 0; - if (!bitStream->Read(count)) { - LOG("Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(count)) { + LOG("Unable to read count from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -62,8 +62,8 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre for (auto i = 0u; i < count; i++) { LWOOBJID id{}; - if (!bitStream->Read(id)) { - LOG("Unable to read id from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits()); + if (!bitStream.Read(id)) { + LOG("Unable to read id from bitStream, aborting Handle! %i", bitStream.GetNumberOfUnreadBits()); return; }; @@ -82,7 +82,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre } else this->m_missAction->Handle(context, bitStream, branch); } -void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* self = Game::entityManager->GetEntity(context->originator); if (self == nullptr) { LOG("Invalid self for (%llu)!", context->originator); @@ -155,11 +155,11 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS }); const auto hit = !targets.empty(); - bitStream->Write(hit); + bitStream.Write(hit); if (this->m_checkEnv) { const auto blocked = false; // TODO - bitStream->Write(blocked); + bitStream.Write(blocked); } if (hit) { @@ -168,9 +168,9 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS context->foundTarget = true; // We want to continue with this behavior const auto count = static_cast(targets.size()); - bitStream->Write(count); + bitStream.Write(count); for (auto* target : targets) { - bitStream->Write(target->GetObjectID()); + bitStream.Write(target->GetObjectID()); } for (auto* target : targets) { diff --git a/dGame/dBehaviors/TacArcBehavior.h b/dGame/dBehaviors/TacArcBehavior.h index d93452727..b331e6fc3 100644 --- a/dGame/dBehaviors/TacArcBehavior.h +++ b/dGame/dBehaviors/TacArcBehavior.h @@ -7,8 +7,8 @@ class TacArcBehavior final : public Behavior { public: explicit TacArcBehavior(const uint32_t behavior_id) : Behavior(behavior_id) {} - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; private: float m_maxRange; diff --git a/dGame/dBehaviors/TargetCasterBehavior.cpp b/dGame/dBehaviors/TargetCasterBehavior.cpp index ff9cfc036..1e2f82f00 100644 --- a/dGame/dBehaviors/TargetCasterBehavior.cpp +++ b/dGame/dBehaviors/TargetCasterBehavior.cpp @@ -3,7 +3,7 @@ #include "BehaviorContext.h" -void TargetCasterBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { +void TargetCasterBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) { branch.target = context->caster; this->m_action->Handle(context, bit_stream, branch); @@ -13,7 +13,7 @@ void TargetCasterBehavior::UnCast(BehaviorContext* context, BehaviorBranchContex this->m_action->UnCast(context, branch); } -void TargetCasterBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) { +void TargetCasterBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) { branch.target = context->caster; this->m_action->Calculate(context, bit_stream, branch); diff --git a/dGame/dBehaviors/TargetCasterBehavior.h b/dGame/dBehaviors/TargetCasterBehavior.h index 387d2732e..2713a1cee 100644 --- a/dGame/dBehaviors/TargetCasterBehavior.h +++ b/dGame/dBehaviors/TargetCasterBehavior.h @@ -13,11 +13,11 @@ class TargetCasterBehavior final : public Behavior explicit TargetCasterBehavior(const uint32_t behavior_id) : Behavior(behavior_id) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bit_stream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bit_stream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/TauntBehavior.cpp b/dGame/dBehaviors/TauntBehavior.cpp index 2e9f2168f..43117ee37 100644 --- a/dGame/dBehaviors/TauntBehavior.cpp +++ b/dGame/dBehaviors/TauntBehavior.cpp @@ -6,7 +6,7 @@ #include "Logger.h" -void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); if (target == nullptr) { @@ -22,7 +22,7 @@ void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea } } -void TauntBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void TauntBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* target = Game::entityManager->GetEntity(branch.target); if (target == nullptr) { diff --git a/dGame/dBehaviors/TauntBehavior.h b/dGame/dBehaviors/TauntBehavior.h index 3ae7db9d3..b5b3196e8 100644 --- a/dGame/dBehaviors/TauntBehavior.h +++ b/dGame/dBehaviors/TauntBehavior.h @@ -14,9 +14,9 @@ class TauntBehavior final : public Behavior explicit TauntBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dBehaviors/VentureVisionBehavior.cpp b/dGame/dBehaviors/VentureVisionBehavior.cpp index 397bdebfe..3aa3aac71 100644 --- a/dGame/dBehaviors/VentureVisionBehavior.cpp +++ b/dGame/dBehaviors/VentureVisionBehavior.cpp @@ -3,7 +3,7 @@ #include "CharacterComponent.h" #include "BehaviorContext.h" -void VentureVisionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void VentureVisionBehavior::Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { const auto targetEntity = Game::entityManager->GetEntity(branch.target); diff --git a/dGame/dBehaviors/VentureVisionBehavior.h b/dGame/dBehaviors/VentureVisionBehavior.h index 727589498..ee89dae92 100644 --- a/dGame/dBehaviors/VentureVisionBehavior.h +++ b/dGame/dBehaviors/VentureVisionBehavior.h @@ -28,7 +28,7 @@ class VentureVisionBehavior final : public Behavior explicit VentureVisionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Handle(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; diff --git a/dGame/dBehaviors/VerifyBehavior.cpp b/dGame/dBehaviors/VerifyBehavior.cpp index 2056f146d..c7ede52f0 100644 --- a/dGame/dBehaviors/VerifyBehavior.cpp +++ b/dGame/dBehaviors/VerifyBehavior.cpp @@ -7,7 +7,7 @@ #include "Logger.h" -void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { +void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) { auto* entity = Game::entityManager->GetEntity(branch.target); auto success = true; @@ -33,12 +33,12 @@ void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS } if (branch.target != LWOOBJID_EMPTY && branch.target != context->originator) { - bitStream->Write(success); + bitStream.Write(success); if (success) { - bitStream->Write(1); - bitStream->Write0(); - bitStream->Write0(); + bitStream.Write(1); + bitStream.Write0(); + bitStream.Write0(); } } diff --git a/dGame/dBehaviors/VerifyBehavior.h b/dGame/dBehaviors/VerifyBehavior.h index a91ff7cfa..ed32111de 100644 --- a/dGame/dBehaviors/VerifyBehavior.h +++ b/dGame/dBehaviors/VerifyBehavior.h @@ -19,7 +19,7 @@ class VerifyBehavior final : public Behavior explicit VerifyBehavior(const uint32_t behaviorId) : Behavior(behaviorId) { } - void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + void Calculate(BehaviorContext* context, RakNet::BitStream& bitStream, BehaviorBranchContext branch) override; void Load() override; }; diff --git a/dGame/dComponents/AchievementVendorComponent.cpp b/dGame/dComponents/AchievementVendorComponent.cpp new file mode 100644 index 000000000..006a2b6f0 --- /dev/null +++ b/dGame/dComponents/AchievementVendorComponent.cpp @@ -0,0 +1,81 @@ +#include "AchievementVendorComponent.h" +#include "MissionComponent.h" +#include "InventoryComponent.h" +#include "eMissionState.h" +#include "CDComponentsRegistryTable.h" +#include "CDItemComponentTable.h" +#include "eVendorTransactionResult.h" +#include "CheatDetection.h" +#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)) { + return true; + } + + CDMissionsTable* missionsTable = CDClientManager::GetTable(); + const auto missions = missionsTable->GetMissionsForReward(lot); + for (const auto mission : missions) { + if (missionComponent->GetMissionState(mission) == eMissionState::COMPLETE) { + m_PlayerPurchasableItems[buyer->GetObjectID()].insert(lot); + return true; + } + } + return false; +} + +void AchievementVendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) { + // get the item Comp from the item LOT + CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::GetTable(); + 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()); + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); + return; + } + + auto* inventoryComponent = buyer->GetComponent(); + if (!inventoryComponent) { + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); + return; + } + + if (costLOT == 13763) { // Faction Token Proxy + auto* missionComponent = buyer->GetComponent(); + if (!missionComponent) return; + + if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) costLOT = 8318; // "Assembly Token" + if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) costLOT = 8321; // "Venture League Token" + if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) costLOT = 8319; // "Sentinels Token" + if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) costLOT = 8320; // "Paradox Token" + } + + const uint32_t altCurrencyCost = itemComp.commendationCost * count; + if (inventoryComponent->GetLotCount(costLOT) < altCurrencyCost) { + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); + return; + } + + inventoryComponent->RemoveItem(costLOT, altCurrencyCost); + inventoryComponent->AddItem(lot, count, eLootSourceType::VENDOR); + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_SUCCESS); + +} + +void AchievementVendorComponent::RefreshInventory(bool isCreation) { + SetHasStandardCostItems(true); + Game::entityManager->SerializeEntity(m_Parent); +} diff --git a/dGame/dComponents/AchievementVendorComponent.h b/dGame/dComponents/AchievementVendorComponent.h new file mode 100644 index 000000000..ba6c7c2a0 --- /dev/null +++ b/dGame/dComponents/AchievementVendorComponent.h @@ -0,0 +1,25 @@ +#ifndef __ACHIEVEMENTVENDORCOMPONENT__H__ +#define __ACHIEVEMENTVENDORCOMPONENT__H__ + +#include "VendorComponent.h" +#include "eReplicaComponentType.h" +#include +#include + +class Entity; + +class AchievementVendorComponent final : public VendorComponent { +public: + static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::ACHIEVEMENT_VENDOR; + 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); + +private: + std::map> m_PlayerPurchasableItems; +}; + + +#endif //!__ACHIEVEMENTVENDORCOMPONENT__H__ diff --git a/dGame/dComponents/ActivityComponent.cpp b/dGame/dComponents/ActivityComponent.cpp index 49ca4faf1..1b2fc338f 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 "eChatMessageType.h" #include "CDCurrencyTableTable.h" #include "CDActivityRewardsTable.h" @@ -90,15 +90,15 @@ void ActivityComponent::LoadActivityData(const int32_t activityId) { } } -void ActivityComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(m_DirtyActivityInfo); +void ActivityComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(m_DirtyActivityInfo); if (m_DirtyActivityInfo) { - outBitStream->Write(m_ActivityPlayers.size()); + outBitStream.Write(m_ActivityPlayers.size()); if (!m_ActivityPlayers.empty()) { for (const auto& activityPlayer : m_ActivityPlayers) { - outBitStream->Write(activityPlayer->playerID); + outBitStream.Write(activityPlayer->playerID); for (const auto& activityValue : activityPlayer->values) { - outBitStream->Write(activityValue); + outBitStream.Write(activityValue); } } } @@ -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, eChatMessageType::CREATE_TEAM); bitStream.Write(leader->GetObjectID()); bitStream.Write(m_Participants.size()); diff --git a/dGame/dComponents/ActivityComponent.h b/dGame/dComponents/ActivityComponent.h index de63b3434..296c6ccce 100644 --- a/dGame/dComponents/ActivityComponent.h +++ b/dGame/dComponents/ActivityComponent.h @@ -155,7 +155,7 @@ class ActivityComponent : public Component { void LoadActivityData(const int32_t activityId); void Update(float deltaTime) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Makes some entity join the minigame, if it's a lobbied one, the entity will be placed in the lobby diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index 171834093..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) @@ -520,11 +520,11 @@ bool BaseCombatAIComponent::IsMech() { } -void BaseCombatAIComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(m_DirtyStateOrTarget || bIsInitialUpdate); +void BaseCombatAIComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(m_DirtyStateOrTarget || bIsInitialUpdate); if (m_DirtyStateOrTarget || bIsInitialUpdate) { - outBitStream->Write(m_State); - outBitStream->Write(m_Target); + outBitStream.Write(m_State); + outBitStream.Write(m_Target); m_DirtyStateOrTarget = false; } } diff --git a/dGame/dComponents/BaseCombatAIComponent.h b/dGame/dComponents/BaseCombatAIComponent.h index f00910e76..89985d647 100644 --- a/dGame/dComponents/BaseCombatAIComponent.h +++ b/dGame/dComponents/BaseCombatAIComponent.h @@ -53,7 +53,7 @@ class BaseCombatAIComponent final : public Component { ~BaseCombatAIComponent() override; void Update(float deltaTime) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Get the current behavioral state of the enemy diff --git a/dGame/dComponents/BouncerComponent.cpp b/dGame/dComponents/BouncerComponent.cpp index 78ee3637f..d1c63bf4a 100644 --- a/dGame/dComponents/BouncerComponent.cpp +++ b/dGame/dComponents/BouncerComponent.cpp @@ -22,10 +22,10 @@ BouncerComponent::BouncerComponent(Entity* parent) : Component(parent) { BouncerComponent::~BouncerComponent() { } -void BouncerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(m_PetEnabled); +void BouncerComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(m_PetEnabled); if (m_PetEnabled) { - outBitStream->Write(m_PetBouncerEnabled); + outBitStream.Write(m_PetBouncerEnabled); } } diff --git a/dGame/dComponents/BouncerComponent.h b/dGame/dComponents/BouncerComponent.h index b41881c64..441ba58ef 100644 --- a/dGame/dComponents/BouncerComponent.h +++ b/dGame/dComponents/BouncerComponent.h @@ -17,7 +17,7 @@ class BouncerComponent final : public Component { BouncerComponent(Entity* parentEntity); ~BouncerComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; Entity* GetParentEntity() const; diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index cdf1d5bc9..2c9406475 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -32,24 +32,24 @@ BuffComponent::BuffComponent(Entity* parent) : Component(parent) { BuffComponent::~BuffComponent() { } -void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void BuffComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { if (!bIsInitialUpdate) return; - outBitStream->Write(!m_Buffs.empty()); + outBitStream.Write(!m_Buffs.empty()); if (!m_Buffs.empty()) { - outBitStream->Write(m_Buffs.size()); + outBitStream.Write(m_Buffs.size()); for (const auto& [id, buff] : m_Buffs) { - outBitStream->Write(id); - outBitStream->Write(buff.time != 0.0f); - if (buff.time != 0.0f) outBitStream->Write(buff.time * 1000.0f); - outBitStream->Write(buff.cancelOnDeath); - outBitStream->Write(buff.cancelOnZone); - outBitStream->Write(buff.cancelOnDamaged); - outBitStream->Write(buff.cancelOnRemoveBuff); - outBitStream->Write(buff.cancelOnUi); - outBitStream->Write(buff.cancelOnLogout); - outBitStream->Write(buff.cancelOnUnequip); - outBitStream->Write0(); // Cancel on Damage Absorb Ran Out. Generally false from what I can tell + outBitStream.Write(id); + outBitStream.Write(buff.time != 0.0f); + if (buff.time != 0.0f) outBitStream.Write(buff.time * 1000.0f); + outBitStream.Write(buff.cancelOnDeath); + outBitStream.Write(buff.cancelOnZone); + outBitStream.Write(buff.cancelOnDamaged); + outBitStream.Write(buff.cancelOnRemoveBuff); + outBitStream.Write(buff.cancelOnUi); + outBitStream.Write(buff.cancelOnLogout); + outBitStream.Write(buff.cancelOnUnequip); + outBitStream.Write0(); // Cancel on Damage Absorb Ran Out. Generally false from what I can tell auto* team = TeamManager::Instance()->GetTeam(buff.source); bool addedByTeammate = false; @@ -57,15 +57,15 @@ void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUp addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0; } - outBitStream->Write(addedByTeammate); // Added by teammate. If source is in the same team as the target, this is true. Otherwise, false. - outBitStream->Write(buff.applyOnTeammates); - if (addedByTeammate) outBitStream->Write(buff.source); + outBitStream.Write(addedByTeammate); // Added by teammate. If source is in the same team as the target, this is true. Otherwise, false. + outBitStream.Write(buff.applyOnTeammates); + if (addedByTeammate) outBitStream.Write(buff.source); - outBitStream->Write(buff.refCount); + outBitStream.Write(buff.refCount); } } - outBitStream->Write0(); // something to do with immunity buffs? + outBitStream.Write0(); // something to do with immunity buffs? } void BuffComponent::Update(float deltaTime) { @@ -208,9 +208,8 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity, bool ignoreRefCount) { const auto& iter = m_Buffs.find(id); - if (iter == m_Buffs.end()) { - return; - } + // If the buff is already scheduled to be removed, don't do it again + if (iter == m_Buffs.end() || m_BuffsToRemove.contains(id)) return; if (!ignoreRefCount && !iter->second.cancelOnRemoveBuff) { iter->second.refCount--; @@ -222,7 +221,7 @@ void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id); - m_BuffsToRemove.push_back(id); + m_BuffsToRemove.insert(id); RemoveBuffEffect(id); } @@ -327,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"); @@ -387,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 { @@ -403,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; @@ -451,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 18aa7a420..507e53a02 100644 --- a/dGame/dComponents/BuffComponent.h +++ b/dGame/dComponents/BuffComponent.h @@ -57,11 +57,11 @@ 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; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void Update(float deltaTime) override; @@ -141,7 +141,7 @@ class BuffComponent final : public Component { std::map m_Buffs; // Buffs to remove at the end of the update frame. - std::vector m_BuffsToRemove; + std::set m_BuffsToRemove; /** * Parameters (=effects) for each buff diff --git a/dGame/dComponents/CMakeLists.txt b/dGame/dComponents/CMakeLists.txt index ac509e11e..c60e135fe 100644 --- a/dGame/dComponents/CMakeLists.txt +++ b/dGame/dComponents/CMakeLists.txt @@ -1,4 +1,5 @@ set(DGAME_DCOMPONENTS_SOURCES + "AchievementVendorComponent.cpp" "ActivityComponent.cpp" "BaseCombatAIComponent.cpp" "BouncerComponent.cpp" @@ -47,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 e4e2ba4bf..d706af9c2 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -78,94 +78,94 @@ bool CharacterComponent::LandingAnimDisabled(int zoneID) { CharacterComponent::~CharacterComponent() { } -void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void CharacterComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { if (bIsInitialUpdate) { - outBitStream->Write(m_ClaimCodes[0] != 0); - if (m_ClaimCodes[0] != 0) outBitStream->Write(m_ClaimCodes[0]); - outBitStream->Write(m_ClaimCodes[1] != 0); - if (m_ClaimCodes[1] != 0) outBitStream->Write(m_ClaimCodes[1]); - outBitStream->Write(m_ClaimCodes[2] != 0); - if (m_ClaimCodes[2] != 0) outBitStream->Write(m_ClaimCodes[2]); - outBitStream->Write(m_ClaimCodes[3] != 0); - if (m_ClaimCodes[3] != 0) outBitStream->Write(m_ClaimCodes[3]); - - outBitStream->Write(m_Character->GetHairColor()); - outBitStream->Write(m_Character->GetHairStyle()); - outBitStream->Write(0); //Default "head" - outBitStream->Write(m_Character->GetShirtColor()); - outBitStream->Write(m_Character->GetPantsColor()); - outBitStream->Write(m_Character->GetShirtStyle()); - outBitStream->Write(0); //Default "head color" - outBitStream->Write(m_Character->GetEyebrows()); - outBitStream->Write(m_Character->GetEyes()); - outBitStream->Write(m_Character->GetMouth()); - outBitStream->Write(0); //AccountID, trying out if 0 works. - outBitStream->Write(m_Character->GetLastLogin()); //Last login - outBitStream->Write(0); //"prop mod last display time" - outBitStream->Write(m_Uscore); //u-score - outBitStream->Write0(); //Not free-to-play (disabled in DLU) + outBitStream.Write(m_ClaimCodes[0] != 0); + if (m_ClaimCodes[0] != 0) outBitStream.Write(m_ClaimCodes[0]); + outBitStream.Write(m_ClaimCodes[1] != 0); + if (m_ClaimCodes[1] != 0) outBitStream.Write(m_ClaimCodes[1]); + outBitStream.Write(m_ClaimCodes[2] != 0); + if (m_ClaimCodes[2] != 0) outBitStream.Write(m_ClaimCodes[2]); + outBitStream.Write(m_ClaimCodes[3] != 0); + if (m_ClaimCodes[3] != 0) outBitStream.Write(m_ClaimCodes[3]); + + outBitStream.Write(m_Character->GetHairColor()); + outBitStream.Write(m_Character->GetHairStyle()); + outBitStream.Write(0); //Default "head" + outBitStream.Write(m_Character->GetShirtColor()); + outBitStream.Write(m_Character->GetPantsColor()); + outBitStream.Write(m_Character->GetShirtStyle()); + outBitStream.Write(0); //Default "head color" + outBitStream.Write(m_Character->GetEyebrows()); + outBitStream.Write(m_Character->GetEyes()); + outBitStream.Write(m_Character->GetMouth()); + outBitStream.Write(0); //AccountID, trying out if 0 works. + outBitStream.Write(m_Character->GetLastLogin()); //Last login + outBitStream.Write(0); //"prop mod last display time" + outBitStream.Write(m_Uscore); //u-score + outBitStream.Write0(); //Not free-to-play (disabled in DLU) //Stats: - outBitStream->Write(m_CurrencyCollected); - outBitStream->Write(m_BricksCollected); - outBitStream->Write(m_SmashablesSmashed); - outBitStream->Write(m_QuickBuildsCompleted); - outBitStream->Write(m_EnemiesSmashed); - outBitStream->Write(m_RocketsUsed); - outBitStream->Write(m_MissionsCompleted); - outBitStream->Write(m_PetsTamed); - outBitStream->Write(m_ImaginationPowerUpsCollected); - outBitStream->Write(m_LifePowerUpsCollected); - outBitStream->Write(m_ArmorPowerUpsCollected); - outBitStream->Write(m_MetersTraveled); - outBitStream->Write(m_TimesSmashed); - outBitStream->Write(m_TotalDamageTaken); - outBitStream->Write(m_TotalDamageHealed); - outBitStream->Write(m_TotalArmorRepaired); - outBitStream->Write(m_TotalImaginationRestored); - outBitStream->Write(m_TotalImaginationUsed); - outBitStream->Write(m_DistanceDriven); - outBitStream->Write(m_TimeAirborneInCar); - outBitStream->Write(m_RacingImaginationPowerUpsCollected); - outBitStream->Write(m_RacingImaginationCratesSmashed); - outBitStream->Write(m_RacingCarBoostsActivated); - outBitStream->Write(m_RacingTimesWrecked); - outBitStream->Write(m_RacingSmashablesSmashed); - outBitStream->Write(m_RacesFinished); - outBitStream->Write(m_FirstPlaceRaceFinishes); - - outBitStream->Write0(); - outBitStream->Write(m_IsLanding); + outBitStream.Write(m_CurrencyCollected); + outBitStream.Write(m_BricksCollected); + outBitStream.Write(m_SmashablesSmashed); + outBitStream.Write(m_QuickBuildsCompleted); + outBitStream.Write(m_EnemiesSmashed); + outBitStream.Write(m_RocketsUsed); + outBitStream.Write(m_MissionsCompleted); + outBitStream.Write(m_PetsTamed); + outBitStream.Write(m_ImaginationPowerUpsCollected); + outBitStream.Write(m_LifePowerUpsCollected); + outBitStream.Write(m_ArmorPowerUpsCollected); + outBitStream.Write(m_MetersTraveled); + outBitStream.Write(m_TimesSmashed); + outBitStream.Write(m_TotalDamageTaken); + outBitStream.Write(m_TotalDamageHealed); + outBitStream.Write(m_TotalArmorRepaired); + outBitStream.Write(m_TotalImaginationRestored); + outBitStream.Write(m_TotalImaginationUsed); + outBitStream.Write(m_DistanceDriven); + outBitStream.Write(m_TimeAirborneInCar); + outBitStream.Write(m_RacingImaginationPowerUpsCollected); + outBitStream.Write(m_RacingImaginationCratesSmashed); + outBitStream.Write(m_RacingCarBoostsActivated); + outBitStream.Write(m_RacingTimesWrecked); + outBitStream.Write(m_RacingSmashablesSmashed); + outBitStream.Write(m_RacesFinished); + outBitStream.Write(m_FirstPlaceRaceFinishes); + + outBitStream.Write0(); + outBitStream.Write(m_IsLanding); if (m_IsLanding) { - outBitStream->Write(m_LastRocketConfig.size()); + outBitStream.Write(m_LastRocketConfig.size()); for (uint16_t character : m_LastRocketConfig) { - outBitStream->Write(character); + outBitStream.Write(character); } } } - outBitStream->Write(m_DirtyGMInfo); + outBitStream.Write(m_DirtyGMInfo); if (m_DirtyGMInfo) { - outBitStream->Write(m_PvpEnabled); - outBitStream->Write(m_IsGM); - outBitStream->Write(m_GMLevel); - outBitStream->Write(m_EditorEnabled); - outBitStream->Write(m_EditorLevel); + outBitStream.Write(m_PvpEnabled); + outBitStream.Write(m_IsGM); + outBitStream.Write(m_GMLevel); + outBitStream.Write(m_EditorEnabled); + outBitStream.Write(m_EditorLevel); } - outBitStream->Write(m_DirtyCurrentActivity); - if (m_DirtyCurrentActivity) outBitStream->Write(m_CurrentActivity); + outBitStream.Write(m_DirtyCurrentActivity); + if (m_DirtyCurrentActivity) outBitStream.Write(m_CurrentActivity); - outBitStream->Write(m_DirtySocialInfo); + outBitStream.Write(m_DirtySocialInfo); if (m_DirtySocialInfo) { - outBitStream->Write(m_GuildID); - outBitStream->Write(m_GuildName.size()); + outBitStream.Write(m_GuildID); + outBitStream.Write(m_GuildName.size()); if (!m_GuildName.empty()) - outBitStream->WriteBits(reinterpret_cast(m_GuildName.c_str()), static_cast(m_GuildName.size()) * sizeof(wchar_t) * 8); + outBitStream.WriteBits(reinterpret_cast(m_GuildName.c_str()), static_cast(m_GuildName.size()) * sizeof(wchar_t) * 8); - outBitStream->Write(m_IsLEGOClubMember); - outBitStream->Write(m_CountryCode); + outBitStream.Write(m_IsLEGOClubMember); + outBitStream.Write(m_CountryCode); } } @@ -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 01c26f9ab..7e63b0bd1 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 */ @@ -69,10 +70,10 @@ 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; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Updates the rocket configuration using a LOT string separated by commas diff --git a/dGame/dComponents/CollectibleComponent.cpp b/dGame/dComponents/CollectibleComponent.cpp index 99fcc6818..f6ba25b20 100644 --- a/dGame/dComponents/CollectibleComponent.cpp +++ b/dGame/dComponents/CollectibleComponent.cpp @@ -1,5 +1,5 @@ #include "CollectibleComponent.h" -void CollectibleComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) { - outBitStream->Write(GetCollectibleId()); +void CollectibleComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) { + outBitStream.Write(GetCollectibleId()); } diff --git a/dGame/dComponents/CollectibleComponent.h b/dGame/dComponents/CollectibleComponent.h index 10a23293d..5ecfb97e9 100644 --- a/dGame/dComponents/CollectibleComponent.h +++ b/dGame/dComponents/CollectibleComponent.h @@ -10,7 +10,7 @@ class CollectibleComponent final : public Component { CollectibleComponent(Entity* parentEntity, int32_t collectibleId) : Component(parentEntity), m_CollectibleId(collectibleId) {} int16_t GetCollectibleId() const { return m_CollectibleId; } - void Serialize(RakNet::BitStream* outBitStream, bool isConstruction) override; + void Serialize(RakNet::BitStream& outBitStream, bool isConstruction) override; private: int16_t m_CollectibleId = 0; }; diff --git a/dGame/dComponents/Component.cpp b/dGame/dComponents/Component.cpp index 1136456cf..8f38fb615 100644 --- a/dGame/dComponents/Component.cpp +++ b/dGame/dComponents/Component.cpp @@ -21,14 +21,14 @@ 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) { } -void Component::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) { +void Component::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) { } diff --git a/dGame/dComponents/Component.h b/dGame/dComponents/Component.h index 70f30f764..160565fbb 100644 --- a/dGame/dComponents/Component.h +++ b/dGame/dComponents/Component.h @@ -34,15 +34,15 @@ 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); + virtual void Serialize(RakNet::BitStream& outBitStream, bool isConstruction); protected: diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index be5227a00..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; @@ -71,95 +68,98 @@ void ControllablePhysicsComponent::Update(float deltaTime) { } -void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void ControllablePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { //If this is a creation, then we assume the position is dirty, even when it isn't. //This is because new clients will still need to receive the position. //if (bIsInitialUpdate) m_DirtyPosition = true; if (bIsInitialUpdate) { - outBitStream->Write(m_InJetpackMode); + outBitStream.Write(m_InJetpackMode); if (m_InJetpackMode) { - outBitStream->Write(m_JetpackEffectID); - outBitStream->Write(m_JetpackFlying); - outBitStream->Write(m_JetpackBypassChecks); + outBitStream.Write(m_JetpackEffectID); + outBitStream.Write(m_JetpackFlying); + outBitStream.Write(m_JetpackBypassChecks); } - outBitStream->Write1(); // always write these on construction - outBitStream->Write(m_ImmuneToStunMoveCount); - outBitStream->Write(m_ImmuneToStunJumpCount); - outBitStream->Write(m_ImmuneToStunTurnCount); - outBitStream->Write(m_ImmuneToStunAttackCount); - outBitStream->Write(m_ImmuneToStunUseItemCount); - outBitStream->Write(m_ImmuneToStunEquipCount); - outBitStream->Write(m_ImmuneToStunInteractCount); + outBitStream.Write1(); // always write these on construction + outBitStream.Write(m_ImmuneToStunMoveCount); + outBitStream.Write(m_ImmuneToStunJumpCount); + outBitStream.Write(m_ImmuneToStunTurnCount); + outBitStream.Write(m_ImmuneToStunAttackCount); + outBitStream.Write(m_ImmuneToStunUseItemCount); + outBitStream.Write(m_ImmuneToStunEquipCount); + outBitStream.Write(m_ImmuneToStunInteractCount); } - if (m_IgnoreMultipliers) m_DirtyCheats = false; + outBitStream.Write(m_DirtyCheats || bIsInitialUpdate); + if (m_DirtyCheats || bIsInitialUpdate) { + outBitStream.Write(m_GravityScale); + outBitStream.Write(m_SpeedMultiplier); - outBitStream->Write(m_DirtyCheats); - if (m_DirtyCheats) { - 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_PickupRadius); - outBitStream->Write(m_InJetpackMode); - m_DirtyEquippedItemInfo = false; + outBitStream.Write(m_DirtyEquippedItemInfo || bIsInitialUpdate); + if (m_DirtyEquippedItemInfo || bIsInitialUpdate) { + outBitStream.Write(m_PickupRadius); + outBitStream.Write(m_InJetpackMode); + + if (!bIsInitialUpdate) m_DirtyEquippedItemInfo = false; } - outBitStream->Write(m_DirtyBubble); - if (m_DirtyBubble) { - outBitStream->Write(m_IsInBubble); + outBitStream.Write(m_DirtyBubble || bIsInitialUpdate); + if (m_DirtyBubble || bIsInitialUpdate) { + outBitStream.Write(m_IsInBubble); if (m_IsInBubble) { - outBitStream->Write(m_BubbleType); - outBitStream->Write(m_SpecialAnims); + outBitStream.Write(m_BubbleType); + outBitStream.Write(m_SpecialAnims); } - m_DirtyBubble = false; + + if (!bIsInitialUpdate) m_DirtyBubble = false; } - outBitStream->Write(m_DirtyPosition || bIsInitialUpdate); + outBitStream.Write(m_DirtyPosition || bIsInitialUpdate); if (m_DirtyPosition || bIsInitialUpdate) { - outBitStream->Write(m_Position.x); - outBitStream->Write(m_Position.y); - outBitStream->Write(m_Position.z); - - outBitStream->Write(m_Rotation.x); - outBitStream->Write(m_Rotation.y); - outBitStream->Write(m_Rotation.z); - outBitStream->Write(m_Rotation.w); - - outBitStream->Write(m_IsOnGround); - outBitStream->Write(m_IsOnRail); - - outBitStream->Write(m_DirtyVelocity); - if (m_DirtyVelocity) { - outBitStream->Write(m_Velocity.x); - outBitStream->Write(m_Velocity.y); - outBitStream->Write(m_Velocity.z); + outBitStream.Write(m_Position.x); + outBitStream.Write(m_Position.y); + outBitStream.Write(m_Position.z); + + outBitStream.Write(m_Rotation.x); + outBitStream.Write(m_Rotation.y); + outBitStream.Write(m_Rotation.z); + outBitStream.Write(m_Rotation.w); + + outBitStream.Write(m_IsOnGround); + outBitStream.Write(m_IsOnRail); + + 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) { - outBitStream->Write(m_AngularVelocity.x); - outBitStream->Write(m_AngularVelocity.y); - outBitStream->Write(m_AngularVelocity.z); + 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 e850cfeb2..6309b8fc3 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -27,9 +27,9 @@ class ControllablePhysicsComponent : public PhysicsComponent { ~ControllablePhysicsComponent() override; 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 Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) 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 68271f26e..8ec1e4c97 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -122,61 +122,61 @@ void DestroyableComponent::Reinitialize(LOT templateID) { } } -void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void DestroyableComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { if (bIsInitialUpdate) { - outBitStream->Write1(); // always write these on construction - outBitStream->Write(m_ImmuneToBasicAttackCount); - outBitStream->Write(m_ImmuneToDamageOverTimeCount); - outBitStream->Write(m_ImmuneToKnockbackCount); - outBitStream->Write(m_ImmuneToInterruptCount); - outBitStream->Write(m_ImmuneToSpeedCount); - outBitStream->Write(m_ImmuneToImaginationGainCount); - outBitStream->Write(m_ImmuneToImaginationLossCount); - outBitStream->Write(m_ImmuneToQuickbuildInterruptCount); - outBitStream->Write(m_ImmuneToPullToPointCount); + outBitStream.Write1(); // always write these on construction + outBitStream.Write(m_ImmuneToBasicAttackCount); + outBitStream.Write(m_ImmuneToDamageOverTimeCount); + outBitStream.Write(m_ImmuneToKnockbackCount); + outBitStream.Write(m_ImmuneToInterruptCount); + outBitStream.Write(m_ImmuneToSpeedCount); + outBitStream.Write(m_ImmuneToImaginationGainCount); + outBitStream.Write(m_ImmuneToImaginationLossCount); + outBitStream.Write(m_ImmuneToQuickbuildInterruptCount); + outBitStream.Write(m_ImmuneToPullToPointCount); } - outBitStream->Write(m_DirtyHealth || bIsInitialUpdate); + outBitStream.Write(m_DirtyHealth || bIsInitialUpdate); if (m_DirtyHealth || bIsInitialUpdate) { - outBitStream->Write(m_iHealth); - outBitStream->Write(m_fMaxHealth); - outBitStream->Write(m_iArmor); - outBitStream->Write(m_fMaxArmor); - outBitStream->Write(m_iImagination); - outBitStream->Write(m_fMaxImagination); - - outBitStream->Write(m_DamageToAbsorb); - outBitStream->Write(IsImmune()); - outBitStream->Write(m_IsGMImmune); - outBitStream->Write(m_IsShielded); - - outBitStream->Write(m_fMaxHealth); - outBitStream->Write(m_fMaxArmor); - outBitStream->Write(m_fMaxImagination); - - outBitStream->Write(m_FactionIDs.size()); + outBitStream.Write(m_iHealth); + outBitStream.Write(m_fMaxHealth); + outBitStream.Write(m_iArmor); + outBitStream.Write(m_fMaxArmor); + outBitStream.Write(m_iImagination); + outBitStream.Write(m_fMaxImagination); + + outBitStream.Write(m_DamageToAbsorb); + outBitStream.Write(IsImmune()); + outBitStream.Write(m_IsGMImmune); + outBitStream.Write(m_IsShielded); + + outBitStream.Write(m_fMaxHealth); + outBitStream.Write(m_fMaxArmor); + outBitStream.Write(m_fMaxImagination); + + outBitStream.Write(m_FactionIDs.size()); for (size_t i = 0; i < m_FactionIDs.size(); ++i) { - outBitStream->Write(m_FactionIDs[i]); + outBitStream.Write(m_FactionIDs[i]); } - outBitStream->Write(m_IsSmashable); + outBitStream.Write(m_IsSmashable); if (bIsInitialUpdate) { - outBitStream->Write(m_IsDead); - outBitStream->Write(m_IsSmashed); + outBitStream.Write(m_IsDead); + outBitStream.Write(m_IsSmashed); if (m_IsSmashable) { - outBitStream->Write(m_IsModuleAssembly); - outBitStream->Write(m_ExplodeFactor != 1.0f); - if (m_ExplodeFactor != 1.0f) outBitStream->Write(m_ExplodeFactor); + outBitStream.Write(m_IsModuleAssembly); + outBitStream.Write(m_ExplodeFactor != 1.0f); + if (m_ExplodeFactor != 1.0f) outBitStream.Write(m_ExplodeFactor); } } m_DirtyHealth = false; } - outBitStream->Write(m_DirtyThreatList || bIsInitialUpdate); + outBitStream.Write(m_DirtyThreatList || bIsInitialUpdate); if (m_DirtyThreatList || bIsInitialUpdate) { - outBitStream->Write(m_HasThreats); + outBitStream.Write(m_HasThreats); m_DirtyThreatList = false; } } @@ -185,8 +185,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 +207,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 +389,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; @@ -785,16 +785,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 1f45b43ef..56f301031 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -25,9 +25,9 @@ class DestroyableComponent final : public Component { ~DestroyableComponent() override; 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 Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; + void LoadFromXml(const tinyxml2::XMLDocument& doc) override; + void UpdateXml(tinyxml2::XMLDocument& doc) override; /** * Initializes the component using a different LOT diff --git a/dGame/dComponents/DonationVendorComponent.cpp b/dGame/dComponents/DonationVendorComponent.cpp index 6abc959ac..7fb06a904 100644 --- a/dGame/dComponents/DonationVendorComponent.cpp +++ b/dGame/dComponents/DonationVendorComponent.cpp @@ -36,13 +36,13 @@ void DonationVendorComponent::SubmitDonation(uint32_t count) { m_DirtyDonationVendor = true; } -void DonationVendorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void DonationVendorComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { VendorComponent::Serialize(outBitStream, bIsInitialUpdate); - outBitStream->Write(bIsInitialUpdate || m_DirtyDonationVendor); + outBitStream.Write(bIsInitialUpdate || m_DirtyDonationVendor); if (bIsInitialUpdate || m_DirtyDonationVendor) { - outBitStream->Write(m_PercentComplete); - outBitStream->Write(m_TotalDonated); - outBitStream->Write(m_TotalRemaining); + outBitStream.Write(m_PercentComplete); + outBitStream.Write(m_TotalDonated); + outBitStream.Write(m_TotalRemaining); if (!bIsInitialUpdate) m_DirtyDonationVendor = false; } } diff --git a/dGame/dComponents/DonationVendorComponent.h b/dGame/dComponents/DonationVendorComponent.h index 7eb608498..af1eb8290 100644 --- a/dGame/dComponents/DonationVendorComponent.h +++ b/dGame/dComponents/DonationVendorComponent.h @@ -10,7 +10,7 @@ class DonationVendorComponent final : public VendorComponent { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::DONATION_VENDOR; DonationVendorComponent(Entity* parent); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; uint32_t GetActivityID() {return m_ActivityId;}; void SubmitDonation(uint32_t count); diff --git a/dGame/dComponents/HavokVehiclePhysicsComponent.cpp b/dGame/dComponents/HavokVehiclePhysicsComponent.cpp index 8c8e14fe9..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,85 +35,66 @@ 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) { - outBitStream->Write(bIsInitialUpdate || m_DirtyPosition); +void HavokVehiclePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(bIsInitialUpdate || m_DirtyPosition); if (bIsInitialUpdate || m_DirtyPosition) { m_DirtyPosition = false; - outBitStream->Write(m_Position.x); - outBitStream->Write(m_Position.y); - outBitStream->Write(m_Position.z); - - outBitStream->Write(m_Rotation.x); - outBitStream->Write(m_Rotation.y); - outBitStream->Write(m_Rotation.z); - outBitStream->Write(m_Rotation.w); - - outBitStream->Write(m_IsOnGround); - outBitStream->Write(m_IsOnRail); - - outBitStream->Write(bIsInitialUpdate || m_DirtyVelocity); - - if (bIsInitialUpdate || m_DirtyVelocity) { - outBitStream->Write(m_Velocity.x); - outBitStream->Write(m_Velocity.y); - outBitStream->Write(m_Velocity.z); - m_DirtyVelocity = false; + outBitStream.Write(m_Position.x); + outBitStream.Write(m_Position.y); + outBitStream.Write(m_Position.z); + + outBitStream.Write(m_Rotation.x); + outBitStream.Write(m_Rotation.y); + outBitStream.Write(m_Rotation.z); + outBitStream.Write(m_Rotation.w); + + outBitStream.Write(m_IsOnGround); + outBitStream.Write(m_IsOnRail); + + 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(bIsInitialUpdate || m_DirtyAngularVelocity); - - if (bIsInitialUpdate || m_DirtyAngularVelocity) { - outBitStream->Write(m_AngularVelocity.x); - outBitStream->Write(m_AngularVelocity.y); - outBitStream->Write(m_AngularVelocity.z); - m_DirtyAngularVelocity = false; + 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(); // local_space_info. TODO: Implement this + outBitStream.Write0(); // local_space_info. TODO: Implement this + + // 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(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; - } - 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. + 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. if (!bIsInitialUpdate) { - outBitStream->Write0(); + outBitStream.Write0(); } } if (bIsInitialUpdate) { - outBitStream->Write(m_EndBehavior); - outBitStream->Write1(); // is input locked? + outBitStream.Write(m_EndBehavior); + outBitStream.Write1(); // is input locked? } - outBitStream->Write0(); -} - -void HavokVehiclePhysicsComponent::Update(float deltaTime) { - if (m_SoftUpdate > 5) { - Game::entityManager->SerializeEntity(m_Parent); - m_SoftUpdate = 0; - } else { - m_SoftUpdate += deltaTime; - } + outBitStream.Write0(); } diff --git a/dGame/dComponents/HavokVehiclePhysicsComponent.h b/dGame/dComponents/HavokVehiclePhysicsComponent.h index 85a0e2790..83eb82fe6 100644 --- a/dGame/dComponents/HavokVehiclePhysicsComponent.h +++ b/dGame/dComponents/HavokVehiclePhysicsComponent.h @@ -15,9 +15,7 @@ class HavokVehiclePhysicsComponent : public PhysicsComponent { HavokVehiclePhysicsComponent(Entity* parentEntity); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; - - void Update(float deltaTime) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Sets the 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 591e05059..172877b00 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -38,7 +38,7 @@ #include "CDObjectSkillsTable.h" #include "CDSkillBehaviorTable.h" -InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) { +InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) { this->m_Dirty = true; this->m_Equipped = {}; this->m_Pushed = {}; @@ -48,7 +48,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 +473,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!"); @@ -557,19 +558,9 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) { itemElement->QueryAttribute("parent", &parent); // End custom xml - std::vector config; + auto* item = new Item(id, lot, inventory, slot, count, bound, {}, parent, subKey); - 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); - } - - 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 +585,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 +622,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())); @@ -654,14 +645,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 +666,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); } @@ -694,11 +675,11 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) { } } -void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool bIsInitialUpdate) { +void InventoryComponent::Serialize(RakNet::BitStream& outBitStream, const bool bIsInitialUpdate) { if (bIsInitialUpdate || m_Dirty) { - outBitStream->Write(true); + outBitStream.Write(true); - outBitStream->Write(m_Equipped.size()); + outBitStream.Write(m_Equipped.size()); for (const auto& pair : m_Equipped) { const auto item = pair.second; @@ -707,21 +688,21 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b AddItemSkills(item.lot); } - outBitStream->Write(item.id); - outBitStream->Write(item.lot); + outBitStream.Write(item.id); + outBitStream.Write(item.lot); - outBitStream->Write0(); + outBitStream.Write0(); - outBitStream->Write(item.count > 0); - if (item.count > 0) outBitStream->Write(item.count); + outBitStream.Write(item.count > 0); + if (item.count > 0) outBitStream.Write(item.count); - outBitStream->Write(item.slot != 0); - if (item.slot != 0) outBitStream->Write(item.slot); + outBitStream.Write(item.slot != 0); + if (item.slot != 0) outBitStream.Write(item.slot); - outBitStream->Write0(); + outBitStream.Write0(); bool flag = !item.config.empty(); - outBitStream->Write(flag); + outBitStream.Write(flag); if (flag) { RakNet::BitStream ldfStream; ldfStream.Write(item.config.size()); // Key count @@ -730,26 +711,26 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b std::string newRocketStr = data->GetValueAsString() + ";"; GeneralUtils::ReplaceInString(newRocketStr, "+", ";"); LDFData* ldf_data = new LDFData(u"assemblyPartLOTs", GeneralUtils::ASCIIToUTF16(newRocketStr)); - ldf_data->WriteToPacket(&ldfStream); + ldf_data->WriteToPacket(ldfStream); delete ldf_data; } else { - data->WriteToPacket(&ldfStream); + data->WriteToPacket(ldfStream); } } - outBitStream->Write(ldfStream.GetNumberOfBytesUsed() + 1); - outBitStream->Write(0); // Don't compress - outBitStream->Write(ldfStream); + outBitStream.Write(ldfStream.GetNumberOfBytesUsed() + 1); + outBitStream.Write(0); // Don't compress + outBitStream.Write(ldfStream); } - outBitStream->Write1(); + outBitStream.Write1(); } m_Dirty = false; } else { - outBitStream->Write(false); + outBitStream.Write(false); } - outBitStream->Write(false); + outBitStream.Write(false); } void InventoryComponent::Update(float deltaTime) { @@ -894,8 +875,6 @@ void InventoryComponent::UnEquipItem(Item* item) { RemoveSlot(item->GetInfo().equipLocation); - PurgeProxies(item); - UnequipScripts(item); Game::entityManager->SerializeEntity(m_Parent); @@ -905,6 +884,8 @@ void InventoryComponent::UnEquipItem(Item* item) { PropertyManagementComponent::Instance()->GetParent()->OnZonePropertyModelRemovedWhileEquipped(m_Parent); Game::zoneManager->GetZoneControlObject()->OnZonePropertyModelRemovedWhileEquipped(m_Parent); } + + PurgeProxies(item); } @@ -1093,7 +1074,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 +1505,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 +1523,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 +1555,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 +1580,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()) { @@ -1622,4 +1603,3 @@ bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){ m_Skills.insert_or_assign(slot, skillId); return true; } - diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index e47e6a593..a1eb14d18 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -38,12 +38,12 @@ enum class eItemType : int32_t; class InventoryComponent final : public Component { public: 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 Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; + void LoadXml(const tinyxml2::XMLDocument& document); + void UpdateXml(tinyxml2::XMLDocument& document) override; /** * Returns an inventory of the specified type, if it exists @@ -470,13 +470,13 @@ 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); }; #endif diff --git a/dGame/dComponents/ItemComponent.cpp b/dGame/dComponents/ItemComponent.cpp index dc413b172..799cd935d 100644 --- a/dGame/dComponents/ItemComponent.cpp +++ b/dGame/dComponents/ItemComponent.cpp @@ -1,5 +1,5 @@ #include "ItemComponent.h" -void ItemComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) { - outBitStream->Write0(); +void ItemComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) { + outBitStream.Write0(); } diff --git a/dGame/dComponents/ItemComponent.h b/dGame/dComponents/ItemComponent.h index 875ef0a57..1a02ad117 100644 --- a/dGame/dComponents/ItemComponent.h +++ b/dGame/dComponents/ItemComponent.h @@ -10,7 +10,7 @@ class ItemComponent final : public Component { ItemComponent(Entity* entity) : Component(entity) {} - void Serialize(RakNet::BitStream* bitStream, bool isConstruction) override; + void Serialize(RakNet::BitStream& bitStream, bool isConstruction) override; }; #endif //!__ITEMCOMPONENT__H__ diff --git a/dGame/dComponents/LUPExhibitComponent.cpp b/dGame/dComponents/LUPExhibitComponent.cpp index a312617d3..00a8cf034 100644 --- a/dGame/dComponents/LUPExhibitComponent.cpp +++ b/dGame/dComponents/LUPExhibitComponent.cpp @@ -15,10 +15,10 @@ void LUPExhibitComponent::NextLUPExhibit() { Game::entityManager->SerializeEntity(m_Parent); } -void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(m_DirtyLUPExhibit); +void LUPExhibitComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(m_DirtyLUPExhibit); if (m_DirtyLUPExhibit) { - outBitStream->Write(m_LUPExhibits[m_LUPExhibitIndex % m_LUPExhibits.size()]); + outBitStream.Write(m_LUPExhibits[m_LUPExhibitIndex % m_LUPExhibits.size()]); if (!bIsInitialUpdate) m_DirtyLUPExhibit = false; } } diff --git a/dGame/dComponents/LUPExhibitComponent.h b/dGame/dComponents/LUPExhibitComponent.h index e66538686..8fd6d7ee3 100644 --- a/dGame/dComponents/LUPExhibitComponent.h +++ b/dGame/dComponents/LUPExhibitComponent.h @@ -18,7 +18,7 @@ class LUPExhibitComponent final : public Component LUPExhibitComponent(Entity* parent) : Component(parent) {}; void Update(float deltaTime) override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void NextLUPExhibit(); private: float m_UpdateTimer = 0.0f; diff --git a/dGame/dComponents/LevelProgressionComponent.cpp b/dGame/dComponents/LevelProgressionComponent.cpp index d271f97b3..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; @@ -37,9 +37,9 @@ void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) { m_CharacterVersion = static_cast(characterVersion); } -void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(bIsInitialUpdate || m_DirtyLevelInfo); - if (bIsInitialUpdate || m_DirtyLevelInfo) outBitStream->Write(m_Level); +void LevelProgressionComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(bIsInitialUpdate || m_DirtyLevelInfo); + if (bIsInitialUpdate || m_DirtyLevelInfo) outBitStream.Write(m_Level); m_DirtyLevelInfo = false; } diff --git a/dGame/dComponents/LevelProgressionComponent.h b/dGame/dComponents/LevelProgressionComponent.h index 6083738c5..e9981ab6a 100644 --- a/dGame/dComponents/LevelProgressionComponent.h +++ b/dGame/dComponents/LevelProgressionComponent.h @@ -21,19 +21,19 @@ class LevelProgressionComponent final : public Component { */ LevelProgressionComponent(Entity* parent); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * 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/MiniGameControlComponent.cpp b/dGame/dComponents/MiniGameControlComponent.cpp index fdd56a2cc..088ee3540 100644 --- a/dGame/dComponents/MiniGameControlComponent.cpp +++ b/dGame/dComponents/MiniGameControlComponent.cpp @@ -1,5 +1,5 @@ #include "MiniGameControlComponent.h" -void MiniGameControlComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) { - outBitStream->Write(0x40000000); +void MiniGameControlComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) { + outBitStream.Write(0x40000000); } diff --git a/dGame/dComponents/MiniGameControlComponent.h b/dGame/dComponents/MiniGameControlComponent.h index e2581b2d2..2cd9ac6a7 100644 --- a/dGame/dComponents/MiniGameControlComponent.h +++ b/dGame/dComponents/MiniGameControlComponent.h @@ -9,7 +9,7 @@ class MiniGameControlComponent final : public Component { static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::MINI_GAME_CONTROL; MiniGameControlComponent(Entity* parent) : Component(parent) {} - void Serialize(RakNet::BitStream* outBitStream, bool isConstruction); + void Serialize(RakNet::BitStream& outBitStream, bool isConstruction); }; #endif //!__MINIGAMECONTROLCOMPONENT__H__ diff --git a/dGame/dComponents/MinigameComponent.cpp b/dGame/dComponents/MinigameComponent.cpp index 6bcb985e0..2174cd8a2 100644 --- a/dGame/dComponents/MinigameComponent.cpp +++ b/dGame/dComponents/MinigameComponent.cpp @@ -1,5 +1,5 @@ #include "MinigameComponent.h" -void MinigameComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) { - outBitStream->Write(0x40000000); +void MinigameComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) { + outBitStream.Write(0x40000000); } 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 42c4df086..a01794f01 100644 --- a/dGame/dComponents/MissionComponent.h +++ b/dGame/dComponents/MissionComponent.h @@ -30,9 +30,9 @@ 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 Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate, unsigned int& flags); + 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 3f8858c04..916809872 100644 --- a/dGame/dComponents/ModelComponent.cpp +++ b/dGame/dComponents/ModelComponent.cpp @@ -6,6 +6,9 @@ #include "BehaviorStates.h" #include "ControlBehaviorMsgs.h" +#include "tinyxml2.h" + +#include "Database.h" ModelComponent::ModelComponent(Entity* parent) : Component(parent) { m_OriginalPosition = m_Parent->GetDefaultPosition(); @@ -14,26 +17,53 @@ ModelComponent::ModelComponent(Entity* parent) : Component(parent) { m_userModelID = m_Parent->GetVarAs(u"userModelID"); } -void ModelComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +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)) { - outBitStream->Write1(); - outBitStream->Write(m_userModelID != LWOOBJID_EMPTY ? m_userModelID : m_Parent->GetObjectID()); - outBitStream->Write(0); - outBitStream->Write0(); + outBitStream.Write1(); + outBitStream.Write(m_userModelID != LWOOBJID_EMPTY ? m_userModelID : m_Parent->GetObjectID()); + outBitStream.Write(0); + outBitStream.Write0(); } //actual model component: - outBitStream->Write1(); // Yes we are writing model info - outBitStream->Write0(); // Is pickable - outBitStream->Write(2); // Physics type - outBitStream->Write(m_OriginalPosition); // Original position - outBitStream->Write(m_OriginalRotation); // Original rotation - - outBitStream->Write1(); // We are writing behavior info - outBitStream->Write(0); // Number of behaviors - outBitStream->Write1(); // Is this model paused - if (bIsInitialUpdate) outBitStream->Write0(); // We are not writing model editing info + outBitStream.Write1(); // Yes we are writing model info + outBitStream.Write0(); // Is pickable + outBitStream.Write(2); // Physics type + outBitStream.Write(m_OriginalPosition); // Original position + outBitStream.Write(m_OriginalRotation); // Original rotation + + outBitStream.Write1(); // We are writing behavior info + outBitStream.Write(0); // Number of behaviors + outBitStream.Write1(); // Is this model paused + if (bIsInitialUpdate) outBitStream.Write0(); // We are not writing model editing info } void ModelComponent::UpdatePendingBehaviorId(const int32_t newId) { @@ -72,3 +102,23 @@ void ModelComponent::MoveToInventory(MoveToInventoryMessage& msg) { m_Behaviors.erase(m_Behaviors.begin() + msg.GetBehaviorIndex()); // TODO move to the inventory } + +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 0d720d04e..9e23eafb0 100644 --- a/dGame/dComponents/ModelComponent.h +++ b/dGame/dComponents/ModelComponent.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include "dCommonVars.h" @@ -28,7 +29,9 @@ class ModelComponent final : public Component { ModelComponent(Entity* parent); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void LoadBehaviors(); + + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Returns the original position of the model @@ -61,7 +64,7 @@ class ModelComponent final : public Component { * @param args the arguments of the message to be deserialized */ template - void HandleControlBehaviorsMsg(AMFArrayValue* args) { + void HandleControlBehaviorsMsg(const AMFArrayValue& args) { static_assert(std::is_base_of_v, "Msg must be a BehaviorMessageBase"); Msg msg(args); for (auto& behavior : m_Behaviors) { @@ -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/ModuleAssemblyComponent.cpp b/dGame/dComponents/ModuleAssemblyComponent.cpp index 5b7042dff..e217d9b72 100644 --- a/dGame/dComponents/ModuleAssemblyComponent.cpp +++ b/dGame/dComponents/ModuleAssemblyComponent.cpp @@ -46,20 +46,20 @@ const std::u16string& ModuleAssemblyComponent::GetAssemblyPartsLOTs() const { return m_AssemblyPartsLOTs; } -void ModuleAssemblyComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void ModuleAssemblyComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { if (bIsInitialUpdate) { - outBitStream->Write1(); + outBitStream.Write1(); - outBitStream->Write(m_SubKey != LWOOBJID_EMPTY); + outBitStream.Write(m_SubKey != LWOOBJID_EMPTY); if (m_SubKey != LWOOBJID_EMPTY) { - outBitStream->Write(m_SubKey); + outBitStream.Write(m_SubKey); } - outBitStream->Write(m_UseOptionalParts); + outBitStream.Write(m_UseOptionalParts); - outBitStream->Write(m_AssemblyPartsLOTs.size()); + outBitStream.Write(m_AssemblyPartsLOTs.size()); for (char16_t character : m_AssemblyPartsLOTs) { - outBitStream->Write(character); + outBitStream.Write(character); } } } diff --git a/dGame/dComponents/ModuleAssemblyComponent.h b/dGame/dComponents/ModuleAssemblyComponent.h index 47e7baa6e..7e050ec7c 100644 --- a/dGame/dComponents/ModuleAssemblyComponent.h +++ b/dGame/dComponents/ModuleAssemblyComponent.h @@ -17,7 +17,7 @@ class ModuleAssemblyComponent final : public Component { ModuleAssemblyComponent(Entity* parent); ~ModuleAssemblyComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void Update(float deltaTime) override; /** 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 366bebd39..77acbb8d2 100644 --- a/dGame/dComponents/MovingPlatformComponent.cpp +++ b/dGame/dComponents/MovingPlatformComponent.cpp @@ -32,25 +32,25 @@ MoverSubComponent::MoverSubComponent(const NiPoint3& startPos) { MoverSubComponent::~MoverSubComponent() = default; -void MoverSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(true); +void MoverSubComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(true); - outBitStream->Write(mState); - outBitStream->Write(mDesiredWaypointIndex); - outBitStream->Write(mShouldStopAtDesiredWaypoint); - outBitStream->Write(mInReverse); + outBitStream.Write(mState); + outBitStream.Write(mDesiredWaypointIndex); + outBitStream.Write(mShouldStopAtDesiredWaypoint); + outBitStream.Write(mInReverse); - outBitStream->Write(mPercentBetweenPoints); + outBitStream.Write(mPercentBetweenPoints); - outBitStream->Write(mPosition.x); - outBitStream->Write(mPosition.y); - outBitStream->Write(mPosition.z); + outBitStream.Write(mPosition.x); + outBitStream.Write(mPosition.y); + outBitStream.Write(mPosition.z); - outBitStream->Write(mCurrentWaypointIndex); - outBitStream->Write(mNextWaypointIndex); + outBitStream.Write(mCurrentWaypointIndex); + outBitStream.Write(mNextWaypointIndex); - outBitStream->Write(mIdleTimeElapsed); - outBitStream->Write(0.0f); // Move time elapsed + outBitStream.Write(mIdleTimeElapsed); + outBitStream.Write(0.0f); // Move time elapsed } //------------- MovingPlatformComponent below -------------- @@ -71,43 +71,43 @@ MovingPlatformComponent::~MovingPlatformComponent() { delete static_cast(m_MoverSubComponent); } -void MovingPlatformComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void MovingPlatformComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { // Here we don't serialize the moving platform to let the client simulate the movement if (!m_Serialize) { - outBitStream->Write(false); - outBitStream->Write(false); + outBitStream.Write(false); + outBitStream.Write(false); return; } - outBitStream->Write(true); + outBitStream.Write(true); auto hasPath = !m_PathingStopped && !m_PathName.empty(); - outBitStream->Write(hasPath); + outBitStream.Write(hasPath); if (hasPath) { // Is on rail - outBitStream->Write1(); + outBitStream.Write1(); - outBitStream->Write(m_PathName.size()); + outBitStream.Write(m_PathName.size()); for (const auto& c : m_PathName) { - outBitStream->Write(c); + outBitStream.Write(c); } // Starting point - outBitStream->Write(0); + outBitStream.Write(0); // Reverse - outBitStream->Write(false); + outBitStream.Write(false); } const auto hasPlatform = m_MoverSubComponent != nullptr; - outBitStream->Write(hasPlatform); + outBitStream.Write(hasPlatform); if (hasPlatform) { auto* mover = static_cast(m_MoverSubComponent); - outBitStream->Write(m_MoverSubComponentType); + outBitStream.Write(m_MoverSubComponentType); if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) { // TODO @@ -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/MovingPlatformComponent.h b/dGame/dComponents/MovingPlatformComponent.h index cf47b9c32..c4fbf3088 100644 --- a/dGame/dComponents/MovingPlatformComponent.h +++ b/dGame/dComponents/MovingPlatformComponent.h @@ -38,7 +38,7 @@ class MoverSubComponent { MoverSubComponent(const NiPoint3& startPos); ~MoverSubComponent(); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate); + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate); /** * The state the platform is currently in @@ -111,7 +111,7 @@ class MovingPlatformComponent final : public Component { MovingPlatformComponent(Entity* parent, const std::string& pathName); ~MovingPlatformComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Stops all pathing, called when an entity starts a quick build associated with this platform diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 1af65b4e5..073c09e17 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 @@ -87,7 +89,6 @@ PetComponent::PetComponent(Entity* parentEntity, uint32_t componentId) : Compone m_StartPosition = NiPoint3Constant::ZERO; m_MovementAI = nullptr; m_TresureTime = 0; - m_Preconditions = nullptr; std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parentEntity->GetVar(u"CheckPrecondition")); @@ -96,42 +97,42 @@ PetComponent::PetComponent(Entity* parentEntity, uint32_t componentId) : Compone } } -void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void PetComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { const bool tamed = m_Owner != LWOOBJID_EMPTY; - outBitStream->Write1(); // Always serialize as dirty for now + outBitStream.Write1(); // Always serialize as dirty for now - outBitStream->Write(m_Status); - outBitStream->Write(tamed ? m_Ability : ePetAbilityType::Invalid); // Something with the overhead icon? + outBitStream.Write(m_Status); + outBitStream.Write(tamed ? m_Ability : ePetAbilityType::Invalid); // Something with the overhead icon? const bool interacting = m_Interaction != LWOOBJID_EMPTY; - outBitStream->Write(interacting); + outBitStream.Write(interacting); if (interacting) { - outBitStream->Write(m_Interaction); + outBitStream.Write(m_Interaction); } - outBitStream->Write(tamed); + outBitStream.Write(tamed); if (tamed) { - outBitStream->Write(m_Owner); + outBitStream.Write(m_Owner); } if (bIsInitialUpdate) { - outBitStream->Write(tamed); + outBitStream.Write(tamed); if (tamed) { - outBitStream->Write(m_ModerationStatus); + outBitStream.Write(m_ModerationStatus); const auto nameData = GeneralUtils::UTF8ToUTF16(m_Name); const auto ownerNameData = GeneralUtils::UTF8ToUTF16(m_OwnerName); - outBitStream->Write(nameData.size()); + outBitStream.Write(nameData.size()); for (const auto c : nameData) { - outBitStream->Write(c); + outBitStream.Write(c); } - outBitStream->Write(ownerNameData.size()); + outBitStream.Write(ownerNameData.size()); for (const auto c : ownerNameData) { - outBitStream->Write(c); + outBitStream.Write(c); } } } @@ -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); } } @@ -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() { @@ -1094,6 +1058,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 6d13bea9d..323330d2e 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -21,7 +21,7 @@ class PetComponent final : public Component explicit PetComponent(Entity* parentEntity, uint32_t componentId); ~PetComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void Update(float deltaTime) override; /** @@ -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 @@ -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 @@ -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 592c2a6b1..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,93 +105,30 @@ 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) { +void PhantomPhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate); - outBitStream->Write(m_EffectInfoDirty || bIsInitialUpdate); + outBitStream.Write(m_EffectInfoDirty || bIsInitialUpdate); if (m_EffectInfoDirty || bIsInitialUpdate) { - outBitStream->Write(m_IsPhysicsEffectActive); + outBitStream.Write(m_IsPhysicsEffectActive); if (m_IsPhysicsEffectActive) { - outBitStream->Write(m_EffectType); - outBitStream->Write(m_DirectionalMultiplier); + outBitStream.Write(m_EffectType); + outBitStream.Write(m_DirectionalMultiplier); // forgive me father for i have sinned - outBitStream->Write0(); - //outBitStream->Write(m_MinMax); + outBitStream.Write0(); + //outBitStream.Write(m_MinMax); //if (m_MinMax) { - //outBitStream->Write(m_Min); - //outBitStream->Write(m_Max); + //outBitStream.Write(m_Min); + //outBitStream.Write(m_Max); //} - outBitStream->Write(m_IsDirectional); + outBitStream.Write(m_IsDirectional); if (m_IsDirectional) { - outBitStream->Write(m_Direction.x); - outBitStream->Write(m_Direction.y); - outBitStream->Write(m_Direction.z); + outBitStream.Write(m_Direction.x); + outBitStream.Write(m_Direction.y); + outBitStream.Write(m_Direction.z); } } @@ -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 2ea9e9794..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 @@ -32,12 +33,7 @@ class PhantomPhysicsComponent final : public PhysicsComponent { PhantomPhysicsComponent(Entity* parent); ~PhantomPhysicsComponent() override; 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(); + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Sets the direction this physics object is pointed at @@ -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 ea57735fc..4a250a6a9 100644 --- a/dGame/dComponents/PhysicsComponent.cpp +++ b/dGame/dComponents/PhysicsComponent.cpp @@ -1,21 +1,222 @@ #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; m_DirtyPosition = false; } -void PhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(bIsInitialUpdate || m_DirtyPosition); +void PhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(bIsInitialUpdate || m_DirtyPosition); if (bIsInitialUpdate || m_DirtyPosition) { - outBitStream->Write(m_Position.x); - outBitStream->Write(m_Position.y); - outBitStream->Write(m_Position.z); - outBitStream->Write(m_Rotation.x); - outBitStream->Write(m_Rotation.y); - outBitStream->Write(m_Rotation.z); - outBitStream->Write(m_Rotation.w); + outBitStream.Write(m_Position.x); + outBitStream.Write(m_Position.y); + outBitStream.Write(m_Position.z); + outBitStream.Write(m_Rotation.x); + outBitStream.Write(m_Rotation.y); + outBitStream.Write(m_Rotation.z); + outBitStream.Write(m_Rotation.w); 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 c1a7f34a9..4bf0828a0 100644 --- a/dGame/dComponents/PhysicsComponent.h +++ b/dGame/dComponents/PhysicsComponent.h @@ -9,12 +9,16 @@ namespace Raknet { class BitStream; }; +enum class eReplicaComponentType : uint32_t; + +class dpEntity; + class PhysicsComponent : public Component { public: PhysicsComponent(Entity* parent); virtual ~PhysicsComponent() = default; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; const NiPoint3& GetPosition() const { return m_Position; } virtual void SetPosition(const NiPoint3& pos) { if (m_Position == pos) return; m_Position = pos; m_DirtyPosition = true; } @@ -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/PlayerForcedMovementComponent.cpp b/dGame/dComponents/PlayerForcedMovementComponent.cpp index d511ad782..0aea882c7 100644 --- a/dGame/dComponents/PlayerForcedMovementComponent.cpp +++ b/dGame/dComponents/PlayerForcedMovementComponent.cpp @@ -6,11 +6,11 @@ PlayerForcedMovementComponent::PlayerForcedMovementComponent(Entity* parent) : C PlayerForcedMovementComponent::~PlayerForcedMovementComponent() {} -void PlayerForcedMovementComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(m_DirtyInfo || bIsInitialUpdate); +void PlayerForcedMovementComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(m_DirtyInfo || bIsInitialUpdate); if (m_DirtyInfo || bIsInitialUpdate) { - outBitStream->Write(m_PlayerOnRail); - outBitStream->Write(m_ShowBillboard); + outBitStream.Write(m_PlayerOnRail); + outBitStream.Write(m_ShowBillboard); } m_DirtyInfo = false; } diff --git a/dGame/dComponents/PlayerForcedMovementComponent.h b/dGame/dComponents/PlayerForcedMovementComponent.h index e5aca37dd..f184ede2c 100644 --- a/dGame/dComponents/PlayerForcedMovementComponent.h +++ b/dGame/dComponents/PlayerForcedMovementComponent.h @@ -19,7 +19,7 @@ class PlayerForcedMovementComponent final : public Component { PlayerForcedMovementComponent(Entity* parent); ~PlayerForcedMovementComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * @brief Set the Player On Rail object diff --git a/dGame/dComponents/PossessableComponent.cpp b/dGame/dComponents/PossessableComponent.cpp index 509b1a07c..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; @@ -27,17 +27,17 @@ PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId) result.finalize(); } -void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(m_DirtyPossessable || bIsInitialUpdate); +void PossessableComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(m_DirtyPossessable || bIsInitialUpdate); if (m_DirtyPossessable || bIsInitialUpdate) { m_DirtyPossessable = false; // reset flag - outBitStream->Write(m_Possessor != LWOOBJID_EMPTY); - if (m_Possessor != LWOOBJID_EMPTY) outBitStream->Write(m_Possessor); + outBitStream.Write(m_Possessor != LWOOBJID_EMPTY); + if (m_Possessor != LWOOBJID_EMPTY) outBitStream.Write(m_Possessor); - outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_NONE); - if (m_AnimationFlag != eAnimationFlags::IDLE_NONE) outBitStream->Write(m_AnimationFlag); + outBitStream.Write(m_AnimationFlag != eAnimationFlags::IDLE_NONE); + if (m_AnimationFlag != eAnimationFlags::IDLE_NONE) outBitStream.Write(m_AnimationFlag); - outBitStream->Write(m_ImmediatelyDepossess); + outBitStream.Write(m_ImmediatelyDepossess); m_ImmediatelyDepossess = false; // reset flag } } diff --git a/dGame/dComponents/PossessableComponent.h b/dGame/dComponents/PossessableComponent.h index 3b075d33a..6f1968a5d 100644 --- a/dGame/dComponents/PossessableComponent.h +++ b/dGame/dComponents/PossessableComponent.h @@ -18,7 +18,7 @@ class PossessableComponent final : public Component { PossessableComponent(Entity* parentEntity, uint32_t componentId); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * @brief mounts the Entity diff --git a/dGame/dComponents/PossessorComponent.cpp b/dGame/dComponents/PossessorComponent.cpp index 0cb649564..46ccbffbc 100644 --- a/dGame/dComponents/PossessorComponent.cpp +++ b/dGame/dComponents/PossessorComponent.cpp @@ -26,15 +26,15 @@ PossessorComponent::~PossessorComponent() { } } -void PossessorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(m_DirtyPossesor || bIsInitialUpdate); +void PossessorComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(m_DirtyPossesor || bIsInitialUpdate); if (m_DirtyPossesor || bIsInitialUpdate) { m_DirtyPossesor = false; - outBitStream->Write(m_Possessable != LWOOBJID_EMPTY); + outBitStream.Write(m_Possessable != LWOOBJID_EMPTY); if (m_Possessable != LWOOBJID_EMPTY) { - outBitStream->Write(m_Possessable); + outBitStream.Write(m_Possessable); } - outBitStream->Write(m_PossessableType); + outBitStream.Write(m_PossessableType); } } diff --git a/dGame/dComponents/PossessorComponent.h b/dGame/dComponents/PossessorComponent.h index e1aba0486..3fa6153dc 100644 --- a/dGame/dComponents/PossessorComponent.h +++ b/dGame/dComponents/PossessorComponent.h @@ -23,7 +23,7 @@ class PossessorComponent final : public Component { PossessorComponent(Entity* parent); ~PossessorComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * @brief Mounts the entity 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 6cef87d38..e3aed82db 100644 --- a/dGame/dComponents/QuickBuildComponent.cpp +++ b/dGame/dComponents/QuickBuildComponent.cpp @@ -55,55 +55,55 @@ QuickBuildComponent::~QuickBuildComponent() { DespawnActivator(); } -void QuickBuildComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void QuickBuildComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { if (m_Parent->GetComponent(eReplicaComponentType::DESTROYABLE) == nullptr) { if (bIsInitialUpdate) { - outBitStream->Write(false); + outBitStream.Write(false); } - outBitStream->Write(false); + outBitStream.Write(false); - outBitStream->Write(false); + outBitStream.Write(false); } // If build state is completed and we've already serialized once in the completed state, // don't serializing this component anymore as this will cause the build to jump again. // If state changes, serialization will begin again. if (!m_StateDirty && m_State == eQuickBuildState::COMPLETED) { - outBitStream->Write0(); - outBitStream->Write0(); + outBitStream.Write0(); + outBitStream.Write0(); return; } // BEGIN Scripted Activity - outBitStream->Write1(); + outBitStream.Write1(); Entity* builder = GetBuilder(); if (builder) { - outBitStream->Write(1); - outBitStream->Write(builder->GetObjectID()); + outBitStream.Write(1); + outBitStream.Write(builder->GetObjectID()); for (int i = 0; i < 10; i++) { - outBitStream->Write(0.0f); + outBitStream.Write(0.0f); } } else { - outBitStream->Write(0); + outBitStream.Write(0); } // END Scripted Activity - outBitStream->Write1(); + outBitStream.Write1(); - outBitStream->Write(m_State); + outBitStream.Write(m_State); - outBitStream->Write(m_ShowResetEffect); - outBitStream->Write(m_Activator != nullptr); + outBitStream.Write(m_ShowResetEffect); + outBitStream.Write(m_Activator != nullptr); - outBitStream->Write(m_Timer); - outBitStream->Write(m_TimerIncomplete); + outBitStream.Write(m_Timer); + outBitStream.Write(m_TimerIncomplete); if (bIsInitialUpdate) { - outBitStream->Write(false); - outBitStream->Write(m_ActivatorPosition); - outBitStream->Write(m_RepositionPlayer); + outBitStream.Write(false); + outBitStream.Write(m_ActivatorPosition); + outBitStream.Write(m_RepositionPlayer); } m_StateDirty = false; } @@ -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/QuickBuildComponent.h b/dGame/dComponents/QuickBuildComponent.h index 556264a8d..1cab86609 100644 --- a/dGame/dComponents/QuickBuildComponent.h +++ b/dGame/dComponents/QuickBuildComponent.h @@ -27,7 +27,7 @@ class QuickBuildComponent final : public Component { QuickBuildComponent(Entity* const entity); ~QuickBuildComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void Update(float deltaTime) override; /** diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index f3772aad6..b896d3f2a 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 @@ -77,6 +78,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()); @@ -433,83 +437,83 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t bu } } -void RacingControlComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void RacingControlComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { // BEGIN Scripted Activity - outBitStream->Write1(); + outBitStream.Write1(); - outBitStream->Write(m_RacingPlayers.size()); + outBitStream.Write(m_RacingPlayers.size()); for (const auto& player : m_RacingPlayers) { - outBitStream->Write(player.playerID); - - outBitStream->Write(player.data[0]); - if (player.finished != 0) outBitStream->Write(player.raceTime); - else outBitStream->Write(player.data[1]); - if (player.finished != 0) outBitStream->Write(player.bestLapTime); - else outBitStream->Write(player.data[2]); - if (player.finished == 1) outBitStream->Write(1.0f); - else outBitStream->Write(player.data[3]); - outBitStream->Write(player.data[4]); - outBitStream->Write(player.data[5]); - outBitStream->Write(player.data[6]); - outBitStream->Write(player.data[7]); - outBitStream->Write(player.data[8]); - outBitStream->Write(player.data[9]); + outBitStream.Write(player.playerID); + + outBitStream.Write(player.data[0]); + if (player.finished != 0) outBitStream.Write(player.raceTime); + else outBitStream.Write(player.data[1]); + if (player.finished != 0) outBitStream.Write(player.bestLapTime); + else outBitStream.Write(player.data[2]); + if (player.finished == 1) outBitStream.Write(1.0f); + else outBitStream.Write(player.data[3]); + outBitStream.Write(player.data[4]); + outBitStream.Write(player.data[5]); + outBitStream.Write(player.data[6]); + outBitStream.Write(player.data[7]); + outBitStream.Write(player.data[8]); + outBitStream.Write(player.data[9]); } // END Scripted Activity - outBitStream->Write1(); - outBitStream->Write(m_RacingPlayers.size()); + outBitStream.Write1(); + outBitStream.Write(m_RacingPlayers.size()); - outBitStream->Write(!m_AllPlayersReady); + outBitStream.Write(!m_AllPlayersReady); if (!m_AllPlayersReady) { int32_t numReady = 0; for (const auto& player : m_RacingPlayers) { - outBitStream->Write1(); // Has more player data - outBitStream->Write(player.playerID); - outBitStream->Write(player.vehicleID); - outBitStream->Write(player.playerIndex); - outBitStream->Write(player.playerLoaded); + outBitStream.Write1(); // Has more player data + outBitStream.Write(player.playerID); + outBitStream.Write(player.vehicleID); + outBitStream.Write(player.playerIndex); + outBitStream.Write(player.playerLoaded); if (player.playerLoaded) numReady++; } - outBitStream->Write0(); // No more data + outBitStream.Write0(); // No more data if (numReady == m_RacingPlayers.size()) m_AllPlayersReady = true; } - outBitStream->Write(!m_RacingPlayers.empty()); + outBitStream.Write(!m_RacingPlayers.empty()); if (!m_RacingPlayers.empty()) { for (const auto& player : m_RacingPlayers) { if (player.finished == 0) continue; - outBitStream->Write1(); // Has more date + outBitStream.Write1(); // Has more date - outBitStream->Write(player.playerID); - outBitStream->Write(player.finished); + outBitStream.Write(player.playerID); + outBitStream.Write(player.finished); } - outBitStream->Write0(); // No more data + outBitStream.Write0(); // No more data } - outBitStream->Write(bIsInitialUpdate); + outBitStream.Write(bIsInitialUpdate); if (bIsInitialUpdate) { - outBitStream->Write(m_RemainingLaps); - outBitStream->Write(m_PathName.size()); + outBitStream.Write(m_RemainingLaps); + outBitStream.Write(m_PathName.size()); for (const auto character : m_PathName) { - outBitStream->Write(character); + outBitStream.Write(character); } } - outBitStream->Write(!m_RacingPlayers.empty()); + outBitStream.Write(!m_RacingPlayers.empty()); if (!m_RacingPlayers.empty()) { for (const auto& player : m_RacingPlayers) { if (player.finished == 0) continue; - outBitStream->Write1(); // Has more data - outBitStream->Write(player.playerID); - outBitStream->Write(player.bestLapTime); - outBitStream->Write(player.raceTime); + outBitStream.Write1(); // Has more data + outBitStream.Write(player.playerID); + outBitStream.Write(player.bestLapTime); + outBitStream.Write(player.raceTime); } - outBitStream->Write0(); // No more data + outBitStream.Write0(); // No more data } } @@ -817,8 +821,10 @@ 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 diff --git a/dGame/dComponents/RacingControlComponent.h b/dGame/dComponents/RacingControlComponent.h index 4a7d387ff..790459e31 100644 --- a/dGame/dComponents/RacingControlComponent.h +++ b/dGame/dComponents/RacingControlComponent.h @@ -110,7 +110,7 @@ class RacingControlComponent final : public Component { RacingControlComponent(Entity* parentEntity); ~RacingControlComponent(); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void Update(float deltaTime) override; /** diff --git a/dGame/dComponents/RenderComponent.cpp b/dGame/dComponents/RenderComponent.cpp index 118e48478..cc5974a1e 100644 --- a/dGame/dComponents/RenderComponent.cpp +++ b/dGame/dComponents/RenderComponent.cpp @@ -45,25 +45,25 @@ RenderComponent::RenderComponent(Entity* const parentEntity, const int32_t compo result.finalize(); } -void RenderComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void RenderComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { if (!bIsInitialUpdate) return; - outBitStream->Write(m_Effects.size()); + outBitStream.Write(m_Effects.size()); for (auto& eff : m_Effects) { - outBitStream->Write(eff.name.size()); + outBitStream.Write(eff.name.size()); // if there is no name, then we don't write anything else if (eff.name.empty()) continue; - for (const auto& value : eff.name) outBitStream->Write(value); + for (const auto& value : eff.name) outBitStream.Write(value); - outBitStream->Write(eff.effectID); + outBitStream.Write(eff.effectID); - outBitStream->Write(eff.type.size()); - for (const auto& value : eff.type) outBitStream->Write(value); + outBitStream.Write(eff.type.size()); + for (const auto& value : eff.type) outBitStream.Write(value); - outBitStream->Write(eff.priority); - outBitStream->Write(eff.secondary); + outBitStream.Write(eff.priority); + outBitStream.Write(eff.secondary); } } @@ -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/RenderComponent.h b/dGame/dComponents/RenderComponent.h index 87b210d76..e2bbcff54 100644 --- a/dGame/dComponents/RenderComponent.h +++ b/dGame/dComponents/RenderComponent.h @@ -65,7 +65,7 @@ class RenderComponent final : public Component { RenderComponent(Entity* const parentEntity, const int32_t componentId = -1); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void Update(float deltaTime) override; /** diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp index 414ce2e83..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) { +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 082dd1e7f..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 Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + 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 5a3855465..c0c90581b 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.cpp +++ b/dGame/dComponents/RocketLaunchpadControlComponent.cpp @@ -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(); @@ -139,7 +139,7 @@ void RocketLaunchpadControlComponent::TellMasterToPrepZone(int zoneID) { CBITSTREAM; BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PREP_ZONE); bitStream.Write(zoneID); - Game::server->SendToMaster(&bitStream); + Game::server->SendToMaster(bitStream); } diff --git a/dScripts/ScriptComponent.cpp b/dGame/dComponents/ScriptComponent.cpp similarity index 78% rename from dScripts/ScriptComponent.cpp rename to dGame/dComponents/ScriptComponent.cpp index 7c44ded37..d6bff5b52 100644 --- a/dScripts/ScriptComponent.cpp +++ b/dGame/dComponents/ScriptComponent.cpp @@ -17,11 +17,11 @@ ScriptComponent::~ScriptComponent() { } -void ScriptComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void ScriptComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { if (bIsInitialUpdate) { const auto& networkSettings = m_Parent->GetNetworkSettings(); auto hasNetworkSettings = !networkSettings.empty(); - outBitStream->Write(hasNetworkSettings); + outBitStream.Write(hasNetworkSettings); if (hasNetworkSettings) { @@ -31,17 +31,17 @@ void ScriptComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitial ldfData.Write(networkSettings.size()); for (auto* networkSetting : networkSettings) { - networkSetting->WriteToPacket(&ldfData); + networkSetting->WriteToPacket(ldfData); } // Finally write everything to the stream - outBitStream->Write(ldfData.GetNumberOfBytesUsed()); - outBitStream->Write(ldfData); + outBitStream.Write(ldfData.GetNumberOfBytesUsed()); + outBitStream.Write(ldfData); } } } -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 93% rename from dScripts/ScriptComponent.h rename to dGame/dComponents/ScriptComponent.h index a28c94195..adc7cc8b0 100644 --- a/dScripts/ScriptComponent.h +++ b/dGame/dComponents/ScriptComponent.h @@ -24,13 +24,13 @@ class ScriptComponent final : public Component { ScriptComponent(Entity* parent, std::string scriptName, bool serialized, bool client = false); ~ScriptComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * 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/ShootingGalleryComponent.cpp b/dGame/dComponents/ShootingGalleryComponent.cpp index 45cd93427..20665a018 100644 --- a/dGame/dComponents/ShootingGalleryComponent.cpp +++ b/dGame/dComponents/ShootingGalleryComponent.cpp @@ -17,50 +17,50 @@ void ShootingGalleryComponent::SetDynamicParams(const DynamicShootingGalleryPara Game::entityManager->SerializeEntity(m_Parent); } -void ShootingGalleryComponent::Serialize(RakNet::BitStream* outBitStream, bool isInitialUpdate) { +void ShootingGalleryComponent::Serialize(RakNet::BitStream& outBitStream, bool isInitialUpdate) { // Start ScriptedActivityComponent - outBitStream->Write(true); + outBitStream.Write(true); if (m_CurrentPlayerID == LWOOBJID_EMPTY) { - outBitStream->Write(0); + outBitStream.Write(0); } else { - outBitStream->Write(1); - outBitStream->Write(m_CurrentPlayerID); + outBitStream.Write(1); + outBitStream.Write(m_CurrentPlayerID); for (size_t i = 0; i < 10; i++) { - outBitStream->Write(0.0f); + outBitStream.Write(0.0f); } } // End ScriptedActivityComponent if (isInitialUpdate) { - outBitStream->Write(m_StaticParams.cameraPosition.GetX()); - outBitStream->Write(m_StaticParams.cameraPosition.GetY()); - outBitStream->Write(m_StaticParams.cameraPosition.GetZ()); + outBitStream.Write(m_StaticParams.cameraPosition.GetX()); + outBitStream.Write(m_StaticParams.cameraPosition.GetY()); + outBitStream.Write(m_StaticParams.cameraPosition.GetZ()); - outBitStream->Write(m_StaticParams.cameraLookatPosition.GetX()); - outBitStream->Write(m_StaticParams.cameraLookatPosition.GetY()); - outBitStream->Write(m_StaticParams.cameraLookatPosition.GetZ()); + outBitStream.Write(m_StaticParams.cameraLookatPosition.GetX()); + outBitStream.Write(m_StaticParams.cameraLookatPosition.GetY()); + outBitStream.Write(m_StaticParams.cameraLookatPosition.GetZ()); } - outBitStream->Write(m_Dirty || isInitialUpdate); + outBitStream.Write(m_Dirty || isInitialUpdate); if (m_Dirty || isInitialUpdate) { - outBitStream->Write(m_DynamicParams.cannonVelocity); - outBitStream->Write(m_DynamicParams.cannonRefireRate); - outBitStream->Write(m_DynamicParams.cannonMinDistance); + outBitStream.Write(m_DynamicParams.cannonVelocity); + outBitStream.Write(m_DynamicParams.cannonRefireRate); + outBitStream.Write(m_DynamicParams.cannonMinDistance); - outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetX()); - outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetY()); - outBitStream->Write(m_DynamicParams.cameraBarrelOffset.GetZ()); + outBitStream.Write(m_DynamicParams.cameraBarrelOffset.GetX()); + outBitStream.Write(m_DynamicParams.cameraBarrelOffset.GetY()); + outBitStream.Write(m_DynamicParams.cameraBarrelOffset.GetZ()); - outBitStream->Write(m_DynamicParams.cannonAngle); + outBitStream.Write(m_DynamicParams.cannonAngle); - outBitStream->Write(m_DynamicParams.facing.GetX()); - outBitStream->Write(m_DynamicParams.facing.GetY()); - outBitStream->Write(m_DynamicParams.facing.GetZ()); + outBitStream.Write(m_DynamicParams.facing.GetX()); + outBitStream.Write(m_DynamicParams.facing.GetY()); + outBitStream.Write(m_DynamicParams.facing.GetZ()); - outBitStream->Write(m_CurrentPlayerID); - outBitStream->Write(m_DynamicParams.cannonTimeout); - outBitStream->Write(m_DynamicParams.cannonFOV); + outBitStream.Write(m_CurrentPlayerID); + outBitStream.Write(m_DynamicParams.cannonTimeout); + outBitStream.Write(m_DynamicParams.cannonFOV); if (!isInitialUpdate) m_Dirty = false; } } diff --git a/dGame/dComponents/ShootingGalleryComponent.h b/dGame/dComponents/ShootingGalleryComponent.h index c4b8fea26..9382d87ea 100644 --- a/dGame/dComponents/ShootingGalleryComponent.h +++ b/dGame/dComponents/ShootingGalleryComponent.h @@ -77,7 +77,7 @@ class ShootingGalleryComponent final : public Component { explicit ShootingGalleryComponent(Entity* parent); ~ShootingGalleryComponent(); - void Serialize(RakNet::BitStream* outBitStream, bool isInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool isInitialUpdate) override; /** * Returns the static params for the shooting gallery diff --git a/dGame/dComponents/SimplePhysicsComponent.cpp b/dGame/dComponents/SimplePhysicsComponent.cpp index 3d8165dd5..3b52395e9 100644 --- a/dGame/dComponents/SimplePhysicsComponent.cpp +++ b/dGame/dComponents/SimplePhysicsComponent.cpp @@ -32,26 +32,26 @@ SimplePhysicsComponent::SimplePhysicsComponent(Entity* parent, uint32_t componen SimplePhysicsComponent::~SimplePhysicsComponent() { } -void SimplePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { +void SimplePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { if (bIsInitialUpdate) { - outBitStream->Write(m_ClimbableType != eClimbableType::CLIMBABLE_TYPE_NOT); - outBitStream->Write(m_ClimbableType); + outBitStream.Write(m_ClimbableType != eClimbableType::CLIMBABLE_TYPE_NOT); + outBitStream.Write(m_ClimbableType); } - outBitStream->Write(m_DirtyVelocity || bIsInitialUpdate); + outBitStream.Write(m_DirtyVelocity || bIsInitialUpdate); if (m_DirtyVelocity || bIsInitialUpdate) { - outBitStream->Write(m_Velocity); - outBitStream->Write(m_AngularVelocity); + outBitStream.Write(m_Velocity); + outBitStream.Write(m_AngularVelocity); m_DirtyVelocity = false; } // Physics motion state if (m_PhysicsMotionState != 0) { - outBitStream->Write1(); - outBitStream->Write(m_PhysicsMotionState); + outBitStream.Write1(); + outBitStream.Write(m_PhysicsMotionState); } else { - outBitStream->Write0(); + outBitStream.Write0(); } PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate); } diff --git a/dGame/dComponents/SimplePhysicsComponent.h b/dGame/dComponents/SimplePhysicsComponent.h index 8f92dd95c..c6ef52a00 100644 --- a/dGame/dComponents/SimplePhysicsComponent.h +++ b/dGame/dComponents/SimplePhysicsComponent.h @@ -33,7 +33,7 @@ class SimplePhysicsComponent : public PhysicsComponent { SimplePhysicsComponent(Entity* parent, uint32_t componentID); ~SimplePhysicsComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Returns the velocity of this entity diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index c43813c1d..58b13dc55 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -31,14 +31,14 @@ ProjectileSyncEntry::ProjectileSyncEntry() { std::unordered_map SkillComponent::m_skillBehaviorCache = {}; -bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t skillUid, RakNet::BitStream* bitStream, const LWOOBJID target, uint32_t skillID) { +bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t skillUid, RakNet::BitStream& bitStream, const LWOOBJID target, uint32_t skillID) { auto* context = new BehaviorContext(this->m_Parent->GetObjectID()); context->caster = m_Parent->GetObjectID(); context->skillID = skillID; - this->m_managedBehaviors.insert_or_assign(skillUid, context); + this->m_managedBehaviors.insert({ skillUid, context }); auto* behavior = Behavior::CreateBehavior(behaviorId); @@ -51,22 +51,29 @@ bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t s return !context->failed; } -void SkillComponent::SyncPlayerSkill(const uint32_t skillUid, const uint32_t syncId, RakNet::BitStream* bitStream) { - const auto index = this->m_managedBehaviors.find(skillUid); +void SkillComponent::SyncPlayerSkill(const uint32_t skillUid, const uint32_t syncId, RakNet::BitStream& bitStream) { + 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); + } } -void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::BitStream* bitStream, const LWOOBJID target) { +void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::BitStream& bitStream, const LWOOBJID target) { auto index = -1; for (auto i = 0u; i < this->m_managedProjectiles.size(); ++i) { @@ -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,12 +254,20 @@ 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) { - auto* bitStream = new RakNet::BitStream(); +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,25 +283,22 @@ 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 bitStream; delete context; // Invalid attack 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; @@ -297,24 +309,26 @@ 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()); + start.sBitStream.assign(reinterpret_cast(bitStream.GetData()), bitStream.GetNumberOfBytesUsed()); // Write message RakNet::BitStream message; BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); message.Write(this->m_Parent->GetObjectID()); - start.Serialize(&message); + start.Serialize(message); - Game::server->Send(&message, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::server->Send(message, UNASSIGNED_SYSTEM_ADDRESS, true); } context->ExecuteUpdates(); - delete bitStream; - // Valid attack return { true, context->skillTime }; } @@ -418,19 +432,19 @@ 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(); auto* behavior = Behavior::CreateBehavior(behaviorId); - auto* bitStream = new RakNet::BitStream(); + RakNet::BitStream bitStream{}; behavior->Calculate(entry.context, bitStream, entry.branchContext); DoClientProjectileImpact projectileImpact; - projectileImpact.sBitStream.assign(reinterpret_cast(bitStream->GetData()), bitStream->GetNumberOfBytesUsed()); + projectileImpact.sBitStream.assign(reinterpret_cast(bitStream.GetData()), bitStream.GetNumberOfBytesUsed()); projectileImpact.i64OwnerID = this->m_Parent->GetObjectID(); projectileImpact.i64OrgID = entry.id; projectileImpact.i64TargetID = entry.branchContext.target; @@ -439,45 +453,37 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); message.Write(this->m_Parent->GetObjectID()); - projectileImpact.Serialize(&message); + projectileImpact.Serialize(message); - Game::server->Send(&message, UNASSIGNED_SYSTEM_ADDRESS, true); + Game::server->Send(message, UNASSIGNED_SYSTEM_ADDRESS, true); entry.context->ExecuteUpdates(); - - delete bitStream; } void SkillComponent::HandleUnmanaged(const uint32_t behaviorId, const LWOOBJID target, LWOOBJID source) { - auto* context = new BehaviorContext(source); + BehaviorContext context{ source }; - context->unmanaged = true; - context->caster = target; + context.unmanaged = true; + context.caster = target; auto* behavior = Behavior::CreateBehavior(behaviorId); - auto* bitStream = new RakNet::BitStream(); - - behavior->Handle(context, bitStream, { target }); + RakNet::BitStream bitStream{}; - delete bitStream; - - delete context; + behavior->Handle(&context, bitStream, { target }); } void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID target) { - auto* context = new BehaviorContext(target); + BehaviorContext context{ target }; - context->caster = target; + context.caster = target; auto* behavior = Behavior::CreateBehavior(behaviorId); - behavior->UnCast(context, { target }); - - delete context; + behavior->UnCast(&context, { target }); } -SkillComponent::SkillComponent(Entity* parent): Component(parent) { +SkillComponent::SkillComponent(Entity* parent) : Component(parent) { this->m_skillUid = 0; } @@ -485,8 +491,8 @@ SkillComponent::~SkillComponent() { Reset(); } -void SkillComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - if (bIsInitialUpdate) outBitStream->Write0(); +void SkillComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + if (bIsInitialUpdate) outBitStream.Write0(); } /// diff --git a/dGame/dComponents/SkillComponent.h b/dGame/dComponents/SkillComponent.h index 530c2a25a..f74b4411a 100644 --- a/dGame/dComponents/SkillComponent.h +++ b/dGame/dComponents/SkillComponent.h @@ -64,7 +64,7 @@ class SkillComponent final : public Component { explicit SkillComponent(Entity* parent); ~SkillComponent() override; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Computes skill updates. Invokes CalculateUpdate. @@ -93,7 +93,7 @@ class SkillComponent final : public Component { * @param bitStream the bitSteam given by the client to determine the behavior path * @param target the explicit target of the skill */ - bool CastPlayerSkill(uint32_t behaviorId, uint32_t skillUid, RakNet::BitStream* bitStream, LWOOBJID target, uint32_t skillID = 0); + bool CastPlayerSkill(uint32_t behaviorId, uint32_t skillUid, RakNet::BitStream& bitStream, LWOOBJID target, uint32_t skillID = 0); /** * Continues a player skill. Should only be called when the server receives a sync message from the client. @@ -101,7 +101,7 @@ class SkillComponent final : public Component { * @param syncId the unique sync ID of the skill given by the client * @param bitStream the bitSteam given by the client to determine the behavior path */ - void SyncPlayerSkill(uint32_t skillUid, uint32_t syncId, RakNet::BitStream* bitStream); + void SyncPlayerSkill(uint32_t skillUid, uint32_t syncId, RakNet::BitStream& bitStream); /** * Continues a player projectile calculation. Should only be called when the server receives a projectile sync message from the client. @@ -109,7 +109,7 @@ class SkillComponent final : public Component { * @param bitStream the bitSteam given by the client to determine the behavior path * @param target the explicit target of the target */ - void SyncPlayerProjectile(LWOOBJID projectileId, RakNet::BitStream* bitStream, LWOOBJID target); + void SyncPlayerProjectile(LWOOBJID projectileId, RakNet::BitStream& bitStream, LWOOBJID target); /** * Registers a player projectile. Should only be called when the server is computing a player projectile. @@ -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/SoundTriggerComponent.cpp b/dGame/dComponents/SoundTriggerComponent.cpp index 34d2441ca..878ce8480 100644 --- a/dGame/dComponents/SoundTriggerComponent.cpp +++ b/dGame/dComponents/SoundTriggerComponent.cpp @@ -2,28 +2,28 @@ #include "Game.h" #include "Logger.h" -void MusicCue::Serialize(RakNet::BitStream* outBitStream){ - outBitStream->Write(name.size()); - outBitStream->Write(name.c_str(), name.size()); - outBitStream->Write(result); - outBitStream->Write(boredomTime); +void MusicCue::Serialize(RakNet::BitStream& outBitStream){ + outBitStream.Write(name.size()); + outBitStream.Write(name.c_str(), name.size()); + outBitStream.Write(result); + outBitStream.Write(boredomTime); } -void MusicParameter::Serialize(RakNet::BitStream* outBitStream){ - outBitStream->Write(name.size()); - outBitStream->Write(name.c_str(), name.size()); - outBitStream->Write(value); +void MusicParameter::Serialize(RakNet::BitStream& outBitStream){ + outBitStream.Write(name.size()); + outBitStream.Write(name.c_str(), name.size()); + outBitStream.Write(value); } -void GUIDResults::Serialize(RakNet::BitStream* outBitStream){ +void GUIDResults::Serialize(RakNet::BitStream& outBitStream){ guid.Serialize(outBitStream); - outBitStream->Write(result); + outBitStream.Write(result); } -void MixerProgram::Serialize(RakNet::BitStream* outBitStream){ - outBitStream->Write(name.size()); - outBitStream->Write(name.c_str(), name.size()); - outBitStream->Write(result); +void MixerProgram::Serialize(RakNet::BitStream& outBitStream){ + outBitStream.Write(name.size()); + outBitStream.Write(name.c_str(), name.size()); + outBitStream.Write(result); } SoundTriggerComponent::SoundTriggerComponent(Entity* parent) : Component(parent) { @@ -55,30 +55,30 @@ SoundTriggerComponent::SoundTriggerComponent(Entity* parent) : Component(parent) if (!mixerName.empty()) this->m_MixerPrograms.push_back(MixerProgram(mixerName)); } -void SoundTriggerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(this->m_Dirty || bIsInitialUpdate); +void SoundTriggerComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(this->m_Dirty || bIsInitialUpdate); if (this->m_Dirty || bIsInitialUpdate) { - outBitStream->Write(this->m_MusicCues.size()); + outBitStream.Write(this->m_MusicCues.size()); for (auto& musicCue : this->m_MusicCues) { musicCue.Serialize(outBitStream); } - outBitStream->Write(this->m_MusicParameters.size()); + outBitStream.Write(this->m_MusicParameters.size()); for (auto& musicParam : this->m_MusicParameters) { musicParam.Serialize(outBitStream); } - outBitStream->Write(this->m_2DAmbientSounds.size()); + outBitStream.Write(this->m_2DAmbientSounds.size()); for (auto twoDAmbientSound : this->m_2DAmbientSounds) { twoDAmbientSound.Serialize(outBitStream); } - outBitStream->Write(this->m_3DAmbientSounds.size()); + outBitStream.Write(this->m_3DAmbientSounds.size()); for (auto threeDAmbientSound : this->m_3DAmbientSounds) { threeDAmbientSound.Serialize(outBitStream); } - outBitStream->Write(this->m_MixerPrograms.size()); + outBitStream.Write(this->m_MixerPrograms.size()); for (auto& mixerProgram : this->m_MixerPrograms) { mixerProgram.Serialize(outBitStream); } diff --git a/dGame/dComponents/SoundTriggerComponent.h b/dGame/dComponents/SoundTriggerComponent.h index 48366017c..2851aff13 100644 --- a/dGame/dComponents/SoundTriggerComponent.h +++ b/dGame/dComponents/SoundTriggerComponent.h @@ -17,7 +17,7 @@ struct MusicCue { this->boredomTime = boredomTime; }; - void Serialize(RakNet::BitStream* outBitStream); + void Serialize(RakNet::BitStream& outBitStream); }; struct MusicParameter { @@ -29,7 +29,7 @@ struct MusicParameter { this->value = value; } - void Serialize(RakNet::BitStream* outBitStream); + void Serialize(RakNet::BitStream& outBitStream); }; struct GUIDResults{ @@ -41,7 +41,7 @@ struct GUIDResults{ this->result = result; } - void Serialize(RakNet::BitStream* outBitStream); + void Serialize(RakNet::BitStream& outBitStream); }; struct MixerProgram { @@ -53,7 +53,7 @@ struct MixerProgram { this->result = result; } - void Serialize(RakNet::BitStream* outBitStream); + void Serialize(RakNet::BitStream& outBitStream); }; @@ -61,7 +61,7 @@ class SoundTriggerComponent : public Component { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::SOUND_TRIGGER; explicit SoundTriggerComponent(Entity* parent); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void ActivateMusicCue(const std::string& name, float bordemTime = -1.0); void DeactivateMusicCue(const std::string& name); diff --git a/dGame/dComponents/SwitchComponent.cpp b/dGame/dComponents/SwitchComponent.cpp index 25f18a4df..e6ad6d001 100644 --- a/dGame/dComponents/SwitchComponent.cpp +++ b/dGame/dComponents/SwitchComponent.cpp @@ -21,8 +21,8 @@ SwitchComponent::~SwitchComponent() { } } -void SwitchComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(m_Active); +void SwitchComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(m_Active); } void SwitchComponent::SetActive(bool active) { diff --git a/dGame/dComponents/SwitchComponent.h b/dGame/dComponents/SwitchComponent.h index f732a8c19..862e57191 100644 --- a/dGame/dComponents/SwitchComponent.h +++ b/dGame/dComponents/SwitchComponent.h @@ -25,7 +25,7 @@ class SwitchComponent final : public Component { Entity* GetParentEntity() const; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; /** * Sets whether the switch is on or off. 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 afa3d0132..b9286d256 100644 --- a/dGame/dComponents/VendorComponent.cpp +++ b/dGame/dComponents/VendorComponent.cpp @@ -8,6 +8,11 @@ #include "CDLootMatrixTable.h" #include "CDLootTableTable.h" #include "CDItemComponentTable.h" +#include "InventoryComponent.h" +#include "Character.h" +#include "eVendorTransactionResult.h" +#include "UserManager.h" +#include "CheatDetection.h" VendorComponent::VendorComponent(Entity* parent) : Component(parent) { m_HasStandardCostItems = false; @@ -16,11 +21,11 @@ VendorComponent::VendorComponent(Entity* parent) : Component(parent) { RefreshInventory(true); } -void VendorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { - outBitStream->Write(bIsInitialUpdate || m_DirtyVendor); +void VendorComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { + outBitStream.Write(bIsInitialUpdate || m_DirtyVendor); if (bIsInitialUpdate || m_DirtyVendor) { - outBitStream->Write(m_HasStandardCostItems); - outBitStream->Write(m_HasMultiCostItems); + outBitStream.Write(m_HasStandardCostItems); + outBitStream.Write(m_HasMultiCostItems); if (!bIsInitialUpdate) m_DirtyVendor = false; } } @@ -35,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; } @@ -47,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); @@ -73,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)); } } } @@ -121,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); @@ -151,3 +135,80 @@ void VendorComponent::HandleMrReeCameras(){ m_Inventory.push_back(SoldItem(camera, 0)); } } + + +void VendorComponent::Buy(Entity* buyer, LOT lot, uint32_t count) { + + if (!SellsItem(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()); + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); + return; + } + + auto* inventoryComponent = buyer->GetComponent(); + if (!inventoryComponent) { + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); + return; + } + CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); + CDItemComponentTable* itemComponentTable = CDClientManager::GetTable(); + int itemCompID = compRegistryTable->GetByIDAndType(lot, eReplicaComponentType::ITEM); + CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); + + // Extra currency that needs to be deducted in case of crafting + auto craftingCurrencies = CDItemComponentTable::ParseCraftingCurrencies(itemComp); + for (const auto& [crafintCurrencyLOT, crafintCurrencyCount]: craftingCurrencies) { + if (inventoryComponent->GetLotCount(crafintCurrencyLOT) < (crafintCurrencyCount * count)) { + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); + return; + } + } + for (const auto& [crafintCurrencyLOT, crafintCurrencyCount]: craftingCurrencies) { + inventoryComponent->RemoveItem(crafintCurrencyLOT, crafintCurrencyCount * count); + } + + + float buyScalar = GetBuyScalar(); + const auto coinCost = static_cast(std::floor((itemComp.baseValue * buyScalar) * count)); + + Character* character = buyer->GetCharacter(); + if (!character || character->GetCoins() < coinCost) { + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); + return; + } + + if (Inventory::IsValidItem(itemComp.currencyLOT)) { + const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * buyScalar) * count; + if (inventoryComponent->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) { + GameMessages::SendVendorTransactionResult(buyer, buyer->GetSystemAddress(), eVendorTransactionResult::PURCHASE_FAIL); + return; + } + inventoryComponent->RemoveItem(itemComp.currencyLOT, altCurrencyCost); + } + + 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; +} + diff --git a/dGame/dComponents/VendorComponent.h b/dGame/dComponents/VendorComponent.h index 48b766d2f..432f18014 100644 --- a/dGame/dComponents/VendorComponent.h +++ b/dGame/dComponents/VendorComponent.h @@ -23,10 +23,10 @@ class VendorComponent : public Component { static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::VENDOR; VendorComponent(Entity* parent); - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override; + 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; } @@ -47,10 +47,11 @@ class VendorComponent : public Component { m_DirtyVendor = true; } + 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 6b381aa5d..b8e3b5286 100644 --- a/dGame/dGameMessages/DoClientProjectileImpact.h +++ b/dGame/dGameMessages/DoClientProjectileImpact.h @@ -19,51 +19,51 @@ class DoClientProjectileImpact { sBitStream = _sBitStream; } - DoClientProjectileImpact(RakNet::BitStream* stream) : DoClientProjectileImpact() { + DoClientProjectileImpact(RakNet::BitStream& stream) : DoClientProjectileImpact() { Deserialize(stream); } ~DoClientProjectileImpact() { } - void Serialize(RakNet::BitStream* stream) { - stream->Write(eGameMessageType::DO_CLIENT_PROJECTILE_IMPACT); + void Serialize(RakNet::BitStream& stream) { + stream.Write(eGameMessageType::DO_CLIENT_PROJECTILE_IMPACT); - stream->Write(i64OrgID != LWOOBJID_EMPTY); - if (i64OrgID != LWOOBJID_EMPTY) stream->Write(i64OrgID); + stream.Write(i64OrgID != LWOOBJID_EMPTY); + if (i64OrgID != LWOOBJID_EMPTY) stream.Write(i64OrgID); - stream->Write(i64OwnerID != LWOOBJID_EMPTY); - if (i64OwnerID != LWOOBJID_EMPTY) stream->Write(i64OwnerID); + stream.Write(i64OwnerID != LWOOBJID_EMPTY); + if (i64OwnerID != LWOOBJID_EMPTY) stream.Write(i64OwnerID); - stream->Write(i64TargetID != LWOOBJID_EMPTY); - if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); + stream.Write(i64TargetID != LWOOBJID_EMPTY); + if (i64TargetID != LWOOBJID_EMPTY) stream.Write(i64TargetID); uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); + stream.Write(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); + stream.Write(sBitStream[k]); } } - bool Deserialize(RakNet::BitStream* stream) { + bool Deserialize(RakNet::BitStream& stream) { bool i64OrgIDIsDefault{}; - stream->Read(i64OrgIDIsDefault); - if (i64OrgIDIsDefault != 0) stream->Read(i64OrgID); + stream.Read(i64OrgIDIsDefault); + if (i64OrgIDIsDefault != 0) stream.Read(i64OrgID); bool i64OwnerIDIsDefault{}; - stream->Read(i64OwnerIDIsDefault); - if (i64OwnerIDIsDefault != 0) stream->Read(i64OwnerID); + stream.Read(i64OwnerIDIsDefault); + if (i64OwnerIDIsDefault != 0) stream.Read(i64OwnerID); bool i64TargetIDIsDefault{}; - stream->Read(i64TargetIDIsDefault); - if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); + stream.Read(i64TargetIDIsDefault); + if (i64TargetIDIsDefault != 0) stream.Read(i64TargetID); uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); + stream.Read(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { unsigned char character; - stream->Read(character); + stream.Read(character); sBitStream.push_back(character); } diff --git a/dGame/dGameMessages/EchoStartSkill.h b/dGame/dGameMessages/EchoStartSkill.h index 389a81e0e..dfb79021c 100644 --- a/dGame/dGameMessages/EchoStartSkill.h +++ b/dGame/dGameMessages/EchoStartSkill.h @@ -32,85 +32,85 @@ class EchoStartSkill { uiSkillHandle = _uiSkillHandle; } - EchoStartSkill(RakNet::BitStream* stream) : EchoStartSkill() { + EchoStartSkill(RakNet::BitStream& stream) : EchoStartSkill() { Deserialize(stream); } ~EchoStartSkill() { } - void Serialize(RakNet::BitStream* stream) { - stream->Write(eGameMessageType::ECHO_START_SKILL); + void Serialize(RakNet::BitStream& stream) { + stream.Write(eGameMessageType::ECHO_START_SKILL); - stream->Write(bUsedMouse); + stream.Write(bUsedMouse); - stream->Write(fCasterLatency != 0.0f); - if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); + stream.Write(fCasterLatency != 0.0f); + if (fCasterLatency != 0.0f) stream.Write(fCasterLatency); - stream->Write(iCastType != 0); - if (iCastType != 0) stream->Write(iCastType); + stream.Write(iCastType != 0); + if (iCastType != 0) stream.Write(iCastType); - stream->Write(lastClickedPosit != NiPoint3Constant::ZERO); - if (lastClickedPosit != NiPoint3Constant::ZERO) stream->Write(lastClickedPosit); + stream.Write(lastClickedPosit != NiPoint3Constant::ZERO); + if (lastClickedPosit != NiPoint3Constant::ZERO) stream.Write(lastClickedPosit); - stream->Write(optionalOriginatorID); + stream.Write(optionalOriginatorID); - stream->Write(optionalTargetID != LWOOBJID_EMPTY); - if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); + stream.Write(optionalTargetID != LWOOBJID_EMPTY); + if (optionalTargetID != LWOOBJID_EMPTY) stream.Write(optionalTargetID); - stream->Write(originatorRot != NiQuaternionConstant::IDENTITY); - if (originatorRot != NiQuaternionConstant::IDENTITY) stream->Write(originatorRot); + stream.Write(originatorRot != NiQuaternionConstant::IDENTITY); + if (originatorRot != NiQuaternionConstant::IDENTITY) stream.Write(originatorRot); uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); + stream.Write(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); + stream.Write(sBitStream[k]); } - stream->Write(skillID); + stream.Write(skillID); - stream->Write(uiSkillHandle != 0); - if (uiSkillHandle != 0) stream->Write(uiSkillHandle); + stream.Write(uiSkillHandle != 0); + if (uiSkillHandle != 0) stream.Write(uiSkillHandle); } - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bUsedMouse); + bool Deserialize(RakNet::BitStream& stream) { + stream.Read(bUsedMouse); bool fCasterLatencyIsDefault{}; - stream->Read(fCasterLatencyIsDefault); - if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); + stream.Read(fCasterLatencyIsDefault); + if (fCasterLatencyIsDefault != 0) stream.Read(fCasterLatency); bool iCastTypeIsDefault{}; - stream->Read(iCastTypeIsDefault); - if (iCastTypeIsDefault != 0) stream->Read(iCastType); + stream.Read(iCastTypeIsDefault); + if (iCastTypeIsDefault != 0) stream.Read(iCastType); bool lastClickedPositIsDefault{}; - stream->Read(lastClickedPositIsDefault); - if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); + stream.Read(lastClickedPositIsDefault); + if (lastClickedPositIsDefault != 0) stream.Read(lastClickedPosit); - stream->Read(optionalOriginatorID); + stream.Read(optionalOriginatorID); bool optionalTargetIDIsDefault{}; - stream->Read(optionalTargetIDIsDefault); - if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); + stream.Read(optionalTargetIDIsDefault); + if (optionalTargetIDIsDefault != 0) stream.Read(optionalTargetID); bool originatorRotIsDefault{}; - stream->Read(originatorRotIsDefault); - if (originatorRotIsDefault != 0) stream->Read(originatorRot); + stream.Read(originatorRotIsDefault); + if (originatorRotIsDefault != 0) stream.Read(originatorRot); uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); + stream.Read(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { unsigned char character; - stream->Read(character); + stream.Read(character); sBitStream.push_back(character); } - stream->Read(skillID); + stream.Read(skillID); bool uiSkillHandleIsDefault{}; - stream->Read(uiSkillHandleIsDefault); - if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); + stream.Read(uiSkillHandleIsDefault); + if (uiSkillHandleIsDefault != 0) stream.Read(uiSkillHandle); return true; } diff --git a/dGame/dGameMessages/EchoSyncSkill.h b/dGame/dGameMessages/EchoSyncSkill.h index ab5a3f2b2..f65daab7b 100644 --- a/dGame/dGameMessages/EchoSyncSkill.h +++ b/dGame/dGameMessages/EchoSyncSkill.h @@ -21,40 +21,40 @@ class EchoSyncSkill { uiSkillHandle = _uiSkillHandle; } - EchoSyncSkill(RakNet::BitStream* stream) : EchoSyncSkill() { + EchoSyncSkill(RakNet::BitStream& stream) : EchoSyncSkill() { Deserialize(stream); } ~EchoSyncSkill() { } - void Serialize(RakNet::BitStream* stream) { - stream->Write(eGameMessageType::ECHO_SYNC_SKILL); + void Serialize(RakNet::BitStream& stream) { + stream.Write(eGameMessageType::ECHO_SYNC_SKILL); - stream->Write(bDone); + stream.Write(bDone); uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); + stream.Write(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); + stream.Write(sBitStream[k]); } - stream->Write(uiBehaviorHandle); - stream->Write(uiSkillHandle); + stream.Write(uiBehaviorHandle); + stream.Write(uiSkillHandle); } - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bDone); + bool Deserialize(RakNet::BitStream& stream) { + stream.Read(bDone); uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); + stream.Read(sBitStreamLength); for (unsigned int k = 0; k < sBitStreamLength; k++) { unsigned char character; - stream->Read(character); + stream.Read(character); sBitStream.push_back(character); } - stream->Read(uiBehaviorHandle); - stream->Read(uiSkillHandle); + stream.Read(uiBehaviorHandle); + stream.Read(uiSkillHandle); return true; } diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index 64790e316..d2432e363 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -39,7 +39,7 @@ #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, eGameMessageType messageID) { CBITSTREAM; @@ -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); } } @@ -269,11 +267,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System auto* skill_component = entity->GetComponent(); if (skill_component != nullptr) { - auto* bs = new RakNet::BitStream(reinterpret_cast(const_cast(message.sBitStream.c_str())), message.sBitStream.size(), false); + auto bs = RakNet::BitStream(reinterpret_cast(&message.sBitStream[0]), message.sBitStream.size(), false); skill_component->SyncPlayerProjectile(message.i64LocalID, bs, message.i64TargetID); - - delete bs; } break; @@ -296,7 +292,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System bool success = false; if (behaviorId > 0) { - RakNet::BitStream* bs = new RakNet::BitStream(reinterpret_cast(const_cast(startSkill.sBitStream.c_str())), startSkill.sBitStream.size(), false); + auto bs = RakNet::BitStream(reinterpret_cast(&startSkill.sBitStream[0]), startSkill.sBitStream.size(), false); auto* skillComponent = entity->GetComponent(); @@ -306,8 +302,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System DestroyableComponent* destComp = entity->GetComponent(); destComp->SetImagination(destComp->GetImagination() - skillTable->GetSkillByID(startSkill.skillID).imaginationcost); } - - delete bs; } if (Game::server->GetZoneID() == 1302) { @@ -331,9 +325,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System echoStartSkill.sBitStream = startSkill.sBitStream; echoStartSkill.skillID = startSkill.skillID; echoStartSkill.uiSkillHandle = startSkill.uiSkillHandle; - echoStartSkill.Serialize(&bitStreamLocal); + echoStartSkill.Serialize(bitStreamLocal); - Game::server->Send(&bitStreamLocal, entity->GetSystemAddress(), true); + Game::server->Send(bitStreamLocal, entity->GetSystemAddress(), true); } } break; @@ -353,13 +347,11 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System } if (usr != nullptr) { - RakNet::BitStream* bs = new RakNet::BitStream(reinterpret_cast(const_cast(sync.sBitStream.c_str())), sync.sBitStream.size(), false); + auto bs = RakNet::BitStream(reinterpret_cast(&sync.sBitStream[0]), sync.sBitStream.size(), false); auto* skillComponent = entity->GetComponent(); skillComponent->SyncPlayerSkill(sync.uiSkillHandle, sync.uiBehaviorHandle, bs); - - delete bs; } EchoSyncSkill echo = EchoSyncSkill(); @@ -368,9 +360,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System echo.uiBehaviorHandle = sync.uiBehaviorHandle; echo.uiSkillHandle = sync.uiSkillHandle; - echo.Serialize(&bitStreamLocal); + echo.Serialize(bitStreamLocal); - Game::server->Send(&bitStreamLocal, sysAddr, true); + Game::server->Send(bitStreamLocal, sysAddr, true); } break; case eGameMessageType::REQUEST_SMASH_PLAYER: diff --git a/dGame/dGameMessages/GameMessageHandler.h b/dGame/dGameMessages/GameMessageHandler.h index aed3d496e..2fefd008b 100644 --- a/dGame/dGameMessages/GameMessageHandler.h +++ b/dGame/dGameMessages/GameMessageHandler.h @@ -22,7 +22,7 @@ #include "eGameMessageType.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, eGameMessageType messageID); }; #endif // GAMEMESSAGEHANDLER_H diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 3c42f4dbc..4bd667b46 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -78,6 +78,7 @@ #include "LevelProgressionComponent.h" #include "DonationVendorComponent.h" #include "GhostComponent.h" +#include "AchievementVendorComponent.h" // Message includes: #include "dZoneManager.h" @@ -97,9 +98,12 @@ #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; @@ -320,8 +324,8 @@ void GameMessages::SendPlayNDAudioEmitter(Entity* entity, const SystemAddress& s bitStream.Write(entity->GetObjectID()); bitStream.Write(eGameMessageType::PLAY_ND_AUDIO_EMITTER); - bitStream.Write0(); - bitStream.Write0(); + bitStream.Write0(); // callback message data {lwoobjid} + bitStream.Write0(); // audio emitterid {uint32_t} uint32_t length = audioGUID.size(); bitStream.Write(length); @@ -329,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; } @@ -367,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; @@ -410,7 +414,8 @@ 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) { @@ -1323,15 +1328,14 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s SEND_PACKET; } -void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr, eVendorTransactionResult result) { CBITSTREAM; CMSGHEADER; - int iResult = 0x02; // success, seems to be the only relevant one bitStream.Write(entity->GetObjectID()); bitStream.Write(eGameMessageType::VENDOR_TRANSACTION_RESULT); - bitStream.Write(iResult); + bitStream.Write(result); SEND_PACKET; } @@ -1643,17 +1647,17 @@ void GameMessages::SendNotifyClientShootingGalleryScore(LWOOBJID objectId, const } -void GameMessages::HandleUpdateShootingGalleryRotation(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleUpdateShootingGalleryRotation(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { float angle = 0.0f; NiPoint3 facing = NiPoint3Constant::ZERO; NiPoint3 muzzlePos = NiPoint3Constant::ZERO; - inStream->Read(angle); - inStream->Read(facing); - inStream->Read(muzzlePos); + inStream.Read(angle); + inStream.Read(facing); + inStream.Read(muzzlePos); } -void GameMessages::HandleActivitySummaryLeaderboardData(RakNet::BitStream* instream, Entity* entity, +void GameMessages::HandleActivitySummaryLeaderboardData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LOG("We got mail!"); } @@ -1665,48 +1669,48 @@ void GameMessages::SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, bitStream.Write(objectID); bitStream.Write(eGameMessageType::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA); - leaderboard->Serialize(&bitStream); + leaderboard->Serialize(bitStream); SEND_PACKET; } -void GameMessages::HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { int32_t gameID = 0; - if (inStream->ReadBit()) inStream->Read(gameID); + if (inStream.ReadBit()) inStream.Read(gameID); Leaderboard::InfoType queryType = Leaderboard::InfoType::MyStanding; - if (inStream->ReadBit()) inStream->Read(queryType); + if (inStream.ReadBit()) inStream.Read(queryType); int32_t resultsEnd = 10; - if (inStream->ReadBit()) inStream->Read(resultsEnd); + if (inStream.ReadBit()) inStream.Read(resultsEnd); int32_t resultsStart = 0; - if (inStream->ReadBit()) inStream->Read(resultsStart); + if (inStream.ReadBit()) inStream.Read(resultsStart); LWOOBJID target{}; - inStream->Read(target); + inStream.Read(target); - bool weekly = inStream->ReadBit(); + bool weekly = inStream.ReadBit(); LeaderboardManager::SendLeaderboard(gameID, queryType, weekly, entity->GetObjectID(), entity->GetObjectID(), resultsStart, resultsEnd); } -void GameMessages::HandleActivityStateChangeRequest(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleActivityStateChangeRequest(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID objectID; - inStream->Read(objectID); + inStream.Read(objectID); int32_t value1; - inStream->Read(value1); + inStream.Read(value1); int32_t value2; - inStream->Read(value2); + inStream.Read(value2); uint32_t stringValueLength; - inStream->Read(stringValueLength); + inStream.Read(stringValueLength); std::u16string stringValue; for (uint32_t i = 0; i < stringValueLength; ++i) { uint16_t character; - inStream->Read(character); + inStream.Read(character); stringValue.push_back(character); } @@ -2159,17 +2163,17 @@ void GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(LWOOBJID objectId, cons SEND_PACKET; } -void GameMessages::HandleSetPropertyAccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleSetPropertyAccess(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint8_t accessType{}; int32_t renew{}; bool accessTypeIsDefault{}; - inStream->Read(accessTypeIsDefault); - if (accessTypeIsDefault != 0) inStream->Read(accessType); + inStream.Read(accessTypeIsDefault); + if (accessTypeIsDefault != 0) inStream.Read(accessType); bool renewIsDefault{}; - inStream->Read(renewIsDefault); - if (renewIsDefault != 0) inStream->Read(renew); + inStream.Read(renewIsDefault); + if (renewIsDefault != 0) inStream.Read(renew); LOG("Set privacy option to: %i", accessType); @@ -2178,11 +2182,11 @@ void GameMessages::HandleSetPropertyAccess(RakNet::BitStream* inStream, Entity* PropertyManagementComponent::Instance()->SetPrivacyOption(static_cast(accessType)); } -void GameMessages::HandleUnUseModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleUnUseModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool unknown{}; LWOOBJID objIdToAddToInventory{}; - inStream->Read(unknown); - inStream->Read(objIdToAddToInventory); + inStream.Read(unknown); + inStream.Read(objIdToAddToInventory); auto* inventoryComponent = entity->GetComponent(); if (inventoryComponent) { auto* inventory = inventoryComponent->GetInventory(eInventoryType::MODELS_IN_BBB); @@ -2204,7 +2208,7 @@ void GameMessages::HandleUnUseModel(RakNet::BitStream* inStream, Entity* entity, } } -void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool isProperty{}; LWOOBJID objectId{}; LWOOBJID playerId{}; @@ -2214,29 +2218,29 @@ void GameMessages::HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream* uint32_t descriptionLength{}; std::u16string description{}; - inStream->Read(isProperty); - inStream->Read(objectId); - inStream->Read(playerId); - inStream->Read(worldId); + inStream.Read(isProperty); + inStream.Read(objectId); + inStream.Read(playerId); + inStream.Read(worldId); - inStream->Read(descriptionLength); + inStream.Read(descriptionLength); for (uint32_t i = 0; i < descriptionLength; ++i) { uint16_t character; - inStream->Read(character); + inStream.Read(character); description.push_back(character); } - inStream->Read(nameLength); + inStream.Read(nameLength); for (uint32_t i = 0; i < nameLength; ++i) { uint16_t character; - inStream->Read(character); + inStream.Read(character); name.push_back(character); } PropertyManagementComponent::Instance()->UpdatePropertyDetails(GeneralUtils::UTF16ToWTF8(name), GeneralUtils::UTF16ToWTF8(description)); } -void GameMessages::HandleQueryPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleQueryPropertyData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LOG("Entity (%i) requesting data", entity->GetLOT()); /* @@ -2264,7 +2268,7 @@ void GameMessages::HandleQueryPropertyData(RakNet::BitStream* inStream, Entity* } } -void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleSetBuildMode(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool start{}; int32_t distanceType = -1; bool modePaused{}; @@ -2272,20 +2276,20 @@ void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entit LWOOBJID playerId{}; NiPoint3 startPosition = NiPoint3Constant::ZERO; - inStream->Read(start); + inStream.Read(start); - if (inStream->ReadBit()) - inStream->Read(distanceType); + if (inStream.ReadBit()) + inStream.Read(distanceType); - inStream->Read(modePaused); + inStream.Read(modePaused); - if (inStream->ReadBit()) - inStream->Read(modeValue); + if (inStream.ReadBit()) + inStream.Read(modeValue); - inStream->Read(playerId); + inStream.Read(playerId); - if (inStream->ReadBit()) - inStream->Read(startPosition); + if (inStream.ReadBit()) + inStream.Read(startPosition); auto* player = Game::entityManager->GetEntity(playerId); @@ -2300,7 +2304,7 @@ void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entit SendSetBuildModeConfirmed(entity->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS, start, false, modePaused, modeValue, playerId, startPosition); } -void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { if (!entity->HasComponent(eReplicaComponentType::PROPERTY_MANAGEMENT)) { return; } @@ -2316,16 +2320,16 @@ void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Enti NiPoint3 targetPosition{}; int32_t targetType{}; - inStream->Read(firstTime); - inStream->Read(success); - inStream->Read(sourceBag); - inStream->Read(sourceId); - inStream->Read(sourceLot); - inStream->Read(sourceType); - inStream->Read(targetId); - inStream->Read(targetLot); - inStream->Read(targetPosition); - inStream->Read(targetType); + inStream.Read(firstTime); + inStream.Read(success); + inStream.Read(sourceBag); + inStream.Read(sourceId); + inStream.Read(sourceLot); + inStream.Read(sourceType); + inStream.Read(targetId); + inStream.Read(targetLot); + inStream.Read(targetPosition); + inStream.Read(targetType); if (sourceType == 1) { sourceType = 4; @@ -2354,19 +2358,19 @@ void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Enti ); } -void GameMessages::HandlePropertyEditorBegin(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandlePropertyEditorBegin(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { PropertyManagementComponent::Instance()->OnStartBuilding(); Game::zoneManager->GetZoneControlObject()->OnZonePropertyEditBegin(); } -void GameMessages::HandlePropertyEditorEnd(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandlePropertyEditorEnd(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { PropertyManagementComponent::Instance()->OnFinishBuilding(); Game::zoneManager->GetZoneControlObject()->OnZonePropertyEditEnd(); } -void GameMessages::HandlePropertyContentsFromClient(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandlePropertyContentsFromClient(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { User* user = UserManager::Instance()->GetUser(sysAddr); Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar()); @@ -2374,52 +2378,52 @@ void GameMessages::HandlePropertyContentsFromClient(RakNet::BitStream* inStream, SendGetModelsOnProperty(player->GetObjectID(), PropertyManagementComponent::Instance()->GetModels(), UNASSIGNED_SYSTEM_ADDRESS); } -void GameMessages::HandlePropertyModelEquipped(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandlePropertyModelEquipped(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { Game::zoneManager->GetZoneControlObject()->OnZonePropertyModelEquipped(); } -void GameMessages::HandlePlacePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandlePlacePropertyModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID model; - inStream->Read(model); + inStream.Read(model); PropertyManagementComponent::Instance()->UpdateModelPosition(model, NiPoint3Constant::ZERO, NiQuaternionConstant::IDENTITY); } -void GameMessages::HandleUpdatePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleUpdatePropertyModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID model; NiPoint3 position; NiQuaternion rotation = NiQuaternionConstant::IDENTITY; - inStream->Read(model); - inStream->Read(position); + inStream.Read(model); + inStream.Read(position); - if (inStream->ReadBit()) { - inStream->Read(rotation); + if (inStream.ReadBit()) { + inStream.Read(rotation); } PropertyManagementComponent::Instance()->UpdateModelPosition(model, position, rotation); } -void GameMessages::HandleDeletePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleDeletePropertyModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID model = LWOOBJID_EMPTY; int deleteReason = 0; - if (inStream->ReadBit()) { - inStream->Read(model); + if (inStream.ReadBit()) { + inStream.Read(model); } - if (inStream->ReadBit()) { - inStream->Read(deleteReason); + if (inStream.ReadBit()) { + inStream.Read(deleteReason); } PropertyManagementComponent::Instance()->DeleteModel(model, deleteReason); } -void GameMessages::HandleBBBLoadItemRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleBBBLoadItemRequest(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID previousItemID = LWOOBJID_EMPTY; - inStream->Read(previousItemID); + inStream.Read(previousItemID); LOG("Load item request for: %lld", previousItemID); LWOOBJID newId = previousItemID; @@ -2486,28 +2490,29 @@ void GameMessages::SendUnSmash(Entity* entity, LWOOBJID builderID, float duratio SEND_PACKET_BROADCAST; } -void GameMessages::HandleControlBehaviors(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleControlBehaviors(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { AMFDeserialize reader; - std::unique_ptr amfArguments(reader.Read(inStream)); + std::unique_ptr amfArguments{ static_cast(reader.Read(inStream)) }; if (amfArguments->GetValueType() != eAmf::Array) return; uint32_t commandLength{}; - inStream->Read(commandLength); + inStream.Read(commandLength); std::string command; - for (uint32_t i = 0; i < commandLength; i++) { + command.reserve(commandLength); + for (uint32_t i = 0; i < commandLength; ++i) { unsigned char character; - inStream->Read(character); + inStream.Read(character); command.push_back(character); } - auto owner = PropertyManagementComponent::Instance()->GetOwner(); + auto* const owner = PropertyManagementComponent::Instance()->GetOwner(); if (!owner) return; - ControlBehaviors::Instance().ProcessCommand(entity, sysAddr, static_cast(amfArguments.get()), command, owner); + ControlBehaviors::Instance().ProcessCommand(entity, *amfArguments, command, owner); } -void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { /* ___ ___ /\ /\___ _ __ ___ / __\ ___ / \_ __ __ _ __ _ ___ _ __ ___ @@ -2538,18 +2543,18 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent */ LWOOBJID localId; - inStream->Read(localId); + inStream.Read(localId); uint32_t sd0Size; - inStream->Read(sd0Size); + inStream.Read(sd0Size); std::shared_ptr sd0Data(new char[sd0Size]); if (sd0Data == nullptr) return; - inStream->ReadAlignedBytes(reinterpret_cast(sd0Data.get()), sd0Size); + inStream.ReadAlignedBytes(reinterpret_cast(sd0Data.get()), sd0Size); uint32_t timeTaken; - inStream->Read(timeTaken); + inStream.Read(timeTaken); /* Disabled this, as it's kinda silly to do this roundabout way of storing plaintext lxfml, then recompressing @@ -2661,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) { @@ -2686,7 +2685,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent }); } -void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool includeNullAddress{}; bool includeNullDescription{}; bool playerOwn{}; @@ -2698,19 +2697,19 @@ void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entit uint32_t filterTextLength{}; std::string filterText{}; - inStream->Read(includeNullAddress); - inStream->Read(includeNullDescription); - inStream->Read(playerOwn); - inStream->Read(updateUi); - inStream->Read(numResults); - inStream->Read(reputation); - inStream->Read(sortMethod); - inStream->Read(startIndex); - inStream->Read(filterTextLength); + inStream.Read(includeNullAddress); + inStream.Read(includeNullDescription); + inStream.Read(playerOwn); + inStream.Read(updateUi); + inStream.Read(numResults); + inStream.Read(reputation); + inStream.Read(sortMethod); + inStream.Read(startIndex); + inStream.Read(filterTextLength); for (auto i = 0u; i < filterTextLength; i++) { char c; - inStream->Read(c); + inStream.Read(c); filterText.push_back(c); } @@ -2734,12 +2733,12 @@ void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entit ); } -void GameMessages::HandleEnterProperty(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleEnterProperty(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t index{}; bool returnToZone{}; - inStream->Read(index); - inStream->Read(returnToZone); + inStream.Read(index); + inStream.Read(returnToZone); auto* player = PlayerManager::GetPlayer(sysAddr); @@ -2755,10 +2754,10 @@ void GameMessages::HandleEnterProperty(RakNet::BitStream* inStream, Entity* enti } } -void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleSetConsumableItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LOT lot; - inStream->Read(lot); + inStream.Read(lot); auto* inventory = entity->GetComponent(); @@ -2830,43 +2829,43 @@ void GameMessages::SendEndCinematic(LWOOBJID objectId, std::u16string pathName, SEND_PACKET; } -void GameMessages::HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleCinematicUpdate(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { eCinematicEvent event; - if (!inStream->ReadBit()) { + if (!inStream.ReadBit()) { event = eCinematicEvent::STARTED; } else { - inStream->Read(event); + inStream.Read(event); } float_t overallTime; - if (!inStream->ReadBit()) { + if (!inStream.ReadBit()) { overallTime = -1.0f; } else { - inStream->Read(overallTime); + inStream.Read(overallTime); } uint32_t pathNameLength; - inStream->Read(pathNameLength); + inStream.Read(pathNameLength); std::u16string pathName; for (size_t i = 0; i < pathNameLength; i++) { char16_t character; - inStream->Read(character); + inStream.Read(character); pathName.push_back(character); } float_t pathTime; - if (!inStream->ReadBit()) { + if (!inStream.ReadBit()) { pathTime = -1.0f; } else { - inStream->Read(pathTime); + inStream.Read(pathTime); } int32_t waypoint; - if (!inStream->ReadBit()) { + if (!inStream.ReadBit()) { waypoint = -1; } else { - inStream->Read(waypoint); + inStream.Read(waypoint); } std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); @@ -3087,23 +3086,23 @@ void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std SEND_PACKET; } -void GameMessages::HandleVerifyAck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleVerifyAck(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool bDifferent; std::string sBitStream; uint32_t uiHandle = 0; - bDifferent = inStream->ReadBit(); + bDifferent = inStream.ReadBit(); uint32_t sBitStreamLength = 0; - inStream->Read(sBitStreamLength); + inStream.Read(sBitStreamLength); for (uint64_t k = 0; k < sBitStreamLength; k++) { uint8_t character; - inStream->Read(character); + inStream.Read(character); sBitStream.push_back(character); } - if (inStream->ReadBit()) { - inStream->Read(uiHandle); + if (inStream.ReadBit()) { + inStream.Read(uiHandle); } } @@ -3230,7 +3229,7 @@ void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, cons SEND_PACKET; } -void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleClientTradeRequest(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { // Check if the player has restricted trade access auto* character = entity->GetCharacter(); @@ -3244,10 +3243,10 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* return; } - bool bNeedInvitePopUp = inStream->ReadBit(); + bool bNeedInvitePopUp = inStream.ReadBit(); LWOOBJID i64Invitee; - inStream->Read(i64Invitee); + inStream.Read(i64Invitee); auto* invitee = Game::entityManager->GetEntity(i64Invitee); @@ -3288,7 +3287,7 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* } } -void GameMessages::HandleClientTradeCancel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleClientTradeCancel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); if (trade == nullptr) return; @@ -3298,8 +3297,8 @@ void GameMessages::HandleClientTradeCancel(RakNet::BitStream* inStream, Entity* TradingManager::Instance()->CancelTrade(entity->GetObjectID(), trade->GetTradeId()); } -void GameMessages::HandleClientTradeAccept(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - bool bFirst = inStream->ReadBit(); +void GameMessages::HandleClientTradeAccept(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { + bool bFirst = inStream.ReadBit(); LOG("Trade accepted from (%llu) -> (%d)", entity->GetObjectID(), bFirst); @@ -3310,12 +3309,12 @@ void GameMessages::HandleClientTradeAccept(RakNet::BitStream* inStream, Entity* trade->SetAccepted(entity->GetObjectID(), bFirst); } -void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleClientTradeUpdate(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint64_t currency; uint32_t itemCount; - inStream->Read(currency); - inStream->Read(itemCount); + inStream.Read(currency); + inStream.Read(itemCount); LOG("Trade update from (%llu) -> (%llu), (%i)", entity->GetObjectID(), currency, itemCount); @@ -3325,8 +3324,8 @@ void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* LWOOBJID itemId; LWOOBJID itemId2; - inStream->Read(itemId); - inStream->Read(itemId2); + inStream.Read(itemId); + inStream.Read(itemId2); LOT lot = 0; LWOOBJID unknown1 = 0; @@ -3336,32 +3335,32 @@ void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* uint32_t ldfSize = 0; bool unknown4; - inStream->Read(lot); - if (inStream->ReadBit()) { - inStream->Read(unknown1); + inStream.Read(lot); + if (inStream.ReadBit()) { + inStream.Read(unknown1); } - if (inStream->ReadBit()) { - inStream->Read(unknown2); + if (inStream.ReadBit()) { + inStream.Read(unknown2); } - if (inStream->ReadBit()) { - inStream->Read(slot); + if (inStream.ReadBit()) { + inStream.Read(slot); } - if (inStream->ReadBit()) { - inStream->Read(unknown3); + if (inStream.ReadBit()) { + inStream.Read(unknown3); } - if (inStream->ReadBit()) // No + if (inStream.ReadBit()) // No { - inStream->Read(ldfSize); - bool compressed = inStream->ReadBit(); + inStream.Read(ldfSize); + bool compressed = inStream.ReadBit(); if (compressed) { uint32_t ldfCompressedSize = 0; - inStream->Read(ldfCompressedSize); - inStream->IgnoreBytes(ldfCompressedSize); + inStream.Read(ldfCompressedSize); + inStream.IgnoreBytes(ldfCompressedSize); } else { - inStream->IgnoreBytes(ldfSize); + inStream.IgnoreBytes(ldfSize); } } - unknown4 = inStream->ReadBit(); + unknown4 = inStream.ReadBit(); items.push_back({ itemId, lot, unknown2 }); @@ -3656,8 +3655,8 @@ void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatu } -void GameMessages::HandleClientExitTamingMinigame(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - bool bVoluntaryExit = inStream->ReadBit(); +void GameMessages::HandleClientExitTamingMinigame(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { + bool bVoluntaryExit = inStream.ReadBit(); auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); @@ -3668,7 +3667,7 @@ void GameMessages::HandleClientExitTamingMinigame(RakNet::BitStream* inStream, E petComponent->ClientExitTamingMinigame(bVoluntaryExit); } -void GameMessages::HandleStartServerPetMinigameTimer(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleStartServerPetMinigameTimer(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); if (petComponent == nullptr) { @@ -3678,24 +3677,24 @@ void GameMessages::HandleStartServerPetMinigameTimer(RakNet::BitStream* inStream petComponent->StartTimer(); } -void GameMessages::HandlePetTamingTryBuild(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandlePetTamingTryBuild(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t brickCount; std::vector bricks; bool clientFailed; - inStream->Read(brickCount); + inStream.Read(brickCount); bricks.reserve(brickCount); for (uint32_t i = 0; i < brickCount; i++) { Brick brick; - inStream->Read(brick); + inStream.Read(brick); bricks.push_back(brick); } - clientFailed = inStream->ReadBit(); + clientFailed = inStream.ReadBit(); auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); @@ -3706,10 +3705,10 @@ void GameMessages::HandlePetTamingTryBuild(RakNet::BitStream* inStream, Entity* petComponent->TryBuild(bricks.size(), clientFailed); } -void GameMessages::HandleNotifyTamingBuildSuccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleNotifyTamingBuildSuccess(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { NiPoint3 position; - inStream->Read(position); + inStream.Read(position); auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); @@ -3720,15 +3719,15 @@ void GameMessages::HandleNotifyTamingBuildSuccess(RakNet::BitStream* inStream, E petComponent->NotifyTamingBuildSuccess(position); } -void GameMessages::HandleRequestSetPetName(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRequestSetPetName(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t nameLength; std::u16string name; - inStream->Read(nameLength); + inStream.Read(nameLength); for (size_t i = 0; i < nameLength; i++) { char16_t character; - inStream->Read(character); + inStream.Read(character); name.push_back(character); } @@ -3745,18 +3744,18 @@ void GameMessages::HandleRequestSetPetName(RakNet::BitStream* inStream, Entity* petComponent->RequestSetPetName(name); } -void GameMessages::HandleCommandPet(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleCommandPet(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { NiPoint3 genericPosInfo; LWOOBJID objIdSource; int32_t iPetCommandType; int32_t iTypeID; bool overrideObey; - inStream->Read(genericPosInfo); - inStream->Read(objIdSource); - inStream->Read(iPetCommandType); - inStream->Read(iTypeID); - overrideObey = inStream->ReadBit(); + inStream.Read(genericPosInfo); + inStream.Read(objIdSource); + inStream.Read(iPetCommandType); + inStream.Read(iTypeID); + overrideObey = inStream.ReadBit(); auto* petComponent = entity->GetComponent(); @@ -3767,10 +3766,10 @@ void GameMessages::HandleCommandPet(RakNet::BitStream* inStream, Entity* entity, petComponent->Command(genericPosInfo, objIdSource, iPetCommandType, iTypeID, overrideObey); } -void GameMessages::HandleDespawnPet(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleDespawnPet(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool bDeletePet; - bDeletePet = inStream->ReadBit(); + bDeletePet = inStream.ReadBit(); auto* petComponent = PetComponent::GetActivePet(entity->GetObjectID()); @@ -3785,26 +3784,26 @@ void GameMessages::HandleDespawnPet(RakNet::BitStream* inStream, Entity* entity, } } -void GameMessages::HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleMessageBoxResponse(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { int32_t iButton; uint32_t identifierLength; std::u16string identifier; uint32_t userDataLength; std::u16string userData; - inStream->Read(iButton); + inStream.Read(iButton); - inStream->Read(identifierLength); + inStream.Read(identifierLength); for (size_t i = 0; i < identifierLength; i++) { char16_t character; - inStream->Read(character); + inStream.Read(character); identifier.push_back(character); } - inStream->Read(userDataLength); + inStream.Read(userDataLength); for (size_t i = 0; i < userDataLength; i++) { char16_t character; - inStream->Read(character); + inStream.Read(character); userData.push_back(character); } @@ -3841,26 +3840,26 @@ void GameMessages::HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* } } -void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { int32_t iButton; uint32_t buttonIdentifierLength; std::u16string buttonIdentifier; uint32_t identifierLength; std::u16string identifier; - inStream->Read(buttonIdentifierLength); + inStream.Read(buttonIdentifierLength); for (size_t i = 0; i < buttonIdentifierLength; i++) { char16_t character; - inStream->Read(character); + inStream.Read(character); buttonIdentifier.push_back(character); } - inStream->Read(iButton); + inStream.Read(iButton); - inStream->Read(identifierLength); + inStream.Read(identifierLength); for (size_t i = 0; i < identifierLength; i++) { char16_t character; - inStream->Read(character); + inStream.Read(character); identifier.push_back(character); } @@ -3989,10 +3988,10 @@ void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objec } -void GameMessages::HandleDismountComplete(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleDismountComplete(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { // Get the objectID from the bitstream LWOOBJID objectId{}; - inStream->Read(objectId); + inStream.Read(objectId); // If we aren't possessing somethings, the don't do anything if (objectId != LWOOBJID_EMPTY) { @@ -4031,17 +4030,17 @@ void GameMessages::HandleDismountComplete(RakNet::BitStream* inStream, Entity* e } -void GameMessages::HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleAcknowledgePossession(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { Game::entityManager->SerializeEntity(entity); LWOOBJID objectId{}; - inStream->Read(objectId); + inStream.Read(objectId); auto* mount = Game::entityManager->GetEntity(objectId); if (mount) Game::entityManager->SerializeEntity(mount); } //Racing -void GameMessages::HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleModuleAssemblyQueryData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { auto* moduleAssemblyComponent = entity->GetComponent(); LOG("Got Query from %i", entity->GetLOT()); @@ -4054,23 +4053,23 @@ void GameMessages::HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, En } -void GameMessages::HandleModularAssemblyNIFCompleted(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleModularAssemblyNIFCompleted(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID objectID; - inStream->Read(objectID); + inStream.Read(objectID); } -void GameMessages::HandleVehicleSetWheelLockState(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - bool bExtraFriction = inStream->ReadBit(); - bool bLocked = inStream->ReadBit(); +void GameMessages::HandleVehicleSetWheelLockState(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { + bool bExtraFriction = inStream.ReadBit(); + bool bLocked = inStream.ReadBit(); } -void GameMessages::HandleRacingClientReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRacingClientReady(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID playerID; - inStream->Read(playerID); + inStream.Read(playerID); auto* player = Game::entityManager->GetEntity(playerID); @@ -4088,7 +4087,7 @@ void GameMessages::HandleRacingClientReady(RakNet::BitStream* inStream, Entity* } -void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRequestDie(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool bClientDeath; bool bSpawnLoot; std::u16string deathType; @@ -4099,31 +4098,31 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, LWOOBJID killerID; LWOOBJID lootOwnerID = LWOOBJID_EMPTY; - bClientDeath = inStream->ReadBit(); - bSpawnLoot = inStream->ReadBit(); + bClientDeath = inStream.ReadBit(); + bSpawnLoot = inStream.ReadBit(); uint32_t deathTypeLength = 0; - inStream->Read(deathTypeLength); + inStream.Read(deathTypeLength); for (size_t i = 0; i < deathTypeLength; i++) { char16_t character; - inStream->Read(character); + inStream.Read(character); deathType.push_back(character); } - inStream->Read(directionRelativeAngleXZ); - inStream->Read(directionRelativeAngleY); - inStream->Read(directionRelativeForce); + inStream.Read(directionRelativeAngleXZ); + inStream.Read(directionRelativeAngleY); + inStream.Read(directionRelativeForce); - if (inStream->ReadBit()) { - inStream->Read(killType); + if (inStream.ReadBit()) { + inStream.Read(killType); } - inStream->Read(killerID); + inStream.Read(killerID); - if (inStream->ReadBit()) { - inStream->Read(lootOwnerID); + if (inStream.ReadBit()) { + inStream.Read(lootOwnerID); } auto* zoneController = Game::zoneManager->GetZoneControlObject(); @@ -4154,20 +4153,20 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, } -void GameMessages::HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { //SendVehicleAddPassiveBoostAction(entity->GetObjectID(), sysAddr); } -void GameMessages::HandleVehicleNotifyServerRemovePassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleVehicleNotifyServerRemovePassiveBoostAction(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { //SendVehicleRemovePassiveBoostAction(entity->GetObjectID(), sysAddr); } -void GameMessages::HandleRacingPlayerInfoResetFinished(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRacingPlayerInfoResetFinished(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID playerID; - inStream->Read(playerID); + inStream.Read(playerID); auto* player = Game::entityManager->GetEntity(playerID); @@ -4198,10 +4197,10 @@ void GameMessages::SendUpdateReputation(const LWOOBJID objectId, const int64_t r SEND_PACKET; } -void GameMessages::HandleUpdatePropertyPerformanceCost(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleUpdatePropertyPerformanceCost(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { float performanceCost = 0.0f; - if (inStream->ReadBit()) inStream->Read(performanceCost); + if (inStream.ReadBit()) inStream.Read(performanceCost); if (performanceCost == 0.0f) return; @@ -4214,16 +4213,16 @@ void GameMessages::HandleUpdatePropertyPerformanceCost(RakNet::BitStream* inStre Database::Get()->UpdatePerformanceCost(zone->GetZoneID(), performanceCost); } -void GameMessages::HandleVehicleNotifyHitImaginationServer(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleVehicleNotifyHitImaginationServer(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID pickupObjID = LWOOBJID_EMPTY; LWOOBJID pickupSpawnerID = LWOOBJID_EMPTY; int32_t pickupSpawnerIndex = -1; NiPoint3 vehiclePosition = NiPoint3Constant::ZERO; - if (inStream->ReadBit()) inStream->Read(pickupObjID); - if (inStream->ReadBit()) inStream->Read(pickupSpawnerID); - if (inStream->ReadBit()) inStream->Read(pickupSpawnerIndex); - if (inStream->ReadBit()) inStream->Read(vehiclePosition); + if (inStream.ReadBit()) inStream.Read(pickupObjID); + if (inStream.ReadBit()) inStream.Read(pickupSpawnerID); + if (inStream.ReadBit()) inStream.Read(pickupSpawnerIndex); + if (inStream.ReadBit()) inStream.Read(vehiclePosition); auto* pickup = Game::entityManager->GetEntity(pickupObjID); @@ -4545,7 +4544,7 @@ void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uin // NT -void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool bAllowPartial{}; int32_t destSlot = -1; int32_t iStackCount = 1; @@ -4556,27 +4555,42 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* LWOOBJID subkey = LWOOBJID_EMPTY; LOT itemLOT = 0; - bAllowPartial = inStream->ReadBit(); - if (inStream->ReadBit()) inStream->Read(destSlot); - if (inStream->ReadBit()) inStream->Read(iStackCount); - if (inStream->ReadBit()) inStream->Read(invTypeDst); - if (inStream->ReadBit()) inStream->Read(invTypeSrc); - if (inStream->ReadBit()) inStream->Read(itemID); - showFlyingLoot = inStream->ReadBit(); - if (inStream->ReadBit()) inStream->Read(subkey); - if (inStream->ReadBit()) inStream->Read(itemLOT); + bAllowPartial = inStream.ReadBit(); + if (inStream.ReadBit()) inStream.Read(destSlot); + if (inStream.ReadBit()) inStream.Read(iStackCount); + if (inStream.ReadBit()) inStream.Read(invTypeDst); + if (inStream.ReadBit()) inStream.Read(invTypeSrc); + if (inStream.ReadBit()) inStream.Read(itemID); + showFlyingLoot = inStream.ReadBit(); + if (inStream.ReadBit()) inStream.Read(subkey); + 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()); @@ -4585,10 +4599,32 @@ 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(eGameMessageType::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; @@ -4617,10 +4653,10 @@ void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditi //------------------------------------------------------------------- Handlers ------------------------------------------------------------------ //----------------------------------------------------------------------------------------------------------------------------------------------- -void GameMessages::HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleToggleGhostReferenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool bOverride = false; - inStream->Read(bOverride); + inStream.Read(bOverride); auto* player = PlayerManager::GetPlayer(sysAddr); @@ -4633,10 +4669,10 @@ void GameMessages::HandleToggleGhostReferenceOverride(RakNet::BitStream* inStrea } -void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { NiPoint3 position; - inStream->Read(position); + inStream.Read(position); auto* player = PlayerManager::GetPlayer(sysAddr); @@ -4649,119 +4685,52 @@ void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream* inStream, } -void GameMessages::HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleBuyFromVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool bConfirmed{}; // This doesn't appear to do anything. Further research is needed. bool countIsDefault{}; int count = 1; LOT item; - inStream->Read(bConfirmed); - inStream->Read(countIsDefault); - if (countIsDefault) inStream->Read(count); - inStream->Read(item); + inStream.Read(bConfirmed); + inStream.Read(countIsDefault); + if (countIsDefault) inStream.Read(count); + inStream.Read(item); User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) return; Entity* player = Game::entityManager->GetEntity(user->GetLoggedInChar()); if (!player) return; - auto* propertyVendorComponent = static_cast(entity->GetComponent(eReplicaComponentType::PROPERTY_VENDOR)); - - if (propertyVendorComponent != nullptr) { - propertyVendorComponent->OnBuyFromVendor(player, bConfirmed, item, count); - + // handle buying normal items + auto* vendorComponent = entity->GetComponent(); + if (vendorComponent) { + vendorComponent->Buy(player, item, count); return; } - const auto isCommendationVendor = entity->GetLOT() == 13806; - - auto* vend = entity->GetComponent(); - if (!vend && !isCommendationVendor) return; - - auto* inv = player->GetComponent(); - if (!inv) return; - - if (!isCommendationVendor && !vend->SellsItem(item)) { - LOG("User %llu %s tried to buy an item %i from a vendor when they do not sell said item", player->GetObjectID(), user->GetUsername().c_str(), item); + // handle buying achievement items + auto* achievementVendorComponent = entity->GetComponent(); + if (achievementVendorComponent) { + achievementVendorComponent->Buy(player, item, count); return; } - CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); - CDItemComponentTable* itemComponentTable = CDClientManager::GetTable(); - - int itemCompID = compRegistryTable->GetByIDAndType(item, eReplicaComponentType::ITEM); - CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); - - Character* character = player->GetCharacter(); - if (!character) return; - - // Extra currency that needs to be deducted in case of crafting - auto craftingCurrencies = CDItemComponentTable::ParseCraftingCurrencies(itemComp); - for (const auto& craftingCurrency : craftingCurrencies) { - inv->RemoveItem(craftingCurrency.first, craftingCurrency.second * count); - } - - if (isCommendationVendor) { - if (itemComp.commendationLOT != 13763) { - return; - } - - auto* missionComponent = player->GetComponent(); - - if (missionComponent == nullptr) { - return; - } - - LOT tokenId = -1; - - if (missionComponent->GetMissionState(545) == eMissionState::COMPLETE) tokenId = 8318; // "Assembly Token" - if (missionComponent->GetMissionState(556) == eMissionState::COMPLETE) tokenId = 8321; // "Venture League Token" - if (missionComponent->GetMissionState(567) == eMissionState::COMPLETE) tokenId = 8319; // "Sentinels Token" - if (missionComponent->GetMissionState(578) == eMissionState::COMPLETE) tokenId = 8320; // "Paradox Token" - - const uint32_t altCurrencyCost = itemComp.commendationCost * count; - - if (inv->GetLotCount(tokenId) < altCurrencyCost) { - return; - } - - inv->RemoveItem(tokenId, altCurrencyCost); - - inv->AddItem(item, count, eLootSourceType::VENDOR); - } else { - float buyScalar = vend->GetBuyScalar(); - - const auto coinCost = static_cast(std::floor((itemComp.baseValue * buyScalar) * count)); - - if (character->GetCoins() < coinCost) { - return; - } - - if (Inventory::IsValidItem(itemComp.currencyLOT)) { - const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * buyScalar) * count; - - if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) { - return; - } - - inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost); - } - - character->SetCoins(character->GetCoins() - (coinCost), eLootSourceType::VENDOR); - inv->AddItem(item, count, eLootSourceType::VENDOR); + // Handle buying properties + auto* propertyVendorComponent = entity->GetComponent(); + if (propertyVendorComponent) { + propertyVendorComponent->OnBuyFromVendor(player, bConfirmed, item, count); + return; } - - GameMessages::SendVendorTransactionResult(entity, sysAddr); } -void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleSellToVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool countIsDefault{}; int count = 1; LWOOBJID iObjID; - inStream->Read(countIsDefault); - if (countIsDefault) inStream->Read(count); - inStream->Read(iObjID); + inStream.Read(countIsDefault); + if (countIsDefault) inStream.Read(count); + inStream.Read(iObjID); User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) return; @@ -4785,7 +4754,10 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit CDItemComponent itemComp = itemComponentTable->GetItemComponentByID(itemCompID); // Items with a base value of 0 or max int are special items that should not be sold if they're not sub items - if (itemComp.baseValue == 0 || itemComp.baseValue == UINT_MAX) return; + if (itemComp.baseValue == 0 || itemComp.baseValue == UINT_MAX) { + GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::SELL_FAIL); + return; + } float sellScalar = vend->GetSellScalar(); if (Inventory::IsValidItem(itemComp.currencyLOT)) { @@ -4793,23 +4765,21 @@ void GameMessages::HandleSellToVendor(RakNet::BitStream* inStream, Entity* entit inv->AddItem(itemComp.currencyLOT, std::floor(altCurrency), eLootSourceType::VENDOR); // Return alt currencies like faction tokens. } - //inv->RemoveItem(count, -1, iObjID); inv->MoveItemToInventory(item, eInventoryType::VENDOR_BUYBACK, count, true, false, true); character->SetCoins(std::floor(character->GetCoins() + (static_cast(itemComp.baseValue * sellScalar) * count)), eLootSourceType::VENDOR); - //Game::entityManager->SerializeEntity(player); // so inventory updates - GameMessages::SendVendorTransactionResult(entity, sysAddr); + GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::SELL_SUCCESS); } -void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleBuybackFromVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool confirmed = false; bool countIsDefault{}; int count = 1; LWOOBJID iObjID; - inStream->Read(confirmed); - inStream->Read(countIsDefault); - if (countIsDefault) inStream->Read(count); - inStream->Read(iObjID); + inStream.Read(confirmed); + inStream.Read(countIsDefault); + if (countIsDefault) inStream.Read(count); + inStream.Read(iObjID); //if (!confirmed) return; they always built in this confirmed garbage... but never used it? @@ -4839,16 +4809,16 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* const auto cost = static_cast(std::floor(((itemComp.baseValue * sellScalar) * count))); if (character->GetCoins() < cost) { + GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_FAIL); return; } if (Inventory::IsValidItem(itemComp.currencyLOT)) { const uint32_t altCurrencyCost = std::floor(itemComp.altCurrencyCost * sellScalar) * count; - if (inv->GetLotCount(itemComp.currencyLOT) < altCurrencyCost) { + GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_FAIL); return; } - inv->RemoveItem(itemComp.currencyLOT, altCurrencyCost); } @@ -4856,19 +4826,19 @@ void GameMessages::HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* inv->MoveItemToInventory(item, Inventory::FindInventoryTypeForLot(item->GetLot()), count, true, false); character->SetCoins(character->GetCoins() - cost, eLootSourceType::VENDOR); //Game::entityManager->SerializeEntity(player); // so inventory updates - GameMessages::SendVendorTransactionResult(entity, sysAddr); + GameMessages::SendVendorTransactionResult(entity, sysAddr, eVendorTransactionResult::PURCHASE_SUCCESS); } -void GameMessages::HandleParseChatMessage(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleParseChatMessage(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { std::u16string wsString; int iClientState; - inStream->Read(iClientState); + inStream.Read(iClientState); uint32_t wsStringLength; - inStream->Read(wsStringLength); + inStream.Read(wsStringLength); for (uint32_t i = 0; i < wsStringLength; ++i) { uint16_t character; - inStream->Read(character); + inStream.Read(character); wsString.push_back(character); } @@ -4877,7 +4847,7 @@ void GameMessages::HandleParseChatMessage(RakNet::BitStream* inStream, Entity* e } } -void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleFireEventServerSide(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t argsLength{}; std::u16string args{}; bool param1IsDefault{}; @@ -4888,19 +4858,19 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity int param3 = -1; LWOOBJID senderID{}; - inStream->Read(argsLength); + inStream.Read(argsLength); for (uint32_t i = 0; i < argsLength; ++i) { uint16_t character; - inStream->Read(character); + inStream.Read(character); args.push_back(character); } - inStream->Read(param1IsDefault); - if (param1IsDefault) inStream->Read(param1); - inStream->Read(param2IsDefault); - if (param2IsDefault) inStream->Read(param2); - inStream->Read(param3IsDefault); - if (param3IsDefault) inStream->Read(param3); - inStream->Read(senderID); + inStream.Read(param1IsDefault); + if (param1IsDefault) inStream.Read(param1); + inStream.Read(param2IsDefault); + if (param2IsDefault) inStream.Read(param2); + inStream.Read(param3IsDefault); + if (param3IsDefault) inStream.Read(param3); + inStream.Read(senderID); auto* sender = Game::entityManager->GetEntity(senderID); auto* player = PlayerManager::GetPlayer(sysAddr); @@ -4961,17 +4931,17 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity entity->OnFireEventServerSide(sender, GeneralUtils::UTF16ToWTF8(args), param1, param2, param3); } -void GameMessages::HandleRequestPlatformResync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRequestPlatformResync(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { if (entity->GetLOT() == 6267 || entity->GetLOT() == 16141) return; GameMessages::SendPlatformResync(entity, sysAddr); } -void GameMessages::HandleQuickBuildCancel(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleQuickBuildCancel(RakNet::BitStream& inStream, Entity* entity) { bool bEarlyRelease; LWOOBJID userID; - inStream->Read(bEarlyRelease); - inStream->Read(userID); + inStream.Read(bEarlyRelease); + inStream.Read(userID); auto* quickBuildComponent = static_cast(entity->GetComponent(eReplicaComponentType::QUICK_BUILD));; if (!quickBuildComponent) return; @@ -4979,18 +4949,18 @@ void GameMessages::HandleQuickBuildCancel(RakNet::BitStream* inStream, Entity* e quickBuildComponent->CancelQuickBuild(Game::entityManager->GetEntity(userID), eQuickBuildFailReason::CANCELED_EARLY); } -void GameMessages::HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRequestUse(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool bIsMultiInteractUse = false; unsigned int multiInteractID; int multiInteractType; bool secondary; LWOOBJID objectID; - inStream->Read(bIsMultiInteractUse); - inStream->Read(multiInteractID); - inStream->Read(multiInteractType); - inStream->Read(objectID); - inStream->Read(secondary); + inStream.Read(bIsMultiInteractUse); + inStream.Read(multiInteractID); + inStream.Read(multiInteractType); + inStream.Read(objectID); + inStream.Read(secondary); Entity* interactedObject = Game::entityManager->GetEntity(objectID); @@ -5027,12 +4997,12 @@ void GameMessages::HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, missionComponent->Progress(eMissionTaskType::INTERACT, interactedObject->GetLOT(), interactedObject->GetObjectID()); } -void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandlePlayEmote(RakNet::BitStream& inStream, Entity* entity) { int emoteID; LWOOBJID targetID; - inStream->Read(emoteID); - inStream->Read(targetID); + inStream.Read(emoteID); + inStream.Read(targetID); LOG_DEBUG("Emote (%i) (%llu)", emoteID, targetID); @@ -5076,10 +5046,10 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) } } -void GameMessages::HandleModularBuildConvertModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleModularBuildConvertModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID modelID; - inStream->Read(modelID); + inStream.Read(modelID); User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) return; @@ -5103,29 +5073,29 @@ void GameMessages::HandleModularBuildConvertModel(RakNet::BitStream* inStream, E item->SetCount(item->GetCount() - 1, false, false, true, eLootSourceType::QUICKBUILD); } -void GameMessages::HandleSetFlag(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleSetFlag(RakNet::BitStream& inStream, Entity* entity) { bool bFlag{}; int32_t iFlagID{}; - inStream->Read(bFlag); - inStream->Read(iFlagID); + inStream.Read(bFlag); + inStream.Read(iFlagID); auto character = entity->GetCharacter(); if (character) character->SetPlayerFlag(iFlagID, bFlag); } -void GameMessages::HandleRespondToMission(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleRespondToMission(RakNet::BitStream& inStream, Entity* entity) { int missionID{}; LWOOBJID playerID{}; LWOOBJID receiverID{}; bool isDefaultReward{}; LOT reward = LOT_NULL; - inStream->Read(missionID); - inStream->Read(playerID); - inStream->Read(receiverID); - inStream->Read(isDefaultReward); - if (isDefaultReward) inStream->Read(reward); + inStream.Read(missionID); + inStream.Read(playerID); + inStream.Read(receiverID); + inStream.Read(isDefaultReward); + if (isDefaultReward) inStream.Read(reward); MissionComponent* missionComponent = static_cast(entity->GetComponent(eReplicaComponentType::MISSION)); if (!missionComponent) { @@ -5147,27 +5117,23 @@ 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) { +void GameMessages::HandleMissionDialogOK(RakNet::BitStream& inStream, Entity* entity) { bool bIsComplete{}; eMissionState iMissionState{}; int missionID{}; LWOOBJID responder{}; Entity* player = nullptr; - inStream->Read(bIsComplete); - inStream->Read(iMissionState); - inStream->Read(missionID); - inStream->Read(responder); + inStream.Read(bIsComplete); + inStream.Read(iMissionState); + inStream.Read(missionID); + 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)); @@ -5191,14 +5157,14 @@ void GameMessages::HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* en }); } -void GameMessages::HandleRequestLinkedMission(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleRequestLinkedMission(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID playerId{}; int missionId{}; bool bMissionOffered{}; - inStream->Read(playerId); - inStream->Read(missionId); - inStream->Read(bMissionOffered); + inStream.Read(playerId); + inStream.Read(missionId); + inStream.Read(bMissionOffered); auto* player = Game::entityManager->GetEntity(playerId); @@ -5209,9 +5175,9 @@ void GameMessages::HandleRequestLinkedMission(RakNet::BitStream* inStream, Entit } } -void GameMessages::HandleHasBeenCollected(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleHasBeenCollected(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID playerID; - inStream->Read(playerID); + inStream.Read(playerID); Entity* player = Game::entityManager->GetEntity(playerID); if (!player || !entity || entity->GetCollectibleID() == 0) return; @@ -5222,7 +5188,7 @@ void GameMessages::HandleHasBeenCollected(RakNet::BitStream* inStream, Entity* e } } -void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream& inStream, Entity* entity) { auto* levelComp = entity->GetComponent(); if (!levelComp) return; auto* character = entity->GetComponent(); @@ -5261,9 +5227,9 @@ void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* GameMessages::SendBroadcastTextToChatbox(entity, UNASSIGNED_SYSTEM_ADDRESS, attrs, wsText); } -void GameMessages::HandlePickupCurrency(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandlePickupCurrency(RakNet::BitStream& inStream, Entity* entity) { unsigned int currency; - inStream->Read(currency); + inStream.Read(currency); if (currency == 0) return; @@ -5273,7 +5239,7 @@ void GameMessages::HandlePickupCurrency(RakNet::BitStream* inStream, Entity* ent } } -void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleRequestDie(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID killerID; LWOOBJID lootOwnerID; bool bDieAccepted = false; @@ -5286,38 +5252,38 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity) bool bSpawnLoot = true; float coinSpawnTime = -1.0f; - inStream->Read(bClientDeath); - inStream->Read(bDieAccepted); - inStream->Read(bSpawnLoot); + inStream.Read(bClientDeath); + inStream.Read(bDieAccepted); + inStream.Read(bSpawnLoot); bool coinSpawnTimeIsDefault{}; - inStream->Read(coinSpawnTimeIsDefault); - if (coinSpawnTimeIsDefault != 0) inStream->Read(coinSpawnTime); + inStream.Read(coinSpawnTimeIsDefault); + if (coinSpawnTimeIsDefault != 0) inStream.Read(coinSpawnTime); /*uint32_t deathTypeLength = deathType.size(); - inStream->Read(deathTypeLength); + inStream.Read(deathTypeLength); for (uint32_t k = 0; k < deathTypeLength; k++) { - inStream->Read(deathType[k]); + inStream.Read(deathType[k]); }*/ - inStream->Read(directionRelative_AngleXZ); - inStream->Read(directionRelative_AngleY); - inStream->Read(directionRelative_Force); + inStream.Read(directionRelative_AngleXZ); + inStream.Read(directionRelative_AngleY); + inStream.Read(directionRelative_Force); bool killTypeIsDefault{}; - inStream->Read(killTypeIsDefault); - if (killTypeIsDefault != 0) inStream->Read(killType); + inStream.Read(killTypeIsDefault); + if (killTypeIsDefault != 0) inStream.Read(killType); - inStream->Read(lootOwnerID); - inStream->Read(killerID); + inStream.Read(lootOwnerID); + inStream.Read(killerID); } -void GameMessages::HandleEquipItem(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleEquipItem(RakNet::BitStream& inStream, Entity* entity) { bool immediate; LWOOBJID objectID; - inStream->Read(immediate); - inStream->Read(immediate); //twice? - inStream->Read(objectID); + inStream.Read(immediate); + inStream.Read(immediate); //twice? + inStream.Read(objectID); InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; @@ -5330,13 +5296,13 @@ void GameMessages::HandleEquipItem(RakNet::BitStream* inStream, Entity* entity) Game::entityManager->SerializeEntity(entity); } -void GameMessages::HandleUnequipItem(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleUnequipItem(RakNet::BitStream& inStream, Entity* entity) { bool immediate; LWOOBJID objectID; - inStream->Read(immediate); - inStream->Read(immediate); - inStream->Read(immediate); - inStream->Read(objectID); + inStream.Read(immediate); + inStream.Read(immediate); + inStream.Read(immediate); + inStream.Read(objectID); InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; @@ -5350,7 +5316,7 @@ void GameMessages::HandleUnequipItem(RakNet::BitStream* inStream, Entity* entity Game::entityManager->SerializeEntity(entity); } -void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { // this is used for a lot more than just inventory trashing (trades, vendors, etc.) but for now since it's just used for that, that's all im going to implement bool bConfirmed = false; bool bDeleteItem = true; @@ -5364,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; @@ -5378,40 +5344,40 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream* inStream, En bool iTradeIDIsDefault = false; LWOOBJID iTradeID = LWOOBJID_EMPTY; - inStream->Read(bConfirmed); - inStream->Read(bDeleteItem); - inStream->Read(bOutSuccess); - inStream->Read(eInvTypeIsDefault); - if (eInvTypeIsDefault) inStream->Read(eInvType); - inStream->Read(eLootTypeSourceIsDefault); - if (eLootTypeSourceIsDefault) inStream->Read(eLootTypeSource); - inStream->Read(extraInfo.length); + inStream.Read(bConfirmed); + inStream.Read(bDeleteItem); + inStream.Read(bOutSuccess); + inStream.Read(eInvTypeIsDefault); + if (eInvTypeIsDefault) inStream.Read(eInvType); + inStream.Read(eLootTypeSourceIsDefault); + if (eLootTypeSourceIsDefault) inStream.Read(eLootTypeSource); + inStream.Read(extraInfo.length); if (extraInfo.length > 0) { for (uint32_t i = 0; i < extraInfo.length; ++i) { uint16_t character; - inStream->Read(character); + inStream.Read(character); extraInfo.name.push_back(character); } uint16_t nullTerm; - inStream->Read(nullTerm); - } - inStream->Read(forceDeletion); - inStream->Read(iLootTypeSourceIsDefault); - if (iLootTypeSourceIsDefault) inStream->Read(iLootTypeSource); - inStream->Read(iObjIDIsDefault); - if (iObjIDIsDefault) inStream->Read(iObjID); - inStream->Read(iObjTemplateIsDefault); - if (iObjTemplateIsDefault) inStream->Read(iObjTemplate); - inStream->Read(iRequestingObjIDIsDefault); - if (iRequestingObjIDIsDefault) inStream->Read(iRequestingObjID); - inStream->Read(iStackCountIsDefault); - if (iStackCountIsDefault) inStream->Read(iStackCount); - inStream->Read(iStackRemainingIsDefault); - if (iStackRemainingIsDefault) inStream->Read(iStackRemaining); - inStream->Read(iSubkeyIsDefault); - if (iSubkeyIsDefault) inStream->Read(iSubkey); - inStream->Read(iTradeIDIsDefault); - if (iTradeIDIsDefault) inStream->Read(iTradeID); + inStream.Read(nullTerm); + } + inStream.Read(forceDeletion); + inStream.Read(iLootTypeSourceIsDefault); + if (iLootTypeSourceIsDefault) inStream.Read(iLootTypeSource); + inStream.Read(iObjIDIsDefault); + if (iObjIDIsDefault) inStream.Read(iObjID); + inStream.Read(iObjTemplateIsDefault); + if (iObjTemplateIsDefault) inStream.Read(iObjTemplate); + inStream.Read(iRequestingObjIDIsDefault); + if (iRequestingObjIDIsDefault) inStream.Read(iRequestingObjID); + inStream.Read(iStackCountIsDefault); + if (iStackCountIsDefault) inStream.Read(iStackCount); + inStream.Read(iStackRemainingIsDefault); + if (iStackRemainingIsDefault) inStream.Read(iStackRemaining); + inStream.Read(iSubkeyIsDefault); + if (iSubkeyIsDefault) inStream.Read(iSubkey); + inStream.Read(iTradeIDIsDefault); + if (iTradeIDIsDefault) inStream.Read(iTradeID); InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; @@ -5425,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); } } } @@ -5452,19 +5419,19 @@ void GameMessages::SendSetGravityScale(const LWOOBJID& target, const float effec SEND_PACKET; } -void GameMessages::HandleMoveItemInInventory(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleMoveItemInInventory(RakNet::BitStream& inStream, Entity* entity) { bool destInvTypeIsDefault = false; int32_t destInvType = eInventoryType::INVALID; LWOOBJID iObjID; int inventoryType; int responseCode; int slot; - inStream->Read(destInvTypeIsDefault); - if (destInvTypeIsDefault) { inStream->Read(destInvType); } - inStream->Read(iObjID); - inStream->Read(inventoryType); - inStream->Read(responseCode); - inStream->Read(slot); + inStream.Read(destInvTypeIsDefault); + if (destInvTypeIsDefault) { inStream.Read(destInvType); } + inStream.Read(iObjID); + inStream.Read(inventoryType); + inStream.Read(responseCode); + inStream.Read(slot); InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; @@ -5479,7 +5446,7 @@ void GameMessages::HandleMoveItemInInventory(RakNet::BitStream* inStream, Entity Game::entityManager->SerializeEntity(entity); } -void GameMessages::HandleMoveItemBetweenInventoryTypes(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleMoveItemBetweenInventoryTypes(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { eInventoryType inventoryTypeA; eInventoryType inventoryTypeB; LWOOBJID objectID; @@ -5489,14 +5456,14 @@ void GameMessages::HandleMoveItemBetweenInventoryTypes(RakNet::BitStream* inStre bool templateIDIsDefault = false; LOT templateID = LOT_NULL; - inStream->Read(inventoryTypeA); - inStream->Read(inventoryTypeB); - inStream->Read(objectID); - inStream->Read(showFlyingLoot); - inStream->Read(stackCountIsDefault); - if (stackCountIsDefault) inStream->Read(stackCount); - inStream->Read(templateIDIsDefault); - if (templateIDIsDefault) inStream->Read(templateID); + inStream.Read(inventoryTypeA); + inStream.Read(inventoryTypeB); + inStream.Read(objectID); + inStream.Read(showFlyingLoot); + inStream.Read(stackCountIsDefault); + if (stackCountIsDefault) inStream.Read(stackCount); + inStream.Read(templateIDIsDefault); + if (templateIDIsDefault) inStream.Read(templateID); auto inv = entity->GetComponent(); if (!inv) return; @@ -5525,10 +5492,10 @@ void GameMessages::HandleMoveItemBetweenInventoryTypes(RakNet::BitStream* inStre Game::entityManager->SerializeEntity(entity); } -void GameMessages::HandleBuildModeSet(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleBuildModeSet(RakNet::BitStream& inStream, Entity* entity) { bool bStart = false; - inStream->Read(bStart); + inStream.Read(bStart); // there's more here but we don't need it (for now?) LOG("Set build mode to (%d) for (%llu)", bStart, entity->GetObjectID()); @@ -5538,7 +5505,7 @@ void GameMessages::HandleBuildModeSet(RakNet::BitStream* inStream, Entity* entit } } -void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleModularBuildFinish(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) return; Entity* character = Game::entityManager->GetEntity(user->GetLoggedInChar()); @@ -5549,7 +5516,7 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* uint8_t count; // 3 for rockets, 7 for cars - inStream->Read(count); + inStream.Read(count); auto* temp = inv->GetInventory(TEMP_MODELS); std::vector modList; @@ -5560,7 +5527,7 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* for (uint32_t k = 0; k < count; k++) { uint32_t mod; - inStream->Read(mod); + inStream.Read(mod); modList.push_back(mod); auto modToStr = GeneralUtils::to_u16string(mod); modules += u"1:" + (modToStr); @@ -5620,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; @@ -5638,7 +5603,7 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* } } -void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) return; Entity* character = Game::entityManager->GetEntity(user->GetLoggedInChar()); @@ -5673,18 +5638,18 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti LOT oldItemLOT = 0; int oldItemTYPE = 0; - inStream->Read(newSourceBAG); - inStream->Read(newSourceID); - inStream->Read(newSourceLOT); - inStream->Read(newSourceTYPE); - inStream->Read(newTargetID); - inStream->Read(newTargetLOT); - inStream->Read(newTargetTYPE); - inStream->Read(newTargetPOS); - inStream->Read(oldItemBAG); - inStream->Read(oldItemID); - inStream->Read(oldItemLOT); - inStream->Read(oldItemTYPE); + inStream.Read(newSourceBAG); + inStream.Read(newSourceID); + inStream.Read(newSourceLOT); + inStream.Read(newSourceTYPE); + inStream.Read(newTargetID); + inStream.Read(newTargetLOT); + inStream.Read(newTargetTYPE); + inStream.Read(newTargetPOS); + inStream.Read(oldItemBAG); + inStream.Read(oldItemID); + inStream.Read(oldItemLOT); + inStream.Read(oldItemTYPE); /* LOG("GameMessages", @@ -5749,7 +5714,7 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti } } -void GameMessages::HandleModularBuildMoveAndEquip(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleModularBuildMoveAndEquip(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { User* user = UserManager::Instance()->GetUser(sysAddr); if (!user) return; Entity* character = Game::entityManager->GetEntity(user->GetLoggedInChar()); @@ -5759,7 +5724,7 @@ void GameMessages::HandleModularBuildMoveAndEquip(RakNet::BitStream* inStream, E LOT templateID; - inStream->Read(templateID); + inStream.Read(templateID); InventoryComponent* inv = static_cast(character->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; @@ -5773,11 +5738,11 @@ void GameMessages::HandleModularBuildMoveAndEquip(RakNet::BitStream* inStream, E inv->MoveItemToInventory(item, eInventoryType::MODELS, 1, false, true); } -void GameMessages::HandlePickupItem(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandlePickupItem(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID lootObjectID; LWOOBJID playerID; - inStream->Read(lootObjectID); - inStream->Read(playerID); + inStream.Read(lootObjectID); + inStream.Read(playerID); entity->PickupItem(lootObjectID); @@ -5794,31 +5759,29 @@ void GameMessages::HandlePickupItem(RakNet::BitStream* inStream, Entity* entity) } } -void GameMessages::HandleResurrect(RakNet::BitStream* inStream, Entity* entity) { - bool immediate = inStream->ReadBit(); +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); } } } -void GameMessages::HandlePushEquippedItemsState(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandlePushEquippedItemsState(RakNet::BitStream& inStream, Entity* entity) { InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; inv->PushEquippedItems(); } -void GameMessages::HandlePopEquippedItemsState(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandlePopEquippedItemsState(RakNet::BitStream& inStream, Entity* entity) { InventoryComponent* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); if (!inv) return; inv->PopEquippedItems(); @@ -5826,10 +5789,10 @@ void GameMessages::HandlePopEquippedItemsState(RakNet::BitStream* inStream, Enti } -void GameMessages::HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleClientItemConsumed(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID itemConsumed; - inStream->Read(itemConsumed); + inStream.Read(itemConsumed); auto* inventory = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); @@ -5852,10 +5815,10 @@ void GameMessages::HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* } -void GameMessages::HandleUseNonEquipmentItem(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleUseNonEquipmentItem(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID itemConsumed; - inStream->Read(itemConsumed); + inStream.Read(itemConsumed); auto* inv = static_cast(entity->GetComponent(eReplicaComponentType::INVENTORY)); @@ -5866,7 +5829,7 @@ void GameMessages::HandleUseNonEquipmentItem(RakNet::BitStream* inStream, Entity if (item) item->UseNonEquip(item); } -void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleMatchRequest(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID activator; //std::map additionalPlayers; uint32_t playerChoicesLen; @@ -5874,19 +5837,19 @@ void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entit int type; int value; - inStream->Read(activator); - inStream->Read(playerChoicesLen); + inStream.Read(activator); + inStream.Read(playerChoicesLen); for (uint32_t i = 0; i < playerChoicesLen; ++i) { uint16_t character; - inStream->Read(character); + inStream.Read(character); playerChoices.push_back(character); } if (playerChoicesLen > 0) { uint16_t nullTerm; - inStream->Read(nullTerm); + inStream.Read(nullTerm); } - inStream->Read(type); - inStream->Read(value); + inStream.Read(type); + inStream.Read(value); std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); if (type == 0) { // join @@ -5912,11 +5875,11 @@ void GameMessages::HandleMatchRequest(RakNet::BitStream* inStream, Entity* entit } } -void GameMessages::HandleGetHotPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleGetHotPropertyData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { SendGetHotPropertyData(inStream, entity, sysAddr); } -void GameMessages::SendGetHotPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::SendGetHotPropertyData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; /** @@ -5957,17 +5920,17 @@ void GameMessages::SendGetHotPropertyData(RakNet::BitStream* inStream, Entity* e SEND_PACKET*/ } -void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleReportBug(RakNet::BitStream& inStream, Entity* entity) { //Definitely not stolen from autogenerated code, no sir: IBugReports::Info reportInfo; //Reading: uint32_t messageLength; - inStream->Read(messageLength); + inStream.Read(messageLength); for (uint32_t i = 0; i < (messageLength); ++i) { uint16_t character; - inStream->Read(character); + inStream.Read(character); reportInfo.body.push_back(static_cast(character)); } @@ -5975,26 +5938,26 @@ void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) if (character) reportInfo.characterId = character->GetID(); uint32_t clientVersionLength; - inStream->Read(clientVersionLength); + inStream.Read(clientVersionLength); for (unsigned int k = 0; k < clientVersionLength; k++) { unsigned char character; - inStream->Read(character); + inStream.Read(character); reportInfo.clientVersion.push_back(character); } uint32_t nOtherPlayerIDLength; - inStream->Read(nOtherPlayerIDLength); + inStream.Read(nOtherPlayerIDLength); for (unsigned int k = 0; k < nOtherPlayerIDLength; k++) { unsigned char character; - inStream->Read(character); + inStream.Read(character); reportInfo.otherPlayer.push_back(character); } uint32_t selectionLength; - inStream->Read(selectionLength); + inStream.Read(selectionLength); for (unsigned int k = 0; k < selectionLength; k++) { unsigned char character; - inStream->Read(character); + inStream.Read(character); reportInfo.selection.push_back(character); } @@ -6002,7 +5965,7 @@ void GameMessages::HandleReportBug(RakNet::BitStream* inStream, Entity* entity) } void -GameMessages::HandleClientRailMovementReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +GameMessages::HandleClientRailMovementReady(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); for (const auto* possibleRail : possibleRails) { const auto* rail = possibleRail->GetComponent(); @@ -6012,8 +5975,8 @@ GameMessages::HandleClientRailMovementReady(RakNet::BitStream* inStream, Entity* } } -void GameMessages::HandleCancelRailMovement(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { - const auto immediate = inStream->ReadBit(); +void GameMessages::HandleCancelRailMovement(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { + const auto immediate = inStream.ReadBit(); const auto possibleRails = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RAIL_ACTIVATOR); for (const auto* possibleRail : possibleRails) { @@ -6024,43 +5987,41 @@ void GameMessages::HandleCancelRailMovement(RakNet::BitStream* inStream, Entity* } } -void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream* inStream, Entity* entity, +void GameMessages::HandlePlayerRailArrivedNotification(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t pathNameLength; - inStream->Read(pathNameLength); + inStream.Read(pathNameLength); std::u16string pathName; for (auto k = 0; k < pathNameLength; k++) { uint16_t c; - inStream->Read(c); + inStream.Read(c); pathName.push_back(c); } int32_t waypointNumber; - inStream->Read(waypointNumber); + inStream.Read(waypointNumber); 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); } } -void GameMessages::HandleModifyPlayerZoneStatistic(RakNet::BitStream* inStream, Entity* entity) { - const auto set = inStream->ReadBit(); +void GameMessages::HandleModifyPlayerZoneStatistic(RakNet::BitStream& inStream, Entity* entity) { + const auto set = inStream.ReadBit(); const auto statisticsName = GeneralUtils::ReadWString(inStream); int32_t value; - if (inStream->ReadBit()) { - inStream->Read(value); + if (inStream.ReadBit()) { + inStream.Read(value); } else { value = 0; } LWOMAPID zone; - if (inStream->ReadBit()) { - inStream->Read(zone); + if (inStream.ReadBit()) { + inStream.Read(zone); } else { zone = LWOMAPID_INVALID; } @@ -6072,13 +6033,13 @@ void GameMessages::HandleModifyPlayerZoneStatistic(RakNet::BitStream* inStream, } } -void GameMessages::HandleUpdatePlayerStatistic(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleUpdatePlayerStatistic(RakNet::BitStream& inStream, Entity* entity) { int32_t updateID; - inStream->Read(updateID); + inStream.Read(updateID); int64_t updateValue; - if (inStream->ReadBit()) { - inStream->Read(updateValue); + if (inStream.ReadBit()) { + inStream.Read(updateValue); } else { updateValue = 1; } @@ -6089,14 +6050,14 @@ void GameMessages::HandleUpdatePlayerStatistic(RakNet::BitStream* inStream, Enti } } -void GameMessages::HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleDeactivateBubbleBuff(RakNet::BitStream& inStream, Entity* entity) { auto controllablePhysicsComponent = entity->GetComponent(); if (controllablePhysicsComponent) controllablePhysicsComponent->DeactivateBubbleBuff(); } -void GameMessages::HandleActivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleActivateBubbleBuff(RakNet::BitStream& inStream, Entity* entity) { bool specialAnimations; - if (!inStream->Read(specialAnimations)) return; + if (!inStream.Read(specialAnimations)) return; std::u16string type = GeneralUtils::ReadWString(inStream); auto bubbleType = eBubbleType::DEFAULT; @@ -6129,9 +6090,9 @@ void GameMessages::SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const S SEND_PACKET; } -void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream& inStream, Entity* entity) { LWOOBJID player_id; - inStream->Read(player_id); + inStream.Read(player_id); auto target = Game::entityManager->GetEntity(player_id); entity->TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, target); }; @@ -6165,25 +6126,25 @@ void GameMessages::SendShowBillboardInteractIcon(const SystemAddress& sysAddr, L else SEND_PACKET } -void GameMessages::HandleRequestActivityExit(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleRequestActivityExit(RakNet::BitStream& inStream, Entity* entity) { bool canceled = false; - inStream->Read(canceled); + inStream.Read(canceled); if (!canceled) return; LWOOBJID player_id = LWOOBJID_EMPTY; - inStream->Read(player_id); + inStream.Read(player_id); auto player = Game::entityManager->GetEntity(player_id); if (!entity || !player) return; entity->RequestActivityExit(entity, player_id, canceled); } -void GameMessages::HandleAddDonationItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleAddDonationItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { uint32_t count = 1; bool hasCount = false; - inStream->Read(hasCount); - if (hasCount) inStream->Read(count); + inStream.Read(hasCount); + if (hasCount) inStream.Read(count); LWOOBJID itemId = LWOOBJID_EMPTY; - inStream->Read(itemId); + inStream.Read(itemId); if (!itemId) return; auto* donationVendorComponent = entity->GetComponent(); @@ -6207,15 +6168,15 @@ void GameMessages::HandleAddDonationItem(RakNet::BitStream* inStream, Entity* en inventoryComponent->MoveItemToInventory(item, eInventoryType::DONATION, count, true, false, true); } -void GameMessages::HandleRemoveDonationItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { +void GameMessages::HandleRemoveDonationItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr) { bool confirmed = false; - inStream->Read(confirmed); + inStream.Read(confirmed); uint32_t count = 1; bool hasCount = false; - inStream->Read(hasCount); - if (hasCount) inStream->Read(count); + inStream.Read(hasCount); + if (hasCount) inStream.Read(count); LWOOBJID itemId = LWOOBJID_EMPTY; - inStream->Read(itemId); + inStream.Read(itemId); if (!itemId) return; User* user = UserManager::Instance()->GetUser(sysAddr); @@ -6232,7 +6193,7 @@ void GameMessages::HandleRemoveDonationItem(RakNet::BitStream* inStream, Entity* inventoryComponent->MoveItemToInventory(item, eInventoryType::BRICKS, count, true, false, true); } -void GameMessages::HandleConfirmDonationOnPlayer(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleConfirmDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity) { auto* inventoryComponent = entity->GetComponent(); if (!inventoryComponent) return; auto* missionComponent = entity->GetComponent(); @@ -6264,7 +6225,7 @@ void GameMessages::HandleConfirmDonationOnPlayer(RakNet::BitStream* inStream, En characterComponent->SetCurrentInteracting(LWOOBJID_EMPTY); } -void GameMessages::HandleCancelDonationOnPlayer(RakNet::BitStream* inStream, Entity* entity) { +void GameMessages::HandleCancelDonationOnPlayer(RakNet::BitStream& inStream, Entity* entity) { auto* inventoryComponent = entity->GetComponent(); if (!inventoryComponent) return; auto* inventory = inventoryComponent->GetInventory(eInventoryType::DONATION); @@ -6277,3 +6238,30 @@ 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(eGameMessageType::SLASH_COMMAND_TEXT_FEEDBACK); + bitStream.Write(text.size()); + bitStream.Write(text); + auto sysAddr = entity->GetSystemAddress(); + SEND_PACKET; +} + +void GameMessages::SendForceCameraTargetCycle(Entity* entity, bool bForceCycling, eCameraTargetCyclingMode cyclingMode, LWOOBJID optionalTargetID) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(eGameMessageType::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 a96bbf602..e3c16471b 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -38,6 +38,13 @@ enum class eUseItemResponse : uint32_t; 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; @@ -135,7 +142,7 @@ namespace GameMessages { void SendVendorOpenWindow(Entity* entity, const SystemAddress& sysAddr); void SendVendorStatusUpdate(Entity* entity, const SystemAddress& sysAddr, bool bUpdateOnly = false); - void SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr); + void SendVendorTransactionResult(Entity* entity, const SystemAddress& sysAddr, eVendorTransactionResult result); void SendRemoveItemFromInventory(Entity* entity, const SystemAddress& sysAddr, LWOOBJID iObjID, LOT templateID, int inventoryType, uint32_t stackCount, uint32_t stackRemaining); void SendConsumeClientItem(Entity* entity, bool bSuccess, LWOOBJID item); @@ -145,7 +152,7 @@ namespace GameMessages { void SendMatchResponse(Entity* entity, const SystemAddress& sysAddr, int response); void SendMatchUpdate(Entity* entity, const SystemAddress& sysAddr, std::string data, eMatchUpdate type); - void HandleUnUseModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleUnUseModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID); // https://lcdruniverse.org/lu_packets/lu_packets/world/gm/client/struct.SetResurrectRestoreValues.html @@ -182,7 +189,7 @@ namespace GameMessages { * @param entity The Entity that sent the message * @param sysAddr The SystemAddress that sent the message */ - void HandleControlBehaviors(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleControlBehaviors(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); // Rails stuff void SendSetRailMovement(const LWOOBJID& objectID, bool pathGoForward, std::u16string pathName, uint32_t pathStart, @@ -196,9 +203,9 @@ namespace GameMessages { bool collisionEnabled = true, bool useDB = true, int32_t railComponentID = -1, LWOOBJID railActivatorObjectID = LWOOBJID_EMPTY); - void HandleClientRailMovementReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleCancelRailMovement(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePlayerRailArrivedNotification(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleClientRailMovementReady(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleCancelRailMovement(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePlayerRailArrivedNotification(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendNotifyClientObject(const LWOOBJID& objectID, std::u16string name, int param1 = 0, int param2 = 0, const LWOOBJID& paramObj = LWOOBJID_EMPTY, std::string paramStr = "", const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SendNotifyClientZoneObject(const LWOOBJID& objectID, const std::u16string& name, int param1, int param2, const LWOOBJID& paramObj, const std::string& paramStr, const SystemAddress& sysAddr); @@ -251,39 +258,39 @@ namespace GameMessages { void SendUGCEquipPostDeleteBasedOnEditMode(LWOOBJID objectId, const SystemAddress& sysAddr, LWOOBJID inventoryItem, int itemTotal); - void HandleSetPropertyAccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleSetPropertyAccess(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleUpdatePropertyOrModelForFilterCheck(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleQueryPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleQueryPropertyData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleSetBuildMode(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleStartBuildingWithItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleStartBuildingWithItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePropertyEditorBegin(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePropertyEditorBegin(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePropertyEditorEnd(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePropertyEditorEnd(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePropertyContentsFromClient(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePropertyContentsFromClient(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePropertyModelEquipped(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePropertyModelEquipped(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePlacePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePlacePropertyModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleUpdatePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleUpdatePropertyModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleDeletePropertyModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleDeletePropertyModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleBBBLoadItemRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleBBBLoadItemRequest(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleBBBSaveRequest(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePropertyEntranceSync(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleEnterProperty(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleEnterProperty(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleSetConsumableItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, bool allowGhostUpdates = true, bool bCloseMultiInteract = true, bool bSendServerNotify = false, bool bUseControlledObjectForAudioListener = false, @@ -292,7 +299,7 @@ namespace GameMessages { void SendEndCinematic(LWOOBJID objectID, std::u16string pathName, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS, float leadOut = -1.0f, bool leavePlayerLocked = false); - void HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleCinematicUpdate(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr, LWOOBJID originator = LWOOBJID_EMPTY, bool bCantAttack = false, bool bCantEquip = false, @@ -344,7 +351,7 @@ namespace GameMessages { void SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1 = 0, int param2 = 0); - void HandleVerifyAck(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleVerifyAck(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJID lootOwnerID, const SystemAddress& sysAddr); @@ -361,13 +368,13 @@ namespace GameMessages { void SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, const std::vector& items, const SystemAddress& sysAddr); - void HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleClientTradeRequest(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleClientTradeCancel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleClientTradeCancel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleClientTradeAccept(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleClientTradeAccept(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleClientTradeUpdate(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); //Pets: void SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId, LWOOBJID playerTamingId, bool bForceTeleport, ePetTamingNotifyType notifyType, NiPoint3 petsDestPos, NiPoint3 telePos, NiQuaternion teleRot, const SystemAddress& sysAddr); @@ -402,23 +409,23 @@ namespace GameMessages { void SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatus, std::u16string name, std::u16string ownerName, const SystemAddress& sysAddr); - void HandleClientExitTamingMinigame(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleClientExitTamingMinigame(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleStartServerPetMinigameTimer(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleStartServerPetMinigameTimer(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePetTamingTryBuild(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePetTamingTryBuild(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleNotifyTamingBuildSuccess(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleNotifyTamingBuildSuccess(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleRequestSetPetName(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleRequestSetPetName(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleCommandPet(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleCommandPet(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleDespawnPet(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleDespawnPet(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleMessageBoxResponse(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleChoiceBoxRespond(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleChoiceBoxRespond(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap = false, bool isZoneStart = false, LWOOBJID sender = LWOOBJID_EMPTY); @@ -455,7 +462,7 @@ namespace GameMessages { * @param entity The Entity that is dismounting * @param sysAddr the system address to send game message responses to */ - void HandleDismountComplete(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleDismountComplete(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); /** * @brief Handle acknowledging that the client possessed something @@ -464,7 +471,7 @@ namespace GameMessages { * @param entity The Entity that is possessing * @param sysAddr the system address to send game message responses to */ - void HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleAcknowledgePossession(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); /** * @brief A request from a client to get the hot properties that would appear on the news feed @@ -474,7 +481,7 @@ namespace GameMessages { * @param entity The Entity that sent the request * @param sysAddr The SystemAddress of the Entity that sent the request */ - void HandleGetHotPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleGetHotPropertyData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); /** * @brief A request from a client to get the hot properties that would appear on the news feed @@ -496,26 +503,26 @@ namespace GameMessages { * @param entity The Entity that sent the request * @param sysAddr The SystemAddress of the Entity that sent the request */ - void SendGetHotPropertyData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void SendGetHotPropertyData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); //Racing: - void HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleModuleAssemblyQueryData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleModularAssemblyNIFCompleted(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleModularAssemblyNIFCompleted(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleVehicleSetWheelLockState(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleVehicleSetWheelLockState(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleRacingClientReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleRacingClientReady(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleRequestDie(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleVehicleNotifyServerRemovePassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleVehicleNotifyServerRemovePassiveBoostAction(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleRacingPlayerInfoResetFinished(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleRacingPlayerInfoResetFinished(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleVehicleNotifyHitImaginationServer(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleVehicleNotifyHitImaginationServer(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendModuleAssemblyDBDataForClient(LWOOBJID objectId, LWOOBJID assemblyID, const std::u16string& data, const SystemAddress& sysAddr); @@ -555,7 +562,7 @@ namespace GameMessages { bool bUseLeaderboards ); - void HandleUpdatePropertyPerformanceCost(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleUpdatePropertyPerformanceCost(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendNotifyClientShootingGalleryScore(LWOOBJID objectId, const SystemAddress& sysAddr, float addTime, @@ -564,20 +571,20 @@ namespace GameMessages { NiPoint3 targetPos ); - void HandleUpdateShootingGalleryRotation(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleUpdateShootingGalleryRotation(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendUpdateReputation(const LWOOBJID objectId, const int64_t reputation, const SystemAddress& sysAddr); // Leaderboards void SendActivitySummaryLeaderboardData(const LWOOBJID& objectID, const Leaderboard* leaderboard, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); - void HandleActivitySummaryLeaderboardData(RakNet::BitStream* instream, Entity* entity, const SystemAddress& sysAddr); + void HandleActivitySummaryLeaderboardData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendRequestActivitySummaryLeaderboardData(const LWOOBJID& objectID, const LWOOBJID& targetID, const SystemAddress& sysAddr, const int32_t& gameID = 0, const int32_t& queryType = 1, const int32_t& resultsEnd = 10, const int32_t& resultsStart = 0, bool weekly = false); - void HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleActivityStateChangeRequest(RakNet::BitStream* inStream, Entity* entity); + void HandleRequestActivitySummaryLeaderboardData(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleActivityStateChangeRequest(RakNet::BitStream& inStream, Entity* entity); void SendVehicleAddPassiveBoostAction(LWOOBJID objectId, const SystemAddress& sysAddr); @@ -587,82 +594,86 @@ namespace GameMessages { //NT: - void HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + 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); //Handlers: - void HandleToggleGhostReferenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleToggleGhostReferenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleSetGhostReferencePosition(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); void SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId); void SendShowBillboardInteractIcon(const SystemAddress& sysAddr, LWOOBJID objectId); - void HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSellToVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleBuybackFromVendor(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleParseChatMessage(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleToggleGhostReffrenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetGhostReffrenceOverride(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleFireEventServerSide(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleRequestPlatformResync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleQuickBuildCancel(RakNet::BitStream* inStream, Entity* entity); - void HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity); - void HandleModularBuildConvertModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleSetFlag(RakNet::BitStream* inStream, Entity* entity); - void HandleRespondToMission(RakNet::BitStream* inStream, Entity* entity); - void HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* entity); - void HandleRequestLinkedMission(RakNet::BitStream* inStream, Entity* entity); - void HandleHasBeenCollected(RakNet::BitStream* inStream, Entity* entity); - void HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* inStream, Entity* entity); - void HandlePickupCurrency(RakNet::BitStream* inStream, Entity* entity); - void HandleRequestDie(RakNet::BitStream* inStream, Entity* entity); - void HandleEquipItem(RakNet::BitStream* inStream, Entity* entity); - void HandleUnequipItem(RakNet::BitStream* inStream, Entity* entity); - void HandleRemoveItemFromInventory(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleMoveItemInInventory(RakNet::BitStream* inStream, Entity* entity); - void HandleMoveItemBetweenInventoryTypes(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleBuildModeSet(RakNet::BitStream* inStream, Entity* entity); - void HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleModularBuildMoveAndEquip(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandlePickupItem(RakNet::BitStream* inStream, Entity* entity); - void HandleResurrect(RakNet::BitStream* inStream, Entity* entity); - void HandleModifyPlayerZoneStatistic(RakNet::BitStream* inStream, Entity* entity); - void HandleUpdatePlayerStatistic(RakNet::BitStream* inStream, Entity* entity); - - void HandlePushEquippedItemsState(RakNet::BitStream* inStream, Entity* entity); - - void HandlePopEquippedItemsState(RakNet::BitStream* inStream, Entity* entity); - - void HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* entity); - - void HandleUseNonEquipmentItem(RakNet::BitStream* inStream, Entity* entity); - - void HandleMatchRequest(RakNet::BitStream* inStream, Entity* entity); - - void HandleReportBug(RakNet::BitStream* inStream, Entity* entity); + void HandleBuyFromVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleSellToVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleBuybackFromVendor(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleParseChatMessage(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleToggleGhostReffrenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleSetGhostReffrenceOverride(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleFireEventServerSide(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleRequestPlatformResync(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleQuickBuildCancel(RakNet::BitStream& inStream, Entity* entity); + void HandleRequestUse(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePlayEmote(RakNet::BitStream& inStream, Entity* entity); + void HandleModularBuildConvertModel(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleSetFlag(RakNet::BitStream& inStream, Entity* entity); + void HandleRespondToMission(RakNet::BitStream& inStream, Entity* entity); + void HandleMissionDialogOK(RakNet::BitStream& inStream, Entity* entity); + void HandleRequestLinkedMission(RakNet::BitStream& inStream, Entity* entity); + void HandleHasBeenCollected(RakNet::BitStream& inStream, Entity* entity); + void HandleNotifyServerLevelProcessingComplete(RakNet::BitStream& inStream, Entity* entity); + void HandlePickupCurrency(RakNet::BitStream& inStream, Entity* entity); + void HandleRequestDie(RakNet::BitStream& inStream, Entity* entity); + void HandleEquipItem(RakNet::BitStream& inStream, Entity* entity); + void HandleUnequipItem(RakNet::BitStream& inStream, Entity* entity); + void HandleRemoveItemFromInventory(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleMoveItemInInventory(RakNet::BitStream& inStream, Entity* entity); + void HandleMoveItemBetweenInventoryTypes(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleBuildModeSet(RakNet::BitStream& inStream, Entity* entity); + void HandleModularBuildFinish(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleDoneArrangingWithItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandleModularBuildMoveAndEquip(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + void HandlePickupItem(RakNet::BitStream& inStream, Entity* entity); + void HandleResurrect(RakNet::BitStream& inStream, Entity* entity); + void HandleModifyPlayerZoneStatistic(RakNet::BitStream& inStream, Entity* entity); + void HandleUpdatePlayerStatistic(RakNet::BitStream& inStream, Entity* entity); + + void HandlePushEquippedItemsState(RakNet::BitStream& inStream, Entity* entity); + + void HandlePopEquippedItemsState(RakNet::BitStream& inStream, Entity* entity); + + void HandleClientItemConsumed(RakNet::BitStream& inStream, Entity* entity); + + void HandleUseNonEquipmentItem(RakNet::BitStream& inStream, Entity* entity); + + void HandleMatchRequest(RakNet::BitStream& inStream, Entity* entity); + + void HandleReportBug(RakNet::BitStream& inStream, Entity* entity); void SendRemoveBuff(Entity* entity, bool fromUnEquip, bool removeImmunity, uint32_t buffId); // bubble - void HandleDeactivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); + void HandleDeactivateBubbleBuff(RakNet::BitStream& inStream, Entity* entity); - void HandleActivateBubbleBuff(RakNet::BitStream* inStream, Entity* entity); + void HandleActivateBubbleBuff(RakNet::BitStream& inStream, Entity* entity); void SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); void SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr); - void HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity); - void HandleRequestActivityExit(RakNet::BitStream* inStream, Entity* entity); + void HandleZoneSummaryDismissed(RakNet::BitStream& inStream, Entity* entity); + void HandleRequestActivityExit(RakNet::BitStream& inStream, Entity* entity); // Donation vendor - void HandleAddDonationItem(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - 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 HandleAddDonationItem(RakNet::BitStream& inStream, Entity* entity, const SystemAddress& sysAddr); + 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 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 090d82741..c15090c03 100644 --- a/dGame/dGameMessages/RequestServerProjectileImpact.h +++ b/dGame/dGameMessages/RequestServerProjectileImpact.h @@ -19,44 +19,44 @@ class RequestServerProjectileImpact { sBitStream = _sBitStream; } - RequestServerProjectileImpact(RakNet::BitStream* stream) : RequestServerProjectileImpact() { + RequestServerProjectileImpact(RakNet::BitStream& stream) : RequestServerProjectileImpact() { Deserialize(stream); } ~RequestServerProjectileImpact() { } - void Serialize(RakNet::BitStream* stream) { - stream->Write(eGameMessageType::REQUEST_SERVER_PROJECTILE_IMPACT); + void Serialize(RakNet::BitStream& stream) { + stream.Write(eGameMessageType::REQUEST_SERVER_PROJECTILE_IMPACT); - stream->Write(i64LocalID != LWOOBJID_EMPTY); - if (i64LocalID != LWOOBJID_EMPTY) stream->Write(i64LocalID); + stream.Write(i64LocalID != LWOOBJID_EMPTY); + if (i64LocalID != LWOOBJID_EMPTY) stream.Write(i64LocalID); - stream->Write(i64TargetID != LWOOBJID_EMPTY); - if (i64TargetID != LWOOBJID_EMPTY) stream->Write(i64TargetID); + stream.Write(i64TargetID != LWOOBJID_EMPTY); + if (i64TargetID != LWOOBJID_EMPTY) stream.Write(i64TargetID); uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); + stream.Write(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); + stream.Write(sBitStream[k]); } } - bool Deserialize(RakNet::BitStream* stream) { + bool Deserialize(RakNet::BitStream& stream) { bool i64LocalIDIsDefault{}; - stream->Read(i64LocalIDIsDefault); - if (i64LocalIDIsDefault != 0) stream->Read(i64LocalID); + stream.Read(i64LocalIDIsDefault); + if (i64LocalIDIsDefault != 0) stream.Read(i64LocalID); bool i64TargetIDIsDefault{}; - stream->Read(i64TargetIDIsDefault); - if (i64TargetIDIsDefault != 0) stream->Read(i64TargetID); + stream.Read(i64TargetIDIsDefault); + if (i64TargetIDIsDefault != 0) stream.Read(i64TargetID); uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); + stream.Read(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { unsigned char character; - stream->Read(character); + stream.Read(character); sBitStream.push_back(character); } diff --git a/dGame/dGameMessages/StartSkill.h b/dGame/dGameMessages/StartSkill.h index 6b0d267ac..bc0f18d73 100644 --- a/dGame/dGameMessages/StartSkill.h +++ b/dGame/dGameMessages/StartSkill.h @@ -36,92 +36,92 @@ class StartSkill { uiSkillHandle = _uiSkillHandle; } - StartSkill(RakNet::BitStream* stream) : StartSkill() { + StartSkill(RakNet::BitStream& stream) : StartSkill() { Deserialize(stream); } ~StartSkill() { } - void Serialize(RakNet::BitStream* stream) { - stream->Write(eGameMessageType::START_SKILL); + void Serialize(RakNet::BitStream& stream) { + stream.Write(eGameMessageType::START_SKILL); - stream->Write(bUsedMouse); + stream.Write(bUsedMouse); - stream->Write(consumableItemID != LWOOBJID_EMPTY); - if (consumableItemID != LWOOBJID_EMPTY) stream->Write(consumableItemID); + stream.Write(consumableItemID != LWOOBJID_EMPTY); + if (consumableItemID != LWOOBJID_EMPTY) stream.Write(consumableItemID); - stream->Write(fCasterLatency != 0.0f); - if (fCasterLatency != 0.0f) stream->Write(fCasterLatency); + stream.Write(fCasterLatency != 0.0f); + if (fCasterLatency != 0.0f) stream.Write(fCasterLatency); - stream->Write(iCastType != 0); - if (iCastType != 0) stream->Write(iCastType); + stream.Write(iCastType != 0); + if (iCastType != 0) stream.Write(iCastType); - stream->Write(lastClickedPosit != NiPoint3Constant::ZERO); - if (lastClickedPosit != NiPoint3Constant::ZERO) stream->Write(lastClickedPosit); + stream.Write(lastClickedPosit != NiPoint3Constant::ZERO); + if (lastClickedPosit != NiPoint3Constant::ZERO) stream.Write(lastClickedPosit); - stream->Write(optionalOriginatorID); + stream.Write(optionalOriginatorID); - stream->Write(optionalTargetID != LWOOBJID_EMPTY); - if (optionalTargetID != LWOOBJID_EMPTY) stream->Write(optionalTargetID); + stream.Write(optionalTargetID != LWOOBJID_EMPTY); + if (optionalTargetID != LWOOBJID_EMPTY) stream.Write(optionalTargetID); - stream->Write(originatorRot != NiQuaternionConstant::IDENTITY); - if (originatorRot != NiQuaternionConstant::IDENTITY) stream->Write(originatorRot); + stream.Write(originatorRot != NiQuaternionConstant::IDENTITY); + if (originatorRot != NiQuaternionConstant::IDENTITY) stream.Write(originatorRot); uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); + stream.Write(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); + stream.Write(sBitStream[k]); } - stream->Write(skillID); + stream.Write(skillID); - stream->Write(uiSkillHandle != 0); - if (uiSkillHandle != 0) stream->Write(uiSkillHandle); + stream.Write(uiSkillHandle != 0); + if (uiSkillHandle != 0) stream.Write(uiSkillHandle); } - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bUsedMouse); + bool Deserialize(RakNet::BitStream& stream) { + stream.Read(bUsedMouse); bool consumableItemIDIsDefault{}; - stream->Read(consumableItemIDIsDefault); - if (consumableItemIDIsDefault != 0) stream->Read(consumableItemID); + stream.Read(consumableItemIDIsDefault); + if (consumableItemIDIsDefault != 0) stream.Read(consumableItemID); bool fCasterLatencyIsDefault{}; - stream->Read(fCasterLatencyIsDefault); - if (fCasterLatencyIsDefault != 0) stream->Read(fCasterLatency); + stream.Read(fCasterLatencyIsDefault); + if (fCasterLatencyIsDefault != 0) stream.Read(fCasterLatency); bool iCastTypeIsDefault{}; - stream->Read(iCastTypeIsDefault); - if (iCastTypeIsDefault != 0) stream->Read(iCastType); + stream.Read(iCastTypeIsDefault); + if (iCastTypeIsDefault != 0) stream.Read(iCastType); bool lastClickedPositIsDefault{}; - stream->Read(lastClickedPositIsDefault); - if (lastClickedPositIsDefault != 0) stream->Read(lastClickedPosit); + stream.Read(lastClickedPositIsDefault); + if (lastClickedPositIsDefault != 0) stream.Read(lastClickedPosit); - stream->Read(optionalOriginatorID); + stream.Read(optionalOriginatorID); bool optionalTargetIDIsDefault{}; - stream->Read(optionalTargetIDIsDefault); - if (optionalTargetIDIsDefault != 0) stream->Read(optionalTargetID); + stream.Read(optionalTargetIDIsDefault); + if (optionalTargetIDIsDefault != 0) stream.Read(optionalTargetID); bool originatorRotIsDefault{}; - stream->Read(originatorRotIsDefault); - if (originatorRotIsDefault != 0) stream->Read(originatorRot); + stream.Read(originatorRotIsDefault); + if (originatorRotIsDefault != 0) stream.Read(originatorRot); uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); + stream.Read(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { unsigned char character; - stream->Read(character); + stream.Read(character); sBitStream.push_back(character); } - stream->Read(skillID); + stream.Read(skillID); bool uiSkillHandleIsDefault{}; - stream->Read(uiSkillHandleIsDefault); - if (uiSkillHandleIsDefault != 0) stream->Read(uiSkillHandle); + stream.Read(uiSkillHandleIsDefault); + if (uiSkillHandleIsDefault != 0) stream.Read(uiSkillHandle); return true; } diff --git a/dGame/dGameMessages/SyncSkill.h b/dGame/dGameMessages/SyncSkill.h index 6485199ea..b881d2705 100644 --- a/dGame/dGameMessages/SyncSkill.h +++ b/dGame/dGameMessages/SyncSkill.h @@ -21,39 +21,39 @@ class SyncSkill { uiSkillHandle = _uiSkillHandle; } - SyncSkill(RakNet::BitStream* stream) : SyncSkill() { + SyncSkill(RakNet::BitStream& stream) : SyncSkill() { Deserialize(stream); } ~SyncSkill() { } - void Serialize(RakNet::BitStream* stream) { - stream->Write(eGameMessageType::SYNC_SKILL); + void Serialize(RakNet::BitStream& stream) { + stream.Write(eGameMessageType::SYNC_SKILL); - stream->Write(bDone); + stream.Write(bDone); uint32_t sBitStreamLength = sBitStream.length(); - stream->Write(sBitStreamLength); + stream.Write(sBitStreamLength); for (unsigned int k = 0; k < sBitStreamLength; k++) { - stream->Write(sBitStream[k]); + stream.Write(sBitStream[k]); } - stream->Write(uiBehaviorHandle); - stream->Write(uiSkillHandle); + stream.Write(uiBehaviorHandle); + stream.Write(uiSkillHandle); } - bool Deserialize(RakNet::BitStream* stream) { - stream->Read(bDone); + bool Deserialize(RakNet::BitStream& stream) { + stream.Read(bDone); uint32_t sBitStreamLength{}; - stream->Read(sBitStreamLength); + stream.Read(sBitStreamLength); for (uint32_t k = 0; k < sBitStreamLength; k++) { unsigned char character; - stream->Read(character); + stream.Read(character); sBitStream.push_back(character); } - stream->Read(uiBehaviorHandle); - stream->Read(uiSkillHandle); + stream.Read(uiBehaviorHandle); + stream.Read(uiSkillHandle); return true; } 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/dPropertyBehaviors/BlockDefinition.cpp b/dGame/dPropertyBehaviors/BlockDefinition.cpp index 2950ac822..e67a90d8b 100644 --- a/dGame/dPropertyBehaviors/BlockDefinition.cpp +++ b/dGame/dPropertyBehaviors/BlockDefinition.cpp @@ -2,8 +2,8 @@ BlockDefinition BlockDefinition::blockDefinitionDefault{}; -BlockDefinition::BlockDefinition(std::string defaultValue, float minimumValue, float maximumValue) { - this->defaultValue = defaultValue; - this->minimumValue = minimumValue; - this->maximumValue = maximumValue; +BlockDefinition::BlockDefinition(const std::string& defaultValue, const float minimumValue, const float maximumValue) + : m_DefaultValue{ defaultValue } + , m_MinimumValue{ minimumValue } + , m_MaximumValue{ maximumValue } { } diff --git a/dGame/dPropertyBehaviors/BlockDefinition.h b/dGame/dPropertyBehaviors/BlockDefinition.h index 3a5a6bf11..84722ea24 100644 --- a/dGame/dPropertyBehaviors/BlockDefinition.h +++ b/dGame/dPropertyBehaviors/BlockDefinition.h @@ -7,19 +7,20 @@ class AMFArrayValue; class BlockDefinition { public: - BlockDefinition(std::string defaultValue = "", float minimumValue = 0.0f, float maximumValue = 0.0f); + BlockDefinition(const std::string& defaultValue = "", const float minimumValue = 0.0f, const float maximumValue = 0.0f); static BlockDefinition blockDefinitionDefault; - std::string& GetDefaultValue() { return defaultValue; }; - float GetMinimumValue() { return minimumValue; }; - float GetMaximumValue() { return maximumValue; }; - void SetDefaultValue(std::string value) { defaultValue = value; }; - void SetMinimumValue(float value) { minimumValue = value; }; - void SetMaximumValue(float value) { maximumValue = value; }; + [[nodiscard]] const std::string& GetDefaultValue() const { return m_DefaultValue; } + [[nodiscard]] float GetMinimumValue() const noexcept { return m_MinimumValue; } + [[nodiscard]] float GetMaximumValue() const noexcept { return m_MaximumValue; } + void SetDefaultValue(const std::string& value) { m_DefaultValue = value; } + void SetMinimumValue(const float value) noexcept { m_MinimumValue = value; } + void SetMaximumValue(const float value) noexcept { m_MaximumValue = value; } + private: - std::string defaultValue; - float minimumValue; - float maximumValue; + std::string m_DefaultValue; + float m_MinimumValue; + float m_MaximumValue; }; #endif //!__BLOCKDEFINITION__H__ 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 73f1391d5..6a21be9b2 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.cpp @@ -1,46 +1,79 @@ #include "Action.h" #include "Amf3.h" -Action::Action() { - type = ""; - valueParameterName = ""; - valueParameterString = ""; - valueParameterDouble = 0.0; -} +#include "tinyxml2.h" -Action::Action(AMFArrayValue* arguments) { - type = ""; - valueParameterName = ""; - valueParameterString = ""; - valueParameterDouble = 0.0; - for (auto& [paramName, paramValue] : arguments->GetAssociative()) { +Action::Action(const AMFArrayValue& arguments) { + for (const auto& [paramName, paramValue] : arguments.GetAssociative()) { if (paramName == "Type") { if (paramValue->GetValueType() != eAmf::String) continue; - type = static_cast(paramValue)->GetValue(); + m_Type = static_cast(paramValue)->GetValue(); } else { - valueParameterName = paramName; + m_ValueParameterName = paramName; // Message is the only known string parameter - if (valueParameterName == "Message") { + if (m_ValueParameterName == "Message") { if (paramValue->GetValueType() != eAmf::String) continue; - valueParameterString = static_cast(paramValue)->GetValue(); + m_ValueParameterString = static_cast(paramValue)->GetValue(); } else { if (paramValue->GetValueType() != eAmf::Double) continue; - valueParameterDouble = static_cast(paramValue)->GetValue(); + m_ValueParameterDouble = static_cast(paramValue)->GetValue(); } } } } void Action::SendBehaviorBlocksToClient(AMFArrayValue& args) const { - auto* actionArgs = args.PushArray(); - actionArgs->Insert("Type", type); + auto* const actionArgs = args.PushArray(); + actionArgs->Insert("Type", m_Type); + + if (m_ValueParameterName.empty()) return; + + if (m_ValueParameterName == "Message") { + actionArgs->Insert(m_ValueParameterName, m_ValueParameterString); + } else { + 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; - auto valueParameterName = GetValueParameterName(); - if (valueParameterName.empty()) return; + action.SetAttribute("ValueParameterName", m_ValueParameterName.c_str()); - if (valueParameterName == "Message") { - actionArgs->Insert(valueParameterName, valueParameterString); + if (m_ValueParameterName == "Message") { + action.SetAttribute("Value", m_ValueParameterString.c_str()); } else { - actionArgs->Insert(valueParameterName, valueParameterDouble); + 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 df6658896..8146e08d7 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/Action.h @@ -3,6 +3,10 @@ #include +namespace tinyxml2 { + class XMLElement; +}; + class AMFArrayValue; /** @@ -11,19 +15,22 @@ class AMFArrayValue; */ class Action { public: - Action(); - Action(AMFArrayValue* arguments); - const std::string& GetType() const { return type; }; - const std::string& GetValueParameterName() const { return valueParameterName; }; - const std::string& GetValueParameterString() const { return valueParameterString; }; - const double GetValueParameterDouble() const { return valueParameterDouble; }; + Action() = default; + Action(const AMFArrayValue& arguments); + [[nodiscard]] const std::string& GetType() const { return m_Type; }; + [[nodiscard]] const std::string& GetValueParameterName() const { return m_ValueParameterName; }; + [[nodiscard]] const std::string& GetValueParameterString() const { return m_ValueParameterString; }; + [[nodiscard]] double GetValueParameterDouble() const noexcept { return m_ValueParameterDouble; }; void SendBehaviorBlocksToClient(AMFArrayValue& args) const; + + void Serialize(tinyxml2::XMLElement& action) const; + void Deserialize(const tinyxml2::XMLElement& action); private: - std::string type; - std::string valueParameterName; - std::string valueParameterString; - double valueParameterDouble; + double m_ValueParameterDouble{ 0.0 }; + std::string m_Type{ "" }; + std::string m_ValueParameterName{ "" }; + std::string m_ValueParameterString{ "" }; }; #endif //!__ACTION__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp index c2ba2eebd..36da8d738 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.cpp @@ -4,27 +4,20 @@ #include "Amf3.h" -ActionContext::ActionContext() { - stripId = 0; - stateId = BehaviorState::HOME_STATE; +ActionContext::ActionContext(const AMFArrayValue& arguments, const std::string& customStateKey, const std::string& customStripKey) + : m_StripId{ GetStripIdFromArgument(arguments, customStripKey) } + , m_StateId{ GetBehaviorStateFromArgument(arguments, customStateKey) } { } -ActionContext::ActionContext(AMFArrayValue* arguments, std::string customStateKey, std::string customStripKey) { - stripId = 0; - stateId = BehaviorState::HOME_STATE; - stripId = GetStripIdFromArgument(arguments, customStripKey); - stateId = GetBehaviorStateFromArgument(arguments, customStateKey); -} - -BehaviorState ActionContext::GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key) { - auto* stateIDValue = arguments->Get(key); +BehaviorState ActionContext::GetBehaviorStateFromArgument(const AMFArrayValue& arguments, const std::string& key) const { + const auto* const stateIDValue = arguments.Get(key); if (!stateIDValue) throw std::invalid_argument("Unable to find behavior state from argument \"" + key + "\""); return static_cast(stateIDValue->GetValue()); } -StripId ActionContext::GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key) { - auto* stripIdValue = arguments->Get(key); +StripId ActionContext::GetStripIdFromArgument(const AMFArrayValue& arguments, const std::string& key) const { + const auto* const stripIdValue = arguments.Get(key); if (!stripIdValue) throw std::invalid_argument("Unable to find strip ID from argument \"" + key + "\""); return static_cast(stripIdValue->GetValue()); diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h index 91e91e728..8ecea8a2b 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/ActionContext.h @@ -12,15 +12,16 @@ class AMFArrayValue; */ class ActionContext { public: - ActionContext(); - ActionContext(AMFArrayValue* arguments, std::string customStateKey = "stateID", std::string customStripKey = "stripID"); - const StripId GetStripId() const { return stripId; }; - const BehaviorState GetStateId() const { return stateId; }; + ActionContext() noexcept = default; + ActionContext(const AMFArrayValue& arguments, const std::string& customStateKey = "stateID", const std::string& customStripKey = "stripID"); + [[nodiscard]] StripId GetStripId() const noexcept { return m_StripId; }; + [[nodiscard]] BehaviorState GetStateId() const noexcept { return m_StateId; }; + private: - BehaviorState GetBehaviorStateFromArgument(AMFArrayValue* arguments, const std::string& key); - StripId GetStripIdFromArgument(AMFArrayValue* arguments, const std::string& key); - StripId stripId; - BehaviorState stateId; + [[nodiscard]] BehaviorState GetBehaviorStateFromArgument(const AMFArrayValue& arguments, const std::string& key) const; + [[nodiscard]] StripId GetStripIdFromArgument(const AMFArrayValue& arguments, const std::string& key) const; + StripId m_StripId{ 0 }; + BehaviorState m_StateId{ BehaviorState::HOME_STATE }; }; #endif //!__ACTIONCONTEXT__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp index 36d9a3dc0..35b9cf0d5 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.cpp @@ -1,13 +1,14 @@ #include "AddActionMessage.h" -AddActionMessage::AddActionMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - actionContext = ActionContext(arguments); - actionIndex = GetActionIndexFromArgument(arguments); +AddActionMessage::AddActionMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_ActionIndex{ GetActionIndexFromArgument(arguments) } + , m_ActionContext{ arguments } { - auto* actionValue = arguments->GetArray("action"); + const auto* const actionValue = arguments.GetArray("action"); if (!actionValue) return; - action = Action(actionValue); + m_Action = Action{ *actionValue }; - LOG_DEBUG("actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i", actionIndex, actionContext.GetStripId(), actionContext.GetStateId(), action.GetType().c_str(), action.GetValueParameterName().c_str(), action.GetValueParameterString().c_str(), action.GetValueParameterDouble(), behaviorId); + LOG_DEBUG("actionIndex %i stripId %i stateId %i type %s valueParameterName %s valueParameterString %s valueParameterDouble %f m_BehaviorId %i", m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_Action.GetType().c_str(), m_Action.GetValueParameterName().c_str(), m_Action.GetValueParameterString().c_str(), m_Action.GetValueParameterDouble(), m_BehaviorId); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h index ac3a96122..7f94820d3 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddActionMessage.h @@ -13,14 +13,18 @@ class AMFArrayValue; */ class AddActionMessage : public BehaviorMessageBase { public: - AddActionMessage(AMFArrayValue* arguments); - int32_t GetActionIndex() const { return actionIndex; }; - Action GetAction() const { return action; }; - ActionContext GetActionContext() const { return actionContext; }; + AddActionMessage(const AMFArrayValue& arguments); + + [[nodiscard]] int32_t GetActionIndex() const noexcept { return m_ActionIndex; }; + + [[nodiscard]] const Action& GetAction() const noexcept { return m_Action; }; + + [[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; }; + private: - int32_t actionIndex = -1; - ActionContext actionContext; - Action action; + int32_t m_ActionIndex{ -1 }; + ActionContext m_ActionContext; + Action m_Action; }; #endif //!__ADDACTIONMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp index cf96ab134..45e3d9741 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.cpp @@ -1,11 +1,9 @@ #include "AddMessage.h" -AddMessage::AddMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - behaviorIndex = 0; - auto* behaviorIndexValue = arguments->Get("BehaviorIndex"); - +AddMessage::AddMessage(const AMFArrayValue& arguments) : BehaviorMessageBase{ arguments } { + const auto* const behaviorIndexValue = arguments.Get("BehaviorIndex"); if (!behaviorIndexValue) return; - behaviorIndex = static_cast(behaviorIndexValue->GetValue()); - LOG_DEBUG("behaviorId %i index %i", behaviorId, behaviorIndex); + m_BehaviorIndex = static_cast(behaviorIndexValue->GetValue()); + LOG_DEBUG("behaviorId %i index %i", m_BehaviorId, m_BehaviorIndex); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h index 766276655..8bf0b70cf 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddMessage.h @@ -9,10 +9,11 @@ */ class AddMessage : public BehaviorMessageBase { public: - AddMessage(AMFArrayValue* arguments); - const uint32_t GetBehaviorIndex() const { return behaviorIndex; }; + AddMessage(const AMFArrayValue& arguments); + [[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; }; + private: - uint32_t behaviorIndex; + uint32_t m_BehaviorIndex{ 0 }; }; #endif //!__ADDMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp index ac6e8db7a..c7207b33f 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.cpp @@ -2,27 +2,24 @@ #include "Action.h" -AddStripMessage::AddStripMessage(AMFArrayValue* const arguments) : BehaviorMessageBase{ arguments } { - actionContext = ActionContext(arguments); - position = StripUiPosition(arguments); +AddStripMessage::AddStripMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_Position{ arguments } + , m_ActionContext{ arguments } { - auto* strip = arguments->GetArray("strip"); + const auto* const strip = arguments.GetArray("strip"); if (!strip) return; - auto* actions = strip->GetArray("actions"); + const auto* const actions = strip->GetArray("actions"); if (!actions) return; - for (uint32_t actionNumber = 0; actionNumber < actions->GetDense().size(); actionNumber++) { - auto* actionValue = actions->GetArray(actionNumber); + for (size_t actionNumber = 0; actionNumber < actions->GetDense().size(); ++actionNumber) { + const auto* const actionValue = actions->GetArray(actionNumber); if (!actionValue) continue; - actionsToAdd.push_back(Action(actionValue)); + m_ActionsToAdd.emplace_back(*actionValue); - LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", position.GetX(), position.GetY(), actionContext.GetStripId(), actionContext.GetStateId(), behaviorId, actionsToAdd.back().GetType().c_str(), actionsToAdd.back().GetValueParameterName().c_str(), actionsToAdd.back().GetValueParameterString().c_str(), actionsToAdd.back().GetValueParameterDouble()); + LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i t %s valueParameterName %s valueParameterString %s valueParameterDouble %f", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId, m_ActionsToAdd.back().GetType().c_str(), m_ActionsToAdd.back().GetValueParameterName().c_str(), m_ActionsToAdd.back().GetValueParameterString().c_str(), m_ActionsToAdd.back().GetValueParameterDouble()); } - LOG_DEBUG("number of actions %i", actionsToAdd.size()); -} - -std::vector AddStripMessage::GetActionsToAdd() const { - return actionsToAdd; + LOG_DEBUG("number of actions %i", m_ActionsToAdd.size()); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h index 2e2bf9a0d..a53610347 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/AddStripMessage.h @@ -18,14 +18,18 @@ class AMFArrayValue; */ class AddStripMessage : public BehaviorMessageBase { public: - AddStripMessage(AMFArrayValue* const arguments); - StripUiPosition GetPosition() const { return position; }; - ActionContext GetActionContext() const { return actionContext; }; - std::vector GetActionsToAdd() const; + AddStripMessage(const AMFArrayValue& arguments); + + [[nodiscard]] const StripUiPosition& GetPosition() const noexcept { return m_Position; } + + [[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; } + + [[nodiscard]] const std::vector& GetActionsToAdd() const noexcept { return m_ActionsToAdd; } + private: - StripUiPosition position; - ActionContext actionContext; - std::vector actionsToAdd; + StripUiPosition m_Position; + ActionContext m_ActionContext; + std::vector m_ActionsToAdd; }; #endif //!__ADDSTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp index a49a8aebb..a1cbb0648 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.cpp @@ -4,26 +4,23 @@ #include "BehaviorStates.h" #include "dCommonVars.h" -BehaviorMessageBase::BehaviorMessageBase(AMFArrayValue* arguments) { - this->behaviorId = GetBehaviorIdFromArgument(arguments); -} - -int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(AMFArrayValue* const arguments) { - const char* const key = "BehaviorID"; - const auto* const behaviorIDValue = arguments->Get(key); +int32_t BehaviorMessageBase::GetBehaviorIdFromArgument(const AMFArrayValue& arguments) { + static constexpr const char* key = "BehaviorID"; + const auto* const behaviorIDValue = arguments.Get(key); + int32_t behaviorId = DefaultBehaviorId; if (behaviorIDValue && behaviorIDValue->GetValueType() == eAmf::String) { - this->behaviorId = - GeneralUtils::TryParse(behaviorIDValue->GetValue()).value_or(this->behaviorId); - } else if (arguments->Get(key) && arguments->Get(key)->GetValueType() != eAmf::Undefined) { + behaviorId = + GeneralUtils::TryParse(behaviorIDValue->GetValue()).value_or(behaviorId); + } else if (arguments.Get(key) && arguments.Get(key)->GetValueType() != eAmf::Undefined) { throw std::invalid_argument("Unable to find behavior ID"); } - return this->behaviorId; + return behaviorId; } -int32_t BehaviorMessageBase::GetActionIndexFromArgument(AMFArrayValue* const arguments, const std::string& keyName) const { - const auto* const actionIndexAmf = arguments->Get(keyName); +int32_t BehaviorMessageBase::GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string& keyName) const { + const auto* const actionIndexAmf = arguments.Get(keyName); if (!actionIndexAmf) throw std::invalid_argument("Unable to find actionIndex"); return static_cast(actionIndexAmf->GetValue()); diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h index f55fde8ec..bb251a748 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/BehaviorMessageBase.h @@ -15,14 +15,15 @@ enum class BehaviorState : uint32_t; */ class BehaviorMessageBase { public: - static constexpr int32_t DefaultBehaviorId = -1; - [[nodiscard]] int32_t GetBehaviorId() const { return behaviorId; }; - [[nodiscard]] bool IsDefaultBehaviorId() { return behaviorId == DefaultBehaviorId; }; - BehaviorMessageBase(AMFArrayValue* const arguments); + static constexpr int32_t DefaultBehaviorId{ -1 }; + BehaviorMessageBase(const AMFArrayValue& arguments) : m_BehaviorId{ GetBehaviorIdFromArgument(arguments) } {} + [[nodiscard]] int32_t GetBehaviorId() const noexcept { return m_BehaviorId; } + [[nodiscard]] bool IsDefaultBehaviorId() const noexcept { return m_BehaviorId == DefaultBehaviorId; } + protected: - [[nodiscard]] int32_t GetBehaviorIdFromArgument(AMFArrayValue* const arguments); - [[nodiscard]] int32_t GetActionIndexFromArgument(AMFArrayValue* const arguments, const std::string& keyName = "actionIndex") const; - int32_t behaviorId = DefaultBehaviorId; + [[nodiscard]] int32_t GetBehaviorIdFromArgument(const AMFArrayValue& arguments); + [[nodiscard]] int32_t GetActionIndexFromArgument(const AMFArrayValue& arguments, const std::string& keyName = "actionIndex") const; + int32_t m_BehaviorId{ DefaultBehaviorId }; }; #endif //!__BEHAVIORMESSAGEBASE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp index 18327ecf6..1efc5aee7 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.cpp @@ -1,11 +1,11 @@ #include "MergeStripsMessage.h" -MergeStripsMessage::MergeStripsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); +MergeStripsMessage::MergeStripsMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_DstActionIndex{ GetActionIndexFromArgument(arguments, "dstActionIndex") } + , m_SourceActionContext{ arguments, "srcStateID", "srcStripID" } + , m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" } { - destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); - dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); - - LOG_DEBUG("srcstripId %i dststripId %i srcstateId %i dststateId %i dstactionIndex %i behaviorId %i", sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), dstActionIndex, behaviorId); + LOG_DEBUG("srcstripId %i dststripId %i srcstateId %i dststateId %i dstactionIndex %i behaviorId %i", m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_DstActionIndex, m_BehaviorId); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h index 7fa4d3a89..d778d6328 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MergeStripsMessage.h @@ -13,17 +13,23 @@ class AMFArrayValue; */ class MergeStripsMessage : public BehaviorMessageBase { public: - MergeStripsMessage(AMFArrayValue* arguments); - int32_t GetDstActionIndex() const { return dstActionIndex; }; - ActionContext GetSourceActionContext() const { return sourceActionContext; }; - ActionContext GetDestinationActionContext() const { return destinationActionContext; }; - const std::vector& GetMigratedActions() const { return migratedActions; }; - void SetMigratedActions(std::vector::const_iterator start, std::vector::const_iterator end) { migratedActions.assign(start, end); }; + MergeStripsMessage(const AMFArrayValue& arguments); + + [[nodiscard]] int32_t GetDstActionIndex() const noexcept { return m_DstActionIndex; } + + [[nodiscard]] const ActionContext& GetSourceActionContext() const noexcept { return m_SourceActionContext; } + + [[nodiscard]] const ActionContext& GetDestinationActionContext() const noexcept { return m_DestinationActionContext; } + + [[nodiscard]] const std::vector& GetMigratedActions() const noexcept { return m_MigratedActions; } + + void SetMigratedActions(std::vector::const_iterator start, std::vector::const_iterator end) { m_MigratedActions.assign(start, end); }; + private: - std::vector migratedActions; - ActionContext sourceActionContext; - ActionContext destinationActionContext; - int32_t dstActionIndex; + int32_t m_DstActionIndex; + std::vector m_MigratedActions; + ActionContext m_SourceActionContext; + ActionContext m_DestinationActionContext; }; #endif //!__MERGESTRIPSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp index 4d45429b7..9791bc2ae 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.cpp @@ -1,11 +1,11 @@ #include "MigrateActionsMessage.h" -MigrateActionsMessage::MigrateActionsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); - srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); +MigrateActionsMessage::MigrateActionsMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_SrcActionIndex{ GetActionIndexFromArgument(arguments, "srcActionIndex") } + , m_DstActionIndex{ GetActionIndexFromArgument(arguments, "dstActionIndex") } + , m_SourceActionContext{ arguments, "srcStateID", "srcStripID" } + , m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" } { - destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); - dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); - - LOG_DEBUG("srcactionIndex %i dstactionIndex %i srcstripId %i dststripId %i srcstateId %i dststateId %i behaviorId %i", srcActionIndex, dstActionIndex, sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), behaviorId); + LOG_DEBUG("srcactionIndex %i dstactionIndex %i srcstripId %i dststripId %i srcstateId %i dststateId %i behaviorId %i", m_SrcActionIndex, m_DstActionIndex, m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_BehaviorId); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h index 2f1ac2439..9813fbf42 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MigrateActionsMessage.h @@ -13,19 +13,26 @@ class AMFArrayValue; */ class MigrateActionsMessage : public BehaviorMessageBase { public: - MigrateActionsMessage(AMFArrayValue* arguments); - int32_t GetSrcActionIndex() const { return srcActionIndex; }; - int32_t GetDstActionIndex() const { return dstActionIndex; }; - ActionContext GetSourceActionContext() const { return sourceActionContext; }; - ActionContext GetDestinationActionContext() const { return destinationActionContext; }; - const std::vector& GetMigratedActions() const { return migratedActions; }; - void SetMigratedActions(std::vector::const_iterator start, std::vector::const_iterator end) { migratedActions.assign(start, end); }; + MigrateActionsMessage(const AMFArrayValue& arguments); + + [[nodiscard]] int32_t GetSrcActionIndex() const noexcept { return m_SrcActionIndex; } + + [[nodiscard]] int32_t GetDstActionIndex() const noexcept { return m_DstActionIndex; } + + [[nodiscard]] const ActionContext& GetSourceActionContext() const noexcept { return m_SourceActionContext; } + + [[nodiscard]] const ActionContext& GetDestinationActionContext() const noexcept { return m_DestinationActionContext; } + + [[nodiscard]] const std::vector& GetMigratedActions() const noexcept { return m_MigratedActions; } + + void SetMigratedActions(std::vector::const_iterator start, std::vector::const_iterator end) { m_MigratedActions.assign(start, end); } + private: - std::vector migratedActions; - ActionContext sourceActionContext; - ActionContext destinationActionContext; - int32_t srcActionIndex; - int32_t dstActionIndex; + int32_t m_SrcActionIndex; + int32_t m_DstActionIndex; + std::vector m_MigratedActions; + ActionContext m_SourceActionContext; + ActionContext m_DestinationActionContext; }; #endif //!__MIGRATEACTIONSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp index 5195e6766..cab5c4a3e 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.cpp @@ -1,9 +1,9 @@ #include "MoveToInventoryMessage.h" -MoveToInventoryMessage::MoveToInventoryMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - auto* behaviorIndexValue = arguments->Get("BehaviorIndex"); +MoveToInventoryMessage::MoveToInventoryMessage(const AMFArrayValue& arguments) : BehaviorMessageBase{ arguments } { + const auto* const behaviorIndexValue = arguments.Get("BehaviorIndex"); if (!behaviorIndexValue) return; - behaviorIndex = static_cast(behaviorIndexValue->GetValue()); - LOG_DEBUG("behaviorId %i behaviorIndex %i", behaviorId, behaviorIndex); + m_BehaviorIndex = static_cast(behaviorIndexValue->GetValue()); + LOG_DEBUG("behaviorId %i behaviorIndex %i", m_BehaviorId, m_BehaviorIndex); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h index dc1057666..e1f88713d 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/MoveToInventoryMessage.h @@ -7,15 +7,15 @@ class AMFArrayValue; /** * @brief Sent when a player moves a Behavior A at position B to their inventory. - * */ #pragma warning("This Control Behavior Message does not have a test yet. Non-developers can ignore this warning.") class MoveToInventoryMessage : public BehaviorMessageBase { public: - MoveToInventoryMessage(AMFArrayValue* arguments); - const uint32_t GetBehaviorIndex() const { return behaviorIndex; }; + MoveToInventoryMessage(const AMFArrayValue& arguments); + [[nodiscard]] uint32_t GetBehaviorIndex() const noexcept { return m_BehaviorIndex; }; + private: - uint32_t behaviorIndex; + uint32_t m_BehaviorIndex; }; #endif //!__MOVETOINVENTORYMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp index d612ae2a1..99fe6f6a4 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.cpp @@ -1,10 +1,10 @@ #include "RearrangeStripMessage.h" -RearrangeStripMessage::RearrangeStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - actionContext = ActionContext(arguments); - srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); +RearrangeStripMessage::RearrangeStripMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_SrcActionIndex{ GetActionIndexFromArgument(arguments, "srcActionIndex") } + , m_DstActionIndex{ GetActionIndexFromArgument(arguments, "dstActionIndex") } + , m_ActionContext{ arguments } { - dstActionIndex = GetActionIndexFromArgument(arguments, "dstActionIndex"); - - LOG_DEBUG("srcactionIndex %i dstactionIndex %i stripId %i behaviorId %i stateId %i", srcActionIndex, dstActionIndex, actionContext.GetStripId(), behaviorId, actionContext.GetStateId()); + LOG_DEBUG("srcactionIndex %i dstactionIndex %i stripId %i behaviorId %i stateId %i", m_SrcActionIndex, m_DstActionIndex, m_ActionContext.GetStripId(), m_BehaviorId, m_ActionContext.GetStateId()); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h index db12c046c..629757bf2 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RearrangeStripMessage.h @@ -10,14 +10,17 @@ */ class RearrangeStripMessage : public BehaviorMessageBase { public: - RearrangeStripMessage(AMFArrayValue* arguments); - int32_t GetSrcActionIndex() const { return srcActionIndex; }; - int32_t GetDstActionIndex() const { return dstActionIndex; }; - ActionContext GetActionContext() const { return actionContext; }; + RearrangeStripMessage(const AMFArrayValue& arguments); + + [[nodiscard]] int32_t GetSrcActionIndex() const noexcept { return m_SrcActionIndex; } + [[nodiscard]] int32_t GetDstActionIndex() const noexcept { return m_DstActionIndex; } + + [[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; } + private: - ActionContext actionContext; - int32_t srcActionIndex; - int32_t dstActionIndex; + int32_t m_SrcActionIndex; + int32_t m_DstActionIndex; + ActionContext m_ActionContext; }; #endif //!__REARRANGESTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp index c6164c6f7..154070123 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.cpp @@ -1,8 +1,9 @@ #include "RemoveActionsMessage.h" -RemoveActionsMessage::RemoveActionsMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - actionContext = ActionContext(arguments); - actionIndex = GetActionIndexFromArgument(arguments); +RemoveActionsMessage::RemoveActionsMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_ActionIndex{ GetActionIndexFromArgument(arguments) } + , m_ActionContext{ arguments } { - LOG_DEBUG("behaviorId %i actionIndex %i stripId %i stateId %i", behaviorId, actionIndex, actionContext.GetStripId(), actionContext.GetStateId()); + LOG_DEBUG("behaviorId %i actionIndex %i stripId %i stateId %i", m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId()); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h index 860df0af4..2caa6366f 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveActionsMessage.h @@ -12,12 +12,15 @@ class AMFArrayValue; */ class RemoveActionsMessage : public BehaviorMessageBase { public: - RemoveActionsMessage(AMFArrayValue* arguments); - int32_t GetActionIndex() const { return actionIndex; }; - ActionContext GetActionContext() const { return actionContext; }; + RemoveActionsMessage(const AMFArrayValue& arguments); + + [[nodiscard]] int32_t GetActionIndex() const noexcept { return m_ActionIndex; } + + [[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; } + private: - ActionContext actionContext; - int32_t actionIndex; + int32_t m_ActionIndex; + ActionContext m_ActionContext; }; #endif //!__REMOVEACTIONSMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp index b70beecee..f02753778 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.cpp @@ -1,7 +1,8 @@ #include "RemoveStripMessage.h" -RemoveStripMessage::RemoveStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - actionContext = ActionContext(arguments); +RemoveStripMessage::RemoveStripMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_ActionContext{ arguments } { - LOG_DEBUG("stripId %i stateId %i behaviorId %i", actionContext.GetStripId(), actionContext.GetStateId(), behaviorId); + LOG_DEBUG("stripId %i stateId %i behaviorId %i", m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h index 6a32ab0c5..37501ea6d 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RemoveStripMessage.h @@ -10,10 +10,12 @@ */ class RemoveStripMessage : public BehaviorMessageBase { public: - RemoveStripMessage(AMFArrayValue* arguments); - ActionContext GetActionContext() const { return actionContext; }; + RemoveStripMessage(const AMFArrayValue& arguments); + + const ActionContext& GetActionContext() const noexcept { return m_ActionContext; } + private: - ActionContext actionContext; + ActionContext m_ActionContext; }; #endif //!__REMOVESTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp index 17365be22..82d88bf83 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.cpp @@ -1,9 +1,9 @@ #include "RenameMessage.h" -RenameMessage::RenameMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - auto* nameAmf = arguments->Get("Name"); +RenameMessage::RenameMessage(const AMFArrayValue& arguments) : BehaviorMessageBase{ arguments } { + const auto* const nameAmf = arguments.Get("Name"); if (!nameAmf) return; - name = nameAmf->GetValue(); - LOG_DEBUG("behaviorId %i n %s", behaviorId, name.c_str()); + m_Name = nameAmf->GetValue(); + LOG_DEBUG("behaviorId %i n %s", m_BehaviorId, m_Name.c_str()); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h index 3f4119d2b..1f4e45c0e 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/RenameMessage.h @@ -7,14 +7,14 @@ class AMFArrayValue; /** * @brief Sent when a player renames this behavior - * */ class RenameMessage : public BehaviorMessageBase { public: - RenameMessage(AMFArrayValue* arguments); - const std::string& GetName() const { return name; }; + RenameMessage(const AMFArrayValue& arguments); + [[nodiscard]] const std::string& GetName() const { return m_Name; }; + private: - std::string name; + std::string m_Name; }; #endif //!__RENAMEMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp index 45dad737a..6003c9823 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.cpp @@ -1,11 +1,11 @@ #include "SplitStripMessage.h" -SplitStripMessage::SplitStripMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - sourceActionContext = ActionContext(arguments, "srcStateID", "srcStripID"); - srcActionIndex = GetActionIndexFromArgument(arguments, "srcActionIndex"); +SplitStripMessage::SplitStripMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_SrcActionIndex{ GetActionIndexFromArgument(arguments, "srcActionIndex") } + , m_SourceActionContext{ arguments, "srcStateID", "srcStripID" } + , m_DestinationActionContext{ arguments, "dstStateID", "dstStripID" } + , m_DestinationPosition{ arguments, "dstStripUI" } { - destinationActionContext = ActionContext(arguments, "dstStateID", "dstStripID"); - destinationPosition = StripUiPosition(arguments, "dstStripUI"); - - LOG_DEBUG("behaviorId %i xPosition %f yPosition %f sourceStrip %i destinationStrip %i sourceState %i destinationState %i srcActindex %i", behaviorId, destinationPosition.GetX(), destinationPosition.GetY(), sourceActionContext.GetStripId(), destinationActionContext.GetStripId(), sourceActionContext.GetStateId(), destinationActionContext.GetStateId(), srcActionIndex); + LOG_DEBUG("behaviorId %i xPosition %f yPosition %f sourceStrip %i destinationStrip %i sourceState %i destinationState %i srcActindex %i", m_BehaviorId, m_DestinationPosition.GetX(), m_DestinationPosition.GetY(), m_SourceActionContext.GetStripId(), m_DestinationActionContext.GetStripId(), m_SourceActionContext.GetStateId(), m_DestinationActionContext.GetStateId(), m_SrcActionIndex); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h index e41d50ebb..33d6ec6a7 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/SplitStripMessage.h @@ -14,20 +14,27 @@ class AMFArrayValue; */ class SplitStripMessage : public BehaviorMessageBase { public: - SplitStripMessage(AMFArrayValue* arguments); - ActionContext GetSourceActionContext() const { return sourceActionContext; }; - ActionContext GetDestinationActionContext() const { return destinationActionContext; }; - int32_t GetSrcActionIndex() const { return srcActionIndex; }; - StripUiPosition GetPosition() const { return destinationPosition; }; - const std::vector& GetTransferredActions() const { return transferredActions; }; - void SetTransferredActions(std::vector::const_iterator begin, std::vector::const_iterator end) { transferredActions.assign(begin, end); }; + SplitStripMessage(const AMFArrayValue& arguments); + + [[nodiscard]] int32_t GetSrcActionIndex() const noexcept { return m_SrcActionIndex; } + + [[nodiscard]] const ActionContext& GetSourceActionContext() const noexcept { return m_SourceActionContext; } + + [[nodiscard]] const ActionContext& GetDestinationActionContext() const noexcept { return m_DestinationActionContext; } + + [[nodiscard]] const StripUiPosition& GetPosition() const noexcept { return m_DestinationPosition; } + + [[nodiscard]] const std::vector& GetTransferredActions() const noexcept { return m_TransferredActions; } + + void SetTransferredActions(std::vector::const_iterator begin, std::vector::const_iterator end) { m_TransferredActions.assign(begin, end); }; + private: - ActionContext sourceActionContext; - ActionContext destinationActionContext; - int32_t srcActionIndex; - StripUiPosition destinationPosition; + int32_t m_SrcActionIndex; + ActionContext m_SourceActionContext; + ActionContext m_DestinationActionContext; + StripUiPosition m_DestinationPosition; - std::vector transferredActions; + std::vector m_TransferredActions; }; #endif //!__SPLITSTRIPMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp index 8b2d1d365..ae153a5f4 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.cpp @@ -1,28 +1,34 @@ #include "StripUiPosition.h" #include "Amf3.h" +#include "tinyxml2.h" -StripUiPosition::StripUiPosition() { - xPosition = 0.0; - yPosition = 0.0; -} - -StripUiPosition::StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName) { - xPosition = 0.0; - yPosition = 0.0; - auto* uiArray = arguments->GetArray(uiKeyName); +StripUiPosition::StripUiPosition(const AMFArrayValue& arguments, const std::string& uiKeyName) { + const auto* const uiArray = arguments.GetArray(uiKeyName); if (!uiArray) return; - auto* xPositionValue = uiArray->Get("x"); - auto* yPositionValue = uiArray->Get("y"); - if (!xPositionValue || !yPositionValue) return; + const auto* const xPositionValue = uiArray->Get("x"); + if (!xPositionValue) return; - yPosition = yPositionValue->GetValue(); - xPosition = xPositionValue->GetValue(); + const auto* const yPositionValue = uiArray->Get("y"); + if (!yPositionValue) return; + + m_YPosition = yPositionValue->GetValue(); + m_XPosition = xPositionValue->GetValue(); } void StripUiPosition::SendBehaviorBlocksToClient(AMFArrayValue& args) const { - auto* uiArgs = args.InsertArray("ui"); - uiArgs->Insert("x", xPosition); - uiArgs->Insert("y", yPosition); + auto* const uiArgs = args.InsertArray("ui"); + 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 92578cdc2..47501ff73 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/StripUiPosition.h @@ -3,20 +3,27 @@ class AMFArrayValue; +namespace tinyxml2 { + class XMLElement; +} + /** * @brief The position of the first Action in a Strip * */ class StripUiPosition { public: - StripUiPosition(); - StripUiPosition(AMFArrayValue* arguments, std::string uiKeyName = "ui"); + StripUiPosition() noexcept = default; + StripUiPosition(const AMFArrayValue& arguments, const std::string& uiKeyName = "ui"); void SendBehaviorBlocksToClient(AMFArrayValue& args) const; - double GetX() const { return xPosition; }; - double GetY() const { return yPosition; }; + [[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 xPosition; - double yPosition; + double m_XPosition{ 0.0 }; + double m_YPosition{ 0.0 }; }; #endif //!__STRIPUIPOSITION__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp index 924a9e62a..fabf2726c 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.cpp @@ -2,14 +2,15 @@ #include "Action.h" -UpdateActionMessage::UpdateActionMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - actionContext = ActionContext(arguments); +UpdateActionMessage::UpdateActionMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_ActionIndex{ GetActionIndexFromArgument(arguments) } + , m_ActionContext{ arguments } { - auto* actionValue = arguments->GetArray("action"); + const auto* const actionValue = arguments.GetArray("action"); if (!actionValue) return; + + m_Action = Action{ *actionValue }; - action = Action(actionValue); - actionIndex = GetActionIndexFromArgument(arguments); - - LOG_DEBUG("type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", action.GetType().c_str(), action.GetValueParameterName().c_str(), action.GetValueParameterString().c_str(), action.GetValueParameterDouble(), behaviorId, actionIndex, actionContext.GetStripId(), actionContext.GetStateId()); + LOG_DEBUG("type %s valueParameterName %s valueParameterString %s valueParameterDouble %f behaviorId %i actionIndex %i stripId %i stateId %i", m_Action.GetType().c_str(), m_Action.GetValueParameterName().c_str(), m_Action.GetValueParameterString().c_str(), m_Action.GetValueParameterDouble(), m_BehaviorId, m_ActionIndex, m_ActionContext.GetStripId(), m_ActionContext.GetStateId()); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h index aa34940b6..c53a4d47e 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateActionMessage.h @@ -13,14 +13,18 @@ class AMFArrayValue; */ class UpdateActionMessage : public BehaviorMessageBase { public: - UpdateActionMessage(AMFArrayValue* arguments); - int32_t GetActionIndex() const { return actionIndex; }; - ActionContext GetActionContext() const { return actionContext; }; - Action GetAction() const { return action; }; + UpdateActionMessage(const AMFArrayValue& arguments); + + [[nodiscard]] int32_t GetActionIndex() const noexcept { return m_ActionIndex; } + + [[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; } + + [[nodiscard]] const Action& GetAction() const noexcept { return m_Action; } + private: - int32_t actionIndex; - ActionContext actionContext; - Action action; + int32_t m_ActionIndex; + ActionContext m_ActionContext; + Action m_Action; }; #endif //!__UPDATEACTIONMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp index 05dc7cf77..badb8c7af 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.cpp @@ -1,8 +1,9 @@ #include "UpdateStripUiMessage.h" -UpdateStripUiMessage::UpdateStripUiMessage(AMFArrayValue* arguments) : BehaviorMessageBase(arguments) { - position = StripUiPosition(arguments); - actionContext = ActionContext(arguments); +UpdateStripUiMessage::UpdateStripUiMessage(const AMFArrayValue& arguments) + : BehaviorMessageBase{ arguments } + , m_Position{ arguments } + , m_ActionContext{ arguments } { - LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i", position.GetX(), position.GetY(), actionContext.GetStripId(), actionContext.GetStateId(), behaviorId); + LOG_DEBUG("xPosition %f yPosition %f stripId %i stateId %i behaviorId %i", m_Position.GetX(), m_Position.GetY(), m_ActionContext.GetStripId(), m_ActionContext.GetStateId(), m_BehaviorId); } diff --git a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h index 0e9afe815..e684fd4a6 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h +++ b/dGame/dPropertyBehaviors/ControlBehaviorMessages/UpdateStripUiMessage.h @@ -13,12 +13,15 @@ class AMFArrayValue; */ class UpdateStripUiMessage : public BehaviorMessageBase { public: - UpdateStripUiMessage(AMFArrayValue* arguments); - StripUiPosition GetPosition() const { return position; }; - ActionContext GetActionContext() const { return actionContext; }; + UpdateStripUiMessage(const AMFArrayValue& arguments); + + [[nodiscard]] const StripUiPosition& GetPosition() const noexcept { return m_Position; }; + + [[nodiscard]] const ActionContext& GetActionContext() const noexcept { return m_ActionContext; }; + private: - StripUiPosition position; - ActionContext actionContext; + StripUiPosition m_Position; + ActionContext m_ActionContext; }; #endif //!__UPDATESTRIPUIMESSAGE__H__ diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.cpp b/dGame/dPropertyBehaviors/ControlBehaviors.cpp index 5fee358de..2e074409a 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviors.cpp +++ b/dGame/dPropertyBehaviors/ControlBehaviors.cpp @@ -63,7 +63,7 @@ void ControlBehaviors::SendBehaviorListToClient(const ControlBehaviorContext& co // TODO This is also supposed to serialize the state of the behaviors in progress but those aren't implemented yet void ControlBehaviors::SendBehaviorBlocksToClient(ControlBehaviorContext& context) { if (!context) return; - BehaviorMessageBase behaviorMsg(context.arguments); + BehaviorMessageBase behaviorMsg{ context.arguments }; context.modelComponent->VerifyBehaviors(); AMFArrayValue behavior; @@ -71,8 +71,8 @@ void ControlBehaviors::SendBehaviorBlocksToClient(ControlBehaviorContext& contex GameMessages::SendUIMessageServerToSingleClient(context.modelOwner, context.modelOwner->GetSystemAddress(), "UpdateBehaviorBlocks", behavior); } -void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) { - UpdateActionMessage updateActionMessage(arguments); +void ControlBehaviors::UpdateAction(const AMFArrayValue& arguments) { + UpdateActionMessage updateActionMessage{ arguments }; auto blockDefinition = GetBlockInfo(updateActionMessage.GetAction().GetType()); if (!blockDefinition) { @@ -95,18 +95,18 @@ void ControlBehaviors::UpdateAction(AMFArrayValue* arguments) { } } -void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner) { - if (!isInitialized || !modelEntity || !modelOwner || !arguments) return; - auto* modelComponent = modelEntity->GetComponent(); +void ControlBehaviors::ProcessCommand(Entity* const modelEntity, const AMFArrayValue& arguments, const std::string& command, Entity* const modelOwner) { + if (!isInitialized || !modelEntity || !modelOwner) return; + auto* const modelComponent = modelEntity->GetComponent(); if (!modelComponent) return; - ControlBehaviorContext context(arguments, modelComponent, modelOwner); + ControlBehaviorContext context{ arguments, modelComponent, modelOwner }; if (command == "sendBehaviorListToClient") { SendBehaviorListToClient(context); } else if (command == "modelTypeChanged") { - auto* modelType = arguments->Get("ModelType"); + const auto* const modelType = arguments.Get("ModelType"); if (!modelType) return; modelEntity->SetVar(u"modelType", modelType->GetValue()); @@ -131,7 +131,7 @@ void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& } else if (command == "rearrangeStrip") { context.modelComponent->HandleControlBehaviorsMsg(arguments); } else if (command == "add") { - AddMessage msg(context.arguments); + AddMessage msg{ context.arguments }; context.modelComponent->AddBehavior(msg); SendBehaviorListToClient(context); } else if (command == "removeActions") { @@ -144,7 +144,7 @@ void ControlBehaviors::ProcessCommand(Entity* modelEntity, const SystemAddress& } else if (command == "sendBehaviorBlocksToClient") { SendBehaviorBlocksToClient(context); } else if (command == "moveToInventory") { - MoveToInventoryMessage msg(arguments); + MoveToInventoryMessage msg{ arguments }; context.modelComponent->MoveToInventory(msg); auto* characterComponent = modelOwner->GetComponent(); if (!characterComponent) return; @@ -239,7 +239,7 @@ ControlBehaviors::ControlBehaviors() { if (values) { auto* value = values->FirstChildElement("Value"); while (value) { - if (value->GetText() == blockDefinition.GetDefaultValue()) blockDefinition.GetDefaultValue() = std::to_string(blockDefinition.GetMaximumValue()); + if (value->GetText() == blockDefinition.GetDefaultValue()) blockDefinition.SetDefaultValue(std::to_string(blockDefinition.GetMaximumValue())); blockDefinition.SetMaximumValue(blockDefinition.GetMaximumValue() + 1); value = value->NextSiblingElement("Value"); } @@ -283,7 +283,7 @@ ControlBehaviors::ControlBehaviors() { } } -std::optional ControlBehaviors::GetBlockInfo(const BlockName& blockName) { +std::optional ControlBehaviors::GetBlockInfo(const std::string& blockName) { auto blockDefinition = blockTypes.find(blockName); return blockDefinition != blockTypes.end() ? std::optional(blockDefinition->second) : std::nullopt; } diff --git a/dGame/dPropertyBehaviors/ControlBehaviors.h b/dGame/dPropertyBehaviors/ControlBehaviors.h index ab7394083..f176a0708 100644 --- a/dGame/dPropertyBehaviors/ControlBehaviors.h +++ b/dGame/dPropertyBehaviors/ControlBehaviors.h @@ -19,15 +19,17 @@ class SystemAddress; typedef std::string BlockName; //! A block name struct ControlBehaviorContext { - ControlBehaviorContext(AMFArrayValue* args, ModelComponent* modelComponent, Entity* modelOwner) : arguments(args), modelComponent(modelComponent), modelOwner(modelOwner) {}; + ControlBehaviorContext(const AMFArrayValue& args, ModelComponent* modelComponent, Entity* modelOwner) noexcept + : arguments{ args }, modelComponent{ modelComponent }, modelOwner{ modelOwner } { + }; operator bool() const { - return arguments != nullptr && modelComponent != nullptr && modelOwner != nullptr; + return modelComponent != nullptr && modelOwner != nullptr; } - AMFArrayValue* arguments; - Entity* modelOwner; + std::reference_wrapper arguments; ModelComponent* modelComponent; + Entity* modelOwner; }; class ControlBehaviors: public Singleton { @@ -37,12 +39,11 @@ class ControlBehaviors: public Singleton { * @brief Main driver for processing Property Behavior commands * * @param modelEntity The model that sent this command - * @param sysAddr The SystemAddress to respond to * @param arguments The arguments formatted as an AMFArrayValue * @param command The command to perform * @param modelOwner The owner of the model which sent this command */ - void ProcessCommand(Entity* modelEntity, const SystemAddress& sysAddr, AMFArrayValue* arguments, std::string command, Entity* modelOwner); + void ProcessCommand(Entity* const modelEntity, const AMFArrayValue& arguments, const std::string& command, Entity* const modelOwner); /** * @brief Gets a blocks parameter values by the name @@ -52,13 +53,13 @@ class ControlBehaviors: public Singleton { * * @return A pair of the block parameter name to its typing */ - std::optional GetBlockInfo(const BlockName& blockName); + [[nodiscard]] std::optional GetBlockInfo(const std::string& blockName); private: void RequestUpdatedID(ControlBehaviorContext& context); void SendBehaviorListToClient(const ControlBehaviorContext& context); void SendBehaviorBlocksToClient(ControlBehaviorContext& context); - void UpdateAction(AMFArrayValue* arguments); - std::map blockTypes{}; + void UpdateAction(const AMFArrayValue& arguments); + std::map> blockTypes{}; // If false, property behaviors will not be able to be edited. bool isInitialized = false; diff --git a/dGame/dPropertyBehaviors/PropertyBehavior.cpp b/dGame/dPropertyBehaviors/PropertyBehavior.cpp index f6f6e4f1f..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; @@ -83,10 +84,6 @@ void PropertyBehavior::HandleMsg(AddMessage& msg) { isLoot = m_BehaviorId != 7965; }; -void PropertyBehavior::SetBehaviorId(int32_t behaviorId) { - m_BehaviorId = behaviorId; -} - void PropertyBehavior::SendBehaviorListToClient(AMFArrayValue& args) const { args.Insert("id", std::to_string(m_BehaviorId)); args.Insert("name", m_Name); @@ -111,21 +108,48 @@ void PropertyBehavior::VerifyLastEditedState() { } void PropertyBehavior::SendBehaviorBlocksToClient(AMFArrayValue& args) const { - auto* stateArray = args.InsertArray("states"); + auto* const stateArray = args.InsertArray("states"); - auto lastState = BehaviorState::HOME_STATE; - for (auto& [stateId, state] : m_States) { + for (const auto& [stateId, state] : m_States) { if (state.IsEmpty()) continue; LOG_DEBUG("Serializing state %i", stateId); - auto* stateArgs = stateArray->PushArray(); + auto* const stateArgs = stateArray->PushArray(); stateArgs->Insert("id", static_cast(stateId)); state.SendBehaviorBlocksToClient(*stateArgs); } - auto* executionState = args.InsertArray("executionState"); + auto* const executionState = args.InsertArray("executionState"); executionState->Insert("stateID", static_cast(m_LastEditedState)); executionState->InsertArray("strips"); // 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 dc53bbed6..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; @@ -13,7 +17,8 @@ class AMFArrayValue; class PropertyBehavior { public: PropertyBehavior(); - template + + template void HandleMsg(Msg& msg); // If the last edited state has no strips, this method will set the last edited state to the first state that has strips. @@ -21,8 +26,11 @@ class PropertyBehavior { void SendBehaviorListToClient(AMFArrayValue& args) const; void SendBehaviorBlocksToClient(AMFArrayValue& args) const; - int32_t GetBehaviorId() const { return m_BehaviorId; } - void SetBehaviorId(int32_t id); + [[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 59a9aa8bf..1fb072c1b 100644 --- a/dGame/dPropertyBehaviors/State.cpp +++ b/dGame/dPropertyBehaviors/State.cpp @@ -2,8 +2,9 @@ #include "Amf3.h" #include "ControlBehaviorMsgs.h" +#include "tinyxml2.h" -template<> +template <> void State::HandleMsg(AddStripMessage& msg) { if (m_Strips.size() <= msg.GetActionContext().GetStripId()) { m_Strips.resize(msg.GetActionContext().GetStripId() + 1); @@ -11,7 +12,7 @@ void State::HandleMsg(AddStripMessage& msg) { m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg); }; -template<> +template <> void State::HandleMsg(AddActionMessage& msg) { if (m_Strips.size() <= msg.GetActionContext().GetStripId()) { return; @@ -20,7 +21,7 @@ void State::HandleMsg(AddActionMessage& msg) { m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg); }; -template<> +template <> void State::HandleMsg(UpdateStripUiMessage& msg) { if (m_Strips.size() <= msg.GetActionContext().GetStripId()) { return; @@ -29,7 +30,7 @@ void State::HandleMsg(UpdateStripUiMessage& msg) { m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg); }; -template<> +template <> void State::HandleMsg(RemoveActionsMessage& msg) { if (m_Strips.size() <= msg.GetActionContext().GetStripId()) { return; @@ -38,7 +39,7 @@ void State::HandleMsg(RemoveActionsMessage& msg) { m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg); }; -template<> +template <> void State::HandleMsg(RearrangeStripMessage& msg) { if (m_Strips.size() <= msg.GetActionContext().GetStripId()) { return; @@ -47,7 +48,7 @@ void State::HandleMsg(RearrangeStripMessage& msg) { m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg); }; -template<> +template <> void State::HandleMsg(UpdateActionMessage& msg) { if (m_Strips.size() <= msg.GetActionContext().GetStripId()) { return; @@ -56,7 +57,7 @@ void State::HandleMsg(UpdateActionMessage& msg) { m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg); }; -template<> +template <> void State::HandleMsg(RemoveStripMessage& msg) { if (m_Strips.size() <= msg.GetActionContext().GetStripId()) { return; @@ -65,7 +66,7 @@ void State::HandleMsg(RemoveStripMessage& msg) { m_Strips.at(msg.GetActionContext().GetStripId()).HandleMsg(msg); }; -template<> +template <> void State::HandleMsg(SplitStripMessage& msg) { if (msg.GetTransferredActions().empty()) { if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) { @@ -82,7 +83,7 @@ void State::HandleMsg(SplitStripMessage& msg) { } }; -template<> +template <> void State::HandleMsg(MergeStripsMessage& msg) { if (msg.GetMigratedActions().empty()) { if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) { @@ -99,7 +100,7 @@ void State::HandleMsg(MergeStripsMessage& msg) { } }; -template<> +template <> void State::HandleMsg(MigrateActionsMessage& msg) { if (msg.GetMigratedActions().empty()) { if (m_Strips.size() <= msg.GetSourceActionContext().GetStripId()) { @@ -117,21 +118,37 @@ void State::HandleMsg(MigrateActionsMessage& msg) { }; bool State::IsEmpty() const { - for (auto& strip : m_Strips) { + for (const auto& strip : m_Strips) { if (!strip.IsEmpty()) return false; } return true; } void State::SendBehaviorBlocksToClient(AMFArrayValue& args) const { - auto* strips = args.InsertArray("strips"); - for (int32_t stripId = 0; stripId < m_Strips.size(); stripId++) { - auto& strip = m_Strips.at(stripId); + auto* const strips = args.InsertArray("strips"); + for (size_t stripId = 0; stripId < m_Strips.size(); ++stripId) { + const auto& strip = m_Strips.at(stripId); if (strip.IsEmpty()) continue; - auto* stripArgs = strips->PushArray(); + auto* const stripArgs = strips->PushArray(); stripArgs->Insert("id", static_cast(stripId)); 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 a6a6d23be..3e8c827fc 100644 --- a/dGame/dPropertyBehaviors/State.h +++ b/dGame/dPropertyBehaviors/State.h @@ -3,15 +3,22 @@ #include "Strip.h" +namespace tinyxml2 { + class XMLElement; +} + class AMFArrayValue; class State { public: - template + template void HandleMsg(Msg& msg); 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 7d27cacd4..d6dc050ba 100644 --- a/dGame/dPropertyBehaviors/Strip.cpp +++ b/dGame/dPropertyBehaviors/Strip.cpp @@ -2,49 +2,49 @@ #include "Amf3.h" #include "ControlBehaviorMsgs.h" +#include "tinyxml2.h" -template<> +template <> void Strip::HandleMsg(AddStripMessage& msg) { m_Actions = msg.GetActionsToAdd(); m_Position = msg.GetPosition(); }; -template<> +template <> void Strip::HandleMsg(AddActionMessage& msg) { if (msg.GetActionIndex() == -1) return; - m_Actions.insert(m_Actions.begin() + msg.GetActionIndex(), msg.GetAction()); }; -template<> +template <> void Strip::HandleMsg(UpdateStripUiMessage& msg) { m_Position = msg.GetPosition(); }; -template<> +template <> void Strip::HandleMsg(RemoveStripMessage& msg) { m_Actions.clear(); }; -template<> +template <> void Strip::HandleMsg(RemoveActionsMessage& msg) { if (msg.GetActionIndex() >= m_Actions.size()) return; m_Actions.erase(m_Actions.begin() + msg.GetActionIndex(), m_Actions.end()); }; -template<> +template <> void Strip::HandleMsg(UpdateActionMessage& msg) { if (msg.GetActionIndex() >= m_Actions.size()) return; m_Actions.at(msg.GetActionIndex()) = msg.GetAction(); }; -template<> +template <> void Strip::HandleMsg(RearrangeStripMessage& msg) { if (msg.GetDstActionIndex() >= m_Actions.size() || msg.GetSrcActionIndex() >= m_Actions.size() || msg.GetSrcActionIndex() <= msg.GetDstActionIndex()) return; std::rotate(m_Actions.begin() + msg.GetDstActionIndex(), m_Actions.begin() + msg.GetSrcActionIndex(), m_Actions.end()); }; -template<> +template <> void Strip::HandleMsg(SplitStripMessage& msg) { if (msg.GetTransferredActions().empty() && !m_Actions.empty()) { auto startToMove = m_Actions.begin() + msg.GetSrcActionIndex(); @@ -56,7 +56,7 @@ void Strip::HandleMsg(SplitStripMessage& msg) { } }; -template<> +template <> void Strip::HandleMsg(MergeStripsMessage& msg) { if (msg.GetMigratedActions().empty() && !m_Actions.empty()) { msg.SetMigratedActions(m_Actions.begin(), m_Actions.end()); @@ -66,7 +66,7 @@ void Strip::HandleMsg(MergeStripsMessage& msg) { } }; -template<> +template <> void Strip::HandleMsg(MigrateActionsMessage& msg) { if (msg.GetMigratedActions().empty() && !m_Actions.empty()) { auto startToMove = m_Actions.begin() + msg.GetSrcActionIndex(); @@ -80,8 +80,29 @@ void Strip::HandleMsg(MigrateActionsMessage& msg) { void Strip::SendBehaviorBlocksToClient(AMFArrayValue& args) const { m_Position.SendBehaviorBlocksToClient(args); - auto* actions = args.InsertArray("actions"); - for (auto& action : m_Actions) { + auto* const actions = args.InsertArray("actions"); + 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 f3e10964e..8fd7d0fe3 100644 --- a/dGame/dPropertyBehaviors/Strip.h +++ b/dGame/dPropertyBehaviors/Strip.h @@ -6,15 +6,22 @@ #include +namespace tinyxml2 { + class XMLElement; +} + class AMFArrayValue; class Strip { public: - template + template void HandleMsg(Msg& msg); void SendBehaviorBlocksToClient(AMFArrayValue& args) const; - bool IsEmpty() const { return m_Actions.empty(); } + 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/GUID.cpp b/dGame/dUtilities/GUID.cpp index 50ac8b03c..ac4042a07 100644 --- a/dGame/dUtilities/GUID.cpp +++ b/dGame/dUtilities/GUID.cpp @@ -13,12 +13,12 @@ GUID::GUID(const std::string& guid) { &this->data4[4], &this->data4[5], &this->data4[6], &this->data4[7]); } -void GUID::Serialize(RakNet::BitStream* outBitStream) { - outBitStream->Write(GetData1()); - outBitStream->Write(GetData2()); - outBitStream->Write(GetData3()); +void GUID::Serialize(RakNet::BitStream& outBitStream) { + outBitStream.Write(GetData1()); + outBitStream.Write(GetData2()); + outBitStream.Write(GetData3()); for (const auto& guidSubPart : GetData4()) { - outBitStream->Write(guidSubPart); + outBitStream.Write(guidSubPart); } } diff --git a/dGame/dUtilities/GUID.h b/dGame/dUtilities/GUID.h index 38e57a6a1..ce6d40c19 100644 --- a/dGame/dUtilities/GUID.h +++ b/dGame/dUtilities/GUID.h @@ -7,7 +7,7 @@ class GUID { public: explicit GUID(); explicit GUID(const std::string& guid); - void Serialize(RakNet::BitStream* outBitStream); + void Serialize(RakNet::BitStream& outBitStream); uint32_t GetData1() const { return data1; 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 fc0c833e7..677728a62 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -94,40 +94,11 @@ 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) { +void Mail::HandleMailStuff(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) { int mailStuffID = 0; - packet->Read(mailStuffID); + packet.Read(mailStuffID); - auto returnVal = std::async(std::launch::async, [packet, &sysAddr, entity, mailStuffID]() { + auto returnVal = std::async(std::launch::async, [&packet, &sysAddr, entity, mailStuffID]() { Mail::MailMessageID stuffID = MailMessageID(mailStuffID); switch (stuffID) { case MailMessageID::AttachmentCollect: @@ -154,7 +125,7 @@ void Mail::HandleMailStuff(RakNet::BitStream* packet, const SystemAddress& sysAd }); } -void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* entity) { +void Mail::HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity) { //std::string subject = GeneralUtils::WStringToString(ReadFromPacket(packet, 50)); //std::string body = GeneralUtils::WStringToString(ReadFromPacket(packet, 400)); //std::string recipient = GeneralUtils::WStringToString(ReadFromPacket(packet, 32)); @@ -176,19 +147,28 @@ 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; uint16_t attachmentCount; - packet->Read(unknown64); - packet->Read(attachmentID); - packet->Read(attachmentCount); //We don't care about the rest of the packet. + packet.Read(unknown64); + packet.Read(attachmentID); + packet.Read(attachmentCount); //We don't care about the rest of the packet. uint32_t itemID = static_cast(attachmentID); LOT itemLOT = 0; //Inventory::InventoryType itemType; @@ -261,58 +241,62 @@ void Mail::HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAdd character->SaveXMLToDatabase(); } -void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player) { +void Mail::HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player) { auto playerMail = Database::Get()->GetMailForPlayer(player->GetCharacter()->GetID(), 20); RakNet::BitStream bitStream; BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::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); + Game::server->Send(bitStream, sysAddr, false); } -void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player) { +void Mail::HandleAttachmentCollect(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player) { int unknown; uint64_t mailID; LWOOBJID playerID; - packet->Read(unknown); - packet->Read(mailID); - packet->Read(playerID); + packet.Read(unknown); + packet.Read(mailID); + packet.Read(playerID); if (mailID > 0 && playerID == player->GetObjectID()) { auto playerMail = Database::Get()->GetMail(mailID); @@ -336,22 +320,22 @@ void Mail::HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddres } } -void Mail::HandleMailDelete(RakNet::BitStream* packet, const SystemAddress& sysAddr) { +void Mail::HandleMailDelete(RakNet::BitStream& packet, const SystemAddress& sysAddr) { int unknown; uint64_t mailID; LWOOBJID playerID; - packet->Read(unknown); - packet->Read(mailID); - packet->Read(playerID); + packet.Read(unknown); + packet.Read(mailID); + packet.Read(playerID); if (mailID > 0) Mail::SendDeleteConfirm(sysAddr, mailID, playerID); } -void Mail::HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAddr) { +void Mail::HandleMailRead(RakNet::BitStream& packet, const SystemAddress& sysAddr) { int unknown; uint64_t mailID; - packet->Read(unknown); - packet->Read(mailID); + packet.Read(unknown); + packet.Read(mailID); if (mailID > 0) Mail::SendReadConfirm(sysAddr, mailID); } @@ -367,7 +351,7 @@ void Mail::SendSendResponse(const SystemAddress& sysAddr, MailSendResponse respo BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::MAIL); bitStream.Write(int(MailMessageID::SendResponse)); bitStream.Write(int(response)); - Game::server->Send(&bitStream, sysAddr, false); + Game::server->Send(bitStream, sysAddr, false); } void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) { @@ -386,7 +370,7 @@ void Mail::SendNotification(const SystemAddress& sysAddr, int mailCount) { bitStream.Write(s4); bitStream.Write(mailCount); bitStream.Write(int(0)); //Unknown - Game::server->Send(&bitStream, sysAddr, false); + Game::server->Send(bitStream, sysAddr, false); } void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t mailID) { @@ -395,7 +379,7 @@ void Mail::SendAttachmentRemoveConfirm(const SystemAddress& sysAddr, uint64_t ma bitStream.Write(int(MailMessageID::AttachmentCollectConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); - Game::server->Send(&bitStream, sysAddr, false); + Game::server->Send(bitStream, sysAddr, false); } void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOOBJID playerID) { @@ -404,7 +388,7 @@ void Mail::SendDeleteConfirm(const SystemAddress& sysAddr, uint64_t mailID, LWOO bitStream.Write(int(MailMessageID::MailDeleteConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); - Game::server->Send(&bitStream, sysAddr, false); + Game::server->Send(bitStream, sysAddr, false); Database::Get()->DeleteMail(mailID); } @@ -415,7 +399,7 @@ void Mail::SendReadConfirm(const SystemAddress& sysAddr, uint64_t mailID) { bitStream.Write(int(MailMessageID::MailReadConfirm)); bitStream.Write(int(0)); //unknown bitStream.Write(mailID); - Game::server->Send(&bitStream, sysAddr, false); + Game::server->Send(bitStream, sysAddr, false); Database::Get()->MarkMailRead(mailID); } diff --git a/dGame/dUtilities/Mail.h b/dGame/dUtilities/Mail.h index c8eabe6b6..07c3e37fb 100644 --- a/dGame/dUtilities/Mail.h +++ b/dGame/dUtilities/Mail.h @@ -79,12 +79,12 @@ namespace Mail { const SystemAddress& sysAddr ); - void HandleMailStuff(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* entity); - void HandleSendMail(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* entity); - void HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player); - void HandleAttachmentCollect(RakNet::BitStream* packet, const SystemAddress& sysAddr, Entity* player); - void HandleMailDelete(RakNet::BitStream* packet, const SystemAddress& sysAddr); - void HandleMailRead(RakNet::BitStream* packet, const SystemAddress& sysAddr); + void HandleMailStuff(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity); + void HandleSendMail(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* entity); + void HandleDataRequest(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player); + void HandleAttachmentCollect(RakNet::BitStream& packet, const SystemAddress& sysAddr, Entity* player); + void HandleMailDelete(RakNet::BitStream& packet, const SystemAddress& sysAddr); + void HandleMailRead(RakNet::BitStream& packet, const SystemAddress& sysAddr); void HandleNotificationRequest(const SystemAddress& sysAddr, uint32_t objectID); void SendSendResponse(const SystemAddress& sysAddr, MailSendResponse response); diff --git a/dGame/dUtilities/Preconditions.cpp b/dGame/dUtilities/Preconditions.cpp index bd855962c..25e8b773c 100644 --- a/dGame/dUtilities/Preconditions.cpp +++ b/dGame/dUtilities/Preconditions.cpp @@ -33,10 +33,10 @@ Precondition::Precondition(const uint32_t 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 +45,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(); } diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index cd938babe..ca4e03d49 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 "eChatMessageType.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, eChatMessageType::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..00add6087 --- /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 "eMasterMessageType.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, 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 + 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..b9eaf7bfe --- /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 "eChatMessageType.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, eChatMessageType::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 fa1a3eac3..6043fe638 100644 --- a/dGame/dUtilities/VanityUtilities.cpp +++ b/dGame/dUtilities/VanityUtilities.cpp @@ -22,18 +22,42 @@ #include <fstream> -std::vector<VanityNPC> VanityUtilities::m_NPCs = {}; -std::vector<VanityParty> VanityUtilities::m_Parties = {}; -std::vector<std::string> VanityUtilities::m_PartyPhrases = {}; + +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() { - if (Game::config->GetValue("disable_vanity") == "1") { - return; + const uint32_t zoneID = Game::server->GetZoneID(); + + if (zoneID == 1200) { + { + EntityInfo info; + info.lot = 8139; + 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())) + }; + + auto* entity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(entity); + } } - const uint32_t zoneID = Game::server->GetZoneID(); + if (Game::config->GetValue("disable_vanity") == "1") return; - for (const auto& npc : m_NPCs) { + for (const auto& npc : objects) { if (npc.m_ID == LWOOBJID_EMPTY) continue; if (npc.m_LOT == 176){ Game::zoneManager->RemoveSpawner(npc.m_ID); @@ -44,174 +68,73 @@ void VanityUtilities::SpawnVanity() { } } - m_NPCs.clear(); - m_Parties.clear(); - m_PartyPhrases.clear(); - - ParseXML((BinaryPathFinder::GetBinaryDir() / "vanity/NPC.xml").string()); - - // Loop through all parties - for (const auto& party : m_Parties) { - const auto chance = party.m_Chance; - const auto zone = party.m_Zone; - - if (zone != Game::server->GetZoneID()) { - continue; - } - - float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); - if (chance < rate) { - continue; - } - - // Copy m_NPCs into a new vector - std::vector<VanityNPC> npcList = m_NPCs; - std::vector<uint32_t> taken = {}; - - LOG("Spawning party with %i locations", party.m_Locations.size()); - - // Loop through all locations - for (const auto& location : party.m_Locations) { - rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); - if (0.75f < rate) { - continue; - } - - // Get a random NPC - auto npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1); - - while (std::find(taken.begin(), taken.end(), npcIndex) != taken.end()) { - npcIndex = GeneralUtils::GenerateRandomNumber<uint32_t>(0, npcList.size() - 1); - } - - auto& npc = npcList[npcIndex]; - // Skip spawners - if (npc.m_LOT == 176) continue; - - taken.push_back(npcIndex); - - LOG("ldf size is %i", npc.ldf.size()); - if (npc.ldf.empty()) { - npc.ldf = { - new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }), - new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") - }; - } + objects.clear(); + loadedFiles.clear(); - // Spawn the NPC - if (npc.m_LOT == 176){ - npc.m_ID = SpawnSpawner(npc.m_LOT, location.m_Position, location.m_Rotation, npc.ldf); - } else { - auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf); - if (!npc.m_Phrases.empty()) { - npcEntity->SetVar<std::vector<std::string>>(u"chats", m_PartyPhrases); - SetupNPCTalk(npcEntity); - } - } - } - return; - } + ParseXml((BinaryPathFinder::GetBinaryDir() / "vanity/root.xml").string()); - // Loop through all NPCs - for (auto& npc : m_NPCs) { - if (npc.m_Locations.find(Game::server->GetZoneID()) == npc.m_Locations.end()) - continue; + // Loop through all objects + for (auto& object : objects) { + if (object.m_Locations.find(Game::server->GetZoneID()) == object.m_Locations.end()) continue; - const std::vector<VanityNPCLocation>& locations = npc.m_Locations.at(Game::server->GetZoneID()); + const std::vector<VanityObjectLocation>& locations = object.m_Locations.at(Game::server->GetZoneID()); // Pick a random location const auto& location = locations[GeneralUtils::GenerateRandomNumber<int>( static_cast<size_t>(0), static_cast<size_t>(locations.size() - 1))]; float rate = GeneralUtils::GenerateRandomNumber<float>(0, 1); - if (location.m_Chance < rate) { - continue; - } + if (location.m_Chance < rate) continue; - if (npc.ldf.empty()) { - npc.ldf = { - new LDFData<std::vector<std::u16string>>(u"syncLDF", { u"custom_script_client" }), - new LDFData<std::u16string>(u"custom_script_client", u"scripts\\ai\\SPEC\\MISSION_MINIGAME_CLIENT.lua") - }; - } - if (npc.m_LOT == 176){ - npc.m_ID = SpawnSpawner(npc.m_LOT, location.m_Position, location.m_Rotation, npc.ldf); + if (object.m_LOT == 176){ + object.m_ID = SpawnSpawner(object, location); } else { // Spawn the NPC - auto* npcEntity = SpawnNPC(npc.m_LOT, npc.m_Name, location.m_Position, location.m_Rotation, npc.m_Equipment, npc.ldf); - if (!npcEntity) continue; - npc.m_ID = npcEntity->GetObjectID(); - if (!npc.m_Phrases.empty()){ - npcEntity->SetVar<std::vector<std::string>>(u"chats", npc.m_Phrases); - - auto* scriptComponent = npcEntity->GetComponent<ScriptComponent>(); - - if (scriptComponent && !npc.m_Script.empty()) { - scriptComponent->SetScript(npc.m_Script); - scriptComponent->SetSerialized(false); - - for (const auto& npc : npc.m_Flags) { - npcEntity->SetVar<bool>(GeneralUtils::ASCIIToUTF16(npc.first), npc.second); - } - } - SetupNPCTalk(npcEntity); + auto* objectEntity = SpawnObject(object, location); + if (!objectEntity) continue; + object.m_ID = objectEntity->GetObjectID(); + if (!object.m_Phrases.empty()){ + objectEntity->SetVar<std::vector<std::string>>(u"chats", object.m_Phrases); + SetupNPCTalk(objectEntity); } } } - - if (zoneID == 1200) { - { - EntityInfo info; - info.lot = 8139; - 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())) }; - - auto* entity = Game::entityManager->CreateEntity(info); - - Game::entityManager->ConstructEntity(entity); - } - } } -LWOOBJID VanityUtilities::SpawnSpawner(LOT lot, const NiPoint3& position, const NiQuaternion& rotation, const std::vector<LDFBaseData*>& ldf){ +LWOOBJID SpawnSpawner(const VanityObject& object, const VanityObjectLocation& location) { SceneObject obj; - obj.lot = lot; + obj.lot = object.m_LOT; // guratantee we have no collisions do { obj.id = ObjectIDManager::GenerateObjectID(); } while(Game::zoneManager->GetSpawner(obj.id)); - obj.position = position; - obj.rotation = rotation; - obj.settings = ldf; + obj.position = location.m_Position; + obj.rotation = location.m_Rotation; + obj.settings = object.m_Config; Level::MakeSpawner(obj); return obj.id; } -Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoint3& position, const NiQuaternion& rotation, const std::vector<LOT>& inventory, const std::vector<LDFBaseData*>& ldf) { +Entity* SpawnObject(const VanityObject& object, const VanityObjectLocation& location) { EntityInfo info; - info.lot = lot; - info.pos = position; - info.rot = rotation; + info.lot = object.m_LOT; + info.pos = location.m_Position; + info.rot = location.m_Rotation; + info.scale = location.m_Scale; info.spawnerID = Game::entityManager->GetZoneControlEntity()->GetObjectID(); - info.settings = ldf; + info.settings = object.m_Config; auto* entity = Game::entityManager->CreateEntity(info); - entity->SetVar(u"npcName", 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 && !inventory.empty()) { - inventoryComponent->SetNPCItems(inventory); + 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); @@ -222,7 +145,12 @@ Entity* VanityUtilities::SpawnNPC(LOT lot, const std::string& name, const NiPoin return entity; } -void VanityUtilities::ParseXML(const std::string& file) { +void ParseXml(const std::string& file) { + if (loadedFiles.contains(file)){ + LOG("Trying to load vanity file %s twice!!!", file.c_str()); + return; + } + loadedFiles.insert(file); // Read the entire file std::ifstream xmlFile(file); std::string xml((std::istreambuf_iterator<char>(xmlFile)), std::istreambuf_iterator<char>()); @@ -231,210 +159,107 @@ void VanityUtilities::ParseXML(const std::string& file) { tinyxml2::XMLDocument doc; doc.Parse(xml.c_str(), xml.size()); - // Read the NPCs - auto* npcs = doc.FirstChildElement("npcs"); - - if (npcs == nullptr) { - LOG("Failed to parse NPCs"); - return; - } - - for (auto* party = npcs->FirstChildElement("party"); party != nullptr; party = party->NextSiblingElement("party")) { - // Get 'zone' as uint32_t and 'chance' as float - uint32_t zone = 0; - float chance = 0.0f; - - if (party->Attribute("zone") != nullptr) { - zone = std::stoul(party->Attribute("zone")); - } - - if (party->Attribute("chance") != nullptr) { - chance = std::stof(party->Attribute("chance")); - } - - VanityParty partyInfo; - partyInfo.m_Zone = zone; - partyInfo.m_Chance = chance; - - auto* locations = party->FirstChildElement("locations"); - - if (locations == nullptr) { - LOG("Failed to parse party locations"); - continue; - } - - for (auto* location = locations->FirstChildElement("location"); location != nullptr; - location = location->NextSiblingElement("location")) { - // Get the location data - 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 (x == nullptr || y == nullptr || z == nullptr || rw == nullptr || rx == nullptr || ry == nullptr - || rz == nullptr) { - LOG("Failed to parse party location data"); + // Read the objects + auto* files = doc.FirstChildElement("files"); + if (files) { + for (auto* file = files->FirstChildElement("file"); file != nullptr; file = file->NextSiblingElement("file")) { + std::string enabled = file->Attribute("enabled"); + std::string filename = file->Attribute("name"); + if (enabled != "1") { continue; } - - VanityNPCLocation 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; - - partyInfo.m_Locations.push_back(locationData); + ParseXml((BinaryPathFinder::GetBinaryDir() / "vanity" / filename).string()); } - - m_Parties.push_back(partyInfo); } - auto* partyPhrases = npcs->FirstChildElement("partyphrases"); - - if (partyPhrases == nullptr) { - LOG("No party phrases found"); - } else { - for (auto* phrase = partyPhrases->FirstChildElement("phrase"); phrase != nullptr; - phrase = phrase->NextSiblingElement("phrase")) { - // Get the phrase - auto* text = phrase->GetText(); - - if (text == nullptr) { - LOG("Failed to parse party phrase"); - continue; - } - - m_PartyPhrases.push_back(text); - } - } + // Read the objects + 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"); - for (auto* npc = npcs->FirstChildElement("npc"); npc != nullptr; npc = npc->NextSiblingElement("npc")) { - // Get the NPC name - auto* name = npc->Attribute("name"); + if (!name) name = ""; - if (!name) name = ""; + // Get the NPC lot + auto lot = GeneralUtils::TryParse<LOT>(object->Attribute("lot")).value_or(LOT_NULL); - // Get the NPC lot - auto* lot = npc->Attribute("lot"); - - if (lot == nullptr) { - LOG("Failed to parse NPC lot"); - continue; - } + if (lot == LOT_NULL) { + LOG("Failed to parse object lot"); + continue; + } - // Get the equipment - auto* equipment = npc->FirstChildElement("equipment"); - std::vector<LOT> inventory; + // Get the equipment + auto* equipment = object->FirstChildElement("equipment"); + std::vector<LOT> inventory; - if (equipment) { - auto* text = equipment->GetText(); + if (equipment) { + auto* text = equipment->GetText(); - if (text != nullptr) { - std::string equipmentString(text); + if (text != nullptr) { + std::string equipmentString(text); - std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ','); + std::vector<std::string> splitEquipment = GeneralUtils::SplitString(equipmentString, ','); - for (auto& item : splitEquipment) { - inventory.push_back(std::stoi(item)); + for (auto& item : splitEquipment) { + // 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 = npc->FirstChildElement("phrases"); - - std::vector<std::string> phraseList = {}; - - if (phrases) { - for (auto* phrase = phrases->FirstChildElement("phrase"); phrase != nullptr; - phrase = phrase->NextSiblingElement("phrase")) { - // Get the phrase - auto* text = phrase->GetText(); - if (text == nullptr) { - LOG("Failed to parse NPC phrase"); - continue; + // 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")) { + // Get the phrase + auto* text = phrase->GetText(); + if (text == nullptr) { + LOG("Failed to parse NPC phrase"); + continue; + } + phraseList.push_back(text); } - phraseList.push_back(text); } - } - - // Get the script - auto* scriptElement = npc->FirstChildElement("script"); - - std::string scriptName = ""; - if (scriptElement != nullptr) { - auto* scriptNameAttribute = scriptElement->Attribute("name"); - if (scriptNameAttribute) scriptName = scriptNameAttribute; - } - - auto* ldfElement = npc->FirstChildElement("ldf"); - std::vector<std::u16string> keys = {}; - - std::vector<LDFBaseData*> ldf = {}; - if(ldfElement) { - for (auto* entry = ldfElement->FirstChildElement("entry"); entry != nullptr; - entry = entry->NextSiblingElement("entry")) { - // Get the ldf data - auto* data = entry->Attribute("data"); - if (!data) continue; - - LDFBaseData* ldfData = LDFBaseData::DataFromString(data); - keys.push_back(ldfData->GetKey()); - ldf.push_back(ldfData); - } - } - if (!keys.empty()) ldf.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys)); - - VanityNPC npcData; - npcData.m_Name = name; - npcData.m_LOT = std::stoi(lot); - npcData.m_Equipment = inventory; - npcData.m_Phrases = phraseList; - npcData.m_Script = scriptName; - npcData.ldf = ldf; - - // Get flags - auto* flags = npc->FirstChildElement("flags"); - - if (flags != nullptr) { - for (auto* flag = flags->FirstChildElement("flag"); flag != nullptr; - flag = flag->NextSiblingElement("flag")) { - // Get the flag name - auto* name = flag->Attribute("name"); - - if (name == nullptr) { - LOG("Failed to parse NPC flag name"); - continue; - } - - // Get the flag value - auto* value = flag->Attribute("value"); - - if (value == nullptr) { - LOG("Failed to parse NPC flag value"); - continue; + 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->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); } - - npcData.m_Flags[name] = std::stoi(value); - } - } - - // Get the zones - for (auto* zone = npc->FirstChildElement("zone"); zone != nullptr; zone = zone->NextSiblingElement("zone")) { - // Get the zone ID - auto* zoneID = zone->Attribute("id"); - - if (zoneID == nullptr) { - LOG("Failed to parse NPC zone ID"); - continue; } + if (!keys.empty()) config.push_back(new LDFData<std::vector<std::u16string>>(u"syncLDF", keys)); + + VanityObject objectData { + .m_Name = name, + .m_LOT = lot, + .m_Equipment = inventory, + .m_Phrases = phraseList, + .m_Config = config + }; // Get the locations - auto* locations = zone->FirstChildElement("locations"); + auto* locations = object->FirstChildElement("locations"); if (locations == nullptr) { LOG("Failed to parse NPC locations"); @@ -443,53 +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* 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 (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; } - VanityNPCLocation 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; + } - if (location->Attribute("chance") != nullptr) { - locationData.m_Chance = std::stof(location->Attribute("chance")); + 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 = GeneralUtils::TryParse<float>(location->Attribute("chance")).value_or(1.0f); + } + + if (location->Attribute("scale")) { + locationData.m_Scale = GeneralUtils::TryParse<float>(location->Attribute("scale")).value_or(1.0f); } - const auto& it = npcData.m_Locations.find(std::stoi(zoneID)); + const auto& it = objectData.m_Locations.find(zoneID.value()); - if (it != npcData.m_Locations.end()) { + if (it != objectData.m_Locations.end()) { it->second.push_back(locationData); } else { - std::vector<VanityNPCLocation> locations; + std::vector<VanityObjectLocation> locations; locations.push_back(locationData); - npcData.m_Locations.insert(std::make_pair(std::stoi(zoneID), locations)); + objectData.m_Locations.insert(std::make_pair(zoneID.value(), locations)); + } + + if (!useLocationsAsRandomSpawnPoint) { + objects.push_back(objectData); + objectData.m_Locations.clear(); } } - } - m_NPCs.push_back(npcData); + if (useLocationsAsRandomSpawnPoint && !objectData.m_Locations.empty()) { + objects.push_back(objectData); + } + } } } -VanityNPC* VanityUtilities::GetNPC(const std::string& name) { - for (size_t i = 0; i < m_NPCs.size(); i++) { - if (m_NPCs[i].m_Name == name) { - return &m_NPCs[i]; +VanityObject* VanityUtilities::GetObject(const std::string& name) { + for (size_t i = 0; i < objects.size(); i++) { + if (objects[i].m_Name == name) { + return &objects[i]; } } - return nullptr; } @@ -498,10 +338,13 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) { // Read the file into a string std::ifstream t(file); - - // If the file does not exist, return an empty string. + std::stringstream output; + // If the file does not exist, return a useful error. if (!t.good()) { - return ""; + output << "File "; + output << file.substr(file.rfind("/") + 1); + output << " not found!\nContact your DarkflameServer admin\nor find the server source at https://github.com/DarkflameUniverse/DarkflameServer"; + return output.str(); } std::stringstream buffer; @@ -511,7 +354,6 @@ std::string VanityUtilities::ParseMarkdown(const std::string& file) { // Loop through all lines in the file. // Replace all instances of the markdown syntax with the corresponding HTML. // Only care about headers - std::stringstream output; std::string line; std::stringstream ss; ss << fileContents; @@ -555,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 cff73bce2..a1d005015 100644 --- a/dGame/dUtilities/VanityUtilities.h +++ b/dGame/dUtilities/VanityUtilities.h @@ -3,73 +3,32 @@ #include "dCommonVars.h" #include "Entity.h" #include <map> +#include <set> -struct VanityNPCLocation -{ +struct VanityObjectLocation { float m_Chance = 1.0f; NiPoint3 m_Position; NiQuaternion m_Rotation; + float m_Scale = 1.0f; }; -struct VanityNPC -{ +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<std::string, bool> m_Flags; - std::map<uint32_t, std::vector<VanityNPCLocation>> m_Locations; - std::vector<LDFBaseData*> ldf; + std::map<uint32_t, std::vector<VanityObjectLocation>> m_Locations; + std::vector<LDFBaseData*> m_Config; }; -struct VanityParty -{ - uint32_t m_Zone; - float m_Chance = 1.0f; - std::vector<VanityNPCLocation> m_Locations; -}; -class VanityUtilities -{ -public: - static void SpawnVanity(); - - static Entity* SpawnNPC( - LOT lot, - const std::string& name, - const NiPoint3& position, - const NiQuaternion& rotation, - const std::vector<LOT>& inventory, - const std::vector<LDFBaseData*>& ldf - ); +namespace VanityUtilities { + void SpawnVanity(); - static LWOOBJID SpawnSpawner( - LOT lot, - const NiPoint3& position, - const NiQuaternion& rotation, - const std::vector<LDFBaseData*>& ldf - ); - - 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 VanityNPC* GetNPC(const std::string& name); - -private: - static void SetupNPCTalk(Entity* npc); - - static void NPCTalk(Entity* npc); - - static std::vector<VanityNPC> m_NPCs; - - static std::vector<VanityParty> m_Parties; - - static std::vector<std::string> m_PartyPhrases; }; diff --git a/dMasterServer/CMakeLists.txt b/dMasterServer/CMakeLists.txt index 32a7b1eca..260e4f16a 100644 --- a/dMasterServer/CMakeLists.txt +++ b/dMasterServer/CMakeLists.txt @@ -7,10 +7,13 @@ set(DMASTERSERVER_SOURCES add_library(dMasterServer ${DMASTERSERVER_SOURCES}) add_executable(MasterServer "MasterServer.cpp") add_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 9ae9930ce..3ec42634b 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -181,7 +181,7 @@ void InstanceManager::RequestAffirmation(Instance* instance, const PendingInstan bitStream.Write(request.id); - Game::server->Send(&bitStream, instance->GetSysAddr(), false); + Game::server->Send(bitStream, instance->GetSysAddr(), false); LOG("Sent affirmation request %llu to %i/%i", request.id, static_cast<int>(instance->GetZoneID().GetMapID()), @@ -361,7 +361,7 @@ void Instance::Shutdown() { BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN); - Game::server->Send(&bitStream, this->m_SysAddr, false); + Game::server->Send(bitStream, this->m_SysAddr, false); LOG("Triggered world shutdown for zone/clone/instance %i/%i/%i", GetMapID(), GetCloneID(), GetInstanceID()); } diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index 1fade06e4..0f36ee373 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -40,6 +40,7 @@ #include "BitStreamUtils.h" #include "Start.h" #include "Server.h" +#include "CDZoneTableTable.h" namespace Game { Logger* logger = nullptr; @@ -277,6 +278,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 +394,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"); @@ -576,7 +589,7 @@ void HandlePacket(Packet* packet) { BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SESSION_KEY_RESPONSE); bitStream.Write(key.first); bitStream.Write(username); - Game::server->Send(&bitStream, packet->systemAddress, false); + Game::server->Send(bitStream, packet->systemAddress, false); break; } } @@ -675,7 +688,7 @@ 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; } @@ -786,7 +799,7 @@ int ShutdownSequence(int32_t signal) { { CBITSTREAM; BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN); - Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); + 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 25ccc9029..715188e84 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> @@ -28,10 +28,10 @@ namespace { std::vector<uint32_t> claimCodes; } -void Stamp::Serialize(RakNet::BitStream* outBitStream){ - outBitStream->Write(type); - outBitStream->Write(value); - outBitStream->Write(timestamp); +void Stamp::Serialize(RakNet::BitStream& outBitStream){ + outBitStream.Write(type); + outBitStream.Write(value); + outBitStream.Write(timestamp); }; void AuthPackets::LoadClaimCodes() { @@ -82,9 +82,9 @@ 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<uint32_t>(774909490); + bitStream.Write<uint64_t>(215523470896); - server->Send(&bitStream, sysAddr, false); + server->Send(bitStream, sysAddr, false); } void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) { @@ -229,7 +229,7 @@ void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAdd RakNet::BitStream loginResponse; BitStreamUtils::WriteHeader(loginResponse, eConnectionType::CLIENT, eClientMessageType::LOGIN_RESPONSE); - loginResponse.Write<uint8_t>(GeneralUtils::CastUnderlyingType(responseCode)); + loginResponse.Write(responseCode); // Event Gating loginResponse.Write(LUString(Game::config->GetValue("event_1"))); @@ -291,16 +291,16 @@ void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAdd stamps.emplace_back(eStamps::PASSPORT_AUTH_WORLD_COMMUNICATION_FINISH, 1); loginResponse.Write<uint32_t>((sizeof(Stamp) * stamps.size()) + sizeof(uint32_t)); - for (auto& stamp : stamps) stamp.Serialize(&loginResponse); + for (auto& stamp : stamps) stamp.Serialize(loginResponse); - server->Send(&loginResponse, sysAddr, false); + server->Send(loginResponse, sysAddr, false); //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); bitStream.Write(sessionKey); bitStream.Write(LUString(username)); - server->SendToMaster(&bitStream); + server->SendToMaster(bitStream); LOG("Set sessionKey: %i for user %s", sessionKey, username.c_str()); } diff --git a/dNet/AuthPackets.h b/dNet/AuthPackets.h index 539bae75a..ee1e4586e 100644 --- a/dNet/AuthPackets.h +++ b/dNet/AuthPackets.h @@ -63,7 +63,7 @@ struct Stamp { this->timestamp = timestamp; } - void Serialize(RakNet::BitStream* outBitStream); + void Serialize(RakNet::BitStream& outBitStream); }; enum class ClientOS : uint8_t { 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..6c9b36b77 100644 --- a/dNet/ChatPackets.cpp +++ b/dNet/ChatPackets.cpp @@ -12,6 +12,30 @@ #include "eConnectionType.h" #include "eChatMessageType.h" +void ShowAllRequest::Serialize(RakNet::BitStream& bitStream) { + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::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, eChatMessageType::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); 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 6d70fedb9..7bd8f4a59 100644 --- a/dNet/MasterPackets.cpp +++ b/dNet/MasterPackets.cpp @@ -12,7 +12,7 @@ void MasterPackets::SendPersistentIDRequest(dServer* server, uint64_t requestID) CBITSTREAM; BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_PERSISTENT_ID); bitStream.Write(requestID); - server->SendToMaster(&bitStream); + server->SendToMaster(bitStream); } void MasterPackets::SendPersistentIDResponse(dServer* server, const SystemAddress& sysAddr, uint64_t requestID, uint32_t objID) { @@ -22,7 +22,7 @@ void MasterPackets::SendPersistentIDResponse(dServer* server, const SystemAddres bitStream.Write(requestID); bitStream.Write(objID); - server->Send(&bitStream, sysAddr, false); + server->Send(bitStream, sysAddr, false); } void MasterPackets::SendZoneTransferRequest(dServer* server, uint64_t requestID, bool mythranShift, uint32_t zoneID, uint32_t cloneID) { @@ -34,7 +34,7 @@ void MasterPackets::SendZoneTransferRequest(dServer* server, uint64_t requestID, bitStream.Write(zoneID); bitStream.Write(cloneID); - server->SendToMaster(&bitStream); + server->SendToMaster(bitStream); } void MasterPackets::SendZoneCreatePrivate(dServer* server, uint32_t zoneID, uint32_t cloneID, const std::string& password) { @@ -49,7 +49,7 @@ void MasterPackets::SendZoneCreatePrivate(dServer* server, uint32_t zoneID, uint bitStream.Write<char>(character); } - server->SendToMaster(&bitStream); + server->SendToMaster(bitStream); } void MasterPackets::SendZoneRequestPrivate(dServer* server, uint64_t requestID, bool mythranShift, const std::string& password) { @@ -64,7 +64,7 @@ void MasterPackets::SendZoneRequestPrivate(dServer* server, uint64_t requestID, bitStream.Write<char>(character); } - server->SendToMaster(&bitStream); + server->SendToMaster(bitStream); } void MasterPackets::SendWorldReady(dServer* server, LWOMAPID zoneId, LWOINSTANCEID instanceId) { @@ -74,7 +74,7 @@ void MasterPackets::SendWorldReady(dServer* server, LWOMAPID zoneId, LWOINSTANCE bitStream.Write(zoneId); bitStream.Write(instanceId); - server->SendToMaster(&bitStream); + server->SendToMaster(bitStream); } 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) { @@ -89,7 +89,7 @@ void MasterPackets::SendZoneTransferResponse(dServer* server, const SystemAddres bitStream.Write<uint16_t>(serverPort); bitStream.Write(LUString(serverIP, 255)); - server->Send(&bitStream, sysAddr, false); + server->Send(bitStream, sysAddr, false); } void MasterPackets::HandleServerInfo(Packet* packet) { @@ -119,5 +119,5 @@ void MasterPackets::SendServerInfo(dServer* server, Packet* packet) { bitStream.Write(server->GetServerType()); bitStream.Write(LUString(server->GetIP())); - server->SendToMaster(&bitStream); + server->SendToMaster(bitStream); } diff --git a/dNet/WorldPackets.cpp b/dNet/WorldPackets.cpp index f92a971f3..44dd687ea 100644 --- a/dNet/WorldPackets.cpp +++ b/dNet/WorldPackets.cpp @@ -12,6 +12,15 @@ #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); @@ -87,13 +96,13 @@ void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, int64_t rep std::unique_ptr<LDFData<int32_t>> chatmode(new LDFData<int32_t>(u"chatmode", static_cast<int32_t>(gm))); std::unique_ptr<LDFData<int64_t>> reputationLdf(new LDFData<int64_t>(u"reputation", reputation)); - objid->WriteToPacket(&data); - lot->WriteToPacket(&data); - name->WriteToPacket(&data); - gmlevel->WriteToPacket(&data); - chatmode->WriteToPacket(&data); - xmlConfigData->WriteToPacket(&data); - reputationLdf->WriteToPacket(&data); + objid->WriteToPacket(data); + lot->WriteToPacket(data); + name->WriteToPacket(data); + gmlevel->WriteToPacket(data); + chatmode->WriteToPacket(data); + xmlConfigData->WriteToPacket(data); + reputationLdf->WriteToPacket(data); //Compress the data before sending: const uint32_t reservedSize = ZCompression::GetMaxCompressedLength(data.GetNumberOfBytesUsed()); @@ -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, eClientMessageType::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, eClientMessageType::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 ed66b42c1..e504a9856 100644 --- a/dNet/dServer.cpp +++ b/dNet/dServer.cpp @@ -159,13 +159,13 @@ void dServer::DeallocateMasterPacket(Packet* packet) { mMasterPeer->DeallocatePacket(packet); } -void dServer::Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast) { - mPeer->Send(bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, sysAddr, broadcast); +void dServer::Send(RakNet::BitStream& bitStream, const SystemAddress& sysAddr, bool broadcast) { + mPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, sysAddr, broadcast); } -void dServer::SendToMaster(RakNet::BitStream* bitStream) { +void dServer::SendToMaster(RakNet::BitStream& bitStream) { if (!mMasterConnectionActive) ConnectToMaster(); - mMasterPeer->Send(bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, mMasterSystemAddress, false); + mMasterPeer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, mMasterSystemAddress, false); } void dServer::Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID) { diff --git a/dNet/dServer.h b/dNet/dServer.h index ef47eea44..40f606f15 100644 --- a/dNet/dServer.h +++ b/dNet/dServer.h @@ -52,8 +52,8 @@ class dServer { Packet* Receive(); void DeallocatePacket(Packet* packet); void DeallocateMasterPacket(Packet* packet); - virtual void Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast); - void SendToMaster(RakNet::BitStream* bitStream); + virtual void Send(RakNet::BitStream& bitStream, const SystemAddress& sysAddr, bool broadcast); + void SendToMaster(RakNet::BitStream& bitStream); void Disconnect(const SystemAddress& sysAddr, eServerDisconnectIdentifiers disconNotifyID); 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/CMakeLists.txt b/dScripts/02_server/DLU/CMakeLists.txt index 64d4cbbdf..fb257d3e6 100644 --- a/dScripts/02_server/DLU/CMakeLists.txt +++ b/dScripts/02_server/DLU/CMakeLists.txt @@ -1,3 +1,3 @@ set(DSCRIPTS_SOURCES_02_SERVER_DLU - "DLUVanityNPC.cpp" + "DLUVanityTeleportingObject.cpp" PARENT_SCOPE) diff --git a/dScripts/02_server/DLU/DLUVanityNPC.cpp b/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp similarity index 51% rename from dScripts/02_server/DLU/DLUVanityNPC.cpp rename to dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp index ba2c66044..60d2d7154 100644 --- a/dScripts/02_server/DLU/DLUVanityNPC.cpp +++ b/dScripts/02_server/DLU/DLUVanityTeleportingObject.cpp @@ -1,24 +1,21 @@ -#include "DLUVanityNPC.h" +#include "DLUVanityTeleportingObject.h" #include "GameMessages.h" #include "dServer.h" #include "VanityUtilities.h" #include "RenderComponent.h" -void DLUVanityNPC::OnStartup(Entity* self) { - m_NPC = VanityUtilities::GetNPC("averysumner - Destroyer of Worlds"); +void DLUVanityTeleportingObject::OnStartup(Entity* self) { + if (!self->HasVar(u"npcName")) return; - if (m_NPC == nullptr) { - 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", 15.0f); - } + self->AddTimer("setupTeleport", m_TeleportInterval); } -void DLUVanityNPC::OnTimerDone(Entity* self, std::string timerName) { +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"); @@ -28,13 +25,14 @@ void DLUVanityNPC::OnTimerDone(Entity* self, std::string timerName) { GameMessages::SendStopFXEffect(self, true, "teleportBeam"); GameMessages::SendStopFXEffect(self, true, "teleportRings"); } else if (timerName == "teleport") { - std::vector<VanityNPCLocation>& locations = m_NPC->m_Locations[Game::server->GetZoneID()]; + std::vector<VanityObjectLocation>& locations = m_Object->m_Locations[Game::server->GetZoneID()]; selectLocation: - VanityNPCLocation& newLocation = locations[GeneralUtils::GenerateRandomNumber<size_t>(0, locations.size() - 1)]; + VanityObjectLocation& newLocation = locations[GeneralUtils::GenerateRandomNumber<size_t>(0, locations.size() - 1)]; + // try to get not the same position, but if we get the same one twice, it's fine if (self->GetPosition() == newLocation.m_Position) { - goto selectLocation; // cry about it + VanityObjectLocation& newLocation = locations[GeneralUtils::GenerateRandomNumber<size_t>(0, locations.size() - 1)]; } self->SetPosition(newLocation.m_Position); @@ -42,6 +40,6 @@ void DLUVanityNPC::OnTimerDone(Entity* self, std::string timerName) { GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportBeam", "teleportBeam"); GameMessages::SendPlayFXEffect(self->GetObjectID(), 6478, u"teleportRings", "teleportRings"); self->AddTimer("stopFX", 2.0f); - self->AddTimer("setupTeleport", 15.0f); + self->AddTimer("setupTeleport", m_TeleportInterval); } } diff --git a/dScripts/02_server/DLU/DLUVanityTeleportingObject.h b/dScripts/02_server/DLU/DLUVanityTeleportingObject.h new file mode 100644 index 000000000..a13ba901c --- /dev/null +++ b/dScripts/02_server/DLU/DLUVanityTeleportingObject.h @@ -0,0 +1,14 @@ +#pragma once +#include "CppScripts.h" + +class VanityObject; +class DLUVanityTeleportingObject : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; + +private: + VanityObject* m_Object; + float m_TeleportInterval = 15.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/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/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/DLU/DLUVanityNPC.h b/dScripts/02_server/Map/FV/Racing/RaceFireballs.h similarity index 62% rename from dScripts/02_server/DLU/DLUVanityNPC.h rename to dScripts/02_server/Map/FV/Racing/RaceFireballs.h index aeb8e051d..e96286ae0 100644 --- a/dScripts/02_server/DLU/DLUVanityNPC.h +++ b/dScripts/02_server/Map/FV/Racing/RaceFireballs.h @@ -1,13 +1,9 @@ #pragma once #include "CppScripts.h" -class VanityNPC; -class DLUVanityNPC : public CppScripts::Script +class RaceFireballs : public CppScripts::Script { public: void OnStartup(Entity* self) override; void OnTimerDone(Entity* self, std::string timerName) override; - -private: - VanityNPC* m_NPC; }; 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/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 071bd7a3e..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" @@ -216,7 +223,7 @@ #include "NtNaomiBreadcrumbServer.h" // DLU Scripts -#include "DLUVanityNPC.h" +#include "DLUVanityTeleportingObject.h" // AM Scripts #include "AmConsoleTeleportServer.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\\DLUVanityNPC.lua") - script = new DLUVanityNPC(); - - // 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..56f5b257e 100644 --- a/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp +++ b/dScripts/ai/MINIGAME/SG_GF/SERVER/SGCannon.cpp @@ -307,11 +307,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 bb879dbdf..d3dc78cc6 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -66,7 +66,7 @@ #include "eObjectBits.h" #include "eConnectionType.h" #include "eServerMessageType.h" -#include "eChatInternalMessageType.h" +#include "eChatMessageType.h" #include "eWorldMessageType.h" #include "eMasterMessageType.h" #include "eGameMessageType.h" @@ -79,6 +79,7 @@ #include "PositionUpdate.h" #include "PlayerManager.h" #include "eLoginResponse.h" +#include "SlashCommandHandler.h" namespace Game { Logger* logger = nullptr; @@ -281,24 +282,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 +312,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 +337,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); @@ -384,14 +386,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 +529,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,126 +543,125 @@ 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<eChatMessageType>(packet->data[3])) { + case eChatMessageType::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 + SEND_PACKET; //send routed packet to player + break; + } - break; - } + case eChatMessageType::GM_ANNOUNCE: { + CINSTREAM_SKIP_HEADER; - case eChatInternalMessageType::ANNOUNCEMENT: { - CINSTREAM_SKIP_HEADER; + std::string title; + std::string msg; - std::string title; - std::string msg; + uint32_t len; + inStream.Read<uint32_t>(len); + for (uint32_t i = 0; len > i; i++) { + char character; + inStream.Read<char>(character); + title += 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; - } + len = 0; + inStream.Read<uint32_t>(len); + for (uint32_t i = 0; len > i; i++) { + char character; + inStream.Read<char>(character); + msg += character; + } - len = 0; - inStream.Read<uint32_t>(len); - for (uint32_t i = 0; len > i; i++) { - char character; - inStream.Read<char>(character); - msg += character; - } + //Send to our clients: + AMFArrayValue args; - //Send to our clients: - AMFArrayValue args; + args.Insert("title", title); + args.Insert("message", msg); - args.Insert("title", title); - args.Insert("message", msg); + GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); - GameMessages::SendUIMessageServerToAllClients("ToggleAnnounce", args); + break; + } - break; - } + case eChatMessageType::GM_MUTE: { + CINSTREAM_SKIP_HEADER; + LWOOBJID playerId; + time_t expire = 0; + inStream.Read(playerId); + inStream.Read(expire); - 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 eChatMessageType::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); + LOG("Deleting team (%llu)", teamID); - break; - } + break; + } - 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); + 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); - LOG("Updating team member (%llu)", member); - } + LOG("Updating team member (%llu)", member); + } - TeamManager::Instance()->UpdateTeam(teamID, lootOption, members); + TeamManager::Instance()->UpdateTeam(teamID, lootOption, members); - break; - } - - 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: { @@ -728,9 +730,9 @@ void HandleMasterPacket(Packet* packet) { { CBITSTREAM; BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PLAYER_ADDED); - bitStream.Write((LWOMAPID)Game::server->GetZoneID()); - bitStream.Write((LWOINSTANCEID)instanceID); - Game::server->SendToMaster(&bitStream); + bitStream.Write<LWOMAPID>(Game::server->GetZoneID()); + bitStream.Write<LWOINSTANCEID>(instanceID); + Game::server->SendToMaster(bitStream); } } @@ -746,7 +748,7 @@ void HandleMasterPacket(Packet* packet) { BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::AFFIRM_TRANSFER_RESPONSE); bitStream.Write(requestID); - Game::server->SendToMaster(&bitStream); + Game::server->SendToMaster(bitStream); break; } @@ -785,6 +787,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 +820,7 @@ void HandlePacket(Packet* packet) { { CBITSTREAM; - BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION); + BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::UNEXPECTED_DISCONNECT); bitStream.Write(user->GetLoggedInChar()); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } @@ -830,9 +833,9 @@ void HandlePacket(Packet* packet) { CBITSTREAM; BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::PLAYER_REMOVED); - bitStream.Write((LWOMAPID)Game::server->GetZoneID()); - bitStream.Write((LWOINSTANCEID)instanceID); - Game::server->SendToMaster(&bitStream); + 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; @@ -895,7 +898,7 @@ void HandlePacket(Packet* packet) { CBITSTREAM; BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::REQUEST_SESSION_KEY); bitStream.Write(username); - Game::server->SendToMaster(&bitStream); + Game::server->SendToMaster(bitStream); //Insert info into our pending list tempSessionInfo info; @@ -950,7 +953,7 @@ void HandlePacket(Packet* packet) { static_cast<int32_t>(messageID) ); - if (isSender) GameMessageHandler::HandleMessage(&dataStream, packet->systemAddress, objectID, messageID); + if (isSender) GameMessageHandler::HandleMessage(dataStream, packet->systemAddress, objectID, messageID); break; } @@ -986,7 +989,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, eChatMessageType::UNEXPECTED_DISCONNECT); bitStream.Write(lastCharacter); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } @@ -1132,7 +1135,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, eChatMessageType::LOGIN_SESSION_NOTIFY); bitStream.Write(player->GetObjectID()); bitStream.Write<uint32_t>(playerName.size()); for (size_t i = 0; i < playerName.size(); i++) { @@ -1177,7 +1180,7 @@ void HandlePacket(Packet* packet) { // FIXME: Change this to the macro to skip the header... LWOOBJID space; bitStream.Read(space); - Mail::HandleMailStuff(&bitStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity()); + Mail::HandleMailStuff(bitStream, packet->systemAddress, UserManager::Instance()->GetUser(packet->systemAddress)->GetLastUsedChar()->GetEntity()); break; } @@ -1207,8 +1210,8 @@ 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); @@ -1461,5 +1464,5 @@ void FinalizeShutdown() { void SendShutdownMessageToMaster() { CBITSTREAM; BitStreamUtils::WriteHeader(bitStream, eConnectionType::MASTER, eMasterMessageType::SHUTDOWN_RESPONSE); - Game::server->SendToMaster(&bitStream); + 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/Level.cpp b/dZoneManager/Level.cpp index 9524d908b..5f35b6290 100644 --- a/dZoneManager/Level.cpp +++ b/dZoneManager/Level.cpp @@ -200,9 +200,6 @@ void Level::ReadFileInfoChunk(std::istream& file, Header& header) { BinaryIO::BinaryRead(file, header.fileInfo.enviromentChunkStart); BinaryIO::BinaryRead(file, header.fileInfo.objectChunkStart); BinaryIO::BinaryRead(file, header.fileInfo.particleChunkStart); - - //PATCH FOR AG: (messed up file?) - if (header.fileInfo.revision == 0xCDCDCDCD && m_ParentZone->GetZoneID().GetMapID() == 1100) header.fileInfo.revision = 26; } void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) { 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/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/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ba75a2f1..e8765191f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,20 +1,19 @@ -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 -) +find_package(GoogleTest REQUIRED) +include(GoogleTest) -# For Windows: Prevent overriding the parent project's compiler/linker settings -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) -FetchContent_MakeAvailable(GoogleTest) -include(GoogleTest) +if(APPLE) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH True) + set(CMAKE_BUILD_WITH_INSTALL_RPATH True) + set(CMAKE_INSTALL_RPATH "@executable_path") +endif() -message(STATUS "gtest fetched and is now ready.") +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 58c465841..c949ae502 100644 --- a/tests/dCommonTests/AMFDeserializeTests.cpp +++ b/tests/dCommonTests/AMFDeserializeTests.cpp @@ -11,10 +11,10 @@ /** * Helper method that all tests use to get their respective AMF. */ -AMFBaseValue* ReadFromBitStream(RakNet::BitStream* bitStream) { +std::unique_ptr<AMFBaseValue> ReadFromBitStream(RakNet::BitStream& bitStream) { AMFDeserialize deserializer; AMFBaseValue* returnValue(deserializer.Read(bitStream)); - return returnValue; + return std::unique_ptr<AMFBaseValue>{ returnValue }; } /** @@ -23,7 +23,7 @@ AMFBaseValue* ReadFromBitStream(RakNet::BitStream* bitStream) { TEST(dCommonTests, AMFDeserializeAMFUndefinedTest) { CBITSTREAM; bitStream.Write<uint8_t>(0x00); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Undefined); } @@ -34,7 +34,7 @@ TEST(dCommonTests, AMFDeserializeAMFUndefinedTest) { TEST(dCommonTests, AMFDeserializeAMFNullTest) { CBITSTREAM; bitStream.Write<uint8_t>(0x01); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Null); } @@ -44,7 +44,7 @@ TEST(dCommonTests, AMFDeserializeAMFNullTest) { TEST(dCommonTests, AMFDeserializeAMFFalseTest) { CBITSTREAM; bitStream.Write<uint8_t>(0x02); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::False); } @@ -54,7 +54,7 @@ TEST(dCommonTests, AMFDeserializeAMFFalseTest) { TEST(dCommonTests, AMFDeserializeAMFTrueTest) { CBITSTREAM; bitStream.Write<uint8_t>(0x03); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::True); } @@ -67,7 +67,7 @@ TEST(dCommonTests, AMFDeserializeAMFIntegerTest) { bitStream.Write<uint8_t>(0x04); // 127 == 01111111 bitStream.Write<uint8_t>(127); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Integer); // Check that the max value of a byte can be read correctly ASSERT_EQ(static_cast<AMFIntValue*>(res.get())->GetValue(), 127); @@ -76,7 +76,7 @@ TEST(dCommonTests, AMFDeserializeAMFIntegerTest) { { bitStream.Write<uint8_t>(0x04); bitStream.Write<uint32_t>(UINT32_MAX); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Integer); // Check that we can read the maximum value correctly ASSERT_EQ(static_cast<AMFIntValue*>(res.get())->GetValue(), 536870911); @@ -90,7 +90,7 @@ TEST(dCommonTests, AMFDeserializeAMFIntegerTest) { bitStream.Write<uint8_t>(255); // 127 == 01111111 bitStream.Write<uint8_t>(127); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Integer); // Check that short max can be read correctly ASSERT_EQ(static_cast<AMFIntValue*>(res.get())->GetValue(), UINT16_MAX); @@ -102,7 +102,7 @@ TEST(dCommonTests, AMFDeserializeAMFIntegerTest) { bitStream.Write<uint8_t>(255); // 127 == 01111111 bitStream.Write<uint8_t>(127); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Integer); // Check that 2 byte max can be read correctly ASSERT_EQ(static_cast<AMFIntValue*>(res.get())->GetValue(), 16383); @@ -116,7 +116,7 @@ TEST(dCommonTests, AMFDeserializeAMFDoubleTest) { CBITSTREAM; bitStream.Write<uint8_t>(0x05); bitStream.Write<double>(25346.4f); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Double); ASSERT_EQ(static_cast<AMFDoubleValue*>(res.get())->GetValue(), 25346.4f); } @@ -130,7 +130,7 @@ TEST(dCommonTests, AMFDeserializeAMFStringTest) { bitStream.Write<uint8_t>(0x0F); std::string toWrite = "stateID"; for (auto e : toWrite) bitStream.Write<char>(e); - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::String); ASSERT_EQ(static_cast<AMFStringValue*>(res.get())->GetValue(), "stateID"); } @@ -145,7 +145,7 @@ TEST(dCommonTests, AMFDeserializeAMFArrayTest) { bitStream.Write<uint8_t>(0x01); bitStream.Write<uint8_t>(0x01); { - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Array); ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetAssociative().size(), 0); ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDense().size(), 0); @@ -164,7 +164,7 @@ TEST(dCommonTests, AMFDeserializeAMFArrayTest) { bitStream.Write<uint8_t>(0x0B); for (auto e : "10447") if (e != '\0') bitStream.Write<char>(e); { - std::unique_ptr<AMFBaseValue> res(ReadFromBitStream(&bitStream)); + std::unique_ptr<AMFBaseValue> res{ ReadFromBitStream(bitStream) }; ASSERT_EQ(res->GetValueType(), eAmf::Array); ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetAssociative().size(), 1); ASSERT_EQ(static_cast<AMFArrayValue*>(res.get())->GetDense().size(), 1); @@ -213,7 +213,7 @@ TEST(dCommonTests, AMFDeserializeUnimplementedValuesTest) { testBitStream.Write(value); bool caughtException = false; try { - ReadFromBitStream(&testBitStream); + ReadFromBitStream(testBitStream); } catch (eAmf unimplementedValueType) { caughtException = true; } @@ -238,119 +238,111 @@ TEST(dCommonTests, AMFDeserializeLivePacketTest) { testFileStream.close(); - std::unique_ptr<AMFBaseValue> resultFromFn(ReadFromBitStream(&testBitStream)); - auto result = static_cast<AMFArrayValue*>(resultFromFn.get()); + std::unique_ptr<AMFBaseValue> resultFromFn{ ReadFromBitStream(testBitStream) }; + auto* result = static_cast<AMFArrayValue*>(resultFromFn.get()); // Test the outermost array ASSERT_EQ(result->Get<std::string>("BehaviorID")->GetValue(), "10447"); ASSERT_EQ(result->Get<std::string>("objectID")->GetValue(), "288300744895913279"); // Test the execution state array - auto executionState = result->GetArray("executionState"); + auto* executionState = result->GetArray("executionState"); ASSERT_NE(executionState, nullptr); - auto strips = executionState->GetArray("strips")->GetDense(); + auto& strips = executionState->GetArray("strips")->GetDense(); ASSERT_EQ(strips.size(), 1); - auto stripsPosition0 = dynamic_cast<AMFArrayValue*>(strips[0]); + auto* stripsPosition0 = dynamic_cast<AMFArrayValue*>(strips[0]); - auto actionIndex = stripsPosition0->Get<double>("actionIndex"); + auto* actionIndex = stripsPosition0->Get<double>("actionIndex"); ASSERT_EQ(actionIndex->GetValue(), 0.0f); - auto stripIdExecution = stripsPosition0->Get<double>("id"); + auto* stripIdExecution = stripsPosition0->Get<double>("id"); ASSERT_EQ(stripIdExecution->GetValue(), 0.0f); - auto stateIdExecution = executionState->Get<double>("stateID"); + auto* stateIdExecution = executionState->Get<double>("stateID"); ASSERT_EQ(stateIdExecution->GetValue(), 0.0f); - auto states = result->GetArray("states")->GetDense(); + auto& states = result->GetArray("states")->GetDense(); ASSERT_EQ(states.size(), 1); - auto firstState = dynamic_cast<AMFArrayValue*>(states[0]); + auto* firstState = dynamic_cast<AMFArrayValue*>(states[0]); - auto stateID = firstState->Get<double>("id"); + auto* stateID = firstState->Get<double>("id"); ASSERT_EQ(stateID->GetValue(), 0.0f); - auto stripsInState = firstState->GetArray("strips")->GetDense(); + auto& stripsInState = firstState->GetArray("strips")->GetDense(); ASSERT_EQ(stripsInState.size(), 1); - auto firstStrip = dynamic_cast<AMFArrayValue*>(stripsInState[0]); + auto* firstStrip = dynamic_cast<AMFArrayValue*>(stripsInState[0]); - auto actionsInFirstStrip = firstStrip->GetArray("actions")->GetDense(); + auto& actionsInFirstStrip = firstStrip->GetArray("actions")->GetDense(); ASSERT_EQ(actionsInFirstStrip.size(), 3); - auto actionID = firstStrip->Get<double>("id"); + auto* actionID = firstStrip->Get<double>("id"); ASSERT_EQ(actionID->GetValue(), 0.0f); - auto uiArray = firstStrip->GetArray("ui"); + auto* uiArray = firstStrip->GetArray("ui"); - auto xPos = uiArray->Get<double>("x"); - auto yPos = uiArray->Get<double>("y"); + auto* xPos = uiArray->Get<double>("x"); + auto* yPos = uiArray->Get<double>("y"); ASSERT_EQ(xPos->GetValue(), 103.0f); ASSERT_EQ(yPos->GetValue(), 82.0f); - auto stripId = firstStrip->Get<double>("id"); + auto* stripId = firstStrip->Get<double>("id"); ASSERT_EQ(stripId->GetValue(), 0.0f); - auto firstAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[0]); + auto* firstAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[0]); - auto firstType = firstAction->Get<std::string>("Type"); + auto* firstType = firstAction->Get<std::string>("Type"); ASSERT_EQ(firstType->GetValue(), "OnInteract"); - auto firstCallback = firstAction->Get<std::string>("__callbackID__"); + auto* firstCallback = firstAction->Get<std::string>("__callbackID__"); ASSERT_EQ(firstCallback->GetValue(), ""); - auto secondAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[1]); + auto* secondAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[1]); - auto secondType = secondAction->Get<std::string>("Type"); + auto* secondType = secondAction->Get<std::string>("Type"); ASSERT_EQ(secondType->GetValue(), "FlyUp"); - auto secondCallback = secondAction->Get<std::string>("__callbackID__"); + auto* secondCallback = secondAction->Get<std::string>("__callbackID__"); ASSERT_EQ(secondCallback->GetValue(), ""); - auto secondDistance = secondAction->Get<double>("Distance"); + auto* secondDistance = secondAction->Get<double>("Distance"); ASSERT_EQ(secondDistance->GetValue(), 25.0f); - auto thirdAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[2]); + auto* thirdAction = dynamic_cast<AMFArrayValue*>(actionsInFirstStrip[2]); - auto thirdType = thirdAction->Get<std::string>("Type"); + auto* thirdType = thirdAction->Get<std::string>("Type"); ASSERT_EQ(thirdType->GetValue(), "FlyDown"); - auto thirdCallback = thirdAction->Get<std::string>("__callbackID__"); + auto* thirdCallback = thirdAction->Get<std::string>("__callbackID__"); ASSERT_EQ(thirdCallback->GetValue(), ""); - auto thirdDistance = thirdAction->Get<double>("Distance"); + auto* thirdDistance = thirdAction->Get<double>("Distance"); ASSERT_EQ(thirdDistance->GetValue(), 25.0f); } -/** - * @brief Tests that having no BitStream returns a nullptr. - */ -TEST(dCommonTests, AMFDeserializeNullTest) { - std::unique_ptr<AMFBaseValue> result(ReadFromBitStream(nullptr)); - ASSERT_EQ(result.get(), nullptr); -} - TEST(dCommonTests, AMFBadConversionTest) { std::ifstream testFileStream; testFileStream.open("AMFBitStreamTest.bin", std::ios::binary); @@ -364,7 +356,7 @@ TEST(dCommonTests, AMFBadConversionTest) { testFileStream.close(); - std::unique_ptr<AMFBaseValue> resultFromFn(ReadFromBitStream(&testBitStream)); + std::unique_ptr<AMFBaseValue> resultFromFn(ReadFromBitStream(testBitStream)); auto result = static_cast<AMFArrayValue*>(resultFromFn.get()); // Actually a string value. 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/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/CastUnderlyingTypeTests.cpp b/tests/dCommonTests/ToUnderlyingTests.cpp similarity index 68% rename from tests/dCommonTests/CastUnderlyingTypeTests.cpp rename to tests/dCommonTests/ToUnderlyingTests.cpp index 9cdfcdd3d..4cbf46358 100644 --- a/tests/dCommonTests/CastUnderlyingTypeTests.cpp +++ b/tests/dCommonTests/ToUnderlyingTests.cpp @@ -7,13 +7,13 @@ #include "eWorldMessageType.h" #define ASSERT_TYPE_EQ(TYPE, ENUM)\ - ASSERT_TRUE(typeid(TYPE) == typeid(GeneralUtils::CastUnderlyingType(static_cast<ENUM>(0)))); + ASSERT_TRUE(typeid(TYPE) == typeid(GeneralUtils::ToUnderlying(static_cast<ENUM>(0)))); #define ASSERT_TYPE_NE(TYPE, ENUM)\ - ASSERT_FALSE(typeid(TYPE) == typeid(GeneralUtils::CastUnderlyingType(static_cast<ENUM>(0)))); + ASSERT_FALSE(typeid(TYPE) == typeid(GeneralUtils::ToUnderlying(static_cast<ENUM>(0)))); // Verify that the underlying enum types are being cast correctly -TEST(CastUnderlyingTypeTests, VerifyCastUnderlyingType) { +TEST(ToUnderlyingTests, VerifyToUnderlying) { ASSERT_TYPE_EQ(uint8_t, eGameMasterLevel); ASSERT_TYPE_EQ(uint16_t, eGameMessageType); ASSERT_TYPE_EQ(uint32_t, eWorldMessageType) diff --git a/tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp b/tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp index 0ca2e2ea9..c47eb489e 100644 --- a/tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp +++ b/tests/dCommonTests/dEnumsTests/MagicEnumTests.cpp @@ -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; diff --git a/tests/dGameTests/CMakeLists.txt b/tests/dGameTests/CMakeLists.txt index b1fdaa070..58f213e0a 100644 --- a/tests/dGameTests/CMakeLists.txt +++ b/tests/dGameTests/CMakeLists.txt @@ -12,8 +12,18 @@ file(COPY ${GAMEMESSAGE_TESTBITSTREAMS} 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 5d9c99bf5..52e3919af 100644 --- a/tests/dGameTests/GameDependencies.h +++ b/tests/dGameTests/GameDependencies.h @@ -19,7 +19,7 @@ class dServerMock : public dServer { dServerMock() {}; ~dServerMock() {}; RakNet::BitStream* GetMostRecentBitStream() { return sentBitStream; }; - void Send(RakNet::BitStream* bitStream, const SystemAddress& sysAddr, bool broadcast) override { sentBitStream = bitStream; }; + void Send(RakNet::BitStream& bitStream, const SystemAddress& sysAddr, bool broadcast) override { sentBitStream = &bitStream; }; }; class GameDependenciesTest : public ::testing::Test { diff --git a/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp b/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp index ff37f1548..d14004ee9 100644 --- a/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp +++ b/tests/dGameTests/dComponentsTests/DestroyableComponentTests.cpp @@ -48,7 +48,7 @@ TEST_F(DestroyableTest, PlacementNewAddComponentTest) { * Test Construction of a DestroyableComponent */ TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) { - destroyableComponent->Serialize(&bitStream, true); + destroyableComponent->Serialize(bitStream, true); // Assert that the full number of bits are present ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 748); { @@ -178,7 +178,7 @@ TEST_F(DestroyableTest, DestroyableComponentSerializeTest) { destroyableComponent->SetMaxHealth(1233.0f); // Now we test a serialization for correctness. - destroyableComponent->Serialize(&bitStream, false); + destroyableComponent->Serialize(bitStream, false); ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 422); { // Now read in the full serialized BitStream diff --git a/tests/dGameTests/dComponentsTests/SimplePhysicsComponentTests.cpp b/tests/dGameTests/dComponentsTests/SimplePhysicsComponentTests.cpp index 896dcf5af..0116dfcc1 100644 --- a/tests/dGameTests/dComponentsTests/SimplePhysicsComponentTests.cpp +++ b/tests/dGameTests/dComponentsTests/SimplePhysicsComponentTests.cpp @@ -30,7 +30,7 @@ class SimplePhysicsTest : public GameDependenciesTest { }; TEST_F(SimplePhysicsTest, SimplePhysicsSerializeTest) { - simplePhysicsComponent->Serialize(&bitStream, false); + simplePhysicsComponent->Serialize(bitStream, false); constexpr uint32_t sizeOfStream = 3 + BYTES_TO_BITS(3 * sizeof(NiPoint3)) + BYTES_TO_BITS(1 * sizeof(NiQuaternion)) + 1 * BYTES_TO_BITS(sizeof(uint32_t)); ASSERT_EQ(bitStream.GetNumberOfBitsUsed(), sizeOfStream); @@ -77,7 +77,7 @@ TEST_F(SimplePhysicsTest, SimplePhysicsSerializeTest) { } TEST_F(SimplePhysicsTest, SimplePhysicsConstructionTest) { - simplePhysicsComponent->Serialize(&bitStream, true); + simplePhysicsComponent->Serialize(bitStream, true); constexpr uint32_t sizeOfStream = 4 + BYTES_TO_BITS(1 * sizeof(int32_t)) + BYTES_TO_BITS(3 * sizeof(NiPoint3)) + BYTES_TO_BITS(1 * sizeof(NiQuaternion)) + 1 * BYTES_TO_BITS(sizeof(uint32_t)); ASSERT_EQ(bitStream.GetNumberOfBitsUsed(), sizeOfStream); diff --git a/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp index 047f56d65..2d37d102c 100644 --- a/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp +++ b/tests/dGameTests/dGameMessagesTests/GameMessageTests.cpp @@ -38,11 +38,11 @@ class GameMessageTests: public GameDependenciesTest { } return readFile; } - AMFArrayValue* ReadArrayFromBitStream(RakNet::BitStream* inStream) { + const AMFArrayValue& ReadArrayFromBitStream(RakNet::BitStream& inStream) { AMFDeserialize des; AMFBaseValue* readArray = des.Read(inStream); EXPECT_EQ(readArray->GetValueType(), eAmf::Array); - return static_cast<AMFArrayValue*>(readArray); + return static_cast<AMFArrayValue&>(*readArray); } }; @@ -87,13 +87,13 @@ TEST_F(GameMessageTests, SendBlueprintLoadItemResponse) { TEST_F(GameMessageTests, ControlBehaviorAddStrip) { auto data = ReadFromFile("addStrip"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - AddStripMessage addStrip(ReadArrayFromBitStream(&inStream)); + 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); ASSERT_EQ(static_cast<uint32_t>(addStrip.GetActionContext().GetStateId()), 0); - ASSERT_EQ(addStrip.GetBehaviorId(), -1); + ASSERT_EQ(addStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); ASSERT_EQ(addStrip.GetActionsToAdd().front().GetType(), "DropImagination"); ASSERT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterName(), "Amount"); ASSERT_EQ(addStrip.GetActionsToAdd().front().GetValueParameterString(), ""); @@ -102,29 +102,29 @@ TEST_F(GameMessageTests, ControlBehaviorAddStrip) { TEST_F(GameMessageTests, ControlBehaviorRemoveStrip) { auto data = ReadFromFile("removeStrip"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - RemoveStripMessage removeStrip(ReadArrayFromBitStream(&inStream)); + 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(), -1); + ASSERT_EQ(removeStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); } TEST_F(GameMessageTests, ControlBehaviorMergeStrips) { auto data = ReadFromFile("mergeStrips"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - MergeStripsMessage mergeStrips(ReadArrayFromBitStream(&inStream)); + 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); ASSERT_EQ(static_cast<uint32_t>(mergeStrips.GetDestinationActionContext().GetStateId()), 0); ASSERT_EQ(mergeStrips.GetDstActionIndex(), 0); - ASSERT_EQ(mergeStrips.GetBehaviorId(), -1); + ASSERT_EQ(mergeStrips.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); } TEST_F(GameMessageTests, ControlBehaviorSplitStrip) { auto data = ReadFromFile("splitStrip"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - SplitStripMessage splitStrip(ReadArrayFromBitStream(&inStream)); + 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); @@ -138,19 +138,19 @@ TEST_F(GameMessageTests, ControlBehaviorSplitStrip) { TEST_F(GameMessageTests, ControlBehaviorUpdateStripUI) { auto data = ReadFromFile("updateStripUI"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - UpdateStripUiMessage updateStripUi(ReadArrayFromBitStream(&inStream)); + 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); ASSERT_EQ(static_cast<uint32_t>(updateStripUi.GetActionContext().GetStateId()), 0); - ASSERT_EQ(updateStripUi.GetBehaviorId(), -1); + ASSERT_EQ(updateStripUi.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); } TEST_F(GameMessageTests, ControlBehaviorAddAction) { auto data = ReadFromFile("addAction"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - AddActionMessage addAction(ReadArrayFromBitStream(&inStream)); + 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); @@ -158,45 +158,45 @@ TEST_F(GameMessageTests, ControlBehaviorAddAction) { ASSERT_EQ(addAction.GetAction().GetValueParameterName(), ""); ASSERT_EQ(addAction.GetAction().GetValueParameterString(), ""); ASSERT_EQ(addAction.GetAction().GetValueParameterDouble(), 0.0); - ASSERT_EQ(addAction.GetBehaviorId(), -1); + ASSERT_EQ(addAction.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); } TEST_F(GameMessageTests, ControlBehaviorMigrateActions) { auto data = ReadFromFile("migrateActions"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - MigrateActionsMessage migrateActions(ReadArrayFromBitStream(&inStream)); + 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); ASSERT_EQ(migrateActions.GetDestinationActionContext().GetStripId(), 0); ASSERT_EQ(static_cast<uint32_t>(migrateActions.GetSourceActionContext().GetStateId()), 0); ASSERT_EQ(static_cast<uint32_t>(migrateActions.GetDestinationActionContext().GetStateId()), 0); - ASSERT_EQ(migrateActions.GetBehaviorId(), -1); + ASSERT_EQ(migrateActions.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); } TEST_F(GameMessageTests, ControlBehaviorRearrangeStrip) { auto data = ReadFromFile("rearrangeStrip"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - RearrangeStripMessage rearrangeStrip(ReadArrayFromBitStream(&inStream)); + 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); - ASSERT_EQ(rearrangeStrip.GetBehaviorId(), -1); + ASSERT_EQ(rearrangeStrip.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); ASSERT_EQ(static_cast<uint32_t>(rearrangeStrip.GetActionContext().GetStateId()), 0); } TEST_F(GameMessageTests, ControlBehaviorAdd) { auto data = ReadFromFile("add"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - AddMessage add(ReadArrayFromBitStream(&inStream)); + 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); - RemoveActionsMessage removeActions(ReadArrayFromBitStream(&inStream)); + 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); @@ -205,21 +205,21 @@ TEST_F(GameMessageTests, ControlBehaviorRemoveActions) { TEST_F(GameMessageTests, ControlBehaviorRename) { auto data = ReadFromFile("rename"); - RakNet::BitStream inStream((unsigned char*)data.c_str(), data.length(), true); - RenameMessage rename(ReadArrayFromBitStream(&inStream)); + 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(), -1); + 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); - UpdateActionMessage updateAction(ReadArrayFromBitStream(&inStream)); + 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(), ""); ASSERT_EQ(updateAction.GetAction().GetValueParameterDouble(), 50.0); - ASSERT_EQ(updateAction.GetBehaviorId(), -1); + ASSERT_EQ(updateAction.GetBehaviorId(), BehaviorMessageBase::DefaultBehaviorId); ASSERT_EQ(updateAction.GetActionIndex(), 1); ASSERT_EQ(updateAction.GetActionContext().GetStripId(), 0); ASSERT_EQ(static_cast<uint32_t>(updateAction.GetActionContext().GetStateId()), 0); diff --git a/tests/dGameTests/dGameMessagesTests/LegacyGameMessageTests.cpp b/tests/dGameTests/dGameMessagesTests/LegacyGameMessageTests.cpp index 0226b0adb..47b930ed4 100644 --- a/tests/dGameTests/dGameMessagesTests/LegacyGameMessageTests.cpp +++ b/tests/dGameTests/dGameMessagesTests/LegacyGameMessageTests.cpp @@ -2,297 +2,297 @@ #include "eGameMessageType.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(eGameMessageType::TELEPORT, static_cast<eGameMessageType>(19)); + EXPECT_EQ(eGameMessageType::SET_PLAYER_CONTROL_SCHEME, static_cast<eGameMessageType>(26)); + EXPECT_EQ(eGameMessageType::DROP_CLIENT_LOOT, static_cast<eGameMessageType>(30)); + EXPECT_EQ(eGameMessageType::DIE, static_cast<eGameMessageType>(37)); + EXPECT_EQ(eGameMessageType::REQUEST_DIE, static_cast<eGameMessageType>(38)); + EXPECT_EQ(eGameMessageType::PLAY_EMOTE, static_cast<eGameMessageType>(41)); + EXPECT_EQ(eGameMessageType::PLAY_ANIMATION, static_cast<eGameMessageType>(43)); + EXPECT_EQ(eGameMessageType::CONTROL_BEHAVIORS, static_cast<eGameMessageType>(48)); + EXPECT_EQ(eGameMessageType::SET_NAME, static_cast<eGameMessageType>(72)); + EXPECT_EQ(eGameMessageType::ECHO_START_SKILL, static_cast<eGameMessageType>(118)); + EXPECT_EQ(eGameMessageType::START_SKILL, static_cast<eGameMessageType>(119)); + EXPECT_EQ(eGameMessageType::VERIFY_ACK, static_cast<eGameMessageType>(121)); + EXPECT_EQ(eGameMessageType::ADD_SKILL, static_cast<eGameMessageType>(127)); + EXPECT_EQ(eGameMessageType::REMOVE_SKILL, static_cast<eGameMessageType>(128)); + EXPECT_EQ(eGameMessageType::SET_CURRENCY, static_cast<eGameMessageType>(133)); + EXPECT_EQ(eGameMessageType::PICKUP_CURRENCY, static_cast<eGameMessageType>(137)); + EXPECT_EQ(eGameMessageType::PICKUP_ITEM, static_cast<eGameMessageType>(139)); + EXPECT_EQ(eGameMessageType::TEAM_PICKUP_ITEM, static_cast<eGameMessageType>(140)); + EXPECT_EQ(eGameMessageType::PLAY_FX_EFFECT, static_cast<eGameMessageType>(154)); + EXPECT_EQ(eGameMessageType::STOP_FX_EFFECT, static_cast<eGameMessageType>(155)); + EXPECT_EQ(eGameMessageType::REQUEST_RESURRECT, static_cast<eGameMessageType>(159)); + EXPECT_EQ(eGameMessageType::RESURRECT, static_cast<eGameMessageType>(160)); + EXPECT_EQ(eGameMessageType::PUSH_EQUIPPED_ITEMS_STATE, static_cast<eGameMessageType>(191)); + EXPECT_EQ(eGameMessageType::POP_EQUIPPED_ITEMS_STATE, static_cast<eGameMessageType>(192)); + EXPECT_EQ(eGameMessageType::SET_GM_LEVEL, static_cast<eGameMessageType>(193)); + EXPECT_EQ(eGameMessageType::SET_STUNNED, static_cast<eGameMessageType>(198)); + EXPECT_EQ(eGameMessageType::SET_STUN_IMMUNITY, static_cast<eGameMessageType>(200)); + EXPECT_EQ(eGameMessageType::KNOCKBACK, static_cast<eGameMessageType>(202)); + EXPECT_EQ(eGameMessageType::REBUILD_CANCEL, static_cast<eGameMessageType>(209)); + EXPECT_EQ(eGameMessageType::ENABLE_REBUILD, static_cast<eGameMessageType>(213)); + EXPECT_EQ(eGameMessageType::MOVE_ITEM_IN_INVENTORY, static_cast<eGameMessageType>(224)); + EXPECT_EQ(eGameMessageType::ADD_ITEM_TO_INVENTORY_CLIENT_SYNC, static_cast<eGameMessageType>(227)); + EXPECT_EQ(eGameMessageType::REMOVE_ITEM_FROM_INVENTORY, static_cast<eGameMessageType>(230)); + EXPECT_EQ(eGameMessageType::EQUIP_INVENTORY, static_cast<eGameMessageType>(231)); + EXPECT_EQ(eGameMessageType::UN_EQUIP_INVENTORY, static_cast<eGameMessageType>(233)); + EXPECT_EQ(eGameMessageType::OFFER_MISSION, static_cast<eGameMessageType>(248)); + EXPECT_EQ(eGameMessageType::RESPOND_TO_MISSION, static_cast<eGameMessageType>(249)); + EXPECT_EQ(eGameMessageType::NOTIFY_MISSION, static_cast<eGameMessageType>(254)); + EXPECT_EQ(eGameMessageType::NOTIFY_MISSION_TASK, static_cast<eGameMessageType>(255)); + EXPECT_EQ(eGameMessageType::REBUILD_NOTIFY_STATE, static_cast<eGameMessageType>(336)); + EXPECT_EQ(eGameMessageType::TERMINATE_INTERACTION, static_cast<eGameMessageType>(357)); + EXPECT_EQ(eGameMessageType::SERVER_TERMINATE_INTERACTION, static_cast<eGameMessageType>(358)); + EXPECT_EQ(eGameMessageType::REQUEST_USE, static_cast<eGameMessageType>(364)); + EXPECT_EQ(eGameMessageType::VENDOR_OPEN_WINDOW, static_cast<eGameMessageType>(369)); + EXPECT_EQ(eGameMessageType::BUY_FROM_VENDOR, static_cast<eGameMessageType>(373)); + EXPECT_EQ(eGameMessageType::SELL_TO_VENDOR, static_cast<eGameMessageType>(374)); + EXPECT_EQ(eGameMessageType::TEAM_SET_OFF_WORLD_FLAG, static_cast<eGameMessageType>(383)); + EXPECT_EQ(eGameMessageType::SET_INVENTORY_SIZE, static_cast<eGameMessageType>(389)); + EXPECT_EQ(eGameMessageType::ACKNOWLEDGE_POSSESSION, static_cast<eGameMessageType>(391)); + EXPECT_EQ(eGameMessageType::SET_SHOOTING_GALLERY_PARAMS, static_cast<eGameMessageType>(400)); + EXPECT_EQ(eGameMessageType::REQUEST_ACTIVITY_START_STOP, static_cast<eGameMessageType>(402)); + EXPECT_EQ(eGameMessageType::REQUEST_ACTIVITY_ENTER, static_cast<eGameMessageType>(403)); + EXPECT_EQ(eGameMessageType::REQUEST_ACTIVITY_EXIT, static_cast<eGameMessageType>(404)); + EXPECT_EQ(eGameMessageType::ACTIVITY_ENTER, static_cast<eGameMessageType>(405)); + EXPECT_EQ(eGameMessageType::ACTIVITY_EXIT, static_cast<eGameMessageType>(406)); + EXPECT_EQ(eGameMessageType::ACTIVITY_START, static_cast<eGameMessageType>(407)); + EXPECT_EQ(eGameMessageType::ACTIVITY_STOP, static_cast<eGameMessageType>(408)); + EXPECT_EQ(eGameMessageType::SHOOTING_GALLERY_CLIENT_AIM_UPDATE, static_cast<eGameMessageType>(409)); + EXPECT_EQ(eGameMessageType::SHOOTING_GALLERY_FIRE, static_cast<eGameMessageType>(411)); + EXPECT_EQ(eGameMessageType::REQUEST_VENDOR_STATUS_UPDATE, static_cast<eGameMessageType>(416)); + EXPECT_EQ(eGameMessageType::VENDOR_STATUS_UPDATE, static_cast<eGameMessageType>(417)); + EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_SHOOTING_GALLERY_SCORE, static_cast<eGameMessageType>(425)); + EXPECT_EQ(eGameMessageType::CONSUME_CLIENT_ITEM, static_cast<eGameMessageType>(427)); + EXPECT_EQ(eGameMessageType::CLIENT_ITEM_CONSUMED, static_cast<eGameMessageType>(428)); + EXPECT_EQ(eGameMessageType::UPDATE_SHOOTING_GALLERY_ROTATION, static_cast<eGameMessageType>(448)); + EXPECT_EQ(eGameMessageType::SET_FLAG, static_cast<eGameMessageType>(471)); + EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_FLAG_CHANGE, static_cast<eGameMessageType>(472)); + EXPECT_EQ(eGameMessageType::VENDOR_TRANSACTION_RESULT, static_cast<eGameMessageType>(476)); + EXPECT_EQ(eGameMessageType::HAS_BEEN_COLLECTED, static_cast<eGameMessageType>(486)); + EXPECT_EQ(eGameMessageType::DISPLAY_CHAT_BUBBLE, static_cast<eGameMessageType>(495)); + EXPECT_EQ(eGameMessageType::SPAWN_PET, static_cast<eGameMessageType>(498)); + EXPECT_EQ(eGameMessageType::DESPAWN_PET, static_cast<eGameMessageType>(499)); + EXPECT_EQ(eGameMessageType::PLAYER_LOADED, static_cast<eGameMessageType>(505)); + EXPECT_EQ(eGameMessageType::PLAYER_READY, static_cast<eGameMessageType>(509)); + EXPECT_EQ(eGameMessageType::REQUEST_LINKED_MISSION, static_cast<eGameMessageType>(515)); + EXPECT_EQ(eGameMessageType::INVALID_ZONE_TRANSFER_LIST, static_cast<eGameMessageType>(519)); + EXPECT_EQ(eGameMessageType::MISSION_DIALOGUE_OK, static_cast<eGameMessageType>(520)); + EXPECT_EQ(eGameMessageType::DISPLAY_MESSAGE_BOX, static_cast<eGameMessageType>(529)); + EXPECT_EQ(eGameMessageType::MESSAGE_BOX_RESPOND, static_cast<eGameMessageType>(530)); + EXPECT_EQ(eGameMessageType::CHOICE_BOX_RESPOND, static_cast<eGameMessageType>(531)); + EXPECT_EQ(eGameMessageType::SMASH, static_cast<eGameMessageType>(537)); + EXPECT_EQ(eGameMessageType::UN_SMASH, static_cast<eGameMessageType>(538)); + EXPECT_EQ(eGameMessageType::PLACE_MODEL_RESPONSE, static_cast<eGameMessageType>(547)); + EXPECT_EQ(eGameMessageType::SET_SHOOTING_GALLERY_RETICULE_EFFECT, static_cast<eGameMessageType>(546)); + EXPECT_EQ(eGameMessageType::SET_JET_PACK_MODE, static_cast<eGameMessageType>(561)); + EXPECT_EQ(eGameMessageType::REGISTER_PET_ID, static_cast<eGameMessageType>(565)); + EXPECT_EQ(eGameMessageType::REGISTER_PET_DBID, static_cast<eGameMessageType>(566)); + EXPECT_EQ(eGameMessageType::SHOW_ACTIVITY_COUNTDOWN, static_cast<eGameMessageType>(568)); + EXPECT_EQ(eGameMessageType::START_ACTIVITY_TIME, static_cast<eGameMessageType>(576)); + EXPECT_EQ(eGameMessageType::ACTIVITY_PAUSE, static_cast<eGameMessageType>(602)); + EXPECT_EQ(eGameMessageType::USE_NON_EQUIPMENT_ITEM, static_cast<eGameMessageType>(603)); + EXPECT_EQ(eGameMessageType::USE_ITEM_RESULT, static_cast<eGameMessageType>(607)); + EXPECT_EQ(eGameMessageType::COMMAND_PET, static_cast<eGameMessageType>(640)); + EXPECT_EQ(eGameMessageType::PET_RESPONSE, static_cast<eGameMessageType>(641)); + EXPECT_EQ(eGameMessageType::REQUEST_ACTIVITY_SUMMARY_LEADERBOARD_DATA, static_cast<eGameMessageType>(648)); + EXPECT_EQ(eGameMessageType::SEND_ACTIVITY_SUMMARY_LEADERBOARD_DATA, static_cast<eGameMessageType>(649)); + EXPECT_EQ(eGameMessageType::NOTIFY_OBJECT, static_cast<eGameMessageType>(656)); + EXPECT_EQ(eGameMessageType::CLIENT_NOTIFY_PET, static_cast<eGameMessageType>(659)); + EXPECT_EQ(eGameMessageType::NOTIFY_PET, static_cast<eGameMessageType>(660)); + EXPECT_EQ(eGameMessageType::NOTIFY_PET_TAMING_MINIGAME, static_cast<eGameMessageType>(661)); + EXPECT_EQ(eGameMessageType::START_SERVER_PET_MINIGAME_TIMER, static_cast<eGameMessageType>(662)); + EXPECT_EQ(eGameMessageType::CLIENT_EXIT_TAMING_MINIGAME, static_cast<eGameMessageType>(663)); + EXPECT_EQ(eGameMessageType::PET_NAME_CHANGED, static_cast<eGameMessageType>(686)); + EXPECT_EQ(eGameMessageType::PET_TAMING_MINIGAME_RESULT, static_cast<eGameMessageType>(667)); + EXPECT_EQ(eGameMessageType::PET_TAMING_TRY_BUILD_RESULT, static_cast<eGameMessageType>(668)); + EXPECT_EQ(eGameMessageType::NOTIFY_TAMING_BUILD_SUCCESS, static_cast<eGameMessageType>(673)); + EXPECT_EQ(eGameMessageType::NOTIFY_TAMING_MODEL_LOADED_ON_SERVER, static_cast<eGameMessageType>(674)); + EXPECT_EQ(eGameMessageType::ACTIVATE_BUBBLE_BUFF, static_cast<eGameMessageType>(678)); + EXPECT_EQ(eGameMessageType::DECTIVATE_BUBBLE_BUFF, static_cast<eGameMessageType>(679)); + EXPECT_EQ(eGameMessageType::ADD_PET_TO_PLAYER, static_cast<eGameMessageType>(681)); + EXPECT_EQ(eGameMessageType::REQUEST_SET_PET_NAME, static_cast<eGameMessageType>(683)); + EXPECT_EQ(eGameMessageType::SET_PET_NAME, static_cast<eGameMessageType>(684)); + EXPECT_EQ(eGameMessageType::NOTIFY_TAMING_PUZZLE_SELECTED, static_cast<eGameMessageType>(675)); + EXPECT_EQ(eGameMessageType::SHOW_PET_ACTION_BUTTON, static_cast<eGameMessageType>(692)); + EXPECT_EQ(eGameMessageType::SET_EMOTE_LOCK_STATE, static_cast<eGameMessageType>(693)); + EXPECT_EQ(eGameMessageType::USE_ITEM_REQUIREMENTS_RESPONSE, static_cast<eGameMessageType>(703)); + EXPECT_EQ(eGameMessageType::PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT, static_cast<eGameMessageType>(713)); + EXPECT_EQ(eGameMessageType::DOWNLOAD_PROPERTY_DATA, static_cast<eGameMessageType>(716)); + EXPECT_EQ(eGameMessageType::QUERY_PROPERTY_DATA, static_cast<eGameMessageType>(717)); + EXPECT_EQ(eGameMessageType::PROPERTY_EDITOR_BEGIN, static_cast<eGameMessageType>(724)); + EXPECT_EQ(eGameMessageType::PROPERTY_EDITOR_END, static_cast<eGameMessageType>(725)); + EXPECT_EQ(eGameMessageType::IS_MINIFIG_IN_A_BUBBLE, static_cast<eGameMessageType>(729)); + EXPECT_EQ(eGameMessageType::START_PATHING, static_cast<eGameMessageType>(733)); + EXPECT_EQ(eGameMessageType::ACTIVATE_BUBBLE_BUFF_FROM_SERVER, static_cast<eGameMessageType>(734)); + EXPECT_EQ(eGameMessageType::DEACTIVATE_BUBBLE_BUFF_FROM_SERVER, static_cast<eGameMessageType>(735)); + EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_ZONE_OBJECT, static_cast<eGameMessageType>(737)); + EXPECT_EQ(eGameMessageType::UPDATE_REPUTATION, static_cast<eGameMessageType>(746)); + EXPECT_EQ(eGameMessageType::PROPERTY_RENTAL_RESPONSE, static_cast<eGameMessageType>(750)); + EXPECT_EQ(eGameMessageType::REQUEST_PLATFORM_RESYNC, static_cast<eGameMessageType>(760)); + EXPECT_EQ(eGameMessageType::PLATFORM_RESYNC, static_cast<eGameMessageType>(761)); + EXPECT_EQ(eGameMessageType::PLAY_CINEMATIC, static_cast<eGameMessageType>(762)); + EXPECT_EQ(eGameMessageType::END_CINEMATIC, static_cast<eGameMessageType>(763)); + EXPECT_EQ(eGameMessageType::CINEMATIC_UPDATE, static_cast<eGameMessageType>(764)); + EXPECT_EQ(eGameMessageType::TOGGLE_GHOST_REFERENCE_OVERRIDE, static_cast<eGameMessageType>(767)); + EXPECT_EQ(eGameMessageType::SET_GHOST_REFERENCE_POSITION, static_cast<eGameMessageType>(768)); + EXPECT_EQ(eGameMessageType::FIRE_EVENT_SERVER_SIDE, static_cast<eGameMessageType>(770)); + EXPECT_EQ(eGameMessageType::SCRIPT_NETWORK_VAR_UPDATE, static_cast<eGameMessageType>(781)); + EXPECT_EQ(eGameMessageType::UPDATE_MODEL_FROM_CLIENT, static_cast<eGameMessageType>(793)); + EXPECT_EQ(eGameMessageType::DELETE_MODEL_FROM_CLIENT, static_cast<eGameMessageType>(794)); + EXPECT_EQ(eGameMessageType::PLAY_ND_AUDIO_EMITTER, static_cast<eGameMessageType>(821)); + EXPECT_EQ(eGameMessageType::PLAY2_D_AMBIENT_SOUND, static_cast<eGameMessageType>(831)); + EXPECT_EQ(eGameMessageType::ENTER_PROPERTY1, static_cast<eGameMessageType>(840)); + EXPECT_EQ(eGameMessageType::ENTER_PROPERTY2, static_cast<eGameMessageType>(841)); + EXPECT_EQ(eGameMessageType::PROPERTY_ENTRANCE_SYNC, static_cast<eGameMessageType>(842)); + EXPECT_EQ(eGameMessageType::PROPERTY_SELECT_QUERY, static_cast<eGameMessageType>(845)); + EXPECT_EQ(eGameMessageType::PARSE_CHAT_MESSAGE, static_cast<eGameMessageType>(850)); + EXPECT_EQ(eGameMessageType::BROADCAST_TEXT_TO_CHATBOX, static_cast<eGameMessageType>(858)); + EXPECT_EQ(eGameMessageType::OPEN_PROPERTY_MANAGEMENT, static_cast<eGameMessageType>(860)); + EXPECT_EQ(eGameMessageType::OPEN_PROPERTY_VENDOR, static_cast<eGameMessageType>(861)); + EXPECT_EQ(eGameMessageType::UPDATE_PROPERTY_OR_MODEL_FOR_FILTER_CHECK, static_cast<eGameMessageType>(863)); + EXPECT_EQ(eGameMessageType::CLIENT_TRADE_REQUEST, static_cast<eGameMessageType>(868)); + EXPECT_EQ(eGameMessageType::SERVER_TRADE_REQUEST, static_cast<eGameMessageType>(869)); + EXPECT_EQ(eGameMessageType::SERVER_TRADE_INVITE, static_cast<eGameMessageType>(870)); + EXPECT_EQ(eGameMessageType::CLIENT_TRADE_REPLY, static_cast<eGameMessageType>(871)); + EXPECT_EQ(eGameMessageType::SERVER_TRADE_REPLY, static_cast<eGameMessageType>(872)); + EXPECT_EQ(eGameMessageType::SERVER_TRADE_INITIAL_REPLY, static_cast<eGameMessageType>(873)); + EXPECT_EQ(eGameMessageType::SERVER_TRADE_FINAL_REPLY, static_cast<eGameMessageType>(874)); + EXPECT_EQ(eGameMessageType::CLIENT_TRADE_UPDATE, static_cast<eGameMessageType>(875)); + EXPECT_EQ(eGameMessageType::SERVER_SIDE_TRADE_UPDATE, static_cast<eGameMessageType>(876)); + EXPECT_EQ(eGameMessageType::SERVER_TRADE_UPDATE, static_cast<eGameMessageType>(877)); + EXPECT_EQ(eGameMessageType::CLIENT_TRADE_CANCEL, static_cast<eGameMessageType>(878)); + EXPECT_EQ(eGameMessageType::CLIENT_SIDE_TRADE_CANCEL, static_cast<eGameMessageType>(879)); + EXPECT_EQ(eGameMessageType::CLIENT_TRADE_ACCEPT, static_cast<eGameMessageType>(880)); + EXPECT_EQ(eGameMessageType::SERVER_SIDE_TRADE_ACCEPT, static_cast<eGameMessageType>(881)); + EXPECT_EQ(eGameMessageType::SERVER_SIDE_TRADE_CANCEL, static_cast<eGameMessageType>(882)); + EXPECT_EQ(eGameMessageType::SERVER_TRADE_CANCEL, static_cast<eGameMessageType>(883)); + EXPECT_EQ(eGameMessageType::SERVER_TRADE_ACCEPT, static_cast<eGameMessageType>(884)); + EXPECT_EQ(eGameMessageType::READY_FOR_UPDATES, static_cast<eGameMessageType>(888)); + EXPECT_EQ(eGameMessageType::ORIENT_TO_OBJECT, static_cast<eGameMessageType>(905)); + EXPECT_EQ(eGameMessageType::ORIENT_TO_POSITION, static_cast<eGameMessageType>(906)); + EXPECT_EQ(eGameMessageType::ORIENT_TO_ANGLE, static_cast<eGameMessageType>(907)); + EXPECT_EQ(eGameMessageType::BOUNCER_ACTIVE_STATUS, static_cast<eGameMessageType>(942)); + EXPECT_EQ(eGameMessageType::UN_USE_BBB_MODEL, static_cast<eGameMessageType>(999)); + EXPECT_EQ(eGameMessageType::BBB_LOAD_ITEM_REQUEST, static_cast<eGameMessageType>(1000)); + EXPECT_EQ(eGameMessageType::BBB_SAVE_REQUEST, static_cast<eGameMessageType>(1001)); + EXPECT_EQ(eGameMessageType::BBB_SAVE_RESPONSE, static_cast<eGameMessageType>(1005)); + EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_OBJECT, static_cast<eGameMessageType>(1042)); + EXPECT_EQ(eGameMessageType::DISPLAY_ZONE_SUMMARY, static_cast<eGameMessageType>(1043)); + EXPECT_EQ(eGameMessageType::ZONE_SUMMARY_DISMISSED, static_cast<eGameMessageType>(1044)); + EXPECT_EQ(eGameMessageType::ACTIVITY_STATE_CHANGE_REQUEST, static_cast<eGameMessageType>(1053)); + EXPECT_EQ(eGameMessageType::MODIFY_PLAYER_ZONE_STATISTIC, static_cast<eGameMessageType>(1046)); + EXPECT_EQ(eGameMessageType::START_BUILDING_WITH_ITEM, static_cast<eGameMessageType>(1057)); + EXPECT_EQ(eGameMessageType::START_ARRANGING_WITH_ITEM, static_cast<eGameMessageType>(1061)); + EXPECT_EQ(eGameMessageType::FINISH_ARRANGING_WITH_ITEM, static_cast<eGameMessageType>(1062)); + EXPECT_EQ(eGameMessageType::DONE_ARRANGING_WITH_ITEM, static_cast<eGameMessageType>(1063)); + EXPECT_EQ(eGameMessageType::SET_BUILD_MODE, static_cast<eGameMessageType>(1068)); + EXPECT_EQ(eGameMessageType::BUILD_MODE_SET, static_cast<eGameMessageType>(1069)); + EXPECT_EQ(eGameMessageType::SET_BUILD_MODE_CONFIRMED, static_cast<eGameMessageType>(1073)); + EXPECT_EQ(eGameMessageType::NOTIFY_CLIENT_FAILED_PRECONDITION, static_cast<eGameMessageType>(1081)); + EXPECT_EQ(eGameMessageType::MOVE_ITEM_BETWEEN_INVENTORY_TYPES, static_cast<eGameMessageType>(1093)); + EXPECT_EQ(eGameMessageType::MODULAR_BUILD_BEGIN, static_cast<eGameMessageType>(1094)); + EXPECT_EQ(eGameMessageType::MODULAR_BUILD_END, static_cast<eGameMessageType>(1095)); + EXPECT_EQ(eGameMessageType::MODULAR_BUILD_MOVE_AND_EQUIP, static_cast<eGameMessageType>(1096)); + EXPECT_EQ(eGameMessageType::MODULAR_BUILD_FINISH, static_cast<eGameMessageType>(1097)); + EXPECT_EQ(eGameMessageType::REPORT_BUG, static_cast<eGameMessageType>(1198)); + EXPECT_EQ(eGameMessageType::MISSION_DIALOGUE_CANCELLED, static_cast<eGameMessageType>(1129)); + EXPECT_EQ(eGameMessageType::ECHO_SYNC_SKILL, static_cast<eGameMessageType>(1144)); + EXPECT_EQ(eGameMessageType::SYNC_SKILL, static_cast<eGameMessageType>(1145)); + EXPECT_EQ(eGameMessageType::REQUEST_SERVER_PROJECTILE_IMPACT, static_cast<eGameMessageType>(1148)); + EXPECT_EQ(eGameMessageType::DO_CLIENT_PROJECTILE_IMPACT, static_cast<eGameMessageType>(1151)); + EXPECT_EQ(eGameMessageType::MODULAR_BUILD_CONVERT_MODEL, static_cast<eGameMessageType>(1155)); + EXPECT_EQ(eGameMessageType::SET_PLAYER_ALLOWED_RESPAWN, static_cast<eGameMessageType>(1165)); + EXPECT_EQ(eGameMessageType::UI_MESSAGE_SERVER_TO_SINGLE_CLIENT, static_cast<eGameMessageType>(1184)); + EXPECT_EQ(eGameMessageType::UI_MESSAGE_SERVER_TO_ALL_CLIENTS, static_cast<eGameMessageType>(1185)); + EXPECT_EQ(eGameMessageType::PET_TAMING_TRY_BUILD, static_cast<eGameMessageType>(1197)); + EXPECT_EQ(eGameMessageType::REQUEST_SMASH_PLAYER, static_cast<eGameMessageType>(1202)); + EXPECT_EQ(eGameMessageType::FIRE_EVENT_CLIENT_SIDE, static_cast<eGameMessageType>(1213)); + EXPECT_EQ(eGameMessageType::TOGGLE_GM_INVIS, static_cast<eGameMessageType>(1218)); + EXPECT_EQ(eGameMessageType::CHANGE_OBJECT_WORLD_STATE, static_cast<eGameMessageType>(1223)); + EXPECT_EQ(eGameMessageType::VEHICLE_LOCK_INPUT, static_cast<eGameMessageType>(1230)); + EXPECT_EQ(eGameMessageType::VEHICLE_UNLOCK_INPUT, static_cast<eGameMessageType>(1231)); + EXPECT_EQ(eGameMessageType::RACING_RESET_PLAYER_TO_LAST_RESET, static_cast<eGameMessageType>(1252)); + EXPECT_EQ(eGameMessageType::RACING_SERVER_SET_PLAYER_LAP_AND_PLANE, static_cast<eGameMessageType>(1253)); + EXPECT_EQ(eGameMessageType::RACING_SET_PLAYER_RESET_INFO, static_cast<eGameMessageType>(1254)); + EXPECT_EQ(eGameMessageType::RACING_PLAYER_INFO_RESET_FINISHED, static_cast<eGameMessageType>(1255)); + EXPECT_EQ(eGameMessageType::LOCK_NODE_ROTATION, static_cast<eGameMessageType>(1260)); + EXPECT_EQ(eGameMessageType::VEHICLE_SET_WHEEL_LOCK_STATE, static_cast<eGameMessageType>(1273)); + EXPECT_EQ(eGameMessageType::NOTIFY_VEHICLE_OF_RACING_OBJECT, static_cast<eGameMessageType>(1276)); + EXPECT_EQ(eGameMessageType::SET_NAME_BILLBOARD_STATE, static_cast<eGameMessageType>(1284)); + EXPECT_EQ(eGameMessageType::PLAYER_REACHED_RESPAWN_CHECKPOINT, static_cast<eGameMessageType>(1296)); + EXPECT_EQ(eGameMessageType::HANDLE_UGC_POST_DELETE_BASED_ON_EDIT_MODE, static_cast<eGameMessageType>(1300)); + EXPECT_EQ(eGameMessageType::HANDLE_UGC_POST_CREATE_BASED_ON_EDIT_MODE, static_cast<eGameMessageType>(1301)); + EXPECT_EQ(eGameMessageType::PROPERTY_CONTENTS_FROM_CLIENT, static_cast<eGameMessageType>(1305)); + EXPECT_EQ(eGameMessageType::GET_MODELS_ON_PROPERTY, static_cast<eGameMessageType>(1306)); + EXPECT_EQ(eGameMessageType::MATCH_REQUEST, static_cast<eGameMessageType>(1308)); + EXPECT_EQ(eGameMessageType::MATCH_RESPONSE, static_cast<eGameMessageType>(1309)); + EXPECT_EQ(eGameMessageType::MATCH_UPDATE, static_cast<eGameMessageType>(1310)); + EXPECT_EQ(eGameMessageType::MODULE_ASSEMBLY_DB_DATA_FOR_CLIENT, static_cast<eGameMessageType>(1131)); + EXPECT_EQ(eGameMessageType::MODULE_ASSEMBLY_QUERY_DATA, static_cast<eGameMessageType>(1132)); + EXPECT_EQ(eGameMessageType::SHOW_BILLBOARD_INTERACT_ICON, static_cast<eGameMessageType>(1337)); + EXPECT_EQ(eGameMessageType::CHANGE_IDLE_FLAGS, static_cast<eGameMessageType>(1338)); + EXPECT_EQ(eGameMessageType::VEHICLE_ADD_PASSIVE_BOOST_ACTION, static_cast<eGameMessageType>(1340)); + EXPECT_EQ(eGameMessageType::VEHICLE_REMOVE_PASSIVE_BOOST_ACTION, static_cast<eGameMessageType>(1341)); + EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_VEHICLE_ADD_PASSIVE_BOOST_ACTION, static_cast<eGameMessageType>(1342)); + EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_VEHICLE_REMOVE_PASSIVE_BOOST_ACTION, static_cast<eGameMessageType>(1343)); + EXPECT_EQ(eGameMessageType::VEHICLE_ADD_SLOWDOWN_ACTION, static_cast<eGameMessageType>(1344)); + EXPECT_EQ(eGameMessageType::VEHICLE_REMOVE_SLOWDOWN_ACTION, static_cast<eGameMessageType>(1345)); + EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_VEHICLE_ADD_SLOWDOWN_ACTION, static_cast<eGameMessageType>(1346)); + EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_VEHICLE_REMOVE_SLOWDOWN_ACTION, static_cast<eGameMessageType>(1347)); + EXPECT_EQ(eGameMessageType::BUYBACK_FROM_VENDOR, static_cast<eGameMessageType>(1350)); + EXPECT_EQ(eGameMessageType::SET_PROPERTY_ACCESS, static_cast<eGameMessageType>(1366)); + EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_PLACED, static_cast<eGameMessageType>(1369)); + EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_ROTATED, static_cast<eGameMessageType>(1370)); + EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_REMOVED_WHILE_EQUIPPED, static_cast<eGameMessageType>(1371)); + EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_EQUIPPED, static_cast<eGameMessageType>(1372)); + EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_PICKED_UP, static_cast<eGameMessageType>(1373)); + EXPECT_EQ(eGameMessageType::ZONE_PROPERTY_MODEL_REMOVED, static_cast<eGameMessageType>(1374)); + EXPECT_EQ(eGameMessageType::NOTIFY_RACING_CLIENT, static_cast<eGameMessageType>(1390)); + EXPECT_EQ(eGameMessageType::RACING_PLAYER_HACK_CAR, static_cast<eGameMessageType>(1391)); + EXPECT_EQ(eGameMessageType::RACING_PLAYER_LOADED, static_cast<eGameMessageType>(1392)); + EXPECT_EQ(eGameMessageType::RACING_CLIENT_READY, static_cast<eGameMessageType>(1393)); + EXPECT_EQ(eGameMessageType::UPDATE_CHAT_MODE, static_cast<eGameMessageType>(1395)); + EXPECT_EQ(eGameMessageType::VEHICLE_NOTIFY_FINISHED_RACE, static_cast<eGameMessageType>(1396)); + EXPECT_EQ(eGameMessageType::SET_CONSUMABLE_ITEM, static_cast<eGameMessageType>(1409)); + EXPECT_EQ(eGameMessageType::SET_STATUS_IMMUNITY, static_cast<eGameMessageType>(1435)); + EXPECT_EQ(eGameMessageType::SET_PET_NAME_MODERATED, static_cast<eGameMessageType>(1448)); + EXPECT_EQ(eGameMessageType::MODIFY_LEGO_SCORE, static_cast<eGameMessageType>(1459)); + EXPECT_EQ(eGameMessageType::RESTORE_TO_POST_LOAD_STATS, static_cast<eGameMessageType>(1468)); + EXPECT_EQ(eGameMessageType::SET_RAIL_MOVEMENT, static_cast<eGameMessageType>(1471)); + EXPECT_EQ(eGameMessageType::START_RAIL_MOVEMENT, static_cast<eGameMessageType>(1472)); + EXPECT_EQ(eGameMessageType::CANCEL_RAIL_MOVEMENT, static_cast<eGameMessageType>(1474)); + EXPECT_EQ(eGameMessageType::CLIENT_RAIL_MOVEMENT_READY, static_cast<eGameMessageType>(1476)); + EXPECT_EQ(eGameMessageType::PLAYER_RAIL_ARRIVED_NOTIFICATION, static_cast<eGameMessageType>(1477)); + EXPECT_EQ(eGameMessageType::UPDATE_PLAYER_STATISTIC, static_cast<eGameMessageType>(1481)); + EXPECT_EQ(eGameMessageType::MODULAR_ASSEMBLY_NIF_COMPLETED, static_cast<eGameMessageType>(1498)); + EXPECT_EQ(eGameMessageType::NOTIFY_NOT_ENOUGH_INV_SPACE, static_cast<eGameMessageType>(1516)); + EXPECT_EQ(eGameMessageType::TEAM_SET_LEADER, static_cast<eGameMessageType>(1557)); + EXPECT_EQ(eGameMessageType::TEAM_INVITE_CONFIRM, static_cast<eGameMessageType>(1558)); + EXPECT_EQ(eGameMessageType::TEAM_GET_STATUS_RESPONSE, static_cast<eGameMessageType>(1559)); + EXPECT_EQ(eGameMessageType::TEAM_ADD_PLAYER, static_cast<eGameMessageType>(1562)); + EXPECT_EQ(eGameMessageType::TEAM_REMOVE_PLAYER, static_cast<eGameMessageType>(1563)); + EXPECT_EQ(eGameMessageType::START_CELEBRATION_EFFECT, static_cast<eGameMessageType>(1618)); + EXPECT_EQ(eGameMessageType::ADD_BUFF, static_cast<eGameMessageType>(1647)); + EXPECT_EQ(eGameMessageType::SERVER_DONE_LOADING_ALL_OBJECTS, static_cast<eGameMessageType>(1642)); + EXPECT_EQ(eGameMessageType::PLACE_PROPERTY_MODEL, static_cast<eGameMessageType>(1170)); + EXPECT_EQ(eGameMessageType::VEHICLE_NOTIFY_HIT_IMAGINATION_SERVER, static_cast<eGameMessageType>(1606)); + EXPECT_EQ(eGameMessageType::ADD_RUN_SPEED_MODIFIER, static_cast<eGameMessageType>(1505)); + EXPECT_EQ(eGameMessageType::GET_HOT_PROPERTY_DATA, static_cast<eGameMessageType>(1511)); + EXPECT_EQ(eGameMessageType::SEND_HOT_PROPERTY_DATA, static_cast<eGameMessageType>(1510)); + EXPECT_EQ(eGameMessageType::REMOVE_RUN_SPEED_MODIFIER, static_cast<eGameMessageType>(1506)); + EXPECT_EQ(eGameMessageType::UPDATE_PROPERTY_PERFORMANCE_COST, static_cast<eGameMessageType>(1547)); + EXPECT_EQ(eGameMessageType::PROPERTY_ENTRANCE_BEGIN, static_cast<eGameMessageType>(1553)); + EXPECT_EQ(eGameMessageType::SET_RESURRECT_RESTORE_VALUES, static_cast<eGameMessageType>(1591)); + EXPECT_EQ(eGameMessageType::VEHICLE_STOP_BOOST, static_cast<eGameMessageType>(1617)); + EXPECT_EQ(eGameMessageType::REMOVE_BUFF, static_cast<eGameMessageType>(1648)); + EXPECT_EQ(eGameMessageType::REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES, static_cast<eGameMessageType>(1666)); + EXPECT_EQ(eGameMessageType::RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES, static_cast<eGameMessageType>(1667)); + EXPECT_EQ(eGameMessageType::PLAYER_SET_CAMERA_CYCLING_MODE, static_cast<eGameMessageType>(1676)); + EXPECT_EQ(eGameMessageType::SET_MOUNT_INVENTORY_ID, static_cast<eGameMessageType>(1727)); + EXPECT_EQ(eGameMessageType::NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE, static_cast<eGameMessageType>(1734)); + EXPECT_EQ(eGameMessageType::NOTIFY_LEVEL_REWARDS, static_cast<eGameMessageType>(1735)); + EXPECT_EQ(eGameMessageType::DISMOUNT_COMPLETE, static_cast<eGameMessageType>(1756)); + EXPECT_EQ(eGameMessageType::MARK_INVENTORY_ITEM_AS_ACTIVE, static_cast<eGameMessageType>(1767)); } diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index 40c81544a..f6056476e 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/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/NPC.xml b/vanity/NPC.xml deleted file mode 100644 index 2311ab462..000000000 --- a/vanity/NPC.xml +++ /dev/null @@ -1,453 +0,0 @@ -<npcs> - <npc 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> - <zone id="1200"> - <locations> - <location x="-352.5" y="287.6" z="217.7" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" /> - </locations> - </zone> - </npc> - <npc name="EmosewaMC - Quickbuilder" lot="6738"> - <equipment>12947, 12949, 12962, 12963</equipment> - <phrases> - <phrase>I hope quickbulds are still working!</phrase> - <phrase>Be careful crossing the gap!</phrase> - <phrase>Have The Maelstrom stopped going invisible?</phrase> - </phrases> - <zone id="1800"> - <locations> - <location x="745.756" y="75.262" z="-207.989" rw="0.838565" rx="0.0" ry="0.544801" rz="0.0" /> - </locations> - </zone> - </npc> - <npc name="Neal - Paradox Scout" lot="6738"> - <equipment>9950, 9944, 14102, 14092</equipment> - <phrases> - <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> - <zone id="1200"> - <locations> - <location x="163.835" y="330.756" z="-141.933" rw="0.774887" rx="0.0" ry="-0.6321" rz="0.0" /> - </locations> - </zone> - </npc> - <npc 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\DLUVanityNPC.lua" /> - <flags> - <flag name="teleport" value="1" /> - </flags> - <zone id="1200"> - <locations> - <location x="-361.583" y="285.541" z="64.4695" rw="0.785518" rx="0.0" ry="0.618838" rz="0.0" /> - <location x="178.188" y="354.528" z="-173.932" rw="0.734375" rx="0.0" ry="-0.678744" rz="0.0" /> - <location x="-318.569" y="287.637695" z="226.728" rw="-0.289502" rx="0.0" ry="0.957178" rz="0.0" /> - <location x="389.093" y="295.119" z="-647.583" rw="0.851229" rx="0.0" ry="-0.524795" rz="0.0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1100"> - <locations> - <location x="287" y="451" z="-98" rw="-0.320221" rx="0" ry="0.947343" rz="0" /> - </locations> - </zone> - <zone id="1800"> - <locations> - <location x="798" y="93" z="325" rw="-0.095" rx="0.0" ry="0.995" rz="0.0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1100"> - <locations> - <location x="444.318" y="421.154" z="54.4241" rw="0.877539" rx="0.0" ry="0.479506" rz="0.0" /> - </locations> - </zone> - </npc> - <!-- Mick - Brick Market Broker --> - <npc 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> - <zone id="1100"> - <locations> - <location x="449.725" y="414.926" z="180.539" rw="0.180645" rx="0.0" ry="0.983548" rz="0.0" /> - </locations> - </zone> - </npc> - <!-- Knightoffaith - Sage of Wanderlust --> - <npc 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> - <zone id="1100"> - <locations> - <location x="-381.053" y="367.787" z="-60.1185" rw="-0.14307" rx="0" ry="0.989713" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1200"> - <locations> - <location x="-429.296" y="291.058" z="212.918" rw="0.339487" rx="0" ry="0.940611" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1200"> - <locations> - <location x="-317.509" y="287.652" z="191.86" rw="0.57124" rx="0" ry="-0.820783" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1300"> - <locations> - <location x="283.986" y="261.208" z="-128.466" rw="0.70207" rx="0" ry="0.712108" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1300"> - <locations> - <location x="204.93" y="294.784" z="471.537" rw="0.85015" rx="0" ry="-0.52654" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1300"> - <locations> - <location x="-47.6296" y="322.527" z="533.5" rw="0.145135" rx="0" ry="0.989412" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1400"> - <locations> - <location x="-490.608" y="51.9449" z="-347.747" rw="0.594978" rx="0" ry="-0.803742" rz="0" /> - </locations> - </zone> - </npc> - <npc name="Wicked" lot="7412"> - <equipment>8287, 2957, 7523, 16613</equipment> - <phrases></phrases> - <zone id="1400"> - <locations> - <location x="264.506" y="339.931" z="54.1201" rw="0.715223" rx="0" ry="0.698896" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1900"> - <locations> - <location x="-493.724" y="1124.05" z="-76.6355" rw="0.1719" rx="0" ry="0.985114" rz="0" /> - </locations> - </zone> - </npc> - 12651 - <npc 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> - <zone id="1900"> - <locations> - <location x="-227.621" y="1188.28" z="145.734" rw="-0.254353" rx="0" ry="0.967111" rz="0" /> - </locations> - </zone> - </npc> - <npc name="Raine" lot="9893"> - <equipment>13342, 7370, 7382</equipment> - <phrases> - <phrase>Per Aspera ad Astra</phrase> - </phrases> - <zone id="1900"> - <locations> - <location x="-190.673" y="1218.34" z="221.6" rw="0.972371" rx="0" ry="-0.233441" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1800"> - <locations> - <location x="-39.2259" y="96.8605" z="-550.077" rw="0.815145" rx="0" ry="-0.579257" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="2000"> - <locations> - <location x="-119.269" y="230.372" z="226.63" rw="0.381416" rx="0" ry="0.924404" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1200"> - <locations> - <location x="197.549" y="259.137" z="-587.759" rw="0.873694" rx="0" ry="0.486475" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1100"> - <locations> - <location x="436.949" y="415.264" z="151.381" rw="0.528425" rx="0" ry="0.84898" rz="0" /> - </locations> - </zone> - </npc> - <npc name="Ben" lot="2279"> - <equipment>8664, 4065, 2587</equipment> - <phrases></phrases> - <zone id="1200"> - <locations> - <location x="284.538" y="260.627" z="-506.692" rw="0.819721" rx="0" ry="0.572763" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <zone id="1300"> - <locations> - <location x="-171.217" y="246.482" z="-147.05" rw="-0.203118" rx="0" ry="0.979154" rz="0" /> - </locations> - </zone> - </npc> - <npc 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> - <phrase>It's not perfect, but it works!</phrase> - </phrases> - <zone id="1201"> - <locations> - <location x="197.709" y="179.335" z="-8.05284" rw="0.544424" rx="0" ry="-0.83881" rz="0" /> - </locations> - </zone> - </npc> - <party zone="1200" chance="0.0"> - <locations> - <location x="-24.3963" y="291.542" z="-117.871" rw="0.480946" rx="0" ry="0.87675" rz="0" /> - <location x="-16.9897" y="291.584" z="-112.438" rw="0.0677884" rx="0" ry="0.9977" rz="0" /> - <location x="-3.52143" y="291.66" z="-118.186" rw="0.519658" rx="0" ry="-0.854375" rz="0" /> - <location x="-4.54551" y="291.661" z="-131.914" rw="0.916747" rx="0" ry="-0.399469" rz="0" /> - <location x="-18.8573" y="291.566" z="-136.347" rw="0.983708" rx="0" ry="0.179772" rz="0" /> - <location x="-17.0958" y="291.824" z="-127.153" rw="0.999554" rx="0" ry="0.0298604" rz="0" /> - <location x="-10.9727" y="291.868" z="-125.387" rw="0.861138" rx="0" ry="0.508372" rz="0" /> - <location x="-21.9406" y="291.284" z="-139.761" rw="0.990094" rx="0" ry="0.140407" rz="0" /> - <location x="4.54396" y="291.19" z="-131.908" rw="0.929764" rx="0" ry="-0.368157" rz="0" /> - <location x="-0.189393" y="291.105" z="-109.617" rw="-0.124242" rx="0" ry="0.992252" rz="0" /> - </locations> - </party> - <partyphrases> - <phrase>Hi there!</phrase> - <phrase>Hi!</phrase> - <phrase>Hahaha!</phrase> - <phrase>Hello there!</phrase> - - <phrase>:D</phrase> - <phrase>:P</phrase> - </partyphrases> -</npcs> diff --git a/vanity/atm.xml b/vanity/atm.xml new file mode 100644 index 000000000..c03a59ce6 --- /dev/null +++ b/vanity/atm.xml @@ -0,0 +1,42 @@ +<objects> + <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 new file mode 100644 index 000000000..a3d4e7ebf --- /dev/null +++ b/vanity/dev-tribute.xml @@ -0,0 +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> + <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> + <phrase>It's not perfect, but it works!</phrase> + </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 new file mode 100644 index 000000000..dcb89217a --- /dev/null +++ b/vanity/root.xml @@ -0,0 +1,5 @@ +<files> + <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