From a05cc525f03e12be8da9a9cba08ed62f4b8c42d4 Mon Sep 17 00:00:00 2001 From: Yehonal Date: Sat, 25 Oct 2025 01:16:09 +0200 Subject: [PATCH 1/4] feat(Config): Implement configuration severity policy and logging mechanism (#23284) --- .github/workflows/dashboard-ci.yml | 19 +- apps/bash_shared/common.sh | 20 +- apps/bash_shared/defines.sh | 2 + apps/bash_shared/includes.sh | 2 + apps/compiler/includes/functions.sh | 37 ++- apps/installer/includes/config/config-main.sh | 9 + apps/installer/includes/config/config.sh | 60 +++++ apps/installer/includes/functions.sh | 2 + apps/installer/includes/includes.sh | 9 +- .../includes/modules-manager/modules.sh | 39 +-- apps/installer/main.sh | 4 + apps/installer/test/test_module_commands.bats | 2 +- apps/startup-scripts/src/simple-restarter | 2 + conf/dist/config.sh | 36 +++ deps/acore/bash-lib/src/common/boolean.sh | 5 + doc/ConfigPolicy.md | 101 +++++++ src/common/Configuration/Config.cpp | 252 +++++++++++++++--- src/common/Configuration/Config.h | 21 +- src/common/Logging/Log.cpp | 5 +- src/server/apps/authserver/Main.cpp | 3 +- src/server/apps/worldserver/Main.cpp | 7 +- .../database/Database/DatabaseLoader.cpp | 21 +- src/tools/dbimport/Main.cpp | 7 +- 23 files changed, 541 insertions(+), 124 deletions(-) create mode 100644 apps/installer/includes/config/config-main.sh create mode 100644 apps/installer/includes/config/config.sh create mode 100644 deps/acore/bash-lib/src/common/boolean.sh create mode 100644 doc/ConfigPolicy.md diff --git a/.github/workflows/dashboard-ci.yml b/.github/workflows/dashboard-ci.yml index 93e4e6791..06b7940d3 100644 --- a/.github/workflows/dashboard-ci.yml +++ b/.github/workflows/dashboard-ci.yml @@ -74,11 +74,16 @@ jobs: - name: Configure AzerothCore settings run: | - # Create basic configuration - cp conf/dist/config.sh conf/config.sh - # Configure dashboard - sed -i 's/MTHREADS=.*/MTHREADS="4"/' conf/config.sh - sed -i 's/CBUILD_TESTING=.*/CBUILD_TESTING="ON"/' conf/config.sh + touch conf/config.sh + echo 'MTHREADS=4' >> conf/config.sh + echo 'CBUILD_TESTING=ON' >> conf/config.sh + echo 'AC_ENABLE_ROOT_CMAKE_INSTALL=1' >> conf/config.sh + echo 'export AC_CONFIG_POLICY=$AC_CONFIG_POLICY_PRESET_ZERO_CONF' >> conf/config.sh + echo 'AC_ENABLE_CONF_COPY_ON_INSTALL=0' >> conf/config.sh + cat conf/config.sh + + # debug content of AC_CONFIG_POLICY + ./acore.sh config show AC_CONFIG_POLICY - name: Test module commands run: | @@ -92,8 +97,6 @@ jobs: ./acore.sh module update --all - name: Run complete installation (deps, compile, database, client-data) - env: - AC_ENABLE_ROOT_CMAKE_INSTALL: 1 run: | # This runs: install-deps, compile, database setup, client-data download ./acore.sh init @@ -113,12 +116,14 @@ jobs: - name: Test authserver dry-run run: | + source ./acore.sh config load cd env/dist/bin timeout 5m ./authserver -dry-run continue-on-error: false - name: Test worldserver dry-run run: | + source ./acore.sh config load cd env/dist/bin timeout 5m ./worldserver -dry-run continue-on-error: false diff --git a/apps/bash_shared/common.sh b/apps/bash_shared/common.sh index acd23eacd..46422119b 100644 --- a/apps/bash_shared/common.sh +++ b/apps/bash_shared/common.sh @@ -1,17 +1,19 @@ function registerHooks() { acore_event_registerHooks "$@"; } function runHooks() { acore_event_runHooks "$@"; } -#shellcheck source=../../conf/dist/config.sh -source "$AC_PATH_CONF/dist/config.sh" # include dist to avoid missing conf variables +function acore_common_loadConfig() { + #shellcheck source=../../conf/dist/config.sh + source "$AC_PATH_CONF/dist/config.sh" # include dist to avoid missing conf variables -# first check if it's defined in env, otherwise use the default -USER_CONF_PATH=${USER_CONF_PATH:-"$AC_PATH_CONF/config.sh"} + # first check if it's defined in env, otherwise use the default + USER_CONF_PATH=${USER_CONF_PATH:-"$AC_PATH_CONF/config.sh"} -if [ -f "$USER_CONF_PATH" ]; then - source "$USER_CONF_PATH" # should overwrite previous -else - echo "NOTICE: file <$USER_CONF_PATH> not found, we use default configuration only." -fi + if [ -f "$USER_CONF_PATH" ]; then + source "$USER_CONF_PATH" # should overwrite previous + else + echo "NOTICE: file <$USER_CONF_PATH> not found, we use default configuration only." + fi +} # # Load modules diff --git a/apps/bash_shared/defines.sh b/apps/bash_shared/defines.sh index 4b014bd9c..af9e9dfc9 100644 --- a/apps/bash_shared/defines.sh +++ b/apps/bash_shared/defines.sh @@ -25,4 +25,6 @@ export AC_PATH_MODULES="$AC_PATH_ROOT/modules" export AC_PATH_DEPS="$AC_PATH_ROOT/deps" +export AC_BASH_LIB_PATH="$AC_PATH_DEPS/acore/bash-lib/src" + export AC_PATH_VAR="$AC_PATH_ROOT/var" diff --git a/apps/bash_shared/includes.sh b/apps/bash_shared/includes.sh index d2bf07db1..679fc8e6d 100644 --- a/apps/bash_shared/includes.sh +++ b/apps/bash_shared/includes.sh @@ -16,6 +16,8 @@ source "$AC_PATH_DEPS/acore/bash-lib/src/event/hooks.sh" # shellcheck source=./common.sh source "$AC_PATH_SHARED/common.sh" +acore_common_loadConfig + if [[ "$OSTYPE" = "msys" ]]; then AC_BINPATH_FULL="$BINPATH" else diff --git a/apps/compiler/includes/functions.sh b/apps/compiler/includes/functions.sh index c955f2847..4428f9132 100644 --- a/apps/compiler/includes/functions.sh +++ b/apps/compiler/includes/functions.sh @@ -1,5 +1,8 @@ #!/usr/bin/env bash +# shellcheck source=../../../deps/acore/bash-lib/src/common/boolean.sh +source "$AC_BASH_LIB_PATH/common/boolean.sh" + # Set SUDO variable - one liner SUDO="" @@ -135,7 +138,8 @@ function comp_compile() { echo "Done" ;; linux*|darwin*) - local confDir=${CONFDIR:-"$AC_BINPATH_FULL/../etc"} + local confDir + confDir=${CONFDIR:-"$AC_BINPATH_FULL/../etc"} # create the folders before installing to # set the current user and permissions @@ -145,6 +149,8 @@ function comp_compile() { mkdir -p "$confDir" mkdir -p "$confDir/modules" + confDir=$(realpath "$confDir") + echo "Cmake install..." $SUDO cmake --install . --config $CTYPE @@ -161,18 +167,25 @@ function comp_compile() { $SUDO setcap cap_sys_nice=eip "$AC_BINPATH_FULL/authserver" fi - [[ -f "$confDir/worldserver.conf.dist" ]] && \ - cp -v --no-clobber "$confDir/worldserver.conf.dist" "$confDir/worldserver.conf" - [[ -f "$confDir/authserver.conf.dist" ]] && \ - cp -v --no-clobber "$confDir/authserver.conf.dist" "$confDir/authserver.conf" - [[ -f "$confDir/dbimport.conf.dist" ]] && \ - cp -v --no-clobber "$confDir/dbimport.conf.dist" "$confDir/dbimport.conf" - for f in "$confDir/modules/"*.dist - do - [[ -e $f ]] || break # handle the case of no *.dist files - cp -v --no-clobber "$f" "${f%.dist}"; - done + if ( isTrue "$AC_ENABLE_CONF_COPY_ON_INSTALL" ) then + echo "Copying default configuration files to $confDir ..." + [[ -f "$confDir/worldserver.conf.dist" && ! -f "$confDir/worldserver.conf" ]] && \ + cp -v "$confDir/worldserver.conf.dist" "$confDir/worldserver.conf" + [[ -f "$confDir/authserver.conf.dist" && ! -f "$confDir/authserver.conf" ]] && \ + cp -v "$confDir/authserver.conf.dist" "$confDir/authserver.conf" + [[ -f "$confDir/dbimport.conf.dist" && ! -f "$confDir/dbimport.conf" ]] && \ + cp -v "$confDir/dbimport.conf.dist" "$confDir/dbimport.conf" + + for f in "$confDir/modules/"*.dist + do + [[ -e $f ]] || break # handle the case of no *.dist files + if [[ ! -f "${f%.dist}" ]]; then + echo "Copying module config $(basename "${f%.dist}")" + cp -v "$f" "${f%.dist}"; + fi + done + fi echo "Done" ;; diff --git a/apps/installer/includes/config/config-main.sh b/apps/installer/includes/config/config-main.sh new file mode 100644 index 000000000..f5f0c01f6 --- /dev/null +++ b/apps/installer/includes/config/config-main.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +CURRENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" || exit ; pwd ) + +# shellcheck source=./config.sh +source "$CURRENT_PATH/config.sh" + +acore_dash_config "$@" + diff --git a/apps/installer/includes/config/config.sh b/apps/installer/includes/config/config.sh new file mode 100644 index 000000000..40192c400 --- /dev/null +++ b/apps/installer/includes/config/config.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash + +CURRENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" || exit ; pwd ) + +# shellcheck source=../../../bash_shared/includes.sh +source "$CURRENT_PATH/../../../bash_shared/includes.sh" +# shellcheck source=../includes.sh +source "$CURRENT_PATH/../includes.sh" +# shellcheck source=../../../bash_shared/menu_system.sh +source "$AC_PATH_APPS/bash_shared/menu_system.sh" + +function acore_dash_configShowValue() { + if [ $# -ne 1 ]; then + echo "Usage: show " + return 1 + fi + + local varName="$1" + local varValue="${!varName}" + if [ -z "$varValue" ]; then + echo "$varName is not set." + else + echo "$varName=$varValue" + fi +} + +function acore_dash_configLoad() { + acore_common_loadConfig + echo "Configuration loaded into the current shell session." +} + +# Configuration management menu definition +# Format: "key|short|description" +config_menu_items=( + "show|s|Show configuration variable value" + "load|l|Load configurations variables within the current shell session" + "help|h|Show detailed help" + "quit|q|Close this menu" +) + +# Menu command handler for configuration operations +function handle_config_command() { + local key="$1" + shift + + case "$key" in + "show") + acore_dash_configShowValue "$@" + ;; + "load") + acore_dash_configLoad + ;; + esac +} + +function acore_dash_config() { + menu_run_with_items "CONFIG MANAGER" handle_config_command -- "${config_menu_items[@]}" -- "$@" + return $? +} + diff --git a/apps/installer/includes/functions.sh b/apps/installer/includes/functions.sh index 3bc7e13e4..28e5b4137 100644 --- a/apps/installer/includes/functions.sh +++ b/apps/installer/includes/functions.sh @@ -183,3 +183,5 @@ function inst_download_client_data { && echo "Remove downloaded file" && rm "$zipPath" \ && echo "INSTALLED_VERSION=$VERSION" > "$dataVersionFile" } + + diff --git a/apps/installer/includes/includes.sh b/apps/installer/includes/includes.sh index c0d6bb8bd..e4c1b9f2b 100644 --- a/apps/installer/includes/includes.sh +++ b/apps/installer/includes/includes.sh @@ -2,6 +2,7 @@ CURRENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd ) +# shellcheck source=../../bash_shared/includes.sh source "$CURRENT_PATH/../../bash_shared/includes.sh" AC_PATH_INSTALLER="$AC_PATH_APPS/installer" @@ -9,14 +10,14 @@ AC_PATH_INSTALLER="$AC_PATH_APPS/installer" J_PATH="$AC_PATH_DEPS/acore/joiner" J_PATH_MODULES="$AC_PATH_MODULES" +# shellcheck source=../../../deps/acore/joiner/joiner.sh source "$J_PATH/joiner.sh" -if [ -f "$AC_PATH_INSTALLER/config.sh" ]; then - source "$AC_PATH_INSTALLER/config.sh" # should overwrite previous -fi - +# shellcheck source=../../compiler/includes/includes.sh source "$AC_PATH_APPS/compiler/includes/includes.sh" +# shellcheck source=../../../deps/semver_bash/semver.sh source "$AC_PATH_DEPS/semver_bash/semver.sh" +# shellcheck source=../includes/functions.sh source "$AC_PATH_INSTALLER/includes/functions.sh" diff --git a/apps/installer/includes/modules-manager/modules.sh b/apps/installer/includes/modules-manager/modules.sh index 91ae3785b..89c7ea50a 100644 --- a/apps/installer/includes/modules-manager/modules.sh +++ b/apps/installer/includes/modules-manager/modules.sh @@ -59,7 +59,6 @@ else C_GREEN='' C_YELLOW='' C_BLUE='' - C_MAGENTA='' C_CYAN='' fi @@ -174,42 +173,8 @@ function inst_module_list() { # Usage: ./acore.sh module [args...] # ./acore.sh module # Interactive menu function inst_module() { - # If no arguments provided, start interactive menu - if [[ $# -eq 0 ]]; then - menu_run_with_items "MODULE MANAGER" handle_module_command -- "${module_menu_items[@]}" -- - return $? - fi - - # Normalize arguments into an array - local tokens=() - read -r -a tokens <<< "$*" - local cmd="${tokens[0]}" - local args=("${tokens[@]:1}") - - case "$cmd" in - ""|"help"|"-h"|"--help") - inst_module_help - ;; - "search"|"s") - inst_module_search "${args[@]}" - ;; - "install"|"i") - inst_module_install "${args[@]}" - ;; - "update"|"u") - inst_module_update "${args[@]}" - ;; - "remove"|"r") - inst_module_remove "${args[@]}" - ;; - "list"|"l") - inst_module_list "${args[@]}" - ;; - *) - print_error "Unknown module command: $cmd. Use 'help' to see available commands." - return 1 - ;; - esac + menu_run_with_items "MODULE MANAGER" handle_module_command -- "${module_menu_items[@]}" -- "$@" + return $? } # ============================================================================= diff --git a/apps/installer/main.sh b/apps/installer/main.sh index fea9dc3ac..a64787269 100644 --- a/apps/installer/main.sh +++ b/apps/installer/main.sh @@ -45,6 +45,7 @@ menu_items=( "docker|dr|Run docker tools" "version|v|Show AzerothCore version" "service-manager|sm|Run service manager to run authserver and worldserver in background" + "config|cf|Configuration manager" "quit|q|Exit from this menu" ) @@ -100,6 +101,9 @@ function handle_menu_command() { bash "$AC_PATH_APPS/startup-scripts/src/service-manager.sh" "$@" exit ;; + "config") + bash "$AC_PATH_APPS/installer/includes/config/config-main.sh" "$@" + ;; "quit") echo "Goodbye!" exit diff --git a/apps/installer/test/test_module_commands.bats b/apps/installer/test/test_module_commands.bats index 1223a80a6..d829c1a32 100755 --- a/apps/installer/test/test_module_commands.bats +++ b/apps/installer/test/test_module_commands.bats @@ -751,5 +751,5 @@ EOF run inst_module "unknown-command" [ "$status" -eq 1 ] - [[ "$output" =~ "Unknown module command" ]] + [[ "$output" =~ "Invalid option" ]] } \ No newline at end of file diff --git a/apps/startup-scripts/src/simple-restarter b/apps/startup-scripts/src/simple-restarter index a158b38be..1865eaa87 100755 --- a/apps/startup-scripts/src/simple-restarter +++ b/apps/startup-scripts/src/simple-restarter @@ -50,6 +50,8 @@ fi # Main restart loop while true; do STARTING_TIME=$(date +%s) + + echo "AC_CONFIG_POLICY: $AC_CONFIG_POLICY" # Use starter script to launch the binary with all parameters "$STARTER_SCRIPT" "$BINPATH" "$BINFILE" "$GDB_FILE" "$CONFIG" "$SYSLOG" "$SYSERR" "$GDB_ENABLED" "$CRASHES_PATH" diff --git a/conf/dist/config.sh b/conf/dist/config.sh index f8e78a8b8..5860cb2a8 100644 --- a/conf/dist/config.sh +++ b/conf/dist/config.sh @@ -118,6 +118,12 @@ export CCACHE_DIR=${CCACHE_DIR:-"$AC_PATH_VAR/ccache"} # export AC_ENABLE_ROOT_CMAKE_INSTALL=${AC_ENABLE_ROOT_CMAKE_INSTALL:-0} +# +# Enable copying configuration files on install +# Default: 1 (true) +# +export AC_ENABLE_CONF_COPY_ON_INSTALL=${AC_ENABLE_CONF_COPY_ON_INSTALL:-1} + ############################################## # # GOOGLE PERF TOOLS @@ -182,4 +188,34 @@ export MODULES_EXCLUDE_LIST="" NO_COLOR=${NO_COLOR:-} FORCE_COLOR=${FORCE_COLOR:-} +############################################## +# +# CONFIGURATION SEVERITY POLICY +# +# Controls how the core reacts to missing configuration files, +# missing/unknown options and invalid values. +# The policy string follows the format "key=severity" separated by commas. +# Supported severities: skip, warn, error, fatal. +# Possible keys: default, missing_file, missing_option, critical_option, +# unknown_option, value_error. +# +# Examples: +# export AC_CONFIG_POLICY="$AC_CONFIG_POLICY_PRESET_DEFAULT" +# export AC_CONFIG_POLICY="default=skip,critical_option=fatal,unknown_option=warn" +# export AC_CONFIG_POLICY="missing_file=fatal,missing_option=error" +# +# Presets: +# AC_CONFIG_POLICY_PRESET_DEFAULT -> mirrors the core default behaviour +# (errors on missing files, fatal on critical) +# AC_CONFIG_POLICY_PRESET_ZERO_CONF -> skips non-critical gaps so the core +# can boot from environment defaults +# AC_CONFIG_POLICY_PRESET_STRICT -> escalates everything to errors/fatals +# + +export AC_CONFIG_POLICY_PRESET_ZERO_CONF='default=skip' +export AC_CONFIG_POLICY_PRESET_DEFAULT='missing_file=error,missing_option=warn,critical_option=fatal,unknown_option=error,value_error=error' +export AC_CONFIG_POLICY_PRESET_STRICT='default=error,missing_file=fatal,missing_option=error,critical_option=fatal,unknown_option=error,value_error=error' + +export AC_CONFIG_POLICY=$AC_CONFIG_POLICY_PRESET_DEFAULT + diff --git a/deps/acore/bash-lib/src/common/boolean.sh b/deps/acore/bash-lib/src/common/boolean.sh new file mode 100644 index 000000000..4f2e365db --- /dev/null +++ b/deps/acore/bash-lib/src/common/boolean.sh @@ -0,0 +1,5 @@ +function isTrue() { + local val + val=$(echo "$1" | tr '[:upper:]' '[:lower:]') + [[ "$val" == "1" || "$val" == "true" || "$val" == "yes" || "$val" == "on" ]] +} \ No newline at end of file diff --git a/doc/ConfigPolicy.md b/doc/ConfigPolicy.md new file mode 100644 index 000000000..daa20b2fb --- /dev/null +++ b/doc/ConfigPolicy.md @@ -0,0 +1,101 @@ +# Configuration Severity Policy + +The configuration loader can decide how strictly it should react when it +encounters missing files, undefined options or invalid values. This document +describes the available knobs and provides ready-to-use presets. + +## Severity Levels + +Each policy entry maps a **key** to one of the following severities: + +| Severity | Description | +|----------|-----------------------------------------------------------------------------| +| `skip` | Ignore the problem and continue silently. | +| `warn` | Log a warning and continue. | +| `error` | Log an error and continue (useful to surface issues without aborting). | +| `fatal` | Log a fatal message and abort the process immediately. | + +## Policy Keys + +The following keys can be customised: + +| Key | Applies to | +|--------------------|----------------------------------------------------------------------| +| `default` | Fallback severity for any key that is not explicitly overridden. | +| `missing_file` | Missing or empty configuration files (worldserver.conf, modules, …). | +| `missing_option` | Options looked up in code but not present in any config file. | +| `critical_option` | Required options (`RealmID`, `*DatabaseInfo`, …). | +| `unknown_option` | Options found in optional configs that the core does not recognise. | +| `value_error` | Options that cannot be converted to the expected type. | + +> Critical options remain fatal by default to prevent the core from booting with +> incomplete database details; you can relax them if required. + +## Configuration Channels + +### `config.sh` + +`conf/dist/config.sh` exposes the `AC_CONFIG_POLICY` variable alongside a few +presets: + +```bash +# Mirrors the default behaviour (errors, with fatal criticals) +export AC_CONFIG_POLICY="$AC_CONFIG_POLICY_PRESET_DEFAULT" + +# Skip anything non-critical so the core can bootstrap from defaults + env vars +export AC_CONFIG_POLICY="$AC_CONFIG_POLICY_PRESET_ZERO_CONF" + +# Treat everything strictly (useful for CI) +export AC_CONFIG_POLICY="$AC_CONFIG_POLICY_PRESET_STRICT" +``` + +The presets are defined as: + +```bash +AC_CONFIG_POLICY_PRESET_DEFAULT='missing_file=error,missing_option=warn,critical_option=fatal,unknown_option=error,value_error=error' +AC_CONFIG_POLICY_PRESET_ZERO_CONF='default=skip,critical_option=fatal,unknown_option=warn,value_error=warn' +AC_CONFIG_POLICY_PRESET_STRICT='default=error,missing_file=fatal,missing_option=error,critical_option=fatal,unknown_option=error,value_error=error' +``` + +Modify or extend these entries to suit your deployment. + +### Environment Variable + +The runtime honours the `AC_CONFIG_POLICY` environment variable, so you can +override the policy without editing `config.sh`: + +```bash +export AC_CONFIG_POLICY="default=skip,critical_option=fatal" +./acore.sh run-worldserver +``` + +### CLI Override + +Every server/tool executable accepts `--config-policy`: + +```bash +./bin/worldserver --config-policy="missing_file=fatal,unknown_option=warn" +./bin/authserver --config-policy "$AC_CONFIG_POLICY_PRESET_STRICT" +``` + +The CLI flag takes precedence over the environment and `config.sh`. + +## Quick Presets + +| Preset | Intended use | +|---------------|---------------------------------------------------------------------------| +| `legacy` | Default behaviour before this feature (errors for missing files/options). | +| `zero-conf` | Zero-touch deployments; rely on defaults/env vars where possible. | +| `strict` | Fail-fast in CI or controlled environments. | + +Feel free to clone these presets and store your own variants inside +`config.sh` or deployment scripts. + +## Tips + +- Pair `fatal` severities with monitoring so regressions in configuration + surface quickly. +- When experimenting locally, start with `zero-conf` and elevate specific keys + to `error`/`fatal` as you validate your setup. +- Remember that number parsing errors (`value_error`) often indicate typos; + keep them at least `error` unless you have a very good reason. diff --git a/src/common/Configuration/Config.cpp b/src/common/Configuration/Config.cpp index 258d15d65..0d23591f9 100644 --- a/src/common/Configuration/Config.cpp +++ b/src/common/Configuration/Config.cpp @@ -21,10 +21,14 @@ #include "StringFormat.h" #include "Tokenize.h" #include "Util.h" +#include +#include #include #include +#include #include #include +#include namespace { @@ -34,13 +38,14 @@ namespace std::unordered_map _configOptions; std::unordered_map _envVarCache; std::mutex _configLock; + ConfigPolicy _policy; - std::vector _fatalConfigOptions = + std::unordered_set _criticalConfigOptions = { - { "RealmID" }, - { "LoginDatabaseInfo" }, - { "WorldDatabaseInfo" }, - { "CharacterDatabaseInfo" }, + "RealmID", + "LoginDatabaseInfo", + "WorldDatabaseInfo", + "CharacterDatabaseInfo", }; // Check system configs like *server.conf* @@ -62,6 +67,29 @@ namespace return foundAppender != std::string_view::npos || foundLogger != std::string_view::npos; } + Optional ParseSeverity(std::string_view value) + { + if (value.empty()) + return std::nullopt; + + std::string lowered(value); + std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](unsigned char c) { return std::tolower(c); }); + + if (lowered == "skip") + return ConfigSeverity::Skip; + + if (lowered == "warn" || lowered == "warning") + return ConfigSeverity::Warn; + + if (lowered == "error") + return ConfigSeverity::Error; + + if (lowered == "fatal" || lowered == "abort" || lowered == "panic") + return ConfigSeverity::Fatal; + + return std::nullopt; + } + template inline void PrintError(std::string_view filename, Format&& fmt, Args&& ... args) { @@ -77,6 +105,138 @@ namespace } } + template + inline void LogWithSeverity(ConfigSeverity severity, std::string_view filename, Format&& fmt, Args&&... args) + { + std::string message = Acore::StringFormat(std::forward(fmt), std::forward(args)...); + + switch (severity) + { + case ConfigSeverity::Skip: + return; + case ConfigSeverity::Warn: + { + if (IsAppConfig(filename)) + fmt::print("{}\n", message); + + LOG_WARN("server.loading", message); + return; + } + case ConfigSeverity::Error: + { + if (IsAppConfig(filename)) + fmt::print("{}\n", message); + + LOG_ERROR("server.loading", message); + return; + } + case ConfigSeverity::Fatal: + { + if (IsAppConfig(filename)) + fmt::print("{}\n", message); + + LOG_FATAL("server.loading", message); + ABORT(message); + } + } + } + + ConfigPolicy ApplyPolicyString(ConfigPolicy policy, std::string_view input) + { + if (input.empty()) + return policy; + + std::vector> overrides; + Optional defaultOverride; + + std::string tokenBuffer(input); + for (std::string_view rawToken : Acore::Tokenize(tokenBuffer, ',', false)) + { + std::string token = Acore::String::Trim(std::string(rawToken), std::locale()); + if (token.empty()) + continue; + + auto separator = token.find('='); + if (separator == std::string::npos) + continue; + + std::string key = Acore::String::Trim(token.substr(0, separator), std::locale()); + std::string value = Acore::String::Trim(token.substr(separator + 1), std::locale()); + + if (key.empty() || value.empty()) + continue; + + auto severity = ParseSeverity(value); + if (!severity) + continue; + + std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c) { return std::tolower(c); }); + + if (key == "default") + { + defaultOverride = severity; + continue; + } + + overrides.emplace_back(std::move(key), *severity); + } + + if (defaultOverride) + { + policy.defaultSeverity = *defaultOverride; + policy.missingFileSeverity = *defaultOverride; + policy.missingOptionSeverity = *defaultOverride; + policy.criticalOptionSeverity = *defaultOverride; + policy.unknownOptionSeverity = *defaultOverride; + policy.valueErrorSeverity = *defaultOverride; + } + + for (auto const& [key, severity] : overrides) + { + if (key == "missing_file" || key == "file") + policy.missingFileSeverity = severity; + else if (key == "missing_option" || key == "option") + policy.missingOptionSeverity = severity; + else if (key == "critical_option" || key == "critical") + policy.criticalOptionSeverity = severity; + else if (key == "unknown_option" || key == "unknown") + policy.unknownOptionSeverity = severity; + else if (key == "value_error" || key == "value") + policy.valueErrorSeverity = severity; + } + + return policy; + } + + ConfigPolicy ApplyPolicyFromArgs(ConfigPolicy policy, std::vector const& args) + { + for (std::size_t i = 0; i < args.size(); ++i) + { + std::string const& arg = args[i]; + std::string_view value; + + constexpr std::string_view shortOpt = "--config-policy"; + + if (arg.rfind(shortOpt, 0) == 0) + { + if (arg.size() == shortOpt.size() && (i + 1) < args.size()) + { + value = args[i + 1]; + ++i; + } + else if (arg.size() > shortOpt.size() && arg[shortOpt.size()] == '=') + { + value = std::string_view(arg).substr(shortOpt.size() + 1); + } + + if (!value.empty()) + policy = ApplyPolicyString(policy, value); + } + } + + return policy; + } + void AddKey(std::string const& optionName, std::string const& optionKey, std::string_view fileName, bool isOptional, [[maybe_unused]] bool isReload) { auto const& itr = _configOptions.find(optionName); @@ -86,7 +246,7 @@ namespace { if (!IsLoggingSystemOptions(optionName) && !isReload) { - PrintError(fileName, "> Config::LoadFile: Found incorrect option '{}' in config file '{}'. Skip", optionName, fileName); + LogWithSeverity(_policy.unknownOptionSeverity, fileName, "> Config::LoadFile: Found incorrect option '{}' in config file '{}'. Skip", optionName, fileName); #ifdef CONFIG_ABORT_INCORRECT_OPTIONS ABORT("> Core can't start if found incorrect options"); @@ -111,13 +271,10 @@ namespace if (in.fail()) { - if (isOptional) - { - // No display erorr if file optional - return false; - } - - throw ConfigException(Acore::StringFormat("Config::LoadFile: Failed open {}file '{}'", isOptional ? "optional " : "", file)); + ConfigSeverity severity = isOptional ? ConfigSeverity::Skip : _policy.missingFileSeverity; + LogWithSeverity(severity, file, "> Config::LoadFile: Failed open {}file '{}'", isOptional ? "optional " : "", file); + // Treat SKIP as a successful no-op so the app can proceed + return severity == ConfigSeverity::Skip; } uint32 count = 0; @@ -181,13 +338,10 @@ namespace // No lines read if (!count) { - if (isOptional) - { - // No display erorr if file optional - return false; - } - - throw ConfigException(Acore::StringFormat("Config::LoadFile: Empty file '{}'", file)); + ConfigSeverity severity = isOptional ? ConfigSeverity::Skip : _policy.missingFileSeverity; + LogWithSeverity(severity, file, "> Config::LoadFile: Empty file '{}'", file); + // Treat SKIP as a successful no-op + return severity == ConfigSeverity::Skip; } // Add correct keys if file load without errors @@ -382,7 +536,6 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog std::string strValue; auto const& itr = _configOptions.find(name); - bool fatalConfig = false; bool notFound = itr == _configOptions.end(); auto envVarName = GetEnvVarName(name); Optional envVar = GetEnvFromCache(name, envVarName); @@ -401,23 +554,23 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog { if (showLogs) { - for (std::string s : _fatalConfigOptions) - if (s == name) - { - fatalConfig = true; - break; - } + bool isCritical = _criticalConfigOptions.find(name) != _criticalConfigOptions.end(); + ConfigSeverity severity = isCritical ? _policy.criticalOptionSeverity : _policy.missingOptionSeverity; - if (fatalConfig) - LOG_FATAL("server.loading", "> Config:\n\nFATAL ERROR: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable\n\nYour server cannot start without this option!", + if (isCritical) + { + LogWithSeverity(severity, _filename, + "> Config:\n\nFATAL ERROR: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable\n\nYour server cannot start without this option!", name, _filename, name, Acore::ToString(def), envVarName); + } else { std::string configs = _filename; if (!_moduleConfigFiles.empty()) configs += " or module config"; - LOG_WARN("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable.", + LogWithSeverity(severity, _filename, + "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable.", name, configs, name, def, envVarName); } } @@ -433,7 +586,8 @@ T ConfigMgr::GetValueDefault(std::string const& name, T const& def, bool showLog { if (showLogs) { - LOG_ERROR("server.loading", "> Config: Bad value defined for name '{}', going to use '{}' instead", + LogWithSeverity(_policy.valueErrorSeverity, _filename, + "> Config: Bad value defined for name '{}', going to use '{}' instead", name, Acore::ToString(def)); } @@ -447,7 +601,6 @@ template<> std::string ConfigMgr::GetValueDefault(std::string const& name, std::string const& def, bool showLogs /*= true*/) const { auto const& itr = _configOptions.find(name); - bool fatalConfig = false; bool notFound = itr == _configOptions.end(); auto envVarName = GetEnvVarName(name); Optional envVar = GetEnvFromCache(name, envVarName); @@ -466,23 +619,23 @@ std::string ConfigMgr::GetValueDefault(std::string const& name, std { if (showLogs) { - for (std::string s : _fatalConfigOptions) - if (s == name) - { - fatalConfig = true; - break; - } + bool isCritical = _criticalConfigOptions.find(name) != _criticalConfigOptions.end(); + ConfigSeverity severity = isCritical ? _policy.criticalOptionSeverity : _policy.missingOptionSeverity; - if (fatalConfig) - LOG_FATAL("server.loading", "> Config:\n\nFATAL ERROR: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable.\n\nYour server cannot start without this option!", + if (isCritical) + { + LogWithSeverity(severity, _filename, + "> Config:\n\nFATAL ERROR: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable.\n\nYour server cannot start without this option!", name, _filename, name, def, envVarName); + } else { std::string configs = _filename; if (!_moduleConfigFiles.empty()) configs += " or module config"; - LOG_WARN("server.loading", "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable.", + LogWithSeverity(severity, _filename, + "> Config: Missing property {} in config file {}, add \"{} = {}\" to this file or define '{}' as an environment variable.", name, configs, name, def, envVarName); } } @@ -509,7 +662,8 @@ bool ConfigMgr::GetOption(std::string const& name, bool const& def, bool s { if (showLogs) { - LOG_ERROR("server.loading", "> Config: Bad value defined for name '{}', going to use '{}' instead", + LogWithSeverity(_policy.valueErrorSeverity, _filename, + "> Config: Bad value defined for name '{}', going to use '{}' instead", name, def ? "true" : "false"); } @@ -558,17 +712,27 @@ std::string const ConfigMgr::GetConfigPath() #endif } -void ConfigMgr::Configure(std::string const& initFileName, std::vector args, std::string_view modulesConfigList /*= {}*/) +void ConfigMgr::Configure(std::string const& initFileName, std::vector args, std::string_view modulesConfigList /*= {}*/, ConfigPolicy policy /*= {}*/) { _filename = initFileName; _args = std::move(args); + _policy = policy; + + if (char const* env = std::getenv("AC_CONFIG_POLICY")) + _policy = ApplyPolicyString(_policy, env); + + _policy = ApplyPolicyFromArgs(_policy, _args); + + _additonalFiles.clear(); + _moduleConfigFiles.clear(); // Add modules config if exist if (!modulesConfigList.empty()) { for (auto const& itr : Acore::Tokenize(modulesConfigList, ',', false)) { - _additonalFiles.emplace_back(itr); + if (!itr.empty()) + _additonalFiles.emplace_back(itr); } } } diff --git a/src/common/Configuration/Config.h b/src/common/Configuration/Config.h index ccb35132d..dad439826 100644 --- a/src/common/Configuration/Config.h +++ b/src/common/Configuration/Config.h @@ -18,10 +18,29 @@ #ifndef CONFIG_H #define CONFIG_H +#include #include #include #include +enum class ConfigSeverity : uint8_t +{ + Skip, + Warn, + Error, + Fatal +}; + +struct ConfigPolicy +{ + ConfigSeverity defaultSeverity = ConfigSeverity::Warn; + ConfigSeverity missingFileSeverity = ConfigSeverity::Error; + ConfigSeverity missingOptionSeverity = ConfigSeverity::Warn; + ConfigSeverity criticalOptionSeverity = ConfigSeverity::Fatal; + ConfigSeverity unknownOptionSeverity = ConfigSeverity::Error; + ConfigSeverity valueErrorSeverity = ConfigSeverity::Error; +}; + class ConfigMgr { ConfigMgr() = default; @@ -32,7 +51,7 @@ class ConfigMgr public: bool LoadAppConfigs(bool isReload = false); bool LoadModulesConfigs(bool isReload = false, bool isNeedPrintInfo = true); - void Configure(std::string const& initFileName, std::vector args, std::string_view modulesConfigList = {}); + void Configure(std::string const& initFileName, std::vector args, std::string_view modulesConfigList = {}, ConfigPolicy policy = {}); static ConfigMgr* instance(); diff --git a/src/common/Logging/Log.cpp b/src/common/Logging/Log.cpp index 2b473a873..ba868a6cb 100644 --- a/src/common/Logging/Log.cpp +++ b/src/common/Logging/Log.cpp @@ -211,13 +211,16 @@ void Log::ReadLoggersFromConfig() AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, {}); appenders[appender->getId()].reset(appender); - Logger* rootLogger = new Logger(LOGGER_ROOT, LOG_LEVEL_ERROR); + Logger* rootLogger = new Logger(LOGGER_ROOT, LOG_LEVEL_WARN); rootLogger->addAppender(appender->getId(), appender); loggers[LOGGER_ROOT].reset(rootLogger); Logger* serverLogger = new Logger("server", LOG_LEVEL_INFO); serverLogger->addAppender(appender->getId(), appender); loggers["server"].reset(serverLogger); + + highestLogLevel = LOG_LEVEL_INFO; + return; } } diff --git a/src/server/apps/authserver/Main.cpp b/src/server/apps/authserver/Main.cpp index b5fbb319a..5295685de 100644 --- a/src/server/apps/authserver/Main.cpp +++ b/src/server/apps/authserver/Main.cpp @@ -278,7 +278,8 @@ variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile) ("help,h", "print usage message") ("version,v", "print version build info") ("dry-run,d", "Dry run") - ("config,c", value(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_REALM_CONFIG))), "use as configuration file"); + ("config,c", value(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_REALM_CONFIG))), "use as configuration file") + ("config-policy", value()->value_name("policy"), "override config severity policy (e.g. default=skip,critical_option=fatal)"); variables_map variablesMap; diff --git a/src/server/apps/worldserver/Main.cpp b/src/server/apps/worldserver/Main.cpp index bdc2f860f..56d26bcae 100644 --- a/src/server/apps/worldserver/Main.cpp +++ b/src/server/apps/worldserver/Main.cpp @@ -423,7 +423,7 @@ bool StartDB() MySQL::Library_Init(); // Load databases - DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_NONE, AC_MODULES_LIST); + DatabaseLoader loader("server.worldserver", DatabaseLoader::DATABASE_MASK_ALL, AC_MODULES_LIST); loader .AddDatabase(LoginDatabase, "Login") .AddDatabase(CharacterDatabase, "Character") @@ -433,7 +433,7 @@ bool StartDB() return false; ///- Get the realm Id from the configuration file - realm.Id.Realm = sConfigMgr->GetOption("RealmID", 0); + realm.Id.Realm = sConfigMgr->GetOption("RealmID", 1); if (!realm.Id.Realm) { LOG_ERROR("server.worldserver", "Realm ID not defined in configuration file"); @@ -710,7 +710,8 @@ variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile, [ ("help,h", "print usage message") ("version,v", "print version build info") ("dry-run,d", "Dry run") - ("config,c", value(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use as configuration file"); + ("config,c", value(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use as configuration file") + ("config-policy", value()->value_name("policy"), "override config severity policy (e.g. default=skip,critical_option=fatal)"); #if AC_PLATFORM == AC_PLATFORM_WINDOWS options_description win("Windows platform specific options"); diff --git a/src/server/database/Database/DatabaseLoader.cpp b/src/server/database/Database/DatabaseLoader.cpp index 5ad77d35d..32bbb107f 100644 --- a/src/server/database/Database/DatabaseLoader.cpp +++ b/src/server/database/Database/DatabaseLoader.cpp @@ -24,6 +24,24 @@ #include #include #include +#include +namespace +{ + std::string const EMPTY_DATABASE_INFO; + std::string const LOGIN_DATABASE_INFO_DEFAULT = "127.0.0.1;3306;acore;acore;acore_auth"; + std::string const WORLD_DATABASE_INFO_DEFAULT = "127.0.0.1;3306;acore;acore;acore_world"; + std::string const CHARACTER_DATABASE_INFO_DEFAULT = "127.0.0.1;3306;acore;acore;acore_characters"; + std::string const& GetDefaultDatabaseInfo(std::string_view name) + { + if (name == "Login") + return LOGIN_DATABASE_INFO_DEFAULT; + if (name == "World") + return WORLD_DATABASE_INFO_DEFAULT; + if (name == "Character") + return CHARACTER_DATABASE_INFO_DEFAULT; + return EMPTY_DATABASE_INFO; + } +} DatabaseLoader::DatabaseLoader(std::string const& logger, uint32 const defaultUpdateMask, std::string_view modulesList) : _logger(logger), @@ -38,7 +56,8 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool& pool, std::st _open.push([this, name, updatesEnabledForThis, &pool]() -> bool { - std::string const dbString = sConfigMgr->GetOption(name + "DatabaseInfo", ""); + std::string const& defaultDatabaseInfo = GetDefaultDatabaseInfo(name); + std::string const dbString = sConfigMgr->GetOption(name + "DatabaseInfo", defaultDatabaseInfo); if (dbString.empty()) { LOG_ERROR(_logger, "Database {} not specified in configuration file!", name); diff --git a/src/tools/dbimport/Main.cpp b/src/tools/dbimport/Main.cpp index 87371f62a..0274091a6 100644 --- a/src/tools/dbimport/Main.cpp +++ b/src/tools/dbimport/Main.cpp @@ -109,8 +109,8 @@ bool StartDB() DatabaseLoader loader = modules.empty() ? DatabaseLoader("dbimport") : - (modules == "all") ? DatabaseLoader("dbimport", DatabaseLoader::DATABASE_NONE, AC_MODULES_LIST) : - DatabaseLoader("dbimport", DatabaseLoader::DATABASE_NONE, modules); + (modules == "all") ? DatabaseLoader("dbimport", DatabaseLoader::DATABASE_MASK_ALL, AC_MODULES_LIST) : + DatabaseLoader("dbimport", DatabaseLoader::DATABASE_MASK_ALL, modules); loader .AddDatabase(LoginDatabase, "Login") @@ -140,7 +140,8 @@ variables_map GetConsoleArguments(int argc, char** argv, fs::path& configFile) ("help,h", "print usage message") ("version,v", "print version build info") ("dry-run,d", "Dry run") - ("config,c", value(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_DB_IMPORT_CONFIG))), "use as configuration file"); + ("config,c", value(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_DB_IMPORT_CONFIG))), "use as configuration file") + ("config-policy", value()->value_name("policy"), "override config severity policy (e.g. default=skip,critical_option=fatal)"); variables_map variablesMap; From f95dabdfb908c34f38d12fe3eb8cbbc74799e238 Mon Sep 17 00:00:00 2001 From: killerwife Date: Sat, 25 Oct 2025 11:00:55 +0200 Subject: [PATCH 2/4] Spell/GameObject: Fix flying upon teleport between map initiated from GO (#23390) --- src/server/game/Entities/GameObject/GameObject.cpp | 12 +++++++++--- src/server/game/Entities/Player/Player.cpp | 11 ----------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 08d2abdc5..4df7d36f4 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1466,7 +1466,7 @@ void GameObject::Use(Unit* user) // by default spell caster is user Unit* spellCaster = user; uint32 spellId = 0; - bool triggered = false; + uint32 triggeredFlags = TRIGGERED_NONE; if (Player* playerUser = user->ToPlayer()) { @@ -1486,6 +1486,10 @@ void GameObject::Use(Unit* user) m_cooldownTime = GameTime::GetGameTimeMS().count() + cooldown * IN_MILLISECONDS; } + if (user->IsPlayer() && GetGoType() != GAMEOBJECT_TYPE_TRAP) // workaround for GO casting + if (!m_goInfo->IsUsableMounted()) + user->RemoveAurasByType(SPELL_AURA_MOUNTED); + switch (GetGoType()) { case GAMEOBJECT_TYPE_DOOR: //0 @@ -1886,7 +1890,6 @@ void GameObject::Use(Unit* user) } } - user->RemoveAurasByType(SPELL_AURA_MOUNTED); spellId = info->spellcaster.spellId; break; } @@ -2056,12 +2059,15 @@ void GameObject::Use(Unit* user) return; } + if (m_goInfo->IsUsableMounted()) + triggeredFlags |= TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE; + if (Player* player = user->ToPlayer()) sOutdoorPvPMgr->HandleCustomSpell(player, spellId, this); if (spellCaster) { - if ((spellCaster->CastSpell(user, spellInfo, triggered) == SPELL_CAST_OK) && GetGoType() == GAMEOBJECT_TYPE_SPELLCASTER) + if ((spellCaster->CastSpell(user, spellInfo, TriggerCastFlags(triggeredFlags)) == SPELL_CAST_OK) && GetGoType() == GAMEOBJECT_TYPE_SPELLCASTER) AddUse(); } else diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e4e703492..beb0bc431 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -1573,17 +1573,6 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (oldmap) oldmap->RemovePlayerFromMap(this, false); - // xinef: do this before setting fall information! - if (IsMounted() && (!GetMap()->GetEntry()->IsDungeon() && !GetMap()->GetEntry()->IsBattlegroundOrArena()) && !m_transport) - { - AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_MOUNTED); - if (!auras.empty()) - { - SetMountBlockId((*auras.begin())->GetId()); - RemoveAurasByType(SPELL_AURA_MOUNTED); - } - } - teleportStore_dest = WorldLocation(mapid, x, y, z, orientation); SetFallInformation(GameTime::GetGameTime().count(), z); // if the player is saved before worldportack (at logout for example) From da9c3a53ce7295b31dd557687d991d6ecdf2a554 Mon Sep 17 00:00:00 2001 From: Rocco Silipo <108557877+Rorschach91@users.noreply.github.com> Date: Sat, 25 Oct 2025 12:23:30 +0200 Subject: [PATCH 3/4] fix(DB/AI): Disclosure quest now works as intended. (#23384) --- .../updates/pending_db_world/Disclosure.sql | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 data/sql/updates/pending_db_world/Disclosure.sql diff --git a/data/sql/updates/pending_db_world/Disclosure.sql b/data/sql/updates/pending_db_world/Disclosure.sql new file mode 100644 index 000000000..5d334f5c7 --- /dev/null +++ b/data/sql/updates/pending_db_world/Disclosure.sql @@ -0,0 +1,86 @@ + +-- Delete old Waypoint and add new ones +DELETE FROM `waypoints` WHERE (`entry` IN (28948)); + +DELETE FROM `waypoint_data` WHERE (`id` IN (2894800, 2894801, 2894802, 2894803, 2894804, 2894805)); +INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES +(2894800, 1, 6232.341, -1965.3967, 484.76993, NULL, 0, 0, 0, 100, 0), +(2894800, 2, 6218.6577, -1962.0309, 484.85934, NULL, 0, 0, 0, 100, 0), +(2894801, 1, 6191.6187, -1930.0017, 485.06897, NULL, 0, 0, 0, 100, 0), +(2894801, 2, 6175.131, -1934.6721, 484.8741, NULL, 0, 0, 0, 100, 0), +(2894801, 3, 6156.749, -1953.0284, 484.90906, NULL, 0, 0, 0, 100, 0), +(2894802, 1, 6119.237, -1976.635, 484.8796, NULL, 0, 0, 0, 100, 0), +(2894802, 2, 6093.954, -1990.4447, 484.8646, NULL, 0, 0, 0, 100, 0), +(2894802, 3, 6089.3467, -2014.2975, 484.85828, NULL, 0, 0, 0, 100, 0), +(2894802, 4, 6113.093, -2041.1102, 484.8815, NULL, 0, 0, 0, 100, 0), +(2894802, 5, 6108.405, -2060.9314, 484.76993, NULL, 0, 0, 0, 100, 0), +(2894803, 1, 6136.712, -2078.5974, 484.86215, NULL, 0, 0, 0, 100, 0), +(2894803, 2, 6157.7085, -2107.486, 485.07727, NULL, 0, 0, 0, 100, 0), +(2894803, 3, 6156.6816, -2122.8438, 485.18344, NULL, 0, 0, 0, 100, 0), +(2894803, 4, 6141.0166, -2128.8904, 485.348, NULL, 0, 0, 0, 100, 0), +(2894803, 5, 6143.3594, -2127.986, 485.39215, NULL, 0, 0, 0, 100, 0), +(2894803, 6, 6118.48, -2123.0764, 473.51685, NULL, 0, 0, 0, 100, 0), +(2894803, 7, 6121.2275, -2108.0781, 473.54965, NULL, 0, 0, 0, 100, 0), +(2894803, 8, 6146.223, -2111.0583, 461.30115, NULL, 0, 0, 0, 100, 0), +(2894803, 9, 6156.9985, -2110.611, 461.30157, NULL, 0, 0, 0, 100, 0), +(2894803, 10, 6160.259, -2087.5088, 461.30212, NULL, 0, 0, 0, 100, 0), +(2894803, 11, 6148.678, -2072.7812, 461.303, NULL, 0, 0, 0, 100, 0), +(2894804, 1, 6144.377, -2044.998, 460.9487, NULL, 0, 0, 0, 100, 0), +(2894804, 2, 6139.7783, -2046.457, 461.30005, NULL, 0, 0, 0, 100, 0), +(2894805, 1, 6161.379, -2028.9777, 458.94113, NULL, 0, 0, 0, 100, 0), +(2894805, 2, 6172.3604, -2019.7084, 455.11356, NULL, 0, 0, 0, 100, 0); + +-- Change Emotes +UPDATE `creature_text` SET `Emote` = 4 WHERE (`CreatureID` = 28948) AND (`GroupID` IN (0)); +UPDATE `creature_text` SET `Emote` = 396 WHERE (`CreatureID` = 28948) AND (`GroupID` IN (1)); +UPDATE `creature_text` SET `Emote` = 5 WHERE (`CreatureID` = 28948) AND (`GroupID` IN (3, 12)); +UPDATE `creature_text` SET `Emote` = 2 WHERE (`CreatureID` = 28948) AND (`GroupID` IN (14)); + +-- Set SmartAI +UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 28948; + +DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 28948); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(28948, 0, 0, 1, 54, 0, 100, 0, 0, 0, 0, 0, 0, 0, 64, 25, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - On Just Summoned - Store Targetlist'), +(28948, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 80, 2894800, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - On Just Summoned - Run Script'), +(28948, 0, 2, 0, 109, 0, 100, 0, 0, 2894800, 0, 0, 0, 0, 80, 2894801, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - On Path 2894800 Finished - Run Script'), +(28948, 0, 3, 0, 109, 0, 100, 0, 0, 2894801, 0, 0, 0, 0, 80, 2894802, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - On Path 2894801 Finished - Run Script'), +(28948, 0, 4, 0, 109, 0, 100, 0, 0, 2894802, 0, 0, 0, 0, 80, 2894803, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - On Path 2894802 Finished - Run Script'), +(28948, 0, 5, 0, 109, 0, 100, 0, 0, 2894803, 0, 0, 0, 0, 80, 2894804, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - On Path 2894803 Finished - Run Script'), +(28948, 0, 6, 0, 109, 0, 100, 0, 0, 2894804, 0, 0, 0, 0, 80, 2894805, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - On Path 2894804 Finished - Run Script'), +(28948, 0, 7, 0, 109, 0, 100, 0, 0, 2894805, 0, 0, 0, 0, 80, 2894806, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - On Path 2894805 Finished - Run Script'); + +-- Set Action Lists +DELETE FROM `smart_scripts` WHERE (`source_type` = 9) AND (`entryorguid` IN (2894800, 2894801, 2894802, 2894803, 2894804, 2894805, 2894806)); +INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES +(2894800, 9, 0, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Set Orientation Stored'), +(2894800, 9, 1, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 0'), +(2894800, 9, 2, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 1'), +(2894800, 9, 3, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 232, 2894800, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Start Path 2894800'), +(2894801, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Set Orientation Stored'), +(2894801, 9, 1, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 2'), +(2894801, 9, 2, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 0, 232, 2894801, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Start Path 2894801'), +(2894802, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Set Orientation Stored'), +(2894802, 9, 1, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 3'), +(2894802, 9, 2, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 232, 2894802, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Start Path 2894802'), +(2894803, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 4'), +(2894803, 9, 1, 0, 0, 0, 100, 0, 8000, 8000, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Set Orientation Stored'), +(2894803, 9, 2, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 5, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 5'), +(2894803, 9, 3, 0, 0, 0, 100, 0, 3000, 3000, 0, 0, 0, 0, 232, 2894803, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Start Path 2894803'), +(2894804, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 6, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 6'), +(2894804, 9, 1, 0, 0, 0, 100, 0, 8000, 8000, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Set Orientation Stored'), +(2894804, 9, 2, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 7, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 7'), +(2894804, 9, 3, 0, 0, 0, 100, 0, 4000, 4000, 0, 0, 0, 0, 232, 2894804, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Start Path 2894804'), +(2894805, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 8'), +(2894805, 9, 1, 0, 0, 0, 100, 0, 6000, 6000, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Set Orientation Stored'), +(2894805, 9, 2, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 9, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 9'), +(2894805, 9, 3, 0, 0, 0, 100, 0, 9000, 9000, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 19, 28931, 30, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Set Orientation Closest Creature \'Blightblood Troll\''), +(2894805, 9, 4, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 10, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 10'), +(2894805, 9, 5, 0, 0, 0, 100, 0, 7000, 7000, 0, 0, 0, 0, 1, 11, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 11'), +(2894805, 9, 6, 0, 0, 0, 100, 0, 8000, 8000, 0, 0, 0, 0, 232, 2894805, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Start Path 2894805'), +(2894806, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Set Orientation Stored'), +(2894806, 9, 1, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 1, 12, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 12'), +(2894806, 9, 2, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 0, 1, 13, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 13'), +(2894806, 9, 3, 0, 0, 0, 100, 0, 5000, 5000, 0, 0, 0, 0, 1, 14, 0, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Say Line 14'), +(2894806, 9, 4, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 0, 11, 53101, 2, 0, 0, 0, 0, 12, 25, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Cast \'Kill Credit\''), +(2894806, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 41, 2000, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Malmortis - Actionlist - Despawn In 2000 ms'); From b7a0fb6466c6d5bf7ac4d94e7104dff254989344 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 25 Oct 2025 10:24:40 +0000 Subject: [PATCH 4/4] chore(DB): import pending files Referenced commit(s): da9c3a53ce7295b31dd557687d991d6ecdf2a554 --- .../Disclosure.sql => db_world/2025_10_25_00.sql} | 1 + 1 file changed, 1 insertion(+) rename data/sql/updates/{pending_db_world/Disclosure.sql => db_world/2025_10_25_00.sql} (99%) diff --git a/data/sql/updates/pending_db_world/Disclosure.sql b/data/sql/updates/db_world/2025_10_25_00.sql similarity index 99% rename from data/sql/updates/pending_db_world/Disclosure.sql rename to data/sql/updates/db_world/2025_10_25_00.sql index 5d334f5c7..bef1087a9 100644 --- a/data/sql/updates/pending_db_world/Disclosure.sql +++ b/data/sql/updates/db_world/2025_10_25_00.sql @@ -1,3 +1,4 @@ +-- DB update 2025_10_24_05 -> 2025_10_25_00 -- Delete old Waypoint and add new ones DELETE FROM `waypoints` WHERE (`entry` IN (28948));