Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-09-22 21:56:15 +08:00
195 changed files with 1915 additions and 1883 deletions
+9 -16
View File
@@ -15,23 +15,16 @@ Versions of AzerothCore:
| AzerothCore Branch | Supported | | AzerothCore Branch | Supported |
| ------------------ | ------------------ | | ------------------ | ------------------ |
| master | :white_check_mark: | | master | :white_check_mark: |
| Any playerbot fork | :red_circle: |
| Any NPCBot fork | :red_circle: |
Versions of MySQL: Versions of MySQL:
| MySQL Version | Supported | | MySQL Version | Supported |
| ------------- | ------------------ | | ------------- | ------------------ |
| 8.1 | :white_check_mark: | | 8.4 | :white_check_mark: |
| 8.0 | :white_check_mark: | | 8.0 | :white_check_mark: |
| 5.7 | :white_check_mark: | | 5.7 and lower | :red_circle: |
| 5.6 and lower | :red_circle: |
Versions of MariaDB:
| MariaDB Version | Supported |
| --------------- | ------------------ |
| 10.6 | :white_check_mark: |
| 10.5 | :white_check_mark: |
| 10.4 and lower | :red_circle: |
Versions of CLang: Versions of CLang:
@@ -44,7 +37,7 @@ Versions of CLang:
Versions of GCC: Versions of GCC:
| GCC Version | Supported | | GCC Version | Supported |
| ----------- | ------------------ | | ------------ | ------------------ |
| 14 | :white_check_mark: | | 14 | :white_check_mark: |
| 12 | :white_check_mark: | | 12 | :white_check_mark: |
| 11 and lower | :red_circle: | | 11 and lower | :red_circle: |
@@ -52,7 +45,7 @@ Versions of GCC:
Versions of Ubuntu: Versions of Ubuntu:
| Ubuntu version | Supported | | Ubuntu version | Supported |
| -------------- | ------------------ | | --------------- | ------------------ |
| 24.04 | :white_check_mark: | | 24.04 | :white_check_mark: |
| 22.04 | :white_check_mark: | | 22.04 | :white_check_mark: |
| 20.04 and lower | :red_circle: | | 20.04 and lower | :red_circle: |
@@ -60,9 +53,9 @@ Versions of Ubuntu:
Versions of macOS: Versions of macOS:
| macOS Version | Supported | | macOS Version | Supported |
| -------------- | ------------------ | | ------------- | ------------------ |
| 12 | :white_check_mark: | | 14 | :white_check_mark: |
| 11 and lower | :red_circle: | | 12 and lower | :red_circle: |
**Note**: We do NOT support any repacks that may or may not have been made based on AzerothCore. This is because they are usually based on older versions and there is no way to know what is in the precompiled binaries. Instead, you should compile your binaries from the AzerothCore source. To get started, read the [Installation Guide](https://www.azerothcore.org/wiki/installation). **Note**: We do NOT support any repacks that may or may not have been made based on AzerothCore. This is because they are usually based on older versions and there is no way to know what is in the precompiled binaries. Instead, you should compile your binaries from the AzerothCore source. To get started, read the [Installation Guide](https://www.azerothcore.org/wiki/installation).
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: os:
- macos-12 - macos-14
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
name: ${{ matrix.os }} name: ${{ matrix.os }}
steps: steps:
+2 -2
View File
@@ -27,8 +27,8 @@ time cmake ../../../ \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DMYSQL_ADD_INCLUDE_PATH=$mysql_include_path \ -DMYSQL_ADD_INCLUDE_PATH=$mysql_include_path \
-DMYSQL_LIBRARY=$mysql_lib_path \ -DMYSQL_LIBRARY=$mysql_lib_path \
-DREADLINE_INCLUDE_DIR=/usr/local/opt/readline/include \ -DREADLINE_INCLUDE_DIR=$(brew --prefix readline)/include \
-DREADLINE_LIBRARY=/usr/local/opt/readline/lib/libreadline.dylib \ -DREADLINE_LIBRARY=$(brew --prefix readline)/lib/libreadline.dylib \
-DOPENSSL_INCLUDE_DIR="$OPENSSL_ROOT_DIR/include" \ -DOPENSSL_INCLUDE_DIR="$OPENSSL_ROOT_DIR/include" \
-DOPENSSL_SSL_LIBRARIES="$OPENSSL_ROOT_DIR/lib/libssl.dylib" \ -DOPENSSL_SSL_LIBRARIES="$OPENSSL_ROOT_DIR/lib/libssl.dylib" \
-DOPENSSL_CRYPTO_LIBRARIES="$OPENSSL_ROOT_DIR/lib/libcrypto.dylib" \ -DOPENSSL_CRYPTO_LIBRARIES="$OPENSSL_ROOT_DIR/lib/libcrypto.dylib" \
+2 -2
View File
@@ -19,11 +19,11 @@ sudo apt-get update -y
sudo apt-get install -y gdbserver gdb unzip curl \ sudo apt-get install -y gdbserver gdb unzip curl \
libncurses-dev libreadline-dev clang g++ \ libncurses-dev libreadline-dev clang g++ \
gcc git cmake make ccache \ gcc git cmake make ccache \
default-libmysqlclient-dev libssl-dev libbz2-dev \ libssl-dev libbz2-dev \
libboost-all-dev gnupg wget libboost-all-dev gnupg wget
# run noninteractive install for MYSQL 8.4 LTS # run noninteractive install for MYSQL 8.4 LTS
wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb wget https://dev.mysql.com/get/mysql-apt-config_0.8.32-1_all.deb
sudo DEBIAN_FRONTEND="noninteractive" dpkg -i ./mysql-apt-config_0.8.32-1_all.deb sudo DEBIAN_FRONTEND="noninteractive" dpkg -i ./mysql-apt-config_0.8.32-1_all.deb
sudo apt-get update sudo apt-get update
sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server sudo DEBIAN_FRONTEND="noninteractive" apt-get install -y mysql-server libmysqlclient-dev
+1 -13
View File
@@ -1,16 +1,4 @@
REVOKE ALL PRIVILEGES ON * . * FROM 'acore'@'localhost'; REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'acore'@'localhost';
REVOKE ALL PRIVILEGES ON `acore_world` . * FROM 'acore'@'localhost';
REVOKE GRANT OPTION ON `acore_world` . * FROM 'acore'@'localhost';
REVOKE ALL PRIVILEGES ON `acore_characters` . * FROM 'acore'@'localhost';
REVOKE GRANT OPTION ON `acore_characters` . * FROM 'acore'@'localhost';
REVOKE ALL PRIVILEGES ON `acore_auth` . * FROM 'acore'@'localhost';
REVOKE GRANT OPTION ON `acore_auth` . * FROM 'acore'@'localhost';
DROP USER 'acore'@'localhost'; DROP USER 'acore'@'localhost';
-9
View File
@@ -1,9 +0,0 @@
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'acore'@'localhost';
DROP USER 'acore'@'localhost';
DROP DATABASE IF EXISTS `acore_world`;
DROP DATABASE IF EXISTS `acore_characters`;
DROP DATABASE IF EXISTS `acore_auth`;
@@ -0,0 +1,4 @@
-- DB update 2024_09_03_00 -> 2024_09_22_00
--
ALTER TABLE `recovery_item`
ADD COLUMN `DeleteDate` INT UNSIGNED NULL DEFAULT NULL AFTER `Count`;
@@ -0,0 +1,6 @@
-- DB update 2024_09_16_00 -> 2024_09_20_00
UPDATE `creature_template` SET `flags_extra` = `flags_extra` | 134217728 WHERE `entry` = 23403;
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 23403) AND (`source_type` = 0) AND (`id` IN (2));
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
(23403, 0, 2, 0, 0, 0, 100, 0, 0, 15000, 30000, 40000, 0, 0, 11, 41392, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Illidari Assassin - In Combat - Cast Riposte');
@@ -0,0 +1,5 @@
-- DB update 2024_09_20_00 -> 2024_09_21_00
--
DELETE FROM `conditions` WHERE `SourceTypeorReferenceiD` = 18 and `SourceGroup` = 34125 AND `ConditionValue1` = 62853;
DELETE FROM `spell_script_names` WHERE `spell_id`=63215 AND `ScriptName`='spell_gen_summon_tournament_mount';
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES (63215, 'spell_gen_summon_tournament_mount');
@@ -0,0 +1,3 @@
-- DB update 2024_09_21_00 -> 2024_09_21_01
DELETE FROM `command` WHERE `name` = 'debug cooldown';
INSERT INTO `command` (`name`, `security`, `help`) VALUES ('debug cooldown', 3, 'Syntax: .debug cooldown #spellID #cooldownTime #itemID\nApply a cooldown of the given duration (in milliseconds) for the given spell and item ID.');
@@ -0,0 +1,2 @@
-- DB update 2024_09_21_01 -> 2024_09_21_02
UPDATE `creature` SET `equipment_id` = 1 WHERE `id1` = 37967;
@@ -0,0 +1,4 @@
-- DB update 2024_09_21_02 -> 2024_09_22_00
--
UPDATE `quest_offer_reward` SET `RewardText`='We will leave this place on our own, $G Lord:Lady; $N - once we are certain that the evil within has been wholly destroyed. Your journey of legend is almost at an end.', `VerifiedBuild`=0 WHERE `ID`=8801;
UPDATE `quest_request_items` SET `CompletionText`='$G Lord:Lady; $N, you have freed us of its grasp.', `VerifiedBuild`=0 WHERE `ID`=8801;
@@ -0,0 +1,41 @@
-- DB update 2024_09_22_00 -> 2024_09_22_01
-- Unyielding Footman
-- Runecloth chance 50 (chance was 20)
UPDATE `creature_loot_template`
SET `Chance` = 50, `GroupId` = 1
WHERE `Entry` = 16904 AND `Item` = 14047;
-- Netherweave Cloth chance 25 (chance was 60)
UPDATE `creature_loot_template`
SET `Chance` = 25, `GroupId` = 1
WHERE `Entry` = 16904 AND `Item` = 21877;
-- Unyielding Sorcerer
-- Runecloth chance 50 (chance was 20)
UPDATE `creature_loot_template`
SET `Chance` = 50, `GroupId` = 1
WHERE `Entry` = 16905 AND `Item` = 14047;
-- Netherweave Cloth chance 25 (chance was 60)
UPDATE `creature_loot_template`
SET `Chance` = 25, `GroupId` = 1
WHERE `Entry` = 16905 AND `Item` = 21877;
-- Unyielding Knight
-- Runecloth chance 50 (chance was 20)
UPDATE `creature_loot_template`
SET `Chance` = 50, `GroupId` = 1
WHERE `Entry` = 16906 AND `Item` = 14047;
-- Netherweave Cloth chance 25 (chance was 60)
UPDATE `creature_loot_template`
SET `Chance` = 25, `GroupId` = 1
WHERE `Entry` = 16906 AND `Item` = 21877;
@@ -0,0 +1,40 @@
-- DB update 2024_09_22_01 -> 2024_09_22_02
-- AzjolNerub
-- Anubarak 29120 txt line ruRU loc (BroadcastTextId unknown)
DELETE FROM `creature_text_locale` WHERE `CreatureID`=29120 AND `GroupID`=5 AND `ID`=0 AND `locale`='ruRU' ;
INSERT INTO `creature_text_locale` (`CreatureID`, `GroupID`, `ID`, `Locale`, `Text`) VALUES
(29120, 5, 0, 'ruRU', 'Я был королем этой империи, когдато. При жизни я был героем смерти, я вернулся завоевателем. Теперь я снова оберегаю это королевство. Забавно, неправда ли?');
-- Pit of Saron
-- Lady Sylvanas Windrunner 36990 use localized lines
UPDATE `creature_text` SET `BroadcastTextId` = 37393 WHERE `CreatureID` = 36990 AND `GroupID`=7 AND `ID`=0;
-- Gorkun Ironskull 37320 use localized lines
UPDATE `creature_text` SET `BroadcastTextId` = 37320 WHERE `CreatureID` = 37581 AND `GroupID`=61 AND `ID`=0;
UPDATE `creature_text` SET `BroadcastTextId` = 37321 WHERE `CreatureID` = 37581 AND `GroupID`=62 AND `ID`=0;
-- Rescued Horde Slave 36889 use localized lines
UPDATE `creature_text` SET `BroadcastTextId` = 36718 WHERE `CreatureID` = 36889 AND `GroupID`=0 AND `ID`=0;
-- connect heroic version template
UPDATE `creature_template` SET `difficulty_entry_1` = 37654 WHERE `entry` = 36889;
-- Rescued Alliance Slave connect heroic version template
UPDATE `creature_template` SET `difficulty_entry_1` = 37653 WHERE `entry` = 36888;
-- remove duplicated line (already exist in GroupID=0
DELETE FROM `creature_text` WHERE `CreatureID`=36993 AND `GroupID`=36 AND `ID`=0;
DELETE FROM `creature_text` WHERE `CreatureID`=36990 AND `GroupID`=37 AND `ID`=0;
-- remove duplicated line (already exist in GroupID=1
DELETE FROM `creature_text` WHERE `CreatureID`=36990 AND `GroupID`=40 AND `ID`=0;
DELETE FROM `creature_text` WHERE `CreatureID`=36993 AND `GroupID`=39 AND `ID`=0;
-- remove duplicated line (already exist in GroupID=2
DELETE FROM `creature_text` WHERE `CreatureID`=36990 AND `GroupID`=46 AND `ID`=0;
-- update comment according to core cript
UPDATE `creature_text` SET `comment` = 'Sylvanas SAY_SYLVANAS_KRICK_1' WHERE `CreatureID` = 36990 AND `GroupID`=0 AND `ID`=0;
UPDATE `creature_text` SET `comment` = 'Sylvanas SAY_SYLVANAS_KRICK_2' WHERE `CreatureID` = 36990 AND `GroupID`=1 AND `ID`=0;
UPDATE `creature_text` SET `comment` = 'Sylvanas SAY_SYLVANAS_KRICK_3' WHERE `CreatureID` = 36990 AND `GroupID`=2 AND `ID`=0;
UPDATE `creature_text` SET `comment` = 'Jaina SAY_JAINA_KRICK_2' WHERE `CreatureID` = 36993 AND `GroupID`=1 AND `ID`=0;
UPDATE `creature_text` SET `comment` = 'Jaina SAY_JAINA_KRICK_1' WHERE `CreatureID` = 36993 AND `GroupID`=0 AND `ID`=0;
+9 -89
View File
@@ -24,77 +24,6 @@
set( MYSQL_FOUND 0 ) set( MYSQL_FOUND 0 )
# Find MariaDB for Windows
if (WIN32)
# Set know versions MariaDB
set(_MARIADB_KNOWN_VERSIONS "MariaDB 10.9" "MariaDB 10.8" "MariaDB 10.7" "MariaDB 10.6" "MariaDB 10.5")
# Set default options
set(MARIADB_FOUND_LIB 0)
set(MARIADB_FOUND_INCLUDE 0)
set(MARIADB_FOUND_EXECUTABLE 0)
set(MARIADB_FOUND 0)
macro(FindLibMariaDB MariaDBVersion)
# Find include
find_path(MYSQL_INCLUDE_DIR
NAMES
mysql.h
PATHS
${MYSQL_ADD_INCLUDE_PATH}
"$ENV{ProgramW6432}/${MariaDBVersion}/include/mysql"
"$ENV{ProgramFiles}/${MariaDBVersion}/include/mysql"
"${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include/mysql"
DOC
"Specify the directory containing mysql.h."
)
if(MYSQL_INCLUDE_DIR)
set(MARIADB_FOUND_INCLUDE 1)
endif()
find_library(MYSQL_LIBRARY
NAMES
libmariadb
PATHS
${MYSQL_ADD_LIBRARIES_PATH}
"$ENV{ProgramW6432}/${MariaDBVersion}/lib"
"$ENV{ProgramW6432}/${MariaDBVersion}/lib/opt"
"$ENV{ProgramFiles}/${MariaDBVersion}/lib"
"$ENV{ProgramFiles}/${MariaDBVersion}/lib/opt"
"$ENV{SystemDrive}/${MariaDBVersion}/lib/opt"
"${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib"
DOC
"Specify the location of the mysql library here."
)
if(MYSQL_LIBRARY)
set(MARIADB_FOUND_LIB 1)
endif()
find_program(MYSQL_EXECUTABLE mysql
PATHS
"$ENV{ProgramW6432}/${MariaDBVersion}/bin"
"$ENV{ProgramW6432}/${MariaDBVersion}/bin/opt"
"$ENV{ProgramFiles}/${MariaDBVersion}/bin"
"$ENV{ProgramFiles}/${MariaDBVersion}/bin/opt"
"$ENV{SystemDrive}/${MariaDBVersion}/bin/opt"
DOC
"path to your mysql binary.")
if (MYSQL_LIBRARY AND MYSQL_INCLUDE_DIR AND MYSQL_EXECUTABLE)
set(MARIADB_FOUND 1)
endif()
endmacro(FindLibMariaDB)
foreach(version ${_MARIADB_KNOWN_VERSIONS})
if (NOT MARIADB_FOUND)
FindLibMariaDB(${version})
endif()
endforeach()
endif()
if( UNIX ) if( UNIX )
set(MYSQL_CONFIG_PREFER_PATH "$ENV{MYSQL_HOME}/bin" CACHE FILEPATH set(MYSQL_CONFIG_PREFER_PATH "$ENV{MYSQL_HOME}/bin" CACHE FILEPATH
"preferred path to MySQL (mysql_config)" "preferred path to MySQL (mysql_config)"
@@ -156,15 +85,12 @@ find_path(MYSQL_INCLUDE_DIR
/usr/local/include/mysql /usr/local/include/mysql
/usr/local/mysql/include /usr/local/mysql/include
"C:/tools/mysql/current/include" # chocolatey package "C:/tools/mysql/current/include" # chocolatey package
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/include" "$ENV{ProgramW6432}/MySQL/MySQL Server 8.4/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.4/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.4/include"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/include" "$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/include"
"$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/include" "$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/include"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.1/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/include" "$ENV{SystemDrive}/MySQL/MySQL Server 8.0/include"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/include"
"$ENV{MYSQL_INCLUDE_DIR}" "$ENV{MYSQL_INCLUDE_DIR}"
"$ENV{MYSQL_DIR}/include" "$ENV{MYSQL_DIR}/include"
DOC DOC
@@ -195,15 +121,12 @@ if( WIN32 )
PATHS PATHS
${MYSQL_ADD_LIBRARIES_PATH} ${MYSQL_ADD_LIBRARIES_PATH}
"C:/tools/mysql/current/lib" # chocolatey package "C:/tools/mysql/current/lib" # chocolatey package
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/lib" "$ENV{ProgramW6432}/MySQL/MySQL Server 8.4/lib"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.4/lib"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.4/lib"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/lib" "$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/lib"
"$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/lib"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/lib"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/lib" "$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/lib"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/lib"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.1/lib"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/lib" "$ENV{SystemDrive}/MySQL/MySQL Server 8.0/lib"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/lib"
"$ENV{MYSQL_LIBRARY}" "$ENV{MYSQL_LIBRARY}"
"$ENV{MYSQL_DIR}/lib" "$ENV{MYSQL_DIR}/lib"
DOC "Specify the location of the mysql library here." DOC "Specify the location of the mysql library here."
@@ -242,15 +165,12 @@ if( WIN32 )
find_program(MYSQL_EXECUTABLE mysql find_program(MYSQL_EXECUTABLE mysql
PATHS PATHS
"C:/tools/mysql/current/bin" # chocolatey package "C:/tools/mysql/current/bin" # chocolatey package
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.1/bin" "$ENV{ProgramW6432}/MySQL/MySQL Server 8.4/bin"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.4/bin"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.4/bin"
"$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/bin" "$ENV{ProgramW6432}/MySQL/MySQL Server 8.0/bin"
"$ENV{ProgramW6432}/MySQL/MySQL Server 5.7/bin"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.1/bin"
"$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/bin" "$ENV{ProgramFiles}/MySQL/MySQL Server 8.0/bin"
"$ENV{ProgramFiles}/MySQL/MySQL Server 5.7/bin"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.1/bin"
"$ENV{SystemDrive}/MySQL/MySQL Server 8.0/bin" "$ENV{SystemDrive}/MySQL/MySQL Server 8.0/bin"
"$ENV{SystemDrive}/MySQL/MySQL Server 5.7/bin"
"$ENV{MYSQL_ROOT}/bin" "$ENV{MYSQL_ROOT}/bin"
DOC DOC
"path to your mysql binary.") "path to your mysql binary.")
-1
View File
@@ -153,7 +153,6 @@ if(WITH_STRICT_DATABASE_TYPE_CHECKS)
message(" *** WITH_STRICT_DATABASE_TYPE_CHECKS - WARNING!") message(" *** WITH_STRICT_DATABASE_TYPE_CHECKS - WARNING!")
message(" *** Validates uses of database Get***() functions from Field class") message(" *** Validates uses of database Get***() functions from Field class")
message(" *** invalid calls will result in returning value 0") message(" *** invalid calls will result in returning value 0")
message(" *** NOT COMPATIBLE WITH MARIADB!")
add_definitions(-DACORE_STRICT_DATABASE_TYPE_CHECKS) add_definitions(-DACORE_STRICT_DATABASE_TYPE_CHECKS)
endif() endif()
@@ -227,5 +227,4 @@ namespace VMAP
if (check != nameLen) { return false; } if (check != nameLen) { return false; }
return true; return true;
} }
} }
@@ -163,6 +163,5 @@ namespace Acore
bool t = Remove(elements._elements, obj, hdl); bool t = Remove(elements._elements, obj, hdl);
return ( !t ? Remove(elements._TailElements, obj, hdl) : t ); return ( !t ? Remove(elements._TailElements, obj, hdl) : t );
} }
} }
#endif #endif
@@ -176,8 +176,7 @@ SourceDirectory = ""
# MySQLExecutable # MySQLExecutable
# Description: The path to your MySQL CLI binary. # Description: The path to your MySQL CLI binary.
# If the path is left empty, built-in path from cmake is used. # If the path is left empty, built-in path from cmake is used.
# Example: "C:/Program Files/MariaDB 10.5/bin/mysql.exe" # Example: "C:/Program Files/MySQL/MySQL Server 8.4/bin/mysql.exe"
# "C:/Program Files/MySQL/MySQL Server 8.0/bin/mysql.exe"
# "mysql.exe" # "mysql.exe"
# "/usr/bin/mysql" # "/usr/bin/mysql"
# Default: "" # Default: ""
-6
View File
@@ -387,12 +387,6 @@ int main(int argc, char** argv)
sScriptMgr->OnStartup(); sScriptMgr->OnStartup();
// Be kind and warn people of EOL deprecation :)
#if !defined(MARIADB_VERSION_ID)
if (MySQL::GetLibraryVersion() < 80000)
LOG_WARN("server", "WARNING: You are using MySQL version 5.7 which is soon EOL!\nThis version will be deprecated. Consider upgrading to MySQL 8.0 or 8.1!");
#endif
// Launch CliRunnable thread // Launch CliRunnable thread
std::shared_ptr<std::thread> cliThread; std::shared_ptr<std::thread> cliThread;
#if AC_PLATFORM == AC_PLATFORM_WINDOWS #if AC_PLATFORM == AC_PLATFORM_WINDOWS
@@ -2616,6 +2616,14 @@ ItemDelete.Quality = 3
ItemDelete.ItemLevel = 80 ItemDelete.ItemLevel = 80
#
# ItemDelete.KeepDays
# Description: Time (in days)
# Default: 0 - (Disabled, Don't delete any it)
# 30 - (Enabled)
ItemDelete.KeepDays = 0
# #
################################################################################################### ###################################################################################################
@@ -63,15 +63,10 @@ DatabaseWorkerPool<T>::DatabaseWorkerPool() :
{ {
WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe."); WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
#if !defined(MARIADB_VERSION_ID) || MARIADB_VERSION_ID < 100600
bool isSupportClientDB = mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION; bool isSupportClientDB = mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION;
bool isSameClientDB = mysql_get_client_version() == MYSQL_VERSION_ID; bool isSameClientDB = mysql_get_client_version() == MYSQL_VERSION_ID;
#else // MariaDB 10.6+
bool isSupportClientDB = mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION;
bool isSameClientDB = true; // Client version 3.2.3?
#endif
WPFatal(isSupportClientDB, "AzerothCore does not support MySQL versions below 5.7 or MariaDB versions below 10.5.\n\nFound version: {} / {}. Server compiled with: {}.\nSearch the wiki for ACE00043 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00043).", WPFatal(isSupportClientDB, "AzerothCore does not support MySQL versions below 8.0\n\nFound version: {} / {}. Server compiled with: {}.\nSearch the wiki for ACE00043 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00043).",
mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID); mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
WPFatal(isSameClientDB, "Used MySQL library version ({} id {}) does not match the version id used to compile AzerothCore (id {}).\nSearch the wiki for ACE00046 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00046).", WPFatal(isSameClientDB, "Used MySQL library version ({} id {}) does not match the version id used to compile AzerothCore (id {}).\nSearch the wiki for ACE00046 in Common Errors (https://www.azerothcore.org/wiki/common-errors#ace00046).",
mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID); mysql_get_client_info(), mysql_get_client_version(), MYSQL_VERSION_ID);
@@ -382,8 +377,6 @@ void DatabaseWorkerPool<T>::KeepAlive()
* *
* DatabaseIncompatibleVersion("8.0.35") => false * DatabaseIncompatibleVersion("8.0.35") => false
* DatabaseIncompatibleVersion("5.6.6") => true * DatabaseIncompatibleVersion("5.6.6") => true
* DatabaseIncompatibleVersion("5.5.5-10.5.5-MariaDB") => false
* DatabaseIncompatibleVersion("5.5.5-10.4.0-MariaDB") => true
* *
* Adapted from stackoverflow response * Adapted from stackoverflow response
* https://stackoverflow.com/a/2941508 * https://stackoverflow.com/a/2941508
@@ -414,17 +407,6 @@ bool DatabaseIncompatibleVersion(std::string const mysqlVersion)
uint8 offset = 0; uint8 offset = 0;
std::string minVersion = MIN_MYSQL_SERVER_VERSION; std::string minVersion = MIN_MYSQL_SERVER_VERSION;
// If the version string contains "MariaDB", use that
if (mysqlVersion.find("MariaDB") != std::string::npos)
{
// All MariaDB 10.X versions have a prefix of 5.5.5 from the
// mysql_get_server_info() function. To make matters more
// annoying, this is removed in MariaDB 11.X
if (mysqlVersion.rfind("5.5.5-", 0) == 0)
offset = 6;
minVersion = MIN_MARIADB_SERVER_VERSION;
}
auto parsedMySQLVersion = parse(mysqlVersion.substr(offset)); auto parsedMySQLVersion = parse(mysqlVersion.substr(offset));
auto parsedMinVersion = parse(minVersion); auto parsedMinVersion = parse(minVersion);
@@ -459,7 +441,7 @@ uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConne
} }
else if (DatabaseIncompatibleVersion(connection->GetServerInfo())) else if (DatabaseIncompatibleVersion(connection->GetServerInfo()))
{ {
LOG_ERROR("sql.driver", "AzerothCore does not support MySQL versions below 5.7 or MariaDB versions below 10.5.\n\nFound server version: {}. Server compiled with: {}.", LOG_ERROR("sql.driver", "AzerothCore does not support MySQL versions below 8.0\n\nFound server version: {}. Server compiled with: {}.",
connection->GetServerInfo(), MYSQL_VERSION_ID); connection->GetServerInfo(), MYSQL_VERSION_ID);
return 1; return 1;
} }
@@ -26,31 +26,17 @@
/** @file DatabaseWorkerPool.h */ /** @file DatabaseWorkerPool.h */
/**
* @def MIN_MYSQL_CLIENT_VERSION
* The minimum MariaDB Client Version
* MARIADB_VERSION_ID is defined if using libmariadbclient instead of libmysqlclient
*/
#if MARIADB_VERSION_ID >= 100600
#define MIN_MYSQL_CLIENT_VERSION 30203u
#else
/** /**
* @def MIN_MYSQL_CLIENT_VERSION * @def MIN_MYSQL_CLIENT_VERSION
* The minimum MySQL Client Version * The minimum MySQL Client Version
*/ */
#define MIN_MYSQL_CLIENT_VERSION 50700u #define MIN_MYSQL_CLIENT_VERSION 80000u
#endif
/** /**
* @def MIN_MYSQL_SERVER_VERSION * @def MIN_MYSQL_SERVER_VERSION
* The minimum MySQL Server Version * The minimum MySQL Server Version
*/ */
#define MIN_MYSQL_SERVER_VERSION "5.7.0" #define MIN_MYSQL_SERVER_VERSION "8.0.0"
/**
* @def MIN_MARIADB_SERVER_VERSION
* The minimum MariaDB Server Version
*/
#define MIN_MARIADB_SERVER_VERSION "10.5.0"
template <typename T> template <typename T>
class ProducerConsumerQueue; class ProducerConsumerQueue;
@@ -253,4 +239,4 @@ private:
#endif #endif
}; };
#endif #endif // _DATABASEWORKERPOOL_H
@@ -588,11 +588,13 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_QUEST_TRACK_ABANDON_TIME, "UPDATE quest_tracker SET quest_abandon_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_QUEST_TRACK_ABANDON_TIME, "UPDATE quest_tracker SET quest_abandon_time = NOW() WHERE id = ? AND character_guid = ? ORDER BY quest_accept_time DESC LIMIT 1", CONNECTION_ASYNC);
// Recovery Item // Recovery Item
PrepareStatement(CHAR_INS_RECOVERY_ITEM, "INSERT INTO recovery_item (Guid, ItemEntry, Count) VALUES (?, ?, ?)", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_RECOVERY_ITEM, "INSERT INTO recovery_item (Guid, ItemEntry, Count, DeleteDate) VALUES (?, ?, ?, UNIX_TIMESTAMP())", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_RECOVERY_ITEM, "SELECT id, itemEntry, Count, Guid FROM recovery_item WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_RECOVERY_ITEM, "SELECT id, itemEntry, Count, Guid FROM recovery_item WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_RECOVERY_ITEM_LIST, "SELECT id, itemEntry, Count FROM recovery_item WHERE Guid = ? ORDER BY id DESC", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_RECOVERY_ITEM_LIST, "SELECT id, itemEntry, Count FROM recovery_item WHERE Guid = ? ORDER BY id DESC", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_RECOVERY_ITEM, "DELETE FROM recovery_item WHERE Guid = ? AND ItemEntry = ? AND Count = ? ORDER BY Id DESC LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RECOVERY_ITEM, "DELETE FROM recovery_item WHERE Guid = ? AND ItemEntry = ? AND Count = ? ORDER BY Id DESC LIMIT 1", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_RECOVERY_ITEM_BY_RECOVERY_ID, "DELETE FROM recovery_item WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RECOVERY_ITEM_BY_RECOVERY_ID, "DELETE FROM recovery_item WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_RECOVERY_ITEM_OLD_ITEMS, "SELECT Guid, ItemEntry FROM recovery_item WHERE DeleteDate IS NOT NULL AND DeleteDate < ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_RECOVERY_ITEM_BY_GUID, "DELETE FROM recovery_item WHERE Guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_HONORPOINTS, "SELECT totalHonorPoints FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_HONORPOINTS, "SELECT totalHonorPoints FROM characters WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_ARENAPOINTS, "SELECT arenaPoints FROM characters WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_ARENAPOINTS, "SELECT arenaPoints FROM characters WHERE guid = ?", CONNECTION_SYNCH);
@@ -508,6 +508,8 @@ enum CharacterDatabaseStatements : uint32
CHAR_SEL_RECOVERY_ITEM_LIST, CHAR_SEL_RECOVERY_ITEM_LIST,
CHAR_DEL_RECOVERY_ITEM, CHAR_DEL_RECOVERY_ITEM,
CHAR_DEL_RECOVERY_ITEM_BY_RECOVERY_ID, CHAR_DEL_RECOVERY_ITEM_BY_RECOVERY_ID,
CHAR_SEL_RECOVERY_ITEM_OLD_ITEMS,
CHAR_DEL_RECOVERY_ITEM_BY_GUID,
CHAR_SEL_HONORPOINTS, CHAR_SEL_HONORPOINTS,
CHAR_SEL_ARENAPOINTS, CHAR_SEL_ARENAPOINTS,
@@ -130,7 +130,6 @@ uint32 MySQLConnection::Open()
if (m_connectionInfo.ssl != "") if (m_connectionInfo.ssl != "")
{ {
#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000
mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED; mysql_ssl_mode opt_use_ssl = SSL_MODE_DISABLED;
if (m_connectionInfo.ssl == "ssl") if (m_connectionInfo.ssl == "ssl")
{ {
@@ -138,15 +137,6 @@ uint32 MySQLConnection::Open()
} }
mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl); mysql_options(mysqlInit, MYSQL_OPT_SSL_MODE, (char const*)&opt_use_ssl);
#else
MySQLBool opt_use_ssl = MySQLBool(0);
if (m_connectionInfo.ssl == "ssl")
{
opt_use_ssl = MySQLBool(1);
}
mysql_options(mysqlInit, MYSQL_OPT_SSL_ENFORCE, (char const*)&opt_use_ssl);
#endif
} }
m_Mysql = reinterpret_cast<MySQLHandle*>(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(), m_Mysql = reinterpret_cast<MySQLHandle*>(mysql_real_connect(mysqlInit, m_connectionInfo.host.c_str(), m_connectionInfo.user.c_str(),
@@ -227,7 +217,7 @@ bool MySQLConnection::Execute(PreparedStatementBase* stmt)
uint32 _s = getMSTime(); uint32 _s = getMSTime();
#if !defined(MARIADB_VERSION_ID) && (MYSQL_VERSION_ID >= 80300) #if MYSQL_VERSION_ID >= 80300
if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr)) if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
#else #else
if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
@@ -279,7 +269,7 @@ bool MySQLConnection::_Query(PreparedStatementBase* stmt, MySQLPreparedStatement
uint32 _s = getMSTime(); uint32 _s = getMSTime();
#if !defined(MARIADB_VERSION_ID) && (MYSQL_VERSION_ID >= 80300) #if MYSQL_VERSION_ID >= 80300
if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr)) if (mysql_stmt_bind_named_param(msql_STMT, msql_BIND, m_mStmt->GetParameterCount(), nullptr))
#else #else
if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) if (mysql_stmt_bind_param(msql_STMT, msql_BIND))
@@ -551,18 +551,9 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
// Set max allowed packet to 1 GB // Set max allowed packet to 1 GB
args.emplace_back("--max-allowed-packet=1GB"); args.emplace_back("--max-allowed-packet=1GB");
#if !defined(MARIADB_VERSION_ID) && MYSQL_VERSION_ID >= 80000
if (ssl == "ssl") if (ssl == "ssl")
args.emplace_back("--ssl-mode=REQUIRED"); args.emplace_back("--ssl-mode=REQUIRED");
#else
if (ssl == "ssl")
args.emplace_back("--ssl");
#endif
// Execute sql file // Execute sql file
args.emplace_back("-e"); args.emplace_back("-e");
args.emplace_back(Acore::StringFormat("BEGIN; SOURCE {}; COMMIT;", path.generic_string())); args.emplace_back(Acore::StringFormat("BEGIN; SOURCE {}; COMMIT;", path.generic_string()));
@@ -260,7 +260,6 @@ AuctionHouseObject* AuctionHouseMgr::GetAuctionsMapByHouseId(uint8 auctionHouseI
} }
return &_neutralAuctions; return &_neutralAuctions;
} }
uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count) uint32 AuctionHouseMgr::GetAuctionDeposit(AuctionHouseEntry const* entry, uint32 time, Item* pItem, uint32 count)
+4 -1
View File
@@ -2252,7 +2252,10 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert
summon->SetVisibleBySummonerOnly(visibleBySummonerOnly); summon->SetVisibleBySummonerOnly(visibleBySummonerOnly);
if (!AddToMap(summon->ToCreature(), summon->GetOwnerGUID().IsPlayer() || (summoner && summoner->GetTransport()))) bool summonerHasTransport = summoner && summoner->GetTransport();
bool summonerIsVehicle = summoner && summoner->IsUnit() && summoner->ToUnit()->IsVehicle();
bool checkTransport = summon->GetOwnerGUID().IsPlayer() || (summonerHasTransport && !summonerIsVehicle);
if (!AddToMap(summon->ToCreature(), checkTransport))
{ {
delete summon; delete summon;
return nullptr; return nullptr;
@@ -4336,6 +4336,49 @@ void Player::DeleteOldCharacters(uint32 keepDays)
} }
} }
/**
* Items which were kept back in the database after being deleted and are now too old (see config option "ItemDelete.KeepDays"), will be completely deleted.
*/
void Player::DeleteOldRecoveryItems()
{
uint32 keepDays = sWorld->getIntConfig(CONFIG_ITEMDELETE_KEEP_DAYS);
if (!keepDays)
return;
Player::DeleteOldRecoveryItems(keepDays);
}
/**
* Items which were kept back in the database after being deleted and are older than the specified amount of days, will be completely deleted.
*/
void Player::DeleteOldRecoveryItems(uint32 keepDays)
{
LOG_INFO("server.loading", "Player::DeleteOldRecoveryItems: Deleting all items which have been deleted {} days before...", keepDays);
LOG_INFO("server.loading", " ");
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_RECOVERY_ITEM_OLD_ITEMS);
stmt->SetData(0, uint32(GameTime::GetGameTime().count() - time_t(keepDays * DAY)));
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (result)
{
LOG_INFO("server.loading", "Player::DeleteOldRecoveryItems: Found {} item(s) to delete", result->GetRowCount());
do
{
Field* fields = result->Fetch();
uint32 guid = fields[0].Get<uint32>();
uint32 itemEntry = fields[1].Get<uint32>();
CharacterDatabasePreparedStatement* deleteStmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RECOVERY_ITEM_BY_GUID);
deleteStmt->SetData(0, guid);
CharacterDatabase.Execute(deleteStmt);
LOG_INFO("server.loading", "Deleted item from recovery_item table where guid {} and item id {}", guid, itemEntry);
} while (result->NextRow());
}
}
void Player::SetMovement(PlayerMovementType pType) void Player::SetMovement(PlayerMovementType pType)
{ {
WorldPacket data; WorldPacket data;
+3
View File
@@ -1568,6 +1568,9 @@ public:
static void DeleteOldCharacters(); static void DeleteOldCharacters();
static void DeleteOldCharacters(uint32 keepDays); static void DeleteOldCharacters(uint32 keepDays);
static void DeleteOldRecoveryItems();
static void DeleteOldRecoveryItems(uint32 keepDays);
bool m_mailsUpdated; bool m_mailsUpdated;
void SetBindPoint(ObjectGuid guid); void SetBindPoint(ObjectGuid guid);
+19 -5
View File
@@ -20259,13 +20259,24 @@ void Unit::OutDebugInfo() const
class AuraMunchingQueue : public BasicEvent class AuraMunchingQueue : public BasicEvent
{ {
public: public:
AuraMunchingQueue(Unit& owner, ObjectGuid targetGUID, int32 basePoints, uint32 spellId) : _owner(owner), _targetGUID(targetGUID), _basePoints(basePoints), _spellId(spellId) { } AuraMunchingQueue(Unit& owner, ObjectGuid targetGUID, int32 basePoints, uint32 spellId, AuraEffect* aurEff, AuraType auraType) : _owner(owner), _targetGUID(targetGUID), _basePoints(basePoints), _spellId(spellId), _aurEff(aurEff), _auraType(auraType) { }
bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override bool Execute(uint64 /*eventTime*/, uint32 /*updateTime*/) override
{ {
if (_owner.IsInWorld() && _owner.FindMap()) if (_owner.IsInWorld() && _owner.FindMap())
if (Unit* target = ObjectAccessor::GetUnit(_owner, _targetGUID)) if (Unit* target = ObjectAccessor::GetUnit(_owner, _targetGUID))
_owner.CastCustomSpell(_spellId, SPELLVALUE_BASE_POINT0, _basePoints, target, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_NO_PERIODIC_RESET), nullptr, nullptr, _owner.GetGUID()); {
bool auraFound = false; // Used to ensure _aurEff exists to avoid wild pointer access/crash
Unit::AuraEffectList const& auraEffects = target->GetAuraEffectsByType(_auraType);
for (Unit::AuraEffectList::const_iterator j = auraEffects.begin(); j != auraEffects.end(); ++j)
if ((*j) == _aurEff)
auraFound = true;
if (!auraFound)
_aurEff = nullptr;
_owner.CastCustomSpell(_spellId, SPELLVALUE_BASE_POINT0, _basePoints, target, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_NO_PERIODIC_RESET), nullptr, _aurEff, _owner.GetGUID());
}
return true; return true;
} }
@@ -20275,13 +20286,16 @@ private:
ObjectGuid _targetGUID; ObjectGuid _targetGUID;
int32 _basePoints; int32 _basePoints;
uint32 _spellId; uint32 _spellId;
AuraEffect* _aurEff;
AuraType _auraType;
}; };
void Unit::CastDelayedSpellWithPeriodicAmount(Unit* caster, uint32 spellId, AuraType auraType, int32 addAmount, uint8 effectIndex) void Unit::CastDelayedSpellWithPeriodicAmount(Unit* caster, uint32 spellId, AuraType auraType, int32 addAmount, uint8 effectIndex)
{ {
AuraEffect* aurEff = nullptr;
for (AuraEffectList::iterator i = m_modAuras[auraType].begin(); i != m_modAuras[auraType].end(); ++i) for (AuraEffectList::iterator i = m_modAuras[auraType].begin(); i != m_modAuras[auraType].end(); ++i)
{ {
AuraEffect* aurEff = *i; aurEff = *i;
if (aurEff->GetCasterGUID() != caster->GetGUID() || aurEff->GetId() != spellId || aurEff->GetEffIndex() != effectIndex || !aurEff->GetTotalTicks()) if (aurEff->GetCasterGUID() != caster->GetGUID() || aurEff->GetId() != spellId || aurEff->GetEffIndex() != effectIndex || !aurEff->GetTotalTicks())
continue; continue;
@@ -20291,9 +20305,9 @@ void Unit::CastDelayedSpellWithPeriodicAmount(Unit* caster, uint32 spellId, Aura
// xinef: delay only for casting on different unit // xinef: delay only for casting on different unit
if (this == caster || !sWorld->getBoolConfig(CONFIG_MUNCHING_BLIZZLIKE)) if (this == caster || !sWorld->getBoolConfig(CONFIG_MUNCHING_BLIZZLIKE))
caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, addAmount, this, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_NO_PERIODIC_RESET), nullptr, nullptr, caster->GetGUID()); caster->CastCustomSpell(spellId, SPELLVALUE_BASE_POINT0, addAmount, this, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_NO_PERIODIC_RESET), nullptr, aurEff, caster->GetGUID());
else else
caster->m_Events.AddEvent(new AuraMunchingQueue(*caster, GetGUID(), addAmount, spellId), caster->m_Events.CalculateQueueTime(400)); caster->m_Events.AddEvent(new AuraMunchingQueue(*caster, GetGUID(), addAmount, spellId, aurEff, auraType), caster->m_Events.CalculateQueueTime(400));
} }
void Unit::SendClearTarget() void Unit::SendClearTarget()
-1
View File
@@ -702,7 +702,6 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields, bool triggerHook)
{ {
sScriptMgr->OnAfterDatabaseLoadCreatureTemplates(_creatureTemplateStoreFast); sScriptMgr->OnAfterDatabaseLoadCreatureTemplates(_creatureTemplateStoreFast);
} }
} }
void ObjectMgr::LoadCreatureTemplateModels() void ObjectMgr::LoadCreatureTemplateModels()
+1 -1
View File
@@ -994,7 +994,7 @@ bool CanRollOnItem(LootItem const& item, Player const* player, Loot* loot)
return false; return false;
uint32 itemCount = player->GetItemCount(item.itemid); uint32 itemCount = player->GetItemCount(item.itemid);
if ((proto->MaxCount > 0 && static_cast<int32>(itemCount) >= proto->MaxCount) || (player->CanEquipUniqueItem(proto) != EQUIP_ERR_OK)) if ((proto->MaxCount > 0 && static_cast<int32>(itemCount) >= proto->MaxCount))
return false; return false;
if (!item.AllowedForPlayer(player, loot->sourceWorldObjectGUID)) if (!item.AllowedForPlayer(player, loot->sourceWorldObjectGUID))
@@ -301,5 +301,4 @@ namespace Movement
return str.str(); return str.str();
} }
} }
-1
View File
@@ -205,7 +205,6 @@ namespace Movement
void set_length(index_type i, length_type length) { lengths[i] = length;} void set_length(index_type i, length_type length) { lengths[i] = length;}
void clear(); void clear();
}; };
} }
#include "SplineImpl.h" #include "SplineImpl.h"
@@ -92,5 +92,4 @@ namespace Movement
SplineBase::clear(); SplineBase::clear();
lengths.clear(); lengths.clear();
} }
} }
@@ -299,7 +299,6 @@ void OutdoorPvP::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/)
void OutdoorPvP::HandlePlayerResurrects(Player* /*player*/, uint32 /*zone*/) void OutdoorPvP::HandlePlayerResurrects(Player* /*player*/, uint32 /*zone*/)
{ {
} }
bool OutdoorPvP::Update(uint32 diff) bool OutdoorPvP::Update(uint32 diff)
@@ -55,7 +55,6 @@ void ScriptMgr::OnBeforeCreatureSelectLevel(const CreatureTemplate* cinfo, Creat
{ {
script->OnBeforeCreatureSelectLevel(cinfo, creature, level); script->OnBeforeCreatureSelectLevel(cinfo, creature, level);
}); });
} }
void ScriptMgr::Creature_SelectLevel(const CreatureTemplate* cinfo, Creature* creature) void ScriptMgr::Creature_SelectLevel(const CreatureTemplate* cinfo, Creature* creature)
@@ -88,10 +88,7 @@ void ScriptMgr::OnCreateMap(Map* map)
{ {
ASSERT(map); ASSERT(map);
ExecuteScript<AllMapScript>([&](AllMapScript* script) CALL_ENABLED_HOOKS(AllMapScript, ALLMAPHOOK_ON_CREATE_MAP, script->OnCreateMap(map));
{
script->OnCreateMap(map);
});
ForeachMaps<WorldMapScript>(map, ForeachMaps<WorldMapScript>(map,
[&](WorldMapScript* script) [&](WorldMapScript* script)
@@ -116,10 +113,7 @@ void ScriptMgr::OnDestroyMap(Map* map)
{ {
ASSERT(map); ASSERT(map);
ExecuteScript<AllMapScript>([&](AllMapScript* script) CALL_ENABLED_HOOKS(AllMapScript, ALLMAPHOOK_ON_DESTROY_MAP, script->OnDestroyMap(map));
{
script->OnDestroyMap(map);
});
ForeachMaps<WorldMapScript>(map, ForeachMaps<WorldMapScript>(map,
[&](WorldMapScript* script) [&](WorldMapScript* script)
@@ -193,10 +187,7 @@ void ScriptMgr::OnPlayerEnterMap(Map* map, Player* player)
ASSERT(map); ASSERT(map);
ASSERT(player); ASSERT(player);
ExecuteScript<AllMapScript>([&](AllMapScript* script) CALL_ENABLED_HOOKS(AllMapScript, ALLMAPHOOK_ON_PLAYER_ENTER_ALL, script->OnPlayerEnterAll(map, player));
{
script->OnPlayerEnterAll(map, player);
});
ExecuteScript<PlayerScript>([=](PlayerScript* script) ExecuteScript<PlayerScript>([=](PlayerScript* script)
{ {
@@ -227,10 +218,7 @@ void ScriptMgr::OnPlayerLeaveMap(Map* map, Player* player)
ASSERT(map); ASSERT(map);
ASSERT(player); ASSERT(player);
ExecuteScript<AllMapScript>([&](AllMapScript* script) CALL_ENABLED_HOOKS(AllMapScript, ALLMAPHOOK_ON_PLAYER_LEAVE_ALL, script->OnPlayerLeaveAll(map, player));
{
script->OnPlayerLeaveAll(map, player);
});
ForeachMaps<WorldMapScript>(map, ForeachMaps<WorldMapScript>(map,
[&](WorldMapScript* script) [&](WorldMapScript* script)
@@ -255,10 +243,7 @@ void ScriptMgr::OnMapUpdate(Map* map, uint32 diff)
{ {
ASSERT(map); ASSERT(map);
ExecuteScript<AllMapScript>([&](AllMapScript* script) CALL_ENABLED_HOOKS(AllMapScript, ALLMAPHOOK_ON_MAP_UPDATE, script->OnMapUpdate(map, diff));
{
script->OnMapUpdate(map, diff);
});
ForeachMaps<WorldMapScript>(map, ForeachMaps<WorldMapScript>(map,
[&](WorldMapScript* script) [&](WorldMapScript* script)
@@ -281,24 +266,22 @@ void ScriptMgr::OnMapUpdate(Map* map, uint32 diff)
void ScriptMgr::OnBeforeCreateInstanceScript(InstanceMap* instanceMap, InstanceScript** instanceData, bool load, std::string data, uint32 completedEncounterMask) void ScriptMgr::OnBeforeCreateInstanceScript(InstanceMap* instanceMap, InstanceScript** instanceData, bool load, std::string data, uint32 completedEncounterMask)
{ {
ExecuteScript<AllMapScript>([&](AllMapScript* script) CALL_ENABLED_HOOKS(AllMapScript, ALLMAPHOOK_ON_BEFORE_CREATE_INSTANCE_SCRIPT, script->OnBeforeCreateInstanceScript(instanceMap, instanceData, load, data, completedEncounterMask));
{
script->OnBeforeCreateInstanceScript(instanceMap, instanceData, load, data, completedEncounterMask);
});
} }
void ScriptMgr::OnDestroyInstance(MapInstanced* mapInstanced, Map* map) void ScriptMgr::OnDestroyInstance(MapInstanced* mapInstanced, Map* map)
{ {
ExecuteScript<AllMapScript>([&](AllMapScript* script) CALL_ENABLED_HOOKS(AllMapScript, ALLMAPHOOK_ON_DESTROY_INSTANCE, script->OnDestroyInstance(mapInstanced, map));
{
script->OnDestroyInstance(mapInstanced, map);
});
} }
AllMapScript::AllMapScript(const char* name) : AllMapScript::AllMapScript(const char* name, std::vector<uint16> enabledHooks) : ScriptObject(name, ALLMAPHOOK_END)
ScriptObject(name)
{ {
ScriptRegistry<AllMapScript>::AddScript(this); // If empty - enable all available hooks.
if (enabledHooks.empty())
for (uint16 i = 0; i < ALLMAPHOOK_END; ++i)
enabledHooks.emplace_back(i);
ScriptRegistry<AllMapScript>::AddScript(this, std::move(enabledHooks));
} }
template class AC_GAME_API ScriptRegistry<AllMapScript>; template class AC_GAME_API ScriptRegistry<AllMapScript>;
@@ -19,11 +19,24 @@
#define SCRIPT_OBJECT_ALL_MAP_SCRIPT_H_ #define SCRIPT_OBJECT_ALL_MAP_SCRIPT_H_
#include "ScriptObject.h" #include "ScriptObject.h"
#include <vector>
enum AllMapHook
{
ALLMAPHOOK_ON_PLAYER_ENTER_ALL,
ALLMAPHOOK_ON_PLAYER_LEAVE_ALL,
ALLMAPHOOK_ON_BEFORE_CREATE_INSTANCE_SCRIPT,
ALLMAPHOOK_ON_DESTROY_INSTANCE,
ALLMAPHOOK_ON_CREATE_MAP,
ALLMAPHOOK_ON_DESTROY_MAP,
ALLMAPHOOK_ON_MAP_UPDATE,
ALLMAPHOOK_END
};
class AllMapScript : public ScriptObject class AllMapScript : public ScriptObject
{ {
protected: protected:
AllMapScript(const char* name); AllMapScript(const char* name, std::vector<uint16> enabledHooks = std::vector<uint16>());
public: public:
/** /**
+1
View File
@@ -113,6 +113,7 @@ void ScriptMgr::Initialize()
ScriptRegistry<UnitScript>::InitEnabledHooksIfNeeded(UNITHOOK_END); ScriptRegistry<UnitScript>::InitEnabledHooksIfNeeded(UNITHOOK_END);
ScriptRegistry<WorldObjectScript>::InitEnabledHooksIfNeeded(WORLDOBJECTHOOK_END); ScriptRegistry<WorldObjectScript>::InitEnabledHooksIfNeeded(WORLDOBJECTHOOK_END);
ScriptRegistry<WorldScript>::InitEnabledHooksIfNeeded(WORLDHOOK_END); ScriptRegistry<WorldScript>::InitEnabledHooksIfNeeded(WORLDHOOK_END);
ScriptRegistry<AllMapScript>::InitEnabledHooksIfNeeded(ALLMAPHOOK_END);
} }
void ScriptMgr::Unload() void ScriptMgr::Unload()
+1
View File
@@ -2931,6 +2931,7 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target)
{ {
if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(effectUnit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL))) if (missInfo != SPELL_MISS_EVADE && !m_caster->IsFriendlyTo(effectUnit) && (!m_spellInfo->IsPositive() || m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
{ {
if (!m_triggeredByAuraSpell.spellInfo || (!(m_triggeredByAuraSpell.spellInfo->Effects[m_triggeredByAuraSpell.effectIndex].TriggerSpell == m_spellInfo->Id) && !(m_triggeredByAuraSpell.spellInfo->IsAuraEffectEqual(m_spellInfo))))
m_caster->CombatStart(effectUnit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_SUPRESS_TARGET_PROCS)); m_caster->CombatStart(effectUnit, !(m_spellInfo->AttributesEx3 & SPELL_ATTR3_SUPRESS_TARGET_PROCS));
// Patch 3.0.8: All player spells which cause a creature to become aggressive to you will now also immediately cause the creature to be tapped. // Patch 3.0.8: All player spells which cause a creature to become aggressive to you will now also immediately cause the creature to be tapped.
+1
View File
@@ -389,6 +389,7 @@ enum WorldIntConfigs
CONFIG_ICC_BUFF_ALLIANCE, CONFIG_ICC_BUFF_ALLIANCE,
CONFIG_ITEMDELETE_QUALITY, CONFIG_ITEMDELETE_QUALITY,
CONFIG_ITEMDELETE_ITEM_LEVEL, CONFIG_ITEMDELETE_ITEM_LEVEL,
CONFIG_ITEMDELETE_KEEP_DAYS,
CONFIG_BG_REWARD_WINNER_HONOR_FIRST, CONFIG_BG_REWARD_WINNER_HONOR_FIRST,
CONFIG_BG_REWARD_WINNER_ARENA_FIRST, CONFIG_BG_REWARD_WINNER_ARENA_FIRST,
CONFIG_BG_REWARD_WINNER_HONOR_LAST, CONFIG_BG_REWARD_WINNER_HONOR_LAST,
+4
View File
@@ -1266,6 +1266,7 @@ void World::LoadConfigSettings(bool reload)
_bool_configs[CONFIG_ITEMDELETE_VENDOR] = sConfigMgr->GetOption<bool>("ItemDelete.Vendor", 0); _bool_configs[CONFIG_ITEMDELETE_VENDOR] = sConfigMgr->GetOption<bool>("ItemDelete.Vendor", 0);
_int_configs[CONFIG_ITEMDELETE_QUALITY] = sConfigMgr->GetOption<int32>("ItemDelete.Quality", 3); _int_configs[CONFIG_ITEMDELETE_QUALITY] = sConfigMgr->GetOption<int32>("ItemDelete.Quality", 3);
_int_configs[CONFIG_ITEMDELETE_ITEM_LEVEL] = sConfigMgr->GetOption<int32>("ItemDelete.ItemLevel", 80); _int_configs[CONFIG_ITEMDELETE_ITEM_LEVEL] = sConfigMgr->GetOption<int32>("ItemDelete.ItemLevel", 80);
_int_configs[CONFIG_ITEMDELETE_KEEP_DAYS] = sConfigMgr->GetOption<int32>("ItemDelete.KeepDays", 0);
_int_configs[CONFIG_FFA_PVP_TIMER] = sConfigMgr->GetOption<int32>("FFAPvPTimer", 30); _int_configs[CONFIG_FFA_PVP_TIMER] = sConfigMgr->GetOption<int32>("FFAPvPTimer", 30);
@@ -2092,6 +2093,9 @@ void World::SetInitialWorldSettings()
// Delete all characters which have been deleted X days before // Delete all characters which have been deleted X days before
Player::DeleteOldCharacters(); Player::DeleteOldCharacters();
// Delete all items which have been deleted X days before
Player::DeleteOldRecoveryItems();
// Delete all custom channels which haven't been used for PreserveCustomChannelDuration days. // Delete all custom channels which haven't been used for PreserveCustomChannelDuration days.
Channel::CleanOldChannelsInDB(); Channel::CleanOldChannelsInDB();
+28
View File
@@ -82,6 +82,7 @@ public:
{ "anim", HandleDebugAnimCommand, SEC_ADMINISTRATOR, Console::No }, { "anim", HandleDebugAnimCommand, SEC_ADMINISTRATOR, Console::No },
{ "arena", HandleDebugArenaCommand, SEC_ADMINISTRATOR, Console::No }, { "arena", HandleDebugArenaCommand, SEC_ADMINISTRATOR, Console::No },
{ "bg", HandleDebugBattlegroundCommand, SEC_ADMINISTRATOR, Console::No }, { "bg", HandleDebugBattlegroundCommand, SEC_ADMINISTRATOR, Console::No },
{ "cooldown", HandleDebugCooldownCommand, SEC_ADMINISTRATOR, Console::No },
{ "getitemstate", HandleDebugGetItemStateCommand, SEC_ADMINISTRATOR, Console::No }, { "getitemstate", HandleDebugGetItemStateCommand, SEC_ADMINISTRATOR, Console::No },
{ "lootrecipient", HandleDebugGetLootRecipientCommand, SEC_ADMINISTRATOR, Console::No }, { "lootrecipient", HandleDebugGetLootRecipientCommand, SEC_ADMINISTRATOR, Console::No },
{ "getvalue", HandleDebugGetValueCommand, SEC_ADMINISTRATOR, Console::No }, { "getvalue", HandleDebugGetValueCommand, SEC_ADMINISTRATOR, Console::No },
@@ -784,6 +785,33 @@ public:
return true; return true;
} }
static bool HandleDebugCooldownCommand(ChatHandler* handler, uint32 spell_id, uint32 end_time, Optional<uint32> item_id)
{
Player* player = handler->GetPlayer();
if (!player || !spell_id || !end_time)
return false;
if (!sSpellMgr->GetSpellInfo(spell_id))
return false;
if (!item_id)
item_id = 0;
else if (!sItemStore.LookupEntry(*item_id))
return false;
if (end_time < player->GetSpellCooldownDelay(spell_id))
player->RemoveSpellCooldown(spell_id, true);
player->AddSpellCooldown(spell_id, *item_id, end_time, true, false);
WorldPacket data;
player->BuildCooldownPacket(data, SPELL_COOLDOWN_FLAG_NONE, spell_id, end_time);
player->SendDirectMessage(&data);
return true;
}
static bool HandleDebugArenaCommand(ChatHandler* /*handler*/) static bool HandleDebugArenaCommand(ChatHandler* /*handler*/)
{ {
sBattlegroundMgr->ToggleArenaTesting(); sBattlegroundMgr->ToggleArenaTesting();
+8 -1
View File
@@ -123,7 +123,14 @@ public:
if (!name.data()) if (!name.data())
return false; return false;
QueryResult result = WorldDatabase.Query("SELECT entry FROM creature_template WHERE name = \"{}\" LIMIT 1" , name.data()); // Make sure we don't pass double quotes into the SQL query. Otherwise it causes a MySQL error
std::string str = name.data(); // Making subtractions to the last character does not with in string_view
if (str.front() == '"')
str = str.substr(1);
if (str.back() == '"')
str = str.substr(0, str.size() - 1);
QueryResult result = WorldDatabase.Query("SELECT entry FROM creature_template WHERE name = \"{}\" LIMIT 1", str);
if (!result) if (!result)
{ {
handler->SendErrorMessage(LANG_COMMAND_GOCREATNOTFOUND); handler->SendErrorMessage(LANG_COMMAND_GOCREATNOTFOUND);
@@ -244,17 +244,17 @@ const Position SBSLeaderEndPos = {823.2f, -4.4497f, 509.49f, 0.86f};
enum eSBSTexts // Ick outro enum eSBSTexts // Ick outro
{ {
SAY_OUTRO_KRICK_1 = 6, SAY_OUTRO_KRICK_1 = 6,
SAY_JAINA_KRICK_1 = 36, SAY_JAINA_KRICK_1 = 0,
SAY_SYLVANAS_KRICK_1 = 37, SAY_SYLVANAS_KRICK_1 = 0,
SAY_OUTRO_KRICK_2 = 7, SAY_OUTRO_KRICK_2 = 7,
SAY_JAINA_KRICK_2 = 39, SAY_JAINA_KRICK_2 = 1,
SAY_SYLVANAS_KRICK_2 = 40, SAY_SYLVANAS_KRICK_2 = 1,
SAY_OUTRO_KRICK_3 = 8, SAY_OUTRO_KRICK_3 = 8,
SAY_TYRANNUS_KRICK_1 = 0, SAY_TYRANNUS_KRICK_1 = 0,
SAY_OUTRO_KRICK_4 = 9, SAY_OUTRO_KRICK_4 = 9,
SAY_TYRANNUS_KRICK_2 = 1, SAY_TYRANNUS_KRICK_2 = 1,
SAY_JAINA_KRICK_3 = 45, SAY_JAINA_KRICK_3 = 45,
SAY_SYLVANAS_KRICK_3 = 46, SAY_SYLVANAS_KRICK_3 = 2,
}; };
/************ /************
@@ -1313,7 +1313,7 @@ struct npc_flame_of_azzinoth : public ScriptedAI
{ {
ScheduleTimedEvent(10s, [&] { ScheduleTimedEvent(10s, [&] {
if (Creature* _blade = ObjectAccessor::GetCreature(*me, _bladeGUID)) if (Creature* _blade = ObjectAccessor::GetCreature(*me, _bladeGUID))
if (Unit* target = _blade->AI()->SelectTarget(SelectTargetMethod::Random, 0, 30.0f, true)) if (Unit* target = _blade->AI()->SelectTarget(SelectTargetMethod::Random, 0, -40.0f, true))
DoCast(target, SPELL_CHARGE); DoCast(target, SPELL_CHARGE);
}, 5s, 20s); }, 5s, 20s);
@@ -1463,16 +1463,6 @@ class spell_illidan_tear_of_azzinoth_summon_channel_aura : public AuraScript
GetTarget()->CastSpell(GetTarget(), SPELL_UNCAGED_WRATH, true); GetTarget()->CastSpell(GetTarget(), SPELL_UNCAGED_WRATH, true);
} }
} }
// xinef: ugly hax, dunno how it really works on blizz
Map::PlayerList const& pl = GetTarget()->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pl.begin(); itr != pl.end(); ++itr)
if (Player* player = itr->GetSource())
if (player->GetPositionX() > 693.4f || player->GetPositionY() < 271.8f || player->GetPositionX() < 658.43f || player->GetPositionY() > 338.68f)
{
GetTarget()->CastSpell(player, SPELL_CHARGE, true);
break;
}
} }
void Register() override void Register() override
@@ -3273,6 +3273,7 @@ enum TournamentMountsSpells
62785 - Summon Tournament Kodo 62785 - Summon Tournament Kodo
62786 - Summon Tournament Hawkstrider 62786 - Summon Tournament Hawkstrider
62787 - Summon Tournament Warhorse 62787 - Summon Tournament Warhorse
63215 - Summon Campaign Charger
63663 - Summon Tournament Argent Charger 63663 - Summon Tournament Argent Charger
63791 - Summon Tournament Hawkstrider (Aspirant) 63791 - Summon Tournament Hawkstrider (Aspirant)
63792 - Summon Tournament Steed (Aspirant) */ 63792 - Summon Tournament Steed (Aspirant) */
+1 -1
View File
@@ -54,7 +54,7 @@ SourceDirectory = ""
# MySQLExecutable # MySQLExecutable
# Description: The path to your MySQL CLI binary. # Description: The path to your MySQL CLI binary.
# If the path is left empty, built-in path from cmake is used. # If the path is left empty, built-in path from cmake is used.
# Example: "C:/Program Files/MariaDB 10.9/bin/mysql.exe" # Example: "C:/Program Files/MySQL Server 8.4/bin/mysql.exe"
# "mysql.exe" # "mysql.exe"
# "/usr/bin/mysql" # "/usr/bin/mysql"
# Default: "" # Default: ""
-1
View File
@@ -568,5 +568,4 @@ void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uin
uint32 nlen = strlen(WmoInstName); uint32 nlen = strlen(WmoInstName);
fwrite(&nlen, sizeof(uint32), 1, pDirfile); fwrite(&nlen, sizeof(uint32), 1, pDirfile);
fwrite(WmoInstName, sizeof(char), nlen, pDirfile); fwrite(WmoInstName, sizeof(char), nlen, pDirfile);
} }