diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 667434d2..5a36df4b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -12,18 +12,21 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ windows-2022, ubuntu-20.04 ] + os: [ windows-2022, ubuntu-20.04, macos-11 ] steps: - uses: actions/checkout@v2 with: submodules: true - - name: Add msbuild to PATH (windows only) + - name: Add msbuild to PATH (Windows only) if: ${{ matrix.os == 'windows-2022' }} uses: microsoft/setup-msbuild@v1.1 with: vs-version: '[17,18)' msbuild-architecture: x64 + - name: Install libssl (Mac Only) + if: ${{ matrix.os == 'macos-11' }} + run: brew install openssl@3 - name: cmake uses: lukka/run-cmake@v10 with: @@ -32,6 +35,7 @@ jobs: testPreset: "ci-${{matrix.os}}" - name: artifacts uses: actions/upload-artifact@v2 + if: ${{ github.ref == 'ref/head/main' }} with: name: build-${{matrix.os}} path: | diff --git a/.gitmodules b/.gitmodules index 086ee95c..6fb56bde 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,6 +10,10 @@ [submodule "thirdparty/libbcrypt"] path = thirdparty/libbcrypt url = https://github.com/trusch/libbcrypt.git +[submodule "thirdparty/mariadb-connector-cpp"] + path = thirdparty/mariadb-connector-cpp + url = https://github.com/mariadb-corporation/mariadb-connector-cpp.git + ignore = dirty [submodule "thirdparty/docker-utils"] path = thirdparty/docker-utils url = https://github.com/lcdr/utils.git diff --git a/CMakeLists.txt b/CMakeLists.txt index a6902a41..e4c91c57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.14) project(Darkflame) include(CTest) +set (CMAKE_CXX_STANDARD 17) + # Read variables from file FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables) @@ -10,113 +12,67 @@ string(REPLACE "\n" ";" variables ${variables}) # Set the cmake variables, formatted as "VARIABLE #" in variables foreach(variable ${variables}) - # If the string contains a #, skip it - if("${variable}" MATCHES "#") - continue() - endif() + # If the string contains a #, skip it + if(NOT "${variable}" MATCHES "#") + + # Split the variable into name and value + string(REPLACE "=" ";" variable ${variable}) - # Split the variable into name and value - string(REPLACE "=" ";" variable ${variable}) + # Check that the length of the variable is 2 (name and value) + list(LENGTH variable length) + if(${length} EQUAL 2) - # Check that the length of the variable is 2 (name and value) - list(LENGTH variable length) - if(NOT ${length} EQUAL 2) - continue() - endif() + list(GET variable 0 variable_name) + list(GET variable 1 variable_value) - list(GET variable 0 variable_name) - list(GET variable 1 variable_value) + # Set the variable + set(${variable_name} ${variable_value}) - # Set the variable - set(${variable_name} ${variable_value}) + # Add compiler definition + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}") - # Add compiler definition - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}") - - message(STATUS "Variable: ${variable_name} = ${variable_value}") + message(STATUS "Variable: ${variable_name} = ${variable_value}") + endif() + endif() endforeach() -# On windows it's better to build this from source, as there's no way FindZLIB is gonna find it -if(NOT WIN32) -find_package(ZLIB REQUIRED) -endif() - -# Fetch External (Non-Submodule) Libraries -if(WIN32) -include(FetchContent) - -FetchContent_Declare( - mysql - URL https://dev.mysql.com/get/Downloads/Connector-C++/mysql-connector-c++-8.0.27-winx64.zip - URL_HASH MD5=e3c53f6e4d0a72fde2713f7597bf9468 -) - -FetchContent_Declare( - zlib - URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip - URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1 -) - -FetchContent_MakeAvailable(zlib) -FetchContent_MakeAvailable(mysql) - -set(ZLIB_INCLUDE_DIRS ${zlib_SOURCE_DIR} ${zlib_BINARY_DIR}) -set_target_properties(zlib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIRS}") # Why? -add_library(ZLIB::ZLIB ALIAS zlib) # You're welcome - -endif(WIN32) -if(UNIX) -if(APPLE) -else() -include(FetchContent) - -FetchContent_Declare( - mysql - URL https://dev.mysql.com/get/Downloads/Connector-C++/mysql-connector-c++-8.0.27-linux-glibc2.12-x86-64bit.tar.gz - URL_HASH MD5=12f086b76c11022cc7139b41a36cdf9e -) - -FetchContent_MakeAvailable(mysql) - -if (__include_backtrace__ AND __compile_backtrace__) - FetchContent_Declare( - backtrace - GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git - ) - - FetchContent_MakeAvailable(backtrace) - - if (NOT EXISTS ${backtrace_SOURCE_DIR}/.libs) - set(backtrace_make_cmd "${backtrace_SOURCE_DIR}/configure --prefix=\"/usr\" --enable-shared --with-system-libunwind") - - execute_process( - COMMAND bash -c "cd ${backtrace_SOURCE_DIR} && ${backtrace_make_cmd} && make && cd ${CMAKE_SOURCE_DIR}" - ) - endif() - - link_directories(${backtrace_SOURCE_DIR}/.libs/) - include_directories(${backtrace_SOURCE_DIR}) -endif(__include_backtrace__) - -endif() -endif(UNIX) - # Set the version set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}") - # Echo the version message(STATUS "Version: ${PROJECT_VERSION}") -set(CMAKE_CXX_STANDARD 17) - -if(WIN32) - add_compile_definitions(_CRT_SECURE_NO_WARNINGS) -endif(WIN32) +# Compiler flags: +# Disabled deprecated warnings as the MySQL includes have deprecated code in them. +# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent. +# Disabled no-register +# Disabled unknown pragmas because Linux doesn't understand Windows pragmas. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}") +if(UNIX) + if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC") + endif() + if (__dynamic) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") + endif() + if (__ggdb) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") + endif() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC") +elseif(MSVC) + # Skip warning for invalid conversion from size_t to uint32_t for all targets below for now + add_compile_options("/wd4267") +elseif(WIN32) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +endif() # Our output dir set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR}) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) # Create a /res directory make_directory(${CMAKE_BINARY_DIR}/res) @@ -128,86 +84,82 @@ make_directory(${CMAKE_BINARY_DIR}/locale) make_directory(${CMAKE_BINARY_DIR}/logs) # Copy ini files on first build -if (NOT EXISTS ${PROJECT_BINARY_DIR}/authconfig.ini) - configure_file( - ${CMAKE_SOURCE_DIR}/resources/authconfig.ini ${PROJECT_BINARY_DIR}/authconfig.ini - COPYONLY - ) -endif() -if (NOT EXISTS ${PROJECT_BINARY_DIR}/chatconfig.ini) - configure_file( - ${CMAKE_SOURCE_DIR}/resources/chatconfig.ini ${PROJECT_BINARY_DIR}/chatconfig.ini - COPYONLY - ) -endif() -if (NOT EXISTS ${PROJECT_BINARY_DIR}/worldconfig.ini) - configure_file( - ${CMAKE_SOURCE_DIR}/resources/worldconfig.ini ${PROJECT_BINARY_DIR}/worldconfig.ini - COPYONLY - ) -endif() -if (NOT EXISTS ${PROJECT_BINARY_DIR}/masterconfig.ini) - configure_file( - ${CMAKE_SOURCE_DIR}/resources/masterconfig.ini ${PROJECT_BINARY_DIR}/masterconfig.ini - COPYONLY - ) +set(INI_FILES "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini") +foreach(ini ${INI_FILES}) + if (NOT EXISTS ${PROJECT_BINARY_DIR}/${ini}) + configure_file( + ${CMAKE_SOURCE_DIR}/resources/${ini} ${PROJECT_BINARY_DIR}/${ini} + COPYONLY + ) + endif() +endforeach() + +# Copy vanity files on first build +set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml") +foreach(file ${VANITY_FILES}) + configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY) +endforeach() + +# Move our migrations for MasterServer to run +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/) +file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql) +foreach(file ${SQL_FILES}) + get_filename_component(file ${file} NAME) + if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/${file}) + configure_file( + ${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/${file} + COPYONLY + ) + endif() +endforeach() + +# Create our list of include directories +set(INCLUDED_DIRECTORIES + "dCommon" + "dChatFilter" + "dGame" + "dGame/dBehaviors" + "dGame/dComponents" + "dGame/dGameMessages" + "dGame/dInventory" + "dGame/dMission" + "dGame/dEntity" + "dGame/dUtilities" + "dPhysics" + "dZoneManager" + "dDatabase" + "dDatabase/Tables" + "dNet" + "dScripts" + + "thirdparty/raknet/Source" + "thirdparty/tinyxml2" + "thirdparty/recastnavigation/Recast/Include" + "thirdparty/recastnavigation/Detour/Include" + "thirdparty/SQLite" + "thirdparty/cpplinq" + ) + +# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux) +if (APPLE) + include_directories("/usr/local/include/") endif() -# Copy files to output -configure_file("${CMAKE_SOURCE_DIR}/vanity/CREDITS.md" "${CMAKE_BINARY_DIR}/vanity/CREDITS.md" COPYONLY) -configure_file("${CMAKE_SOURCE_DIR}/vanity/INFO.md" "${CMAKE_BINARY_DIR}/vanity/INFO.md" COPYONLY) -configure_file("${CMAKE_SOURCE_DIR}/vanity/TESTAMENT.md" "${CMAKE_BINARY_DIR}/vanity/TESTAMENT.md" COPYONLY) -configure_file("${CMAKE_SOURCE_DIR}/vanity/NPC.xml" "${CMAKE_BINARY_DIR}/vanity/NPC.xml" COPYONLY) +if (WIN32) + set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include") +elseif (UNIX) + set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt") + set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt") +endif() -# 3rdparty includes -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/raknet/Source/) -if(UNIX) - if(APPLE) - include_directories(/usr/local/include/) - include_directories(/usr/local/mysql-connector-c++/include/jdbc/) - include_directories(/usr/local/mysql-connector-c++/include/jdbc/cppconn/) - else() - include_directories(${mysql_SOURCE_DIR}/include/jdbc/) - include_directories(${mysql_SOURCE_DIR}/include/jdbc/cppconn/) - endif(APPLE) -endif(UNIX) -if(WIN32) -include_directories(${mysql_SOURCE_DIR}/include/jdbc) -include_directories(${mysql_SOURCE_DIR}/include/jdbc/cppconn) -endif(WIN32) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Include) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Include) include_directories(${ZLIB_INCLUDE_DIRS}) - -# Bcrypt -if (NOT WIN32) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt) -else () -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include) -endif () - -# Our includes +# Add binary directory as an include directory include_directories(${PROJECT_BINARY_DIR}) -include_directories(${PROJECT_SOURCE_DIR}/dChatFilter/) -include_directories(${PROJECT_SOURCE_DIR}/dCommon/) -include_directories(${PROJECT_SOURCE_DIR}/dGame/) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dBehaviors) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dComponents) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dGameMessages) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dInventory) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dMission) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dEntity) -include_directories(${PROJECT_SOURCE_DIR}/dGame/dUtilities) -include_directories(${PROJECT_SOURCE_DIR}/dPhysics/) -include_directories(${PROJECT_SOURCE_DIR}/dZoneManager/) -include_directories(${PROJECT_SOURCE_DIR}/dDatabase/) -include_directories(${PROJECT_SOURCE_DIR}/dDatabase/Tables/) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/SQLite/) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/cpplinq/) -include_directories(${PROJECT_SOURCE_DIR}/dNet/) -include_directories(${PROJECT_SOURCE_DIR}/dScripts/) + +# Actually include the directories from our list +foreach (dir ${INCLUDED_DIRECTORIES}) + include_directories(${PROJECT_SOURCE_DIR}/${dir}) +endforeach() # Link dGame to LUA if(__include_lua__) @@ -217,311 +169,116 @@ if(__include_lua__) include_directories(${PROJECT_SOURCE_DIR}/dLua/) endif(UNIX) -# Default to linking to libmysql -set(MYSQL_LIB mysql) -if(WIN32) -set(MYSQL_LIB mysqlcppconn) -endif(WIN32) - -# Lib folders: +# Add linking directories: link_directories(${PROJECT_BINARY_DIR}) -if(UNIX) - if(APPLE) - link_directories(/usr/local/mysql-connector-c++/lib64/) - else() - link_directories(${mysql_SOURCE_DIR}/lib64/) - # Link to libmysqlcppconn on Linux - set(MYSQL_LIB mysqlcppconn) - endif(APPLE) -endif(UNIX) -if(WIN32) -link_directories(${mysql_SOURCE_DIR}/lib64/vs14) -endif(WIN32) +# Load all of our third party directories +add_subdirectory(thirdparty) -# Source Code +# Glob together all headers that need to be precompiled file( -GLOB SOURCES -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dWorldServer/*.cpp + GLOB HEADERS_DDATABASE + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/dDatabase/*.h + ${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h + ${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h ) -# Source Code for AuthServer file( -GLOB SOURCES_AUTH -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dAuthServer/*.cpp + GLOB HEADERS_DZONEMANAGER + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/dZoneManager/*.h ) -# Source Code for MasterServer file( -GLOB SOURCES_MASTER -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dMasterServer/*.cpp + GLOB HEADERS_DCOMMON + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/dCommon/*.h ) -# Source Code for ChatServer file( -GLOB SOURCES_CHAT -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dChatServer/*.cpp + GLOB HEADERS_DGAME + LIST_DIRECTORIES false + ${PROJECT_SOURCE_DIR}/dGame/Entity.h + ${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h + ${PROJECT_SOURCE_DIR}/dGame/EntityManager.h + ${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h ) -# Source Code for raknet -file( -GLOB SOURCES_RAKNET -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/thirdparty/raknet/Source/*.cpp +# Add our library subdirectories for creation of the library object +add_subdirectory(dCommon) +add_subdirectory(dDatabase) +add_subdirectory(dChatFilter) +add_subdirectory(dNet) +add_subdirectory(dScripts) # Add for dGame to use +add_subdirectory(dGame) +add_subdirectory(dZoneManager) +add_subdirectory(dPhysics) + +# Create a list of common libraries shared between all binaries +set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp") + +# Add platform specific common libraries +if (UNIX) + set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "dl" "pthread") + + if (NOT APPLE AND __include_backtrace__) + set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "backtrace") + endif() +endif() + +add_subdirectory(tests) + +# Include all of our binary directories +add_subdirectory(dWorldServer) +add_subdirectory(dAuthServer) +add_subdirectory(dChatServer) +add_subdirectory(dMasterServer) # Add MasterServer last so it can rely on the other binaries + +# Add our precompiled headers +target_precompile_headers( + dGame PRIVATE + ${HEADERS_DGAME} ) -# Source Code for recast -file( -GLOB SOURCES_RECAST -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Source/*.cpp -) - -# Source Code for detour -file( -GLOB SOURCES_DETOUR -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Source/*.cpp -) - -# Source Code for tinyxml2 -file( -GLOB SOURCES_TINYXML2 -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.cpp -) - -# Source Code for libbcrypt -file( -GLOB SOURCES_LIBBCRYPT -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/*.c -${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/src/*.c -) - -# Source Code for dCommon -file( -GLOB SOURCES_DCOMMON -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dCommon/*.cpp -) - -# Source Code for dChatFilter -file( -GLOB SOURCES_DCHATFILTER -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dChatFilter/*.cpp -) - -# Source Code for dDatabase -file( -GLOB SOURCES_DDATABASE -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dDatabase/*.cpp -${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.cpp -${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.cpp -${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.c -) - -# Source Code for dNet -file( -GLOB SOURCES_DNET -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dNet/*.cpp -) - -# Source Code for dGame -file( -GLOB SOURCES_DGAME -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dGame/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dBehaviors/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dComponents/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dGameMessages/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dInventory/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dMission/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dEntity/*.cpp -${PROJECT_SOURCE_DIR}/dGame/dUtilities/*.cpp -${PROJECT_SOURCE_DIR}/dScripts/*.cpp +target_precompile_headers( + dZoneManager PRIVATE + ${HEADERS_DZONEMANAGER} ) # If we are including LUA, include the dLua files in dGame -if(__include_lua__) - file( - GLOB SOURCES_DLUA - LIST_DIRECTORIES false - RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" - ${PROJECT_SOURCE_DIR}/dLua/*.cpp - ) +#if(__include_lua__) +# file( +# GLOB SOURCES_DLUA +# LIST_DIRECTORIES false +# RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" +# ${PROJECT_SOURCE_DIR}/dLua/*.cpp +# ) - # Append the dLua files to the dGame files - set(SOURCES_DGAME ${SOURCES_DGAME} ${SOURCES_DLUA}) -endif(__include_lua__) +# Append the dLua files to the dGame files +#set(SOURCES_DGAME ${SOURCES_DGAME} ${SOURCES_DLUA}) +#endif(__include_lua__) +## Need to specify to use the CXX compiler language here or else we get errors including . +#target_precompile_headers( +# dDatabase PRIVATE +# "$<$:${HEADERS_DDATABASE}>" +#) -# Source Code for dZoneManager -file( -GLOB SOURCES_DZM -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dZoneManager/*.cpp +target_precompile_headers( + dCommon PRIVATE + ${HEADERS_DCOMMON} ) -# Source Code for dPhysics -file( -GLOB SOURCES_DPHYSICS -LIST_DIRECTORIES false -RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" -${PROJECT_SOURCE_DIR}/dPhysics/*.cpp -) - -if(MSVC) - # Skip warning for invalid conversion from size_t to uint32_t for all targets below for now - add_compile_options("/wd4267") -endif(MSVC) - -# 3rdparty static libraries: -#add_library(zlib ${SOURCES_ZLIB}) -add_library(raknet ${SOURCES_RAKNET}) -add_library(tinyxml2 ${SOURCES_TINYXML2}) -add_library(detour ${SOURCES_DETOUR}) -add_library(recast ${SOURCES_RECAST}) -add_library(libbcrypt ${SOURCES_LIBBCRYPT}) - -# Our static libraries: -add_library(dCommon ${SOURCES_DCOMMON}) -add_library(dChatFilter ${SOURCES_DCHATFILTER}) -add_library(dDatabase ${SOURCES_DDATABASE}) -add_library(dNet ${SOURCES_DNET}) -add_library(dGame ${SOURCES_DGAME}) -add_library(dZoneManager ${SOURCES_DZM}) -add_library(dPhysics ${SOURCES_DPHYSICS}) -target_link_libraries(dNet dCommon) #Needed because otherwise linker errors occur. -target_link_libraries(dCommon ZLIB::ZLIB) -target_link_libraries(dCommon libbcrypt) - -if(WIN32) -target_link_libraries(raknet ws2_32) -endif(WIN32) - -# Our executables: -add_executable(WorldServer ${SOURCES}) -add_executable(AuthServer ${SOURCES_AUTH}) -add_executable(MasterServer ${SOURCES_MASTER}) -add_executable(ChatServer ${SOURCES_CHAT}) - -# Target libraries to link to: -target_link_libraries(WorldServer dCommon) -target_link_libraries(WorldServer dChatFilter) -target_link_libraries(WorldServer dDatabase) -target_link_libraries(WorldServer dNet) -target_link_libraries(WorldServer dGame) -target_link_libraries(WorldServer dZoneManager) -target_link_libraries(WorldServer dPhysics) -target_link_libraries(WorldServer detour) -target_link_libraries(WorldServer recast) -target_link_libraries(WorldServer raknet) -target_link_libraries(WorldServer ${MYSQL_LIB}) -if(UNIX) -target_link_libraries(WorldServer pthread) -target_link_libraries(WorldServer dl) - -if(NOT APPLE AND __include_backtrace__) -target_link_libraries(WorldServer backtrace) -target_link_libraries(MasterServer backtrace) -target_link_libraries(AuthServer backtrace) -target_link_libraries(ChatServer backtrace) -endif() - -endif(UNIX) -target_link_libraries(WorldServer tinyxml2) - -# Target libraries for Auth: -target_link_libraries(AuthServer dCommon) -target_link_libraries(AuthServer dDatabase) -target_link_libraries(AuthServer dNet) -target_link_libraries(AuthServer raknet) -target_link_libraries(AuthServer ${MYSQL_LIB}) -if(UNIX) -target_link_libraries(AuthServer pthread) -target_link_libraries(AuthServer dl) -endif(UNIX) - -# Target libraries for Master: -target_link_libraries(MasterServer dCommon) -target_link_libraries(MasterServer dDatabase) -target_link_libraries(MasterServer dNet) -target_link_libraries(MasterServer raknet) -target_link_libraries(MasterServer ${MYSQL_LIB}) -if(UNIX) -target_link_libraries(MasterServer pthread) -target_link_libraries(MasterServer dl) -endif(UNIX) - -# Target libraries for Chat: -target_link_libraries(ChatServer dCommon) -target_link_libraries(ChatServer dChatFilter) -target_link_libraries(ChatServer dDatabase) -target_link_libraries(ChatServer dNet) -target_link_libraries(ChatServer raknet) -target_link_libraries(ChatServer ${MYSQL_LIB}) -if(UNIX) -target_link_libraries(ChatServer pthread) -target_link_libraries(ChatServer dl) -endif(UNIX) - # Link dGame to LUA -if(__include_lua__) - find_package(Lua REQUIRED) +#if(__include_lua__) +# find_package(Lua REQUIRED) - target_link_libraries(dGame ${LUA_LIBRARIES}) +# target_link_libraries(dGame ${LUA_LIBRARIES}) - message(STATUS "Linking dGame to LUA " ${LUA_LIBRARIES}) -endif(UNIX) - -# Compiler flags: -# Disabled deprecated warnings as the MySQL includes have deprecated code in them. -# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent. -# Disabled no-register -# Disabled unknown pragmas because Linux doesn't understand Windows pragmas. -if(UNIX) - if(APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -Wno-unused-result -Wno-unknown-pragmas -fpermissive -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -Wno-unused-result -Wno-unknown-pragmas -fpermissive -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC") - endif() - if (__dynamic) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") - endif() - if (__ggdb) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb") - endif() -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC") -endif(UNIX) - -if(WIN32) -add_dependencies(MasterServer WorldServer) -add_dependencies(MasterServer AuthServer) -add_dependencies(MasterServer ChatServer) -endif() - -# Finally, add the tests -add_subdirectory(tests) +# message(STATUS "Linking dGame to LUA " ${LUA_LIBRARIES}) +#endif(UNIX) +target_precompile_headers( + tinyxml2 PRIVATE + "$<$:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>" +) diff --git a/CMakePresets.json b/CMakePresets.json index 241220e0..133d6a3c 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -19,6 +19,15 @@ "description": "Same as default, Used in GitHub actions workflow", "inherits": "default" }, + { + "name": "ci-macos-11", + "displayName": "CI configure step for MacOS", + "description": "Same as default, Used in GitHub actions workflow", + "inherits": "default", + "cacheVariables": { + "OPENSSL_ROOT_DIR": "/usr/local/Cellar/openssl@3/3.0.5/" + } + }, { "name": "ci-windows-2022", "displayName": "CI configure step for Windows", @@ -66,6 +75,13 @@ "displayName": "Linux CI Build", "description": "This preset is used by the CI build on linux", "jobs": 2 + }, + { + "name": "ci-macos-11", + "configurePreset": "ci-macos-11", + "displayName": "MacOS CI Build", + "description": "This preset is used by the CI build on MacOS", + "jobs": 2 } ], "testPresets": [ @@ -81,6 +97,18 @@ "outputOnFailure": true } }, + { + "name": "ci-macos-11", + "configurePreset": "ci-macos-11", + "displayName": "CI Tests on MacOS", + "description": "Runs all tests on a Mac configuration", + "execution": { + "jobs": 2 + }, + "output": { + "outputOnFailure": true + } + }, { "name": "ci-windows-2022", "configurePreset": "ci-windows-2022", diff --git a/CMakeVariables.txt b/CMakeVariables.txt index b50b4446..db89fef7 100644 --- a/CMakeVariables.txt +++ b/CMakeVariables.txt @@ -1,6 +1,6 @@ PROJECT_VERSION_MAJOR=1 PROJECT_VERSION_MINOR=0 -PROJECT_VERSION_PATCH=2 +PROJECT_VERSION_PATCH=3 # LICENSE LICENSE=AGPL-3.0 # The network version. @@ -16,3 +16,5 @@ NET_VERSION=171022 # Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs. # __compile_backtrace__=1 # Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries. +__maria_db_connector_compile_jobs__=1 +# Set to the number of jobs (make -j equivalent) to compile the mariadbconn files with. \ No newline at end of file diff --git a/Docker.md b/Docker.md index ba52c39c..7d5f7bc6 100644 --- a/Docker.md +++ b/Docker.md @@ -4,7 +4,7 @@ - [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker) - [Docker Compose](https://docs.docker.com/compose/install/) (Included in Docker Desktop) -- LEGO® Universe Client (packed or unpacked). Check the main [README](./README.md) for details on this. +- LEGO® Universe packed Client. Check the main [README](./README.md) for details on this. ## Run server inside Docker @@ -21,6 +21,15 @@ **NOTE #2**: To stop the server simply run `docker compose down` and to restart it just run `docker compose up -d` again. No need to run all the steps above every time. +**NOTE #3**: Docker buildkit needs to be enabled. https://docs.docker.com/develop/develop-images/build_enhancements/#to-enable-buildkit-builds + +**NOTE #4**: Make sure to run the following in the repo root directory after cloning so submodules are also downloaded. +``` +git submodule init +git submodule update +``` +**NOTE #5**: If DarkflameSetup fails due to not having cdclient.fdb, rename CDClient.fdb (in the same folder) to cdclient.fdb + ## Disable brickbuildfix If you don't need the http server running on port 80 do this: diff --git a/README.md b/README.md index 42848839..5781c7b8 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,6 @@ Development of the latest iteration of Darkflame Universe has been done primaril ```bash git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer ``` - **Python** Some tools utilized to streamline the setup process require Python 3, make sure you have it installed. @@ -44,7 +43,7 @@ This was done make sure that older and incomplete clients wouldn't produce false If you're using a DLU client you'll have to go into the "CMakeVariables.txt" file and change the NET_VERSION variable to 171023 to match the modified client's version number. ### Linux builds -Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. +Make sure packages like `gcc`, `cmake`, and `zlib` are installed. Depending on the distribution, these packages might already be installed. Note that on systems like Ubuntu, you will need the `zlib1g-dev` package so that the header files are available. `libssl-dev` will also be required as well as `openssl`. CMake must be version 3.14 or higher! @@ -71,22 +70,19 @@ make ``` ### MacOS builds +Ensure `cmake`, `zlib` and `open ssl` are installed as well as a compiler (e.g `clang` or `gcc`). -**Download precompiled MySQL connector** +In the repository root folder run the following. Ensure -DOPENSSL_ROOT_DIR=/path/to/openssl points to your openssl install location ```bash -# Install required tools -brew install boost mysql-connector-c++ +# Create the build directory, preserving it if it already exists +mkdir -p build +cd build -# Symlinks for finding the required modules -sudo ln -s /usr/local/mysql-connector-c++/lib64/libmysqlcppconn.dylib /usr/local/mysql-connector-c++/lib64/libmysql.dylib -sudo ln -s /usr/local/mysql-connector-c++/lib64/libcrypto.1.1.dylib /usr/local/mysql/lib/libcrypto.1.1.dylib -``` +# Run CMake to generate build files +cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl -Then follow the Linux build steps (gcc is not required), but before running `make`, run the following to make sure all the libs are available in the build folder: - -```bash -sudo ln -s /usr/local/mysql-connector-c++/lib64/libssl.1.1.dylib /path/to/build/folder/libssl.1.1.dylib -sudo ln -s /usr/local/mysql-connector-c++/lib64/libcrypto.1.1.dylib /path/to/build/folder/libcrypto.1.1.dylib +# Get cmake to build the project. If make files are being used then using make and appending `-j` and the amount of cores to utilize may be preferable, for example `make -j8` +cmake --build . --config Release ``` ### Windows builds (native) @@ -102,9 +98,20 @@ cd build cmake .. :: Run CMake with build flag to build -cmake --build . +cmake --build . --config Release ``` +**Windows for ARM** has not been tested but should build by doing the following +```batch +:: Create the build directory +mkdir build +cd build +:: Run CMake to generate make files +cmake .. -DMARIADB_BUILD_SOURCE=ON + +:: Run CMake with build flag to build +cmake --build . --config Release +``` ### Windows builds (WSL) This section will go through how to install [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) and building in a Linux environment under Windows. WSL requires Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11. @@ -128,15 +135,23 @@ sudo apt install build-essential [**Follow the Linux instructions**](#linux-builds) +### ARM builds +AArch64 builds should work on linux and MacOS using their respective build steps. Windows ARM should build but it has not been tested + +### Updating your build +To update your server to the latest version navigate to your cloned directory +```bash +cd /path/to/DarkflameServer +``` +run the following commands to update to the latest changes +```bash +git pull +git submodule update --init --recursive +``` +now follow the build section for your system + ## Setting up the environment -### Database -Darkflame Universe utilizes a MySQL/MariaDB database for account and character information. - -Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running. -* Create a database for Darkflame Universe to use -* Run each SQL file in the order at which they appear [here](migrations/dlu/) on the database - ### Resources **LEGO® Universe 1.10.64** @@ -180,6 +195,13 @@ certutil -hashfile SHA256 * Move and rename `cdclient.sqlite` into `build/res/CDServer.sqlite` * Run each SQL file in the order at which they appear [here](migrations/cdserver/) on the SQLite database +### Database +Darkflame Universe utilizes a MySQL/MariaDB database for account and character information. + +Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running. +* Create a database for Darkflame Universe to use +* Use the command `./MasterServer -m` to automatically run them. + **Configuration** After the server has been built there should be four `ini` files in the build director: `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. Go through them and fill in the database credentials and configure other settings if necessary. @@ -396,20 +418,28 @@ Here is a summary of the commands available in-game. All commands are prefixed b ## Credits -### Contributors to DLUv3 -* DarwinAnim8or -* Wincent01 -* Mick -* averysumner -* Jon002 -* Jonny -* Xiphoseer +## Active Contributors +* [EmosewaMC](https://github.com/EmosewaMC) +* [Jettford](https://github.com/Jettford) + +## DLU Team +* [DarwinAnim8or](https://github.com/DarwinAnim8or) +* [Wincent01](https://github.com/Wincent01) +* [Mick](https://github.com/MickVermeulen) +* [averysumner](https://github.com/codeshaunted) +* [Jon002](https://github.com/jaller200) +* [Jonny](https://github.com/cuzitsjonny) +* TheMachine +* Matthew +* [Raine](https://github.com/Rainebannister) +* Bricknave ### Research and tools -* lcdr +* [lcdr](https://github.com/lcdr) +* [Xiphoseer](https://github.com/Xiphoseer) ### Community management -* Neal +* [Neal](https://github.com/NealSpellman) ### Former contributors * TheMachine diff --git a/dAuthServer/CMakeLists.txt b/dAuthServer/CMakeLists.txt new file mode 100644 index 00000000..353f2a54 --- /dev/null +++ b/dAuthServer/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DAUTHSERVER_SOURCES "AuthServer.cpp") + +add_executable(AuthServer ${DAUTHSERVER_SOURCES}) +target_link_libraries(AuthServer ${COMMON_LIBRARIES}) diff --git a/dChatFilter/CMakeLists.txt b/dChatFilter/CMakeLists.txt new file mode 100644 index 00000000..24b5e428 --- /dev/null +++ b/dChatFilter/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DCHATFILTER_SOURCES "dChatFilter.cpp") + +add_library(dChatFilter STATIC ${DCHATFILTER_SOURCES}) +target_link_libraries(dChatFilter dDatabase) diff --git a/dChatServer/CMakeLists.txt b/dChatServer/CMakeLists.txt new file mode 100644 index 00000000..948593fb --- /dev/null +++ b/dChatServer/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DCHATSERVER_SOURCES "ChatPacketHandler.cpp" + "ChatServer.cpp" + "PlayerContainer.cpp") + +add_executable(ChatServer ${DCHATSERVER_SOURCES}) +target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter) diff --git a/dChatServer/ChatPacketHandler.cpp b/dChatServer/ChatPacketHandler.cpp index 899fd355..4f055121 100644 --- a/dChatServer/ChatPacketHandler.cpp +++ b/dChatServer/ChatPacketHandler.cpp @@ -8,6 +8,10 @@ #include "dServer.h" #include "GeneralUtils.h" #include "dLogger.h" +#include "AddFriendResponseCode.h" +#include "AddFriendResponseType.h" +#include "RakString.h" +#include "dConfig.h" extern PlayerContainer playerContainer; @@ -21,44 +25,41 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { auto player = playerContainer.GetPlayerData(playerID); if (!player) return; - //Get our friends list from the Db: - auto stmt = Database::CreatePreppedStmt("SELECT * FROM friends WHERE player_id = ? OR friend_id = ?"); - stmt->setUInt64(1, playerID); - stmt->setUInt64(2, playerID); + //Get our friends list from the Db. Using a derived table since the friend of a player can be in either column. + std::unique_ptr stmt(Database::CreatePreppedStmt( + "SELECT fr.requested_player, best_friend, ci.name FROM " + "(SELECT CASE " + "WHEN player_id = ? THEN friend_id " + "WHEN friend_id = ? THEN player_id " + "END AS requested_player, best_friend FROM friends) AS fr " + "JOIN charinfo AS ci ON ci.id = fr.requested_player " + "WHERE fr.requested_player IS NOT NULL;")); + stmt->setUInt(1, static_cast(playerID)); + stmt->setUInt(2, static_cast(playerID)); std::vector friends; - auto res = stmt->executeQuery(); + std::unique_ptr res(stmt->executeQuery()); while (res->next()) { FriendData fd; fd.isFTP = false; // not a thing in DLU - fd.friendID = res->getInt64(1); - if (fd.friendID == playerID) fd.friendID = res->getUInt64(2); + fd.friendID = res->getUInt(1); + GeneralUtils::SetBit(fd.friendID, static_cast(eObjectBits::OBJECT_BIT_PERSISTENT)); + GeneralUtils::SetBit(fd.friendID, static_cast(eObjectBits::OBJECT_BIT_CHARACTER)); - fd.isBestFriend = res->getInt(3) == 2; //0 = friends, 1 = requested, 2 = bffs - - //We need to find their name as well: - { - auto stmt = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE id=? limit 1"); - stmt->setInt(1, fd.friendID); - - auto res = stmt->executeQuery(); - while (res->next()) { - fd.friendName = res->getString(1); - } - - delete res; - delete stmt; - } + fd.isBestFriend = res->getInt(2) == 3; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs + if (fd.isBestFriend) player->countOfBestFriends+=1; + fd.friendName = res->getString(3); //Now check if they're online: auto fr = playerContainer.GetPlayerData(fd.friendID); + if (fr) { fd.isOnline = true; fd.zoneID = fr->zoneID; //Since this friend is online, we need to update them on the fact that we've just logged in: - SendFriendUpdate(fr, player, 1); + SendFriendUpdate(fr, player, 1, fd.isBestFriend); } else { fd.isOnline = false; @@ -68,9 +69,6 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { friends.push_back(fd); } - delete res; - delete stmt; - //Now, we need to send the friendlist to the server they came from: CBITSTREAM; PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); @@ -93,20 +91,150 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { } void ChatPacketHandler::HandleFriendRequest(Packet* packet) { + auto maxNumberOfBestFriendsAsString = Game::config->GetValue("max_number_of_best_friends"); + // If this config option doesn't exist, default to 5 which is what live used. + auto maxNumberOfBestFriends = maxNumberOfBestFriendsAsString != "" ? std::stoi(maxNumberOfBestFriendsAsString) : 5U; CINSTREAM; - LWOOBJID playerID; - inStream.Read(playerID); - inStream.Read(playerID); - std::string playerName = PacketUtils::ReadString(0x14, packet, true); - //There's another bool here to determine if it's a best friend request, but we're not handling it right now. + LWOOBJID requestorPlayerID; + inStream.Read(requestorPlayerID); + inStream.Read(requestorPlayerID); + uint32_t spacing{}; + inStream.Read(spacing); + std::string playerName = ""; + uint16_t character; + bool noMoreLettersInName = false; - //PacketUtils::SavePacket("FriendRequest.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed()); - - //We need to check to see if the player is actually online or not: - auto targetData = playerContainer.GetPlayerData(playerName); - if (targetData) { - SendFriendRequest(targetData, playerContainer.GetPlayerData(playerID)); + for (uint32_t j = 0; j < 33; j++) { + inStream.Read(character); + if (character == '\0') noMoreLettersInName = true; + if (!noMoreLettersInName) playerName.push_back(static_cast(character)); } + + char isBestFriendRequest{}; + inStream.Read(isBestFriendRequest); + + auto requestor = playerContainer.GetPlayerData(requestorPlayerID); + std::unique_ptr requestee(playerContainer.GetPlayerData(playerName)); + + // Check if player is online first + if (isBestFriendRequest && !requestee) { + for (auto friendDataCandidate : requestor->friends) { + if (friendDataCandidate.friendName == playerName) { + requestee.reset(new PlayerData()); + // Setup the needed info since you can add a best friend offline. + requestee->playerID = friendDataCandidate.friendID; + requestee->playerName = friendDataCandidate.friendName; + requestee->zoneID = LWOZONEID(); + + FriendData requesteeFriendData{}; + requesteeFriendData.friendID = requestor->playerID; + requesteeFriendData.friendName = requestor->playerName; + requesteeFriendData.isFTP = false; + requesteeFriendData.isOnline = false; + requesteeFriendData.zoneID = requestor->zoneID; + requestee->friends.push_back(requesteeFriendData); + requestee->sysAddr = UNASSIGNED_SYSTEM_ADDRESS; + break; + } + } + } + + // If at this point we dont have a target, then they arent online and we cant send the request. + // Send the response code that corresponds to what the error is. + if (!requestee) { + std::unique_ptr nameQuery(Database::CreatePreppedStmt("SELECT name from charinfo where name = ?;")); + nameQuery->setString(1, playerName); + std::unique_ptr result(nameQuery->executeQuery()); + + requestee.reset(new PlayerData()); + requestee->playerName = playerName; + + SendFriendResponse(requestor, requestee.get(), result->next() ? AddFriendResponseType::NOTONLINE : AddFriendResponseType::INVALIDCHARACTER); + return; + } + + if (isBestFriendRequest) { + std::unique_ptr friendUpdate(Database::CreatePreppedStmt("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;")); + friendUpdate->setUInt(1, static_cast(requestorPlayerID)); + friendUpdate->setUInt(2, static_cast(requestee->playerID)); + friendUpdate->setUInt(3, static_cast(requestee->playerID)); + friendUpdate->setUInt(4, static_cast(requestorPlayerID)); + std::unique_ptr result(friendUpdate->executeQuery()); + + LWOOBJID queryPlayerID = LWOOBJID_EMPTY; + LWOOBJID queryFriendID = LWOOBJID_EMPTY; + uint8_t oldBestFriendStatus{}; + uint8_t bestFriendStatus{}; + + if (result->next()) { + // Get the IDs + queryPlayerID = result->getInt(1); + queryFriendID = result->getInt(2); + oldBestFriendStatus = result->getInt(3); + bestFriendStatus = oldBestFriendStatus; + + // Set the bits + GeneralUtils::SetBit(queryPlayerID, static_cast(eObjectBits::OBJECT_BIT_CHARACTER)); + GeneralUtils::SetBit(queryPlayerID, static_cast(eObjectBits::OBJECT_BIT_PERSISTENT)); + GeneralUtils::SetBit(queryFriendID, static_cast(eObjectBits::OBJECT_BIT_CHARACTER)); + GeneralUtils::SetBit(queryFriendID, static_cast(eObjectBits::OBJECT_BIT_PERSISTENT)); + + // Since this player can either be the friend of someone else or be friends with someone else + // their column in the database determines what bit gets set. When the value hits 3, they + // are now best friends with the other player. + if (queryPlayerID == requestorPlayerID) { + bestFriendStatus |= 1ULL << 0; + } else { + bestFriendStatus |= 1ULL << 1; + } + } + + // Only do updates if there was a change in the bff status. + if (oldBestFriendStatus != bestFriendStatus) { + if (requestee->countOfBestFriends >= maxNumberOfBestFriends || requestor->countOfBestFriends >= maxNumberOfBestFriends) { + if (requestee->countOfBestFriends >= maxNumberOfBestFriends) { + SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::THEIRFRIENDLISTFULL, false); + } + if (requestor->countOfBestFriends >= maxNumberOfBestFriends) { + SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::YOURFRIENDSLISTFULL, false); + } + } else { + // Then update the database with this new info. + std::unique_ptr updateQuery(Database::CreatePreppedStmt("UPDATE friends SET best_friend = ? WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;")); + updateQuery->setUInt(1, bestFriendStatus); + updateQuery->setUInt(2, static_cast(requestorPlayerID)); + updateQuery->setUInt(3, static_cast(requestee->playerID)); + updateQuery->setUInt(4, static_cast(requestee->playerID)); + updateQuery->setUInt(5, static_cast(requestorPlayerID)); + updateQuery->executeUpdate(); + // Sent the best friend update here if the value is 3 + if (bestFriendStatus == 3U) { + requestee->countOfBestFriends+=1; + requestor->countOfBestFriends+=1; + if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee.get(), requestor, AddFriendResponseType::ACCEPTED, false, true); + if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::ACCEPTED, false, true); + for (auto& friendData : requestor->friends) { + if (friendData.friendID == requestee->playerID) { + friendData.isBestFriend = true; + } + } + for (auto& friendData : requestee->friends) { + if (friendData.friendID == requestor->playerID) { + friendData.isBestFriend = true; + } + } + } + } + } else { + if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), AddFriendResponseType::WAITINGAPPROVAL, true, true); + } + } else { + // Do not send this if we are requesting to be a best friend. + SendFriendRequest(requestee.get(), requestor); + } + + // If the player is actually a player and not a ghost one defined above, release it from being deleted. + if (requestee->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) requestee.release(); } void ChatPacketHandler::HandleFriendResponse(Packet* packet) { @@ -114,30 +242,75 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) { LWOOBJID playerID; inStream.Read(playerID); inStream.Read(playerID); - - uint8_t responseCode = packet->data[0x14]; + + AddFriendResponseCode clientResponseCode = static_cast(packet->data[0x14]); std::string friendName = PacketUtils::ReadString(0x15, packet, true); - Game::logger->Log("ChatPacketHandler", "Friend response code: %i\n", responseCode); - - if (responseCode != 0) return; //If we're not accepting the request, end here, do not insert to friends table. - - PacketUtils::SavePacket("HandleFriendResponse.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed()); - //Now to try and find both of these: - auto goonA = playerContainer.GetPlayerData(playerID); - auto goonB = playerContainer.GetPlayerData(friendName); - if (!goonA || !goonB) return; + auto requestor = playerContainer.GetPlayerData(playerID); + auto requestee = playerContainer.GetPlayerData(friendName); + if (!requestor || !requestee) return; - SendFriendResponse(goonB, goonA, responseCode); - SendFriendResponse(goonA, goonB, responseCode); //Do we need to send it to both? I think so so both get the updated friendlist but... idk. + AddFriendResponseType serverResponseCode{}; + uint8_t isAlreadyBestFriends = 0U; + // We need to convert this response code to one we can actually send back to the client. + switch (clientResponseCode) { + case AddFriendResponseCode::ACCEPTED: + serverResponseCode = AddFriendResponseType::ACCEPTED; + break; + case AddFriendResponseCode::BUSY: + serverResponseCode = AddFriendResponseType::BUSY; + break; + case AddFriendResponseCode::CANCELLED: + serverResponseCode = AddFriendResponseType::CANCELLED; + break; + case AddFriendResponseCode::REJECTED: + serverResponseCode = AddFriendResponseType::DECLINED; + break; + } - auto stmt = Database::CreatePreppedStmt("INSERT INTO `friends`(`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?)"); - stmt->setUInt64(1, goonA->playerID); - stmt->setUInt64(2, goonB->playerID); - stmt->setInt(3, 0); - stmt->execute(); - delete stmt; + // Now that we have handled the base cases, we need to check the other cases. + if (serverResponseCode == AddFriendResponseType::ACCEPTED) { + for (auto friendData : requestor->friends) { + if (friendData.friendID == requestee->playerID) { + serverResponseCode = AddFriendResponseType::ALREADYFRIEND; + if (friendData.isBestFriend) { + isAlreadyBestFriends = 1U; + } + } + } + } + + // This message is NOT sent for best friends and is handled differently for those requests. + if (serverResponseCode == AddFriendResponseType::ACCEPTED) { + // Add the each player to the others friend list. + FriendData requestorData; + requestorData.zoneID = requestor->zoneID; + requestorData.friendID = requestor->playerID; + requestorData.friendName = requestor->playerName; + requestorData.isBestFriend = false; + requestorData.isFTP = false; + requestorData.isOnline = true; + requestee->friends.push_back(requestorData); + + FriendData requesteeData; + requesteeData.zoneID = requestee->zoneID; + requesteeData.friendID = requestee->playerID; + requesteeData.friendName = requestee->playerName; + requesteeData.isBestFriend = false; + requesteeData.isFTP = false; + requesteeData.isOnline = true; + requestor->friends.push_back(requesteeData); + + std::unique_ptr statement(Database::CreatePreppedStmt("INSERT IGNORE INTO `friends` (`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?);")); + statement->setUInt(1, static_cast(requestor->playerID)); + statement->setUInt(2, static_cast(requestee->playerID)); + statement->setInt(3, 0); + statement->execute(); + } + + if (serverResponseCode != AddFriendResponseType::DECLINED) SendFriendResponse(requestor, requestee, serverResponseCode, isAlreadyBestFriends); + if (serverResponseCode != AddFriendResponseType::ALREADYFRIEND) SendFriendResponse(requestee, requestor, serverResponseCode, isAlreadyBestFriends); } void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { @@ -145,50 +318,55 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { LWOOBJID playerID; inStream.Read(playerID); inStream.Read(playerID); - std::string friendName = PacketUtils::ReadString(16, packet, true); + std::string friendName = PacketUtils::ReadString(0x14, packet, true); //we'll have to query the db here to find the user, since you can delete them while they're offline. //First, we need to find their ID: - auto stmt = Database::CreatePreppedStmt("select id from charinfo where name=? limit 1;"); + std::unique_ptr stmt(Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? LIMIT 1;")); stmt->setString(1, friendName.c_str()); LWOOBJID friendID = 0; - auto res = stmt->executeQuery(); + std::unique_ptr res(stmt->executeQuery()); while (res->next()) { - friendID = res->getUInt64(1); + friendID = res->getUInt(1); } - delete res; - delete stmt; + // Convert friendID to LWOOBJID + GeneralUtils::SetBit(friendID, static_cast(eObjectBits::OBJECT_BIT_PERSISTENT)); + GeneralUtils::SetBit(friendID, static_cast(eObjectBits::OBJECT_BIT_CHARACTER)); - //Set our bits to convert to the BIG BOY objectID. - friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_CHARACTER); - friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_PERSISTENT); - - //YEET: - auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1"); - deletestmt->setUInt64(1, playerID); - deletestmt->setUInt64(2, friendID); + std::unique_ptr deletestmt(Database::CreatePreppedStmt("DELETE FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;")); + deletestmt->setUInt(1, static_cast(playerID)); + deletestmt->setUInt(2, static_cast(friendID)); + deletestmt->setUInt(3, static_cast(friendID)); + deletestmt->setUInt(4, static_cast(playerID)); deletestmt->execute(); - delete deletestmt; - - //because I'm lazy and they can be reversed: - { - auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1"); - deletestmt->setUInt64(1, friendID); - deletestmt->setUInt64(2, playerID); - deletestmt->execute(); - delete deletestmt; - } //Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended: auto goonA = playerContainer.GetPlayerData(playerID); if (goonA) { + // Remove the friend from our list of friends + for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) { + if ((*friendData).friendID == friendID) { + if ((*friendData).isBestFriend) --goonA->countOfBestFriends; + goonA->friends.erase(friendData); + break; + } + } SendRemoveFriend(goonA, friendName, true); } - + auto goonB = playerContainer.GetPlayerData(friendID); if (!goonB) return; + // Do it again for other person + for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) { + if ((*friendData).friendID == playerID) { + if ((*friendData).isBestFriend) --goonB->countOfBestFriends; + goonB->friends.erase(friendData); + break; + } + } + std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID)); SendRemoveFriend(goonB, goonAName, true); } @@ -206,7 +384,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) if (playerContainer.GetIsMuted(sender)) return; - const auto senderName = std::string(sender->playerName.C_String()); + const auto senderName = std::string(sender->playerName.c_str()); inStream.SetReadOffset(0x14 * 8); @@ -217,8 +395,6 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s\n", senderName.c_str(), channel, message.c_str()); - //PacketUtils::SavePacket("chat.bin", reinterpret_cast(packet->data), packet->length); - if (channel != 8) return; auto* team = playerContainer.GetTeam(playerID); @@ -231,7 +407,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) if (otherMember == nullptr) return; - const auto otherName = std::string(otherMember->playerName.C_String()); + const auto otherName = std::string(otherMember->playerName.c_str()); CBITSTREAM; PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); @@ -267,8 +443,8 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) { if (playerContainer.GetIsMuted(goonA)) return; - std::string goonAName = goonA->playerName.C_String(); - std::string goonBName = goonB->playerName.C_String(); + std::string goonAName = goonA->playerName.c_str(); + std::string goonBName = goonB->playerName.c_str(); //To the sender: { @@ -454,8 +630,6 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) playerContainer.RemoveMember(team, kickedId, false, true, false); } - - //PacketUtils::SavePacket("kick.bin", reinterpret_cast(packet->data), packet->length); } void ChatPacketHandler::HandleTeamPromote(Packet* packet) @@ -481,8 +655,6 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) playerContainer.PromoteMember(team, promoted->playerID); } - - //PacketUtils::SavePacket("promote.bin", reinterpret_cast(packet->data), packet->length); } void ChatPacketHandler::HandleTeamLootOption(Packet* packet) @@ -509,8 +681,6 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet) playerContainer.UpdateTeamsOnWorld(team, false); } - - //PacketUtils::SavePacket("option.bin", reinterpret_cast(packet->data), packet->length); } void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) @@ -550,7 +720,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) playerContainer.TeamStatusUpdate(team); - const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String())); + const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.c_str())); for (const auto memberId : team->memberIDs) { @@ -560,7 +730,6 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) const auto memberName = playerContainer.GetName(memberId); - //ChatPacketHandler::SendTeamAddPlayer(otherMember, false, false, false, data->playerID, leaderName, data->zoneID); if (otherMember != nullptr) { ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID); @@ -581,7 +750,7 @@ void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) //portion that will get routed: PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_TEAM_INVITE); - PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream); + PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream); bitStream.Write(sender->playerID); SystemAddress sysAddr = receiver->sysAddr; @@ -745,7 +914,7 @@ void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i SEND_PACKET; } -void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType) { +void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend) { /*chat notification is displayed if log in / out and friend is updated in friends list [u8] - update type Update types @@ -767,7 +936,7 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_UPDATE_FRIEND_NOTIFY); bitStream.Write(notifyType); - std::string playerName = playerData->playerName.C_String(); + std::string playerName = playerData->playerName.c_str(); PacketUtils::WritePacketWString(playerName, 33, &bitStream); @@ -783,19 +952,20 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla bitStream.Write(playerData->zoneID.GetCloneID()); } - bitStream.Write(0); //isBFF + bitStream.Write(isBestFriend); //isBFF bitStream.Write(0); //isFTP SystemAddress sysAddr = friendData->sysAddr; SEND_PACKET; } -void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq) { +void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender) { if (!receiver || !sender) return; //Make sure people aren't requesting people that they're already friends with: for (auto fr : receiver->friends) { if (fr.friendID == sender->playerID) { + SendFriendResponse(sender, receiver, AddFriendResponseType::ALREADYFRIEND, fr.isBestFriend); return; //we have this player as a friend, yeet this function so it doesn't send another request. } } @@ -806,30 +976,34 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send //portion that will get routed: PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_REQUEST); - PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream); - bitStream.Write(0); + PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream); + bitStream.Write(0); // This is a BFF flag however this is unused in live and does not have an implementation client side. SystemAddress sysAddr = receiver->sysAddr; SEND_PACKET; } -void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode) { +void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) { if (!receiver || !sender) return; CBITSTREAM; PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER); bitStream.Write(receiver->playerID); - //portion that will get routed: + // Portion that will get routed: PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_RESPONSE); - bitStream.Write(responseCode); - bitStream.Write(1); //isOnline - PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream); - bitStream.Write(sender->playerID); - bitStream.Write(sender->zoneID); - bitStream.Write(0); //isBFF - bitStream.Write(0); //isFTP - + bitStream.Write(responseCode); + // For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver. + bitStream.Write(responseCode != AddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS); + // Then write the player name + PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream); + // Then if this is an acceptance code, write the following extra info. + if (responseCode == AddFriendResponseType::ACCEPTED) { + bitStream.Write(sender->playerID); + bitStream.Write(sender->zoneID); + bitStream.Write(isBestFriendRequest); //isBFF + bitStream.Write(0); //isFTP + } SystemAddress sysAddr = receiver->sysAddr; SEND_PACKET; } diff --git a/dChatServer/ChatPacketHandler.h b/dChatServer/ChatPacketHandler.h index e38a65c1..fffd1ca4 100644 --- a/dChatServer/ChatPacketHandler.h +++ b/dChatServer/ChatPacketHandler.h @@ -4,6 +4,7 @@ #include "BitStream.h" struct PlayerData; +enum class AddFriendResponseType : uint8_t; namespace ChatPacketHandler { void HandleFriendlistRequest(Packet* packet); @@ -31,10 +32,9 @@ namespace ChatPacketHandler { void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID); //FriendData is the player we're SENDING this stuff to. Player is the friend that changed state. - void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType); + void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend); - void SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq = false); - void SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode = 3); + void SendFriendRequest(PlayerData* receiver, PlayerData* sender); + void SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U); void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful); }; - diff --git a/dChatServer/PlayerContainer.cpp b/dChatServer/PlayerContainer.cpp index d261b32f..1517153d 100644 --- a/dChatServer/PlayerContainer.cpp +++ b/dChatServer/PlayerContainer.cpp @@ -20,17 +20,25 @@ PlayerContainer::~PlayerContainer() { void PlayerContainer::InsertPlayer(Packet* packet) { CINSTREAM; PlayerData* data = new PlayerData(); + inStream.SetReadOffset(inStream.GetReadOffset() + 64); inStream.Read(data->playerID); - inStream.Read(data->playerID); - inStream.Read(data->playerName); + + uint32_t len; + inStream.Read(len); + + for (int i = 0; i < len; i++) { + char character; inStream.Read(character); + data->playerName += character; + } + inStream.Read(data->zoneID); inStream.Read(data->muteExpire); data->sysAddr = packet->systemAddress; - mNames[data->playerID] = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String())); + mNames[data->playerID] = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.c_str())); mPlayers.insert(std::make_pair(data->playerID, data)); - Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i\n", data->playerName.C_String(), data->playerID, data->zoneID.GetMapID()); + Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i\n", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID()); auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);"); @@ -49,26 +57,22 @@ void PlayerContainer::RemovePlayer(Packet* packet) { inStream.Read(playerID); //Before they get kicked, we need to also send a message to their friends saying that they disconnected. - auto player = this->GetPlayerData(playerID); + std::unique_ptr player(this->GetPlayerData(playerID)); if (player == nullptr) { return; } for (auto& fr : player->friends) { - //if (!fr.isOnline) continue; - auto fd = this->GetPlayerData(fr.friendID); - if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0); + if (fd) ChatPacketHandler::SendFriendUpdate(fd, player.get(), 0, fr.isBestFriend); } auto* team = GetTeam(playerID); if (team != nullptr) { - //TeamStatusUpdate(team); - - const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.C_String())); + const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.c_str())); for (const auto memberId : team->memberIDs) { @@ -77,7 +81,6 @@ void PlayerContainer::RemovePlayer(Packet* packet) { if (otherMember == nullptr) continue; ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, {0, 0, 0}); - //ChatPacketHandler::SendTeamRemovePlayer(otherMember, false, false, true, false, team->leaderID, player->playerID, memberName); } } @@ -237,16 +240,10 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) if (leader == nullptr || member == nullptr) return; - const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String())); - const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.C_String())); + const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.c_str())); + const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.c_str())); ChatPacketHandler::SendTeamInviteConfirm(member, false, leader->playerID, leader->zoneID, team->lootFlag, 0, 0, leaderName); - - /* - ChatPacketHandler::SendTeamAddPlayer(member, false, false, false, leader->playerID, leaderName, leader->zoneID); - - Game::logger->Log("PlayerContainer", "Team invite successfully accepted, leader: %s, member: %s\n", leader->playerName.C_String(), member->playerName.C_String()); - */ if (!team->local) { @@ -348,7 +345,7 @@ void PlayerContainer::DisbandTeam(TeamData* team) if (otherMember == nullptr) continue; - const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(otherMember->playerName.C_String())); + const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(otherMember->playerName.c_str())); ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY); ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember->playerID, memberName); @@ -371,7 +368,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) if (leader == nullptr) return; - const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String())); + const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.c_str())); for (const auto memberId : team->memberIDs) { @@ -383,10 +380,6 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) { ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader->zoneID, team->lootFlag, 0, leaderName); } - else - { - //ChatPacketHandler::SendTeamStatus(otherMember, LWOOBJID_EMPTY, LWOZONEID(0, 0, 0), 1, 0, u""); - } } UpdateTeamsOnWorld(team, false); diff --git a/dChatServer/PlayerContainer.h b/dChatServer/PlayerContainer.h index dc78d3b0..9216a361 100644 --- a/dChatServer/PlayerContainer.h +++ b/dChatServer/PlayerContainer.h @@ -9,11 +9,12 @@ struct PlayerData { LWOOBJID playerID; - RakNet::RakString playerName; + std::string playerName; SystemAddress sysAddr; LWOZONEID zoneID; std::vector friends; time_t muteExpire; + uint8_t countOfBestFriends = 0; }; struct TeamData { @@ -45,7 +46,7 @@ public: PlayerData* GetPlayerData(const std::string& playerName) { for (auto player : mPlayers) { if (player.second) { - std::string pn = player.second->playerName.C_String(); + std::string pn = player.second->playerName.c_str(); if (pn == playerName) return player.second; } } diff --git a/dCommon/AddFriendResponseCode.h b/dCommon/AddFriendResponseCode.h new file mode 100644 index 00000000..bb2faff7 --- /dev/null +++ b/dCommon/AddFriendResponseCode.h @@ -0,0 +1,15 @@ +#pragma once + +#ifndef __ADDFRIENDRESPONSECODE__H__ +#define __ADDFRIENDRESPONSECODE__H__ + +#include + +enum class AddFriendResponseCode : uint8_t { + ACCEPTED = 0, + REJECTED, + BUSY, + CANCELLED +}; + +#endif //!__ADDFRIENDRESPONSECODE__H__ diff --git a/dCommon/AddFriendResponseType.h b/dCommon/AddFriendResponseType.h new file mode 100644 index 00000000..305796e8 --- /dev/null +++ b/dCommon/AddFriendResponseType.h @@ -0,0 +1,24 @@ +#pragma once + +#ifndef __ADDFRIENDRESPONSETYPE__H__ +#define __ADDFRIENDRESPONSETYPE__H__ + +#include + +enum class AddFriendResponseType : uint8_t { + ACCEPTED = 0, + ALREADYFRIEND, + INVALIDCHARACTER, + GENERALERROR, + YOURFRIENDSLISTFULL, + THEIRFRIENDLISTFULL, + DECLINED, + BUSY, + NOTONLINE, + WAITINGAPPROVAL, + MYTHRAN, + CANCELLED, + FRIENDISFREETRIAL +}; + +#endif //!__ADDFRIENDRESPONSETYPE__H__ diff --git a/dCommon/CMakeLists.txt b/dCommon/CMakeLists.txt new file mode 100644 index 00000000..7e047a9c --- /dev/null +++ b/dCommon/CMakeLists.txt @@ -0,0 +1,26 @@ +set(DCOMMON_SOURCES "AMFFormat.cpp" + "AMFFormat_BitStream.cpp" + "BinaryIO.cpp" + "dConfig.cpp" + "Diagnostics.cpp" + "dLogger.cpp" + "GeneralUtils.cpp" + "LDFFormat.cpp" + "MD5.cpp" + "Metrics.cpp" + "NiPoint3.cpp" + "NiQuaternion.cpp" + "SHA512.cpp" + "Type.cpp" + "ZCompression.cpp") + +include_directories(${PROJECT_SOURCE_DIR}/dCommon/) + +add_library(dCommon STATIC ${DCOMMON_SOURCES}) + +target_link_libraries(dCommon libbcrypt) + +if (UNIX) + find_package(ZLIB REQUIRED) + target_link_libraries(dCommon ZLIB::ZLIB) +endif() diff --git a/dCommon/GeneralUtils.cpp b/dCommon/GeneralUtils.cpp index b3461e8a..01306226 100644 --- a/dCommon/GeneralUtils.cpp +++ b/dCommon/GeneralUtils.cpp @@ -188,3 +188,53 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream *inStream) { return string; } + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +std::vector GeneralUtils::GetFileNamesFromFolder(const std::string& folder) +{ + std::vector names; + std::string search_path = folder + "/*.*"; + WIN32_FIND_DATA fd; + HANDLE hFind = ::FindFirstFile(search_path.c_str(), &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + names.push_back(fd.cFileName); + } + } while (::FindNextFile(hFind, &fd)); + ::FindClose(hFind); + } + return names; +} +#else +#include +#include +#include +#include +#include +#include + +std::vector GeneralUtils::GetFileNamesFromFolder(const std::string& folder) { + std::vector names; + struct dirent* entry; + DIR* dir = opendir(folder.c_str()); + if (dir == NULL) { + return names; + } + + while ((entry = readdir(dir)) != NULL) { + std::string value(entry->d_name, strlen(entry->d_name)); + if (value == "." || value == "..") { + continue; + } + names.push_back(value); + } + + closedir(dir); + + return names; +} +#endif \ No newline at end of file diff --git a/dCommon/GeneralUtils.h b/dCommon/GeneralUtils.h index 58b9e962..4973201e 100644 --- a/dCommon/GeneralUtils.h +++ b/dCommon/GeneralUtils.h @@ -128,6 +128,8 @@ namespace GeneralUtils { std::vector SplitString(const std::string& str, char delimiter); + std::vector GetFileNamesFromFolder(const std::string& folder); + template T Parse(const char* value); diff --git a/dCommon/LDFFormat.cpp b/dCommon/LDFFormat.cpp index 13fcb5cb..8290faec 100644 --- a/dCommon/LDFFormat.cpp +++ b/dCommon/LDFFormat.cpp @@ -54,7 +54,7 @@ LDFBaseData * LDFBaseData::DataFromString(const std::string& format) { } case LDF_TYPE_S32: { - int32_t data = static_cast(stol(dataArray[1])); + int32_t data = static_cast(stoull(dataArray[1])); return new LDFData(key, data); } diff --git a/dCommon/ZCompression.cpp b/dCommon/ZCompression.cpp index 3a66323d..28588bb8 100644 --- a/dCommon/ZCompression.cpp +++ b/dCommon/ZCompression.cpp @@ -1,5 +1,7 @@ #include "ZCompression.h" +#ifndef _WIN32 + #include namespace ZCompression @@ -70,4 +72,6 @@ namespace ZCompression return(nRet); // -1 or len of output */ } -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/dCommon/ZCompression.h b/dCommon/ZCompression.h index ec870fb8..6db2a600 100644 --- a/dCommon/ZCompression.h +++ b/dCommon/ZCompression.h @@ -2,6 +2,10 @@ #include +#include "dPlatforms.h" + +#ifndef DARKFLAME_PLATFORM_WIN32 + namespace ZCompression { int32_t GetMaxCompressedLength(int32_t nLenSrc); @@ -10,3 +14,5 @@ namespace ZCompression int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr); } + +#endif diff --git a/dCommon/dCommonVars.h b/dCommon/dCommonVars.h index cbecdd37..c458b9fb 100644 --- a/dCommon/dCommonVars.h +++ b/dCommon/dCommonVars.h @@ -407,14 +407,20 @@ enum eReplicaComponentType : int32_t { COMPONENT_TYPE_MISSION = 84, //!< The Mission Component COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen COMPONENT_TYPE_RAIL_ACTIVATOR = 104, - COMPONENT_TYPE_POSSESSOR = 107, //!< The Component 107 - COMPONENT_TYPE_POSSESSABLE = 108, //!< The Component 108 + COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component + COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component COMPONENT_TYPE_MODEL = 5398484 //look man idk }; +enum class UseItemResponse : uint32_t { + NoImaginationForPet = 1, + FailedPrecondition, + MountsNotAllowed +}; + /** * Represents the different types of inventories an entity may have */ @@ -434,33 +440,6 @@ enum eInventoryType : uint32_t { INVALID // made up, for internal use!!! }; -enum eItemType : int32_t { - ITEM_TYPE_UNKNOWN = -1, //!< An unknown item type - ITEM_TYPE_BRICK = 1, //!< A brick - ITEM_TYPE_HAT = 2, //!< A hat / head item - ITEM_TYPE_HAIR = 3, //!< A hair item - ITEM_TYPE_NECK = 4, //!< A neck item - ITEM_TYPE_LEFT_HAND = 5, //!< A left handed item - ITEM_TYPE_RIGHT_HAND = 6, //!< A right handed item - ITEM_TYPE_LEGS = 7, //!< A pants item - ITEM_TYPE_LEFT_TRINKET = 8, //!< A left handled trinket item - ITEM_TYPE_RIGHT_TRINKET = 9, //!< A right handed trinket item - ITEM_TYPE_BEHAVIOR = 10, //!< A behavior - ITEM_TYPE_PROPERTY = 11, //!< A property - ITEM_TYPE_MODEL = 12, //!< A model - ITEM_TYPE_COLLECTIBLE = 13, //!< A collectible item - ITEM_TYPE_CONSUMABLE = 14, //!< A consumable item - ITEM_TYPE_CHEST = 15, //!< A chest item - ITEM_TYPE_EGG = 16, //!< An egg - ITEM_TYPE_PET_FOOD = 17, //!< A pet food item - ITEM_TYPE_QUEST_OBJECT = 18, //!< A quest item - ITEM_TYPE_PET_INVENTORY_ITEM = 19, //!< A pet inventory item - ITEM_TYPE_PACKAGE = 20, //!< A package - ITEM_TYPE_LOOT_MODEL = 21, //!< A loot model - ITEM_TYPE_VEHICLE = 22, //!< A vehicle - ITEM_TYPE_CURRENCY = 23 //!< Currency -}; - enum eRebuildState : uint32_t { REBUILD_OPEN, REBUILD_COMPLETED = 2, @@ -658,7 +637,6 @@ enum ePlayerFlags { NJ_WU_SHOW_DAILY_CHEST = 2099 }; - //======== FUNC =========== template diff --git a/dCommon/dPlatforms.h b/dCommon/dPlatforms.h new file mode 100644 index 00000000..d19e8121 --- /dev/null +++ b/dCommon/dPlatforms.h @@ -0,0 +1,29 @@ +#pragma once + +#if defined(_WIN32) + #define DARKFLAME_PLATFORM_WIN32 +#elif defined(__APPLE__) && defined(__MACH__) + #include + #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + #define DARKFLAME_PLATFORM_IOS + #elif TARGET_OS_MAC + #define DARKFLAME_PLATFORM_MACOS + #else + #error unknown Apple operating system + #endif +#elif defined(__unix__) + #define DARKFLAME_PLATFORM_UNIX + #if defined(__ANDROID__) + #define DARKFLAME_PLATFORM_ANDROID + #elif defined(__linux__) + #define DARKFLAME_PLATFORM_LINUX + #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + #define DARKFLAME_PLATFORM_FREEBSD + #elif defined(__CYGWIN__) + #define DARKFLAME_PLATFORM_CYGWIN + #else + #error unknown unix operating system + #endif +#else + #error unknown operating system +#endif \ No newline at end of file diff --git a/dCommon/eAninmationFlags.h b/dCommon/eAninmationFlags.h new file mode 100644 index 00000000..09cfde22 --- /dev/null +++ b/dCommon/eAninmationFlags.h @@ -0,0 +1,44 @@ +#pragma once + +#ifndef __EANINMATIONFLAGS__H__ +#define __EANINMATIONFLAGS__H__ + +#include + +enum class eAnimationFlags : uint32_t { + IDLE_INVALID = 0, // made up, for internal use!!! + IDLE_BASIC, + IDLE_SWIM, + IDLE_CARRY, + IDLE_SWORD, + IDLE_HAMMER, + IDLE_SPEAR, + IDLE_PISTOL, + IDLE_BOW, + IDLE_COMBAT, + IDLE_JETPACK, + IDLE_HORSE, + IDLE_SG, + IDLE_ORGAN, + IDLE_SKATEBOARD, + IDLE_DAREDEVIL, + IDLE_SAMURAI, + IDLE_SUMMONER, + IDLE_BUCCANEER, + IDLE_MISC, + IDLE_NINJA, + IDLE_MISC1, + IDLE_MISC2, + IDLE_MISC3, + IDLE_MISC4, + IDLE_MISC5, + IDLE_MISC6, + IDLE_MISC7, + IDLE_MISC8, + IDLE_MISC9, + IDLE_MISC10, + IDLE_MISC11, + IDLE_MISC12 +}; + +#endif //!__EANINMATIONFLAGS__H__ \ No newline at end of file diff --git a/dCommon/eItemType.h b/dCommon/eItemType.h new file mode 100644 index 00000000..453e8737 --- /dev/null +++ b/dCommon/eItemType.h @@ -0,0 +1,36 @@ +#pragma once + +#ifndef __EITEMTYPE__H__ +#define __EITEMTYPE__H__ + +#include + +enum class eItemType : int32_t { + ITEM_TYPE_UNKNOWN = -1, //!< An unknown item type + ITEM_TYPE_BRICK = 1, //!< A brick + ITEM_TYPE_HAT = 2, //!< A hat / head item + ITEM_TYPE_HAIR = 3, //!< A hair item + ITEM_TYPE_NECK = 4, //!< A neck item + ITEM_TYPE_LEFT_HAND = 5, //!< A left handed item + ITEM_TYPE_RIGHT_HAND = 6, //!< A right handed item + ITEM_TYPE_LEGS = 7, //!< A pants item + ITEM_TYPE_LEFT_TRINKET = 8, //!< A left handled trinket item + ITEM_TYPE_RIGHT_TRINKET = 9, //!< A right handed trinket item + ITEM_TYPE_BEHAVIOR = 10, //!< A behavior + ITEM_TYPE_PROPERTY = 11, //!< A property + ITEM_TYPE_MODEL = 12, //!< A model + ITEM_TYPE_COLLECTIBLE = 13, //!< A collectible item + ITEM_TYPE_CONSUMABLE = 14, //!< A consumable item + ITEM_TYPE_CHEST = 15, //!< A chest item + ITEM_TYPE_EGG = 16, //!< An egg + ITEM_TYPE_PET_FOOD = 17, //!< A pet food item + ITEM_TYPE_QUEST_OBJECT = 18, //!< A quest item + ITEM_TYPE_PET_INVENTORY_ITEM = 19, //!< A pet inventory item + ITEM_TYPE_PACKAGE = 20, //!< A package + ITEM_TYPE_LOOT_MODEL = 21, //!< A loot model + ITEM_TYPE_VEHICLE = 22, //!< A vehicle + ITEM_TYPE_CURRENCY = 23, //!< Currency + ITEM_TYPE_MOUNT = 24 //!< A Mount +}; + +#endif //!__EITEMTYPE__H__ \ No newline at end of file diff --git a/dDatabase/CDClientDatabase.cpp b/dDatabase/CDClientDatabase.cpp index d61d6fe7..d09b2daa 100644 --- a/dDatabase/CDClientDatabase.cpp +++ b/dDatabase/CDClientDatabase.cpp @@ -13,3 +13,8 @@ void CDClientDatabase::Connect(const std::string& filename) { CppSQLite3Query CDClientDatabase::ExecuteQuery(const std::string& query) { return conn->execQuery(query.c_str()); } + +//! Makes prepared statements +CppSQLite3Statement CDClientDatabase::CreatePreppedStmt(const std::string& query) { + return conn->compileStatement(query.c_str()); +} diff --git a/dDatabase/CDClientDatabase.h b/dDatabase/CDClientDatabase.h index fbb1dc86..91e9ee10 100644 --- a/dDatabase/CDClientDatabase.h +++ b/dDatabase/CDClientDatabase.h @@ -40,4 +40,10 @@ namespace CDClientDatabase { */ CppSQLite3Query ExecuteQuery(const std::string& query); + //! Queries the CDClient and parses arguments + /*! + \param query The query with formatted arguments + \return prepared SQLite Statement + */ + CppSQLite3Statement CreatePreppedStmt(const std::string& query); }; diff --git a/dDatabase/CDClientManager.cpp b/dDatabase/CDClientManager.cpp index 7ad852bc..75ada1ea 100644 --- a/dDatabase/CDClientManager.cpp +++ b/dDatabase/CDClientManager.cpp @@ -8,7 +8,7 @@ void CDClientManager::Initialize(void) { tables.insert(std::make_pair("ActivityRewards", new CDActivityRewardsTable())); UNUSED(tables.insert(std::make_pair("Animations", new CDAnimationsTable()))); tables.insert(std::make_pair("BehaviorParameter", new CDBehaviorParameterTable())); - UNUSED(tables.insert(std::make_pair("BehaviorTemplate", new CDBehaviorTemplateTable()))); + tables.insert(std::make_pair("BehaviorTemplate", new CDBehaviorTemplateTable())); tables.insert(std::make_pair("ComponentsRegistry", new CDComponentsRegistryTable())); tables.insert(std::make_pair("CurrencyTable", new CDCurrencyTableTable())); tables.insert(std::make_pair("DestructibleComponent", new CDDestructibleComponentTable())); diff --git a/dDatabase/CMakeLists.txt b/dDatabase/CMakeLists.txt new file mode 100644 index 00000000..9e55fbe2 --- /dev/null +++ b/dDatabase/CMakeLists.txt @@ -0,0 +1,13 @@ +set(DDATABASE_SOURCES "CDClientDatabase.cpp" + "CDClientManager.cpp" + "Database.cpp" + "MigrationRunner.cpp") + +add_subdirectory(Tables) + +foreach(file ${DDATABASE_TABLES_SOURCES}) + set(DDATABASE_SOURCES ${DDATABASE_SOURCES} "Tables/${file}") +endforeach() + +add_library(dDatabase STATIC ${DDATABASE_SOURCES}) +target_link_libraries(dDatabase sqlite3 mariadbConnCpp) diff --git a/dDatabase/Database.cpp b/dDatabase/Database.cpp index 7ba138cf..26a45359 100644 --- a/dDatabase/Database.cpp +++ b/dDatabase/Database.cpp @@ -8,9 +8,10 @@ using namespace std; sql::Driver * Database::driver; sql::Connection * Database::con; +sql::Properties Database::props; +std::string Database::database; void Database::Connect(const string& host, const string& database, const string& username, const string& password) { - driver = get_driver_instance(); //To bypass debug issues: std::string newHost = "tcp://" + host; @@ -19,17 +20,33 @@ void Database::Connect(const string& host, const string& database, const string& const char* szUsername = username.c_str(); const char* szPassword = password.c_str(); - con = driver->connect(szHost, szUsername, szPassword); - con->setSchema(szDatabase); + driver = sql::mariadb::get_driver_instance(); - bool myTrue = true; - con->setClientOption("MYSQL_OPT_RECONNECT", &myTrue); -} //Connect + sql::Properties properties; + properties["hostName"] = szHost; + properties["user"] = szUsername; + properties["password"] = szPassword; + properties["autoReconnect"] = "true"; -void Database::Destroy(std::string source) { + Database::props = properties; + Database::database = database; + + Database::Connect(); +} + +void Database::Connect() { + con = driver->connect(Database::props); + con->setSchema(Database::database); +} + +void Database::Destroy(std::string source, bool log) { if (!con) return; - if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!\n", source.c_str()); - else Game::logger->Log("Database", "Destroying MySQL connection!\n"); + + if (log) { + if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!\n", source.c_str()); + else Game::logger->Log("Database", "Destroying MySQL connection!\n"); + } + con->close(); delete con; } //Destroy @@ -45,13 +62,7 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) { sql::SQLString str(test, size); if (!con) { - //Connect to the MySQL Database - std::string mysql_host = Game::config->GetValue("mysql_host"); - std::string mysql_database = Game::config->GetValue("mysql_database"); - std::string mysql_username = Game::config->GetValue("mysql_username"); - std::string mysql_password = Game::config->GetValue("mysql_password"); - - Connect(mysql_host, mysql_database, mysql_username, mysql_password); + Connect(); Game::logger->Log("Database", "Trying to reconnect to MySQL\n"); } @@ -61,17 +72,15 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) { con = nullptr; - //Connect to the MySQL Database - std::string mysql_host = Game::config->GetValue("mysql_host"); - std::string mysql_database = Game::config->GetValue("mysql_database"); - std::string mysql_username = Game::config->GetValue("mysql_username"); - std::string mysql_password = Game::config->GetValue("mysql_password"); - - Connect(mysql_host, mysql_database, mysql_username, mysql_password); + Connect(); Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection\n"); } auto* stmt = con->prepareStatement(str); return stmt; -} //CreatePreppedStmt \ No newline at end of file +} //CreatePreppedStmt + +void Database::Commit() { + Database::con->commit(); +} \ No newline at end of file diff --git a/dDatabase/Database.h b/dDatabase/Database.h index 6e458065..ece62a95 100644 --- a/dDatabase/Database.h +++ b/dDatabase/Database.h @@ -1,13 +1,7 @@ #pragma once #include -#include -#include -#include -#include -#include -#include -#include +#include class MySqlException : public std::runtime_error { public: @@ -19,10 +13,17 @@ class Database { private: static sql::Driver *driver; static sql::Connection *con; - + static sql::Properties props; + static std::string database; public: static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password); - static void Destroy(std::string source=""); + static void Connect(); + static void Destroy(std::string source = "", bool log = true); + static sql::Statement* CreateStmt(); static sql::PreparedStatement* CreatePreppedStmt(const std::string& query); + static void Commit(); + + static std::string GetDatabase() { return database; } + static sql::Properties GetProperties() { return props; } }; diff --git a/dDatabase/MigrationRunner.cpp b/dDatabase/MigrationRunner.cpp new file mode 100644 index 00000000..a058b85e --- /dev/null +++ b/dDatabase/MigrationRunner.cpp @@ -0,0 +1,78 @@ +#include "MigrationRunner.h" + +#include "GeneralUtils.h" + +#include +#include +#include + +void MigrationRunner::RunMigrations() { + auto stmt = Database::CreatePreppedStmt("CREATE TABLE IF NOT EXISTS migration_history (name TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP());"); + stmt->executeQuery(); + delete stmt; + + sql::SQLString finalSQL = ""; + Migration checkMigration{}; + + for (const auto& entry : GeneralUtils::GetFileNamesFromFolder("./migrations/")) { + auto migration = LoadMigration(entry); + + if (migration.data.empty()) { + continue; + } + + checkMigration = migration; + + stmt = Database::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;"); + stmt->setString(1, migration.name); + auto res = stmt->executeQuery(); + bool doExit = res->next(); + delete res; + delete stmt; + if (doExit) continue; + + Game::logger->Log("MigrationRunner", "Running migration: " + migration.name + "\n"); + + finalSQL.append(migration.data); + finalSQL.append('\n'); + + stmt = Database::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);"); + stmt->setString(1, entry); + stmt->execute(); + delete stmt; + } + + if (!finalSQL.empty()) { + try { + auto simpleStatement = Database::CreateStmt(); + simpleStatement->execute(finalSQL); + delete simpleStatement; + } + catch (sql::SQLException e) { + Game::logger->Log("MigrationRunner", std::string("Encountered error running migration: ") + e.what() + "\n"); + } + } +} + +Migration MigrationRunner::LoadMigration(std::string path) { + Migration migration{}; + std::ifstream file("./migrations/" + path); + + if (file.is_open()) { + std::hash hash; + + std::string line; + std::string total = ""; + + while (std::getline(file, line)) { + total += line; + } + + file.close(); + + migration.name = path; + migration.data = total; + } + + return migration; +} diff --git a/dDatabase/MigrationRunner.h b/dDatabase/MigrationRunner.h new file mode 100644 index 00000000..343b252d --- /dev/null +++ b/dDatabase/MigrationRunner.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Database.h" + +#include "dCommonVars.h" +#include "Game.h" +#include "dCommonVars.h" +#include "dLogger.h" + +struct Migration { + std::string data; + std::string name; +}; + +class MigrationRunner { +public: + static void RunMigrations(); + static Migration LoadMigration(std::string path); +}; \ No newline at end of file diff --git a/dDatabase/Tables/CDBehaviorParameterTable.cpp b/dDatabase/Tables/CDBehaviorParameterTable.cpp index ef267425..05f39016 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.cpp +++ b/dDatabase/Tables/CDBehaviorParameterTable.cpp @@ -3,33 +3,31 @@ //! Constructor CDBehaviorParameterTable::CDBehaviorParameterTable(void) { -#ifdef CDCLIENT_CACHE_ALL - auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); - while (!tableData.eof()) { - CDBehaviorParameter entry; - entry.behaviorID = tableData.getIntField(0, -1); - entry.parameterID = tableData.getStringField(1, ""); - entry.value = tableData.getFloatField(2, -1.0f); - - //Check if we have an entry with this ID: - auto it = m_entries.find(entry.behaviorID); - if (it != m_entries.end()) { - it->second.insert(std::make_pair(entry.parameterID, entry.value)); + auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter"); + size_t hash = 0; + while (!tableData.eof()) { + hash = 0; + CDBehaviorParameter entry; + entry.behaviorID = tableData.getIntField(0, -1); + auto candidateStringToAdd = std::string(tableData.getStringField(1, "")); + auto parameter = m_ParametersList.find(candidateStringToAdd); + if (parameter != m_ParametersList.end()) { + entry.parameterID = parameter; + } else { + entry.parameterID = m_ParametersList.insert(candidateStringToAdd).first; } - else { - //Otherwise, insert it: - m_entries.insert(std::make_pair(entry.behaviorID, std::map())); - auto jit = m_entries.find(entry.behaviorID); + entry.value = tableData.getFloatField(2, -1.0f); - //Add our value as well: - jit->second.insert(std::make_pair(entry.parameterID, entry.value)); - } + GeneralUtils::hash_combine(hash, entry.behaviorID); + GeneralUtils::hash_combine(hash, *entry.parameterID); - tableData.nextRow(); - } + auto it = m_Entries.find(entry.behaviorID); + m_ParametersList.insert(*entry.parameterID); + m_Entries.insert(std::make_pair(hash, entry)); + tableData.nextRow(); + } tableData.finalize(); -#endif } //! Destructor @@ -37,54 +35,36 @@ CDBehaviorParameterTable::~CDBehaviorParameterTable(void) { } //! Returns the table's name std::string CDBehaviorParameterTable::GetName(void) const { - return "BehaviorParameter"; + return "BehaviorParameter"; } -float CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) +CDBehaviorParameter CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue) { + CDBehaviorParameter returnValue; + returnValue.behaviorID = 0; + returnValue.parameterID = m_ParametersList.end(); + returnValue.value = defaultValue; + size_t hash = 0; GeneralUtils::hash_combine(hash, behaviorID); GeneralUtils::hash_combine(hash, name); // Search for specific parameter const auto& it = m_Entries.find(hash); - if (it != m_Entries.end()) { - return it->second; - } - - // Check if this behavior has already been checked - const auto& itChecked = m_Entries.find(behaviorID); - if (itChecked != m_Entries.end()) { - return defaultValue; - } - -#ifndef CDCLIENT_CACHE_ALL - std::stringstream query; - - query << "SELECT parameterID, value FROM BehaviorParameter WHERE behaviorID = " << std::to_string(behaviorID); - - auto tableData = CDClientDatabase::ExecuteQuery(query.str()); - - m_Entries.insert_or_assign(behaviorID, 0); - - while (!tableData.eof()) { - const std::string parameterID = tableData.getStringField(0, ""); - const float value = tableData.getFloatField(1, 0); - - size_t parameterHash = 0; - GeneralUtils::hash_combine(parameterHash, behaviorID); - GeneralUtils::hash_combine(parameterHash, parameterID); - - m_Entries.insert_or_assign(parameterHash, value); - - tableData.nextRow(); - } - - const auto& it2 = m_Entries.find(hash); - if (it2 != m_Entries.end()) { - return it2->second; - } -#endif - - return defaultValue; + return it != m_Entries.end() ? it->second : returnValue; +} + +std::map CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) { + size_t hash; + std::map returnInfo; + for (auto parameterCandidate : m_ParametersList) { + hash = 0; + GeneralUtils::hash_combine(hash, behaviorID); + GeneralUtils::hash_combine(hash, parameterCandidate); + auto infoCandidate = m_Entries.find(hash); + if (infoCandidate != m_Entries.end()) { + returnInfo.insert(std::make_pair(*(infoCandidate->second.parameterID), infoCandidate->second.value)); + } + } + return returnInfo; } diff --git a/dDatabase/Tables/CDBehaviorParameterTable.h b/dDatabase/Tables/CDBehaviorParameterTable.h index 3d14d66d..c45d287b 100644 --- a/dDatabase/Tables/CDBehaviorParameterTable.h +++ b/dDatabase/Tables/CDBehaviorParameterTable.h @@ -2,7 +2,8 @@ // Custom Classes #include "CDTable.h" -#include +#include +#include /*! \file CDBehaviorParameterTable.hpp @@ -11,16 +12,16 @@ //! BehaviorParameter Entry Struct struct CDBehaviorParameter { - unsigned int behaviorID; //!< The Behavior ID - std::string parameterID; //!< The Parameter ID - float value; //!< The value of the behavior template + unsigned int behaviorID; //!< The Behavior ID + std::unordered_set::iterator parameterID; //!< The Parameter ID + float value; //!< The value of the behavior template }; //! BehaviorParameter table class CDBehaviorParameterTable : public CDTable { private: - std::map m_Entries; - + std::unordered_map m_Entries; + std::unordered_set m_ParametersList; public: //! Constructor @@ -35,5 +36,7 @@ public: */ std::string GetName(void) const override; - float GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); + CDBehaviorParameter GetEntry(const uint32_t behaviorID, const std::string& name, const float defaultValue = 0); + + std::map GetParametersByBehaviorID(uint32_t behaviorID); }; diff --git a/dDatabase/Tables/CDBehaviorTemplateTable.cpp b/dDatabase/Tables/CDBehaviorTemplateTable.cpp index f9830317..b832400d 100644 --- a/dDatabase/Tables/CDBehaviorTemplateTable.cpp +++ b/dDatabase/Tables/CDBehaviorTemplateTable.cpp @@ -16,7 +16,7 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) { // Reserve the size this->entries.reserve(size); - + // Now get the data auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate"); while (!tableData.eof()) { @@ -24,9 +24,16 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) { entry.behaviorID = tableData.getIntField(0, -1); entry.templateID = tableData.getIntField(1, -1); entry.effectID = tableData.getIntField(2, -1); - entry.effectHandle = tableData.getStringField(3, ""); + auto candidateToAdd = tableData.getStringField(3, ""); + auto parameter = m_EffectHandles.find(candidateToAdd); + if (parameter != m_EffectHandles.end()) { + entry.effectHandle = parameter; + } else { + entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first; + } this->entries.push_back(entry); + this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry)); tableData.nextRow(); } @@ -55,3 +62,16 @@ std::vector CDBehaviorTemplateTable::Query(std::function CDBehaviorTemplateTable::GetEntries(void) const { return this->entries; } + +const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) { + auto entry = this->entriesMappedByBehaviorID.find(behaviorID); + if (entry == this->entriesMappedByBehaviorID.end()) { + CDBehaviorTemplate entryToReturn; + entryToReturn.behaviorID = 0; + entryToReturn.effectHandle = m_EffectHandles.end(); + entryToReturn.effectID = 0; + return entryToReturn; + } else { + return entry->second; + } +} diff --git a/dDatabase/Tables/CDBehaviorTemplateTable.h b/dDatabase/Tables/CDBehaviorTemplateTable.h index a63c2160..170da854 100644 --- a/dDatabase/Tables/CDBehaviorTemplateTable.h +++ b/dDatabase/Tables/CDBehaviorTemplateTable.h @@ -2,6 +2,8 @@ // Custom Classes #include "CDTable.h" +#include +#include /*! \file CDBehaviorTemplateTable.hpp @@ -10,10 +12,10 @@ //! BehaviorTemplate Entry Struct struct CDBehaviorTemplate { - unsigned int behaviorID; //!< The Behavior ID - unsigned int templateID; //!< The Template ID (LOT) - unsigned int effectID; //!< The Effect ID attached - std::string effectHandle; //!< The effect handle + unsigned int behaviorID; //!< The Behavior ID + unsigned int templateID; //!< The Template ID (LOT) + unsigned int effectID; //!< The Effect ID attached + std::unordered_set::iterator effectHandle; //!< The effect handle }; @@ -21,7 +23,8 @@ struct CDBehaviorTemplate { class CDBehaviorTemplateTable : public CDTable { private: std::vector entries; - + std::unordered_map entriesMappedByBehaviorID; + std::unordered_set m_EffectHandles; public: //! Constructor @@ -47,5 +50,6 @@ public: \return The entries */ std::vector GetEntries(void) const; - + + const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID); }; diff --git a/dDatabase/Tables/CDItemComponentTable.cpp b/dDatabase/Tables/CDItemComponentTable.cpp index 149b2ce8..698f72a4 100644 --- a/dDatabase/Tables/CDItemComponentTable.cpp +++ b/dDatabase/Tables/CDItemComponentTable.cpp @@ -168,7 +168,7 @@ std::map CDItemComponentTable::ParseCraftingCurrencies(const CDIt // Checking for 2 here, not sure what to do when there's more stuff than expected if (amountSplit.size() == 2) { currencies.insert({ - std::stol(amountSplit[0]), + std::stoull(amountSplit[0]), std::stoi(amountSplit[1]) }); } diff --git a/dDatabase/Tables/CMakeLists.txt b/dDatabase/Tables/CMakeLists.txt new file mode 100644 index 00000000..b6a02b02 --- /dev/null +++ b/dDatabase/Tables/CMakeLists.txt @@ -0,0 +1,38 @@ +set(DDATABASE_TABLES_SOURCES "CDActivitiesTable.cpp" + "CDActivityRewardsTable.cpp" + "CDAnimationsTable.cpp" + "CDBehaviorParameterTable.cpp" + "CDBehaviorTemplateTable.cpp" + "CDBrickIDTableTable.cpp" + "CDComponentsRegistryTable.cpp" + "CDCurrencyTableTable.cpp" + "CDDestructibleComponentTable.cpp" + "CDEmoteTable.cpp" + "CDFeatureGatingTable.cpp" + "CDInventoryComponentTable.cpp" + "CDItemComponentTable.cpp" + "CDItemSetSkillsTable.cpp" + "CDItemSetsTable.cpp" + "CDLevelProgressionLookupTable.cpp" + "CDLootMatrixTable.cpp" + "CDLootTableTable.cpp" + "CDMissionEmailTable.cpp" + "CDMissionNPCComponentTable.cpp" + "CDMissionsTable.cpp" + "CDMissionTasksTable.cpp" + "CDMovementAIComponentTable.cpp" + "CDObjectSkillsTable.cpp" + "CDObjectsTable.cpp" + "CDPackageComponentTable.cpp" + "CDPhysicsComponentTable.cpp" + "CDPropertyEntranceComponentTable.cpp" + "CDPropertyTemplateTable.cpp" + "CDProximityMonitorComponentTable.cpp" + "CDRailActivatorComponent.cpp" + "CDRarityTableTable.cpp" + "CDRebuildComponentTable.cpp" + "CDRewardsTable.cpp" + "CDScriptComponentTable.cpp" + "CDSkillBehaviorTable.cpp" + "CDVendorComponentTable.cpp" + "CDZoneTableTable.cpp" PARENT_SCOPE) diff --git a/dGame/CMakeLists.txt b/dGame/CMakeLists.txt new file mode 100644 index 00000000..5acdba31 --- /dev/null +++ b/dGame/CMakeLists.txt @@ -0,0 +1,59 @@ +set(DGAME_SOURCES "Character.cpp" + "Entity.cpp" + "EntityManager.cpp" + "LeaderboardManager.cpp" + "Player.cpp" + "TeamManager.cpp" + "TradingManager.cpp" + "User.cpp" + "UserManager.cpp") + +add_subdirectory(dBehaviors) + +foreach(file ${DGAME_DBEHAVIORS_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dBehaviors/${file}") +endforeach() + +add_subdirectory(dComponents) + +foreach(file ${DGAME_DCOMPONENTS_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dComponents/${file}") +endforeach() + +add_subdirectory(dEntity) + +foreach(file ${DGAME_DENTITY_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dEntity/${file}") +endforeach() + +add_subdirectory(dGameMessages) + +foreach(file ${DGAME_DGAMEMESSAGES_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dGameMessages/${file}") +endforeach() + +add_subdirectory(dInventory) + +foreach(file ${DGAME_DINVENTORY_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dInventory/${file}") +endforeach() + +add_subdirectory(dMission) + +foreach(file ${DGAME_DMISSION_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dMission/${file}") +endforeach() + +add_subdirectory(dUtilities) + +foreach(file ${DGAME_DUTILITIES_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "dUtilities/${file}") +endforeach() + +foreach(file ${DSCRIPT_SOURCES}) + set(DGAME_SOURCES ${DGAME_SOURCES} "${PROJECT_SOURCE_DIR}/dScripts/${file}") +endforeach() + +add_library(dGame STATIC ${DGAME_SOURCES}) + +target_link_libraries(dGame dDatabase) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 132a0eb7..a063b3c6 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -79,6 +79,7 @@ Entity::Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity) m_Components = {}; m_DieCallbacks = {}; m_PhantomCollisionCallbacks = {}; + m_IsParentChildDirty = true; m_Settings = info.settings; m_NetworkSettings = info.networkSettings; @@ -98,22 +99,6 @@ Entity::~Entity() { m_Character->SaveXMLToDatabase(); } - if (IsPlayer()) { - Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); - for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerExit(zoneControl, this); - } - - std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_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); - } - } - } - } - CancelAllTimers(); CancelCallbackTimers(); @@ -124,6 +109,14 @@ Entity::~Entity() { m_Components.erase(pair.first); } + + for (auto child : m_ChildEntities) { + if (child) child->RemoveParent(); + } + + if (m_ParentEntity) { + m_ParentEntity->RemoveChild(this); + } } void Entity::Initialize() @@ -220,8 +213,9 @@ void Entity::Initialize() m_Components.insert(std::make_pair(COMPONENT_TYPE_ZONE_CONTROL, nullptr)); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_POSSESSABLE) > 0) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSABLE, new PossessableComponent(this))); + uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_POSSESSABLE); + if (possessableComponentId > 0) { + m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSABLE, new PossessableComponent(this, possessableComponentId))); } if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MODULE_ASSEMBLY) > 0) { @@ -447,6 +441,8 @@ void Entity::Initialize() }*/ if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_CHARACTER) > 0 || m_Character) { + // Character Component always has a possessor component + m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSOR, new PossessorComponent(this))); CharacterComponent* comp = new CharacterComponent(this, m_Character); m_Components.insert(std::make_pair(COMPONENT_TYPE_CHARACTER, comp)); } @@ -561,19 +557,6 @@ void Entity::Initialize() comp->SetPostImaginationCost(rebCompData[0].post_imagination_cost); comp->SetTimeBeforeSmash(rebCompData[0].time_before_smash); - const auto rebuildActivatorValue = GetVarAsString(u"rebuild_activators"); - - if (!rebuildActivatorValue.empty()) { - std::vector split = GeneralUtils::SplitString(rebuildActivatorValue, 0x1f); - NiPoint3 pos; - - pos.x = std::stof(split[0]); - pos.y = std::stof(split[1]); - pos.z = std::stof(split[2]); - - comp->SetActivatorPosition(pos); - } - const auto rebuildResetTime = GetVar(u"rebuild_reset_time"); if (rebuildResetTime != 0.0f) { @@ -631,10 +614,6 @@ void Entity::Initialize() m_Components.insert(std::make_pair(COMPONENT_TYPE_RENDER, render)); } - if ((compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_POSSESSOR) > 0) || m_Character) { - m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSOR, new PossessorComponent(this))); - } - if ((compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_MISSION_OFFER) > 0) || m_Character) { m_Components.insert(std::make_pair(COMPONENT_TYPE_MISSION_OFFER, new MissionOfferComponent(this, m_TemplateID))); } @@ -974,8 +953,11 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke } else outBitStream->Write0(); //No GM Level } - outBitStream->Write((m_ParentEntity != nullptr || m_ChildEntities.size() > 0)); - if (m_ParentEntity || m_ChildEntities.size() > 0) { + + // 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 == PACKET_TYPE_CONSTRUCTION); + if (m_IsParentChildDirty || packetType == PACKET_TYPE_CONSTRUCTION) { + m_IsParentChildDirty = false; outBitStream->Write(m_ParentEntity != nullptr); if (m_ParentEntity) { outBitStream->Write(m_ParentEntity->GetObjectID()); @@ -1079,8 +1061,15 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType } CharacterComponent* characterComponent; - if (TryGetComponent(COMPONENT_TYPE_CHARACTER, characterComponent)) - { + if (TryGetComponent(COMPONENT_TYPE_CHARACTER, characterComponent)) { + + PossessorComponent* possessorComponent; + if (TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) { + possessorComponent->Serialize(outBitStream, bIsInitialUpdate, flags); + } else { + // Should never happen, but just to be safe + outBitStream->Write0(); + } characterComponent->Serialize(outBitStream, bIsInitialUpdate, flags); } @@ -1186,11 +1175,10 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType outBitStream->Write(0x40000000); } - PossessorComponent* possessorComponent; - if (TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) - { - possessorComponent->Serialize(outBitStream, bIsInitialUpdate, flags); - } + // BBB Component, unused currently + // Need to to write0 so that is serlaizese correctly + // TODO: Implement BBB Component + outBitStream->Write0(); /* if (m_Trigger != nullptr) @@ -1218,17 +1206,21 @@ void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) { } void Entity::Update(const float deltaTime) { - for (int i = 0; i < m_Timers.size(); i++) { - m_Timers[i]->Update(deltaTime); - if (m_Timers[i]->GetTime() <= 0) { - const auto timerName = m_Timers[i]->GetName(); + uint32_t timerPosition; + timerPosition = 0; + while (timerPosition < m_Timers.size()) { + m_Timers[timerPosition]->Update(deltaTime); + if (m_Timers[timerPosition]->GetTime() <= 0) { + const auto timerName = m_Timers[timerPosition]->GetName(); - delete m_Timers[i]; - m_Timers.erase(m_Timers.begin() + i); + delete m_Timers[timerPosition]; + m_Timers.erase(m_Timers.begin() + timerPosition); for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { script->OnTimerDone(this, timerName); } + } else { + timerPosition++; } } @@ -1240,6 +1232,14 @@ void Entity::Update(const float deltaTime) { m_CallbackTimers.erase(m_CallbackTimers.begin() + i); } } + + // Add pending timers to the list of timers so they start next tick. + if (m_PendingTimers.size() > 0) { + for (auto namedTimer : m_PendingTimers) { + m_Timers.push_back(namedTimer); + } + m_PendingTimers.clear(); + } if (IsSleeping()) { @@ -1661,12 +1661,30 @@ void Entity::RegisterCoinDrop(uint64_t count) { } void Entity::AddChild(Entity* child) { + m_IsParentChildDirty = true; m_ChildEntities.push_back(child); } +void Entity::RemoveChild(Entity* child) { + if (!child) return; + uint32_t entityPosition = 0; + while (entityPosition < m_ChildEntities.size()) { + if (!m_ChildEntities[entityPosition] || (m_ChildEntities[entityPosition])->GetObjectID() == child->GetObjectID()) { + m_IsParentChildDirty = true; + m_ChildEntities.erase(m_ChildEntities.begin() + entityPosition); + } else { + entityPosition++; + } + } +} + +void Entity::RemoveParent() { + this->m_ParentEntity = nullptr; +} + void Entity::AddTimer(std::string name, float time) { EntityTimer* timer = new EntityTimer(name, time); - m_Timers.push_back(timer); + m_PendingTimers.push_back(timer); } void Entity::AddCallbackTimer(float time, std::function callback) { diff --git a/dGame/Entity.h b/dGame/Entity.h index cef7b97f..85f992e8 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -143,6 +143,8 @@ public: void SetProximityRadius(dpEntity* entity, std::string name); void AddChild(Entity* child); + void RemoveChild(Entity* child); + void RemoveParent(); void AddTimer(std::string name, float time); void AddCallbackTimer(float time, std::function callback); bool HasTimer(const std::string& name); @@ -308,6 +310,7 @@ protected: std::unordered_map m_Components; //The int is the ID of the component std::vector m_Timers; + std::vector m_PendingTimers; std::vector m_CallbackTimers; bool m_ShouldDestroyAfterUpdate = false; @@ -322,6 +325,8 @@ protected: int8_t m_Observers = 0; + bool m_IsParentChildDirty = true; + /* * Collision */ diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index aacb2bc8..da0cf685 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -217,37 +217,42 @@ void EntityManager::UpdateEntities(const float deltaTime) { m_EntitiesToKill.clear(); - for (const auto& entry : m_EntitiesToDelete) + for (const auto entry : m_EntitiesToDelete) { - auto* entity = GetEntity(entry); + // Get all this info first before we delete the player. + auto entityToDelete = GetEntity(entry); - m_Entities.erase(entry); + auto networkIdToErase = entityToDelete->GetNetworkId(); - const auto& iter = std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entity); + const auto& ghostingToDelete = std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entityToDelete); - if (iter != m_EntitiesToGhost.end()) + if (entityToDelete) { - m_EntitiesToGhost.erase(iter); - } - - if (entity != nullptr) - { - if (entity->GetNetworkId() != 0) + // If we are a player run through the player destructor. + if (entityToDelete->IsPlayer()) { - m_LostNetworkIds.push(entity->GetNetworkId()); - } - - if (entity->IsPlayer()) - { - delete dynamic_cast(entity); + delete dynamic_cast(entityToDelete); } else { - delete entity; + delete entityToDelete; } - entity = nullptr; + entityToDelete = nullptr; + + if (networkIdToErase != 0) + { + m_LostNetworkIds.push(networkIdToErase); + } } + + if (ghostingToDelete != m_EntitiesToGhost.end()) + { + m_EntitiesToGhost.erase(ghostingToDelete); + } + + m_Entities.erase(entry); + } m_EntitiesToDelete.clear(); @@ -396,7 +401,7 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr Game::server->Send(&stream, sysAddr, false); } - PacketUtils::SavePacket("[24]_"+std::to_string(entity->GetObjectID()) + "_" + std::to_string(m_SerializationCounter) + ".bin", (char*)stream.GetData(), stream.GetNumberOfBytesUsed()); + // PacketUtils::SavePacket("[24]_"+std::to_string(entity->GetObjectID()) + "_" + std::to_string(m_SerializationCounter) + ".bin", (char*)stream.GetData(), stream.GetNumberOfBytesUsed()); if (entity->IsPlayer()) { diff --git a/dGame/LeaderboardManager.cpp b/dGame/LeaderboardManager.cpp index 0efe9c77..793d402c 100644 --- a/dGame/LeaderboardManager.cpp +++ b/dGame/LeaderboardManager.cpp @@ -3,8 +3,10 @@ #include "Database.h" #include "EntityManager.h" #include "Character.h" +#include "Game.h" #include "GameMessages.h" #include "dLogger.h" +#include "dConfig.h" Leaderboard::Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector entries, LWOOBJID relatedPlayer, LeaderboardType leaderboardType) { @@ -90,6 +92,7 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t const auto storedTime = result->getInt(1); const auto storedScore = result->getInt(2); auto highscore = true; + bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1"; switch (leaderboardType) { case ShootingGallery: @@ -97,8 +100,11 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t highscore = false; break; case Racing: + if (time >= storedTime) + highscore = false; + break; case MonumentRace: - if (time > storedTime) + if (time >= storedTime) highscore = false; break; case FootRace: @@ -106,8 +112,18 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t highscore = false; break; case Survival: + if (classicSurvivalScoring) { + if (time <= storedTime) { // Based on time (LU live) + highscore = false; + } + } + else { + if (score <= storedScore) // Based on score (DLU) + highscore = false; + } + break; case SurvivalNS: - if (score < storedScore || time >= storedTime) + if (!(score > storedScore || (time < storedTime && score >= storedScore))) highscore = false; break; default: @@ -125,7 +141,7 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t delete result; if (any) { - auto* statement = Database::CreatePreppedStmt("UPDATE leaderboard SET time = ?, score = ? WHERE character_id = ? AND game_id = ?"); + auto* statement = Database::CreatePreppedStmt("UPDATE leaderboard SET time = ?, score = ?, last_played=SYSDATE() WHERE character_id = ? AND game_id = ?;"); statement->setInt(1, time); statement->setInt(2, score); statement->setUInt64(3, character->GetID()); @@ -134,6 +150,7 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t delete statement; } else { + // Note: last_played will be set to SYSDATE() by default when inserting into leaderboard auto* statement = Database::CreatePreppedStmt("INSERT INTO leaderboard (character_id, game_id, time, score) VALUES (?, ?, ?, ?);"); statement->setUInt64(1, character->GetID()); statement->setInt(2, gameID); @@ -149,15 +166,62 @@ Leaderboard *LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoTy auto leaderboardType = GetLeaderboardType(gameID); std::string query; + bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1"; switch (infoType) { case InfoType::Standings: - query = leaderboardType == MonumentRace ? standingsQueryAsc : standingsQuery; + switch (leaderboardType) { + case ShootingGallery: + query = standingsScoreQuery; // Shooting gallery is based on the highest score. + break; + case FootRace: + query = standingsTimeQuery; // The higher your time, the better for FootRace. + break; + case Survival: + query = classicSurvivalScoring ? standingsTimeQuery : standingsScoreQuery; + break; + case SurvivalNS: + query = standingsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. + break; + default: + query = standingsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. + } break; case InfoType::Friends: - query = leaderboardType == MonumentRace ? friendsQueryAsc : friendsQuery; + switch (leaderboardType) { + case ShootingGallery: + query = friendsScoreQuery; // Shooting gallery is based on the highest score. + break; + case FootRace: + query = friendsTimeQuery; // The higher your time, the better for FootRace. + break; + case Survival: + query = classicSurvivalScoring ? friendsTimeQuery : friendsScoreQuery; + break; + case SurvivalNS: + query = friendsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. + break; + default: + query = friendsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. + } break; + default: - query = leaderboardType == MonumentRace ? topPlayersQueryAsc : topPlayersQuery; + switch (leaderboardType) { + case ShootingGallery: + query = topPlayersScoreQuery; // Shooting gallery is based on the highest score. + break; + case FootRace: + query = topPlayersTimeQuery; // The higher your time, the better for FootRace. + break; + case Survival: + query = classicSurvivalScoring ? topPlayersTimeQuery : topPlayersScoreQuery; + break; + case SurvivalNS: + query = topPlayersScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time. + break; + default: + query = topPlayersTimeQueryAsc; // MonumentRace and Racing are based on the shortest time. + } } auto* statement = Database::CreatePreppedStmt(query); @@ -183,14 +247,15 @@ Leaderboard *LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoTy uint32_t index = 0; while (res->next()) { - entries.push_back({ - res->getUInt64(4), - res->getString(5), - res->getUInt(1), - res->getUInt(2), - res->getUInt(3), - res->getUInt(6) - }); + LeaderboardEntry entry; + entry.playerID = res->getUInt64(4); + entry.playerName = res->getString(5); + entry.time = res->getUInt(1); + entry.score = res->getUInt(2); + entry.placement = res->getUInt(3); + entry.lastPlayed = res->getUInt(6); + + entries.push_back(entry); index++; } @@ -220,7 +285,7 @@ LeaderboardType LeaderboardManager::GetLeaderboardType(uint32_t gameID) { return LeaderboardType::None; } -const std::string LeaderboardManager::topPlayersQuery = +const std::string LeaderboardManager::topPlayersScoreQuery = "WITH leaderboard_vales AS ( " " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " "RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " @@ -231,7 +296,7 @@ const std::string LeaderboardManager::topPlayersQuery = "SELECT time, score, leaderboard_rank, id, name, last_played " "FROM leaderboard_vales LIMIT 11;"; -const std::string LeaderboardManager::friendsQuery = +const std::string LeaderboardManager::friendsScoreQuery = "WITH leaderboard_vales AS ( " " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, " " RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " @@ -249,7 +314,7 @@ const std::string LeaderboardManager::friendsQuery = "FROM leaderboard_vales, personal_values " "WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);"; -const std::string LeaderboardManager::standingsQuery = +const std::string LeaderboardManager::standingsScoreQuery = "WITH leaderboard_vales AS ( " " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " " RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank " @@ -265,7 +330,7 @@ const std::string LeaderboardManager::standingsQuery = "FROM leaderboard_vales, personal_values " "WHERE leaderboard_rank BETWEEN min_rank AND max_rank;"; -const std::string LeaderboardManager::topPlayersQueryAsc = +const std::string LeaderboardManager::topPlayersScoreQueryAsc = "WITH leaderboard_vales AS ( " " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " "RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " @@ -276,7 +341,7 @@ const std::string LeaderboardManager::topPlayersQueryAsc = "SELECT time, score, leaderboard_rank, id, name, last_played " "FROM leaderboard_vales LIMIT 11;"; -const std::string LeaderboardManager::friendsQueryAsc = +const std::string LeaderboardManager::friendsScoreQueryAsc = "WITH leaderboard_vales AS ( " " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, " " RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " @@ -294,7 +359,7 @@ const std::string LeaderboardManager::friendsQueryAsc = "FROM leaderboard_vales, personal_values " "WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);"; -const std::string LeaderboardManager::standingsQueryAsc = +const std::string LeaderboardManager::standingsScoreQueryAsc = "WITH leaderboard_vales AS ( " " SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " " RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank " @@ -309,3 +374,93 @@ const std::string LeaderboardManager::standingsQueryAsc = "SELECT time, score, leaderboard_rank, id, name, last_played " "FROM leaderboard_vales, personal_values " "WHERE leaderboard_rank BETWEEN min_rank AND max_rank;"; + +const std::string LeaderboardManager::topPlayersTimeQuery = +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " +"RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +"INNER JOIN charinfo c ON l.character_id = c.id " +"WHERE l.game_id = ? " +"ORDER BY leaderboard_rank) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales LIMIT 11;"; + +const std::string LeaderboardManager::friendsTimeQuery = +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, " +" RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +" INNER JOIN charinfo c ON l.character_id = c.id " +" INNER JOIN friends f ON f.player_id = c.id " +" WHERE l.game_id = ? " +" ORDER BY leaderboard_rank), " +" personal_values AS ( " +" SELECT id as related_player_id, " +" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " +" GREATEST(leaderboard_rank + 5, 11) AS max_rank " +" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales, personal_values " +"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);"; + +const std::string LeaderboardManager::standingsTimeQuery = +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " +" RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +" INNER JOIN charinfo c ON l.character_id = c.id " +" WHERE l.game_id = ? " +" ORDER BY leaderboard_rank), " +"personal_values AS ( " +" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " +" GREATEST(leaderboard_rank + 5, 11) AS max_rank " +" FROM leaderboard_vales WHERE id = ? LIMIT 1) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales, personal_values " +"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;"; + +const std::string LeaderboardManager::topPlayersTimeQueryAsc = +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " +"RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +"INNER JOIN charinfo c ON l.character_id = c.id " +"WHERE l.game_id = ? " +"ORDER BY leaderboard_rank) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales LIMIT 11;"; + +const std::string LeaderboardManager::friendsTimeQueryAsc = +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, " +" RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +" INNER JOIN charinfo c ON l.character_id = c.id " +" INNER JOIN friends f ON f.player_id = c.id " +" WHERE l.game_id = ? " +" ORDER BY leaderboard_rank), " +" personal_values AS ( " +" SELECT id as related_player_id, " +" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " +" GREATEST(leaderboard_rank + 5, 11) AS max_rank " +" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales, personal_values " +"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);"; + +const std::string LeaderboardManager::standingsTimeQueryAsc = +"WITH leaderboard_vales AS ( " +" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, " +" RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank " +" FROM leaderboard l " +" INNER JOIN charinfo c ON l.character_id = c.id " +" WHERE l.game_id = ? " +" ORDER BY leaderboard_rank), " +"personal_values AS ( " +" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, " +" GREATEST(leaderboard_rank + 5, 11) AS max_rank " +" FROM leaderboard_vales WHERE id = ? LIMIT 1) " +"SELECT time, score, leaderboard_rank, id, name, last_played " +"FROM leaderboard_vales, personal_values " +"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;"; diff --git a/dGame/LeaderboardManager.h b/dGame/LeaderboardManager.h index ce092462..c4479f1a 100644 --- a/dGame/LeaderboardManager.h +++ b/dGame/LeaderboardManager.h @@ -60,11 +60,21 @@ public: static LeaderboardType GetLeaderboardType(uint32_t gameID); private: static LeaderboardManager* address; - static const std::string topPlayersQuery; - static const std::string friendsQuery; - static const std::string standingsQuery; - static const std::string topPlayersQueryAsc; - static const std::string friendsQueryAsc; - static const std::string standingsQueryAsc; + + // Modified 12/12/2021: Existing queries were renamed to be more descriptive. + static const std::string topPlayersScoreQuery; + static const std::string friendsScoreQuery; + static const std::string standingsScoreQuery; + static const std::string topPlayersScoreQueryAsc; + static const std::string friendsScoreQueryAsc; + static const std::string standingsScoreQueryAsc; + + // Added 12/12/2021: Queries dictated by time are needed for certain minigames. + static const std::string topPlayersTimeQuery; + static const std::string friendsTimeQuery; + static const std::string standingsTimeQuery; + static const std::string topPlayersTimeQueryAsc; + static const std::string friendsTimeQueryAsc; + static const std::string standingsTimeQueryAsc; }; diff --git a/dGame/Player.cpp b/dGame/Player.cpp index 518e4a74..e63559b5 100644 --- a/dGame/Player.cpp +++ b/dGame/Player.cpp @@ -13,6 +13,7 @@ #include "dZoneManager.h" #include "CharacterComponent.h" #include "Mail.h" +#include "CppScripts.h" std::vector Player::m_Players = {}; @@ -275,5 +276,21 @@ Player::~Player() return; } + if (IsPlayer()) { + Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); + for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { + script->OnPlayerExit(zoneControl, this); + } + + std::vector scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_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); + } + } + } + } + m_Players.erase(iter); } diff --git a/dGame/UserManager.cpp b/dGame/UserManager.cpp index 1d14cb0a..3956942a 100644 --- a/dGame/UserManager.cpp +++ b/dGame/UserManager.cpp @@ -369,10 +369,8 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) } LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet); - objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_CHARACTER); - objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_PERSISTENT); - - uint32_t charID = static_cast(objectID); + uint32_t charID = static_cast(objectID); + Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)\n", objectID, charID); //Check if this user has this character: @@ -402,10 +400,14 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) } { sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM friends WHERE player_id=? OR friend_id=?;"); - stmt->setUInt64(1, charID); - stmt->setUInt64(2, charID); + stmt->setUInt(1, charID); + stmt->setUInt(2, charID); stmt->execute(); delete stmt; + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION); + bitStream.Write(objectID); + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } { sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM leaderboard WHERE character_id=?;"); diff --git a/dGame/dBehaviors/Behavior.cpp b/dGame/dBehaviors/Behavior.cpp index db5bbf2f..489bd1a7 100644 --- a/dGame/dBehaviors/Behavior.cpp +++ b/dGame/dBehaviors/Behavior.cpp @@ -7,6 +7,7 @@ #include "dLogger.h" #include "BehaviorTemplates.h" #include "BehaviorBranchContext.h" +#include /* * Behavior includes @@ -45,6 +46,7 @@ #include "InterruptBehavior.h" #include "PlayEffectBehavior.h" #include "DamageAbsorptionBehavior.h" +#include "VentureVisionBehavior.h" #include "BlockBehavior.h" #include "ClearTargetBehavior.h" #include "PullToPointBehavior.h" @@ -68,7 +70,7 @@ #include "RenderComponent.h" #include "DestroyableComponent.h" -std::map Behavior::Cache = {}; +std::unordered_map Behavior::Cache = {}; CDBehaviorParameterTable* Behavior::BehaviorParameterTable = nullptr; Behavior* Behavior::GetBehavior(const uint32_t behaviorId) @@ -91,21 +93,21 @@ Behavior* Behavior::GetBehavior(const uint32_t behaviorId) Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) { auto* cached = GetBehavior(behaviorId); - + if (cached != nullptr) { return cached; } - + if (behaviorId == 0) { return new EmptyBehavior(0); } - + const auto templateId = GetBehaviorTemplate(behaviorId); Behavior* behavior = nullptr; - + switch (templateId) { case BehaviorTemplates::BEHAVIOR_EMPTY: break; @@ -176,7 +178,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) case BehaviorTemplates::BEHAVIOR_LOOT_BUFF: behavior = new LootBuffBehavior(behaviorId); break; - case BehaviorTemplates::BEHAVIOR_VENTURE_VISION: break; + case BehaviorTemplates::BEHAVIOR_VENTURE_VISION: + behavior = new VentureVisionBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_SPAWN_OBJECT: behavior = new SpawnBehavior(behaviorId); break; @@ -191,8 +195,8 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) behavior = new JetPackBehavior(behaviorId); break; case BehaviorTemplates::BEHAVIOR_SKILL_EVENT: - behavior = new SkillEventBehavior(behaviorId); - break; + behavior = new SkillEventBehavior(behaviorId); + break; case BehaviorTemplates::BEHAVIOR_CONSUME_ITEM: break; case BehaviorTemplates::BEHAVIOR_SKILL_CAST_FAILED: behavior = new SkillCastFailedBehavior(behaviorId); @@ -272,7 +276,7 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) if (behavior == nullptr) { //Game::logger->Log("Behavior", "Failed to load unimplemented template id (%i)!\n", templateId); - + behavior = new EmptyBehavior(behaviorId); } @@ -281,30 +285,23 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) return behavior; } -BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) -{ - std::stringstream query; +BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) { + auto behaviorTemplateTable = CDClientManager::Instance()->GetTable("BehaviorTemplate"); - query << "SELECT templateID FROM BehaviorTemplate WHERE behaviorID = " << std::to_string(behaviorId); - - auto result = CDClientDatabase::ExecuteQuery(query.str()); - - // Make sure we do not proceed if we are trying to load an invalid behavior - if (result.eof()) - { - if (behaviorId != 0) - { - Game::logger->Log("Behavior::GetBehaviorTemplate", "Failed to load behavior template with id (%i)!\n", behaviorId); + BehaviorTemplates templateID = BehaviorTemplates::BEHAVIOR_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); } - - return BehaviorTemplates::BEHAVIOR_EMPTY; } - - const auto id = static_cast(result.getIntField(0)); - result.finalize(); + if (templateID == BehaviorTemplates::BEHAVIOR_EMPTY && behaviorId != 0) { + Game::logger->Log("Behavior", "Failed to load behavior template with id (%i)!\n", behaviorId); + } - return id; + return templateID; } // For use with enemies, to display the correct damage animations on the players @@ -325,7 +322,7 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID return; } - + auto* renderComponent = targetEntity->GetComponent(); const auto typeString = GeneralUtils::UTF16ToWTF8(type); @@ -348,28 +345,35 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID if (renderComponent == nullptr) { GameMessages::SendPlayFXEffect(targetEntity, effectId, type, pair->second, secondary, 1, 1, true); - + return; } renderComponent->PlayEffect(effectId, type, pair->second, secondary); - + return; } } - - std::stringstream query; - - if (!type.empty()) - { - query << "SELECT effectName FROM BehaviorEffect WHERE effectType = '" << typeString << "' AND effectID = " << std::to_string(effectId) << ";"; - } - else - { - query << "SELECT effectName, effectType FROM BehaviorEffect WHERE effectID = " << std::to_string(effectId) << ";"; - } - auto result = CDClientDatabase::ExecuteQuery(query.str()); + // The SQlite result object becomes invalid if the query object leaves scope. + // So both queries are defined before the if statement + CppSQLite3Query result; + auto typeQuery = CDClientDatabase::CreatePreppedStmt( + "SELECT effectName FROM BehaviorEffect WHERE effectType = ? AND effectID = ?;"); + + auto idQuery = CDClientDatabase::CreatePreppedStmt( + "SELECT effectName, effectType FROM BehaviorEffect WHERE effectID = ?;"); + + if (!type.empty()) { + typeQuery.bind(1, typeString.c_str()); + typeQuery.bind(2, (int) effectId); + + result = typeQuery.execQuery(); + } else { + idQuery.bind(1, (int) effectId); + + result = idQuery.execQuery(); + } if (result.eof() || result.fieldIsNull(0)) { @@ -381,7 +385,7 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID if (type.empty()) { const auto typeResult = result.getStringField(1); - + type = GeneralUtils::ASCIIToUTF16(typeResult); m_effectType = new std::string(typeResult); @@ -394,7 +398,7 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID if (renderComponent == nullptr) { GameMessages::SendPlayFXEffect(targetEntity, effectId, type, name, secondary, 1, 1, true); - + return; } @@ -403,6 +407,17 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID Behavior::Behavior(const uint32_t behaviorId) { + auto behaviorTemplateTable = CDClientManager::Instance()->GetTable("BehaviorTemplate"); + + CDBehaviorTemplate templateInDatabase{}; + + if (behaviorTemplateTable) { + auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId); + if (templateEntry.behaviorID == behaviorId) { + templateInDatabase = templateEntry; + } + } + this->m_behaviorId = behaviorId; // Add to cache @@ -414,18 +429,8 @@ Behavior::Behavior(const uint32_t behaviorId) this->m_templateId = BehaviorTemplates::BEHAVIOR_EMPTY; } - /* - * Get standard info - */ - - std::stringstream query; - - query << "SELECT templateID, effectID, effectHandle FROM BehaviorTemplate WHERE behaviorID = " << std::to_string(behaviorId); - - auto result = CDClientDatabase::ExecuteQuery(query.str()); - // Make sure we do not proceed if we are trying to load an invalid behavior - if (result.eof()) + if (templateInDatabase.behaviorID == 0) { Game::logger->Log("Behavior", "Failed to load behavior with id (%i)!\n", behaviorId); @@ -436,34 +441,19 @@ Behavior::Behavior(const uint32_t behaviorId) return; } - this->m_templateId = static_cast(result.getIntField(0)); - - this->m_effectId = result.getIntField(1); + this->m_templateId = static_cast(templateInDatabase.templateID); - if (!result.fieldIsNull(2)) - { - const std::string effectHandle = result.getStringField(2); - if (effectHandle == "") - { - this->m_effectHandle = nullptr; - } - else - { - this->m_effectHandle = new std::string(effectHandle); - } - } - else - { - this->m_effectHandle = nullptr; - } + this->m_effectId = templateInDatabase.effectID; - result.finalize(); + this->m_effectHandle = *templateInDatabase.effectHandle != "" ? new std::string(*templateInDatabase.effectHandle) : nullptr; } float Behavior::GetFloat(const std::string& name, const float defaultValue) const { - return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue); + // Get the behavior parameter entry and return its value. + if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); + return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue).value; } @@ -493,24 +483,14 @@ Behavior* Behavior::GetAction(float value) const std::map Behavior::GetParameterNames() const { - std::map parameters; - - std::stringstream query; - - query << "SELECT parameterID, value FROM BehaviorParameter WHERE behaviorID = " << std::to_string(this->m_behaviorId); - - auto tableData = CDClientDatabase::ExecuteQuery(query.str()); - - while (!tableData.eof()) - { - parameters.insert_or_assign(tableData.getStringField(0, ""), tableData.getFloatField(1, 0)); - - tableData.nextRow(); + std::map templatesInDatabase; + // Find behavior template by its behavior id. + if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable("BehaviorParameter"); + if (BehaviorParameterTable) { + templatesInDatabase = BehaviorParameterTable->GetParametersByBehaviorID(this->m_behaviorId); } - tableData.finalize(); - - return parameters; + return templatesInDatabase; } void Behavior::Load() diff --git a/dGame/dBehaviors/Behavior.h b/dGame/dBehaviors/Behavior.h index e8700f48..34ba469b 100644 --- a/dGame/dBehaviors/Behavior.h +++ b/dGame/dBehaviors/Behavior.h @@ -19,7 +19,7 @@ public: /* * Static */ - static std::map Cache; + static std::unordered_map Cache; static CDBehaviorParameterTable* BehaviorParameterTable; static Behavior* GetBehavior(uint32_t behaviorId); diff --git a/dGame/dBehaviors/BehaviorSlot.h b/dGame/dBehaviors/BehaviorSlot.h index 54ba5708..af0d4e03 100644 --- a/dGame/dBehaviors/BehaviorSlot.h +++ b/dGame/dBehaviors/BehaviorSlot.h @@ -1,5 +1,8 @@ #pragma once +#ifndef BEHAVIORSLOT_H +#define BEHAVIORSLOT_H + enum class BehaviorSlot { Invalid = -1, @@ -9,3 +12,5 @@ enum class BehaviorSlot Head, Consumable }; + +#endif diff --git a/dGame/dBehaviors/CMakeLists.txt b/dGame/dBehaviors/CMakeLists.txt new file mode 100644 index 00000000..fe8e89b8 --- /dev/null +++ b/dGame/dBehaviors/CMakeLists.txt @@ -0,0 +1,51 @@ +set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp" + "AndBehavior.cpp" + "ApplyBuffBehavior.cpp" + "AreaOfEffectBehavior.cpp" + "AttackDelayBehavior.cpp" + "BasicAttackBehavior.cpp" + "Behavior.cpp" + "BehaviorBranchContext.cpp" + "BehaviorContext.cpp" + "BehaviorTemplates.cpp" + "BlockBehavior.cpp" + "BuffBehavior.cpp" + "CarBoostBehavior.cpp" + "ChainBehavior.cpp" + "ChangeOrientationBehavior.cpp" + "ChargeUpBehavior.cpp" + "ClearTargetBehavior.cpp" + "DamageAbsorptionBehavior.cpp" + "DamageReductionBehavior.cpp" + "DurationBehavior.cpp" + "EmptyBehavior.cpp" + "EndBehavior.cpp" + "ForceMovementBehavior.cpp" + "HealBehavior.cpp" + "ImaginationBehavior.cpp" + "ImmunityBehavior.cpp" + "InterruptBehavior.cpp" + "JetPackBehavior.cpp" + "KnockbackBehavior.cpp" + "LootBuffBehavior.cpp" + "MovementSwitchBehavior.cpp" + "NpcCombatSkillBehavior.cpp" + "OverTimeBehavior.cpp" + "PlayEffectBehavior.cpp" + "ProjectileAttackBehavior.cpp" + "PullToPointBehavior.cpp" + "RepairBehavior.cpp" + "SkillCastFailedBehavior.cpp" + "SkillEventBehavior.cpp" + "SpawnBehavior.cpp" + "SpawnQuickbuildBehavior.cpp" + "SpeedBehavior.cpp" + "StartBehavior.cpp" + "StunBehavior.cpp" + "SwitchBehavior.cpp" + "SwitchMultipleBehavior.cpp" + "TacArcBehavior.cpp" + "TargetCasterBehavior.cpp" + "TauntBehavior.cpp" + "VentureVisionBehavior.cpp" + "VerifyBehavior.cpp" PARENT_SCOPE) diff --git a/dGame/dBehaviors/SwitchMultipleBehavior.cpp b/dGame/dBehaviors/SwitchMultipleBehavior.cpp index 691e8b53..93662060 100644 --- a/dGame/dBehaviors/SwitchMultipleBehavior.cpp +++ b/dGame/dBehaviors/SwitchMultipleBehavior.cpp @@ -39,15 +39,15 @@ void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStre // TODO } -void SwitchMultipleBehavior::Load() -{ - const auto b = std::to_string(this->m_behaviorId); - std::stringstream query; - query << "SELECT replace(bP1.parameterID, 'behavior ', '') as key, bP1.value as behavior, " - << "(select bP2.value FROM BehaviorParameter bP2 WHERE bP2.behaviorID = " << b << " AND bP2.parameterID LIKE 'value %' " - << "AND replace(bP1.parameterID, 'behavior ', '') = replace(bP2.parameterID, 'value ', '')) as value " - << "FROM BehaviorParameter bP1 WHERE bP1.behaviorID = " << b << " AND bP1.parameterID LIKE 'behavior %'"; - auto result = CDClientDatabase::ExecuteQuery(query.str()); +void SwitchMultipleBehavior::Load() { + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT replace(bP1.parameterID, 'behavior ', '') as key, bP1.value as behavior, " + "(select bP2.value FROM BehaviorParameter bP2 WHERE bP2.behaviorID = ?1 AND bP2.parameterID LIKE 'value %' " + "AND replace(bP1.parameterID, 'behavior ', '') = replace(bP2.parameterID, 'value ', '')) as value " + "FROM BehaviorParameter bP1 WHERE bP1.behaviorID = ?1 AND bP1.parameterID LIKE 'behavior %';"); + query.bind(1, (int) this->m_behaviorId); + + auto result = query.execQuery(); while (!result.eof()) { const auto behavior_id = static_cast(result.getFloatField(1)); diff --git a/dGame/dBehaviors/VentureVisionBehavior.cpp b/dGame/dBehaviors/VentureVisionBehavior.cpp new file mode 100644 index 00000000..9061deb7 --- /dev/null +++ b/dGame/dBehaviors/VentureVisionBehavior.cpp @@ -0,0 +1,47 @@ +#include "VentureVisionBehavior.h" +#include "BehaviorBranchContext.h" +#include "CharacterComponent.h" +#include "BehaviorContext.h" + +void VentureVisionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch){ + + const auto targetEntity = EntityManager::Instance()->GetEntity(branch.target); + + if (targetEntity) { + auto characterComponent = targetEntity->GetComponent(); + + if (characterComponent) { + if (m_show_collectibles) characterComponent->AddVentureVisionEffect(m_ShowCollectibles); + if (m_show_minibosses) characterComponent->AddVentureVisionEffect(m_ShowMiniBosses); + if (m_show_pet_digs) characterComponent->AddVentureVisionEffect(m_ShowPetDigs); + } + + if (branch.duration > 0) context->RegisterTimerBehavior(this, branch); + } +} + +void VentureVisionBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { + const auto targetEntity = EntityManager::Instance()->GetEntity(branch.target); + + if (targetEntity) { + auto characterComponent = targetEntity->GetComponent(); + + if (characterComponent) { + if (m_show_collectibles) characterComponent->RemoveVentureVisionEffect(m_ShowCollectibles); + if (m_show_minibosses) characterComponent->RemoveVentureVisionEffect(m_ShowMiniBosses); + if (m_show_pet_digs) characterComponent->RemoveVentureVisionEffect(m_ShowPetDigs); + } + } +} + +void VentureVisionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { + UnCast(context, branch); +} + +void VentureVisionBehavior::Load(){ + this->m_show_pet_digs = GetBoolean("show_pet_digs"); + + this->m_show_minibosses = GetBoolean("show_minibosses"); + + this->m_show_collectibles = GetBoolean("show_collectibles"); +} diff --git a/dGame/dBehaviors/VentureVisionBehavior.h b/dGame/dBehaviors/VentureVisionBehavior.h new file mode 100644 index 00000000..96b2642b --- /dev/null +++ b/dGame/dBehaviors/VentureVisionBehavior.h @@ -0,0 +1,41 @@ +#pragma once + +#ifndef __VENTUREVISIONBEHAVIOR__H__ +#define __VENTUREVISIONBEHAVIOR__H__ + +#include "Behavior.h" + +class VentureVisionBehavior final : public Behavior +{ +public: + bool m_show_pet_digs; + + bool m_show_minibosses; + + bool m_show_collectibles; + + const std::string m_ShowCollectibles = "bShowCollectibles"; + + const std::string m_ShowMiniBosses = "bShowMiniBosses"; + + const std::string m_ShowPetDigs = "bShowPetDigs"; + + + /* + * Inherited + */ + + explicit VentureVisionBehavior(const uint32_t behaviorId) : Behavior(behaviorId) + { + } + + void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; + + void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override; + + void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override; + + void Load() override; +}; + +#endif //!__VENTUREVISIONBEHAVIOR__H__ diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index 858b129d..0903e621 100644 --- a/dGame/dComponents/BaseCombatAIComponent.cpp +++ b/dGame/dComponents/BaseCombatAIComponent.cpp @@ -35,11 +35,11 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) m_SoftTimer = 5.0f; //Grab the aggro information from BaseCombatAI: - std::stringstream componentQuery; - - componentQuery << "SELECT aggroRadius, tetherSpeed, pursuitSpeed, softTetherRadius, hardTetherRadius FROM BaseCombatAIComponent WHERE id = " << std::to_string(id); - - auto componentResult = CDClientDatabase::ExecuteQuery(componentQuery.str()); + auto componentQuery = CDClientDatabase::CreatePreppedStmt( + "SELECT aggroRadius, tetherSpeed, pursuitSpeed, softTetherRadius, hardTetherRadius FROM BaseCombatAIComponent WHERE id = ?;"); + componentQuery.bind(1, (int) id); + + auto componentResult = componentQuery.execQuery(); if (!componentResult.eof()) { @@ -64,12 +64,11 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) /* * Find skills */ - - std::stringstream query; - - query << "SELECT skillID, cooldown, behaviorID FROM SkillBehavior WHERE skillID IN (SELECT skillID FROM ObjectSkills WHERE objectTemplate = " << std::to_string(parent->GetLOT()) << " )"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto skillQuery = CDClientDatabase::CreatePreppedStmt( + "SELECT skillID, cooldown, behaviorID FROM SkillBehavior WHERE skillID IN (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);"); + skillQuery.bind(1, (int) parent->GetLOT()); + + auto result = skillQuery.execQuery(); while (!result.eof()) { const auto skillId = static_cast(result.getIntField(0)); diff --git a/dGame/dComponents/BuffComponent.cpp b/dGame/dComponents/BuffComponent.cpp index 06c859c8..9c12e87d 100644 --- a/dGame/dComponents/BuffComponent.cpp +++ b/dGame/dComponents/BuffComponent.cpp @@ -371,12 +371,12 @@ const std::vector& BuffComponent::GetBuffParameters(int32_t buffI return pair->second; } - std::stringstream query; - - query << "SELECT * FROM BuffParameters WHERE BuffID = " << std::to_string(buffId) << ";"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT * FROM BuffParameters WHERE BuffID = ?;"); + query.bind(1, (int) buffId); + auto result = query.execQuery(); + std::vector parameters {}; while (!result.eof()) diff --git a/dGame/dComponents/BuildBorderComponent.cpp b/dGame/dComponents/BuildBorderComponent.cpp index ed2fe2d2..1747f0ed 100644 --- a/dGame/dComponents/BuildBorderComponent.cpp +++ b/dGame/dComponents/BuildBorderComponent.cpp @@ -42,6 +42,8 @@ void BuildBorderComponent::OnUse(Entity* originator) { return; } + inventoryComponent->PushEquippedItems(); + Game::logger->Log("BuildBorderComponent", "Starting with %llu\n", buildArea); if (PropertyManagementComponent::Instance() != nullptr) { diff --git a/dGame/dComponents/CMakeLists.txt b/dGame/dComponents/CMakeLists.txt new file mode 100644 index 00000000..706395ea --- /dev/null +++ b/dGame/dComponents/CMakeLists.txt @@ -0,0 +1,40 @@ +set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp" + "BouncerComponent.cpp" + "BuffComponent.cpp" + "BuildBorderComponent.cpp" + "CharacterComponent.cpp" + "Component.cpp" + "ControllablePhysicsComponent.cpp" + "DestroyableComponent.cpp" + "InventoryComponent.cpp" + "LUPExhibitComponent.cpp" + "MissionComponent.cpp" + "MissionOfferComponent.cpp" + "ModelComponent.cpp" + "ModuleAssemblyComponent.cpp" + "MovementAIComponent.cpp" + "MovingPlatformComponent.cpp" + "PetComponent.cpp" + "PhantomPhysicsComponent.cpp" + "PossessableComponent.cpp" + "PossessorComponent.cpp" + "PropertyComponent.cpp" + "PropertyEntranceComponent.cpp" + "PropertyManagementComponent.cpp" + "PropertyVendorComponent.cpp" + "ProximityMonitorComponent.cpp" + "RacingControlComponent.cpp" + "RailActivatorComponent.cpp" + "RebuildComponent.cpp" + "RenderComponent.cpp" + "RigidbodyPhantomPhysicsComponent.cpp" + "RocketLaunchLupComponent.cpp" + "RocketLaunchpadControlComponent.cpp" + "ScriptedActivityComponent.cpp" + "ShootingGalleryComponent.cpp" + "SimplePhysicsComponent.cpp" + "SkillComponent.cpp" + "SoundTriggerComponent.cpp" + "SwitchComponent.cpp" + "VehiclePhysicsComponent.cpp" + "VendorComponent.cpp" PARENT_SCOPE) diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index f7941af8..dd2b69bb 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -10,7 +10,6 @@ #include "InventoryComponent.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" -#include "PossessorComponent.h" #include "VehiclePhysicsComponent.h" #include "GameMessages.h" #include "Item.h" @@ -81,13 +80,6 @@ CharacterComponent::~CharacterComponent() { } void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { - outBitStream->Write(m_IsRacing); - if (m_IsRacing) { - outBitStream->Write1(); - outBitStream->Write(m_VehicleObjectID); - outBitStream->Write(0); - } - outBitStream->Write1(); outBitStream->Write(m_Level); outBitStream->Write0(); @@ -793,3 +785,32 @@ ZoneStatistics& CharacterComponent::GetZoneStatisticsForMap(LWOMAPID mapID) { m_ZoneStatistics.insert({ mapID, {0, 0, 0, 0, 0 } }); return m_ZoneStatistics.at(mapID); } + +void CharacterComponent::AddVentureVisionEffect(std::string ventureVisionType) { + const auto ventureVisionTypeIterator = m_ActiveVentureVisionEffects.find(ventureVisionType); + + if (ventureVisionTypeIterator != m_ActiveVentureVisionEffects.end()) { + ventureVisionTypeIterator->second = ++ventureVisionTypeIterator->second; + } else { + // If the effect it not found, insert it into the active effects. + m_ActiveVentureVisionEffects.insert(std::make_pair(ventureVisionType, 1U)); + } + + UpdateClientMinimap(true, ventureVisionType); +} + +void CharacterComponent::RemoveVentureVisionEffect(std::string ventureVisionType) { + const auto ventureVisionTypeIterator = m_ActiveVentureVisionEffects.find(ventureVisionType); + + if (ventureVisionTypeIterator != m_ActiveVentureVisionEffects.end()) { + ventureVisionTypeIterator->second = --ventureVisionTypeIterator->second; + UpdateClientMinimap(ventureVisionTypeIterator->second != 0U, ventureVisionType); + } +} + +void CharacterComponent::UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const { + if (!m_Parent) return; + AMFArrayValue arrayToSend; + arrayToSend.InsertValue(ventureVisionType, showFaction ? static_cast(new AMFTrueValue()) : static_cast(new AMFFalseValue())); + GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", &arrayToSend); +} diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index 99c8a098..009530c4 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -143,24 +143,6 @@ public: */ void SetIsRacing(bool isRacing) { m_IsRacing = isRacing; } - /** - * Gets the (optional) object ID of the vehicle the character is currently in - * @return the object ID of the vehilce the character is in - */ - const LWOOBJID GetVehicleObjectID() const { return m_VehicleObjectID; } - - /** - * Sets the (optional) object ID of the vehicle the character is currently in - * @param vehicleObjectID the ID of the vehicle the character is in - */ - void SetVehicleObjectID(LWOOBJID vehicleObjectID) { m_VehicleObjectID = vehicleObjectID; } - - /** - * Sets the possesible type that's currently used, merely used by the shooting gallery if it's 0 - * @param value the possesible type to set - */ - void SetPossessableType(uint8_t value) { m_PossessableType = value; } - /** * Gets whether this character has PvP enabled, allowing combat between players * @return @@ -197,6 +179,18 @@ public: */ void SetLastRocketItemID(LWOOBJID lastRocketItemID) { m_LastRocketItemID = lastRocketItemID; } + /** + * Gets the object ID of the mount item that is being used + * @return the object ID of the mount item that is being used + */ + LWOOBJID GetMountItemID() const { return m_MountItemID; } + + /** + * Sets the object ID of the mount item that is being used + * @param m_MountItemID the object ID of the mount item that is being used + */ + void SetMountItemID(LWOOBJID mountItemID) { m_MountItemID = mountItemID; } + /** * Gives the player rewards for the last level that they leveled up from */ @@ -292,23 +286,38 @@ public: */ void UpdatePlayerStatistic(StatisticID updateID, uint64_t updateValue = 1); + /** + * Add a venture vision effect to the player minimap. + */ + void AddVentureVisionEffect(std::string ventureVisionType); + + /** + * Remove a venture vision effect from the player minimap. + * When an effect hits 0 active effects, it is deactivated. + */ + void RemoveVentureVisionEffect(std::string ventureVisionType); + + /** + * Update the client minimap to reveal the specified factions + */ + void UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const; + /** * Character info regarding this character, including clothing styles, etc. */ Character* m_Character; private: + /** + * The map of active venture vision effects + */ + std::map m_ActiveVentureVisionEffects; /** * Whether this character is racing */ bool m_IsRacing; - /** - * The object ID of the vehicle the character is currently in - */ - LWOOBJID m_VehicleObjectID; - /** * Possessible type, used by the shooting gallery */ @@ -582,6 +591,11 @@ private: * ID of the last rocket used */ LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY; + + /** + * Mount Item ID + */ + LWOOBJID m_MountItemID = LWOOBJID_EMPTY; }; #endif // CHARACTERCOMPONENT_H diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 49b15b3f..72194568 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -106,7 +106,7 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn outBitStream->Write0(); //Contains info about immunities this object has, but it's left out for now. } - outBitStream->Write(m_DirtyHealth || bIsInitialUpdate); + outBitStream->Write(m_DirtyHealth || bIsInitialUpdate); if (m_DirtyHealth || bIsInitialUpdate) { outBitStream->Write(m_iHealth); outBitStream->Write(m_fMaxHealth); @@ -114,12 +114,12 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn 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); @@ -130,14 +130,14 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn } outBitStream->Write(m_IsSmashable); - + if (bIsInitialUpdate) { outBitStream->Write(m_IsDead); outBitStream->Write(m_IsSmashed); - + if (m_IsSmashable) { outBitStream->Write(m_HasBricks); - + if (m_ExplodeFactor != 1.0f) { outBitStream->Write1(); outBitStream->Write(m_ExplodeFactor); @@ -146,10 +146,10 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn } } } - + m_DirtyHealth = false; } - + if (m_DirtyThreatList || bIsInitialUpdate) { outBitStream->Write1(); outBitStream->Write(m_HasThreats); @@ -167,7 +167,7 @@ void DestroyableComponent::LoadFromXML(tinyxml2::XMLDocument* doc) { } auto* buffComponent = m_Parent->GetComponent(); - + if (buffComponent != nullptr) { buffComponent->LoadFromXML(doc); } @@ -187,9 +187,9 @@ void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument* doc) { Game::logger->Log("DestroyableComponent", "Failed to find dest tag!\n"); return; } - + auto* buffComponent = m_Parent->GetComponent(); - + if (buffComponent != nullptr) { buffComponent->UpdateXml(doc); } @@ -235,7 +235,7 @@ void DestroyableComponent::SetMaxHealth(float value, bool playAnim) { args.InsertValue("amount", amount); args.InsertValue("type", type); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); - + delete amount; delete type; } @@ -283,7 +283,7 @@ void DestroyableComponent::SetMaxArmor(float value, bool playAnim) { args.InsertValue("type", type); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); - + delete amount; delete type; } @@ -329,7 +329,7 @@ void DestroyableComponent::SetMaxImagination(float value, bool playAnim) { args.InsertValue("amount", amount); args.InsertValue("type", type); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); - + delete amount; delete type; } @@ -342,7 +342,7 @@ void DestroyableComponent::SetDamageToAbsorb(int32_t value) m_DamageToAbsorb = value; } -void DestroyableComponent::SetDamageReduction(int32_t value) +void DestroyableComponent::SetDamageReduction(int32_t value) { m_DirtyHealth = true; m_DamageReduction = value; @@ -354,7 +354,7 @@ void DestroyableComponent::SetIsImmune(bool value) m_ImmuneStacks = value ? 1 : 0; } -void DestroyableComponent::SetIsGMImmune(bool value) +void DestroyableComponent::SetIsGMImmune(bool value) { m_DirtyHealth = true; m_IsGMImmune = value; @@ -375,11 +375,11 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore m_FactionIDs.push_back(factionID); m_DirtyHealth = true; - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT enemyList FROM Factions WHERE faction = ?;"); + query.bind(1, (int) factionID); - query << "SELECT enemyList FROM Factions WHERE faction = " << std::to_string(factionID); - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof()) return; @@ -389,10 +389,10 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore std::stringstream ss(list_string); std::string token; - + while (std::getline(ss, token, ',')) { if (token.empty()) continue; - + auto id = std::stoi(token); auto exclude = std::find(m_FactionIDs.begin(), m_FactionIDs.end(), id) != m_FactionIDs.end(); @@ -406,7 +406,7 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore { continue; } - + AddEnemyFaction(id); } @@ -522,7 +522,7 @@ bool DestroyableComponent::CheckValidity(const LWOOBJID target, const bool ignor if (targetQuickbuild != nullptr) { const auto state = targetQuickbuild->GetState(); - + if (state != REBUILD_COMPLETED) { return false; @@ -562,7 +562,7 @@ void DestroyableComponent::Imagine(const int32_t deltaImagination) { auto current = static_cast(GetImagination()); const auto max = static_cast(GetMaxImagination()); - + current += deltaImagination; current = std::min(current, max); @@ -635,7 +635,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 damage -= absorbDamage; absorb -= absorbDamage; - + const auto armorDamage = std::min(damage, armor); damage -= armorDamage; @@ -657,7 +657,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 { EntityManager::Instance()->SerializeEntity(m_Parent); } - + auto* attacker = EntityManager::Instance()->GetEntity(source); m_Parent->OnHit(attacker); m_Parent->OnHitOrHealResult(attacker, sourceDamage); @@ -696,10 +696,10 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType if (owner != nullptr) { - auto* team = TeamManager::Instance()->GetTeam(owner->GetObjectID()); - owner = owner->GetOwner(); // If the owner is overwritten, we collect that here + auto* team = TeamManager::Instance()->GetTeam(owner->GetObjectID()); + const auto isEnemy = m_Parent->GetComponent() != nullptr; auto* inventoryComponent = owner->GetComponent(); @@ -736,7 +736,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType } } } - + const auto isPlayer = m_Parent->IsPlayer(); GameMessages::SendDie(m_Parent, source, source, true, killType, deathType, 0, 0, 0, isPlayer, false, 1); @@ -765,14 +765,14 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType auto* member = EntityManager::Instance()->GetEntity(specificOwner); if (member) LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); - } + } else { for (const auto memberId : team->members) { // Free for all auto* member = EntityManager::Instance()->GetEntity(memberId); if (member == nullptr) continue; - LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); + LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); } } } @@ -846,7 +846,7 @@ void DestroyableComponent::PopImmunity(int32_t stacks) m_ImmuneStacks -= stacks; } -void DestroyableComponent::FixStats() +void DestroyableComponent::FixStats() { auto* entity = GetParent(); @@ -904,7 +904,7 @@ void DestroyableComponent::FixStats() // Add the stats const auto& info = mission->GetClientInfo(); - + maxHealth += info.reward_maxhealth; maxImagination += info.reward_maximagination; } diff --git a/dGame/dComponents/InventoryComponent.cpp b/dGame/dComponents/InventoryComponent.cpp index 7235d2db..0772482c 100644 --- a/dGame/dComponents/InventoryComponent.cpp +++ b/dGame/dComponents/InventoryComponent.cpp @@ -24,6 +24,8 @@ #include "dZoneManager.h" #include "PropertyManagementComponent.h" #include "DestroyableComponent.h" +#include "dConfig.h" +#include "eItemType.h" InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent) { @@ -51,18 +53,18 @@ InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* do auto items = inventoryComponentTable->Query([=](const CDInventoryComponent entry) { return entry.id == componentId; }); auto slot = 0u; - + for (const auto& item : items) { if (!item.equip || !Inventory::IsValidItem(item.itemid)) { continue; } - + const LWOOBJID id = ObjectIDManager::Instance()->GenerateObjectID(); const auto& info = Inventory::FindItemComponent(item.itemid); - + UpdateSlot(info.equipLocation, { id, static_cast(item.itemid), item.count, slot++ }); } } @@ -178,7 +180,7 @@ void InventoryComponent::AddItem( auto* missions = static_cast(this->m_Parent->GetComponent(COMPONENT_TYPE_MISSION)); auto* inventory = GetInventory(inventoryType); - + if (!config.empty() || bound) { const auto slot = preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot) ? preferredSlot : inventory->FindEmptySlot(); @@ -189,6 +191,7 @@ void InventoryComponent::AddItem( return; } + auto* item = new Item(lot, inventory, slot, count, config, parent, showFlyingLoot, isModMoveAndEquip, subKey, bound, lootSourceType); if (missions != nullptr && !IsTransferInventory(inventoryType)) @@ -200,14 +203,15 @@ void InventoryComponent::AddItem( } const auto info = Inventory::FindItemComponent(lot); - + auto left = count; int32_t outOfSpace = 0; auto stack = static_cast(info.stackSize); - if (inventoryType == eInventoryType::BRICKS) + // info.itemType of 1 is item type brick + if (inventoryType == eInventoryType::BRICKS || (stack == 0 && info.itemType == 1)) { stack = 999; } @@ -215,7 +219,7 @@ void InventoryComponent::AddItem( { stack = 1; } - + auto* existing = FindItemByLot(lot, inventoryType); if (existing != nullptr) @@ -239,7 +243,7 @@ void InventoryComponent::AddItem( const auto size = std::min(left, stack); left -= size; - + int32_t slot; if (preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot)) @@ -252,7 +256,7 @@ void InventoryComponent::AddItem( { slot = inventory->FindEmptySlot(); } - + if (slot == -1) { auto* player = dynamic_cast(GetParent()); @@ -275,9 +279,9 @@ void InventoryComponent::AddItem( { GameMessages::SendDropClientLoot(this->m_Parent, this->m_Parent->GetObjectID(), lot, 0, this->m_Parent->GetPosition(), 1); } - + break; - + default: break; } @@ -326,7 +330,7 @@ void InventoryComponent::RemoveItem(const LOT lot, const uint32_t count, eInvent { break; } - + const auto delta = std::min(left, item->GetCount()); item->SetCount(item->GetCount() - delta); @@ -341,19 +345,17 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in { return; } - + auto* origin = item->GetInventory(); - + const auto lot = item->GetLot(); - + if (item->GetConfig().empty() && !item->GetBound() || (item->GetBound() && item->GetInfo().isBOP)) { auto left = std::min(count, origin->GetLotCount(lot)); while (left > 0) { - item = origin->FindItemByLot(lot, ignoreEquipped); - if (item == nullptr) { item = origin->FindItemByLot(lot, false); @@ -383,7 +385,7 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in { config.push_back(data->Copy()); } - + const auto delta = std::min(item->GetCount(), count); AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, LWOOBJID_EMPTY, origin->GetType(), 0, item->GetBound(), preferredSlot); @@ -441,7 +443,7 @@ Item* InventoryComponent::FindItemByLot(const LOT lot, eInventoryType inventoryT return inventory->FindItemByLot(lot, ignoreEquipped, ignoreBound); } -Item* InventoryComponent::FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType) +Item* InventoryComponent::FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType) { if (inventoryType == INVALID) { @@ -600,7 +602,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) unsigned int count; bool bound; LWOOBJID subKey = LWOOBJID_EMPTY; - + itemElement->QueryAttribute("id", &id); itemElement->QueryAttribute("l", &lot); itemElement->QueryAttribute("eq", &equipped); @@ -611,23 +613,23 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document) // Begin custom xml auto parent = LWOOBJID_EMPTY; - + itemElement->QueryAttribute("parent", &parent); // End custom xml std::vector config; auto* extraInfo = itemElement->FirstChildElement("x"); - + if (extraInfo) { std::string modInfo = extraInfo->Attribute("ma"); - + LDFBaseData* moduleAssembly = new LDFData(u"assemblyPartLOTs", GeneralUtils::ASCIIToUTF16(modInfo.substr(2, modInfo.size() - 1))); - + config.push_back(moduleAssembly); } - + const auto* item = new Item(id, lot, inventory, slot, count, bound, config, parent, subKey); if (equipped) @@ -705,7 +707,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) bags->LinkEndChild(bag); } - + auto* items = inventoryElement->FirstChildElement("items"); if (items == nullptr) @@ -759,10 +761,10 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) itemElement->LinkEndChild(extraInfo); } - + bagElement->LinkEndChild(itemElement); } - + items->LinkEndChild(bagElement); } } @@ -772,13 +774,13 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b if (bIsInitialUpdate || m_Dirty) { outBitStream->Write(true); - + outBitStream->Write(m_Equipped.size()); for (const auto& pair : m_Equipped) { const auto item = pair.second; - + if (bIsInitialUpdate) { AddItemSkills(item.lot); @@ -786,12 +788,12 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b outBitStream->Write(item.id); outBitStream->Write(item.lot); - + outBitStream->Write0(); - + 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); @@ -818,7 +820,7 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b outBitStream->Write(ldfStream); } - outBitStream->Write1(); + outBitStream->Write1(); } m_Dirty = false; @@ -827,7 +829,7 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b { outBitStream->Write(false); } - + outBitStream->Write(false); } @@ -836,7 +838,7 @@ void InventoryComponent::ResetFlags() m_Dirty = false; } -void InventoryComponent::Update(float deltaTime) +void InventoryComponent::Update(float deltaTime) { for (auto* set : m_Itemsets) { @@ -865,7 +867,7 @@ void InventoryComponent::UpdateSlot(const std::string& location, EquippedItem it UnEquipItem(old); } } - + m_Equipped.insert_or_assign(location, item); m_Dirty = true; @@ -877,14 +879,14 @@ void InventoryComponent::RemoveSlot(const std::string& location) { return; } - + m_Equipped.erase(location); m_Dirty = true; } void InventoryComponent::EquipItem(Item* item, const bool skipChecks) -{ +{ if (!Inventory::IsValidItem(item->GetLot())) { return; @@ -985,19 +987,11 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) // #107 auto* possessorComponent = m_Parent->GetComponent(); - if (possessorComponent != nullptr) - { - previousPossessorID = possessorComponent->GetPossessable(); - possessorComponent->SetPossessable(carEntity->GetObjectID()); - } + if (possessorComponent) possessorComponent->SetPossessable(carEntity->GetObjectID()); auto* characterComponent = m_Parent->GetComponent(); - if (characterComponent != nullptr) - { - characterComponent->SetIsRacing(true); - characterComponent->SetVehicleObjectID(carEntity->GetObjectID()); - } + if (characterComponent) characterComponent->SetIsRacing(true); EntityManager::Instance()->ConstructEntity(carEntity); EntityManager::Instance()->SerializeEntity(m_Parent); @@ -1030,14 +1024,14 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) { return; } - - if (type == ITEM_TYPE_LOOT_MODEL || type == ITEM_TYPE_VEHICLE) + + if (type == eItemType::ITEM_TYPE_LOOT_MODEL || type == eItemType::ITEM_TYPE_VEHICLE) { return; } } - if (type != ITEM_TYPE_LOOT_MODEL && type != ITEM_TYPE_MODEL) + if (type != eItemType::ITEM_TYPE_LOOT_MODEL && type != eItemType::ITEM_TYPE_MODEL) { if (!item->GetBound() && !item->GetPreconditionExpression()->Check(m_Parent)) { @@ -1049,7 +1043,7 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) const auto lot = item->GetLot(); CheckItemSet(lot); - + for (auto* set : m_Itemsets) { set->OnEquip(lot); @@ -1079,7 +1073,7 @@ void InventoryComponent::UnEquipItem(Item* item) } const auto lot = item->GetLot(); - + if (!Inventory::IsValidItem(lot)) { return; @@ -1097,7 +1091,7 @@ void InventoryComponent::UnEquipItem(Item* item) RemoveItemSkills(item->GetLot()); RemoveSlot(item->GetInfo().equipLocation); - + PurgeProxies(item); EntityManager::Instance()->SerializeEntity(m_Parent); @@ -1115,7 +1109,7 @@ void InventoryComponent::ApplyBuff(Item* item) const const auto buffs = FindBuffs(item, true); for (const auto buff : buffs) - { + { SkillComponent::HandleUnmanaged(buff, m_Parent->GetObjectID()); } } @@ -1165,6 +1159,18 @@ void InventoryComponent::PopEquippedItems() item->Equip(); } + m_Pushed.clear(); + + auto destroyableComponent = m_Parent->GetComponent(); + + // Reset stats to full + if (destroyableComponent) { + destroyableComponent->SetHealth(static_cast(destroyableComponent->GetMaxHealth())); + destroyableComponent->SetArmor(static_cast(destroyableComponent->GetMaxArmor())); + destroyableComponent->SetImagination(static_cast(destroyableComponent->GetMaxImagination())); + EntityManager::Instance()->SerializeEntity(m_Parent); + } + m_Dirty = true; } @@ -1182,22 +1188,21 @@ bool InventoryComponent::IsEquipped(const LOT lot) const return false; } -void InventoryComponent::CheckItemSet(const LOT lot) -{ +void InventoryComponent::CheckItemSet(const LOT lot) { // Check if the lot is in the item set cache - if (std::find(m_ItemSetsChecked.begin(), m_ItemSetsChecked.end(), lot) != m_ItemSetsChecked.end()) - { + if (std::find(m_ItemSetsChecked.begin(), m_ItemSetsChecked.end(), lot) != m_ItemSetsChecked.end()) { return; } - std::stringstream query; + const std::string lot_query = "%" + std::to_string(lot) + "%"; - query << "SELECT setID FROM ItemSets WHERE itemIDs LIKE '%" << std::to_string(lot) << "%'"; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT setID FROM ItemSets WHERE itemIDs LIKE ?;"); + query.bind(1, lot_query.c_str()); - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); - while (!result.eof()) - { + while (!result.eof()) { const auto id = result.getIntField(0); bool found = false; @@ -1223,11 +1228,11 @@ void InventoryComponent::CheckItemSet(const LOT lot) } m_ItemSetsChecked.push_back(lot); - + result.finalize(); } -void InventoryComponent::SetConsumable(LOT lot) +void InventoryComponent::SetConsumable(LOT lot) { m_Consumable = lot; } @@ -1247,7 +1252,7 @@ void InventoryComponent::AddItemSkills(const LOT lot) { return; } - + const auto index = m_Skills.find(slot); const auto skill = FindSkill(lot); @@ -1272,14 +1277,14 @@ void InventoryComponent::AddItemSkills(const LOT lot) void InventoryComponent::RemoveItemSkills(const LOT lot) { const auto info = Inventory::FindItemComponent(lot); - + const auto slot = FindBehaviorSlot(static_cast(info.itemType)); - + if (slot == BehaviorSlot::Invalid) { return; } - + const auto index = m_Skills.find(slot); if (index == m_Skills.end()) @@ -1292,7 +1297,7 @@ void InventoryComponent::RemoveItemSkills(const LOT lot) GameMessages::SendRemoveSkill(m_Parent, old); m_Skills.erase(slot); - + if (slot == BehaviorSlot::Primary) { m_Skills.insert_or_assign(BehaviorSlot::Primary, 1); @@ -1301,7 +1306,7 @@ void InventoryComponent::RemoveItemSkills(const LOT lot) } } -void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger) +void InventoryComponent::TriggerPassiveAbility(PassiveAbilityTrigger trigger) { for (auto* set : m_Itemsets) { @@ -1328,7 +1333,7 @@ bool InventoryComponent::HasAnyPassive(const std::vectorGetObjectID()); @@ -1338,7 +1343,7 @@ void InventoryComponent::DespawnPet() } } -void InventoryComponent::SpawnPet(Item* item) +void InventoryComponent::SpawnPet(Item* item) { auto* current = PetComponent::GetActivePet(m_Parent->GetObjectID()); @@ -1352,16 +1357,24 @@ void InventoryComponent::SpawnPet(Item* item) } } + // First check if we can summon the pet. You need 1 imagination to do so. + auto destroyableComponent = m_Parent->GetComponent(); + + if (Game::config->GetValue("pets_take_imagination") == "1" && destroyableComponent && destroyableComponent->GetImagination() <= 0) { + GameMessages::SendUseItemRequirementsResponse(m_Parent->GetObjectID(), m_Parent->GetSystemAddress(), UseItemResponse::NoImaginationForPet); + return; + } + EntityInfo info {}; info.lot = item->GetLot(); info.pos = m_Parent->GetPosition(); info.rot = NiQuaternion::IDENTITY; info.spawnerID = m_Parent->GetObjectID(); - + auto* pet = EntityManager::Instance()->CreateEntity(info); auto* petComponent = pet->GetComponent(); - + if (petComponent != nullptr) { petComponent->Activate(item); @@ -1370,7 +1383,7 @@ void InventoryComponent::SpawnPet(Item* item) EntityManager::Instance()->ConstructEntity(pet); } -void InventoryComponent::SetDatabasePet(LWOOBJID id, const DatabasePet& data) +void InventoryComponent::SetDatabasePet(LWOOBJID id, const DatabasePet& data) { m_Pets.insert_or_assign(id, data); } @@ -1391,7 +1404,7 @@ bool InventoryComponent::IsPet(LWOOBJID id) const return pair != m_Pets.end(); } -void InventoryComponent::RemoveDatabasePet(LWOOBJID id) +void InventoryComponent::RemoveDatabasePet(LWOOBJID id) { m_Pets.erase(id); } @@ -1399,22 +1412,22 @@ void InventoryComponent::RemoveDatabasePet(LWOOBJID id) BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type) { switch (type) { - case ITEM_TYPE_HAT: + case eItemType::ITEM_TYPE_HAT: return BehaviorSlot::Head; - case ITEM_TYPE_NECK: + case eItemType::ITEM_TYPE_NECK: return BehaviorSlot::Neck; - case ITEM_TYPE_LEFT_HAND: + case eItemType::ITEM_TYPE_LEFT_HAND: return BehaviorSlot::Offhand; - case ITEM_TYPE_RIGHT_HAND: + case eItemType::ITEM_TYPE_RIGHT_HAND: return BehaviorSlot::Primary; - case ITEM_TYPE_CONSUMABLE: + case eItemType::ITEM_TYPE_CONSUMABLE: return BehaviorSlot::Consumable; default: return BehaviorSlot::Invalid; } } -bool InventoryComponent::IsTransferInventory(eInventoryType type) +bool InventoryComponent::IsTransferInventory(eInventoryType type) { return type == VENDOR_BUYBACK || type == VAULT_ITEMS || type == VAULT_MODELS || type == TEMP_ITEMS || type == TEMP_MODELS; } @@ -1465,11 +1478,12 @@ std::vector InventoryComponent::FindBuffs(Item* item, bool castOnEquip continue; } - + if (missions != nullptr && castOnEquip) { missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, result.skillID); } + // If item is not a proxy, add its buff to the added buffs. if (item->GetParent() == LWOOBJID_EMPTY) buffs.push_back(static_cast(entry.behaviorID)); } @@ -1478,18 +1492,18 @@ std::vector InventoryComponent::FindBuffs(Item* item, bool castOnEquip return buffs; } -void InventoryComponent::SetNPCItems(const std::vector& items) +void InventoryComponent::SetNPCItems(const std::vector& items) { m_Equipped.clear(); auto slot = 0u; - + for (const auto& item : items) { const LWOOBJID id = ObjectIDManager::Instance()->GenerateObjectID(); const auto& info = Inventory::FindItemComponent(item); - + UpdateSlot(info.equipLocation, { id, static_cast(item), 1, slot++ }, true); } @@ -1524,9 +1538,9 @@ std::vector InventoryComponent::GenerateProxies(Item* parent) { return proxies; } - + subItems.erase(std::remove_if(subItems.begin(), subItems.end(), ::isspace), subItems.end()); - + std::stringstream stream(subItems); std::string segment; std::vector lots; @@ -1541,7 +1555,7 @@ std::vector InventoryComponent::GenerateProxies(Item* parent) { Game::logger->Log("InventoryComponent", "Failed to parse proxy (%s): (%s)!\n", segment.c_str(), exception.what()); } - } + } for (const auto lot : lots) { @@ -1558,7 +1572,7 @@ std::vector InventoryComponent::GenerateProxies(Item* parent) proxies.push_back(proxy); } - + return proxies; } @@ -1567,7 +1581,7 @@ std::vector InventoryComponent::FindProxies(const LWOOBJID parent) auto* inventory = GetInventory(ITEM_SETS); std::vector proxies; - + for (const auto& pair : inventory->GetItems()) { auto* item = pair.second; @@ -1609,7 +1623,7 @@ bool InventoryComponent::IsParentValid(Item* root) } const auto id = root->GetId(); - + for (const auto& pair : m_Inventories) { const auto items = pair.second->GetItems(); @@ -1631,7 +1645,7 @@ bool InventoryComponent::IsParentValid(Item* root) void InventoryComponent::CheckProxyIntegrity() { std::vector dead; - + for (const auto& pair : m_Inventories) { const auto& items = pair.second->GetItems(); @@ -1646,7 +1660,7 @@ void InventoryComponent::CheckProxyIntegrity() { continue; } - + if (IsValidProxy(parent)) { continue; @@ -1671,7 +1685,7 @@ void InventoryComponent::CheckProxyIntegrity() for (const auto& candidate : items) { auto* item = candidate.second; - + const auto parent = item->GetParent(); if (parent != LWOOBJID_EMPTY) @@ -1703,7 +1717,7 @@ void InventoryComponent::CheckProxyIntegrity() void InventoryComponent::PurgeProxies(Item* item) { const auto root = item->GetParent(); - + if (root != LWOOBJID_EMPTY) { item = FindItemById(root); @@ -1712,7 +1726,7 @@ void InventoryComponent::PurgeProxies(Item* item) { UnEquipItem(item); } - + return; } @@ -1726,7 +1740,7 @@ void InventoryComponent::PurgeProxies(Item* item) } } -void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) +void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) { auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); @@ -1744,7 +1758,7 @@ void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) LWOOBJID id; LOT lot; int32_t moderationStatus; - + petElement->QueryAttribute("id", &id); petElement->QueryAttribute("l", &lot); petElement->QueryAttribute("m", &moderationStatus); @@ -1761,7 +1775,7 @@ void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document) } } -void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) +void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) { auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet"); @@ -1783,8 +1797,7 @@ void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) petElement->SetAttribute("m", pet.second.moderationState); petElement->SetAttribute("n", pet.second.name.c_str()); petElement->SetAttribute("t", 0); - + petInventoryElement->LinkEndChild(petElement); } } - diff --git a/dGame/dComponents/InventoryComponent.h b/dGame/dComponents/InventoryComponent.h index bf18d132..a7d3f8ea 100644 --- a/dGame/dComponents/InventoryComponent.h +++ b/dGame/dComponents/InventoryComponent.h @@ -1,4 +1,7 @@ -#pragma once +#pragma once + +#ifndef INVENTORYCOMPONENT_H +#define INVENTORYCOMPONENT_H #include #include @@ -22,6 +25,8 @@ class ItemSet; typedef std::map EquipmentMap; +enum class eItemType : int32_t; + /** * Handles the inventory of entity, including the items they possess and have equipped. An entity can have inventories * of different types, each type representing a different group of items, see `eInventoryType` for a list of @@ -445,3 +450,5 @@ private: */ void UpdatePetXml(tinyxml2::XMLDocument* document); }; + +#endif diff --git a/dGame/dComponents/MissionComponent.cpp b/dGame/dComponents/MissionComponent.cpp index a0e63914..1b809f48 100644 --- a/dGame/dComponents/MissionComponent.cpp +++ b/dGame/dComponents/MissionComponent.cpp @@ -450,11 +450,11 @@ const std::vector& MissionComponent::QueryAchievements(MissionTaskType } bool MissionComponent::RequiresItem(const LOT lot) { - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT type FROM Objects WHERE id = ?;"); + query.bind(1, (int) lot); - query << "SELECT type FROM Objects WHERE id = " << std::to_string(lot); - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof()) { return false; diff --git a/dGame/dComponents/PetComponent.cpp b/dGame/dComponents/PetComponent.cpp index 39d7eb60..d54087aa 100644 --- a/dGame/dComponents/PetComponent.cpp +++ b/dGame/dComponents/PetComponent.cpp @@ -16,6 +16,7 @@ #include "../dWorldServer/ObjectIDManager.h" #include "Game.h" +#include "dConfig.h" #include "dChatFilter.h" #include "Database.h" @@ -81,6 +82,20 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId) : Component(par if (!checkPreconditions.empty()) { SetPreconditions(checkPreconditions); } + // Get the imagination drain rate from the CDClient + auto query = CDClientDatabase::CreatePreppedStmt("SELECT imaginationDrainRate FROM PetComponent WHERE id = ?;"); + + query.bind(1, static_cast(componentId)); + + auto result = query.execQuery(); + + // Should a result not exist for this pet default to 60 seconds. + if (!result.eof() && !result.fieldIsNull(0)) { + imaginationDrainRate = result.getFloatField(0, 60.0f); + } else { + imaginationDrainRate = 60.0f; + } + result.finalize(); } void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) @@ -172,13 +187,12 @@ void PetComponent::OnUse(Entity* originator) std::string buildFile; - if (cached == buildCache.end()) - { - std::stringstream query; + if (cached == buildCache.end()) { + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = ?;"); + query.bind(1, (int) m_Parent->GetLOT()); - query << "SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = " << std::to_string(m_Parent->GetLOT()) << ";"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof()) { @@ -637,7 +651,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) inventoryComponent->SetDatabasePet(petSubKey, databasePet); - Activate(item, false); + Activate(item, false, true); m_Timer = 0; @@ -898,8 +912,10 @@ void PetComponent::Wander() m_Timer += (m_MovementAI->GetCurrentPosition().x - destination.x) / info.wanderSpeed; } -void PetComponent::Activate(Item* item, bool registerPet) +void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) { + AddDrainImaginationTimer(item, fromTaming); + m_ItemId = item->GetId(); m_DatabaseId = item->GetSubKey(); @@ -969,6 +985,44 @@ void PetComponent::Activate(Item* item, bool registerPet) GameMessages::SendShowPetActionButton(m_Owner, 3, true, owner->GetSystemAddress()); } +void PetComponent::AddDrainImaginationTimer(Item* item, bool fromTaming) { + if (Game::config->GetValue("pets_take_imagination") != "1") return; + + auto playerInventory = item->GetInventory(); + if (!playerInventory) return; + + auto playerInventoryComponent = playerInventory->GetComponent(); + if (!playerInventoryComponent) return; + + auto playerEntity = playerInventoryComponent->GetParent(); + if (!playerEntity) return; + + auto playerDestroyableComponent = playerEntity->GetComponent(); + if (!playerDestroyableComponent) return; + + // Drain by 1 when you summon pet or when this method is called, but not when we have just tamed this pet. + if (!fromTaming) playerDestroyableComponent->Imagine(-1); + + // Set this to a variable so when this is called back from the player the timer doesn't fire off. + m_Parent->AddCallbackTimer(imaginationDrainRate, [playerDestroyableComponent, this, item](){ + if (!playerDestroyableComponent) { + Game::logger->Log("PetComponent", "No petComponent and/or no playerDestroyableComponent\n"); + return; + } + + // If we are out of imagination despawn the pet. + if (playerDestroyableComponent->GetImagination() == 0) { + this->Deactivate(); + auto playerEntity = playerDestroyableComponent->GetParent(); + if (!playerEntity) return; + + GameMessages::SendUseItemRequirementsResponse(playerEntity->GetObjectID(), playerEntity->GetSystemAddress(), UseItemResponse::NoImaginationForPet); + } + + this->AddDrainImaginationTimer(item); + }); +} + void PetComponent::Deactivate() { GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true); diff --git a/dGame/dComponents/PetComponent.h b/dGame/dComponents/PetComponent.h index 845cfe31..913cbc56 100644 --- a/dGame/dComponents/PetComponent.h +++ b/dGame/dComponents/PetComponent.h @@ -82,7 +82,7 @@ public: * @param item the item to create the pet from * @param registerPet notifies the client that the pet was spawned, not necessary if this pet is being tamed */ - void Activate(Item* item, bool registerPet = true); + void Activate(Item* item, bool registerPet = true, bool fromTaming = false); /** * Despawns the pet @@ -203,6 +203,14 @@ public: */ static PetComponent* GetActivePet(LWOOBJID owner); + /** + * Adds the timer to the owner of this pet to drain imagination at the rate + * specified by the parameter imaginationDrainRate + * + * @param item The item that represents this pet in the inventory. + */ + void AddDrainImaginationTimer(Item* item, bool fromTaming = false); + private: /** @@ -346,4 +354,9 @@ private: * Preconditions that need to be met before an entity can tame this pet */ PreconditionExpression* m_Preconditions; + + /** + * The rate at which imagination is drained from the user for having the pet out. + */ + float imaginationDrainRate; }; \ No newline at end of file diff --git a/dGame/dComponents/PossessableComponent.cpp b/dGame/dComponents/PossessableComponent.cpp index d4fd0d62..8190b9eb 100644 --- a/dGame/dComponents/PossessableComponent.cpp +++ b/dGame/dComponents/PossessableComponent.cpp @@ -1,51 +1,46 @@ #include "PossessableComponent.h" - #include "PossessorComponent.h" #include "EntityManager.h" +#include "Inventory.h" +#include "Item.h" -PossessableComponent::PossessableComponent(Entity* parent) : Component(parent) -{ - m_Possessor = LWOOBJID_EMPTY; +PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId) : Component(parent){ + m_Possessor = LWOOBJID_EMPTY; + CDItemComponent item = Inventory::FindItemComponent(m_Parent->GetLOT()); + m_AnimationFlag = static_cast(item.animationFlag); + + // Get the possession Type from the CDClient + auto query = CDClientDatabase::CreatePreppedStmt("SELECT possessionType, depossessOnHit FROM PossessableComponent WHERE id = ?;"); + + query.bind(1, static_cast(componentId)); + + auto result = query.execQuery(); + + // Should a result not exist for this default to attached visible + if (!result.eof()) { + m_PossessionType = static_cast(result.getIntField(0, 0)); + m_DepossessOnHit = static_cast(result.getIntField(1, 0)); + } else { + m_PossessionType = ePossessionType::ATTACHED_VISIBLE; + m_DepossessOnHit = false; + } + result.finalize(); } -PossessableComponent::~PossessableComponent() -{ - -} +void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + outBitStream->Write(m_DirtyPossessable || bIsInitialUpdate); + if (m_DirtyPossessable || bIsInitialUpdate) { + m_DirtyPossessable = false; + outBitStream->Write(m_Possessor != LWOOBJID_EMPTY); + if (m_Possessor != LWOOBJID_EMPTY) outBitStream->Write(m_Possessor); -void PossessableComponent::SetPossessor(LWOOBJID value) -{ - m_Possessor = value; -} + outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_INVALID); + if(m_AnimationFlag != eAnimationFlags::IDLE_INVALID) outBitStream->Write(m_AnimationFlag); -LWOOBJID PossessableComponent::GetPossessor() const -{ - return m_Possessor; -} - -void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) -{ - outBitStream->Write(m_Possessor != LWOOBJID_EMPTY); - if (m_Possessor != LWOOBJID_EMPTY) - { - outBitStream->Write1(); - outBitStream->Write(m_Possessor); - outBitStream->Write0(); - outBitStream->Write0(); - } -} - -void PossessableComponent::Update(float deltaTime) -{ - + outBitStream->Write(m_ImmediatelyDepossess); + } } void PossessableComponent::OnUse(Entity* originator) { - PossessorComponent* possessorComponent; - if (originator->TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) { - SetPossessor(originator->GetObjectID()); - possessorComponent->SetPossessable(m_Parent->GetObjectID()); - EntityManager::Instance()->SerializeEntity(m_Parent); - EntityManager::Instance()->SerializeEntity(originator); - } -} + // TODO: Implement this +} \ No newline at end of file diff --git a/dGame/dComponents/PossessableComponent.h b/dGame/dComponents/PossessableComponent.h index 744ebfc5..a37b6e34 100644 --- a/dGame/dComponents/PossessableComponent.h +++ b/dGame/dComponents/PossessableComponent.h @@ -3,44 +3,113 @@ #include "BitStream.h" #include "Entity.h" #include "Component.h" +#include "Item.h" +#include "PossessorComponent.h" +#include "eAninmationFlags.h" /** * Represents an entity that can be controlled by some other entity, generally used by cars to indicate that some * player is controlling it. */ class PossessableComponent : public Component { -public: - static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSABLE; - - PossessableComponent(Entity* parentEntity); - ~PossessableComponent() override; + public: + static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSABLE; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime) override; + PossessableComponent(Entity* parentEntity, uint32_t componentId); - /** - * Sets the possessor of this entity - * @param value the ID of the possessor to set - */ - void SetPossessor(LWOOBJID value); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Returns the possessor of this entity - * @return the possessor of this entitythe - */ - LWOOBJID GetPossessor() const; + /** + * Sets the possessor of this entity + * @param value the ID of the possessor to set + */ + void SetPossessor(LWOOBJID value) { m_Possessor = value; m_DirtyPossessable = true;}; - /** - * Handles an OnUsed event by some other entity, if said entity has a PossessorComponent it becomes the possessor - * of this entity - * @param originator the entity that caused the event to trigger - */ - void OnUse(Entity* originator) override; + /** + * Returns the possessor of this entity + * @return the possessor of this entity + */ + LWOOBJID GetPossessor() const { return m_Possessor; }; -private: + /** + * Sets the animation Flag of the possessable + * @param value the animation flag to set to + */ + void SetAnimationFlag(eAnimationFlags value) { m_AnimationFlag = value; m_DirtyPossessable = true;}; - /** - * The possessor of this entity, e.g. the entity that controls this entity - */ - LWOOBJID m_Possessor; + /** + * Returns the possession type of this entity + * @return the possession type of this entity + */ + ePossessionType GetPossessionType() const { return m_PossessionType; }; + + /** + * Returns if the entity should deposses on hit + * @return if the entity should deposses on hit + */ + bool GetDepossessOnHit() const { return m_DepossessOnHit; }; + + /** + * Forcibly depossess the entity + */ + void ForceDepossess() { m_ImmediatelyDepossess = true; m_DirtyPossessable = true;}; + + /** + * Set if the parent entity was spawned from an item + * @param value if the parent entity was spawned from an item + */ + void SetItemSpawned(bool value) { m_ItemSpawned = value;}; + + /** + * Returns if the parent entity was spawned from an item + * @return if the parent entity was spawned from an item + */ + LWOOBJID GetItemSpawned() const { return m_ItemSpawned; }; + + /** + * Handles an OnUsed event by some other entity, if said entity has a Possessor it becomes the possessor + * of this entity + * @param originator the entity that caused the event to trigger + */ + void OnUse(Entity* originator) override; + + private: + + /** + * @brief Whether the possessor is dirty + */ + bool m_DirtyPossessable = true; + + /** + * @brief The possessor of this entity, e.g. the entity that controls this entity + */ + LWOOBJID m_Possessor = LWOOBJID_EMPTY; + + /** + * @brief The type of possesstion to use on this entity + */ + ePossessionType m_PossessionType = ePossessionType::NO_POSSESSION; + + /** + * @brief Should the possessable be dismount on hit + */ + bool m_DepossessOnHit = false; + + /** + * @brief What animaiton flag to use + * + */ + eAnimationFlags m_AnimationFlag = eAnimationFlags::IDLE_INVALID; + + /** + * @brief Should this be immediately depossessed + * + */ + bool m_ImmediatelyDepossess = false; + + /** + * @brief Whether the parent entity was spawned from an item + * + */ + bool m_ItemSpawned = false; }; diff --git a/dGame/dComponents/PossessorComponent.cpp b/dGame/dComponents/PossessorComponent.cpp index 4f532805..4ace324b 100644 --- a/dGame/dComponents/PossessorComponent.cpp +++ b/dGame/dComponents/PossessorComponent.cpp @@ -1,35 +1,21 @@ #include "PossessorComponent.h" -PossessorComponent::PossessorComponent(Entity* parent) : Component(parent) -{ - m_Possessable = LWOOBJID_EMPTY; +PossessorComponent::PossessorComponent(Entity* parent) : Component(parent) { + m_Possessable = LWOOBJID_EMPTY; } -PossessorComponent::~PossessorComponent() -{ - -} +PossessorComponent::~PossessorComponent() {} -void PossessorComponent::SetPossessable(LWOOBJID value) -{ - m_Possessable = value; -} -LWOOBJID PossessorComponent::GetPossessable() const -{ - return m_Possessable; -} -void PossessorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) -{ - outBitStream->Write(m_Possessable != LWOOBJID_EMPTY); - if (m_Possessable != LWOOBJID_EMPTY) - { - outBitStream->Write(m_Possessable); - } -} - -void PossessorComponent::Update(float deltaTime) -{ - +void PossessorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { + outBitStream->Write(m_DirtyPossesor || bIsInitialUpdate); + if (m_DirtyPossesor || bIsInitialUpdate) { + m_DirtyPossesor = false; + outBitStream->Write(m_Possessable != LWOOBJID_EMPTY); + if (m_Possessable != LWOOBJID_EMPTY) { + outBitStream->Write(m_Possessable); + } + outBitStream->Write(m_PossessableType); + } } diff --git a/dGame/dComponents/PossessorComponent.h b/dGame/dComponents/PossessorComponent.h index 0c1a436e..a81868a5 100644 --- a/dGame/dComponents/PossessorComponent.h +++ b/dGame/dComponents/PossessorComponent.h @@ -4,35 +4,78 @@ #include "Entity.h" #include "Component.h" +// possession types +enum class ePossessionType : uint8_t { + NO_POSSESSION = 0, + ATTACHED_VISIBLE, + NOT_ATTACHED_VISIBLE, + NOT_ATTACHED_NOT_VISIBLE, +}; + /** * Represents an entity that can posess other entities. Generally used by players to drive a car. */ class PossessorComponent : public Component { -public: - static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSOR; - - PossessorComponent(Entity* parent); - ~PossessorComponent() override; + public: + static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSOR; - void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - void Update(float deltaTime) override; + PossessorComponent(Entity* parent); + ~PossessorComponent() override; - /** - * Sets the entity that this entity is possessing - * @param value the ID of the entity this ID should posess - */ - void SetPossessable(LWOOBJID value); + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); - /** - * Returns the entity that this entity is currently posessing - * @return the entity that this entity is currently posessing - */ - LWOOBJID GetPossessable() const; + /** + * Sets the entity that this entity is possessing + * @param value the ID of the entity this ID should posess + */ + void SetPossessable(LWOOBJID value) { m_Possessable = value; m_DirtyPossesor = true; } -private: + /** + * Returns the entity that this entity is currently posessing + * @return the entity that this entity is currently posessing + */ + LWOOBJID GetPossessable() const { return m_Possessable; } - /** - * The ID of the entity this entity is possessing (e.g. the ID of a car) - */ - LWOOBJID m_Possessable; + /** + * Sets if we are busy mounting or dismounting + * @param value if we are busy mounting or dismounting + */ + void SetIsBusy(bool value) { m_IsBusy = value; } + + /** + * Returns if we are busy mounting or dismounting + * @return if we are busy mounting or dismounting + */ + bool GetIsBusy() const { return m_IsBusy; } + + /** + * Sets the possesible type that's currently used, merely used by the shooting gallery if it's 0 + * @param value the possesible type to set + */ + void SetPossessableType(ePossessionType value) { m_PossessableType = value; m_DirtyPossesor = true; } + + private: + + /** + * The ID of the entity this entity is possessing (e.g. the ID of a car) + */ + LWOOBJID m_Possessable = LWOOBJID_EMPTY; + + /** + * @brief possessable type + * + */ + ePossessionType m_PossessableType = ePossessionType::NO_POSSESSION; + + /** + * @brief if the possessor is dirty + * + */ + bool m_DirtyPossesor = false; + + /** + * @brief if the possessor is busy mounting or dismounting + * + */ + bool m_IsBusy = false; }; diff --git a/dGame/dComponents/PropertyEntranceComponent.cpp b/dGame/dComponents/PropertyEntranceComponent.cpp index 6779d1c3..87e0c7ed 100644 --- a/dGame/dComponents/PropertyEntranceComponent.cpp +++ b/dGame/dComponents/PropertyEntranceComponent.cpp @@ -102,7 +102,7 @@ PropertySelectQueryProperty PropertyEntranceComponent::SetPropertyValues(Propert return property; } -std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMethod, std::string customQuery, bool wantLimits) { +std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery, bool wantLimits) { std::string base; if (customQuery == "") { base = baseQueryForProperties; @@ -115,15 +115,13 @@ std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMe auto friendsListQuery = Database::CreatePreppedStmt("SELECT * FROM (SELECT CASE WHEN player_id = ? THEN friend_id WHEN friend_id = ? THEN player_id END AS requested_player FROM friends ) AS fr WHERE requested_player IS NOT NULL ORDER BY requested_player DESC;"); - friendsListQuery->setInt64(1, entity->GetObjectID()); - friendsListQuery->setInt64(2, entity->GetObjectID()); + friendsListQuery->setUInt(1, character->GetID()); + friendsListQuery->setUInt(2, character->GetID()); auto friendsListQueryResult = friendsListQuery->executeQuery(); while (friendsListQueryResult->next()) { - auto playerIDToConvert = friendsListQueryResult->getInt64(1); - playerIDToConvert = GeneralUtils::ClearBit(playerIDToConvert, OBJECT_BIT_CHARACTER); - playerIDToConvert = GeneralUtils::ClearBit(playerIDToConvert, OBJECT_BIT_PERSISTENT); + auto playerIDToConvert = friendsListQueryResult->getInt(1); friendsList = friendsList + std::to_string(playerIDToConvert) + ","; } // Replace trailing comma with the closing parenthesis. @@ -172,8 +170,8 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl // If the player has a property this query will have a single result. if (playerPropertyLookupResults->next()) { const auto cloneId = playerPropertyLookupResults->getUInt64(4); - const auto propertyName = playerPropertyLookupResults->getString(5).asStdString(); - const auto propertyDescription = playerPropertyLookupResults->getString(6).asStdString(); + const auto propertyName = std::string(playerPropertyLookupResults->getString(5).c_str()); + const auto propertyDescription = std::string(playerPropertyLookupResults->getString(6).c_str()); const auto privacyOption = playerPropertyLookupResults->getInt(9); const auto modApproved = playerPropertyLookupResults->getBoolean(10); const auto dateLastUpdated = playerPropertyLookupResults->getInt64(11); @@ -193,7 +191,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl entries.push_back(playerEntry); - const auto query = BuildQuery(entity, sortMethod); + const auto query = BuildQuery(entity, sortMethod, character); auto propertyLookup = Database::CreatePreppedStmt(query); @@ -212,8 +210,8 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl const auto propertyId = propertyEntry->getUInt64(1); const auto owner = propertyEntry->getInt(2); const auto cloneId = propertyEntry->getUInt64(4); - const auto propertyNameFromDb = propertyEntry->getString(5).asStdString(); - const auto propertyDescriptionFromDb = propertyEntry->getString(6).asStdString(); + const auto propertyNameFromDb = std::string(propertyEntry->getString(5).c_str()); + const auto propertyDescriptionFromDb = std::string(propertyEntry->getString(6).c_str()); const auto privacyOption = propertyEntry->getInt(9); const auto modApproved = propertyEntry->getBoolean(10); const auto dateLastUpdated = propertyEntry->getInt(11); @@ -239,7 +237,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl continue; } else { isOwned = cloneId == character->GetPropertyCloneID(); - ownerName = nameResult->getString(1).asStdString(); + ownerName = std::string(nameResult->getString(1).c_str()); } delete nameResult; @@ -262,17 +260,17 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl // Query to get friend and best friend fields auto friendCheck = Database::CreatePreppedStmt("SELECT best_friend FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?)"); - friendCheck->setInt64(1, entity->GetObjectID()); - friendCheck->setInt64(2, ownerObjId); - friendCheck->setInt64(3, ownerObjId); - friendCheck->setInt64(4, entity->GetObjectID()); + friendCheck->setUInt(1, character->GetID()); + friendCheck->setUInt(2, ownerObjId); + friendCheck->setUInt(3, ownerObjId); + friendCheck->setUInt(4, character->GetID()); auto friendResult = friendCheck->executeQuery(); // If we got a result than the two players are friends. if (friendResult->next()) { isFriend = true; - if (friendResult->getInt(1) == 2) { + if (friendResult->getInt(1) == 3) { isBestFriend = true; } } @@ -326,7 +324,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl // Query here is to figure out whether or not to display the button to go to the next page or not. int32_t numberOfProperties = 0; - auto buttonQuery = BuildQuery(entity, sortMethod, "SELECT COUNT(*) FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? ", false); + auto buttonQuery = BuildQuery(entity, sortMethod, character, "SELECT COUNT(*) FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? ", false); auto propertiesLeft = Database::CreatePreppedStmt(buttonQuery); propertiesLeft->setUInt(1, this->m_MapID); @@ -346,4 +344,4 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl propertiesLeft = nullptr; GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, numberOfProperties - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr); -} \ No newline at end of file +} diff --git a/dGame/dComponents/PropertyEntranceComponent.h b/dGame/dComponents/PropertyEntranceComponent.h index a3be38a6..fe583e92 100644 --- a/dGame/dComponents/PropertyEntranceComponent.h +++ b/dGame/dComponents/PropertyEntranceComponent.h @@ -60,7 +60,7 @@ class PropertyEntranceComponent : public Component { PropertySelectQueryProperty SetPropertyValues(PropertySelectQueryProperty property, LWOCLONEID cloneId = LWOCLONEID_INVALID, std::string ownerName = "", std::string propertyName = "", std::string propertyDescription = "", float reputation = 0, bool isBFF = false, bool isFriend = false, bool isModeratorApproved = false, bool isAlt = false, bool isOwned = false, uint32_t privacyOption = 0, uint32_t timeLastUpdated = 0, float performanceCost = 0.0f); - std::string BuildQuery(Entity* entity, int32_t sortMethod, std::string customQuery = "", bool wantLimits = true); + std::string BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery = "", bool wantLimits = true); private: /** diff --git a/dGame/dComponents/PropertyManagementComponent.cpp b/dGame/dComponents/PropertyManagementComponent.cpp index 0a428e04..f27ea283 100644 --- a/dGame/dComponents/PropertyManagementComponent.cpp +++ b/dGame/dComponents/PropertyManagementComponent.cpp @@ -2,6 +2,7 @@ #include +#include "MissionComponent.h" #include "EntityManager.h" #include "PropertyDataMessage.h" #include "UserManager.h" @@ -40,11 +41,11 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo const auto zoneId = worldId.GetMapID(); const auto cloneId = worldId.GetCloneID(); - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); + query.bind(1, (int) zoneId); - query << "SELECT id FROM PropertyTemplate WHERE mapID = " << std::to_string(zoneId) << ";"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof() || result.fieldIsNull(0)) { @@ -75,7 +76,7 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo this->moderatorRequested = propertyEntry->getInt(10) == 0 && rejectionReason == "" && privacyOption == PropertyPrivacyOption::Public; this->LastUpdatedTime = propertyEntry->getUInt64(11); this->claimedTime = propertyEntry->getUInt64(12); - this->rejectionReason = propertyEntry->getString(13).asStdString(); + this->rejectionReason = std::string(propertyEntry->getString(13).c_str()); this->reputation = propertyEntry->getUInt(14); Load(); @@ -102,12 +103,12 @@ void PropertyManagementComponent::SetOwner(Entity* value) std::vector PropertyManagementComponent::GetPaths() const { const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); - - std::stringstream query {}; - query << "SELECT path FROM PropertyTemplate WHERE mapID = " << std::to_string(zoneId) << ";"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT path FROM PropertyTemplate WHERE mapID = ?;"); + query.bind(1, (int) zoneId); + + auto result = query.execQuery(); std::vector paths {}; @@ -285,6 +286,10 @@ void PropertyManagementComponent::OnStartBuilding() player->SendToZone(zoneId); } + auto inventoryComponent = ownerEntity->GetComponent(); + + // Push equipped items + if (inventoryComponent) inventoryComponent->PushEquippedItems(); } void PropertyManagementComponent::OnFinishBuilding() @@ -865,7 +870,7 @@ void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const result->next(); - const auto reason = result->getString(1).asStdString();; + const auto reason = std::string(result->getString(1).c_str()); const auto modApproved = result->getInt(2); if (reason != "") { moderatorRequested = false; diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index 1d86b274..7bea03f6 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -212,6 +212,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity *player, if (possessorComponent != nullptr) { possessorComponent->SetPossessable(carEntity->GetObjectID()); + possessorComponent->SetPossessableType(ePossessionType::ATTACHED_VISIBLE); // for racing it's always Attached_Visible } // Set the player's current activity as racing. @@ -219,7 +220,6 @@ void RacingControlComponent::LoadPlayerVehicle(Entity *player, if (characterComponent != nullptr) { characterComponent->SetIsRacing(true); - characterComponent->SetVehicleObjectID(carEntity->GetObjectID()); } // Init the player's racing entry. diff --git a/dGame/dComponents/RebuildComponent.cpp b/dGame/dComponents/RebuildComponent.cpp index abee5e16..603a18cc 100644 --- a/dGame/dComponents/RebuildComponent.cpp +++ b/dGame/dComponents/RebuildComponent.cpp @@ -6,6 +6,8 @@ #include "Game.h" #include "dLogger.h" #include "CharacterComponent.h" +#include "MissionComponent.h" +#include "MissionTaskType.h" #include "dServer.h" #include "PacketUtils.h" @@ -22,6 +24,20 @@ RebuildComponent::RebuildComponent(Entity* entity) : Component(entity) { { m_Precondition = new PreconditionExpression(GeneralUtils::UTF16ToWTF8(checkPreconditions)); } + + // Should a setting that has the build activator position exist, fetch that setting here and parse it for position. + // It is assumed that the user who sets this setting uses the correct character delimiter (character 31 or in hex 0x1F) + auto positionAsVector = GeneralUtils::SplitString(m_Parent->GetVarAsString(u"rebuild_activators"), 0x1F); + if (positionAsVector.size() == 3 && + GeneralUtils::TryParse(positionAsVector[0], m_ActivatorPosition.x) && + GeneralUtils::TryParse(positionAsVector[1], m_ActivatorPosition.y) && + GeneralUtils::TryParse(positionAsVector[2], m_ActivatorPosition.z)) { + } else { + Game::logger->Log("RebuildComponent", "Failed to find activator position for lot %i. Defaulting to parents position.\n", m_Parent->GetLOT()); + m_ActivatorPosition = m_Parent->GetPosition(); + } + + SpawnActivator(); } RebuildComponent::~RebuildComponent() { diff --git a/dGame/dComponents/RenderComponent.cpp b/dGame/dComponents/RenderComponent.cpp index aeb56f56..faec4ab6 100644 --- a/dGame/dComponents/RenderComponent.cpp +++ b/dGame/dComponents/RenderComponent.cpp @@ -198,14 +198,16 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e return; } - std::stringstream query; + const std::string effectType_str = GeneralUtils::UTF16ToWTF8(effectType); - query << "SELECT animation_length FROM Animations WHERE animation_type IN (SELECT animationName FROM BehaviorEffect WHERE effectID = " << std::to_string(effectId) << " AND effectType = '" << GeneralUtils::UTF16ToWTF8(effectType) << "');"; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT animation_length FROM Animations WHERE animation_type IN (SELECT animationName FROM BehaviorEffect WHERE effectID = ? AND effectType = ?);"); + query.bind(1, effectId); + query.bind(2, effectType_str.c_str()); - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); - if (result.eof() || result.fieldIsNull(0)) - { + if (result.eof() || result.fieldIsNull(0)) { result.finalize(); m_DurationCache[effectId] = 0; @@ -214,7 +216,7 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e return; } - + effect->time = static_cast(result.getFloatField(0)); result.finalize(); diff --git a/dGame/dComponents/RocketLaunchLupComponent.cpp b/dGame/dComponents/RocketLaunchLupComponent.cpp index fa2a5b16..3c326540 100644 --- a/dGame/dComponents/RocketLaunchLupComponent.cpp +++ b/dGame/dComponents/RocketLaunchLupComponent.cpp @@ -1,21 +1,17 @@ #include "RocketLaunchLupComponent.h" -#include "CDClientDatabase.h" #include "RocketLaunchpadControlComponent.h" #include "InventoryComponent.h" #include "CharacterComponent.h" RocketLaunchLupComponent::RocketLaunchLupComponent(Entity* parent) : Component(parent) { m_Parent = parent; - - // get the lup worlds from the cdclient - std::string query = "SELECT * FROM LUPZoneIDs;"; - auto results = CDClientDatabase::ExecuteQuery(query); - while (!results.eof()) { - // fallback to 1600 incase there is an issue - m_LUPWorlds.push_back(results.getIntField(0, 1600)); - results.nextRow(); + std::string zoneString = GeneralUtils::UTF16ToWTF8(m_Parent->GetVar(u"MultiZoneIDs")); + std::stringstream ss(zoneString); + for (int i; ss >> i;) { + m_LUPWorlds.push_back(i); + if (ss.peek() == ';') + ss.ignore(); } - results.finalize(); } RocketLaunchLupComponent::~RocketLaunchLupComponent() {} @@ -29,11 +25,7 @@ void RocketLaunchLupComponent::OnUse(Entity* originator) { } void RocketLaunchLupComponent::OnSelectWorld(Entity* originator, uint32_t index) { - // Add one to index because the actual LUP worlds start at index 1. - index++; - auto* rocketLaunchpadControlComponent = m_Parent->GetComponent(); - if (!rocketLaunchpadControlComponent) return; rocketLaunchpadControlComponent->Launch(originator, m_LUPWorlds[index], 0); diff --git a/dGame/dComponents/RocketLaunchpadControlComponent.cpp b/dGame/dComponents/RocketLaunchpadControlComponent.cpp index 8585815f..357fb2d0 100644 --- a/dGame/dComponents/RocketLaunchpadControlComponent.cpp +++ b/dGame/dComponents/RocketLaunchpadControlComponent.cpp @@ -19,11 +19,11 @@ #include "PacketUtils.h" RocketLaunchpadControlComponent::RocketLaunchpadControlComponent(Entity* parent, int rocketId) : Component(parent) { - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT targetZone, defaultZoneID, targetScene, altLandingPrecondition, altLandingSpawnPointName FROM RocketLaunchpadControlComponent WHERE id = ?;"); + query.bind(1, rocketId); - query << "SELECT targetZone, defaultZoneID, targetScene, altLandingPrecondition, altLandingSpawnPointName FROM RocketLaunchpadControlComponent WHERE id = " << std::to_string(rocketId); - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (!result.eof() && !result.fieldIsNull(0)) { @@ -48,7 +48,7 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId, { return; } - + // This also gets triggered by a proximity monitor + item equip, I will set that up when havok is ready auto* characterComponent = originator->GetComponent(); auto* character = originator->GetCharacter(); @@ -77,11 +77,11 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId, character->SaveXMLToDatabase(); SetSelectedMapId(originator->GetObjectID(), zone); - - GameMessages::SendFireEventClientSide(m_Parent->GetObjectID(), originator->GetSystemAddress(), u"RocketEquipped", rocket->GetId(), cloneId, -1, originator->GetObjectID()); - GameMessages::SendChangeObjectWorldState(rocket->GetId(), WORLDSTATE_ATTACHED, UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendFireEventClientSide(m_Parent->GetObjectID(), originator->GetSystemAddress(), u"RocketEquipped", rocket->GetId(), cloneId, -1, originator->GetObjectID()); + GameMessages::SendChangeObjectWorldState(rocket->GetId(), WORLDSTATE_ATTACHED, UNASSIGNED_SYSTEM_ADDRESS); + EntityManager::Instance()->SerializeEntity(originator); } @@ -112,7 +112,7 @@ void RocketLaunchpadControlComponent::OnProximityUpdate(Entity* entering, std::s // Proximity rockets are handled by item equipment } -void RocketLaunchpadControlComponent::SetSelectedMapId(LWOOBJID player, LWOMAPID mapID) +void RocketLaunchpadControlComponent::SetSelectedMapId(LWOOBJID player, LWOMAPID mapID) { m_SelectedMapIds[player] = mapID; } @@ -126,7 +126,7 @@ LWOMAPID RocketLaunchpadControlComponent::GetSelectedMapId(LWOOBJID player) cons return index->second; } -void RocketLaunchpadControlComponent::SetSelectedCloneId(LWOOBJID player, LWOCLONEID cloneId) +void RocketLaunchpadControlComponent::SetSelectedCloneId(LWOOBJID player, LWOCLONEID cloneId) { m_SelectedCloneIds[player] = cloneId; } diff --git a/dGame/dComponents/ScriptedActivityComponent.cpp b/dGame/dComponents/ScriptedActivityComponent.cpp index 026fafce..4d62fb0b 100644 --- a/dGame/dComponents/ScriptedActivityComponent.cpp +++ b/dGame/dComponents/ScriptedActivityComponent.cpp @@ -487,22 +487,24 @@ void ActivityInstance::StartZone() { return; auto* leader = participants[0]; - - CBITSTREAM; - PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_CREATE_TEAM); - - bitStream.Write(leader->GetObjectID()); - bitStream.Write(m_Participants.size()); - - for (const auto& participant : m_Participants) { - bitStream.Write(participant); - } - LWOZONEID zoneId = LWOZONEID(m_ActivityInfo.instanceMapID, 0, leader->GetCharacter()->GetPropertyCloneID()); - bitStream.Write(zoneId); + // only make a team if we have more than one participant + if (participants.size() > 1){ + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_CREATE_TEAM); - Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + bitStream.Write(leader->GetObjectID()); + bitStream.Write(m_Participants.size()); + + for (const auto& participant : m_Participants) { + bitStream.Write(participant); + } + + bitStream.Write(zoneId); + + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } const auto cloneId = GeneralUtils::GenerateRandomNumber(1, UINT32_MAX); for (Entity* player : participants) { diff --git a/dGame/dComponents/SimplePhysicsComponent.cpp b/dGame/dComponents/SimplePhysicsComponent.cpp index 8a4cff4e..c9a42971 100644 --- a/dGame/dComponents/SimplePhysicsComponent.cpp +++ b/dGame/dComponents/SimplePhysicsComponent.cpp @@ -17,6 +17,17 @@ SimplePhysicsComponent::SimplePhysicsComponent(uint32_t componentID, Entity* par m_Position = m_Parent->GetDefaultPosition(); m_Rotation = m_Parent->GetDefaultRotation(); m_IsDirty = true; + + const auto& climbable_type = m_Parent->GetVar(u"climbable"); + if (climbable_type == u"wall") { + SetClimbableType(eClimbableType::CLIMBABLE_TYPE_WALL); + } else if (climbable_type == u"ladder") { + SetClimbableType(eClimbableType::CLIMBABLE_TYPE_LADDER); + } else if (climbable_type == u"wallstick") { + SetClimbableType(eClimbableType::CLIMBABLE_TYPE_WALL_STICK); + } else { + SetClimbableType(eClimbableType::CLIMBABLE_TYPE_NOT); + } } SimplePhysicsComponent::~SimplePhysicsComponent() { @@ -24,10 +35,10 @@ SimplePhysicsComponent::~SimplePhysicsComponent() { void SimplePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { if (bIsInitialUpdate) { - outBitStream->Write0(); // climbable - outBitStream->Write(0); // climbableType + outBitStream->Write(m_ClimbableType != eClimbableType::CLIMBABLE_TYPE_NOT); + outBitStream->Write(m_ClimbableType); } - + outBitStream->Write(m_DirtyVelocity || bIsInitialUpdate); if (m_DirtyVelocity || bIsInitialUpdate) { outBitStream->Write(m_Velocity); @@ -46,7 +57,7 @@ void SimplePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIs { outBitStream->Write0(); } - + outBitStream->Write(m_IsDirty || bIsInitialUpdate); if (m_IsDirty || bIsInitialUpdate) { outBitStream->Write(m_Position.x); @@ -66,7 +77,7 @@ uint32_t SimplePhysicsComponent::GetPhysicsMotionState() const return m_PhysicsMotionState; } -void SimplePhysicsComponent::SetPhysicsMotionState(uint32_t value) +void SimplePhysicsComponent::SetPhysicsMotionState(uint32_t value) { m_PhysicsMotionState = value; } diff --git a/dGame/dComponents/SimplePhysicsComponent.h b/dGame/dComponents/SimplePhysicsComponent.h index 081b056b..49e6be5b 100644 --- a/dGame/dComponents/SimplePhysicsComponent.h +++ b/dGame/dComponents/SimplePhysicsComponent.h @@ -14,16 +14,24 @@ class Entity; +enum class eClimbableType : int32_t { + CLIMBABLE_TYPE_NOT = 0, + CLIMBABLE_TYPE_LADDER, + CLIMBABLE_TYPE_WALL, + CLIMBABLE_TYPE_WALL_STICK +}; + + /** * Component that serializes locations of entities to the client */ class SimplePhysicsComponent : public Component { public: static const uint32_t ComponentType = COMPONENT_TYPE_SIMPLE_PHYSICS; - + SimplePhysicsComponent(uint32_t componentID, Entity* parent); ~SimplePhysicsComponent() override; - + void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags); /** @@ -86,6 +94,18 @@ public: */ void SetPhysicsMotionState(uint32_t value); + /** + * Returns the ClimbableType of this entity + * @return the ClimbableType of this entity + */ + const eClimbableType& GetClimabbleType() { return m_ClimbableType; } + + /** + * Sets the ClimbableType of this entity + * @param value the ClimbableType to set + */ + void SetClimbableType(const eClimbableType& value) { m_ClimbableType = value; } + private: /** @@ -122,6 +142,11 @@ private: * The current physics motion state */ uint32_t m_PhysicsMotionState = 0; + + /** + * Whether or not the entity is climbable + */ + eClimbableType m_ClimbableType = eClimbableType::CLIMBABLE_TYPE_NOT; }; #endif // SIMPLEPHYSICSCOMPONENT_H diff --git a/dGame/dComponents/SkillComponent.cpp b/dGame/dComponents/SkillComponent.cpp index 483e360f..7aa29523 100644 --- a/dGame/dComponents/SkillComponent.cpp +++ b/dGame/dComponents/SkillComponent.cpp @@ -38,11 +38,11 @@ bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t s auto* behavior = Behavior::CreateBehavior(behaviorId); const auto branch = BehaviorBranchContext(target, 0); - + behavior->Handle(context, bitStream, branch); context->ExecuteUpdates(); - + return !context->failed; } @@ -78,24 +78,23 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B break; } } - + if (index == -1) { Game::logger->Log("SkillComponent", "Failed to find projectile id (%llu)!\n", projectileId); - + return; } const auto sync_entry = this->m_managedProjectiles.at(index); - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT behaviorID FROM SkillBehavior WHERE skillID = (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);"); + query.bind(1, (int) sync_entry.lot); - query << "SELECT behaviorID FROM SkillBehavior WHERE skillID = (SELECT skillID FROM ObjectSkills WHERE objectTemplate = " << std::to_string(sync_entry.lot) << ")"; + auto result = query.execQuery(); - auto result = CDClientDatabase::ExecuteQuery(query.str()); - - if (result.eof()) - { + if (result.eof()) { Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!\n", sync_entry.lot); return; @@ -115,7 +114,7 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B { branch.target = target; } - + behavior->Handle(sync_entry.context, bitStream, branch); this->m_managedProjectiles.erase(this->m_managedProjectiles.begin() + index); @@ -129,7 +128,7 @@ void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, Behav entry.branchContext = branch; entry.lot = lot; entry.id = projectileId; - + this->m_managedProjectiles.push_back(entry); } @@ -141,7 +140,7 @@ void SkillComponent::Update(const float deltaTime) } std::map keep {}; - + for (const auto& pair : this->m_managedBehaviors) { auto* context = pair.second; @@ -150,7 +149,7 @@ void SkillComponent::Update(const float deltaTime) { continue; } - + if (context->clientInitalized) { context->CalculateUpdate(deltaTime); @@ -164,7 +163,7 @@ void SkillComponent::Update(const float deltaTime) if (context->syncEntries.empty() && context->timerEntries.empty()) { auto any = false; - + for (const auto& projectile : this->m_managedProjectiles) { if (projectile.context == context) @@ -180,13 +179,13 @@ void SkillComponent::Update(const float deltaTime) context->Reset(); delete context; - + context = nullptr; continue; } } - + keep.insert_or_assign(pair.first, context); } @@ -254,9 +253,9 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c context->caster = m_Parent->GetObjectID(); context->clientInitalized = clientInitalized; - + context->foundTarget = target != LWOOBJID_EMPTY || ignoreTarget || clientInitalized; - + behavior->Calculate(context, bitStream, { target, 0}); for (auto* script : CppScripts::GetEntityScripts(m_Parent)) { @@ -278,7 +277,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c { // Echo start skill GameMessages::EchoStartSkill start; - + start.iCastType = 0; start.skillID = skillId; start.uiSkillHandle = context->skillUId; @@ -353,7 +352,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime) const auto targetPosition = target->GetPosition(); const auto closestPoint = Vector3::ClosestPointOnLine(entry.lastPosition, position, targetPosition); - + const auto distance = Vector3::DistanceSquared(targetPosition, closestPoint); if (distance > 3 * 3) @@ -399,12 +398,12 @@ void SkillComponent::CalculateUpdate(const float deltaTime) } entry.lastPosition = position; - + managedProjectile = entry; } - + std::vector valid; - + for (auto& entry : this->m_managedProjectiles) { if (entry.calculation) @@ -412,7 +411,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime) if (entry.time >= entry.maxTime) { entry.branchContext.target = LWOOBJID_EMPTY; - + SyncProjectileCalculation(entry); continue; @@ -430,8 +429,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) { auto* other = EntityManager::Instance()->GetEntity(entry.branchContext.target); - if (other == nullptr) - { + if (other == nullptr) { if (entry.branchContext.target != LWOOBJID_EMPTY) { Game::logger->Log("SkillComponent", "Invalid projectile target (%llu)!\n", entry.branchContext.target); @@ -440,14 +438,12 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) return; } - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT behaviorID FROM SkillBehavior WHERE skillID = (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);"); + query.bind(1, (int) entry.lot); + auto result = query.execQuery(); - query << "SELECT behaviorID FROM SkillBehavior WHERE skillID = (SELECT skillID FROM ObjectSkills WHERE objectTemplate = " << std::to_string(entry.lot) << ")"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); - - if (result.eof()) - { + if (result.eof()) { Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!\n", entry.lot); return; @@ -456,13 +452,13 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry) const auto behaviorId = static_cast(result.getIntField(0)); result.finalize(); - + auto* behavior = Behavior::CreateBehavior(behaviorId); auto* bitStream = new RakNet::BitStream(); behavior->Calculate(entry.context, bitStream, entry.branchContext); - + GameMessages::DoClientProjectileImpact projectileImpact; projectileImpact.sBitStream.assign((char*) bitStream->GetData(), bitStream->GetNumberOfBytesUsed()); @@ -498,19 +494,19 @@ void SkillComponent::HandleUnmanaged(const uint32_t behaviorId, const LWOOBJID t delete bitStream; - delete context; + delete context; } void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID target) { auto* context = new BehaviorContext(target); - + context->caster = target; auto* behavior = Behavior::CreateBehavior(behaviorId); behavior->UnCast(context, { target }); - + delete context; } diff --git a/dGame/dEntity/CMakeLists.txt b/dGame/dEntity/CMakeLists.txt new file mode 100644 index 00000000..4bb49799 --- /dev/null +++ b/dGame/dEntity/CMakeLists.txt @@ -0,0 +1,2 @@ +set(DGAME_DENTITY_SOURCES "EntityCallbackTimer.cpp" + "EntityTimer.cpp" PARENT_SCOPE) diff --git a/dGame/dGameMessages/CMakeLists.txt b/dGame/dGameMessages/CMakeLists.txt new file mode 100644 index 00000000..3c3cb53f --- /dev/null +++ b/dGame/dGameMessages/CMakeLists.txt @@ -0,0 +1,4 @@ +set(DGAME_DGAMEMESSAGES_SOURCES "GameMessageHandler.cpp" + "GameMessages.cpp" + "PropertyDataMessage.cpp" + "PropertySelectQueryProperty.cpp" PARENT_SCOPE) diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index a813f6d3..292afc71 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -147,7 +147,7 @@ void GameMessages::SendPlayAnimation(Entity* entity, const std::u16string& anima PacketUtils::WriteWString(bitStream, animationName, animationIDLength); bitStream.Write(bExpectAnimToExist); - + bitStream.Write(bPlayImmediate); bitStream.Write(bTriggerOnCompleteMsg); @@ -427,7 +427,7 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System LWONameValue extraInfo; auto config = item->GetConfig(); - + for (auto* data : config) { extraInfo.name += GeneralUtils::ASCIIToUTF16(data->GetString()) + u","; @@ -435,7 +435,7 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System if (extraInfo.name.length() > 0) extraInfo.name.pop_back(); // remove the last comma - bitStream.Write(extraInfo.name.size()); + bitStream.Write(extraInfo.name.size()); if (extraInfo.name.size() > 0) { for (uint32_t i = 0; i < extraInfo.name.size(); ++i) { bitStream.Write(static_cast(extraInfo.name[i])); @@ -447,10 +447,10 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System bitStream.Write(subKey != LWOOBJID_EMPTY); if (subKey != LWOOBJID_EMPTY) bitStream.Write(subKey); - + auto* inventory = item->GetInventory(); const auto inventoryType = inventory->GetType(); - + bitStream.Write(inventoryType != eInventoryType::ITEMS); if (inventoryType != eInventoryType::ITEMS) bitStream.Write(inventoryType); @@ -458,7 +458,7 @@ void GameMessages::SendAddItemToInventoryClientSync(Entity* entity, const System if (itemCount != 1) bitStream.Write(itemCount); const auto count = item->GetCount(); - + bitStream.Write(count != 0); //items total if (count != 0) bitStream.Write(count); @@ -1008,7 +1008,7 @@ void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, if (GameConfig::GetValue("no_drops") == 1) { return; } - + bool bUsePosition = false; NiPoint3 finalPosition; LWOOBJID lootID = LWOOBJID_EMPTY; @@ -1063,7 +1063,7 @@ void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, if (spawnPos != NiPoint3::ZERO) bitStream.Write(spawnPos); auto* team = TeamManager::Instance()->GetTeam(owner); - + // Currency and powerups should not sync if (team != nullptr && currency == 0) { @@ -1086,7 +1086,7 @@ void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, return; } } - + SystemAddress sysAddr = entity->GetSystemAddress(); SEND_PACKET; } @@ -1097,7 +1097,7 @@ void GameMessages::SendSetPlayerControlScheme(Entity* entity, eControlSceme cont bool bDelayCamSwitchIfInCinematic = true; bool bSwitchCam = true; - + bitStream.Write(entity->GetObjectID()); bitStream.Write(uint16_t(GAME_MSG_SET_PLAYER_CONTROL_SCHEME)); @@ -1265,7 +1265,7 @@ void GameMessages::SendVendorStatusUpdate(Entity* entity, const SystemAddress& s bitStream.Write(entity->GetObjectID()); bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_STATUS_UPDATE); - bitStream.Write(bUpdateOnly); + bitStream.Write(bUpdateOnly); bitStream.Write(static_cast(vendorItems.size())); for (std::pair item : vendorItems) { @@ -1282,7 +1282,7 @@ void GameMessages::SendVendorTransactionResult(Entity* entity, const SystemAddre CMSGHEADER int iResult = 0x02; // success, seems to be the only relevant one - + bitStream.Write(entity->GetObjectID()); bitStream.Write(GAME_MSG::GAME_MSG_VENDOR_TRANSACTION_RESULT); bitStream.Write(iResult); @@ -1363,6 +1363,18 @@ void GameMessages::SendUseItemResult(Entity* entity, LOT templateID, bool useIte SEND_PACKET } +void GameMessages::SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, UseItemResponse itemResponse) { + CBITSTREAM + CMSGHEADER + + bitStream.Write(objectID); + bitStream.Write(GAME_MSG::GAME_MSG_USE_ITEM_REQUIREMENTS_RESPONSE); + + bitStream.Write(itemResponse); + + SEND_PACKET +} + void GameMessages::SendMoveInventoryBatch(Entity* entity, uint32_t stackCount, int srcInv, int dstInv, const LWOOBJID& iObjID) { CBITSTREAM CMSGHEADER @@ -1525,7 +1537,7 @@ void GameMessages::NotifyLevelRewards(LWOOBJID objectID, const SystemAddress& sy bitStream.Write(level); bitStream.Write(sending_rewards); - + SEND_PACKET } @@ -1537,7 +1549,7 @@ void GameMessages::SendSetShootingGalleryParams(LWOOBJID objectId, const SystemA NiPoint3 playerPosOffset, float projectileVelocity, float timeLimit, - bool bUseLeaderboards) + bool bUseLeaderboards) { CBITSTREAM CMSGHEADER @@ -1573,7 +1585,7 @@ void GameMessages::SendNotifyClientShootingGalleryScore(LWOOBJID objectId, const float addTime, int32_t score, LWOOBJID target, - NiPoint3 targetPos) + NiPoint3 targetPos) { CBITSTREAM CMSGHEADER @@ -1590,7 +1602,7 @@ 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 = NiPoint3::ZERO; @@ -1821,13 +1833,13 @@ void GameMessages::SendNotifyClientObject(const LWOOBJID& objectID, std::u16stri for (auto character : name) { bitStream.Write(character); } - + bitStream.Write(param1); - + bitStream.Write(param2); bitStream.Write(paramObj); - + bitStream.Write(uint32_t(paramStr.size())); for (auto character : paramStr) { bitStream.Write(character); @@ -1976,7 +1988,7 @@ void GameMessages::SendDownloadPropertyData(const LWOOBJID objectId, const Prope data.Serialize(bitStream); Game::logger->Log("SendDownloadPropertyData", "(%llu) sending property data (%d)\n", objectId, sysAddr == UNASSIGNED_SYSTEM_ADDRESS); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } @@ -1988,12 +2000,12 @@ void GameMessages::SendPropertyRentalResponse(const LWOOBJID objectId, const LWO bitStream.Write(objectId); bitStream.Write(GAME_MSG::GAME_MSG_PROPERTY_RENTAL_RESPONSE); - + bitStream.Write(cloneId); bitStream.Write(code); bitStream.Write(propertyId); bitStream.Write(rentDue); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } @@ -2066,7 +2078,7 @@ void GameMessages::SendZonePropertyModelEquipped(LWOOBJID objectId, LWOOBJID pla bitStream.Write(playerId); bitStream.Write(propertyId); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } @@ -2103,7 +2115,7 @@ void GameMessages::SendPlaceModelResponse(LWOOBJID objectId, const SystemAddress { bitStream.Write(response); } - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; @@ -2119,7 +2131,7 @@ void GameMessages::SendUGCEquipPreCreateBasedOnEditMode(LWOOBJID objectId, const bitStream.Write(modelCount); bitStream.Write(model); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } @@ -2238,7 +2250,7 @@ void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entit NiPoint3 startPosition = NiPoint3::ZERO; inStream->Read(start); - + if (inStream->ReadBit()) inStream->Read(distanceType); @@ -2261,7 +2273,7 @@ void GameMessages::HandleSetBuildMode(RakNet::BitStream* inStream, Entity* entit player->GetCharacter()->SetBuildMode(start); Game::logger->Log("GameMessages", "Sending build mode confirm (%i): (%d) (%i) (%d) (%i) (%llu)\n", entity->GetLOT(), start, distanceType, modePaused, modeValue, playerId); - + SendSetBuildModeConfirmed(entity->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS, start, false, modePaused, modeValue, playerId, startPosition); } @@ -2271,7 +2283,7 @@ void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Enti { return; } - + bool firstTime{}; bool success{}; int32_t sourceBag{}; @@ -2299,11 +2311,11 @@ void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Enti } Game::logger->Log("GameMessages", "Handling start building with item (%i): (%d) (%d) (%i) (%llu) (%i) (%i) (%llu) (%i) (%i)\n", entity->GetLOT(), firstTime, success, sourceBag, sourceId, sourceLot, sourceType, targetId, targetLot, targetType); - + auto* user = UserManager::Instance()->GetUser(sysAddr); auto* player = EntityManager::Instance()->GetEntity(user->GetLoggedInChar()); - + SendStartArrangingWithItem( player, sysAddr, @@ -2324,7 +2336,7 @@ void GameMessages::HandleStartBuildingWithItem(RakNet::BitStream* inStream, Enti void GameMessages::HandlePropertyEditorBegin(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { PropertyManagementComponent::Instance()->OnStartBuilding(); - + dZoneManager::Instance()->GetZoneControlObject()->OnZonePropertyEditBegin(); } @@ -2354,7 +2366,7 @@ void GameMessages::HandlePlacePropertyModel(RakNet::BitStream* inStream, Entity* LWOOBJID model; inStream->Read(model); - + PropertyManagementComponent::Instance()->UpdateModelPosition(model, NiPoint3::ZERO, NiQuaternion::IDENTITY); } @@ -2371,7 +2383,7 @@ void GameMessages::HandleUpdatePropertyModel(RakNet::BitStream* inStream, Entity { inStream->Read(rotation); } - + PropertyManagementComponent::Instance()->UpdateModelPosition(model, position, rotation); } @@ -2410,18 +2422,18 @@ void GameMessages::HandleBBBLoadItemRequest(RakNet::BitStream* inStream, Entity* void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { /* - ___ ___ - /\ /\___ _ __ ___ / __\ ___ / \_ __ __ _ __ _ ___ _ __ ___ + ___ ___ + /\ /\___ _ __ ___ / __\ ___ / \_ __ __ _ __ _ ___ _ __ ___ / /_/ / _ \ '__/ _ \ /__\/// _ \ / /\ / '__/ _` |/ _` |/ _ \| '_ \/ __| / __ / __/ | | __/ / \/ \ __/ / /_//| | | (_| | (_| | (_) | | | \__ \ \/ /_/ \___|_| \___| \_____/\___| /___,' |_| \__,_|\__, |\___/|_| |_|___/ - |___/ - ___ _ - / __\ _____ ____ _ _ __ ___ / \ - /__\/// _ \ \ /\ / / _` | '__/ _ \/ / - / \/ \ __/\ V V / (_| | | | __/\_/ - \_____/\___| \_/\_/ \__,_|_| \___\/ - + |___/ + ___ _ + / __\ _____ ____ _ _ __ ___ / \ + /__\/// _ \ \ /\ / / _` | '__/ _ \/ / + / \/ \ __/\ V V / (_| | | | __/\_/ + \_____/\___| \_/\_/ \__,_|_| \___\/ + <>=======() (/\___ /|\\ ()==========<>_ \_/ | \\ //|\ ______/ \) @@ -2451,7 +2463,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent uint8_t c; inStream->Read(c); } - + uint32_t lxfmlSize; inStream->Read(lxfmlSize); uint8_t* inData = static_cast(std::malloc(lxfmlSize)); @@ -2459,13 +2471,13 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent if (inData == nullptr) { return; } - + for (uint32_t i = 0; i < lxfmlSize; ++i) { uint8_t c; inStream->Read(c); inData[i] = c; } - + inStream->Read(timeTaken); /* @@ -2493,7 +2505,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent //Now, the cave of dragons: - //We runs this in async because the http library here is blocking, meaning it'll halt the thread. + //We runs this in async because the http library here is blocking, meaning it'll halt the thread. //But we don't want the server to go unresponsive, because then the client would disconnect. std::async(std::launch::async, [&]() { @@ -2515,11 +2527,11 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent const auto zoneId = worldId.GetMapID(); const auto cloneId = worldId.GetCloneID(); - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); + query.bind(1, (int) zoneId); - query << "SELECT id FROM PropertyTemplate WHERE mapID = " << std::to_string(zoneId) << ";"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof() || result.fieldIsNull(0)) { return; @@ -2583,7 +2595,7 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent */ ////Send off to UGC for processing, if enabled: - //if (Game::config->GetValue("ugc_remote") == "1") { + //if (Game::config->GetValue("ugc_remote") == "1") { // std::string ugcIP = Game::config->GetValue("ugc_ip"); // int ugcPort = std::stoi(Game::config->GetValue("ugc_port")); @@ -2738,7 +2750,7 @@ 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; @@ -2751,10 +2763,10 @@ void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity* inventory->SetConsumable(lot); } -void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, +void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener, int endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished, - bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) + bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) { CBITSTREAM; CMSGHEADER; @@ -2794,7 +2806,7 @@ void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, } void GameMessages::SendEndCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr, - float leadOut, bool leavePlayerLocked) + float leadOut, bool leavePlayerLocked) { CBITSTREAM; CMSGHEADER; @@ -2868,7 +2880,7 @@ void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, bool bCantAttackOutChangeWasApplied, bool bCantEquipOutChangeWasApplied, bool bCantInteractOutChangeWasApplied, bool bCantJumpOutChangeWasApplied, bool bCantMoveOutChangeWasApplied, bool bCantTurnOutChangeWasApplied, - bool bCantUseItemOutChangeWasApplied) + bool bCantUseItemOutChangeWasApplied) { CBITSTREAM; CMSGHEADER; @@ -2903,7 +2915,7 @@ void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, bitStream.Write(bCantUseItemOutChangeWasApplied); bitStream.Write(bDontTerminateInteract); - + bitStream.Write(bIgnoreImmunity); if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; @@ -2911,7 +2923,7 @@ void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, } -void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) +void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -2927,7 +2939,7 @@ void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, } -void GameMessages::SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, uint32_t modifier, const SystemAddress& sysAddr) +void GameMessages::SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, uint32_t modifier, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -2945,7 +2957,7 @@ void GameMessages::SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, u SEND_PACKET; } -void GameMessages::SendRemoveRunSpeedModifier(LWOOBJID objectId, uint32_t modifier, const SystemAddress& sysAddr) +void GameMessages::SendRemoveRunSpeedModifier(LWOOBJID objectId, uint32_t modifier, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -2997,7 +3009,7 @@ void GameMessages::SendPropertySelectQuery(LWOOBJID objectId, int32_t navOffset, SEND_PACKET; } -void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1, int param2) +void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std::u16string name, const SystemAddress& sysAddr, int param1, int param2) { CBITSTREAM; CMSGHEADER; @@ -3011,7 +3023,7 @@ void GameMessages::SendNotifyObject(LWOOBJID objectId, LWOOBJID objIDSender, std { bitStream.Write(character); } - + bitStream.Write(param1); bitStream.Write(param2); @@ -3019,7 +3031,7 @@ 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; @@ -3041,7 +3053,7 @@ void GameMessages::HandleVerifyAck(RakNet::BitStream* inStream, Entity* entity, } } -void GameMessages::SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJID lootOwnerID, const SystemAddress& sysAddr) +void GameMessages::SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJID lootOwnerID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3051,7 +3063,7 @@ void GameMessages::SendTeamPickupItem(LWOOBJID objectId, LWOOBJID lootID, LWOOBJ bitStream.Write(lootID); bitStream.Write(lootOwnerID); - + if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; SEND_PACKET; } @@ -3132,7 +3144,7 @@ void GameMessages::SendServerTradeAccept(LWOOBJID objectId, bool bFirst, const S SEND_PACKET; } -void GameMessages::SendServerTradeCancel(LWOOBJID objectId, const SystemAddress& sysAddr) +void GameMessages::SendServerTradeCancel(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3144,7 +3156,7 @@ void GameMessages::SendServerTradeCancel(LWOOBJID objectId, const SystemAddress& SEND_PACKET; } -void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, const std::vector& items, const SystemAddress& sysAddr) +void GameMessages::SendServerTradeUpdate(LWOOBJID objectId, uint64_t coins, const std::vector& items, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3230,7 +3242,7 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* { TradingManager::Instance()->NewTrade(entity->GetObjectID(), i64Invitee); } - + SendServerTradeInvite( i64Invitee, bNeedInvitePopUp, @@ -3244,7 +3256,7 @@ void GameMessages::HandleClientTradeRequest(RakNet::BitStream* inStream, Entity* void GameMessages::HandleClientTradeCancel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); - + if (trade == nullptr) return; Game::logger->Log("GameMessages", "Trade canceled from (%llu)\n", entity->GetObjectID()); @@ -3257,9 +3269,9 @@ void GameMessages::HandleClientTradeAccept(RakNet::BitStream* inStream, Entity* bool bFirst = inStream->ReadBit(); Game::logger->Log("GameMessages", "Trade accepted from (%llu) -> (%d)\n", entity->GetObjectID(), bFirst); - + auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); - + if (trade == nullptr) return; trade->SetAccepted(entity->GetObjectID(), bFirst); @@ -3331,9 +3343,9 @@ void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* Game::logger->Log("GameMessages", "Trade item from (%llu) -> (%llu)/(%llu), (%i), (%llu), (%i), (%i)\n", entity->GetObjectID(), itemId, itemId2, lot, unknown1, unknown2, unknown3); } - + auto* trade = TradingManager::Instance()->GetPlayerTrade(entity->GetObjectID()); - + if (trade == nullptr) return; trade->SetCoins(entity->GetObjectID(), currency); @@ -3343,7 +3355,7 @@ void GameMessages::HandleClientTradeUpdate(RakNet::BitStream* inStream, Entity* //Pets: -void GameMessages::SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId, LWOOBJID playerTamingId, bool bForceTeleport, uint32_t notifyType, NiPoint3 petsDestPos, NiPoint3 telePos, NiQuaternion teleRot, const SystemAddress& sysAddr) +void GameMessages::SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId, LWOOBJID playerTamingId, bool bForceTeleport, uint32_t notifyType, NiPoint3 petsDestPos, NiPoint3 telePos, NiQuaternion teleRot, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3366,7 +3378,7 @@ void GameMessages::SendNotifyPetTamingMinigame(LWOOBJID objectId, LWOOBJID petId SEND_PACKET; } -void GameMessages::SendNotifyTamingModelLoadedOnServer(LWOOBJID objectId, const SystemAddress& sysAddr) +void GameMessages::SendNotifyTamingModelLoadedOnServer(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3378,7 +3390,7 @@ void GameMessages::SendNotifyTamingModelLoadedOnServer(LWOOBJID objectId, const SEND_PACKET; } -void GameMessages::SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, std::vector& bricks, const SystemAddress& sysAddr) +void GameMessages::SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, std::vector& bricks, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3397,7 +3409,7 @@ void GameMessages::SendNotifyPetTamingPuzzleSelected(LWOOBJID objectId, std::vec SEND_PACKET; } -void GameMessages::SendPetTamingTryBuildResult(LWOOBJID objectId, bool bSuccess, int32_t iNumCorrect, const SystemAddress& sysAddr) +void GameMessages::SendPetTamingTryBuildResult(LWOOBJID objectId, bool bSuccess, int32_t iNumCorrect, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3413,7 +3425,7 @@ void GameMessages::SendPetTamingTryBuildResult(LWOOBJID objectId, bool bSuccess, SEND_PACKET; } -void GameMessages::SendPetResponse(LWOOBJID objectId, LWOOBJID objIDPet, int32_t iPetCommandType, int32_t iResponse, int32_t iTypeID, const SystemAddress& sysAddr) +void GameMessages::SendPetResponse(LWOOBJID objectId, LWOOBJID objIDPet, int32_t iPetCommandType, int32_t iResponse, int32_t iTypeID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3430,7 +3442,7 @@ void GameMessages::SendPetResponse(LWOOBJID objectId, LWOOBJID objIDPet, int32_t SEND_PACKET; } -void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType, std::u16string name, LWOOBJID petDBID, LOT petLOT, const SystemAddress& sysAddr) +void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType, std::u16string name, LWOOBJID petDBID, LOT petLOT, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3444,7 +3456,7 @@ void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType, { bitStream.Write(character); } - + bitStream.Write(petDBID); bitStream.Write(petLOT); @@ -3452,7 +3464,7 @@ void GameMessages::SendAddPetToPlayer(LWOOBJID objectId, int32_t iElementalType, SEND_PACKET; } -void GameMessages::SendRegisterPetID(LWOOBJID objectId, LWOOBJID objID, const SystemAddress& sysAddr) +void GameMessages::SendRegisterPetID(LWOOBJID objectId, LWOOBJID objID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3466,7 +3478,7 @@ void GameMessages::SendRegisterPetID(LWOOBJID objectId, LWOOBJID objID, const Sy SEND_PACKET; } -void GameMessages::SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, const SystemAddress& sysAddr) +void GameMessages::SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3480,7 +3492,7 @@ void GameMessages::SendRegisterPetDBID(LWOOBJID objectId, LWOOBJID petDBID, cons SEND_PACKET; } -void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, int32_t iType, LWOOBJID itemID, const SystemAddress& sysAddr) +void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive, int32_t iType, LWOOBJID itemID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3489,7 +3501,7 @@ void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive bitStream.Write(GAME_MSG::GAME_MSG_MARK_INVENTORY_ITEM_AS_ACTIVE); bitStream.Write(bActive); - + bitStream.Write(iType != 0); if (iType != 0) bitStream.Write(iType); @@ -3500,7 +3512,7 @@ void GameMessages::SendMarkInventoryItemAsActive(LWOOBJID objectId, bool bActive SEND_PACKET; } -void GameMessages::SendClientExitTamingMinigame(LWOOBJID objectId, bool bVoluntaryExit, const SystemAddress& sysAddr) +void GameMessages::SendClientExitTamingMinigame(LWOOBJID objectId, bool bVoluntaryExit, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3514,7 +3526,7 @@ void GameMessages::SendClientExitTamingMinigame(LWOOBJID objectId, bool bVolunta SEND_PACKET; } -void GameMessages::SendShowPetActionButton(LWOOBJID objectId, int32_t buttonLabel, bool bShow, const SystemAddress& sysAddr) +void GameMessages::SendShowPetActionButton(LWOOBJID objectId, int32_t buttonLabel, bool bShow, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3545,7 +3557,7 @@ void GameMessages::SendPlayEmote(LWOOBJID objectId, int32_t emoteID, LWOOBJID ta } -void GameMessages::SendBouncerActiveStatus(LWOOBJID objectId, bool bActive, const SystemAddress& sysAddr) +void GameMessages::SendBouncerActiveStatus(LWOOBJID objectId, bool bActive, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3560,7 +3572,7 @@ void GameMessages::SendBouncerActiveStatus(LWOOBJID objectId, bool bActive, cons } -void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJID petDBID, const SystemAddress& sysAddr) +void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJID petDBID, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3573,7 +3585,7 @@ void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJ { bitStream.Write(character); } - + bitStream.Write(petDBID != LWOOBJID_EMPTY); if (petDBID != LWOOBJID_EMPTY) bitStream.Write(petDBID); @@ -3582,14 +3594,14 @@ void GameMessages::SendSetPetName(LWOOBJID objectId, std::u16string name, LWOOBJ } -void GameMessages::SendSetPetNameModerated(LWOOBJID objectId, LWOOBJID petDBID, int32_t nModerationStatus, const SystemAddress& sysAddr) +void GameMessages::SendSetPetNameModerated(LWOOBJID objectId, LWOOBJID petDBID, int32_t nModerationStatus, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; bitStream.Write(objectId); bitStream.Write(GAME_MSG::GAME_MSG_SET_PET_NAME_MODERATED); - + bitStream.Write(petDBID != LWOOBJID_EMPTY); if (petDBID != LWOOBJID_EMPTY) bitStream.Write(petDBID); @@ -3600,7 +3612,7 @@ void GameMessages::SendSetPetNameModerated(LWOOBJID objectId, LWOOBJID petDBID, } -void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatus, std::u16string name, std::u16string ownerName, const SystemAddress& sysAddr) +void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatus, std::u16string name, std::u16string ownerName, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3615,7 +3627,7 @@ void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatu { bitStream.Write(character); } - + bitStream.Write(static_cast(ownerName.size())); for (const auto character : ownerName) { @@ -3627,7 +3639,7 @@ void GameMessages::SendPetNameChanged(LWOOBJID objectId, int32_t moderationStatu } -void GameMessages::HandleClientExitTamingMinigame(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) +void GameMessages::HandleClientExitTamingMinigame(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { bool bVoluntaryExit = inStream->ReadBit(); @@ -3641,7 +3653,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()); @@ -3653,7 +3665,7 @@ 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; @@ -3684,7 +3696,7 @@ 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; @@ -3700,7 +3712,7 @@ 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; @@ -3713,7 +3725,7 @@ void GameMessages::HandleRequestSetPetName(RakNet::BitStream* inStream, Entity* inStream->Read(character); name.push_back(character); } - + auto* petComponent = PetComponent::GetTamingPet(entity->GetObjectID()); if (petComponent == nullptr) @@ -3729,14 +3741,14 @@ 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); @@ -3753,7 +3765,7 @@ 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; @@ -3776,7 +3788,7 @@ 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; @@ -3801,7 +3813,7 @@ void GameMessages::HandleMessageBoxResponse(RakNet::BitStream* inStream, Entity* inStream->Read(character); userData.push_back(character); } - + Game::logger->Log("HandleMessageBoxResponse", "Button: " + std::to_string(iButton) + "; LOT: " + std::to_string(entity->GetLOT()) + " identifier: " + GeneralUtils::UTF16ToWTF8(identifier) + "; userData: " + GeneralUtils::UTF16ToWTF8(userData) + "\n"); auto* user = UserManager::Instance()->GetUser(sysAddr); @@ -3840,7 +3852,7 @@ 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; @@ -3865,7 +3877,7 @@ void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream* inStream, Entity* e inStream->Read(character); identifier.push_back(character); } - + Game::logger->Log("HandleChoiceBoxRespond", "Button: " + std::to_string(iButton) + "; LOT: " + std::to_string(entity->GetLOT()) + " buttonIdentifier: " + GeneralUtils::UTF16ToWTF8(buttonIdentifier) + "; userData: " + GeneralUtils::UTF16ToWTF8(identifier) + "\n"); auto* user = UserManager::Instance()->GetUser(sysAddr); @@ -3885,7 +3897,7 @@ void GameMessages::HandleChoiceBoxRespond(RakNet::BitStream* inStream, Entity* e entity->OnChoiceBoxResponse(userEntity, iButton, buttonIdentifier, identifier); } -void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap, bool isZoneStart, LWOOBJID sender) +void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress& sysAddr, bool isPropertyMap, bool isZoneStart, LWOOBJID sender) { CBITSTREAM; CMSGHEADER; @@ -3904,7 +3916,7 @@ void GameMessages::SendDisplayZoneSummary(LWOOBJID objectId, const SystemAddress //UI -void GameMessages::SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeSlotsNeeded, eInventoryType inventoryType, const SystemAddress& sysAddr) +void GameMessages::SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeSlotsNeeded, eInventoryType inventoryType, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3920,7 +3932,7 @@ void GameMessages::SendNotifyNotEnoughInvSpace(LWOOBJID objectId, uint32_t freeS SEND_PACKET; } -void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID callbackClient, const std::u16string& identifier, int32_t imageID, const std::u16string& text, const std::u16string& userData, const SystemAddress& sysAddr) +void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID callbackClient, const std::u16string& identifier, int32_t imageID, const std::u16string& text, const std::u16string& userData, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -3938,7 +3950,7 @@ void GameMessages::SendDisplayMessageBox(LWOOBJID objectId, bool bShow, LWOOBJID } bitStream.Write(imageID); - + bitStream.Write(static_cast(text.size())); for (const auto character : text) { @@ -3974,6 +3986,47 @@ void GameMessages::SendDisplayChatBubble(LWOOBJID objectId, const std::u16string SEND_PACKET; } +// Mounts + +void GameMessages::SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr){ + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(entity->GetObjectID()); + bitStream.Write(GAME_MSG::GAME_MSG_SET_MOUNT_INVENTORY_ID); + bitStream.Write(objectID); + + SEND_PACKET_BROADCAST; +} + + +void GameMessages::HandleDismountComplete(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr){ + LWOOBJID objectId{}; + inStream->Read(objectId); + auto* mount = EntityManager::Instance()->GetEntity(objectId); + + if (objectId != LWOOBJID_EMPTY) { + PossessorComponent* possessor; + if (entity->TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessor)) { + if (mount) { + possessor->SetIsBusy(false); + possessor->SetPossessable(LWOOBJID_EMPTY); + possessor->SetPossessableType(ePossessionType::NO_POSSESSION); + + GameMessages::SendSetStunned(entity->GetObjectID(), eStunState::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); + + EntityManager::Instance()->SerializeEntity(entity); + } + } + } +} + + +void GameMessages::HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { + Game::logger->Log("HandleAcknowledgePossession", "Got AcknowledgePossession from %i\n", entity->GetLOT()); + EntityManager::Instance()->SerializeEntity(entity); +} + //Racing void GameMessages::HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) @@ -3986,12 +4039,12 @@ void GameMessages::HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, En { Game::logger->Log("HandleModuleAssemblyQueryData", "Returning assembly %s\n", GeneralUtils::UTF16ToWTF8(moduleAssemblyComponent->GetAssemblyPartsLOTs()).c_str()); - SendModuleAssemblyDBDataForClient(entity->GetObjectID(), moduleAssemblyComponent->GetSubKey(), moduleAssemblyComponent->GetAssemblyPartsLOTs(), UNASSIGNED_SYSTEM_ADDRESS); + SendModuleAssemblyDBDataForClient(entity->GetObjectID(), moduleAssemblyComponent->GetSubKey(), moduleAssemblyComponent->GetAssemblyPartsLOTs(), UNASSIGNED_SYSTEM_ADDRESS); } } -void GameMessages::HandleModularAssemblyNIFCompleted(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) +void GameMessages::HandleModularAssemblyNIFCompleted(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { LWOOBJID objectID; @@ -3999,14 +4052,14 @@ void GameMessages::HandleModularAssemblyNIFCompleted(RakNet::BitStream* inStream } -void GameMessages::HandleVehicleSetWheelLockState(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) +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; @@ -4030,15 +4083,7 @@ void GameMessages::HandleRacingClientReady(RakNet::BitStream* inStream, Entity* } -void GameMessages::HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) -{ - Game::logger->Log("HandleAcknowledgePossession", "Got AcknowledgePossession from %i\n", entity->GetLOT()); - - EntityManager::Instance()->SerializeEntity(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; @@ -4052,7 +4097,7 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, bClientDeath = inStream->ReadBit(); bSpawnLoot = inStream->ReadBit(); - + uint32_t deathTypeLength = 0; inStream->Read(deathTypeLength); @@ -4111,13 +4156,13 @@ void GameMessages::HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStr } -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; @@ -4178,7 +4223,7 @@ void GameMessages::HandleUpdatePropertyPerformanceCost(RakNet::BitStream* inStre updatePerformanceCostQuery = nullptr; } -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; @@ -4338,7 +4383,7 @@ void GameMessages::SendRacingResetPlayerToLastReset(LWOOBJID objectId, LWOOBJID } -void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, int32_t param1, LWOOBJID paramObj, std::u16string paramStr, LWOOBJID singleClient, const SystemAddress& sysAddr) +void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, int32_t param1, LWOOBJID paramObj, std::u16string paramStr, LWOOBJID singleClient, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -4366,7 +4411,7 @@ void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, } -void GameMessages::SendActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr) +void GameMessages::SendActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -4379,7 +4424,7 @@ void GameMessages::SendActivityEnter(LWOOBJID objectId, const SystemAddress& sys } -void GameMessages::SendActivityStart(LWOOBJID objectId, const SystemAddress& sysAddr) +void GameMessages::SendActivityStart(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -4392,7 +4437,7 @@ void GameMessages::SendActivityStart(LWOOBJID objectId, const SystemAddress& sys } -void GameMessages::SendActivityExit(LWOOBJID objectId, const SystemAddress& sysAddr) +void GameMessages::SendActivityExit(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -4405,7 +4450,7 @@ void GameMessages::SendActivityExit(LWOOBJID objectId, const SystemAddress& sysA } -void GameMessages::SendActivityStop(LWOOBJID objectId, bool bExit, bool bUserCancel, const SystemAddress& sysAddr) +void GameMessages::SendActivityStop(LWOOBJID objectId, bool bExit, bool bUserCancel, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -4447,7 +4492,7 @@ void GameMessages::SendVehicleRemovePassiveBoostAction(LWOOBJID objectId, const } -void GameMessages::SendVehicleNotifyFinishedRace(LWOOBJID objectId, const SystemAddress& sysAddr) +void GameMessages::SendVehicleNotifyFinishedRace(LWOOBJID objectId, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -4549,7 +4594,7 @@ void GameMessages::HandleRequestMoveItemBetweenInventoryTypes(RakNet::BitStream* } -void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr) +void GameMessages::SendShowActivityCountdown(LWOOBJID objectId, bool bPlayAdditionalSound, bool bPlayCountdownSound, std::u16string sndName, int32_t stateToPlaySoundOn, const SystemAddress& sysAddr) { CBITSTREAM; CMSGHEADER; @@ -4578,7 +4623,7 @@ 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; @@ -4589,13 +4634,13 @@ void GameMessages::HandleToggleGhostReferenceOverride(RakNet::BitStream* inStrea if (player != nullptr) { player->SetGhostOverride(bOverride); - + EntityManager::Instance()->UpdateGhosting(player); } } -void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) +void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) { NiPoint3 position; @@ -4638,7 +4683,7 @@ void GameMessages::HandleBuyFromVendor(RakNet::BitStream* inStream, Entity* enti } const auto isCommendationVendor = entity->GetLOT() == 13806; - + VendorComponent* vend = static_cast(entity->GetComponent(COMPONENT_TYPE_VENDOR)); if (!vend && !isCommendationVendor) return; @@ -4911,7 +4956,7 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity LWOCLONEID cloneId = 0; LWOMAPID mapId = 0; - + auto* rocketPad = entity->GetComponent(); if (rocketPad == nullptr) return; @@ -4936,7 +4981,7 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity } Game::logger->Log("FireEventServerSide", "Player %llu has requested zone transfer to (%i, %i).\n", sender->GetObjectID(), (int) mapId, (int) cloneId); - + auto* character = player->GetCharacter(); if (mapId <= 0) { @@ -4945,7 +4990,7 @@ void GameMessages::HandleFireEventServerSide(RakNet::BitStream* inStream, Entity ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, mapId, cloneId, false, [=](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", character->GetName().c_str(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - + if (character) { character->SetZoneID(zoneID); character->SetZoneInstance(zoneInstance); @@ -4999,12 +5044,12 @@ void GameMessages::HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, return; } - + if (interactedObject->GetLOT() == 9524) { entity->GetCharacter()->SetBuildMode(true); } - + if (bIsMultiInteractUse) { if (multiInteractType == 0) @@ -5027,7 +5072,7 @@ void GameMessages::HandleRequestUse(RakNet::BitStream* inStream, Entity* entity, //Perform use task if possible: auto missionComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION)); - + if (missionComponent == nullptr) return; missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_MISSION_INTERACTION, interactedObject->GetLOT(), interactedObject->GetObjectID()); @@ -5042,7 +5087,7 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) inStream->Read(targetID); Game::logger->Log("GameMessages", "Emote (%i) (%llu)\n", emoteID, targetID); - + //TODO: If targetID != 0, and we have one of the "perform emote" missions, complete them. if (emoteID == 0) return; @@ -5052,13 +5097,13 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity) if (mission) { mission->Progress(MissionTaskType::MISSION_TASK_TYPE_EMOTE, emoteID, targetID); } - + if (targetID != LWOOBJID_EMPTY) { auto* targetEntity = EntityManager::Instance()->GetEntity(targetID); Game::logger->Log("GameMessages", "Emote target found (%d)\n", targetEntity != nullptr); - + if (targetEntity != nullptr) { targetEntity->OnEmoteReceived(emoteID, entity); @@ -5210,7 +5255,7 @@ void GameMessages::HandleRequestLinkedMission(RakNet::BitStream* inStream, Entit auto* player = EntityManager::Instance()->GetEntity(playerId); auto* missionOfferComponent = static_cast(entity->GetComponent(COMPONENT_TYPE_MISSION_OFFER)); - + if (missionOfferComponent != nullptr) { missionOfferComponent->OfferMissions(player, 0); @@ -5233,7 +5278,7 @@ void GameMessages::HandleHasBeenCollected(RakNet::BitStream* inStream, Entity* e void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* inStream, Entity* entity) { auto* character = static_cast(entity->GetComponent(COMPONENT_TYPE_CHARACTER)); if (!character) return; - + //Update our character's level in memory: character->SetLevel(character->GetLevel() + 1); @@ -5269,7 +5314,7 @@ void GameMessages::HandleNotifyServerLevelProcessingComplete(RakNet::BitStream* void GameMessages::HandlePickupCurrency(RakNet::BitStream* inStream, Entity* entity) { unsigned int currency; inStream->Read(currency); - + if (currency == 0) return; auto* ch = entity->GetCharacter(); @@ -5294,7 +5339,7 @@ void GameMessages::HandleRequestDie(RakNet::BitStream* inStream, Entity* entity) inStream->Read(bClientDeath); inStream->Read(bDieAccepted); inStream->Read(bSpawnLoot); - + bool coinSpawnTimeIsDefault{}; inStream->Read(coinSpawnTimeIsDefault); if (coinSpawnTimeIsDefault != 0) inStream->Read(coinSpawnTime); @@ -5331,7 +5376,7 @@ void GameMessages::HandleEquipItem(RakNet::BitStream* inStream, Entity* entity) if (!item) return; item->Equip(); - + EntityManager::Instance()->SerializeEntity(entity); } @@ -5349,9 +5394,9 @@ void GameMessages::HandleUnequipItem(RakNet::BitStream* inStream, Entity* entity auto* item = inv->FindItemById(objectID); if (!item) return; - + item->UnEquip(); - + EntityManager::Instance()->SerializeEntity(entity); } @@ -5427,9 +5472,9 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream* inStream, En { return; } - + iStackCount = std::min(item->GetCount(), iStackCount); - + if (bConfirmed) { for (auto i = 0; i < iStackCount; ++i) { if (eInvType == eInventoryType::MODELS) @@ -5442,7 +5487,7 @@ void GameMessages::HandleRemoveItemFromInventory(RakNet::BitStream* inStream, En EntityManager::Instance()->SerializeEntity(entity); auto* missionComponent = entity->GetComponent(); - + if (missionComponent != nullptr) { missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, item->GetLot(), LWOOBJID_EMPTY, "", -iStackCount); @@ -5502,16 +5547,18 @@ void GameMessages::HandleMoveItemBetweenInventoryTypes(RakNet::BitStream* inStre auto* item = inv->FindItemById(objectID); - if (item == nullptr) - { - item = inv->FindItemByLot(templateID); - - if (item == nullptr) - { - return; + if (!item) { + // Attempt to find the item by lot in inventory A since A is the source inventory. + item = inv->FindItemByLot(templateID, static_cast(inventoryTypeA)); + if (!item) { + // As a final resort, try to find the item in its default inventory based on type. + item = inv->FindItemByLot(templateID); + if (!item) { + return; + } } } - + if (entity->GetCharacter()) { if (entity->GetCharacter()->GetBuildMode()) { showFlyingLoot = false; @@ -5529,7 +5576,7 @@ void GameMessages::HandleBuildModeSet(RakNet::BitStream* inStream, Entity* entit // there's more here but we don't need it (for now?) Game::logger->Log("GameMessages", "Set build mode to (%d) for (%llu)\n", bStart, entity->GetObjectID()); - + if (entity->GetCharacter()) { entity->GetCharacter()->SetBuildMode(bStart); } @@ -5593,7 +5640,7 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity* } auto* missionComponent = character->GetComponent(); - + if (entity->GetLOT() != 9980 || Game::server->GetZoneID() != 1200) { if (missionComponent != nullptr) @@ -5672,7 +5719,7 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti inStream->Read(oldItemTYPE); /* - Game::logger->Log("GameMessages", + Game::logger->Log("GameMessages", "\nnewSourceBAG: %d\nnewSourceID: %llu\nnewSourceLOT: %d\nnewSourceTYPE: %d\nnewTargetID: %llu\nnewTargetLOT: %d\nnewTargetTYPE: %d\nnewTargetPOS: %f, %f, %f\noldItemBAG: %d\noldItemID: %llu\noldItemLOT: %d\noldItemTYPE: %d\n", newSourceBAG, newSourceID, newSourceLOT, newSourceTYPE, newTargetID, newTargetLOT, newTargetTYPE, newTargetPOS.x, newTargetPOS.y, newTargetPOS.z, oldItemBAG, oldItemID, oldItemLOT, oldItemTYPE ); @@ -5680,7 +5727,7 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti if (PropertyManagementComponent::Instance() != nullptr) { const auto& buildAreas = EntityManager::Instance()->GetEntitiesByComponent(COMPONENT_TYPE_BUILD_BORDER); - + const auto& entities = EntityManager::Instance()->GetEntitiesInGroup("PropertyPlaque"); Entity* buildArea; @@ -5690,7 +5737,7 @@ void GameMessages::HandleDoneArrangingWithItem(RakNet::BitStream* inStream, Enti } else if (!entities.empty()) { buildArea = entities[0]; - + Game::logger->Log("BuildBorderComponent", "Using PropertyPlaque\n"); } else { @@ -5825,7 +5872,7 @@ void GameMessages::HandleClientItemConsumed(RakNet::BitStream* inStream, Entity* inStream->Read(itemConsumed); auto* inventory = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); - + if (inventory == nullptr) { return; @@ -5852,13 +5899,13 @@ void GameMessages::HandleUseNonEquipmentItem(RakNet::BitStream* inStream, Entity LWOOBJID itemConsumed; inStream->Read(itemConsumed); - + auto* inv = static_cast(entity->GetComponent(COMPONENT_TYPE_INVENTORY)); - + if (!inv) return; auto* item = inv->FindItemById(itemConsumed); - + if (item == nullptr) { return; diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 602cb4b2..18e1467e 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -328,6 +328,34 @@ namespace GameMessages { void SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr); + // Mounts + /** + * @brief Set the Inventory LWOOBJID of the mount + * + * @param entity The entity that is mounting + * @param sysAddr the system address to send game message responses to + * @param objectID LWOOBJID of the item in inventory that is being used + */ + void SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr); + + /** + * @brief Handle client dismounting mount + * + * @param inStream Raknet BitStream of incoming data + * @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); + + /** + * @brief Handle acknowledging that the client possessed something + * + * @param inStream Raknet BitStream of incoming data + * @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); + //Racing: void HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); @@ -337,8 +365,6 @@ namespace GameMessages { void HandleRacingClientReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); - void HandleAcknowledgePossession(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); @@ -372,6 +398,7 @@ namespace GameMessages { void SendActivityPause(LWOOBJID objectId, bool pause = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SendStartActivityTime(LWOOBJID objectId, float_t startTime, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); void SendRequestActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr, bool bStart, LWOOBJID userID); + void SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, UseItemResponse itemResponse); // SG: diff --git a/dGame/dGameMessages/PropertySelectQueryProperty.h b/dGame/dGameMessages/PropertySelectQueryProperty.h index 61fa7b86..e633f41b 100644 --- a/dGame/dGameMessages/PropertySelectQueryProperty.h +++ b/dGame/dGameMessages/PropertySelectQueryProperty.h @@ -1,5 +1,8 @@ #pragma once +#ifndef PROPERTYSELECTQUERY_H +#define PROPERTYSELECTQUERY_H + #include "Entity.h" class PropertySelectQueryProperty final @@ -24,3 +27,5 @@ public: float PerformanceCost = 0; // The performance cost of the property uint32_t PerformanceIndex = 0; // The performance index of the property? Always 0? }; + +#endif diff --git a/dGame/dInventory/CMakeLists.txt b/dGame/dInventory/CMakeLists.txt new file mode 100644 index 00000000..60cfca75 --- /dev/null +++ b/dGame/dInventory/CMakeLists.txt @@ -0,0 +1,5 @@ +set(DGAME_DINVENTORY_SOURCES "EquippedItem.cpp" + "Inventory.cpp" + "Item.cpp" + "ItemSet.cpp" + "ItemSetPassiveAbility.cpp" PARENT_SCOPE) diff --git a/dGame/dInventory/Inventory.cpp b/dGame/dInventory/Inventory.cpp index 6e8be6aa..53ff37b4 100644 --- a/dGame/dInventory/Inventory.cpp +++ b/dGame/dInventory/Inventory.cpp @@ -1,7 +1,8 @@ -#include "Inventory.h" +#include "Inventory.h" #include "GameMessages.h" #include "Game.h" #include "Item.h" +#include "eItemType.h" std::vector Inventory::m_GameMasterRestrictedItems = { 1727, // GM Only - JetPack @@ -274,40 +275,41 @@ eInventoryType Inventory::FindInventoryTypeForLot(const LOT lot) const auto itemType = static_cast(itemComponent.itemType); switch (itemType) { - case ITEM_TYPE_BRICK: + case eItemType::ITEM_TYPE_BRICK: return BRICKS; - case ITEM_TYPE_BEHAVIOR: + case eItemType::ITEM_TYPE_BEHAVIOR: return BEHAVIORS; - case ITEM_TYPE_PROPERTY: + case eItemType::ITEM_TYPE_PROPERTY: return PROPERTY_DEEDS; - case ITEM_TYPE_MODEL: - case ITEM_TYPE_VEHICLE: - case ITEM_TYPE_LOOT_MODEL: + case eItemType::ITEM_TYPE_MODEL: + case eItemType::ITEM_TYPE_VEHICLE: + case eItemType::ITEM_TYPE_LOOT_MODEL: + case eItemType::ITEM_TYPE_MOUNT: return MODELS; - case ITEM_TYPE_HAT: - case ITEM_TYPE_HAIR: - case ITEM_TYPE_NECK: - case ITEM_TYPE_LEFT_HAND: - case ITEM_TYPE_RIGHT_HAND: - case ITEM_TYPE_LEGS: - case ITEM_TYPE_LEFT_TRINKET: - case ITEM_TYPE_RIGHT_TRINKET: - case ITEM_TYPE_COLLECTIBLE: - case ITEM_TYPE_CONSUMABLE: - case ITEM_TYPE_CHEST: - case ITEM_TYPE_EGG: - case ITEM_TYPE_PET_FOOD: - case ITEM_TYPE_PET_INVENTORY_ITEM: - case ITEM_TYPE_PACKAGE: - case ITEM_TYPE_CURRENCY: + case eItemType::ITEM_TYPE_HAT: + case eItemType::ITEM_TYPE_HAIR: + case eItemType::ITEM_TYPE_NECK: + case eItemType::ITEM_TYPE_LEFT_HAND: + case eItemType::ITEM_TYPE_RIGHT_HAND: + case eItemType::ITEM_TYPE_LEGS: + case eItemType::ITEM_TYPE_LEFT_TRINKET: + case eItemType::ITEM_TYPE_RIGHT_TRINKET: + case eItemType::ITEM_TYPE_COLLECTIBLE: + case eItemType::ITEM_TYPE_CONSUMABLE: + case eItemType::ITEM_TYPE_CHEST: + case eItemType::ITEM_TYPE_EGG: + case eItemType::ITEM_TYPE_PET_FOOD: + case eItemType::ITEM_TYPE_PET_INVENTORY_ITEM: + case eItemType::ITEM_TYPE_PACKAGE: + case eItemType::ITEM_TYPE_CURRENCY: return ITEMS; - case ITEM_TYPE_QUEST_OBJECT: - case ITEM_TYPE_UNKNOWN: + case eItemType::ITEM_TYPE_QUEST_OBJECT: + case eItemType::ITEM_TYPE_UNKNOWN: default: return HIDDEN; } diff --git a/dGame/dInventory/Inventory.h b/dGame/dInventory/Inventory.h index 0d3d9e69..b65a2040 100644 --- a/dGame/dInventory/Inventory.h +++ b/dGame/dInventory/Inventory.h @@ -1,5 +1,8 @@ #pragma once +#ifndef INVENTORY_H +#define INVENTORY_H + #include #include @@ -182,3 +185,5 @@ private: */ static std::vector m_GameMasterRestrictedItems; }; + +#endif diff --git a/dGame/dInventory/Item.cpp b/dGame/dInventory/Item.cpp index a8e8d408..0d254e5b 100644 --- a/dGame/dInventory/Item.cpp +++ b/dGame/dInventory/Item.cpp @@ -311,7 +311,9 @@ bool Item::UseNonEquip() const auto success = !packages.empty(); - Game::logger->Log("Item", "Used (%i) with (%d)\n", lot, success); + auto inventoryComponent = inventory->GetComponent(); + + auto playerEntity = inventoryComponent->GetParent(); if (subKey != LWOOBJID_EMPTY) { @@ -324,8 +326,7 @@ bool Item::UseNonEquip() return true; } } - - if (success) + if (success && (playerEntity->GetGMLevel() >= eGameMasterLevel::GAME_MASTER_LEVEL_JUNIOR_DEVELOPER || this->GetPreconditionExpression()->Check(playerEntity))) { auto* entityParent = inventory->GetComponent()->GetParent(); @@ -342,7 +343,7 @@ bool Item::UseNonEquip() LootGenerator::Instance().GiveLoot(inventory->GetComponent()->GetParent(), result, eLootSourceType::LOOT_SOURCE_CONSUMPTION); } - + Game::logger->Log("Item", "Used (%i)\n", lot); inventory->GetComponent()->RemoveItem(lot, 1); } @@ -386,11 +387,11 @@ void Item::DisassembleModel() const auto componentId = table->GetByIDAndType(GetLot(), COMPONENT_TYPE_RENDER); - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT render_asset FROM RenderComponent WHERE id = ?;"); + query.bind(1, (int) componentId); - query << "SELECT render_asset FROM RenderComponent WHERE id = " << std::to_string(componentId) << ";"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof()) { diff --git a/dGame/dInventory/ItemSet.cpp b/dGame/dInventory/ItemSet.cpp index d1e74df4..feddd757 100644 --- a/dGame/dInventory/ItemSet.cpp +++ b/dGame/dInventory/ItemSet.cpp @@ -15,17 +15,17 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) this->m_PassiveAbilities = ItemSetPassiveAbility::FindAbilities(id, m_InventoryComponent->GetParent(), this); - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT skillSetWith2, skillSetWith3, skillSetWith4, skillSetWith5, skillSetWith6, itemIDs FROM ItemSets WHERE setID = ?;"); + query.bind(1, (int) id); - query << "SELECT skillSetWith2, skillSetWith3, skillSetWith4, skillSetWith5, skillSetWith6, itemIDs FROM ItemSets WHERE setID = " << std::to_string(id); - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof()) { return; } - + for (auto i = 0; i < 5; ++i) { if (result.fieldIsNull(i)) @@ -33,11 +33,11 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) continue; } - std::stringstream skillQuery; + auto skillQuery = CDClientDatabase::CreatePreppedStmt( + "SELECT SkillID FROM ItemSetSkills WHERE SkillSetID = ?;"); + skillQuery.bind(1, result.getIntField(i)); - skillQuery << "SELECT SkillID FROM ItemSetSkills WHERE SkillSetID = " << std::to_string(result.getIntField(i)); - - auto skillResult = CDClientDatabase::ExecuteQuery(skillQuery.str()); + auto skillResult = skillQuery.execQuery(); if (skillResult.eof()) { @@ -49,10 +49,10 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) if (skillResult.fieldIsNull(0)) { skillResult.nextRow(); - + continue; } - + const auto skillId = skillResult.getIntField(0); switch (i) @@ -75,7 +75,7 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) default: break; } - + skillResult.nextRow(); } } @@ -83,7 +83,7 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) std::string ids = result.getStringField(5); ids.erase(std::remove_if(ids.begin(), ids.end(), ::isspace), ids.end()); - + std::istringstream stream(ids); std::string token; @@ -99,9 +99,9 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) m_Items.push_back(value); } } - + m_Equipped = {}; - + for (const auto item : m_Items) { if (inventoryComponent->IsEquipped(item)) @@ -141,11 +141,11 @@ void ItemSet::OnEquip(const LOT lot) auto* skillComponent = m_InventoryComponent->GetParent()->GetComponent(); auto* missionComponent = m_InventoryComponent->GetParent()->GetComponent(); - + for (const auto skill : skillSet) { auto* skillTable = CDClientManager::Instance()->GetTable("SkillBehavior"); - + const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID; missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, skill); @@ -167,11 +167,11 @@ void ItemSet::OnUnEquip(const LOT lot) { return; } - + const auto& skillSet = GetSkillSet(m_Equipped.size()); m_Equipped.erase(index); - + if (skillSet.empty()) { return; @@ -199,7 +199,7 @@ uint32_t ItemSet::GetID() const return m_ID; } -void ItemSet::Update(float deltaTime) +void ItemSet::Update(float deltaTime) { for (auto& passiveAbility : m_PassiveAbilities) { @@ -207,7 +207,7 @@ void ItemSet::Update(float deltaTime) } } -void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger) +void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger) { for (auto& passiveAbility : m_PassiveAbilities) { diff --git a/dGame/dMission/CMakeLists.txt b/dGame/dMission/CMakeLists.txt new file mode 100644 index 00000000..652c3cb2 --- /dev/null +++ b/dGame/dMission/CMakeLists.txt @@ -0,0 +1,3 @@ +set(DGAME_DMISSION_SOURCES "Mission.cpp" + "MissionPrerequisites.cpp" + "MissionTask.cpp" PARENT_SCOPE) diff --git a/dGame/dMission/Mission.cpp b/dGame/dMission/Mission.cpp index 31987505..aeb26838 100644 --- a/dGame/dMission/Mission.cpp +++ b/dGame/dMission/Mission.cpp @@ -421,7 +421,9 @@ void Mission::YieldRewards() { if (param.empty() || (param[0] & 1) == 0) // Should items be removed? { for (const auto target : task->GetAllTargets()) { - inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue); + // This is how live did it. ONLY remove item collection items from the items and hidden inventories and none of the others. + inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::ITEMS); + inventoryComponent->RemoveItem(target, task->GetClientInfo().targetValue, eInventoryType::HIDDEN); missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, target, LWOOBJID_EMPTY, "", -task->GetClientInfo().targetValue); } diff --git a/dGame/dMission/Mission.h b/dGame/dMission/Mission.h index cca72daf..4fb6c60f 100644 --- a/dGame/dMission/Mission.h +++ b/dGame/dMission/Mission.h @@ -1,5 +1,8 @@ #pragma once +#ifndef MISSION_H +#define MISSION_H + #include #include @@ -259,3 +262,5 @@ private: */ std::vector m_Tasks; }; + +#endif diff --git a/dGame/dMission/MissionLockState.h b/dGame/dMission/MissionLockState.h index 417c066a..e2dcedd7 100644 --- a/dGame/dMission/MissionLockState.h +++ b/dGame/dMission/MissionLockState.h @@ -1,8 +1,13 @@ #pragma once +#ifndef MISSIONLOCKSTATE_H +#define MISSIONLOCKSTATE_H + enum class MissionLockState : int { MISSION_LOCK_LOCKED, MISSION_LOCK_NEW, MISSION_LOCK_UNLOCKED, }; + +#endif diff --git a/dGame/dMission/MissionState.h b/dGame/dMission/MissionState.h index 161a4021..c189c708 100644 --- a/dGame/dMission/MissionState.h +++ b/dGame/dMission/MissionState.h @@ -1,5 +1,8 @@ #pragma once +#ifndef __MISSIONSTATE__H__ +#define __MISSIONSTATE__H__ + /** * Represents the possible states a mission can be in */ @@ -49,3 +52,5 @@ enum class MissionState : int { */ MISSION_STATE_COMPLETE_READY_TO_COMPLETE = 12 }; + +#endif //!__MISSIONSTATE__H__ diff --git a/dGame/dMission/MissionTask.h b/dGame/dMission/MissionTask.h index b77b9c59..3fcbbe3d 100644 --- a/dGame/dMission/MissionTask.h +++ b/dGame/dMission/MissionTask.h @@ -1,5 +1,8 @@ #pragma once +#ifndef MISSIONTASK_H +#define MISSIONTASK_H + #include "CDMissionTasksTable.h" #include "MissionTaskType.h" #include "dCommonVars.h" @@ -180,3 +183,5 @@ private: */ void CheckCompletion() const; }; + +#endif diff --git a/dGame/dMission/MissionTaskType.h b/dGame/dMission/MissionTaskType.h index 263bf470..345f8fff 100644 --- a/dGame/dMission/MissionTaskType.h +++ b/dGame/dMission/MissionTaskType.h @@ -1,5 +1,8 @@ #pragma once +#ifndef MISSIONTASKTYPE_H +#define MISSIONTASKTYPE_H + //! An enum for mission task types enum class MissionTaskType : int { MISSION_TASK_TYPE_UNKNOWN = -1, //!< The task type is unknown @@ -24,3 +27,5 @@ enum class MissionTaskType : int { MISSION_TASK_TYPE_PLACE_MODEL = 25, //!< A task for picking up a model MISSION_TASK_TYPE_VISIT_PROPERTY = 30 //!< A task for visiting a property }; + +#endif diff --git a/dGame/dUtilities/CMakeLists.txt b/dGame/dUtilities/CMakeLists.txt new file mode 100644 index 00000000..0c848bf4 --- /dev/null +++ b/dGame/dUtilities/CMakeLists.txt @@ -0,0 +1,9 @@ +set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp" + "dLocale.cpp" + "GameConfig.cpp" + "GUID.cpp" + "Loot.cpp" + "Mail.cpp" + "Preconditions.cpp" + "SlashCommandHandler.cpp" + "VanityUtilities.cpp" PARENT_SCOPE) diff --git a/dGame/dUtilities/Mail.cpp b/dGame/dUtilities/Mail.cpp index 79e99c7d..7e77cd77 100644 --- a/dGame/dUtilities/Mail.cpp +++ b/dGame/dUtilities/Mail.cpp @@ -306,9 +306,9 @@ void Mail::HandleDataRequest(RakNet::BitStream* packet, const SystemAddress& sys WriteToPacket(&bitStream, body, 400); WriteToPacket(&bitStream, sender, 32);*/ - WriteStringAsWString(&bitStream, res->getString(7), 50); //subject - WriteStringAsWString(&bitStream, res->getString(8), 400); //body - WriteStringAsWString(&bitStream, res->getString(3), 32); //sender + WriteStringAsWString(&bitStream, res->getString(7).c_str(), 50); //subject + WriteStringAsWString(&bitStream, res->getString(8).c_str(), 400); //body + WriteStringAsWString(&bitStream, res->getString(3).c_str(), 32); //sender bitStream.Write(uint32_t(0)); bitStream.Write(uint64_t(0)); diff --git a/dGame/dUtilities/Preconditions.cpp b/dGame/dUtilities/Preconditions.cpp index b29af130..bd10b814 100644 --- a/dGame/dUtilities/Preconditions.cpp +++ b/dGame/dUtilities/Preconditions.cpp @@ -15,20 +15,19 @@ std::map Preconditions::cache = {}; -Precondition::Precondition(const uint32_t condition) -{ - std::stringstream query; +Precondition::Precondition(const uint32_t condition) { + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT type, targetLOT, targetCount FROM Preconditions WHERE id = ?;"); + query.bind(1, (int) condition); - query << "SELECT type, targetLOT, targetCount FROM Preconditions WHERE id = " << std::to_string(condition) << ";"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof()) { this->type = PreconditionType::ItemEquipped; this->count = 1; this->values = { 0 }; - + Game::logger->Log("Precondition", "Failed to find precondition of id (%i)!\n", condition); return; @@ -99,11 +98,11 @@ bool Precondition::Check(Entity* player, bool evaluateCosts) const } auto passedAny = false; - + for (const auto value : values) { const auto passed = CheckValue(player, value, evaluateCosts); - + if (passed && any) { return true; @@ -222,7 +221,7 @@ PreconditionExpression::PreconditionExpression(const std::string& conditions) return; } - + std::stringstream a; std::stringstream b; @@ -310,16 +309,16 @@ bool PreconditionExpression::Check(Entity* player, bool evaluateCosts) const { return true; } - + const auto a = Preconditions::Check(player, condition, evaluateCosts); if (!a) { GameMessages::SendNotifyClientFailedPrecondition(player->GetObjectID(), player->GetSystemAddress(), u"", condition); } - - const auto b = next == nullptr ? true : next->Check(player); - + + const auto b = next == nullptr ? true : next->Check(player, evaluateCosts); + return m_or ? a || b : a && b; } diff --git a/dGame/dUtilities/SlashCommandHandler.cpp b/dGame/dUtilities/SlashCommandHandler.cpp index 266986c9..2226c76d 100644 --- a/dGame/dUtilities/SlashCommandHandler.cpp +++ b/dGame/dUtilities/SlashCommandHandler.cpp @@ -70,48 +70,48 @@ #endif void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) { - std::string chatCommand; - std::vector args; + std::string chatCommand; + std::vector args; - uint32_t breakIndex = 0; - for (uint32_t i = 1; i < command.size(); ++i) { - if (command[i] == L' ') { - breakIndex = i; - break; - } + uint32_t breakIndex = 0; + for (uint32_t i = 1; i < command.size(); ++i) { + if (command[i] == L' ') { + breakIndex = i; + break; + } - chatCommand.push_back(static_cast(command[i])); - breakIndex++; - } + chatCommand.push_back(static_cast(command[i])); + breakIndex++; + } - uint32_t index = ++breakIndex; - while (true) { - std::string arg; + uint32_t index = ++breakIndex; + while (true) { + std::string arg; - while (index < command.size()) { - if (command[index] == L' ') { - args.push_back(arg); - arg = ""; - index++; - continue; - } + while (index < command.size()) { + if (command[index] == L' ') { + args.push_back(arg); + arg = ""; + index++; + continue; + } - arg.push_back(static_cast(command[index])); - index++; - } + arg.push_back(static_cast(command[index])); + index++; + } - if (arg != "") { - args.push_back(arg); - } + if (arg != "") { + args.push_back(arg); + } - break; - } + break; + } - //Game::logger->Log("SlashCommandHandler", "Received chat command \"%s\"\n", GeneralUtils::UTF16ToWTF8(command).c_str()); + //Game::logger->Log("SlashCommandHandler", "Received chat command \"%s\"\n", GeneralUtils::UTF16ToWTF8(command).c_str()); - User* user = UserManager::Instance()->GetUser(sysAddr); - if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > GAME_MASTER_LEVEL_CIVILIAN) { - if (args.size() != 1) return; + User* user = UserManager::Instance()->GetUser(sysAddr); + if ((chatCommand == "setgmlevel" || chatCommand == "makegm" || chatCommand == "gmlevel") && user->GetMaxGMLevel() > GAME_MASTER_LEVEL_CIVILIAN) { + if (args.size() != 1) return; uint32_t level; @@ -133,10 +133,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit level = user->GetMaxGMLevel(); } - if (level == entity->GetGMLevel()) return; - bool success = user->GetMaxGMLevel() >= level; + if (level == entity->GetGMLevel()) return; + bool success = user->GetMaxGMLevel() >= level; + + if (success) { - if (success) { if (entity->GetGMLevel() > GAME_MASTER_LEVEL_CIVILIAN && level == GAME_MASTER_LEVEL_CIVILIAN) { GameMessages::SendToggleGMInvis(entity->GetObjectID(), false, UNASSIGNED_SYSTEM_ADDRESS); @@ -307,7 +308,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - if ((chatCommand == "leave-zone")) { + if (chatCommand == "leave-zone") { const auto currentZone = dZoneManager::Instance()->GetZone()->GetZoneID().GetMapID(); auto newZone = 0; @@ -348,7 +349,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit }); } - if ((chatCommand == "join" && !args.empty())) { + if (chatCommand == "join" && !args.empty()) { ChatPackets::SendSystemMessage(sysAddr, u"Requesting private map..."); const auto& password = args[0]; @@ -401,8 +402,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit auto stmt = Database::CreatePreppedStmt("INSERT INTO command_log (character_id, command) VALUES (?, ?);"); stmt->setInt(1, entity->GetCharacter()->GetID()); stmt->setString(2, GeneralUtils::UTF16ToWTF8(command).c_str()); - stmt->execute(); - delete stmt; + stmt->execute(); + delete stmt; if (chatCommand == "setminifig" && args.size() == 2 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_FORUM_MODERATOR) { // could break characters so only allow if GM > 0 int32_t minifigItemId; @@ -605,6 +606,10 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit if (chatCommand == "runmacro" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_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; + std::ifstream infile("./res/macros/" + args[0] + ".scm"); if (infile.good()) { @@ -998,13 +1003,14 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit return; } - pos.SetX(x); - pos.SetY(y); - pos.SetZ(z); + pos.SetX(x); + pos.SetY(y); + pos.SetZ(z); + + Game::logger->Log("SlashCommandHandler", "Teleporting objectID: %llu to %f, %f, %f\n", entity->GetObjectID(), pos.x, pos.y, pos.z); + GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } else if (args.size() == 2) { - Game::logger->Log("SlashCommandHandler", "Teleporting objectID: %llu to %f, %f, %f\n", entity->GetObjectID(), pos.x, pos.y, pos.z); - GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); - } else if (args.size() == 2) { float x, z; if (!GeneralUtils::TryParse(args[0], x)) @@ -1023,12 +1029,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit pos.SetY(0.0f); pos.SetZ(z); - - Game::logger->Log("SlashCommandHandler", "Teleporting objectID: %llu to X: %f, Z: %f\n", entity->GetObjectID(), pos.x, pos.z); - GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); - } else { - ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport () - if no Y given, will teleport to the height of the terrain (or any physics object)."); - } + Game::logger->Log("SlashCommandHandler", "Teleporting objectID: %llu to X: %f, Z: %f\n", entity->GetObjectID(), pos.x, pos.z); + GameMessages::SendTeleport(entity->GetObjectID(), pos, NiQuaternion(), sysAddr); + } else { + ChatPackets::SendSystemMessage(sysAddr, u"Correct usage: /teleport () - if no Y given, will teleport to the height of the terrain (or any physics object)."); + } auto* possessorComponent = entity->GetComponent(); @@ -1268,7 +1273,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit //------------------------------------------------- - if (chatCommand == "buffme" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "buffme" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { auto dest = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); if (dest) { dest->SetHealth(999); @@ -1278,9 +1283,8 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit dest->SetImagination(999); dest->SetMaxImagination(999.0f); } - - EntityManager::Instance()->SerializeEntity(entity); - } + EntityManager::Instance()->SerializeEntity(entity); + } if (chatCommand == "startcelebration" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { int32_t celebration; @@ -1294,7 +1298,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendStartCelebrationEffect(entity, entity->GetSystemAddress(), celebration); } - if (chatCommand == "buffmed" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { + if (chatCommand == "buffmed" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { auto dest = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); if (dest) { dest->SetHealth(9); @@ -1304,11 +1308,11 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit dest->SetImagination(9); dest->SetMaxImagination(9.0f); } + EntityManager::Instance()->SerializeEntity(entity); + } - EntityManager::Instance()->SerializeEntity(entity); - } + if (chatCommand == "refillstats" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { - if (chatCommand == "refillstats" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) { auto dest = static_cast(entity->GetComponent(COMPONENT_TYPE_DESTROYABLE)); if (dest) { dest->SetHealth((int)dest->GetMaxHealth()); @@ -1316,22 +1320,28 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit dest->SetImagination((int)dest->GetMaxImagination()); } - EntityManager::Instance()->SerializeEntity(entity); - } + EntityManager::Instance()->SerializeEntity(entity); + } if (chatCommand == "lookup" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() == 1) { - std::string query = "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE '%" + args[0] + "%' OR `name` LIKE '%" + args[0] + "%' OR `description` LIKE '%" + args[0] + "%'"; - auto tables = CDClientDatabase::ExecuteQuery(query.c_str()); - while (!tables.eof()) { - std::string message = std::to_string(tables.getIntField(0)) + " - " + tables.getStringField(1); - ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(message, message.size())); - tables.nextRow(); - } - } + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT `id`, `name` FROM `Objects` WHERE `displayName` LIKE ?1 OR `name` LIKE ?1 OR `description` LIKE ?1 LIMIT 50"); - if (chatCommand == "spawn" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { - ControllablePhysicsComponent* comp = static_cast(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); - if (!comp) return; + const std::string query_text = "%" + args[0] + "%"; + 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::ASCIIToUTF16(message, message.size())); + tables.nextRow(); + } + } + + if (chatCommand == "spawn" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) { + ControllablePhysicsComponent* comp = static_cast(entity->GetComponent(COMPONENT_TYPE_CONTROLLABLE_PHYSICS)); + if (!comp) return; uint32_t lot; @@ -1374,6 +1384,74 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit GameMessages::SendModifyLEGOScore(entity, entity->GetSystemAddress(), uscore, eLootSourceType::LOOT_SOURCE_MODERATION); } + if ((chatCommand == "setlevel") && args.size() >= 1 && entity->GetGMLevel() >= GAME_MASTER_LEVEL_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 = Player::GetPlayer(requestedPlayerToSetLevelOf); + + if (!requestedPlayer) { + ChatPackets::SendSystemMessage(sysAddr, u"No player found with username: (" + GeneralUtils::ASCIIToUTF16(requestedPlayerToSetLevelOf) + u")."); + return; + } + + if (!requestedPlayer->GetOwner()) { + ChatPackets::SendSystemMessage(sysAddr, u"No entity found with username: (" + GeneralUtils::ASCIIToUTF16(requestedPlayerToSetLevelOf) + u")."); + return; + } + + entity = requestedPlayer->GetOwner(); + } + uint32_t requestedLevel; + uint32_t oldLevel; + // first check the level is valid + + if (!GeneralUtils::TryParse(args[0], requestedLevel)) + { + ChatPackets::SendSystemMessage(sysAddr, u"Invalid level."); + return; + } + // query to set our uscore to the correct value for this level + + auto characterComponent = entity->GetComponent(); + auto query = CDClientDatabase::CreatePreppedStmt("SELECT requiredUScore from LevelProgressionLookup WHERE id = ?;"); + query.bind(1, (int)requestedLevel); + auto result = query.execQuery(); + + if (result.eof()) return; + + // Set the UScore first + oldLevel = characterComponent->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; + characterComponent->SetLevel(oldLevel); + characterComponent->HandleLevelUp(); + } + } else { + characterComponent->SetLevel(requestedLevel); + } + + if (requestedPlayerToSetLevelOf != "") { + ChatPackets::SendSystemMessage( + sysAddr, u"Set " + GeneralUtils::ASCIIToUTF16(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() >= GAME_MASTER_LEVEL_DEVELOPER) { const auto position = entity->GetPosition(); @@ -1519,53 +1597,27 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit const auto objid = entity->GetObjectID(); if (force || CheckIfAccessibleZone(reqZone)) { // to prevent tomfoolery - bool darwin = true; //Putting this on true, as I'm sick of having to wait 3-4 seconds on a transfer while trying to quickly moderate properties - Character* character = entity->GetCharacter(); - if (character) { - std::string lowerName = character->GetName(); - std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), ::tolower); - // feel free to add your name to the list - if (lowerName.find("max") != std::string::npos || lowerName.find("darwin") != std::string::npos || lowerName.find("gie") != std::string::npos) { - darwin = true; - } - } + 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) { - if (!darwin) { - GameMessages::SendPlayAnimation(entity, u"lup-teleport"); - GameMessages::SendSetStunned(objid, PUSH, user->GetSystemAddress(), - LWOOBJID_EMPTY, true, true, true, true, true, true, true, true - ); - } - - ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, reqZone, cloneId, false, [objid, darwin](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { auto* entity = EntityManager::Instance()->GetEntity(objid); + if (!entity) return; - if (entity == nullptr) { - return; + const auto sysAddr = entity->GetSystemAddress(); + + ChatPackets::SendSystemMessage(sysAddr, u"Transfering map..."); + + Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); + if (entity->GetCharacter()) { + entity->GetCharacter()->SetZoneID(zoneID); + entity->GetCharacter()->SetZoneInstance(zoneInstance); + entity->GetCharacter()->SetZoneClone(zoneClone); + entity->GetComponent()->SetLastRocketConfig(u""); } - float transferTime = 3.32999992370605f; - if (darwin) transferTime = 0.0f; - - entity->AddCallbackTimer(transferTime, [=] { - const auto sysAddr = entity->GetSystemAddress(); - - ChatPackets::SendSystemMessage(sysAddr, u"Transfering map..."); - - Game::logger->Log("UserManager", "Transferring %s to Zone %i (Instance %i | Clone %i | Mythran Shift: %s) with IP %s and Port %i\n", sysAddr.ToString(), zoneID, zoneInstance, zoneClone, mythranShift == true ? "true" : "false", serverIP.c_str(), serverPort); - if (entity->GetCharacter()) { - entity->GetCharacter()->SetZoneID(zoneID); - entity->GetCharacter()->SetZoneInstance(zoneInstance); - entity->GetCharacter()->SetZoneClone(zoneClone); - entity->GetComponent()->SetLastRocketConfig(u""); - } - - entity->GetCharacter()->SaveXMLToDatabase(); - - WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); - }); + entity->GetCharacter()->SaveXMLToDatabase(); + WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); return; }); } else { @@ -2043,12 +2095,15 @@ void SlashCommandHandler::SendAnnouncement(const std::string& title, const std:: CBITSTREAM; PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ANNOUNCEMENT); - RakNet::RakString rsTitle(title.c_str()); - RakNet::RakString rsMsg(message.c_str()); + bitStream.Write(title.size()); + for (auto character : title) { + bitStream.Write(character); + } - bitStream.Write(rsTitle); - bitStream.Write(rsMsg); + bitStream.Write(message.size()); + for (auto character : message) { + bitStream.Write(character); + } Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } - diff --git a/dGame/dUtilities/VanityUtilities.cpp b/dGame/dUtilities/VanityUtilities.cpp index e8fd4cf0..c3f8f6b4 100644 --- a/dGame/dUtilities/VanityUtilities.cpp +++ b/dGame/dUtilities/VanityUtilities.cpp @@ -11,6 +11,8 @@ #include "dConfig.h" #include "dServer.h" #include "tinyxml2.h" +#include "Game.h" +#include "dLogger.h" #include diff --git a/dMasterServer/CMakeLists.txt b/dMasterServer/CMakeLists.txt new file mode 100644 index 00000000..08fc63db --- /dev/null +++ b/dMasterServer/CMakeLists.txt @@ -0,0 +1,10 @@ +set(DMASTERSERVER_SOURCES "InstanceManager.cpp" + "MasterServer.cpp" + "ObjectIDManager.cpp") + +add_executable(MasterServer ${DMASTERSERVER_SOURCES}) +target_link_libraries(MasterServer ${COMMON_LIBRARIES}) + +if(WIN32) + add_dependencies(MasterServer WorldServer AuthServer ChatServer) +endif() diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index e1e4728f..2e881934 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -19,6 +19,7 @@ #include "CDClientDatabase.h" #include "CDClientManager.h" #include "Database.h" +#include "MigrationRunner.h" #include "Diagnostics.h" #include "dCommonVars.h" #include "dConfig.h" @@ -61,6 +62,10 @@ int main(int argc, char** argv) { Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); +#if defined(_WIN32) && defined(MARIADB_PLUGIN_DIR_OVERRIDE) + _putenv_s("MARIADB_PLUGIN_DIR", MARIADB_PLUGIN_DIR_OVERRIDE); +#endif + //Triggers the shutdown sequence at application exit std::atexit(ShutdownSequence); signal(SIGINT, [](int) { ShutdownSequence(); }); @@ -123,6 +128,13 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } + if (argc > 1 && (strcmp(argv[1], "-m") == 0 || strcmp(argv[1], "--migrations") == 0)) { + MigrationRunner::RunMigrations(); + Game::logger->Log("MigrationRunner", "Finished running migrations\n"); + + return EXIT_SUCCESS; + } + //If the first command line argument is -a or --account then make the user //input a username and password, with the password being hidden. if (argc > 1 && @@ -485,7 +497,10 @@ void HandlePacket(Packet* packet) { CBITSTREAM; PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_NEW_SESSION_ALERT); bitStream.Write(sessionKey); - bitStream.Write(RakNet::RakString(username.c_str())); + bitStream.Write(username.size()); + for (auto character : username) { + bitStream.Write(character); + } SEND_PACKET_BROADCAST; break; @@ -560,14 +575,20 @@ void HandlePacket(Packet* packet) { uint32_t mapId; LWOCLONEID cloneId; - RakNet::RakString password; + std::string password; inStream.Read(mapId); inStream.Read(cloneId); - inStream.Read(password); - Game::im->CreatePrivateInstance(mapId, cloneId, - password.C_String()); + uint32_t len; + inStream.Read(len); + for (int i = 0; len > i; i++) { + char character; + inStream.Read(character); + password += character; + } + + Game::im->CreatePrivateInstance(mapId, cloneId, password.c_str()); break; } @@ -579,15 +600,22 @@ void HandlePacket(Packet* packet) { uint64_t requestID = 0; uint8_t mythranShift = false; - RakNet::RakString password; + std::string password; inStream.Read(requestID); inStream.Read(mythranShift); - inStream.Read(password); + + uint32_t len; + inStream.Read(len); - auto* instance = Game::im->FindPrivateInstance(password.C_String()); + for (int i = 0; i < len; i++) { + char character; inStream.Read(character); + password += character; + } - Game::logger->Log( "MasterServer", "Join private zone: %llu %d %s %p\n", requestID, mythranShift, password.C_String(), instance); + auto* instance = Game::im->FindPrivateInstance(password.c_str()); + + Game::logger->Log( "MasterServer", "Join private zone: %llu %d %s %p\n", requestID, mythranShift, password.c_str(), instance); if (instance == nullptr) { return; diff --git a/dNet/CMakeLists.txt b/dNet/CMakeLists.txt new file mode 100644 index 00000000..938c0449 --- /dev/null +++ b/dNet/CMakeLists.txt @@ -0,0 +1,11 @@ +set(DNET_SOURCES "AuthPackets.cpp" + "ChatPackets.cpp" + "ClientPackets.cpp" + "dServer.cpp" + "MasterPackets.cpp" + "PacketUtils.cpp" + "WorldPackets.cpp" + "ZoneInstanceManager.cpp") + +add_library(dNet STATIC ${DNET_SOURCES}) +target_link_libraries(dNet dCommon dDatabase) diff --git a/dNet/MasterPackets.cpp b/dNet/MasterPackets.cpp index 96ad1b81..bf58d71c 100644 --- a/dNet/MasterPackets.cpp +++ b/dNet/MasterPackets.cpp @@ -43,8 +43,10 @@ void MasterPackets::SendZoneCreatePrivate(dServer* server, uint32_t zoneID, uint bitStream.Write(zoneID); bitStream.Write(cloneID); - RakNet::RakString passwd(password.c_str()); - bitStream.Write(passwd); + bitStream.Write(password.size()); + for (auto character : password) { + bitStream.Write(character); + } server->SendToMaster(&bitStream); } @@ -56,8 +58,10 @@ void MasterPackets::SendZoneRequestPrivate(dServer* server, uint64_t requestID, bitStream.Write(requestID); bitStream.Write(static_cast(mythranShift)); - RakNet::RakString passwd(password.c_str()); - bitStream.Write(passwd); + bitStream.Write(password.size()); + for (auto character : password) { + bitStream.Write(character); + } server->SendToMaster(&bitStream); } diff --git a/dNet/dMessageIdentifiers.h b/dNet/dMessageIdentifiers.h index 8e20ab54..5ad3921c 100644 --- a/dNet/dMessageIdentifiers.h +++ b/dNet/dMessageIdentifiers.h @@ -376,6 +376,7 @@ enum GAME_MSG : unsigned short { GAME_MSG_NOTIFY_PET_TAMING_PUZZLE_SELECTED = 675, GAME_MSG_SHOW_PET_ACTION_BUTTON = 692, GAME_MSG_SET_EMOTE_LOCK_STATE = 693, + GAME_MSG_USE_ITEM_REQUIREMENTS_RESPONSE = 703, GAME_MSG_PLAY_EMBEDDED_EFFECT_ON_ALL_CLIENTS_NEAR_OBJECT = 713, GAME_MSG_DOWNLOAD_PROPERTY_DATA = 716, GAME_MSG_QUERY_PROPERTY_DATA = 717, @@ -534,8 +535,10 @@ enum GAME_MSG : unsigned short { GAME_MSG_REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666, GAME_MSG_RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667, GAME_MSG_PLAYER_SET_CAMERA_CYCLING_MODE = 1676, + GAME_MSG_SET_MOUNT_INVENTORY_ID = 1726, GAME_MSG_NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE = 1734, GAME_MSG_NOTIFY_LEVEL_REWARDS = 1735, + GAME_MSG_DISMOUNT_COMPLETE = 1756, GAME_MSG_MARK_INVENTORY_ITEM_AS_ACTIVE = 1767, END }; \ No newline at end of file diff --git a/dPhysics/CMakeLists.txt b/dPhysics/CMakeLists.txt new file mode 100644 index 00000000..383393cc --- /dev/null +++ b/dPhysics/CMakeLists.txt @@ -0,0 +1,9 @@ +set(DPHYSICS_SOURCES "dpCollisionChecks.cpp" + "dpEntity.cpp" + "dpGrid.cpp" + "dpShapeBase.cpp" + "dpShapeBox.cpp" + "dpShapeSphere.cpp" + "dpWorld.cpp") + +add_library(dPhysics STATIC ${DPHYSICS_SOURCES}) diff --git a/dPhysics/dpCollisionGroups.h b/dPhysics/dpCollisionGroups.h index 7a6830eb..5853070f 100644 --- a/dPhysics/dpCollisionGroups.h +++ b/dPhysics/dpCollisionGroups.h @@ -1,5 +1,7 @@ #pragma once +#include + /* * Collision Groups */ diff --git a/dScripts/ActMine.cpp b/dScripts/ActMine.cpp new file mode 100644 index 00000000..9cc116b1 --- /dev/null +++ b/dScripts/ActMine.cpp @@ -0,0 +1,53 @@ +#include "ActMine.h" +#include "SkillComponent.h" +#include "DestroyableComponent.h" +#include "RebuildComponent.h" + +void ActMine::OnStartup(Entity* self) { + self->SetVar(u"RebuildComplete", false); + self->SetProximityRadius(MINE_RADIUS, "mineRadius"); +} + +void ActMine::OnRebuildNotifyState(Entity* self, eRebuildState state) +{ + if (state == eRebuildState::REBUILD_COMPLETED) { + auto* rebuild = self->GetComponent(); + if (rebuild) { + auto* builder = rebuild->GetBuilder(); + self->SetVar(u"Builder", builder->GetObjectID()); + } + + self->SetVar(u"RebuildComplete", true); + self->SetVar(u"NumWarnings", 0); + self->AddToGroup("reset"); + } + +} + +void ActMine::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { + auto* detroyable = self->GetComponent(); + if (!detroyable) return; + if (status == "ENTER" && self->GetVar(u"RebuildComplete") == true && detroyable->IsEnemy(entering)) { + GameMessages::SendPlayFXEffect(self->GetObjectID(), 242, u"orange", "sirenlight_B"); + self->AddTimer("Tick", TICK_TIME); + } +} + +void ActMine::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "Tick") { + if (self->GetVar(u"NumWarnings") >= MAX_WARNINGS){ + auto* skill = self->GetComponent(); + if (!skill) return; + skill->CalculateBehavior(SKILL_ID, BEHAVIOR_ID, LWOOBJID_EMPTY); + self->AddTimer("BlowedUp", BLOWED_UP_TIME); + } else { + GameMessages::SendPlayFXEffect(self->GetObjectID(), 242, u"orange", "sirenlight_B"); + self->AddTimer("Tick", TICK_TIME); + self->SetVar(u"NumWarnings", self->GetVar(u"NumWarnings") + 1); + } + } + + if (timerName == "BlowedUp") { + self->Kill(self); + } +} \ No newline at end of file diff --git a/dScripts/ActMine.h b/dScripts/ActMine.h new file mode 100644 index 00000000..ae6ef17e --- /dev/null +++ b/dScripts/ActMine.h @@ -0,0 +1,18 @@ +#pragma once +#include "CppScripts.h" + +class ActMine : public CppScripts::Script { + public: + void OnStartup(Entity* self) override; + void OnRebuildNotifyState(Entity* self, eRebuildState state) override; + void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override; + void OnTimerDone(Entity* self, std::string timerName) override; + private: + int MAX_WARNINGS = 3; + float MINE_RADIUS = 10.0; + float TICK_TIME = 0.25; + float BLOWED_UP_TIME = 0.1; + uint32_t SKILL_ID = 317; + uint32_t BEHAVIOR_ID = 3719; +}; + diff --git a/dScripts/ActNinjaTurret.cpp b/dScripts/ActNinjaTurret.cpp index 4aecd327..8c361ad7 100644 --- a/dScripts/ActNinjaTurret.cpp +++ b/dScripts/ActNinjaTurret.cpp @@ -2,18 +2,12 @@ void ActNinjaTurret::OnRebuildNotifyState(Entity* self, eRebuildState state) { - Game::logger->Log("ActNinjaTurret", "Rebuild state: %i\n", state); - if (state == eRebuildState::REBUILD_COMPLETED) { - Game::logger->Log("ActNinjaTurret", "I am build\n"); - self->SetVar(u"AmBuilt", true); } else if (state == eRebuildState::REBUILD_RESETTING) { - Game::logger->Log("ActNinjaTurret", "I am not build\n"); - self->SetVar(u"AmBuilt", false); } } @@ -22,8 +16,6 @@ void ActNinjaTurret::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { - Game::logger->Log("ActNinjaTurret", "Got server side event %s\n", args.c_str()); - if (args == "ISpawned" && self->GetVar(u"AmBuilt")) { sender->Smash(); diff --git a/dScripts/ActSharkPlayerDeathTrigger.cpp b/dScripts/ActSharkPlayerDeathTrigger.cpp index 4185496c..a8aaac8b 100644 --- a/dScripts/ActSharkPlayerDeathTrigger.cpp +++ b/dScripts/ActSharkPlayerDeathTrigger.cpp @@ -1,24 +1,17 @@ #include "ActSharkPlayerDeathTrigger.h" +#include "MissionComponent.h" +#include "MissionTaskType.h" #include "Entity.h" -#include "GameMessages.h" -#include "Game.h" -#include "dLogger.h" - -void ActSharkPlayerDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) { - -} void ActSharkPlayerDeathTrigger::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { if (args == "achieve") { - MissionComponent* mis = static_cast(sender->GetComponent(COMPONENT_TYPE_MISSION)); - if (!mis) return; + auto missionComponent = sender->GetComponent(); + if (!missionComponent) return; - mis->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, 8419); + missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SCRIPT, 8419); if (sender->GetIsDead() || !sender->GetPlayerReadyForUpdates()) return; //Don't kill already dead players or players not ready - - Game::logger->Log("ActSharkPlayerDeathTrigger", "%i\n", self->GetLOT()); if (sender->GetCharacter()) { sender->Smash(self->GetObjectID(), eKillType::VIOLENT, u"big-shark-death"); diff --git a/dScripts/ActSharkPlayerDeathTrigger.h b/dScripts/ActSharkPlayerDeathTrigger.h index 6f00fd00..cbd3c960 100644 --- a/dScripts/ActSharkPlayerDeathTrigger.h +++ b/dScripts/ActSharkPlayerDeathTrigger.h @@ -4,8 +4,7 @@ class ActSharkPlayerDeathTrigger : public CppScripts::Script { public: - void OnCollisionPhantom(Entity* self, Entity* target); void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, - int32_t param3); + int32_t param3) override; }; diff --git a/dScripts/ActivityManager.cpp b/dScripts/ActivityManager.cpp index f84963df..e464b20d 100644 --- a/dScripts/ActivityManager.cpp +++ b/dScripts/ActivityManager.cpp @@ -4,6 +4,7 @@ #include "LeaderboardManager.h" #include "GameMessages.h" #include +#include "dLogger.h" bool ActivityManager::IsPlayerInActivity(Entity *self, LWOOBJID playerID) { const auto* sac = self->GetComponent(); diff --git a/dScripts/AgBugsprayer.cpp b/dScripts/AgBugsprayer.cpp index 26e2880c..cfea5cf4 100644 --- a/dScripts/AgBugsprayer.cpp +++ b/dScripts/AgBugsprayer.cpp @@ -1,7 +1,6 @@ #include "AgBugsprayer.h" #include "SkillComponent.h" - void AgBugsprayer::OnRebuildComplete(Entity* self, Entity* target) { self->AddTimer("castSkill", 1); diff --git a/dScripts/AgBusDoor.cpp b/dScripts/AgBusDoor.cpp index 8c22dc8c..4453fcad 100644 --- a/dScripts/AgBusDoor.cpp +++ b/dScripts/AgBusDoor.cpp @@ -1,8 +1,6 @@ #include "AgBusDoor.h" #include "Entity.h" #include "GameMessages.h" -#include "Game.h" -#include "dLogger.h" #include "ProximityMonitorComponent.h" void AgBusDoor::OnStartup(Entity* self) { diff --git a/dScripts/AgCagedBricksServer.cpp b/dScripts/AgCagedBricksServer.cpp index 7ad6858c..ec9f5306 100644 --- a/dScripts/AgCagedBricksServer.cpp +++ b/dScripts/AgCagedBricksServer.cpp @@ -12,7 +12,11 @@ void AgCagedBricksServer::OnUse(Entity* self, Entity* user) { } //Set the flag & mission status: - user->GetCharacter()->SetPlayerFlag(74, true); + auto character = user->GetCharacter(); + + if (!character) return; + + character->SetPlayerFlag(74, true); //Remove the maelstrom cube: auto inv = static_cast(user->GetComponent(COMPONENT_TYPE_INVENTORY)); diff --git a/dScripts/AgFans.cpp b/dScripts/AgFans.cpp index 996a58e7..dbc09547 100644 --- a/dScripts/AgFans.cpp +++ b/dScripts/AgFans.cpp @@ -1,5 +1,8 @@ #include "AgFans.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "PhantomPhysicsComponent.h" #include "RenderComponent.h" void AgFans::OnStartup(Entity* self) { diff --git a/dScripts/AgFans.h b/dScripts/AgFans.h index 09cc89d9..800267af 100644 --- a/dScripts/AgFans.h +++ b/dScripts/AgFans.h @@ -1,8 +1,5 @@ #pragma once #include "CppScripts.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "PhantomPhysicsComponent.h" class AgFans : public CppScripts::Script { diff --git a/dScripts/AgImagSmashable.h b/dScripts/AgImagSmashable.h index 88efe3fe..fd047c34 100644 --- a/dScripts/AgImagSmashable.h +++ b/dScripts/AgImagSmashable.h @@ -4,7 +4,6 @@ class AgImagSmashable : public CppScripts::Script { public: void OnDie(Entity* self, Entity* killer); - private: void CrateAnimal(Entity* self); }; \ No newline at end of file diff --git a/dScripts/AgJetEffectServer.cpp b/dScripts/AgJetEffectServer.cpp index 0572fb46..599f4d01 100644 --- a/dScripts/AgJetEffectServer.cpp +++ b/dScripts/AgJetEffectServer.cpp @@ -1,15 +1,8 @@ #include "AgJetEffectServer.h" - #include "GameMessages.h" #include "EntityManager.h" -#include "PhantomPhysicsComponent.h" #include "SkillComponent.h" - -void AgJetEffectServer::OnStartup(Entity* self) -{ -} - void AgJetEffectServer::OnUse(Entity* self, Entity* user) { if (inUse) @@ -41,7 +34,6 @@ void AgJetEffectServer::OnUse(Entity* self, Entity* user) GameMessages::SendPlayFXEffect(effect, 641, u"create", "radarDish", LWOOBJID_EMPTY, 1, 1, true); self->AddTimer("radarDish", 2); - //self->AddTimer("PlayEffect", 2.5f); self->AddTimer("CineDone", 9); } diff --git a/dScripts/AgJetEffectServer.h b/dScripts/AgJetEffectServer.h index 0069d0bb..094c73d2 100644 --- a/dScripts/AgJetEffectServer.h +++ b/dScripts/AgJetEffectServer.h @@ -4,16 +4,12 @@ class AgJetEffectServer final : public CppScripts::Script { public: - void OnStartup(Entity* self) override; - void OnUse(Entity* self, Entity* user) override; void OnRebuildComplete(Entity* self, Entity* target) override; void OnTimerDone(Entity* self, std::string timerName) override; - private: LWOOBJID builder; - bool inUse; }; diff --git a/dScripts/AgLaserSensorServer.cpp b/dScripts/AgLaserSensorServer.cpp index f1d87468..342cc7e1 100644 --- a/dScripts/AgLaserSensorServer.cpp +++ b/dScripts/AgLaserSensorServer.cpp @@ -1,5 +1,9 @@ #include "AgLaserSensorServer.h" +#include "PhantomPhysicsComponent.h" +#include "SkillComponent.h" +#include "EntityManager.h" +#include "AgMonumentLaserServer.h" #include "EntityManager.h" void AgLaserSensorServer::OnStartup(Entity* self) { diff --git a/dScripts/AgLaserSensorServer.h b/dScripts/AgLaserSensorServer.h index 92d33efb..72e09dd8 100644 --- a/dScripts/AgLaserSensorServer.h +++ b/dScripts/AgLaserSensorServer.h @@ -1,9 +1,7 @@ #pragma once #include "CppScripts.h" -#include "PhantomPhysicsComponent.h" -#include "SkillComponent.h" -#include "EntityManager.h" -#include "AgMonumentLaserServer.h" + +class SkillComponent; class AgLaserSensorServer : public CppScripts::Script { public: diff --git a/dScripts/AgMonumentBirds.cpp b/dScripts/AgMonumentBirds.cpp index 212a0631..5870cfff 100644 --- a/dScripts/AgMonumentBirds.cpp +++ b/dScripts/AgMonumentBirds.cpp @@ -1,6 +1,5 @@ #include "AgMonumentBirds.h" #include "GameMessages.h" -#include "DestroyableComponent.h" //-------------------------------------------------------------- //Makes the ag birds fly away when you get close and smashes them. diff --git a/dScripts/AgPropGuard.cpp b/dScripts/AgPropGuard.cpp index 18fcd7c2..b05eef4f 100644 --- a/dScripts/AgPropGuard.cpp +++ b/dScripts/AgPropGuard.cpp @@ -1,9 +1,9 @@ #include "AgPropGuard.h" #include "Entity.h" #include "Character.h" -#include "GameMessages.h" #include "EntityManager.h" #include "InventoryComponent.h" +#include "MissionComponent.h" #include "Item.h" void AgPropGuard::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) diff --git a/dScripts/AgSalutingNpcs.cpp b/dScripts/AgSalutingNpcs.cpp index 6a39f06f..618dc631 100644 --- a/dScripts/AgSalutingNpcs.cpp +++ b/dScripts/AgSalutingNpcs.cpp @@ -1,5 +1,4 @@ #include "AgSalutingNpcs.h" - #include "GameMessages.h" diff --git a/dScripts/AgShipPlayerDeathTrigger.cpp b/dScripts/AgShipPlayerDeathTrigger.cpp index 6ba2d193..d20edee7 100644 --- a/dScripts/AgShipPlayerDeathTrigger.cpp +++ b/dScripts/AgShipPlayerDeathTrigger.cpp @@ -1,12 +1,8 @@ #include "AgShipPlayerDeathTrigger.h" #include "Entity.h" -#include "GameMessages.h" -#include "Game.h" -#include "dLogger.h" void AgShipPlayerDeathTrigger::OnCollisionPhantom(Entity* self, Entity* target) { if (target->GetLOT() == 1 && !target->GetIsDead()) { - Game::logger->Log("CppScripts::AgShipPlayerDeathTrigger", "Attempting to kill %llu\n", target->GetObjectID()); target->Smash(self->GetObjectID(), eKillType::VIOLENT, u"electro-shock-death"); } } \ No newline at end of file diff --git a/dScripts/AgSpaceStuff.cpp b/dScripts/AgSpaceStuff.cpp index 507b908f..18e4eb47 100644 --- a/dScripts/AgSpaceStuff.cpp +++ b/dScripts/AgSpaceStuff.cpp @@ -1,9 +1,7 @@ #include "AgSpaceStuff.h" #include "GeneralUtils.h" #include "GameMessages.h" -#include "dZoneManager.h" #include "EntityManager.h" -#include "Game.h" void AgSpaceStuff::OnStartup(Entity* self) { self->AddTimer("FloaterScale", 5.0f); diff --git a/dScripts/AgSurvivalBuffStation.cpp b/dScripts/AgSurvivalBuffStation.cpp index 86a2f653..8a6cfb05 100644 --- a/dScripts/AgSurvivalBuffStation.cpp +++ b/dScripts/AgSurvivalBuffStation.cpp @@ -3,7 +3,6 @@ #include "EntityManager.h" #include "GameMessages.h" #include "SkillComponent.h" -#include "dLogger.h" #include "TeamManager.h" void AgSurvivalBuffStation::OnRebuildComplete(Entity* self, Entity* target) { diff --git a/dScripts/AgSurvivalSpiderling.cpp b/dScripts/AgSurvivalSpiderling.cpp index ebb0395b..d44455d8 100644 --- a/dScripts/AgSurvivalSpiderling.cpp +++ b/dScripts/AgSurvivalSpiderling.cpp @@ -1,6 +1,5 @@ #include "AgSurvivalSpiderling.h" #include "BaseCombatAIComponent.h" -#include "GameMessages.h" void AgSurvivalSpiderling::OnStartup(Entity *self) { BaseWavesGenericEnemy::OnStartup(self); diff --git a/dScripts/AgTurret.cpp b/dScripts/AgTurret.cpp index a439ecf1..6db493d5 100644 --- a/dScripts/AgTurret.cpp +++ b/dScripts/AgTurret.cpp @@ -1,6 +1,4 @@ #include "AgTurret.h" -#include "EntityManager.h" -#include "RebuildComponent.h" #include "GameMessages.h" void AgTurret::OnStartup(Entity* self) { diff --git a/dScripts/AllCrateChicken.cpp b/dScripts/AllCrateChicken.cpp index c4aeec80..1a368a80 100644 --- a/dScripts/AllCrateChicken.cpp +++ b/dScripts/AllCrateChicken.cpp @@ -1,6 +1,4 @@ #include "AllCrateChicken.h" -#include "dCommonVars.h" -#include "EntityManager.h" #include "Entity.h" void AllCrateChicken::OnStartup(Entity* self) { diff --git a/dScripts/AmConsoleTeleportServer.cpp b/dScripts/AmConsoleTeleportServer.cpp index 5c60e827..5087aae2 100644 --- a/dScripts/AmConsoleTeleportServer.cpp +++ b/dScripts/AmConsoleTeleportServer.cpp @@ -1,5 +1,6 @@ #include "AmConsoleTeleportServer.h" - +#include "ChooseYourDestinationNsToNt.h" +#include "AMFFormat.h" void AmConsoleTeleportServer::OnStartup(Entity* self) { diff --git a/dScripts/AmConsoleTeleportServer.h b/dScripts/AmConsoleTeleportServer.h index ac241ee5..8236e67e 100644 --- a/dScripts/AmConsoleTeleportServer.h +++ b/dScripts/AmConsoleTeleportServer.h @@ -1,8 +1,6 @@ #pragma once #include "CppScripts.h" -#include "ChooseYourDestinationNsToNt.h" #include "BaseConsoleTeleportServer.h" -#include "AMFFormat.h" class AmConsoleTeleportServer : public CppScripts::Script, BaseConsoleTeleportServer { diff --git a/dScripts/AmDarklingDragon.cpp b/dScripts/AmDarklingDragon.cpp index be87f466..94066167 100644 --- a/dScripts/AmDarklingDragon.cpp +++ b/dScripts/AmDarklingDragon.cpp @@ -6,7 +6,6 @@ #include "SkillComponent.h" #include "BaseCombatAIComponent.h" - void AmDarklingDragon::OnStartup(Entity* self) { self->SetVar(u"weakspot", 0); @@ -48,15 +47,11 @@ void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t auto* destroyableComponent = self->GetComponent(); if (destroyableComponent != nullptr) { - Game::logger->Log("AmDarklingDragon", "Armor is %i\n", destroyableComponent->GetArmor()); - if (destroyableComponent->GetArmor() > 0) return; auto weakpoint = self->GetVar(u"weakpoint"); if (weakpoint == 0) { - Game::logger->Log("AmDarklingDragon", "Activating weakpoint\n"); - self->AddTimer("ReviveTimer", 12); auto* baseCombatAIComponent = self->GetComponent(); diff --git a/dScripts/AmDarklingMech.cpp b/dScripts/AmDarklingMech.cpp index 59eb6b45..33c3fcbf 100644 --- a/dScripts/AmDarklingMech.cpp +++ b/dScripts/AmDarklingMech.cpp @@ -1,5 +1,4 @@ #include "AmDarklingMech.h" -#include "DestroyableComponent.h" void AmDarklingMech::OnStartup(Entity* self) { diff --git a/dScripts/AmDarklingMech.h b/dScripts/AmDarklingMech.h index 363e4db8..cc179795 100644 --- a/dScripts/AmDarklingMech.h +++ b/dScripts/AmDarklingMech.h @@ -1,8 +1,5 @@ #pragma once #include "CppScripts.h" -#include "ChooseYourDestinationNsToNt.h" -#include "BaseConsoleTeleportServer.h" -#include "AMFFormat.h" #include "BaseEnemyMech.h" class AmDarklingMech : public BaseEnemyMech diff --git a/dScripts/AmDrawBridge.cpp b/dScripts/AmDrawBridge.cpp index 2c774ca1..8e52e3e4 100644 --- a/dScripts/AmDrawBridge.cpp +++ b/dScripts/AmDrawBridge.cpp @@ -3,7 +3,6 @@ #include "GameMessages.h" #include "SimplePhysicsComponent.h" - void AmDrawBridge::OnStartup(Entity* self) { self->SetNetworkVar(u"InUse", false); diff --git a/dScripts/AmDropshipComputer.cpp b/dScripts/AmDropshipComputer.cpp index 836b09b0..d25bd4f2 100644 --- a/dScripts/AmDropshipComputer.cpp +++ b/dScripts/AmDropshipComputer.cpp @@ -2,7 +2,6 @@ #include "MissionComponent.h" #include "RebuildComponent.h" #include "InventoryComponent.h" -#include "GameMessages.h" #include "dZoneManager.h" void AmDropshipComputer::OnStartup(Entity* self) @@ -27,12 +26,12 @@ void AmDropshipComputer::OnUse(Entity* self, Entity* user) return; } - if (inventoryComponent->GetLotCount(12323) != 0) + if (inventoryComponent->GetLotCount(m_NexusTalonDataCard) != 0 || missionComponent->GetMission(979)->GetMissionState() == MissionState::MISSION_STATE_COMPLETE) { return; } - inventoryComponent->AddItem(12323, 1, eLootSourceType::LOOT_SOURCE_NONE); + inventoryComponent->AddItem(m_NexusTalonDataCard, 1, eLootSourceType::LOOT_SOURCE_NONE); } void AmDropshipComputer::OnDie(Entity* self, Entity* killer) diff --git a/dScripts/AmDropshipComputer.h b/dScripts/AmDropshipComputer.h index 9b28d92d..620770af 100644 --- a/dScripts/AmDropshipComputer.h +++ b/dScripts/AmDropshipComputer.h @@ -8,4 +8,6 @@ public: void OnUse(Entity* self, Entity* user) override; void OnDie(Entity* self, Entity* killer) override; void OnTimerDone(Entity* self, std::string timerName) override; +private: + const LOT m_NexusTalonDataCard = 12323; }; diff --git a/dScripts/AmShieldGenerator.cpp b/dScripts/AmShieldGenerator.cpp index 1f9b5f9c..0e942612 100644 --- a/dScripts/AmShieldGenerator.cpp +++ b/dScripts/AmShieldGenerator.cpp @@ -6,7 +6,6 @@ #include "BaseCombatAIComponent.h" #include "SkillComponent.h" - void AmShieldGenerator::OnStartup(Entity* self) { self->SetProximityRadius(20, "shield"); diff --git a/dScripts/AmShieldGeneratorQuickbuild.cpp b/dScripts/AmShieldGeneratorQuickbuild.cpp index a2d99ad2..aa80148c 100644 --- a/dScripts/AmShieldGeneratorQuickbuild.cpp +++ b/dScripts/AmShieldGeneratorQuickbuild.cpp @@ -8,7 +8,6 @@ #include "RebuildComponent.h" #include "MissionComponent.h" - void AmShieldGeneratorQuickbuild::OnStartup(Entity* self) { self->SetProximityRadius(20, "shield"); diff --git a/dScripts/AmSkullkinDrill.cpp b/dScripts/AmSkullkinDrill.cpp index 8b4986d0..d5b7e7e6 100644 --- a/dScripts/AmSkullkinDrill.cpp +++ b/dScripts/AmSkullkinDrill.cpp @@ -87,8 +87,6 @@ void AmSkullkinDrill::TriggerDrill(Entity* self) if (standObj != nullptr) { - Game::logger->Log("AmSkullkinDrill", "Disabling knockback\n"); - standObj->SetVar(u"bActive", false); } @@ -213,8 +211,6 @@ void AmSkullkinDrill::OnArrived(Entity* self, uint32_t waypointIndex) if (standObj != nullptr) { - Game::logger->Log("AmSkullkinDrill", "Disabling knockback\n"); - standObj->SetVar(u"bActive", false); } @@ -302,8 +298,6 @@ void AmSkullkinDrill::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t void AmSkullkinDrill::OnTimerDone(Entity* self, std::string timerName) { - Game::logger->Log("AmSkullkinDrill", "Timer: %s\n", timerName.c_str()); - if (timerName == "killDrill") { const auto childID = self->GetVar(u"ChildSmash"); @@ -323,8 +317,6 @@ void AmSkullkinDrill::OnTimerDone(Entity* self, std::string timerName) if (standObj != nullptr) { - Game::logger->Log("AmSkullkinDrill", "Enabling knockback\n"); - standObj->SetVar(u"bActive", true); } @@ -351,8 +343,6 @@ void AmSkullkinDrill::OnTimerDone(Entity* self, std::string timerName) { const auto& animName = data[1]; - Game::logger->Log("AmSkullkinDrill", "Anim done: %s\n", animName.c_str()); - const auto playerID = self->GetVar(u"userID"); auto* player = EntityManager::Instance()->GetEntity(playerID); @@ -364,8 +354,6 @@ void AmSkullkinDrill::OnTimerDone(Entity* self, std::string timerName) if (animName == "spinjitzu-staff-windup") { - Game::logger->Log("AmSkullkinDrill", "Triggering drill\n"); - TriggerDrill(self); GameMessages::SendPlayAnimation(player, u"spinjitzu-staff-loop"); diff --git a/dScripts/AmSkullkinTower.cpp b/dScripts/AmSkullkinTower.cpp index 6869b94b..1b9e8c6d 100644 --- a/dScripts/AmSkullkinTower.cpp +++ b/dScripts/AmSkullkinTower.cpp @@ -2,7 +2,6 @@ #include "EntityManager.h" #include "DestroyableComponent.h" #include "MovingPlatformComponent.h" -#include "dCommonVars.h" #include "GameMessages.h" #include "MissionComponent.h" diff --git a/dScripts/BaseConsoleTeleportServer.cpp b/dScripts/BaseConsoleTeleportServer.cpp index ef2d00e0..6475e025 100644 --- a/dScripts/BaseConsoleTeleportServer.cpp +++ b/dScripts/BaseConsoleTeleportServer.cpp @@ -1,8 +1,6 @@ #include "BaseConsoleTeleportServer.h" #include "GameMessages.h" #include "Player.h" -#include "RocketLaunchpadControlComponent.h" - void BaseConsoleTeleportServer::BaseOnUse(Entity* self, Entity* user) { diff --git a/dScripts/BaseEnemyMech.cpp b/dScripts/BaseEnemyMech.cpp index eb95095a..17c7a347 100644 --- a/dScripts/BaseEnemyMech.cpp +++ b/dScripts/BaseEnemyMech.cpp @@ -1,8 +1,5 @@ #include "BaseEnemyMech.h" #include "Entity.h" -#include "GameMessages.h" -#include "Game.h" -#include "dLogger.h" #include "ControllablePhysicsComponent.h" #include "EntityManager.h" #include "dpWorld.h" @@ -21,7 +18,6 @@ void BaseEnemyMech::OnDie(Entity* self, Entity* killer) { if (!controlPhys) return; NiPoint3 newLoc = {controlPhys->GetPosition().x, dpWorld::Instance().GetHeightAtPoint(controlPhys->GetPosition()), controlPhys->GetPosition().z }; - //NiPoint3 newLoc = { controlPhys->GetPosition().x, controlPhys->GetPosition().y, controlPhys->GetPosition().z }; EntityInfo info = EntityInfo(); std::vector cfg; diff --git a/dScripts/BaseFootRaceManager.cpp b/dScripts/BaseFootRaceManager.cpp index 0c5d9f19..0da51bc5 100644 --- a/dScripts/BaseFootRaceManager.cpp +++ b/dScripts/BaseFootRaceManager.cpp @@ -12,7 +12,7 @@ void BaseFootRaceManager::OnFireEventServerSide(Entity *self, Entity *sender, st if (splitArguments.size() > 1) { const auto eventName = splitArguments[0]; - const auto player = EntityManager::Instance()->GetEntity(std::stol(splitArguments[1])); + const auto player = EntityManager::Instance()->GetEntity(std::stoull(splitArguments[1])); if (player != nullptr) { if (eventName == "updatePlayer") { diff --git a/dScripts/BasePropertyServer.cpp b/dScripts/BasePropertyServer.cpp index 27e3767b..ce36caa9 100644 --- a/dScripts/BasePropertyServer.cpp +++ b/dScripts/BasePropertyServer.cpp @@ -1,6 +1,4 @@ #include "BasePropertyServer.h" -#include -#include "dCommonVars.h" #include "GameMessages.h" #include "EntityManager.h" #include "dZoneManager.h" @@ -8,7 +6,8 @@ #include "DestroyableComponent.h" #include "Entity.h" #include "RenderComponent.h" -#include "dServer.h" +#include "PropertyManagementComponent.h" +#include "MissionComponent.h" void BasePropertyServer::SetGameVariables(Entity *self) { self->SetVar(ClaimMarkerGroup, ""); @@ -170,11 +169,10 @@ void BasePropertyServer::BaseZonePropertyRented(Entity* self, Entity* player) co EntityManager::Instance()->DestructEntity(plaque); } - if (self->GetVar(brickLinkMissionIDFlag) != 0) { - auto plaques = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(PropertyPlaqueGroup)); - for (auto* plaque : plaques) { - EntityManager::Instance()->DestructEntity(plaque); - } + auto brickLinkMissionID = self->GetVar(brickLinkMissionIDFlag); + if (brickLinkMissionID != 0) { + auto missionComponent = player->GetComponent(); + if (missionComponent) missionComponent->CompleteMission(brickLinkMissionID, true); } ActivateSpawner(self->GetVar(PropObjsSpawner)); @@ -337,7 +335,7 @@ void BasePropertyServer::BaseTimerDone(Entity* self, const std::string& timerNam const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); // No guard for the spider instance fight - if (Game::server->GetZoneID() == 1150) + if (dZoneManager::Instance()->GetZoneID().GetMapID() == 1150) return; const auto entities = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(GuardGroup)); diff --git a/dScripts/BasePropertyServer.h b/dScripts/BasePropertyServer.h index 8d9a2d7e..79a52f54 100644 --- a/dScripts/BasePropertyServer.h +++ b/dScripts/BasePropertyServer.h @@ -1,7 +1,5 @@ #pragma once #include "CppScripts.h" -#include "PropertyManagementComponent.h" -#include "PropertyVendorComponent.h" class BasePropertyServer : public CppScripts::Script { public: diff --git a/dScripts/BaseRandomServer.cpp b/dScripts/BaseRandomServer.cpp index 182544be..7026178c 100644 --- a/dScripts/BaseRandomServer.cpp +++ b/dScripts/BaseRandomServer.cpp @@ -1,8 +1,8 @@ #include "BaseRandomServer.h" -#include "EntityManager.h" #include "dZoneManager.h" -#include "DestroyableComponent.h" #include "Spawner.h" +#include "dLogger.h" +#include "Entity.h" void BaseRandomServer::BaseStartup(Entity* self) { diff --git a/dScripts/BaseRandomServer.h b/dScripts/BaseRandomServer.h index d04414f1..68aadf30 100644 --- a/dScripts/BaseRandomServer.h +++ b/dScripts/BaseRandomServer.h @@ -1,8 +1,8 @@ #pragma once -#include "CppScripts.h" -#include "Entity.h" -#include "dCommonVars.h" +#include + +class Spawner; class BaseRandomServer { public: diff --git a/dScripts/BaseSurvivalServer.cpp b/dScripts/BaseSurvivalServer.cpp index dd9b9365..f6a326e8 100644 --- a/dScripts/BaseSurvivalServer.cpp +++ b/dScripts/BaseSurvivalServer.cpp @@ -4,6 +4,8 @@ #include "EntityManager.h" #include "dZoneManager.h" #include "Player.h" +#include "MissionTaskType.h" +#include "MissionComponent.h" #include "Character.h" void BaseSurvivalServer::SetGameVariables(Entity *self) { diff --git a/dScripts/BaseSurvivalServer.h b/dScripts/BaseSurvivalServer.h index 55e1f8f9..c85f1bbf 100644 --- a/dScripts/BaseSurvivalServer.h +++ b/dScripts/BaseSurvivalServer.h @@ -1,6 +1,5 @@ #pragma once #include "ActivityManager.h" -#include "CppScripts.h" /** * State for each active game diff --git a/dScripts/BaseWavesServer.cpp b/dScripts/BaseWavesServer.cpp index ac8da8a7..2c8a2edd 100644 --- a/dScripts/BaseWavesServer.cpp +++ b/dScripts/BaseWavesServer.cpp @@ -4,6 +4,8 @@ #include "EntityManager.h" #include "dZoneManager.h" #include "Player.h" +#include "MissionTaskType.h" +#include "MissionComponent.h" #include "Character.h" // Done @@ -60,8 +62,11 @@ void BaseWavesServer::BaseStartup(Entity* self) { // Done void BaseWavesServer::BasePlayerExit(Entity* self, Entity* player) { - state.waitingPlayers.erase(std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID())); - state.players.erase(std::find(state.players.begin(), state.players.end(), player->GetObjectID())); + auto waitingPlayerToErase = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID()); + if (waitingPlayerToErase != state.waitingPlayers.end()) state.waitingPlayers.erase(waitingPlayerToErase); + + auto playerToErase = std::find(state.players.begin(), state.players.end(), player->GetObjectID()); + if (playerToErase != state.players.end()) state.players.erase(playerToErase); if (!self->GetNetworkVar(WavesStartedVariable)) { PlayerConfirmed(self); diff --git a/dScripts/BaseWavesServer.h b/dScripts/BaseWavesServer.h index cb04f50b..3dc90da8 100644 --- a/dScripts/BaseWavesServer.h +++ b/dScripts/BaseWavesServer.h @@ -1,6 +1,5 @@ #pragma once #include "ActivityManager.h" -#include "CppScripts.h" /** * State for each active game diff --git a/dScripts/BootyDigServer.cpp b/dScripts/BootyDigServer.cpp index eeb3bfd4..50d873e0 100644 --- a/dScripts/BootyDigServer.cpp +++ b/dScripts/BootyDigServer.cpp @@ -1,6 +1,8 @@ #include "BootyDigServer.h" #include "EntityManager.h" #include "RenderComponent.h" +#include "MissionComponent.h" +#include "MissionTaskType.h" void BootyDigServer::OnStartup(Entity *self) { auto* zoneControlObject = EntityManager::Instance()->GetZoneControlEntity(); diff --git a/dScripts/BossSpiderQueenEnemyServer.cpp b/dScripts/BossSpiderQueenEnemyServer.cpp index 9896fd45..dd0b80c8 100644 --- a/dScripts/BossSpiderQueenEnemyServer.cpp +++ b/dScripts/BossSpiderQueenEnemyServer.cpp @@ -6,7 +6,10 @@ #include "EntityManager.h" #include "Entity.h" #include "dZoneManager.h" -#include "dServer.h" + +#include "DestroyableComponent.h" +#include "ControllablePhysicsComponent.h" +#include "BaseCombatAIComponent.h" #include "GameMessages.h" #include "SkillComponent.h" @@ -49,7 +52,7 @@ void BossSpiderQueenEnemyServer::OnStartup(Entity* self) { } void BossSpiderQueenEnemyServer::OnDie(Entity* self, Entity* killer) { - if (Game::server->GetZoneID() == instanceZoneID) { + if (dZoneManager::Instance()->GetZoneID().GetMapID() == instanceZoneID) { auto* missionComponent = killer->GetComponent(); if (missionComponent == nullptr) return; diff --git a/dScripts/BossSpiderQueenEnemyServer.h b/dScripts/BossSpiderQueenEnemyServer.h index 34faf055..f3219cf7 100644 --- a/dScripts/BossSpiderQueenEnemyServer.h +++ b/dScripts/BossSpiderQueenEnemyServer.h @@ -1,10 +1,6 @@ #pragma once #include "CppScripts.h" -#include "DestroyableComponent.h" -#include "ControllablePhysicsComponent.h" -#include "BaseCombatAIComponent.h" - /* -------------------------------------------------------------- @@ -17,7 +13,9 @@ -------------------------------------------------------------- */ - +class DestroyableComponent; +class ControllablePhysicsComponent; +class BaseCombatAIComponent; class BossSpiderQueenEnemyServer final : public CppScripts::Script { public: void OnStartup(Entity* self) override; diff --git a/dScripts/BuccaneerValiantShip.cpp b/dScripts/BuccaneerValiantShip.cpp index 1cc1e633..710a0d1a 100644 --- a/dScripts/BuccaneerValiantShip.cpp +++ b/dScripts/BuccaneerValiantShip.cpp @@ -1,6 +1,5 @@ #include "BuccaneerValiantShip.h" #include "SkillComponent.h" -#include "dLogger.h" void BuccaneerValiantShip::OnStartup(Entity* self) { self->AddCallbackTimer(1.0F, [self]() { diff --git a/dScripts/BurningTile.cpp b/dScripts/BurningTile.cpp index 95a0bf17..b9a05391 100644 --- a/dScripts/BurningTile.cpp +++ b/dScripts/BurningTile.cpp @@ -1,7 +1,5 @@ #include "BurningTile.h" - #include "SkillComponent.h" -#include "GameMessages.h" void BurningTile::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { diff --git a/dScripts/CMakeLists.txt b/dScripts/CMakeLists.txt new file mode 100644 index 00000000..1fa177ba --- /dev/null +++ b/dScripts/CMakeLists.txt @@ -0,0 +1,253 @@ +set(DSCRIPT_SOURCES "ActivityManager.cpp" + "ActMine.cpp" + "ActNinjaTurret.cpp" + "ActParadoxPipeFix.cpp" + "ActPlayerDeathTrigger.cpp" + "ActSharkPlayerDeathTrigger.cpp" + "ActVehicleDeathTrigger.cpp" + "AgBugsprayer.cpp" + "AgBusDoor.cpp" + "AgCagedBricksServer.cpp" + "AgDarkSpiderling.cpp" + "AgFans.cpp" + "AgImagSmashable.cpp" + "AgJetEffectServer.cpp" + "AgLaserSensorServer.cpp" + "AgMonumentBirds.cpp" + "AgMonumentLaserServer.cpp" + "AgMonumentRaceCancel.cpp" + "AgMonumentRaceGoal.cpp" + "AgPicnicBlanket.cpp" + "AgPropGuard.cpp" + "AgPropguards.cpp" + "AgQbElevator.cpp" + "AgSalutingNpcs.cpp" + "AgShipPlayerDeathTrigger.cpp" + "AgShipPlayerShockServer.cpp" + "AgSpaceStuff.cpp" + "AgStagePlatforms.cpp" + "AgStromlingProperty.cpp" + "AgSurvivalBuffStation.cpp" + "AgSurvivalMech.cpp" + "AgSurvivalSpiderling.cpp" + "AgSurvivalStromling.cpp" + "AgTurret.cpp" + "AllCrateChicken.cpp" + "AmBlueX.cpp" + "AmBridge.cpp" + "AmConsoleTeleportServer.cpp" + "AmDarklingDragon.cpp" + "AmDarklingMech.cpp" + "AmDrawBridge.cpp" + "AmDropshipComputer.cpp" + "AmScrollReaderServer.cpp" + "AmShieldGenerator.cpp" + "AmShieldGeneratorQuickbuild.cpp" + "AmSkeletonEngineer.cpp" + "AmSkullkinDrill.cpp" + "AmSkullkinDrillStand.cpp" + "AmSkullkinTower.cpp" + "AmTeapotServer.cpp" + "AmTemplateSkillVolume.cpp" + "AnvilOfArmor.cpp" + "BankInteractServer.cpp" + "BaseConsoleTeleportServer.cpp" + "BaseEnemyApe.cpp" + "BaseEnemyMech.cpp" + "BaseFootRaceManager.cpp" + "BaseInteractDropLootServer.cpp" + "BasePropertyServer.cpp" + "BaseRandomServer.cpp" + "BaseSurvivalServer.cpp" + "BaseWavesGenericEnemy.cpp" + "BaseWavesServer.cpp" + "Binoculars.cpp" + "BootyDigServer.cpp" + "BossSpiderQueenEnemyServer.cpp" + "BuccaneerValiantShip.cpp" + "BurningTile.cpp" + "CatapultBaseServer.cpp" + "CatapultBouncerServer.cpp" + "CauldronOfLife.cpp" + "CavePrisonCage.cpp" + "ChooseYourDestinationNsToNt.cpp" + "ClRing.cpp" + "CppScripts.cpp" + "CrabServer.cpp" + "DamagingPets.cpp" + "Darkitect.cpp" + "DLUVanityNPC.cpp" + "EnemyNjBuff.cpp" + "EnemyRoninSpawner.cpp" + "EnemySkeletonSpawner.cpp" + "EnemySpiderSpawner.cpp" + "ExplodingAsset.cpp" + "FallingTile.cpp" + "FireFirstSkillonStartup.cpp" + "FlameJetServer.cpp" + "ForceVolumeServer.cpp" + "FountainOfImagination.cpp" + "FvBounceOverWall.cpp" + "FvBrickPuzzleServer.cpp" + "FvCandle.cpp" + "FvConsoleLeftQuickbuild.cpp" + "FvConsoleRightQuickbuild.cpp" + "FvDragonSmashingGolemQb.cpp" + "FvFacilityBrick.cpp" + "FvFlyingCreviceDragon.cpp" + "FvFong.cpp" + "FvFreeGfNinjas.cpp" + "FvHorsemenTrigger.cpp" + "FvMaelstromCavalry.cpp" + "FvMaelstromDragon.cpp" + "FvNinjaGuard.cpp" + "FvPandaServer.cpp" + "FvPandaSpawnerServer.cpp" + "FvPassThroughWall.cpp" + "FvRaceSmashEggImagineServer.cpp" + "GfApeSmashingQB.cpp" + "GfBanana.cpp" + "GfBananaCluster.cpp" + "GfCampfire.cpp" + "GfCaptainsCannon.cpp" + "GfJailkeepMission.cpp" + "GfJailWalls.cpp" + "GfOrgan.cpp" + "GfTikiTorch.cpp" + "GrowingFlower.cpp" + "HydrantBroken.cpp" + "HydrantSmashable.cpp" + "ImaginationBackpackHealServer.cpp" + "ImaginationShrineServer.cpp" + "ImgBrickConsoleQB.cpp" + "InstanceExitTransferPlayerToLastNonInstance.cpp" + "InvalidScript.cpp" + "LegoDieRoll.cpp" + "Lieutenant.cpp" + "MaestromExtracticatorServer.cpp" + "MailBoxServer.cpp" + "MastTeleport.cpp" + "MinigameTreasureChestServer.cpp" + "MonCoreNookDoors.cpp" + "MonCoreSmashableDoors.cpp" + "NjColeNPC.cpp" + "NjDragonEmblemChestServer.cpp" + "NjEarthDragonPetServer.cpp" + "NjEarthPetServer.cpp" + "NjGarmadonCelebration.cpp" + "NjhubLavaPlayerDeathTrigger.cpp" + "NjIceRailActivator.cpp" + "NjJayMissionItems.cpp" + "NjMonastryBossInstance.cpp" + "NjNPCMissionSpinjitzuServer.cpp" + "NjNyaMissionitems.cpp" + "NjRailActivatorsServer.cpp" + "NjRailPostServer.cpp" + "NjRailSwitch.cpp" + "NjScrollChestServer.cpp" + "NjWuNPC.cpp" + "NPCAddRemoveItem.cpp" + "NpcAgCourseStarter.cpp" + "NpcCowboyServer.cpp" + "NpcEpsilonServer.cpp" + "NpcNjAssistantServer.cpp" + "NpcNpSpacemanBob.cpp" + "NpcPirateServer.cpp" + "NpcWispServer.cpp" + "NsConcertChoiceBuild.cpp" + "NsConcertChoiceBuildManager.cpp" + "NsConcertInstrument.cpp" + "NsConcertQuickBuild.cpp" + "NsGetFactionMissionServer.cpp" + "NsJohnnyMissionServer.cpp" + "NsLegoClubDoor.cpp" + "NsLupTeleport.cpp" + "NsModularBuild.cpp" + "NsQbImaginationStatue.cpp" + "NsTokenConsoleServer.cpp" + "NtAssemblyTubeServer.cpp" + "NtBeamImaginationCollectors.cpp" + "NtCombatChallengeDummy.cpp" + "NtCombatChallengeExplodingDummy.cpp" + "NtCombatChallengeServer.cpp" + "NtConsoleTeleportServer.cpp" + "NtDarkitectRevealServer.cpp" + "NtDirtCloudServer.cpp" + "NtDukeServer.cpp" + "NtFactionSpyServer.cpp" + "NtHaelServer.cpp" + "NtImagBeamBuffer.cpp" + "NtOverbuildServer.cpp" + "NtParadoxPanelServer.cpp" + "NtParadoxTeleServer.cpp" + "NtSentinelWalkwayServer.cpp" + "NtSleepingGuard.cpp" + "NtVandaServer.cpp" + "NtVentureCannonServer.cpp" + "NtVentureSpeedPadServer.cpp" + "NtXRayServer.cpp" + "PersonalFortress.cpp" + "PetDigBuild.cpp" + "PetDigServer.cpp" + "PetFromDigServer.cpp" + "PetFromObjectServer.cpp" + "PropertyBankInteract.cpp" + "PropertyDeathPlane.cpp" + "PropertyDevice.cpp" + "PropertyFXDamage.cpp" + "PropertyPlatform.cpp" + "PrSeagullFly.cpp" + "PrWhistle.cpp" + "QbEnemyStunner.cpp" + "RaceImagineCrateServer.cpp" + "RaceImaginePowerup.cpp" + "RaceMaelstromGeiser.cpp" + "RaceSmashServer.cpp" + "RainOfArrows.cpp" + "RandomSpawnerFin.cpp" + "RandomSpawnerPit.cpp" + "RandomSpawnerStr.cpp" + "RandomSpawnerZip.cpp" + "RemoveRentalGear.cpp" + "RockHydrantBroken.cpp" + "RockHydrantSmashable.cpp" + "ScriptComponent.cpp" + "ScriptedPowerupSpawner.cpp" + "SGCannon.cpp" + "SpawnGryphonServer.cpp" + "SpawnLionServer.cpp" + "SpawnPetBaseServer.cpp" + "SpawnSaberCatServer.cpp" + "SpawnShrakeServer.cpp" + "SpawnStegoServer.cpp" + "SpecialImaginePowerupSpawner.cpp" + "SpiderBossTreasureChestServer.cpp" + "SsModularBuildServer.cpp" + "StinkyFishTarget.cpp" + "StoryBoxInteractServer.cpp" + "Sunflower.cpp" + "TokenConsoleServer.cpp" + "TouchMissionUpdateServer.cpp" + "TreasureChestDragonServer.cpp" + "TriggerAmbush.cpp" + "VeBricksampleServer.cpp" + "VeEpsilonServer.cpp" + "VeMech.cpp" + "VeMissionConsole.cpp" + "WaveBossApe.cpp" + "WaveBossHammerling.cpp" + "WaveBossHorsemen.cpp" + "WaveBossSpiderling.cpp" + "WhFans.cpp" + "WildAmbients.cpp" + "WishingWellServer.cpp" + "ZoneAgMedProperty.cpp" + "ZoneAgProperty.cpp" + "ZoneAgSpiderQueen.cpp" + "ZoneAgSurvival.cpp" + "ZoneFvProperty.cpp" + "ZoneGfProperty.cpp" + "ZoneNsMedProperty.cpp" + "ZoneNsProperty.cpp" + "ZoneNsWaves.cpp" + "ZoneSGServer.cpp" PARENT_SCOPE) diff --git a/dScripts/CatapultBaseServer.cpp b/dScripts/CatapultBaseServer.cpp index 81db8abd..33539de8 100644 --- a/dScripts/CatapultBaseServer.cpp +++ b/dScripts/CatapultBaseServer.cpp @@ -1,8 +1,6 @@ #include "CatapultBaseServer.h" #include "GameMessages.h" #include "EntityManager.h" -#include "dZoneManager.h" - void CatapultBaseServer::OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1, int32_t param2) { diff --git a/dScripts/CatapultBaseServer.h b/dScripts/CatapultBaseServer.h index ad949022..a174fcaf 100644 --- a/dScripts/CatapultBaseServer.h +++ b/dScripts/CatapultBaseServer.h @@ -1,8 +1,5 @@ #pragma once #include "CppScripts.h" -#include "Spawner.h" -#include "dZoneManager.h" -#include "dCommonVars.h" class CatapultBaseServer : public CppScripts::Script { public: diff --git a/dScripts/CatapultBouncerServer.cpp b/dScripts/CatapultBouncerServer.cpp index 0952a7ff..098f38ac 100644 --- a/dScripts/CatapultBouncerServer.cpp +++ b/dScripts/CatapultBouncerServer.cpp @@ -1,7 +1,6 @@ #include "CatapultBouncerServer.h" #include "GameMessages.h" #include "EntityManager.h" -#include "dZoneManager.h" void CatapultBouncerServer::OnRebuildComplete(Entity* self, Entity* target) { diff --git a/dScripts/CatapultBouncerServer.h b/dScripts/CatapultBouncerServer.h index 1178a46f..06f03bf4 100644 --- a/dScripts/CatapultBouncerServer.h +++ b/dScripts/CatapultBouncerServer.h @@ -1,8 +1,5 @@ #pragma once #include "CppScripts.h" -#include "Spawner.h" -#include "dZoneManager.h" -#include "dCommonVars.h" class CatapultBouncerServer : public CppScripts::Script { public: diff --git a/dScripts/CavePrisonCage.cpp b/dScripts/CavePrisonCage.cpp index 793050b3..5fe47f2d 100644 --- a/dScripts/CavePrisonCage.cpp +++ b/dScripts/CavePrisonCage.cpp @@ -1,9 +1,9 @@ #include "CavePrisonCage.h" #include "EntityManager.h" #include "RebuildComponent.h" -#include "MovingPlatformComponent.h" #include "GameMessages.h" #include "Character.h" +#include "dZoneManager.h" void CavePrisonCage::OnStartup(Entity *self) { diff --git a/dScripts/CavePrisonCage.h b/dScripts/CavePrisonCage.h index 47f95a98..5ae357d5 100644 --- a/dScripts/CavePrisonCage.h +++ b/dScripts/CavePrisonCage.h @@ -1,8 +1,5 @@ #pragma once #include "CppScripts.h" -#include "Spawner.h" -#include "dZoneManager.h" -#include "dCommonVars.h" class CavePrisonCage : public CppScripts::Script { public: diff --git a/dScripts/ChooseYourDestinationNsToNt.cpp b/dScripts/ChooseYourDestinationNsToNt.cpp index 2ed8ebdc..823d7c85 100644 --- a/dScripts/ChooseYourDestinationNsToNt.cpp +++ b/dScripts/ChooseYourDestinationNsToNt.cpp @@ -1,8 +1,6 @@ #include "ChooseYourDestinationNsToNt.h" #include "Character.h" #include "GameMessages.h" -#include "dZoneManager.h" -#include "EntityManager.h" bool ChooseYourDestinationNsToNt::CheckChoice(Entity* self, Entity* player) { diff --git a/dScripts/ChooseYourDestinationNsToNt.h b/dScripts/ChooseYourDestinationNsToNt.h index 7a02b38b..cbf3709e 100644 --- a/dScripts/ChooseYourDestinationNsToNt.h +++ b/dScripts/ChooseYourDestinationNsToNt.h @@ -1,5 +1,4 @@ #pragma once -#include "CppScripts.h" class ChooseYourDestinationNsToNt { diff --git a/dScripts/ClRing.cpp b/dScripts/ClRing.cpp index 5b2910d3..5de3e683 100644 --- a/dScripts/ClRing.cpp +++ b/dScripts/ClRing.cpp @@ -1,6 +1,4 @@ #include "ClRing.h" -#include "EntityManager.h" -#include "Character.h" void ClRing::OnCollisionPhantom(Entity* self, Entity* target) { diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index a87f027d..76407138 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -4,10 +4,8 @@ #include "CppScripts.h" #include "GameMessages.h" -#include "dpWorld.h" #include "Entity.h" #include "ScriptComponent.h" -#include "EntityManager.h" #include "Game.h" #include "dLogger.h" #include "InvalidScript.h" @@ -164,6 +162,8 @@ #include "BaseFootRaceManager.h" #include "PropertyPlatform.h" #include "MailBoxServer.h" +#include "ActMine.h" +#include "FireFirstSkillonStartup.h" // Racing Scripts #include "RaceImagineCrateServer.h" @@ -591,6 +591,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr return 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") @@ -801,7 +803,8 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new LegoDieRoll(); else if (scriptName == "scripts\\EquipmentScripts\\BuccaneerValiantShip.lua") script = new BuccaneerValiantShip(); - + else if (scriptName == "scripts\\EquipmentScripts\\FireFirstSkillonStartup.lua") + script = new FireFirstSkillonStartup(); // FB else if (scriptName == "scripts\\ai\\NS\\WH\\L_ROCKHYDRANT_BROKEN.lua") script = new RockHydrantBroken(); diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index e58061e1..640fe020 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -1,12 +1,8 @@ #pragma once #include "dCommonVars.h" -#include "RakNetTypes.h" -#include -#include "MissionComponent.h" #include "MissionState.h" -#include "Game.h" -#include "dLogger.h" -#include "Loot.h" +#include +#include class User; class Entity; diff --git a/dScripts/DLUVanityNPC.cpp b/dScripts/DLUVanityNPC.cpp index ec8a0574..c219a5f9 100644 --- a/dScripts/DLUVanityNPC.cpp +++ b/dScripts/DLUVanityNPC.cpp @@ -1,6 +1,7 @@ #include "DLUVanityNPC.h" #include "GameMessages.h" #include "dServer.h" +#include "VanityUtilities.h" void DLUVanityNPC::OnStartup(Entity* self) { diff --git a/dScripts/DLUVanityNPC.h b/dScripts/DLUVanityNPC.h index baacf5dd..4eba3554 100644 --- a/dScripts/DLUVanityNPC.h +++ b/dScripts/DLUVanityNPC.h @@ -1,7 +1,7 @@ #pragma once #include "CppScripts.h" -#include "VanityUtilities.h" +class VanityNPC; class DLUVanityNPC : public CppScripts::Script { public: diff --git a/dScripts/DamagingPets.h b/dScripts/DamagingPets.h index d0044fb5..04c4e6bf 100644 --- a/dScripts/DamagingPets.h +++ b/dScripts/DamagingPets.h @@ -1,5 +1,4 @@ #pragma once - #include "CppScripts.h" /** diff --git a/dScripts/Darkitect.h b/dScripts/Darkitect.h index f0d19648..56b1c832 100644 --- a/dScripts/Darkitect.h +++ b/dScripts/Darkitect.h @@ -1,5 +1,4 @@ #pragma once - class Entity; class Darkitect diff --git a/dScripts/EnemySpiderSpawner.cpp b/dScripts/EnemySpiderSpawner.cpp index 96f5e6c8..98524ae1 100644 --- a/dScripts/EnemySpiderSpawner.cpp +++ b/dScripts/EnemySpiderSpawner.cpp @@ -1,9 +1,7 @@ #include "EnemySpiderSpawner.h" #include "GameMessages.h" -#include "SimplePhysicsComponent.h" #include "EntityManager.h" #include "DestroyableComponent.h" -#include "MovementAIComponent.h" //---------------------------------------------- //--Initiate egg hatching on call diff --git a/dScripts/ExplodingAsset.cpp b/dScripts/ExplodingAsset.cpp index 929d2082..b4bd6913 100644 --- a/dScripts/ExplodingAsset.cpp +++ b/dScripts/ExplodingAsset.cpp @@ -1,7 +1,7 @@ #include "ExplodingAsset.h" - #include "DestroyableComponent.h" #include "GameMessages.h" +#include "MissionComponent.h" #include "SkillComponent.h" //TODO: this has to be updated so that you only get killed if you're in a certain radius. diff --git a/dScripts/FallingTile.cpp b/dScripts/FallingTile.cpp index 5bd8adc6..2dd8c7bc 100644 --- a/dScripts/FallingTile.cpp +++ b/dScripts/FallingTile.cpp @@ -2,7 +2,6 @@ #include "MovingPlatformComponent.h" #include "GameMessages.h" - void FallingTile::OnStartup(Entity* self) { auto* movingPlatfromComponent = self->GetComponent(); diff --git a/dScripts/FireFirstSkillonStartup.cpp b/dScripts/FireFirstSkillonStartup.cpp new file mode 100644 index 00000000..da1b420e --- /dev/null +++ b/dScripts/FireFirstSkillonStartup.cpp @@ -0,0 +1,24 @@ +#include "FireFirstSkillonStartup.h" +#include "Entity.h" +#include "SkillComponent.h" +#include "CDClientDatabase.h" +#include "CDObjectSkillsTable.h" + +void FireFirstSkillonStartup::OnStartup(Entity* self) { + auto skillComponent = self->GetComponent(); + if (!skillComponent) return; + + // Get the skill IDs of this object. + CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable("ObjectSkills"); + std::vector skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); }); + + // For each skill, cast it with the associated behavior ID. + for (auto skill : skills) { + CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID); + + // Should parent entity be null, make the originator self. + const auto target = self->GetParentEntity() ? self->GetParentEntity()->GetObjectID() : self->GetObjectID(); + skillComponent->CalculateBehavior(skill.skillID, behaviorData.behaviorID, LWOOBJID_EMPTY, false, false, target); + } +} \ No newline at end of file diff --git a/dScripts/FireFirstSkillonStartup.h b/dScripts/FireFirstSkillonStartup.h new file mode 100644 index 00000000..ad182e70 --- /dev/null +++ b/dScripts/FireFirstSkillonStartup.h @@ -0,0 +1,12 @@ +#pragma once +#ifndef __FIREFIRSTSKILLONSTARTUP__H__ +#define __FIREFIRSTSKILLONSTARTUP__H__ + +#include "CppScripts.h" + +class FireFirstSkillonStartup : public CppScripts::Script { + public: + void OnStartup(Entity* self) override; +}; + +#endif //!__FIREFIRSTSKILLONSTARTUP__H__ diff --git a/dScripts/FlameJetServer.cpp b/dScripts/FlameJetServer.cpp index 9ecf4fa2..0e6d91cc 100644 --- a/dScripts/FlameJetServer.cpp +++ b/dScripts/FlameJetServer.cpp @@ -1,5 +1,4 @@ #include "FlameJetServer.h" - #include "SkillComponent.h" #include "GameMessages.h" diff --git a/dScripts/ForceVolumeServer.cpp b/dScripts/ForceVolumeServer.cpp index ce3e0bd6..e9320527 100644 --- a/dScripts/ForceVolumeServer.cpp +++ b/dScripts/ForceVolumeServer.cpp @@ -2,17 +2,11 @@ #include "PhantomPhysicsComponent.h" #include "EntityManager.h" - void ForceVolumeServer::OnStartup(Entity* self) { auto* phantomPhysicsComponent = self->GetComponent(); - if (phantomPhysicsComponent == nullptr) - { - Game::logger->Log("ForceVolumeServer", "Failed to find PhantomPhysicsComponent\n"); - - return; - } + if (phantomPhysicsComponent == nullptr) return; const auto forceAmount = self->GetVar(u"ForceAmt"); const auto forceX = self->GetVar(u"ForceX"); diff --git a/dScripts/FountainOfImagination.cpp b/dScripts/FountainOfImagination.cpp index 2d752db4..43351e18 100644 --- a/dScripts/FountainOfImagination.cpp +++ b/dScripts/FountainOfImagination.cpp @@ -1,4 +1,6 @@ #include "FountainOfImagination.h" +#include "dCommonVars.h" +#include "Entity.h" void FountainOfImagination::OnStartup(Entity *self) { self->SetVar(u"numCycles", 6); diff --git a/dScripts/FvBounceOverWall.cpp b/dScripts/FvBounceOverWall.cpp index 348bc36c..1c85ffbd 100644 --- a/dScripts/FvBounceOverWall.cpp +++ b/dScripts/FvBounceOverWall.cpp @@ -1,4 +1,5 @@ #include "FvBounceOverWall.h" +#include "MissionComponent.h" void FvBounceOverWall::OnCollisionPhantom(Entity* self, Entity* target) { auto missionComponent = target->GetComponent(); diff --git a/dScripts/FvCandle.cpp b/dScripts/FvCandle.cpp index 2081faf3..63f90f0b 100644 --- a/dScripts/FvCandle.cpp +++ b/dScripts/FvCandle.cpp @@ -1,5 +1,6 @@ #include "FvCandle.h" #include "MissionComponent.h" +#include "RenderComponent.h" std::vector FvCandle::m_Missions = {850, 1431, 1529, 1566, 1603}; diff --git a/dScripts/FvCandle.h b/dScripts/FvCandle.h index 1df63675..362d2a05 100644 --- a/dScripts/FvCandle.h +++ b/dScripts/FvCandle.h @@ -1,6 +1,5 @@ #pragma once #include "CppScripts.h" -#include "RenderComponent.h" class FvCandle : public CppScripts::Script { diff --git a/dScripts/FvConsoleLeftQuickbuild.cpp b/dScripts/FvConsoleLeftQuickbuild.cpp index 4b0a4f6c..ef281f15 100644 --- a/dScripts/FvConsoleLeftQuickbuild.cpp +++ b/dScripts/FvConsoleLeftQuickbuild.cpp @@ -1,7 +1,4 @@ #include "FvConsoleLeftQuickbuild.h" -#include "RebuildComponent.h" -#include "GeneralUtils.h" -#include "dZoneManager.h" #include "EntityManager.h" #include "GameMessages.h" diff --git a/dScripts/FvConsoleRightQuickbuild.cpp b/dScripts/FvConsoleRightQuickbuild.cpp index d72658b0..0bf9849a 100644 --- a/dScripts/FvConsoleRightQuickbuild.cpp +++ b/dScripts/FvConsoleRightQuickbuild.cpp @@ -1,7 +1,4 @@ #include "FvConsoleRightQuickbuild.h" -#include "RebuildComponent.h" -#include "GeneralUtils.h" -#include "dZoneManager.h" #include "EntityManager.h" #include "GameMessages.h" diff --git a/dScripts/FvFacilityBrick.cpp b/dScripts/FvFacilityBrick.cpp index 639265a7..fce9e630 100644 --- a/dScripts/FvFacilityBrick.cpp +++ b/dScripts/FvFacilityBrick.cpp @@ -1,10 +1,8 @@ #include "FvFacilityBrick.h" #include "GameMessages.h" -#include "GeneralUtils.h" #include "dZoneManager.h" #include "EntityManager.h" - void FvFacilityBrick::OnStartup(Entity* self) { self->SetVar(u"ConsoleLEFTActive", false); @@ -13,8 +11,6 @@ void FvFacilityBrick::OnStartup(Entity* self) void FvFacilityBrick::OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1, int32_t param2) { - Game::logger->Log("FvFacilityBrick", "Notify: %s\n", name.c_str()); - auto* brickSpawner = dZoneManager::Instance()->GetSpawnersByName("ImaginationBrick")[0]; auto* bugSpawner = dZoneManager::Instance()->GetSpawnersByName("MaelstromBug")[0]; auto* canisterSpawner = dZoneManager::Instance()->GetSpawnersByName("BrickCanister")[0]; diff --git a/dScripts/FvFong.cpp b/dScripts/FvFong.cpp index 890bf0ff..9a3de0b2 100644 --- a/dScripts/FvFong.cpp +++ b/dScripts/FvFong.cpp @@ -1,6 +1,6 @@ #include "FvFong.h" #include "Darkitect.h" -#include "MissionComponent.h" +#include "MissionState.h" void FvFong::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { diff --git a/dScripts/FvFreeGfNinjas.cpp b/dScripts/FvFreeGfNinjas.cpp index 0d749b01..8022b32f 100644 --- a/dScripts/FvFreeGfNinjas.cpp +++ b/dScripts/FvFreeGfNinjas.cpp @@ -1,5 +1,6 @@ #include "FvFreeGfNinjas.h" #include "Character.h" +#include "MissionComponent.h" void FvFreeGfNinjas::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { if (missionID == 705 && missionState == MissionState::MISSION_STATE_AVAILABLE) { diff --git a/dScripts/FvHorsemenTrigger.cpp b/dScripts/FvHorsemenTrigger.cpp index e984ab99..541c11e0 100644 --- a/dScripts/FvHorsemenTrigger.cpp +++ b/dScripts/FvHorsemenTrigger.cpp @@ -11,8 +11,6 @@ void FvHorsemenTrigger::OnStartup(Entity* self) void FvHorsemenTrigger::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { - Game::logger->Log("FvHorsemenTrigger", "Proximity update\n"); - if (name != "horsemenTrigger" || !entering->IsPlayer()) { return; @@ -24,12 +22,10 @@ void FvHorsemenTrigger::OnProximityUpdate(Entity* self, Entity* entering, std::s if (status == "ENTER" && iter == players.end()) { - Game::logger->Log("FvHorsemenTrigger", "Proximity enter\n"); players.push_back(entering->GetObjectID()); } else if (status == "LEAVE" && iter != players.end()) { - Game::logger->Log("FvHorsemenTrigger", "Proximity leave\n"); players.erase(iter); } @@ -42,7 +38,6 @@ FvHorsemenTrigger::OnFireEventServerSide(Entity *self, Entity *sender, std::stri { auto players = self->GetVar>(u"players"); - Game::logger->Log("FvHorsemenTrigger", "Got event %s with %i players\n", args.c_str(), players.size()); if (args == "HorsemenDeath") { for (const auto& playerId : self->GetVar>(u"players")) diff --git a/dScripts/FvMaelstromCavalry.cpp b/dScripts/FvMaelstromCavalry.cpp index d4d93645..b4a32991 100644 --- a/dScripts/FvMaelstromCavalry.cpp +++ b/dScripts/FvMaelstromCavalry.cpp @@ -5,16 +5,12 @@ void FvMaelstromCavalry::OnStartup(Entity* self) { for (const auto& group : self->GetGroups()) { - Game::logger->Log("FvMaelstromCavalry", "Got group: %s\n", group.c_str()); - const auto& objects = EntityManager::Instance()->GetEntitiesInGroup(group); for (auto* obj : objects) { if (obj->GetLOT() != 8551) continue; - Game::logger->Log("FvMaelstromCavalry", "Trigger in group: %s\n", group.c_str()); - obj->OnFireEventServerSide(self, "ISpawned"); } } @@ -27,8 +23,6 @@ void FvMaelstromCavalry::OnDie(Entity* self, Entity* killer) return; } - Game::logger->Log("FvMaelstromCavalry", "Killer: %i\n", killer->GetLOT()); - if (killer->GetLOT() != 8665) { return; @@ -38,8 +32,6 @@ void FvMaelstromCavalry::OnDie(Entity* self, Entity* killer) for (auto* trigger : triggers) { - Game::logger->Log("FvMaelstromCavalry", "Trigger for: %i\n", killer->GetLOT()); - trigger->OnFireEventServerSide(self, "HorsemenDeath"); } } diff --git a/dScripts/FvMaelstromCavalry.h b/dScripts/FvMaelstromCavalry.h index cfa9ff4b..0fc3e840 100644 --- a/dScripts/FvMaelstromCavalry.h +++ b/dScripts/FvMaelstromCavalry.h @@ -1,6 +1,5 @@ #pragma once #include "CppScripts.h" -#include "RenderComponent.h" class FvMaelstromCavalry : public CppScripts::Script { diff --git a/dScripts/FvMaelstromDragon.cpp b/dScripts/FvMaelstromDragon.cpp index e67ce815..afdfa4ae 100644 --- a/dScripts/FvMaelstromDragon.cpp +++ b/dScripts/FvMaelstromDragon.cpp @@ -2,7 +2,6 @@ #include "EntityManager.h" #include "SkillComponent.h" #include "BaseCombatAIComponent.h" -#include "RenderComponent.h" #include "DestroyableComponent.h" void FvMaelstromDragon::OnStartup(Entity* self) diff --git a/dScripts/FvMaelstromDragon.h b/dScripts/FvMaelstromDragon.h index 993306d3..52af80c4 100644 --- a/dScripts/FvMaelstromDragon.h +++ b/dScripts/FvMaelstromDragon.h @@ -1,6 +1,5 @@ #pragma once #include "CppScripts.h" -#include "RenderComponent.h" class FvMaelstromDragon : public CppScripts::Script { diff --git a/dScripts/FvPassThroughWall.cpp b/dScripts/FvPassThroughWall.cpp index 66130a9f..e894f923 100644 --- a/dScripts/FvPassThroughWall.cpp +++ b/dScripts/FvPassThroughWall.cpp @@ -1,5 +1,6 @@ #include "FvPassThroughWall.h" #include "InventoryComponent.h" +#include "MissionComponent.h" void FvPassThroughWall::OnCollisionPhantom(Entity* self, Entity* target) { auto missionComponent = target->GetComponent(); diff --git a/dScripts/FvRaceSmashEggImagineServer.cpp b/dScripts/FvRaceSmashEggImagineServer.cpp index 8e0d0897..696504e2 100644 --- a/dScripts/FvRaceSmashEggImagineServer.cpp +++ b/dScripts/FvRaceSmashEggImagineServer.cpp @@ -1,9 +1,10 @@ +#include "FvRaceSmashEggImagineServer.h" #include "CharacterComponent.h" #include "DestroyableComponent.h" #include "EntityManager.h" -#include "FvRaceSmashEggImagineServer.h" #include "PossessableComponent.h" #include "RacingTaskParam.h" +#include "MissionComponent.h" void FvRaceSmashEggImagineServer::OnDie(Entity *self, Entity *killer) { if (killer != nullptr) { diff --git a/dScripts/GfBanana.cpp b/dScripts/GfBanana.cpp index 65c434ba..346c9ad7 100644 --- a/dScripts/GfBanana.cpp +++ b/dScripts/GfBanana.cpp @@ -3,12 +3,9 @@ #include "Entity.h" #include "DestroyableComponent.h" #include "EntityManager.h" -#include "dLogger.h" void GfBanana::SpawnBanana(Entity* self) { - Game::logger->Log("GfBanana", "Spawning banana\n"); - auto position = self->GetPosition(); const auto rotation = self->GetRotation(); @@ -44,8 +41,6 @@ void GfBanana::OnStartup(Entity* self) void GfBanana::OnHit(Entity* self, Entity* attacker) { - Game::logger->Log("GfBanana", "Spawning cluster\n"); - auto* destroyable = self->GetComponent(); destroyable->SetHealth(9999); diff --git a/dScripts/GfBananaCluster.cpp b/dScripts/GfBananaCluster.cpp index 8ccc3be6..aacba224 100644 --- a/dScripts/GfBananaCluster.cpp +++ b/dScripts/GfBananaCluster.cpp @@ -1,4 +1,5 @@ #include "GfBananaCluster.h" +#include "Entity.h" void GfBananaCluster::OnStartup(Entity* self) { diff --git a/dScripts/GfCampfire.cpp b/dScripts/GfCampfire.cpp index caeaa6da..48170c66 100644 --- a/dScripts/GfCampfire.cpp +++ b/dScripts/GfCampfire.cpp @@ -1,11 +1,8 @@ #include "GfCampfire.h" -#include "GameMessages.h" - #include "RenderComponent.h" #include "SkillComponent.h" #include "MissionComponent.h" #include "RenderComponent.h" -#include "ProximityMonitorComponent.h" #include "EntityManager.h" void GfCampfire::OnStartup(Entity* self) { diff --git a/dScripts/GfJailWalls.cpp b/dScripts/GfJailWalls.cpp index 184fbd69..da547d0b 100644 --- a/dScripts/GfJailWalls.cpp +++ b/dScripts/GfJailWalls.cpp @@ -1,5 +1,4 @@ #include "GfJailWalls.h" -#include "EntityManager.h" #include "dZoneManager.h" #include "GeneralUtils.h" diff --git a/dScripts/GfTikiTorch.cpp b/dScripts/GfTikiTorch.cpp index d0e5d58d..dd1c14a7 100644 --- a/dScripts/GfTikiTorch.cpp +++ b/dScripts/GfTikiTorch.cpp @@ -1,7 +1,7 @@ #include "GfTikiTorch.h" #include "GameMessages.h" #include "EntityManager.h" - +#include "MissionComponent.h" #include "RenderComponent.h" void GfTikiTorch::OnStartup(Entity* self) { diff --git a/dScripts/ImaginationBackpackHealServer.cpp b/dScripts/ImaginationBackpackHealServer.cpp index 3f572a8f..1d7da2c5 100644 --- a/dScripts/ImaginationBackpackHealServer.cpp +++ b/dScripts/ImaginationBackpackHealServer.cpp @@ -1,5 +1,6 @@ #include "ImaginationBackpackHealServer.h" #include "GameMessages.h" +#include "MissionComponent.h" void ImaginationBackpackHealServer::OnSkillEventFired(Entity *self, Entity *caster, const std::string &message) { if (message == "CastImaginationBackpack") { diff --git a/dScripts/ImaginationShrineServer.cpp b/dScripts/ImaginationShrineServer.cpp index 0b40b44f..54c02614 100644 --- a/dScripts/ImaginationShrineServer.cpp +++ b/dScripts/ImaginationShrineServer.cpp @@ -1,7 +1,6 @@ #include "ImaginationShrineServer.h" #include "RebuildComponent.h" - void ImaginationShrineServer::OnUse(Entity* self, Entity* user) { // If the rebuild component is complete, use the shrine diff --git a/dScripts/ImgBrickConsoleQB.cpp b/dScripts/ImgBrickConsoleQB.cpp index 4d2d1e96..0dfb6288 100644 --- a/dScripts/ImgBrickConsoleQB.cpp +++ b/dScripts/ImgBrickConsoleQB.cpp @@ -197,8 +197,6 @@ void ImgBrickConsoleQB::OnDie(Entity* self, Entity* killer) self->SetVar(u"Died", true); - Game::logger->Log("ImgBrickConsoleQB", "On Die...\n"); - auto* rebuildComponent = self->GetComponent(); if (rebuildComponent->GetState() == REBUILD_COMPLETED) @@ -266,16 +264,12 @@ void ImgBrickConsoleQB::OnDie(Entity* self, Entity* killer) } self->SetNetworkVar(u"used", false); - - Game::logger->Log("ImgBrickConsoleQB", "Died...\n"); } void ImgBrickConsoleQB::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "reset") { - Game::logger->Log("ImgBrickConsoleQB", "Resetting...\n"); - auto* rebuildComponent = self->GetComponent(); if (rebuildComponent->GetState() == REBUILD_OPEN) @@ -285,8 +279,6 @@ void ImgBrickConsoleQB::OnTimerDone(Entity* self, std::string timerName) } else if (timerName == "Die") { - Game::logger->Log("ImgBrickConsoleQB", "Die...\n"); - const auto consoles = EntityManager::Instance()->GetEntitiesInGroup("Console"); for (auto* console : consoles) diff --git a/dScripts/ImgBrickConsoleQB.h b/dScripts/ImgBrickConsoleQB.h index 1fdcf84a..f51f8e6c 100644 --- a/dScripts/ImgBrickConsoleQB.h +++ b/dScripts/ImgBrickConsoleQB.h @@ -1,6 +1,5 @@ #pragma once #include "CppScripts.h" -#include class ImgBrickConsoleQB : public CppScripts::Script { diff --git a/dScripts/InstanceExitTransferPlayerToLastNonInstance.cpp b/dScripts/InstanceExitTransferPlayerToLastNonInstance.cpp index 4bd99f7f..307c6c73 100644 --- a/dScripts/InstanceExitTransferPlayerToLastNonInstance.cpp +++ b/dScripts/InstanceExitTransferPlayerToLastNonInstance.cpp @@ -2,13 +2,10 @@ #include "GameMessages.h" #include "Player.h" #include "Character.h" -#include "Game.h" #include "dServer.h" void InstanceExitTransferPlayerToLastNonInstance::OnUse(Entity* self, Entity* user) { - Game::logger->Log("Instance", "OnUse\n"); - auto transferText = self->GetVar(u"transferText"); if (transferText.empty()) transferText = u"DRAGON_EXIT_QUESTION"; diff --git a/dScripts/LegoDieRoll.cpp b/dScripts/LegoDieRoll.cpp index 4b375a38..386313be 100644 --- a/dScripts/LegoDieRoll.cpp +++ b/dScripts/LegoDieRoll.cpp @@ -1,7 +1,7 @@ #include "LegoDieRoll.h" #include "Entity.h" -#include "dLogger.h" #include "GameMessages.h" +#include "MissionComponent.h" void LegoDieRoll::OnStartup(Entity* self) { self->AddTimer("DoneRolling", 10.0f); @@ -48,7 +48,6 @@ void LegoDieRoll::OnTimerDone(Entity* self, std::string timerName) { break; } default: - Game::logger->LogDebug("LegoDieRoll", "Invalid animation: roll-die-%i\n", dieRoll); break; } } diff --git a/dScripts/MastTeleport.cpp b/dScripts/MastTeleport.cpp index 601f7dbf..94d5f552 100644 --- a/dScripts/MastTeleport.cpp +++ b/dScripts/MastTeleport.cpp @@ -1,7 +1,6 @@ #include "MastTeleport.h" #include "EntityManager.h" #include "GameMessages.h" -#include "Game.h" #include "Preconditions.h" #ifdef _WIN32 diff --git a/dScripts/MinigameTreasureChestServer.cpp b/dScripts/MinigameTreasureChestServer.cpp index ff32b527..fc3f14c0 100644 --- a/dScripts/MinigameTreasureChestServer.cpp +++ b/dScripts/MinigameTreasureChestServer.cpp @@ -3,7 +3,6 @@ #include "TeamManager.h" #include "EntityManager.h" #include "dZoneManager.h" -#include "dServer.h" void MinigameTreasureChestServer::OnUse(Entity *self, Entity *user) { auto* sac = self->GetComponent(); @@ -56,7 +55,7 @@ uint32_t MinigameTreasureChestServer::CalculateActivityRating(Entity *self, LWOO void MinigameTreasureChestServer::OnStartup(Entity *self) { // BONS treasure chest thinks it's on FV, causing it to start a lobby - if (Game::server->GetZoneID() == 1204) { + if (dZoneManager::Instance()->GetZoneID().GetMapID() == 1204) { auto* sac = self->GetComponent(); if (sac != nullptr) { sac->SetInstanceMapID(1204); diff --git a/dScripts/MissionConsoleServer.cpp b/dScripts/MissionConsoleServer.cpp deleted file mode 100644 index 136f2cb6..00000000 --- a/dScripts/MissionConsoleServer.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "MissionConsoleServer.h" diff --git a/dScripts/MissionConsoleServer.h b/dScripts/MissionConsoleServer.h deleted file mode 100644 index c502fc00..00000000 --- a/dScripts/MissionConsoleServer.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class MissionConsoleServer : public CppScripts::Script { -}; - diff --git a/dScripts/MonCoreNookDoors.cpp b/dScripts/MonCoreNookDoors.cpp index c038c1dd..c3fcf9be 100644 --- a/dScripts/MonCoreNookDoors.cpp +++ b/dScripts/MonCoreNookDoors.cpp @@ -1,6 +1,4 @@ #include "MonCoreNookDoors.h" -#include "GameMessages.h" -#include "EntityManager.h" #include "dZoneManager.h" void MonCoreNookDoors::OnStartup(Entity* self) diff --git a/dScripts/MonCoreSmashableDoors.cpp b/dScripts/MonCoreSmashableDoors.cpp index 1ea1bef9..0e7950f5 100644 --- a/dScripts/MonCoreSmashableDoors.cpp +++ b/dScripts/MonCoreSmashableDoors.cpp @@ -1,7 +1,5 @@ #include "MonCoreSmashableDoors.h" -#include "GameMessages.h" #include "EntityManager.h" -#include "dZoneManager.h" void MonCoreSmashableDoors::OnDie(Entity* self, Entity* killer) { diff --git a/dScripts/NjEarthDragonPetServer.cpp b/dScripts/NjEarthDragonPetServer.cpp index 3be5c63a..2b91f33c 100644 --- a/dScripts/NjEarthDragonPetServer.cpp +++ b/dScripts/NjEarthDragonPetServer.cpp @@ -1,4 +1,5 @@ #include "NjEarthDragonPetServer.h" +#include "Entity.h" void NjEarthDragonPetServer::SetVariables(Entity *self) { self->SetVar(u"petLOT", 16210); diff --git a/dScripts/NjEarthDragonPetServer.h b/dScripts/NjEarthDragonPetServer.h index 41c068f4..2227bbb6 100644 --- a/dScripts/NjEarthDragonPetServer.h +++ b/dScripts/NjEarthDragonPetServer.h @@ -1,5 +1,4 @@ #pragma once -//#include "NjPetSpawnerServer.h" #include "SpawnPetBaseServer.h" class NjEarthDragonPetServer : public SpawnPetBaseServer { diff --git a/dScripts/NjJayMissionItems.h b/dScripts/NjJayMissionItems.h index 7f30d7f0..19cb4f40 100644 --- a/dScripts/NjJayMissionItems.h +++ b/dScripts/NjJayMissionItems.h @@ -1,6 +1,8 @@ #pragma once #include "NjNPCMissionSpinjitzuServer.h" #include "NPCAddRemoveItem.h" +#include +#include class NjJayMissionItems : public NjNPCMissionSpinjitzuServer, NPCAddRemoveItem { void OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) override; diff --git a/dScripts/NjMonastryBossInstance.cpp b/dScripts/NjMonastryBossInstance.cpp index 17c4b296..cd34ea2c 100644 --- a/dScripts/NjMonastryBossInstance.cpp +++ b/dScripts/NjMonastryBossInstance.cpp @@ -1,15 +1,14 @@ -#include -#include "RebuildComponent.h" #include "NjMonastryBossInstance.h" +#include "RebuildComponent.h" #include "DestroyableComponent.h" #include "EntityManager.h" -#include "GameMessages.h" #include "dZoneManager.h" #include "GameMessages.h" #include "BaseCombatAIComponent.h" #include "BuffComponent.h" #include "SkillComponent.h" #include "TeamManager.h" +#include // // // // // // // // Event handling // @@ -91,15 +90,33 @@ void NjMonastryBossInstance::OnPlayerLoaded(Entity *self, Entity *player) { void NjMonastryBossInstance::OnPlayerExit(Entity *self, Entity *player) { UpdatePlayer(self, player->GetObjectID(), true); - //TODO: Add functionality to dynamically turn off the large team variable when enough players leave. - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLeft", 0, 0, - player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); + // Fetch the total players loaded from the vars + auto totalPlayersLoaded = self->GetVar >(TotalPlayersLoadedVariable); + + // Find the player to remove + auto playerToRemove = std::find(totalPlayersLoaded.begin(), totalPlayersLoaded.end(), player->GetObjectID()); + + // If we found the player remove them from out list of players + if (playerToRemove != totalPlayersLoaded.end()) { + totalPlayersLoaded.erase(playerToRemove); + } else { + Game::logger->Log("NjMonastryBossInstance", "Failed to remove player at exit.\n"); + } + + // Set the players loaded var back + self->SetVar>(TotalPlayersLoadedVariable, totalPlayersLoaded); + + // Since this is an exit method, check if enough players have left. If enough have left + // resize the instance to account for such. + if (totalPlayersLoaded.size() <= 2) self->SetVar(LargeTeamVariable, false); + + GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayerLeft", 0, 0, player->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); } void NjMonastryBossInstance::OnActivityTimerDone(Entity *self, const std::string &name) { auto split = GeneralUtils::SplitString(name, TimerSplitChar); auto timerName = split[0]; - auto objectID = split.size() > 1 ? (LWOOBJID) std::stol(split[1]) : LWOOBJID_EMPTY; + auto objectID = split.size() > 1 ? (LWOOBJID) std::stoull(split[1]) : LWOOBJID_EMPTY; if (timerName == WaitingForPlayersTimer) { StartFight(self); diff --git a/dScripts/NjNPCMissionSpinjitzuServer.h b/dScripts/NjNPCMissionSpinjitzuServer.h index 51150373..5b346ee7 100644 --- a/dScripts/NjNPCMissionSpinjitzuServer.h +++ b/dScripts/NjNPCMissionSpinjitzuServer.h @@ -1,5 +1,6 @@ #pragma once #include "CppScripts.h" +#include static std::map ElementFlags = { {u"earth", ePlayerFlags::NJ_EARTH_SPINJITZU}, diff --git a/dScripts/NjNyaMissionitems.h b/dScripts/NjNyaMissionitems.h index 91681126..5e2bbc7b 100644 --- a/dScripts/NjNyaMissionitems.h +++ b/dScripts/NjNyaMissionitems.h @@ -1,5 +1,7 @@ #pragma once #include "NPCAddRemoveItem.h" +#include +#include class NjNyaMissionitems : public NPCAddRemoveItem { std::map> GetSettings() override; diff --git a/dScripts/NjPetSpawnerServer.cpp b/dScripts/NjPetSpawnerServer.cpp deleted file mode 100644 index d09e5f01..00000000 --- a/dScripts/NjPetSpawnerServer.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// Created by Mick Vermeulen on 23/08/2021. -// - -#include "NjPetSpawnerServer.h" diff --git a/dScripts/NjPetSpawnerServer.h b/dScripts/NjPetSpawnerServer.h deleted file mode 100644 index 56b6c147..00000000 --- a/dScripts/NjPetSpawnerServer.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once -#include "SpawnPetBaseServer.h" - -class NjPetSpawnerServer : public SpawnPetBaseServer { - -}; diff --git a/dScripts/NjhubLavaPlayerDeathTrigger.cpp b/dScripts/NjhubLavaPlayerDeathTrigger.cpp index ff31df2c..af47f99b 100644 --- a/dScripts/NjhubLavaPlayerDeathTrigger.cpp +++ b/dScripts/NjhubLavaPlayerDeathTrigger.cpp @@ -1,4 +1,5 @@ #include "NjhubLavaPlayerDeathTrigger.h" +#include "Entity.h" void NjhubLavaPlayerDeathTrigger::OnCollisionPhantom(Entity *self, Entity *target) { diff --git a/dScripts/NjhubLavaPlayerDeathTrigger.h b/dScripts/NjhubLavaPlayerDeathTrigger.h index d7e78604..48ff85d0 100644 --- a/dScripts/NjhubLavaPlayerDeathTrigger.h +++ b/dScripts/NjhubLavaPlayerDeathTrigger.h @@ -1,7 +1,6 @@ #pragma once #include "CppScripts.h" - class NjhubLavaPlayerDeathTrigger : public CppScripts::Script { void OnCollisionPhantom(Entity *self, Entity *target) override; }; diff --git a/dScripts/NpcAgCourseStarter.cpp b/dScripts/NpcAgCourseStarter.cpp index 4e6dd5c5..188186fb 100644 --- a/dScripts/NpcAgCourseStarter.cpp +++ b/dScripts/NpcAgCourseStarter.cpp @@ -1,11 +1,9 @@ #include "NpcAgCourseStarter.h" #include "EntityManager.h" -#include "GeneralUtils.h" #include "ScriptedActivityComponent.h" #include "GameMessages.h" #include "LeaderboardManager.h" -#include "Game.h" -#include "dLogger.h" +#include "MissionComponent.h" #include void NpcAgCourseStarter::OnStartup(Entity* self) { @@ -35,8 +33,6 @@ void NpcAgCourseStarter::OnMessageBoxResponse(Entity* self, Entity* sender, int3 } if (identifier == u"player_dialog_cancel_course" && button == 1) { - Game::logger->Log("OnMessageBoxResponse", "Removing player %llu\n", sender->GetObjectID()); - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"stop_timer", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"cancel_timer", 0, 0, LWOOBJID_EMPTY, "", sender->GetSystemAddress()); @@ -58,8 +54,6 @@ void NpcAgCourseStarter::OnMessageBoxResponse(Entity* self, Entity* sender, int3 data->values[1] = *(float*)&startTime; - Game::logger->Log("NpcAgCourseStarter", "Start time: %llu / %f\n", startTime, data->values[1]); - EntityManager::Instance()->SerializeEntity(self); } else if (identifier == u"FootRaceCancel") { @@ -94,9 +88,6 @@ void NpcAgCourseStarter::OnFireEventServerSide(Entity *self, Entity *sender, std time_t endTime = std::time(0); time_t finish = (endTime - *(time_t *) &data->values[1]); - Game::logger->Log("NpcAgCourseStarter", "End time: %llu, start time %llu, finish: %llu\n", endTime, - *(time_t *) &data->values[1], finish); - data->values[2] = *(float *) &finish; auto *missionComponent = sender->GetComponent(); diff --git a/dScripts/NpcCowboyServer.cpp b/dScripts/NpcCowboyServer.cpp index 9223dcd4..f4986045 100644 --- a/dScripts/NpcCowboyServer.cpp +++ b/dScripts/NpcCowboyServer.cpp @@ -1,5 +1,5 @@ #include "NpcCowboyServer.h" -#include "MissionComponent.h" +#include "MissionState.h" #include "InventoryComponent.h" void NpcCowboyServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) diff --git a/dScripts/NpcNjAssistantServer.cpp b/dScripts/NpcNjAssistantServer.cpp index 7ff21c8e..b9743756 100644 --- a/dScripts/NpcNjAssistantServer.cpp +++ b/dScripts/NpcNjAssistantServer.cpp @@ -1,6 +1,7 @@ #include "NpcNjAssistantServer.h" #include "GameMessages.h" #include "InventoryComponent.h" +#include "MissionComponent.h" #include "Item.h" void NpcNjAssistantServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { diff --git a/dScripts/NpcNpSpacemanBob.cpp b/dScripts/NpcNpSpacemanBob.cpp index 2893e039..91fe0f95 100644 --- a/dScripts/NpcNpSpacemanBob.cpp +++ b/dScripts/NpcNpSpacemanBob.cpp @@ -1,10 +1,6 @@ #include "NpcNpSpacemanBob.h" #include "DestroyableComponent.h" -#include "Entity.h" -#include "GameMessages.h" -#include "MissionState.h" -#include "Game.h" -#include "dLogger.h" +#include "MissionComponent.h" void NpcNpSpacemanBob::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { diff --git a/dScripts/NpcWispServer.cpp b/dScripts/NpcWispServer.cpp index 03c8f071..0f573d65 100644 --- a/dScripts/NpcWispServer.cpp +++ b/dScripts/NpcWispServer.cpp @@ -1,10 +1,8 @@ #include "NpcWispServer.h" #include "InventoryComponent.h" - #include "EntityManager.h" #include "Entity.h" #include "GameMessages.h" -#include "Item.h" void NpcWispServer::OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) { if (missionID != 1849 && missionID != 1883) diff --git a/dScripts/NsConcertChoiceBuildManager.cpp b/dScripts/NsConcertChoiceBuildManager.cpp index 562ff61a..8875beed 100644 --- a/dScripts/NsConcertChoiceBuildManager.cpp +++ b/dScripts/NsConcertChoiceBuildManager.cpp @@ -1,6 +1,5 @@ #include "NsConcertChoiceBuildManager.h" #include "EntityManager.h" -#include "Player.h" const std::vector NsConcertChoiceBuildManager::crates { { "laser", 11203, 5.0, "Concert_Laser_QB_" }, diff --git a/dScripts/NsConcertInstrument.cpp b/dScripts/NsConcertInstrument.cpp index bfd35083..a449a6a4 100644 --- a/dScripts/NsConcertInstrument.cpp +++ b/dScripts/NsConcertInstrument.cpp @@ -5,6 +5,7 @@ #include "EntityManager.h" #include "RebuildComponent.h" #include "SoundTriggerComponent.h" +#include "MissionComponent.h" // Constants are at the bottom diff --git a/dScripts/NsConcertQuickBuild.cpp b/dScripts/NsConcertQuickBuild.cpp index 6bf501c4..ba7b4010 100644 --- a/dScripts/NsConcertQuickBuild.cpp +++ b/dScripts/NsConcertQuickBuild.cpp @@ -2,9 +2,9 @@ #include "EntityManager.h" #include "NsConcertChoiceBuildManager.h" #include "DestroyableComponent.h" -#include "RenderComponent.h" #include "GameMessages.h" #include "MovingPlatformComponent.h" +#include "MissionComponent.h" const float NsConcertQuickBuild::resetTime = 40.0f; const float NsConcertQuickBuild::resetBlinkTime = 6.0f; diff --git a/dScripts/NsJohnnyMissionServer.cpp b/dScripts/NsJohnnyMissionServer.cpp index 435f50c8..6fc73a82 100644 --- a/dScripts/NsJohnnyMissionServer.cpp +++ b/dScripts/NsJohnnyMissionServer.cpp @@ -1,4 +1,5 @@ #include "NsJohnnyMissionServer.h" +#include "MissionComponent.h" void NsJohnnyMissionServer::OnMissionDialogueOK(Entity *self, Entity *target, int missionID, MissionState missionState) { if (missionID == 773 && missionState <= MissionState::MISSION_STATE_ACTIVE) { diff --git a/dScripts/NsLegoClubDoor.cpp b/dScripts/NsLegoClubDoor.cpp index 1e575c54..0b773b09 100644 --- a/dScripts/NsLegoClubDoor.cpp +++ b/dScripts/NsLegoClubDoor.cpp @@ -1,8 +1,7 @@ #include "NsLegoClubDoor.h" #include "dZoneManager.h" -#include "EntityManager.h" -#include "GeneralUtils.h" #include "GameMessages.h" +#include "AMFFormat.h" void NsLegoClubDoor::OnStartup(Entity* self) { diff --git a/dScripts/NsLegoClubDoor.h b/dScripts/NsLegoClubDoor.h index 480c9250..7f17692d 100644 --- a/dScripts/NsLegoClubDoor.h +++ b/dScripts/NsLegoClubDoor.h @@ -2,7 +2,6 @@ #include "CppScripts.h" #include "ChooseYourDestinationNsToNt.h" #include "BaseConsoleTeleportServer.h" -#include "AMFFormat.h" class NsLegoClubDoor : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer { diff --git a/dScripts/NsLupTeleport.cpp b/dScripts/NsLupTeleport.cpp index 28f598a4..4c196d01 100644 --- a/dScripts/NsLupTeleport.cpp +++ b/dScripts/NsLupTeleport.cpp @@ -1,8 +1,7 @@ #include "NsLupTeleport.h" #include "dZoneManager.h" -#include "EntityManager.h" -#include "GeneralUtils.h" #include "GameMessages.h" +#include "AMFFormat.h" void NsLupTeleport::OnStartup(Entity* self) { diff --git a/dScripts/NsLupTeleport.h b/dScripts/NsLupTeleport.h index 3ace6698..833f5f0a 100644 --- a/dScripts/NsLupTeleport.h +++ b/dScripts/NsLupTeleport.h @@ -2,7 +2,6 @@ #include "CppScripts.h" #include "ChooseYourDestinationNsToNt.h" #include "BaseConsoleTeleportServer.h" -#include "AMFFormat.h" class NsLupTeleport : public CppScripts::Script, ChooseYourDestinationNsToNt, BaseConsoleTeleportServer { diff --git a/dScripts/NsModularBuild.cpp b/dScripts/NsModularBuild.cpp index 09d3d695..065d061e 100644 --- a/dScripts/NsModularBuild.cpp +++ b/dScripts/NsModularBuild.cpp @@ -1,6 +1,5 @@ #include "NsModularBuild.h" -#include "EntityManager.h" -#include "Character.h" +#include "MissionComponent.h" void NsModularBuild::OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector modules) { if (bCompleted) { diff --git a/dScripts/NsQbImaginationStatue.cpp b/dScripts/NsQbImaginationStatue.cpp index 6b512119..4404ba5f 100644 --- a/dScripts/NsQbImaginationStatue.cpp +++ b/dScripts/NsQbImaginationStatue.cpp @@ -1,9 +1,6 @@ #include "NsQbImaginationStatue.h" #include "EntityManager.h" -#include "Loot.h" #include "GameMessages.h" -#include "ScriptedActivityComponent.h" -#include "RebuildComponent.h" void NsQbImaginationStatue::OnStartup(Entity* self) { diff --git a/dScripts/NsTokenConsoleServer.cpp b/dScripts/NsTokenConsoleServer.cpp index 0e9ac09e..976b9bc8 100644 --- a/dScripts/NsTokenConsoleServer.cpp +++ b/dScripts/NsTokenConsoleServer.cpp @@ -1,6 +1,5 @@ #include "NsTokenConsoleServer.h" #include "InventoryComponent.h" -#include "EntityManager.h" #include "GameMessages.h" #include "Character.h" #include "MissionComponent.h" diff --git a/dScripts/NtAssemblyTubeServer.cpp b/dScripts/NtAssemblyTubeServer.cpp index 5f05f54e..935993f4 100644 --- a/dScripts/NtAssemblyTubeServer.cpp +++ b/dScripts/NtAssemblyTubeServer.cpp @@ -1,9 +1,7 @@ #include "NtAssemblyTubeServer.h" #include "GameMessages.h" -#include "dZoneManager.h" #include "EntityManager.h" -#include "SkillComponent.h" -#include "DestroyableComponent.h" +#include "MissionComponent.h" void NtAssemblyTubeServer::OnStartup(Entity* self) { @@ -17,8 +15,6 @@ void NtAssemblyTubeServer::OnPlayerLoaded(Entity* self, Entity* player) void NtAssemblyTubeServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { - Game::logger->Log("NtAssemblyTubeServer", "Entering\n"); - if (status != "ENTER" || !entering->IsPlayer() || name != "teleport") return; auto* player = entering; diff --git a/dScripts/NtCombatChallengeDummy.cpp b/dScripts/NtCombatChallengeDummy.cpp index 76f8576f..a391e00f 100644 --- a/dScripts/NtCombatChallengeDummy.cpp +++ b/dScripts/NtCombatChallengeDummy.cpp @@ -1,7 +1,6 @@ #include "NtCombatChallengeDummy.h" #include "EntityManager.h" - void NtCombatChallengeDummy::OnDie(Entity* self, Entity* killer) { const auto challengeObjectID = self->GetVar(u"challengeObjectID"); diff --git a/dScripts/NtCombatChallengeExplodingDummy.cpp b/dScripts/NtCombatChallengeExplodingDummy.cpp index dd61817d..24494939 100644 --- a/dScripts/NtCombatChallengeExplodingDummy.cpp +++ b/dScripts/NtCombatChallengeExplodingDummy.cpp @@ -1,5 +1,4 @@ #include "NtCombatChallengeExplodingDummy.h" -#include "NtCombatChallengeDummy.h" #include "EntityManager.h" #include "SkillComponent.h" diff --git a/dScripts/NtCombatChallengeServer.cpp b/dScripts/NtCombatChallengeServer.cpp index 2c6a5426..4bf5dffc 100644 --- a/dScripts/NtCombatChallengeServer.cpp +++ b/dScripts/NtCombatChallengeServer.cpp @@ -1,27 +1,16 @@ #include "NtCombatChallengeServer.h" -#include "Character.h" #include "GameMessages.h" #include "EntityManager.h" #include "InventoryComponent.h" #include "MissionComponent.h" - void NtCombatChallengeServer::OnUse(Entity* self, Entity* user) { - auto* character = user->GetCharacter(); - - if (character == nullptr) - { - return; - } - GameMessages::SendNotifyClientObject(self->GetObjectID(), u"UI_Open", 0, 0, user->GetObjectID(), "", user->GetSystemAddress()); } void NtCombatChallengeServer::OnDie(Entity* self, Entity* killer) { - Game::logger->Log("NtCombatChallengeServer", "Smashed\n"); - if (killer != self && killer != nullptr) { SpawnTargetDummy(self); @@ -47,8 +36,6 @@ void NtCombatChallengeServer::OnHitOrHealResult(Entity* self, Entity* attacker, self->SetVar(u"totalDmg", totalDmg); self->SetNetworkVar(u"totalDmg", totalDmg); - Game::logger->Log("NtCombatChallengeServer", "Damage %i -> %i\n", damage, totalDmg); - GameMessages::SendPlayNDAudioEmitter(self, attacker->GetSystemAddress(), scoreSound); } @@ -169,12 +156,8 @@ void NtCombatChallengeServer::ResetGame(Entity* self) { for (const auto& mission : tMissions) { - Game::logger->Log("NtCombatChallengeServer", "Mission %i, %i\n", mission.mission, mission.damage); - if (totalDmg >= mission.damage) { - Game::logger->Log("NtCombatChallengeServer", "Progressing Mission %i, %i\n", mission.mission, mission.damage); - missionComponent->ForceProgressTaskType(mission.mission, 1, 1); } } diff --git a/dScripts/NtConsoleTeleportServer.cpp b/dScripts/NtConsoleTeleportServer.cpp index 91354c0b..b03ae34e 100644 --- a/dScripts/NtConsoleTeleportServer.cpp +++ b/dScripts/NtConsoleTeleportServer.cpp @@ -1,5 +1,6 @@ #include "NtConsoleTeleportServer.h" - +#include "Entity.h" +#include "AMFFormat.h" void NtConsoleTeleportServer::OnStartup(Entity* self) { diff --git a/dScripts/NtConsoleTeleportServer.h b/dScripts/NtConsoleTeleportServer.h index 0d834cd6..7bba7ee1 100644 --- a/dScripts/NtConsoleTeleportServer.h +++ b/dScripts/NtConsoleTeleportServer.h @@ -2,7 +2,6 @@ #include "CppScripts.h" #include "ChooseYourDestinationNsToNt.h" #include "BaseConsoleTeleportServer.h" -#include "AMFFormat.h" class NtConsoleTeleportServer : public CppScripts::Script, BaseConsoleTeleportServer { diff --git a/dScripts/NtDirtCloudServer.cpp b/dScripts/NtDirtCloudServer.cpp index ee011dd8..82572703 100644 --- a/dScripts/NtDirtCloudServer.cpp +++ b/dScripts/NtDirtCloudServer.cpp @@ -1,5 +1,4 @@ #include "NtDirtCloudServer.h" -#include "dZoneManager.h" #include "MissionComponent.h" std::map> NtDirtCloudServer::m_Missions = diff --git a/dScripts/NtDukeServer.cpp b/dScripts/NtDukeServer.cpp index fe196811..df3f39d6 100644 --- a/dScripts/NtDukeServer.cpp +++ b/dScripts/NtDukeServer.cpp @@ -1,5 +1,6 @@ #include "NtDukeServer.h" #include "InventoryComponent.h" +#include "MissionComponent.h" void NtDukeServer::SetVariables(Entity *self) { self->SetVar(m_SpyProximityVariable, 35.0f); diff --git a/dScripts/NtFactionSpyServer.cpp b/dScripts/NtFactionSpyServer.cpp index b99990c0..f1104e34 100644 --- a/dScripts/NtFactionSpyServer.cpp +++ b/dScripts/NtFactionSpyServer.cpp @@ -3,6 +3,7 @@ #include "ProximityMonitorComponent.h" #include "InventoryComponent.h" #include "GameMessages.h" +#include "MissionComponent.h" void NtFactionSpyServer::OnStartup(Entity *self) { SetVariables(self); diff --git a/dScripts/NtHaelServer.cpp b/dScripts/NtHaelServer.cpp index 2e2643fe..a4c16e1f 100644 --- a/dScripts/NtHaelServer.cpp +++ b/dScripts/NtHaelServer.cpp @@ -1,4 +1,5 @@ #include "NtHaelServer.h" +#include "Entity.h" void NtHaelServer::SetVariables(Entity *self) { self->SetVar(m_SpyProximityVariable, 25.0f); diff --git a/dScripts/NtParadoxTeleServer.cpp b/dScripts/NtParadoxTeleServer.cpp index 41d21cb7..84222374 100644 --- a/dScripts/NtParadoxTeleServer.cpp +++ b/dScripts/NtParadoxTeleServer.cpp @@ -1,9 +1,7 @@ #include "NtParadoxTeleServer.h" #include "GameMessages.h" -#include "dZoneManager.h" #include "EntityManager.h" -#include "SkillComponent.h" -#include "DestroyableComponent.h" +#include "MissionComponent.h" void NtParadoxTeleServer::OnStartup(Entity* self) { @@ -17,8 +15,6 @@ void NtParadoxTeleServer::OnPlayerLoaded(Entity* self, Entity* player) void NtParadoxTeleServer::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { - Game::logger->Log("NtParadoxTeleServer", "Entering\n"); - if (status != "ENTER" || !entering->IsPlayer() || name != "teleport") return; auto* player = entering; diff --git a/dScripts/NtSentinelWalkwayServer.cpp b/dScripts/NtSentinelWalkwayServer.cpp index 5f4b50e2..3d7c75a3 100644 --- a/dScripts/NtSentinelWalkwayServer.cpp +++ b/dScripts/NtSentinelWalkwayServer.cpp @@ -1,7 +1,7 @@ #include "NtSentinelWalkwayServer.h" #include "PhantomPhysicsComponent.h" #include "EntityManager.h" - +#include "MissionComponent.h" void NtSentinelWalkwayServer::OnStartup(Entity* self) { @@ -9,8 +9,6 @@ void NtSentinelWalkwayServer::OnStartup(Entity* self) if (phantomPhysicsComponent == nullptr) { - Game::logger->Log("NtSentinelWalkwayServer", "Failed to find PhantomPhysicsComponent\n"); - return; } @@ -21,8 +19,6 @@ void NtSentinelWalkwayServer::OnStartup(Entity* self) force = 115; } - Game::logger->Log("NtSentinelWalkwayServer", "Setting force to %i\n", force); - const auto forward = self->GetRotation().GetRightVector() * -1; phantomPhysicsComponent->SetEffectType(0); // PUSH diff --git a/dScripts/NtVentureCannonServer.cpp b/dScripts/NtVentureCannonServer.cpp index 0b72c8b7..66172733 100644 --- a/dScripts/NtVentureCannonServer.cpp +++ b/dScripts/NtVentureCannonServer.cpp @@ -2,7 +2,6 @@ #include "GameMessages.h" #include "EntityManager.h" - void NtVentureCannonServer::OnUse(Entity* self, Entity* user) { auto* player = user; diff --git a/dScripts/NtVentureSpeedPadServer.cpp b/dScripts/NtVentureSpeedPadServer.cpp index 1f44ec04..19a752d2 100644 --- a/dScripts/NtVentureSpeedPadServer.cpp +++ b/dScripts/NtVentureSpeedPadServer.cpp @@ -2,7 +2,6 @@ #include "SkillComponent.h" #include "MissionComponent.h" - void NtVentureSpeedPadServer::OnStartup(Entity* self) { self->SetProximityRadius(3, "speedboost"); diff --git a/dScripts/NtXRayServer.cpp b/dScripts/NtXRayServer.cpp index 7fae01c6..b65cf65b 100644 --- a/dScripts/NtXRayServer.cpp +++ b/dScripts/NtXRayServer.cpp @@ -1,6 +1,4 @@ #include "NtXRayServer.h" -#include "PhantomPhysicsComponent.h" -#include "EntityManager.h" #include "SkillComponent.h" void NtXRayServer::OnCollisionPhantom(Entity* self, Entity* target) diff --git a/dScripts/PetDigBuild.cpp b/dScripts/PetDigBuild.cpp index 31b3db06..7ff88fff 100644 --- a/dScripts/PetDigBuild.cpp +++ b/dScripts/PetDigBuild.cpp @@ -1,5 +1,6 @@ #include "PetDigBuild.h" #include "EntityManager.h" +#include "MissionComponent.h" void PetDigBuild::OnRebuildComplete(Entity* self, Entity* target) { auto flagNumber = self->GetVar(u"flagNum"); diff --git a/dScripts/PetDigServer.cpp b/dScripts/PetDigServer.cpp index a78c0881..dc7e85dd 100644 --- a/dScripts/PetDigServer.cpp +++ b/dScripts/PetDigServer.cpp @@ -1,7 +1,6 @@ -#include +#include "dZoneManager.h" #include "PetDigServer.h" #include "MissionComponent.h" -#include "InventoryComponent.h" #include "EntityManager.h" #include "Character.h" #include "PetComponent.h" diff --git a/dScripts/PrSeagullFly.cpp b/dScripts/PrSeagullFly.cpp index 728b245f..a4dd5fcd 100644 --- a/dScripts/PrSeagullFly.cpp +++ b/dScripts/PrSeagullFly.cpp @@ -1,4 +1,5 @@ #include "PrSeagullFly.h" +#include "Entity.h" void PrSeagullFly::OnStartup(Entity* self) { diff --git a/dScripts/PrWhistle.cpp b/dScripts/PrWhistle.cpp index 850059d2..4d4d0708 100644 --- a/dScripts/PrWhistle.cpp +++ b/dScripts/PrWhistle.cpp @@ -1,6 +1,6 @@ #include "PrWhistle.h" #include "Character.h" -#include "CharacterComponent.h" +#include "Entity.h" void PrWhistle::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) diff --git a/dScripts/PropertyDeathPlane.cpp b/dScripts/PropertyDeathPlane.cpp index b682be67..93981dac 100644 --- a/dScripts/PropertyDeathPlane.cpp +++ b/dScripts/PropertyDeathPlane.cpp @@ -1,8 +1,6 @@ #include "PropertyDeathPlane.h" #include "Entity.h" #include "GameMessages.h" -#include "Game.h" -#include "dLogger.h" #include "EntityManager.h" void PropertyDeathPlane::OnCollisionPhantom(Entity* self, Entity* target) @@ -16,7 +14,5 @@ void PropertyDeathPlane::OnCollisionPhantom(Entity* self, Entity* target) auto* teleport = teleportGroup[0]; - Game::logger->Log("PropertyDeathPlane", "Teleporting!\n"); - GameMessages::SendTeleport(target->GetObjectID(), teleport->GetPosition(), teleport->GetRotation(), target->GetSystemAddress()); } diff --git a/dScripts/PropertyDevice.cpp b/dScripts/PropertyDevice.cpp index 6d8e2c0a..ed0d7b81 100644 --- a/dScripts/PropertyDevice.cpp +++ b/dScripts/PropertyDevice.cpp @@ -1,6 +1,7 @@ #include "PropertyDevice.h" #include "GameMessages.h" #include "EntityManager.h" +#include "MissionComponent.h" void PropertyDevice::OnStartup(Entity *self) { auto* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); diff --git a/dScripts/QbEnemyStunner.cpp b/dScripts/QbEnemyStunner.cpp index ba089844..a3dfa94b 100644 --- a/dScripts/QbEnemyStunner.cpp +++ b/dScripts/QbEnemyStunner.cpp @@ -1,7 +1,5 @@ #include "QbEnemyStunner.h" -#include "EntityManager.h" #include "SkillComponent.h" -#include "GameMessages.h" #include "DestroyableComponent.h" void QbEnemyStunner::OnRebuildComplete(Entity* self, Entity* target) @@ -13,16 +11,32 @@ void QbEnemyStunner::OnRebuildComplete(Entity* self, Entity* target) destroyable->SetFaction(115); } - auto* skillComponent = self->GetComponent(); + auto skillComponent = self->GetComponent(); + if (!skillComponent) return; - if (skillComponent != nullptr) - { - skillComponent->CalculateBehavior(499, 6095, LWOOBJID_EMPTY); + // Get the skill IDs of this object. + CDObjectSkillsTable* skillsTable = CDClientManager::Instance()->GetTable("ObjectSkills"); + auto skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == self->GetLOT()); }); + std::map skillBehaviorMap; + // For each skill, cast it with the associated behavior ID. + for (auto skill : skills) { + CDSkillBehaviorTable* skillBehaviorTable = CDClientManager::Instance()->GetTable("SkillBehavior"); + CDSkillBehavior behaviorData = skillBehaviorTable->GetSkillByID(skill.skillID); + + skillBehaviorMap.insert(std::make_pair(skill.skillID, behaviorData.behaviorID)); } - self->AddTimer("TickTime", 1); + // If there are no skills found, insert a default skill to use. + if (skillBehaviorMap.size() == 0) { + skillBehaviorMap.insert(std::make_pair(499U, 6095U)); + } + + // Start all skills associated with the object next tick + self->AddTimer("TickTime", 0); self->AddTimer("PlayEffect", 20); + + self->SetVar>(u"skillBehaviorMap", skillBehaviorMap); } void QbEnemyStunner::OnTimerDone(Entity* self, std::string timerName) @@ -45,9 +59,16 @@ void QbEnemyStunner::OnTimerDone(Entity* self, std::string timerName) if (skillComponent != nullptr) { - skillComponent->CalculateBehavior(499, 6095, LWOOBJID_EMPTY); + auto skillBehaviorMap = self->GetVar>(u"skillBehaviorMap"); + if (skillBehaviorMap.size() == 0) { + // Should no skills have been found, default to the mermaid stunner + skillComponent->CalculateBehavior(499U, 6095U, LWOOBJID_EMPTY); + } else { + for (auto pair : skillBehaviorMap) { + skillComponent->CalculateBehavior(pair.first, pair.second, LWOOBJID_EMPTY); + } + } } - self->AddTimer("TickTime", 1); } } diff --git a/dScripts/RaceImagineCrateServer.cpp b/dScripts/RaceImagineCrateServer.cpp index 166b3363..3729004a 100644 --- a/dScripts/RaceImagineCrateServer.cpp +++ b/dScripts/RaceImagineCrateServer.cpp @@ -1,10 +1,10 @@ #include "CharacterComponent.h" #include "DestroyableComponent.h" #include "EntityManager.h" -#include "GameMessages.h" #include "PossessableComponent.h" #include "RaceImagineCrateServer.h" #include "RacingTaskParam.h" +#include "MissionComponent.h" #include "SkillComponent.h" void RaceImagineCrateServer::OnDie(Entity* self, Entity* killer) diff --git a/dScripts/RaceImaginePowerup.cpp b/dScripts/RaceImaginePowerup.cpp index 43e20e9d..a940b88d 100644 --- a/dScripts/RaceImaginePowerup.cpp +++ b/dScripts/RaceImaginePowerup.cpp @@ -1,11 +1,9 @@ -#include "CharacterComponent.h" #include "DestroyableComponent.h" #include "EntityManager.h" -#include "PossessableComponent.h" #include "PossessorComponent.h" #include "RaceImaginePowerup.h" #include "RacingTaskParam.h" - +#include "MissionComponent.h" void RaceImaginePowerup::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) diff --git a/dScripts/RaceMaelstromGeiser.cpp b/dScripts/RaceMaelstromGeiser.cpp index 8e91c5fe..88a45bbd 100644 --- a/dScripts/RaceMaelstromGeiser.cpp +++ b/dScripts/RaceMaelstromGeiser.cpp @@ -1,14 +1,10 @@ #include "RaceMaelstromGeiser.h" -#include "DestroyableComponent.h" #include "GameMessages.h" #include "PossessableComponent.h" #include "PossessorComponent.h" #include "EntityManager.h" #include "RacingControlComponent.h" #include "dZoneManager.h" -#include "Game.h" -#include "dLogger.h" - void RaceMaelstromGeiser::OnStartup(Entity* self) { @@ -26,15 +22,11 @@ void RaceMaelstromGeiser::OnProximityUpdate(Entity* self, Entity* entering, std: return; } - Game::logger->Log("RaceMaelstromGeiser", "Entered\n"); - if (!self->GetVar(u"AmFiring")) { return; } - Game::logger->Log("RaceMaelstromGeiser", "Smashing!\n"); - auto* possessableComponent = entering->GetComponent(); Entity* vehicle; diff --git a/dScripts/RaceSmashServer.cpp b/dScripts/RaceSmashServer.cpp index 582a8ed3..8c8b3f79 100644 --- a/dScripts/RaceSmashServer.cpp +++ b/dScripts/RaceSmashServer.cpp @@ -3,6 +3,7 @@ #include "PossessableComponent.h" #include "RaceSmashServer.h" #include "RacingTaskParam.h" +#include "MissionComponent.h" void RaceSmashServer::OnDie(Entity *self, Entity *killer) { // Crate is smashed by the car diff --git a/dScripts/SGCannon.cpp b/dScripts/SGCannon.cpp index a5c2c843..ab179226 100644 --- a/dScripts/SGCannon.cpp +++ b/dScripts/SGCannon.cpp @@ -9,8 +9,8 @@ #include "CharacterComponent.h" #include "SimplePhysicsComponent.h" #include "MovementAIComponent.h" -#include "ControllablePhysicsComponent.h" #include "../dWorldServer/ObjectIDManager.h" +#include "MissionComponent.h" void SGCannon::OnStartup(Entity *self) { Game::logger->Log("SGCannon", "OnStartup\n"); @@ -95,21 +95,16 @@ void SGCannon::OnActivityStateChangeRequest(Entity *self, LWOOBJID senderID, int Game::logger->Log("SGCannon", "Shooting gallery component is null\n"); } - auto* possessorComponent = player->GetComponent(); - - /*if (possessorComponent != nullptr) { - possessorComponent->SetPossessable(self->GetObjectID()); - - EntityManager::Instance()->SerializeEntity(player); - }*/ - auto* characterComponent = player->GetComponent(); if (characterComponent != nullptr) { characterComponent->SetIsRacing(true); - characterComponent->SetVehicleObjectID(self->GetObjectID()); - characterComponent->SetPossessableType(0); characterComponent->SetCurrentActivity(2); + auto possessor = player->GetComponent(); + if(possessor) { + possessor->SetPossessable(self->GetObjectID()); + possessor->SetPossessableType(ePossessionType::NO_POSSESSION); + } EntityManager::Instance()->SerializeEntity(player); } @@ -144,8 +139,9 @@ void SGCannon::OnMessageBoxResponse(Entity *self, Entity *sender, int32_t button if (player != nullptr) { if (button == 1 && identifier == u"Shooting_Gallery_Stop") { - static_cast(player)->SendToZone(1300); - + UpdatePlayer(self, player->GetObjectID(), true); + RemovePlayer(player->GetObjectID()); + StopGame(self, true); return; } diff --git a/dScripts/ScriptComponent.cpp b/dScripts/ScriptComponent.cpp index ce68c2d6..062eed72 100644 --- a/dScripts/ScriptComponent.cpp +++ b/dScripts/ScriptComponent.cpp @@ -5,7 +5,6 @@ #include "Entity.h" #include "ScriptComponent.h" -#include "InvalidScript.h" ScriptComponent::ScriptComponent(Entity* parent, std::string scriptName, bool serialized, bool client) : Component(parent) { m_Serialized = serialized; diff --git a/dScripts/ScriptComponent.h b/dScripts/ScriptComponent.h index d87d1744..54cf2236 100644 --- a/dScripts/ScriptComponent.h +++ b/dScripts/ScriptComponent.h @@ -6,7 +6,6 @@ #ifndef SCRIPTCOMPONENT_H #define SCRIPTCOMPONENT_H -#include "BitStream.h" #include "CppScripts.h" #include "Component.h" #include diff --git a/dScripts/ScriptedPowerupSpawner.cpp b/dScripts/ScriptedPowerupSpawner.cpp index fe35dfed..91c25856 100644 --- a/dScripts/ScriptedPowerupSpawner.cpp +++ b/dScripts/ScriptedPowerupSpawner.cpp @@ -1,6 +1,5 @@ #include "ScriptedPowerupSpawner.h" #include "RenderComponent.h" -#include "GameMessages.h" #include "EntityManager.h" void ScriptedPowerupSpawner::OnTemplateStartup(Entity *self) { diff --git a/dScripts/SpawnGryphonServer.cpp b/dScripts/SpawnGryphonServer.cpp index 93cbbac9..d411569c 100644 --- a/dScripts/SpawnGryphonServer.cpp +++ b/dScripts/SpawnGryphonServer.cpp @@ -1,6 +1,7 @@ #include "SpawnGryphonServer.h" #include "InventoryComponent.h" #include "GameMessages.h" +#include "MissionComponent.h" void SpawnGryphonServer::SetVariables(Entity *self) { self->SetVar(u"petLOT", 12433); diff --git a/dScripts/SpawnLionServer.cpp b/dScripts/SpawnLionServer.cpp index 5c6b79d3..b19531a4 100644 --- a/dScripts/SpawnLionServer.cpp +++ b/dScripts/SpawnLionServer.cpp @@ -1,4 +1,5 @@ #include "SpawnLionServer.h" +#include "Entity.h" void SpawnLionServer::SetVariables(Entity *self) { self->SetVar(u"petLOT", 3520); diff --git a/dScripts/SpawnPetBaseServer.cpp b/dScripts/SpawnPetBaseServer.cpp index 4706da1d..d23e371a 100644 --- a/dScripts/SpawnPetBaseServer.cpp +++ b/dScripts/SpawnPetBaseServer.cpp @@ -55,7 +55,7 @@ bool SpawnPetBaseServer::CheckNumberOfPets(Entity *self, Entity* user) { if (petID.empty()) continue; - const auto* spawnedPet = EntityManager::Instance()->GetEntity(std::stol(petID)); + const auto* spawnedPet = EntityManager::Instance()->GetEntity(std::stoull(petID)); if (spawnedPet == nullptr) continue; diff --git a/dScripts/SpawnSaberCatServer.cpp b/dScripts/SpawnSaberCatServer.cpp index 1d3a5df8..e89d9df7 100644 --- a/dScripts/SpawnSaberCatServer.cpp +++ b/dScripts/SpawnSaberCatServer.cpp @@ -1,4 +1,5 @@ #include "SpawnSaberCatServer.h" +#include "Entity.h" void SpawnSaberCatServer::SetVariables(Entity *self) { self->SetVar(u"petLOT", 12432); diff --git a/dScripts/SpawnShrakeServer.cpp b/dScripts/SpawnShrakeServer.cpp index 954cbc3f..5be55ebc 100644 --- a/dScripts/SpawnShrakeServer.cpp +++ b/dScripts/SpawnShrakeServer.cpp @@ -1,4 +1,5 @@ #include "SpawnShrakeServer.h" +#include "Entity.h" void SpawnShrakeServer::SetVariables(Entity *self) { self->SetVar(u"petLOT", 12434); diff --git a/dScripts/SpawnStegoServer.cpp b/dScripts/SpawnStegoServer.cpp index ef79d889..d845ff45 100644 --- a/dScripts/SpawnStegoServer.cpp +++ b/dScripts/SpawnStegoServer.cpp @@ -1,4 +1,5 @@ #include "SpawnStegoServer.h" +#include "Entity.h" void SpawnStegoServer::SetVariables(Entity *self) { self->SetVar(u"petLOT", 12431); diff --git a/dScripts/SpecialImaginePowerupSpawner.cpp b/dScripts/SpecialImaginePowerupSpawner.cpp index f19b8d28..8417efa2 100644 --- a/dScripts/SpecialImaginePowerupSpawner.cpp +++ b/dScripts/SpecialImaginePowerupSpawner.cpp @@ -5,7 +5,6 @@ #include "DestroyableComponent.h" #include "EntityManager.h" - void SpecialImaginePowerupSpawner::OnStartup(Entity* self) { self->SetProximityRadius(1.5f, "powerupEnter"); diff --git a/dScripts/SsModularBuildServer.cpp b/dScripts/SsModularBuildServer.cpp index ff05d0e4..33f8db47 100644 --- a/dScripts/SsModularBuildServer.cpp +++ b/dScripts/SsModularBuildServer.cpp @@ -1,6 +1,5 @@ #include "SsModularBuildServer.h" -#include "EntityManager.h" -#include "Character.h" +#include "MissionComponent.h" void SsModularBuildServer::OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector modules) { int missionNum = 1732; diff --git a/dScripts/StoryBoxInteractServer.cpp b/dScripts/StoryBoxInteractServer.cpp index 12cb6815..e5899f5d 100644 --- a/dScripts/StoryBoxInteractServer.cpp +++ b/dScripts/StoryBoxInteractServer.cpp @@ -1,7 +1,6 @@ #include "StoryBoxInteractServer.h" #include "Character.h" #include "GameMessages.h" -#include "Game.h" #include "dServer.h" #include "AMFFormat.h" diff --git a/dScripts/Sunflower.cpp b/dScripts/Sunflower.cpp index ac3134d5..436ca5f4 100644 --- a/dScripts/Sunflower.cpp +++ b/dScripts/Sunflower.cpp @@ -1,4 +1,5 @@ #include "Sunflower.h" +#include "Entity.h" void Sunflower::OnStartup(Entity *self) { self->SetVar(u"numCycles", 6); diff --git a/dScripts/TokenConsoleServer.cpp b/dScripts/TokenConsoleServer.cpp index 58565869..378cc17f 100644 --- a/dScripts/TokenConsoleServer.cpp +++ b/dScripts/TokenConsoleServer.cpp @@ -1,9 +1,7 @@ #include "TokenConsoleServer.h" #include "InventoryComponent.h" -#include "Item.h" #include "GameMessages.h" #include "Character.h" -#include "dCommonVars.h" //2021-05-03 - max - added script, omitted some parts related to inheritance in lua which we don't need diff --git a/dScripts/TreasureChestDragonServer.cpp b/dScripts/TreasureChestDragonServer.cpp index d0e8eaec..80f8aa48 100644 --- a/dScripts/TreasureChestDragonServer.cpp +++ b/dScripts/TreasureChestDragonServer.cpp @@ -1,7 +1,6 @@ #include "TreasureChestDragonServer.h" #include "ScriptedActivityComponent.h" #include "TeamManager.h" -#include "Loot.h" #include "EntityManager.h" void TreasureChestDragonServer::OnStartup(Entity* self) diff --git a/dScripts/TriggerAmbush.cpp b/dScripts/TriggerAmbush.cpp index 42b1ea8f..f9fb8cf7 100644 --- a/dScripts/TriggerAmbush.cpp +++ b/dScripts/TriggerAmbush.cpp @@ -1,7 +1,6 @@ #include "TriggerAmbush.h" #include "dZoneManager.h" -#include "EntityManager.h" void TriggerAmbush::OnStartup(Entity* self) { @@ -11,21 +10,15 @@ void TriggerAmbush::OnStartup(Entity* self) void TriggerAmbush::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { if (name != "ambush" || status != "ENTER" || !entering->IsPlayer()) return; - - Game::logger->Log("TriggerAmbush", "Got ambush collision!\n"); if (self->GetVar(u"triggered")) return; self->SetVar(u"triggered", true); - Game::logger->Log("TriggerAmbush", "Triggering ambush!\n"); - const auto spawners = dZoneManager::Instance()->GetSpawnersByName("Ambush"); for (auto* spawner : spawners) { - Game::logger->Log("TriggerAmbush", "Triggering ambush on spawner!\n"); - spawner->Activate(); } diff --git a/dScripts/VeBricksampleServer.cpp b/dScripts/VeBricksampleServer.cpp index f42cd9a4..76486d78 100644 --- a/dScripts/VeBricksampleServer.cpp +++ b/dScripts/VeBricksampleServer.cpp @@ -1,6 +1,7 @@ #include "VeBricksampleServer.h" #include "InventoryComponent.h" #include "EntityManager.h" +#include "MissionComponent.h" #include "GameMessages.h" void VeBricksampleServer::OnUse(Entity *self, Entity *user) { diff --git a/dScripts/WaveBossApe.cpp b/dScripts/WaveBossApe.cpp index c7fdccf2..f4d8a132 100644 --- a/dScripts/WaveBossApe.cpp +++ b/dScripts/WaveBossApe.cpp @@ -1,5 +1,6 @@ #include "WaveBossApe.h" #include "BaseCombatAIComponent.h" +#include "Entity.h" void WaveBossApe::OnStartup(Entity *self) { BaseWavesGenericEnemy::OnStartup(self); diff --git a/dScripts/WaveBossHammerling.cpp b/dScripts/WaveBossHammerling.cpp index 6dce0ae3..4775bf42 100644 --- a/dScripts/WaveBossHammerling.cpp +++ b/dScripts/WaveBossHammerling.cpp @@ -1,5 +1,6 @@ #include "WaveBossHammerling.h" #include "BaseCombatAIComponent.h" +#include "Entity.h" void WaveBossHammerling::OnStartup(Entity *self) { BaseWavesGenericEnemy::OnStartup(self); diff --git a/dScripts/WaveBossHorsemen.cpp b/dScripts/WaveBossHorsemen.cpp index 75bffa5b..c129d654 100644 --- a/dScripts/WaveBossHorsemen.cpp +++ b/dScripts/WaveBossHorsemen.cpp @@ -1,5 +1,6 @@ #include "WaveBossHorsemen.h" #include "BaseCombatAIComponent.h" +#include "Entity.h" void WaveBossHorsemen::OnStartup(Entity *self) { BaseWavesGenericEnemy::OnStartup(self); diff --git a/dScripts/WaveBossSpiderling.cpp b/dScripts/WaveBossSpiderling.cpp index f168cb7b..5c8f8766 100644 --- a/dScripts/WaveBossSpiderling.cpp +++ b/dScripts/WaveBossSpiderling.cpp @@ -1,5 +1,6 @@ #include "WaveBossSpiderling.h" #include "BaseCombatAIComponent.h" +#include "Entity.h" void WaveBossSpiderling::OnStartup(Entity *self) { BaseWavesGenericEnemy::OnStartup(self); diff --git a/dScripts/WhFans.cpp b/dScripts/WhFans.cpp index 3a594a4c..f71383cf 100644 --- a/dScripts/WhFans.cpp +++ b/dScripts/WhFans.cpp @@ -1,6 +1,9 @@ #include "WhFans.h" #include "RenderComponent.h" +#include "GameMessages.h" +#include "EntityManager.h" +#include "PhantomPhysicsComponent.h" void WhFans::OnStartup(Entity* self) { self->SetVar(u"alive", true); diff --git a/dScripts/WhFans.h b/dScripts/WhFans.h index 91aaa9d8..d41eed5b 100644 --- a/dScripts/WhFans.h +++ b/dScripts/WhFans.h @@ -1,9 +1,5 @@ #pragma once #include "CppScripts.h" -#include "GameMessages.h" -#include "EntityManager.h" -#include "PhantomPhysicsComponent.h" - class WhFans : public CppScripts::Script { public: diff --git a/dScripts/WildAmbients.cpp b/dScripts/WildAmbients.cpp index 8ad0f04a..f6414ee8 100644 --- a/dScripts/WildAmbients.cpp +++ b/dScripts/WildAmbients.cpp @@ -1,6 +1,4 @@ #include "WildAmbients.h" -#include "EntityManager.h" -#include "Character.h" #include "GameMessages.h" void WildAmbients::OnUse(Entity* self, Entity* user) diff --git a/dScripts/WishingWellServer.cpp b/dScripts/WishingWellServer.cpp index 36bca973..09e953ac 100644 --- a/dScripts/WishingWellServer.cpp +++ b/dScripts/WishingWellServer.cpp @@ -1,8 +1,6 @@ #include "WishingWellServer.h" -#include "Loot.h" #include "ScriptedActivityComponent.h" #include "GameMessages.h" -#include "Game.h" void WishingWellServer::OnStartup(Entity* self) { diff --git a/dScripts/ZoneAgMedProperty.cpp b/dScripts/ZoneAgMedProperty.cpp index 7fdca69b..da8214b1 100644 --- a/dScripts/ZoneAgMedProperty.cpp +++ b/dScripts/ZoneAgMedProperty.cpp @@ -1,7 +1,7 @@ #include "ZoneAgMedProperty.h" +#include "Entity.h" void ZoneAgMedProperty::SetGameVariables(Entity *self) { - Game::logger->Log("Properties", "Setting variables in instance\n"); self->SetVar(ClaimMarkerGroup, "ClaimMarker"); self->SetVar(GeneratorGroup, "Generator"); diff --git a/dScripts/ZoneAgProperty.cpp b/dScripts/ZoneAgProperty.cpp index ce30af68..44650a35 100644 --- a/dScripts/ZoneAgProperty.cpp +++ b/dScripts/ZoneAgProperty.cpp @@ -1,12 +1,11 @@ #include "ZoneAgProperty.h" #include "EntityManager.h" -#include "BasePropertyServer.h" #include "Character.h" #include "Entity.h" #include "GameMessages.h" #include "dZoneManager.h" -#include "LDFFormat.h" #include "RenderComponent.h" +#include "MissionComponent.h" void ZoneAgProperty::SetGameVariables(Entity *self) { self->SetVar(GuardGroup, "Guard"); @@ -340,7 +339,6 @@ void ZoneAgProperty::OnZonePropertyModelPickedUp(Entity* self, Entity* player) { } void ZoneAgProperty::OnZonePropertyModelRemoved(Entity* self, Entity* player) { - Game::logger->Log("OnZonePropertyModelRemoved", "Removed flag updated!\n"); auto* character = player->GetCharacter(); character->SetPlayerFlag(111, true); } diff --git a/dScripts/ZoneAgProperty.h b/dScripts/ZoneAgProperty.h index 3d88215b..4044be57 100644 --- a/dScripts/ZoneAgProperty.h +++ b/dScripts/ZoneAgProperty.h @@ -1,5 +1,4 @@ #pragma once -#include "CppScripts.h" #include "BasePropertyServer.h" class ZoneAgProperty : public BasePropertyServer { diff --git a/dScripts/ZoneAgSpiderQueen.cpp b/dScripts/ZoneAgSpiderQueen.cpp index 57f93698..27c11aa7 100644 --- a/dScripts/ZoneAgSpiderQueen.cpp +++ b/dScripts/ZoneAgSpiderQueen.cpp @@ -1,10 +1,8 @@ #include "ZoneAgSpiderQueen.h" #include "GameMessages.h" #include "EntityManager.h" -#include "Character.h" #include "ZoneAgProperty.h" #include "DestroyableComponent.h" -#include "dZoneManager.h" void ZoneAgSpiderQueen::SetGameVariables(Entity *self) { ZoneAgProperty::SetGameVariables(self); diff --git a/dScripts/ZoneAgSurvival.h b/dScripts/ZoneAgSurvival.h index 3f84c6d0..c5d803ae 100644 --- a/dScripts/ZoneAgSurvival.h +++ b/dScripts/ZoneAgSurvival.h @@ -1,6 +1,7 @@ #pragma once #include "CppScripts.h" #include "BaseSurvivalServer.h" +#include class ZoneAgSurvival : public BaseSurvivalServer { Constants GetConstants() override; diff --git a/dScripts/ZoneFvProperty.cpp b/dScripts/ZoneFvProperty.cpp index bc573667..64aaad9e 100644 --- a/dScripts/ZoneFvProperty.cpp +++ b/dScripts/ZoneFvProperty.cpp @@ -1,4 +1,5 @@ #include "ZoneFvProperty.h" +#include "Entity.h" void ZoneFvProperty::SetGameVariables(Entity *self) { self->SetVar(ClaimMarkerGroup, "Platform"); diff --git a/dScripts/ZoneGfProperty.cpp b/dScripts/ZoneGfProperty.cpp index 630e915a..925320c3 100644 --- a/dScripts/ZoneGfProperty.cpp +++ b/dScripts/ZoneGfProperty.cpp @@ -1,4 +1,5 @@ #include "ZoneGfProperty.h" +#include "Entity.h" void ZoneGfProperty::SetGameVariables(Entity *self) { self->SetVar(ClaimMarkerGroup, "BehavQB"); diff --git a/dScripts/ZoneNsMedProperty.cpp b/dScripts/ZoneNsMedProperty.cpp index 92675815..feaadf31 100644 --- a/dScripts/ZoneNsMedProperty.cpp +++ b/dScripts/ZoneNsMedProperty.cpp @@ -1,4 +1,5 @@ #include "ZoneNsMedProperty.h" +#include "Entity.h" void ZoneNsMedProperty::SetGameVariables(Entity *self) { self->SetVar(ClaimMarkerGroup, "ClaimMarker"); diff --git a/dScripts/ZoneNsProperty.cpp b/dScripts/ZoneNsProperty.cpp index eec62aa5..72eb1ead 100644 --- a/dScripts/ZoneNsProperty.cpp +++ b/dScripts/ZoneNsProperty.cpp @@ -1,4 +1,5 @@ #include "ZoneNsProperty.h" +#include "Entity.h" void ZoneNsProperty::SetGameVariables(Entity *self) { self->SetVar(ClaimMarkerGroup, "Rhino"); diff --git a/dWorldServer/CMakeLists.txt b/dWorldServer/CMakeLists.txt new file mode 100644 index 00000000..3df808a2 --- /dev/null +++ b/dWorldServer/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DWORLDSERVER_SOURCES "ObjectIDManager.cpp" + "PerformanceManager.cpp" + "WorldServer.cpp") + +add_executable(WorldServer ${DWORLDSERVER_SOURCES}) +target_link_libraries(WorldServer ${COMMON_LIBRARIES} dChatFilter dGame dZoneManager dPhysics detour recast tinyxml2) diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index c23b44b7..d7a3b41e 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -546,18 +546,31 @@ void HandlePacketChat(Packet* packet) { LWOOBJID header; inStream.Read(header); - RakNet::RakString title; - RakNet::RakString msg; + std::string title; + std::string msg; - inStream.Read(title); - inStream.Read(msg); + uint32_t len; + inStream.Read(len); + for (int i = 0; len > i; i++) { + char character; + inStream.Read(character); + title += character; + } + + len = 0; + inStream.Read(len); + for (int i = 0; len > i; i++) { + char character; + inStream.Read(character); + msg += character; + } //Send to our clients: AMFArrayValue args; auto* titleValue = new AMFStringValue(); - titleValue->SetStringValue(title.C_String()); + titleValue->SetStringValue(title.c_str()); auto* messageValue = new AMFStringValue(); - messageValue->SetStringValue(msg.C_String()); + messageValue->SetStringValue(msg.c_str()); args.InsertValue("title", titleValue); args.InsertValue("message", messageValue); @@ -669,10 +682,12 @@ void HandlePacket(Packet* packet) { Game::logger->Log("WorldServer", "Deleting player %llu\n", entity->GetObjectID()); EntityManager::Instance()->DestroyEntity(entity); + } + { CBITSTREAM; PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION); - bitStream.Write(c->GetObjectID()); + bitStream.Write(user->GetLoggedInChar()); Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); } @@ -802,19 +817,27 @@ void HandlePacket(Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); uint32_t sessionKey = inStream.Read(sessionKey); - RakNet::RakString username; - inStream.Read(username); + + std::string username; + + uint32_t len; + inStream.Read(len); + + for (int i = 0; i < len; i++) { + char character; inStream.Read(character); + username += character; + } //Find them: - User* user = UserManager::Instance()->GetUser(username.C_String()); + User* user = UserManager::Instance()->GetUser(username.c_str()); if (!user) { - Game::logger->Log("WorldServer", "Got new session alert for user %s, but they're not logged in.\n", username.C_String()); + Game::logger->Log("WorldServer", "Got new session alert for user %s, but they're not logged in.\n", username.c_str()); return; } //Check the key: if (sessionKey != std::atoi(user->GetSessionKey().c_str())) { - Game::logger->Log("WorldServer", "Got new session alert for user %s, but the session key is invalid.\n", username.C_String()); + Game::logger->Log("WorldServer", "Got new session alert for user %s, but the session key is invalid.\n", username.c_str()); Game::server->Disconnect(user->GetSystemAddress(), SERVER_DISCON_INVALID_SESSION_KEY); return; } @@ -930,6 +953,19 @@ void HandlePacket(Packet* packet) { playerID = GeneralUtils::ClearBit(playerID, OBJECT_BIT_CHARACTER); playerID = GeneralUtils::ClearBit(playerID, OBJECT_BIT_PERSISTENT); + auto user = UserManager::Instance()->GetUser(packet->systemAddress); + + if (user) { + auto lastCharacter = user->GetLoggedInChar(); + // This means we swapped characters and we need to remove the previous player from the container. + if (static_cast(lastCharacter) != playerID) { + CBITSTREAM; + PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION); + bitStream.Write(lastCharacter); + Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false); + } + } + UserManager::Instance()->LoginCharacter(packet->systemAddress, static_cast(playerID)); break; } @@ -998,11 +1034,11 @@ void HandlePacket(Packet* packet) { const auto zoneId = Game::server->GetZoneID(); const auto cloneId = g_CloneID; - std::stringstream query; + auto query = CDClientDatabase::CreatePreppedStmt( + "SELECT id FROM PropertyTemplate WHERE mapID = ?;"); + query.bind(1, (int) zoneId); - query << "SELECT id FROM PropertyTemplate WHERE mapID = " << std::to_string(zoneId) << ";"; - - auto result = CDClientDatabase::ExecuteQuery(query.str()); + auto result = query.execQuery(); if (result.eof() || result.fieldIsNull(0)) { Game::logger->Log("WorldServer", "No property templates found for zone %d, not sending BBB\n", zoneId); @@ -1107,14 +1143,12 @@ void HandlePacket(Packet* packet) { CBITSTREAM; PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_ADDED_NOTIFICATION); bitStream.Write(player->GetObjectID()); - bitStream.Write(playerName.size()); + bitStream.Write(playerName.size()); for (size_t i = 0; i < playerName.size(); i++) { bitStream.Write(playerName[i]); } - //bitStream.Write(playerName); - auto zone = dZoneManager::Instance()->GetZone()->GetZoneID(); bitStream.Write(zone.GetMapID()); bitStream.Write(zone.GetInstanceID()); diff --git a/dZoneManager/CMakeLists.txt b/dZoneManager/CMakeLists.txt new file mode 100644 index 00000000..1dd3841b --- /dev/null +++ b/dZoneManager/CMakeLists.txt @@ -0,0 +1,6 @@ +set(DZONEMANAGER_SOURCES "dZoneManager.cpp" + "Level.cpp" + "Spawner.cpp" + "Zone.cpp") + +add_library(dZoneManager STATIC ${DZONEMANAGER_SOURCES}) diff --git a/dZoneManager/dZoneManager.cpp b/dZoneManager/dZoneManager.cpp index e5de1beb..12215378 100644 --- a/dZoneManager/dZoneManager.cpp +++ b/dZoneManager/dZoneManager.cpp @@ -16,7 +16,7 @@ dZoneManager* dZoneManager::m_Address = nullptr; void dZoneManager::Initialize(const LWOZONEID& zoneID) { Game::logger->Log("dZoneManager", "Preparing zone: %i/%i/%i\n", zoneID.GetMapID(), zoneID.GetInstanceID(), zoneID.GetCloneID()); - + int64_t startTime = 0; int64_t endTime = 0; @@ -52,7 +52,7 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { m_pZone->Initalize(); endTime = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); - + Game::logger->Log("dZoneManager", "Zone prepared in: %llu ms\n", (endTime - startTime)); VanityUtilities::SpawnVanity(); @@ -60,13 +60,13 @@ void dZoneManager::Initialize(const LWOZONEID& zoneID) { dZoneManager::~dZoneManager() { if (m_pZone) delete m_pZone; - + for (std::pair p : m_Spawners) { if (p.second) { delete p.second; p.second = nullptr; } - + m_Spawners.erase(p.first); } } @@ -146,7 +146,7 @@ void dZoneManager::Update(float deltaTime) { LWOOBJID dZoneManager::MakeSpawner(SpawnerInfo info) { auto objectId = info.spawnerID; - + if (objectId == LWOOBJID_EMPTY) { objectId = ObjectIDManager::Instance()->GenerateObjectID(); @@ -155,18 +155,18 @@ LWOOBJID dZoneManager::MakeSpawner(SpawnerInfo info) info.spawnerID = objectId; } - + auto* spawner = new Spawner(info); EntityInfo entityInfo{}; entityInfo.id = objectId; entityInfo.lot = 176; - + auto* entity = EntityManager::Instance()->CreateEntity(entityInfo, nullptr, nullptr, false, objectId); EntityManager::Instance()->ConstructEntity(entity); - + AddSpawner(objectId, spawner); return objectId; @@ -219,9 +219,9 @@ void dZoneManager::RemoveSpawner(const LWOOBJID id) spawner->Deactivate(); Game::logger->Log("dZoneManager", "Destroying spawner (%llu)\n", id); - + m_Spawners.erase(id); - + delete spawner; } diff --git a/docker/AccountManager.Dockerfile b/docker/AccountManager.Dockerfile index dd56e3b9..60226339 100644 --- a/docker/AccountManager.Dockerfile +++ b/docker/AccountManager.Dockerfile @@ -8,7 +8,7 @@ COPY ./thirdparty/AccountManager . ADD docker/credentials_example.py credentials.py ADD docker/resources_example.py resources.py -RUN apk add libffi-dev build-base --no-cache && pip3 install -r requirements.txt +RUN apk add curl libffi-dev build-base --no-cache && pip3 install -r requirements.txt EXPOSE 5000 CMD python3 app.py diff --git a/docker/Dockerfile b/docker/Dockerfile index 98a9b93d..27387e22 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -35,7 +35,7 @@ RUN echo "Build server" && \ mkdir -p cmake_build && \ cd cmake_build && \ sed -i -e "s/171022/${BUILD_VERSION}/g" ../CMakeVariables.txt && \ - cmake .. && \ + cmake .. -DCMAKE_BUILD_RPATH_USE_ORIGIN=TRUE && \ make -j $BUILD_THREADS RUN unzip /build/resources/navmeshes.zip -d /build/cmake_build/res/maps @@ -56,4 +56,4 @@ RUN mkdir -p /build/cmake_build && ln -s /app/_deps /build/cmake_build/_deps COPY docker/start_server.sh /start_server.sh -CMD [ "/start_server.sh" ] \ No newline at end of file +CMD [ "/start_server.sh" ] diff --git a/docker/brickfix.Dockerfile b/docker/brickfix.Dockerfile index 20a9444a..3323cd65 100644 --- a/docker/brickfix.Dockerfile +++ b/docker/brickfix.Dockerfile @@ -1,5 +1,7 @@ # syntax=docker/dockerfile:1 FROM python:3.9.9-slim +RUN apt-get update && \ + apt-get install curl -y WORKDIR /empty_dir EXPOSE 80 CMD python -m http.server 80 diff --git a/docs/Commands.md b/docs/Commands.md new file mode 100644 index 00000000..b5588f68 --- /dev/null +++ b/docs/Commands.md @@ -0,0 +1,141 @@ +# In-game commands + +Here is a summary of the commands available in-game. All commands are prefixed by `/` and typed in the in-game chat window. Some commands requires admin privileges. Operands within `<>` are required, operands within `()` are not. For the full list of in-game commands, please checkout [the source file](../dGame/dUtilities/SlashCommandHandler.cpp). + +## General Commands + +|Command|Usage|Description|Admin Level Requirement| +|--- |--- |--- |--- | +|credits|`/credits`|Displays the names of the people behind Darkflame Universe.|| +|die|`/die`|Smashes the player.|| +|info|`/info`|Displays server info to the user, including where to find the server's source code.|| +|instanceinfo|`/instanceinfo`|Displays in the chat the current zone, clone, and instance id.|| +|ping|`/ping (-l)`|Displays in chat your average ping. If the `-l` flag is used, the latest ping is displayed.|| +|pvp|`/pvp`|Toggle your PVP flag.|| +|resurrect|`/resurrect`|Resurrects the player.|| +|requestmailcount|`/requestmailcount`|Sends notification with number of unread messages in the player's mailbox.|| +|skip-ags|`/skip-ags`|Skips the Avant Gardens Survival minigame mission, "Impress the Sentinel Faction".|| +|skip-sg|`/skip-sg`|Skips the Shooting Gallery minigame mission, "Monarch of the Sea".|| +|who|`/who`|Displays in chat all players on the instance.|| + +## Moderation Commands + +|Command|Usage|Description|Admin Level Requirement| +|--- |--- |--- |--- | +|gmlevel|`/gmlevel `|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`.|| +|kick|`/kick `|Kicks the player off the server.|2| +|mailitem|`/mailitem `|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."|3| +|ban|`/ban `|Bans a user from the server.|4| +|approveproperty|`/approveproperty`|Approves the property the player is currently visiting.|5| +|mute|`/mute (days) (hours)`|Mute player for the given amount of time. If no time is given, the mute is indefinite.|6| +|gmimmune|`/gmimmunve `|Sets the character's GMImmune state, where value can be one of "1", to make yourself immune to damage, or "0" to undo.|8| +|gminvis|`/gminvis`|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.|8| +|setname|`/setname `|Sets a temporary name for your player. The name resets when you log out.|8| +|title|`/title `|Temporarily appends your player's name with " - <title>". This resets when you log out.|8| + +## Server Operation Commands + +|Command|Usage|Description|Admin Level Requirement| +|--- |--- |--- |--- | +|announce|`/announce`|Sends a announcement. `/setanntitle` and `/setannmsg` must be called first to configure the announcement.|8| +|config-set|`/config-set <key> <value>`|Set configuration item.|8| +|config-get|`/config-get <key>`|Get current value of a configuration item.|8| +|kill|`/kill <username>`|Smashes the character whom the given user is playing.|8| +|metrics|`/metrics`|Prints some information about the server's performance.|8| +|setannmsg|`/setannmsg <title>`|Sets the message of an announcement.|8| +|setanntitle|`/setanntitle <title>`|Sets the title of an announcement.|8| +|shutdownuniverse|`/shutdownuniverse`|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.|9| + +## Development Commands + +These commands are primarily for development and testing. The usage of many of these commands relies on knowledge of the codebase and client SQLite database. + +|Command|Usage|Description|Admin Level Requirement| +|--- |--- |--- |--- | +|fix-stats|`/fix-stats`|Resets skills, buffs, and destroyables.|| +|join|`/join <password>`|Joins a private zone with given password.|| +|leave-zone|`/leave-zone`|If you are in an instanced zone, transfers you to the closest main world. For example, if you are in an instance of Avant Gardens Survival or the Spider Queen Battle, you are sent to Avant Gardens. If you are in the Battle of Nimbus Station, you are sent to Nimbus Station.|| +|setminifig|`/setminifig <body part> <minifig item id>`|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.|1| +|testmap|`/testmap <zone> (force) (clone-id)`|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).|1| +|reportproxphys|`/reportproxphys`|Prints to console the position and radius of proximity sensors.|6| +|spawnphysicsverts|`/spawnphysicsverts`|Spawns a 1x1 brick at all vertices of phantom physics objects.|6| +|teleport|`/teleport <x> (y) <z>`|Teleports you. If no Y is given, you are teleported to the height of the terrain or physics object at (x, z). Alias: `/tele`.|6| +|activatespawner|`/activatespawner <spawner name>`|Activates spawner by name.|8| +|addmission|`/addmission <mission id>`|Accepts the mission, adding it to your journal.|8| +|boost|`/boost`|Adds a passive boost action if you are in a vehicle.|8| +|buff|`/buff <id> <duration>`|Applies the buff with the given id for the given number of seconds.|8| +|buffme|`/buffme`|Sets health, armor, and imagination to 999.|8| +|buffmed|`/buffmed`|Sets health, armor, and imagination to 9.|8| +|clearflag|`/clearflag <flag id>`|Removes the given health or inventory flag from your player. Equivalent of calling `/setflag off <flag id>`.|8| +|completemission|`/completemission <mission id>`|Completes the mission, removing it from your journal.|8| +|createprivate|`/createprivate <zone id> <clone id> <password>`|Creates a private zone with password.|8| +|debugui|`/debugui`|Toggle Debug UI.|8| +|dismount|`/dismount`|Dismounts you from the vehicle.|8| +|force-save|`/force-save`|While saving to database usually happens on regular intervals and when you disconnect from the server, this command saves your player's data to the database.|8| +|freecam|`/freecam`|Toggles freecam mode.|8| +|freemoney|`/freemoney <coins>`|Gives coins.|8| +|getnavmeshheight|`/getnavmeshheight`|Displays the navmesh height at your current position.|8| +|giveuscore|`/giveuscore <uscore>`|Gives uscore.|8| +|gmadditem|`/gmadditem <id> (count)`|Adds the given item to your inventory by id.|8| +|inspect|`/inspect <component> (-m <waypoint> \| -a <animation> \| -s \| -p \| -f (faction) \| -t)`|Finds the closest entity with the given component or LDF variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has. See [Detailed `/inspect` Usage](#detailed-inspect-usage) below.|8| +|list-spawns|`/list-spawns`|Lists all the character spawn points in the zone. Additionally, this command will display the current scene that plays when the character lands in the next zone, if there is one.|8| +|locrow|`/locrow`|Prints the your current position and rotation information to the console.|8| +|lookup|`/lookup <query>`|Searches through the Objects table in the client SQLite database for items whose display name, name, or description contains the query.|8| +|playanimation|`/playanimation <id>`|Plays animation with given ID. Alias: `/playanim`.|8| +|playeffect|`/playeffect <effect id> <effect type> <effect name>`|Plays an effect.|8| +|playlvlfx|`/playlvlfx`|Plays the level up animation on your character.|8| +|playrebuildfx|`/playrebuildfx`|Plays the quickbuild animation on your character.|8| +|pos|`/pos`|Displays your current position in chat and in the console.|8| +|refillstats|`/refillstats`|Refills health, armor, and imagination to their maximum level.|8| +|reforge|`/reforge <base item id> <reforged item id>`|Reforges an item.|8| +|resetmission|`/resetmission <mission id>`|Sets the state of the mission to accepted but not yet started.|8| +|rot|`/rot`|Displays your current rotation in chat and in the console.|8| +|runmacro|`/runmacro <macro>`|Runs any command macro found in `./res/macros/`|8| +|setcontrolscheme|`/setcontrolscheme <scheme number>`|Sets the character control scheme to the specified number.|8| +|setcurrency|`/setcurrency <coins>`|Sets your coins.|8| +|setflag|`/setflag (value) <flag id>`|Sets the given inventory or health flag to the given value, where value can be one of "on" or "off". If no value is given, by default this adds the flag to your character (equivalent of calling `/setflag on <flag id>`).|8| +|setinventorysize|`/setinventorysize <size>`|Sets your inventory size to the given size. Alias: `/setinvsize`|8| +|setuistate|`/setuistate <ui state>`|Changes UI state.|8| +|spawn|`/spawn <id>`|Spawns an object at your location by id.|8| +|speedboost|`/speedboost <amount>`|Sets the speed multiplier to the given amount. `/speedboost 1.5` will set the speed multiplier to 1.5x the normal speed.|8| +|startcelebration|`/startcelebration <id>`|Starts a celebration effect on your character.|8| +|stopeffect|`/stopeffect <effect id>`|Stops the given effect.|8| +|toggle|`/toggle <ui state>`|Toggles UI state.|8| +|tpall|`/tpall`|Teleports all characters to your current position.|8| +|triggerspawner|`/triggerspawner <spawner name>`|Triggers spawner by name.|8| +|unlock-emote|`/unlock-emote <emote id>`|Unlocks for your character the emote of the given id.|8| +|Set Level|`/setlevel <requested_level> (username)`|Sets the using entities level to the requested level. Takes an optional parameter of an in-game players username to set the level of.|8| +|crash|`/crash`|Crashes the server.|9| +|rollloot|`/rollloot <loot matrix index> <item id> <amount>`|Rolls loot matrix.|9| + +## Detailed `/inspect` Usage + +`/inspect <component> (-m <waypoint> | -a <animation> | -s | -p | -f (faction) | -t)` + +Finds the closest entity with the given component or LDF variable (ignoring players and racing cars), printing its ID, distance from the player, and whether it is sleeping, as well as the the IDs of all components the entity has. + +### `/inspect` Options + +* `-m`: If the entity has a moving platform component, sends it to the given waypoint, or stops the platform if `waypoint` is `-1`. +* `-a`: Plays the given animation on the entity. +* `-s`: Prints the entity's settings and spawner ID. +* `-p`: Prints the entity's position +* `-f`: If the entity has a destroyable component, prints whether the entity is smashable and its friendly and enemy faction IDs; if `faction` is specified, adds that faction to the entity. +* `-t`: If the entity has a phantom physics component, prints the effect type, direction, directional multiplier, and whether the effect is active; in any case, if the entity has a trigger, prints the trigger ID. + +## Game Master Levels + +There are 9 Game master levels + +|Level|Variable Name|Description| +|--- |--- |--- | +|0|GAME_MASTER_LEVEL_CIVILIAN|Normal player| +|1|GAME_MASTER_LEVEL_FORUM_MODERATOR|Forum moderator. No permissions on live servers.| +|2|GAME_MASTER_LEVEL_JUNIOR_MODERATOR|Can kick/mute and pull chat logs| +|3|GAME_MASTER_LEVEL_MODERATOR|Can return lost items| +|4|GAME_MASTER_LEVEL_SENIOR_MODERATOR|Can ban| +|5|GAME_MASTER_LEVEL_LEAD_MODERATOR|Can approve properties| +|6|GAME_MASTER_LEVEL_JUNIOR_DEVELOPER|Junior developer & future content team. Civilan on live.| +|7|GAME_MASTER_LEVEL_INACTIVE_DEVELOPER|Inactive developer, limited permissions.| +|8|GAME_MASTER_LEVEL_DEVELOPER|Active developer, full permissions on live.| +|9|GAME_MASTER_LEVEL_OPERATOR|Can shutdown server for restarts & updates.| diff --git a/migrations/cdserver/3_plunger_gun_fix.sql b/migrations/cdserver/3_plunger_gun_fix.sql index 35654e8b..3d33592e 100644 --- a/migrations/cdserver/3_plunger_gun_fix.sql +++ b/migrations/cdserver/3_plunger_gun_fix.sql @@ -1,2 +1 @@ --- File added April 9th, 2022 UPDATE ItemComponent SET itemType = 5 where id = 7082; diff --git a/migrations/dlu/2_reporter_id.sql b/migrations/dlu/2_reporter_id.sql index 26103342..dc2a9a7e 100644 --- a/migrations/dlu/2_reporter_id.sql +++ b/migrations/dlu/2_reporter_id.sql @@ -1 +1 @@ -ALTER TABLE bug_reports ADD reporter_id INT NOT NULL DEFAULT 0; +ALTER TABLE bug_reports ADD (reporter_id) INT NOT NULL DEFAULT 0; diff --git a/migrations/dlu/4_friends_list_objectids.sql b/migrations/dlu/4_friends_list_objectids.sql new file mode 100644 index 00000000..efb3a7ae --- /dev/null +++ b/migrations/dlu/4_friends_list_objectids.sql @@ -0,0 +1 @@ +UPDATE friends SET player_id = player_id % 0x100000000, friend_id = friend_id % 0x100000000; \ No newline at end of file diff --git a/resources/worldconfig.ini b/resources/worldconfig.ini index d8d8ef87..931da28c 100644 --- a/resources/worldconfig.ini +++ b/resources/worldconfig.ini @@ -52,4 +52,15 @@ solo_racing=0 disable_anti_speedhack=0 # 0 or 1, check server fdb (res/CDServer.fdb) against clients -check_fdb=0 \ No newline at end of file +check_fdb=0 + +# 0 or 1, DLU leaderboards will rate Avant Gardens Survival based on score by default. +# This option should be set to 1 if you would like it to reflect the game when it was live (scoring based on time). +classic_survival_scoring=0 + +# If this value is 1, pets will consume imagination as they did in live. if 0 they will not consume imagination at all. +pets_take_imagination=1 + +# If you would like to increase the maximum number of best friends a player can have on the server +# Change the value below to what you would like this to be (5 is live accurate) +max_number_of_best_friends=5 \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index eab4bbc9..b0e2c28d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,21 +1,21 @@ # create the testing file and list of tests create_test_sourcelist (Tests - CommonCxxTests.cpp - TestNiPoint3.cpp - TestLDFFormat.cpp + CommonCxxTests.cpp + TestNiPoint3.cpp + TestLDFFormat.cpp ) - + # add the executable add_executable (CommonCxxTests ${Tests}) -target_link_libraries(CommonCxxTests dCommon raknet) - +target_link_libraries(CommonCxxTests ${COMMON_LIBRARIES}) + # remove the test driver source file set (TestsToRun ${Tests}) remove (TestsToRun CommonCxxTests.cpp) # Add all the ADD_TEST for each test foreach (test ${TestsToRun}) - get_filename_component (TName ${test} NAME_WE) - add_test (NAME ${TName} COMMAND CommonCxxTests ${TName}) - set_property(TEST ${TName} PROPERTY ENVIRONMENT CTEST_OUTPUT_ON_FAILURE=1) + get_filename_component (TName ${test} NAME_WE) + add_test (NAME ${TName} COMMAND CommonCxxTests ${TName}) + set_property(TEST ${TName} PROPERTY ENVIRONMENT CTEST_OUTPUT_ON_FAILURE=1) endforeach () diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt new file mode 100644 index 00000000..119ce4fd --- /dev/null +++ b/thirdparty/CMakeLists.txt @@ -0,0 +1,236 @@ +# Source Code for raknet +file( + GLOB SOURCES_RAKNET + LIST_DIRECTORIES false + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + ${CMAKE_CURRENT_SOURCE_DIR}/raknet/Source/*.cpp +) + +# Source Code for recast +file( + GLOB SOURCES_RECAST + LIST_DIRECTORIES false + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + ${CMAKE_CURRENT_SOURCE_DIR}/recastnavigation/Recast/Source/*.cpp +) + +# Source Code for detour +file( + GLOB SOURCES_DETOUR + LIST_DIRECTORIES false + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + ${CMAKE_CURRENT_SOURCE_DIR}/recastnavigation/Detour/Source/*.cpp +) + +# Source Code for tinyxml2 +file( + GLOB SOURCES_TINYXML2 + LIST_DIRECTORIES false + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + ${CMAKE_CURRENT_SOURCE_DIR}/tinyxml2/tinyxml2.cpp +) + +# Source Code for libbcrypt +file( + GLOB SOURCES_LIBBCRYPT + LIST_DIRECTORIES false + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + ${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/*.c + ${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/src/*.c +) + +file( + GLOB SOURCES_SQLITE3 + LIST_DIRECTORIES false + RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" + ${CMAKE_CURRENT_SOURCE_DIR}/SQLite/*.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/SQLite/*.c +) + +# mariadb connector cpp +# On Windows ClangCL can't compile the connector from source but can link to an msvc compiled one, +# so prefer the prebuilt binaries unless MARIADB_BUILD_SOURCE is specified +if(WIN32 AND NOT MARIADB_BUILD_SOURCE) + set(MARIADB_MSI_DIR "${PROJECT_BINARY_DIR}/msi") + set(MARIADB_CONNECTOR_DIR "${PROJECT_BINARY_DIR}/mariadbcpp") + set(MARIADB_C_CONNECTOR_DIR "${MARIADB_CONNECTOR_DIR}/MariaDB/MariaDB Connector C 64-bit") + set(MARIADB_CPP_CONNECTOR_DIR "${MARIADB_CONNECTOR_DIR}/MariaDB/MariaDB C++ Connector 64-bit") + + file(MAKE_DIRECTORY "${MARIADB_MSI_DIR}") + file(MAKE_DIRECTORY "${MARIADB_CONNECTOR_DIR}") + + if(NOT EXISTS "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" ) + message("Downloading mariadb connector/c") + file(DOWNLOAD https://dlm.mariadb.com/1936366/connectors/c/connector-c-3.2.5/mariadb-connector-c-3.2.5-win64.msi + "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" + EXPECTED_HASH MD5=09d418c290109068a5bea136dafca36b) + endif() + + if(NOT EXISTS "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.msi" ) + message("Downloading mariadb connector/c++") + file(DOWNLOAD https://dlm.mariadb.com/1683453/connectors/cpp/connector-cpp-1.0.1/mariadb-connector-cpp-1.0.1-win64.msi + "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.msi" + EXPECTED_HASH MD5=548e743fbf067d21d42b81d958bf4ed7) + endif() + + + file(TO_NATIVE_PATH "${MARIADB_CONNECTOR_DIR}" MSIEXEC_TARGETDIR) + # extract msi files without installing to users system + if(NOT EXISTS "${MARIADB_C_CONNECTOR_DIR}") + file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/mariadb-connector-c-3.2.5-win64.msi" MSI_DIR) + execute_process(COMMAND msiexec /a ${MSI_DIR} /qn TARGETDIR=${MSIEXEC_TARGETDIR}) + endif() + + if(NOT EXISTS "${MARIADB_CPP_CONNECTOR_DIR}") + file(TO_NATIVE_PATH "${MARIADB_MSI_DIR}/mariadb-connector-cpp-1.0.1-win64.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(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" + "${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_compile_definitions(MARIADB_PLUGIN_DIR_OVERRIDE="${MARIADB_CPP_CONNECTOR_DIR}/plugin") +else() # Build from source + + include(ExternalProject) + if(WIN32) + set(MARIADB_EXTRA_COMPILE_FLAGS /EHsc) + set(MARIADB_EXTRA_CMAKE_ARGS -DWITH_MSI=OFF) + elseif(APPLE) + set(MARIADB_EXTRA_COMPILE_FLAGS -D_GLIBCXX_USE_CXX11_ABI=0) + set(MARIADB_EXTRA_CMAKE_ARGS -DWITH_EXTERNAL_ZLIB=ON -DOPENSSL_ROOT_DIR=${OPENSSL_ROOT_DIR}) + else() + set(MARIADB_EXTRA_COMPILE_FLAGS -D_GLIBCXX_USE_CXX11_ABI=0) + endif() + + ExternalProject_Add(mariadb_connector_cpp + SOURCE_DIR ${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp + CMAKE_ARGS "-DCMAKE_CXX_FLAGS:STRING= ${MARIADB_EXTRA_COMPILE_FLAGS}" + -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${__maria_db_connector_compile_jobs__} + INSTALL_COMMAND "") + + ExternalProject_Get_Property(mariadb_connector_cpp BINARY_DIR) + + if(WIN32) + set(MARIADB_SHARED_LIBRARY_NAME mariadbcpp.dll) + set(MARIADB_PLUGIN_SUFFIX .dll) + set(MARIADB_IMPLIB_LOCATION "${BINARY_DIR}/RelWithDebInfo/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") + else() + set(MARIADB_SHARED_LIBRARY_NAME libmariadbcpp${CMAKE_SHARED_LIBRARY_SUFFIX}) + set(MARIADB_PLUGIN_SUFFIX .so) + 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}/$<CONFIG>") + 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") + 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}) + +if(WIN32) + set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_IMPLIB ${MARIADB_IMPLIB_LOCATION}) +endif() + +# Add directories to include lists +target_include_directories(mariadbConnCpp INTERFACE ${MARIADB_INCLUDE_DIR}) +add_dependencies(mariadbConnCpp mariadb_connector_cpp) + +# Create our third party library objects +add_library(raknet ${SOURCES_RAKNET}) +add_library(tinyxml2 ${SOURCES_TINYXML2}) +add_library(detour ${SOURCES_DETOUR}) +add_library(recast ${SOURCES_RECAST}) +add_library(libbcrypt ${SOURCES_LIBBCRYPT}) +add_library(sqlite3 ${SOURCES_SQLITE3}) + +if(WIN32) + # Link Win Sockets 2 to RakNet + target_link_libraries(raknet ws2_32) +elseif(UNIX) + # Add warning disable flags and link Unix libraries to sqlite3 + target_link_libraries(sqlite3 pthread dl m) + + # -Wno-unused-result -Wno-unknown-pragmas -fpermissive + target_compile_options(sqlite3 PRIVATE "-Wno-return-local-addr" "-Wno-maybe-uninitialized") + target_compile_options(raknet PRIVATE "-Wno-write-strings" "-Wformat-overflow=0" "-Wformat=0") + target_compile_options(libbcrypt PRIVATE "-Wno-implicit-function-declaration" "-Wno-int-conversion") +endif() + +# Download Backtrace if configured +if(UNIX AND NOT APPLE) + include(FetchContent) + if (__include_backtrace__ AND __compile_backtrace__) + FetchContent_Declare( + backtrace + GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git + ) + + FetchContent_MakeAvailable(backtrace) + + if (NOT EXISTS ${backtrace_SOURCE_DIR}/.libs) + set(backtrace_make_cmd "${backtrace_SOURCE_DIR}/configure --prefix=\"/usr\" --enable-shared --with-system-libunwind") + + execute_process( + COMMAND bash -c "cd ${backtrace_SOURCE_DIR} && ${backtrace_make_cmd} && make && cd ${CMAKE_SOURCE_DIR}" + ) + endif() + + link_directories(${backtrace_SOURCE_DIR}/.libs/) + include_directories(${backtrace_SOURCE_DIR}) + endif() +endif() \ No newline at end of file diff --git a/thirdparty/cpplinq/cpplinq.hpp b/thirdparty/cpplinq/cpplinq.hpp index d25cde85..ae9169d9 100644 --- a/thirdparty/cpplinq/cpplinq.hpp +++ b/thirdparty/cpplinq/cpplinq.hpp @@ -14,6 +14,8 @@ #ifndef CPPLINQ__HEADER_GUARD # define CPPLINQ__HEADER_GUARD +#undef min +#undef max #define NOMINMAX // ---------------------------------------------------------------------------- diff --git a/thirdparty/mariadb-connector-cpp b/thirdparty/mariadb-connector-cpp new file mode 160000 index 00000000..3fbdf8fa --- /dev/null +++ b/thirdparty/mariadb-connector-cpp @@ -0,0 +1 @@ +Subproject commit 3fbdf8fa337d532861f6a61494a72dbce6402f8b diff --git a/thirdparty/raknet/Source/FileList.cpp b/thirdparty/raknet/Source/FileList.cpp index ebb2a706..c432ce85 100644 --- a/thirdparty/raknet/Source/FileList.cpp +++ b/thirdparty/raknet/Source/FileList.cpp @@ -3,7 +3,7 @@ #include <assert.h> #if defined(_WIN32) || defined(__CYGWIN__) #include <io.h> -#elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) +#elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) && !defined ( __aarch64__ ) #include <sys/io.h> #endif #include "DS_Queue.h" diff --git a/thirdparty/raknet/Source/Gen_RPC8.h b/thirdparty/raknet/Source/Gen_RPC8.h index b29a1fc9..029383c4 100644 --- a/thirdparty/raknet/Source/Gen_RPC8.h +++ b/thirdparty/raknet/Source/Gen_RPC8.h @@ -133,6 +133,7 @@ namespace GenRPC #define AUTO_RPC_ABI_PPC 4 // first 6 args (even if float) in int reg; first 13 floats in reg. // parameter passing area with shadow area. +#define AUTO_RPC_ABI_AARCH64 5 // Configure the parameters for the system. #if defined(__i386__) || defined( _M_IX86 ) || defined( __INTEL__ ) @@ -176,6 +177,18 @@ typedef double HardwareReal; typedef unsigned long long NaturalWord; typedef double HardwareReal; // could be changed to __float128 on AMD64/nonwin +#elif defined( __aarch64__ ) || defined (_M_ARM64) +#define AUTO_RPC_ABI AUTO_RPC_ABI_AARCH64 +#define AUTO_RPC_AUTORPC_WORD 64 +#define AUTO_RPC_INT_REG_PARAMS 8 +#define AUTO_RPC_FLOAT_REG_PARAMS 8 +#define AUTO_RPC_PARAMETER_REFERENCE_THRESHOLD 0 +#define AUTO_RPC_INT_SHADOW_OF_FLOATS 0 +#define AUTO_RPC_ALLOC_SEPARATE_FLOATS 1 +#define AUTO_RPC_CREATE_FLOAT_MAP 0 +typedef unsigned long long NaturalWord; +typedef double HardwareReal; + #elif defined ( _PS3 ) typedef double HardwareReal; typedef unsigned long long NaturalWord; diff --git a/thirdparty/raknet/Source/Types.h b/thirdparty/raknet/Source/Types.h index b0690c8e..ef85c2a9 100644 --- a/thirdparty/raknet/Source/Types.h +++ b/thirdparty/raknet/Source/Types.h @@ -92,8 +92,8 @@ defined(__amd64) || defined(__amd64__) || \ defined(__alpha__) || defined(__alpha) || defined(__ia64) || defined(__ia64__) || \ defined(_M_ALPHA) || defined(ns32000) || defined(__ns32000__) || defined(sequent) || \ - defined(MIPSEL) || defined(_MIPSEL) || defined(sun386) || defined(__sun386__) - + defined(MIPSEL) || defined(_MIPSEL) || defined(sun386) || defined(__sun386__) || \ + defined(__aarch64__) || defined (_M_ARM64) # define HOST_ENDIAN_IS_LITTLE #else @@ -128,8 +128,8 @@ namespace cat defined(__amd64) || defined(__amd64__) || defined(_M_X64) || \ defined(__alpha__) || defined(__alpha) || defined(__ia64) || defined(__ia64__) || \ defined(_M_ALPHA) || defined(ns32000) || defined(__ns32000__) || defined(sequent) || \ - defined(MIPSEL) || defined(_MIPSEL) || defined(sun386) || defined(__sun386__) - + defined(MIPSEL) || defined(_MIPSEL) || defined(sun386) || defined(__sun386__) || \ + defined(__aarch64__) || defined (_M_ARM64) # define LITTLE_ENDIAN #else diff --git a/vanity/CREDITS.md b/vanity/CREDITS.md index e4a67c81..e130cfb3 100644 --- a/vanity/CREDITS.md +++ b/vanity/CREDITS.md @@ -4,9 +4,11 @@ DarwinAnim8or (Max) Wincent01 Mick -averysumner +averysumner (codeshaunted) Jon002 Jonny +EmosewaMC +Jettford ## Research & Tooling Xiphoseer