From 8a8ef66e4baf74434be51baf61bd793b957c9b12 Mon Sep 17 00:00:00 2001 From: Niam5 Date: Thu, 15 Feb 2024 23:34:17 -0600 Subject: [PATCH] Add Eluna LUA Engine Compiles but has features disabled. Use at own risk! --- .gitmodules | 4 + cmake/options.cmake | 3 +- cmake/showoptions.cmake | 9 + dep/CMakeLists.txt | 4 + dep/lualib/CMakeLists.txt | 21 ++ dep/lualib/lua/CMakeLists.txt | 151 ++++++++ dep/lualib/lua/lua.hpp | 10 + dep/lualib/luajit/CMakeLists.txt | 155 ++++++++ src/common/CMakeLists.txt | 6 + src/server/database/Database/Field.h | 2 + src/server/database/Database/QueryResult.cpp | 6 + src/server/database/Database/QueryResult.h | 1 + .../game/Battlegrounds/Battleground.cpp | 19 + src/server/game/CMakeLists.txt | 30 +- .../game/Chat/ChatCommands/ChatCommand.cpp | 14 + src/server/game/Combat/CombatManager.cpp | 36 ++ .../game/Entities/Creature/Creature.cpp | 12 + .../game/Entities/GameObject/GameObject.cpp | 48 +++ .../game/Entities/GameObject/GameObject.h | 4 + src/server/game/Entities/Object/Object.cpp | 37 ++ src/server/game/Entities/Object/Object.h | 15 + src/server/game/Entities/Player/Player.cpp | 55 +++ src/server/game/Entities/Unit/Unit.cpp | 7 + src/server/game/Events/GameEventMgr.cpp | 18 + src/server/game/Handlers/CharacterHandler.cpp | 3 + src/server/game/Handlers/ChatHandler.cpp | 60 +++ src/server/game/Handlers/LootHandler.cpp | 16 + src/server/game/Handlers/NPCHandler.cpp | 41 ++ src/server/game/Handlers/QuestHandler.cpp | 18 + src/server/game/Handlers/SpellHandler.cpp | 8 + src/server/game/LuaEngine | 1 + src/server/game/Maps/Map.cpp | 62 ++- src/server/game/Maps/Map.h | 15 + src/server/game/Maps/MapManager.cpp | 29 ++ src/server/game/Scripting/ScriptMgr.cpp | 355 ++++++++++++++++++ src/server/game/Scripting/ScriptMgr.h | 16 + src/server/game/Server/WorldSession.cpp | 34 ++ src/server/game/Server/WorldSocket.cpp | 3 + src/server/game/Spells/SpellEffects.cpp | 14 + src/server/game/World/World.cpp | 36 ++ src/server/game/World/World.h | 7 + src/server/shared/DataStores/DB2Store.h | 22 ++ src/server/worldserver/CMakeLists.txt | 2 +- src/server/worldserver/worldserver.conf.dist | 67 ++++ 44 files changed, 1468 insertions(+), 8 deletions(-) create mode 100644 .gitmodules create mode 100644 dep/lualib/CMakeLists.txt create mode 100644 dep/lualib/lua/CMakeLists.txt create mode 100644 dep/lualib/lua/lua.hpp create mode 100644 dep/lualib/luajit/CMakeLists.txt create mode 160000 src/server/game/LuaEngine diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000..8b08f010d6c95 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "src/server/game/LuaEngine"] + path = src/server/game/LuaEngine + url = https://github.com/ElunaLuaEngine/Eluna.git + branch = tc-retail diff --git a/cmake/options.cmake b/cmake/options.cmake index 42803a4f112cf..4ff0dcfbc13e8 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -34,6 +34,7 @@ foreach(SCRIPT_MODULE ${SCRIPT_MODULE_LIST}) endforeach() option(TOOLS "Build map/vmap/mmap extraction/assembler tools" 1) +option(ELUNA "Build Eluna Lua Engine" 1) option(USE_SCRIPTPCH "Use precompiled headers when compiling scripts" 1) option(USE_COREPCH "Use precompiled headers when compiling servers" 1) option(WITH_DYNAMIC_LINKING "Enable dynamic library linking." 0) @@ -47,7 +48,7 @@ if(WITH_DYNAMIC_LINKING OR WITH_DYNAMIC_LINKING_FORCED) else() set(BUILD_SHARED_LIBS OFF) endif() -if(WITH_FILESYSTEM_WATCHER OR BUILD_SHARED_LIBS) +if(WITH_FILESYSTEM_WATCHER OR BUILD_SHARED_LIBS OR ELUNA) set(BUILD_EFSW ON) endif() option(WITH_WARNINGS "Show all warnings during compile" 0) diff --git a/cmake/showoptions.cmake b/cmake/showoptions.cmake index 12cf83a467ed0..4592bcbab5583 100644 --- a/cmake/showoptions.cmake +++ b/cmake/showoptions.cmake @@ -34,6 +34,15 @@ else() message("* Build with scripts : No") endif() +if(ELUNA) + message("* Build Eluna LuaEngine : Yes (default)") + add_definitions(-DELUNA) + add_definitions(-DELUNA_TRINITY) + add_definitions(-DELUNA_EXPANSION=9) +else() + message("* Build Eluna LuaEngine : No") +endif() + if(TOOLS) message("* Build map/vmap tools : Yes (default)") else() diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt index 0aa598ca46401..23fabb2453d7b 100644 --- a/dep/CMakeLists.txt +++ b/dep/CMakeLists.txt @@ -50,3 +50,7 @@ if(BUILD_TESTING) GIT_SHALLOW 1) FetchContent_MakeAvailable(Catch2) endif() + +if (ELUNA) + add_subdirectory(lualib) +endif() \ No newline at end of file diff --git a/dep/lualib/CMakeLists.txt b/dep/lualib/CMakeLists.txt new file mode 100644 index 0000000000000..14bf629cd8735 --- /dev/null +++ b/dep/lualib/CMakeLists.txt @@ -0,0 +1,21 @@ +set(LUA_VERSION "lua52" CACHE STRING "Lua version to use") +set_property(CACHE LUA_VERSION PROPERTY STRINGS luajit lua51 lua52 lua53 lua54) +MESSAGE(STATUS "Lua version: ${LUA_VERSION}") + +# Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24: +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") + cmake_policy(SET CMP0135 NEW) +endif() + +option(LUA_STATIC "link lua statically" OFF) +if (LUA_STATIC) + MESSAGE(STATUS "Lua linking: static") +else() + MESSAGE(STATUS "Lua linking: dynamic") +endif() + +if (LUA_VERSION MATCHES "luajit") + add_subdirectory(luajit) +else() + add_subdirectory(lua) +endif() diff --git a/dep/lualib/lua/CMakeLists.txt b/dep/lualib/lua/CMakeLists.txt new file mode 100644 index 0000000000000..a678ab30f61de --- /dev/null +++ b/dep/lualib/lua/CMakeLists.txt @@ -0,0 +1,151 @@ +# BSD-3-Clause +# Copyright (c) 2022, Rochet2 +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +project ( lua C ) + +# LUA_VERSION must be one of lua51, lua52, lua53, lua54 + +include(FetchContent) +FetchContent_Declare( + lua51 + URL https://www.lua.org/ftp/lua-5.1.5.tar.gz + URL_HASH SHA256=2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333 +) +FetchContent_Declare( + lua52 + URL https://www.lua.org/ftp/lua-5.2.4.tar.gz + URL_HASH SHA256=b9e2e4aad6789b3b63a056d442f7b39f0ecfca3ae0f1fc0ae4e9614401b69f4b +) +FetchContent_Declare( + lua53 + URL https://www.lua.org/ftp/lua-5.3.6.tar.gz + URL_HASH SHA256=fc5fd69bb8736323f026672b1b7235da613d7177e72558893a0bdcd320466d60 +) +FetchContent_Declare( + lua54 + URL https://www.lua.org/ftp/lua-5.4.4.tar.gz + URL_HASH SHA256=164c7849653b80ae67bec4b7473b884bf5cc8d2dca05653475ec2ed27b9ebf61 +) +FetchContent_MakeAvailable(${LUA_VERSION}) + +# Easen warnings +string(REGEX REPLACE "( |^)/W[0-9]( |$)" "\\1/W2\\2" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +string(REGEX REPLACE "( |^)/W[0-9]( |$)" "\\1/W2\\2" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + +set(LUA_SOURCE_FOLDER "${${LUA_VERSION}_SOURCE_DIR}/src") + +file(GLOB LOCAL_SOURCES_H ${LUA_SOURCE_FOLDER}/*.h) +file(GLOB LOCAL_SOURCES_C ${LUA_SOURCE_FOLDER}/*.c) +# Compile lua as C++ so it uses exceptions instead of longjmp +# Disabled for now as some libraries expect lua to be C +# set_source_files_properties(${LOCAL_SOURCES_H} ${LOCAL_SOURCES_C} PROPERTIES LANGUAGE CXX ) +list(REMOVE_ITEM LOCAL_SOURCES_C ${LUA_SOURCE_FOLDER}/lua.c) +list(REMOVE_ITEM LOCAL_SOURCES_C ${LUA_SOURCE_FOLDER}/luac.c) + +if (LUA_STATIC) + add_library(lualib STATIC ${LOCAL_SOURCES_H} ${LOCAL_SOURCES_C}) + set_property(TARGET lualib PROPERTY POSITION_INDEPENDENT_CODE ON) +else() + add_library(lualib SHARED ${LOCAL_SOURCES_H} ${LOCAL_SOURCES_C}) + set_property(TARGET lualib PROPERTY POSITION_INDEPENDENT_CODE ON) +endif() +add_library(lualib_static STATIC ${LOCAL_SOURCES_H} ${LOCAL_SOURCES_C}) +set_target_properties(lualib PROPERTIES LINKER_LANGUAGE C) +set_target_properties(lualib_static PROPERTIES LINKER_LANGUAGE C) +target_include_directories(lualib PUBLIC "${LUA_SOURCE_FOLDER}" "${CMAKE_CURRENT_SOURCE_DIR}") +target_include_directories(lualib_static PUBLIC "${LUA_SOURCE_FOLDER}" "${CMAKE_CURRENT_SOURCE_DIR}") +if (WIN32) + set_target_properties(lualib PROPERTIES OUTPUT_NAME ${LUA_VERSION}) + install(TARGETS lualib DESTINATION "${CMAKE_INSTALL_PREFIX}") + if (NOT LUA_STATIC) + install(FILES $ DESTINATION "${CMAKE_INSTALL_PREFIX}" OPTIONAL) + endif() + # set_target_properties(lualib PROPERTIES PUBLIC_HEADER "${LOCAL_SOURCES_H};${CMAKE_CURRENT_SOURCE_DIR}/lua.hpp") + # install(TARGETS lualib PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_PREFIX}/include") + # set_target_properties(lualib_static PROPERTIES OUTPUT_NAME ${LUA_VERSION}_static) + # install(TARGETS lualib_static DESTINATION "${CMAKE_INSTALL_PREFIX}") +else() + set_target_properties(lualib PROPERTIES PUBLIC_HEADER "${LOCAL_SOURCES_H};${CMAKE_CURRENT_SOURCE_DIR}/lua.hpp") + install(TARGETS lualib + DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_PREFIX}/include" + ) + install(TARGETS lualib_static DESTINATION "${CMAKE_INSTALL_PREFIX}/lib") +endif() +if (WIN32) + target_compile_definitions(lualib PRIVATE _CRT_SECURE_NO_WARNINGS) + target_compile_definitions(lualib_static PRIVATE _CRT_SECURE_NO_WARNINGS) + if (NOT LUA_STATIC) + target_compile_definitions(lualib PRIVATE LUA_BUILD_AS_DLL) + endif() +elseif (APPLE) + target_compile_definitions(lualib PUBLIC LUA_USE_MACOSX) + target_compile_definitions(lualib_static PUBLIC LUA_USE_MACOSX) + target_compile_options(lualib PRIVATE -Wno-deprecated-declarations -Wno-empty-body) + target_compile_options(lualib_static PRIVATE -Wno-deprecated-declarations -Wno-empty-body) + target_link_libraries(lualib readline) + target_link_libraries(lualib_static readline) + # set_target_properties(lualib PROPERTIES COMPILE_FLAGS -undefined dynamic_lookup) + # set_target_properties(lualib_static PROPERTIES COMPILE_FLAGS -undefined dynamic_lookup) +elseif (UNIX) + target_compile_definitions(lualib PUBLIC LUA_USE_LINUX) + target_link_libraries(lualib ${CMAKE_DL_LIBS} m readline) + target_compile_definitions(lualib_static PUBLIC LUA_USE_LINUX) + target_link_libraries(lualib_static ${CMAKE_DL_LIBS} m readline) + set_target_properties(lualib PROPERTIES OUTPUT_NAME ${LUA_VERSION}) + set_target_properties(lualib_static PROPERTIES OUTPUT_NAME ${LUA_VERSION}) +endif() + +add_executable(lua_interpreter ${LUA_SOURCE_FOLDER}/lua.c) +target_link_libraries(lua_interpreter lualib_static) +target_compile_definitions(lua_interpreter PRIVATE _CRT_SECURE_NO_WARNINGS) +set_target_properties(lua_interpreter PROPERTIES OUTPUT_NAME ${LUA_VERSION}_interpreter) +if (WIN32) + install(TARGETS lua_interpreter DESTINATION "${CMAKE_INSTALL_PREFIX}") + install(FILES $ DESTINATION "${CMAKE_INSTALL_PREFIX}" OPTIONAL) +else() + install(TARGETS lua_interpreter DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") +endif() +#install(TARGETS lualib +# DESTINATION "${CMAKE_INSTALL_PREFIX}" +# LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/lua/lib" +# RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/lua/lib" +# ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/lua/lib" +#) + +add_executable(lua_compiler ${LUA_SOURCE_FOLDER}/luac.c) +target_link_libraries(lua_compiler lualib_static) +target_compile_definitions(lua_compiler PRIVATE _CRT_SECURE_NO_WARNINGS) +set_target_properties(lua_compiler PROPERTIES OUTPUT_NAME ${LUA_VERSION}_compiler) +if (WIN32) + install(TARGETS lua_compiler DESTINATION "${CMAKE_INSTALL_PREFIX}") + install(FILES $ DESTINATION "${CMAKE_INSTALL_PREFIX}" OPTIONAL) +else() + install(TARGETS lua_compiler DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") +endif() diff --git a/dep/lualib/lua/lua.hpp b/dep/lualib/lua/lua.hpp new file mode 100644 index 0000000000000..0e30bf0fd2894 --- /dev/null +++ b/dep/lualib/lua/lua.hpp @@ -0,0 +1,10 @@ +// Some lua sources include this file and some do not, +// so here is the file to be used with all lua sources as some libraries expect it to exist. + +#pragma once + +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +} diff --git a/dep/lualib/luajit/CMakeLists.txt b/dep/lualib/luajit/CMakeLists.txt new file mode 100644 index 0000000000000..58f14ceaf455a --- /dev/null +++ b/dep/lualib/luajit/CMakeLists.txt @@ -0,0 +1,155 @@ +# BSD-3-Clause +# Copyright (c) 2022, Rochet2 +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# * Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +project ( lua C ) + +# Download source +include(FetchContent) +FetchContent_Declare( + luajit21 + GIT_REPOSITORY https://github.com/LuaJIT/LuaJIT.git + GIT_TAG a91d0d9d3bba1a936669cfac3244509a0f2ac0e3 # 2.1.0-beta3+ where mac builds without extra setup +) +FetchContent_MakeAvailable(luajit21) + +set(LUA_SRC_FOLDER "${luajit21_SOURCE_DIR}") +set(LUA_BIN_FOLDER "${luajit21_BINARY_DIR}") +# note that the / at the end means that we copy folder contents, not the folder itself +file(COPY ${LUA_SRC_FOLDER}/ DESTINATION ${LUA_BIN_FOLDER}) + +if (WIN32) + if (LUA_STATIC) + # build luajit static + add_custom_command( + OUTPUT ${LUA_BIN_FOLDER}/src/lua51.lib ${LUA_BIN_FOLDER}/src/luajit.exe + WORKING_DIRECTORY ${LUA_BIN_FOLDER}/src + COMMAND call msvcbuild.bat static + ) + + # add it as a library target + add_custom_target(luajit_target DEPENDS ${LUA_BIN_FOLDER}/src/lua51.lib) + add_library(lualib STATIC IMPORTED GLOBAL) + add_dependencies(lualib luajit_target) + set_target_properties(lualib + PROPERTIES + IMPORTED_LOCATION ${LUA_BIN_FOLDER}/src/lua51.lib + INTERFACE_INCLUDE_DIRECTORIES "${LUA_SRC_FOLDER}/src" + ) + + # install generated files + install(FILES ${LUA_BIN_FOLDER}/src/lua51.lib ${LUA_BIN_FOLDER}/src/luajit.exe DESTINATION "${CMAKE_INSTALL_PREFIX}") + install(DIRECTORY ${LUA_BIN_FOLDER}/src/jit DESTINATION "${CMAKE_INSTALL_PREFIX}/lua") + else() + # build luajit dll + add_custom_command( + OUTPUT ${LUA_BIN_FOLDER}/src/lua51.dll ${LUA_BIN_FOLDER}/src/lua51.lib ${LUA_BIN_FOLDER}/src/luajit.exe + WORKING_DIRECTORY ${LUA_BIN_FOLDER}/src + # COMMAND echo luajit built on platform $(Platform) + # COMMAND cd $(VSInstallDir)/VC + # COMMAND if \"$(Platform)\"==\"Win32\" echo \"luajit building $(Platform)\" & call $(VSInstallDir)/VC/vcvarsall.bat $(Platform) & call msvcbuild.bat + # COMMAND if \"$(Platform)\"==\"Win32\" echo \"luajit building 64bit\" & call $(VSInstallDir)/VC/vcvarsall.bat x64 + # COMMAND if \"$(Platform)\"==\"Win64\" echo luajit building 64bit + # COMMAND if \"$(Platform)\"==\"Win64\" call $(VSInstallDir)/VC/vcvarsall.bat x64 + # COMMAND cd ${LUA_BIN_FOLDER}/src + COMMAND call msvcbuild.bat + # COMMAND ${CMAKE_COMMAND} -E copy ${LUA_BIN_FOLDER}/src/lua51.dll ${CMAKE_BINARY_DIR}/$(ConfigurationName)/ + # COMMAND ${CMAKE_COMMAND} -E copy ${LUA_BIN_FOLDER}/src/lua51.lib ${CMAKE_BINARY_DIR}/$(ConfigurationName)/ + # COMMAND ${CMAKE_COMMAND} -E copy ${LUA_BIN_FOLDER}/src/luajit.exe ${CMAKE_BINARY_DIR}/$(ConfigurationName)/ + ) + + # add it as a library target + add_custom_target(luajit_target DEPENDS ${LUA_BIN_FOLDER}/src/lua51.lib) + add_library(lualib SHARED IMPORTED GLOBAL) + add_dependencies(lualib luajit_target) + set_target_properties(lualib + PROPERTIES + IMPORTED_LOCATION ${LUA_BIN_FOLDER}/src/lua51.dll + IMPORTED_IMPLIB ${LUA_BIN_FOLDER}/src/lua51.lib + INTERFACE_INCLUDE_DIRECTORIES "${LUA_SRC_FOLDER}/src" + ) + + # install generated files + install(FILES ${LUA_BIN_FOLDER}/src/lua51.dll ${LUA_BIN_FOLDER}/src/lua51.lib ${LUA_BIN_FOLDER}/src/luajit.exe DESTINATION "${CMAKE_INSTALL_PREFIX}") + install(DIRECTORY ${LUA_BIN_FOLDER}/src/jit DESTINATION "${CMAKE_INSTALL_PREFIX}/lua") + endif() +endif() + +if (UNIX OR APPLE) + #option(LUA_USR "Use /usr/local/ as lua library location" OFF) + #if (LUA_USR) + # set(LUA_INSTALL_PATH "/usr/local") + #else() + set(LUA_INSTALL_PATH "${CMAKE_CURRENT_BINARY_DIR}/BIN") + #endif() + + if (LUA_STATIC) + set(LUAJIT_LIB_PATH "${LUA_INSTALL_PATH}/lib/libluajit-5.1.a") + else() + if (APPLE) + set(LUAJIT_LIB_PATH "${LUA_INSTALL_PATH}/lib/libluajit-5.1.2.1.0.dylib") + elseif(UNIX) + set(LUAJIT_LIB_PATH "${LUA_INSTALL_PATH}/lib/libluajit-5.1.so.2.1.0") + endif() + endif() + + # build luajit + # if (LUA_USR) + # add_custom_command( + # OUTPUT ${LUAJIT_LIB_PATH} + # COMMAND $(MAKE) -C ${LUA_BIN_FOLDER} + # COMMAND $(MAKE) -C ${LUA_BIN_FOLDER} install + # ) + # else () + add_custom_command( + OUTPUT ${LUAJIT_LIB_PATH} + # COMMAND $(MAKE) -C ${LUA_BIN_FOLDER} PREFIX=${LUA_INSTALL_PATH} + COMMAND $(MAKE) -C ${LUA_BIN_FOLDER} install PREFIX=${LUA_INSTALL_PATH} + ) + # endif() + add_custom_target(luajit_target DEPENDS ${LUAJIT_LIB_PATH}) + + # add it as a library target + if (LUA_STATIC) + add_library(lualib STATIC IMPORTED GLOBAL) + # on static build the libraries are not a part of the luajit archive + target_link_libraries(lualib INTERFACE ${CMAKE_DL_LIBS}) + else() + add_library(lualib SHARED IMPORTED GLOBAL) + endif() + add_dependencies(lualib luajit_target) + set_target_properties(lualib + PROPERTIES + # IMPORTED_LOCATION ${LUAJIT_LIB_PATH} # cmake bullshit. spent days figuring this and turns out set_target_properties does squat shit while set_property works fine. + INTERFACE_INCLUDE_DIRECTORIES "${LUA_SRC_FOLDER}/src" + ) + set_property(TARGET lualib PROPERTY IMPORTED_LOCATION ${LUAJIT_LIB_PATH}) + + # install generated files + install(DIRECTORY ${LUA_INSTALL_PATH}/ DESTINATION ${CMAKE_INSTALL_PREFIX}) +endif() diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index ae8896f17823e..3d3a05aeee221 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -74,6 +74,12 @@ target_link_libraries(common jemalloc openssl_ed25519 short_alloc) + +if (ELUNA) + target_link_libraries(common + PUBLIC + lualib) +endif() add_dependencies(common revision_data.h) diff --git a/src/server/database/Database/Field.h b/src/server/database/Database/Field.h index 1d28d8cf7133d..72fca6b307c9f 100644 --- a/src/server/database/Database/Field.h +++ b/src/server/database/Database/Field.h @@ -130,6 +130,8 @@ class TC_DATABASE_API Field return _value == nullptr; } + DatabaseFieldTypes GetType() { return _meta->Type; } + private: char const* _value; // Actual data in memory uint32 _length; // Length diff --git a/src/server/database/Database/QueryResult.cpp b/src/server/database/Database/QueryResult.cpp index cbb349e5803cf..fce2993729086 100644 --- a/src/server/database/Database/QueryResult.cpp +++ b/src/server/database/Database/QueryResult.cpp @@ -597,6 +597,12 @@ bool PreparedResultSet::_NextRow() return retval == 0 || retval == MYSQL_DATA_TRUNCATED; } +char* ResultSet::GetFieldName(uint32 index) const +{ + ASSERT(index < _fieldCount); + return _fields[index].name; +} + void ResultSet::CleanUp() { if (_currentRow) diff --git a/src/server/database/Database/QueryResult.h b/src/server/database/Database/QueryResult.h index a6d964f846d9e..5e2fe4e91a2e6 100644 --- a/src/server/database/Database/QueryResult.h +++ b/src/server/database/Database/QueryResult.h @@ -31,6 +31,7 @@ class TC_DATABASE_API ResultSet bool NextRow(); uint64 GetRowCount() const { return _rowCount; } uint32 GetFieldCount() const { return _fieldCount; } + char* GetFieldName(uint32 index) const; Field* Fetch() const { return _currentRow; } Field const& operator[](std::size_t index) const; diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index f9b2944fd7d57..0bcfa4f797579 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -48,6 +48,9 @@ #include "Util.h" #include "WorldStateMgr.h" #include +#ifdef ELUNA +#include "LuaEngine.h" +#endif template void Battleground::BroadcastWorker(Do& _do) @@ -115,6 +118,12 @@ Battleground::Battleground(Battleground const&) = default; Battleground::~Battleground() { +#ifdef ELUNA + if (m_Map) + if (Eluna* e = m_Map->GetEluna()) + e->OnBGDestroy(this, GetTypeID(), GetInstanceID()); +#endif + // unload map if (m_Map) { @@ -380,6 +389,11 @@ inline void Battleground::_ProcessJoin(uint32 diff) GetBgMap()->GetBattlegroundScript()->OnStart(); +#ifdef ELUNA + if (Eluna* e = GetBgMap()->GetEluna()) + e->OnBGStart(this, GetTypeID(), GetInstanceID()); +#endif + if (StartMessageIds[BG_STARTING_EVENT_FOURTH]) SendBroadcastText(StartMessageIds[BG_STARTING_EVENT_FOURTH], CHAT_MSG_BG_SYSTEM_NEUTRAL); SetStatus(STATUS_IN_PROGRESS); @@ -774,6 +788,11 @@ void Battleground::EndBattleground(Team winner) GetBgMap()->GetBattlegroundScript()->OnEnd(winner); } +#ifdef ELUNA + //the type of the winner,change Team to BattlegroundTeamId,it could be better. + if (Eluna* e = GetBgMap()->GetEluna()) + e->OnBGEnd(this, GetTypeID(), GetInstanceID(), Team(winner)); +#endif } uint32 Battleground::GetScriptId() const diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 3b73e12789b75..535dd390aba0f 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -25,6 +25,7 @@ else() ) endif() +# Exclude files in the LuaEngine directory for Mangos, CMangos and VMangos CollectSourceFiles( ${CMAKE_CURRENT_SOURCE_DIR} PRIVATE_SOURCES @@ -38,13 +39,14 @@ endif() GroupSources(${CMAKE_CURRENT_SOURCE_DIR}) +# Exclude files in the LuaEngine directory for Mangos, CMangos and VMangos CollectIncludeDirectories( ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC_INCLUDES # Exclude ${CMAKE_CURRENT_SOURCE_DIR}/PrecompiledHeaders ${ELUNA_EXCLUDE_DIRS}) - + # Provide an interface target for the game project to allow # dependent projects to build meanwhile. add_library(game-interface INTERFACE) @@ -102,3 +104,29 @@ endif() if(USE_COREPCH) add_cxx_pch(game ${PRIVATE_PCH_HEADER}) endif() + +if(ELUNA) + if(WIN32) + if (MSVC) + add_custom_command(TARGET game + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/extensions/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/LuaEngine/extensions ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/lua_scripts/extensions/ + ) + elseif(MINGW) + add_custom_command(TARGET game + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/bin/lua_scripts/extensions/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/LuaEngine/extensions ${CMAKE_BINARY_DIR}/bin/lua_scripts/extensions/ + ) + endif() + endif() + + if(UNIX) + install(DIRECTORY LuaEngine/extensions DESTINATION bin/lua_scripts/) + elseif(WIN32) + install(DIRECTORY LuaEngine/extensions DESTINATION "${CMAKE_INSTALL_PREFIX}/lua_scripts/") + endif() + + add_subdirectory(LuaEngine) +endif() \ No newline at end of file diff --git a/src/server/game/Chat/ChatCommands/ChatCommand.cpp b/src/server/game/Chat/ChatCommands/ChatCommand.cpp index a26cb7aa7b4bd..15f6d575c35a0 100644 --- a/src/server/game/Chat/ChatCommands/ChatCommand.cpp +++ b/src/server/game/Chat/ChatCommands/ChatCommand.cpp @@ -26,6 +26,9 @@ #include "Player.h" #include "ScriptMgr.h" #include "WorldSession.h" +#ifdef ELUNA +#include "LuaEngine.h" +#endif using ChatSubCommandMap = std::map; @@ -300,12 +303,23 @@ namespace Trinity::Impl::ChatCommands } else if (!handler.HasSentErrorMessage()) { /* invocation failed, we should show usage */ +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnCommand(handler.IsConsole() ? nullptr : handler.GetSession()->GetPlayer(), std::string(cmdStr).c_str())) + return true; +#endif cmd->SendCommandHelp(handler); handler.SetSentErrorMessage(true); } return true; } +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnCommand(handler.IsConsole() ? nullptr : handler.GetSession()->GetPlayer(), std::string(cmdStr).c_str())) + return true; +#endif + return false; } diff --git a/src/server/game/Combat/CombatManager.cpp b/src/server/game/Combat/CombatManager.cpp index 18e084f8e0d57..eff645e35ecfd 100644 --- a/src/server/game/Combat/CombatManager.cpp +++ b/src/server/game/Combat/CombatManager.cpp @@ -20,6 +20,9 @@ #include "Creature.h" #include "CreatureAI.h" #include "Player.h" +#ifdef ELUNA +#include "LuaEngine.h" +#endif /*static*/ bool CombatManager::CanBeginCombat(Unit const* a, Unit const* b) { @@ -74,6 +77,20 @@ void CombatReference::EndCombat() bool const needSecondAI = second->GetCombatManager().UpdateOwnerCombatState(); // ...and if that happened, also notify the AI of it... +#ifdef ELUNA + if (needFirstAI) + { + if (Player* player = first->ToPlayer()) + if (Eluna* e = first->GetEluna()) + e->OnPlayerLeaveCombat(player); + } + if (needSecondAI) + { + if (Player* player = second->ToPlayer()) + if (Eluna* e = second->GetEluna()) + e->OnPlayerLeaveCombat(player); + } +#endif if (needFirstAI) if (UnitAI* firstAI = first->GetAI()) firstAI->JustExitedCombat(); @@ -109,8 +126,15 @@ void CombatReference::SuppressFor(Unit* who) { Suppress(who); if (who->GetCombatManager().UpdateOwnerCombatState()) + { +#ifdef ELUNA + if (Player* player = who->ToPlayer()) + if (Eluna* e = player->GetEluna()) + e->OnPlayerLeaveCombat(player); +#endif if (UnitAI* ai = who->GetAI()) ai->JustExitedCombat(); + } } bool PvPCombatReference::Update(uint32 tdiff) @@ -302,8 +326,15 @@ void CombatManager::SuppressPvPCombat(UnitFilter* unitFilter /*= nullptr*/) combatRef->Suppress(_owner); if (UpdateOwnerCombatState()) + { +#ifdef ELUNA + if (Player* player = _owner->ToPlayer()) + if (Eluna* e = player->GetEluna()) + e->OnPlayerLeaveCombat(player); +#endif if (UnitAI* ownerAI = _owner->GetAI()) ownerAI->JustExitedCombat(); + } } void CombatManager::EndAllPvECombat(UnitFilter* unitFilter /*= nullptr*/) @@ -365,6 +396,11 @@ void CombatManager::EndAllPvPCombat(UnitFilter* unitFilter /*= nullptr*/) /*static*/ void CombatManager::NotifyAICombat(Unit* me, Unit* other) { +#ifdef ELUNA + if (Player* player = me->ToPlayer()) + if (Eluna* e = player->GetEluna()) + e->OnPlayerEnterCombat(player, other); +#endif if (UnitAI* ai = me->GetAI()) ai->JustEnteredCombat(other); } diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 652ee520ecb41..7f59c9018f76e 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -54,6 +54,9 @@ #include "ZoneScript.h" #include #include +#ifdef ELUNA +#include "LuaEngine.h" +#endif CreatureMovementData::CreatureMovementData() : HoverInitiallyEnabled(false), Chase(CreatureChaseMovementType::Run), Random(CreatureRandomMovementType::Walk), InteractionPauseTimer(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)) { } @@ -351,6 +354,11 @@ void Creature::AddToWorld() if (GetZoneScript()) GetZoneScript()->OnCreatureCreate(this); + +#ifndef ELUNA + if (Eluna* e = GetEluna()) + e->OnAddToWorld(this); +#endif } } @@ -358,6 +366,10 @@ void Creature::RemoveFromWorld() { if (IsInWorld()) { +#ifndef ELUNA + if (Eluna* e = GetEluna()) + e->OnRemoveFromWorld(this); +#endif if (GetZoneScript()) GetZoneScript()->OnCreatureRemove(this); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index eb48c74b1fa09..f9e3b61d1f0b2 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -59,6 +59,9 @@ #include #include #include +#ifdef ELUNA +#include "LuaEngine.h" +#endif void GameObjectTemplate::InitializeQueryData() { @@ -948,6 +951,15 @@ void GameObject::AddToWorld() EnableCollision(toggledState); WorldObject::AddToWorld(); + +#ifdef ELUNA + if (Eluna* e = GetEluna()) + { + // one of these should really be deprecated, they serve the exact same purpose + e->OnAddToWorld(this); + e->OnSpawn(this); + } +#endif } } @@ -956,6 +968,10 @@ void GameObject::RemoveFromWorld() ///- Remove the gameobject from the accessor if (IsInWorld()) { +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnRemoveFromWorld(this); +#endif if (m_zoneScript) m_zoneScript->OnGameObjectRemove(this); @@ -1245,6 +1261,15 @@ GameObject* GameObject::CreateGameObjectFromDB(ObjectGuid::LowType spawnId, Map* void GameObject::Update(uint32 diff) { +#ifdef ELUNA + if (Eluna* e = GetEluna()) + { + e->UpdateAI(this, diff); + + if (elunaEvents) // can be null on maps without eluna + elunaEvents->Update(diff); + } +#endif WorldObject::Update(diff); if (AI()) @@ -2582,6 +2607,12 @@ void GameObject::Use(Unit* user) playerUser->RemoveAurasByType(SPELL_AURA_MOUNTED); playerUser->PlayerTalkClass->ClearMenus(); + +#ifdef ELUNA + if (Eluna* e = GetEluna()) + if (e->OnGossipHello(playerUser, this)) + return; +#endif if (AI()->OnGossipHello(playerUser)) return; } @@ -3702,6 +3733,10 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, WorldOb case GO_DESTRUCTIBLE_DAMAGED: { if (GetGOInfo()->destructibleBuilding.DamagedEvent && attackerOrHealer) +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnDamaged(this, attackerOrHealer); +#endif GameEvents::Trigger(GetGOInfo()->destructibleBuilding.DamagedEvent, attackerOrHealer, this); AI()->Damaged(attackerOrHealer, m_goInfo->destructibleBuilding.DamagedEvent); @@ -3727,6 +3762,10 @@ void GameObject::SetDestructibleState(GameObjectDestructibleState state, WorldOb } case GO_DESTRUCTIBLE_DESTROYED: { +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnDestroyed(this, attackerOrHealer); +#endif if (GetGOInfo()->destructibleBuilding.DestroyedEvent && attackerOrHealer) GameEvents::Trigger(GetGOInfo()->destructibleBuilding.DestroyedEvent, attackerOrHealer, this); AI()->Destroyed(attackerOrHealer, m_goInfo->destructibleBuilding.DestroyedEvent); @@ -3780,6 +3819,11 @@ void GameObject::SetLootState(LootState state, Unit* unit) else m_lootStateUnitGUID.Clear(); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnLootStateChanged(this, state); +#endif + AI()->OnLootStateChanged(state, unit); // Start restock timer if the chest is partially looted or not looted at all @@ -3864,6 +3908,10 @@ void GameObject::SetGoState(GOState state) { GOState oldState = GetGoState(); SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::State), state); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnGameObjectStateChanged(this, state); +#endif if (AI()) AI()->OnStateChanged(state); diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 381317169db63..5a8cc0213f53c 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -23,6 +23,10 @@ #include "GameObjectData.h" #include "MapObject.h" #include "SharedDefines.h" +#ifdef ELUNA +#include "LuaEngine.h" +#include "ElunaEventMgr.h" +#endif class GameObject; class GameObjectAI; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 7feb6610bd464..0dadcb6072c3f 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -59,6 +59,10 @@ #include "World.h" #include #include +#ifdef ELUNA +#include "LuaEngine.h" +#include "ElunaConfig.h" +#endif constexpr float VisibilityDistances[AsUnderlyingType(VisibilityDistanceType::Max)] = { @@ -879,6 +883,9 @@ void MovementInfo::OutDebug() } WorldObject::WorldObject(bool isWorldObject) : Object(), WorldLocation(), LastUsedScriptID(0), +#ifdef ELUNA +elunaEvents(nullptr), +#endif m_movementInfo(), m_name(), m_isActive(false), m_isFarVisible(false), m_isStoredInWorldObjectGridContainer(isWorldObject), m_zoneScript(nullptr), m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_outdoors(false), m_liquidStatus(LIQUID_MAP_NO_WATER), m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0), _heartbeatTimer(HEARTBEAT_INTERVAL) @@ -889,6 +896,11 @@ m_currMap(nullptr), m_InstanceId(0), _dbPhase(0), m_notifyflags(0), _heartbeatTi WorldObject::~WorldObject() { +#ifdef ELUNA + delete elunaEvents; + elunaEvents = NULL; +#endif + // this may happen because there are many !create/delete if (IsStoredInWorldObjectGridContainer() && m_currMap) { @@ -1819,6 +1831,21 @@ void WorldObject::SetMap(Map* map) m_currMap = map; m_mapId = map->GetId(); m_InstanceId = map->GetInstanceId(); +#ifdef ELUNA + //@todo: possibly look into cleanly clearing all pending events from previous map's event mgr. + + // if multistate, delete elunaEvents and set to nullptr. events shouldn't move across states. + // in single state, the timed events should move across maps + if (!sElunaConfig->IsElunaCompatibilityMode()) + { + delete elunaEvents; + elunaEvents = nullptr; // set to null in case map doesn't use eluna + } + + if (Eluna* e = map->GetEluna()) + if (!elunaEvents) + elunaEvents = new ElunaEventProcessor(e, this); +#endif if (IsStoredInWorldObjectGridContainer()) m_currMap->AddWorldObject(this); } @@ -3848,6 +3875,16 @@ std::string WorldObject::GetDebugInfo() const return sstr.str(); } +#ifdef ELUNA +Eluna* WorldObject::GetEluna() const +{ + if (const Map* map = FindMap()) + return map->GetEluna(); + + return nullptr; +} +#endif + template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector&, uint32, float) const; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index e5a205919edd0..d0ab3846abb47 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -36,6 +36,9 @@ #include "UpdateFields.h" #include #include +#ifdef ELUNA +#include "LuaValue.h" +#endif class AreaTrigger; class Conversation; @@ -43,6 +46,10 @@ class Corpse; class Creature; class CreatureAI; class DynamicObject; +#ifdef ELUNA +class ElunaEventProcessor; +class Eluna; +#endif class GameObject; class InstanceScript; class Item; @@ -749,6 +756,14 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation uint32 LastUsedScriptID; +#ifdef ELUNA + ElunaEventProcessor* elunaEvents; + + Eluna* GetEluna() const; + + LuaVal lua_data = LuaVal({}); +#endif + // Transports TransportBase* GetTransport() const { return m_transport; } float GetTransOffsetX() const { return m_movementInfo.transport.pos.GetPositionX(); } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ff98f642fc039..3534248c7b7d0 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -141,6 +141,9 @@ #include #include #include +#ifdef ELUNA +#include "LuaEngine.h" +#endif #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) @@ -4486,6 +4489,10 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) // recast lost by death auras of any items held in the inventory CastAllObtainSpells(); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnResurrect(this); +#endif if (!applySickness) return; @@ -11420,6 +11427,15 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto, bool skipRequiredL if (ChrSpecialization(artifact->ChrSpecializationID) != GetPrimarySpecialization()) return EQUIP_ERR_CANT_USE_ITEM; +#ifdef ELUNA + if (Eluna* e = GetEluna()) + { + InventoryResult eres = e->OnCanUseItem(this, proto->BasicData->ID); + if (eres != EQUIP_ERR_OK) + return eres; + } +#endif + return EQUIP_ERR_OK; } @@ -11785,6 +11801,13 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) ApplyEquipCooldown(pItem2); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + { + e->OnEquip(this, pItem2, bag, slot); // This should be removed in the future + e->OnItemEquip(this, pItem2, slot); + } +#endif return pItem2; } @@ -11797,6 +11820,13 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) UpdateAverageItemLevelEquipped(); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + { + e->OnEquip(this, pItem, bag, slot); // This should be removed in the future + e->OnItemEquip(this, pItem, slot); + } +#endif return pItem; } @@ -14729,6 +14759,10 @@ void Player::AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver) { case TYPEID_UNIT: PlayerTalkClass->ClearMenus(); +#ifndef ELUNA + if (Eluna* e = GetEluna()) + e->OnQuestAccept(this, questGiver->ToCreature(), quest); +#endif questGiver->ToCreature()->AI()->OnQuestAccept(this, quest); break; case TYPEID_ITEM: @@ -14763,6 +14797,10 @@ void Player::AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver) } case TYPEID_GAMEOBJECT: PlayerTalkClass->ClearMenus(); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnQuestAccept(this, questGiver->ToGameObject(), quest); +#endif questGiver->ToGameObject()->AI()->OnQuestAccept(this, quest); break; default: @@ -16181,6 +16219,10 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object const* questgiver) const { case TYPEID_GAMEOBJECT: { +#ifndef ELUNA + if (Eluna* e = GetEluna()) + e->GetDialogStatus(this, questgiver->ToGameObject()); +#endif if (GameObjectAI* ai = questgiver->ToGameObject()->AI()) if (Optional questStatus = ai->GetDialogStatus(this)) return *questStatus; @@ -16190,6 +16232,10 @@ QuestGiverStatus Player::GetQuestDialogStatus(Object const* questgiver) const } case TYPEID_UNIT: { +#ifndef ELUNA + if (Eluna* e = GetEluna()) + e->GetDialogStatus(this, questgiver->ToCreature()); +#endif Creature const* questGiverCreature = questgiver->ToCreature(); if (!questGiverCreature->IsInteractionAllowedWhileHostile() && questGiverCreature->IsHostileTo(this)) return QuestGiverStatus::None; @@ -26686,6 +26732,11 @@ void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot* else ApplyItemLootedSpell(sObjectMgr->GetItemTemplate(item->itemid)); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnLootItem(this, newitem, item->count, this->GetLootGUID()); +#endif + break; } case LootItemType::Currency: @@ -27111,6 +27162,10 @@ TalentLearnResult Player::LearnTalent(uint32 talentId, int32* spellOnCooldown) TC_LOG_DEBUG("misc", "Player::LearnTalent: TalentID: {} Spell: {} Group: {}\n", talentId, spellid, GetActiveTalentGroup()); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + e->OnLearnTalents(this, talentId, 0, spellid); +#endif return TALENT_LEARN_OK; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 1561c86c4730c..1f182e49dcfe9 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -93,6 +93,10 @@ #include #include #include +#ifdef ELUNA +#include "LuaEngine.h" +#include "ElunaEventMgr.h" +#endif float baseMoveSpeed[MAX_MOVE_TYPE] = { @@ -419,6 +423,9 @@ Unit::~Unit() void Unit::Update(uint32 p_time) { +#ifdef ELUNA + elunaEvents->Update(p_time); +#endif // WARNING! Order of execution here is important, do not change. // Spells must be processed with event system BEFORE they go to _UpdateSpells. // Or else we may have some SPELL_STATE_FINISHED spells stalled in pointers, that is bad. diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 1278190915185..5d5976e35d144 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -34,6 +34,9 @@ #include "StringConvert.h" #include "World.h" #include "WorldStateMgr.h" +#ifdef ELUNA +#include "LuaEngine.h" +#endif GameEventMgr* GameEventMgr::instance() { @@ -145,6 +148,11 @@ bool GameEventMgr::StartEvent(uint16 event_id, bool overwrite) if (data.end <= data.start) data.end = data.start + data.length; } +#ifdef ELUNA + if (IsActiveEvent(event_id)) + if (Eluna* e = sWorld->GetEluna()) + e->OnGameEventStart(event_id); +#endif return false; } else @@ -168,6 +176,11 @@ bool GameEventMgr::StartEvent(uint16 event_id, bool overwrite) if (overwrite && conditions_met) sWorld->ForceGameEventUpdate(); +#ifdef ELUNA + if (IsActiveEvent(event_id)) + if (Eluna* e = sWorld->GetEluna()) + e->OnGameEventStart(event_id); +#endif return conditions_met; } } @@ -210,6 +223,11 @@ void GameEventMgr::StopEvent(uint16 event_id, bool overwrite) CharacterDatabase.CommitTransaction(trans); } } +#ifdef ELUNA + if (!IsActiveEvent(event_id)) + if (Eluna* e = sWorld->GetEluna()) + e->OnGameEventStop(event_id); +#endif } void GameEventMgr::LoadFromDB() diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index ebd3489cf0ecf..e9749705db16b 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -64,6 +64,9 @@ #include "Util.h" #include "World.h" #include +#ifdef ELUNA +#include "LuaEngine.h" +#endif class LoginQueryHolder : public CharacterDatabaseQueryHolder { diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 410eb8ec122f7..8058e333a529f 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -42,6 +42,9 @@ #include "Warden.h" #include "World.h" #include +#ifdef ELUNA +#include "LuaEngine.h" +#endif enum class ChatWhisperTargetStatus : uint8 { @@ -256,6 +259,12 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s return ChatMessageResult::LevelTooLow; } +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, lang, msg)) + return ChatMessageResult::Ok; +#endif + sender->Say(msg, lang); break; } @@ -271,6 +280,12 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s return ChatMessageResult::LevelTooLow; } +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, LANG_UNIVERSAL, msg)) + return ChatMessageResult::Ok; +#endif + sender->TextEmote(msg); break; } @@ -286,6 +301,12 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s return ChatMessageResult::LevelTooLow; } +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, lang, msg)) + return ChatMessageResult::Ok; +#endif + sender->Yell(msg, lang); break; } @@ -343,6 +364,11 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s (HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS) && !sender->isAcceptWhispers() && !sender->IsInWhisperWhiteList(receiver->GetGUID()))) sender->AddWhisperWhiteList(receiver->GetGUID()); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(GetPlayer(), type, lang, msg, receiver)) + return ChatMessageResult::Ok; +#endif GetPlayer()->Whisper(msg, lang, receiver); break; } @@ -361,6 +387,11 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s type = CHAT_MSG_PARTY_LEADER; sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, lang, msg, group)) + return ChatMessageResult::Ok; +#endif WorldPackets::Chat::Chat packet; packet.Initialize(ChatMsg(type), lang, sender, nullptr, msg); @@ -375,6 +406,12 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s { sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, guild); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, lang, msg, guild)) + return ChatMessageResult::Ok; +#endif + guild->BroadcastToGuild(this, false, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } } @@ -388,6 +425,12 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s { sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, guild); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, lang, msg, guild)) + return ChatMessageResult::Ok; +#endif + guild->BroadcastToGuild(this, true, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } } @@ -404,6 +447,12 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, lang, msg, group)) + return ChatMessageResult::Ok; +#endif + WorldPackets::Chat::Chat packet; packet.Initialize(ChatMsg(type), lang, sender, nullptr, msg); group->BroadcastPacket(packet.Write(), false); @@ -425,6 +474,12 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s sScriptMgr->OnPlayerChat(GetPlayer(), type, lang, msg, group); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, lang, msg, group)) + return ChatMessageResult::Ok; +#endif + WorldPackets::Chat::Chat packet; //in battleground, raid warning is sent only to players in battleground - code is ok packet.Initialize(CHAT_MSG_RAID_WARNING, lang, sender, nullptr, msg); @@ -452,6 +507,11 @@ ChatMessageResult WorldSession::HandleChatMessage(ChatMsg type, Language lang, s return ChatMessageResult::ChannelIsReadOnly; sScriptMgr->OnPlayerChat(sender, type, lang, msg, chn); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnChat(sender, type, lang, msg, chn)) + return ChatMessageResult::Ok; +#endif chn->Say(sender->GetGUID(), msg, lang); } break; diff --git a/src/server/game/Handlers/LootHandler.cpp b/src/server/game/Handlers/LootHandler.cpp index 3f7a3cc7fd292..28ade01be9ce1 100644 --- a/src/server/game/Handlers/LootHandler.cpp +++ b/src/server/game/Handlers/LootHandler.cpp @@ -38,6 +38,10 @@ #include "SpellMgr.h" #include "World.h" +#ifdef ELUNA +#include "LuaEngine.h" +#endif + class AELootCreatureCheck { public: @@ -198,6 +202,10 @@ void WorldSession::HandleLootMoneyOpcode(WorldPackets::Loot::LootMoney& /*packet SendPacket(packet.Write()); } +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnLootMoney(player, loot->gold); +#endif loot->LootMoney(); // Delete the money loot record from the DB @@ -475,6 +483,14 @@ void WorldSession::HandleLootMasterGiveOpcode(WorldPackets::Loot::MasterLootItem else target->ApplyItemLootedSpell(sObjectMgr->GetItemTemplate(item.itemid)); +#ifdef ELUNA + if (Eluna* e = target->GetEluna()) + { + Item* newitem = target->StoreNewItem(dest, item.itemid, true, item.randomBonusListId, item.GetAllowedLooters(), item.context, &item.BonusListIDs); + e->OnLootItem(target, newitem, item.count, req.Object); + } +#endif + // mark as looted item.count = 0; item.is_looted = true; diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index b8a0b8aa7acbb..d9d2080f828a0 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -38,6 +38,9 @@ #include "SpellInfo.h" #include "Trainer.h" #include "WorldPacket.h" +#ifdef ELUNA +#include "LuaEngine.h" +#endif enum class TabardVendorType : int32 { @@ -183,6 +186,10 @@ void WorldSession::HandleGossipHelloOpcode(WorldPackets::NPC::Hello& packet) } _player->PlayerTalkClass->ClearMenus(); +#ifdef ELUNA + if (Eluna* e = GetPlayer()->GetEluna()) + if (!e->OnGossipHello(_player, unit)) +#endif if (!unit->AI()->OnGossipHello(_player)) { // _player->TalkedToCreature(unit->GetEntry(), unit->GetGUID()); @@ -201,6 +208,7 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelec if (_player->PlayerTalkClass->GetInteractionData().SourceGuid != packet.GossipUnit) return; + Item* item = nullptr; Creature* unit = nullptr; GameObject* go = nullptr; if (packet.GossipUnit.IsCreatureOrVehicle()) @@ -221,6 +229,23 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelec return; } } + else if (packet.GossipUnit.IsItem()) + { + item = _player->GetItemByGuid(packet.GossipUnit); + if (!item) + { + TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found.", packet.GossipUnit.ToString()); + return; + } + } + else if (packet.GossipUnit.IsPlayer()) + { + if (_player->GetGUID() != packet.GossipUnit || packet.GossipID != _player->PlayerTalkClass->GetGossipMenu().GetMenuId()) + { + TC_LOG_DEBUG("network", "WORLD: HandleGossipSelectOptionOpcode - %s not found.", packet.GossipUnit.ToString()); + return; + } + } else { @@ -248,11 +273,19 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelec { if (unit) { +#ifdef ELUNA + if (Eluna* e = GetPlayer()->GetEluna()) + if (!e->OnGossipSelectCode(_player, unit, _player->PlayerTalkClass->GetGossipOptionSender(gossipMenuItem->OrderIndex), _player->PlayerTalkClass->GetGossipOptionAction(gossipMenuItem->OrderIndex), packet.PromotionCode.c_str())) +#endif if (!unit->AI()->OnGossipSelectCode(_player, packet.GossipID, gossipMenuItem->OrderIndex, packet.PromotionCode.c_str())) _player->OnGossipSelect(unit, packet.GossipOptionID, packet.GossipID); } else { +#ifdef ELUNA + if (Eluna* e = GetPlayer()->GetEluna()) + if (!e->OnGossipSelectCode(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(gossipMenuItem->OrderIndex), _player->PlayerTalkClass->GetGossipOptionAction(gossipMenuItem->OrderIndex), packet.PromotionCode.c_str())) +#endif if (!go->AI()->OnGossipSelectCode(_player, packet.GossipID, gossipMenuItem->OrderIndex, packet.PromotionCode.c_str())) _player->OnGossipSelect(go, packet.GossipOptionID, packet.GossipID); } @@ -261,11 +294,19 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPackets::NPC::GossipSelec { if (unit) { +#ifdef ELUNA + if (Eluna* e = GetPlayer()->GetEluna()) + if (!e->OnGossipSelect(_player, unit, _player->PlayerTalkClass->GetGossipOptionSender(gossipMenuItem->OrderIndex), _player->PlayerTalkClass->GetGossipOptionAction(gossipMenuItem->OrderIndex))) +#endif if (!unit->AI()->OnGossipSelect(_player, packet.GossipID, gossipMenuItem->OrderIndex)) _player->OnGossipSelect(unit, packet.GossipOptionID, packet.GossipID); } else { +#ifdef ELUNA + if (Eluna* e = GetPlayer()->GetEluna()) + if (!e->OnGossipSelect(_player, go, _player->PlayerTalkClass->GetGossipOptionSender(gossipMenuItem->OrderIndex), _player->PlayerTalkClass->GetGossipOptionAction(gossipMenuItem->OrderIndex))) +#endif if (!go->AI()->OnGossipSelect(_player, packet.GossipID, gossipMenuItem->OrderIndex)) _player->OnGossipSelect(go, packet.GossipOptionID, packet.GossipID); } diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index cca62c6ac08ed..1a8f57b0617c7 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -37,6 +37,9 @@ #include "ReputationMgr.h" #include "ScriptMgr.h" #include "World.h" +#ifdef ELUNA +#include "LuaEngine.h" +#endif void WorldSession::HandleQuestgiverStatusQueryOpcode(WorldPackets::Quest::QuestGiverStatusQuery& packet) { @@ -75,6 +78,13 @@ void WorldSession::HandleQuestgiverHelloOpcode(WorldPackets::Quest::QuestGiverHe creature->SetHomePosition(creature->GetPosition()); _player->PlayerTalkClass->ClearMenus(); + +#ifdef ELUNA + if (Eluna* e = GetPlayer()->GetEluna()) + if (e->OnGossipHello(_player, creature)) + return; +#endif + if (creature->AI()->OnGossipHello(_player)) return; @@ -377,6 +387,9 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest { if (_player->CanRewardQuest(quest, packet.Choice.LootItemType, packet.Choice.Item.ItemID, true)) // Then check if player can receive the reward item (if inventory is not full, if player doesn't have too many unique items, and so on). If not, the client will close the gossip window { +#ifdef ELUNA +// sEluna->OnQuestReward(_player, object, quest, packet.Choice.Item.ItemID); +#endif _player->RewardQuest(quest, packet.Choice.LootItemType, packet.Choice.Item.ItemID, object); } } @@ -450,6 +463,11 @@ void WorldSession::HandleQuestLogRemoveQuest(WorldPackets::Quest::QuestLogRemove _player->RemoveActiveQuest(questId); _player->DespawnPersonalSummonsForQuest(questId); +#ifdef ELUNA + if (Eluna* e = GetPlayer()->GetEluna()) + e->OnQuestAbandon(_player, questId); +#endif + TC_LOG_INFO("network", "Player {} abandoned quest {}", _player->GetGUID().ToString(), questId); if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp index 2515320fc4b30..14b60dbb74939 100644 --- a/src/server/game/Handlers/SpellHandler.cpp +++ b/src/server/game/Handlers/SpellHandler.cpp @@ -42,6 +42,9 @@ #include "TemporarySummon.h" #include "TotemPackets.h" #include "World.h" +#ifdef ELUNA +#include "LuaEngine.h" +#endif void WorldSession::HandleUseItemOpcode(WorldPackets::Spells::UseItem& packet) { @@ -218,6 +221,11 @@ void WorldSession::HandleGameobjectReportUse(WorldPackets::GameObject::GameObjRe if (GameObject* go = GetPlayer()->GetGameObjectIfCanInteractWith(packet.Guid)) { +#ifdef ELUNA + if (Eluna* e = GetPlayer()->GetEluna()) + if (e->OnGameObjectUse(_player, go)) + return; +#endif if (go->AI()->OnReportUse(_player)) return; diff --git a/src/server/game/LuaEngine b/src/server/game/LuaEngine new file mode 160000 index 0000000000000..803640bcdf87d --- /dev/null +++ b/src/server/game/LuaEngine @@ -0,0 +1 @@ +Subproject commit 803640bcdf87d39c16474313ce511467e868a2df diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 9f1120da59eb7..96e1bdbbd059d 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -64,6 +64,11 @@ #include "WorldStatePackets.h" #include #include +#ifdef ELUNA +#include "LuaEngine.h" +#include "ElunaConfig.h" +#include "ElunaLoader.h" +#endif #define DEFAULT_GRID_EXPIRY 300 #define MAX_GRID_LOAD_TIME 50 @@ -90,6 +95,11 @@ struct RespawnInfoWithHandle : RespawnInfo Map::~Map() { +#ifdef ELUNA + delete eluna; + eluna = nullptr; +#endif + // Delete all waiting spawns, else there will be a memory leak // This doesn't delete from database. UnloadAllRespawnInfos(); @@ -141,6 +151,13 @@ m_activeNonPlayersIter(m_activeNonPlayers.end()), _transportsUpdateIter(_transpo i_gridExpiry(expiry), m_terrain(sTerrainMgr.LoadTerrain(id)), m_forceEnabledNavMeshFilterFlags(0), m_forceDisabledNavMeshFilterFlags(0), i_scriptLock(false), _respawnTimes(std::make_unique()), _respawnCheckTimer(0), _vignetteUpdateTimer(5200, 5200) { +#ifdef ELUNA + // lua state begins uninitialized + eluna = nullptr; + + if (sElunaConfig->IsElunaEnabled() && !sElunaConfig->IsElunaCompatibilityMode() && sElunaConfig->ShouldMapLoadEluna(id)) + eluna = new Eluna(this); +#endif for (uint32 x = 0; x < MAX_NUMBER_OF_GRIDS; ++x) { for (uint32 y = 0; y < MAX_NUMBER_OF_GRIDS; ++y) @@ -2583,6 +2600,16 @@ void Map::AddObjectToRemoveList(WorldObject* obj) { ASSERT(obj->GetMapId() == GetId() && obj->GetInstanceId() == GetInstanceId()); +#ifdef ELUNA + if (Eluna* e = GetEluna()) + { + if (Creature* creature = obj->ToCreature()) + e->OnRemove(creature); + else if (GameObject* gameobject = obj->ToGameObject()) + e->OnRemove(gameobject); + } +#endif + obj->SetDestroyedObject(true); obj->CleanupsBeforeDelete(false); // remove or simplify at least cross referenced links @@ -2991,11 +3018,26 @@ void InstanceMap::CreateInstanceData() if (i_data != nullptr) return; - InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(GetId()); - if (mInstance) + bool isElunaAI = false; + +#ifdef ELUNA + if (Eluna* e = GetEluna()) { - i_script_id = mInstance->ScriptId; - i_data = sScriptMgr->CreateInstanceData(this); + i_data = e->GetInstanceData(this); + if (i_data) + isElunaAI = true; + } +#endif + + // if Eluna AI was fetched succesfully we should not call CreateInstanceData nor set the unused scriptID + if (!isElunaAI) + { + InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(GetId()); + if (mInstance) + { + i_script_id = mInstance->ScriptId; + i_data = sScriptMgr->CreateInstanceData(this); + } } if (!i_data) @@ -3018,7 +3060,7 @@ void InstanceMap::CreateInstanceData() i_data->SetEntranceLocation(lockData->EntranceWorldSafeLocId); if (!lockData->Data.empty()) { - TC_LOG_DEBUG("maps", "Loading instance data for `{}` with id {}", sObjectMgr->GetScriptName(i_script_id), i_InstanceId); + TC_LOG_DEBUG("maps", "Loading instance data for `{}` with id {}", isElunaAI ? "ElunaAI" : sObjectMgr->GetScriptName(i_script_id), i_InstanceId); i_data->Load(lockData->Data.c_str()); } else @@ -4084,4 +4126,14 @@ std::string InstanceMap::GetDebugInfo() const return sstr.str(); } +#ifdef ELUNA +Eluna* Map::GetEluna() const +{ + if (sElunaConfig->IsElunaCompatibilityMode()) + return sWorld->GetEluna(); + + return eluna; +} +#endif + template class TC_GAME_API TypeUnorderedMapContainer; diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 901e03e0264a8..6f20c7815789b 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -43,11 +43,17 @@ #include #include #include +#ifdef ELUNA +#include "LuaValue.h" +#endif class Battleground; class BattlegroundMap; class BattlegroundScript; class CreatureGroup; +#ifdef ELUNA +class Eluna; +#endif class GameObjectModel; class Group; class InstanceLock; @@ -722,6 +728,11 @@ class TC_GAME_API Map : public GridRefManager void InitSpawnGroupState(); void UpdateSpawnGroupConditions(); +#ifdef ELUNA + Eluna* GetEluna() const; + + LuaVal lua_data = LuaVal({}); +#endif private: // Type specific code for add/remove to/from grid template @@ -808,6 +819,10 @@ class TC_GAME_API Map : public GridRefManager MPSCQueue _farSpellCallbacks; +#ifdef ELUNA + Eluna* eluna; +#endif + /*********************************************************/ /*** Phasing ***/ /*********************************************************/ diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp index 902d665ca610c..6d456f999f8ce 100644 --- a/src/server/game/Maps/MapManager.cpp +++ b/src/server/game/Maps/MapManager.cpp @@ -35,6 +35,10 @@ #include "WorldStateMgr.h" #include #include +#ifdef ELUNA +#include "LuaEngine.h" +#include "ElunaConfig.h" +#endif MapManager::MapManager() : _freeInstanceIds(std::make_unique()), _nextInstanceId(0), _scheduledScripts(0) @@ -50,6 +54,14 @@ void MapManager::Initialize() Map::InitStateMachine(); int num_threads(sWorld->getIntConfig(CONFIG_NUMTHREADS)); +#if ELUNA + if (sElunaConfig->IsElunaEnabled() && sElunaConfig->IsElunaCompatibilityMode() && num_threads > 1) + { + // Force 1 thread for Eluna if compatibility mode is enabled. Compatibility mode is single state and does not allow more update threads. + TC_LOG_ERROR("maps", "Map update threads set to {}, when Eluna in compatibility mode only allows 1, changing to 1", num_threads); + num_threads = 1; + } +#endif // Start mtmaps if needed. if (num_threads > 0) m_updater.activate(num_threads); @@ -134,6 +146,11 @@ BattlegroundMap* MapManager::CreateBattleground(uint32 mapId, uint32 instanceId, if (sWorld->getBoolConfig(CONFIG_BATTLEGROUNDMAP_LOAD_GRIDS)) map->LoadAllCells(); +#ifdef ELUNA + if (Eluna* e = map->GetEluna()) + e->OnBGCreate(bg, bg->GetTypeID(), bg->GetInstanceID()); +#endif + return map; } @@ -468,6 +485,18 @@ void MapManager::FreeInstanceId(uint32 instanceId) // If freed instance id is lower than the next id available for new instances, use the freed one instead _nextInstanceId = std::min(instanceId, _nextInstanceId); _freeInstanceIds->set(instanceId, true); +/*#ifdef ELUNA + for (MapMapType::iterator itr = i_maps.begin(); itr != i_maps.end(); ++itr) + { + if (!(*itr).second->Instanceable()) + continue; + + Map* iMap = (*itr).second->ToInstanceMap()->~InstanceMap + Map* iMap = (*itr).second->ToMapInstanced()->FindInstanceMap(instanceId); + if (iMap && iMap->GetEluna()) + iMap->GetEluna()->FreeInstanceId(instanceId); + } +#endif*/ } // hack to allow conditions to access what faction owns the map (these worldstates should not be set on these maps) diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index e69b64a73fa6c..d97a24a277c9f 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -50,6 +50,12 @@ #include "Weather.h" #include "WorldPacket.h" #include +#ifdef ELUNA +#include "LuaEngine.h" +#include "ElunaConfig.h" +#include "ElunaUtility.h" +#include "Battleground.h" +#endif // Trait which indicates whether this script type // must be assigned in the database. @@ -1464,11 +1470,19 @@ void ScriptMgr::OnPacketSend(WorldSession* session, WorldPacket const& packet) void ScriptMgr::OnOpenStateChange(bool open) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnOpenStateChange(open); +#endif FOREACH_SCRIPT(WorldScript)->OnOpenStateChange(open); } void ScriptMgr::OnConfigLoad(bool reload) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnConfigLoad(reload); +#endif FOREACH_SCRIPT(WorldScript)->OnConfigLoad(reload); } @@ -1479,16 +1493,31 @@ void ScriptMgr::OnMotdChange(std::string& newMotd) void ScriptMgr::OnShutdownInitiate(ShutdownExitCode code, ShutdownMask mask) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnShutdownInitiate(code, mask); +#endif FOREACH_SCRIPT(WorldScript)->OnShutdownInitiate(code, mask); } void ScriptMgr::OnShutdownCancel() { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnShutdownCancel(); +#endif FOREACH_SCRIPT(WorldScript)->OnShutdownCancel(); } void ScriptMgr::OnWorldUpdate(uint32 diff) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + { + e->UpdateEluna(diff); + e->OnWorldUpdate(diff); + } +#endif FOREACH_SCRIPT(WorldScript)->OnUpdate(diff); } @@ -1551,6 +1580,11 @@ void ScriptMgr::OnCreateMap(Map* map) { ASSERT(map); +#ifdef ELUNA + if (Eluna* e = map->GetEluna()) + e->OnCreate(map); +#endif + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnCreate(map); SCR_MAP_END; @@ -1568,6 +1602,11 @@ void ScriptMgr::OnDestroyMap(Map* map) { ASSERT(map); +#ifdef ELUNA + if (Eluna* e = map->GetEluna()) + e->OnDestroy(map); +#endif + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnDestroy(map); SCR_MAP_END; @@ -1586,6 +1625,13 @@ void ScriptMgr::OnPlayerEnterMap(Map* map, Player* player) ASSERT(map); ASSERT(player); +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnMapChanged(player); + if (Eluna* e = map->GetEluna()) + e->OnPlayerEnter(map, player); +#endif + FOREACH_SCRIPT(PlayerScript)->OnMapChanged(player); SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); @@ -1606,6 +1652,11 @@ void ScriptMgr::OnPlayerLeaveMap(Map* map, Player* player) ASSERT(map); ASSERT(player); +#ifdef ELUNA + if (Eluna* e = map->GetEluna()) + e->OnPlayerLeave(map, player); +#endif + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnPlayerLeave(map, player); SCR_MAP_END; @@ -1623,6 +1674,16 @@ void ScriptMgr::OnMapUpdate(Map* map, uint32 diff) { ASSERT(map); +#ifdef ELUNA + if (Eluna* e = map->GetEluna()) + { + if (!sElunaConfig->IsElunaCompatibilityMode()) + e->UpdateEluna(diff); + + e->OnUpdate(map, diff); + } +#endif + SCR_MAP_BGN(WorldMapScript, map, itr, end, entry, IsWorldMap); itr->second->OnUpdate(map, diff); SCR_MAP_END; @@ -1661,6 +1722,12 @@ bool ScriptMgr::OnQuestAccept(Player* player, Item* item, Quest const* quest) ASSERT(item); ASSERT(quest); +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + if (e->OnQuestAccept(player, item, quest)) + return false; +#endif + GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false); player->PlayerTalkClass->ClearMenus(); return tmpscript->OnQuestAccept(player, item, quest); @@ -1671,6 +1738,12 @@ bool ScriptMgr::OnItemUse(Player* player, Item* item, SpellCastTargets const& ta ASSERT(player); ASSERT(item); +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + if (!e->OnUse(player, item, targets)) + return true; +#endif + GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false); return tmpscript->OnUse(player, item, targets, castId); } @@ -1680,6 +1753,12 @@ bool ScriptMgr::OnItemExpire(Player* player, ItemTemplate const* proto) ASSERT(player); ASSERT(proto); +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + if (e->OnExpire(player, proto)) + return false; +#endif + GET_SCRIPT_RET(ItemScript, proto->ScriptId, tmpscript, false); return tmpscript->OnExpire(player, proto); } @@ -1689,6 +1768,12 @@ bool ScriptMgr::OnItemRemove(Player* player, Item* item) ASSERT(player); ASSERT(item); +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + if (e->OnRemove(player, item)) + return false; +#endif + GET_SCRIPT_RET(ItemScript, item->GetScriptId(), tmpscript, false); return tmpscript->OnRemove(player, item); } @@ -1704,6 +1789,34 @@ bool ScriptMgr::OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo co return tmpscript->OnCastItemCombatSpell(player, victim, spellInfo, item); } +void ScriptMgr::OnGossipSelect(Player* player, Item* item, uint32 sender, uint32 action) +{ + ASSERT(player); + ASSERT(item); + +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->HandleGossipSelectOption(player, item, sender, action, ""); +#endif + + GET_SCRIPT(ItemScript, item->GetScriptId(), tmpscript); + tmpscript->OnGossipSelect(player, item, sender, action); +} + +void ScriptMgr::OnGossipSelectCode(Player* player, Item* item, uint32 sender, uint32 action, const char* code) +{ + ASSERT(player); + ASSERT(item); + +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->HandleGossipSelectOption(player, item, sender, action, code); +#endif + + GET_SCRIPT(ItemScript, item->GetScriptId(), tmpscript); + tmpscript->OnGossipSelectCode(player, item, sender, action, code); +} + bool ScriptMgr::CanCreateCreatureAI(uint32 scriptId) const { return !!ScriptRegistry::Instance()->GetScriptById(scriptId); @@ -1713,6 +1826,12 @@ CreatureAI* ScriptMgr::GetCreatureAI(Creature* creature) { ASSERT(creature); +#ifndef ELUNA + if (Eluna* e = creature->GetEluna()) + if (CreatureAI* luaAI = e->GetAI(creature)) + return luaAI; +#endif + GET_SCRIPT_RET(CreatureScript, creature->GetScriptId(), tmpscript, nullptr); return tmpscript->GetAI(creature); } @@ -1726,6 +1845,11 @@ GameObjectAI* ScriptMgr::GetGameObjectAI(GameObject* gameobject) { ASSERT(gameobject); + +/*#ifdef ELUNA + sEluna->OnSpawn(gameobject); +#endif*/ + GET_SCRIPT_RET(GameObjectScript, gameobject->GetScriptId(), tmpscript, nullptr); return tmpscript->GetAI(gameobject); } @@ -1748,6 +1872,12 @@ bool ScriptMgr::OnAreaTrigger(Player* player, AreaTriggerEntry const* trigger, b ASSERT(player); ASSERT(trigger); +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + if (e->OnAreaTrigger(player, trigger)) + return false; +#endif + GET_SCRIPT_RET(AreaTriggerScript, sObjectMgr->GetAreaTriggerScriptId(trigger->ID), tmpscript, false); return entered ? tmpscript->OnTrigger(player, trigger) : tmpscript->OnExit(player, trigger); } @@ -1781,6 +1911,11 @@ void ScriptMgr::OnWeatherChange(Weather* weather, WeatherState state, float grad { ASSERT(weather); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnChange(weather, weather->GetZone(), state, grade); +#endif + GET_SCRIPT(WeatherScript, weather->GetScriptId(), tmpscript); tmpscript->OnChange(weather, state, grade); } @@ -1798,6 +1933,10 @@ void ScriptMgr::OnAuctionAdd(AuctionHouseObject* ah, AuctionPosting* auction) ASSERT(ah); ASSERT(auction); +#ifdef ELUNA + //sEluna->OnAdd(ah, auction); +#endif + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionAdd(ah, auction); } @@ -1806,6 +1945,10 @@ void ScriptMgr::OnAuctionRemove(AuctionHouseObject* ah, AuctionPosting* auction) ASSERT(ah); ASSERT(auction); +#ifdef ELUNA + //sEluna->OnRemove(ah, auction); +#endif + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionRemove(ah, auction); } @@ -1814,6 +1957,10 @@ void ScriptMgr::OnAuctionSuccessful(AuctionHouseObject* ah, AuctionPosting* auct ASSERT(ah); ASSERT(auction); +#ifdef ELUNA + //sEluna->OnSuccessful(ah, entry); +#endif + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionSuccessful(ah, auction); } @@ -1822,6 +1969,10 @@ void ScriptMgr::OnAuctionExpire(AuctionHouseObject* ah, AuctionPosting* auction) ASSERT(ah); ASSERT(auction); +#ifdef ELUNA + //sEluna->OnExpire(ah, entry); +#endif + FOREACH_SCRIPT(AuctionHouseScript)->OnAuctionExpire(ah, auction); } @@ -1838,6 +1989,11 @@ void ScriptMgr::OnInstall(Vehicle* veh) ASSERT(veh); ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT); +#ifdef ELUNA + if (Eluna* e = veh->GetBase()->GetEluna()) + e->OnInstall(veh); +#endif + GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript); tmpscript->OnInstall(veh); } @@ -1847,6 +2003,11 @@ void ScriptMgr::OnUninstall(Vehicle* veh) ASSERT(veh); ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT); +#ifdef ELUNA + if (Eluna* e = veh->GetBase()->GetEluna()) + e->OnUninstall(veh); +#endif + GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript); tmpscript->OnUninstall(veh); } @@ -1866,6 +2027,11 @@ void ScriptMgr::OnInstallAccessory(Vehicle* veh, Creature* accessory) ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT); ASSERT(accessory); +#ifdef ELUNA + if (Eluna* e = veh->GetBase()->GetEluna()) + e->OnInstallAccessory(veh, accessory); +#endif + GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript); tmpscript->OnInstallAccessory(veh, accessory); } @@ -1876,6 +2042,11 @@ void ScriptMgr::OnAddPassenger(Vehicle* veh, Unit* passenger, int8 seatId) ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT); ASSERT(passenger); +#ifdef ELUNA + if (Eluna* e = veh->GetBase()->GetEluna()) + e->OnAddPassenger(veh, passenger, seatId); +#endif + GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript); tmpscript->OnAddPassenger(veh, passenger, seatId); } @@ -1886,6 +2057,11 @@ void ScriptMgr::OnRemovePassenger(Vehicle* veh, Unit* passenger) ASSERT(veh->GetBase()->GetTypeId() == TYPEID_UNIT); ASSERT(passenger); +#ifdef ELUNA + if (Eluna* e = veh->GetBase()->GetEluna()) + e->OnRemovePassenger(veh, passenger); +#endif + GET_SCRIPT(VehicleScript, veh->GetBase()->ToCreature()->GetScriptId(), tmpscript); tmpscript->OnRemovePassenger(veh, passenger); } @@ -1941,11 +2117,19 @@ void ScriptMgr::OnRelocate(Transport* transport, uint32 mapId, float x, float y, void ScriptMgr::OnStartup() { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnStartup(); +#endif FOREACH_SCRIPT(WorldScript)->OnStartup(); } void ScriptMgr::OnShutdown() { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnShutdown(); +#endif FOREACH_SCRIPT(WorldScript)->OnShutdown(); } @@ -1971,36 +2155,64 @@ bool ScriptMgr::OnCriteriaCheck(uint32 scriptId, Player* source, Unit* target) // Player void ScriptMgr::OnPVPKill(Player* killer, Player* killed) { +#ifdef ELUNA + if (Eluna* e = killer->GetEluna()) + e->OnPVPKill(killer, killed); +#endif FOREACH_SCRIPT(PlayerScript)->OnPVPKill(killer, killed); } void ScriptMgr::OnCreatureKill(Player* killer, Creature* killed) { +#ifdef ELUNA + if (Eluna* e = killer->GetEluna()) + e->OnCreatureKill(killer, killed); +#endif FOREACH_SCRIPT(PlayerScript)->OnCreatureKill(killer, killed); } void ScriptMgr::OnPlayerKilledByCreature(Creature* killer, Player* killed) { +#ifdef ELUNA + if (Eluna* e = killer->GetEluna()) + e->OnPlayerKilledByCreature(killer, killed); +#endif FOREACH_SCRIPT(PlayerScript)->OnPlayerKilledByCreature(killer, killed); } void ScriptMgr::OnPlayerLevelChanged(Player* player, uint8 oldLevel) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnLevelChanged(player, oldLevel); +#endif FOREACH_SCRIPT(PlayerScript)->OnLevelChanged(player, oldLevel); } void ScriptMgr::OnPlayerFreeTalentPointsChanged(Player* player, uint32 points) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnFreeTalentPointsChanged(player, points); +#endif FOREACH_SCRIPT(PlayerScript)->OnFreeTalentPointsChanged(player, points); } void ScriptMgr::OnPlayerTalentsReset(Player* player, bool noCost) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnTalentsReset(player, noCost); +#endif FOREACH_SCRIPT(PlayerScript)->OnTalentsReset(player, noCost); } void ScriptMgr::OnPlayerMoneyChanged(Player* player, int64& amount) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnMoneyChanged(player, amount); +#endif FOREACH_SCRIPT(PlayerScript)->OnMoneyChanged(player, amount); } @@ -2011,26 +2223,46 @@ void ScriptMgr::OnPlayerMoneyLimit(Player* player, int64 amount) void ScriptMgr::OnGivePlayerXP(Player* player, uint32& amount, Unit* victim) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnGiveXP(player, amount, victim); +#endif FOREACH_SCRIPT(PlayerScript)->OnGiveXP(player, amount, victim); } void ScriptMgr::OnPlayerReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnReputationChange(player, factionID, standing, incremental); +#endif FOREACH_SCRIPT(PlayerScript)->OnReputationChange(player, factionID, standing, incremental); } void ScriptMgr::OnPlayerDuelRequest(Player* target, Player* challenger) { +#ifdef ELUNA + if (Eluna* e = target->GetEluna()) + e->OnDuelRequest(target, challenger); +#endif FOREACH_SCRIPT(PlayerScript)->OnDuelRequest(target, challenger); } void ScriptMgr::OnPlayerDuelStart(Player* player1, Player* player2) { +#ifdef ELUNA + if (Eluna* e = player1->GetEluna()) + e->OnDuelStart(player1, player2); +#endif FOREACH_SCRIPT(PlayerScript)->OnDuelStart(player1, player2); } void ScriptMgr::OnPlayerDuelEnd(Player* winner, Player* loser, DuelCompleteType type) { +#ifdef ELUNA + if (Eluna* e = winner->GetEluna()) + e->OnDuelEnd(winner, loser, type); +#endif FOREACH_SCRIPT(PlayerScript)->OnDuelEnd(winner, loser, type); } @@ -2066,31 +2298,60 @@ void ScriptMgr::OnPlayerClearEmote(Player* player) void ScriptMgr::OnPlayerTextEmote(Player* player, uint32 textEmote, uint32 emoteNum, ObjectGuid guid) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnTextEmote(player, textEmote, emoteNum, guid); +#endif FOREACH_SCRIPT(PlayerScript)->OnTextEmote(player, textEmote, emoteNum, guid); } void ScriptMgr::OnPlayerSpellCast(Player* player, Spell* spell, bool skipCheck) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnSpellCast(player, spell, skipCheck); +#endif FOREACH_SCRIPT(PlayerScript)->OnSpellCast(player, spell, skipCheck); } void ScriptMgr::OnPlayerLogin(Player* player, bool firstLogin) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + { + if (firstLogin) + e->OnFirstLogin(player); + + e->OnLogin(player); + } +#endif FOREACH_SCRIPT(PlayerScript)->OnLogin(player, firstLogin); } void ScriptMgr::OnPlayerLogout(Player* player) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnLogout(player); +#endif FOREACH_SCRIPT(PlayerScript)->OnLogout(player); } void ScriptMgr::OnPlayerCreate(Player* player) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnCreate(player); +#endif FOREACH_SCRIPT(PlayerScript)->OnCreate(player); } void ScriptMgr::OnPlayerDelete(ObjectGuid guid, uint32 accountId) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnDelete(GUID_LOPART(guid)); +#endif FOREACH_SCRIPT(PlayerScript)->OnDelete(guid, accountId); } @@ -2101,19 +2362,49 @@ void ScriptMgr::OnPlayerFailedDelete(ObjectGuid guid, uint32 accountId) void ScriptMgr::OnPlayerSave(Player* player) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnSave(player); +#endif FOREACH_SCRIPT(PlayerScript)->OnSave(player); } void ScriptMgr::OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent, uint8 extendState) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnBindToInstance(player, difficulty, mapid, permanent); +#endif FOREACH_SCRIPT(PlayerScript)->OnBindToInstance(player, difficulty, mapid, permanent, extendState); } void ScriptMgr::OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea) { +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->OnUpdateZone(player, newZone, newArea); +#endif FOREACH_SCRIPT(PlayerScript)->OnUpdateZone(player, newZone, newArea); } +void ScriptMgr::OnGossipSelect(Player* player, uint32 menu_id, uint32 sender, uint32 action) +{ +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->HandleGossipSelectOption(player, menu_id, sender, action, ""); +#endif + FOREACH_SCRIPT(PlayerScript)->OnGossipSelect(player, menu_id, sender, action); +} + +void ScriptMgr::OnGossipSelectCode(Player* player, uint32 menu_id, uint32 sender, uint32 action, const char* code) +{ +#ifdef ELUNA + if (Eluna* e = player->GetEluna()) + e->HandleGossipSelectOption(player, menu_id, sender, action, code); +#endif + FOREACH_SCRIPT(PlayerScript)->OnGossipSelectCode(player, menu_id, sender, action, code); +} + void ScriptMgr::OnQuestStatusChange(Player* player, uint32 questId) { FOREACH_SCRIPT(PlayerScript)->OnQuestStatusChange(player, questId); @@ -2168,57 +2459,101 @@ void ScriptMgr::OnFailedPasswordChange(uint32 accountId) // Guild void ScriptMgr::OnGuildAddMember(Guild* guild, Player* player, uint8 plRank) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnAddMember(guild, player, plRank); +#endif FOREACH_SCRIPT(GuildScript)->OnAddMember(guild, player, plRank); } void ScriptMgr::OnGuildRemoveMember(Guild* guild, ObjectGuid guid, bool isDisbanding, bool isKicked) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnRemoveMember(guild, guid, isDisbanding); +#endif FOREACH_SCRIPT(GuildScript)->OnRemoveMember(guild, guid, isDisbanding, isKicked); } void ScriptMgr::OnGuildMOTDChanged(Guild* guild, const std::string& newMotd) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnMOTDChanged(guild, newMotd); +#endif FOREACH_SCRIPT(GuildScript)->OnMOTDChanged(guild, newMotd); } void ScriptMgr::OnGuildInfoChanged(Guild* guild, const std::string& newInfo) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnInfoChanged(guild, newInfo); +#endif FOREACH_SCRIPT(GuildScript)->OnInfoChanged(guild, newInfo); } void ScriptMgr::OnGuildCreate(Guild* guild, Player* leader, const std::string& name) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnCreate(guild, leader, name); +#endif FOREACH_SCRIPT(GuildScript)->OnCreate(guild, leader, name); } void ScriptMgr::OnGuildDisband(Guild* guild) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnDisband(guild); +#endif FOREACH_SCRIPT(GuildScript)->OnDisband(guild); } void ScriptMgr::OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint64 &amount, bool isRepair) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnMemberWitdrawMoney(guild, player, amount, isRepair); +#endif FOREACH_SCRIPT(GuildScript)->OnMemberWitdrawMoney(guild, player, amount, isRepair); } void ScriptMgr::OnGuildMemberDepositMoney(Guild* guild, Player* player, uint64 &amount) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnMemberDepositMoney(guild, player, amount); +#endif FOREACH_SCRIPT(GuildScript)->OnMemberDepositMoney(guild, player, amount); } void ScriptMgr::OnGuildItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, bool isDestBank, uint8 destContainer, uint8 destSlotId) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnItemMove(guild, player, pItem, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId); +#endif FOREACH_SCRIPT(GuildScript)->OnItemMove(guild, player, pItem, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId); } void ScriptMgr::OnGuildEvent(Guild* guild, uint8 eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnEvent(guild, eventType, playerGuid1, playerGuid2, newRank); +#endif FOREACH_SCRIPT(GuildScript)->OnEvent(guild, eventType, playerGuid1, playerGuid2, newRank); } void ScriptMgr::OnGuildBankEvent(Guild* guild, uint8 eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint64 itemOrMoney, uint16 itemStackCount, uint8 destTabId) { +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnBankEvent(guild, eventType, tabId, playerGuid, itemOrMoney, itemStackCount, destTabId); +#endif FOREACH_SCRIPT(GuildScript)->OnBankEvent(guild, eventType, tabId, playerGuid, itemOrMoney, itemStackCount, destTabId); } @@ -2226,30 +2561,50 @@ void ScriptMgr::OnGuildBankEvent(Guild* guild, uint8 eventType, uint8 tabId, Obj void ScriptMgr::OnGroupAddMember(Group* group, ObjectGuid guid) { ASSERT(group); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnAddMember(group, guid); +#endif FOREACH_SCRIPT(GroupScript)->OnAddMember(group, guid); } void ScriptMgr::OnGroupInviteMember(Group* group, ObjectGuid guid) { ASSERT(group); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnInviteMember(group, guid); +#endif FOREACH_SCRIPT(GroupScript)->OnInviteMember(group, guid); } void ScriptMgr::OnGroupRemoveMember(Group* group, ObjectGuid guid, RemoveMethod method, ObjectGuid kicker, char const* reason) { ASSERT(group); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnRemoveMember(group, guid, method); +#endif FOREACH_SCRIPT(GroupScript)->OnRemoveMember(group, guid, method, kicker, reason); } void ScriptMgr::OnGroupChangeLeader(Group* group, ObjectGuid newLeaderGuid, ObjectGuid oldLeaderGuid) { ASSERT(group); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnChangeLeader(group, newLeaderGuid, oldLeaderGuid); +#endif FOREACH_SCRIPT(GroupScript)->OnChangeLeader(group, newLeaderGuid, oldLeaderGuid); } void ScriptMgr::OnGroupDisband(Group* group) { ASSERT(group); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + e->OnDisband(group); +#endif FOREACH_SCRIPT(GroupScript)->OnDisband(group); } diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 31a5842a383d3..b4b1ecc1e2544 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -402,6 +402,12 @@ class TC_GAME_API ItemScript : public ScriptObject // Called before casting a combat spell from this item (chance on hit spells of item template, can be used to prevent cast if returning false) virtual bool OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo const* spellInfo, Item* item); + + // Called when a player selects an option in an item gossip window + virtual void OnGossipSelect(Player* /*player*/, Item* /*item*/, uint32 /*sender*/, uint32 /*action*/) { } + + // Called when a player selects an option in an item gossip window + virtual void OnGossipSelectCode(Player* /*player*/, Item* /*item*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) { } }; class TC_GAME_API UnitScript : public ScriptObject @@ -776,6 +782,12 @@ class TC_GAME_API PlayerScript : public ScriptObject // Called when a player changes to a new map (after moving to new map) virtual void OnMapChanged(Player* player); + // Called when a player selects an option in a player gossip window + virtual void OnGossipSelect(Player* /*player*/, uint32 /*menu_id*/, uint32 /*sender*/, uint32 /*action*/) { } + + // Called when a player selects an option in a player gossip window + virtual void OnGossipSelectCode(Player* /*player*/, uint32 /*menu_id*/, uint32 /*sender*/, uint32 /*action*/, const char* /*code*/) { } + // Called after a player's quest status has been changed virtual void OnQuestStatusChange(Player* player, uint32 questId); @@ -1120,6 +1132,8 @@ class TC_GAME_API ScriptMgr bool OnItemExpire(Player* player, ItemTemplate const* proto); bool OnItemRemove(Player* player, Item* item); bool OnCastItemCombatSpell(Player* player, Unit* victim, SpellInfo const* spellInfo, Item* item); + void OnGossipSelect(Player* player, Item* item, uint32 sender, uint32 action); + void OnGossipSelectCode(Player* player, Item* item, uint32 sender, uint32 action, const char* code); public: /* CreatureScript */ @@ -1227,6 +1241,8 @@ class TC_GAME_API ScriptMgr void OnPlayerSave(Player* player); void OnPlayerBindToInstance(Player* player, Difficulty difficulty, uint32 mapid, bool permanent, uint8 extendState); void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea); + void OnGossipSelect(Player* player, uint32 menu_id, uint32 sender, uint32 action); + void OnGossipSelectCode(Player* player, uint32 menu_id, uint32 sender, uint32 action, const char* code); void OnQuestStatusChange(Player* player, uint32 questId); void OnPlayerRepop(Player* player); void OnMovieComplete(Player* player, uint32 movieId); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index b55b64a877410..1ab48a16d88f3 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -54,6 +54,9 @@ #include "World.h" #include "WorldSocket.h" #include +#ifdef ELUNA +#include "LuaEngine.h" +#endif namespace { @@ -292,6 +295,17 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/ sScriptMgr->OnPacketSend(this, *packet); +#ifdef ELUNA + if (Player* plr = GetPlayer()) + { + if (Eluna* e = plr->GetEluna()) + { + if (!e->OnPacketSend(this, *packet)) + return; + } + } +#endif + TC_LOG_TRACE("network.opcode", "S->C: {} {}", GetPlayerInfo(), GetOpcodeNameForLogging(static_cast(packet->GetOpcode()))); m_Socket[conIdx]->SendPacket(*packet); } @@ -369,6 +383,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if(AntiDOS.EvaluateOpcode(*packet, currentTime)) { sScriptMgr->OnPacketReceive(this, *packet); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnPacketReceive(this, *packet)) + break; +#endif opHandle->Call(this, *packet); } else @@ -384,6 +403,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) { // not expected _player or must checked in packet hanlder sScriptMgr->OnPacketReceive(this, *packet); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnPacketReceive(this, *packet)) + break; +#endif opHandle->Call(this, *packet); } else @@ -397,6 +421,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) else if (AntiDOS.EvaluateOpcode(*packet, currentTime)) { sScriptMgr->OnPacketReceive(this, *packet); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnPacketReceive(this, *packet)) + break; +#endif opHandle->Call(this, *packet); } else @@ -418,6 +447,11 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) if (AntiDOS.EvaluateOpcode(*packet, currentTime)) { sScriptMgr->OnPacketReceive(this, *packet); +#ifdef ELUNA + if (Eluna* e = sWorld->GetEluna()) + if (!e->OnPacketReceive(this, *packet)) + break; +#endif opHandle->Call(this, *packet); } else diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 2bdde59e956ab..df3c14a4ebc7d 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -37,6 +37,9 @@ #include "WorldPacket.h" #include "WorldSession.h" #include +#ifdef ELUNA +#include "LuaEngine.h" +#endif #pragma pack(push, 1) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index c74646f42c0b8..595946dd05f76 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -85,6 +85,9 @@ #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" +#ifdef ELUNA +#include "LuaEngine.h" +#endif NonDefaultConstructible SpellEffectHandlers[TOTAL_SPELL_EFFECTS] = { @@ -592,6 +595,17 @@ void Spell::EffectDummy() // normal DB scripted effect TC_LOG_DEBUG("spells", "Spell ScriptStart spellid {} in EffectDummy({})", m_spellInfo->Id, effectInfo->EffectIndex); m_caster->GetMap()->ScriptsStart(sSpellScripts, uint32(m_spellInfo->Id | (effectInfo->EffectIndex << 24)), m_caster, unitTarget); +#ifdef ELUNA + if (Eluna* e = m_caster->GetEluna()) + { + if (gameObjTarget) + e->OnDummyEffect(m_caster, m_spellInfo->Id, effectInfo->EffectIndex, gameObjTarget); + //else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT) + //e->OnDummyEffect(m_caster, m_spellInfo->Id, effectInfo->EffectIndex, unitTarget->ToCreature()); + else if (itemTarget) + e->OnDummyEffect(m_caster, m_spellInfo->Id, effectInfo->EffectIndex, itemTarget); + } +#endif } void Spell::EffectTriggerSpell() diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 2ec553204c7f5..537173fde7d26 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -106,6 +106,11 @@ #include "WorldSession.h" #include "WorldSocket.h" #include "WorldStateMgr.h" +#ifdef ELUNA +#include "LuaEngine.h" +#include "ElunaLoader.h" +#include "ElunaConfig.h" +#endif #include @@ -1776,6 +1781,24 @@ bool World::SetInitialWorldSettings() return false; } +#ifdef ELUNA + ///- Initialize Lua Engine + TC_LOG_INFO("server.loading", "Loading Eluna config..."); + sElunaConfig->Initialize(); + + ///- Initialize Lua Engine + if (sElunaConfig->IsElunaEnabled()) + { + TC_LOG_INFO("server.loading", "Loading Lua scripts..."); + sElunaLoader->LoadScripts(); + + if (sElunaConfig->GetConfig(CONFIG_ELUNA_SCRIPT_RELOADER)) + { + TC_LOG_INFO("server.loading", "Loading Eluna script reloader..."); + sElunaLoader->InitializeFileWatcher(); + } + } +#endif ///- Initialize pool manager sPoolMgr->Initialize(); @@ -2401,6 +2424,14 @@ bool World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading creature StaticFlags overrides..."); sObjectMgr->LoadCreatureStaticFlagsOverride(); // must be after LoadCreatures +#ifdef ELUNA + if (sElunaConfig->IsElunaEnabled()) + { + TC_LOG_INFO("server.loading", "Starting Eluna world state..."); + eluna = new Eluna(nullptr, sElunaConfig->IsElunaCompatibilityMode()); + } +#endif + TC_LOG_INFO("server.loading", "Initializing Scripts..."); sScriptMgr->Initialize(); sScriptMgr->OnConfigLoad(false); // must be done after the ScriptMgr has been properly initialized @@ -2560,6 +2591,11 @@ bool World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading phase names..."); sObjectMgr->LoadPhaseNames(); +#ifdef ELUNA + if (GetEluna()) + GetEluna()->OnConfigLoad(false); // Must be done after Eluna is initialized and scripts have run. +#endif + uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); TC_LOG_INFO("server.worldserver", "World initialized in {} minutes {} seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000)); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 56892b85884ea..2e4c2ae73f115 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -38,6 +38,9 @@ #include #include +#ifdef ELUNA +class Eluna; +#endif class Player; class WorldPacket; class WorldSession; @@ -794,6 +797,10 @@ class TC_GAME_API World void SetForcedWarModeFactionBalanceState(TeamId team, int32 reward = 0); void DisableForcedWarModeFactionBalanceState(); +#ifdef ELUNA + Eluna* GetEluna() const { return eluna; } + Eluna* eluna; +#endif protected: void _UpdateGameTime(); diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h index 362155552b2bc..d390083b161a0 100644 --- a/src/server/shared/DataStores/DB2Store.h +++ b/src/server/shared/DataStores/DB2Store.h @@ -22,6 +22,7 @@ #include "Errors.h" #include "DBStorageIterator.h" #include +#include class ByteBuffer; struct DB2LoadInfo; @@ -85,6 +86,27 @@ class DB2Storage : public DB2StorageBase iterator begin() const { return iterator(reinterpret_cast(_indexTable), _indexTableSize, _minId); } iterator end() const { return iterator(reinterpret_cast(_indexTable), _indexTableSize, _indexTableSize); } +/* +#ifdef ELUNA + void SetEntry(uint32 id, T* t) + { + if (id >= _indexTableSize) + { + // Resize + typedef char* ptr; + size_t newSize = id + 1; + ptr* newArr = new ptr[newSize]; + memset(newArr, 0, newSize * sizeof(ptr)); + memcpy(newArr, _indexTable.AsChar, _indexTableSize * sizeof(ptr)); + delete[] reinterpret_cast(_indexTable.AsT); + _indexTable.AsChar = newArr; + _indexTableSize = newSize; + } + + delete _indexTable.AsT[id]; + _indexTable.AsT[id] = t; + } +#endif*/ }; #endif diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index ca7a869ba1635..efdc080108dd5 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -91,4 +91,4 @@ endif() # Generate precompiled header if(USE_COREPCH) add_cxx_pch(worldserver ${PRIVATE_PCH_HEADER}) -endif() +endif() \ No newline at end of file diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 27c6592412848..db8cc01c5535c 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -36,6 +36,7 @@ # AUCTION HOUSE BOT ITEM FINE TUNING # AUCTION HOUSE BOT BUYER CONFIG # BLACK MARKET SETTINGS +# ELUNA SETTINGS # LOGGING SYSTEM SETTINGS # CURRENCIES SETTINGS # PACKET SPOOF PROTECTION SETTINGS @@ -4089,6 +4090,70 @@ BlackMarket.UpdatePeriod = 24 # ################################################################################################### +################################################################################################### +# ELUNA SETTINGS +# +# Eluna.Enabled +# Description: Enable or disable Eluna LuaEngine +# Default: true - (enabled) +# false - (disabled) +# +# Eluna.CompatibilityMode +# Description: Toggles Eluna between compatibility mode (single-threaded) or multistate mode. +# Compatibility mode limits the core to a single map update thread. +# Default: true - (enabled) +# false - (disabled) +# +# Eluna.ScriptReloader +# Description: Enable or disable the automated script reloader. +# This will automatically reload Eluna when it detects changes to scripts. +# Default: false - (disabled) +# true - (enabled) +# +# Eluna.OnlyOnMaps +# Description: When Eluna is enabled, a state will only be created for a list of specified maps +# This only works for multistate mode. +# Default: "" - (enabled on all maps) +# "0,1,2,..." - (enabled on specific maps only) +# +# Eluna.TraceBack +# Description: Sets whether to use debug.traceback function on a lua error or not. +# Notice that you can redefine the function. +# Default: false - (use default error output) +# true - (use debug.traceback function) +# +# Eluna.ScriptPath +# Description: Sets the location of the script folder to load scripts from +# The path can be relative or absolute. +# Default: "lua_scripts" +# +# Eluna.RequirePaths +# Description: Sets the location of additional require paths. +# These paths are absolute and follows the standard Lua require path patterns. +# Below are a set of "standard" paths used by most package managers. +# "/usr/share/%s/?.lua;/usr/local/share/lua/%s/?.lua;/usr/local/share/lua/%s/?/init.lua;/usr/share/lua/%s/?.lua;/usr/share/lua/%s/?/init.lua;" +# Default: "" +# +# Eluna.RequireCPaths +# Description: Sets the location of additional require C paths. +# These paths are absolute and follows the standard Lua require path patterns. +# Below are a set of "standard" paths used by most package managers. +# "/usr/local/lib/lua/%s/?.so;/usr/lib/x86_64-linux-gnu/lua/%s/?.so;/usr/local/lib/lua/%s/loadall.so;" +# Default: "" +# + +Eluna.Enabled = true +Eluna.CompatibilityMode = false +Eluna.ScriptReloader = false +Eluna.OnlyOnMaps = "" +Eluna.TraceBack = false +Eluna.ScriptPath = "lua_scripts" +Eluna.RequirePaths = "" +Eluna.RequireCPaths = "" + +# +################################################################################################### + ################################################################################################### # LOGGING SYSTEM SETTINGS # @@ -4160,6 +4225,7 @@ Appender.Console=1,3,0 Appender.Server=2,2,0,Server.log,w Appender.GM=2,2,1,GM.log Appender.DBErrors=2,2,0,DBErrors.log +Appender.Eluna=2,5,3,Eluna.log,a # Logger config values: Given a logger "name" # Logger.name @@ -4186,6 +4252,7 @@ Logger.scripts.hotswap=3,Console Server Logger.sql.sql=5,Console DBErrors Logger.sql.updates=3,Console Server Logger.mmaps=3,Server +Logger.eluna=1,Console Eluna #Logger.addon=3,Console Server #Logger.ahbot=3,Console Server