mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-05-23 15:22:28 +00:00
Merge branch 'main' into scripting-lua
This commit is contained in:
commit
e37f1bcee3
8
.github/workflows/build-and-test.yml
vendored
8
.github/workflows/build-and-test.yml
vendored
@ -12,18 +12,21 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ windows-2022, ubuntu-20.04 ]
|
os: [ windows-2022, ubuntu-20.04, macos-11 ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Add msbuild to PATH (windows only)
|
- name: Add msbuild to PATH (Windows only)
|
||||||
if: ${{ matrix.os == 'windows-2022' }}
|
if: ${{ matrix.os == 'windows-2022' }}
|
||||||
uses: microsoft/setup-msbuild@v1.1
|
uses: microsoft/setup-msbuild@v1.1
|
||||||
with:
|
with:
|
||||||
vs-version: '[17,18)'
|
vs-version: '[17,18)'
|
||||||
msbuild-architecture: x64
|
msbuild-architecture: x64
|
||||||
|
- name: Install libssl (Mac Only)
|
||||||
|
if: ${{ matrix.os == 'macos-11' }}
|
||||||
|
run: brew install openssl@3
|
||||||
- name: cmake
|
- name: cmake
|
||||||
uses: lukka/run-cmake@v10
|
uses: lukka/run-cmake@v10
|
||||||
with:
|
with:
|
||||||
@ -32,6 +35,7 @@ jobs:
|
|||||||
testPreset: "ci-${{matrix.os}}"
|
testPreset: "ci-${{matrix.os}}"
|
||||||
- name: artifacts
|
- name: artifacts
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
|
if: ${{ github.ref == 'ref/head/main' }}
|
||||||
with:
|
with:
|
||||||
name: build-${{matrix.os}}
|
name: build-${{matrix.os}}
|
||||||
path: |
|
path: |
|
||||||
|
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -10,6 +10,10 @@
|
|||||||
[submodule "thirdparty/libbcrypt"]
|
[submodule "thirdparty/libbcrypt"]
|
||||||
path = thirdparty/libbcrypt
|
path = thirdparty/libbcrypt
|
||||||
url = https://github.com/trusch/libbcrypt.git
|
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"]
|
[submodule "thirdparty/docker-utils"]
|
||||||
path = thirdparty/docker-utils
|
path = thirdparty/docker-utils
|
||||||
url = https://github.com/lcdr/utils.git
|
url = https://github.com/lcdr/utils.git
|
||||||
|
649
CMakeLists.txt
649
CMakeLists.txt
@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.14)
|
|||||||
project(Darkflame)
|
project(Darkflame)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
|
set (CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
# Read variables from file
|
# Read variables from file
|
||||||
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
|
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
|
# Set the cmake variables, formatted as "VARIABLE #" in variables
|
||||||
foreach(variable ${variables})
|
foreach(variable ${variables})
|
||||||
# If the string contains a #, skip it
|
# If the string contains a #, skip it
|
||||||
if("${variable}" MATCHES "#")
|
if(NOT "${variable}" MATCHES "#")
|
||||||
continue()
|
|
||||||
endif()
|
# Split the variable into name and value
|
||||||
|
string(REPLACE "=" ";" variable ${variable})
|
||||||
|
|
||||||
# Split the variable into name and value
|
# Check that the length of the variable is 2 (name and value)
|
||||||
string(REPLACE "=" ";" variable ${variable})
|
list(LENGTH variable length)
|
||||||
|
if(${length} EQUAL 2)
|
||||||
|
|
||||||
# Check that the length of the variable is 2 (name and value)
|
list(GET variable 0 variable_name)
|
||||||
list(LENGTH variable length)
|
list(GET variable 1 variable_value)
|
||||||
if(NOT ${length} EQUAL 2)
|
|
||||||
continue()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(GET variable 0 variable_name)
|
# Set the variable
|
||||||
list(GET variable 1 variable_value)
|
set(${variable_name} ${variable_value})
|
||||||
|
|
||||||
# Set the variable
|
# Add compiler definition
|
||||||
set(${variable_name} ${variable_value})
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}")
|
||||||
|
|
||||||
# Add compiler definition
|
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}")
|
endif()
|
||||||
|
endif()
|
||||||
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
|
||||||
endforeach()
|
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 the version
|
||||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
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
|
# Echo the version
|
||||||
message(STATUS "Version: ${PROJECT_VERSION}")
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
# Compiler flags:
|
||||||
|
# Disabled deprecated warnings as the MySQL includes have deprecated code in them.
|
||||||
if(WIN32)
|
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
|
||||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
# Disabled no-register
|
||||||
endif(WIN32)
|
# 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
|
# Our output dir
|
||||||
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_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
|
# Create a /res directory
|
||||||
make_directory(${CMAKE_BINARY_DIR}/res)
|
make_directory(${CMAKE_BINARY_DIR}/res)
|
||||||
@ -128,86 +84,82 @@ make_directory(${CMAKE_BINARY_DIR}/locale)
|
|||||||
make_directory(${CMAKE_BINARY_DIR}/logs)
|
make_directory(${CMAKE_BINARY_DIR}/logs)
|
||||||
|
|
||||||
# Copy ini files on first build
|
# Copy ini files on first build
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/authconfig.ini)
|
set(INI_FILES "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini")
|
||||||
configure_file(
|
foreach(ini ${INI_FILES})
|
||||||
${CMAKE_SOURCE_DIR}/resources/authconfig.ini ${PROJECT_BINARY_DIR}/authconfig.ini
|
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${ini})
|
||||||
COPYONLY
|
configure_file(
|
||||||
)
|
${CMAKE_SOURCE_DIR}/resources/${ini} ${PROJECT_BINARY_DIR}/${ini}
|
||||||
endif()
|
COPYONLY
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/chatconfig.ini)
|
)
|
||||||
configure_file(
|
endif()
|
||||||
${CMAKE_SOURCE_DIR}/resources/chatconfig.ini ${PROJECT_BINARY_DIR}/chatconfig.ini
|
endforeach()
|
||||||
COPYONLY
|
|
||||||
)
|
# Copy vanity files on first build
|
||||||
endif()
|
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/worldconfig.ini)
|
foreach(file ${VANITY_FILES})
|
||||||
configure_file(
|
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
||||||
${CMAKE_SOURCE_DIR}/resources/worldconfig.ini ${PROJECT_BINARY_DIR}/worldconfig.ini
|
endforeach()
|
||||||
COPYONLY
|
|
||||||
)
|
# Move our migrations for MasterServer to run
|
||||||
endif()
|
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/)
|
||||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/masterconfig.ini)
|
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql)
|
||||||
configure_file(
|
foreach(file ${SQL_FILES})
|
||||||
${CMAKE_SOURCE_DIR}/resources/masterconfig.ini ${PROJECT_BINARY_DIR}/masterconfig.ini
|
get_filename_component(file ${file} NAME)
|
||||||
COPYONLY
|
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()
|
endif()
|
||||||
|
|
||||||
# Copy files to output
|
if (WIN32)
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/CREDITS.md" "${CMAKE_BINARY_DIR}/vanity/CREDITS.md" COPYONLY)
|
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include")
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/INFO.md" "${CMAKE_BINARY_DIR}/vanity/INFO.md" COPYONLY)
|
elseif (UNIX)
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/TESTAMENT.md" "${CMAKE_BINARY_DIR}/vanity/TESTAMENT.md" COPYONLY)
|
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt")
|
||||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/NPC.xml" "${CMAKE_BINARY_DIR}/vanity/NPC.xml" COPYONLY)
|
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})
|
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||||
|
# Add binary directory as an include directory
|
||||||
# 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
|
|
||||||
include_directories(${PROJECT_BINARY_DIR})
|
include_directories(${PROJECT_BINARY_DIR})
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dChatFilter/)
|
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
|
# Actually include the directories from our list
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/)
|
foreach (dir ${INCLUDED_DIRECTORIES})
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dBehaviors)
|
include_directories(${PROJECT_SOURCE_DIR}/${dir})
|
||||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dComponents)
|
endforeach()
|
||||||
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/)
|
|
||||||
|
|
||||||
# Link dGame to LUA
|
# Link dGame to LUA
|
||||||
if(__include_lua__)
|
if(__include_lua__)
|
||||||
@ -217,311 +169,116 @@ if(__include_lua__)
|
|||||||
include_directories(${PROJECT_SOURCE_DIR}/dLua/)
|
include_directories(${PROJECT_SOURCE_DIR}/dLua/)
|
||||||
endif(UNIX)
|
endif(UNIX)
|
||||||
|
|
||||||
# Default to linking to libmysql
|
# Add linking directories:
|
||||||
set(MYSQL_LIB mysql)
|
|
||||||
if(WIN32)
|
|
||||||
set(MYSQL_LIB mysqlcppconn)
|
|
||||||
endif(WIN32)
|
|
||||||
|
|
||||||
# Lib folders:
|
|
||||||
link_directories(${PROJECT_BINARY_DIR})
|
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
|
# Load all of our third party directories
|
||||||
set(MYSQL_LIB mysqlcppconn)
|
add_subdirectory(thirdparty)
|
||||||
endif(APPLE)
|
|
||||||
endif(UNIX)
|
|
||||||
if(WIN32)
|
|
||||||
link_directories(${mysql_SOURCE_DIR}/lib64/vs14)
|
|
||||||
endif(WIN32)
|
|
||||||
|
|
||||||
# Source Code
|
# Glob together all headers that need to be precompiled
|
||||||
file(
|
file(
|
||||||
GLOB SOURCES
|
GLOB HEADERS_DDATABASE
|
||||||
LIST_DIRECTORIES false
|
LIST_DIRECTORIES false
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
${PROJECT_SOURCE_DIR}/dDatabase/*.h
|
||||||
${PROJECT_SOURCE_DIR}/dWorldServer/*.cpp
|
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h
|
||||||
|
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Source Code for AuthServer
|
|
||||||
file(
|
file(
|
||||||
GLOB SOURCES_AUTH
|
GLOB HEADERS_DZONEMANAGER
|
||||||
LIST_DIRECTORIES false
|
LIST_DIRECTORIES false
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
${PROJECT_SOURCE_DIR}/dZoneManager/*.h
|
||||||
${PROJECT_SOURCE_DIR}/dAuthServer/*.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Source Code for MasterServer
|
|
||||||
file(
|
file(
|
||||||
GLOB SOURCES_MASTER
|
GLOB HEADERS_DCOMMON
|
||||||
LIST_DIRECTORIES false
|
LIST_DIRECTORIES false
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
${PROJECT_SOURCE_DIR}/dCommon/*.h
|
||||||
${PROJECT_SOURCE_DIR}/dMasterServer/*.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Source Code for ChatServer
|
|
||||||
file(
|
file(
|
||||||
GLOB SOURCES_CHAT
|
GLOB HEADERS_DGAME
|
||||||
LIST_DIRECTORIES false
|
LIST_DIRECTORIES false
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
${PROJECT_SOURCE_DIR}/dGame/Entity.h
|
||||||
${PROJECT_SOURCE_DIR}/dChatServer/*.cpp
|
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h
|
||||||
|
${PROJECT_SOURCE_DIR}/dGame/EntityManager.h
|
||||||
|
${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h
|
||||||
)
|
)
|
||||||
|
|
||||||
# Source Code for raknet
|
# Add our library subdirectories for creation of the library object
|
||||||
file(
|
add_subdirectory(dCommon)
|
||||||
GLOB SOURCES_RAKNET
|
add_subdirectory(dDatabase)
|
||||||
LIST_DIRECTORIES false
|
add_subdirectory(dChatFilter)
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
add_subdirectory(dNet)
|
||||||
${PROJECT_SOURCE_DIR}/thirdparty/raknet/Source/*.cpp
|
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
|
target_precompile_headers(
|
||||||
file(
|
dZoneManager PRIVATE
|
||||||
GLOB SOURCES_RECAST
|
${HEADERS_DZONEMANAGER}
|
||||||
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
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# If we are including LUA, include the dLua files in dGame
|
# If we are including LUA, include the dLua files in dGame
|
||||||
if(__include_lua__)
|
#if(__include_lua__)
|
||||||
file(
|
# file(
|
||||||
GLOB SOURCES_DLUA
|
# GLOB SOURCES_DLUA
|
||||||
LIST_DIRECTORIES false
|
# LIST_DIRECTORIES false
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
# RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
${PROJECT_SOURCE_DIR}/dLua/*.cpp
|
# ${PROJECT_SOURCE_DIR}/dLua/*.cpp
|
||||||
)
|
# )
|
||||||
|
|
||||||
# Append the dLua files to the dGame files
|
# Append the dLua files to the dGame files
|
||||||
set(SOURCES_DGAME ${SOURCES_DGAME} ${SOURCES_DLUA})
|
#set(SOURCES_DGAME ${SOURCES_DGAME} ${SOURCES_DLUA})
|
||||||
endif(__include_lua__)
|
#endif(__include_lua__)
|
||||||
|
## Need to specify to use the CXX compiler language here or else we get errors including <string>.
|
||||||
|
#target_precompile_headers(
|
||||||
|
# dDatabase PRIVATE
|
||||||
|
# "$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
|
||||||
|
#)
|
||||||
|
|
||||||
# Source Code for dZoneManager
|
target_precompile_headers(
|
||||||
file(
|
dCommon PRIVATE
|
||||||
GLOB SOURCES_DZM
|
${HEADERS_DCOMMON}
|
||||||
LIST_DIRECTORIES false
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
${PROJECT_SOURCE_DIR}/dZoneManager/*.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# 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
|
# Link dGame to LUA
|
||||||
if(__include_lua__)
|
#if(__include_lua__)
|
||||||
find_package(Lua REQUIRED)
|
# find_package(Lua REQUIRED)
|
||||||
|
|
||||||
target_link_libraries(dGame ${LUA_LIBRARIES})
|
# target_link_libraries(dGame ${LUA_LIBRARIES})
|
||||||
|
|
||||||
message(STATUS "Linking dGame to LUA " ${LUA_LIBRARIES})
|
# message(STATUS "Linking dGame to LUA " ${LUA_LIBRARIES})
|
||||||
endif(UNIX)
|
#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)
|
|
||||||
|
|
||||||
|
target_precompile_headers(
|
||||||
|
tinyxml2 PRIVATE
|
||||||
|
"$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>"
|
||||||
|
)
|
||||||
|
@ -19,6 +19,15 @@
|
|||||||
"description": "Same as default, Used in GitHub actions workflow",
|
"description": "Same as default, Used in GitHub actions workflow",
|
||||||
"inherits": "default"
|
"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",
|
"name": "ci-windows-2022",
|
||||||
"displayName": "CI configure step for Windows",
|
"displayName": "CI configure step for Windows",
|
||||||
@ -66,6 +75,13 @@
|
|||||||
"displayName": "Linux CI Build",
|
"displayName": "Linux CI Build",
|
||||||
"description": "This preset is used by the CI build on linux",
|
"description": "This preset is used by the CI build on linux",
|
||||||
"jobs": 2
|
"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": [
|
"testPresets": [
|
||||||
@ -81,6 +97,18 @@
|
|||||||
"outputOnFailure": true
|
"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",
|
"name": "ci-windows-2022",
|
||||||
"configurePreset": "ci-windows-2022",
|
"configurePreset": "ci-windows-2022",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
PROJECT_VERSION_MAJOR=1
|
PROJECT_VERSION_MAJOR=1
|
||||||
PROJECT_VERSION_MINOR=0
|
PROJECT_VERSION_MINOR=0
|
||||||
PROJECT_VERSION_PATCH=2
|
PROJECT_VERSION_PATCH=3
|
||||||
# LICENSE
|
# LICENSE
|
||||||
LICENSE=AGPL-3.0
|
LICENSE=AGPL-3.0
|
||||||
# The network version.
|
# The network version.
|
||||||
@ -16,3 +16,5 @@ NET_VERSION=171022
|
|||||||
# Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs.
|
# Set __include_backtrace__ to 1 to includes the backtrace library for better crashlogs.
|
||||||
# __compile_backtrace__=1
|
# __compile_backtrace__=1
|
||||||
# Set __compile_backtrace__ to 1 to compile the backtrace library instead of using system libraries.
|
# 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.
|
11
Docker.md
11
Docker.md
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
- [Docker](https://docs.docker.com/get-docker/) (Docker Desktop or on Linux normal Docker)
|
- [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)
|
- [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
|
## 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 #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
|
## Disable brickbuildfix
|
||||||
|
|
||||||
If you don't need the http server running on port 80 do this:
|
If you don't need the http server running on port 80 do this:
|
||||||
|
94
README.md
94
README.md
@ -31,7 +31,6 @@ Development of the latest iteration of Darkflame Universe has been done primaril
|
|||||||
```bash
|
```bash
|
||||||
git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
||||||
```
|
```
|
||||||
|
|
||||||
**Python**
|
**Python**
|
||||||
|
|
||||||
Some tools utilized to streamline the setup process require Python 3, make sure you have it installed.
|
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.
|
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
|
### 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!
|
CMake must be version 3.14 or higher!
|
||||||
|
|
||||||
@ -71,22 +70,19 @@ make
|
|||||||
```
|
```
|
||||||
|
|
||||||
### MacOS builds
|
### 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
|
```bash
|
||||||
# Install required tools
|
# Create the build directory, preserving it if it already exists
|
||||||
brew install boost mysql-connector-c++
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
# Symlinks for finding the required modules
|
# Run CMake to generate build files
|
||||||
sudo ln -s /usr/local/mysql-connector-c++/lib64/libmysqlcppconn.dylib /usr/local/mysql-connector-c++/lib64/libmysql.dylib
|
cmake .. -DOPENSSL_ROOT_DIR=/path/to/openssl
|
||||||
sudo ln -s /usr/local/mysql-connector-c++/lib64/libcrypto.1.1.dylib /usr/local/mysql/lib/libcrypto.1.1.dylib
|
|
||||||
```
|
|
||||||
|
|
||||||
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:
|
# 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
|
||||||
```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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Windows builds (native)
|
### Windows builds (native)
|
||||||
@ -102,9 +98,20 @@ cd build
|
|||||||
cmake ..
|
cmake ..
|
||||||
|
|
||||||
:: Run CMake with build flag to build
|
:: 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)
|
### 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.
|
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)
|
[**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
|
## 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
|
### Resources
|
||||||
|
|
||||||
**LEGO® Universe 1.10.64**
|
**LEGO® Universe 1.10.64**
|
||||||
@ -180,6 +195,13 @@ certutil -hashfile <file> SHA256
|
|||||||
* Move and rename `cdclient.sqlite` into `build/res/CDServer.sqlite`
|
* 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
|
* 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**
|
**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.
|
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
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
### Contributors to DLUv3
|
## Active Contributors
|
||||||
* DarwinAnim8or
|
* [EmosewaMC](https://github.com/EmosewaMC)
|
||||||
* Wincent01
|
* [Jettford](https://github.com/Jettford)
|
||||||
* Mick
|
|
||||||
* averysumner
|
## DLU Team
|
||||||
* Jon002
|
* [DarwinAnim8or](https://github.com/DarwinAnim8or)
|
||||||
* Jonny
|
* [Wincent01](https://github.com/Wincent01)
|
||||||
* Xiphoseer
|
* [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
|
### Research and tools
|
||||||
* lcdr
|
* [lcdr](https://github.com/lcdr)
|
||||||
|
* [Xiphoseer](https://github.com/Xiphoseer)
|
||||||
|
|
||||||
### Community management
|
### Community management
|
||||||
* Neal
|
* [Neal](https://github.com/NealSpellman)
|
||||||
|
|
||||||
### Former contributors
|
### Former contributors
|
||||||
* TheMachine
|
* TheMachine
|
||||||
|
4
dAuthServer/CMakeLists.txt
Normal file
4
dAuthServer/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(DAUTHSERVER_SOURCES "AuthServer.cpp")
|
||||||
|
|
||||||
|
add_executable(AuthServer ${DAUTHSERVER_SOURCES})
|
||||||
|
target_link_libraries(AuthServer ${COMMON_LIBRARIES})
|
4
dChatFilter/CMakeLists.txt
Normal file
4
dChatFilter/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(DCHATFILTER_SOURCES "dChatFilter.cpp")
|
||||||
|
|
||||||
|
add_library(dChatFilter STATIC ${DCHATFILTER_SOURCES})
|
||||||
|
target_link_libraries(dChatFilter dDatabase)
|
6
dChatServer/CMakeLists.txt
Normal file
6
dChatServer/CMakeLists.txt
Normal file
@ -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)
|
@ -8,6 +8,10 @@
|
|||||||
#include "dServer.h"
|
#include "dServer.h"
|
||||||
#include "GeneralUtils.h"
|
#include "GeneralUtils.h"
|
||||||
#include "dLogger.h"
|
#include "dLogger.h"
|
||||||
|
#include "AddFriendResponseCode.h"
|
||||||
|
#include "AddFriendResponseType.h"
|
||||||
|
#include "RakString.h"
|
||||||
|
#include "dConfig.h"
|
||||||
|
|
||||||
extern PlayerContainer playerContainer;
|
extern PlayerContainer playerContainer;
|
||||||
|
|
||||||
@ -21,44 +25,41 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
|||||||
auto player = playerContainer.GetPlayerData(playerID);
|
auto player = playerContainer.GetPlayerData(playerID);
|
||||||
if (!player) return;
|
if (!player) return;
|
||||||
|
|
||||||
//Get our friends list from the Db:
|
//Get our friends list from the Db. Using a derived table since the friend of a player can be in either column.
|
||||||
auto stmt = Database::CreatePreppedStmt("SELECT * FROM friends WHERE player_id = ? OR friend_id = ?");
|
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt(
|
||||||
stmt->setUInt64(1, playerID);
|
"SELECT fr.requested_player, best_friend, ci.name FROM "
|
||||||
stmt->setUInt64(2, playerID);
|
"(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<uint32_t>(playerID));
|
||||||
|
stmt->setUInt(2, static_cast<uint32_t>(playerID));
|
||||||
|
|
||||||
std::vector<FriendData> friends;
|
std::vector<FriendData> friends;
|
||||||
|
|
||||||
auto res = stmt->executeQuery();
|
std::unique_ptr<sql::ResultSet> res(stmt->executeQuery());
|
||||||
while (res->next()) {
|
while (res->next()) {
|
||||||
FriendData fd;
|
FriendData fd;
|
||||||
fd.isFTP = false; // not a thing in DLU
|
fd.isFTP = false; // not a thing in DLU
|
||||||
fd.friendID = res->getInt64(1);
|
fd.friendID = res->getUInt(1);
|
||||||
if (fd.friendID == playerID) fd.friendID = res->getUInt64(2);
|
GeneralUtils::SetBit(fd.friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
|
||||||
|
GeneralUtils::SetBit(fd.friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
|
||||||
|
|
||||||
fd.isBestFriend = res->getInt(3) == 2; //0 = friends, 1 = requested, 2 = bffs
|
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;
|
||||||
//We need to find their name as well:
|
fd.friendName = res->getString(3);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Now check if they're online:
|
//Now check if they're online:
|
||||||
auto fr = playerContainer.GetPlayerData(fd.friendID);
|
auto fr = playerContainer.GetPlayerData(fd.friendID);
|
||||||
|
|
||||||
if (fr) {
|
if (fr) {
|
||||||
fd.isOnline = true;
|
fd.isOnline = true;
|
||||||
fd.zoneID = fr->zoneID;
|
fd.zoneID = fr->zoneID;
|
||||||
|
|
||||||
//Since this friend is online, we need to update them on the fact that we've just logged in:
|
//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 {
|
else {
|
||||||
fd.isOnline = false;
|
fd.isOnline = false;
|
||||||
@ -68,9 +69,6 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
|||||||
friends.push_back(fd);
|
friends.push_back(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete res;
|
|
||||||
delete stmt;
|
|
||||||
|
|
||||||
//Now, we need to send the friendlist to the server they came from:
|
//Now, we need to send the friendlist to the server they came from:
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
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) {
|
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;
|
CINSTREAM;
|
||||||
LWOOBJID playerID;
|
LWOOBJID requestorPlayerID;
|
||||||
inStream.Read(playerID);
|
inStream.Read(requestorPlayerID);
|
||||||
inStream.Read(playerID);
|
inStream.Read(requestorPlayerID);
|
||||||
std::string playerName = PacketUtils::ReadString(0x14, packet, true);
|
uint32_t spacing{};
|
||||||
//There's another bool here to determine if it's a best friend request, but we're not handling it right now.
|
inStream.Read(spacing);
|
||||||
|
std::string playerName = "";
|
||||||
|
uint16_t character;
|
||||||
|
bool noMoreLettersInName = false;
|
||||||
|
|
||||||
//PacketUtils::SavePacket("FriendRequest.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed());
|
for (uint32_t j = 0; j < 33; j++) {
|
||||||
|
inStream.Read(character);
|
||||||
//We need to check to see if the player is actually online or not:
|
if (character == '\0') noMoreLettersInName = true;
|
||||||
auto targetData = playerContainer.GetPlayerData(playerName);
|
if (!noMoreLettersInName) playerName.push_back(static_cast<char>(character));
|
||||||
if (targetData) {
|
|
||||||
SendFriendRequest(targetData, playerContainer.GetPlayerData(playerID));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char isBestFriendRequest{};
|
||||||
|
inStream.Read(isBestFriendRequest);
|
||||||
|
|
||||||
|
auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
|
||||||
|
std::unique_ptr<PlayerData> 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<sql::PreparedStatement> nameQuery(Database::CreatePreppedStmt("SELECT name from charinfo where name = ?;"));
|
||||||
|
nameQuery->setString(1, playerName);
|
||||||
|
std::unique_ptr<sql::ResultSet> 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<sql::PreparedStatement> 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<uint32_t>(requestorPlayerID));
|
||||||
|
friendUpdate->setUInt(2, static_cast<uint32_t>(requestee->playerID));
|
||||||
|
friendUpdate->setUInt(3, static_cast<uint32_t>(requestee->playerID));
|
||||||
|
friendUpdate->setUInt(4, static_cast<uint32_t>(requestorPlayerID));
|
||||||
|
std::unique_ptr<sql::ResultSet> 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<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
|
||||||
|
GeneralUtils::SetBit(queryPlayerID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
|
||||||
|
GeneralUtils::SetBit(queryFriendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
|
||||||
|
GeneralUtils::SetBit(queryFriendID, static_cast<size_t>(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<sql::PreparedStatement> 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<uint32_t>(requestorPlayerID));
|
||||||
|
updateQuery->setUInt(3, static_cast<uint32_t>(requestee->playerID));
|
||||||
|
updateQuery->setUInt(4, static_cast<uint32_t>(requestee->playerID));
|
||||||
|
updateQuery->setUInt(5, static_cast<uint32_t>(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) {
|
void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||||
@ -114,30 +242,75 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
|||||||
LWOOBJID playerID;
|
LWOOBJID playerID;
|
||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
|
|
||||||
uint8_t responseCode = packet->data[0x14];
|
AddFriendResponseCode clientResponseCode = static_cast<AddFriendResponseCode>(packet->data[0x14]);
|
||||||
std::string friendName = PacketUtils::ReadString(0x15, packet, true);
|
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:
|
//Now to try and find both of these:
|
||||||
auto goonA = playerContainer.GetPlayerData(playerID);
|
auto requestor = playerContainer.GetPlayerData(playerID);
|
||||||
auto goonB = playerContainer.GetPlayerData(friendName);
|
auto requestee = playerContainer.GetPlayerData(friendName);
|
||||||
if (!goonA || !goonB) return;
|
if (!requestor || !requestee) return;
|
||||||
|
|
||||||
SendFriendResponse(goonB, goonA, responseCode);
|
AddFriendResponseType serverResponseCode{};
|
||||||
SendFriendResponse(goonA, goonB, responseCode); //Do we need to send it to both? I think so so both get the updated friendlist but... idk.
|
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 (?,?,?)");
|
// Now that we have handled the base cases, we need to check the other cases.
|
||||||
stmt->setUInt64(1, goonA->playerID);
|
if (serverResponseCode == AddFriendResponseType::ACCEPTED) {
|
||||||
stmt->setUInt64(2, goonB->playerID);
|
for (auto friendData : requestor->friends) {
|
||||||
stmt->setInt(3, 0);
|
if (friendData.friendID == requestee->playerID) {
|
||||||
stmt->execute();
|
serverResponseCode = AddFriendResponseType::ALREADYFRIEND;
|
||||||
delete stmt;
|
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<sql::PreparedStatement> statement(Database::CreatePreppedStmt("INSERT IGNORE INTO `friends` (`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?);"));
|
||||||
|
statement->setUInt(1, static_cast<uint32_t>(requestor->playerID));
|
||||||
|
statement->setUInt(2, static_cast<uint32_t>(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) {
|
void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||||
@ -145,50 +318,55 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
|||||||
LWOOBJID playerID;
|
LWOOBJID playerID;
|
||||||
inStream.Read(playerID);
|
inStream.Read(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.
|
//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:
|
//First, we need to find their ID:
|
||||||
auto stmt = Database::CreatePreppedStmt("select id from charinfo where name=? limit 1;");
|
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? LIMIT 1;"));
|
||||||
stmt->setString(1, friendName.c_str());
|
stmt->setString(1, friendName.c_str());
|
||||||
|
|
||||||
LWOOBJID friendID = 0;
|
LWOOBJID friendID = 0;
|
||||||
auto res = stmt->executeQuery();
|
std::unique_ptr<sql::ResultSet> res(stmt->executeQuery());
|
||||||
while (res->next()) {
|
while (res->next()) {
|
||||||
friendID = res->getUInt64(1);
|
friendID = res->getUInt(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete res;
|
// Convert friendID to LWOOBJID
|
||||||
delete stmt;
|
GeneralUtils::SetBit(friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_PERSISTENT));
|
||||||
|
GeneralUtils::SetBit(friendID, static_cast<size_t>(eObjectBits::OBJECT_BIT_CHARACTER));
|
||||||
|
|
||||||
//Set our bits to convert to the BIG BOY objectID.
|
std::unique_ptr<sql::PreparedStatement> deletestmt(Database::CreatePreppedStmt("DELETE FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"));
|
||||||
friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_CHARACTER);
|
deletestmt->setUInt(1, static_cast<uint32_t>(playerID));
|
||||||
friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_PERSISTENT);
|
deletestmt->setUInt(2, static_cast<uint32_t>(friendID));
|
||||||
|
deletestmt->setUInt(3, static_cast<uint32_t>(friendID));
|
||||||
//YEET:
|
deletestmt->setUInt(4, static_cast<uint32_t>(playerID));
|
||||||
auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1");
|
|
||||||
deletestmt->setUInt64(1, playerID);
|
|
||||||
deletestmt->setUInt64(2, friendID);
|
|
||||||
deletestmt->execute();
|
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:
|
//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);
|
auto goonA = playerContainer.GetPlayerData(playerID);
|
||||||
if (goonA) {
|
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);
|
SendRemoveFriend(goonA, friendName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto goonB = playerContainer.GetPlayerData(friendID);
|
auto goonB = playerContainer.GetPlayerData(friendID);
|
||||||
if (!goonB) return;
|
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));
|
std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID));
|
||||||
SendRemoveFriend(goonB, goonAName, true);
|
SendRemoveFriend(goonB, goonAName, true);
|
||||||
}
|
}
|
||||||
@ -206,7 +384,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
|||||||
|
|
||||||
if (playerContainer.GetIsMuted(sender)) return;
|
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);
|
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());
|
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<char*>(packet->data), packet->length);
|
|
||||||
|
|
||||||
if (channel != 8) return;
|
if (channel != 8) return;
|
||||||
|
|
||||||
auto* team = playerContainer.GetTeam(playerID);
|
auto* team = playerContainer.GetTeam(playerID);
|
||||||
@ -231,7 +407,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
|||||||
|
|
||||||
if (otherMember == nullptr) return;
|
if (otherMember == nullptr) return;
|
||||||
|
|
||||||
const auto otherName = std::string(otherMember->playerName.C_String());
|
const auto otherName = std::string(otherMember->playerName.c_str());
|
||||||
|
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
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;
|
if (playerContainer.GetIsMuted(goonA)) return;
|
||||||
|
|
||||||
std::string goonAName = goonA->playerName.C_String();
|
std::string goonAName = goonA->playerName.c_str();
|
||||||
std::string goonBName = goonB->playerName.C_String();
|
std::string goonBName = goonB->playerName.c_str();
|
||||||
|
|
||||||
//To the sender:
|
//To the sender:
|
||||||
{
|
{
|
||||||
@ -454,8 +630,6 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet)
|
|||||||
|
|
||||||
playerContainer.RemoveMember(team, kickedId, false, true, false);
|
playerContainer.RemoveMember(team, kickedId, false, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//PacketUtils::SavePacket("kick.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPacketHandler::HandleTeamPromote(Packet* packet)
|
void ChatPacketHandler::HandleTeamPromote(Packet* packet)
|
||||||
@ -481,8 +655,6 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet)
|
|||||||
|
|
||||||
playerContainer.PromoteMember(team, promoted->playerID);
|
playerContainer.PromoteMember(team, promoted->playerID);
|
||||||
}
|
}
|
||||||
|
|
||||||
//PacketUtils::SavePacket("promote.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
|
void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
|
||||||
@ -509,8 +681,6 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
|
|||||||
|
|
||||||
playerContainer.UpdateTeamsOnWorld(team, false);
|
playerContainer.UpdateTeamsOnWorld(team, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//PacketUtils::SavePacket("option.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
||||||
@ -550,7 +720,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
|||||||
|
|
||||||
playerContainer.TeamStatusUpdate(team);
|
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)
|
for (const auto memberId : team->memberIDs)
|
||||||
{
|
{
|
||||||
@ -560,7 +730,6 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
|||||||
|
|
||||||
const auto memberName = playerContainer.GetName(memberId);
|
const auto memberName = playerContainer.GetName(memberId);
|
||||||
|
|
||||||
//ChatPacketHandler::SendTeamAddPlayer(otherMember, false, false, false, data->playerID, leaderName, data->zoneID);
|
|
||||||
if (otherMember != nullptr)
|
if (otherMember != nullptr)
|
||||||
{
|
{
|
||||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
|
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
|
||||||
@ -581,7 +750,7 @@ void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender)
|
|||||||
//portion that will get routed:
|
//portion that will get routed:
|
||||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_TEAM_INVITE);
|
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);
|
bitStream.Write(sender->playerID);
|
||||||
|
|
||||||
SystemAddress sysAddr = receiver->sysAddr;
|
SystemAddress sysAddr = receiver->sysAddr;
|
||||||
@ -745,7 +914,7 @@ void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i
|
|||||||
SEND_PACKET;
|
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
|
/*chat notification is displayed if log in / out and friend is updated in friends list
|
||||||
[u8] - update type
|
[u8] - update type
|
||||||
Update types
|
Update types
|
||||||
@ -767,7 +936,7 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla
|
|||||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_UPDATE_FRIEND_NOTIFY);
|
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_UPDATE_FRIEND_NOTIFY);
|
||||||
bitStream.Write<uint8_t>(notifyType);
|
bitStream.Write<uint8_t>(notifyType);
|
||||||
|
|
||||||
std::string playerName = playerData->playerName.C_String();
|
std::string playerName = playerData->playerName.c_str();
|
||||||
|
|
||||||
PacketUtils::WritePacketWString(playerName, 33, &bitStream);
|
PacketUtils::WritePacketWString(playerName, 33, &bitStream);
|
||||||
|
|
||||||
@ -783,19 +952,20 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla
|
|||||||
bitStream.Write(playerData->zoneID.GetCloneID());
|
bitStream.Write(playerData->zoneID.GetCloneID());
|
||||||
}
|
}
|
||||||
|
|
||||||
bitStream.Write<uint8_t>(0); //isBFF
|
bitStream.Write<uint8_t>(isBestFriend); //isBFF
|
||||||
bitStream.Write<uint8_t>(0); //isFTP
|
bitStream.Write<uint8_t>(0); //isFTP
|
||||||
|
|
||||||
SystemAddress sysAddr = friendData->sysAddr;
|
SystemAddress sysAddr = friendData->sysAddr;
|
||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq) {
|
void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender) {
|
||||||
if (!receiver || !sender) return;
|
if (!receiver || !sender) return;
|
||||||
|
|
||||||
//Make sure people aren't requesting people that they're already friends with:
|
//Make sure people aren't requesting people that they're already friends with:
|
||||||
for (auto fr : receiver->friends) {
|
for (auto fr : receiver->friends) {
|
||||||
if (fr.friendID == sender->playerID) {
|
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.
|
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:
|
//portion that will get routed:
|
||||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_REQUEST);
|
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_REQUEST);
|
||||||
PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream);
|
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||||
bitStream.Write<uint8_t>(0);
|
bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
|
||||||
|
|
||||||
SystemAddress sysAddr = receiver->sysAddr;
|
SystemAddress sysAddr = receiver->sysAddr;
|
||||||
SEND_PACKET;
|
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;
|
if (!receiver || !sender) return;
|
||||||
|
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||||
bitStream.Write(receiver->playerID);
|
bitStream.Write(receiver->playerID);
|
||||||
|
|
||||||
//portion that will get routed:
|
// Portion that will get routed:
|
||||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_RESPONSE);
|
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_RESPONSE);
|
||||||
bitStream.Write<uint8_t>(responseCode);
|
bitStream.Write(responseCode);
|
||||||
bitStream.Write<uint8_t>(1); //isOnline
|
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
|
||||||
PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream);
|
bitStream.Write<uint8_t>(responseCode != AddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
bitStream.Write(sender->playerID);
|
// Then write the player name
|
||||||
bitStream.Write(sender->zoneID);
|
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||||
bitStream.Write<uint8_t>(0); //isBFF
|
// Then if this is an acceptance code, write the following extra info.
|
||||||
bitStream.Write<uint8_t>(0); //isFTP
|
if (responseCode == AddFriendResponseType::ACCEPTED) {
|
||||||
|
bitStream.Write(sender->playerID);
|
||||||
|
bitStream.Write(sender->zoneID);
|
||||||
|
bitStream.Write(isBestFriendRequest); //isBFF
|
||||||
|
bitStream.Write<uint8_t>(0); //isFTP
|
||||||
|
}
|
||||||
SystemAddress sysAddr = receiver->sysAddr;
|
SystemAddress sysAddr = receiver->sysAddr;
|
||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "BitStream.h"
|
#include "BitStream.h"
|
||||||
|
|
||||||
struct PlayerData;
|
struct PlayerData;
|
||||||
|
enum class AddFriendResponseType : uint8_t;
|
||||||
|
|
||||||
namespace ChatPacketHandler {
|
namespace ChatPacketHandler {
|
||||||
void HandleFriendlistRequest(Packet* packet);
|
void HandleFriendlistRequest(Packet* packet);
|
||||||
@ -31,10 +32,9 @@ namespace ChatPacketHandler {
|
|||||||
void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
|
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.
|
//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 SendFriendRequest(PlayerData* receiver, PlayerData* sender);
|
||||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode = 3);
|
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);
|
void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,17 +20,25 @@ PlayerContainer::~PlayerContainer() {
|
|||||||
void PlayerContainer::InsertPlayer(Packet* packet) {
|
void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||||
CINSTREAM;
|
CINSTREAM;
|
||||||
PlayerData* data = new PlayerData();
|
PlayerData* data = new PlayerData();
|
||||||
|
inStream.SetReadOffset(inStream.GetReadOffset() + 64);
|
||||||
inStream.Read(data->playerID);
|
inStream.Read(data->playerID);
|
||||||
inStream.Read(data->playerID);
|
|
||||||
inStream.Read(data->playerName);
|
uint32_t len;
|
||||||
|
inStream.Read<uint32_t>(len);
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
char character; inStream.Read<char>(character);
|
||||||
|
data->playerName += character;
|
||||||
|
}
|
||||||
|
|
||||||
inStream.Read(data->zoneID);
|
inStream.Read(data->zoneID);
|
||||||
inStream.Read(data->muteExpire);
|
inStream.Read(data->muteExpire);
|
||||||
data->sysAddr = packet->systemAddress;
|
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));
|
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 (?, ?, ?, ?);");
|
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);
|
inStream.Read(playerID);
|
||||||
|
|
||||||
//Before they get kicked, we need to also send a message to their friends saying that they disconnected.
|
//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<PlayerData> player(this->GetPlayerData(playerID));
|
||||||
|
|
||||||
if (player == nullptr) {
|
if (player == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& fr : player->friends) {
|
for (auto& fr : player->friends) {
|
||||||
//if (!fr.isOnline) continue;
|
|
||||||
|
|
||||||
auto fd = this->GetPlayerData(fr.friendID);
|
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);
|
auto* team = GetTeam(playerID);
|
||||||
|
|
||||||
if (team != nullptr)
|
if (team != nullptr)
|
||||||
{
|
{
|
||||||
//TeamStatusUpdate(team);
|
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.c_str()));
|
||||||
|
|
||||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.C_String()));
|
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs)
|
for (const auto memberId : team->memberIDs)
|
||||||
{
|
{
|
||||||
@ -77,7 +81,6 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
|||||||
if (otherMember == nullptr) continue;
|
if (otherMember == nullptr) continue;
|
||||||
|
|
||||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, {0, 0, 0});
|
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;
|
if (leader == nullptr || member == nullptr) return;
|
||||||
|
|
||||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String()));
|
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.c_str()));
|
||||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.C_String()));
|
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::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)
|
if (!team->local)
|
||||||
{
|
{
|
||||||
@ -348,7 +345,7 @@ void PlayerContainer::DisbandTeam(TeamData* team)
|
|||||||
|
|
||||||
if (otherMember == nullptr) continue;
|
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::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
|
||||||
ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember->playerID, memberName);
|
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;
|
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)
|
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);
|
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);
|
UpdateTeamsOnWorld(team, false);
|
||||||
|
@ -9,11 +9,12 @@
|
|||||||
|
|
||||||
struct PlayerData {
|
struct PlayerData {
|
||||||
LWOOBJID playerID;
|
LWOOBJID playerID;
|
||||||
RakNet::RakString playerName;
|
std::string playerName;
|
||||||
SystemAddress sysAddr;
|
SystemAddress sysAddr;
|
||||||
LWOZONEID zoneID;
|
LWOZONEID zoneID;
|
||||||
std::vector<FriendData> friends;
|
std::vector<FriendData> friends;
|
||||||
time_t muteExpire;
|
time_t muteExpire;
|
||||||
|
uint8_t countOfBestFriends = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TeamData {
|
struct TeamData {
|
||||||
@ -45,7 +46,7 @@ public:
|
|||||||
PlayerData* GetPlayerData(const std::string& playerName) {
|
PlayerData* GetPlayerData(const std::string& playerName) {
|
||||||
for (auto player : mPlayers) {
|
for (auto player : mPlayers) {
|
||||||
if (player.second) {
|
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;
|
if (pn == playerName) return player.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
dCommon/AddFriendResponseCode.h
Normal file
15
dCommon/AddFriendResponseCode.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __ADDFRIENDRESPONSECODE__H__
|
||||||
|
#define __ADDFRIENDRESPONSECODE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class AddFriendResponseCode : uint8_t {
|
||||||
|
ACCEPTED = 0,
|
||||||
|
REJECTED,
|
||||||
|
BUSY,
|
||||||
|
CANCELLED
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ADDFRIENDRESPONSECODE__H__
|
24
dCommon/AddFriendResponseType.h
Normal file
24
dCommon/AddFriendResponseType.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __ADDFRIENDRESPONSETYPE__H__
|
||||||
|
#define __ADDFRIENDRESPONSETYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
enum class AddFriendResponseType : uint8_t {
|
||||||
|
ACCEPTED = 0,
|
||||||
|
ALREADYFRIEND,
|
||||||
|
INVALIDCHARACTER,
|
||||||
|
GENERALERROR,
|
||||||
|
YOURFRIENDSLISTFULL,
|
||||||
|
THEIRFRIENDLISTFULL,
|
||||||
|
DECLINED,
|
||||||
|
BUSY,
|
||||||
|
NOTONLINE,
|
||||||
|
WAITINGAPPROVAL,
|
||||||
|
MYTHRAN,
|
||||||
|
CANCELLED,
|
||||||
|
FRIENDISFREETRIAL
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__ADDFRIENDRESPONSETYPE__H__
|
26
dCommon/CMakeLists.txt
Normal file
26
dCommon/CMakeLists.txt
Normal file
@ -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()
|
@ -188,3 +188,53 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream *inStream) {
|
|||||||
|
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
std::vector<std::string> GeneralUtils::GetFileNamesFromFolder(const std::string& folder)
|
||||||
|
{
|
||||||
|
std::vector<std::string> 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 <stdio.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
std::vector<std::string> GeneralUtils::GetFileNamesFromFolder(const std::string& folder) {
|
||||||
|
std::vector<std::string> 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
|
@ -128,6 +128,8 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
||||||
|
|
||||||
|
std::vector<std::string> GetFileNamesFromFolder(const std::string& folder);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Parse(const char* value);
|
T Parse(const char* value);
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ LDFBaseData * LDFBaseData::DataFromString(const std::string& format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case LDF_TYPE_S32: {
|
case LDF_TYPE_S32: {
|
||||||
int32_t data = static_cast<int32_t>(stol(dataArray[1]));
|
int32_t data = static_cast<int32_t>(stoull(dataArray[1]));
|
||||||
return new LDFData<int32_t>(key, data);
|
return new LDFData<int32_t>(key, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "ZCompression.h"
|
#include "ZCompression.h"
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
namespace ZCompression
|
namespace ZCompression
|
||||||
@ -70,4 +72,6 @@ namespace ZCompression
|
|||||||
return(nRet); // -1 or len of output
|
return(nRet); // -1 or len of output
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "dPlatforms.h"
|
||||||
|
|
||||||
|
#ifndef DARKFLAME_PLATFORM_WIN32
|
||||||
|
|
||||||
namespace ZCompression
|
namespace ZCompression
|
||||||
{
|
{
|
||||||
int32_t GetMaxCompressedLength(int32_t nLenSrc);
|
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);
|
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -407,14 +407,20 @@ enum eReplicaComponentType : int32_t {
|
|||||||
COMPONENT_TYPE_MISSION = 84, //!< The Mission Component
|
COMPONENT_TYPE_MISSION = 84, //!< The Mission Component
|
||||||
COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen
|
COMPONENT_TYPE_ROCKET_LAUNCH_LUP = 97, //!< The LUP Launchpad Componen
|
||||||
COMPONENT_TYPE_RAIL_ACTIVATOR = 104,
|
COMPONENT_TYPE_RAIL_ACTIVATOR = 104,
|
||||||
COMPONENT_TYPE_POSSESSOR = 107, //!< The Component 107
|
COMPONENT_TYPE_POSSESSABLE = 108, //!< The Possessable Component
|
||||||
COMPONENT_TYPE_POSSESSABLE = 108, //!< The Component 108
|
COMPONENT_TYPE_POSSESSOR = 110, //!< The Possessor Component
|
||||||
COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component
|
COMPONENT_TYPE_BUILD_BORDER = 114, //!< The Build Border Component
|
||||||
COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component
|
COMPONENT_TYPE_DESTROYABLE = 1000, //!< The Destroyable Component
|
||||||
|
|
||||||
COMPONENT_TYPE_MODEL = 5398484 //look man idk
|
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
|
* Represents the different types of inventories an entity may have
|
||||||
*/
|
*/
|
||||||
@ -434,33 +440,6 @@ enum eInventoryType : uint32_t {
|
|||||||
INVALID // made up, for internal use!!!
|
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 {
|
enum eRebuildState : uint32_t {
|
||||||
REBUILD_OPEN,
|
REBUILD_OPEN,
|
||||||
REBUILD_COMPLETED = 2,
|
REBUILD_COMPLETED = 2,
|
||||||
@ -658,7 +637,6 @@ enum ePlayerFlags {
|
|||||||
NJ_WU_SHOW_DAILY_CHEST = 2099
|
NJ_WU_SHOW_DAILY_CHEST = 2099
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//======== FUNC ===========
|
//======== FUNC ===========
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
29
dCommon/dPlatforms.h
Normal file
29
dCommon/dPlatforms.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define DARKFLAME_PLATFORM_WIN32
|
||||||
|
#elif defined(__APPLE__) && defined(__MACH__)
|
||||||
|
#include <TargetConditionals.h>
|
||||||
|
#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
|
44
dCommon/eAninmationFlags.h
Normal file
44
dCommon/eAninmationFlags.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __EANINMATIONFLAGS__H__
|
||||||
|
#define __EANINMATIONFLAGS__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
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__
|
36
dCommon/eItemType.h
Normal file
36
dCommon/eItemType.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __EITEMTYPE__H__
|
||||||
|
#define __EITEMTYPE__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
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__
|
@ -13,3 +13,8 @@ void CDClientDatabase::Connect(const std::string& filename) {
|
|||||||
CppSQLite3Query CDClientDatabase::ExecuteQuery(const std::string& query) {
|
CppSQLite3Query CDClientDatabase::ExecuteQuery(const std::string& query) {
|
||||||
return conn->execQuery(query.c_str());
|
return conn->execQuery(query.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Makes prepared statements
|
||||||
|
CppSQLite3Statement CDClientDatabase::CreatePreppedStmt(const std::string& query) {
|
||||||
|
return conn->compileStatement(query.c_str());
|
||||||
|
}
|
||||||
|
@ -40,4 +40,10 @@ namespace CDClientDatabase {
|
|||||||
*/
|
*/
|
||||||
CppSQLite3Query ExecuteQuery(const std::string& query);
|
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);
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ void CDClientManager::Initialize(void) {
|
|||||||
tables.insert(std::make_pair("ActivityRewards", new CDActivityRewardsTable()));
|
tables.insert(std::make_pair("ActivityRewards", new CDActivityRewardsTable()));
|
||||||
UNUSED(tables.insert(std::make_pair("Animations", new CDAnimationsTable())));
|
UNUSED(tables.insert(std::make_pair("Animations", new CDAnimationsTable())));
|
||||||
tables.insert(std::make_pair("BehaviorParameter", new CDBehaviorParameterTable()));
|
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("ComponentsRegistry", new CDComponentsRegistryTable()));
|
||||||
tables.insert(std::make_pair("CurrencyTable", new CDCurrencyTableTable()));
|
tables.insert(std::make_pair("CurrencyTable", new CDCurrencyTableTable()));
|
||||||
tables.insert(std::make_pair("DestructibleComponent", new CDDestructibleComponentTable()));
|
tables.insert(std::make_pair("DestructibleComponent", new CDDestructibleComponentTable()));
|
||||||
|
13
dDatabase/CMakeLists.txt
Normal file
13
dDatabase/CMakeLists.txt
Normal file
@ -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)
|
@ -8,9 +8,10 @@ using namespace std;
|
|||||||
|
|
||||||
sql::Driver * Database::driver;
|
sql::Driver * Database::driver;
|
||||||
sql::Connection * Database::con;
|
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) {
|
void Database::Connect(const string& host, const string& database, const string& username, const string& password) {
|
||||||
driver = get_driver_instance();
|
|
||||||
|
|
||||||
//To bypass debug issues:
|
//To bypass debug issues:
|
||||||
std::string newHost = "tcp://" + host;
|
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* szUsername = username.c_str();
|
||||||
const char* szPassword = password.c_str();
|
const char* szPassword = password.c_str();
|
||||||
|
|
||||||
con = driver->connect(szHost, szUsername, szPassword);
|
driver = sql::mariadb::get_driver_instance();
|
||||||
con->setSchema(szDatabase);
|
|
||||||
|
|
||||||
bool myTrue = true;
|
sql::Properties properties;
|
||||||
con->setClientOption("MYSQL_OPT_RECONNECT", &myTrue);
|
properties["hostName"] = szHost;
|
||||||
} //Connect
|
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 (!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();
|
con->close();
|
||||||
delete con;
|
delete con;
|
||||||
} //Destroy
|
} //Destroy
|
||||||
@ -45,13 +62,7 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
|
|||||||
sql::SQLString str(test, size);
|
sql::SQLString str(test, size);
|
||||||
|
|
||||||
if (!con) {
|
if (!con) {
|
||||||
//Connect to the MySQL Database
|
Connect();
|
||||||
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);
|
|
||||||
Game::logger->Log("Database", "Trying to reconnect to MySQL\n");
|
Game::logger->Log("Database", "Trying to reconnect to MySQL\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,17 +72,15 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
|
|||||||
|
|
||||||
con = nullptr;
|
con = nullptr;
|
||||||
|
|
||||||
//Connect to the MySQL Database
|
Connect();
|
||||||
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);
|
|
||||||
Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection\n");
|
Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* stmt = con->prepareStatement(str);
|
auto* stmt = con->prepareStatement(str);
|
||||||
|
|
||||||
return stmt;
|
return stmt;
|
||||||
} //CreatePreppedStmt
|
} //CreatePreppedStmt
|
||||||
|
|
||||||
|
void Database::Commit() {
|
||||||
|
Database::con->commit();
|
||||||
|
}
|
@ -1,13 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <mysql_connection.h>
|
#include <conncpp.hpp>
|
||||||
#include <cppconn/driver.h>
|
|
||||||
#include <cppconn/exception.h>
|
|
||||||
#include <cppconn/resultset.h>
|
|
||||||
#include <cppconn/statement.h>
|
|
||||||
#include <cppconn/prepared_statement.h>
|
|
||||||
#include <cppconn/sqlstring.h>
|
|
||||||
|
|
||||||
class MySqlException : public std::runtime_error {
|
class MySqlException : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
@ -19,10 +13,17 @@ class Database {
|
|||||||
private:
|
private:
|
||||||
static sql::Driver *driver;
|
static sql::Driver *driver;
|
||||||
static sql::Connection *con;
|
static sql::Connection *con;
|
||||||
|
static sql::Properties props;
|
||||||
|
static std::string database;
|
||||||
public:
|
public:
|
||||||
static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password);
|
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::Statement* CreateStmt();
|
||||||
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
|
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
|
||||||
|
static void Commit();
|
||||||
|
|
||||||
|
static std::string GetDatabase() { return database; }
|
||||||
|
static sql::Properties GetProperties() { return props; }
|
||||||
};
|
};
|
||||||
|
78
dDatabase/MigrationRunner.cpp
Normal file
78
dDatabase/MigrationRunner.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include "MigrationRunner.h"
|
||||||
|
|
||||||
|
#include "GeneralUtils.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
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<std::string> hash;
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::string total = "";
|
||||||
|
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
total += line;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
migration.name = path;
|
||||||
|
migration.data = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
return migration;
|
||||||
|
}
|
19
dDatabase/MigrationRunner.h
Normal file
19
dDatabase/MigrationRunner.h
Normal file
@ -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);
|
||||||
|
};
|
@ -3,33 +3,31 @@
|
|||||||
|
|
||||||
//! Constructor
|
//! Constructor
|
||||||
CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
|
CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
|
||||||
#ifdef CDCLIENT_CACHE_ALL
|
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
|
||||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
|
size_t hash = 0;
|
||||||
while (!tableData.eof()) {
|
while (!tableData.eof()) {
|
||||||
CDBehaviorParameter entry;
|
hash = 0;
|
||||||
entry.behaviorID = tableData.getIntField(0, -1);
|
CDBehaviorParameter entry;
|
||||||
entry.parameterID = tableData.getStringField(1, "");
|
entry.behaviorID = tableData.getIntField(0, -1);
|
||||||
entry.value = tableData.getFloatField(2, -1.0f);
|
auto candidateStringToAdd = std::string(tableData.getStringField(1, ""));
|
||||||
|
auto parameter = m_ParametersList.find(candidateStringToAdd);
|
||||||
//Check if we have an entry with this ID:
|
if (parameter != m_ParametersList.end()) {
|
||||||
auto it = m_entries.find(entry.behaviorID);
|
entry.parameterID = parameter;
|
||||||
if (it != m_entries.end()) {
|
} else {
|
||||||
it->second.insert(std::make_pair(entry.parameterID, entry.value));
|
entry.parameterID = m_ParametersList.insert(candidateStringToAdd).first;
|
||||||
}
|
}
|
||||||
else {
|
entry.value = tableData.getFloatField(2, -1.0f);
|
||||||
//Otherwise, insert it:
|
|
||||||
m_entries.insert(std::make_pair(entry.behaviorID, std::map<std::string, float>()));
|
|
||||||
auto jit = m_entries.find(entry.behaviorID);
|
|
||||||
|
|
||||||
//Add our value as well:
|
GeneralUtils::hash_combine(hash, entry.behaviorID);
|
||||||
jit->second.insert(std::make_pair(entry.parameterID, entry.value));
|
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();
|
tableData.finalize();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Destructor
|
//! Destructor
|
||||||
@ -37,54 +35,36 @@ CDBehaviorParameterTable::~CDBehaviorParameterTable(void) { }
|
|||||||
|
|
||||||
//! Returns the table's name
|
//! Returns the table's name
|
||||||
std::string CDBehaviorParameterTable::GetName(void) const {
|
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;
|
size_t hash = 0;
|
||||||
GeneralUtils::hash_combine(hash, behaviorID);
|
GeneralUtils::hash_combine(hash, behaviorID);
|
||||||
GeneralUtils::hash_combine(hash, name);
|
GeneralUtils::hash_combine(hash, name);
|
||||||
|
|
||||||
// Search for specific parameter
|
// Search for specific parameter
|
||||||
const auto& it = m_Entries.find(hash);
|
const auto& it = m_Entries.find(hash);
|
||||||
if (it != m_Entries.end()) {
|
return it != m_Entries.end() ? it->second : returnValue;
|
||||||
return it->second;
|
}
|
||||||
}
|
|
||||||
|
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
|
||||||
// Check if this behavior has already been checked
|
size_t hash;
|
||||||
const auto& itChecked = m_Entries.find(behaviorID);
|
std::map<std::string, float> returnInfo;
|
||||||
if (itChecked != m_Entries.end()) {
|
for (auto parameterCandidate : m_ParametersList) {
|
||||||
return defaultValue;
|
hash = 0;
|
||||||
}
|
GeneralUtils::hash_combine(hash, behaviorID);
|
||||||
|
GeneralUtils::hash_combine(hash, parameterCandidate);
|
||||||
#ifndef CDCLIENT_CACHE_ALL
|
auto infoCandidate = m_Entries.find(hash);
|
||||||
std::stringstream query;
|
if (infoCandidate != m_Entries.end()) {
|
||||||
|
returnInfo.insert(std::make_pair(*(infoCandidate->second.parameterID), infoCandidate->second.value));
|
||||||
query << "SELECT parameterID, value FROM BehaviorParameter WHERE behaviorID = " << std::to_string(behaviorID);
|
}
|
||||||
|
}
|
||||||
auto tableData = CDClientDatabase::ExecuteQuery(query.str());
|
return returnInfo;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
// Custom Classes
|
// Custom Classes
|
||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\file CDBehaviorParameterTable.hpp
|
\file CDBehaviorParameterTable.hpp
|
||||||
@ -11,16 +12,16 @@
|
|||||||
|
|
||||||
//! BehaviorParameter Entry Struct
|
//! BehaviorParameter Entry Struct
|
||||||
struct CDBehaviorParameter {
|
struct CDBehaviorParameter {
|
||||||
unsigned int behaviorID; //!< The Behavior ID
|
unsigned int behaviorID; //!< The Behavior ID
|
||||||
std::string parameterID; //!< The Parameter ID
|
std::unordered_set<std::string>::iterator parameterID; //!< The Parameter ID
|
||||||
float value; //!< The value of the behavior template
|
float value; //!< The value of the behavior template
|
||||||
};
|
};
|
||||||
|
|
||||||
//! BehaviorParameter table
|
//! BehaviorParameter table
|
||||||
class CDBehaviorParameterTable : public CDTable {
|
class CDBehaviorParameterTable : public CDTable {
|
||||||
private:
|
private:
|
||||||
std::map<size_t, float> m_Entries;
|
std::unordered_map<size_t, CDBehaviorParameter> m_Entries;
|
||||||
|
std::unordered_set<std::string> m_ParametersList;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Constructor
|
//! Constructor
|
||||||
@ -35,5 +36,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
std::string GetName(void) const override;
|
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<std::string, float> GetParametersByBehaviorID(uint32_t behaviorID);
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,7 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
|
|||||||
|
|
||||||
// Reserve the size
|
// Reserve the size
|
||||||
this->entries.reserve(size);
|
this->entries.reserve(size);
|
||||||
|
|
||||||
// Now get the data
|
// Now get the data
|
||||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
|
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
|
||||||
while (!tableData.eof()) {
|
while (!tableData.eof()) {
|
||||||
@ -24,9 +24,16 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
|
|||||||
entry.behaviorID = tableData.getIntField(0, -1);
|
entry.behaviorID = tableData.getIntField(0, -1);
|
||||||
entry.templateID = tableData.getIntField(1, -1);
|
entry.templateID = tableData.getIntField(1, -1);
|
||||||
entry.effectID = tableData.getIntField(2, -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->entries.push_back(entry);
|
||||||
|
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
|
||||||
tableData.nextRow();
|
tableData.nextRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,3 +62,16 @@ std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<boo
|
|||||||
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
|
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
|
||||||
return this->entries;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
// Custom Classes
|
// Custom Classes
|
||||||
#include "CDTable.h"
|
#include "CDTable.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\file CDBehaviorTemplateTable.hpp
|
\file CDBehaviorTemplateTable.hpp
|
||||||
@ -10,10 +12,10 @@
|
|||||||
|
|
||||||
//! BehaviorTemplate Entry Struct
|
//! BehaviorTemplate Entry Struct
|
||||||
struct CDBehaviorTemplate {
|
struct CDBehaviorTemplate {
|
||||||
unsigned int behaviorID; //!< The Behavior ID
|
unsigned int behaviorID; //!< The Behavior ID
|
||||||
unsigned int templateID; //!< The Template ID (LOT)
|
unsigned int templateID; //!< The Template ID (LOT)
|
||||||
unsigned int effectID; //!< The Effect ID attached
|
unsigned int effectID; //!< The Effect ID attached
|
||||||
std::string effectHandle; //!< The effect handle
|
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -21,7 +23,8 @@ struct CDBehaviorTemplate {
|
|||||||
class CDBehaviorTemplateTable : public CDTable {
|
class CDBehaviorTemplateTable : public CDTable {
|
||||||
private:
|
private:
|
||||||
std::vector<CDBehaviorTemplate> entries;
|
std::vector<CDBehaviorTemplate> entries;
|
||||||
|
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
|
||||||
|
std::unordered_set<std::string> m_EffectHandles;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//! Constructor
|
//! Constructor
|
||||||
@ -47,5 +50,6 @@ public:
|
|||||||
\return The entries
|
\return The entries
|
||||||
*/
|
*/
|
||||||
std::vector<CDBehaviorTemplate> GetEntries(void) const;
|
std::vector<CDBehaviorTemplate> GetEntries(void) const;
|
||||||
|
|
||||||
|
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
|
||||||
};
|
};
|
||||||
|
@ -168,7 +168,7 @@ std::map<LOT, uint32_t> CDItemComponentTable::ParseCraftingCurrencies(const CDIt
|
|||||||
// Checking for 2 here, not sure what to do when there's more stuff than expected
|
// Checking for 2 here, not sure what to do when there's more stuff than expected
|
||||||
if (amountSplit.size() == 2) {
|
if (amountSplit.size() == 2) {
|
||||||
currencies.insert({
|
currencies.insert({
|
||||||
std::stol(amountSplit[0]),
|
std::stoull(amountSplit[0]),
|
||||||
std::stoi(amountSplit[1])
|
std::stoi(amountSplit[1])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
38
dDatabase/Tables/CMakeLists.txt
Normal file
38
dDatabase/Tables/CMakeLists.txt
Normal file
@ -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)
|
59
dGame/CMakeLists.txt
Normal file
59
dGame/CMakeLists.txt
Normal file
@ -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)
|
120
dGame/Entity.cpp
120
dGame/Entity.cpp
@ -79,6 +79,7 @@ Entity::Entity(const LWOOBJID& objectID, EntityInfo info, Entity* parentEntity)
|
|||||||
m_Components = {};
|
m_Components = {};
|
||||||
m_DieCallbacks = {};
|
m_DieCallbacks = {};
|
||||||
m_PhantomCollisionCallbacks = {};
|
m_PhantomCollisionCallbacks = {};
|
||||||
|
m_IsParentChildDirty = true;
|
||||||
|
|
||||||
m_Settings = info.settings;
|
m_Settings = info.settings;
|
||||||
m_NetworkSettings = info.networkSettings;
|
m_NetworkSettings = info.networkSettings;
|
||||||
@ -98,22 +99,6 @@ Entity::~Entity() {
|
|||||||
m_Character->SaveXMLToDatabase();
|
m_Character->SaveXMLToDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsPlayer()) {
|
|
||||||
Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity();
|
|
||||||
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) {
|
|
||||||
script->OnPlayerExit(zoneControl, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Entity*> 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();
|
CancelAllTimers();
|
||||||
CancelCallbackTimers();
|
CancelCallbackTimers();
|
||||||
|
|
||||||
@ -124,6 +109,14 @@ Entity::~Entity() {
|
|||||||
|
|
||||||
m_Components.erase(pair.first);
|
m_Components.erase(pair.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto child : m_ChildEntities) {
|
||||||
|
if (child) child->RemoveParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ParentEntity) {
|
||||||
|
m_ParentEntity->RemoveChild(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::Initialize()
|
void Entity::Initialize()
|
||||||
@ -220,8 +213,9 @@ void Entity::Initialize()
|
|||||||
m_Components.insert(std::make_pair(COMPONENT_TYPE_ZONE_CONTROL, nullptr));
|
m_Components.insert(std::make_pair(COMPONENT_TYPE_ZONE_CONTROL, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_POSSESSABLE) > 0) {
|
uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, COMPONENT_TYPE_POSSESSABLE);
|
||||||
m_Components.insert(std::make_pair(COMPONENT_TYPE_POSSESSABLE, new PossessableComponent(this)));
|
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) {
|
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) {
|
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);
|
CharacterComponent* comp = new CharacterComponent(this, m_Character);
|
||||||
m_Components.insert(std::make_pair(COMPONENT_TYPE_CHARACTER, comp));
|
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->SetPostImaginationCost(rebCompData[0].post_imagination_cost);
|
||||||
comp->SetTimeBeforeSmash(rebCompData[0].time_before_smash);
|
comp->SetTimeBeforeSmash(rebCompData[0].time_before_smash);
|
||||||
|
|
||||||
const auto rebuildActivatorValue = GetVarAsString(u"rebuild_activators");
|
|
||||||
|
|
||||||
if (!rebuildActivatorValue.empty()) {
|
|
||||||
std::vector<std::string> 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<float>(u"rebuild_reset_time");
|
const auto rebuildResetTime = GetVar<float>(u"rebuild_reset_time");
|
||||||
|
|
||||||
if (rebuildResetTime != 0.0f) {
|
if (rebuildResetTime != 0.0f) {
|
||||||
@ -631,10 +614,6 @@ void Entity::Initialize()
|
|||||||
m_Components.insert(std::make_pair(COMPONENT_TYPE_RENDER, render));
|
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) {
|
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)));
|
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
|
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);
|
outBitStream->Write(m_ParentEntity != nullptr);
|
||||||
if (m_ParentEntity) {
|
if (m_ParentEntity) {
|
||||||
outBitStream->Write(m_ParentEntity->GetObjectID());
|
outBitStream->Write(m_ParentEntity->GetObjectID());
|
||||||
@ -1079,8 +1061,15 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
|||||||
}
|
}
|
||||||
|
|
||||||
CharacterComponent* characterComponent;
|
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);
|
characterComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1186,11 +1175,10 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
|||||||
outBitStream->Write<uint32_t>(0x40000000);
|
outBitStream->Write<uint32_t>(0x40000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
PossessorComponent* possessorComponent;
|
// BBB Component, unused currently
|
||||||
if (TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent))
|
// Need to to write0 so that is serlaizese correctly
|
||||||
{
|
// TODO: Implement BBB Component
|
||||||
possessorComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
outBitStream->Write0();
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (m_Trigger != nullptr)
|
if (m_Trigger != nullptr)
|
||||||
@ -1218,17 +1206,21 @@ void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Entity::Update(const float deltaTime) {
|
void Entity::Update(const float deltaTime) {
|
||||||
for (int i = 0; i < m_Timers.size(); i++) {
|
uint32_t timerPosition;
|
||||||
m_Timers[i]->Update(deltaTime);
|
timerPosition = 0;
|
||||||
if (m_Timers[i]->GetTime() <= 0) {
|
while (timerPosition < m_Timers.size()) {
|
||||||
const auto timerName = m_Timers[i]->GetName();
|
m_Timers[timerPosition]->Update(deltaTime);
|
||||||
|
if (m_Timers[timerPosition]->GetTime() <= 0) {
|
||||||
|
const auto timerName = m_Timers[timerPosition]->GetName();
|
||||||
|
|
||||||
delete m_Timers[i];
|
delete m_Timers[timerPosition];
|
||||||
m_Timers.erase(m_Timers.begin() + i);
|
m_Timers.erase(m_Timers.begin() + timerPosition);
|
||||||
|
|
||||||
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
|
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
|
||||||
script->OnTimerDone(this, timerName);
|
script->OnTimerDone(this, timerName);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
timerPosition++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1240,6 +1232,14 @@ void Entity::Update(const float deltaTime) {
|
|||||||
m_CallbackTimers.erase(m_CallbackTimers.begin() + i);
|
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())
|
if (IsSleeping())
|
||||||
{
|
{
|
||||||
@ -1661,12 +1661,30 @@ void Entity::RegisterCoinDrop(uint64_t count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Entity::AddChild(Entity* child) {
|
void Entity::AddChild(Entity* child) {
|
||||||
|
m_IsParentChildDirty = true;
|
||||||
m_ChildEntities.push_back(child);
|
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) {
|
void Entity::AddTimer(std::string name, float time) {
|
||||||
EntityTimer* timer = new EntityTimer(name, time);
|
EntityTimer* timer = new EntityTimer(name, time);
|
||||||
m_Timers.push_back(timer);
|
m_PendingTimers.push_back(timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::AddCallbackTimer(float time, std::function<void()> callback) {
|
void Entity::AddCallbackTimer(float time, std::function<void()> callback) {
|
||||||
|
@ -143,6 +143,8 @@ public:
|
|||||||
void SetProximityRadius(dpEntity* entity, std::string name);
|
void SetProximityRadius(dpEntity* entity, std::string name);
|
||||||
|
|
||||||
void AddChild(Entity* child);
|
void AddChild(Entity* child);
|
||||||
|
void RemoveChild(Entity* child);
|
||||||
|
void RemoveParent();
|
||||||
void AddTimer(std::string name, float time);
|
void AddTimer(std::string name, float time);
|
||||||
void AddCallbackTimer(float time, std::function<void()> callback);
|
void AddCallbackTimer(float time, std::function<void()> callback);
|
||||||
bool HasTimer(const std::string& name);
|
bool HasTimer(const std::string& name);
|
||||||
@ -308,6 +310,7 @@ protected:
|
|||||||
|
|
||||||
std::unordered_map<int32_t, Component*> m_Components; //The int is the ID of the component
|
std::unordered_map<int32_t, Component*> m_Components; //The int is the ID of the component
|
||||||
std::vector<EntityTimer*> m_Timers;
|
std::vector<EntityTimer*> m_Timers;
|
||||||
|
std::vector<EntityTimer*> m_PendingTimers;
|
||||||
std::vector<EntityCallbackTimer*> m_CallbackTimers;
|
std::vector<EntityCallbackTimer*> m_CallbackTimers;
|
||||||
|
|
||||||
bool m_ShouldDestroyAfterUpdate = false;
|
bool m_ShouldDestroyAfterUpdate = false;
|
||||||
@ -322,6 +325,8 @@ protected:
|
|||||||
|
|
||||||
int8_t m_Observers = 0;
|
int8_t m_Observers = 0;
|
||||||
|
|
||||||
|
bool m_IsParentChildDirty = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Collision
|
* Collision
|
||||||
*/
|
*/
|
||||||
|
@ -217,37 +217,42 @@ void EntityManager::UpdateEntities(const float deltaTime) {
|
|||||||
|
|
||||||
m_EntitiesToKill.clear();
|
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 we are a player run through the player destructor.
|
||||||
}
|
if (entityToDelete->IsPlayer())
|
||||||
|
|
||||||
if (entity != nullptr)
|
|
||||||
{
|
|
||||||
if (entity->GetNetworkId() != 0)
|
|
||||||
{
|
{
|
||||||
m_LostNetworkIds.push(entity->GetNetworkId());
|
delete dynamic_cast<Player*>(entityToDelete);
|
||||||
}
|
|
||||||
|
|
||||||
if (entity->IsPlayer())
|
|
||||||
{
|
|
||||||
delete dynamic_cast<Player*>(entity);
|
|
||||||
}
|
}
|
||||||
else
|
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();
|
m_EntitiesToDelete.clear();
|
||||||
@ -396,7 +401,7 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr
|
|||||||
Game::server->Send(&stream, sysAddr, false);
|
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())
|
if (entity->IsPlayer())
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
#include "Character.h"
|
#include "Character.h"
|
||||||
|
#include "Game.h"
|
||||||
#include "GameMessages.h"
|
#include "GameMessages.h"
|
||||||
#include "dLogger.h"
|
#include "dLogger.h"
|
||||||
|
#include "dConfig.h"
|
||||||
|
|
||||||
Leaderboard::Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector<LeaderboardEntry> entries,
|
Leaderboard::Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector<LeaderboardEntry> entries,
|
||||||
LWOOBJID relatedPlayer, LeaderboardType leaderboardType) {
|
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 storedTime = result->getInt(1);
|
||||||
const auto storedScore = result->getInt(2);
|
const auto storedScore = result->getInt(2);
|
||||||
auto highscore = true;
|
auto highscore = true;
|
||||||
|
bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1";
|
||||||
|
|
||||||
switch (leaderboardType) {
|
switch (leaderboardType) {
|
||||||
case ShootingGallery:
|
case ShootingGallery:
|
||||||
@ -97,8 +100,11 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t
|
|||||||
highscore = false;
|
highscore = false;
|
||||||
break;
|
break;
|
||||||
case Racing:
|
case Racing:
|
||||||
|
if (time >= storedTime)
|
||||||
|
highscore = false;
|
||||||
|
break;
|
||||||
case MonumentRace:
|
case MonumentRace:
|
||||||
if (time > storedTime)
|
if (time >= storedTime)
|
||||||
highscore = false;
|
highscore = false;
|
||||||
break;
|
break;
|
||||||
case FootRace:
|
case FootRace:
|
||||||
@ -106,8 +112,18 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t
|
|||||||
highscore = false;
|
highscore = false;
|
||||||
break;
|
break;
|
||||||
case Survival:
|
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:
|
case SurvivalNS:
|
||||||
if (score < storedScore || time >= storedTime)
|
if (!(score > storedScore || (time < storedTime && score >= storedScore)))
|
||||||
highscore = false;
|
highscore = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -125,7 +141,7 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t
|
|||||||
delete result;
|
delete result;
|
||||||
|
|
||||||
if (any) {
|
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(1, time);
|
||||||
statement->setInt(2, score);
|
statement->setInt(2, score);
|
||||||
statement->setUInt64(3, character->GetID());
|
statement->setUInt64(3, character->GetID());
|
||||||
@ -134,6 +150,7 @@ void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t
|
|||||||
|
|
||||||
delete statement;
|
delete statement;
|
||||||
} else {
|
} 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 (?, ?, ?, ?);");
|
auto* statement = Database::CreatePreppedStmt("INSERT INTO leaderboard (character_id, game_id, time, score) VALUES (?, ?, ?, ?);");
|
||||||
statement->setUInt64(1, character->GetID());
|
statement->setUInt64(1, character->GetID());
|
||||||
statement->setInt(2, gameID);
|
statement->setInt(2, gameID);
|
||||||
@ -149,15 +166,62 @@ Leaderboard *LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoTy
|
|||||||
auto leaderboardType = GetLeaderboardType(gameID);
|
auto leaderboardType = GetLeaderboardType(gameID);
|
||||||
|
|
||||||
std::string query;
|
std::string query;
|
||||||
|
bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1";
|
||||||
switch (infoType) {
|
switch (infoType) {
|
||||||
case InfoType::Standings:
|
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;
|
break;
|
||||||
case InfoType::Friends:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
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);
|
auto* statement = Database::CreatePreppedStmt(query);
|
||||||
@ -183,14 +247,15 @@ Leaderboard *LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoTy
|
|||||||
|
|
||||||
uint32_t index = 0;
|
uint32_t index = 0;
|
||||||
while (res->next()) {
|
while (res->next()) {
|
||||||
entries.push_back({
|
LeaderboardEntry entry;
|
||||||
res->getUInt64(4),
|
entry.playerID = res->getUInt64(4);
|
||||||
res->getString(5),
|
entry.playerName = res->getString(5);
|
||||||
res->getUInt(1),
|
entry.time = res->getUInt(1);
|
||||||
res->getUInt(2),
|
entry.score = res->getUInt(2);
|
||||||
res->getUInt(3),
|
entry.placement = res->getUInt(3);
|
||||||
res->getUInt(6)
|
entry.lastPlayed = res->getUInt(6);
|
||||||
});
|
|
||||||
|
entries.push_back(entry);
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +285,7 @@ LeaderboardType LeaderboardManager::GetLeaderboardType(uint32_t gameID) {
|
|||||||
return LeaderboardType::None;
|
return LeaderboardType::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string LeaderboardManager::topPlayersQuery =
|
const std::string LeaderboardManager::topPlayersScoreQuery =
|
||||||
"WITH leaderboard_vales AS ( "
|
"WITH leaderboard_vales AS ( "
|
||||||
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
|
" 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 "
|
"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 "
|
"SELECT time, score, leaderboard_rank, id, name, last_played "
|
||||||
"FROM leaderboard_vales LIMIT 11;";
|
"FROM leaderboard_vales LIMIT 11;";
|
||||||
|
|
||||||
const std::string LeaderboardManager::friendsQuery =
|
const std::string LeaderboardManager::friendsScoreQuery =
|
||||||
"WITH leaderboard_vales AS ( "
|
"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, "
|
" 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 "
|
" 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 "
|
"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);";
|
"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 ( "
|
"WITH leaderboard_vales AS ( "
|
||||||
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
|
" 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 "
|
" 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 "
|
"FROM leaderboard_vales, personal_values "
|
||||||
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
|
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
|
||||||
|
|
||||||
const std::string LeaderboardManager::topPlayersQueryAsc =
|
const std::string LeaderboardManager::topPlayersScoreQueryAsc =
|
||||||
"WITH leaderboard_vales AS ( "
|
"WITH leaderboard_vales AS ( "
|
||||||
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
|
" 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 "
|
"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 "
|
"SELECT time, score, leaderboard_rank, id, name, last_played "
|
||||||
"FROM leaderboard_vales LIMIT 11;";
|
"FROM leaderboard_vales LIMIT 11;";
|
||||||
|
|
||||||
const std::string LeaderboardManager::friendsQueryAsc =
|
const std::string LeaderboardManager::friendsScoreQueryAsc =
|
||||||
"WITH leaderboard_vales AS ( "
|
"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, "
|
" 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 "
|
" 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 "
|
"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);";
|
"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 ( "
|
"WITH leaderboard_vales AS ( "
|
||||||
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
|
" 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 "
|
" 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 "
|
"SELECT time, score, leaderboard_rank, id, name, last_played "
|
||||||
"FROM leaderboard_vales, personal_values "
|
"FROM leaderboard_vales, personal_values "
|
||||||
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
|
"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;";
|
||||||
|
@ -60,11 +60,21 @@ public:
|
|||||||
static LeaderboardType GetLeaderboardType(uint32_t gameID);
|
static LeaderboardType GetLeaderboardType(uint32_t gameID);
|
||||||
private:
|
private:
|
||||||
static LeaderboardManager* address;
|
static LeaderboardManager* address;
|
||||||
static const std::string topPlayersQuery;
|
|
||||||
static const std::string friendsQuery;
|
// Modified 12/12/2021: Existing queries were renamed to be more descriptive.
|
||||||
static const std::string standingsQuery;
|
static const std::string topPlayersScoreQuery;
|
||||||
static const std::string topPlayersQueryAsc;
|
static const std::string friendsScoreQuery;
|
||||||
static const std::string friendsQueryAsc;
|
static const std::string standingsScoreQuery;
|
||||||
static const std::string standingsQueryAsc;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "dZoneManager.h"
|
#include "dZoneManager.h"
|
||||||
#include "CharacterComponent.h"
|
#include "CharacterComponent.h"
|
||||||
#include "Mail.h"
|
#include "Mail.h"
|
||||||
|
#include "CppScripts.h"
|
||||||
|
|
||||||
std::vector<Player*> Player::m_Players = {};
|
std::vector<Player*> Player::m_Players = {};
|
||||||
|
|
||||||
@ -275,5 +276,21 @@ Player::~Player()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsPlayer()) {
|
||||||
|
Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity();
|
||||||
|
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) {
|
||||||
|
script->OnPlayerExit(zoneControl, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Entity*> 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);
|
m_Players.erase(iter);
|
||||||
}
|
}
|
||||||
|
@ -369,10 +369,8 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet);
|
LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet);
|
||||||
objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_CHARACTER);
|
uint32_t charID = static_cast<uint32_t>(objectID);
|
||||||
objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_PERSISTENT);
|
|
||||||
|
|
||||||
uint32_t charID = static_cast<uint32_t>(objectID);
|
|
||||||
Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)\n", objectID, charID);
|
Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)\n", objectID, charID);
|
||||||
|
|
||||||
//Check if this user has this character:
|
//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=?;");
|
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM friends WHERE player_id=? OR friend_id=?;");
|
||||||
stmt->setUInt64(1, charID);
|
stmt->setUInt(1, charID);
|
||||||
stmt->setUInt64(2, charID);
|
stmt->setUInt(2, charID);
|
||||||
stmt->execute();
|
stmt->execute();
|
||||||
delete stmt;
|
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=?;");
|
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM leaderboard WHERE character_id=?;");
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "dLogger.h"
|
#include "dLogger.h"
|
||||||
#include "BehaviorTemplates.h"
|
#include "BehaviorTemplates.h"
|
||||||
#include "BehaviorBranchContext.h"
|
#include "BehaviorBranchContext.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Behavior includes
|
* Behavior includes
|
||||||
@ -45,6 +46,7 @@
|
|||||||
#include "InterruptBehavior.h"
|
#include "InterruptBehavior.h"
|
||||||
#include "PlayEffectBehavior.h"
|
#include "PlayEffectBehavior.h"
|
||||||
#include "DamageAbsorptionBehavior.h"
|
#include "DamageAbsorptionBehavior.h"
|
||||||
|
#include "VentureVisionBehavior.h"
|
||||||
#include "BlockBehavior.h"
|
#include "BlockBehavior.h"
|
||||||
#include "ClearTargetBehavior.h"
|
#include "ClearTargetBehavior.h"
|
||||||
#include "PullToPointBehavior.h"
|
#include "PullToPointBehavior.h"
|
||||||
@ -68,7 +70,7 @@
|
|||||||
#include "RenderComponent.h"
|
#include "RenderComponent.h"
|
||||||
#include "DestroyableComponent.h"
|
#include "DestroyableComponent.h"
|
||||||
|
|
||||||
std::map<uint32_t, Behavior*> Behavior::Cache = {};
|
std::unordered_map<uint32_t, Behavior*> Behavior::Cache = {};
|
||||||
CDBehaviorParameterTable* Behavior::BehaviorParameterTable = nullptr;
|
CDBehaviorParameterTable* Behavior::BehaviorParameterTable = nullptr;
|
||||||
|
|
||||||
Behavior* Behavior::GetBehavior(const uint32_t behaviorId)
|
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)
|
Behavior* Behavior::CreateBehavior(const uint32_t behaviorId)
|
||||||
{
|
{
|
||||||
auto* cached = GetBehavior(behaviorId);
|
auto* cached = GetBehavior(behaviorId);
|
||||||
|
|
||||||
if (cached != nullptr)
|
if (cached != nullptr)
|
||||||
{
|
{
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (behaviorId == 0)
|
if (behaviorId == 0)
|
||||||
{
|
{
|
||||||
return new EmptyBehavior(0);
|
return new EmptyBehavior(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto templateId = GetBehaviorTemplate(behaviorId);
|
const auto templateId = GetBehaviorTemplate(behaviorId);
|
||||||
|
|
||||||
Behavior* behavior = nullptr;
|
Behavior* behavior = nullptr;
|
||||||
|
|
||||||
switch (templateId)
|
switch (templateId)
|
||||||
{
|
{
|
||||||
case BehaviorTemplates::BEHAVIOR_EMPTY: break;
|
case BehaviorTemplates::BEHAVIOR_EMPTY: break;
|
||||||
@ -176,7 +178,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId)
|
|||||||
case BehaviorTemplates::BEHAVIOR_LOOT_BUFF:
|
case BehaviorTemplates::BEHAVIOR_LOOT_BUFF:
|
||||||
behavior = new LootBuffBehavior(behaviorId);
|
behavior = new LootBuffBehavior(behaviorId);
|
||||||
break;
|
break;
|
||||||
case BehaviorTemplates::BEHAVIOR_VENTURE_VISION: break;
|
case BehaviorTemplates::BEHAVIOR_VENTURE_VISION:
|
||||||
|
behavior = new VentureVisionBehavior(behaviorId);
|
||||||
|
break;
|
||||||
case BehaviorTemplates::BEHAVIOR_SPAWN_OBJECT:
|
case BehaviorTemplates::BEHAVIOR_SPAWN_OBJECT:
|
||||||
behavior = new SpawnBehavior(behaviorId);
|
behavior = new SpawnBehavior(behaviorId);
|
||||||
break;
|
break;
|
||||||
@ -191,8 +195,8 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId)
|
|||||||
behavior = new JetPackBehavior(behaviorId);
|
behavior = new JetPackBehavior(behaviorId);
|
||||||
break;
|
break;
|
||||||
case BehaviorTemplates::BEHAVIOR_SKILL_EVENT:
|
case BehaviorTemplates::BEHAVIOR_SKILL_EVENT:
|
||||||
behavior = new SkillEventBehavior(behaviorId);
|
behavior = new SkillEventBehavior(behaviorId);
|
||||||
break;
|
break;
|
||||||
case BehaviorTemplates::BEHAVIOR_CONSUME_ITEM: break;
|
case BehaviorTemplates::BEHAVIOR_CONSUME_ITEM: break;
|
||||||
case BehaviorTemplates::BEHAVIOR_SKILL_CAST_FAILED:
|
case BehaviorTemplates::BEHAVIOR_SKILL_CAST_FAILED:
|
||||||
behavior = new SkillCastFailedBehavior(behaviorId);
|
behavior = new SkillCastFailedBehavior(behaviorId);
|
||||||
@ -272,7 +276,7 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId)
|
|||||||
if (behavior == nullptr)
|
if (behavior == nullptr)
|
||||||
{
|
{
|
||||||
//Game::logger->Log("Behavior", "Failed to load unimplemented template id (%i)!\n", templateId);
|
//Game::logger->Log("Behavior", "Failed to load unimplemented template id (%i)!\n", templateId);
|
||||||
|
|
||||||
behavior = new EmptyBehavior(behaviorId);
|
behavior = new EmptyBehavior(behaviorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,30 +285,23 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId)
|
|||||||
return behavior;
|
return behavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId)
|
BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) {
|
||||||
{
|
auto behaviorTemplateTable = CDClientManager::Instance()->GetTable<CDBehaviorTemplateTable>("BehaviorTemplate");
|
||||||
std::stringstream query;
|
|
||||||
|
|
||||||
query << "SELECT templateID FROM BehaviorTemplate WHERE behaviorID = " << std::to_string(behaviorId);
|
BehaviorTemplates templateID = BehaviorTemplates::BEHAVIOR_EMPTY;
|
||||||
|
// Find behavior template by its behavior id. Default to 0.
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
if (behaviorTemplateTable) {
|
||||||
|
auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId);
|
||||||
// Make sure we do not proceed if we are trying to load an invalid behavior
|
if (templateEntry.behaviorID == behaviorId) {
|
||||||
if (result.eof())
|
templateID = static_cast<BehaviorTemplates>(templateEntry.templateID);
|
||||||
{
|
|
||||||
if (behaviorId != 0)
|
|
||||||
{
|
|
||||||
Game::logger->Log("Behavior::GetBehaviorTemplate", "Failed to load behavior template with id (%i)!\n", behaviorId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return BehaviorTemplates::BEHAVIOR_EMPTY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto id = static_cast<BehaviorTemplates>(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
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* renderComponent = targetEntity->GetComponent<RenderComponent>();
|
auto* renderComponent = targetEntity->GetComponent<RenderComponent>();
|
||||||
|
|
||||||
const auto typeString = GeneralUtils::UTF16ToWTF8(type);
|
const auto typeString = GeneralUtils::UTF16ToWTF8(type);
|
||||||
@ -348,28 +345,35 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID
|
|||||||
if (renderComponent == nullptr)
|
if (renderComponent == nullptr)
|
||||||
{
|
{
|
||||||
GameMessages::SendPlayFXEffect(targetEntity, effectId, type, pair->second, secondary, 1, 1, true);
|
GameMessages::SendPlayFXEffect(targetEntity, effectId, type, pair->second, secondary, 1, 1, true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderComponent->PlayEffect(effectId, type, pair->second, secondary);
|
renderComponent->PlayEffect(effectId, type, pair->second, secondary);
|
||||||
|
|
||||||
return;
|
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))
|
if (result.eof() || result.fieldIsNull(0))
|
||||||
{
|
{
|
||||||
@ -381,7 +385,7 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID
|
|||||||
if (type.empty())
|
if (type.empty())
|
||||||
{
|
{
|
||||||
const auto typeResult = result.getStringField(1);
|
const auto typeResult = result.getStringField(1);
|
||||||
|
|
||||||
type = GeneralUtils::ASCIIToUTF16(typeResult);
|
type = GeneralUtils::ASCIIToUTF16(typeResult);
|
||||||
|
|
||||||
m_effectType = new std::string(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)
|
if (renderComponent == nullptr)
|
||||||
{
|
{
|
||||||
GameMessages::SendPlayFXEffect(targetEntity, effectId, type, name, secondary, 1, 1, true);
|
GameMessages::SendPlayFXEffect(targetEntity, effectId, type, name, secondary, 1, 1, true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,6 +407,17 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID
|
|||||||
|
|
||||||
Behavior::Behavior(const uint32_t behaviorId)
|
Behavior::Behavior(const uint32_t behaviorId)
|
||||||
{
|
{
|
||||||
|
auto behaviorTemplateTable = CDClientManager::Instance()->GetTable<CDBehaviorTemplateTable>("BehaviorTemplate");
|
||||||
|
|
||||||
|
CDBehaviorTemplate templateInDatabase{};
|
||||||
|
|
||||||
|
if (behaviorTemplateTable) {
|
||||||
|
auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId);
|
||||||
|
if (templateEntry.behaviorID == behaviorId) {
|
||||||
|
templateInDatabase = templateEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->m_behaviorId = behaviorId;
|
this->m_behaviorId = behaviorId;
|
||||||
|
|
||||||
// Add to cache
|
// Add to cache
|
||||||
@ -414,18 +429,8 @@ Behavior::Behavior(const uint32_t behaviorId)
|
|||||||
this->m_templateId = BehaviorTemplates::BEHAVIOR_EMPTY;
|
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
|
// 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);
|
Game::logger->Log("Behavior", "Failed to load behavior with id (%i)!\n", behaviorId);
|
||||||
|
|
||||||
@ -436,34 +441,19 @@ Behavior::Behavior(const uint32_t behaviorId)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_templateId = static_cast<BehaviorTemplates>(result.getIntField(0));
|
this->m_templateId = static_cast<BehaviorTemplates>(templateInDatabase.templateID);
|
||||||
|
|
||||||
this->m_effectId = result.getIntField(1);
|
|
||||||
|
|
||||||
if (!result.fieldIsNull(2))
|
this->m_effectId = templateInDatabase.effectID;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.finalize();
|
this->m_effectHandle = *templateInDatabase.effectHandle != "" ? new std::string(*templateInDatabase.effectHandle) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float Behavior::GetFloat(const std::string& name, const float defaultValue) const
|
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<CDBehaviorParameterTable>("BehaviorParameter");
|
||||||
|
return BehaviorParameterTable->GetEntry(this->m_behaviorId, name, defaultValue).value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -493,24 +483,14 @@ Behavior* Behavior::GetAction(float value) const
|
|||||||
|
|
||||||
std::map<std::string, float> Behavior::GetParameterNames() const
|
std::map<std::string, float> Behavior::GetParameterNames() const
|
||||||
{
|
{
|
||||||
std::map<std::string, float> parameters;
|
std::map<std::string, float> templatesInDatabase;
|
||||||
|
// Find behavior template by its behavior id.
|
||||||
std::stringstream query;
|
if (!BehaviorParameterTable) BehaviorParameterTable = CDClientManager::Instance()->GetTable<CDBehaviorParameterTable>("BehaviorParameter");
|
||||||
|
if (BehaviorParameterTable) {
|
||||||
query << "SELECT parameterID, value FROM BehaviorParameter WHERE behaviorID = " << std::to_string(this->m_behaviorId);
|
templatesInDatabase = BehaviorParameterTable->GetParametersByBehaviorID(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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tableData.finalize();
|
return templatesInDatabase;
|
||||||
|
|
||||||
return parameters;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Behavior::Load()
|
void Behavior::Load()
|
||||||
|
@ -19,7 +19,7 @@ public:
|
|||||||
/*
|
/*
|
||||||
* Static
|
* Static
|
||||||
*/
|
*/
|
||||||
static std::map<uint32_t, Behavior*> Cache;
|
static std::unordered_map<uint32_t, Behavior*> Cache;
|
||||||
static CDBehaviorParameterTable* BehaviorParameterTable;
|
static CDBehaviorParameterTable* BehaviorParameterTable;
|
||||||
|
|
||||||
static Behavior* GetBehavior(uint32_t behaviorId);
|
static Behavior* GetBehavior(uint32_t behaviorId);
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef BEHAVIORSLOT_H
|
||||||
|
#define BEHAVIORSLOT_H
|
||||||
|
|
||||||
enum class BehaviorSlot
|
enum class BehaviorSlot
|
||||||
{
|
{
|
||||||
Invalid = -1,
|
Invalid = -1,
|
||||||
@ -9,3 +12,5 @@ enum class BehaviorSlot
|
|||||||
Head,
|
Head,
|
||||||
Consumable
|
Consumable
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
51
dGame/dBehaviors/CMakeLists.txt
Normal file
51
dGame/dBehaviors/CMakeLists.txt
Normal file
@ -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)
|
@ -39,15 +39,15 @@ void SwitchMultipleBehavior::Calculate(BehaviorContext* context, RakNet::BitStre
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitchMultipleBehavior::Load()
|
void SwitchMultipleBehavior::Load() {
|
||||||
{
|
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||||
const auto b = std::to_string(this->m_behaviorId);
|
"SELECT replace(bP1.parameterID, 'behavior ', '') as key, bP1.value as behavior, "
|
||||||
std::stringstream query;
|
"(select bP2.value FROM BehaviorParameter bP2 WHERE bP2.behaviorID = ?1 AND bP2.parameterID LIKE 'value %' "
|
||||||
query << "SELECT replace(bP1.parameterID, 'behavior ', '') as key, bP1.value as behavior, "
|
"AND replace(bP1.parameterID, 'behavior ', '') = replace(bP2.parameterID, 'value ', '')) as value "
|
||||||
<< "(select bP2.value FROM BehaviorParameter bP2 WHERE bP2.behaviorID = " << b << " AND bP2.parameterID LIKE 'value %' "
|
"FROM BehaviorParameter bP1 WHERE bP1.behaviorID = ?1 AND bP1.parameterID LIKE 'behavior %';");
|
||||||
<< "AND replace(bP1.parameterID, 'behavior ', '') = replace(bP2.parameterID, 'value ', '')) as value "
|
query.bind(1, (int) this->m_behaviorId);
|
||||||
<< "FROM BehaviorParameter bP1 WHERE bP1.behaviorID = " << b << " AND bP1.parameterID LIKE 'behavior %'";
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
auto result = query.execQuery();
|
||||||
|
|
||||||
while (!result.eof()) {
|
while (!result.eof()) {
|
||||||
const auto behavior_id = static_cast<uint32_t>(result.getFloatField(1));
|
const auto behavior_id = static_cast<uint32_t>(result.getFloatField(1));
|
||||||
|
47
dGame/dBehaviors/VentureVisionBehavior.cpp
Normal file
47
dGame/dBehaviors/VentureVisionBehavior.cpp
Normal file
@ -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<CharacterComponent>();
|
||||||
|
|
||||||
|
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<CharacterComponent>();
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
41
dGame/dBehaviors/VentureVisionBehavior.h
Normal file
41
dGame/dBehaviors/VentureVisionBehavior.h
Normal file
@ -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__
|
@ -35,11 +35,11 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id)
|
|||||||
m_SoftTimer = 5.0f;
|
m_SoftTimer = 5.0f;
|
||||||
|
|
||||||
//Grab the aggro information from BaseCombatAI:
|
//Grab the aggro information from BaseCombatAI:
|
||||||
std::stringstream componentQuery;
|
auto componentQuery = CDClientDatabase::CreatePreppedStmt(
|
||||||
|
"SELECT aggroRadius, tetherSpeed, pursuitSpeed, softTetherRadius, hardTetherRadius FROM BaseCombatAIComponent WHERE id = ?;");
|
||||||
componentQuery << "SELECT aggroRadius, tetherSpeed, pursuitSpeed, softTetherRadius, hardTetherRadius FROM BaseCombatAIComponent WHERE id = " << std::to_string(id);
|
componentQuery.bind(1, (int) id);
|
||||||
|
|
||||||
auto componentResult = CDClientDatabase::ExecuteQuery(componentQuery.str());
|
auto componentResult = componentQuery.execQuery();
|
||||||
|
|
||||||
if (!componentResult.eof())
|
if (!componentResult.eof())
|
||||||
{
|
{
|
||||||
@ -64,12 +64,11 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id)
|
|||||||
/*
|
/*
|
||||||
* Find skills
|
* Find skills
|
||||||
*/
|
*/
|
||||||
|
auto skillQuery = CDClientDatabase::CreatePreppedStmt(
|
||||||
std::stringstream query;
|
"SELECT skillID, cooldown, behaviorID FROM SkillBehavior WHERE skillID IN (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);");
|
||||||
|
skillQuery.bind(1, (int) parent->GetLOT());
|
||||||
query << "SELECT skillID, cooldown, behaviorID FROM SkillBehavior WHERE skillID IN (SELECT skillID FROM ObjectSkills WHERE objectTemplate = " << std::to_string(parent->GetLOT()) << " )";
|
|
||||||
|
auto result = skillQuery.execQuery();
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
while (!result.eof()) {
|
while (!result.eof()) {
|
||||||
const auto skillId = static_cast<uint32_t>(result.getIntField(0));
|
const auto skillId = static_cast<uint32_t>(result.getIntField(0));
|
||||||
|
@ -371,12 +371,12 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
|
|||||||
return pair->second;
|
return pair->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream query;
|
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||||
|
"SELECT * FROM BuffParameters WHERE BuffID = ?;");
|
||||||
query << "SELECT * FROM BuffParameters WHERE BuffID = " << std::to_string(buffId) << ";";
|
query.bind(1, (int) buffId);
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
|
auto result = query.execQuery();
|
||||||
|
|
||||||
std::vector<BuffParameter> parameters {};
|
std::vector<BuffParameter> parameters {};
|
||||||
|
|
||||||
while (!result.eof())
|
while (!result.eof())
|
||||||
|
@ -42,6 +42,8 @@ void BuildBorderComponent::OnUse(Entity* originator) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inventoryComponent->PushEquippedItems();
|
||||||
|
|
||||||
Game::logger->Log("BuildBorderComponent", "Starting with %llu\n", buildArea);
|
Game::logger->Log("BuildBorderComponent", "Starting with %llu\n", buildArea);
|
||||||
|
|
||||||
if (PropertyManagementComponent::Instance() != nullptr) {
|
if (PropertyManagementComponent::Instance() != nullptr) {
|
||||||
|
40
dGame/dComponents/CMakeLists.txt
Normal file
40
dGame/dComponents/CMakeLists.txt
Normal file
@ -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)
|
@ -10,7 +10,6 @@
|
|||||||
#include "InventoryComponent.h"
|
#include "InventoryComponent.h"
|
||||||
#include "ControllablePhysicsComponent.h"
|
#include "ControllablePhysicsComponent.h"
|
||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
#include "PossessorComponent.h"
|
|
||||||
#include "VehiclePhysicsComponent.h"
|
#include "VehiclePhysicsComponent.h"
|
||||||
#include "GameMessages.h"
|
#include "GameMessages.h"
|
||||||
#include "Item.h"
|
#include "Item.h"
|
||||||
@ -81,13 +80,6 @@ CharacterComponent::~CharacterComponent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
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<uint8_t>(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
outBitStream->Write1();
|
outBitStream->Write1();
|
||||||
outBitStream->Write(m_Level);
|
outBitStream->Write(m_Level);
|
||||||
outBitStream->Write0();
|
outBitStream->Write0();
|
||||||
@ -793,3 +785,32 @@ ZoneStatistics& CharacterComponent::GetZoneStatisticsForMap(LWOMAPID mapID) {
|
|||||||
m_ZoneStatistics.insert({ mapID, {0, 0, 0, 0, 0 } });
|
m_ZoneStatistics.insert({ mapID, {0, 0, 0, 0, 0 } });
|
||||||
return m_ZoneStatistics.at(mapID);
|
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<AMFValue*>(new AMFTrueValue()) : static_cast<AMFValue*>(new AMFFalseValue()));
|
||||||
|
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", &arrayToSend);
|
||||||
|
}
|
||||||
|
@ -143,24 +143,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetIsRacing(bool isRacing) { m_IsRacing = isRacing; }
|
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
|
* Gets whether this character has PvP enabled, allowing combat between players
|
||||||
* @return
|
* @return
|
||||||
@ -197,6 +179,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetLastRocketItemID(LWOOBJID lastRocketItemID) { m_LastRocketItemID = lastRocketItemID; }
|
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
|
* 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);
|
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 info regarding this character, including clothing styles, etc.
|
||||||
*/
|
*/
|
||||||
Character* m_Character;
|
Character* m_Character;
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The map of active venture vision effects
|
||||||
|
*/
|
||||||
|
std::map<std::string, uint32_t> m_ActiveVentureVisionEffects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this character is racing
|
* Whether this character is racing
|
||||||
*/
|
*/
|
||||||
bool m_IsRacing;
|
bool m_IsRacing;
|
||||||
|
|
||||||
/**
|
|
||||||
* The object ID of the vehicle the character is currently in
|
|
||||||
*/
|
|
||||||
LWOOBJID m_VehicleObjectID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Possessible type, used by the shooting gallery
|
* Possessible type, used by the shooting gallery
|
||||||
*/
|
*/
|
||||||
@ -582,6 +591,11 @@ private:
|
|||||||
* ID of the last rocket used
|
* ID of the last rocket used
|
||||||
*/
|
*/
|
||||||
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
|
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mount Item ID
|
||||||
|
*/
|
||||||
|
LWOOBJID m_MountItemID = LWOOBJID_EMPTY;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CHARACTERCOMPONENT_H
|
#endif // CHARACTERCOMPONENT_H
|
||||||
|
@ -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->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) {
|
if (m_DirtyHealth || bIsInitialUpdate) {
|
||||||
outBitStream->Write(m_iHealth);
|
outBitStream->Write(m_iHealth);
|
||||||
outBitStream->Write(m_fMaxHealth);
|
outBitStream->Write(m_fMaxHealth);
|
||||||
@ -114,12 +114,12 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
|
|||||||
outBitStream->Write(m_fMaxArmor);
|
outBitStream->Write(m_fMaxArmor);
|
||||||
outBitStream->Write(m_iImagination);
|
outBitStream->Write(m_iImagination);
|
||||||
outBitStream->Write(m_fMaxImagination);
|
outBitStream->Write(m_fMaxImagination);
|
||||||
|
|
||||||
outBitStream->Write(m_DamageToAbsorb);
|
outBitStream->Write(m_DamageToAbsorb);
|
||||||
outBitStream->Write(IsImmune());
|
outBitStream->Write(IsImmune());
|
||||||
outBitStream->Write(m_IsGMImmune);
|
outBitStream->Write(m_IsGMImmune);
|
||||||
outBitStream->Write(m_IsShielded);
|
outBitStream->Write(m_IsShielded);
|
||||||
|
|
||||||
outBitStream->Write(m_fMaxHealth);
|
outBitStream->Write(m_fMaxHealth);
|
||||||
outBitStream->Write(m_fMaxArmor);
|
outBitStream->Write(m_fMaxArmor);
|
||||||
outBitStream->Write(m_fMaxImagination);
|
outBitStream->Write(m_fMaxImagination);
|
||||||
@ -130,14 +130,14 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write(m_IsSmashable);
|
outBitStream->Write(m_IsSmashable);
|
||||||
|
|
||||||
if (bIsInitialUpdate) {
|
if (bIsInitialUpdate) {
|
||||||
outBitStream->Write(m_IsDead);
|
outBitStream->Write(m_IsDead);
|
||||||
outBitStream->Write(m_IsSmashed);
|
outBitStream->Write(m_IsSmashed);
|
||||||
|
|
||||||
if (m_IsSmashable) {
|
if (m_IsSmashable) {
|
||||||
outBitStream->Write(m_HasBricks);
|
outBitStream->Write(m_HasBricks);
|
||||||
|
|
||||||
if (m_ExplodeFactor != 1.0f) {
|
if (m_ExplodeFactor != 1.0f) {
|
||||||
outBitStream->Write1();
|
outBitStream->Write1();
|
||||||
outBitStream->Write(m_ExplodeFactor);
|
outBitStream->Write(m_ExplodeFactor);
|
||||||
@ -146,10 +146,10 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_DirtyHealth = false;
|
m_DirtyHealth = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_DirtyThreatList || bIsInitialUpdate) {
|
if (m_DirtyThreatList || bIsInitialUpdate) {
|
||||||
outBitStream->Write1();
|
outBitStream->Write1();
|
||||||
outBitStream->Write(m_HasThreats);
|
outBitStream->Write(m_HasThreats);
|
||||||
@ -167,7 +167,7 @@ void DestroyableComponent::LoadFromXML(tinyxml2::XMLDocument* doc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto* buffComponent = m_Parent->GetComponent<BuffComponent>();
|
auto* buffComponent = m_Parent->GetComponent<BuffComponent>();
|
||||||
|
|
||||||
if (buffComponent != nullptr) {
|
if (buffComponent != nullptr) {
|
||||||
buffComponent->LoadFromXML(doc);
|
buffComponent->LoadFromXML(doc);
|
||||||
}
|
}
|
||||||
@ -187,9 +187,9 @@ void DestroyableComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
|
|||||||
Game::logger->Log("DestroyableComponent", "Failed to find dest tag!\n");
|
Game::logger->Log("DestroyableComponent", "Failed to find dest tag!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* buffComponent = m_Parent->GetComponent<BuffComponent>();
|
auto* buffComponent = m_Parent->GetComponent<BuffComponent>();
|
||||||
|
|
||||||
if (buffComponent != nullptr) {
|
if (buffComponent != nullptr) {
|
||||||
buffComponent->UpdateXml(doc);
|
buffComponent->UpdateXml(doc);
|
||||||
}
|
}
|
||||||
@ -235,7 +235,7 @@ void DestroyableComponent::SetMaxHealth(float value, bool playAnim) {
|
|||||||
args.InsertValue("amount", amount);
|
args.InsertValue("amount", amount);
|
||||||
args.InsertValue("type", type);
|
args.InsertValue("type", type);
|
||||||
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
|
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
|
||||||
|
|
||||||
delete amount;
|
delete amount;
|
||||||
delete type;
|
delete type;
|
||||||
}
|
}
|
||||||
@ -283,7 +283,7 @@ void DestroyableComponent::SetMaxArmor(float value, bool playAnim) {
|
|||||||
args.InsertValue("type", type);
|
args.InsertValue("type", type);
|
||||||
|
|
||||||
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
|
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
|
||||||
|
|
||||||
delete amount;
|
delete amount;
|
||||||
delete type;
|
delete type;
|
||||||
}
|
}
|
||||||
@ -329,7 +329,7 @@ void DestroyableComponent::SetMaxImagination(float value, bool playAnim) {
|
|||||||
args.InsertValue("amount", amount);
|
args.InsertValue("amount", amount);
|
||||||
args.InsertValue("type", type);
|
args.InsertValue("type", type);
|
||||||
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
|
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args);
|
||||||
|
|
||||||
delete amount;
|
delete amount;
|
||||||
delete type;
|
delete type;
|
||||||
}
|
}
|
||||||
@ -342,7 +342,7 @@ void DestroyableComponent::SetDamageToAbsorb(int32_t value)
|
|||||||
m_DamageToAbsorb = value;
|
m_DamageToAbsorb = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyableComponent::SetDamageReduction(int32_t value)
|
void DestroyableComponent::SetDamageReduction(int32_t value)
|
||||||
{
|
{
|
||||||
m_DirtyHealth = true;
|
m_DirtyHealth = true;
|
||||||
m_DamageReduction = value;
|
m_DamageReduction = value;
|
||||||
@ -354,7 +354,7 @@ void DestroyableComponent::SetIsImmune(bool value)
|
|||||||
m_ImmuneStacks = value ? 1 : 0;
|
m_ImmuneStacks = value ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyableComponent::SetIsGMImmune(bool value)
|
void DestroyableComponent::SetIsGMImmune(bool value)
|
||||||
{
|
{
|
||||||
m_DirtyHealth = true;
|
m_DirtyHealth = true;
|
||||||
m_IsGMImmune = value;
|
m_IsGMImmune = value;
|
||||||
@ -375,11 +375,11 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore
|
|||||||
m_FactionIDs.push_back(factionID);
|
m_FactionIDs.push_back(factionID);
|
||||||
m_DirtyHealth = true;
|
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 = query.execQuery();
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
if (result.eof()) return;
|
if (result.eof()) return;
|
||||||
|
|
||||||
@ -389,10 +389,10 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore
|
|||||||
|
|
||||||
std::stringstream ss(list_string);
|
std::stringstream ss(list_string);
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|
||||||
while (std::getline(ss, token, ',')) {
|
while (std::getline(ss, token, ',')) {
|
||||||
if (token.empty()) continue;
|
if (token.empty()) continue;
|
||||||
|
|
||||||
auto id = std::stoi(token);
|
auto id = std::stoi(token);
|
||||||
|
|
||||||
auto exclude = std::find(m_FactionIDs.begin(), m_FactionIDs.end(), id) != m_FactionIDs.end();
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddEnemyFaction(id);
|
AddEnemyFaction(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,7 +522,7 @@ bool DestroyableComponent::CheckValidity(const LWOOBJID target, const bool ignor
|
|||||||
if (targetQuickbuild != nullptr)
|
if (targetQuickbuild != nullptr)
|
||||||
{
|
{
|
||||||
const auto state = targetQuickbuild->GetState();
|
const auto state = targetQuickbuild->GetState();
|
||||||
|
|
||||||
if (state != REBUILD_COMPLETED)
|
if (state != REBUILD_COMPLETED)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -562,7 +562,7 @@ void DestroyableComponent::Imagine(const int32_t deltaImagination)
|
|||||||
{
|
{
|
||||||
auto current = static_cast<int32_t>(GetImagination());
|
auto current = static_cast<int32_t>(GetImagination());
|
||||||
const auto max = static_cast<int32_t>(GetMaxImagination());
|
const auto max = static_cast<int32_t>(GetMaxImagination());
|
||||||
|
|
||||||
current += deltaImagination;
|
current += deltaImagination;
|
||||||
|
|
||||||
current = std::min(current, max);
|
current = std::min(current, max);
|
||||||
@ -635,7 +635,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
|
|||||||
|
|
||||||
damage -= absorbDamage;
|
damage -= absorbDamage;
|
||||||
absorb -= absorbDamage;
|
absorb -= absorbDamage;
|
||||||
|
|
||||||
const auto armorDamage = std::min(damage, armor);
|
const auto armorDamage = std::min(damage, armor);
|
||||||
|
|
||||||
damage -= armorDamage;
|
damage -= armorDamage;
|
||||||
@ -657,7 +657,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
|
|||||||
{
|
{
|
||||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* attacker = EntityManager::Instance()->GetEntity(source);
|
auto* attacker = EntityManager::Instance()->GetEntity(source);
|
||||||
m_Parent->OnHit(attacker);
|
m_Parent->OnHit(attacker);
|
||||||
m_Parent->OnHitOrHealResult(attacker, sourceDamage);
|
m_Parent->OnHitOrHealResult(attacker, sourceDamage);
|
||||||
@ -696,10 +696,10 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
|||||||
|
|
||||||
if (owner != nullptr)
|
if (owner != nullptr)
|
||||||
{
|
{
|
||||||
auto* team = TeamManager::Instance()->GetTeam(owner->GetObjectID());
|
|
||||||
|
|
||||||
owner = owner->GetOwner(); // If the owner is overwritten, we collect that here
|
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<BaseCombatAIComponent>() != nullptr;
|
const auto isEnemy = m_Parent->GetComponent<BaseCombatAIComponent>() != nullptr;
|
||||||
|
|
||||||
auto* inventoryComponent = owner->GetComponent<InventoryComponent>();
|
auto* inventoryComponent = owner->GetComponent<InventoryComponent>();
|
||||||
@ -736,7 +736,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto isPlayer = m_Parent->IsPlayer();
|
const auto isPlayer = m_Parent->IsPlayer();
|
||||||
|
|
||||||
GameMessages::SendDie(m_Parent, source, source, true, killType, deathType, 0, 0, 0, isPlayer, false, 1);
|
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);
|
auto* member = EntityManager::Instance()->GetEntity(specificOwner);
|
||||||
|
|
||||||
if (member) LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins());
|
if (member) LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (const auto memberId : team->members) { // Free for all
|
for (const auto memberId : team->members) { // Free for all
|
||||||
auto* member = EntityManager::Instance()->GetEntity(memberId);
|
auto* member = EntityManager::Instance()->GetEntity(memberId);
|
||||||
|
|
||||||
if (member == nullptr) continue;
|
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;
|
m_ImmuneStacks -= stacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyableComponent::FixStats()
|
void DestroyableComponent::FixStats()
|
||||||
{
|
{
|
||||||
auto* entity = GetParent();
|
auto* entity = GetParent();
|
||||||
|
|
||||||
@ -904,7 +904,7 @@ void DestroyableComponent::FixStats()
|
|||||||
|
|
||||||
// Add the stats
|
// Add the stats
|
||||||
const auto& info = mission->GetClientInfo();
|
const auto& info = mission->GetClientInfo();
|
||||||
|
|
||||||
maxHealth += info.reward_maxhealth;
|
maxHealth += info.reward_maxhealth;
|
||||||
maxImagination += info.reward_maximagination;
|
maxImagination += info.reward_maximagination;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
#include "dZoneManager.h"
|
#include "dZoneManager.h"
|
||||||
#include "PropertyManagementComponent.h"
|
#include "PropertyManagementComponent.h"
|
||||||
#include "DestroyableComponent.h"
|
#include "DestroyableComponent.h"
|
||||||
|
#include "dConfig.h"
|
||||||
|
#include "eItemType.h"
|
||||||
|
|
||||||
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent)
|
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 items = inventoryComponentTable->Query([=](const CDInventoryComponent entry) { return entry.id == componentId; });
|
||||||
|
|
||||||
auto slot = 0u;
|
auto slot = 0u;
|
||||||
|
|
||||||
for (const auto& item : items)
|
for (const auto& item : items)
|
||||||
{
|
{
|
||||||
if (!item.equip || !Inventory::IsValidItem(item.itemid))
|
if (!item.equip || !Inventory::IsValidItem(item.itemid))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const LWOOBJID id = ObjectIDManager::Instance()->GenerateObjectID();
|
const LWOOBJID id = ObjectIDManager::Instance()->GenerateObjectID();
|
||||||
|
|
||||||
const auto& info = Inventory::FindItemComponent(item.itemid);
|
const auto& info = Inventory::FindItemComponent(item.itemid);
|
||||||
|
|
||||||
UpdateSlot(info.equipLocation, { id, static_cast<LOT>(item.itemid), item.count, slot++ });
|
UpdateSlot(info.equipLocation, { id, static_cast<LOT>(item.itemid), item.count, slot++ });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,7 +180,7 @@ void InventoryComponent::AddItem(
|
|||||||
auto* missions = static_cast<MissionComponent*>(this->m_Parent->GetComponent(COMPONENT_TYPE_MISSION));
|
auto* missions = static_cast<MissionComponent*>(this->m_Parent->GetComponent(COMPONENT_TYPE_MISSION));
|
||||||
|
|
||||||
auto* inventory = GetInventory(inventoryType);
|
auto* inventory = GetInventory(inventoryType);
|
||||||
|
|
||||||
if (!config.empty() || bound)
|
if (!config.empty() || bound)
|
||||||
{
|
{
|
||||||
const auto slot = preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot) ? preferredSlot : inventory->FindEmptySlot();
|
const auto slot = preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot) ? preferredSlot : inventory->FindEmptySlot();
|
||||||
@ -189,6 +191,7 @@ void InventoryComponent::AddItem(
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* item = new Item(lot, inventory, slot, count, config, parent, showFlyingLoot, isModMoveAndEquip, subKey, bound, lootSourceType);
|
auto* item = new Item(lot, inventory, slot, count, config, parent, showFlyingLoot, isModMoveAndEquip, subKey, bound, lootSourceType);
|
||||||
|
|
||||||
if (missions != nullptr && !IsTransferInventory(inventoryType))
|
if (missions != nullptr && !IsTransferInventory(inventoryType))
|
||||||
@ -200,14 +203,15 @@ void InventoryComponent::AddItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto info = Inventory::FindItemComponent(lot);
|
const auto info = Inventory::FindItemComponent(lot);
|
||||||
|
|
||||||
auto left = count;
|
auto left = count;
|
||||||
|
|
||||||
int32_t outOfSpace = 0;
|
int32_t outOfSpace = 0;
|
||||||
|
|
||||||
auto stack = static_cast<uint32_t>(info.stackSize);
|
auto stack = static_cast<uint32_t>(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;
|
stack = 999;
|
||||||
}
|
}
|
||||||
@ -215,7 +219,7 @@ void InventoryComponent::AddItem(
|
|||||||
{
|
{
|
||||||
stack = 1;
|
stack = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* existing = FindItemByLot(lot, inventoryType);
|
auto* existing = FindItemByLot(lot, inventoryType);
|
||||||
|
|
||||||
if (existing != nullptr)
|
if (existing != nullptr)
|
||||||
@ -239,7 +243,7 @@ void InventoryComponent::AddItem(
|
|||||||
const auto size = std::min(left, stack);
|
const auto size = std::min(left, stack);
|
||||||
|
|
||||||
left -= size;
|
left -= size;
|
||||||
|
|
||||||
int32_t slot;
|
int32_t slot;
|
||||||
|
|
||||||
if (preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot))
|
if (preferredSlot != -1 && inventory->IsSlotEmpty(preferredSlot))
|
||||||
@ -252,7 +256,7 @@ void InventoryComponent::AddItem(
|
|||||||
{
|
{
|
||||||
slot = inventory->FindEmptySlot();
|
slot = inventory->FindEmptySlot();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot == -1)
|
if (slot == -1)
|
||||||
{
|
{
|
||||||
auto* player = dynamic_cast<Player*>(GetParent());
|
auto* player = dynamic_cast<Player*>(GetParent());
|
||||||
@ -275,9 +279,9 @@ void InventoryComponent::AddItem(
|
|||||||
{
|
{
|
||||||
GameMessages::SendDropClientLoot(this->m_Parent, this->m_Parent->GetObjectID(), lot, 0, this->m_Parent->GetPosition(), 1);
|
GameMessages::SendDropClientLoot(this->m_Parent, this->m_Parent->GetObjectID(), lot, 0, this->m_Parent->GetPosition(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -326,7 +330,7 @@ void InventoryComponent::RemoveItem(const LOT lot, const uint32_t count, eInvent
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto delta = std::min<uint32_t>(left, item->GetCount());
|
const auto delta = std::min<uint32_t>(left, item->GetCount());
|
||||||
|
|
||||||
item->SetCount(item->GetCount() - delta);
|
item->SetCount(item->GetCount() - delta);
|
||||||
@ -341,19 +345,17 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* origin = item->GetInventory();
|
auto* origin = item->GetInventory();
|
||||||
|
|
||||||
const auto lot = item->GetLot();
|
const auto lot = item->GetLot();
|
||||||
|
|
||||||
if (item->GetConfig().empty() && !item->GetBound() || (item->GetBound() && item->GetInfo().isBOP))
|
if (item->GetConfig().empty() && !item->GetBound() || (item->GetBound() && item->GetInfo().isBOP))
|
||||||
{
|
{
|
||||||
auto left = std::min<uint32_t>(count, origin->GetLotCount(lot));
|
auto left = std::min<uint32_t>(count, origin->GetLotCount(lot));
|
||||||
|
|
||||||
while (left > 0)
|
while (left > 0)
|
||||||
{
|
{
|
||||||
item = origin->FindItemByLot(lot, ignoreEquipped);
|
|
||||||
|
|
||||||
if (item == nullptr)
|
if (item == nullptr)
|
||||||
{
|
{
|
||||||
item = origin->FindItemByLot(lot, false);
|
item = origin->FindItemByLot(lot, false);
|
||||||
@ -383,7 +385,7 @@ void InventoryComponent::MoveItemToInventory(Item* item, const eInventoryType in
|
|||||||
{
|
{
|
||||||
config.push_back(data->Copy());
|
config.push_back(data->Copy());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto delta = std::min<uint32_t>(item->GetCount(), count);
|
const auto delta = std::min<uint32_t>(item->GetCount(), count);
|
||||||
|
|
||||||
AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, LWOOBJID_EMPTY, origin->GetType(), 0, item->GetBound(), preferredSlot);
|
AddItem(lot, delta, eLootSourceType::LOOT_SOURCE_NONE, inventory, config, LWOOBJID_EMPTY, showFlyingLot, isModMoveAndEquip, 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);
|
return inventory->FindItemByLot(lot, ignoreEquipped, ignoreBound);
|
||||||
}
|
}
|
||||||
|
|
||||||
Item* InventoryComponent::FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType)
|
Item* InventoryComponent::FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType)
|
||||||
{
|
{
|
||||||
if (inventoryType == INVALID)
|
if (inventoryType == INVALID)
|
||||||
{
|
{
|
||||||
@ -600,7 +602,7 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document)
|
|||||||
unsigned int count;
|
unsigned int count;
|
||||||
bool bound;
|
bool bound;
|
||||||
LWOOBJID subKey = LWOOBJID_EMPTY;
|
LWOOBJID subKey = LWOOBJID_EMPTY;
|
||||||
|
|
||||||
itemElement->QueryAttribute("id", &id);
|
itemElement->QueryAttribute("id", &id);
|
||||||
itemElement->QueryAttribute("l", &lot);
|
itemElement->QueryAttribute("l", &lot);
|
||||||
itemElement->QueryAttribute("eq", &equipped);
|
itemElement->QueryAttribute("eq", &equipped);
|
||||||
@ -611,23 +613,23 @@ void InventoryComponent::LoadXml(tinyxml2::XMLDocument* document)
|
|||||||
|
|
||||||
// Begin custom xml
|
// Begin custom xml
|
||||||
auto parent = LWOOBJID_EMPTY;
|
auto parent = LWOOBJID_EMPTY;
|
||||||
|
|
||||||
itemElement->QueryAttribute("parent", &parent);
|
itemElement->QueryAttribute("parent", &parent);
|
||||||
// End custom xml
|
// End custom xml
|
||||||
|
|
||||||
std::vector<LDFBaseData*> config;
|
std::vector<LDFBaseData*> config;
|
||||||
|
|
||||||
auto* extraInfo = itemElement->FirstChildElement("x");
|
auto* extraInfo = itemElement->FirstChildElement("x");
|
||||||
|
|
||||||
if (extraInfo)
|
if (extraInfo)
|
||||||
{
|
{
|
||||||
std::string modInfo = extraInfo->Attribute("ma");
|
std::string modInfo = extraInfo->Attribute("ma");
|
||||||
|
|
||||||
LDFBaseData* moduleAssembly = new LDFData<std::u16string>(u"assemblyPartLOTs", GeneralUtils::ASCIIToUTF16(modInfo.substr(2, modInfo.size() - 1)));
|
LDFBaseData* moduleAssembly = new LDFData<std::u16string>(u"assemblyPartLOTs", GeneralUtils::ASCIIToUTF16(modInfo.substr(2, modInfo.size() - 1)));
|
||||||
|
|
||||||
config.push_back(moduleAssembly);
|
config.push_back(moduleAssembly);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* item = new Item(id, lot, inventory, slot, count, bound, config, parent, subKey);
|
const auto* item = new Item(id, lot, inventory, slot, count, bound, config, parent, subKey);
|
||||||
|
|
||||||
if (equipped)
|
if (equipped)
|
||||||
@ -705,7 +707,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document)
|
|||||||
|
|
||||||
bags->LinkEndChild(bag);
|
bags->LinkEndChild(bag);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* items = inventoryElement->FirstChildElement("items");
|
auto* items = inventoryElement->FirstChildElement("items");
|
||||||
|
|
||||||
if (items == nullptr)
|
if (items == nullptr)
|
||||||
@ -759,10 +761,10 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document)
|
|||||||
|
|
||||||
itemElement->LinkEndChild(extraInfo);
|
itemElement->LinkEndChild(extraInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
bagElement->LinkEndChild(itemElement);
|
bagElement->LinkEndChild(itemElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
items->LinkEndChild(bagElement);
|
items->LinkEndChild(bagElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -772,13 +774,13 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b
|
|||||||
if (bIsInitialUpdate || m_Dirty)
|
if (bIsInitialUpdate || m_Dirty)
|
||||||
{
|
{
|
||||||
outBitStream->Write(true);
|
outBitStream->Write(true);
|
||||||
|
|
||||||
outBitStream->Write<uint32_t>(m_Equipped.size());
|
outBitStream->Write<uint32_t>(m_Equipped.size());
|
||||||
|
|
||||||
for (const auto& pair : m_Equipped)
|
for (const auto& pair : m_Equipped)
|
||||||
{
|
{
|
||||||
const auto item = pair.second;
|
const auto item = pair.second;
|
||||||
|
|
||||||
if (bIsInitialUpdate)
|
if (bIsInitialUpdate)
|
||||||
{
|
{
|
||||||
AddItemSkills(item.lot);
|
AddItemSkills(item.lot);
|
||||||
@ -786,12 +788,12 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b
|
|||||||
|
|
||||||
outBitStream->Write(item.id);
|
outBitStream->Write(item.id);
|
||||||
outBitStream->Write(item.lot);
|
outBitStream->Write(item.lot);
|
||||||
|
|
||||||
outBitStream->Write0();
|
outBitStream->Write0();
|
||||||
|
|
||||||
outBitStream->Write(item.count > 0);
|
outBitStream->Write(item.count > 0);
|
||||||
if (item.count > 0) outBitStream->Write(item.count);
|
if (item.count > 0) outBitStream->Write(item.count);
|
||||||
|
|
||||||
outBitStream->Write(item.slot != 0);
|
outBitStream->Write(item.slot != 0);
|
||||||
if (item.slot != 0) outBitStream->Write<uint16_t>(item.slot);
|
if (item.slot != 0) outBitStream->Write<uint16_t>(item.slot);
|
||||||
|
|
||||||
@ -818,7 +820,7 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b
|
|||||||
outBitStream->Write(ldfStream);
|
outBitStream->Write(ldfStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write1();
|
outBitStream->Write1();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Dirty = false;
|
m_Dirty = false;
|
||||||
@ -827,7 +829,7 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b
|
|||||||
{
|
{
|
||||||
outBitStream->Write(false);
|
outBitStream->Write(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write(false);
|
outBitStream->Write(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,7 +838,7 @@ void InventoryComponent::ResetFlags()
|
|||||||
m_Dirty = false;
|
m_Dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::Update(float deltaTime)
|
void InventoryComponent::Update(float deltaTime)
|
||||||
{
|
{
|
||||||
for (auto* set : m_Itemsets)
|
for (auto* set : m_Itemsets)
|
||||||
{
|
{
|
||||||
@ -865,7 +867,7 @@ void InventoryComponent::UpdateSlot(const std::string& location, EquippedItem it
|
|||||||
UnEquipItem(old);
|
UnEquipItem(old);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Equipped.insert_or_assign(location, item);
|
m_Equipped.insert_or_assign(location, item);
|
||||||
|
|
||||||
m_Dirty = true;
|
m_Dirty = true;
|
||||||
@ -877,14 +879,14 @@ void InventoryComponent::RemoveSlot(const std::string& location)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Equipped.erase(location);
|
m_Equipped.erase(location);
|
||||||
|
|
||||||
m_Dirty = true;
|
m_Dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::EquipItem(Item* item, const bool skipChecks)
|
void InventoryComponent::EquipItem(Item* item, const bool skipChecks)
|
||||||
{
|
{
|
||||||
if (!Inventory::IsValidItem(item->GetLot()))
|
if (!Inventory::IsValidItem(item->GetLot()))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -985,19 +987,11 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks)
|
|||||||
// #107
|
// #107
|
||||||
auto* possessorComponent = m_Parent->GetComponent<PossessorComponent>();
|
auto* possessorComponent = m_Parent->GetComponent<PossessorComponent>();
|
||||||
|
|
||||||
if (possessorComponent != nullptr)
|
if (possessorComponent) possessorComponent->SetPossessable(carEntity->GetObjectID());
|
||||||
{
|
|
||||||
previousPossessorID = possessorComponent->GetPossessable();
|
|
||||||
possessorComponent->SetPossessable(carEntity->GetObjectID());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||||
|
|
||||||
if (characterComponent != nullptr)
|
if (characterComponent) characterComponent->SetIsRacing(true);
|
||||||
{
|
|
||||||
characterComponent->SetIsRacing(true);
|
|
||||||
characterComponent->SetVehicleObjectID(carEntity->GetObjectID());
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityManager::Instance()->ConstructEntity(carEntity);
|
EntityManager::Instance()->ConstructEntity(carEntity);
|
||||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||||
@ -1030,14 +1024,14 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == ITEM_TYPE_LOOT_MODEL || type == ITEM_TYPE_VEHICLE)
|
if (type == eItemType::ITEM_TYPE_LOOT_MODEL || type == eItemType::ITEM_TYPE_VEHICLE)
|
||||||
{
|
{
|
||||||
return;
|
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))
|
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();
|
const auto lot = item->GetLot();
|
||||||
|
|
||||||
CheckItemSet(lot);
|
CheckItemSet(lot);
|
||||||
|
|
||||||
for (auto* set : m_Itemsets)
|
for (auto* set : m_Itemsets)
|
||||||
{
|
{
|
||||||
set->OnEquip(lot);
|
set->OnEquip(lot);
|
||||||
@ -1079,7 +1073,7 @@ void InventoryComponent::UnEquipItem(Item* item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto lot = item->GetLot();
|
const auto lot = item->GetLot();
|
||||||
|
|
||||||
if (!Inventory::IsValidItem(lot))
|
if (!Inventory::IsValidItem(lot))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -1097,7 +1091,7 @@ void InventoryComponent::UnEquipItem(Item* item)
|
|||||||
RemoveItemSkills(item->GetLot());
|
RemoveItemSkills(item->GetLot());
|
||||||
|
|
||||||
RemoveSlot(item->GetInfo().equipLocation);
|
RemoveSlot(item->GetInfo().equipLocation);
|
||||||
|
|
||||||
PurgeProxies(item);
|
PurgeProxies(item);
|
||||||
|
|
||||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||||
@ -1115,7 +1109,7 @@ void InventoryComponent::ApplyBuff(Item* item) const
|
|||||||
const auto buffs = FindBuffs(item, true);
|
const auto buffs = FindBuffs(item, true);
|
||||||
|
|
||||||
for (const auto buff : buffs)
|
for (const auto buff : buffs)
|
||||||
{
|
{
|
||||||
SkillComponent::HandleUnmanaged(buff, m_Parent->GetObjectID());
|
SkillComponent::HandleUnmanaged(buff, m_Parent->GetObjectID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1165,6 +1159,18 @@ void InventoryComponent::PopEquippedItems()
|
|||||||
item->Equip();
|
item->Equip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_Pushed.clear();
|
||||||
|
|
||||||
|
auto destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
|
||||||
|
|
||||||
|
// Reset stats to full
|
||||||
|
if (destroyableComponent) {
|
||||||
|
destroyableComponent->SetHealth(static_cast<int32_t>(destroyableComponent->GetMaxHealth()));
|
||||||
|
destroyableComponent->SetArmor(static_cast<int32_t>(destroyableComponent->GetMaxArmor()));
|
||||||
|
destroyableComponent->SetImagination(static_cast<int32_t>(destroyableComponent->GetMaxImagination()));
|
||||||
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
||||||
|
}
|
||||||
|
|
||||||
m_Dirty = true;
|
m_Dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1182,22 +1188,21 @@ bool InventoryComponent::IsEquipped(const LOT lot) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::CheckItemSet(const LOT lot)
|
void InventoryComponent::CheckItemSet(const LOT lot) {
|
||||||
{
|
|
||||||
// Check if the lot is in the item set cache
|
// 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;
|
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);
|
const auto id = result.getIntField(0);
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -1223,11 +1228,11 @@ void InventoryComponent::CheckItemSet(const LOT lot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_ItemSetsChecked.push_back(lot);
|
m_ItemSetsChecked.push_back(lot);
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::SetConsumable(LOT lot)
|
void InventoryComponent::SetConsumable(LOT lot)
|
||||||
{
|
{
|
||||||
m_Consumable = lot;
|
m_Consumable = lot;
|
||||||
}
|
}
|
||||||
@ -1247,7 +1252,7 @@ void InventoryComponent::AddItemSkills(const LOT lot)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto index = m_Skills.find(slot);
|
const auto index = m_Skills.find(slot);
|
||||||
|
|
||||||
const auto skill = FindSkill(lot);
|
const auto skill = FindSkill(lot);
|
||||||
@ -1272,14 +1277,14 @@ void InventoryComponent::AddItemSkills(const LOT lot)
|
|||||||
void InventoryComponent::RemoveItemSkills(const LOT lot)
|
void InventoryComponent::RemoveItemSkills(const LOT lot)
|
||||||
{
|
{
|
||||||
const auto info = Inventory::FindItemComponent(lot);
|
const auto info = Inventory::FindItemComponent(lot);
|
||||||
|
|
||||||
const auto slot = FindBehaviorSlot(static_cast<eItemType>(info.itemType));
|
const auto slot = FindBehaviorSlot(static_cast<eItemType>(info.itemType));
|
||||||
|
|
||||||
if (slot == BehaviorSlot::Invalid)
|
if (slot == BehaviorSlot::Invalid)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto index = m_Skills.find(slot);
|
const auto index = m_Skills.find(slot);
|
||||||
|
|
||||||
if (index == m_Skills.end())
|
if (index == m_Skills.end())
|
||||||
@ -1292,7 +1297,7 @@ void InventoryComponent::RemoveItemSkills(const LOT lot)
|
|||||||
GameMessages::SendRemoveSkill(m_Parent, old);
|
GameMessages::SendRemoveSkill(m_Parent, old);
|
||||||
|
|
||||||
m_Skills.erase(slot);
|
m_Skills.erase(slot);
|
||||||
|
|
||||||
if (slot == BehaviorSlot::Primary)
|
if (slot == BehaviorSlot::Primary)
|
||||||
{
|
{
|
||||||
m_Skills.insert_or_assign(BehaviorSlot::Primary, 1);
|
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)
|
for (auto* set : m_Itemsets)
|
||||||
{
|
{
|
||||||
@ -1328,7 +1333,7 @@ bool InventoryComponent::HasAnyPassive(const std::vector<ItemSetPassiveAbilityID
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::DespawnPet()
|
void InventoryComponent::DespawnPet()
|
||||||
{
|
{
|
||||||
auto* current = PetComponent::GetActivePet(m_Parent->GetObjectID());
|
auto* current = PetComponent::GetActivePet(m_Parent->GetObjectID());
|
||||||
|
|
||||||
@ -1338,7 +1343,7 @@ void InventoryComponent::DespawnPet()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::SpawnPet(Item* item)
|
void InventoryComponent::SpawnPet(Item* item)
|
||||||
{
|
{
|
||||||
auto* current = PetComponent::GetActivePet(m_Parent->GetObjectID());
|
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<DestroyableComponent>();
|
||||||
|
|
||||||
|
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 {};
|
EntityInfo info {};
|
||||||
info.lot = item->GetLot();
|
info.lot = item->GetLot();
|
||||||
info.pos = m_Parent->GetPosition();
|
info.pos = m_Parent->GetPosition();
|
||||||
info.rot = NiQuaternion::IDENTITY;
|
info.rot = NiQuaternion::IDENTITY;
|
||||||
info.spawnerID = m_Parent->GetObjectID();
|
info.spawnerID = m_Parent->GetObjectID();
|
||||||
|
|
||||||
auto* pet = EntityManager::Instance()->CreateEntity(info);
|
auto* pet = EntityManager::Instance()->CreateEntity(info);
|
||||||
|
|
||||||
auto* petComponent = pet->GetComponent<PetComponent>();
|
auto* petComponent = pet->GetComponent<PetComponent>();
|
||||||
|
|
||||||
if (petComponent != nullptr)
|
if (petComponent != nullptr)
|
||||||
{
|
{
|
||||||
petComponent->Activate(item);
|
petComponent->Activate(item);
|
||||||
@ -1370,7 +1383,7 @@ void InventoryComponent::SpawnPet(Item* item)
|
|||||||
EntityManager::Instance()->ConstructEntity(pet);
|
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);
|
m_Pets.insert_or_assign(id, data);
|
||||||
}
|
}
|
||||||
@ -1391,7 +1404,7 @@ bool InventoryComponent::IsPet(LWOOBJID id) const
|
|||||||
return pair != m_Pets.end();
|
return pair != m_Pets.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::RemoveDatabasePet(LWOOBJID id)
|
void InventoryComponent::RemoveDatabasePet(LWOOBJID id)
|
||||||
{
|
{
|
||||||
m_Pets.erase(id);
|
m_Pets.erase(id);
|
||||||
}
|
}
|
||||||
@ -1399,22 +1412,22 @@ void InventoryComponent::RemoveDatabasePet(LWOOBJID id)
|
|||||||
BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type)
|
BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ITEM_TYPE_HAT:
|
case eItemType::ITEM_TYPE_HAT:
|
||||||
return BehaviorSlot::Head;
|
return BehaviorSlot::Head;
|
||||||
case ITEM_TYPE_NECK:
|
case eItemType::ITEM_TYPE_NECK:
|
||||||
return BehaviorSlot::Neck;
|
return BehaviorSlot::Neck;
|
||||||
case ITEM_TYPE_LEFT_HAND:
|
case eItemType::ITEM_TYPE_LEFT_HAND:
|
||||||
return BehaviorSlot::Offhand;
|
return BehaviorSlot::Offhand;
|
||||||
case ITEM_TYPE_RIGHT_HAND:
|
case eItemType::ITEM_TYPE_RIGHT_HAND:
|
||||||
return BehaviorSlot::Primary;
|
return BehaviorSlot::Primary;
|
||||||
case ITEM_TYPE_CONSUMABLE:
|
case eItemType::ITEM_TYPE_CONSUMABLE:
|
||||||
return BehaviorSlot::Consumable;
|
return BehaviorSlot::Consumable;
|
||||||
default:
|
default:
|
||||||
return BehaviorSlot::Invalid;
|
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;
|
return type == VENDOR_BUYBACK || type == VAULT_ITEMS || type == VAULT_MODELS || type == TEMP_ITEMS || type == TEMP_MODELS;
|
||||||
}
|
}
|
||||||
@ -1465,11 +1478,12 @@ std::vector<uint32_t> InventoryComponent::FindBuffs(Item* item, bool castOnEquip
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (missions != nullptr && castOnEquip)
|
if (missions != nullptr && castOnEquip)
|
||||||
{
|
{
|
||||||
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, result.skillID);
|
missions->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, result.skillID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If item is not a proxy, add its buff to the added buffs.
|
// If item is not a proxy, add its buff to the added buffs.
|
||||||
if (item->GetParent() == LWOOBJID_EMPTY) buffs.push_back(static_cast<uint32_t>(entry.behaviorID));
|
if (item->GetParent() == LWOOBJID_EMPTY) buffs.push_back(static_cast<uint32_t>(entry.behaviorID));
|
||||||
}
|
}
|
||||||
@ -1478,18 +1492,18 @@ std::vector<uint32_t> InventoryComponent::FindBuffs(Item* item, bool castOnEquip
|
|||||||
return buffs;
|
return buffs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::SetNPCItems(const std::vector<LOT>& items)
|
void InventoryComponent::SetNPCItems(const std::vector<LOT>& items)
|
||||||
{
|
{
|
||||||
m_Equipped.clear();
|
m_Equipped.clear();
|
||||||
|
|
||||||
auto slot = 0u;
|
auto slot = 0u;
|
||||||
|
|
||||||
for (const auto& item : items)
|
for (const auto& item : items)
|
||||||
{
|
{
|
||||||
const LWOOBJID id = ObjectIDManager::Instance()->GenerateObjectID();
|
const LWOOBJID id = ObjectIDManager::Instance()->GenerateObjectID();
|
||||||
|
|
||||||
const auto& info = Inventory::FindItemComponent(item);
|
const auto& info = Inventory::FindItemComponent(item);
|
||||||
|
|
||||||
UpdateSlot(info.equipLocation, { id, static_cast<LOT>(item), 1, slot++ }, true);
|
UpdateSlot(info.equipLocation, { id, static_cast<LOT>(item), 1, slot++ }, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1524,9 +1538,9 @@ std::vector<Item*> InventoryComponent::GenerateProxies(Item* parent)
|
|||||||
{
|
{
|
||||||
return proxies;
|
return proxies;
|
||||||
}
|
}
|
||||||
|
|
||||||
subItems.erase(std::remove_if(subItems.begin(), subItems.end(), ::isspace), subItems.end());
|
subItems.erase(std::remove_if(subItems.begin(), subItems.end(), ::isspace), subItems.end());
|
||||||
|
|
||||||
std::stringstream stream(subItems);
|
std::stringstream stream(subItems);
|
||||||
std::string segment;
|
std::string segment;
|
||||||
std::vector<uint32_t> lots;
|
std::vector<uint32_t> lots;
|
||||||
@ -1541,7 +1555,7 @@ std::vector<Item*> InventoryComponent::GenerateProxies(Item* parent)
|
|||||||
{
|
{
|
||||||
Game::logger->Log("InventoryComponent", "Failed to parse proxy (%s): (%s)!\n", segment.c_str(), exception.what());
|
Game::logger->Log("InventoryComponent", "Failed to parse proxy (%s): (%s)!\n", segment.c_str(), exception.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto lot : lots)
|
for (const auto lot : lots)
|
||||||
{
|
{
|
||||||
@ -1558,7 +1572,7 @@ std::vector<Item*> InventoryComponent::GenerateProxies(Item* parent)
|
|||||||
|
|
||||||
proxies.push_back(proxy);
|
proxies.push_back(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
return proxies;
|
return proxies;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1567,7 +1581,7 @@ std::vector<Item*> InventoryComponent::FindProxies(const LWOOBJID parent)
|
|||||||
auto* inventory = GetInventory(ITEM_SETS);
|
auto* inventory = GetInventory(ITEM_SETS);
|
||||||
|
|
||||||
std::vector<Item*> proxies;
|
std::vector<Item*> proxies;
|
||||||
|
|
||||||
for (const auto& pair : inventory->GetItems())
|
for (const auto& pair : inventory->GetItems())
|
||||||
{
|
{
|
||||||
auto* item = pair.second;
|
auto* item = pair.second;
|
||||||
@ -1609,7 +1623,7 @@ bool InventoryComponent::IsParentValid(Item* root)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto id = root->GetId();
|
const auto id = root->GetId();
|
||||||
|
|
||||||
for (const auto& pair : m_Inventories)
|
for (const auto& pair : m_Inventories)
|
||||||
{
|
{
|
||||||
const auto items = pair.second->GetItems();
|
const auto items = pair.second->GetItems();
|
||||||
@ -1631,7 +1645,7 @@ bool InventoryComponent::IsParentValid(Item* root)
|
|||||||
void InventoryComponent::CheckProxyIntegrity()
|
void InventoryComponent::CheckProxyIntegrity()
|
||||||
{
|
{
|
||||||
std::vector<Item*> dead;
|
std::vector<Item*> dead;
|
||||||
|
|
||||||
for (const auto& pair : m_Inventories)
|
for (const auto& pair : m_Inventories)
|
||||||
{
|
{
|
||||||
const auto& items = pair.second->GetItems();
|
const auto& items = pair.second->GetItems();
|
||||||
@ -1646,7 +1660,7 @@ void InventoryComponent::CheckProxyIntegrity()
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsValidProxy(parent))
|
if (IsValidProxy(parent))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -1671,7 +1685,7 @@ void InventoryComponent::CheckProxyIntegrity()
|
|||||||
for (const auto& candidate : items)
|
for (const auto& candidate : items)
|
||||||
{
|
{
|
||||||
auto* item = candidate.second;
|
auto* item = candidate.second;
|
||||||
|
|
||||||
const auto parent = item->GetParent();
|
const auto parent = item->GetParent();
|
||||||
|
|
||||||
if (parent != LWOOBJID_EMPTY)
|
if (parent != LWOOBJID_EMPTY)
|
||||||
@ -1703,7 +1717,7 @@ void InventoryComponent::CheckProxyIntegrity()
|
|||||||
void InventoryComponent::PurgeProxies(Item* item)
|
void InventoryComponent::PurgeProxies(Item* item)
|
||||||
{
|
{
|
||||||
const auto root = item->GetParent();
|
const auto root = item->GetParent();
|
||||||
|
|
||||||
if (root != LWOOBJID_EMPTY)
|
if (root != LWOOBJID_EMPTY)
|
||||||
{
|
{
|
||||||
item = FindItemById(root);
|
item = FindItemById(root);
|
||||||
@ -1712,7 +1726,7 @@ void InventoryComponent::PurgeProxies(Item* item)
|
|||||||
{
|
{
|
||||||
UnEquipItem(item);
|
UnEquipItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
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");
|
auto* petInventoryElement = document->FirstChildElement("obj")->FirstChildElement("pet");
|
||||||
|
|
||||||
@ -1744,7 +1758,7 @@ void InventoryComponent::LoadPetXml(tinyxml2::XMLDocument* document)
|
|||||||
LWOOBJID id;
|
LWOOBJID id;
|
||||||
LOT lot;
|
LOT lot;
|
||||||
int32_t moderationStatus;
|
int32_t moderationStatus;
|
||||||
|
|
||||||
petElement->QueryAttribute("id", &id);
|
petElement->QueryAttribute("id", &id);
|
||||||
petElement->QueryAttribute("l", &lot);
|
petElement->QueryAttribute("l", &lot);
|
||||||
petElement->QueryAttribute("m", &moderationStatus);
|
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");
|
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("m", pet.second.moderationState);
|
||||||
petElement->SetAttribute("n", pet.second.name.c_str());
|
petElement->SetAttribute("n", pet.second.name.c_str());
|
||||||
petElement->SetAttribute("t", 0);
|
petElement->SetAttribute("t", 0);
|
||||||
|
|
||||||
petInventoryElement->LinkEndChild(petElement);
|
petInventoryElement->LinkEndChild(petElement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef INVENTORYCOMPONENT_H
|
||||||
|
#define INVENTORYCOMPONENT_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
@ -22,6 +25,8 @@ class ItemSet;
|
|||||||
|
|
||||||
typedef std::map<std::string, EquippedItem> EquipmentMap;
|
typedef std::map<std::string, EquippedItem> EquipmentMap;
|
||||||
|
|
||||||
|
enum class eItemType : int32_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the inventory of entity, including the items they possess and have equipped. An entity can have inventories
|
* 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
|
* 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);
|
void UpdatePetXml(tinyxml2::XMLDocument* document);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -450,11 +450,11 @@ const std::vector<uint32_t>& MissionComponent::QueryAchievements(MissionTaskType
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool MissionComponent::RequiresItem(const LOT lot) {
|
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 = query.execQuery();
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
if (result.eof()) {
|
if (result.eof()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "../dWorldServer/ObjectIDManager.h"
|
#include "../dWorldServer/ObjectIDManager.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
#include "dConfig.h"
|
||||||
#include "dChatFilter.h"
|
#include "dChatFilter.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
|
|
||||||
@ -81,6 +82,20 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId) : Component(par
|
|||||||
if (!checkPreconditions.empty()) {
|
if (!checkPreconditions.empty()) {
|
||||||
SetPreconditions(checkPreconditions);
|
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<int>(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)
|
void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags)
|
||||||
@ -172,13 +187,12 @@ void PetComponent::OnUse(Entity* originator)
|
|||||||
|
|
||||||
std::string buildFile;
|
std::string buildFile;
|
||||||
|
|
||||||
if (cached == buildCache.end())
|
if (cached == buildCache.end()) {
|
||||||
{
|
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||||
std::stringstream query;
|
"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 = query.execQuery();
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
if (result.eof())
|
if (result.eof())
|
||||||
{
|
{
|
||||||
@ -637,7 +651,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position)
|
|||||||
|
|
||||||
inventoryComponent->SetDatabasePet(petSubKey, databasePet);
|
inventoryComponent->SetDatabasePet(petSubKey, databasePet);
|
||||||
|
|
||||||
Activate(item, false);
|
Activate(item, false, true);
|
||||||
|
|
||||||
m_Timer = 0;
|
m_Timer = 0;
|
||||||
|
|
||||||
@ -898,8 +912,10 @@ void PetComponent::Wander()
|
|||||||
m_Timer += (m_MovementAI->GetCurrentPosition().x - destination.x) / info.wanderSpeed;
|
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_ItemId = item->GetId();
|
||||||
m_DatabaseId = item->GetSubKey();
|
m_DatabaseId = item->GetSubKey();
|
||||||
|
|
||||||
@ -969,6 +985,44 @@ void PetComponent::Activate(Item* item, bool registerPet)
|
|||||||
GameMessages::SendShowPetActionButton(m_Owner, 3, true, owner->GetSystemAddress());
|
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<DestroyableComponent>();
|
||||||
|
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()
|
void PetComponent::Deactivate()
|
||||||
{
|
{
|
||||||
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true);
|
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), -1, u"despawn", "", LWOOBJID_EMPTY, 1, 1, true);
|
||||||
|
@ -82,7 +82,7 @@ public:
|
|||||||
* @param item the item to create the pet from
|
* @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
|
* @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
|
* Despawns the pet
|
||||||
@ -203,6 +203,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
static PetComponent* GetActivePet(LWOOBJID owner);
|
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:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -346,4 +354,9 @@ private:
|
|||||||
* Preconditions that need to be met before an entity can tame this pet
|
* Preconditions that need to be met before an entity can tame this pet
|
||||||
*/
|
*/
|
||||||
PreconditionExpression* m_Preconditions;
|
PreconditionExpression* m_Preconditions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The rate at which imagination is drained from the user for having the pet out.
|
||||||
|
*/
|
||||||
|
float imaginationDrainRate;
|
||||||
};
|
};
|
@ -1,51 +1,46 @@
|
|||||||
#include "PossessableComponent.h"
|
#include "PossessableComponent.h"
|
||||||
|
|
||||||
#include "PossessorComponent.h"
|
#include "PossessorComponent.h"
|
||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
|
#include "Inventory.h"
|
||||||
|
#include "Item.h"
|
||||||
|
|
||||||
PossessableComponent::PossessableComponent(Entity* parent) : Component(parent)
|
PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId) : Component(parent){
|
||||||
{
|
m_Possessor = LWOOBJID_EMPTY;
|
||||||
m_Possessor = LWOOBJID_EMPTY;
|
CDItemComponent item = Inventory::FindItemComponent(m_Parent->GetLOT());
|
||||||
|
m_AnimationFlag = static_cast<eAnimationFlags>(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<int>(componentId));
|
||||||
|
|
||||||
|
auto result = query.execQuery();
|
||||||
|
|
||||||
|
// Should a result not exist for this default to attached visible
|
||||||
|
if (!result.eof()) {
|
||||||
|
m_PossessionType = static_cast<ePossessionType>(result.getIntField(0, 0));
|
||||||
|
m_DepossessOnHit = static_cast<bool>(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)
|
outBitStream->Write(m_AnimationFlag != eAnimationFlags::IDLE_INVALID);
|
||||||
{
|
if(m_AnimationFlag != eAnimationFlags::IDLE_INVALID) outBitStream->Write(m_AnimationFlag);
|
||||||
m_Possessor = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
LWOOBJID PossessableComponent::GetPossessor() const
|
outBitStream->Write(m_ImmediatelyDepossess);
|
||||||
{
|
}
|
||||||
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)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PossessableComponent::OnUse(Entity* originator) {
|
void PossessableComponent::OnUse(Entity* originator) {
|
||||||
PossessorComponent* possessorComponent;
|
// TODO: Implement this
|
||||||
if (originator->TryGetComponent(COMPONENT_TYPE_POSSESSOR, possessorComponent)) {
|
}
|
||||||
SetPossessor(originator->GetObjectID());
|
|
||||||
possessorComponent->SetPossessable(m_Parent->GetObjectID());
|
|
||||||
EntityManager::Instance()->SerializeEntity(m_Parent);
|
|
||||||
EntityManager::Instance()->SerializeEntity(originator);
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,44 +3,113 @@
|
|||||||
#include "BitStream.h"
|
#include "BitStream.h"
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
#include "Component.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
|
* Represents an entity that can be controlled by some other entity, generally used by cars to indicate that some
|
||||||
* player is controlling it.
|
* player is controlling it.
|
||||||
*/
|
*/
|
||||||
class PossessableComponent : public Component {
|
class PossessableComponent : public Component {
|
||||||
public:
|
public:
|
||||||
static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSABLE;
|
static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSABLE;
|
||||||
|
|
||||||
PossessableComponent(Entity* parentEntity);
|
|
||||||
~PossessableComponent() override;
|
|
||||||
|
|
||||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
PossessableComponent(Entity* parentEntity, uint32_t componentId);
|
||||||
void Update(float deltaTime) override;
|
|
||||||
|
|
||||||
/**
|
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||||
* Sets the possessor of this entity
|
|
||||||
* @param value the ID of the possessor to set
|
|
||||||
*/
|
|
||||||
void SetPossessor(LWOOBJID value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the possessor of this entity
|
* Sets the possessor of this entity
|
||||||
* @return the possessor of this entitythe
|
* @param value the ID of the possessor to set
|
||||||
*/
|
*/
|
||||||
LWOOBJID GetPossessor() const;
|
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
|
* Returns the possessor of this entity
|
||||||
* of this entity
|
* @return the possessor of this entity
|
||||||
* @param originator the entity that caused the event to trigger
|
*/
|
||||||
*/
|
LWOOBJID GetPossessor() const { return m_Possessor; };
|
||||||
void OnUse(Entity* originator) override;
|
|
||||||
|
|
||||||
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
|
* Returns the possession type of this entity
|
||||||
*/
|
* @return the possession type of this entity
|
||||||
LWOOBJID m_Possessor;
|
*/
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
@ -1,35 +1,21 @@
|
|||||||
#include "PossessorComponent.h"
|
#include "PossessorComponent.h"
|
||||||
|
|
||||||
PossessorComponent::PossessorComponent(Entity* parent) : Component(parent)
|
PossessorComponent::PossessorComponent(Entity* parent) : Component(parent) {
|
||||||
{
|
m_Possessable = LWOOBJID_EMPTY;
|
||||||
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)
|
void PossessorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||||
{
|
outBitStream->Write(m_DirtyPossesor || bIsInitialUpdate);
|
||||||
outBitStream->Write(m_Possessable != LWOOBJID_EMPTY);
|
if (m_DirtyPossesor || bIsInitialUpdate) {
|
||||||
if (m_Possessable != LWOOBJID_EMPTY)
|
m_DirtyPossesor = false;
|
||||||
{
|
outBitStream->Write(m_Possessable != LWOOBJID_EMPTY);
|
||||||
outBitStream->Write(m_Possessable);
|
if (m_Possessable != LWOOBJID_EMPTY) {
|
||||||
}
|
outBitStream->Write(m_Possessable);
|
||||||
}
|
}
|
||||||
|
outBitStream->Write(m_PossessableType);
|
||||||
void PossessorComponent::Update(float deltaTime)
|
}
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,35 +4,78 @@
|
|||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
#include "Component.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.
|
* Represents an entity that can posess other entities. Generally used by players to drive a car.
|
||||||
*/
|
*/
|
||||||
class PossessorComponent : public Component {
|
class PossessorComponent : public Component {
|
||||||
public:
|
public:
|
||||||
static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSOR;
|
static const uint32_t ComponentType = COMPONENT_TYPE_POSSESSOR;
|
||||||
|
|
||||||
PossessorComponent(Entity* parent);
|
|
||||||
~PossessorComponent() override;
|
|
||||||
|
|
||||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
PossessorComponent(Entity* parent);
|
||||||
void Update(float deltaTime) override;
|
~PossessorComponent() override;
|
||||||
|
|
||||||
/**
|
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||||
* Sets the entity that this entity is possessing
|
|
||||||
* @param value the ID of the entity this ID should posess
|
|
||||||
*/
|
|
||||||
void SetPossessable(LWOOBJID value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the entity that this entity is currently posessing
|
* Sets the entity that this entity is possessing
|
||||||
* @return the entity that this entity is currently posessing
|
* @param value the ID of the entity this ID should posess
|
||||||
*/
|
*/
|
||||||
LWOOBJID GetPossessable() const;
|
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)
|
* Sets if we are busy mounting or dismounting
|
||||||
*/
|
* @param value if we are busy mounting or dismounting
|
||||||
LWOOBJID m_Possessable;
|
*/
|
||||||
|
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;
|
||||||
};
|
};
|
||||||
|
@ -102,7 +102,7 @@ PropertySelectQueryProperty PropertyEntranceComponent::SetPropertyValues(Propert
|
|||||||
return property;
|
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;
|
std::string base;
|
||||||
if (customQuery == "") {
|
if (customQuery == "") {
|
||||||
base = baseQueryForProperties;
|
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;");
|
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->setUInt(1, character->GetID());
|
||||||
friendsListQuery->setInt64(2, entity->GetObjectID());
|
friendsListQuery->setUInt(2, character->GetID());
|
||||||
|
|
||||||
auto friendsListQueryResult = friendsListQuery->executeQuery();
|
auto friendsListQueryResult = friendsListQuery->executeQuery();
|
||||||
|
|
||||||
while (friendsListQueryResult->next()) {
|
while (friendsListQueryResult->next()) {
|
||||||
auto playerIDToConvert = friendsListQueryResult->getInt64(1);
|
auto playerIDToConvert = friendsListQueryResult->getInt(1);
|
||||||
playerIDToConvert = GeneralUtils::ClearBit(playerIDToConvert, OBJECT_BIT_CHARACTER);
|
|
||||||
playerIDToConvert = GeneralUtils::ClearBit(playerIDToConvert, OBJECT_BIT_PERSISTENT);
|
|
||||||
friendsList = friendsList + std::to_string(playerIDToConvert) + ",";
|
friendsList = friendsList + std::to_string(playerIDToConvert) + ",";
|
||||||
}
|
}
|
||||||
// Replace trailing comma with the closing parenthesis.
|
// 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 the player has a property this query will have a single result.
|
||||||
if (playerPropertyLookupResults->next()) {
|
if (playerPropertyLookupResults->next()) {
|
||||||
const auto cloneId = playerPropertyLookupResults->getUInt64(4);
|
const auto cloneId = playerPropertyLookupResults->getUInt64(4);
|
||||||
const auto propertyName = playerPropertyLookupResults->getString(5).asStdString();
|
const auto propertyName = std::string(playerPropertyLookupResults->getString(5).c_str());
|
||||||
const auto propertyDescription = playerPropertyLookupResults->getString(6).asStdString();
|
const auto propertyDescription = std::string(playerPropertyLookupResults->getString(6).c_str());
|
||||||
const auto privacyOption = playerPropertyLookupResults->getInt(9);
|
const auto privacyOption = playerPropertyLookupResults->getInt(9);
|
||||||
const auto modApproved = playerPropertyLookupResults->getBoolean(10);
|
const auto modApproved = playerPropertyLookupResults->getBoolean(10);
|
||||||
const auto dateLastUpdated = playerPropertyLookupResults->getInt64(11);
|
const auto dateLastUpdated = playerPropertyLookupResults->getInt64(11);
|
||||||
@ -193,7 +191,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
|
|||||||
|
|
||||||
entries.push_back(playerEntry);
|
entries.push_back(playerEntry);
|
||||||
|
|
||||||
const auto query = BuildQuery(entity, sortMethod);
|
const auto query = BuildQuery(entity, sortMethod, character);
|
||||||
|
|
||||||
auto propertyLookup = Database::CreatePreppedStmt(query);
|
auto propertyLookup = Database::CreatePreppedStmt(query);
|
||||||
|
|
||||||
@ -212,8 +210,8 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
|
|||||||
const auto propertyId = propertyEntry->getUInt64(1);
|
const auto propertyId = propertyEntry->getUInt64(1);
|
||||||
const auto owner = propertyEntry->getInt(2);
|
const auto owner = propertyEntry->getInt(2);
|
||||||
const auto cloneId = propertyEntry->getUInt64(4);
|
const auto cloneId = propertyEntry->getUInt64(4);
|
||||||
const auto propertyNameFromDb = propertyEntry->getString(5).asStdString();
|
const auto propertyNameFromDb = std::string(propertyEntry->getString(5).c_str());
|
||||||
const auto propertyDescriptionFromDb = propertyEntry->getString(6).asStdString();
|
const auto propertyDescriptionFromDb = std::string(propertyEntry->getString(6).c_str());
|
||||||
const auto privacyOption = propertyEntry->getInt(9);
|
const auto privacyOption = propertyEntry->getInt(9);
|
||||||
const auto modApproved = propertyEntry->getBoolean(10);
|
const auto modApproved = propertyEntry->getBoolean(10);
|
||||||
const auto dateLastUpdated = propertyEntry->getInt(11);
|
const auto dateLastUpdated = propertyEntry->getInt(11);
|
||||||
@ -239,7 +237,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
|
|||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
isOwned = cloneId == character->GetPropertyCloneID();
|
isOwned = cloneId == character->GetPropertyCloneID();
|
||||||
ownerName = nameResult->getString(1).asStdString();
|
ownerName = std::string(nameResult->getString(1).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
delete nameResult;
|
delete nameResult;
|
||||||
@ -262,17 +260,17 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
|
|||||||
// Query to get friend and best friend fields
|
// 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 = ?)");
|
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->setUInt(1, character->GetID());
|
||||||
friendCheck->setInt64(2, ownerObjId);
|
friendCheck->setUInt(2, ownerObjId);
|
||||||
friendCheck->setInt64(3, ownerObjId);
|
friendCheck->setUInt(3, ownerObjId);
|
||||||
friendCheck->setInt64(4, entity->GetObjectID());
|
friendCheck->setUInt(4, character->GetID());
|
||||||
|
|
||||||
auto friendResult = friendCheck->executeQuery();
|
auto friendResult = friendCheck->executeQuery();
|
||||||
|
|
||||||
// If we got a result than the two players are friends.
|
// If we got a result than the two players are friends.
|
||||||
if (friendResult->next()) {
|
if (friendResult->next()) {
|
||||||
isFriend = true;
|
isFriend = true;
|
||||||
if (friendResult->getInt(1) == 2) {
|
if (friendResult->getInt(1) == 3) {
|
||||||
isBestFriend = true;
|
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.
|
// 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;
|
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);
|
auto propertiesLeft = Database::CreatePreppedStmt(buttonQuery);
|
||||||
|
|
||||||
propertiesLeft->setUInt(1, this->m_MapID);
|
propertiesLeft->setUInt(1, this->m_MapID);
|
||||||
@ -346,4 +344,4 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
|
|||||||
propertiesLeft = nullptr;
|
propertiesLeft = nullptr;
|
||||||
|
|
||||||
GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, numberOfProperties - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr);
|
GameMessages::SendPropertySelectQuery(m_Parent->GetObjectID(), startIndex, numberOfProperties - (startIndex + numResults) > 0, character->GetPropertyCloneID(), false, true, entries, sysAddr);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
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:
|
private:
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "MissionComponent.h"
|
||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
#include "PropertyDataMessage.h"
|
#include "PropertyDataMessage.h"
|
||||||
#include "UserManager.h"
|
#include "UserManager.h"
|
||||||
@ -40,11 +41,11 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo
|
|||||||
const auto zoneId = worldId.GetMapID();
|
const auto zoneId = worldId.GetMapID();
|
||||||
const auto cloneId = worldId.GetCloneID();
|
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 = query.execQuery();
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
if (result.eof() || result.fieldIsNull(0))
|
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->moderatorRequested = propertyEntry->getInt(10) == 0 && rejectionReason == "" && privacyOption == PropertyPrivacyOption::Public;
|
||||||
this->LastUpdatedTime = propertyEntry->getUInt64(11);
|
this->LastUpdatedTime = propertyEntry->getUInt64(11);
|
||||||
this->claimedTime = propertyEntry->getUInt64(12);
|
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);
|
this->reputation = propertyEntry->getUInt(14);
|
||||||
|
|
||||||
Load();
|
Load();
|
||||||
@ -102,12 +103,12 @@ void PropertyManagementComponent::SetOwner(Entity* value)
|
|||||||
std::vector<NiPoint3> PropertyManagementComponent::GetPaths() const
|
std::vector<NiPoint3> PropertyManagementComponent::GetPaths() const
|
||||||
{
|
{
|
||||||
const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID();
|
const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID();
|
||||||
|
|
||||||
std::stringstream query {};
|
|
||||||
|
|
||||||
query << "SELECT path FROM PropertyTemplate WHERE mapID = " << std::to_string(zoneId) << ";";
|
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||||
|
"SELECT path FROM PropertyTemplate WHERE mapID = ?;");
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
query.bind(1, (int) zoneId);
|
||||||
|
|
||||||
|
auto result = query.execQuery();
|
||||||
|
|
||||||
std::vector<NiPoint3> paths {};
|
std::vector<NiPoint3> paths {};
|
||||||
|
|
||||||
@ -285,6 +286,10 @@ void PropertyManagementComponent::OnStartBuilding()
|
|||||||
|
|
||||||
player->SendToZone(zoneId);
|
player->SendToZone(zoneId);
|
||||||
}
|
}
|
||||||
|
auto inventoryComponent = ownerEntity->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
|
// Push equipped items
|
||||||
|
if (inventoryComponent) inventoryComponent->PushEquippedItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PropertyManagementComponent::OnFinishBuilding()
|
void PropertyManagementComponent::OnFinishBuilding()
|
||||||
@ -865,7 +870,7 @@ void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const
|
|||||||
|
|
||||||
result->next();
|
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);
|
const auto modApproved = result->getInt(2);
|
||||||
if (reason != "") {
|
if (reason != "") {
|
||||||
moderatorRequested = false;
|
moderatorRequested = false;
|
||||||
|
@ -212,6 +212,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity *player,
|
|||||||
|
|
||||||
if (possessorComponent != nullptr) {
|
if (possessorComponent != nullptr) {
|
||||||
possessorComponent->SetPossessable(carEntity->GetObjectID());
|
possessorComponent->SetPossessable(carEntity->GetObjectID());
|
||||||
|
possessorComponent->SetPossessableType(ePossessionType::ATTACHED_VISIBLE); // for racing it's always Attached_Visible
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the player's current activity as racing.
|
// Set the player's current activity as racing.
|
||||||
@ -219,7 +220,6 @@ void RacingControlComponent::LoadPlayerVehicle(Entity *player,
|
|||||||
|
|
||||||
if (characterComponent != nullptr) {
|
if (characterComponent != nullptr) {
|
||||||
characterComponent->SetIsRacing(true);
|
characterComponent->SetIsRacing(true);
|
||||||
characterComponent->SetVehicleObjectID(carEntity->GetObjectID());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init the player's racing entry.
|
// Init the player's racing entry.
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "dLogger.h"
|
#include "dLogger.h"
|
||||||
#include "CharacterComponent.h"
|
#include "CharacterComponent.h"
|
||||||
|
#include "MissionComponent.h"
|
||||||
|
#include "MissionTaskType.h"
|
||||||
|
|
||||||
#include "dServer.h"
|
#include "dServer.h"
|
||||||
#include "PacketUtils.h"
|
#include "PacketUtils.h"
|
||||||
@ -22,6 +24,20 @@ RebuildComponent::RebuildComponent(Entity* entity) : Component(entity) {
|
|||||||
{
|
{
|
||||||
m_Precondition = new PreconditionExpression(GeneralUtils::UTF16ToWTF8(checkPreconditions));
|
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() {
|
RebuildComponent::~RebuildComponent() {
|
||||||
|
@ -198,14 +198,16 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e
|
|||||||
return;
|
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();
|
result.finalize();
|
||||||
|
|
||||||
m_DurationCache[effectId] = 0;
|
m_DurationCache[effectId] = 0;
|
||||||
@ -214,7 +216,7 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
effect->time = static_cast<float>(result.getFloatField(0));
|
effect->time = static_cast<float>(result.getFloatField(0));
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
#include "RocketLaunchLupComponent.h"
|
#include "RocketLaunchLupComponent.h"
|
||||||
#include "CDClientDatabase.h"
|
|
||||||
#include "RocketLaunchpadControlComponent.h"
|
#include "RocketLaunchpadControlComponent.h"
|
||||||
#include "InventoryComponent.h"
|
#include "InventoryComponent.h"
|
||||||
#include "CharacterComponent.h"
|
#include "CharacterComponent.h"
|
||||||
|
|
||||||
RocketLaunchLupComponent::RocketLaunchLupComponent(Entity* parent) : Component(parent) {
|
RocketLaunchLupComponent::RocketLaunchLupComponent(Entity* parent) : Component(parent) {
|
||||||
m_Parent = parent;
|
m_Parent = parent;
|
||||||
|
std::string zoneString = GeneralUtils::UTF16ToWTF8(m_Parent->GetVar<std::u16string>(u"MultiZoneIDs"));
|
||||||
// get the lup worlds from the cdclient
|
std::stringstream ss(zoneString);
|
||||||
std::string query = "SELECT * FROM LUPZoneIDs;";
|
for (int i; ss >> i;) {
|
||||||
auto results = CDClientDatabase::ExecuteQuery(query);
|
m_LUPWorlds.push_back(i);
|
||||||
while (!results.eof()) {
|
if (ss.peek() == ';')
|
||||||
// fallback to 1600 incase there is an issue
|
ss.ignore();
|
||||||
m_LUPWorlds.push_back(results.getIntField(0, 1600));
|
|
||||||
results.nextRow();
|
|
||||||
}
|
}
|
||||||
results.finalize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RocketLaunchLupComponent::~RocketLaunchLupComponent() {}
|
RocketLaunchLupComponent::~RocketLaunchLupComponent() {}
|
||||||
@ -29,11 +25,7 @@ void RocketLaunchLupComponent::OnUse(Entity* originator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RocketLaunchLupComponent::OnSelectWorld(Entity* originator, uint32_t index) {
|
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<RocketLaunchpadControlComponent>();
|
auto* rocketLaunchpadControlComponent = m_Parent->GetComponent<RocketLaunchpadControlComponent>();
|
||||||
|
|
||||||
if (!rocketLaunchpadControlComponent) return;
|
if (!rocketLaunchpadControlComponent) return;
|
||||||
|
|
||||||
rocketLaunchpadControlComponent->Launch(originator, m_LUPWorlds[index], 0);
|
rocketLaunchpadControlComponent->Launch(originator, m_LUPWorlds[index], 0);
|
||||||
|
@ -19,11 +19,11 @@
|
|||||||
#include "PacketUtils.h"
|
#include "PacketUtils.h"
|
||||||
|
|
||||||
RocketLaunchpadControlComponent::RocketLaunchpadControlComponent(Entity* parent, int rocketId) : Component(parent) {
|
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 = query.execQuery();
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
if (!result.eof() && !result.fieldIsNull(0))
|
if (!result.eof() && !result.fieldIsNull(0))
|
||||||
{
|
{
|
||||||
@ -48,7 +48,7 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId,
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This also gets triggered by a proximity monitor + item equip, I will set that up when havok is ready
|
// This also gets triggered by a proximity monitor + item equip, I will set that up when havok is ready
|
||||||
auto* characterComponent = originator->GetComponent<CharacterComponent>();
|
auto* characterComponent = originator->GetComponent<CharacterComponent>();
|
||||||
auto* character = originator->GetCharacter();
|
auto* character = originator->GetCharacter();
|
||||||
@ -77,11 +77,11 @@ void RocketLaunchpadControlComponent::Launch(Entity* originator, LWOMAPID mapId,
|
|||||||
character->SaveXMLToDatabase();
|
character->SaveXMLToDatabase();
|
||||||
|
|
||||||
SetSelectedMapId(originator->GetObjectID(), zone);
|
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);
|
EntityManager::Instance()->SerializeEntity(originator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ void RocketLaunchpadControlComponent::OnProximityUpdate(Entity* entering, std::s
|
|||||||
// Proximity rockets are handled by item equipment
|
// 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;
|
m_SelectedMapIds[player] = mapID;
|
||||||
}
|
}
|
||||||
@ -126,7 +126,7 @@ LWOMAPID RocketLaunchpadControlComponent::GetSelectedMapId(LWOOBJID player) cons
|
|||||||
return index->second;
|
return index->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RocketLaunchpadControlComponent::SetSelectedCloneId(LWOOBJID player, LWOCLONEID cloneId)
|
void RocketLaunchpadControlComponent::SetSelectedCloneId(LWOOBJID player, LWOCLONEID cloneId)
|
||||||
{
|
{
|
||||||
m_SelectedCloneIds[player] = cloneId;
|
m_SelectedCloneIds[player] = cloneId;
|
||||||
}
|
}
|
||||||
|
@ -487,22 +487,24 @@ void ActivityInstance::StartZone() {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
auto* leader = participants[0];
|
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());
|
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<uint32_t>(1, UINT32_MAX);
|
const auto cloneId = GeneralUtils::GenerateRandomNumber<uint32_t>(1, UINT32_MAX);
|
||||||
for (Entity* player : participants) {
|
for (Entity* player : participants) {
|
||||||
|
@ -17,6 +17,17 @@ SimplePhysicsComponent::SimplePhysicsComponent(uint32_t componentID, Entity* par
|
|||||||
m_Position = m_Parent->GetDefaultPosition();
|
m_Position = m_Parent->GetDefaultPosition();
|
||||||
m_Rotation = m_Parent->GetDefaultRotation();
|
m_Rotation = m_Parent->GetDefaultRotation();
|
||||||
m_IsDirty = true;
|
m_IsDirty = true;
|
||||||
|
|
||||||
|
const auto& climbable_type = m_Parent->GetVar<std::u16string>(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() {
|
SimplePhysicsComponent::~SimplePhysicsComponent() {
|
||||||
@ -24,10 +35,10 @@ SimplePhysicsComponent::~SimplePhysicsComponent() {
|
|||||||
|
|
||||||
void SimplePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
void SimplePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||||
if (bIsInitialUpdate) {
|
if (bIsInitialUpdate) {
|
||||||
outBitStream->Write0(); // climbable
|
outBitStream->Write(m_ClimbableType != eClimbableType::CLIMBABLE_TYPE_NOT);
|
||||||
outBitStream->Write<int32_t>(0); // climbableType
|
outBitStream->Write(m_ClimbableType);
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write(m_DirtyVelocity || bIsInitialUpdate);
|
outBitStream->Write(m_DirtyVelocity || bIsInitialUpdate);
|
||||||
if (m_DirtyVelocity || bIsInitialUpdate) {
|
if (m_DirtyVelocity || bIsInitialUpdate) {
|
||||||
outBitStream->Write(m_Velocity);
|
outBitStream->Write(m_Velocity);
|
||||||
@ -46,7 +57,7 @@ void SimplePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIs
|
|||||||
{
|
{
|
||||||
outBitStream->Write0();
|
outBitStream->Write0();
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write(m_IsDirty || bIsInitialUpdate);
|
outBitStream->Write(m_IsDirty || bIsInitialUpdate);
|
||||||
if (m_IsDirty || bIsInitialUpdate) {
|
if (m_IsDirty || bIsInitialUpdate) {
|
||||||
outBitStream->Write(m_Position.x);
|
outBitStream->Write(m_Position.x);
|
||||||
@ -66,7 +77,7 @@ uint32_t SimplePhysicsComponent::GetPhysicsMotionState() const
|
|||||||
return m_PhysicsMotionState;
|
return m_PhysicsMotionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimplePhysicsComponent::SetPhysicsMotionState(uint32_t value)
|
void SimplePhysicsComponent::SetPhysicsMotionState(uint32_t value)
|
||||||
{
|
{
|
||||||
m_PhysicsMotionState = value;
|
m_PhysicsMotionState = value;
|
||||||
}
|
}
|
||||||
|
@ -14,16 +14,24 @@
|
|||||||
|
|
||||||
class Entity;
|
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
|
* Component that serializes locations of entities to the client
|
||||||
*/
|
*/
|
||||||
class SimplePhysicsComponent : public Component {
|
class SimplePhysicsComponent : public Component {
|
||||||
public:
|
public:
|
||||||
static const uint32_t ComponentType = COMPONENT_TYPE_SIMPLE_PHYSICS;
|
static const uint32_t ComponentType = COMPONENT_TYPE_SIMPLE_PHYSICS;
|
||||||
|
|
||||||
SimplePhysicsComponent(uint32_t componentID, Entity* parent);
|
SimplePhysicsComponent(uint32_t componentID, Entity* parent);
|
||||||
~SimplePhysicsComponent() override;
|
~SimplePhysicsComponent() override;
|
||||||
|
|
||||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,6 +94,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetPhysicsMotionState(uint32_t value);
|
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:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -122,6 +142,11 @@ private:
|
|||||||
* The current physics motion state
|
* The current physics motion state
|
||||||
*/
|
*/
|
||||||
uint32_t m_PhysicsMotionState = 0;
|
uint32_t m_PhysicsMotionState = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the entity is climbable
|
||||||
|
*/
|
||||||
|
eClimbableType m_ClimbableType = eClimbableType::CLIMBABLE_TYPE_NOT;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SIMPLEPHYSICSCOMPONENT_H
|
#endif // SIMPLEPHYSICSCOMPONENT_H
|
||||||
|
@ -38,11 +38,11 @@ bool SkillComponent::CastPlayerSkill(const uint32_t behaviorId, const uint32_t s
|
|||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
const auto branch = BehaviorBranchContext(target, 0);
|
const auto branch = BehaviorBranchContext(target, 0);
|
||||||
|
|
||||||
behavior->Handle(context, bitStream, branch);
|
behavior->Handle(context, bitStream, branch);
|
||||||
|
|
||||||
context->ExecuteUpdates();
|
context->ExecuteUpdates();
|
||||||
|
|
||||||
return !context->failed;
|
return !context->failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,24 +78,23 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index == -1)
|
if (index == -1)
|
||||||
{
|
{
|
||||||
Game::logger->Log("SkillComponent", "Failed to find projectile id (%llu)!\n", projectileId);
|
Game::logger->Log("SkillComponent", "Failed to find projectile id (%llu)!\n", projectileId);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sync_entry = this->m_managedProjectiles.at(index);
|
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);
|
Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!\n", sync_entry.lot);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -115,7 +114,7 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B
|
|||||||
{
|
{
|
||||||
branch.target = target;
|
branch.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
behavior->Handle(sync_entry.context, bitStream, branch);
|
behavior->Handle(sync_entry.context, bitStream, branch);
|
||||||
|
|
||||||
this->m_managedProjectiles.erase(this->m_managedProjectiles.begin() + index);
|
this->m_managedProjectiles.erase(this->m_managedProjectiles.begin() + index);
|
||||||
@ -129,7 +128,7 @@ void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, Behav
|
|||||||
entry.branchContext = branch;
|
entry.branchContext = branch;
|
||||||
entry.lot = lot;
|
entry.lot = lot;
|
||||||
entry.id = projectileId;
|
entry.id = projectileId;
|
||||||
|
|
||||||
this->m_managedProjectiles.push_back(entry);
|
this->m_managedProjectiles.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +140,7 @@ void SkillComponent::Update(const float deltaTime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::map<uint32_t, BehaviorContext*> keep {};
|
std::map<uint32_t, BehaviorContext*> keep {};
|
||||||
|
|
||||||
for (const auto& pair : this->m_managedBehaviors)
|
for (const auto& pair : this->m_managedBehaviors)
|
||||||
{
|
{
|
||||||
auto* context = pair.second;
|
auto* context = pair.second;
|
||||||
@ -150,7 +149,7 @@ void SkillComponent::Update(const float deltaTime)
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context->clientInitalized)
|
if (context->clientInitalized)
|
||||||
{
|
{
|
||||||
context->CalculateUpdate(deltaTime);
|
context->CalculateUpdate(deltaTime);
|
||||||
@ -164,7 +163,7 @@ void SkillComponent::Update(const float deltaTime)
|
|||||||
if (context->syncEntries.empty() && context->timerEntries.empty())
|
if (context->syncEntries.empty() && context->timerEntries.empty())
|
||||||
{
|
{
|
||||||
auto any = false;
|
auto any = false;
|
||||||
|
|
||||||
for (const auto& projectile : this->m_managedProjectiles)
|
for (const auto& projectile : this->m_managedProjectiles)
|
||||||
{
|
{
|
||||||
if (projectile.context == context)
|
if (projectile.context == context)
|
||||||
@ -180,13 +179,13 @@ void SkillComponent::Update(const float deltaTime)
|
|||||||
context->Reset();
|
context->Reset();
|
||||||
|
|
||||||
delete context;
|
delete context;
|
||||||
|
|
||||||
context = nullptr;
|
context = nullptr;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keep.insert_or_assign(pair.first, context);
|
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->caster = m_Parent->GetObjectID();
|
||||||
|
|
||||||
context->clientInitalized = clientInitalized;
|
context->clientInitalized = clientInitalized;
|
||||||
|
|
||||||
context->foundTarget = target != LWOOBJID_EMPTY || ignoreTarget || clientInitalized;
|
context->foundTarget = target != LWOOBJID_EMPTY || ignoreTarget || clientInitalized;
|
||||||
|
|
||||||
behavior->Calculate(context, bitStream, { target, 0});
|
behavior->Calculate(context, bitStream, { target, 0});
|
||||||
|
|
||||||
for (auto* script : CppScripts::GetEntityScripts(m_Parent)) {
|
for (auto* script : CppScripts::GetEntityScripts(m_Parent)) {
|
||||||
@ -278,7 +277,7 @@ SkillExecutionResult SkillComponent::CalculateBehavior(const uint32_t skillId, c
|
|||||||
{
|
{
|
||||||
// Echo start skill
|
// Echo start skill
|
||||||
GameMessages::EchoStartSkill start;
|
GameMessages::EchoStartSkill start;
|
||||||
|
|
||||||
start.iCastType = 0;
|
start.iCastType = 0;
|
||||||
start.skillID = skillId;
|
start.skillID = skillId;
|
||||||
start.uiSkillHandle = context->skillUId;
|
start.uiSkillHandle = context->skillUId;
|
||||||
@ -353,7 +352,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime)
|
|||||||
const auto targetPosition = target->GetPosition();
|
const auto targetPosition = target->GetPosition();
|
||||||
|
|
||||||
const auto closestPoint = Vector3::ClosestPointOnLine(entry.lastPosition, position, targetPosition);
|
const auto closestPoint = Vector3::ClosestPointOnLine(entry.lastPosition, position, targetPosition);
|
||||||
|
|
||||||
const auto distance = Vector3::DistanceSquared(targetPosition, closestPoint);
|
const auto distance = Vector3::DistanceSquared(targetPosition, closestPoint);
|
||||||
|
|
||||||
if (distance > 3 * 3)
|
if (distance > 3 * 3)
|
||||||
@ -399,12 +398,12 @@ void SkillComponent::CalculateUpdate(const float deltaTime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
entry.lastPosition = position;
|
entry.lastPosition = position;
|
||||||
|
|
||||||
managedProjectile = entry;
|
managedProjectile = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ProjectileSyncEntry> valid;
|
std::vector<ProjectileSyncEntry> valid;
|
||||||
|
|
||||||
for (auto& entry : this->m_managedProjectiles)
|
for (auto& entry : this->m_managedProjectiles)
|
||||||
{
|
{
|
||||||
if (entry.calculation)
|
if (entry.calculation)
|
||||||
@ -412,7 +411,7 @@ void SkillComponent::CalculateUpdate(const float deltaTime)
|
|||||||
if (entry.time >= entry.maxTime)
|
if (entry.time >= entry.maxTime)
|
||||||
{
|
{
|
||||||
entry.branchContext.target = LWOOBJID_EMPTY;
|
entry.branchContext.target = LWOOBJID_EMPTY;
|
||||||
|
|
||||||
SyncProjectileCalculation(entry);
|
SyncProjectileCalculation(entry);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -430,8 +429,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry)
|
|||||||
{
|
{
|
||||||
auto* other = EntityManager::Instance()->GetEntity(entry.branchContext.target);
|
auto* other = EntityManager::Instance()->GetEntity(entry.branchContext.target);
|
||||||
|
|
||||||
if (other == nullptr)
|
if (other == nullptr) {
|
||||||
{
|
|
||||||
if (entry.branchContext.target != LWOOBJID_EMPTY)
|
if (entry.branchContext.target != LWOOBJID_EMPTY)
|
||||||
{
|
{
|
||||||
Game::logger->Log("SkillComponent", "Invalid projectile target (%llu)!\n", entry.branchContext.target);
|
Game::logger->Log("SkillComponent", "Invalid projectile target (%llu)!\n", entry.branchContext.target);
|
||||||
@ -440,14 +438,12 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry)
|
|||||||
return;
|
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) << ")";
|
if (result.eof()) {
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
if (result.eof())
|
|
||||||
{
|
|
||||||
Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!\n", entry.lot);
|
Game::logger->Log("SkillComponent", "Failed to find skill id for (%i)!\n", entry.lot);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -456,13 +452,13 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry)
|
|||||||
const auto behaviorId = static_cast<uint32_t>(result.getIntField(0));
|
const auto behaviorId = static_cast<uint32_t>(result.getIntField(0));
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
auto* bitStream = new RakNet::BitStream();
|
auto* bitStream = new RakNet::BitStream();
|
||||||
|
|
||||||
behavior->Calculate(entry.context, bitStream, entry.branchContext);
|
behavior->Calculate(entry.context, bitStream, entry.branchContext);
|
||||||
|
|
||||||
GameMessages::DoClientProjectileImpact projectileImpact;
|
GameMessages::DoClientProjectileImpact projectileImpact;
|
||||||
|
|
||||||
projectileImpact.sBitStream.assign((char*) bitStream->GetData(), bitStream->GetNumberOfBytesUsed());
|
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 bitStream;
|
||||||
|
|
||||||
delete context;
|
delete context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID target)
|
void SkillComponent::HandleUnCast(const uint32_t behaviorId, const LWOOBJID target)
|
||||||
{
|
{
|
||||||
auto* context = new BehaviorContext(target);
|
auto* context = new BehaviorContext(target);
|
||||||
|
|
||||||
context->caster = target;
|
context->caster = target;
|
||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
behavior->UnCast(context, { target });
|
behavior->UnCast(context, { target });
|
||||||
|
|
||||||
delete context;
|
delete context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
dGame/dEntity/CMakeLists.txt
Normal file
2
dGame/dEntity/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set(DGAME_DENTITY_SOURCES "EntityCallbackTimer.cpp"
|
||||||
|
"EntityTimer.cpp" PARENT_SCOPE)
|
4
dGame/dGameMessages/CMakeLists.txt
Normal file
4
dGame/dGameMessages/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(DGAME_DGAMEMESSAGES_SOURCES "GameMessageHandler.cpp"
|
||||||
|
"GameMessages.cpp"
|
||||||
|
"PropertyDataMessage.cpp"
|
||||||
|
"PropertySelectQueryProperty.cpp" PARENT_SCOPE)
|
File diff suppressed because it is too large
Load Diff
@ -328,6 +328,34 @@ namespace GameMessages {
|
|||||||
|
|
||||||
void SendDisplayChatBubble(LWOOBJID objectId, const std::u16string& text, const SystemAddress& sysAddr);
|
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:
|
//Racing:
|
||||||
void HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
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 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 HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||||
|
|
||||||
void HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
void HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||||
@ -372,6 +398,7 @@ namespace GameMessages {
|
|||||||
void SendActivityPause(LWOOBJID objectId, bool pause = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS);
|
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 SendStartActivityTime(LWOOBJID objectId, float_t startTime, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
void SendRequestActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr, bool bStart, LWOOBJID userID);
|
void SendRequestActivityEnter(LWOOBJID objectId, const SystemAddress& sysAddr, bool bStart, LWOOBJID userID);
|
||||||
|
void SendUseItemRequirementsResponse(LWOOBJID objectID, const SystemAddress& sysAddr, UseItemResponse itemResponse);
|
||||||
|
|
||||||
// SG:
|
// SG:
|
||||||
|
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef PROPERTYSELECTQUERY_H
|
||||||
|
#define PROPERTYSELECTQUERY_H
|
||||||
|
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
|
|
||||||
class PropertySelectQueryProperty final
|
class PropertySelectQueryProperty final
|
||||||
@ -24,3 +27,5 @@ public:
|
|||||||
float PerformanceCost = 0; // The performance cost of the property
|
float PerformanceCost = 0; // The performance cost of the property
|
||||||
uint32_t PerformanceIndex = 0; // The performance index of the property? Always 0?
|
uint32_t PerformanceIndex = 0; // The performance index of the property? Always 0?
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
5
dGame/dInventory/CMakeLists.txt
Normal file
5
dGame/dInventory/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
set(DGAME_DINVENTORY_SOURCES "EquippedItem.cpp"
|
||||||
|
"Inventory.cpp"
|
||||||
|
"Item.cpp"
|
||||||
|
"ItemSet.cpp"
|
||||||
|
"ItemSetPassiveAbility.cpp" PARENT_SCOPE)
|
@ -1,7 +1,8 @@
|
|||||||
#include "Inventory.h"
|
#include "Inventory.h"
|
||||||
#include "GameMessages.h"
|
#include "GameMessages.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Item.h"
|
#include "Item.h"
|
||||||
|
#include "eItemType.h"
|
||||||
|
|
||||||
std::vector<LOT> Inventory::m_GameMasterRestrictedItems = {
|
std::vector<LOT> Inventory::m_GameMasterRestrictedItems = {
|
||||||
1727, // GM Only - JetPack
|
1727, // GM Only - JetPack
|
||||||
@ -274,40 +275,41 @@ eInventoryType Inventory::FindInventoryTypeForLot(const LOT lot)
|
|||||||
const auto itemType = static_cast<eItemType>(itemComponent.itemType);
|
const auto itemType = static_cast<eItemType>(itemComponent.itemType);
|
||||||
|
|
||||||
switch (itemType) {
|
switch (itemType) {
|
||||||
case ITEM_TYPE_BRICK:
|
case eItemType::ITEM_TYPE_BRICK:
|
||||||
return BRICKS;
|
return BRICKS;
|
||||||
|
|
||||||
case ITEM_TYPE_BEHAVIOR:
|
case eItemType::ITEM_TYPE_BEHAVIOR:
|
||||||
return BEHAVIORS;
|
return BEHAVIORS;
|
||||||
|
|
||||||
case ITEM_TYPE_PROPERTY:
|
case eItemType::ITEM_TYPE_PROPERTY:
|
||||||
return PROPERTY_DEEDS;
|
return PROPERTY_DEEDS;
|
||||||
|
|
||||||
case ITEM_TYPE_MODEL:
|
case eItemType::ITEM_TYPE_MODEL:
|
||||||
case ITEM_TYPE_VEHICLE:
|
case eItemType::ITEM_TYPE_VEHICLE:
|
||||||
case ITEM_TYPE_LOOT_MODEL:
|
case eItemType::ITEM_TYPE_LOOT_MODEL:
|
||||||
|
case eItemType::ITEM_TYPE_MOUNT:
|
||||||
return MODELS;
|
return MODELS;
|
||||||
|
|
||||||
case ITEM_TYPE_HAT:
|
case eItemType::ITEM_TYPE_HAT:
|
||||||
case ITEM_TYPE_HAIR:
|
case eItemType::ITEM_TYPE_HAIR:
|
||||||
case ITEM_TYPE_NECK:
|
case eItemType::ITEM_TYPE_NECK:
|
||||||
case ITEM_TYPE_LEFT_HAND:
|
case eItemType::ITEM_TYPE_LEFT_HAND:
|
||||||
case ITEM_TYPE_RIGHT_HAND:
|
case eItemType::ITEM_TYPE_RIGHT_HAND:
|
||||||
case ITEM_TYPE_LEGS:
|
case eItemType::ITEM_TYPE_LEGS:
|
||||||
case ITEM_TYPE_LEFT_TRINKET:
|
case eItemType::ITEM_TYPE_LEFT_TRINKET:
|
||||||
case ITEM_TYPE_RIGHT_TRINKET:
|
case eItemType::ITEM_TYPE_RIGHT_TRINKET:
|
||||||
case ITEM_TYPE_COLLECTIBLE:
|
case eItemType::ITEM_TYPE_COLLECTIBLE:
|
||||||
case ITEM_TYPE_CONSUMABLE:
|
case eItemType::ITEM_TYPE_CONSUMABLE:
|
||||||
case ITEM_TYPE_CHEST:
|
case eItemType::ITEM_TYPE_CHEST:
|
||||||
case ITEM_TYPE_EGG:
|
case eItemType::ITEM_TYPE_EGG:
|
||||||
case ITEM_TYPE_PET_FOOD:
|
case eItemType::ITEM_TYPE_PET_FOOD:
|
||||||
case ITEM_TYPE_PET_INVENTORY_ITEM:
|
case eItemType::ITEM_TYPE_PET_INVENTORY_ITEM:
|
||||||
case ITEM_TYPE_PACKAGE:
|
case eItemType::ITEM_TYPE_PACKAGE:
|
||||||
case ITEM_TYPE_CURRENCY:
|
case eItemType::ITEM_TYPE_CURRENCY:
|
||||||
return ITEMS;
|
return ITEMS;
|
||||||
|
|
||||||
case ITEM_TYPE_QUEST_OBJECT:
|
case eItemType::ITEM_TYPE_QUEST_OBJECT:
|
||||||
case ITEM_TYPE_UNKNOWN:
|
case eItemType::ITEM_TYPE_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return HIDDEN;
|
return HIDDEN;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef INVENTORY_H
|
||||||
|
#define INVENTORY_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -182,3 +185,5 @@ private:
|
|||||||
*/
|
*/
|
||||||
static std::vector<LOT> m_GameMasterRestrictedItems;
|
static std::vector<LOT> m_GameMasterRestrictedItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -311,7 +311,9 @@ bool Item::UseNonEquip()
|
|||||||
|
|
||||||
const auto success = !packages.empty();
|
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)
|
if (subKey != LWOOBJID_EMPTY)
|
||||||
{
|
{
|
||||||
@ -324,8 +326,7 @@ bool Item::UseNonEquip()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (success && (playerEntity->GetGMLevel() >= eGameMasterLevel::GAME_MASTER_LEVEL_JUNIOR_DEVELOPER || this->GetPreconditionExpression()->Check(playerEntity)))
|
||||||
if (success)
|
|
||||||
{
|
{
|
||||||
auto* entityParent = inventory->GetComponent()->GetParent();
|
auto* entityParent = inventory->GetComponent()->GetParent();
|
||||||
|
|
||||||
@ -342,7 +343,7 @@ bool Item::UseNonEquip()
|
|||||||
|
|
||||||
LootGenerator::Instance().GiveLoot(inventory->GetComponent()->GetParent(), result, eLootSourceType::LOOT_SOURCE_CONSUMPTION);
|
LootGenerator::Instance().GiveLoot(inventory->GetComponent()->GetParent(), result, eLootSourceType::LOOT_SOURCE_CONSUMPTION);
|
||||||
}
|
}
|
||||||
|
Game::logger->Log("Item", "Used (%i)\n", lot);
|
||||||
inventory->GetComponent()->RemoveItem(lot, 1);
|
inventory->GetComponent()->RemoveItem(lot, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,11 +387,11 @@ void Item::DisassembleModel()
|
|||||||
|
|
||||||
const auto componentId = table->GetByIDAndType(GetLot(), COMPONENT_TYPE_RENDER);
|
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 = query.execQuery();
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
if (result.eof())
|
if (result.eof())
|
||||||
{
|
{
|
||||||
|
@ -15,17 +15,17 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent)
|
|||||||
|
|
||||||
this->m_PassiveAbilities = ItemSetPassiveAbility::FindAbilities(id, m_InventoryComponent->GetParent(), this);
|
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 = query.execQuery();
|
||||||
|
|
||||||
auto result = CDClientDatabase::ExecuteQuery(query.str());
|
|
||||||
|
|
||||||
if (result.eof())
|
if (result.eof())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i = 0; i < 5; ++i)
|
for (auto i = 0; i < 5; ++i)
|
||||||
{
|
{
|
||||||
if (result.fieldIsNull(i))
|
if (result.fieldIsNull(i))
|
||||||
@ -33,11 +33,11 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent)
|
|||||||
continue;
|
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 = skillQuery.execQuery();
|
||||||
|
|
||||||
auto skillResult = CDClientDatabase::ExecuteQuery(skillQuery.str());
|
|
||||||
|
|
||||||
if (skillResult.eof())
|
if (skillResult.eof())
|
||||||
{
|
{
|
||||||
@ -49,10 +49,10 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent)
|
|||||||
if (skillResult.fieldIsNull(0))
|
if (skillResult.fieldIsNull(0))
|
||||||
{
|
{
|
||||||
skillResult.nextRow();
|
skillResult.nextRow();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto skillId = skillResult.getIntField(0);
|
const auto skillId = skillResult.getIntField(0);
|
||||||
|
|
||||||
switch (i)
|
switch (i)
|
||||||
@ -75,7 +75,7 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
skillResult.nextRow();
|
skillResult.nextRow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,7 +83,7 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent)
|
|||||||
std::string ids = result.getStringField(5);
|
std::string ids = result.getStringField(5);
|
||||||
|
|
||||||
ids.erase(std::remove_if(ids.begin(), ids.end(), ::isspace), ids.end());
|
ids.erase(std::remove_if(ids.begin(), ids.end(), ::isspace), ids.end());
|
||||||
|
|
||||||
std::istringstream stream(ids);
|
std::istringstream stream(ids);
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|
||||||
@ -99,9 +99,9 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent)
|
|||||||
m_Items.push_back(value);
|
m_Items.push_back(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Equipped = {};
|
m_Equipped = {};
|
||||||
|
|
||||||
for (const auto item : m_Items)
|
for (const auto item : m_Items)
|
||||||
{
|
{
|
||||||
if (inventoryComponent->IsEquipped(item))
|
if (inventoryComponent->IsEquipped(item))
|
||||||
@ -141,11 +141,11 @@ void ItemSet::OnEquip(const LOT lot)
|
|||||||
|
|
||||||
auto* skillComponent = m_InventoryComponent->GetParent()->GetComponent<SkillComponent>();
|
auto* skillComponent = m_InventoryComponent->GetParent()->GetComponent<SkillComponent>();
|
||||||
auto* missionComponent = m_InventoryComponent->GetParent()->GetComponent<MissionComponent>();
|
auto* missionComponent = m_InventoryComponent->GetParent()->GetComponent<MissionComponent>();
|
||||||
|
|
||||||
for (const auto skill : skillSet)
|
for (const auto skill : skillSet)
|
||||||
{
|
{
|
||||||
auto* skillTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior");
|
auto* skillTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior");
|
||||||
|
|
||||||
const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID;
|
const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID;
|
||||||
|
|
||||||
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, skill);
|
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, skill);
|
||||||
@ -167,11 +167,11 @@ void ItemSet::OnUnEquip(const LOT lot)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& skillSet = GetSkillSet(m_Equipped.size());
|
const auto& skillSet = GetSkillSet(m_Equipped.size());
|
||||||
|
|
||||||
m_Equipped.erase(index);
|
m_Equipped.erase(index);
|
||||||
|
|
||||||
if (skillSet.empty())
|
if (skillSet.empty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -199,7 +199,7 @@ uint32_t ItemSet::GetID() const
|
|||||||
return m_ID;
|
return m_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemSet::Update(float deltaTime)
|
void ItemSet::Update(float deltaTime)
|
||||||
{
|
{
|
||||||
for (auto& passiveAbility : m_PassiveAbilities)
|
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)
|
for (auto& passiveAbility : m_PassiveAbilities)
|
||||||
{
|
{
|
||||||
|
3
dGame/dMission/CMakeLists.txt
Normal file
3
dGame/dMission/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
set(DGAME_DMISSION_SOURCES "Mission.cpp"
|
||||||
|
"MissionPrerequisites.cpp"
|
||||||
|
"MissionTask.cpp" PARENT_SCOPE)
|
@ -421,7 +421,9 @@ void Mission::YieldRewards() {
|
|||||||
if (param.empty() || (param[0] & 1) == 0) // Should items be removed?
|
if (param.empty() || (param[0] & 1) == 0) // Should items be removed?
|
||||||
{
|
{
|
||||||
for (const auto target : task->GetAllTargets()) {
|
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);
|
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_ITEM_COLLECTION, target, LWOOBJID_EMPTY, "", -task->GetClientInfo().targetValue);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef MISSION_H
|
||||||
|
#define MISSION_H
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -259,3 +262,5 @@ private:
|
|||||||
*/
|
*/
|
||||||
std::vector<MissionTask*> m_Tasks;
|
std::vector<MissionTask*> m_Tasks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef MISSIONLOCKSTATE_H
|
||||||
|
#define MISSIONLOCKSTATE_H
|
||||||
|
|
||||||
enum class MissionLockState : int
|
enum class MissionLockState : int
|
||||||
{
|
{
|
||||||
MISSION_LOCK_LOCKED,
|
MISSION_LOCK_LOCKED,
|
||||||
MISSION_LOCK_NEW,
|
MISSION_LOCK_NEW,
|
||||||
MISSION_LOCK_UNLOCKED,
|
MISSION_LOCK_UNLOCKED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef __MISSIONSTATE__H__
|
||||||
|
#define __MISSIONSTATE__H__
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the possible states a mission can be in
|
* Represents the possible states a mission can be in
|
||||||
*/
|
*/
|
||||||
@ -49,3 +52,5 @@ enum class MissionState : int {
|
|||||||
*/
|
*/
|
||||||
MISSION_STATE_COMPLETE_READY_TO_COMPLETE = 12
|
MISSION_STATE_COMPLETE_READY_TO_COMPLETE = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif //!__MISSIONSTATE__H__
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef MISSIONTASK_H
|
||||||
|
#define MISSIONTASK_H
|
||||||
|
|
||||||
#include "CDMissionTasksTable.h"
|
#include "CDMissionTasksTable.h"
|
||||||
#include "MissionTaskType.h"
|
#include "MissionTaskType.h"
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
@ -180,3 +183,5 @@ private:
|
|||||||
*/
|
*/
|
||||||
void CheckCompletion() const;
|
void CheckCompletion() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef MISSIONTASKTYPE_H
|
||||||
|
#define MISSIONTASKTYPE_H
|
||||||
|
|
||||||
//! An enum for mission task types
|
//! An enum for mission task types
|
||||||
enum class MissionTaskType : int {
|
enum class MissionTaskType : int {
|
||||||
MISSION_TASK_TYPE_UNKNOWN = -1, //!< The task type is unknown
|
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_PLACE_MODEL = 25, //!< A task for picking up a model
|
||||||
MISSION_TASK_TYPE_VISIT_PROPERTY = 30 //!< A task for visiting a property
|
MISSION_TASK_TYPE_VISIT_PROPERTY = 30 //!< A task for visiting a property
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user