diff --git a/.gitignore b/.gitignore
index ca87c0fcc7..551ae1d8be 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,12 @@ nbproject/*
cmake-build-*/*
.vs
*.user
+
+# acore modules
+.aider*
+/modules/*
+!/modules/*.md
+!/modules/*.sh
+!/modules/CMakeLists.txt
+!/modules/*.h
+!/modules/*.cmake
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cc306ab0ce..6400fced22 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,3 +104,38 @@ if(BUILD_TESTING)
set_property(GLOBAL PROPERTY USE_FOLDERS OFF)
endif()
endif()
+
+#
+# Loading dyn modules
+#
+
+# some utils for cmake
+include(dep/acore/cmake-utils/utils.cmake)
+include(ConfigureModules)
+include(ConfigInstall)
+
+# add modules and dependencies from AzerothCore
+CU_SUBDIRLIST(sub_DIRS "${CMAKE_SOURCE_DIR}/modules" FALSE FALSE)
+message(STATUS "Checking for modules")
+FOREACH(subdir ${sub_DIRS})
+ message(STATUS "Checking module: ${subdir}")
+ get_filename_component(MODULENAME ${subdir} NAME)
+
+ if (";${DISABLED_AC_MODULES};" MATCHES ";${MODULENAME};")
+ continue()
+ endif()
+
+ STRING(REPLACE "${CMAKE_SOURCE_DIR}/" "" subdir_rel ${subdir})
+ if(EXISTS "${subdir}/CMakeLists.txt")
+ message(STATUS "Adding module: ${MODULENAME}")
+ add_subdirectory("${subdir_rel}")
+ else()
+ message(STATUS "Skipping moduole ${MODULENAME}, no CMAKE file.")
+ endif()
+ENDFOREACH()
+
+if (SERVERS)
+ # add modules sources
+ add_subdirectory(modules)
+endif()
+
diff --git a/cmake/macros/ConfigInstall.cmake b/cmake/macros/ConfigInstall.cmake
new file mode 100644
index 0000000000..090e3dba2c
--- /dev/null
+++ b/cmake/macros/ConfigInstall.cmake
@@ -0,0 +1,106 @@
+#
+# This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+
+#
+# Use it like:
+# CopyApplicationConfig(${APP_PROJECT_NAME} ${APPLICATION_NAME})
+#
+
+function(CopyApplicationConfig projectName appName)
+ GetPathToApplication(${appName} SOURCE_APP_PATH)
+
+ if(WIN32)
+ if("${CMAKE_MAKE_PROGRAM}" MATCHES "MSBuild")
+ add_custom_command(TARGET ${projectName}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/configs")
+ add_custom_command(TARGET ${projectName}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${SOURCE_APP_PATH}/${appName}.conf.dist" "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/configs")
+ elseif(MINGW)
+ add_custom_command(TARGET ${servertype}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/configs")
+ add_custom_command(TARGET ${servertype}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${SOURCE_APP_PATH}/${appName}.conf.dist ${CMAKE_BINARY_DIR}/bin/configs")
+ endif()
+ endif()
+
+ if(UNIX)
+ install(FILES "${SOURCE_APP_PATH}/${appName}.conf.dist" DESTINATION "${CONF_DIR}")
+ elseif(WIN32)
+ install(FILES "${SOURCE_APP_PATH}/${appName}.conf.dist" DESTINATION "${CMAKE_INSTALL_PREFIX}/configs")
+ endif()
+endfunction()
+
+function(CopyToolConfig projectName appName)
+ GetPathToTool(${appName} SOURCE_APP_PATH)
+
+ if(WIN32)
+ if("${CMAKE_MAKE_PROGRAM}" MATCHES "MSBuild")
+ add_custom_command(TARGET ${projectName}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/configs")
+ add_custom_command(TARGET ${projectName}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${SOURCE_APP_PATH}/${appName}.conf.dist" "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/configs")
+ elseif(MINGW)
+ add_custom_command(TARGET ${servertype}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/configs")
+ add_custom_command(TARGET ${servertype}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${SOURCE_APP_PATH}/${appName}.conf.dist ${CMAKE_BINARY_DIR}/bin/configs")
+ endif()
+ endif()
+
+ if(UNIX)
+ install(FILES "${SOURCE_APP_PATH}/${appName}.conf.dist" DESTINATION "${CONF_DIR}")
+ elseif(WIN32)
+ install(FILES "${SOURCE_APP_PATH}/${appName}.conf.dist" DESTINATION "${CMAKE_INSTALL_PREFIX}/configs")
+ endif()
+endfunction()
+
+#
+# Use it like:
+# CopyModuleConfig("acore.conf.dist")
+#
+
+function(CopyModuleConfig configDir)
+ set(postPath "configs/modules")
+
+ if(WIN32)
+ if("${CMAKE_MAKE_PROGRAM}" MATCHES "MSBuild")
+ add_custom_command(TARGET modules
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/${postPath}")
+ add_custom_command(TARGET modules
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${configDir}" "${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/${postPath}")
+ elseif(MINGW)
+ add_custom_command(TARGET modules
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/${postPath}")
+ add_custom_command(TARGET modules
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy "${configDir} ${CMAKE_BINARY_DIR}/bin/${postPath}")
+ endif()
+ endif()
+
+ if(UNIX)
+ install(FILES "${configDir}" DESTINATION "${CONF_DIR}/modules")
+ elseif(WIN32)
+ install(FILES "${configDir}" DESTINATION "${CMAKE_INSTALL_PREFIX}/${postPath}")
+ endif()
+ unset(postPath)
+endfunction()
diff --git a/cmake/macros/ConfigureModules.cmake b/cmake/macros/ConfigureModules.cmake
new file mode 100644
index 0000000000..8a21fa1c80
--- /dev/null
+++ b/cmake/macros/ConfigureModules.cmake
@@ -0,0 +1,73 @@
+#
+# This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+
+# Returns the base path to the script directory in the source directory
+function(GetModulesBasePath variable)
+ set(${variable} "${CMAKE_SOURCE_DIR}/modules" PARENT_SCOPE)
+endfunction()
+
+# Stores the absolut path of the given module in the variable
+function(GetPathToModuleSource module variable)
+ GetModulesBasePath(MODULE_BASE_PATH)
+ set(${variable} "${MODULE_BASE_PATH}/${module}/src" PARENT_SCOPE)
+endfunction()
+
+# Stores the project name of the given module in the variable
+function(GetProjectNameOfModuleName module variable)
+ string(TOLOWER "mod_${SOURCE_MODULE}" GENERATED_NAME)
+ set(${variable} "${GENERATED_NAME}" PARENT_SCOPE)
+endfunction()
+
+# Creates a list of all script modules
+# and stores it in the given variable.
+function(GetModuleSourceList variable)
+ GetModulesBasePath(BASE_PATH)
+ file(GLOB LOCALE_MODULE_LIST RELATIVE
+ ${BASE_PATH}
+ ${BASE_PATH}/*)
+
+ set(${variable})
+ foreach(SOURCE_MODULE ${LOCALE_MODULE_LIST})
+ GetPathToModuleSource(${SOURCE_MODULE} MODULE_SOURCE_PATH)
+ if(IS_DIRECTORY ${MODULE_SOURCE_PATH})
+ list(APPEND ${variable} ${SOURCE_MODULE})
+ endif()
+ endforeach()
+ set(${variable} ${${variable}} PARENT_SCOPE)
+endfunction()
+
+# Converts the given script module name into it's
+# variable name which holds the linkage type.
+function(ModuleNameToVariable module variable)
+ string(TOUPPER ${module} ${variable})
+ set(${variable} "MODULE_${${variable}}")
+ set(${variable} ${${variable}} PARENT_SCOPE)
+endfunction()
+
+# Stores in the given variable whether dynamic linking is required
+function(IsDynamicLinkingModulesRequired variable)
+ if(MODULES MATCHES "dynamic")
+ set(IS_DEFAULT_VALUE_DYNAMIC_MODULE ON)
+ endif()
+
+ GetModuleSourceList(MODULES_MODULE_LIST)
+ set(IS_REQUIRED OFF)
+ foreach(SOURCE_MODULE ${MODULES_MODULE_LIST})
+ ModuleNameToVariable(${SOURCE_MODULE} MODULE_MODULE_VARIABLE)
+ if((${MODULE_MODULE_VARIABLE} STREQUAL "dynamic") OR
+ (${MODULE_MODULE_VARIABLE} STREQUAL "default" AND IS_DEFAULT_VALUE_DYNAMIC_MODULE))
+ set(IS_REQUIRED ON)
+ break()
+ endif()
+ endforeach()
+ set(${variable} ${IS_REQUIRED} PARENT_SCOPE)
+endfunction()
diff --git a/cmake/options.cmake b/cmake/options.cmake
index e650123d71..966730efa4 100644
--- a/cmake/options.cmake
+++ b/cmake/options.cmake
@@ -59,3 +59,17 @@ option(BUILD_TESTING "Build test suite" 0)
if(UNIX)
option(USE_LD_GOLD "Use GNU gold linker" 0)
endif()
+
+# stuff for modules
+set(MODULES_AVAILABLE_OPTIONS none static dynamic)
+set(MODULES "static" CACHE STRING "Build core with modules")
+set_property(CACHE MODULES PROPERTY STRINGS ${MODULES_AVAILABLE_OPTIONS})
+
+# Log a error when the value of the MODULES variable isn't a valid option.
+if(MODULES)
+ list(FIND MODULES_AVAILABLE_OPTIONS "${MODULES}" MODULES_INDEX)
+ if(${MODULES_INDEX} EQUAL -1)
+ message(FATAL_ERROR "The value (${MODULES}) of your MODULES variable is invalid! "
+ "Allowed values are: ${MODULES_AVAILABLE_OPTIONS}. Set static")
+ endif()
+endif()
diff --git a/cmake/showoptions.cmake b/cmake/showoptions.cmake
index dea6ef01ed..fe038a3d0f 100644
--- a/cmake/showoptions.cmake
+++ b/cmake/showoptions.cmake
@@ -39,6 +39,12 @@ else()
message("* Build map/vmap tools : No")
endif()
+if (MODULES AND (NOT MODULES STREQUAL "none"))
+ message("* Build with modules : Yes (${MODULES})")
+else()
+ message("* Build with modules : No")
+endif()
+
if(BUILD_TESTING)
message("* Build unit tests : Yes")
else()
diff --git a/dep/acore/cmake-utils/.gitignore b/dep/acore/cmake-utils/.gitignore
new file mode 100644
index 0000000000..92da74b036
--- /dev/null
+++ b/dep/acore/cmake-utils/.gitignore
@@ -0,0 +1,50 @@
+!.gitignore
+
+!*
+
+#
+#Generic
+#
+
+.directory
+.mailmap
+*.orig
+*.rej
+*~
+.hg/
+*.kdev*
+.DS_Store
+CMakeLists.txt.user
+*.bak
+*.patch
+*.diff
+*.REMOTE.*
+*.BACKUP.*
+*.BASE.*
+*.LOCAL.*
+
+#
+# IDE & other softwares
+#
+/.settings/
+/.externalToolBuilders/*
+# exclude in all levels
+nbproject/
+.sync.ffs_db
+*.kate-swp
+
+#
+# Eclipse
+#
+*.pydevproject
+.metadata
+.gradle
+tmp/
+*.tmp
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.project
+.cproject
diff --git a/dep/acore/cmake-utils/.gitrepo b/dep/acore/cmake-utils/.gitrepo
new file mode 100644
index 0000000000..67403e7fa5
--- /dev/null
+++ b/dep/acore/cmake-utils/.gitrepo
@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+ remote = https://github.com/azerothcore/cmake-utils
+ branch = master
+ commit = 1589c53ac61b7909c6950f1d85833441cbd58790
+ method = merge
+ cmdver = 0.4.3
+ parent = ebcbd4e904f835beef8db05c88f2e971c48c2820
diff --git a/dep/acore/cmake-utils/README.md b/dep/acore/cmake-utils/README.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/dep/acore/cmake-utils/utils.cmake b/dep/acore/cmake-utils/utils.cmake
new file mode 100644
index 0000000000..e395530cf0
--- /dev/null
+++ b/dep/acore/cmake-utils/utils.cmake
@@ -0,0 +1,137 @@
+
+#
+# CU_SUBDIRLIST
+#
+FUNCTION(CU_SUBDIRLIST result curdir recursive includeRoot)
+ # glob recurse seem's doesn't work
+ FILE(GLOB children RELATIVE ${curdir} "${curdir}/[^\\.]*")
+ if (${includeRoot})
+ SET(dirlist "${curdir}")
+ else()
+ SET(dirlist "")
+ endif()
+
+ FOREACH(child ${children})
+ IF(IS_DIRECTORY "${curdir}/${child}")
+ if (${recursive})
+ CU_SUBDIRLIST(sub_Dirs "${curdir}/${child}" TRUE FALSE)
+ SET(dirlist "${curdir}/${child}" ${sub_Dirs} ${dirlist})
+ else()
+ SET(dirlist "${curdir}/${child}" ${dirlist})
+ endif()
+ ENDIF()
+ ENDFOREACH()
+ SET(${result} ${dirlist} PARENT_SCOPE)
+ENDFUNCTION(CU_SUBDIRLIST result curdir recursive)
+
+#
+# CU_SET_GLOBAL
+#
+MACRO(CU_SET_GLOBAL name val)
+ set_property ( GLOBAL PROPERTY ${name} ${val})
+ # after set , create the variable for current scope
+ CU_GET_GLOBAL(${name})
+ENDMACRO()
+
+MACRO(CU_ADD_GLOBAL name val)
+ CU_GET_GLOBAL(${name})
+
+ set_property ( GLOBAL PROPERTY ${name}
+ ${${name}}
+ ${val}
+ )
+ # after set , create the variable for current scope
+ CU_GET_GLOBAL(${name})
+ENDMACRO()
+
+#
+# CU_GET_GLOBAL
+#
+MACRO(CU_GET_GLOBAL name)
+ get_property(${name} GLOBAL PROPERTY ${name})
+ENDMACRO()
+
+#
+# CU_SET_CACHE
+#
+MACRO(CU_SET_CACHE name val)
+ set(${name} ${val} CACHE INTERNAL "CU Var")
+ENDMACRO()
+
+#
+# CU_LIST_ADD_CACHE
+#
+MACRO(CU_LIST_ADD_CACHE name val)
+
+ # avoid duplicates
+ if (";${${name}};" MATCHES ";${val};")
+ # nothing to do for now
+ else()
+ set(${name} ${val} ${${name}} CACHE INTERNAL "CU Var")
+ endif()
+ENDMACRO()
+
+
+#
+# CU_SET_PATH
+#
+MACRO(CU_SET_PATH name val)
+ CU_SET_CACHE(${name} ${val})
+
+ CU_ADD_INC_PATH(${val})
+ENDMACRO()
+
+#
+# CU_ADD_INC_PATH
+#
+MACRO(CU_ADD_INC_PATH val)
+
+ if (";${CU_INC_PATHS};" MATCHES ";${val};")
+ # nothing to do for now
+ else()
+ set(CU_INC_PATHS
+ ${CU_INC_PATHS}
+ ${val}
+ )
+
+ #update cache
+ CU_SET_CACHE("CU_INC_PATHS" "${CU_INC_PATHS}")
+ include_directories(${val})
+ endif()
+ENDMACRO()
+
+
+#
+# CU_LOAD_INC_PATHS
+#
+MACRO(CU_LOAD_INC_PATHS)
+ include_directories(${CU_INC_PATHS})
+ENDMACRO()
+
+#
+# CU_SET_PARENT
+#
+MACRO(CU_SET_PARENT name val)
+ set(${name} ${val} PARENT_SCOPE)
+ENDMACRO()
+
+
+MACRO(CU_ADD_HOOK hook_name value)
+ CU_ADD_GLOBAL(${hook_name} "${value}")
+ENDMACRO()
+
+MACRO(CU_RUN_HOOK hook_name)
+ CU_GET_GLOBAL(${hook_name})
+ message(STATUS "Running cmake hook: ${hook_name}")
+ if (${hook_name})
+ set(HOOK_ARRAY ${${hook_name}})
+ FOREACH (hook_file ${HOOK_ARRAY})
+ message("Including ${hook_file}")
+ include("${hook_file}")
+ ENDFOREACH()
+ else()
+ message(STATUS "No hooks registered for ${hook_name}")
+ endif()
+ENDMACRO()
+
+
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
new file mode 100644
index 0000000000..e4005696ca
--- /dev/null
+++ b/modules/CMakeLists.txt
@@ -0,0 +1,385 @@
+#
+# This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+
+# Make the script module list available in the current scope
+GetModuleSourceList(MODULES_MODULE_LIST)
+
+# Make the native install offset available in this scope
+GetInstallOffset(INSTALL_OFFSET)
+
+# Sets the MODULES_${SOURCE_MODULE} variables
+# when using predefined templates for script building
+# like dynamic, static
+# Sets MODULES_DEFAULT_LINKAGE
+if(MODULES MATCHES "dynamic")
+ set(MODULES_DEFAULT_LINKAGE "dynamic")
+elseif(MODULES MATCHES "static")
+ set(MODULES_DEFAULT_LINKAGE "static")
+else()
+ set(MODULES_DEFAULT_LINKAGE "disabled")
+endif()
+
+# Add support old api modules
+CU_GET_GLOBAL("AC_ADD_SCRIPTS_LIST")
+CU_GET_GLOBAL("AC_ADD_SCRIPTS_INCLUDE")
+
+set("AC_SCRIPTS_INCLUDES" "")
+set("AC_MODULE_LIST" "")
+set("AC_SCRIPTS_LIST" "")
+set(MOD_ELUNA_FOUND 0)
+set(MOD_ELUNA_PATH "")
+
+foreach(include ${AC_ADD_SCRIPTS_INCLUDE})
+ set("AC_SCRIPTS_INCLUDES" "#include \"${include}\"\n${AC_SCRIPTS_INCLUDES}")
+endforeach()
+
+foreach(void ${AC_ADD_SCRIPTS_LIST})
+ set("AC_MODULE_LIST" "void ${void};\n${AC_MODULE_LIST}")
+endforeach()
+
+foreach(scriptName ${AC_ADD_SCRIPTS_LIST})
+ set("AC_SCRIPTS_LIST" " ${scriptName};\n${AC_SCRIPTS_LIST}")
+endforeach()
+
+function(ConfigureElunaModule moduleName)
+ set(MOD_ELUNA_FOUND 1 PARENT_SCOPE)
+ GetPathToModuleSource(${SOURCE_MODULE} MODULE_SOURCE_PATH)
+ set(MOD_ELUNA_PATH ${MODULE_SOURCE_PATH} PARENT_SCOPE)
+
+ # Define eluna compile options
+ target_compile_options(game-interface
+ INTERFACE
+ -DAZEROTHCORE
+ -DWOTLK)
+endfunction()
+
+# Set the MODULES_${SOURCE_MODULE} variables from the
+# variables set above
+foreach(SOURCE_MODULE ${MODULES_MODULE_LIST})
+ message(STATUS "Setting up module ${SOURCE_MODULE}")
+ ModuleNameToVariable(${SOURCE_MODULE} MODULE_MODULE_VARIABLE)
+
+ if(${MODULE_MODULE_VARIABLE} STREQUAL "default")
+ set(${MODULE_MODULE_VARIABLE} ${MODULES_DEFAULT_LINKAGE})
+ endif()
+
+ # Use only static for deprecated api loaders
+ if (AC_SCRIPTS_INCLUDES MATCHES "${SOURCE_MODULE}")
+ set(${MODULE_MODULE_VARIABLE} "static")
+ endif()
+
+ # Use only static for mod-eluna
+ if (SOURCE_MODULE MATCHES "mod-eluna")
+ ConfigureElunaModule(${SOURCE_MODULE})
+ endif()
+
+ set(${MODULE_MODULE_VARIABLE} "static")
+
+ # Build the Graph values
+ if(${MODULE_MODULE_VARIABLE} MATCHES "dynamic")
+ GetProjectNameOfModuleName(${SOURCE_MODULE} MODULE_SOURCE_PROJECT_NAME)
+ GetNativeSharedLibraryName(${MODULE_SOURCE_PROJECT_NAME} MODULE_PROJECT_LIBRARY)
+ list(APPEND MODULE_GRAPH_KEYS ${MODULE_SOURCE_PROJECT_NAME})
+ set(MODULE_GRAPH_VALUE_DISPLAY_${MODULE_SOURCE_PROJECT_NAME} ${MODULE_PROJECT_LIBRARY})
+ list(APPEND MODULE_GRAPH_VALUE_CONTAINS_MODULES_${MODULE_SOURCE_PROJECT_NAME} ${SOURCE_MODULE})
+ elseif(${MODULE_MODULE_VARIABLE} MATCHES "static")
+ list(APPEND MODULE_GRAPH_KEYS worldserver)
+ set(MODULE_GRAPH_VALUE_DISPLAY_worldserver worldserver)
+ list(APPEND MODULE_GRAPH_VALUE_CONTAINS_MODULES_worldserver ${SOURCE_MODULE})
+ else()
+ message(STATUS "Module disabled ${SOURCE_MODULE}")
+ list(APPEND MODULE_GRAPH_KEYS disabled)
+ set(MODULE_GRAPH_VALUE_DISPLAY_disabled disabled)
+ list(APPEND MODULE_GRAPH_VALUE_CONTAINS_MODULES_disabled ${SOURCE_MODULE})
+ endif()
+endforeach()
+
+list(SORT MODULE_GRAPH_KEYS)
+list(REMOVE_DUPLICATES MODULE_GRAPH_KEYS)
+
+# Display the module graph
+message("* Modules configuration (${MODULES}):
+ |")
+
+foreach(MODULE_GRAPH_KEY ${MODULE_GRAPH_KEYS})
+if(NOT MODULE_GRAPH_KEY STREQUAL "disabled")
+ message(" +- ${MODULE_GRAPH_VALUE_DISPLAY_${MODULE_GRAPH_KEY}}")
+else()
+ message(" | ${MODULE_GRAPH_VALUE_DISPLAY_${MODULE_GRAPH_KEY}}")
+endif()
+foreach(MODULE_GRAPH_PROJECT_ENTRY ${MODULE_GRAPH_VALUE_CONTAINS_MODULES_${MODULE_GRAPH_KEY}})
+ message(" | +- ${MODULE_GRAPH_PROJECT_ENTRY}")
+endforeach()
+message(" |")
+endforeach()
+
+message("")
+
+# Base sources which are used by every script project
+if (USE_SCRIPTPCH)
+ set(PRIVATE_PCH_HEADER ModulesPCH.h)
+endif()
+
+GroupSources(${CMAKE_CURRENT_SOURCE_DIR})
+
+# Configures the scriptloader with the given name and stores the output in the LOADER_OUT variable.
+# It is possible to expose multiple subdirectories from the same scriptloader through passing
+# it to the variable arguments
+function(ConfigureScriptLoader SCRIPTLOADER_NAME LOADER_OUT IS_DYNAMIC_SCRIPTLOADER)
+ # Deduces following variables which are referenced by thge template:
+ # ACORE_IS_DYNAMIC_SCRIPTLOADER
+ # ACORE_SCRIPTS_FORWARD_DECL
+ # ACORE_SCRIPTS_INVOKE
+ # ACORE_CURRENT_SCRIPT_PROJECT
+
+ # To generate export macros
+ set(ACORE_IS_DYNAMIC_SCRIPTLOADER ${IS_DYNAMIC_SCRIPTLOADER})
+
+ # To generate forward declarations of the loading functions
+ unset(ACORE_SCRIPTS_FORWARD_DECL)
+ unset(ACORE_SCRIPTS_INVOKE)
+
+ # The current script project which is built in
+ set(ACORE_CURRENT_SCRIPT_PROJECT ${SCRIPTLOADER_NAME})
+
+ foreach(LOCALE_SCRIPT_MODULE ${ARGN})
+
+ # Replace bad words
+ string(REGEX REPLACE - "_" LOCALE_SCRIPT_MODULE ${LOCALE_SCRIPT_MODULE})
+
+ # Determine the loader function ("Add##${NameOfDirectory}##Scripts()")
+ set(LOADER_FUNCTION
+ "Add${LOCALE_SCRIPT_MODULE}Scripts()")
+
+ # Generate the funciton call and the forward declarations
+ set(ACORE_SCRIPTS_FORWARD_DECL
+ "${ACORE_SCRIPTS_FORWARD_DECL}void ${LOADER_FUNCTION};\n")
+
+ set(ACORE_SCRIPTS_INVOKE
+ "${ACORE_SCRIPTS_INVOKE} ${LOADER_FUNCTION};\n")
+ endforeach()
+
+ set(GENERATED_LOADER ${CMAKE_CURRENT_BINARY_DIR}/gen_scriptloader/${SCRIPTLOADER_NAME}/ModulesLoader.cpp)
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ModulesLoader.cpp.in.cmake ${GENERATED_LOADER})
+ set(${LOADER_OUT} ${GENERATED_LOADER} PARENT_SCOPE)
+endfunction()
+
+# Generates the actual module projects
+# Fills the STATIC_SCRIPT_MODULES and DYNAMIC_SCRIPT_MODULE_PROJECTS variables
+# which contain the names which scripts are linked statically/dynamically and
+# adds the sources of the static modules to the PRIVATE_SOURCES_MODULES variable.
+foreach(SOURCE_MODULE ${MODULES_MODULE_LIST})
+ GetPathToModuleSource(${SOURCE_MODULE} MODULE_SOURCE_PATH)
+ ModuleNameToVariable(${SOURCE_MODULE} MODULE_MODULE_VARIABLE)
+
+ if(NOT (${MODULE_MODULE_VARIABLE} STREQUAL "disabled"))
+ list(APPEND MODULE_LIST__ ${SOURCE_MODULE})
+ endif()
+
+ if((${MODULE_MODULE_VARIABLE} STREQUAL "disabled") OR
+ (${MODULE_MODULE_VARIABLE} STREQUAL "static"))
+
+ # Uninstall disabled modules
+ GetProjectNameOfModuleName(${SOURCE_MODULE} MODULE_SOURCE_PROJECT_NAME)
+ GetNativeSharedLibraryName(${MODULE_SOURCE_PROJECT_NAME} SCRIPT_MODULE_OUTPUT_NAME)
+ list(APPEND DISABLED_SCRIPT_MODULE_PROJECTS ${INSTALL_OFFSET}/${SCRIPT_MODULE_OUTPUT_NAME})
+ if(${MODULE_MODULE_VARIABLE} STREQUAL "static")
+
+ # Add the module content to the whole static module
+ CollectSourceFiles(${MODULE_SOURCE_PATH} PRIVATE_SOURCES_MODULES)
+ CollectIncludeDirectories(${MODULE_SOURCE_PATH} PUBLIC_INCLUDES)
+
+ # Skip deprecated api loaders
+ if (AC_SCRIPTS_INCLUDES MATCHES "${SOURCE_MODULE}")
+ message("> Module (${SOURCE_MODULE}) using deprecated loader api")
+ continue()
+ endif()
+
+ # Add the module name to STATIC_SCRIPT_MODULES
+ list(APPEND STATIC_SCRIPT_MODULES ${SOURCE_MODULE})
+
+ endif()
+ elseif(${MODULE_MODULE_VARIABLE} STREQUAL "dynamic")
+
+ # Generate an own dynamic module which is loadable on runtime
+ # Add the module content to the whole static module
+ unset(MODULE_SOURCE_PRIVATE_SOURCES)
+ CollectSourceFiles(${MODULE_SOURCE_PATH} MODULE_SOURCE_PRIVATE_SOURCES)
+ CollectIncludeDirectories(${MODULE_SOURCE_PATH} PUBLIC_INCLUDES)
+
+ # Configure the scriptloader
+ ConfigureScriptLoader(${SOURCE_MODULE} SCRIPT_MODULE_PRIVATE_SCRIPTLOADER ON ${SOURCE_MODULE})
+ GetProjectNameOfModuleName(${SOURCE_MODULE} MODULE_SOURCE_PROJECT_NAME)
+
+ # Add the module name to DYNAMIC_SCRIPT_MODULES
+ list(APPEND DYNAMIC_SCRIPT_MODULE_PROJECTS ${MODULE_SOURCE_PROJECT_NAME})
+
+ # Create the script module project
+ add_library(${MODULE_SOURCE_PROJECT_NAME} SHARED
+ ${MODULE_SOURCE_PRIVATE_SOURCES}
+ ${SCRIPT_MODULE_PRIVATE_SCRIPTLOADER})
+
+ target_link_libraries(${MODULE_SOURCE_PROJECT_NAME}
+ PRIVATE
+ acore-core-interface
+ PUBLIC
+ game)
+
+ target_include_directories(${MODULE_SOURCE_PROJECT_NAME}
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${PUBLIC_INCLUDES})
+
+ set_target_properties(${MODULE_SOURCE_PROJECT_NAME}
+ PROPERTIES
+ FOLDER
+ "modules")
+
+ if(UNIX)
+ install(TARGETS ${MODULE_SOURCE_PROJECT_NAME}
+ DESTINATION ${INSTALL_OFFSET} COMPONENT ${MODULE_SOURCE_PROJECT_NAME})
+ elseif(WIN32)
+ install(TARGETS ${MODULE_SOURCE_PROJECT_NAME}
+ RUNTIME DESTINATION ${INSTALL_OFFSET} COMPONENT ${MODULE_SOURCE_PROJECT_NAME})
+ if(MSVC)
+ # Place the script modules in the script subdirectory
+ set_target_properties(${MODULE_SOURCE_PROJECT_NAME} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/bin/Debug/scripts
+ RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/bin/Release/scripts
+ RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_BINARY_DIR}/bin/RelWithDebInfo/scripts
+ RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_BINARY_DIR}/bin/MinSizeRel/scripts)
+ endif()
+ endif()
+ else()
+ message(FATAL_ERROR "Unknown value \"${${MODULE_MODULE_VARIABLE}}\" for module (${SOURCE_MODULE})!")
+ endif()
+endforeach()
+
+# Add the dynamic script modules to the worldserver as dependency
+set(WORLDSERVER_DYNAMIC_SCRIPT_MODULES_DEPENDENCIES ${DYNAMIC_SCRIPT_MODULE_PROJECTS} PARENT_SCOPE)
+
+ConfigureScriptLoader("static" SCRIPT_MODULE_PRIVATE_SCRIPTLOADER OFF ${STATIC_SCRIPT_MODULES})
+
+list(REMOVE_DUPLICATES SCRIPT_MODULE_PRIVATE_SCRIPTLOADER)
+
+if (MOD_ELUNA_FOUND)
+ list(REMOVE_ITEM PRIVATE_SOURCES_MODULES ${MOD_ELUNA_PATH}/lualib/lua.c)
+ list(REMOVE_ITEM PRIVATE_SOURCES_MODULES ${MOD_ELUNA_PATH}/lualib/luac.c)
+endif()
+
+add_library(modules STATIC
+ ModulesScriptLoader.h
+ ${SCRIPT_MODULE_PRIVATE_SCRIPTLOADER}
+ ${PRIVATE_SOURCES_MODULES})
+
+target_link_libraries(modules
+ PRIVATE
+ acore-core-interface
+ PUBLIC
+ game-interface)
+
+target_include_directories(modules
+ PUBLIC
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${PUBLIC_INCLUDES})
+
+# Enables Devs to Include a cmake file in their module that will get run inline with the config.
+foreach(SOURCE_MODULE ${MODULES_MODULE_LIST})
+ include("${CMAKE_SOURCE_DIR}/modules/${SOURCE_MODULE}/${SOURCE_MODULE}.cmake" OPTIONAL)
+endforeach()
+
+set_target_properties(modules
+ PROPERTIES
+ FOLDER
+ "modules")
+
+# Generate precompiled header
+# if (USE_SCRIPTPCH)
+# list(APPEND ALL_SCRIPT_PROJECTS modules ${DYNAMIC_SCRIPT_MODULE_PROJECTS})
+# add_cxx_pch("${ALL_SCRIPT_PROJECTS}" ${PRIVATE_PCH_HEADER})
+# endif()
+
+# Remove all shared libraries in the installl directory which
+# are contained in the static library already.
+if (DISABLED_SCRIPT_MODULE_PROJECTS)
+ install(CODE "
+ foreach(SCRIPT_TO_UNINSTALL ${DISABLED_SCRIPT_MODULE_PROJECTS})
+ if(EXISTS \"\${SCRIPT_TO_UNINSTALL}\")
+ message(STATUS \"Uninstalling: \${SCRIPT_TO_UNINSTALL}\")
+ file(REMOVE \"\${SCRIPT_TO_UNINSTALL}\")
+ endif()
+ endforeach()
+ ")
+endif()
+
+# Stores the absolut path of the given config module in the variable
+function(GetPathToModuleConfig module variable)
+ set(${variable} "${CMAKE_SOURCE_DIR}/modules/${module}/conf" PARENT_SCOPE)
+endfunction()
+
+message(STATUS "* Modules config list:
+ |")
+
+foreach(ModuleName ${MODULE_LIST__})
+ GetPathToModuleConfig(${ModuleName} MODULE_CONFIG_PATH)
+
+ set(MODULE_LIST ${MODULE_LIST}${ModuleName},)
+
+ file(GLOB MODULE_CONFIG_LIST RELATIVE
+ ${MODULE_CONFIG_PATH}
+ ${MODULE_CONFIG_PATH}/*.conf.dist)
+
+ message(STATUS " +- ${ModuleName}")
+
+ foreach(configFileName ${MODULE_CONFIG_LIST})
+ CopyModuleConfig("${MODULE_CONFIG_PATH}/${configFileName}")
+ set(CONFIG_LIST ${CONFIG_LIST}${configFileName},)
+ message(STATUS " | * ${configFileName}")
+ endforeach()
+endforeach()
+
+# Define modules list
+target_compile_options(modules
+ INTERFACE
+ -DAC_MODULES_LIST=$<1:"${MODULE_LIST}">)
+
+# Define modules config list
+target_compile_options(modules
+ INTERFACE
+ -DCONFIG_FILE_LIST=$<1:"${CONFIG_LIST}">)
+
+if (MOD_ELUNA_FOUND)
+ if (APPLE)
+ target_compile_definitions(modules
+ PUBLIC
+ LUA_USE_MACOSX)
+ elseif (UNIX)
+ target_compile_definitions(modules
+ PUBLIC
+ LUA_USE_LINUX)
+ endif()
+
+ if (WIN32)
+ if (MSVC)
+ set(MSVC_CONFIGURATION_NAME $(ConfigurationName)/)
+ endif()
+
+ add_custom_command(TARGET modules
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bin/${MSVC_CONFIGURATION_NAME}lua_scripts/extensions/"
+ COMMAND ${CMAKE_COMMAND} -E copy_directory "${MOD_ELUNA_PATH}/LuaEngine/extensions" "${CMAKE_BINARY_DIR}/bin/${MSVC_CONFIGURATION_NAME}lua_scripts/extensions/")
+ endif()
+
+ install(DIRECTORY "${MOD_ELUNA_PATH}/LuaEngine/extensions" DESTINATION "${CMAKE_INSTALL_PREFIX}/bin/lua_scripts/")
+endif()
+
+message("")
diff --git a/modules/ModulesLoader.cpp.in.cmake b/modules/ModulesLoader.cpp.in.cmake
new file mode 100644
index 0000000000..ec542a4bc7
--- /dev/null
+++ b/modules/ModulesLoader.cpp.in.cmake
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+// This file was created automatically from your script configuration!
+// Use CMake to reconfigure this file, never change it on your own!
+
+#cmakedefine ACORE_IS_DYNAMIC_SCRIPTLOADER
+
+#include "Define.h"
+#include
+#include
+
+// Add deprecated api loaders include
+@AC_SCRIPTS_INCLUDES@
+// Includes list
+@ACORE_SCRIPTS_FORWARD_DECL@
+#ifdef ACORE_IS_DYNAMIC_SCRIPTLOADER
+# include "revision.h"
+# define AC_MODULES_API AC_API_EXPORT
+extern "C" {
+
+/// Exposed in script module to return the name of the script module
+/// contained in this shared library.
+AC_MODULES_API char const* GetScriptModule()
+{
+ return "@ACORE_CURRENT_SCRIPT_PROJECT@";
+}
+
+#else
+# include "ModulesScriptLoader.h"
+# define AC_MODULES_API
+#endif
+
+/// Exposed in script modules to register all scripts to the ScriptMgr.
+AC_MODULES_API void AddModulesScripts()
+{
+ // Modules
+@ACORE_SCRIPTS_INVOKE@
+ // Deprecated api modules
+@AC_SCRIPTS_LIST@}
+
+/// Exposed in script modules to get the build directive of the module.
+AC_MODULES_API char const* GetModulesBuildDirective()
+{
+ return _BUILD_DIRECTIVE;
+}
+
+#ifdef ACORE_IS_DYNAMIC_SCRIPTLOADER
+} // extern "C"
+#endif
\ No newline at end of file
diff --git a/modules/ModulesPCH.h b/modules/ModulesPCH.h
new file mode 100644
index 0000000000..305faa88f9
--- /dev/null
+++ b/modules/ModulesPCH.h
@@ -0,0 +1,26 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+#ifndef _MODULES_PRECOMPILED_H_
+#define _MODULES_PRECOMPILED_H_
+
+#include "ObjectMgr.h"
+#include "ScriptedCreature.h"
+#include "ScriptedGossip.h"
+#include "ScriptMgr.h"
+
+#endif
diff --git a/modules/ModulesScriptLoader.h b/modules/ModulesScriptLoader.h
new file mode 100644
index 0000000000..4117882202
--- /dev/null
+++ b/modules/ModulesScriptLoader.h
@@ -0,0 +1,23 @@
+/*
+ * This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Affero General Public License as published by the
+ * Free Software Foundation; either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+#ifndef _MODULES_SCRIPT_LOADER_H_
+#define _MODULES_SCRIPT_LOADER_H_
+
+void AddModulesScripts();
+
+#endif
diff --git a/modules/create_module.sh b/modules/create_module.sh
new file mode 100644
index 0000000000..51e9de479a
--- /dev/null
+++ b/modules/create_module.sh
@@ -0,0 +1,105 @@
+#!/bin/bash
+## Just run it with bash or `git bash` on windows, and it will ask for the module's name and tada!
+## By Barbz
+
+##------------------------------- VARIABLES ---------------------------------##
+
+MODULE_TEMPLATE_URL="https://github.com/azerothcore/skeleton-module/"
+GIT_COMMIT_MSG_SETUP="setup_git_commit_template.sh"
+
+##------------------------------- CODE ---------------------------------##
+
+read -p "Enter the name of your future module: " "MODULE_NAME"
+echo $MODULE_NAME | fgrep -q ' '
+
+while [ $? -eq 0 ]
+do
+ echo 'Blanks are not allowed!'
+ read -p "Enter the name of your future module: " MODULE_NAME
+ echo $MODULE_NAME | fgrep -q ' '
+done
+
+if test -n "$MODULE_NAME"
+then
+ echo "--- Cloning 'skeleton-module' as $MODULE_NAME/"
+ git clone --depth 1 -b master $MODULE_TEMPLATE_URL $MODULE_NAME
+
+ echo "--- Removing 'skeleton-module/.git/' history"
+ cd $MODULE_NAME && rm -rf .git/
+
+ echo "--- Init new git repository"
+ git init && git add -A && git commit -m "Initial commit - $MODULE_NAME"
+
+ echo "--- Configure git for nice commit messages"
+ source "$GIT_COMMIT_MSG_SETUP" || bash "$GIT_COMMIT_MSG_SETUP"
+
+ echo "--- Ready to code"
+fi
+
+
+# ## TODO Set the remote origin with username, repo url etc
+
+ # $USER_NAME/$MODULE_NAME.git
+
+ # echo "Do you want to set your git remote?"
+ # select yn in "Yes" "No"; do
+ # case $yn in
+ # Yes )
+ # CONFIGURE_GIT=1; break;;
+ # No )
+ # CONFIGURE_GIT=0;
+ # exit;;
+ # esac
+ # done
+
+
+ # if test "$CONFIGURE_GIT" == "1"
+ # then
+ # PS3='Where do you want to push your module?'
+ # options=("github.com" "gitlab.com" "bitbucket.org" "Quit")
+ # select opt in "${options[@]}"
+ # do
+ # case $opt in
+ # "github.com")
+ # echo "you chose choice 1"
+ # break
+ # ;;
+ # "gitlab.com")
+ # echo "you chose choice 2"
+ # break
+ # ;;
+ # "bitbucket.org")
+ # echo "you chose choice $REPLY which is $opt"
+ # break
+ # ;;
+ # "Quit")
+ # break
+ # ;;
+ # *) echo "invalid option $REPLY";;
+ # esac
+ # done
+
+ # REMOTE_HOST="$opt"
+
+ # PS3='HTTPS or SSH?'
+ # options=("HTTPS (default)" "SSH" "Quit")
+ # select opt in "${options[@]}"
+ # do
+ # case $opt in
+ # "HTTPS")
+ # echo "you chose choice 1"
+ # break
+ # ;;
+ # "SSH")
+ # echo "you chose choice $REPLY which is $opt"
+ # break
+ # ;;
+ # "Quit")
+ # break
+ # ;;
+ # *) echo "invalid option $REPLY";;
+ # esac
+ # done
+
+ # REMOTE_PROTOCOL="$opt"
+ # fi
diff --git a/modules/how_to_make_a_module.md b/modules/how_to_make_a_module.md
new file mode 100644
index 0000000000..52db7a86cf
--- /dev/null
+++ b/modules/how_to_make_a_module.md
@@ -0,0 +1,22 @@
+# CREATE A NEW AZEROTHCORE MODULE
+
+1) Read this page first:
+
+http://www.azerothcore.org/wiki/Create-a-Module
+
+
+2) Run the script `create_module.sh`:
+- If you're on windows, execute it with Git Bash (right click on it and choose Git bash) if you have installed Git extensions
+- If you're on linux, just run it with bash or with ./create_module.sh
+
+This script will create the base of your module, with a clean history and add a git configuration option to this repository only (local config).
+
+
+NOTE: You can also clone our skeleton-module manually, clean the history, and configure but you should use the script instead https://github.com/azerothcore/skeleton-module/
+
+
+3) Share it with the community!
+
+Join us on our discord, share it there, then we might fork it officially and it will appear in the module catalogue.
+
+Note: For Advanced CMake implementations a .cmake file in your module folder will be included in the config of Modules if it exists. See: ./CMakeList.txt around line #290
\ No newline at end of file