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