diff --git a/.github/workflows/build-ubuntu.yml b/.github/workflows/build-ubuntu.yml
index 61703025c..3293c5f65 100644
--- a/.github/workflows/build-ubuntu.yml
+++ b/.github/workflows/build-ubuntu.yml
@@ -36,11 +36,13 @@ jobs:
strategy:
fail-fast: false
matrix:
- os: [ubuntu-22.04]
+ os: [ubuntu-22.04, ubuntu-24.04]
buildtype: [linux-release]
include:
- os: ubuntu-22.04
triplet: x64-linux
+ - os: ubuntu-24.04
+ triplet: x64-linux
steps:
- name: Checkout repository
@@ -48,14 +50,23 @@ jobs:
- name: Install Linux Dependencies
run: >
- sudo apt-get update && sudo apt-get install ccache linux-headers-$(uname -r)
+ sudo apt-get update && sudo apt-get install ccache linux-headers-"$(uname -r)"
+
+ - name: Switch to gcc-12 on Ubuntu 22.04
+ if: matrix.os == 'ubuntu-22.04'
+ run: |
+ sudo apt install gcc-12 g++-12
+ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-12 100 --slave /usr/bin/g++ g++ /usr/bin/g++-12 --slave /usr/bin/gcov gcov /usr/bin/gcov-12
+ sudo update-alternatives --set gcc /usr/bin/gcc-12
- - name: Switch to gcc-11
- if: matrix.os == 'ubuntu-20.04'
+ - name: Switch to gcc-14 on Ubuntu 24.04
+ if: matrix.os == 'ubuntu-24.04'
run: |
- sudo apt install gcc-11 g++-11
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-11 100 --slave /usr/bin/g++ g++ /usr/bin/g++-11 --slave /usr/bin/gcov gcov /usr/bin/gcov-11
- sudo update-alternatives --set gcc /usr/bin/gcc-11
+ sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
+ sudo apt-get update
+ sudo apt-get install gcc-14 g++-14 -y
+ sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100 --slave /usr/bin/g++ g++ /usr/bin/g++-14 --slave /usr/bin/gcov gcov /usr/bin/gcov-14
+ sudo update-alternatives --set gcc /usr/bin/gcc-14
- name: CCache
uses: hendrikmuhs/ccache-action@main
@@ -70,7 +81,7 @@ jobs:
run: |
vcpkgCommitId=$(grep '.builtin-baseline' vcpkg.json | awk -F: '{print $2}' | tr -d '," ')
echo "vcpkg commit ID: $vcpkgCommitId"
- echo "VCPKG_GIT_COMMIT_ID=$vcpkgCommitId" >> $GITHUB_ENV
+ echo "VCPKG_GIT_COMMIT_ID=$vcpkgCommitId" >> "$GITHUB_ENV"
- name: Get vcpkg commit id from vcpkg.json
uses: lukka/run-vcpkg@main
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9f0d7cdc7..c0ab25857 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,30 +7,31 @@ cmake_minimum_required(VERSION 3.22 FATAL_ERROR)
# VCPKG
# cmake -DCMAKE_TOOLCHAIN_FILE=/opt/workspace/vcpkg/scripts/buildsystems/vcpkg.cmake ..
-# Needed libs is in file vcpkg.json
+# Needed libs are in file vcpkg.json
# Windows required libs: .\vcpkg install --triplet x64-windows asio pugixml spdlog curl protobuf parallel-hashmap magic-enum mio luajit libmariadb mpir abseil bshoshany-thread-pool
+
if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
- set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
- CACHE STRING "")
+ set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
+ CACHE STRING "")
endif()
if(DEFINED ENV{VCPKG_DEFAULT_TRIPLET} AND NOT DEFINED VCPKG_TARGET_TRIPLET)
- set(VCPKG_TARGET_TRIPLET "$ENV{VCPKG_DEFAULT_TRIPLET}" CACHE STRING "")
+ set(VCPKG_TARGET_TRIPLET "$ENV{VCPKG_DEFAULT_TRIPLET}" CACHE STRING "")
endif()
set(VCPKG_FEATURE_FLAGS "versions")
set(VCPKG_BUILD_TYPE "release")
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# *****************************************************************************
# Project canary
# *****************************************************************************
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
- project(otxserver-debug)
+ project(otxserver-debug LANGUAGES CXX)
else()
- project(otxserver)
+ project(otxserver LANGUAGES CXX)
endif()
-
# *****************************************************************************
# Append cmake search path
# *****************************************************************************
@@ -54,7 +55,7 @@ option(FEATURE_METRICS "Enable metrics feature" OFF)
# Options Code
# *****************************************************************************
-if(FEATURE_METRIC)
+if(FEATURE_METRICS)
log_option_enabled("metrics")
else ()
log_option_disabled("metrics")
@@ -66,52 +67,21 @@ if(OPTIONS_ENABLE_CCACHE)
if(CCACHE)
log_option_enabled("ccache")
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE})
- else()
+ else()
log_option_disabled("ccache")
endif()
endif()
-
# === SCCACHE ===
if(OPTIONS_ENABLE_SCCACHE)
- find_program(SCCACHE_PATH sccache)
- if(SCCACHE_PATH)
- log_option_enabled("sccache")
- set(CMAKE_C_COMPILER_LAUNCHER ${SCCACHE_PATH})
- set(CMAKE_CXX_COMPILER_LAUNCHER ${SCCACHE_PATH})
- else()
- log_option_disabled("sccache")
- endif()
-endif()
-
-
-# === IPO ===
-if(OPTIONS_ENABLE_IPO)
- if(MSVC)
- log_option_enabled("IPO/LTO")
- set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /GL")
- set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
- set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
- set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
- set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
+ find_program(SCCACHE_PATH sccache)
+ if(SCCACHE_PATH)
+ log_option_enabled("sccache")
+ set(CMAKE_C_COMPILER_LAUNCHER ${SCCACHE_PATH})
+ set(CMAKE_CXX_COMPILER_LAUNCHER ${SCCACHE_PATH})
else()
- if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" OR CMAKE_BUILD_TYPE STREQUAL "Release")
- log_option_enabled("IPO/LTO")
- include(CheckIPOSupported)
- check_ipo_supported(RESULT result OUTPUT output)
- if(result)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=auto")
- message(STATUS "IPO/LTO enabled with -flto=auto for non-MSVC compiler.")
- set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
- else()
- log_war("IPO/LTO not supported: ${output}")
- endif()
- else()
- log_option_disabled("IPO/LTO")
- endif ()
+ log_option_disabled("sccache")
endif()
-else()
- log_option_disabled("IPO/LTO")
endif()
option(BUILD_TESTS "Build tests" OFF) # By default, tests will not be built
@@ -122,6 +92,6 @@ option(RUN_TESTS_AFTER_BUILD "Run tests when building" OFF) # By default, tests
# *****************************************************************************
add_subdirectory(src)
-if(BUILD_TESTS)
+if(BUILD_TESTS OR PACKAGE_TESTS)
add_subdirectory(tests)
endif()
diff --git a/CMakePresets.json b/CMakePresets.json
index 49f631e19..0bd22012b 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -83,9 +83,21 @@
"description": "Build Debug Mode",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
+ "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"DEBUG_LOG": "ON",
- "SPEED_UP_BUILD_UNITY": "OFF",
- "ASAN_ENABLED": "ON"
+ "SPEED_UP_BUILD_UNITY": "OFF"
+ }
+ },
+ {
+ "name": "linux-debug-asan",
+ "inherits": "linux-release",
+ "displayName": "Linux - Debug Build",
+ "description": "Build Debug Mode With ASAN Enable",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Debug",
+ "DEBUG_LOG": "ON",
+ "ASAN_ENABLED": "ON",
+ "SPEED_UP_BUILD_UNITY": "OFF"
}
},
{
diff --git a/README.md b/README.md
index c1db7f702..c1a5bbf23 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+# The OTX Server - Based on: Canary Server
+
## Builds
[![Build - Ubuntu](https://github.com/mattyx14/otxserver/actions/workflows/build-ubuntu.yml/badge.svg)](https://github.com/mattyx14/otxserver/actions/workflows/build-ubuntu.yml)
[![Build - Windows](https://github.com/mattyx14/otxserver/actions/workflows/build-windows-cmake.yml/badge.svg)](https://github.com/mattyx14/otxserver/actions/workflows/build-windows-cmake.yml)
@@ -21,19 +23,6 @@ With downloads, support, tutorials, Lua scripts, C++ codes, PHP codes and more .
* [OTLand](https://otland.net/) - [English]
* [Tibia Face](https://tibiaface.foroactivo.com/) - [Espaņol]
-## Special Thanks OTServBR-Global
-- our partners OTServBR-Global.
-- our crew (majesty, gpedro, eduardo dantas)
-- our testers (raphaellb, petardako, szulcek and olimpotibia)
-- [our contributors](https://github.com/opentibiabr/canary/graphs/contributors)
-- [fear lucien](https://github.com/FearLucien)
-- [cjaker](https://github.com/Eternal-Scripts)
-- [slavidodo](https://github.com/slavidodo)
-- [mignari and our awesome tools](https://github.com/ottools)
-- [saiyansking/optimized_forgottenserver and contributors](https://github.com/SaiyansKing/optimized_forgottenserver)
-- [otland/forgottenserver](https://github.com/otland/forgottenserver) and contributors.
-- if we forget someone, we apologize by forgot you. but you know, **forgot**tenserver.
-
## Contacts OTX Server 2:
- Matty(English & Spanish):
Facebook: https://www.facebook.com/Mattyx14/
@@ -41,3 +30,25 @@ E-mail: darkylive@live.com.mx
Whatsapp: +523211136700
- Reason(English & Portuguese):
Discord: Reason#2913
+
+## Special Thanks
+
+- Our contributors ([Canary](https://github.com/opentibiabr/canary/graphs/contributors) | [OTServBR-Global](https://github.com/opentibiabr/otservbr-global/graphs/contributors)).
+
+## Sponsors
+
+See our [donate page](https://docs.opentibiabr.com/home/donate).
+
+## Project supported by JetBrains
+
+We extend our heartfelt gratitude to Jetbrains for generously granting us licenses to collaborate on this and various
+other open-source initiatives.
+
+
+
+
+
+## Partners
+
+[![Supported by OTServ Brasil](https://raw.githubusercontent.com/otbr/otserv-brasil/main/otbr.png)](https://forums.otserv.com.br)
+
diff --git a/cmake/modules/BaseConfig.cmake b/cmake/modules/BaseConfig.cmake
index a1980d0f6..14dc6e221 100644
--- a/cmake/modules/BaseConfig.cmake
+++ b/cmake/modules/BaseConfig.cmake
@@ -3,9 +3,7 @@ cmake_minimum_required(VERSION 3.22 FATAL_ERROR)
# *****************************************************************************
# CMake Features
# *****************************************************************************
-set(CMAKE_CXX_STANDARD 20)
-set(GNUCXX_MINIMUM_VERSION 11)
-set(MSVC_MINIMUM_VERSION "19.32")
+set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
@@ -15,9 +13,6 @@ set(Boost_NO_WARN_NEW_VERSIONS ON)
# Make will print more details
set(CMAKE_VERBOSE_MAKEFILE OFF)
-# Generate compile_commands.json
-set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
-
# *****************************************************************************
# Packages / Libs
# *****************************************************************************
@@ -50,21 +45,21 @@ find_path(BOOST_DI_INCLUDE_DIRS "boost/di.hpp")
# === GCC Minimum Version ===
if (CMAKE_COMPILER_IS_GNUCXX)
message("-- Compiler: GCC - Version: ${CMAKE_CXX_COMPILER_VERSION}")
- if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS GNUCXX_MINIMUM_VERSION)
- message(FATAL_ERROR "GCC version must be at least ${GNUCXX_MINIMUM_VERSION}!")
+ if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11)
+ message(FATAL_ERROR "GCC version must be at least 11!")
endif()
endif()
# === Minimum required version for visual studio ===
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
message("-- Compiler: Visual Studio - Version: ${CMAKE_CXX_COMPILER_VERSION}")
- if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS MSVC_MINIMUM_VERSION)
- message(FATAL_ERROR "Visual Studio version must be at least ${MSVC_MINIMUM_VERSION}")
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.32")
+ message(FATAL_ERROR "Visual Studio version must be at least 19.32")
endif()
endif()
# *****************************************************************************
-# Sanity Checks
+# Options
# *****************************************************************************
option(TOGGLE_BIN_FOLDER "Use build/bin folder for generate compilation files" ON)
option(OPTIONS_ENABLE_OPENMP "Enable Open Multi-Processing support." ON)
@@ -74,6 +69,30 @@ option(BUILD_STATIC_LIBRARY "Build using static libraries" OFF)
option(SPEED_UP_BUILD_UNITY "Compile using build unity for speed up build" ON)
option(USE_PRECOMPILED_HEADER "Compile using precompiled header" ON)
+# === TOGGLE_BIN_FOLDER ===
+if(TOGGLE_BIN_FOLDER)
+ log_option_enabled("TOGGLE_BIN_FOLDER")
+else()
+ log_option_disabled("TOGGLE_BIN_FOLDER")
+endif()
+
+# === OPTIONS_ENABLE_OPENMP ===
+if(OPTIONS_ENABLE_OPENMP)
+ log_option_enabled("OPTIONS_ENABLE_OPENMP")
+else()
+ log_option_disabled("OPTIONS_ENABLE_OPENMP")
+endif()
+
+# === DEBUG LOG ===
+# cmake -DDEBUG_LOG=ON ..
+if(DEBUG_LOG)
+ add_definitions(-DDEBUG_LOG=ON)
+ add_definitions(-DSPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_TRACE)
+ log_option_enabled("DEBUG LOG")
+else()
+ log_option_disabled("DEBUG LOG")
+endif()
+
# === ASAN ===
if(ASAN_ENABLED)
log_option_enabled("asan")
@@ -87,10 +106,9 @@ else()
log_option_disabled("asan")
endif()
-# Build static libs
+# === BUILD_STATIC_LIBRARY ===
if(BUILD_STATIC_LIBRARY)
log_option_enabled("STATIC_LIBRARY")
-
if(MSVC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
elseif(UNIX AND NOT APPLE)
@@ -102,14 +120,63 @@ else()
log_option_disabled("STATIC_LIBRARY")
endif()
-# === DEBUG LOG ===
-# cmake -DDEBUG_LOG=ON ..
-if(DEBUG_LOG)
- add_definitions(-DDEBUG_LOG=ON)
- log_option_enabled("DEBUG LOG")
+# === SPEED_UP_BUILD_UNITY ===
+if(SPEED_UP_BUILD_UNITY)
+ log_option_enabled("SPEED_UP_BUILD_UNITY")
else()
- log_option_disabled("DEBUG LOG")
-endif(DEBUG_LOG)
+ log_option_disabled("SPEED_UP_BUILD_UNITY")
+endif()
+
+# === USE_PRECOMPILED_HEADER ===
+if(USE_PRECOMPILED_HEADER)
+ log_option_enabled("USE_PRECOMPILED_HEADER")
+else()
+ log_option_disabled("USE_PRECOMPILED_HEADER")
+endif()
+
+# === IPO Configuration ===
+function(configure_linking target_name)
+ if(OPTIONS_ENABLE_IPO)
+ # Check if IPO/LTO is supported
+ include(CheckIPOSupported)
+ check_ipo_supported(RESULT ipo_supported OUTPUT ipo_output LANGUAGES CXX)
+
+ # Get the GCC compiler version, if applicable
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ execute_process(
+ COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
+ OUTPUT_VARIABLE GCC_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ endif()
+
+ if(ipo_supported)
+ set_property(TARGET ${target_name} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
+ log_option_enabled("IPO/LTO enabled for target ${target_name}.")
+
+ if(MSVC)
+ target_compile_options(${target_name} PRIVATE /GL)
+ target_link_options(${target_name} PRIVATE /LTCG)
+ elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+ # Check if it's running on Linux, using GCC 14, and in Debug mode
+ if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
+ CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND
+ GCC_VERSION VERSION_EQUAL "14" AND
+ CMAKE_BUILD_TYPE STREQUAL "Debug")
+ log_option_disabled("LTO disabled for GCC 14 in Debug mode on Linux for target ${target_name}.")
+ # Disable LTO for Debug builds with GCC 14
+ target_compile_options(${target_name} PRIVATE -fno-lto)
+ target_link_options(${target_name} PRIVATE -fno-lto)
+ else()
+ target_compile_options(${target_name} PRIVATE -flto=auto)
+ target_link_options(${target_name} PRIVATE -flto=auto)
+ endif()
+ endif()
+ else()
+ log_option_disabled("IPO/LTO is not supported for target ${target_name}: ${ipo_output}")
+ endif()
+ endif()
+endfunction()
# *****************************************************************************
# Compiler Options
@@ -119,39 +186,38 @@ if (MSVC)
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_${type} "${CMAKE_CXX_FLAGS_${type}}")
string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_${type} "${CMAKE_C_FLAGS_${type}}")
endforeach(type)
-
add_compile_options(/MP /FS /Zf /EHsc)
else()
add_compile_options(-Wno-unused-parameter -Wno-sign-compare -Wno-switch -Wno-implicit-fallthrough -Wno-extra)
endif()
-## Link compilation files to build/bin folder, else link to the main dir
+# === Compiler Features ===
+add_library(project_options INTERFACE)
+target_compile_features(project_options INTERFACE cxx_std_23)
+
+# *****************************************************************************
+# Output Directory Function
+# *****************************************************************************
function(set_output_directory target_name)
if (TOGGLE_BIN_FOLDER)
set_target_properties(${target_name}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
- )
+ )
else()
set_target_properties(${target_name}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/"
- )
+ )
endif()
endfunction()
-## Setup shared target basic configurations
+# *****************************************************************************
+# Setup Target Function
+# *****************************************************************************
function(setup_target TARGET_NAME)
if (MSVC AND BUILD_STATIC_LIBRARY)
set_property(TARGET ${TARGET_NAME} PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>")
endif()
+ target_link_libraries(${TARGET_NAME} PUBLIC project_options)
endfunction()
-
-# *****************************************************************************
-# DEBUG: Print cmake variables
-# *****************************************************************************
-#get_cmake_property(_variableNames VARIABLES)
-#list (SORT _variableNames)
-#foreach (_variableName ${_variableNames})
-# message(STATUS "${_variableName}=${${_variableName}}")
-#endforeach()
diff --git a/cmake/modules/CanaryLib.cmake b/cmake/modules/CanaryLib.cmake
index a3f5410b9..916970c37 100644
--- a/cmake/modules/CanaryLib.cmake
+++ b/cmake/modules/CanaryLib.cmake
@@ -22,13 +22,10 @@ add_subdirectory(utils)
# Add more global sources - please add preferably in the sub_directory CMakeLists.
target_sources(${PROJECT_NAME}_lib PRIVATE canary_server.cpp)
-# Add public pre compiler header to lib, to pass down to related targets
-if (NOT SPEED_UP_BUILD_UNITY)
+# Conditional Precompiled Headers
+if(USE_PRECOMPILED_HEADER)
target_precompile_headers(${PROJECT_NAME}_lib PUBLIC pch.hpp)
-endif()
-
-if(NOT SPEED_UP_BUILD_UNITY AND USE_PRECOMPILED_HEADERS)
- target_compile_definitions(${PROJECT_NAME}_lib PUBLIC -DUSE_PRECOMPILED_HEADERS)
+ target_compile_definitions(${PROJECT_NAME}_lib PUBLIC USE_PRECOMPILED_HEADERS)
endif()
# *****************************************************************************
@@ -38,38 +35,21 @@ if (CMAKE_COMPILER_IS_GNUCXX)
target_compile_options(${PROJECT_NAME}_lib PRIVATE -Wno-deprecated-declarations)
endif()
-# Sets the NDEBUG macro for RelWithDebInfo and Release configurations.
-# This disables assertions in these configurations, optimizing the code for performance
-# and reducing debugging overhead, while keeping debug information available for diagnostics.
+# Sets the NDEBUG macro for Release and RelWithDebInfo configurations.
target_compile_definitions(${PROJECT_NAME}_lib PUBLIC
- $<$:NDEBUG>
- $<$:NDEBUG>
+ $<$:NDEBUG>
+ $<$:NDEBUG>
)
-# === IPO ===
-if(MSVC)
- target_compile_options(${PROJECT_NAME}_lib PRIVATE "/GL")
- set_target_properties(${PROJECT_NAME}_lib PROPERTIES
- STATIC_LINKER_FLAGS "/LTCG"
- SHARED_LINKER_FLAGS "/LTCG"
- MODULE_LINKER_FLAGS "/LTCG"
- EXE_LINKER_FLAGS "/LTCG")
-else()
- include(CheckIPOSupported)
- check_ipo_supported(RESULT result)
- if(result)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=auto")
- message(STATUS "IPO/LTO enabled with -flto=auto for non-MSVC compiler.")
- set_property(TARGET ${PROJECT_NAME}_lib PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE)
- else()
- message(WARNING "IPO/LTO is not supported: ${output}")
- endif()
-endif()
+# Configurar IPO e Linkagem Incremental
+configure_linking(${PROJECT_NAME}_lib)
# === UNITY BUILD (compile time reducer) ===
if(SPEED_UP_BUILD_UNITY)
set_target_properties(${PROJECT_NAME}_lib PROPERTIES UNITY_BUILD ON)
- log_option_enabled("Build unity for speed up compilation")
+ log_option_enabled("Build unity for speed up compilation for taget ${PROJECT_NAME}_lib")
+else()
+ log_option_disabled("Build unity")
endif()
# *****************************************************************************
@@ -82,13 +62,14 @@ target_include_directories(${PROJECT_NAME}_lib
${GMP_INCLUDE_DIRS}
${LUAJIT_INCLUDE_DIRS}
${PARALLEL_HASHMAP_INCLUDE_DIRS}
- )
+ ${ATOMIC_QUEUE_INCLUDE_DIRS}
+)
# *****************************************************************************
# Target links to external dependencies
# *****************************************************************************
target_link_libraries(${PROJECT_NAME}_lib
- PUBLIC
+ PUBLIC
${GMP_LIBRARIES}
${LUAJIT_LIBRARIES}
CURL::libcurl
@@ -104,13 +85,11 @@ target_link_libraries(${PROJECT_NAME}_lib
spdlog::spdlog
unofficial::argon2::libargon2
unofficial::libmariadb
- unofficial::mariadbclient
protobuf
)
if(FEATURE_METRICS)
add_definitions(-DFEATURE_METRICS)
-
target_link_libraries(${PROJECT_NAME}_lib
PUBLIC
opentelemetry-cpp::common
@@ -136,11 +115,10 @@ if (MSVC)
else()
set(VCPKG_TARGET_TRIPLET "x64-windows" CACHE STRING "")
endif()
-
target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${MYSQL_CLIENT_LIBS})
else()
target_link_libraries(${PROJECT_NAME}_lib PUBLIC Threads::Threads)
-endif (MSVC)
+endif()
# === OpenMP ===
if(OPTIONS_ENABLE_OPENMP)
@@ -152,3 +130,12 @@ if(OPTIONS_ENABLE_OPENMP)
else()
log_option_disabled("openmp")
endif()
+
+# === Optimization Flags ===
+if(CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo" OR CMAKE_BUILD_TYPE STREQUAL "Release")
+ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
+ target_compile_options(${PROJECT_NAME}_lib PRIVATE -O3 -march=native)
+ elseif(MSVC)
+ target_compile_options(${PROJECT_NAME}_lib PRIVATE /O2)
+ endif()
+endif()
diff --git a/cmake/modules/FindMySQL.cmake b/cmake/modules/FindMySQL.cmake
index e96b1e27d..9e3b45873 100644
--- a/cmake/modules/FindMySQL.cmake
+++ b/cmake/modules/FindMySQL.cmake
@@ -58,7 +58,7 @@ IF (WIN32)
ADD_DEFINITIONS(-DDBUG_OFF)
ENDIF (CMAKE_BUILD_TYPE STREQUAL Debug)
- FIND_LIBRARY(MYSQL_LIB NAMES mysqlclient libmariadb
+ FIND_LIBRARY(MYSQL_LIB NAMES mariadbclient libmariadb
PATHS
$ENV{MYSQL_DIR}/lib/${libsuffixDist}
$ENV{MYSQL_DIR}/libmysql
diff --git a/config.lua.dist b/config.lua.dist
index 81d8e5a3f..86050471a 100644
--- a/config.lua.dist
+++ b/config.lua.dist
@@ -9,7 +9,8 @@ coreDirectory = "data"
-- Set log level
-- It can be trace, debug, info, warning, error, critical, off (default: info).
--- NOTE: Will only display logs with level higher or equal the one set.
+-- NOTE: It will only be valid after the server starts up and only display logs with level higher or equal the one set.
+-- NOTE: Debug and trace logs are only available if compiled in debug mode.
logLevel = "info"
--- Toggles the server's maintenance mode.
@@ -52,7 +53,7 @@ cleanProtectionZones = false
-- Connection Config
-- NOTE: allowOldProtocol can allow login on 10x protocol. (11.00)
-- NOTE: maxPlayers set to 0 means no limit
--- NOTE: MaxPacketsPerSeconds if you change you will be subject to bugs by WPE, keep the default value of 25,
+-- NOTE: MaxPacketsPerSeconds if you change you will be subject to bugs by WPE, keep the default value of 25,
-- It's recommended to use a range like min 50 in this function, otherwise you will be disconnected after equipping two-handed distance weapons.
ip = "127.0.0.1"
allowOldProtocol = false
@@ -66,8 +67,6 @@ serverMotd = "Welcome to The OTX Server"
statusTimeout = 5 * 1000
replaceKickOnLogin = true
maxPacketsPerSecond = 25
-maxItem = 2000
-maxContainer = 100
maxPlayersOnlinePerAccount = 1
maxPlayersOutsidePZPerAccount = 1
@@ -81,6 +80,12 @@ freeDepotLimit = 2000
premiumDepotLimit = 10000
depotBoxes = 20
+-- Item and containers limit
+-- NOTE: 'maxContainerDepth' defines the maximum depth to which containers can be nested
+maxItem = 5000
+maxContainer = 500
+maxContainerDepth = 200
+
-- Augments System (Get more info in: https://github.com/opentibiabr/canary/pull/2602)
-- NOTE: the following values are for all weapons and equipments that have type of "increase damage", "powerful impact" and "strong impact".
-- To customize the percentage of a particular item with these augment types, please add to the item "augments" section on items.xml as the example above.
@@ -141,7 +146,7 @@ forgeAmountMultiplier = 3
forgeMinSlivers = 3
forgeMaxSlivers = 7
forgeInfluencedLimit = 300
-forgeFiendishLimit = 3
+forgeFiendishLimit = 4
forgeFiendishIntervalType = "hour"
forgeFiendishIntervalTime = "1"
@@ -254,7 +259,7 @@ onlyPremiumAccount = false
-- NOTE: enablePlayerPutItemInAmmoSlot = true, will enable players to put any items on ammo slot, more used in custom shopping system
-- NOTE: startStreakLevel will make a reward streak level for new players who never logged in
-- NOTE: if showLootsInBestiary is true, will cause all loots to be shown in the bestiary even if the player has not reached the required number of kills
--- NOTE: minTownIdToBankTransfer blocks towns less than defined from receiving money transfers
+-- NOTE: minTownIdToBankTransferFromMain blocks towns less than defined from receiving money transfers
-- NOTE: enableSupportOutfit enable GODS and GMS to select support outfit (gamemaster, customer support or community manager)
stashMoving = false
stashItemCount = 5000
@@ -275,7 +280,7 @@ storeInboxMaxLimit = 2000
enablePlayerPutItemInAmmoSlot = false
startStreakLevel = 0
showLootsInBestiary = false
-minTownIdToBankTransfer = 3
+minTownIdToBankTransferFromMain = 4
enableSupportOutfit = true
-- Teleport summon
diff --git a/docs/python-scripts/normalize_cpp_own_includes.py.py b/docs/python-scripts/normalize_cpp_own_includes.py.py
new file mode 100644
index 000000000..d5e0ca0e8
--- /dev/null
+++ b/docs/python-scripts/normalize_cpp_own_includes.py.py
@@ -0,0 +1,72 @@
+import os
+
+# Path to the directory containing C++ files (.cpp)
+directory_path = "path/to/src"
+
+def normalize_include_line(line):
+ # Normalize the include line by removing extra spaces and using '/' as separator
+ return ' '.join(line.strip().split()).replace('\\', '/')
+
+def correct_include_path(line, correct_include):
+ # Check if the include line matches the correct include, regardless of the path
+ if line.strip().startswith('#include') and ('"' + correct_include.split('/')[-1] + '"') in line:
+ return f'#include "{correct_include}"\n'
+ return line
+
+# Function to modify files and correct their own includes
+def modify_includes(directory):
+ for root, dirs, files in os.walk(directory):
+ for filename in files:
+ if filename.endswith('.cpp'):
+ file_path = os.path.join(root, filename)
+ correct_include = f"{os.path.relpath(root, directory).replace('\\', '/')}/{filename.replace('.cpp', '.hpp')}"
+
+ # Remove './' from the beginning of the path, if present
+ if correct_include.startswith('./'):
+ correct_include = correct_include[2:]
+
+ include_statement = f'#include "{correct_include}"\n'
+
+ with open(file_path, 'r', encoding='utf8') as file:
+ lines = file.readlines()
+
+ corrected_lines = []
+ include_found = False
+ include_renamed = False
+ include_at_correct_position = False
+
+ # Normalize lines and correct includes as necessary
+ for i, line in enumerate(lines):
+ normalized_line = normalize_include_line(line)
+ if correct_include in normalized_line:
+ # If the correct include was found and is in the correct position
+ include_found = True
+ if i == next((idx for idx, l in enumerate(lines) if l.strip().startswith('#include')), i):
+ include_at_correct_position = True
+ if include_at_correct_position:
+ corrected_lines.append(line) # Keep the original include if it is correct and in the right position
+ elif filename.replace('.cpp', '.hpp') in normalized_line:
+ # Replace any old version of the include with the corrected version
+ corrected_lines.append(correct_include_path(line, correct_include))
+ include_renamed = True
+ else:
+ corrected_lines.append(line)
+
+ # If the include was found but not in the correct position, or was renamed, move it to the first include position
+ if (include_found and not include_at_correct_position) or include_renamed:
+ # Remove any occurrence of the correct include that is out of place
+ corrected_lines = [line for line in corrected_lines if line.strip() != include_statement.strip()]
+ # Find the first include position and insert the correct include
+ first_include_index = next((i for i, line in enumerate(corrected_lines) if line.strip().startswith('#include')), len(corrected_lines))
+ corrected_lines.insert(first_include_index, include_statement)
+ # Add a blank line immediately after the first include, if necessary
+ if first_include_index + 1 < len(corrected_lines) and not corrected_lines[first_include_index + 1].isspace():
+ corrected_lines.insert(first_include_index + 1, '\n')
+
+ # Write the changes back to the file only if modifications were made
+ if corrected_lines != lines:
+ with open(file_path, 'w', encoding='utf8') as file:
+ file.writelines(corrected_lines)
+
+# Call the function to modify the files
+modify_includes(directory_path)
diff --git a/sonar-project.properties b/sonar-project.properties
deleted file mode 100644
index e5ef1cf71..000000000
--- a/sonar-project.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-sonar.projectKey=opentibiabr_otx-server
-sonar.organization=otxserver
-sonar.projectName=otxserver
-sonar.projectVersion=6.2
-sonar.sources=./src
-sonar.sourceEncoding=UTF-8
-sonar.cfamily.cpp20=true
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 72fe2f3c1..e65318ca5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,24 +15,17 @@ if(MSVC)
target_sources(${PROJECT_NAME} PRIVATE ../cmake/otxserver.rc)
endif()
-if (UNIX)
-
- if(CMAKE_BUILD_TYPE STREQUAL "Debug")
- target_compile_options(${PROJECT_NAME}_lib
- PRIVATE
- -Wall -Wextra -Wpedantic
- )
- endif()
-
- if(CMAKE_BUILD_TYPE STREQUAL "Debug")
- target_compile_options(${PROJECT_NAME}
- PRIVATE
- -Wall -Wextra -Wpedantic
- )
- endif()
-
-endif (UNIX)
-
setup_target(${PROJECT_NAME})
set_output_directory(${PROJECT_NAME})
target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_lib)
+
+# Configure IPO and Incremental Linking for the executable
+configure_linking(${PROJECT_NAME})
+
+# Compiler warnings and options
+if (UNIX)
+ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ target_compile_options(${PROJECT_NAME}_lib PRIVATE -Wall -Wextra -Wpedantic)
+ target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic)
+ endif()
+endif()
diff --git a/src/account/account.cpp b/src/account/account.cpp
index 2e5f58dd8..93596f77b 100644
--- a/src/account/account.cpp
+++ b/src/account/account.cpp
@@ -7,144 +7,144 @@
* Website: https://docs.opentibiabr.com/
*/
-#include "pch.hpp"
-
#include "account/account.hpp"
#include "account/account_repository_db.hpp"
-#include "config/configmanager.hpp"
-#include "utils/definitions.hpp"
+#include "account/account_info.hpp"
#include "security/argon.hpp"
#include "utils/tools.hpp"
-#include "lib/logging/log_with_spd_log.hpp"
-
-#include "enums/account_type.hpp"
#include "enums/account_coins.hpp"
#include "enums/account_errors.hpp"
+#include "enums/account_type.hpp"
Account::Account(const uint32_t &id) {
m_descriptor.clear();
- m_account.id = id;
- m_account.premiumRemainingDays = 0;
- m_account.premiumLastDay = 0;
- m_account.accountType = ACCOUNT_TYPE_NORMAL;
+ m_account = std::make_unique();
+ m_account->id = id;
+ m_account->premiumRemainingDays = 0;
+ m_account->premiumLastDay = 0;
+ m_account->accountType = ACCOUNT_TYPE_NORMAL;
}
Account::Account(std::string descriptor) :
m_descriptor(std::move(descriptor)) {
- m_account.id = 0;
- m_account.premiumRemainingDays = 0;
- m_account.premiumLastDay = 0;
- m_account.accountType = ACCOUNT_TYPE_NORMAL;
+ m_account = std::make_unique();
+ m_account->id = 0;
+ m_account->premiumRemainingDays = 0;
+ m_account->premiumLastDay = 0;
+ m_account->accountType = ACCOUNT_TYPE_NORMAL;
}
-uint8_t Account::load() {
- if (m_account.id != 0 && g_accountRepository().loadByID(m_account.id, m_account)) {
+AccountErrors_t Account::load() {
+ using enum AccountErrors_t;
+ if (m_account->id != 0 && g_accountRepository().loadByID(m_account->id, m_account)) {
m_accLoaded = true;
- return enumToValue(AccountErrors_t::Ok);
+ return Ok;
}
if (!m_descriptor.empty() && g_accountRepository().loadByEmailOrName(getProtocolCompat(), m_descriptor, m_account)) {
m_accLoaded = true;
- return enumToValue(AccountErrors_t::Ok);
+ return Ok;
}
if (!m_descriptor.empty() && g_accountRepository().loadBySession(m_descriptor, m_account)) {
m_accLoaded = true;
- return enumToValue(AccountErrors_t::Ok);
+ return Ok;
}
updatePremiumTime();
- return enumToValue(AccountErrors_t::LoadingAccount);
+ return LoadingAccount;
}
-uint8_t Account::reload() {
+AccountErrors_t Account::reload() {
if (!m_accLoaded) {
- return enumToValue(AccountErrors_t::NotInitialized);
+ return AccountErrors_t::NotInitialized;
}
return load();
}
-uint8_t Account::save() {
+AccountErrors_t Account::save() const {
+ using enum AccountErrors_t;
if (!m_accLoaded) {
- return enumToValue(AccountErrors_t::NotInitialized);
+ return NotInitialized;
}
-
if (!g_accountRepository().save(m_account)) {
- return enumToValue(AccountErrors_t::Storage);
+ return Storage;
}
-
- return enumToValue(AccountErrors_t::Ok);
+ return Ok;
}
-std::tuple Account::getCoins(const uint8_t &type) const {
+std::tuple Account::getCoins(CoinType type) const {
+ using enum AccountErrors_t;
if (!m_accLoaded) {
- return { 0, enumToValue(AccountErrors_t::NotInitialized) };
+ return { 0, NotInitialized };
}
uint32_t coins = 0;
- if (!g_accountRepository().getCoins(m_account.id, type, coins)) {
- return { 0, enumToValue(AccountErrors_t::Storage) };
+ if (!g_accountRepository().getCoins(m_account->id, type, coins)) {
+ return { 0, Storage };
}
- return { coins, enumToValue(AccountErrors_t::Ok) };
+ return { coins, Ok };
}
-uint8_t Account::addCoins(const uint8_t &type, const uint32_t &amount, const std::string &detail) {
+AccountErrors_t Account::addCoins(CoinType type, const uint32_t &amount, const std::string &detail) {
+ using enum AccountErrors_t;
if (!m_accLoaded) {
- return enumToValue(AccountErrors_t::NotInitialized);
+ return NotInitialized;
}
if (amount == 0) {
- return enumToValue(AccountErrors_t::Ok);
+ return Ok;
}
auto [coins, result] = getCoins(type);
- if (AccountErrors_t::Ok != enumFromValue(result)) {
+ if (Ok != result) {
return result;
}
- if (!g_accountRepository().setCoins(m_account.id, type, coins + amount)) {
- return enumToValue(AccountErrors_t::Storage);
+ if (!g_accountRepository().setCoins(m_account->id, type, coins + amount)) {
+ return Storage;
}
- registerCoinTransaction(enumToValue(CoinTransactionType::Add), type, amount, detail);
+ registerCoinTransaction(CoinTransactionType::Add, type, amount, detail);
- return enumToValue(AccountErrors_t::Ok);
+ return Ok;
}
-uint8_t Account::removeCoins(const uint8_t &type, const uint32_t &amount, const std::string &detail) {
+AccountErrors_t Account::removeCoins(CoinType type, const uint32_t &amount, const std::string &detail) {
+ using enum AccountErrors_t;
if (!m_accLoaded) {
- return enumToValue(AccountErrors_t::NotInitialized);
+ return NotInitialized;
}
if (amount == 0) {
- return enumToValue(AccountErrors_t::Ok);
+ return Ok;
}
auto [coins, result] = getCoins(type);
- if (AccountErrors_t::Ok != enumFromValue(result)) {
+ if (Ok != result) {
return result;
}
if (coins < amount) {
g_logger().info("Account doesn't have enough coins! current[{}], remove:[{}]", coins, amount);
- return enumToValue(AccountErrors_t::RemoveCoins);
+ return RemoveCoins;
}
- if (!g_accountRepository().setCoins(m_account.id, type, coins - amount)) {
- return enumToValue(AccountErrors_t::Storage);
+ if (!g_accountRepository().setCoins(m_account->id, type, coins - amount)) {
+ return Storage;
}
- registerCoinTransaction(enumToValue(CoinTransactionType::Remove), type, amount, detail);
+ registerCoinTransaction(CoinTransactionType::Remove, type, amount, detail);
- return enumToValue(AccountErrors_t::Ok);
+ return Ok;
}
-void Account::registerCoinTransaction(const uint8_t &transactionType, const uint8_t &type, const uint32_t &amount, const std::string &detail) {
+void Account::registerCoinTransaction(CoinTransactionType transactionType, CoinType type, const uint32_t &amount, const std::string &detail) {
if (!m_accLoaded) {
return;
}
@@ -153,17 +153,17 @@ void Account::registerCoinTransaction(const uint8_t &transactionType, const uint
return;
}
- if (!g_accountRepository().registerCoinsTransaction(m_account.id, transactionType, amount, type, detail)) {
+ if (!g_accountRepository().registerCoinsTransaction(m_account->id, transactionType, amount, type, detail)) {
g_logger().error(
"Failed to register transaction: 'account:[{}], transaction "
"type:[{}], coins:[{}], coin type:[{}], description:[{}]",
- m_account.id, transactionType, amount, type, detail
+ m_account->id, transactionType, amount, type, detail
);
}
}
[[nodiscard]] uint32_t Account::getID() const {
- return m_account.id;
+ return m_account->id;
};
std::string Account::getDescriptor() const {
@@ -176,61 +176,61 @@ std::string Account::getPassword() {
}
std::string password;
- if (!g_accountRepository().getPassword(m_account.id, password)) {
+ if (!g_accountRepository().getPassword(m_account->id, password)) {
password.clear();
- g_logger().error("Failed to get password for account[{}]!", m_account.id);
+ g_logger().error("Failed to get password for account[{}]!", m_account->id);
}
return password;
}
void Account::addPremiumDays(const int32_t &days) {
- auto timeLeft = std::max(0, static_cast((m_account.premiumLastDay - getTimeNow()) % 86400));
- setPremiumDays(m_account.premiumRemainingDays + days);
- m_account.premiumDaysPurchased += days;
+ auto timeLeft = std::max(0, static_cast((m_account->premiumLastDay - getTimeNow()) % 86400));
+ setPremiumDays(m_account->premiumRemainingDays + days);
+ m_account->premiumDaysPurchased += days;
if (timeLeft > 0) {
- m_account.premiumLastDay += timeLeft;
+ m_account->premiumLastDay += timeLeft;
}
}
void Account::setPremiumDays(const int32_t &days) {
- m_account.premiumRemainingDays = days;
- m_account.premiumLastDay = getTimeNow() + (days * 86400);
+ m_account->premiumRemainingDays = days;
+ m_account->premiumLastDay = getTimeNow() + (days * 86400);
if (days <= 0) {
- m_account.premiumLastDay = 0;
- m_account.premiumRemainingDays = 0;
+ m_account->premiumLastDay = 0;
+ m_account->premiumRemainingDays = 0;
}
}
[[nodiscard]] uint32_t Account::getPremiumRemainingDays() const {
- return m_account.premiumLastDay > getTimeNow() ? static_cast((m_account.premiumLastDay - getTimeNow()) / 86400) : 0;
+ return m_account->premiumLastDay > getTimeNow() ? static_cast((m_account->premiumLastDay - getTimeNow()) / 86400) : 0;
}
[[nodiscard]] uint32_t Account::getPremiumDaysPurchased() const {
- return m_account.premiumDaysPurchased;
+ return m_account->premiumDaysPurchased;
}
-uint8_t Account::setAccountType(const uint8_t &accountType) {
- m_account.accountType = accountType;
- return enumToValue(AccountErrors_t::Ok);
+AccountErrors_t Account::setAccountType(AccountType accountType) {
+ m_account->accountType = accountType;
+ return AccountErrors_t::Ok;
}
-[[nodiscard]] uint8_t Account::getAccountType() const {
- return m_account.accountType;
+[[nodiscard]] AccountType Account::getAccountType() const {
+ return m_account->accountType;
}
void Account::updatePremiumTime() {
- time_t lastDay = m_account.premiumLastDay;
- uint32_t remainingDays = m_account.premiumRemainingDays;
+ time_t lastDay = m_account->premiumLastDay;
+ uint32_t remainingDays = m_account->premiumRemainingDays;
time_t currentTime = getTimeNow();
auto daysLeft = static_cast((lastDay - currentTime) / 86400);
auto timeLeft = static_cast((lastDay - currentTime) % 86400);
- m_account.premiumRemainingDays = daysLeft > 0 ? daysLeft : 0;
+ m_account->premiumRemainingDays = daysLeft > 0 ? daysLeft : 0;
if (daysLeft == 0 && timeLeft == 0) {
setPremiumDays(0);
@@ -240,26 +240,27 @@ void Account::updatePremiumTime() {
setPremiumDays(0);
}
- if (remainingDays == m_account.premiumRemainingDays) {
+ if (remainingDays == m_account->premiumRemainingDays) {
return;
}
- if (AccountErrors_t::Ok != enumFromValue(save())) {
+ if (AccountErrors_t::Ok != save()) {
g_logger().error("Failed to update account premium time: [{}]", getDescriptor());
}
}
-std::tuple, uint8_t>
+std::tuple, AccountErrors_t>
Account::getAccountPlayers() const {
- auto valueToReturn = enumToValue(m_accLoaded ? AccountErrors_t::Ok : AccountErrors_t::NotInitialized);
- return { m_account.players, valueToReturn };
+ using enum AccountErrors_t;
+ auto valueToReturn = m_accLoaded ? Ok : NotInitialized;
+ return { m_account->players, valueToReturn };
}
void Account::setProtocolCompat(bool toggle) {
- m_account.oldProtocol = toggle;
+ m_account->oldProtocol = toggle;
}
bool Account::getProtocolCompat() const {
- return m_account.oldProtocol;
+ return m_account->oldProtocol;
}
bool Account::authenticate() {
@@ -272,8 +273,8 @@ bool Account::authenticate(const std::string &secret) {
}
bool Account::authenticateSession() {
- if (m_account.sessionExpires < getTimeNow()) {
- g_logger().error("Session expired for account[{}] expired at [{}] current time [{}]!", m_account.id, m_account.sessionExpires, getTimeNow());
+ if (m_account->sessionExpires < getTimeNow()) {
+ g_logger().error("Session expired for account[{}] expired at [{}] current time [{}]!", m_account->id, m_account->sessionExpires, getTimeNow());
return false;
}
return true;
@@ -293,9 +294,9 @@ bool Account::authenticatePassword(const std::string &password) {
}
uint32_t Account::getAccountAgeInDays() const {
- return static_cast(std::ceil((getTimeNow() - m_account.creationTime) / 86400));
+ return static_cast(std::ceil((getTimeNow() - m_account->creationTime) / 86400));
}
[[nodiscard]] time_t Account::getPremiumLastDay() const {
- return m_account.premiumLastDay;
+ return m_account->premiumLastDay;
}
diff --git a/src/account/account.hpp b/src/account/account.hpp
index d968ba8dd..2c6098a8d 100644
--- a/src/account/account.hpp
+++ b/src/account/account.hpp
@@ -9,13 +9,20 @@
#pragma once
-#include "account/account_info.hpp"
+struct AccountInfo;
+
+enum class CoinType : uint8_t;
+enum class CoinTransactionType : uint8_t;
+enum class AccountErrors_t : uint8_t;
+enum AccountType : uint8_t;
class Account {
public:
explicit Account(const uint32_t &id);
explicit Account(std::string descriptor);
+ ~Account() = default;
+
/** Coins
* @brief Get the amount of coins that the account has from database.
*
@@ -24,7 +31,7 @@ class Account {
* @return uint32_t Number of coins
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
- [[nodiscard]] std::tuple getCoins(const uint8_t &type) const;
+ [[nodiscard]] std::tuple getCoins(CoinType type) const;
/**
* @brief Add coins to the account.
@@ -33,7 +40,7 @@ class Account {
* @param amount Amount of coins to be added
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
- uint8_t addCoins(const uint8_t &type, const uint32_t &amount, const std::string &detail = "ADD Coins");
+ AccountErrors_t addCoins(CoinType type, const uint32_t &amount, const std::string &detail = "ADD Coins");
/**
* @brief Removes coins from the account.
@@ -42,7 +49,7 @@ class Account {
* @param amount Amount of coins to be removed
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
- uint8_t removeCoins(const uint8_t &type, const uint32_t &amount, const std::string &detail = "REMOVE Coins");
+ AccountErrors_t removeCoins(CoinType type, const uint32_t &amount, const std::string &detail = "REMOVE Coins");
/**
* @brief Registers a coin transaction.
@@ -51,7 +58,7 @@ class Account {
* @param amount Amount of coins to be added
* @param detail Detail of the transaction
*/
- void registerCoinTransaction(const uint8_t &transactionType, const uint8_t &type, const uint32_t &amount, const std::string &detail);
+ void registerCoinTransaction(CoinTransactionType transactionType, CoinType type, const uint32_t &amount, const std::string &detail);
/***************************************************************************
* Account Load/Save
@@ -62,14 +69,14 @@ class Account {
*
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
- uint8_t save();
+ AccountErrors_t save() const;
/**
* @brief Load Account Information.
*
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
- uint8_t load();
+ AccountErrors_t load();
/**
* @brief Re-Load Account Information to get update information(mainly the
@@ -77,7 +84,7 @@ class Account {
*
* @return AccountErrors_t AccountErrors_t::Ok(0) Success, otherwise Fail.
*/
- uint8_t reload();
+ AccountErrors_t reload();
/***************************************************************************
* Setters and Getters
@@ -105,12 +112,12 @@ class Account {
[[nodiscard]] time_t getPremiumLastDay() const;
- uint8_t setAccountType(const uint8_t &accountType);
- [[nodiscard]] uint8_t getAccountType() const;
+ AccountErrors_t setAccountType(AccountType accountType);
+ [[nodiscard]] AccountType getAccountType() const;
void updatePremiumTime();
- std::tuple, uint8_t> getAccountPlayers() const;
+ std::tuple, AccountErrors_t> getAccountPlayers() const;
// Old protocol compat
void setProtocolCompat(bool toggle);
@@ -126,6 +133,6 @@ class Account {
private:
std::string m_descriptor;
- AccountInfo m_account;
+ std::unique_ptr m_account;
bool m_accLoaded = false;
};
diff --git a/src/account/account_info.hpp b/src/account/account_info.hpp
index 698c3b96c..b9dad60db 100644
--- a/src/account/account_info.hpp
+++ b/src/account/account_info.hpp
@@ -14,11 +14,15 @@
#include
#endif
+#include "enums/account_type.hpp"
+
struct AccountInfo {
+ ~AccountInfo() = default;
+
uint32_t id = 0;
uint32_t premiumRemainingDays = 0;
time_t premiumLastDay = 0;
- uint8_t accountType = 0;
+ AccountType accountType = ACCOUNT_TYPE_NONE;
phmap::flat_hash_map players;
bool oldProtocol = false;
time_t sessionExpires = 0;
diff --git a/src/account/account_repository.cpp b/src/account/account_repository.cpp
index babca8470..f32982564 100644
--- a/src/account/account_repository.cpp
+++ b/src/account/account_repository.cpp
@@ -7,8 +7,6 @@
* Website: https://docs.opentibiabr.com/
*/
-#include "pch.hpp"
-
#include "account/account_repository.hpp"
#include "lib/di/container.hpp"
diff --git a/src/account/account_repository.hpp b/src/account/account_repository.hpp
index 0d4dcc7ab..5a9cd5292 100644
--- a/src/account/account_repository.hpp
+++ b/src/account/account_repository.hpp
@@ -11,6 +11,9 @@
struct AccountInfo;
+enum class CoinType : uint8_t;
+enum class CoinTransactionType : uint8_t;
+
class AccountRepository {
public:
AccountRepository() = default;
@@ -22,20 +25,22 @@ class AccountRepository {
static AccountRepository &getInstance();
- virtual bool loadByID(const uint32_t &id, AccountInfo &acc) = 0;
- virtual bool loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, AccountInfo &acc) = 0;
- virtual bool loadBySession(const std::string &email, AccountInfo &acc) = 0;
- virtual bool save(const AccountInfo &accInfo) = 0;
+ virtual bool loadByID(const uint32_t &id, std::unique_ptr &acc) = 0;
+ virtual bool loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, std::unique_ptr &acc) = 0;
+ virtual bool loadBySession(const std::string &email, std::unique_ptr &acc) = 0;
+ virtual bool save(const std::unique_ptr &accInfo) = 0;
+
+ virtual bool getCharacterByAccountIdAndName(const uint32_t &id, const std::string &name) = 0;
virtual bool getPassword(const uint32_t &id, std::string &password) = 0;
- virtual bool getCoins(const uint32_t &id, const uint8_t &type, uint32_t &coins) = 0;
- virtual bool setCoins(const uint32_t &id, const uint8_t &type, const uint32_t &amount) = 0;
+ virtual bool getCoins(const uint32_t &id, CoinType coinType, uint32_t &coins) = 0;
+ virtual bool setCoins(const uint32_t &id, CoinType coinType, const uint32_t &amount) = 0;
virtual bool registerCoinsTransaction(
const uint32_t &id,
- uint8_t type,
+ CoinTransactionType type,
uint32_t coins,
- const uint8_t &coinType,
+ CoinType coinType,
const std::string &description
) = 0;
};
diff --git a/src/account/account_repository_db.cpp b/src/account/account_repository_db.cpp
index b150a636a..c3f02bfe9 100644
--- a/src/account/account_repository_db.cpp
+++ b/src/account/account_repository_db.cpp
@@ -7,33 +7,33 @@
* Website: https://docs.opentibiabr.com/
*/
-#include "pch.hpp"
-
#include "account/account_repository_db.hpp"
#include "database/database.hpp"
-#include "lib/logging/logger.hpp"
+#include "enums/account_coins.hpp"
#include "utils/definitions.hpp"
#include "utils/tools.hpp"
-#include "enums/account_type.hpp"
-#include "enums/account_coins.hpp"
-#include "account/account_info.hpp"
-AccountRepositoryDB::AccountRepositoryDB() :
- coinTypeToColumn({ { enumToValue(CoinType::Normal), "coins" }, { enumToValue(CoinType::Tournament), "tournament_coins" }, { enumToValue(CoinType::Transferable), "coins_transferable" } }) { }
+AccountRepositoryDB::AccountRepositoryDB() {
+ coinTypeToColumn = {
+ { CoinType::Normal, "coins" },
+ { CoinType::Tournament, "coins_tournament" },
+ { CoinType::Transferable, "coins_transferable" }
+ };
+}
-bool AccountRepositoryDB::loadByID(const uint32_t &id, AccountInfo &acc) {
+bool AccountRepositoryDB::loadByID(const uint32_t &id, std::unique_ptr &acc) {
auto query = fmt::format("SELECT `id`, `type`, `premdays`, `lastday`, `creation`, `premdays_purchased`, 0 AS `expires` FROM `accounts` WHERE `id` = {}", id);
return load(query, acc);
};
-bool AccountRepositoryDB::loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, AccountInfo &acc) {
+bool AccountRepositoryDB::loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, std::unique_ptr &acc) {
auto identifier = oldProtocol ? "name" : "email";
auto query = fmt::format("SELECT `id`, `type`, `premdays`, `lastday`, `creation`, `premdays_purchased`, 0 AS `expires` FROM `accounts` WHERE `{}` = {}", identifier, g_database().escapeString(emailOrName));
return load(query, acc);
};
-bool AccountRepositoryDB::loadBySession(const std::string &sessionKey, AccountInfo &acc) {
+bool AccountRepositoryDB::loadBySession(const std::string &sessionKey, std::unique_ptr &acc) {
auto query = fmt::format(
"SELECT `accounts`.`id`, `type`, `premdays`, `lastday`, `creation`, `premdays_purchased`, `account_sessions`.`expires` "
"FROM `accounts` "
@@ -44,26 +44,36 @@ bool AccountRepositoryDB::loadBySession(const std::string &sessionKey, AccountIn
return load(query, acc);
};
-bool AccountRepositoryDB::save(const AccountInfo &accInfo) {
+bool AccountRepositoryDB::save(const std::unique_ptr &accInfo) {
bool successful = g_database().executeQuery(
fmt::format(
"UPDATE `accounts` SET `type` = {}, `premdays` = {}, `lastday` = {}, `creation` = {}, `premdays_purchased` = {} WHERE `id` = {}",
- accInfo.accountType,
- accInfo.premiumRemainingDays,
- accInfo.premiumLastDay,
- accInfo.creationTime,
- accInfo.premiumDaysPurchased,
- accInfo.id
+ accInfo->accountType,
+ accInfo->premiumRemainingDays,
+ accInfo->premiumLastDay,
+ accInfo->creationTime,
+ accInfo->premiumDaysPurchased,
+ accInfo->id
)
);
if (!successful) {
- g_logger().error("Failed to save account:[{}]", accInfo.id);
+ g_logger().error("Failed to save account:[{}]", accInfo->id);
}
return successful;
};
+bool AccountRepositoryDB::getCharacterByAccountIdAndName(const uint32_t &id, const std::string &name) {
+ auto result = g_database().storeQuery(fmt::format("SELECT `id` FROM `players` WHERE `account_id` = {} AND `name` = {}", id, g_database().escapeString(name)));
+ if (!result) {
+ g_logger().error("Failed to get character: [{}] from account: [{}]!", name, id);
+ return false;
+ }
+
+ return result->countResults() == 1;
+}
+
bool AccountRepositoryDB::getPassword(const uint32_t &id, std::string &password) {
auto result = g_database().storeQuery(fmt::format("SELECT * FROM `accounts` WHERE `id` = {}", id));
if (!result) {
@@ -75,15 +85,18 @@ bool AccountRepositoryDB::getPassword(const uint32_t &id, std::string &password)
return true;
};
-bool AccountRepositoryDB::getCoins(const uint32_t &id, const uint8_t &type, uint32_t &coins) {
- if (coinTypeToColumn.find(type) == coinTypeToColumn.end()) {
- g_logger().error("[{}]: invalid coin type:[{}]", __FUNCTION__, type);
+bool AccountRepositoryDB::getCoins(const uint32_t &id, CoinType coinType, uint32_t &coins) {
+ auto it = coinTypeToColumn.find(coinType);
+ if (it == coinTypeToColumn.end()) {
+ g_logger().error("[{}] invalid coin type:[{}]", __FUNCTION__, coinType);
return false;
}
- auto result = g_database().storeQuery(fmt::format(
+ auto column = it->second;
+
+ const auto result = g_database().storeQuery(fmt::format(
"SELECT `{}` FROM `accounts` WHERE `id` = {}",
- coinTypeToColumn.at(type),
+ column,
id
));
@@ -91,20 +104,23 @@ bool AccountRepositoryDB::getCoins(const uint32_t &id, const uint8_t &type, uint
return false;
}
- coins = result->getNumber(coinTypeToColumn.at(type));
+ coins = result->getNumber(column);
return true;
};
-bool AccountRepositoryDB::setCoins(const uint32_t &id, const uint8_t &type, const uint32_t &amount) {
- if (coinTypeToColumn.find(type) == coinTypeToColumn.end()) {
- g_logger().error("[{}]: invalid coin type:[{}]", __FUNCTION__, type);
+bool AccountRepositoryDB::setCoins(const uint32_t &id, CoinType coinType, const uint32_t &amount) {
+ auto it = coinTypeToColumn.find(coinType);
+ if (it == coinTypeToColumn.end()) {
+ g_logger().error("[{}]: invalid coin type:[{}]", __FUNCTION__, coinType);
return false;
}
- bool successful = g_database().executeQuery(fmt::format(
+ auto column = it->second;
+
+ const bool successful = g_database().executeQuery(fmt::format(
"UPDATE `accounts` SET `{}` = {} WHERE `id` = {}",
- coinTypeToColumn.at(type),
+ column,
amount,
id
));
@@ -118,9 +134,9 @@ bool AccountRepositoryDB::setCoins(const uint32_t &id, const uint8_t &type, cons
bool AccountRepositoryDB::registerCoinsTransaction(
const uint32_t &id,
- uint8_t type,
+ CoinTransactionType type,
uint32_t coins,
- const uint8_t &coinType,
+ CoinType coinType,
const std::string &description
) {
bool successful = g_database().executeQuery(
@@ -148,13 +164,13 @@ bool AccountRepositoryDB::registerCoinsTransaction(
return successful;
};
-bool AccountRepositoryDB::loadAccountPlayers(AccountInfo &acc) {
+bool AccountRepositoryDB::loadAccountPlayers(std::unique_ptr &acc) const {
auto result = g_database().storeQuery(
- fmt::format("SELECT `name`, `deletion` FROM `players` WHERE `account_id` = {} ORDER BY `name` ASC", acc.id)
+ fmt::format("SELECT `name`, `deletion` FROM `players` WHERE `account_id` = {} ORDER BY `name` ASC", acc->id)
);
if (!result) {
- g_logger().error("Failed to load account[{}] players!", acc.id);
+ g_logger().error("Failed to load account[{}] players!", acc->id);
return false;
}
@@ -163,43 +179,43 @@ bool AccountRepositoryDB::loadAccountPlayers(AccountInfo &acc) {
continue;
}
- acc.players.try_emplace({ result->getString("name"), result->getNumber("deletion") });
+ acc->players.try_emplace({ result->getString("name"), result->getNumber("deletion") });
} while (result->next());
return true;
}
-bool AccountRepositoryDB::load(const std::string &query, AccountInfo &acc) {
+bool AccountRepositoryDB::load(const std::string &query, std::unique_ptr &acc) {
auto result = g_database().storeQuery(query);
if (result == nullptr) {
return false;
}
- acc.id = result->getNumber("id");
- acc.accountType = result->getNumber("type");
- acc.premiumLastDay = result->getNumber("lastday");
- acc.sessionExpires = result->getNumber("expires");
- acc.premiumDaysPurchased = result->getNumber("premdays_purchased");
- acc.creationTime = result->getNumber("creation");
- acc.premiumRemainingDays = acc.premiumLastDay > getTimeNow() ? (acc.premiumLastDay - getTimeNow()) / 86400 : 0;
+ acc->id = result->getNumber("id");
+ acc->accountType = result->getNumber("type");
+ acc->premiumLastDay = result->getNumber("lastday");
+ acc->sessionExpires = result->getNumber("expires");
+ acc->premiumDaysPurchased = result->getNumber("premdays_purchased");
+ acc->creationTime = result->getNumber("creation");
+ acc->premiumRemainingDays = acc->premiumLastDay > getTimeNow() ? (acc->premiumLastDay - getTimeNow()) / 86400 : 0;
setupLoyaltyInfo(acc);
return loadAccountPlayers(acc);
}
-void AccountRepositoryDB::setupLoyaltyInfo(AccountInfo &acc) {
- if (acc.premiumDaysPurchased >= acc.premiumRemainingDays && acc.creationTime != 0) {
+void AccountRepositoryDB::setupLoyaltyInfo(std::unique_ptr &acc) {
+ if (acc->premiumDaysPurchased >= acc->premiumRemainingDays && acc->creationTime != 0) {
return;
}
- if (acc.premiumDaysPurchased < acc.premiumRemainingDays) {
- acc.premiumDaysPurchased = acc.premiumRemainingDays;
+ if (acc->premiumDaysPurchased < acc->premiumRemainingDays) {
+ acc->premiumDaysPurchased = acc->premiumRemainingDays;
}
- if (acc.creationTime == 0) {
- acc.creationTime = getTimeNow();
+ if (acc->creationTime == 0) {
+ acc->creationTime = getTimeNow();
}
save(acc);
diff --git a/src/account/account_repository_db.hpp b/src/account/account_repository_db.hpp
index 651600e3b..e7a11c15e 100644
--- a/src/account/account_repository_db.hpp
+++ b/src/account/account_repository_db.hpp
@@ -11,30 +11,36 @@
#include "account/account_repository.hpp"
+enum class CoinType : uint8_t;
+enum class CoinTransactionType : uint8_t;
+
class AccountRepositoryDB final : public AccountRepository {
public:
AccountRepositoryDB();
- bool loadByID(const uint32_t &id, AccountInfo &acc) override;
- bool loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, AccountInfo &acc) override;
- bool loadBySession(const std::string &esseionKey, AccountInfo &acc) override;
- bool save(const AccountInfo &accInfo) override;
+ bool loadByID(const uint32_t &id, std::unique_ptr &acc) override;
+ bool loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, std::unique_ptr &acc) override;
+ bool loadBySession(const std::string &esseionKey, std::unique_ptr &acc) override;
+ bool save(const std::unique_ptr &accInfo) override;
+
+ bool getCharacterByAccountIdAndName(const uint32_t &id, const std::string &name) override;
bool getPassword(const uint32_t &id, std::string &password) override;
- bool getCoins(const uint32_t &id, const uint8_t &type, uint32_t &coins) override;
- bool setCoins(const uint32_t &id, const uint8_t &type, const uint32_t &amount) override;
+ bool getCoins(const uint32_t &id, CoinType coinType, uint32_t &coins) override;
+ bool setCoins(const uint32_t &id, CoinType coinType, const uint32_t &amount) override;
bool registerCoinsTransaction(
const uint32_t &id,
- uint8_t type,
+ CoinTransactionType type,
uint32_t coins,
- const uint8_t &coinType,
+ CoinType coinType,
const std::string &description
) override;
private:
- const std::map coinTypeToColumn;
- bool load(const std::string &query, AccountInfo &acc);
- bool loadAccountPlayers(AccountInfo &acc);
- void setupLoyaltyInfo(AccountInfo &acc);
+ std::unordered_map coinTypeToColumn {};
+
+ bool load(const std::string &query, std::unique_ptr &acc);
+ bool loadAccountPlayers(std::unique_ptr &acc) const;
+ void setupLoyaltyInfo(std::unique_ptr &acc);
};
diff --git a/src/canary_server.cpp b/src/canary_server.cpp
index ef1be1b1f..687fa51b6 100644
--- a/src/canary_server.cpp
+++ b/src/canary_server.cpp
@@ -7,19 +7,22 @@
* Website: https://docs.opentibiabr.com/
*/
-#include "pch.hpp"
-
#include "canary_server.hpp"
-#include "declarations.hpp"
+#include "config/configmanager.hpp"
+#include "creatures/npcs/npcs.hpp"
#include "creatures/players/grouping/familiars.hpp"
+#include "creatures/players/imbuements/imbuements.hpp"
#include "creatures/players/storages/storages.hpp"
#include "database/databasemanager.hpp"
+#include "declarations.hpp"
#include "game/game.hpp"
-#include "game/zones/zone.hpp"
#include "game/scheduling/dispatcher.hpp"
#include "game/scheduling/events_scheduler.hpp"
+#include "game/zones/zone.hpp"
+#include "io/io_bosstiary.hpp"
#include "io/iomarket.hpp"
+#include "io/ioprey.hpp"
#include "lib/thread/thread_pool.hpp"
#include "lua/creature/events.hpp"
#include "lua/modules/modules.hpp"
@@ -28,8 +31,6 @@
#include "server/network/protocol/protocollogin.hpp"
#include "server/network/protocol/protocolstatus.hpp"
#include "server/network/webhook/webhook.hpp"
-#include "io/ioprey.hpp"
-#include "io/io_bosstiary.hpp"
#include "core.hpp"
@@ -60,16 +61,16 @@ int CanaryServer::run() {
try {
loadConfigLua();
- logger.info("Server protocol: {}.{}{}", CLIENT_VERSION_UPPER, CLIENT_VERSION_LOWER, g_configManager().getBoolean(OLD_PROTOCOL, __FUNCTION__) ? " and 10x allowed!" : "");
+ logger.info("Server protocol: {}.{}{}", CLIENT_VERSION_UPPER, CLIENT_VERSION_LOWER, g_configManager().getBoolean(OLD_PROTOCOL) ? " and 10x allowed!" : "");
#ifdef FEATURE_METRICS
metrics::Options metricsOptions;
- metricsOptions.enablePrometheusExporter = g_configManager().getBoolean(METRICS_ENABLE_PROMETHEUS, __FUNCTION__);
+ metricsOptions.enablePrometheusExporter = g_configManager().getBoolean(METRICS_ENABLE_PROMETHEUS);
if (metricsOptions.enablePrometheusExporter) {
- metricsOptions.prometheusOptions.url = g_configManager().getString(METRICS_PROMETHEUS_ADDRESS, __FUNCTION__);
+ metricsOptions.prometheusOptions.url = g_configManager().getString(METRICS_PROMETHEUS_ADDRESS);
}
- metricsOptions.enableOStreamExporter = g_configManager().getBoolean(METRICS_ENABLE_OSTREAM, __FUNCTION__);
+ metricsOptions.enableOStreamExporter = g_configManager().getBoolean(METRICS_ENABLE_OSTREAM);
if (metricsOptions.enableOStreamExporter) {
- metricsOptions.ostreamOptions.export_interval_millis = std::chrono::milliseconds(g_configManager().getNumber(METRICS_OSTREAM_INTERVAL, __FUNCTION__));
+ metricsOptions.ostreamOptions.export_interval_millis = std::chrono::milliseconds(g_configManager().getNumber(METRICS_OSTREAM_INTERVAL));
}
g_metrics().init(metricsOptions);
#endif
@@ -99,8 +100,7 @@ int CanaryServer::run() {
#endif
g_game().start(&serviceManager);
- g_game().setGameState(GAME_STATE_NORMAL);
- if (g_configManager().getBoolean(TOGGLE_MAINTAIN_MODE, __FUNCTION__)) {
+ if (g_configManager().getBoolean(TOGGLE_MAINTAIN_MODE)) {
g_game().setGameState(GAME_STATE_CLOSED);
g_logger().warn("Initialized in maintain mode!");
g_webhook().sendMessage(":yellow_square: Server is now **online** _(access restricted to staff)_");
@@ -123,7 +123,7 @@ int CanaryServer::run() {
loaderStatus.notify_one();
},
- "CanaryServer::run"
+ __FUNCTION__
);
loaderStatus.wait(LoaderStatus::LOADING);
@@ -134,7 +134,8 @@ int CanaryServer::run() {
return EXIT_FAILURE;
}
- logger.info("{} {}", g_configManager().getString(SERVER_NAME, __FUNCTION__), "server online!");
+ logger.info("{} {}", g_configManager().getString(SERVER_NAME), "server online!");
+ g_logger().setLevel(g_configManager().getString(LOGLEVEL));
serviceManager.run();
@@ -143,7 +144,7 @@ int CanaryServer::run() {
}
void CanaryServer::setWorldType() {
- const std::string worldType = asLowerCaseString(g_configManager().getString(WORLD_TYPE, __FUNCTION__));
+ const std::string worldType = asLowerCaseString(g_configManager().getString(WORLD_TYPE));
if (worldType == "pvp") {
g_game().setWorldType(WORLD_TYPE_PVP);
} else if (worldType == "no-pvp") {
@@ -154,7 +155,7 @@ void CanaryServer::setWorldType() {
throw FailedToInitializeCanary(
fmt::format(
"Unknown world type: {}, valid world types are: pvp, no-pvp and pvp-enforced",
- g_configManager().getString(WORLD_TYPE, __FUNCTION__)
+ g_configManager().getString(WORLD_TYPE)
)
);
}
@@ -164,11 +165,11 @@ void CanaryServer::setWorldType() {
void CanaryServer::loadMaps() const {
try {
- g_game().loadMainMap(g_configManager().getString(MAP_NAME, __FUNCTION__));
+ g_game().loadMainMap(g_configManager().getString(MAP_NAME));
// If "mapCustomEnabled" is true on config.lua, then load the custom map
- if (g_configManager().getBoolean(TOGGLE_MAP_CUSTOM, __FUNCTION__)) {
- g_game().loadCustomMaps(g_configManager().getString(DATA_DIRECTORY, __FUNCTION__) + "/world/custom/");
+ if (g_configManager().getBoolean(TOGGLE_MAP_CUSTOM)) {
+ g_game().loadCustomMaps(g_configManager().getString(DATA_DIRECTORY) + "/world/custom/");
}
Zone::refreshAll();
} catch (const std::exception &err) {
@@ -178,7 +179,7 @@ void CanaryServer::loadMaps() const {
void CanaryServer::setupHousesRent() {
RentPeriod_t rentPeriod;
- std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD, __FUNCTION__));
+ std::string strRentPeriod = asLowerCaseString(g_configManager().getString(HOUSE_RENT_PERIOD));
if (strRentPeriod == "yearly") {
rentPeriod = RENTPERIOD_YEARLY;
@@ -205,16 +206,15 @@ void CanaryServer::logInfos() {
logger.info("{} - Version {}", ProtocolStatus::SERVER_NAME, SERVER_RELEASE_VERSION);
#endif
- logger.debug("Compiled with {}, on {} {}, for platform {}\n", getCompiler(), __DATE__, __TIME__, getPlatform());
+ logger.debug("Compiled with {}, on {} {}, for platform {}", getCompiler(), __DATE__, __TIME__, getPlatform());
#if defined(LUAJIT_VERSION)
logger.debug("Linked with {} for Lua support", LUAJIT_VERSION);
#endif
logger.info("A server developed by: {}", ProtocolStatus::SERVER_DEVELOPERS);
- logger.info("Visit our website for updates, support, and resources: \n"
- "https://docs.opentibiabr.com/home/welcome/ \n"
- "https://github.com/mattyx14/otxserver/\n");
+ logger.info("Visit our website for updates, support, and resources: "
+ "https://docs.opentibiabr.com/");
}
/**
@@ -292,7 +292,7 @@ void CanaryServer::loadConfigLua() {
modulesLoadHelper(g_configManager().load(), g_configManager().getConfigFileLua());
#ifdef _WIN32
- const std::string &defaultPriority = g_configManager().getString(DEFAULT_PRIORITY, __FUNCTION__);
+ const std::string &defaultPriority = g_configManager().getString(DEFAULT_PRIORITY);
if (strcasecmp(defaultPriority.c_str(), "high") == 0) {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
} else if (strcasecmp(defaultPriority.c_str(), "above-normal") == 0) {
@@ -318,7 +318,7 @@ void CanaryServer::initializeDatabase() {
DatabaseManager::updateDatabase();
- if (g_configManager().getBoolean(OPTIMIZE_DATABASE, __FUNCTION__)
+ if (g_configManager().getBoolean(OPTIMIZE_DATABASE)
&& !DatabaseManager::optimizeTables()) {
logger.debug("No tables were optimized");
}
@@ -326,8 +326,8 @@ void CanaryServer::initializeDatabase() {
void CanaryServer::loadModules() {
// If "USE_ANY_DATAPACK_FOLDER" is set to true then you can choose any datapack folder for your server
- const auto useAnyDatapack = g_configManager().getBoolean(USE_ANY_DATAPACK_FOLDER, __FUNCTION__);
- auto datapackName = g_configManager().getString(DATA_DIRECTORY, __FUNCTION__);
+ const auto useAnyDatapack = g_configManager().getBoolean(USE_ANY_DATAPACK_FOLDER);
+ auto datapackName = g_configManager().getString(DATA_DIRECTORY);
if (!useAnyDatapack && datapackName != "data-canary" && datapackName != "data-otservbr-global") {
throw FailedToInitializeCanary(fmt::format(
"The datapack folder name '{}' is wrong, please select valid "
@@ -342,7 +342,7 @@ void CanaryServer::loadModules() {
g_luaEnvironment().initState();
}
- auto coreFolder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__);
+ auto coreFolder = g_configManager().getString(CORE_DIRECTORY);
// Load appearances.dat first
modulesLoadHelper((g_game().loadAppearanceProtobuf(coreFolder + "/items/appearances.dat") == ERROR_NONE), "appearances.dat");
@@ -356,7 +356,7 @@ void CanaryServer::loadModules() {
modulesLoadHelper(Item::items.loadFromXml(), "items.xml");
- const auto datapackFolder = g_configManager().getString(DATA_DIRECTORY, __FUNCTION__);
+ const auto datapackFolder = g_configManager().getString(DATA_DIRECTORY);
logger.debug("Loading core scripts on folder: {}/", coreFolder);
// Load first core Lua libs
modulesLoadHelper((g_luaEnvironment().loadFile(coreFolder + "/core.lua", "core.lua") == 0), "core.lua");
@@ -368,6 +368,7 @@ void CanaryServer::loadModules() {
modulesLoadHelper(g_modules().loadFromXml(), "modules/modules.xml");
logger.debug("Loading datapack scripts on folder: {}/", datapackName);
+ modulesLoadHelper(g_scripts().loadScripts(datapackFolder + "/scripts/lib", true, false), datapackFolder + "/scripts/libs");
// Load scripts
modulesLoadHelper(g_scripts().loadScripts(datapackFolder + "/scripts", false, false), datapackFolder + "/scripts");
// Load monsters
diff --git a/src/config/config_enums.hpp b/src/config/config_enums.hpp
index bf4805050..559045fdb 100644
--- a/src/config/config_enums.hpp
+++ b/src/config/config_enums.hpp
@@ -142,6 +142,7 @@ enum ConfigKey_t : uint16_t {
MAX_ALLOWED_ON_A_DUMMY,
MAX_CONTAINER_ITEM,
MAX_CONTAINER,
+ MAX_CONTAINER_DEPTH,
MAX_DAMAGE_REFLECTION,
MAX_ELEMENTAL_RESISTANCE,
MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER,
@@ -157,7 +158,7 @@ enum ConfigKey_t : uint16_t {
METRICS_PROMETHEUS_ADDRESS,
MIN_DELAY_BETWEEN_CONDITIONS,
MIN_ELEMENTAL_RESISTANCE,
- MIN_TOWN_ID_TO_BANK_TRANSFER,
+ MIN_TOWN_ID_TO_BANK_TRANSFER_FROM_MAIN,
MOMENTUM_CHANCE_FORMULA_A,
MOMENTUM_CHANCE_FORMULA_B,
MOMENTUM_CHANCE_FORMULA_C,
diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp
index 6390d0699..1c00df76c 100644
--- a/src/config/configmanager.cpp
+++ b/src/config/configmanager.cpp
@@ -7,12 +7,12 @@
* Website: https://docs.opentibiabr.com/
*/
-#include "pch.hpp"
-
#include "config/configmanager.hpp"
+
#include "lib/di/container.hpp"
#include "game/game.hpp"
#include "server/network/webhook/webhook.hpp"
+#include "utils/tools.hpp"
#if LUA_VERSION_NUM >= 502
#undef lua_strlen
@@ -37,10 +37,6 @@ bool ConfigManager::load() {
return false;
}
-#ifndef DEBUG_LOG
- g_logger().setLevel(loadStringConfig(L, LOGLEVEL, "logLevel", "info"));
-#endif
-
// Parse config
// Info that must be loaded one time (unless we reset the modules involved)
if (!loaded) {
@@ -271,6 +267,7 @@ bool ConfigManager::load() {
loadIntConfig(L, MAX_ALLOWED_ON_A_DUMMY, "maxAllowedOnADummy", 1);
loadIntConfig(L, MAX_CONTAINER_ITEM, "maxItem", 5000);
loadIntConfig(L, MAX_CONTAINER, "maxContainer", 500);
+ loadIntConfig(L, MAX_CONTAINER_DEPTH, "maxContainerDepth", 200);
loadIntConfig(L, MAX_DAMAGE_REFLECTION, "maxDamageReflection", 200);
loadIntConfig(L, MAX_ELEMENTAL_RESISTANCE, "maxElementalResistance", 200);
loadIntConfig(L, MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER, "maxMarketOffersAtATimePerPlayer", 100);
@@ -283,7 +280,7 @@ bool ConfigManager::load() {
loadIntConfig(L, METRICS_OSTREAM_INTERVAL, "metricsOstreamInterval", 1000);
loadIntConfig(L, MIN_DELAY_BETWEEN_CONDITIONS, "minDelayBetweenConditions", 0);
loadIntConfig(L, MIN_ELEMENTAL_RESISTANCE, "minElementalResistance", -200);
- loadIntConfig(L, MIN_TOWN_ID_TO_BANK_TRANSFER, "minTownIdToBankTransfer", 3);
+ loadIntConfig(L, MIN_TOWN_ID_TO_BANK_TRANSFER_FROM_MAIN, "minTownIdToBankTransferFromMain", 4);
loadIntConfig(L, MONTH_KILLS_TO_RED, "monthKillsToRedSkull", 10);
loadIntConfig(L, MULTIPLIER_ATTACKONFIST, "multiplierSpeedOnFist", 5);
loadIntConfig(L, ORANGE_SKULL_DURATION, "orangeSkullDuration", 7);
@@ -364,6 +361,7 @@ bool ConfigManager::load() {
loadStringConfig(L, TIBIADROME_CONCOCTION_TICK_TYPE, "tibiadromeConcoctionTickType", "online");
loadStringConfig(L, URL, "url", "");
loadStringConfig(L, WORLD_TYPE, "worldType", "pvp");
+ loadStringConfig(L, LOGLEVEL, "logLevel", "info");
loaded = true;
lua_close(L);
@@ -372,14 +370,14 @@ bool ConfigManager::load() {
bool ConfigManager::reload() {
const bool result = load();
- if (transformToSHA1(getString(SERVER_MOTD, __FUNCTION__)) != g_game().getMotdHash()) {
+ if (transformToSHA1(getString(SERVER_MOTD)) != g_game().getMotdHash()) {
g_game().incrementMotdNum();
}
return result;
}
void ConfigManager::missingConfigWarning(const char* identifier) {
- g_logger().warn("[{}]: Missing configuration for identifier: {}", __FUNCTION__, identifier);
+ g_logger().debug("[{}]: Missing configuration for identifier: {}", __FUNCTION__, identifier);
}
std::string ConfigManager::loadStringConfig(lua_State* L, const ConfigKey_t &key, const char* identifier, const std::string &defaultValue) {
@@ -434,35 +432,35 @@ float ConfigManager::loadFloatConfig(lua_State* L, const ConfigKey_t &key, const
return value;
}
-const std::string &ConfigManager::getString(const ConfigKey_t &key, std::string_view context) const {
+const std::string &ConfigManager::getString(const ConfigKey_t &key, const std::source_location &location /*= std::source_location::current()*/) const {
static const std::string dummyStr;
if (configs.contains(key) && std::holds_alternative(configs.at(key))) {
return std::get(configs.at(key));
}
- g_logger().warn("[ConfigManager::getString] - Accessing invalid or wrong type index: {}[{}], Function: {}", magic_enum::enum_name(key), fmt::underlying(key), context);
+ g_logger().warn("[{}] accessing invalid or wrong type index: {}[{}]. Called line: {}:{}, in {}", __FUNCTION__, magic_enum::enum_name(key), fmt::underlying(key), location.line(), location.column(), location.function_name());
return dummyStr;
}
-int32_t ConfigManager::getNumber(const ConfigKey_t &key, std::string_view context) const {
+int32_t ConfigManager::getNumber(const ConfigKey_t &key, const std::source_location &location /*= std::source_location::current()*/) const {
if (configs.contains(key) && std::holds_alternative(configs.at(key))) {
return std::get(configs.at(key));
}
- g_logger().warn("[ConfigManager::getNumber] - Accessing invalid or wrong type index: {}[{}], Function: {}", magic_enum::enum_name(key), fmt::underlying(key), context);
+ g_logger().warn("[{}] accessing invalid or wrong type index: {}[{}]. Called line: {}:{}, in {}", __FUNCTION__, magic_enum::enum_name(key), fmt::underlying(key), location.line(), location.column(), location.function_name());
return 0;
}
-bool ConfigManager::getBoolean(const ConfigKey_t &key, std::string_view context) const {
+bool ConfigManager::getBoolean(const ConfigKey_t &key, const std::source_location &location /*= std::source_location::current()*/) const {
if (configs.contains(key) && std::holds_alternative(configs.at(key))) {
return std::get(configs.at(key));
}
- g_logger().warn("[ConfigManager::getBoolean] - Accessing invalid or wrong type index: {}[{}], Function: {}", magic_enum::enum_name(key), fmt::underlying(key), context);
+ g_logger().warn("[{}] accessing invalid or wrong type index: {}[{}]. Called line: {}:{}, in {}", __FUNCTION__, magic_enum::enum_name(key), fmt::underlying(key), location.line(), location.column(), location.function_name());
return false;
}
-float ConfigManager::getFloat(const ConfigKey_t &key, std::string_view context) const {
+float ConfigManager::getFloat(const ConfigKey_t &key, const std::source_location &location /*= std::source_location::current()*/) const {
if (configs.contains(key) && std::holds_alternative(configs.at(key))) {
return std::get(configs.at(key));
}
- g_logger().warn("[ConfigManager::getFloat] - Accessing invalid or wrong type index: {}[{}], Function: {}", magic_enum::enum_name(key), fmt::underlying(key), context);
+ g_logger().warn("[{}] accessing invalid or wrong type index: {}[{}]. Called line: {}:{}, in {}", __FUNCTION__, magic_enum::enum_name(key), fmt::underlying(key), location.line(), location.column(), location.function_name());
return 0.0f;
}
diff --git a/src/config/configmanager.hpp b/src/config/configmanager.hpp
index 2a0c08619..ddc15e45e 100644
--- a/src/config/configmanager.hpp
+++ b/src/config/configmanager.hpp
@@ -36,10 +36,10 @@ class ConfigManager {
return configFileLua;
};
- [[nodiscard]] const std::string &getString(const ConfigKey_t &key, std::string_view context) const;
- [[nodiscard]] int32_t getNumber(const ConfigKey_t &key, std::string_view context) const;
- [[nodiscard]] bool getBoolean(const ConfigKey_t &key, std::string_view context) const;
- [[nodiscard]] float getFloat(const ConfigKey_t &key, std::string_view context) const;
+ [[nodiscard]] const std::string &getString(const ConfigKey_t &key, const std::source_location &location = std::source_location::current()) const;
+ [[nodiscard]] int32_t getNumber(const ConfigKey_t &key, const std::source_location &location = std::source_location::current()) const;
+ [[nodiscard]] bool getBoolean(const ConfigKey_t &key, const std::source_location &location = std::source_location::current()) const;
+ [[nodiscard]] float getFloat(const ConfigKey_t &key, const std::source_location &location = std::source_location::current()) const;
private:
phmap::flat_hash_map configs;
diff --git a/src/core.hpp b/src/core.hpp
index 5802c4966..635211884 100644
--- a/src/core.hpp
+++ b/src/core.hpp
@@ -14,8 +14,8 @@ static constexpr auto AUTHENTICATOR_PERIOD = 30U;
// SERVER_MAJOR_VERSION is the actual full version of the server, including minor and patch numbers.
// This is intended for internal use to identify the exact state of the server (release) software.
-static constexpr auto SERVER_RELEASE_VERSION = "6.2";
-static constexpr auto CLIENT_VERSION = 1332;
+static constexpr auto SERVER_RELEASE_VERSION = "3.1.2";
+static constexpr auto CLIENT_VERSION = 1340;
#define CLIENT_VERSION_UPPER (CLIENT_VERSION / 100)
#define CLIENT_VERSION_LOWER (CLIENT_VERSION % 100)
diff --git a/src/creatures/appearance/mounts/mounts.cpp b/src/creatures/appearance/mounts/mounts.cpp
index 7014d0b02..4b40d3835 100644
--- a/src/creatures/appearance/mounts/mounts.cpp
+++ b/src/creatures/appearance/mounts/mounts.cpp
@@ -7,9 +7,9 @@
* Website: https://docs.opentibiabr.com/
*/
-#include "pch.hpp"
-
#include "creatures/appearance/mounts/mounts.hpp"
+
+#include "config/configmanager.hpp"
#include "game/game.hpp"
#include "utils/pugicast.hpp"
#include "utils/tools.hpp"
@@ -21,7 +21,7 @@ bool Mounts::reload() {
bool Mounts::loadFromXml() {
pugi::xml_document doc;
- auto folder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__) + "/XML/mounts.xml";
+ auto folder = g_configManager().getString(CORE_DIRECTORY) + "/XML/mounts.xml";
pugi::xml_parse_result result = doc.load_file(folder.c_str());
if (!result) {
printXMLError(__FUNCTION__, folder, result);
@@ -30,7 +30,7 @@ bool Mounts::loadFromXml() {
for (auto mountNode : doc.child("mounts").children()) {
auto lookType = pugi::cast(mountNode.attribute("clientid").value());
- if (g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && lookType != 0 && !g_game().isLookTypeRegistered(lookType)) {
+ if (g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS) && lookType != 0 && !g_game().isLookTypeRegistered(lookType)) {
g_logger().warn("{} - An unregistered creature mount with id '{}' was blocked to prevent client crash.", __FUNCTION__, lookType);
continue;
}
diff --git a/src/creatures/appearance/outfit/outfit.cpp b/src/creatures/appearance/outfit/outfit.cpp
index 251bf7bde..4910f937b 100644
--- a/src/creatures/appearance/outfit/outfit.cpp
+++ b/src/creatures/appearance/outfit/outfit.cpp
@@ -7,12 +7,16 @@
* Website: https://docs.opentibiabr.com/
*/
-#include "pch.hpp"
-
#include "creatures/appearance/outfit/outfit.hpp"
+
+#include "config/configmanager.hpp"
+#include "creatures/players/player.hpp"
+#include "game/game.hpp"
+#include "lib/di/container.hpp"
#include "utils/pugicast.hpp"
#include "utils/tools.hpp"
-#include "game/game.hpp"
+
+std::vector> outfits[PLAYERSEX_LAST + 1];
Outfits &Outfits::getInstance() {
return inject();
@@ -27,7 +31,7 @@ bool Outfits::reload() {
bool Outfits::loadFromXml() {
pugi::xml_document doc;
- auto folder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__) + "/XML/outfits.xml";
+ auto folder = g_configManager().getString(CORE_DIRECTORY) + "/XML/outfits.xml";
pugi::xml_parse_result result = doc.load_file(folder.c_str());
if (!result) {
printXMLError(__FUNCTION__, folder, result);
@@ -58,7 +62,7 @@ bool Outfits::loadFromXml() {
}
if (auto lookType = pugi::cast(lookTypeAttribute.value());
- g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS, __FUNCTION__) && lookType != 0
+ g_configManager().getBoolean(WARN_UNSAFE_SCRIPTS) && lookType != 0
&& !g_game().isLookTypeRegistered(lookType)) {
g_logger().warn("[Outfits::loadFromXml] An unregistered creature looktype type with id '{}' was ignored to prevent client crash.", lookType);
continue;
@@ -103,3 +107,17 @@ std::shared_ptr Outfits::getOutfitByLookType(const std::shared_ptr> &Outfits::getOutfits(PlayerSex_t sex) const {
+ return outfits[sex];
+}
+
+std::shared_ptr Outfits::getOutfitByName(PlayerSex_t sex, const std::string &name) const {
+ for (const auto &outfit : outfits[sex]) {
+ if (outfit->name == name) {
+ return outfit;
+ }
+ }
+
+ return nullptr;
+}
diff --git a/src/creatures/appearance/outfit/outfit.hpp b/src/creatures/appearance/outfit/outfit.hpp
index 0d89a2c93..2d9488449 100644
--- a/src/creatures/appearance/outfit/outfit.hpp
+++ b/src/creatures/appearance/outfit/outfit.hpp
@@ -9,9 +9,7 @@
#pragma once
-#include "declarations.hpp"
-#include "lib/di/container.hpp"
-
+enum PlayerSex_t : uint8_t;
class Player;
struct OutfitEntry {
@@ -50,10 +48,7 @@ class Outfits {
bool loadFromXml();
[[nodiscard]] std::shared_ptr getOutfitByLookType(const std::shared_ptr &player, uint16_t lookType, bool isOppositeOutfit = false) const;
- [[nodiscard]] const std::vector> &getOutfits(PlayerSex_t sex) const {
- return outfits[sex];
- }
+ [[nodiscard]] const std::vector> &getOutfits(PlayerSex_t sex) const;
-private:
- std::vector> outfits[PLAYERSEX_LAST + 1];
+ std::shared_ptr getOutfitByName(PlayerSex_t sex, const std::string &name) const;
};
diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp
index 8e3de0da1..a63f42093 100644
--- a/src/creatures/combat/combat.cpp
+++ b/src/creatures/combat/combat.cpp
@@ -7,24 +7,28 @@
* Website: https://docs.opentibiabr.com/
*/
-#include "pch.hpp"
-
-#include "declarations.hpp"
#include "creatures/combat/combat.hpp"
-#include "lua/creature/events.hpp"
+
+#include "config/configmanager.hpp"
+#include "creatures/combat/condition.hpp"
+#include "creatures/combat/spells.hpp"
+#include "creatures/monsters/monster.hpp"
+#include "creatures/monsters/monsters.hpp"
+#include "creatures/players/grouping/party.hpp"
+#include "creatures/players/imbuements/imbuements.hpp"
#include "creatures/players/wheel/player_wheel.hpp"
#include "game/game.hpp"
#include "game/scheduling/dispatcher.hpp"
#include "io/iobestiary.hpp"
-#include "creatures/monsters/monster.hpp"
-#include "creatures/monsters/monsters.hpp"
+#include "io/ioprey.hpp"
#include "items/weapons/weapons.hpp"
-#include "map/spectators.hpp"
#include "lib/metrics/metrics.hpp"
#include "lua/callbacks/event_callback.hpp"
#include "lua/callbacks/events_callbacks.hpp"
+#include "lua/creature/events.hpp"
+#include "map/spectators.hpp"
-int32_t Combat::getLevelFormula(std::shared_ptr player, const std::shared_ptr wheelSpell, const CombatDamage &damage) const {
+int32_t Combat::getLevelFormula(const std::shared_ptr &player, const std::shared_ptr &wheelSpell, const CombatDamage &damage) const {
if (!player) {
return 0;
}
@@ -43,7 +47,7 @@ int32_t Combat::getLevelFormula(std::shared_ptr player, const std::share
return levelFormula;
}
-CombatDamage Combat::getCombatDamage(std::shared_ptr creature, std::shared_ptr target) const {
+CombatDamage Combat::getCombatDamage(const std::shared_ptr &creature, const std::shared_ptr &target) const {
CombatDamage damage;
damage.origin = params.origin;
damage.primary.type = params.combatType;
@@ -66,7 +70,7 @@ CombatDamage Combat::getCombatDamage(std::shared_ptr creature, std::sh
int32_t min, max;
if (creature->getCombatValues(min, max)) {
damage.primary.value = normal_random(min, max);
- } else if (std::shared_ptr player = creature->getPlayer()) {
+ } else if (const auto &player = creature->getPlayer()) {
if (params.valueCallback) {
params.valueCallback->getMinMaxValues(player, damage, params.useCharges);
} else if (formulaType == COMBAT_FORMULA_LEVELMAGIC) {
@@ -76,8 +80,8 @@ CombatDamage Combat::getCombatDamage(std::shared_ptr creature, std::sh
static_cast(levelFormula * maxa + maxb)
);
} else if (formulaType == COMBAT_FORMULA_SKILL) {
- std::shared_ptr- tool = player->getWeapon();
- const WeaponShared_ptr weapon = g_weapons().getWeapon(tool);
+ const auto &tool = player->getWeapon();
+ const WeaponShared_ptr &weapon = g_weapons().getWeapon(tool);
if (weapon) {
damage.primary.value = normal_random(
static_cast(minb),
@@ -184,7 +188,7 @@ ConditionType_t Combat::DamageToConditionType(CombatType_t type) {
}
}
-bool Combat::isPlayerCombat(std::shared_ptr target) {
+bool Combat::isPlayerCombat(const std::shared_ptr &target) {
if (target->getPlayer()) {
return true;
}
@@ -196,7 +200,7 @@ bool Combat::isPlayerCombat(std::shared_ptr target) {
return false;
}
-ReturnValue Combat::canTargetCreature(std::shared_ptr player, std::shared_ptr target) {
+ReturnValue Combat::canTargetCreature(const std::shared_ptr &player, const std::shared_ptr &target) {
if (player == target) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}
@@ -241,10 +245,10 @@ ReturnValue Combat::canTargetCreature(std::shared_ptr player, std::share
}
}
- return Combat::canDoCombat(player, target, true);
+ return canDoCombat(player, target, true);
}
-ReturnValue Combat::canDoCombat(std::shared_ptr caster, std::shared_ptr tile, bool aggressive) {
+ReturnValue Combat::canDoCombat(const std::shared_ptr &caster, const std::shared_ptr &tile, bool aggressive) {
if (tile->hasProperty(CONST_PROP_BLOCKPROJECTILE)) {
return RETURNVALUE_NOTENOUGHROOM;
}
@@ -269,7 +273,7 @@ ReturnValue Combat::canDoCombat(std::shared_ptr caster, std::shared_pt
return RETURNVALUE_FIRSTGOUPSTAIRS;
}
- if (std::shared_ptr player = caster->getPlayer()) {
+ if (const auto &player = caster->getPlayer()) {
if (player->hasFlag(PlayerFlags_t::IgnoreProtectionZone)) {
return RETURNVALUE_NOERROR;
}
@@ -282,12 +286,12 @@ ReturnValue Combat::canDoCombat(std::shared_ptr caster, std::shared_pt
return ret;
}
-bool Combat::isInPvpZone(std::shared_ptr attacker, std::shared_ptr target) {
+bool Combat::isInPvpZone(const std::shared_ptr &attacker, const std::shared_ptr &target) {
return attacker->getZoneType() == ZONE_PVP && target->getZoneType() == ZONE_PVP;
}
-bool Combat::isProtected(std::shared_ptr attacker, std::shared_ptr target) {
- uint32_t protectionLevel = g_configManager().getNumber(PROTECTION_LEVEL, __FUNCTION__);
+bool Combat::isProtected(const std::shared_ptr &attacker, const std::shared_ptr &target) {
+ uint32_t protectionLevel = g_configManager().getNumber(PROTECTION_LEVEL);
if (target->getLevel() < protectionLevel || attacker->getLevel() < protectionLevel) {
return true;
}
@@ -303,33 +307,33 @@ bool Combat::isProtected(std::shared_ptr attacker, std::shared_ptr attacker, std::shared_ptr target, bool aggressive) {
+ReturnValue Combat::canDoCombat(const std::shared_ptr &attacker, const std::shared_ptr &target, bool aggressive) {
if (!aggressive) {
return RETURNVALUE_NOERROR;
}
- auto targetPlayer = target ? target->getPlayer() : nullptr;
+ const auto &targetPlayer = target ? target->getPlayer() : nullptr;
if (target) {
- std::shared_ptr tile = target->getTile();
+ const std::shared_ptr &tile = target->getTile();
if (tile->hasProperty(CONST_PROP_BLOCKPROJECTILE)) {
return RETURNVALUE_NOTENOUGHROOM;
}
- if (tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
- auto permittedOnPz = targetPlayer ? targetPlayer->hasPermittedConditionInPZ() : false;
+ if (targetPlayer && tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
+ const auto permittedOnPz = targetPlayer->hasPermittedConditionInPZ();
return permittedOnPz ? RETURNVALUE_NOERROR : RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE;
}
}
if (attacker) {
- const std::shared_ptr attackerMaster = attacker->getMaster();
+ const auto &attackerMaster = attacker->getMaster();
+ const auto &attackerPlayer = attacker->getPlayer();
if (targetPlayer) {
if (targetPlayer->hasFlag(PlayerFlags_t::CannotBeAttacked)) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}
- const std::shared_ptr targetPlayerTile = targetPlayer->getTile();
-
- if (const std::shared_ptr attackerPlayer = attacker->getPlayer()) {
+ const auto &targetPlayerTile = targetPlayer->getTile();
+ if (attackerPlayer) {
if (attackerPlayer->hasFlag(PlayerFlags_t::CannotAttackPlayer)) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}
@@ -339,7 +343,7 @@ ReturnValue Combat::canDoCombat(std::shared_ptr attacker, std::shared_
}
// nopvp-zone
- auto attackerTile = attackerPlayer->getTile();
+ const auto &attackerTile = attackerPlayer->getTile();
if (targetPlayerTile && targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE)) {
return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
} else if (attackerTile && attackerTile->hasFlag(TILESTATE_NOPVPZONE) && targetPlayerTile && !targetPlayerTile->hasFlag(TILESTATE_NOPVPZONE | TILESTATE_PROTECTIONZONE)) {
@@ -352,7 +356,7 @@ ReturnValue Combat::canDoCombat(std::shared_ptr attacker, std::shared_
}
if (attackerMaster) {
- if (const std::shared_ptr masterAttackerPlayer = attackerMaster->getPlayer()) {
+ if (const auto &masterAttackerPlayer = attackerMaster->getPlayer()) {
if (masterAttackerPlayer->hasFlag(PlayerFlags_t::CannotAttackPlayer)) {
return RETURNVALUE_YOUMAYNOTATTACKTHISPLAYER;
}
@@ -377,7 +381,7 @@ ReturnValue Combat::canDoCombat(std::shared_ptr attacker, std::shared_
return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
}
- if (const std::shared_ptr attackerPlayer = attacker->getPlayer()) {
+ if (attackerPlayer) {
if (attackerPlayer->hasFlag(PlayerFlags_t::CannotAttackMonster)) {
return RETURNVALUE_YOUMAYNOTATTACKTHISCREATURE;
}
@@ -386,7 +390,7 @@ ReturnValue Combat::canDoCombat(std::shared_ptr attacker, std::shared_
return RETURNVALUE_ACTIONNOTPERMITTEDINANOPVPZONE;
}
} else if (attacker->getMonster()) {
- const std::shared_ptr targetMaster = target->getMaster();
+ const auto &targetMaster = target->getMaster();
if ((!targetMaster || !targetMaster->getPlayer()) && attacker->getFaction() == FACTION_DEFAULT) {
if (!attackerMaster || !attackerMaster->getPlayer()) {
@@ -429,6 +433,14 @@ void Combat::setPlayerCombatValues(formulaType_t newFormulaType, double newMina,
this->maxb = newMaxb;
}
+void Combat::postCombatEffects(const std::shared_ptr &caster, const Position &origin, const Position &pos) const {
+ postCombatEffects(caster, origin, pos, params);
+}
+
+void Combat::setOrigin(CombatOrigin origin) {
+ params.origin = origin;
+}
+
bool Combat::setParam(CombatParam_t param, uint32_t value) {
switch (param) {
case COMBAT_PARAM_TYPE: {
@@ -499,6 +511,18 @@ bool Combat::setParam(CombatParam_t param, uint32_t value) {
return false;
}
+void Combat::setArea(std::unique_ptr &newArea) {
+ this->area = std::move(newArea);
+}
+
+bool Combat::hasArea() const {
+ return area != nullptr;
+}
+
+void Combat::addCondition(const std::shared_ptr &condition) {
+ params.conditionList.emplace_back(condition);
+}
+
bool Combat::setCallback(CallBackParam_t key) {
switch (key) {
case CALLBACK_PARAM_LEVELMAGICVALUE: {
@@ -540,7 +564,7 @@ void Combat::setChainCallback(uint8_t chainTargets, uint8_t chainDistance, bool
g_logger().trace("ChainCallback created: {}, with targets: {}, distance: {}, backtracking: {}", params.chainCallback != nullptr, chainTargets, chainDistance, backtracking);
}
-CallBack* Combat::getCallback(CallBackParam_t key) {
+CallBack* Combat::getCallback(CallBackParam_t key) const {
switch (key) {
case CALLBACK_PARAM_LEVELMAGICVALUE:
case CALLBACK_PARAM_SKILLVALUE: {
@@ -566,7 +590,7 @@ CallBack* Combat::getCallback(CallBackParam_t key) {
return nullptr;
}
-void Combat::CombatHealthFunc(std::shared_ptr caster, std::shared_ptr target, const CombatParams ¶ms, CombatDamage* data) {
+void Combat::CombatHealthFunc(const std::shared_ptr &caster, const std::shared_ptr &target, const CombatParams ¶ms, CombatDamage* data) {
if (!data) {
g_logger().error("[{}]: CombatDamage is nullptr", __FUNCTION__);
return;
@@ -595,10 +619,15 @@ void Combat::CombatHealthFunc(std::shared_ptr caster, std::shared_ptr<
targetPlayer = target->getPlayer();
}
+ g_logger().trace("[{}] (old) eventcallback: 'creatureOnCombat', damage primary: '{}', secondary: '{}'", __FUNCTION__, damage.primary.value, damage.secondary.value);
+ g_callbacks().executeCallback(EventCallback_t::creatureOnCombat, &EventCallback::creatureOnCombat, caster, target, std::ref(damage));
+ g_logger().trace("[{}] (new) eventcallback: 'creatureOnCombat', damage primary: '{}', secondary: '{}'", __FUNCTION__, damage.primary.value, damage.secondary.value);
+
if (attackerPlayer) {
- std::shared_ptr
- item = attackerPlayer->getWeapon();
+ const auto &item = attackerPlayer->getWeapon();
damage = applyImbuementElementalDamage(attackerPlayer, item, damage);
g_events().eventPlayerOnCombat(attackerPlayer, target, item, damage);
+ g_callbacks().executeCallback(EventCallback_t::playerOnCombat, &EventCallback::playerOnCombat, attackerPlayer, target, item, std::ref(damage));
if (targetPlayer && targetPlayer->getSkull() != SKULL_BLACK) {
if (damage.primary.type != COMBAT_HEALING) {
@@ -619,16 +648,19 @@ void Combat::CombatHealthFunc(std::shared_ptr caster, std::shared_ptr<
// Player attacking monster
if (attackerPlayer && targetMonster) {
- const std::unique_ptr &slot = attackerPlayer->getPreyWithMonster(targetMonster->getRaceId());
+ const auto &slot = attackerPlayer->getPreyWithMonster(targetMonster->getRaceId());
if (slot && slot->isOccupied() && slot->bonus == PreyBonus_Damage && slot->bonusTimeLeft > 0) {
damage.primary.value += static_cast(std::ceil((damage.primary.value * slot->bonusPercentage) / 100));
damage.secondary.value += static_cast(std::ceil((damage.secondary.value * slot->bonusPercentage) / 100));
}
+
+ // Monster type onPlayerAttack event
+ targetMonster->onAttackedByPlayer(attackerPlayer);
}
// Monster attacking player
if (attackerMonster && targetPlayer) {
- const std::unique_ptr &slot = targetPlayer->getPreyWithMonster(attackerMonster->getRaceId());
+ const auto &slot = targetPlayer->getPreyWithMonster(attackerMonster->getRaceId());
if (slot && slot->isOccupied() && slot->bonus == PreyBonus_Defense && slot->bonusTimeLeft > 0) {
damage.primary.value -= static_cast(std::ceil((damage.primary.value * slot->bonusPercentage) / 100));
damage.secondary.value -= static_cast(std::ceil((damage.secondary.value * slot->bonusPercentage) / 100));
@@ -641,7 +673,7 @@ void Combat::CombatHealthFunc(std::shared_ptr caster, std::shared_ptr<
}
}
-CombatDamage Combat::applyImbuementElementalDamage(std::shared_ptr attackerPlayer, std::shared_ptr
- item, CombatDamage damage) {
+CombatDamage Combat::applyImbuementElementalDamage(const std::shared_ptr &attackerPlayer, std::shared_ptr
- item, CombatDamage damage) {
if (!item) {
return damage;
}
@@ -683,7 +715,7 @@ CombatDamage Combat::applyImbuementElementalDamage(std::shared_ptr attac
return damage;
}
-void Combat::CombatManaFunc(std::shared_ptr caster, std::shared_ptr target, const CombatParams ¶ms, CombatDamage* data) {
+void Combat::CombatManaFunc(const std::shared_ptr &caster, const std::shared_ptr &target, const CombatParams ¶ms, CombatDamage* data) {
if (!data) {
g_logger().error("[{}]: CombatDamage is nullptr", __FUNCTION__);
return;
@@ -702,7 +734,7 @@ void Combat::CombatManaFunc(std::shared_ptr caster, std::shared_ptr player) {
+bool Combat::checkFearConditionAffected(const std::shared_ptr &player) {
if (player->isImmuneFear()) {
return false;
}
@@ -711,7 +743,7 @@ bool Combat::checkFearConditionAffected(std::shared_ptr player) {
return false;
}
- auto party = player->getParty();
+ const auto &party = player->getParty();
if (party) {
auto affectedCount = (party->getMemberCount() + 5) / 5;
g_logger().debug("[{}] Player is member of a party, {} members can be feared", __FUNCTION__, affectedCount);
@@ -730,7 +762,7 @@ bool Combat::checkFearConditionAffected(std::shared_ptr player) {
return true;
}
-void Combat::CombatConditionFunc(std::shared_ptr caster, std::shared_ptr target, const CombatParams ¶ms, CombatDamage* data) {
+void Combat::CombatConditionFunc(const std::shared_ptr &caster, const std::shared_ptr &target, const CombatParams ¶ms, CombatDamage* data) {
if (params.origin == ORIGIN_MELEE && data && data->primary.value == 0 && data->secondary.value == 0) {
return;
}
@@ -748,7 +780,7 @@ void Combat::CombatConditionFunc(std::shared_ptr caster, std::shared_p
} else if (caster && caster->getMonster()) {
uint16_t playerCharmRaceid = player->parseRacebyCharm(CHARM_CLEANSE, false, 0);
if (playerCharmRaceid != 0) {
- const auto mType = g_monsters().getMonsterType(caster->getName());
+ const auto &mType = g_monsters().getMonsterType(caster->getName());
if (mType && playerCharmRaceid == mType->info.raceid) {
const auto charm = g_iobestiary().getBestiaryCharm(CHARM_CLEANSE);
if (charm && (charm->chance > normal_random(0, 100))) {
@@ -783,18 +815,18 @@ void Combat::CombatConditionFunc(std::shared_ptr caster, std::shared_p
}
}
-void Combat::CombatDispelFunc(std::shared_ptr, std::shared_ptr target, const CombatParams ¶ms, CombatDamage*) {
+void Combat::CombatDispelFunc(const std::shared_ptr &, const std::shared_ptr &target, const CombatParams ¶ms, CombatDamage*) {
if (target) {
target->removeCombatCondition(params.dispelType);
}
}
-void Combat::CombatNullFunc(std::shared_ptr caster, std::shared_ptr target, const CombatParams ¶ms, CombatDamage*) {
+void Combat::CombatNullFunc(const std::shared_ptr &caster, const std::shared_ptr &target, const CombatParams ¶ms, CombatDamage*) {
CombatConditionFunc(caster, target, params, nullptr);
CombatDispelFunc(caster, target, params, nullptr);
}
-void Combat::combatTileEffects(const CreatureVector &spectators, std::shared_ptr caster, std::shared_ptr tile, const CombatParams ¶ms) {
+void Combat::combatTileEffects(const CreatureVector &spectators, const std::shared_ptr &caster, const std::shared_ptr &tile, const CombatParams ¶ms) {
if (params.itemId != 0) {
uint16_t itemId = params.itemId;
switch (itemId) {
@@ -857,7 +889,7 @@ void Combat::combatTileEffects(const CreatureVector &spectators, std::shared_ptr
}
}
- std::shared_ptr
- item = Item::CreateItem(itemId);
+ const auto &item = Item::CreateItem(itemId);
if (caster) {
item->setOwner(caster);
}
@@ -883,7 +915,7 @@ void Combat::combatTileEffects(const CreatureVector &spectators, std::shared_ptr
}
}
-void Combat::postCombatEffects(std::shared_ptr caster, const Position &origin, const Position &pos, const CombatParams ¶ms) {
+void Combat::postCombatEffects(const std::shared_ptr &caster, const Position &origin, const Position &pos, const CombatParams ¶ms) {
if (caster && params.distanceEffect != CONST_ANI_NONE) {
addDistanceEffect(caster, origin, pos, params.distanceEffect);
}
@@ -895,13 +927,13 @@ void Combat::postCombatEffects(std::shared_ptr caster, const Position
}
}
-void Combat::addDistanceEffect(std::shared_ptr caster, const Position &fromPos, const Position &toPos, uint16_t effect) {
+void Combat::addDistanceEffect(const std::shared_ptr &caster, const Position &fromPos, const Position &toPos, uint16_t effect) {
if (effect == CONST_ANI_WEAPONTYPE) {
if (!caster) {
return;
}
- std::shared_ptr player = caster->getPlayer();
+ const auto &player = caster->getPlayer();
if (!player) {
return;
}
@@ -945,7 +977,7 @@ void Combat::doChainEffect(const Position &origin, const Position &dest, uint8_t
fpp.maxSearchDist = 9;
Position pos = origin;
if (g_game().map.getPathMatching(origin, dirList, FrozenPathingConditionCall(dest), fpp)) {
- for (auto dir : dirList) {
+ for (const auto &dir : dirList) {
pos = getNextPosition(dir, pos);
g_game().addMagicEffect(pos, effect);
}
@@ -998,17 +1030,17 @@ void Combat::setupChain(const std::shared_ptr &weapon) {
setParam(COMBAT_PARAM_BLOCKARMOR, true);
};
- setChainCallback(g_configManager().getNumber(COMBAT_CHAIN_TARGETS, __FUNCTION__), 1, true);
+ setChainCallback(g_configManager().getNumber(COMBAT_CHAIN_TARGETS), 1, true);
switch (weaponType) {
case WEAPON_SWORD:
- setCommonValues(g_configManager().getFloat(COMBAT_CHAIN_SKILL_FORMULA_SWORD, __FUNCTION__), MELEE_ATK_SWORD, CONST_ME_SLASH);
+ setCommonValues(g_configManager().getFloat(COMBAT_CHAIN_SKILL_FORMULA_SWORD), MELEE_ATK_SWORD, CONST_ME_SLASH);
break;
case WEAPON_CLUB:
- setCommonValues(g_configManager().getFloat(COMBAT_CHAIN_SKILL_FORMULA_CLUB, __FUNCTION__), MELEE_ATK_CLUB, CONST_ME_BLACK_BLOOD);
+ setCommonValues(g_configManager().getFloat(COMBAT_CHAIN_SKILL_FORMULA_CLUB), MELEE_ATK_CLUB, CONST_ME_BLACK_BLOOD);
break;
case WEAPON_AXE:
- setCommonValues(g_configManager().getFloat(COMBAT_CHAIN_SKILL_FORMULA_AXE, __FUNCTION__), MELEE_ATK_AXE, CONST_ANI_WHIRLWINDAXE);
+ setCommonValues(g_configManager().getFloat(COMBAT_CHAIN_SKILL_FORMULA_AXE), MELEE_ATK_AXE, CONST_ANI_WHIRLWINDAXE);
break;
}
@@ -1030,7 +1062,7 @@ void Combat::setupChain(const std::shared_ptr &weapon) {
}
}
-bool Combat::doCombatChain(std::shared_ptr caster, std::shared_ptr target, bool aggressive) const {
+bool Combat::doCombatChain(const std::shared_ptr &caster, const std::shared_ptr &target, bool aggressive) const {
metrics::method_latency measure(__METHOD_NAME__);
if (!params.chainCallback) {
return false;
@@ -1040,7 +1072,7 @@ bool Combat::doCombatChain(std::shared_ptr caster, std::shared_ptrgetChainValues(caster, maxTargets, chainDistance, backtracking);
- auto targets = pickChainTargets(caster, params, chainDistance, maxTargets, aggressive, backtracking, std::move(target));
+ auto targets = pickChainTargets(caster, params, chainDistance, maxTargets, aggressive, backtracking, target);
g_logger().debug("[{}] Chain targets: {}", __FUNCTION__, targets.size());
if (targets.empty() || (targets.size() == 1 && targets.begin()->second.empty())) {
@@ -1049,11 +1081,11 @@ bool Combat::doCombatChain(std::shared_ptr caster, std::shared_ptr(50, g_configManager().getNumber(COMBAT_CHAIN_DELAY, __FUNCTION__));
+ auto delay = i * std::max(50, g_configManager().getNumber(COMBAT_CHAIN_DELAY));
++i;
- for (auto to : toVector) {
+ for (const auto &to : toVector) {
auto nextTarget = g_game().getCreatureByID(to);
if (!nextTarget) {
continue;
@@ -1061,7 +1093,7 @@ bool Combat::doCombatChain(std::shared_ptr caster, std::shared_ptrdoChainEffect(from, nextTarget->getPosition(), combat->params.chainEffect);
+ Combat::doChainEffect(from, nextTarget->getPosition(), combat->params.chainEffect);
combat->doCombat(caster, nextTarget, from, affected);
}
},
@@ -1073,7 +1105,7 @@ bool Combat::doCombatChain(std::shared_ptr caster, std::shared_ptr caster, std::shared_ptr target) const {
+bool Combat::doCombat(const std::shared_ptr &caster, const std::shared_ptr &target) const {
if (caster != nullptr && params.chainCallback) {
return doCombatChain(caster, target, params.aggressive);
}
@@ -1081,7 +1113,7 @@ bool Combat::doCombat(std::shared_ptr caster, std::shared_ptrgetPosition() : Position());
}
-bool Combat::doCombat(std::shared_ptr caster, std::shared_ptr target, const Position &origin, int affected /* = 1 */) const {
+bool Combat::doCombat(const std::shared_ptr &caster, const std::shared_ptr &target, const Position &origin, int affected /* = 1 */) const {
// target combat callback function
if (params.combatType != COMBAT_NONE) {
CombatDamage damage = getCombatDamage(caster, target);
@@ -1098,7 +1130,7 @@ bool Combat::doCombat(std::shared_ptr caster, std::shared_ptr caster, const Position &position) const {
+bool Combat::doCombat(const std::shared_ptr &caster, const Position &position) const {
if (caster != nullptr && params.chainCallback) {
return doCombatChain(caster, caster, params.aggressive);
}
@@ -1119,7 +1151,7 @@ bool Combat::doCombat(std::shared_ptr caster, const Position &position
return true;
}
-void Combat::CombatFunc(std::shared_ptr caster, const Position &origin, const Position &pos, const std::unique_ptr &area, const CombatParams ¶ms, CombatFunction func, CombatDamage* data) {
+void Combat::CombatFunc(const std::shared_ptr &caster, const Position &origin, const Position &pos, const std::unique_ptr &area, const CombatParams ¶ms, const CombatFunction &func, CombatDamage* data) {
std::vector> tileList;
if (caster) {
@@ -1132,7 +1164,7 @@ void Combat::CombatFunc(std::shared_ptr caster, const Position &origin
uint32_t maxY = 0;
// calculate the max viewable range
- for (const std::shared_ptr &tile : tileList) {
+ for (const auto &tile : tileList) {
const Position &tilePos = tile->getPosition();
uint32_t diff = Position::getDistanceX(tilePos, pos);
@@ -1150,14 +1182,16 @@ void Combat::CombatFunc(std::shared_ptr caster, const Position &origin
const int32_t rangeY = maxY + MAP_MAX_VIEW_PORT_Y;
int affected = 0;
- for (const std::shared_ptr &tile : tileList) {
+ for (const auto &tile : tileList) {
if (canDoCombat(caster, tile, params.aggressive) != RETURNVALUE_NOERROR) {
continue;
}
if (CreatureVector* creatures = tile->getCreatures()) {
- const std::shared_ptr topCreature = tile->getTopCreature();
- for (auto &creature : *creatures) {
+ const auto &topCreature = tile->getTopCreature();
+ // A copy of the tile's creature list is made because modifications to this vector, such as adding or removing creatures through a Lua callback, may occur during the iteration within the for loop.
+ CreatureVector creaturesCopy = *creatures;
+ for (const auto &creature : creaturesCopy) {
if (params.targetCasterOrTopMost) {
if (caster && caster->getTile() == tile) {
if (creature != caster) {
@@ -1200,19 +1234,21 @@ void Combat::CombatFunc(std::shared_ptr caster, const Position &origin
// Wheel of destiny get beam affected total
auto spectators = Spectators().find(pos, true, rangeX, rangeX, rangeY, rangeY);
- std::shared_ptr casterPlayer = caster ? caster->getPlayer() : nullptr;
+ const std::shared_ptr &casterPlayer = caster ? caster->getPlayer() : nullptr;
uint8_t beamAffectedTotal = casterPlayer ? casterPlayer->wheel()->getBeamAffectedTotal(tmpDamage) : 0;
uint8_t beamAffectedCurrent = 0;
tmpDamage.affected = affected;
- for (const std::shared_ptr &tile : tileList) {
+ for (const auto &tile : tileList) {
if (canDoCombat(caster, tile, params.aggressive) != RETURNVALUE_NOERROR) {
continue;
}
if (CreatureVector* creatures = tile->getCreatures()) {
- const std::shared_ptr topCreature = tile->getTopCreature();
- for (auto &creature : *creatures) {
+ const auto &topCreature = tile->getTopCreature();
+ // A copy of the tile's creature list is made because modifications to this vector, such as adding or removing creatures through a Lua callback, may occur during the iteration within the for loop.
+ CreatureVector creaturesCopy = *creatures;
+ for (const auto &creature : creaturesCopy) {
if (params.targetCasterOrTopMost) {
if (caster && caster->getTile() == tile) {
if (creature != caster) {
@@ -1250,11 +1286,11 @@ void Combat::CombatFunc(std::shared_ptr caster, const Position &origin
postCombatEffects(caster, origin, pos, params);
}
-void Combat::doCombatHealth(std::shared_ptr caster, std::shared_ptr target, CombatDamage &damage, const CombatParams ¶ms) {
- doCombatHealth(caster, std::move(target), caster ? caster->getPosition() : Position(), damage, params);
+void Combat::doCombatHealth(const std::shared_ptr &caster, const std::shared_ptr &target, CombatDamage &damage, const CombatParams ¶ms) {
+ doCombatHealth(caster, target, caster ? caster->getPosition() : Position(), damage, params);
}
-void Combat::doCombatHealth(std::shared_ptr caster, std::shared_ptr target, const Position &origin, CombatDamage &damage, const CombatParams ¶ms) {
+void Combat::doCombatHealth(const std::shared_ptr &caster, const std::shared_ptr &target, const Position &origin, CombatDamage &damage, const CombatParams ¶ms) {
bool canCombat = !params.aggressive || (caster != target && Combat::canDoCombat(caster, target, params.aggressive) == RETURNVALUE_NOERROR);
if ((caster && target)
&& (caster == target || canCombat)
@@ -1288,17 +1324,17 @@ void Combat::doCombatHealth(std::shared_ptr caster, std::shared_ptr caster, const Position &position, const std::unique_ptr &area, CombatDamage &damage, const CombatParams ¶ms) {
+void Combat::doCombatHealth(const std::shared_ptr