mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-26 15:37:20 +00:00
Merge branch 'main' into cdclient-rework
This commit is contained in:
commit
45ae46f6f1
7
.github/workflows/build-and-test.yml
vendored
7
.github/workflows/build-and-test.yml
vendored
@ -12,18 +12,21 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ windows-2022, ubuntu-20.04 ]
|
||||
os: [ windows-2022, ubuntu-20.04, macos-11 ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Add msbuild to PATH (windows only)
|
||||
- name: Add msbuild to PATH (Windows only)
|
||||
if: ${{ matrix.os == 'windows-2022' }}
|
||||
uses: microsoft/setup-msbuild@v1.1
|
||||
with:
|
||||
vs-version: '[17,18)'
|
||||
msbuild-architecture: x64
|
||||
- name: Install libssl (Mac Only)
|
||||
if: ${{ matrix.os == 'macos-11' }}
|
||||
run: brew install openssl@3
|
||||
- name: cmake
|
||||
uses: lukka/run-cmake@v10
|
||||
with:
|
||||
|
546
CMakeLists.txt
546
CMakeLists.txt
@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.14)
|
||||
project(Darkflame)
|
||||
include(CTest)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Read variables from file
|
||||
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
|
||||
|
||||
@ -10,92 +12,67 @@ string(REPLACE "\n" ";" variables ${variables})
|
||||
|
||||
# Set the cmake variables, formatted as "VARIABLE #" in variables
|
||||
foreach(variable ${variables})
|
||||
# If the string contains a #, skip it
|
||||
if(NOT "${variable}" MATCHES "#")
|
||||
|
||||
# Split the variable into name and value
|
||||
string(REPLACE "=" ";" variable ${variable})
|
||||
# If the string contains a #, skip it
|
||||
if(NOT "${variable}" MATCHES "#")
|
||||
|
||||
# Split the variable into name and value
|
||||
string(REPLACE "=" ";" variable ${variable})
|
||||
|
||||
# Check that the length of the variable is 2 (name and value)
|
||||
list(LENGTH variable length)
|
||||
if(${length} EQUAL 2)
|
||||
# Check that the length of the variable is 2 (name and value)
|
||||
list(LENGTH variable length)
|
||||
if(${length} EQUAL 2)
|
||||
|
||||
list(GET variable 0 variable_name)
|
||||
list(GET variable 1 variable_value)
|
||||
list(GET variable 0 variable_name)
|
||||
list(GET variable 1 variable_value)
|
||||
|
||||
# Set the variable
|
||||
set(${variable_name} ${variable_value})
|
||||
# Set the variable
|
||||
set(${variable_name} ${variable_value})
|
||||
|
||||
# Add compiler definition
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}")
|
||||
# Add compiler definition
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D${variable_name}=${variable_value}")
|
||||
|
||||
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
||||
message(STATUS "Variable: ${variable_name} = ${variable_value}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# On windows it's better to build this from source, as there's no way FindZLIB is gonna find it
|
||||
if(NOT WIN32)
|
||||
find_package(ZLIB REQUIRED)
|
||||
endif()
|
||||
|
||||
# Fetch External (Non-Submodule) Libraries
|
||||
if(WIN32)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
zlib
|
||||
URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip
|
||||
URL_HASH MD5=9d6a627693163bbbf3f26403a3a0b0b1
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(zlib)
|
||||
|
||||
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 AND NOT APPLE)
|
||||
include(FetchContent)
|
||||
if (__include_backtrace__ AND __compile_backtrace__)
|
||||
FetchContent_Declare(
|
||||
backtrace
|
||||
GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(backtrace)
|
||||
|
||||
if (NOT EXISTS ${backtrace_SOURCE_DIR}/.libs)
|
||||
set(backtrace_make_cmd "${backtrace_SOURCE_DIR}/configure --prefix=\"/usr\" --enable-shared --with-system-libunwind")
|
||||
|
||||
execute_process(
|
||||
COMMAND bash -c "cd ${backtrace_SOURCE_DIR} && ${backtrace_make_cmd} && make && cd ${CMAKE_SOURCE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
link_directories(${backtrace_SOURCE_DIR}/.libs/)
|
||||
include_directories(${backtrace_SOURCE_DIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Set the version
|
||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}")
|
||||
|
||||
# Echo the version
|
||||
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
if(WIN32)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
endif(WIN32)
|
||||
# Compiler flags:
|
||||
# Disabled deprecated warnings as the MySQL includes have deprecated code in them.
|
||||
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.
|
||||
# Disabled no-register
|
||||
# Disabled unknown pragmas because Linux doesn't understand Windows pragmas.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPROJECT_VERSION=${PROJECT_VERSION}")
|
||||
if(UNIX)
|
||||
if(APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -fPIC")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -D_GLIBCXX_USE_CXX11_ABI=0 -D_GLIBCXX_USE_CXX17_ABI=0 -static-libgcc -fPIC")
|
||||
endif()
|
||||
if (__dynamic)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic")
|
||||
endif()
|
||||
if (__ggdb)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -O2 -fPIC")
|
||||
elseif(MSVC)
|
||||
# Skip warning for invalid conversion from size_t to uint32_t for all targets below for now
|
||||
add_compile_options("/wd4267")
|
||||
elseif(WIN32)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
# Our output dir
|
||||
set(CMAKE_BINARY_DIR ${PROJECT_BINARY_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Create a /res directory
|
||||
make_directory(${CMAKE_BINARY_DIR}/res)
|
||||
@ -107,351 +84,172 @@ make_directory(${CMAKE_BINARY_DIR}/locale)
|
||||
make_directory(${CMAKE_BINARY_DIR}/logs)
|
||||
|
||||
# Copy ini files on first build
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/authconfig.ini)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/authconfig.ini ${PROJECT_BINARY_DIR}/authconfig.ini
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/chatconfig.ini)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/chatconfig.ini ${PROJECT_BINARY_DIR}/chatconfig.ini
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/worldconfig.ini)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/worldconfig.ini ${PROJECT_BINARY_DIR}/worldconfig.ini
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/masterconfig.ini)
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/masterconfig.ini ${PROJECT_BINARY_DIR}/masterconfig.ini
|
||||
COPYONLY
|
||||
)
|
||||
set(INI_FILES "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini")
|
||||
foreach(ini ${INI_FILES})
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${ini})
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/resources/${ini} ${PROJECT_BINARY_DIR}/${ini}
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Copy vanity files on first build
|
||||
set(VANITY_FILES "CREDITS.md" "INFO.md" "TESTAMENT.md" "NPC.xml")
|
||||
foreach(file ${VANITY_FILES})
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/${file}" "${CMAKE_BINARY_DIR}/vanity/${file}" COPYONLY)
|
||||
endforeach()
|
||||
|
||||
# Move our migrations for MasterServer to run
|
||||
file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/migrations/)
|
||||
file(GLOB SQL_FILES ${CMAKE_SOURCE_DIR}/migrations/dlu/*.sql)
|
||||
foreach(file ${SQL_FILES})
|
||||
get_filename_component(file ${file} NAME)
|
||||
if (NOT EXISTS ${PROJECT_BINARY_DIR}/migrations/${file})
|
||||
configure_file(
|
||||
${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/${file}
|
||||
COPYONLY
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Create our list of include directories
|
||||
set(INCLUDED_DIRECTORIES
|
||||
"dCommon"
|
||||
"dChatFilter"
|
||||
"dGame"
|
||||
"dGame/dBehaviors"
|
||||
"dGame/dComponents"
|
||||
"dGame/dGameMessages"
|
||||
"dGame/dInventory"
|
||||
"dGame/dMission"
|
||||
"dGame/dEntity"
|
||||
"dGame/dUtilities"
|
||||
"dPhysics"
|
||||
"dZoneManager"
|
||||
"dDatabase"
|
||||
"dDatabase/Tables"
|
||||
"dNet"
|
||||
"dScripts"
|
||||
|
||||
"thirdparty/raknet/Source"
|
||||
"thirdparty/tinyxml2"
|
||||
"thirdparty/recastnavigation/Recast/Include"
|
||||
"thirdparty/recastnavigation/Detour/Include"
|
||||
"thirdparty/SQLite"
|
||||
"thirdparty/cpplinq"
|
||||
)
|
||||
|
||||
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
||||
if (APPLE)
|
||||
include_directories("/usr/local/include/")
|
||||
endif()
|
||||
|
||||
# Copy files to output
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/CREDITS.md" "${CMAKE_BINARY_DIR}/vanity/CREDITS.md" COPYONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/INFO.md" "${CMAKE_BINARY_DIR}/vanity/INFO.md" COPYONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/TESTAMENT.md" "${CMAKE_BINARY_DIR}/vanity/TESTAMENT.md" COPYONLY)
|
||||
configure_file("${CMAKE_SOURCE_DIR}/vanity/NPC.xml" "${CMAKE_BINARY_DIR}/vanity/NPC.xml" COPYONLY)
|
||||
if (WIN32)
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include")
|
||||
elseif (UNIX)
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt")
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt")
|
||||
endif()
|
||||
|
||||
# 3rdparty includes
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/raknet/Source/)
|
||||
if(APPLE)
|
||||
include_directories(/usr/local/include/)
|
||||
endif(APPLE)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Recast/Include)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/recastnavigation/Detour/Include)
|
||||
include_directories(${ZLIB_INCLUDE_DIRS})
|
||||
|
||||
# Bcrypt
|
||||
if (NOT WIN32)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt)
|
||||
else ()
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include)
|
||||
endif ()
|
||||
|
||||
# Our includes
|
||||
# Add binary directory as an include directory
|
||||
include_directories(${PROJECT_BINARY_DIR})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dChatFilter/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dCommon/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dBehaviors)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dComponents)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dGameMessages)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dInventory)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dMission)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dEntity)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dGame/dUtilities)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dPhysics/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dZoneManager/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dDatabase/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dDatabase/Tables/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/SQLite/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/thirdparty/cpplinq/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dNet/)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/dScripts/)
|
||||
|
||||
# Lib folders:
|
||||
# Actually include the directories from our list
|
||||
foreach (dir ${INCLUDED_DIRECTORIES})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/${dir})
|
||||
endforeach()
|
||||
|
||||
# Add linking directories:
|
||||
link_directories(${PROJECT_BINARY_DIR})
|
||||
|
||||
# Third-Party libraries
|
||||
# Load all of our third party directories
|
||||
add_subdirectory(thirdparty)
|
||||
|
||||
# Source Code
|
||||
# Glob together all headers that need to be precompiled
|
||||
file(
|
||||
GLOB SOURCES
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dWorldServer/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for AuthServer
|
||||
file(
|
||||
GLOB SOURCES_AUTH
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dAuthServer/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for MasterServer
|
||||
file(
|
||||
GLOB SOURCES_MASTER
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dMasterServer/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for ChatServer
|
||||
file(
|
||||
GLOB SOURCES_CHAT
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dChatServer/*.cpp
|
||||
)
|
||||
|
||||
# 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
|
||||
GLOB HEADERS_DDATABASE
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/*.h
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
||||
)
|
||||
|
||||
file(
|
||||
GLOB HEADERS_DDATABASE
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/*.h
|
||||
${PROJECT_SOURCE_DIR}/dDatabase/Tables/*.h
|
||||
${PROJECT_SOURCE_DIR}/thirdparty/SQLite/*.h
|
||||
GLOB HEADERS_DZONEMANAGER
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dZoneManager/*.h
|
||||
)
|
||||
|
||||
file(
|
||||
GLOB HEADERS_DZONEMANAGER
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dZoneManager/*.h
|
||||
GLOB HEADERS_DCOMMON
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dCommon/*.h
|
||||
)
|
||||
|
||||
file(
|
||||
GLOB HEADERS_DCOMMON
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dCommon/*.h
|
||||
GLOB HEADERS_DGAME
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dGame/Entity.h
|
||||
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h
|
||||
${PROJECT_SOURCE_DIR}/dGame/EntityManager.h
|
||||
${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h
|
||||
)
|
||||
|
||||
file(
|
||||
GLOB HEADERS_DGAME
|
||||
LIST_DIRECTORIES false
|
||||
${PROJECT_SOURCE_DIR}/dGame/Entity.h
|
||||
${PROJECT_SOURCE_DIR}/dGame/dGameMessages/GameMessages.h
|
||||
${PROJECT_SOURCE_DIR}/dGame/EntityManager.h
|
||||
${PROJECT_SOURCE_DIR}/dScripts/CppScripts.h
|
||||
)
|
||||
# Add our library subdirectories for creation of the library object
|
||||
add_subdirectory(dCommon)
|
||||
add_subdirectory(dDatabase)
|
||||
add_subdirectory(dChatFilter)
|
||||
add_subdirectory(dNet)
|
||||
add_subdirectory(dScripts) # Add for dGame to use
|
||||
add_subdirectory(dGame)
|
||||
add_subdirectory(dZoneManager)
|
||||
add_subdirectory(dPhysics)
|
||||
|
||||
# Source Code for dNet
|
||||
file(
|
||||
GLOB SOURCES_DNET
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dNet/*.cpp
|
||||
)
|
||||
# Create a list of common libraries shared between all binaries
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp")
|
||||
|
||||
# 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
|
||||
)
|
||||
# Add platform specific common libraries
|
||||
if (UNIX)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "dl" "pthread")
|
||||
|
||||
# Source Code for dZoneManager
|
||||
file(
|
||||
GLOB SOURCES_DZM
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dZoneManager/*.cpp
|
||||
)
|
||||
if (NOT APPLE AND __include_backtrace__)
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} "backtrace")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Source Code for dPhysics
|
||||
file(
|
||||
GLOB SOURCES_DPHYSICS
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${PROJECT_SOURCE_DIR}/dPhysics/*.cpp
|
||||
)
|
||||
add_subdirectory(tests)
|
||||
|
||||
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)
|
||||
# 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
|
||||
|
||||
# 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(dDatabase sqlite3)
|
||||
target_link_libraries(dNet dCommon) #Needed because otherwise linker errors occur.
|
||||
target_link_libraries(dCommon ZLIB::ZLIB)
|
||||
target_link_libraries(dCommon libbcrypt)
|
||||
target_link_libraries(dDatabase mariadbConnCpp)
|
||||
target_link_libraries(dNet dDatabase)
|
||||
target_link_libraries(dGame dDatabase)
|
||||
target_link_libraries(dChatFilter dDatabase)
|
||||
|
||||
|
||||
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})
|
||||
|
||||
# Add out precompiled headers
|
||||
# Add our precompiled headers
|
||||
target_precompile_headers(
|
||||
dGame PRIVATE
|
||||
${HEADERS_DGAME}
|
||||
dGame PRIVATE
|
||||
${HEADERS_DGAME}
|
||||
)
|
||||
|
||||
target_precompile_headers(
|
||||
dZoneManager PRIVATE
|
||||
${HEADERS_DZONEMANAGER}
|
||||
dZoneManager PRIVATE
|
||||
${HEADERS_DZONEMANAGER}
|
||||
)
|
||||
|
||||
# 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}>"
|
||||
dDatabase PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:${HEADERS_DDATABASE}>"
|
||||
)
|
||||
|
||||
target_precompile_headers(
|
||||
dCommon PRIVATE
|
||||
${HEADERS_DCOMMON}
|
||||
dCommon PRIVATE
|
||||
${HEADERS_DCOMMON}
|
||||
)
|
||||
|
||||
target_precompile_headers(
|
||||
tinyxml2 PRIVATE
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>"
|
||||
)
|
||||
|
||||
# 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 mariadbConnCpp)
|
||||
if(UNIX)
|
||||
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 mariadbConnCpp)
|
||||
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 mariadbConnCpp)
|
||||
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 mariadbConnCpp)
|
||||
if(UNIX)
|
||||
target_link_libraries(ChatServer pthread)
|
||||
target_link_libraries(ChatServer dl)
|
||||
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 -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")
|
||||
endif(UNIX)
|
||||
|
||||
if(WIN32)
|
||||
add_dependencies(MasterServer WorldServer)
|
||||
add_dependencies(MasterServer AuthServer)
|
||||
add_dependencies(MasterServer ChatServer)
|
||||
endif()
|
||||
|
||||
# Finally, add the tests
|
||||
add_subdirectory(tests)
|
||||
|
||||
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",
|
||||
"inherits": "default"
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"displayName": "CI configure step for MacOS",
|
||||
"description": "Same as default, Used in GitHub actions workflow",
|
||||
"inherits": "default",
|
||||
"cacheVariables": {
|
||||
"OPENSSL_ROOT_DIR": "/usr/local/Cellar/openssl@3/3.0.5/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-windows-2022",
|
||||
"displayName": "CI configure step for Windows",
|
||||
@ -66,6 +75,13 @@
|
||||
"displayName": "Linux CI Build",
|
||||
"description": "This preset is used by the CI build on linux",
|
||||
"jobs": 2
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"displayName": "MacOS CI Build",
|
||||
"description": "This preset is used by the CI build on MacOS",
|
||||
"jobs": 2
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
@ -81,6 +97,18 @@
|
||||
"outputOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-macos-11",
|
||||
"configurePreset": "ci-macos-11",
|
||||
"displayName": "CI Tests on MacOS",
|
||||
"description": "Runs all tests on a Mac configuration",
|
||||
"execution": {
|
||||
"jobs": 2
|
||||
},
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci-windows-2022",
|
||||
"configurePreset": "ci-windows-2022",
|
||||
|
@ -1,6 +1,6 @@
|
||||
PROJECT_VERSION_MAJOR=1
|
||||
PROJECT_VERSION_MINOR=0
|
||||
PROJECT_VERSION_PATCH=2
|
||||
PROJECT_VERSION_PATCH=3
|
||||
# LICENSE
|
||||
LICENSE=AGPL-3.0
|
||||
# The network version.
|
||||
|
14
README.md
14
README.md
@ -152,13 +152,6 @@ now follow the build section for your system
|
||||
|
||||
## Setting up the environment
|
||||
|
||||
### Database
|
||||
Darkflame Universe utilizes a MySQL/MariaDB database for account and character information.
|
||||
|
||||
Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running.
|
||||
* Create a database for Darkflame Universe to use
|
||||
* Run each SQL file in the order at which they appear [here](migrations/dlu/) on the database
|
||||
|
||||
### Resources
|
||||
|
||||
**LEGO® Universe 1.10.64**
|
||||
@ -202,6 +195,13 @@ certutil -hashfile <file> SHA256
|
||||
* Move and rename `cdclient.sqlite` into `build/res/CDServer.sqlite`
|
||||
* Run each SQL file in the order at which they appear [here](migrations/cdserver/) on the SQLite database
|
||||
|
||||
### Database
|
||||
Darkflame Universe utilizes a MySQL/MariaDB database for account and character information.
|
||||
|
||||
Initial setup can vary drastically based on which operating system or distribution you are running; there are instructions out there for most setups, follow those and come back here when you have a database up and running.
|
||||
* Create a database for Darkflame Universe to use
|
||||
* Use the command `./MasterServer -m` to automatically run them.
|
||||
|
||||
**Configuration**
|
||||
|
||||
After the server has been built there should be four `ini` files in the build director: `authconfig.ini`, `chatconfig.ini`, `masterconfig.ini`, and `worldconfig.ini`. Go through them and fill in the database credentials and configure other settings if necessary.
|
||||
|
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 "GeneralUtils.h"
|
||||
#include "dLogger.h"
|
||||
#include "AddFriendResponseCode.h"
|
||||
#include "AddFriendResponseType.h"
|
||||
#include "RakString.h"
|
||||
#include "dConfig.h"
|
||||
|
||||
extern PlayerContainer playerContainer;
|
||||
|
||||
@ -21,44 +25,41 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
auto player = playerContainer.GetPlayerData(playerID);
|
||||
if (!player) return;
|
||||
|
||||
//Get our friends list from the Db:
|
||||
auto stmt = Database::CreatePreppedStmt("SELECT * FROM friends WHERE player_id = ? OR friend_id = ?");
|
||||
stmt->setUInt64(1, playerID);
|
||||
stmt->setUInt64(2, playerID);
|
||||
//Get our friends list from the Db. Using a derived table since the friend of a player can be in either column.
|
||||
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt(
|
||||
"SELECT fr.requested_player, best_friend, ci.name FROM "
|
||||
"(SELECT CASE "
|
||||
"WHEN player_id = ? THEN friend_id "
|
||||
"WHEN friend_id = ? THEN player_id "
|
||||
"END AS requested_player, best_friend FROM friends) AS fr "
|
||||
"JOIN charinfo AS ci ON ci.id = fr.requested_player "
|
||||
"WHERE fr.requested_player IS NOT NULL;"));
|
||||
stmt->setUInt(1, static_cast<uint32_t>(playerID));
|
||||
stmt->setUInt(2, static_cast<uint32_t>(playerID));
|
||||
|
||||
std::vector<FriendData> friends;
|
||||
|
||||
auto res = stmt->executeQuery();
|
||||
std::unique_ptr<sql::ResultSet> res(stmt->executeQuery());
|
||||
while (res->next()) {
|
||||
FriendData fd;
|
||||
fd.isFTP = false; // not a thing in DLU
|
||||
fd.friendID = res->getInt64(1);
|
||||
if (fd.friendID == playerID) fd.friendID = res->getUInt64(2);
|
||||
fd.friendID = res->getUInt(1);
|
||||
GeneralUtils::SetBit(fd.friendID, static_cast<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
|
||||
|
||||
//We need to find their name as well:
|
||||
{
|
||||
auto stmt = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE id=? limit 1");
|
||||
stmt->setInt(1, fd.friendID);
|
||||
|
||||
auto res = stmt->executeQuery();
|
||||
while (res->next()) {
|
||||
fd.friendName = res->getString(1);
|
||||
}
|
||||
|
||||
delete res;
|
||||
delete stmt;
|
||||
}
|
||||
fd.isBestFriend = res->getInt(2) == 3; //0 = friends, 1 = left_requested, 2 = right_requested, 3 = both_accepted - are now bffs
|
||||
if (fd.isBestFriend) player->countOfBestFriends+=1;
|
||||
fd.friendName = res->getString(3);
|
||||
|
||||
//Now check if they're online:
|
||||
auto fr = playerContainer.GetPlayerData(fd.friendID);
|
||||
|
||||
if (fr) {
|
||||
fd.isOnline = true;
|
||||
fd.zoneID = fr->zoneID;
|
||||
|
||||
//Since this friend is online, we need to update them on the fact that we've just logged in:
|
||||
SendFriendUpdate(fr, player, 1);
|
||||
SendFriendUpdate(fr, player, 1, fd.isBestFriend);
|
||||
}
|
||||
else {
|
||||
fd.isOnline = false;
|
||||
@ -68,9 +69,6 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
friends.push_back(fd);
|
||||
}
|
||||
|
||||
delete res;
|
||||
delete stmt;
|
||||
|
||||
//Now, we need to send the friendlist to the server they came from:
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
@ -93,20 +91,150 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
auto maxNumberOfBestFriendsAsString = Game::config->GetValue("max_number_of_best_friends");
|
||||
// If this config option doesn't exist, default to 5 which is what live used.
|
||||
auto maxNumberOfBestFriends = maxNumberOfBestFriendsAsString != "" ? std::stoi(maxNumberOfBestFriendsAsString) : 5U;
|
||||
CINSTREAM;
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
inStream.Read(playerID);
|
||||
std::string playerName = PacketUtils::ReadString(0x14, packet, true);
|
||||
//There's another bool here to determine if it's a best friend request, but we're not handling it right now.
|
||||
LWOOBJID requestorPlayerID;
|
||||
inStream.Read(requestorPlayerID);
|
||||
inStream.Read(requestorPlayerID);
|
||||
uint32_t spacing{};
|
||||
inStream.Read(spacing);
|
||||
std::string playerName = "";
|
||||
uint16_t character;
|
||||
bool noMoreLettersInName = false;
|
||||
|
||||
//PacketUtils::SavePacket("FriendRequest.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed());
|
||||
|
||||
//We need to check to see if the player is actually online or not:
|
||||
auto targetData = playerContainer.GetPlayerData(playerName);
|
||||
if (targetData) {
|
||||
SendFriendRequest(targetData, playerContainer.GetPlayerData(playerID));
|
||||
for (uint32_t j = 0; j < 33; j++) {
|
||||
inStream.Read(character);
|
||||
if (character == '\0') noMoreLettersInName = true;
|
||||
if (!noMoreLettersInName) playerName.push_back(static_cast<char>(character));
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -114,30 +242,75 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
inStream.Read(playerID);
|
||||
|
||||
uint8_t responseCode = packet->data[0x14];
|
||||
|
||||
AddFriendResponseCode clientResponseCode = static_cast<AddFriendResponseCode>(packet->data[0x14]);
|
||||
std::string friendName = PacketUtils::ReadString(0x15, packet, true);
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "Friend response code: %i\n", responseCode);
|
||||
|
||||
if (responseCode != 0) return; //If we're not accepting the request, end here, do not insert to friends table.
|
||||
|
||||
PacketUtils::SavePacket("HandleFriendResponse.bin", (char*)inStream.GetData(), inStream.GetNumberOfBytesUsed());
|
||||
|
||||
//Now to try and find both of these:
|
||||
auto goonA = playerContainer.GetPlayerData(playerID);
|
||||
auto goonB = playerContainer.GetPlayerData(friendName);
|
||||
if (!goonA || !goonB) return;
|
||||
auto requestor = playerContainer.GetPlayerData(playerID);
|
||||
auto requestee = playerContainer.GetPlayerData(friendName);
|
||||
if (!requestor || !requestee) return;
|
||||
|
||||
SendFriendResponse(goonB, goonA, responseCode);
|
||||
SendFriendResponse(goonA, goonB, responseCode); //Do we need to send it to both? I think so so both get the updated friendlist but... idk.
|
||||
AddFriendResponseType serverResponseCode{};
|
||||
uint8_t isAlreadyBestFriends = 0U;
|
||||
// We need to convert this response code to one we can actually send back to the client.
|
||||
switch (clientResponseCode) {
|
||||
case AddFriendResponseCode::ACCEPTED:
|
||||
serverResponseCode = AddFriendResponseType::ACCEPTED;
|
||||
break;
|
||||
case AddFriendResponseCode::BUSY:
|
||||
serverResponseCode = AddFriendResponseType::BUSY;
|
||||
break;
|
||||
case AddFriendResponseCode::CANCELLED:
|
||||
serverResponseCode = AddFriendResponseType::CANCELLED;
|
||||
break;
|
||||
case AddFriendResponseCode::REJECTED:
|
||||
serverResponseCode = AddFriendResponseType::DECLINED;
|
||||
break;
|
||||
}
|
||||
|
||||
auto stmt = Database::CreatePreppedStmt("INSERT INTO `friends`(`player_id`, `friend_id`, `best_friend`) VALUES (?,?,?)");
|
||||
stmt->setUInt64(1, goonA->playerID);
|
||||
stmt->setUInt64(2, goonB->playerID);
|
||||
stmt->setInt(3, 0);
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
// Now that we have handled the base cases, we need to check the other cases.
|
||||
if (serverResponseCode == AddFriendResponseType::ACCEPTED) {
|
||||
for (auto friendData : requestor->friends) {
|
||||
if (friendData.friendID == requestee->playerID) {
|
||||
serverResponseCode = AddFriendResponseType::ALREADYFRIEND;
|
||||
if (friendData.isBestFriend) {
|
||||
isAlreadyBestFriends = 1U;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This message is NOT sent for best friends and is handled differently for those requests.
|
||||
if (serverResponseCode == AddFriendResponseType::ACCEPTED) {
|
||||
// Add the each player to the others friend list.
|
||||
FriendData requestorData;
|
||||
requestorData.zoneID = requestor->zoneID;
|
||||
requestorData.friendID = requestor->playerID;
|
||||
requestorData.friendName = requestor->playerName;
|
||||
requestorData.isBestFriend = false;
|
||||
requestorData.isFTP = false;
|
||||
requestorData.isOnline = true;
|
||||
requestee->friends.push_back(requestorData);
|
||||
|
||||
FriendData requesteeData;
|
||||
requesteeData.zoneID = requestee->zoneID;
|
||||
requesteeData.friendID = requestee->playerID;
|
||||
requesteeData.friendName = requestee->playerName;
|
||||
requesteeData.isBestFriend = false;
|
||||
requesteeData.isFTP = false;
|
||||
requesteeData.isOnline = true;
|
||||
requestor->friends.push_back(requesteeData);
|
||||
|
||||
std::unique_ptr<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) {
|
||||
@ -145,50 +318,55 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
LWOOBJID playerID;
|
||||
inStream.Read(playerID);
|
||||
inStream.Read(playerID);
|
||||
std::string friendName = PacketUtils::ReadString(16, packet, true);
|
||||
std::string friendName = PacketUtils::ReadString(0x14, packet, true);
|
||||
|
||||
//we'll have to query the db here to find the user, since you can delete them while they're offline.
|
||||
//First, we need to find their ID:
|
||||
auto stmt = Database::CreatePreppedStmt("select id from charinfo where name=? limit 1;");
|
||||
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt("SELECT id FROM charinfo WHERE name=? LIMIT 1;"));
|
||||
stmt->setString(1, friendName.c_str());
|
||||
|
||||
LWOOBJID friendID = 0;
|
||||
auto res = stmt->executeQuery();
|
||||
std::unique_ptr<sql::ResultSet> res(stmt->executeQuery());
|
||||
while (res->next()) {
|
||||
friendID = res->getUInt64(1);
|
||||
friendID = res->getUInt(1);
|
||||
}
|
||||
|
||||
delete res;
|
||||
delete stmt;
|
||||
// Convert friendID to LWOOBJID
|
||||
GeneralUtils::SetBit(friendID, static_cast<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.
|
||||
friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_CHARACTER);
|
||||
friendID = GeneralUtils::ClearBit(friendID, OBJECT_BIT_PERSISTENT);
|
||||
|
||||
//YEET:
|
||||
auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1");
|
||||
deletestmt->setUInt64(1, playerID);
|
||||
deletestmt->setUInt64(2, friendID);
|
||||
std::unique_ptr<sql::PreparedStatement> deletestmt(Database::CreatePreppedStmt("DELETE FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"));
|
||||
deletestmt->setUInt(1, static_cast<uint32_t>(playerID));
|
||||
deletestmt->setUInt(2, static_cast<uint32_t>(friendID));
|
||||
deletestmt->setUInt(3, static_cast<uint32_t>(friendID));
|
||||
deletestmt->setUInt(4, static_cast<uint32_t>(playerID));
|
||||
deletestmt->execute();
|
||||
delete deletestmt;
|
||||
|
||||
//because I'm lazy and they can be reversed:
|
||||
{
|
||||
auto deletestmt = Database::CreatePreppedStmt("DELETE FROM `friends` WHERE player_id=? AND friend_id=? LIMIT 1");
|
||||
deletestmt->setUInt64(1, friendID);
|
||||
deletestmt->setUInt64(2, playerID);
|
||||
deletestmt->execute();
|
||||
delete deletestmt;
|
||||
}
|
||||
|
||||
//Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended:
|
||||
auto goonA = playerContainer.GetPlayerData(playerID);
|
||||
if (goonA) {
|
||||
// Remove the friend from our list of friends
|
||||
for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) {
|
||||
if ((*friendData).friendID == friendID) {
|
||||
if ((*friendData).isBestFriend) --goonA->countOfBestFriends;
|
||||
goonA->friends.erase(friendData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
SendRemoveFriend(goonA, friendName, true);
|
||||
}
|
||||
|
||||
|
||||
auto goonB = playerContainer.GetPlayerData(friendID);
|
||||
if (!goonB) return;
|
||||
// Do it again for other person
|
||||
for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) {
|
||||
if ((*friendData).friendID == playerID) {
|
||||
if ((*friendData).isBestFriend) --goonB->countOfBestFriends;
|
||||
goonB->friends.erase(friendData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID));
|
||||
SendRemoveFriend(goonB, goonAName, true);
|
||||
}
|
||||
@ -206,7 +384,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
||||
|
||||
if (playerContainer.GetIsMuted(sender)) return;
|
||||
|
||||
const auto senderName = std::string(sender->playerName.C_String());
|
||||
const auto senderName = std::string(sender->playerName.c_str());
|
||||
|
||||
inStream.SetReadOffset(0x14 * 8);
|
||||
|
||||
@ -217,8 +395,6 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
||||
|
||||
Game::logger->Log("ChatPacketHandler", "Got a message from (%s) [%d]: %s\n", senderName.c_str(), channel, message.c_str());
|
||||
|
||||
//PacketUtils::SavePacket("chat.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
||||
|
||||
if (channel != 8) return;
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
@ -231,7 +407,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet)
|
||||
|
||||
if (otherMember == nullptr) return;
|
||||
|
||||
const auto otherName = std::string(otherMember->playerName.C_String());
|
||||
const auto otherName = std::string(otherMember->playerName.c_str());
|
||||
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
@ -267,8 +443,8 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
|
||||
if (playerContainer.GetIsMuted(goonA)) return;
|
||||
|
||||
std::string goonAName = goonA->playerName.C_String();
|
||||
std::string goonBName = goonB->playerName.C_String();
|
||||
std::string goonAName = goonA->playerName.c_str();
|
||||
std::string goonBName = goonB->playerName.c_str();
|
||||
|
||||
//To the sender:
|
||||
{
|
||||
@ -454,8 +630,6 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet)
|
||||
|
||||
playerContainer.RemoveMember(team, kickedId, false, true, false);
|
||||
}
|
||||
|
||||
//PacketUtils::SavePacket("kick.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamPromote(Packet* packet)
|
||||
@ -481,8 +655,6 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet)
|
||||
|
||||
playerContainer.PromoteMember(team, promoted->playerID);
|
||||
}
|
||||
|
||||
//PacketUtils::SavePacket("promote.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
|
||||
@ -509,8 +681,6 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet)
|
||||
|
||||
playerContainer.UpdateTeamsOnWorld(team, false);
|
||||
}
|
||||
|
||||
//PacketUtils::SavePacket("option.bin", reinterpret_cast<char*>(packet->data), packet->length);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
||||
@ -550,7 +720,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
||||
|
||||
playerContainer.TeamStatusUpdate(team);
|
||||
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String()));
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.c_str()));
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
@ -560,7 +730,6 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet)
|
||||
|
||||
const auto memberName = playerContainer.GetName(memberId);
|
||||
|
||||
//ChatPacketHandler::SendTeamAddPlayer(otherMember, false, false, false, data->playerID, leaderName, data->zoneID);
|
||||
if (otherMember != nullptr)
|
||||
{
|
||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
|
||||
@ -581,7 +750,7 @@ void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender)
|
||||
//portion that will get routed:
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_TEAM_INVITE);
|
||||
|
||||
PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream);
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
bitStream.Write(sender->playerID);
|
||||
|
||||
SystemAddress sysAddr = receiver->sysAddr;
|
||||
@ -745,7 +914,7 @@ void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType) {
|
||||
void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend) {
|
||||
/*chat notification is displayed if log in / out and friend is updated in friends list
|
||||
[u8] - update type
|
||||
Update types
|
||||
@ -767,7 +936,7 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_UPDATE_FRIEND_NOTIFY);
|
||||
bitStream.Write<uint8_t>(notifyType);
|
||||
|
||||
std::string playerName = playerData->playerName.C_String();
|
||||
std::string playerName = playerData->playerName.c_str();
|
||||
|
||||
PacketUtils::WritePacketWString(playerName, 33, &bitStream);
|
||||
|
||||
@ -783,19 +952,20 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla
|
||||
bitStream.Write(playerData->zoneID.GetCloneID());
|
||||
}
|
||||
|
||||
bitStream.Write<uint8_t>(0); //isBFF
|
||||
bitStream.Write<uint8_t>(isBestFriend); //isBFF
|
||||
bitStream.Write<uint8_t>(0); //isFTP
|
||||
|
||||
SystemAddress sysAddr = friendData->sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq) {
|
||||
void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* sender) {
|
||||
if (!receiver || !sender) return;
|
||||
|
||||
//Make sure people aren't requesting people that they're already friends with:
|
||||
for (auto fr : receiver->friends) {
|
||||
if (fr.friendID == sender->playerID) {
|
||||
SendFriendResponse(sender, receiver, AddFriendResponseType::ALREADYFRIEND, fr.isBestFriend);
|
||||
return; //we have this player as a friend, yeet this function so it doesn't send another request.
|
||||
}
|
||||
}
|
||||
@ -806,30 +976,34 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send
|
||||
|
||||
//portion that will get routed:
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_REQUEST);
|
||||
PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream);
|
||||
bitStream.Write<uint8_t>(0);
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
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;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
||||
void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode) {
|
||||
void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready, uint8_t isBestFriendRequest) {
|
||||
if (!receiver || !sender) return;
|
||||
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
// Portion that will get routed:
|
||||
PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_ADD_FRIEND_RESPONSE);
|
||||
bitStream.Write<uint8_t>(responseCode);
|
||||
bitStream.Write<uint8_t>(1); //isOnline
|
||||
PacketUtils::WritePacketWString(sender->playerName.C_String(), 33, &bitStream);
|
||||
bitStream.Write(sender->playerID);
|
||||
bitStream.Write(sender->zoneID);
|
||||
bitStream.Write<uint8_t>(0); //isBFF
|
||||
bitStream.Write<uint8_t>(0); //isFTP
|
||||
|
||||
bitStream.Write(responseCode);
|
||||
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
|
||||
bitStream.Write<uint8_t>(responseCode != AddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
|
||||
// Then write the player name
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
// Then if this is an acceptance code, write the following extra info.
|
||||
if (responseCode == AddFriendResponseType::ACCEPTED) {
|
||||
bitStream.Write(sender->playerID);
|
||||
bitStream.Write(sender->zoneID);
|
||||
bitStream.Write(isBestFriendRequest); //isBFF
|
||||
bitStream.Write<uint8_t>(0); //isFTP
|
||||
}
|
||||
SystemAddress sysAddr = receiver->sysAddr;
|
||||
SEND_PACKET;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "BitStream.h"
|
||||
|
||||
struct PlayerData;
|
||||
enum class AddFriendResponseType : uint8_t;
|
||||
|
||||
namespace ChatPacketHandler {
|
||||
void HandleFriendlistRequest(Packet* packet);
|
||||
@ -31,10 +32,9 @@ namespace ChatPacketHandler {
|
||||
void SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID);
|
||||
|
||||
//FriendData is the player we're SENDING this stuff to. Player is the friend that changed state.
|
||||
void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType);
|
||||
void SendFriendUpdate(PlayerData* friendData, PlayerData* playerData, uint8_t notifyType, uint8_t isBestFriend);
|
||||
|
||||
void SendFriendRequest(PlayerData* receiver, PlayerData* sender, bool isBFFReq = false);
|
||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, uint8_t responseCode = 3);
|
||||
void SendFriendRequest(PlayerData* receiver, PlayerData* sender);
|
||||
void SendFriendResponse(PlayerData* receiver, PlayerData* sender, AddFriendResponseType responseCode, uint8_t isBestFriendsAlready = 0U, uint8_t isBestFriendRequest = 0U);
|
||||
void SendRemoveFriend(PlayerData* receiver, std::string& personToRemove, bool isSuccessful);
|
||||
};
|
||||
|
||||
|
@ -20,17 +20,25 @@ PlayerContainer::~PlayerContainer() {
|
||||
void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||
CINSTREAM;
|
||||
PlayerData* data = new PlayerData();
|
||||
inStream.SetReadOffset(inStream.GetReadOffset() + 64);
|
||||
inStream.Read(data->playerID);
|
||||
inStream.Read(data->playerID);
|
||||
inStream.Read(data->playerName);
|
||||
|
||||
uint32_t len;
|
||||
inStream.Read<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->muteExpire);
|
||||
data->sysAddr = packet->systemAddress;
|
||||
|
||||
mNames[data->playerID] = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.C_String()));
|
||||
mNames[data->playerID] = GeneralUtils::ASCIIToUTF16(std::string(data->playerName.c_str()));
|
||||
|
||||
mPlayers.insert(std::make_pair(data->playerID, data));
|
||||
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i\n", data->playerName.C_String(), data->playerID, data->zoneID.GetMapID());
|
||||
Game::logger->Log("PlayerContainer", "Added user: %s (%llu), zone: %i\n", data->playerName.c_str(), data->playerID, data->zoneID.GetMapID());
|
||||
|
||||
auto* insertLog = Database::CreatePreppedStmt("INSERT INTO activity_log (character_id, activity, time, map_id) VALUES (?, ?, ?, ?);");
|
||||
|
||||
@ -49,26 +57,22 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||
inStream.Read(playerID);
|
||||
|
||||
//Before they get kicked, we need to also send a message to their friends saying that they disconnected.
|
||||
auto player = this->GetPlayerData(playerID);
|
||||
std::unique_ptr<PlayerData> player(this->GetPlayerData(playerID));
|
||||
|
||||
if (player == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& fr : player->friends) {
|
||||
//if (!fr.isOnline) continue;
|
||||
|
||||
auto fd = this->GetPlayerData(fr.friendID);
|
||||
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player, 0);
|
||||
if (fd) ChatPacketHandler::SendFriendUpdate(fd, player.get(), 0, fr.isBestFriend);
|
||||
}
|
||||
|
||||
auto* team = GetTeam(playerID);
|
||||
|
||||
if (team != nullptr)
|
||||
{
|
||||
//TeamStatusUpdate(team);
|
||||
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.C_String()));
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(player->playerName.c_str()));
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
@ -77,7 +81,6 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||
if (otherMember == nullptr) continue;
|
||||
|
||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, playerID, {0, 0, 0});
|
||||
//ChatPacketHandler::SendTeamRemovePlayer(otherMember, false, false, true, false, team->leaderID, player->playerID, memberName);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,16 +240,10 @@ void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID)
|
||||
|
||||
if (leader == nullptr || member == nullptr) return;
|
||||
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String()));
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.C_String()));
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.c_str()));
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(member->playerName.c_str()));
|
||||
|
||||
ChatPacketHandler::SendTeamInviteConfirm(member, false, leader->playerID, leader->zoneID, team->lootFlag, 0, 0, leaderName);
|
||||
|
||||
/*
|
||||
ChatPacketHandler::SendTeamAddPlayer(member, false, false, false, leader->playerID, leaderName, leader->zoneID);
|
||||
|
||||
Game::logger->Log("PlayerContainer", "Team invite successfully accepted, leader: %s, member: %s\n", leader->playerName.C_String(), member->playerName.C_String());
|
||||
*/
|
||||
|
||||
if (!team->local)
|
||||
{
|
||||
@ -348,7 +345,7 @@ void PlayerContainer::DisbandTeam(TeamData* team)
|
||||
|
||||
if (otherMember == nullptr) continue;
|
||||
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(otherMember->playerName.C_String()));
|
||||
const auto memberName = GeneralUtils::ASCIIToUTF16(std::string(otherMember->playerName.c_str()));
|
||||
|
||||
ChatPacketHandler::SendTeamSetLeader(otherMember, LWOOBJID_EMPTY);
|
||||
ChatPacketHandler::SendTeamRemovePlayer(otherMember, true, false, false, team->local, team->leaderID, otherMember->playerID, memberName);
|
||||
@ -371,7 +368,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team)
|
||||
|
||||
if (leader == nullptr) return;
|
||||
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.C_String()));
|
||||
const auto leaderName = GeneralUtils::ASCIIToUTF16(std::string(leader->playerName.c_str()));
|
||||
|
||||
for (const auto memberId : team->memberIDs)
|
||||
{
|
||||
@ -383,10 +380,6 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team)
|
||||
{
|
||||
ChatPacketHandler::SendTeamStatus(otherMember, team->leaderID, leader->zoneID, team->lootFlag, 0, leaderName);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ChatPacketHandler::SendTeamStatus(otherMember, LWOOBJID_EMPTY, LWOZONEID(0, 0, 0), 1, 0, u"");
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTeamsOnWorld(team, false);
|
||||
|
@ -9,11 +9,12 @@
|
||||
|
||||
struct PlayerData {
|
||||
LWOOBJID playerID;
|
||||
RakNet::RakString playerName;
|
||||
std::string playerName;
|
||||
SystemAddress sysAddr;
|
||||
LWOZONEID zoneID;
|
||||
std::vector<FriendData> friends;
|
||||
time_t muteExpire;
|
||||
uint8_t countOfBestFriends = 0;
|
||||
};
|
||||
|
||||
struct TeamData {
|
||||
@ -45,7 +46,7 @@ public:
|
||||
PlayerData* GetPlayerData(const std::string& playerName) {
|
||||
for (auto player : mPlayers) {
|
||||
if (player.second) {
|
||||
std::string pn = player.second->playerName.C_String();
|
||||
std::string pn = player.second->playerName.c_str();
|
||||
if (pn == playerName) return player.second;
|
||||
}
|
||||
}
|
||||
|
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;
|
||||
}
|
||||
|
||||
#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> GetFileNamesFromFolder(const std::string& folder);
|
||||
|
||||
template <typename T>
|
||||
T Parse(const char* value);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "ZCompression.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
namespace ZCompression
|
||||
@ -70,4 +72,6 @@ namespace ZCompression
|
||||
return(nRet); // -1 or len of output
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -2,6 +2,10 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "dPlatforms.h"
|
||||
|
||||
#ifndef DARKFLAME_PLATFORM_WIN32
|
||||
|
||||
namespace ZCompression
|
||||
{
|
||||
int32_t GetMaxCompressedLength(int32_t nLenSrc);
|
||||
@ -10,3 +14,5 @@ namespace ZCompression
|
||||
|
||||
int32_t Decompress(const uint8_t* abSrc, int32_t nLenSrc, uint8_t* abDst, int32_t nLenDst, int32_t& nErr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -440,33 +440,6 @@ enum eInventoryType : uint32_t {
|
||||
INVALID // made up, for internal use!!!
|
||||
};
|
||||
|
||||
enum eItemType : int32_t {
|
||||
ITEM_TYPE_UNKNOWN = -1, //!< An unknown item type
|
||||
ITEM_TYPE_BRICK = 1, //!< A brick
|
||||
ITEM_TYPE_HAT = 2, //!< A hat / head item
|
||||
ITEM_TYPE_HAIR = 3, //!< A hair item
|
||||
ITEM_TYPE_NECK = 4, //!< A neck item
|
||||
ITEM_TYPE_LEFT_HAND = 5, //!< A left handed item
|
||||
ITEM_TYPE_RIGHT_HAND = 6, //!< A right handed item
|
||||
ITEM_TYPE_LEGS = 7, //!< A pants item
|
||||
ITEM_TYPE_LEFT_TRINKET = 8, //!< A left handled trinket item
|
||||
ITEM_TYPE_RIGHT_TRINKET = 9, //!< A right handed trinket item
|
||||
ITEM_TYPE_BEHAVIOR = 10, //!< A behavior
|
||||
ITEM_TYPE_PROPERTY = 11, //!< A property
|
||||
ITEM_TYPE_MODEL = 12, //!< A model
|
||||
ITEM_TYPE_COLLECTIBLE = 13, //!< A collectible item
|
||||
ITEM_TYPE_CONSUMABLE = 14, //!< A consumable item
|
||||
ITEM_TYPE_CHEST = 15, //!< A chest item
|
||||
ITEM_TYPE_EGG = 16, //!< An egg
|
||||
ITEM_TYPE_PET_FOOD = 17, //!< A pet food item
|
||||
ITEM_TYPE_QUEST_OBJECT = 18, //!< A quest item
|
||||
ITEM_TYPE_PET_INVENTORY_ITEM = 19, //!< A pet inventory item
|
||||
ITEM_TYPE_PACKAGE = 20, //!< A package
|
||||
ITEM_TYPE_LOOT_MODEL = 21, //!< A loot model
|
||||
ITEM_TYPE_VEHICLE = 22, //!< A vehicle
|
||||
ITEM_TYPE_CURRENCY = 23 //!< Currency
|
||||
};
|
||||
|
||||
enum eRebuildState : uint32_t {
|
||||
REBUILD_OPEN,
|
||||
REBUILD_COMPLETED = 2,
|
||||
|
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
|
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
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,6 +8,8 @@ using namespace std;
|
||||
|
||||
sql::Driver * Database::driver;
|
||||
sql::Connection * Database::con;
|
||||
sql::Properties Database::props;
|
||||
std::string Database::database;
|
||||
|
||||
void Database::Connect(const string& host, const string& database, const string& username, const string& password) {
|
||||
|
||||
@ -25,14 +27,26 @@ void Database::Connect(const string& host, const string& database, const string&
|
||||
properties["user"] = szUsername;
|
||||
properties["password"] = szPassword;
|
||||
properties["autoReconnect"] = "true";
|
||||
con = driver->connect(properties);
|
||||
con->setSchema(szDatabase);
|
||||
} //Connect
|
||||
|
||||
void Database::Destroy(std::string source) {
|
||||
Database::props = properties;
|
||||
Database::database = database;
|
||||
|
||||
Database::Connect();
|
||||
}
|
||||
|
||||
void Database::Connect() {
|
||||
con = driver->connect(Database::props);
|
||||
con->setSchema(Database::database);
|
||||
}
|
||||
|
||||
void Database::Destroy(std::string source, bool log) {
|
||||
if (!con) return;
|
||||
if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!\n", source.c_str());
|
||||
else Game::logger->Log("Database", "Destroying MySQL connection!\n");
|
||||
|
||||
if (log) {
|
||||
if (source != "") Game::logger->Log("Database", "Destroying MySQL connection from %s!\n", source.c_str());
|
||||
else Game::logger->Log("Database", "Destroying MySQL connection!\n");
|
||||
}
|
||||
|
||||
con->close();
|
||||
delete con;
|
||||
} //Destroy
|
||||
@ -48,13 +62,7 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
|
||||
sql::SQLString str(test, size);
|
||||
|
||||
if (!con) {
|
||||
//Connect to the MySQL Database
|
||||
std::string mysql_host = Game::config->GetValue("mysql_host");
|
||||
std::string mysql_database = Game::config->GetValue("mysql_database");
|
||||
std::string mysql_username = Game::config->GetValue("mysql_username");
|
||||
std::string mysql_password = Game::config->GetValue("mysql_password");
|
||||
|
||||
Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||
Connect();
|
||||
Game::logger->Log("Database", "Trying to reconnect to MySQL\n");
|
||||
}
|
||||
|
||||
@ -64,13 +72,7 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
|
||||
|
||||
con = nullptr;
|
||||
|
||||
//Connect to the MySQL Database
|
||||
std::string mysql_host = Game::config->GetValue("mysql_host");
|
||||
std::string mysql_database = Game::config->GetValue("mysql_database");
|
||||
std::string mysql_username = Game::config->GetValue("mysql_username");
|
||||
std::string mysql_password = Game::config->GetValue("mysql_password");
|
||||
|
||||
Connect(mysql_host, mysql_database, mysql_username, mysql_password);
|
||||
Connect();
|
||||
Game::logger->Log("Database", "Trying to reconnect to MySQL from invalid or closed connection\n");
|
||||
}
|
||||
|
||||
@ -79,3 +81,6 @@ sql::PreparedStatement* Database::CreatePreppedStmt(const std::string& query) {
|
||||
return stmt;
|
||||
} //CreatePreppedStmt
|
||||
|
||||
void Database::Commit() {
|
||||
Database::con->commit();
|
||||
}
|
@ -13,10 +13,17 @@ class Database {
|
||||
private:
|
||||
static sql::Driver *driver;
|
||||
static sql::Connection *con;
|
||||
|
||||
static sql::Properties props;
|
||||
static std::string database;
|
||||
public:
|
||||
static void Connect(const std::string& host, const std::string& database, const std::string& username, const std::string& password);
|
||||
static void Destroy(std::string source="");
|
||||
static void Connect();
|
||||
static void Destroy(std::string source = "", bool log = true);
|
||||
|
||||
static sql::Statement* CreateStmt();
|
||||
static sql::PreparedStatement* CreatePreppedStmt(const std::string& query);
|
||||
static void Commit();
|
||||
|
||||
static std::string GetDatabase() { return database; }
|
||||
static sql::Properties GetProperties() { return props; }
|
||||
};
|
||||
|
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);
|
||||
};
|
@ -24,7 +24,13 @@ CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
|
||||
entry.behaviorID = tableData.getIntField(0, -1);
|
||||
entry.templateID = tableData.getIntField(1, -1);
|
||||
entry.effectID = tableData.getIntField(2, -1);
|
||||
entry.effectHandle = tableData.getStringField(3, "");
|
||||
auto candidateToAdd = tableData.getStringField(3, "");
|
||||
auto parameter = m_EffectHandles.find(candidateToAdd);
|
||||
if (parameter != m_EffectHandles.end()) {
|
||||
entry.effectHandle = parameter;
|
||||
} else {
|
||||
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
|
||||
}
|
||||
|
||||
this->entries.push_back(entry);
|
||||
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
|
||||
@ -62,7 +68,8 @@ const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behav
|
||||
if (entry == this->entriesMappedByBehaviorID.end()) {
|
||||
CDBehaviorTemplate entryToReturn;
|
||||
entryToReturn.behaviorID = 0;
|
||||
entryToReturn.effectHandle = "";
|
||||
entryToReturn.effectHandle = m_EffectHandles.end();
|
||||
entryToReturn.effectID = 0;
|
||||
return entryToReturn;
|
||||
} else {
|
||||
return entry->second;
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
/*!
|
||||
\file CDBehaviorTemplateTable.hpp
|
||||
@ -11,10 +12,10 @@
|
||||
|
||||
//! BehaviorTemplate Entry Struct
|
||||
struct CDBehaviorTemplate {
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
unsigned int templateID; //!< The Template ID (LOT)
|
||||
unsigned int effectID; //!< The Effect ID attached
|
||||
std::string effectHandle; //!< The effect handle
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
unsigned int templateID; //!< The Template ID (LOT)
|
||||
unsigned int effectID; //!< The Effect ID attached
|
||||
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
|
||||
};
|
||||
|
||||
|
||||
@ -23,6 +24,7 @@ class CDBehaviorTemplateTable : public CDTable {
|
||||
private:
|
||||
std::vector<CDBehaviorTemplate> entries;
|
||||
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
|
||||
std::unordered_set<std::string> m_EffectHandles;
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
|
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)
|
@ -109,6 +109,11 @@ Entity::~Entity() {
|
||||
|
||||
m_Components.erase(pair.first);
|
||||
}
|
||||
|
||||
for (auto child : m_ChildEntities) {
|
||||
if (child) child->RemoveParent();
|
||||
}
|
||||
|
||||
if (m_ParentEntity) {
|
||||
m_ParentEntity->RemoveChild(this);
|
||||
}
|
||||
@ -1201,17 +1206,21 @@ void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) {
|
||||
}
|
||||
|
||||
void Entity::Update(const float deltaTime) {
|
||||
for (int i = 0; i < m_Timers.size(); i++) {
|
||||
m_Timers[i]->Update(deltaTime);
|
||||
if (m_Timers[i]->GetTime() <= 0) {
|
||||
const auto timerName = m_Timers[i]->GetName();
|
||||
uint32_t timerPosition;
|
||||
timerPosition = 0;
|
||||
while (timerPosition < m_Timers.size()) {
|
||||
m_Timers[timerPosition]->Update(deltaTime);
|
||||
if (m_Timers[timerPosition]->GetTime() <= 0) {
|
||||
const auto timerName = m_Timers[timerPosition]->GetName();
|
||||
|
||||
delete m_Timers[i];
|
||||
m_Timers.erase(m_Timers.begin() + i);
|
||||
delete m_Timers[timerPosition];
|
||||
m_Timers.erase(m_Timers.begin() + timerPosition);
|
||||
|
||||
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
|
||||
script->OnTimerDone(this, timerName);
|
||||
}
|
||||
} else {
|
||||
timerPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1223,6 +1232,14 @@ void Entity::Update(const float deltaTime) {
|
||||
m_CallbackTimers.erase(m_CallbackTimers.begin() + i);
|
||||
}
|
||||
}
|
||||
|
||||
// Add pending timers to the list of timers so they start next tick.
|
||||
if (m_PendingTimers.size() > 0) {
|
||||
for (auto namedTimer : m_PendingTimers) {
|
||||
m_Timers.push_back(namedTimer);
|
||||
}
|
||||
m_PendingTimers.clear();
|
||||
}
|
||||
|
||||
if (IsSleeping())
|
||||
{
|
||||
@ -1650,18 +1667,24 @@ void Entity::AddChild(Entity* child) {
|
||||
|
||||
void Entity::RemoveChild(Entity* child) {
|
||||
if (!child) return;
|
||||
for (auto entity = m_ChildEntities.begin(); entity != m_ChildEntities.end(); entity++) {
|
||||
if (*entity && (*entity)->GetObjectID() == child->GetObjectID()) {
|
||||
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(entity);
|
||||
return;
|
||||
m_ChildEntities.erase(m_ChildEntities.begin() + entityPosition);
|
||||
} else {
|
||||
entityPosition++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::RemoveParent() {
|
||||
this->m_ParentEntity = nullptr;
|
||||
}
|
||||
|
||||
void Entity::AddTimer(std::string name, float time) {
|
||||
EntityTimer* timer = new EntityTimer(name, time);
|
||||
m_Timers.push_back(timer);
|
||||
m_PendingTimers.push_back(timer);
|
||||
}
|
||||
|
||||
void Entity::AddCallbackTimer(float time, std::function<void()> callback) {
|
||||
|
@ -144,6 +144,7 @@ public:
|
||||
|
||||
void AddChild(Entity* child);
|
||||
void RemoveChild(Entity* child);
|
||||
void RemoveParent();
|
||||
void AddTimer(std::string name, float time);
|
||||
void AddCallbackTimer(float time, std::function<void()> callback);
|
||||
bool HasTimer(const std::string& name);
|
||||
@ -309,6 +310,7 @@ protected:
|
||||
|
||||
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_PendingTimers;
|
||||
std::vector<EntityCallbackTimer*> m_CallbackTimers;
|
||||
|
||||
bool m_ShouldDestroyAfterUpdate = false;
|
||||
|
@ -401,7 +401,7 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr
|
||||
Game::server->Send(&stream, sysAddr, false);
|
||||
}
|
||||
|
||||
PacketUtils::SavePacket("[24]_"+std::to_string(entity->GetObjectID()) + "_" + std::to_string(m_SerializationCounter) + ".bin", (char*)stream.GetData(), stream.GetNumberOfBytesUsed());
|
||||
// PacketUtils::SavePacket("[24]_"+std::to_string(entity->GetObjectID()) + "_" + std::to_string(m_SerializationCounter) + ".bin", (char*)stream.GetData(), stream.GetNumberOfBytesUsed());
|
||||
|
||||
if (entity->IsPlayer())
|
||||
{
|
||||
|
@ -369,10 +369,8 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
}
|
||||
|
||||
LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet);
|
||||
objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_CHARACTER);
|
||||
objectID = GeneralUtils::ClearBit(objectID, OBJECT_BIT_PERSISTENT);
|
||||
|
||||
uint32_t charID = static_cast<uint32_t>(objectID);
|
||||
uint32_t charID = static_cast<uint32_t>(objectID);
|
||||
|
||||
Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)\n", objectID, charID);
|
||||
|
||||
//Check if this user has this character:
|
||||
@ -402,10 +400,14 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
}
|
||||
{
|
||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM friends WHERE player_id=? OR friend_id=?;");
|
||||
stmt->setUInt64(1, charID);
|
||||
stmt->setUInt64(2, charID);
|
||||
stmt->setUInt(1, charID);
|
||||
stmt->setUInt(2, charID);
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION);
|
||||
bitStream.Write(objectID);
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
}
|
||||
{
|
||||
sql::PreparedStatement* stmt = Database::CreatePreppedStmt("DELETE FROM leaderboard WHERE character_id=?;");
|
||||
|
@ -409,7 +409,7 @@ Behavior::Behavior(const uint32_t behaviorId)
|
||||
{
|
||||
auto behaviorTemplateTable = CDClientManager::Instance()->GetTable<CDBehaviorTemplateTable>("BehaviorTemplate");
|
||||
|
||||
CDBehaviorTemplate templateInDatabase;
|
||||
CDBehaviorTemplate templateInDatabase{};
|
||||
|
||||
if (behaviorTemplateTable) {
|
||||
auto templateEntry = behaviorTemplateTable->GetByBehaviorID(behaviorId);
|
||||
@ -445,7 +445,7 @@ Behavior::Behavior(const uint32_t behaviorId)
|
||||
|
||||
this->m_effectId = templateInDatabase.effectID;
|
||||
|
||||
this->m_effectHandle = templateInDatabase.effectHandle != "" ? new std::string(templateInDatabase.effectHandle) : nullptr;
|
||||
this->m_effectHandle = *templateInDatabase.effectHandle != "" ? new std::string(*templateInDatabase.effectHandle) : nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
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)
|
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)
|
@ -179,6 +179,18 @@ public:
|
||||
*/
|
||||
void SetLastRocketItemID(LWOOBJID lastRocketItemID) { m_LastRocketItemID = lastRocketItemID; }
|
||||
|
||||
/**
|
||||
* Gets the object ID of the mount item that is being used
|
||||
* @return the object ID of the mount item that is being used
|
||||
*/
|
||||
LWOOBJID GetMountItemID() const { return m_MountItemID; }
|
||||
|
||||
/**
|
||||
* Sets the object ID of the mount item that is being used
|
||||
* @param m_MountItemID the object ID of the mount item that is being used
|
||||
*/
|
||||
void SetMountItemID(LWOOBJID mountItemID) { m_MountItemID = mountItemID; }
|
||||
|
||||
/**
|
||||
* Gives the player rewards for the last level that they leveled up from
|
||||
*/
|
||||
@ -579,6 +591,11 @@ private:
|
||||
* ID of the last rocket used
|
||||
*/
|
||||
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
|
||||
|
||||
/**
|
||||
* Mount Item ID
|
||||
*/
|
||||
LWOOBJID m_MountItemID = LWOOBJID_EMPTY;
|
||||
};
|
||||
|
||||
#endif // CHARACTERCOMPONENT_H
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "PropertyManagementComponent.h"
|
||||
#include "DestroyableComponent.h"
|
||||
#include "dConfig.h"
|
||||
#include "eItemType.h"
|
||||
|
||||
InventoryComponent::InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document) : Component(parent)
|
||||
{
|
||||
@ -1024,13 +1025,13 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks)
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == ITEM_TYPE_LOOT_MODEL || type == ITEM_TYPE_VEHICLE)
|
||||
if (type == eItemType::ITEM_TYPE_LOOT_MODEL || type == eItemType::ITEM_TYPE_VEHICLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != ITEM_TYPE_LOOT_MODEL && type != ITEM_TYPE_MODEL)
|
||||
if (type != eItemType::ITEM_TYPE_LOOT_MODEL && type != eItemType::ITEM_TYPE_MODEL)
|
||||
{
|
||||
if (!item->GetBound() && !item->GetPreconditionExpression()->Check(m_Parent))
|
||||
{
|
||||
@ -1411,15 +1412,15 @@ void InventoryComponent::RemoveDatabasePet(LWOOBJID id)
|
||||
BehaviorSlot InventoryComponent::FindBehaviorSlot(const eItemType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ITEM_TYPE_HAT:
|
||||
case eItemType::ITEM_TYPE_HAT:
|
||||
return BehaviorSlot::Head;
|
||||
case ITEM_TYPE_NECK:
|
||||
case eItemType::ITEM_TYPE_NECK:
|
||||
return BehaviorSlot::Neck;
|
||||
case ITEM_TYPE_LEFT_HAND:
|
||||
case eItemType::ITEM_TYPE_LEFT_HAND:
|
||||
return BehaviorSlot::Offhand;
|
||||
case ITEM_TYPE_RIGHT_HAND:
|
||||
case eItemType::ITEM_TYPE_RIGHT_HAND:
|
||||
return BehaviorSlot::Primary;
|
||||
case ITEM_TYPE_CONSUMABLE:
|
||||
case eItemType::ITEM_TYPE_CONSUMABLE:
|
||||
return BehaviorSlot::Consumable;
|
||||
default:
|
||||
return BehaviorSlot::Invalid;
|
||||
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#ifndef INVENTORYCOMPONENT_H
|
||||
#define INVENTORYCOMPONENT_H
|
||||
@ -25,6 +25,8 @@ class ItemSet;
|
||||
|
||||
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
|
||||
* of different types, each type representing a different group of items, see `eInventoryType` for a list of
|
||||
|
@ -1,10 +1,13 @@
|
||||
#include "PossessableComponent.h"
|
||||
#include "PossessorComponent.h"
|
||||
#include "EntityManager.h"
|
||||
#include "Inventory.h"
|
||||
#include "Item.h"
|
||||
|
||||
PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId) : Component(parent){
|
||||
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 = ?;");
|
||||
|
@ -54,6 +54,18 @@ class PossessableComponent : public Component {
|
||||
*/
|
||||
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
|
||||
@ -95,4 +107,9 @@ class PossessableComponent : public Component {
|
||||
*/
|
||||
bool m_ImmediatelyDepossess = false;
|
||||
|
||||
/**
|
||||
* @brief Whether the parent entity was spawned from an item
|
||||
*
|
||||
*/
|
||||
bool m_ItemSpawned = false;
|
||||
};
|
||||
|
@ -36,6 +36,18 @@ class PossessorComponent : public Component {
|
||||
*/
|
||||
LWOOBJID GetPossessable() const { return m_Possessable; }
|
||||
|
||||
/**
|
||||
* Sets if we are busy mounting or dismounting
|
||||
* @param value if we are busy mounting or dismounting
|
||||
*/
|
||||
void SetIsBusy(bool value) { m_IsBusy = value; }
|
||||
|
||||
/**
|
||||
* Returns if we are busy mounting or dismounting
|
||||
* @return if we are busy mounting or dismounting
|
||||
*/
|
||||
bool GetIsBusy() const { return m_IsBusy; }
|
||||
|
||||
/**
|
||||
* Sets the possesible type that's currently used, merely used by the shooting gallery if it's 0
|
||||
* @param value the possesible type to set
|
||||
@ -60,4 +72,10 @@ class PossessorComponent : public Component {
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMethod, std::string customQuery, bool wantLimits) {
|
||||
std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery, bool wantLimits) {
|
||||
std::string base;
|
||||
if (customQuery == "") {
|
||||
base = baseQueryForProperties;
|
||||
@ -115,15 +115,13 @@ std::string PropertyEntranceComponent::BuildQuery(Entity* entity, int32_t sortMe
|
||||
|
||||
auto friendsListQuery = Database::CreatePreppedStmt("SELECT * FROM (SELECT CASE WHEN player_id = ? THEN friend_id WHEN friend_id = ? THEN player_id END AS requested_player FROM friends ) AS fr WHERE requested_player IS NOT NULL ORDER BY requested_player DESC;");
|
||||
|
||||
friendsListQuery->setInt64(1, entity->GetObjectID());
|
||||
friendsListQuery->setInt64(2, entity->GetObjectID());
|
||||
friendsListQuery->setUInt(1, character->GetID());
|
||||
friendsListQuery->setUInt(2, character->GetID());
|
||||
|
||||
auto friendsListQueryResult = friendsListQuery->executeQuery();
|
||||
|
||||
while (friendsListQueryResult->next()) {
|
||||
auto playerIDToConvert = friendsListQueryResult->getInt64(1);
|
||||
playerIDToConvert = GeneralUtils::ClearBit(playerIDToConvert, OBJECT_BIT_CHARACTER);
|
||||
playerIDToConvert = GeneralUtils::ClearBit(playerIDToConvert, OBJECT_BIT_PERSISTENT);
|
||||
auto playerIDToConvert = friendsListQueryResult->getInt(1);
|
||||
friendsList = friendsList + std::to_string(playerIDToConvert) + ",";
|
||||
}
|
||||
// Replace trailing comma with the closing parenthesis.
|
||||
@ -193,7 +191,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
|
||||
|
||||
entries.push_back(playerEntry);
|
||||
|
||||
const auto query = BuildQuery(entity, sortMethod);
|
||||
const auto query = BuildQuery(entity, sortMethod, character);
|
||||
|
||||
auto propertyLookup = Database::CreatePreppedStmt(query);
|
||||
|
||||
@ -262,17 +260,17 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
|
||||
// Query to get friend and best friend fields
|
||||
auto friendCheck = Database::CreatePreppedStmt("SELECT best_friend FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?)");
|
||||
|
||||
friendCheck->setInt64(1, entity->GetObjectID());
|
||||
friendCheck->setInt64(2, ownerObjId);
|
||||
friendCheck->setInt64(3, ownerObjId);
|
||||
friendCheck->setInt64(4, entity->GetObjectID());
|
||||
friendCheck->setUInt(1, character->GetID());
|
||||
friendCheck->setUInt(2, ownerObjId);
|
||||
friendCheck->setUInt(3, ownerObjId);
|
||||
friendCheck->setUInt(4, character->GetID());
|
||||
|
||||
auto friendResult = friendCheck->executeQuery();
|
||||
|
||||
// If we got a result than the two players are friends.
|
||||
if (friendResult->next()) {
|
||||
isFriend = true;
|
||||
if (friendResult->getInt(1) == 2) {
|
||||
if (friendResult->getInt(1) == 3) {
|
||||
isBestFriend = true;
|
||||
}
|
||||
}
|
||||
@ -326,7 +324,7 @@ void PropertyEntranceComponent::OnPropertyEntranceSync(Entity* entity, bool incl
|
||||
// Query here is to figure out whether or not to display the button to go to the next page or not.
|
||||
int32_t numberOfProperties = 0;
|
||||
|
||||
auto buttonQuery = BuildQuery(entity, sortMethod, "SELECT COUNT(*) FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? ", false);
|
||||
auto buttonQuery = BuildQuery(entity, sortMethod, character, "SELECT COUNT(*) FROM properties as p JOIN charinfo as ci ON ci.prop_clone_id = p.clone_id where p.zone_id = ? AND (p.description LIKE ? OR p.name LIKE ? OR ci.name LIKE ?) AND p.privacy_option >= ? ", false);
|
||||
auto propertiesLeft = Database::CreatePreppedStmt(buttonQuery);
|
||||
|
||||
propertiesLeft->setUInt(1, this->m_MapID);
|
||||
|
@ -60,7 +60,7 @@ class PropertyEntranceComponent : public Component {
|
||||
|
||||
PropertySelectQueryProperty SetPropertyValues(PropertySelectQueryProperty property, LWOCLONEID cloneId = LWOCLONEID_INVALID, std::string ownerName = "", std::string propertyName = "", std::string propertyDescription = "", float reputation = 0, bool isBFF = false, bool isFriend = false, bool isModeratorApproved = false, bool isAlt = false, bool isOwned = false, uint32_t privacyOption = 0, uint32_t timeLastUpdated = 0, float performanceCost = 0.0f);
|
||||
|
||||
std::string BuildQuery(Entity* entity, int32_t sortMethod, std::string customQuery = "", bool wantLimits = true);
|
||||
std::string BuildQuery(Entity* entity, int32_t sortMethod, Character* character, std::string customQuery = "", bool wantLimits = true);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
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);
|
||||
|
||||
// Mounts
|
||||
/**
|
||||
* @brief Set the Inventory LWOOBJID of the mount
|
||||
*
|
||||
* @param entity The entity that is mounting
|
||||
* @param sysAddr the system address to send game message responses to
|
||||
* @param objectID LWOOBJID of the item in inventory that is being used
|
||||
*/
|
||||
void SendSetMountInventoryID(Entity* entity, const LWOOBJID& objectID, const SystemAddress& sysAddr);
|
||||
|
||||
/**
|
||||
* @brief Handle client dismounting mount
|
||||
*
|
||||
* @param inStream Raknet BitStream of incoming data
|
||||
* @param entity The Entity that is dismounting
|
||||
* @param sysAddr the system address to send game message responses to
|
||||
*/
|
||||
void HandleDismountComplete(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||
|
||||
/**
|
||||
* @brief Handle acknowledging that the client possessed something
|
||||
*
|
||||
* @param inStream Raknet BitStream of incoming data
|
||||
* @param entity The Entity that is possessing
|
||||
* @param sysAddr the system address to send game message responses to
|
||||
*/
|
||||
void HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||
|
||||
//Racing:
|
||||
void HandleModuleAssemblyQueryData(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||
|
||||
@ -337,8 +365,6 @@ namespace GameMessages {
|
||||
|
||||
void HandleRacingClientReady(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||
|
||||
void HandleAcknowledgePossession(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||
|
||||
void HandleRequestDie(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||
|
||||
void HandleVehicleNotifyServerAddPassiveBoostAction(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
|
||||
|
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 "Game.h"
|
||||
#include "Item.h"
|
||||
#include "eItemType.h"
|
||||
|
||||
std::vector<LOT> Inventory::m_GameMasterRestrictedItems = {
|
||||
1727, // GM Only - JetPack
|
||||
@ -274,40 +275,41 @@ eInventoryType Inventory::FindInventoryTypeForLot(const LOT lot)
|
||||
const auto itemType = static_cast<eItemType>(itemComponent.itemType);
|
||||
|
||||
switch (itemType) {
|
||||
case ITEM_TYPE_BRICK:
|
||||
case eItemType::ITEM_TYPE_BRICK:
|
||||
return BRICKS;
|
||||
|
||||
case ITEM_TYPE_BEHAVIOR:
|
||||
case eItemType::ITEM_TYPE_BEHAVIOR:
|
||||
return BEHAVIORS;
|
||||
|
||||
case ITEM_TYPE_PROPERTY:
|
||||
case eItemType::ITEM_TYPE_PROPERTY:
|
||||
return PROPERTY_DEEDS;
|
||||
|
||||
case ITEM_TYPE_MODEL:
|
||||
case ITEM_TYPE_VEHICLE:
|
||||
case ITEM_TYPE_LOOT_MODEL:
|
||||
case eItemType::ITEM_TYPE_MODEL:
|
||||
case eItemType::ITEM_TYPE_VEHICLE:
|
||||
case eItemType::ITEM_TYPE_LOOT_MODEL:
|
||||
case eItemType::ITEM_TYPE_MOUNT:
|
||||
return MODELS;
|
||||
|
||||
case ITEM_TYPE_HAT:
|
||||
case ITEM_TYPE_HAIR:
|
||||
case ITEM_TYPE_NECK:
|
||||
case ITEM_TYPE_LEFT_HAND:
|
||||
case ITEM_TYPE_RIGHT_HAND:
|
||||
case ITEM_TYPE_LEGS:
|
||||
case ITEM_TYPE_LEFT_TRINKET:
|
||||
case ITEM_TYPE_RIGHT_TRINKET:
|
||||
case ITEM_TYPE_COLLECTIBLE:
|
||||
case ITEM_TYPE_CONSUMABLE:
|
||||
case ITEM_TYPE_CHEST:
|
||||
case ITEM_TYPE_EGG:
|
||||
case ITEM_TYPE_PET_FOOD:
|
||||
case ITEM_TYPE_PET_INVENTORY_ITEM:
|
||||
case ITEM_TYPE_PACKAGE:
|
||||
case ITEM_TYPE_CURRENCY:
|
||||
case eItemType::ITEM_TYPE_HAT:
|
||||
case eItemType::ITEM_TYPE_HAIR:
|
||||
case eItemType::ITEM_TYPE_NECK:
|
||||
case eItemType::ITEM_TYPE_LEFT_HAND:
|
||||
case eItemType::ITEM_TYPE_RIGHT_HAND:
|
||||
case eItemType::ITEM_TYPE_LEGS:
|
||||
case eItemType::ITEM_TYPE_LEFT_TRINKET:
|
||||
case eItemType::ITEM_TYPE_RIGHT_TRINKET:
|
||||
case eItemType::ITEM_TYPE_COLLECTIBLE:
|
||||
case eItemType::ITEM_TYPE_CONSUMABLE:
|
||||
case eItemType::ITEM_TYPE_CHEST:
|
||||
case eItemType::ITEM_TYPE_EGG:
|
||||
case eItemType::ITEM_TYPE_PET_FOOD:
|
||||
case eItemType::ITEM_TYPE_PET_INVENTORY_ITEM:
|
||||
case eItemType::ITEM_TYPE_PACKAGE:
|
||||
case eItemType::ITEM_TYPE_CURRENCY:
|
||||
return ITEMS;
|
||||
|
||||
case ITEM_TYPE_QUEST_OBJECT:
|
||||
case ITEM_TYPE_UNKNOWN:
|
||||
case eItemType::ITEM_TYPE_QUEST_OBJECT:
|
||||
case eItemType::ITEM_TYPE_UNKNOWN:
|
||||
default:
|
||||
return HIDDEN;
|
||||
}
|
||||
|
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)
|
9
dGame/dUtilities/CMakeLists.txt
Normal file
9
dGame/dUtilities/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
set(DGAME_DUTILITIES_SOURCES "BrickDatabase.cpp"
|
||||
"dLocale.cpp"
|
||||
"GameConfig.cpp"
|
||||
"GUID.cpp"
|
||||
"Loot.cpp"
|
||||
"Mail.cpp"
|
||||
"Preconditions.cpp"
|
||||
"SlashCommandHandler.cpp"
|
||||
"VanityUtilities.cpp" PARENT_SCOPE)
|
@ -2017,11 +2017,15 @@ void SlashCommandHandler::SendAnnouncement(const std::string& title, const std::
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_ANNOUNCEMENT);
|
||||
|
||||
RakNet::RakString rsTitle(title.c_str());
|
||||
RakNet::RakString rsMsg(message.c_str());
|
||||
bitStream.Write<uint32_t>(title.size());
|
||||
for (auto character : title) {
|
||||
bitStream.Write<char>(character);
|
||||
}
|
||||
|
||||
bitStream.Write(rsTitle);
|
||||
bitStream.Write(rsMsg);
|
||||
bitStream.Write<uint32_t>(message.size());
|
||||
for (auto character : message) {
|
||||
bitStream.Write<char>(character);
|
||||
}
|
||||
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
}
|
||||
|
10
dMasterServer/CMakeLists.txt
Normal file
10
dMasterServer/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
set(DMASTERSERVER_SOURCES "InstanceManager.cpp"
|
||||
"MasterServer.cpp"
|
||||
"ObjectIDManager.cpp")
|
||||
|
||||
add_executable(MasterServer ${DMASTERSERVER_SOURCES})
|
||||
target_link_libraries(MasterServer ${COMMON_LIBRARIES})
|
||||
|
||||
if(WIN32)
|
||||
add_dependencies(MasterServer WorldServer AuthServer ChatServer)
|
||||
endif()
|
@ -19,6 +19,7 @@
|
||||
#include "CDClientDatabase.h"
|
||||
#include "CDClientManager.h"
|
||||
#include "Database.h"
|
||||
#include "MigrationRunner.h"
|
||||
#include "Diagnostics.h"
|
||||
#include "dCommonVars.h"
|
||||
#include "dConfig.h"
|
||||
@ -127,6 +128,13 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc > 1 && (strcmp(argv[1], "-m") == 0 || strcmp(argv[1], "--migrations") == 0)) {
|
||||
MigrationRunner::RunMigrations();
|
||||
Game::logger->Log("MigrationRunner", "Finished running migrations\n");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
//If the first command line argument is -a or --account then make the user
|
||||
//input a username and password, with the password being hidden.
|
||||
if (argc > 1 &&
|
||||
@ -491,7 +499,10 @@ void HandlePacket(Packet* packet) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_NEW_SESSION_ALERT);
|
||||
bitStream.Write(sessionKey);
|
||||
bitStream.Write(RakNet::RakString(username.c_str()));
|
||||
bitStream.Write<uint32_t>(username.size());
|
||||
for (auto character : username) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
SEND_PACKET_BROADCAST;
|
||||
|
||||
break;
|
||||
@ -566,14 +577,20 @@ void HandlePacket(Packet* packet) {
|
||||
|
||||
uint32_t mapId;
|
||||
LWOCLONEID cloneId;
|
||||
RakNet::RakString password;
|
||||
std::string password;
|
||||
|
||||
inStream.Read(mapId);
|
||||
inStream.Read(cloneId);
|
||||
inStream.Read(password);
|
||||
|
||||
Game::im->CreatePrivateInstance(mapId, cloneId,
|
||||
password.C_String());
|
||||
uint32_t len;
|
||||
inStream.Read<uint32_t>(len);
|
||||
for (int i = 0; len > i; i++) {
|
||||
char character;
|
||||
inStream.Read<char>(character);
|
||||
password += character;
|
||||
}
|
||||
|
||||
Game::im->CreatePrivateInstance(mapId, cloneId, password.c_str());
|
||||
|
||||
break;
|
||||
}
|
||||
@ -585,15 +602,22 @@ void HandlePacket(Packet* packet) {
|
||||
uint64_t requestID = 0;
|
||||
uint8_t mythranShift = false;
|
||||
|
||||
RakNet::RakString password;
|
||||
std::string password;
|
||||
|
||||
inStream.Read(requestID);
|
||||
inStream.Read(mythranShift);
|
||||
inStream.Read(password);
|
||||
|
||||
uint32_t len;
|
||||
inStream.Read<uint32_t>(len);
|
||||
|
||||
auto* instance = Game::im->FindPrivateInstance(password.C_String());
|
||||
for (int i = 0; i < len; i++) {
|
||||
char character; inStream.Read<char>(character);
|
||||
password += character;
|
||||
}
|
||||
|
||||
Game::logger->Log( "MasterServer", "Join private zone: %llu %d %s %p\n", requestID, mythranShift, password.C_String(), instance);
|
||||
auto* instance = Game::im->FindPrivateInstance(password.c_str());
|
||||
|
||||
Game::logger->Log( "MasterServer", "Join private zone: %llu %d %s %p\n", requestID, mythranShift, password.c_str(), instance);
|
||||
|
||||
if (instance == nullptr) {
|
||||
return;
|
||||
|
11
dNet/CMakeLists.txt
Normal file
11
dNet/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
set(DNET_SOURCES "AuthPackets.cpp"
|
||||
"ChatPackets.cpp"
|
||||
"ClientPackets.cpp"
|
||||
"dServer.cpp"
|
||||
"MasterPackets.cpp"
|
||||
"PacketUtils.cpp"
|
||||
"WorldPackets.cpp"
|
||||
"ZoneInstanceManager.cpp")
|
||||
|
||||
add_library(dNet STATIC ${DNET_SOURCES})
|
||||
target_link_libraries(dNet dCommon dDatabase)
|
@ -43,8 +43,10 @@ void MasterPackets::SendZoneCreatePrivate(dServer* server, uint32_t zoneID, uint
|
||||
bitStream.Write(zoneID);
|
||||
bitStream.Write(cloneID);
|
||||
|
||||
RakNet::RakString passwd(password.c_str());
|
||||
bitStream.Write(passwd);
|
||||
bitStream.Write<uint32_t>(password.size());
|
||||
for (auto character : password) {
|
||||
bitStream.Write<char>(character);
|
||||
}
|
||||
|
||||
server->SendToMaster(&bitStream);
|
||||
}
|
||||
@ -56,8 +58,10 @@ void MasterPackets::SendZoneRequestPrivate(dServer* server, uint64_t requestID,
|
||||
bitStream.Write(requestID);
|
||||
bitStream.Write(static_cast<uint8_t>(mythranShift));
|
||||
|
||||
RakNet::RakString passwd(password.c_str());
|
||||
bitStream.Write(passwd);
|
||||
bitStream.Write<uint32_t>(password.size());
|
||||
for (auto character : password) {
|
||||
bitStream.Write<char>(character);
|
||||
}
|
||||
|
||||
server->SendToMaster(&bitStream);
|
||||
}
|
||||
|
@ -535,8 +535,10 @@ enum GAME_MSG : unsigned short {
|
||||
GAME_MSG_REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666,
|
||||
GAME_MSG_RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667,
|
||||
GAME_MSG_PLAYER_SET_CAMERA_CYCLING_MODE = 1676,
|
||||
GAME_MSG_SET_MOUNT_INVENTORY_ID = 1726,
|
||||
GAME_MSG_NOTIFY_SERVER_LEVEL_PROCESSING_COMPLETE = 1734,
|
||||
GAME_MSG_NOTIFY_LEVEL_REWARDS = 1735,
|
||||
GAME_MSG_DISMOUNT_COMPLETE = 1756,
|
||||
GAME_MSG_MARK_INVENTORY_ITEM_AS_ACTIVE = 1767,
|
||||
END
|
||||
};
|
9
dPhysics/CMakeLists.txt
Normal file
9
dPhysics/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
set(DPHYSICS_SOURCES "dpCollisionChecks.cpp"
|
||||
"dpEntity.cpp"
|
||||
"dpGrid.cpp"
|
||||
"dpShapeBase.cpp"
|
||||
"dpShapeBox.cpp"
|
||||
"dpShapeSphere.cpp"
|
||||
"dpWorld.cpp")
|
||||
|
||||
add_library(dPhysics STATIC ${DPHYSICS_SOURCES})
|
@ -169,11 +169,10 @@ void BasePropertyServer::BaseZonePropertyRented(Entity* self, Entity* player) co
|
||||
EntityManager::Instance()->DestructEntity(plaque);
|
||||
}
|
||||
|
||||
if (self->GetVar<int32_t>(brickLinkMissionIDFlag) != 0) {
|
||||
auto plaques = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar<std::string>(PropertyPlaqueGroup));
|
||||
for (auto* plaque : plaques) {
|
||||
EntityManager::Instance()->DestructEntity(plaque);
|
||||
}
|
||||
auto brickLinkMissionID = self->GetVar<uint32_t>(brickLinkMissionIDFlag);
|
||||
if (brickLinkMissionID != 0) {
|
||||
auto missionComponent = player->GetComponent<MissionComponent>();
|
||||
if (missionComponent) missionComponent->CompleteMission(brickLinkMissionID, true);
|
||||
}
|
||||
|
||||
ActivateSpawner(self->GetVar<std::string>(PropObjsSpawner));
|
||||
|
253
dScripts/CMakeLists.txt
Normal file
253
dScripts/CMakeLists.txt
Normal file
@ -0,0 +1,253 @@
|
||||
set(DSCRIPT_SOURCES "ActivityManager.cpp"
|
||||
"ActMine.cpp"
|
||||
"ActNinjaTurret.cpp"
|
||||
"ActParadoxPipeFix.cpp"
|
||||
"ActPlayerDeathTrigger.cpp"
|
||||
"ActSharkPlayerDeathTrigger.cpp"
|
||||
"ActVehicleDeathTrigger.cpp"
|
||||
"AgBugsprayer.cpp"
|
||||
"AgBusDoor.cpp"
|
||||
"AgCagedBricksServer.cpp"
|
||||
"AgDarkSpiderling.cpp"
|
||||
"AgFans.cpp"
|
||||
"AgImagSmashable.cpp"
|
||||
"AgJetEffectServer.cpp"
|
||||
"AgLaserSensorServer.cpp"
|
||||
"AgMonumentBirds.cpp"
|
||||
"AgMonumentLaserServer.cpp"
|
||||
"AgMonumentRaceCancel.cpp"
|
||||
"AgMonumentRaceGoal.cpp"
|
||||
"AgPicnicBlanket.cpp"
|
||||
"AgPropGuard.cpp"
|
||||
"AgPropguards.cpp"
|
||||
"AgQbElevator.cpp"
|
||||
"AgSalutingNpcs.cpp"
|
||||
"AgShipPlayerDeathTrigger.cpp"
|
||||
"AgShipPlayerShockServer.cpp"
|
||||
"AgSpaceStuff.cpp"
|
||||
"AgStagePlatforms.cpp"
|
||||
"AgStromlingProperty.cpp"
|
||||
"AgSurvivalBuffStation.cpp"
|
||||
"AgSurvivalMech.cpp"
|
||||
"AgSurvivalSpiderling.cpp"
|
||||
"AgSurvivalStromling.cpp"
|
||||
"AgTurret.cpp"
|
||||
"AllCrateChicken.cpp"
|
||||
"AmBlueX.cpp"
|
||||
"AmBridge.cpp"
|
||||
"AmConsoleTeleportServer.cpp"
|
||||
"AmDarklingDragon.cpp"
|
||||
"AmDarklingMech.cpp"
|
||||
"AmDrawBridge.cpp"
|
||||
"AmDropshipComputer.cpp"
|
||||
"AmScrollReaderServer.cpp"
|
||||
"AmShieldGenerator.cpp"
|
||||
"AmShieldGeneratorQuickbuild.cpp"
|
||||
"AmSkeletonEngineer.cpp"
|
||||
"AmSkullkinDrill.cpp"
|
||||
"AmSkullkinDrillStand.cpp"
|
||||
"AmSkullkinTower.cpp"
|
||||
"AmTeapotServer.cpp"
|
||||
"AmTemplateSkillVolume.cpp"
|
||||
"AnvilOfArmor.cpp"
|
||||
"BankInteractServer.cpp"
|
||||
"BaseConsoleTeleportServer.cpp"
|
||||
"BaseEnemyApe.cpp"
|
||||
"BaseEnemyMech.cpp"
|
||||
"BaseFootRaceManager.cpp"
|
||||
"BaseInteractDropLootServer.cpp"
|
||||
"BasePropertyServer.cpp"
|
||||
"BaseRandomServer.cpp"
|
||||
"BaseSurvivalServer.cpp"
|
||||
"BaseWavesGenericEnemy.cpp"
|
||||
"BaseWavesServer.cpp"
|
||||
"Binoculars.cpp"
|
||||
"BootyDigServer.cpp"
|
||||
"BossSpiderQueenEnemyServer.cpp"
|
||||
"BuccaneerValiantShip.cpp"
|
||||
"BurningTile.cpp"
|
||||
"CatapultBaseServer.cpp"
|
||||
"CatapultBouncerServer.cpp"
|
||||
"CauldronOfLife.cpp"
|
||||
"CavePrisonCage.cpp"
|
||||
"ChooseYourDestinationNsToNt.cpp"
|
||||
"ClRing.cpp"
|
||||
"CppScripts.cpp"
|
||||
"CrabServer.cpp"
|
||||
"DamagingPets.cpp"
|
||||
"Darkitect.cpp"
|
||||
"DLUVanityNPC.cpp"
|
||||
"EnemyNjBuff.cpp"
|
||||
"EnemyRoninSpawner.cpp"
|
||||
"EnemySkeletonSpawner.cpp"
|
||||
"EnemySpiderSpawner.cpp"
|
||||
"ExplodingAsset.cpp"
|
||||
"FallingTile.cpp"
|
||||
"FireFirstSkillonStartup.cpp"
|
||||
"FlameJetServer.cpp"
|
||||
"ForceVolumeServer.cpp"
|
||||
"FountainOfImagination.cpp"
|
||||
"FvBounceOverWall.cpp"
|
||||
"FvBrickPuzzleServer.cpp"
|
||||
"FvCandle.cpp"
|
||||
"FvConsoleLeftQuickbuild.cpp"
|
||||
"FvConsoleRightQuickbuild.cpp"
|
||||
"FvDragonSmashingGolemQb.cpp"
|
||||
"FvFacilityBrick.cpp"
|
||||
"FvFlyingCreviceDragon.cpp"
|
||||
"FvFong.cpp"
|
||||
"FvFreeGfNinjas.cpp"
|
||||
"FvHorsemenTrigger.cpp"
|
||||
"FvMaelstromCavalry.cpp"
|
||||
"FvMaelstromDragon.cpp"
|
||||
"FvNinjaGuard.cpp"
|
||||
"FvPandaServer.cpp"
|
||||
"FvPandaSpawnerServer.cpp"
|
||||
"FvPassThroughWall.cpp"
|
||||
"FvRaceSmashEggImagineServer.cpp"
|
||||
"GfApeSmashingQB.cpp"
|
||||
"GfBanana.cpp"
|
||||
"GfBananaCluster.cpp"
|
||||
"GfCampfire.cpp"
|
||||
"GfCaptainsCannon.cpp"
|
||||
"GfJailkeepMission.cpp"
|
||||
"GfJailWalls.cpp"
|
||||
"GfOrgan.cpp"
|
||||
"GfTikiTorch.cpp"
|
||||
"GrowingFlower.cpp"
|
||||
"HydrantBroken.cpp"
|
||||
"HydrantSmashable.cpp"
|
||||
"ImaginationBackpackHealServer.cpp"
|
||||
"ImaginationShrineServer.cpp"
|
||||
"ImgBrickConsoleQB.cpp"
|
||||
"InstanceExitTransferPlayerToLastNonInstance.cpp"
|
||||
"InvalidScript.cpp"
|
||||
"LegoDieRoll.cpp"
|
||||
"Lieutenant.cpp"
|
||||
"MaestromExtracticatorServer.cpp"
|
||||
"MailBoxServer.cpp"
|
||||
"MastTeleport.cpp"
|
||||
"MinigameTreasureChestServer.cpp"
|
||||
"MonCoreNookDoors.cpp"
|
||||
"MonCoreSmashableDoors.cpp"
|
||||
"NjColeNPC.cpp"
|
||||
"NjDragonEmblemChestServer.cpp"
|
||||
"NjEarthDragonPetServer.cpp"
|
||||
"NjEarthPetServer.cpp"
|
||||
"NjGarmadonCelebration.cpp"
|
||||
"NjhubLavaPlayerDeathTrigger.cpp"
|
||||
"NjIceRailActivator.cpp"
|
||||
"NjJayMissionItems.cpp"
|
||||
"NjMonastryBossInstance.cpp"
|
||||
"NjNPCMissionSpinjitzuServer.cpp"
|
||||
"NjNyaMissionitems.cpp"
|
||||
"NjRailActivatorsServer.cpp"
|
||||
"NjRailPostServer.cpp"
|
||||
"NjRailSwitch.cpp"
|
||||
"NjScrollChestServer.cpp"
|
||||
"NjWuNPC.cpp"
|
||||
"NPCAddRemoveItem.cpp"
|
||||
"NpcAgCourseStarter.cpp"
|
||||
"NpcCowboyServer.cpp"
|
||||
"NpcEpsilonServer.cpp"
|
||||
"NpcNjAssistantServer.cpp"
|
||||
"NpcNpSpacemanBob.cpp"
|
||||
"NpcPirateServer.cpp"
|
||||
"NpcWispServer.cpp"
|
||||
"NsConcertChoiceBuild.cpp"
|
||||
"NsConcertChoiceBuildManager.cpp"
|
||||
"NsConcertInstrument.cpp"
|
||||
"NsConcertQuickBuild.cpp"
|
||||
"NsGetFactionMissionServer.cpp"
|
||||
"NsJohnnyMissionServer.cpp"
|
||||
"NsLegoClubDoor.cpp"
|
||||
"NsLupTeleport.cpp"
|
||||
"NsModularBuild.cpp"
|
||||
"NsQbImaginationStatue.cpp"
|
||||
"NsTokenConsoleServer.cpp"
|
||||
"NtAssemblyTubeServer.cpp"
|
||||
"NtBeamImaginationCollectors.cpp"
|
||||
"NtCombatChallengeDummy.cpp"
|
||||
"NtCombatChallengeExplodingDummy.cpp"
|
||||
"NtCombatChallengeServer.cpp"
|
||||
"NtConsoleTeleportServer.cpp"
|
||||
"NtDarkitectRevealServer.cpp"
|
||||
"NtDirtCloudServer.cpp"
|
||||
"NtDukeServer.cpp"
|
||||
"NtFactionSpyServer.cpp"
|
||||
"NtHaelServer.cpp"
|
||||
"NtImagBeamBuffer.cpp"
|
||||
"NtOverbuildServer.cpp"
|
||||
"NtParadoxPanelServer.cpp"
|
||||
"NtParadoxTeleServer.cpp"
|
||||
"NtSentinelWalkwayServer.cpp"
|
||||
"NtSleepingGuard.cpp"
|
||||
"NtVandaServer.cpp"
|
||||
"NtVentureCannonServer.cpp"
|
||||
"NtVentureSpeedPadServer.cpp"
|
||||
"NtXRayServer.cpp"
|
||||
"PersonalFortress.cpp"
|
||||
"PetDigBuild.cpp"
|
||||
"PetDigServer.cpp"
|
||||
"PetFromDigServer.cpp"
|
||||
"PetFromObjectServer.cpp"
|
||||
"PropertyBankInteract.cpp"
|
||||
"PropertyDeathPlane.cpp"
|
||||
"PropertyDevice.cpp"
|
||||
"PropertyFXDamage.cpp"
|
||||
"PropertyPlatform.cpp"
|
||||
"PrSeagullFly.cpp"
|
||||
"PrWhistle.cpp"
|
||||
"QbEnemyStunner.cpp"
|
||||
"RaceImagineCrateServer.cpp"
|
||||
"RaceImaginePowerup.cpp"
|
||||
"RaceMaelstromGeiser.cpp"
|
||||
"RaceSmashServer.cpp"
|
||||
"RainOfArrows.cpp"
|
||||
"RandomSpawnerFin.cpp"
|
||||
"RandomSpawnerPit.cpp"
|
||||
"RandomSpawnerStr.cpp"
|
||||
"RandomSpawnerZip.cpp"
|
||||
"RemoveRentalGear.cpp"
|
||||
"RockHydrantBroken.cpp"
|
||||
"RockHydrantSmashable.cpp"
|
||||
"ScriptComponent.cpp"
|
||||
"ScriptedPowerupSpawner.cpp"
|
||||
"SGCannon.cpp"
|
||||
"SpawnGryphonServer.cpp"
|
||||
"SpawnLionServer.cpp"
|
||||
"SpawnPetBaseServer.cpp"
|
||||
"SpawnSaberCatServer.cpp"
|
||||
"SpawnShrakeServer.cpp"
|
||||
"SpawnStegoServer.cpp"
|
||||
"SpecialImaginePowerupSpawner.cpp"
|
||||
"SpiderBossTreasureChestServer.cpp"
|
||||
"SsModularBuildServer.cpp"
|
||||
"StinkyFishTarget.cpp"
|
||||
"StoryBoxInteractServer.cpp"
|
||||
"Sunflower.cpp"
|
||||
"TokenConsoleServer.cpp"
|
||||
"TouchMissionUpdateServer.cpp"
|
||||
"TreasureChestDragonServer.cpp"
|
||||
"TriggerAmbush.cpp"
|
||||
"VeBricksampleServer.cpp"
|
||||
"VeEpsilonServer.cpp"
|
||||
"VeMech.cpp"
|
||||
"VeMissionConsole.cpp"
|
||||
"WaveBossApe.cpp"
|
||||
"WaveBossHammerling.cpp"
|
||||
"WaveBossHorsemen.cpp"
|
||||
"WaveBossSpiderling.cpp"
|
||||
"WhFans.cpp"
|
||||
"WildAmbients.cpp"
|
||||
"WishingWellServer.cpp"
|
||||
"ZoneAgMedProperty.cpp"
|
||||
"ZoneAgProperty.cpp"
|
||||
"ZoneAgSpiderQueen.cpp"
|
||||
"ZoneAgSurvival.cpp"
|
||||
"ZoneFvProperty.cpp"
|
||||
"ZoneGfProperty.cpp"
|
||||
"ZoneNsMedProperty.cpp"
|
||||
"ZoneNsProperty.cpp"
|
||||
"ZoneNsWaves.cpp"
|
||||
"ZoneSGServer.cpp" PARENT_SCOPE)
|
6
dWorldServer/CMakeLists.txt
Normal file
6
dWorldServer/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(DWORLDSERVER_SOURCES "ObjectIDManager.cpp"
|
||||
"PerformanceManager.cpp"
|
||||
"WorldServer.cpp")
|
||||
|
||||
add_executable(WorldServer ${DWORLDSERVER_SOURCES})
|
||||
target_link_libraries(WorldServer ${COMMON_LIBRARIES} dChatFilter dGame dZoneManager dPhysics detour recast tinyxml2)
|
@ -546,18 +546,31 @@ void HandlePacketChat(Packet* packet) {
|
||||
LWOOBJID header;
|
||||
inStream.Read(header);
|
||||
|
||||
RakNet::RakString title;
|
||||
RakNet::RakString msg;
|
||||
std::string title;
|
||||
std::string msg;
|
||||
|
||||
inStream.Read(title);
|
||||
inStream.Read(msg);
|
||||
uint32_t len;
|
||||
inStream.Read<uint32_t>(len);
|
||||
for (int i = 0; len > i; i++) {
|
||||
char character;
|
||||
inStream.Read<char>(character);
|
||||
title += character;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
inStream.Read<uint32_t>(len);
|
||||
for (int i = 0; len > i; i++) {
|
||||
char character;
|
||||
inStream.Read<char>(character);
|
||||
msg += character;
|
||||
}
|
||||
|
||||
//Send to our clients:
|
||||
AMFArrayValue args;
|
||||
auto* titleValue = new AMFStringValue();
|
||||
titleValue->SetStringValue(title.C_String());
|
||||
titleValue->SetStringValue(title.c_str());
|
||||
auto* messageValue = new AMFStringValue();
|
||||
messageValue->SetStringValue(msg.C_String());
|
||||
messageValue->SetStringValue(msg.c_str());
|
||||
|
||||
args.InsertValue("title", titleValue);
|
||||
args.InsertValue("message", messageValue);
|
||||
@ -669,10 +682,12 @@ void HandlePacket(Packet* packet) {
|
||||
Game::logger->Log("WorldServer", "Deleting player %llu\n", entity->GetObjectID());
|
||||
|
||||
EntityManager::Instance()->DestroyEntity(entity);
|
||||
}
|
||||
|
||||
{
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION);
|
||||
bitStream.Write(c->GetObjectID());
|
||||
bitStream.Write(user->GetLoggedInChar());
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
}
|
||||
|
||||
@ -802,19 +817,27 @@ void HandlePacket(Packet* packet) {
|
||||
RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||
uint64_t header = inStream.Read(header);
|
||||
uint32_t sessionKey = inStream.Read(sessionKey);
|
||||
RakNet::RakString username;
|
||||
inStream.Read(username);
|
||||
|
||||
std::string username;
|
||||
|
||||
uint32_t len;
|
||||
inStream.Read(len);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
char character; inStream.Read<char>(character);
|
||||
username += character;
|
||||
}
|
||||
|
||||
//Find them:
|
||||
User* user = UserManager::Instance()->GetUser(username.C_String());
|
||||
User* user = UserManager::Instance()->GetUser(username.c_str());
|
||||
if (!user) {
|
||||
Game::logger->Log("WorldServer", "Got new session alert for user %s, but they're not logged in.\n", username.C_String());
|
||||
Game::logger->Log("WorldServer", "Got new session alert for user %s, but they're not logged in.\n", username.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
//Check the key:
|
||||
if (sessionKey != std::atoi(user->GetSessionKey().c_str())) {
|
||||
Game::logger->Log("WorldServer", "Got new session alert for user %s, but the session key is invalid.\n", username.C_String());
|
||||
Game::logger->Log("WorldServer", "Got new session alert for user %s, but the session key is invalid.\n", username.c_str());
|
||||
Game::server->Disconnect(user->GetSystemAddress(), SERVER_DISCON_INVALID_SESSION_KEY);
|
||||
return;
|
||||
}
|
||||
@ -930,6 +953,19 @@ void HandlePacket(Packet* packet) {
|
||||
playerID = GeneralUtils::ClearBit(playerID, OBJECT_BIT_CHARACTER);
|
||||
playerID = GeneralUtils::ClearBit(playerID, OBJECT_BIT_PERSISTENT);
|
||||
|
||||
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
|
||||
|
||||
if (user) {
|
||||
auto lastCharacter = user->GetLoggedInChar();
|
||||
// This means we swapped characters and we need to remove the previous player from the container.
|
||||
if (static_cast<uint32_t>(lastCharacter) != playerID) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_REMOVED_NOTIFICATION);
|
||||
bitStream.Write(lastCharacter);
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
}
|
||||
}
|
||||
|
||||
UserManager::Instance()->LoginCharacter(packet->systemAddress, static_cast<uint32_t>(playerID));
|
||||
break;
|
||||
}
|
||||
@ -1107,14 +1143,12 @@ void HandlePacket(Packet* packet) {
|
||||
CBITSTREAM;
|
||||
PacketUtils::WriteHeader(bitStream, CHAT_INTERNAL, MSG_CHAT_INTERNAL_PLAYER_ADDED_NOTIFICATION);
|
||||
bitStream.Write(player->GetObjectID());
|
||||
bitStream.Write<uint16_t>(playerName.size());
|
||||
bitStream.Write<uint32_t>(playerName.size());
|
||||
for (size_t i = 0; i < playerName.size(); i++)
|
||||
{
|
||||
bitStream.Write(playerName[i]);
|
||||
}
|
||||
|
||||
//bitStream.Write(playerName);
|
||||
|
||||
auto zone = dZoneManager::Instance()->GetZone()->GetZoneID();
|
||||
bitStream.Write(zone.GetMapID());
|
||||
bitStream.Write(zone.GetInstanceID());
|
||||
|
6
dZoneManager/CMakeLists.txt
Normal file
6
dZoneManager/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(DZONEMANAGER_SOURCES "dZoneManager.cpp"
|
||||
"Level.cpp"
|
||||
"Spawner.cpp"
|
||||
"Zone.cpp")
|
||||
|
||||
add_library(dZoneManager STATIC ${DZONEMANAGER_SOURCES})
|
@ -1,2 +1 @@
|
||||
-- File added April 9th, 2022
|
||||
UPDATE ItemComponent SET itemType = 5 where id = 7082;
|
||||
|
@ -1 +1 @@
|
||||
ALTER TABLE bug_reports ADD reporter_id INT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE bug_reports ADD (reporter_id) INT NOT NULL DEFAULT 0;
|
||||
|
1
migrations/dlu/4_friends_list_objectids.sql
Normal file
1
migrations/dlu/4_friends_list_objectids.sql
Normal file
@ -0,0 +1 @@
|
||||
UPDATE friends SET player_id = player_id % 0x100000000, friend_id = friend_id % 0x100000000;
|
@ -60,3 +60,7 @@ classic_survival_scoring=0
|
||||
|
||||
# If this value is 1, pets will consume imagination as they did in live. if 0 they will not consume imagination at all.
|
||||
pets_take_imagination=1
|
||||
|
||||
# If you would like to increase the maximum number of best friends a player can have on the server
|
||||
# Change the value below to what you would like this to be (5 is live accurate)
|
||||
max_number_of_best_friends=5
|
@ -1,17 +1,13 @@
|
||||
# create the testing file and list of tests
|
||||
create_test_sourcelist (Tests
|
||||
CommonCxxTests.cpp
|
||||
TestNiPoint3.cpp
|
||||
TestLDFFormat.cpp
|
||||
CommonCxxTests.cpp
|
||||
TestNiPoint3.cpp
|
||||
TestLDFFormat.cpp
|
||||
)
|
||||
|
||||
|
||||
# add the executable
|
||||
add_executable (CommonCxxTests ${Tests})
|
||||
target_link_libraries(CommonCxxTests dCommon raknet)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(CommonCxxTests ws2_32)
|
||||
endif(WIN32)
|
||||
target_link_libraries(CommonCxxTests ${COMMON_LIBRARIES})
|
||||
|
||||
# remove the test driver source file
|
||||
set (TestsToRun ${Tests})
|
||||
@ -19,7 +15,7 @@ remove (TestsToRun CommonCxxTests.cpp)
|
||||
|
||||
# Add all the ADD_TEST for each test
|
||||
foreach (test ${TestsToRun})
|
||||
get_filename_component (TName ${test} NAME_WE)
|
||||
add_test (NAME ${TName} COMMAND CommonCxxTests ${TName})
|
||||
set_property(TEST ${TName} PROPERTY ENVIRONMENT CTEST_OUTPUT_ON_FAILURE=1)
|
||||
get_filename_component (TName ${test} NAME_WE)
|
||||
add_test (NAME ${TName} COMMAND CommonCxxTests ${TName})
|
||||
set_property(TEST ${TName} PROPERTY ENVIRONMENT CTEST_OUTPUT_ON_FAILURE=1)
|
||||
endforeach ()
|
||||
|
102
thirdparty/CMakeLists.txt
vendored
102
thirdparty/CMakeLists.txt
vendored
@ -1,50 +1,50 @@
|
||||
# Source Code for raknet
|
||||
file(
|
||||
GLOB SOURCES_RAKNET
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/raknet/Source/*.cpp
|
||||
GLOB SOURCES_RAKNET
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/raknet/Source/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for recast
|
||||
file(
|
||||
GLOB SOURCES_RECAST
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/recastnavigation/Recast/Source/*.cpp
|
||||
GLOB SOURCES_RECAST
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/recastnavigation/Recast/Source/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for detour
|
||||
file(
|
||||
GLOB SOURCES_DETOUR
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/recastnavigation/Detour/Source/*.cpp
|
||||
GLOB SOURCES_DETOUR
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/recastnavigation/Detour/Source/*.cpp
|
||||
)
|
||||
|
||||
# Source Code for tinyxml2
|
||||
file(
|
||||
GLOB SOURCES_TINYXML2
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tinyxml2/tinyxml2.cpp
|
||||
GLOB SOURCES_TINYXML2
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tinyxml2/tinyxml2.cpp
|
||||
)
|
||||
|
||||
# Source Code for libbcrypt
|
||||
file(
|
||||
GLOB SOURCES_LIBBCRYPT
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/*.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/src/*.c
|
||||
GLOB SOURCES_LIBBCRYPT
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/*.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libbcrypt/src/*.c
|
||||
)
|
||||
|
||||
file(
|
||||
GLOB SOURCES_SQLITE3
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SQLite/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SQLite/*.c
|
||||
GLOB SOURCES_SQLITE3
|
||||
LIST_DIRECTORIES false
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SQLite/*.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/SQLite/*.c
|
||||
)
|
||||
|
||||
# mariadb connector cpp
|
||||
@ -147,7 +147,6 @@ else() # Build from source
|
||||
set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/RelWithDebInfo/${MARIADB_SHARED_LIBRARY_NAME}")
|
||||
set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}/$<CONFIG>")
|
||||
set(MARIADB_PLUGINS_LOCATION "${BINARY_DIR}/libmariadb/RelWithDebInfo")
|
||||
message(STATUS "1 ${CMAKE_SOURCE_DIR}")
|
||||
else()
|
||||
set(MARIADB_SHARED_LIBRARY_LOCATION "${BINARY_DIR}/${MARIADB_SHARED_LIBRARY_NAME}")
|
||||
set(MARIADB_SHARED_LIBRARY_COPY_LOCATION "${PROJECT_BINARY_DIR}")
|
||||
@ -179,16 +178,19 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.
|
||||
file(REMOVE "${CMAKE_SOURCE_DIR}/thirdparty/mariadb-connector-cpp/test/CMakeLists.txt")
|
||||
endif()
|
||||
|
||||
# Create mariadb connector library object
|
||||
add_library(mariadbConnCpp SHARED IMPORTED GLOBAL)
|
||||
set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_LOCATION ${MARIADB_SHARED_LIBRARY_LOCATION})
|
||||
|
||||
if(WIN32)
|
||||
set_property(TARGET mariadbConnCpp PROPERTY IMPORTED_IMPLIB ${MARIADB_IMPLIB_LOCATION})
|
||||
endif()
|
||||
|
||||
# Add directories to include lists
|
||||
target_include_directories(mariadbConnCpp INTERFACE ${MARIADB_INCLUDE_DIR})
|
||||
add_dependencies(mariadbConnCpp mariadb_connector_cpp)
|
||||
|
||||
# 3rdparty static libraries:
|
||||
#add_library(zlib ${SOURCES_ZLIB})
|
||||
# Create our third party library objects
|
||||
add_library(raknet ${SOURCES_RAKNET})
|
||||
add_library(tinyxml2 ${SOURCES_TINYXML2})
|
||||
add_library(detour ${SOURCES_DETOUR})
|
||||
@ -196,11 +198,39 @@ add_library(recast ${SOURCES_RECAST})
|
||||
add_library(libbcrypt ${SOURCES_LIBBCRYPT})
|
||||
add_library(sqlite3 ${SOURCES_SQLITE3})
|
||||
|
||||
if(UNIX)
|
||||
target_link_libraries(sqlite3 pthread dl m)
|
||||
if(WIN32)
|
||||
# Link Win Sockets 2 to RakNet
|
||||
target_link_libraries(raknet ws2_32)
|
||||
elseif(UNIX)
|
||||
# Add warning disable flags and link Unix libraries to sqlite3
|
||||
target_link_libraries(sqlite3 pthread dl m)
|
||||
|
||||
# -Wno-unused-result -Wno-unknown-pragmas -fpermissive
|
||||
target_compile_options(sqlite3 PRIVATE "-Wno-return-local-addr" "-Wno-maybe-uninitialized")
|
||||
target_compile_options(raknet PRIVATE "-Wno-write-strings" "-Wformat-overflow=0" "-Wformat=0")
|
||||
target_compile_options(libbcrypt PRIVATE "-Wno-implicit-function-declaration" "-Wno-int-conversion")
|
||||
endif(UNIX)
|
||||
# -Wno-unused-result -Wno-unknown-pragmas -fpermissive
|
||||
target_compile_options(sqlite3 PRIVATE "-Wno-return-local-addr" "-Wno-maybe-uninitialized")
|
||||
target_compile_options(raknet PRIVATE "-Wno-write-strings" "-Wformat-overflow=0" "-Wformat=0")
|
||||
target_compile_options(libbcrypt PRIVATE "-Wno-implicit-function-declaration" "-Wno-int-conversion")
|
||||
endif()
|
||||
|
||||
# Download Backtrace if configured
|
||||
if(UNIX AND NOT APPLE)
|
||||
include(FetchContent)
|
||||
if (__include_backtrace__ AND __compile_backtrace__)
|
||||
FetchContent_Declare(
|
||||
backtrace
|
||||
GIT_REPOSITORY https://github.com/ianlancetaylor/libbacktrace.git
|
||||
)
|
||||
|
||||
FetchContent_MakeAvailable(backtrace)
|
||||
|
||||
if (NOT EXISTS ${backtrace_SOURCE_DIR}/.libs)
|
||||
set(backtrace_make_cmd "${backtrace_SOURCE_DIR}/configure --prefix=\"/usr\" --enable-shared --with-system-libunwind")
|
||||
|
||||
execute_process(
|
||||
COMMAND bash -c "cd ${backtrace_SOURCE_DIR} && ${backtrace_make_cmd} && make && cd ${CMAKE_SOURCE_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
link_directories(${backtrace_SOURCE_DIR}/.libs/)
|
||||
include_directories(${backtrace_SOURCE_DIR})
|
||||
endif()
|
||||
endif()
|
2
thirdparty/cpplinq/cpplinq.hpp
vendored
2
thirdparty/cpplinq/cpplinq.hpp
vendored
@ -14,6 +14,8 @@
|
||||
#ifndef CPPLINQ__HEADER_GUARD
|
||||
# define CPPLINQ__HEADER_GUARD
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
#define NOMINMAX
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user