Merge branch 'master' into fix/raise-ally-target-check

This commit is contained in:
Luca Folloni 2025-10-26 12:07:48 +01:00 committed by GitHub
commit 05a27d11c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
42 changed files with 896 additions and 440 deletions

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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"
;;

View File

@ -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 "$@"

View File

@ -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 <VAR_NAME>"
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 $?
}

View File

@ -183,3 +183,5 @@ function inst_download_client_data {
&& echo "Remove downloaded file" && rm "$zipPath" \
&& echo "INSTALLED_VERSION=$VERSION" > "$dataVersionFile"
}

View File

@ -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"

View File

@ -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 <search|install|update|remove> [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 $?
}
# =============================================================================
@ -683,7 +648,7 @@ function inst_getVersionBranch() {
res="none"
# since we've the pair version,branch alternated in not associative and one-dimensional
# array, we've to simulate the association with length/2 trick
for idx in `seq 0 $((${#vers[*]}/2-1))`; do
for idx in $(seq 0 $((${#vers[*]}/2-1))); do
semverParseInto "${vers[idx*2]}" MODULE_MAJOR MODULE_MINOR MODULE_PATCH MODULE_SPECIAL
if [[ $MODULE_MAJOR -eq $ACV_MAJOR && $MODULE_MINOR -le $ACV_MINOR ]]; then
res="${vers[idx*2+1]}"

View File

@ -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

View File

@ -751,5 +751,5 @@ EOF
run inst_module "unknown-command"
[ "$status" -eq 1 ]
[[ "$output" =~ "Unknown module command" ]]
[[ "$output" =~ "Invalid option" ]]
}

View File

@ -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"

36
conf/dist/config.sh vendored
View File

@ -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

View File

@ -0,0 +1,87 @@
-- DB update 2025_10_24_05 -> 2025_10_25_00
-- 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');

View File

@ -0,0 +1,8 @@
-- DB update 2025_10_25_00 -> 2025_10_25_01
--
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 27970;
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 27970);
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
(27970, 0, 0, 0, 0, 0, 100, 2, 3000, 9000, 16000, 16000, 0, 0, 11, 51819, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Raging Construct - In Combat - Cast \'Potent Jolt\' (Normal Dungeon)'),
(27970, 0, 1, 0, 0, 0, 100, 4, 3000, 9000, 16000, 16000, 0, 0, 11, 61514, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Raging Construct - In Combat - Cast \'Potent Jolt\' (Heroic Dungeon)'),
(27970, 0, 2, 0, 0, 0, 100, 6, 4000, 7000, 9000, 12000, 0, 0, 11, 28168, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Raging Construct - In Combat - Cast \'Arcing Smash\' (Dungeon)');

View File

@ -0,0 +1,5 @@
function isTrue() {
local val
val=$(echo "$1" | tr '[:upper:]' '[:lower:]')
[[ "$val" == "1" || "$val" == "true" || "$val" == "yes" || "$val" == "on" ]]
}

101
doc/ConfigPolicy.md Normal file
View File

@ -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.

View File

@ -21,10 +21,14 @@
#include "StringFormat.h"
#include "Tokenize.h"
#include "Util.h"
#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <fstream>
#include <locale>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
namespace
{
@ -34,13 +38,14 @@ namespace
std::unordered_map<std::string /*name*/, std::string /*value*/> _configOptions;
std::unordered_map<std::string /*name*/, std::string /*value*/> _envVarCache;
std::mutex _configLock;
ConfigPolicy _policy;
std::vector<std::string> _fatalConfigOptions =
std::unordered_set<std::string> _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<ConfigSeverity> 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<typename Format, typename... Args>
inline void PrintError(std::string_view filename, Format&& fmt, Args&& ... args)
{
@ -77,6 +105,138 @@ namespace
}
}
template<typename Format, typename... Args>
inline void LogWithSeverity(ConfigSeverity severity, std::string_view filename, Format&& fmt, Args&&... args)
{
std::string message = Acore::StringFormat(std::forward<Format>(fmt), std::forward<Args>(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<std::pair<std::string, ConfigSeverity>> overrides;
Optional<ConfigSeverity> 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<std::string> 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<std::string> 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>(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<std::string> envVar = GetEnvFromCache(name, envVarName);
@ -466,23 +619,23 @@ std::string ConfigMgr::GetValueDefault<std::string>(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<bool>(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<std::string> args, std::string_view modulesConfigList /*= {}*/)
void ConfigMgr::Configure(std::string const& initFileName, std::vector<std::string> 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);
}
}
}

View File

@ -18,10 +18,29 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <cstdint>
#include <stdexcept>
#include <string_view>
#include <vector>
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<std::string> args, std::string_view modulesConfigList = {});
void Configure(std::string const& initFileName, std::vector<std::string> args, std::string_view modulesConfigList = {}, ConfigPolicy policy = {});
static ConfigMgr* instance();

View File

@ -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;
}
}

View File

@ -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<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_REALM_CONFIG))), "use <arg> as configuration file");
("config,c", value<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_REALM_CONFIG))), "use <arg> as configuration file")
("config-policy", value<std::string>()->value_name("policy"), "override config severity policy (e.g. default=skip,critical_option=fatal)");
variables_map variablesMap;

View File

@ -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<uint32>("RealmID", 0);
realm.Id.Realm = sConfigMgr->GetOption<uint32>("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<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use <arg> as configuration file");
("config,c", value<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_CORE_CONFIG))), "use <arg> as configuration file")
("config-policy", value<std::string>()->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");

View File

@ -24,6 +24,24 @@
#include <errmsg.h>
#include <mysqld_error.h>
#include <thread>
#include <string_view>
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<T>& pool, std::st
_open.push([this, name, updatesEnabledForThis, &pool]() -> bool
{
std::string const dbString = sConfigMgr->GetOption<std::string>(name + "DatabaseInfo", "");
std::string const& defaultDatabaseInfo = GetDefaultDatabaseInfo(name);
std::string const dbString = sConfigMgr->GetOption<std::string>(name + "DatabaseInfo", defaultDatabaseInfo);
if (dbString.empty())
{
LOG_ERROR(_logger, "Database {} not specified in configuration file!", name);

View File

@ -1999,7 +1999,7 @@ void Creature::setDeathState(DeathState state, bool despawn)
bool needsFalling = !despawn && (IsFlying() || IsHovering()) && !IsUnderWater();
SetHover(false);
SetDisableGravity(false, false, false);
SetDisableGravity(false);
if (needsFalling)
GetMotionMaster()->MoveFall(0, true);
@ -3230,47 +3230,6 @@ bool Creature::SetWalk(bool enable)
return true;
}
/**
* @brief Enable or disable the creature's fly mode by adding or removing: MOVEMENTFLAG_FLYING. Infom also the client
*/
bool Creature::SetDisableGravity(bool disable, bool packetOnly /*= false*/, bool updateAnimationTier /*= true*/)
{
//! It's possible only a packet is sent but moveflags are not updated
//! Need more research on this
if (!packetOnly && !Unit::SetDisableGravity(disable))
return false;
if (m_movedByPlayer)
{
WorldPacket data(disable ? SMSG_MOVE_GRAVITY_DISABLE : SMSG_MOVE_GRAVITY_ENABLE, 12);
data << GetPackGUID();
data << m_movedByPlayer->ToPlayer()->GetSession()->GetOrderCounter(); // movement counter
m_movedByPlayer->ToPlayer()->SendDirectMessage(&data);
m_movedByPlayer->ToPlayer()->GetSession()->IncrementOrderCounter();
data.Initialize(MSG_MOVE_GRAVITY_CHNG, 64);
data << GetPackGUID();
BuildMovementPacket(&data);
m_movedByPlayer->ToPlayer()->SendMessageToSet(&data, false);
return true;
}
if (updateAnimationTier && IsAlive() && !HasUnitState(UNIT_STATE_ROOT) && !IsRooted())
{
if (IsLevitating())
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_FLY);
else if (IsHovering())
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_HOVER);
else
SetByteValue(UNIT_FIELD_BYTES_1, UNIT_BYTES_1_OFFSET_ANIM_TIER, UNIT_BYTE1_FLAG_GROUND);
}
WorldPacket data(disable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE, 9);
data << GetPackGUID();
SendMessageToSet(&data, false);
return true;
}
bool Creature::SetSwim(bool enable)
{
if (!Unit::SetSwim(enable))
@ -3385,19 +3344,23 @@ void Creature::UpdateMovementFlags()
if (GetMovementTemplate().IsFlightAllowed() && isInAir && !IsFalling())
{
if (GetMovementTemplate().Flight == CreatureFlightMovementType::CanFly)
if (GetMovementTemplate().Flight == CreatureFlightMovementType::CanFly && !m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY))
SetCanFly(true);
else
else if (!IsLevitating())
SetDisableGravity(true);
if (!HasHoverAura())
if (!HasHoverAura() && IsHovering())
SetHover(false);
}
else
{
SetCanFly(false);
SetDisableGravity(false);
if (IsAlive() && (CanHover() || HasHoverAura()))
if (m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY))
SetCanFly(false);
if (IsLevitating())
SetDisableGravity(false);
if (IsAlive() && (GetMovementTemplate().Ground == CreatureGroundMovementType::Hover || HasHoverAura()) && !IsHovering())
SetHover(true);
}

View File

@ -83,7 +83,7 @@ public:
[[nodiscard]] bool CanWalk() const { return GetMovementTemplate().IsGroundAllowed(); }
[[nodiscard]] bool CanSwim() const override;
[[nodiscard]] bool CanEnterWater() const override;
[[nodiscard]] bool CanFly() const override { return GetMovementTemplate().IsFlightAllowed() || IsFlying(); }
[[nodiscard]] bool CanFly() const override { return GetMovementTemplate().IsFlightAllowed() || IsFlying(); }
[[nodiscard]] bool CanHover() const { return GetMovementTemplate().Ground == CreatureGroundMovementType::Hover || IsHovering(); }
[[nodiscard]] bool IsRooted() const { return GetMovementTemplate().IsRooted(); }
@ -145,7 +145,6 @@ public:
[[nodiscard]] CreatureAI* AI() const { return (CreatureAI*)i_AI; }
bool SetWalk(bool enable) override;
bool SetDisableGravity(bool disable, bool packetOnly = false, bool updateAnimationTier = true) override;
bool SetSwim(bool enable) override;
bool HasSpellFocus(Spell const* focusSpell = nullptr) const;

View File

@ -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

View File

@ -417,6 +417,8 @@ Player::Player(WorldSession* session): Unit(), m_mover(this)
GetObjectVisibilityContainer().InitForPlayer();
sScriptMgr->OnConstructPlayer(this);
m_expectingChangeTransport = false;
}
Player::~Player()
@ -1573,17 +1575,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)
@ -11704,7 +11695,7 @@ void Player::SendInitialPacketsAfterAddToMap()
// manual send package (have code in HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true); that must not be re-applied.
if (IsImmobilizedState())
{
auto const counter = GetSession()->GetOrderCounter();
uint32 const counter = GetSession()->GetOrderCounter();
setCompoundState << uint8(2 + GetPackGUID().size() + 4);
setCompoundState << uint16(SMSG_FORCE_MOVE_ROOT);
setCompoundState << GetPackGUID();
@ -11714,7 +11705,7 @@ void Player::SendInitialPacketsAfterAddToMap()
if (HasAuraType(SPELL_AURA_FEATHER_FALL))
{
auto const counter = GetSession()->GetOrderCounter();
uint32 const counter = GetSession()->GetOrderCounter();
setCompoundState << uint8(2 + GetPackGUID().size() + 4);
setCompoundState << uint16(SMSG_MOVE_FEATHER_FALL);
setCompoundState << GetPackGUID();
@ -11724,7 +11715,7 @@ void Player::SendInitialPacketsAfterAddToMap()
if (HasAuraType(SPELL_AURA_WATER_WALK))
{
auto const counter = GetSession()->GetOrderCounter();
uint32 const counter = GetSession()->GetOrderCounter();
setCompoundState << uint8(2 + GetPackGUID().size() + 4);
setCompoundState << uint16(SMSG_MOVE_WATER_WALK);
setCompoundState << GetPackGUID();
@ -11734,7 +11725,7 @@ void Player::SendInitialPacketsAfterAddToMap()
if (HasAuraType(SPELL_AURA_HOVER))
{
auto const counter = GetSession()->GetOrderCounter();
uint32 const counter = GetSession()->GetOrderCounter();
setCompoundState << uint8(2 + GetPackGUID().size() + 4);
setCompoundState << uint16(SMSG_MOVE_SET_HOVER);
setCompoundState << GetPackGUID();
@ -16034,24 +16025,6 @@ bool Player::IsInWhisperWhiteList(ObjectGuid guid)
return false;
}
bool Player::SetDisableGravity(bool disable, bool packetOnly /*= false*/, bool /*updateAnimationTier = true*/)
{
if (!packetOnly && !Unit::SetDisableGravity(disable))
return false;
WorldPacket data(disable ? SMSG_MOVE_GRAVITY_DISABLE : SMSG_MOVE_GRAVITY_ENABLE, 12);
data << GetPackGUID();
data << GetSession()->GetOrderCounter(); // movement counter
SendDirectMessage(&data);
GetSession()->IncrementOrderCounter();
data.Initialize(MSG_MOVE_GRAVITY_CHNG, 64);
data << GetPackGUID();
BuildMovementPacket(&data);
SendMessageToSet(&data, false);
return true;
}
Guild* Player::GetGuild() const
{
uint32 guildId = GetGuildId();

View File

@ -2566,8 +2566,6 @@ public:
bool IsInWhisperWhiteList(ObjectGuid guid);
void RemoveFromWhisperWhiteList(ObjectGuid guid) { WhisperList.remove(guid); }
bool SetDisableGravity(bool disable, bool packetOnly = false, bool updateAnimationTier = true) override;
[[nodiscard]] bool CanFly() const override { return m_movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY); }
[[nodiscard]] bool CanEnterWater() const override { return true; }
bool IsFreeFlying() const { return HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || HasAuraType(SPELL_AURA_FLY); }
@ -2635,6 +2633,9 @@ public:
std::string GetDebugInfo() const override;
bool IsExpectingChangeTransport() const { return m_expectingChangeTransport; }
void SetExpectingChangeTransport(bool state) { m_expectingChangeTransport = state; }
/*********************************************************/
/*** SPELL QUEUE SYSTEM ***/
/*********************************************************/
@ -3015,6 +3016,8 @@ private:
PlayerSettingMap m_charSettingsMap;
Seconds m_creationTime;
bool m_expectingChangeTransport;
};
void AddItemsSetItem(Player* player, Item* item);

View File

@ -14523,116 +14523,55 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
propagateSpeedChange();
WorldPacket data;
if (!forced)
{
switch (mtype)
{
case MOVE_WALK:
data.Initialize(MSG_MOVE_SET_WALK_SPEED, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
case MOVE_RUN:
data.Initialize(MSG_MOVE_SET_RUN_SPEED, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
case MOVE_RUN_BACK:
data.Initialize(MSG_MOVE_SET_RUN_BACK_SPEED, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
case MOVE_SWIM:
data.Initialize(MSG_MOVE_SET_SWIM_SPEED, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
case MOVE_SWIM_BACK:
data.Initialize(MSG_MOVE_SET_SWIM_BACK_SPEED, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
case MOVE_TURN_RATE:
data.Initialize(MSG_MOVE_SET_TURN_RATE, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
case MOVE_FLIGHT:
data.Initialize(MSG_MOVE_SET_FLIGHT_SPEED, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
case MOVE_FLIGHT_BACK:
data.Initialize(MSG_MOVE_SET_FLIGHT_BACK_SPEED, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
case MOVE_PITCH_RATE:
data.Initialize(MSG_MOVE_SET_PITCH_RATE, 8 + 4 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4);
break;
default:
LOG_ERROR("entities.unit", "Unit::SetSpeed: Unsupported move type ({}), data not sent to client.", mtype);
return;
}
SpeedOpcodePair const& speedOpcodes = SetSpeed2Opc_table[mtype];
if (forced && IsClientControlled())
{
Player* player = const_cast<Player*>(GetClientControlling());
uint32 const counter = player->GetSession()->GetOrderCounter();
// register forced speed changes for WorldSession::HandleForceSpeedChangeAck
// and do it only for real sent packets and use run for run/mounted as client expected
++player->m_forced_speed_changes[mtype];
WorldPacket data(speedOpcodes[static_cast<size_t>(SpeedOpcodeIndex::PC)], 18);
data << GetPackGUID();
data << counter;
if (mtype == MOVE_RUN)
data << uint8(0); // new 2.1.0
data << GetSpeed(mtype);
player->GetSession()->SendPacket(&data);
player->GetSession()->IncrementOrderCounter();
}
else if (forced)
{
WorldPacket data(speedOpcodes[static_cast<size_t>(SpeedOpcodeIndex::NPC)], 12);
data << GetPackGUID();
BuildMovementPacket(&data);
data << float(GetSpeed(mtype));
SendMessageToSet(&data, true);
}
else
if (IsPlayer())
{
if (IsPlayer())
// Xinef: update speed of pet also
if (!IsInCombat())
{
// register forced speed changes for WorldSession::HandleForceSpeedChangeAck
// and do it only for real sent packets and use run for run/mounted as client expected
++ToPlayer()->m_forced_speed_changes[mtype];
Unit* pet = ToPlayer()->GetPet();
if (!pet)
pet = GetCharm();
// Xinef: update speed of pet also
if (!IsInCombat())
{
Unit* pet = ToPlayer()->GetPet();
if (!pet)
pet = GetCharm();
// xinef: do not affect vehicles and possesed pets
if (pet && (pet->HasUnitFlag(UNIT_FLAG_POSSESSED) || pet->IsVehicle()))
pet = nullptr;
// xinef: do not affect vehicles and possesed pets
if (pet && (pet->HasUnitFlag(UNIT_FLAG_POSSESSED) || pet->IsVehicle()))
pet = nullptr;
if (pet && pet->IsCreature() && !pet->IsInCombat() && pet->GetMotionMaster()->GetCurrentMovementGeneratorType() == FOLLOW_MOTION_TYPE)
pet->UpdateSpeed(mtype, forced);
if (pet && pet->IsCreature() && !pet->IsInCombat() && pet->GetMotionMaster()->GetCurrentMovementGeneratorType() == FOLLOW_MOTION_TYPE)
pet->UpdateSpeed(mtype, forced);
if (Unit* critter = ObjectAccessor::GetUnit(*this, GetCritterGUID()))
critter->UpdateSpeed(mtype, forced);
}
ToPlayer()->SetCanTeleport(true);
if (Unit* critter = ObjectAccessor::GetUnit(*this, GetCritterGUID()))
critter->UpdateSpeed(mtype, forced);
}
switch (mtype)
{
case MOVE_WALK:
data.Initialize(SMSG_FORCE_WALK_SPEED_CHANGE, 16);
break;
case MOVE_RUN:
data.Initialize(SMSG_FORCE_RUN_SPEED_CHANGE, 17);
break;
case MOVE_RUN_BACK:
data.Initialize(SMSG_FORCE_RUN_BACK_SPEED_CHANGE, 16);
break;
case MOVE_SWIM:
data.Initialize(SMSG_FORCE_SWIM_SPEED_CHANGE, 16);
break;
case MOVE_SWIM_BACK:
data.Initialize(SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, 16);
break;
case MOVE_TURN_RATE:
data.Initialize(SMSG_FORCE_TURN_RATE_CHANGE, 16);
break;
case MOVE_FLIGHT:
data.Initialize(SMSG_FORCE_FLIGHT_SPEED_CHANGE, 16);
break;
case MOVE_FLIGHT_BACK:
data.Initialize(SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, 16);
break;
case MOVE_PITCH_RATE:
data.Initialize(SMSG_FORCE_PITCH_RATE_CHANGE, 16);
break;
default:
LOG_ERROR("entities.unit", "Unit::SetSpeed: Unsupported move type ({}), data not sent to client.", mtype);
return;
}
data << GetPackGUID();
data << (IsPlayer() ? ToPlayer()->GetSession()->GetOrderCounter() : uint32(0)); // movement counter
if (mtype == MOVE_RUN)
data << uint8(0); // new 2.1.0
data << float(GetSpeed(mtype));
SendMessageToSet(&data, true);
if (IsPlayer()) // TODO: Resolve this mess
ToPlayer()->GetSession()->IncrementOrderCounter();
ToPlayer()->SetCanTeleport(true);
}
}
@ -18343,7 +18282,7 @@ void Unit::SendMoveRoot(bool apply)
// Wrath+ force root: when unit is controlled by a player
else
{
auto const counter = client->GetSession()->GetOrderCounter();
uint32 const counter = client->GetSession()->GetOrderCounter();
WorldPacket data(apply ? SMSG_FORCE_MOVE_ROOT : SMSG_FORCE_MOVE_UNROOT, guid.size() + 4);
data << guid;
@ -19603,6 +19542,9 @@ void Unit::_ExitVehicle(Position const* exitPosition)
if (!vehicleBase)
return;
if (IsPlayer())
ToPlayer()->SetExpectingChangeTransport(true);
SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT
Position pos;
@ -20381,22 +20323,39 @@ bool Unit::SetWalk(bool enable)
return true;
}
bool Unit::SetDisableGravity(bool disable, bool /*packetOnly = false*/, bool /*updateAnimationTier = true*/)
void Unit::SetDisableGravity(bool enable)
{
if (disable == IsLevitating())
return false;
bool isClientControlled = IsClientControlled();
if (disable)
if (!isClientControlled)
{
AddUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING);
}
else
{
RemoveUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
if (enable)
m_movementInfo.AddMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
else
m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
}
return true;
if (!IsInWorld()) // is sent on add to map
return;
if (isClientControlled)
{
if (Player const* player = GetClientControlling())
{
uint32 const counter = player->GetSession()->GetOrderCounter();
WorldPacket data(enable ? SMSG_MOVE_GRAVITY_DISABLE : SMSG_MOVE_GRAVITY_ENABLE, GetPackGUID().size() + 4);
data << GetPackGUID();
data << counter;
player->GetSession()->SendPacket(&data);
player->GetSession()->IncrementOrderCounter();
return;
}
}
WorldPacket data(enable ? SMSG_SPLINE_MOVE_GRAVITY_DISABLE : SMSG_SPLINE_MOVE_GRAVITY_ENABLE, 9);
data << GetPackGUID();
SendMessageToSet(&data, true);
}
bool Unit::SetSwim(bool enable)
@ -20443,7 +20402,7 @@ void Unit::SetCanFly(bool enable)
{
if (Player const* player = GetClientControlling())
{
auto const counter = player->GetSession()->GetOrderCounter();
uint32 const counter = player->GetSession()->GetOrderCounter();
WorldPacket data(enable ? SMSG_MOVE_SET_CAN_FLY : SMSG_MOVE_UNSET_CAN_FLY, GetPackGUID().size() + 4);
data << GetPackGUID();
@ -20478,7 +20437,7 @@ void Unit::SetFeatherFall(bool enable)
{
if (Player const* player = GetClientControlling())
{
auto const counter = player->GetSession()->GetOrderCounter();
uint32 const counter = player->GetSession()->GetOrderCounter();
WorldPacket data(enable ? SMSG_MOVE_FEATHER_FALL : SMSG_MOVE_NORMAL_FALL, GetPackGUID().size() + 4);
@ -20538,7 +20497,7 @@ void Unit::SetHover(bool enable)
{
WorldPacket data(enable ? SMSG_MOVE_SET_HOVER : SMSG_MOVE_UNSET_HOVER, GetPackGUID().size() + 4);
auto const counter = player->GetSession()->GetOrderCounter();
uint32 const counter = player->GetSession()->GetOrderCounter();
data << GetPackGUID();
data << counter;
@ -20572,7 +20531,7 @@ void Unit::SetWaterWalking(bool enable)
{
if (Player const* player = GetClientControlling())
{
auto const counter = player->GetSession()->GetOrderCounter();
uint32 const counter = player->GetSession()->GetOrderCounter();
WorldPacket data(enable ? SMSG_MOVE_WATER_WALK : SMSG_MOVE_LAND_WALK, GetPackGUID().size() + 4);
data << GetPackGUID();

View File

@ -624,6 +624,28 @@ typedef std::unordered_map<uint32, uint32> PacketCooldowns;
struct SpellProcEventEntry; // used only privately
enum class SpeedOpcodeIndex : uint32
{
PC,
NPC,
ACK_RESPONSE,
MAX
};
typedef const Opcodes SpeedOpcodePair[static_cast<size_t>(SpeedOpcodeIndex::MAX)];
SpeedOpcodePair SetSpeed2Opc_table[MAX_MOVE_TYPE] =
{
{SMSG_FORCE_WALK_SPEED_CHANGE, SMSG_SPLINE_SET_WALK_SPEED, MSG_MOVE_SET_WALK_SPEED},
{SMSG_FORCE_RUN_SPEED_CHANGE, SMSG_SPLINE_SET_RUN_SPEED, MSG_MOVE_SET_RUN_SPEED},
{SMSG_FORCE_RUN_BACK_SPEED_CHANGE, SMSG_SPLINE_SET_RUN_BACK_SPEED, MSG_MOVE_SET_RUN_BACK_SPEED},
{SMSG_FORCE_SWIM_SPEED_CHANGE, SMSG_SPLINE_SET_SWIM_SPEED, MSG_MOVE_SET_SWIM_SPEED},
{SMSG_FORCE_SWIM_BACK_SPEED_CHANGE, SMSG_SPLINE_SET_SWIM_BACK_SPEED, MSG_MOVE_SET_SWIM_BACK_SPEED},
{SMSG_FORCE_TURN_RATE_CHANGE, SMSG_SPLINE_SET_TURN_RATE, MSG_MOVE_SET_TURN_RATE},
{SMSG_FORCE_FLIGHT_SPEED_CHANGE, SMSG_SPLINE_SET_FLIGHT_SPEED, MSG_MOVE_SET_FLIGHT_SPEED},
{SMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE, SMSG_SPLINE_SET_FLIGHT_BACK_SPEED, MSG_MOVE_SET_FLIGHT_BACK_SPEED},
{SMSG_FORCE_PITCH_RATE_CHANGE, SMSG_SPLINE_SET_PITCH_RATE, MSG_MOVE_SET_PITCH_RATE},
};
class Unit : public WorldObject
{
public:
@ -1681,7 +1703,7 @@ public:
void MonsterMoveWithSpeed(float x, float y, float z, float speed); // Not to be used outside of cinematics
virtual bool SetWalk(bool enable);
virtual bool SetDisableGravity(bool disable, bool packetOnly = false, bool updateAnimationTier = true);
void SetDisableGravity(bool disable);
virtual bool SetSwim(bool enable);
void SetCanFly(bool enable);
void SetWaterWalking(bool enable);

View File

@ -423,7 +423,9 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
if (_me->IsInWorld())
{
unit->SendClearTarget(); // SMSG_BREAK_TARGET
unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
if (unit->IsPlayer())
unit->ToPlayer()->SetExpectingChangeTransport(true);
// also adds MOVEMENTFLAG_ROOT
Movement::MoveSplineInit init(unit);
init.DisableTransportPathTransformations();

View File

@ -1490,6 +1490,8 @@ void WorldSession::HandleMoveFlagChangeOpcode(WorldPacket& recv_data)
{
LOG_DEBUG("network", "WORLD: {}", GetOpcodeNameForLogging((Opcodes)recv_data.GetOpcode()));
Opcodes opcode = (Opcodes)recv_data.GetOpcode();
ObjectGuid guid;
uint32 counter;
uint32 isApplied;
@ -1507,7 +1509,8 @@ void WorldSession::HandleMoveFlagChangeOpcode(WorldPacket& recv_data)
movementInfo.guid = guid;
ReadMovementInfo(recv_data, &movementInfo);
recv_data >> isApplied;
if (opcode != CMSG_MOVE_GRAVITY_DISABLE_ACK && opcode != CMSG_MOVE_GRAVITY_ENABLE_ACK)
recv_data >> isApplied;
sScriptMgr->AnticheatSetCanFlybyServer(_player, movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY));
@ -1516,6 +1519,12 @@ void WorldSession::HandleMoveFlagChangeOpcode(WorldPacket& recv_data)
mover->m_movementInfo.flags = movementInfo.GetMovementFlags();
if (!ProcessMovementInfo(movementInfo, mover, plrMover, recv_data))
{
recv_data.rfinish(); // prevent warnings spam
return;
}
Opcodes response;
switch (recv_data.GetOpcode())
@ -1524,17 +1533,12 @@ void WorldSession::HandleMoveFlagChangeOpcode(WorldPacket& recv_data)
case CMSG_MOVE_FEATHER_FALL_ACK: response = MSG_MOVE_FEATHER_FALL; break;
case CMSG_MOVE_WATER_WALK_ACK: response = MSG_MOVE_WATER_WALK; break;
case CMSG_MOVE_SET_CAN_FLY_ACK: response = MSG_MOVE_UPDATE_CAN_FLY; break;
case CMSG_MOVE_GRAVITY_DISABLE_ACK: response = MSG_MOVE_GRAVITY_CHNG; break;
case CMSG_MOVE_GRAVITY_ENABLE_ACK: response = MSG_MOVE_GRAVITY_CHNG; break;
default: return;
}
if (!ProcessMovementInfo(movementInfo, mover, plrMover, recv_data))
{
recv_data.rfinish(); // prevent warnings spam
return;
}
WorldPacket data(response, 8);
data << guid.WriteAsPacked();
WriteMovementInfo(&data, &movementInfo);
_player->m_mover->SendMessageToSet(&data, _player);
}

View File

@ -376,9 +376,11 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
return;
}
if (opcode == CMSG_MOVE_FALL_RESET || opcode == CMSG_MOVE_CHNG_TRANSPORT)
return;
/* process position-change */
WorldPacket data(opcode, recvData.size());
movementInfo.guid = mover->GetGUID();
WriteMovementInfo(&data, &movementInfo);
mover->SendMessageToSet(&data, _player);
}
@ -517,7 +519,10 @@ bool WorldSession::VerifyMovementInfo(MovementInfo const& movementInfo, Player*
}
if (!mover->movespline->Finalized())
return false;
{
if (!mover->movespline->isBoarding() || (opcode != CMSG_FORCE_MOVE_UNROOT_ACK && opcode != CMSG_FORCE_MOVE_ROOT_ACK))
return false;
}
// Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE
if (mover->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE))
@ -655,26 +660,39 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket& recvData)
/* extract packet */
ObjectGuid guid;
uint32 unk1;
uint32 counter;
MovementInfo movementInfo;
float newspeed;
recvData >> guid.ReadAsPacked();
recvData >> counter; // counter or moveEvent
movementInfo.guid = guid;
ReadMovementInfo(recvData, &movementInfo);
recvData >> newspeed;
Unit* mover = _player->m_mover;
// pussywizard: special check, only player mover allowed here
if (guid != _player->m_mover->GetGUID() || guid != _player->GetGUID())
if (guid != mover->GetGUID() || guid != _player->GetGUID())
{
recvData.rfinish(); // prevent warnings spam
return;
}
// continue parse packet
recvData >> unk1; // counter or moveEvent
if (!ProcessMovementInfo(movementInfo, mover, _player, recvData))
{
recvData.rfinish(); // prevent warnings spam
return;
}
MovementInfo movementInfo;
movementInfo.guid = guid;
ReadMovementInfo(recvData, &movementInfo);
recvData >> newspeed;
if (opcode == CMSG_MOVE_SET_COLLISION_HGT_ACK)
{
WorldPacket data(MSG_MOVE_SET_COLLISION_HGT, 18);
WriteMovementInfo(&data, &movementInfo);
data << newspeed; // new collision height
mover->SendMessageToSet(&data, _player);
return;
}
// client ACK send one packet for mounted/run case and need skip all except last from its
// in other cases anti-cheat check can be fail in false case
@ -685,42 +703,15 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket& recvData)
switch (opcode)
{
case CMSG_FORCE_WALK_SPEED_CHANGE_ACK:
move_type = MOVE_WALK;
force_move_type = MOVE_WALK;
break;
case CMSG_FORCE_RUN_SPEED_CHANGE_ACK:
move_type = MOVE_RUN;
force_move_type = MOVE_RUN;
break;
case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK:
move_type = MOVE_RUN_BACK;
force_move_type = MOVE_RUN_BACK;
break;
case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK:
move_type = MOVE_SWIM;
force_move_type = MOVE_SWIM;
break;
case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK:
move_type = MOVE_SWIM_BACK;
force_move_type = MOVE_SWIM_BACK;
break;
case CMSG_FORCE_TURN_RATE_CHANGE_ACK:
move_type = MOVE_TURN_RATE;
force_move_type = MOVE_TURN_RATE;
break;
case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK:
move_type = MOVE_FLIGHT;
force_move_type = MOVE_FLIGHT;
break;
case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK:
move_type = MOVE_FLIGHT_BACK;
force_move_type = MOVE_FLIGHT_BACK;
break;
case CMSG_FORCE_PITCH_RATE_CHANGE_ACK:
move_type = MOVE_PITCH_RATE;
force_move_type = MOVE_PITCH_RATE;
break;
case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break;
case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break;
case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break;
case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break;
case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break;
case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break;
case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break;
case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break;
case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break;
default:
LOG_ERROR("network.opcode", "WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: {}", opcode);
return;
@ -728,6 +719,12 @@ void WorldSession::HandleForceSpeedChangeAck(WorldPacket& recvData)
sScriptMgr->AnticheatSetUnderACKmount(_player);
SpeedOpcodePair const& speedOpcodes = SetSpeed2Opc_table[move_type];
WorldPacket data(speedOpcodes[static_cast<size_t>(SpeedOpcodeIndex::ACK_RESPONSE)], 18);
WriteMovementInfo(&data, &movementInfo);
data << newspeed;
mover->SendMessageToSet(&data, _player);
// skip all forced speed changes except last and unexpected
// in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both.
if (_player->m_forced_speed_changes[force_move_type] > 0)
@ -967,13 +964,15 @@ void WorldSession::ComputeNewClockDelta()
void WorldSession::HandleMoveRootAck(WorldPacket& recvData)
{
LOG_DEBUG("network", "WORLD: {}", GetOpcodeNameForLogging((Opcodes)recvData.GetOpcode()));
Opcodes opcode = (Opcodes)recvData.GetOpcode();
LOG_DEBUG("network", "WORLD: {}", GetOpcodeNameForLogging(opcode));
ObjectGuid guid;
uint32 counter;
MovementInfo movementInfo;
recvData >> guid.ReadAsPacked();
recvData >> counter;
movementInfo.guid = guid;
ReadMovementInfo(recvData, &movementInfo);
Unit* mover = _player->m_mover;
@ -981,7 +980,7 @@ void WorldSession::HandleMoveRootAck(WorldPacket& recvData)
if (mover->GetGUID() != guid)
return;
if (recvData.GetOpcode() == CMSG_FORCE_MOVE_UNROOT_ACK) // unroot case
if (opcode == CMSG_FORCE_MOVE_UNROOT_ACK) // unroot case
{
if (!mover->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_ROOT))
return;
@ -995,8 +994,10 @@ void WorldSession::HandleMoveRootAck(WorldPacket& recvData)
if (!ProcessMovementInfo(movementInfo, mover, _player, recvData))
return;
WorldPacket data(recvData.GetOpcode() == CMSG_FORCE_MOVE_UNROOT_ACK ? MSG_MOVE_UNROOT : MSG_MOVE_ROOT);
data << guid.WriteAsPacked();
if (_player->IsExpectingChangeTransport())
return;
WorldPacket data(opcode == CMSG_FORCE_MOVE_UNROOT_ACK ? MSG_MOVE_UNROOT : MSG_MOVE_ROOT);
WriteMovementInfo(&data, &movementInfo);
mover->SendMessageToSet(&data, _player);
}

View File

@ -198,54 +198,70 @@ void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recvData)
void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData)
{
ObjectGuid guid; // used only for proper packet read
ObjectGuid guid; // used only for proper packet read
MovementInfo movementInfo; // used only for proper packet read
uint32 movementCounter; // spline counter
Unit* mover = _player->m_mover;
recvData >> guid.ReadAsPacked();
MovementInfo movementInfo; // used only for proper packet read
movementInfo.guid = guid;
ReadMovementInfo(recvData, &movementInfo);
recvData >> movementCounter;
recvData.read_skip<uint32>(); // spline id
// in taxi flight packet received in 2 case:
// 1) end taxi path in far (multi-node) flight
// 2) switch from one map to other in case multim-map taxi path
// we need process only (1)
uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination();
if (curDest)
if (_player->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_TAXI_FLIGHT)) // taxi spline case
{
TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest);
// in taxi flight packet received in 2 case:
// 1) end taxi path in far (multi-node) flight
// 2) switch from one map to other in case multim-map taxi path
// we need process only (1)
// far teleport case
if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination();
if (curDest)
{
if (FlightPathMovementGenerator* flight = dynamic_cast<FlightPathMovementGenerator*>(GetPlayer()->GetMotionMaster()->top()))
{
// short preparations to continue flight
flight->SetCurrentNodeAfterTeleport();
TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()];
flight->SkipCurrentNode();
TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest);
GetPlayer()->TeleportTo(curDestNode->map_id, node->x, node->y, node->z, GetPlayer()->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI);
// far teleport case
if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
{
if (FlightPathMovementGenerator* flight = dynamic_cast<FlightPathMovementGenerator*>(GetPlayer()->GetMotionMaster()->top()))
{
// short preparations to continue flight
flight->SetCurrentNodeAfterTeleport();
TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()];
flight->SkipCurrentNode();
GetPlayer()->TeleportTo(curDestNode->map_id, node->x, node->y, node->z, GetPlayer()->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI);
}
}
return;
}
// at this point only 1 node is expected (final destination)
if (GetPlayer()->m_taxi.GetPath().size() != 1)
{
return;
}
GetPlayer()->CleanupAfterTaxiFlight();
GetPlayer()->SetFallInformation(GameTime::GetGameTime().count(), GetPlayer()->GetPositionZ());
if (GetPlayer()->pvpInfo.IsHostile)
{
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
}
return;
}
// at this point only 1 node is expected (final destination)
if (GetPlayer()->m_taxi.GetPath().size() != 1)
{
if (mover->GetGUID() != guid)
return;
}
GetPlayer()->CleanupAfterTaxiFlight();
GetPlayer()->SetFallInformation(GameTime::GetGameTime().count(), GetPlayer()->GetPositionZ());
if (GetPlayer()->pvpInfo.IsHostile)
{
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
}
if (!_player->IsExpectingChangeTransport() || !mover->movespline || mover->movespline->GetId() != movementCounter)
return;
_player->SetExpectingChangeTransport(false);
WorldPacket data(_player->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_ROOT) ? MSG_MOVE_ROOT : MSG_MOVE_UNROOT, recvData.size());
WriteMovementInfo(&data, &movementInfo);
mover->SendMessageToSet(&data, _player);
}
void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recvData)

View File

@ -117,6 +117,7 @@ namespace Movement
[[nodiscard]] bool isCyclic() const { return splineflags.cyclic; }
[[nodiscard]] bool isFalling() const { return splineflags.falling; }
[[nodiscard]] bool isWalking() const { return splineflags.walkmode; }
[[nodiscard]] bool isBoarding() const { return splineflags.transportEnter || splineflags.transportExit; }
[[nodiscard]] Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3(); }
[[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1) : Vector3(); }
[[nodiscard]] int32 currentPathIdx() const;

View File

@ -1245,7 +1245,7 @@ void OpcodeTable::Initialize()
/*0x45A*/ DEFINE_HANDLER(MSG_MOVE_SET_PITCH_RATE_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x45B*/ DEFINE_HANDLER(MSG_MOVE_SET_PITCH_RATE, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x45C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_PITCH_RATE_CHANGE, STATUS_NEVER);
/*0x45D*/ DEFINE_HANDLER(CMSG_FORCE_PITCH_RATE_CHANGE_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x45D*/ DEFINE_HANDLER(CMSG_FORCE_PITCH_RATE_CHANGE_ACK, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleForceSpeedChangeAck );
/*0x45E*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_SET_PITCH_RATE, STATUS_NEVER);
/*0x45F*/ DEFINE_HANDLER(CMSG_CALENDAR_EVENT_INVITE_NOTES, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x460*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_CALENDAR_EVENT_INVITE_NOTES, STATUS_NEVER);
@ -1359,9 +1359,9 @@ void OpcodeTable::Initialize()
/*0x4CC*/ DEFINE_HANDLER(CMSG_END_BATTLEFIELD_CHEAT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x4CD*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MULTIPLE_PACKETS, STATUS_NEVER);
/*0x4CE*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_DISABLE, STATUS_NEVER);
/*0x4CF*/ DEFINE_HANDLER(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x4CF*/ DEFINE_HANDLER(CMSG_MOVE_GRAVITY_DISABLE_ACK, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleMoveFlagChangeOpcode );
/*0x4D0*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_GRAVITY_ENABLE, STATUS_NEVER);
/*0x4D1*/ DEFINE_HANDLER(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x4D1*/ DEFINE_HANDLER(CMSG_MOVE_GRAVITY_ENABLE_ACK, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleMoveFlagChangeOpcode );
/*0x4D2*/ DEFINE_SERVER_OPCODE_HANDLER(MSG_MOVE_GRAVITY_CHNG, STATUS_NEVER);
/*0x4D3*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_DISABLE, STATUS_NEVER);
/*0x4D4*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SPLINE_MOVE_GRAVITY_ENABLE, STATUS_NEVER);
@ -1431,7 +1431,7 @@ void OpcodeTable::Initialize()
/*0x514*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_SEND_ALL_COMBAT_LOG, STATUS_NEVER);
/*0x515*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_OPEN_LFG_DUNGEON_FINDER, STATUS_NEVER);
/*0x516*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_SET_COLLISION_HGT, STATUS_NEVER);
/*0x517*/ DEFINE_HANDLER(CMSG_MOVE_SET_COLLISION_HGT_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x517*/ DEFINE_HANDLER(CMSG_MOVE_SET_COLLISION_HGT_ACK, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleForceSpeedChangeAck );
/*0x518*/ DEFINE_HANDLER(MSG_MOVE_SET_COLLISION_HGT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x519*/ DEFINE_HANDLER(CMSG_CLEAR_RANDOM_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );
/*0x51A*/ DEFINE_HANDLER(CMSG_CLEAR_HOLIDAY_BG_WIN_TIME, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL );

View File

@ -417,10 +417,10 @@ public:
if (CheckModifySpeed(handler, target, allSpeed, 0.1f, 50.0f))
{
NotifyModification(handler, target, LANG_YOU_CHANGE_ASPEED, LANG_YOURS_ASPEED_CHANGED, allSpeed);
target->SetSpeed(MOVE_WALK, allSpeed);
target->SetSpeed(MOVE_RUN, allSpeed);
target->SetSpeed(MOVE_SWIM, allSpeed);
target->SetSpeed(MOVE_FLIGHT, allSpeed);
target->SetSpeed(MOVE_WALK, allSpeed, true);
target->SetSpeed(MOVE_RUN, allSpeed, true);
target->SetSpeed(MOVE_SWIM, allSpeed, true);
target->SetSpeed(MOVE_FLIGHT, allSpeed, true);
return true;
}

View File

@ -2566,7 +2566,7 @@ public:
me->SetCanFly(false);
me->SetDisableGravity(false);
me->GetMotionMaster()->MovePoint(POINT_DROP_PLAYER, _destPoint, FORCED_MOVEMENT_NONE, 0.f, false);
me->SetDisableGravity(true, true);
me->SetDisableGravity(true);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
break;
case EVENT_MOVE_TO_SIPHON_POS:
@ -2732,7 +2732,7 @@ class spell_the_lich_king_valkyr_target_search : public SpellScript
if (Unit* target = GetHitUnit())
{
GetCaster()->GetMotionMaster()->MoveCharge(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ() + 4.0f, 42.0f, EVENT_CHARGE);
GetCaster()->SetDisableGravity(true, true);
GetCaster()->SetDisableGravity(true);
}
}

View File

@ -528,9 +528,7 @@ public:
init.Launch();
pPlayer->SetUnitMovementFlags(MOVEMENTFLAG_NONE);
pPlayer->SetDisableGravity(true, true);
sScriptMgr->AnticheatSetCanFlybyServer(pPlayer, true);
pPlayer->SetDisableGravity(true);
WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, 8);
data << pPlayer->GetPackGUID();
@ -941,10 +939,7 @@ public:
if (!bUpdatedFlying && timer)
{
bUpdatedFlying = true;
plr->SetDisableGravity(true, true);
sScriptMgr->AnticheatSetCanFlybyServer(plr, true);
sScriptMgr->AnticheatSetUnderACKmount(plr);
plr->SetDisableGravity(true);
}
plr->SendMonsterMove(me->GetPositionX() + dist * cos(arcangle), me->GetPositionY() + dist * std::sin(arcangle), me->GetPositionZ(), VORTEX_DEFAULT_DIFF * 2, SPLINEFLAG_FLYING);

View File

@ -347,7 +347,7 @@ struct boss_kaelthas : public BossAI
}
else if (point == POINT_AIR)
{
me->SetDisableGravity(true, false, false); // updating AnimationTier will break drowning animation later
me->SetDisableGravity(true); // updating AnimationTier will break drowning animation later
}
else if (point == POINT_START_LAST_PHASE)
{

View File

@ -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<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_DB_IMPORT_CONFIG))), "use <arg> as configuration file");
("config,c", value<fs::path>(&configFile)->default_value(fs::path(sConfigMgr->GetConfigPath() + std::string(_ACORE_DB_IMPORT_CONFIG))), "use <arg> as configuration file")
("config-policy", value<std::string>()->value_name("policy"), "override config severity policy (e.g. default=skip,critical_option=fatal)");
variables_map variablesMap;