Merge remote-tracking branch 'tc/3.3.5' into 4.3.4

Note: additional hand-picked ports from 6.x to fix build

Conflicts:
	sql/updates/world/2016_02_22_00_world.sql
	sql/updates/world/2016_02_22_01_world.sql
	sql/updates/world/2016_02_22_02_world.sql
	sql/updates/world/2016_03_07_00_world.sql
	src/server/authserver/Realms/RealmList.cpp
	src/server/authserver/Realms/RealmList.h
	src/server/authserver/Server/AuthSession.cpp
	src/server/game/Accounts/AccountMgr.cpp
	src/server/game/AuctionHouse/AuctionHouseMgr.cpp
	src/server/game/Chat/Chat.cpp
	src/server/game/Conditions/ConditionMgr.cpp
	src/server/game/Conditions/ConditionMgr.h
	src/server/game/Entities/Player/Player.cpp
	src/server/game/Handlers/CharacterHandler.cpp
	src/server/game/Handlers/MiscHandler.cpp
	src/server/game/Scripting/ScriptLoader.cpp
	src/server/game/Scripting/ScriptLoader.h
	src/server/game/Server/WorldSession.cpp
	src/server/game/Server/WorldSocket.cpp
	src/server/game/World/World.cpp
	src/server/game/World/World.h
	src/server/scripts/CMakeLists.txt
	src/server/scripts/Commands/cs_gm.cpp
	src/server/scripts/Commands/cs_misc.cpp
	src/server/scripts/Commands/cs_rbac.cpp
	src/server/scripts/Commands/cs_ticket.cpp
	src/server/scripts/Commands/cs_wp.cpp
	src/server/scripts/EasternKingdoms/CMakeLists.txt
	src/server/scripts/EasternKingdoms/zone_burning_steppes.cpp
	src/server/scripts/EasternKingdoms/zone_stormwind_city.cpp
	src/server/scripts/Kalimdor/CMakeLists.txt
	src/server/scripts/Kalimdor/zone_dustwallow_marsh.cpp
	src/server/scripts/Kalimdor/zone_orgrimmar.cpp
	src/server/scripts/OutdoorPvP/CMakeLists.txt
	src/server/scripts/Spells/spell_dk.cpp
	src/server/scripts/Spells/spell_hunter.cpp
	src/server/shared/CMakeLists.txt
	src/server/worldserver/CMakeLists.txt
	src/server/worldserver/Main.cpp
	src/tools/mmaps_generator/CMakeLists.txt
This commit is contained in:
ariel- committed 2016-03-11 18:32:07 -03:00
commit 65aec5f8f7
143 files changed
+4022 -4094

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
# Set build-directive (used in core to tell which buildtype we used)
add_definitions(-D_BUILD_DIRECTIVE='"$(CONFIGURATION)"')
add_definitions(-D_BUILD_DIRECTIVE='"${CMAKE_BUILD_TYPE}"')
if(WITH_WARNINGS)
set(WARNING_FLAGS "-W -Wall -Wextra -Winit-self -Wfatal-errors -Wno-mismatched-tags")
+45 -26
View File
@@ -11,7 +11,7 @@ FUNCTION(GET_COMMON_PCH_PARAMS PCH_HEADER PCH_FE INCLUDE_PREFIX)
SET(INCLUDE_FLAGS ${INCLUDE_FLAGS_LIST} PARENT_SCOPE)
ENDFUNCTION(GET_COMMON_PCH_PARAMS)
FUNCTION(GENERATE_CXX_PCH_COMMAND TARGET_NAME INCLUDE_FLAGS IN PCH_SRC OUT)
FUNCTION(GENERATE_CXX_PCH_COMMAND TARGET_NAME_LIST INCLUDE_FLAGS IN PCH_SRC OUT)
IF (CMAKE_BUILD_TYPE)
STRING(TOUPPER _${CMAKE_BUILD_TYPE} CURRENT_BUILD_TYPE)
ENDIF ()
@@ -55,50 +55,69 @@ FUNCTION(GENERATE_CXX_PCH_COMMAND TARGET_NAME INCLUDE_FLAGS IN PCH_SRC OUT)
DEPENDS ${OUT}
)
ADD_DEPENDENCIES(${TARGET_NAME} generate_${PCH_SRC_N})
FOREACH(TARGET_NAME ${TARGET_NAME_LIST})
ADD_DEPENDENCIES(${TARGET_NAME} generate_${PCH_SRC_N})
ENDFOREACH()
ENDFUNCTION(GENERATE_CXX_PCH_COMMAND)
FUNCTION(ADD_CXX_PCH_GCC TARGET_NAME PCH_HEADER PCH_SOURCE)
FUNCTION(ADD_CXX_PCH_GCC TARGET_NAME_LIST PCH_HEADER PCH_SOURCE)
GET_COMMON_PCH_PARAMS(${PCH_HEADER} "gch" "-I")
GENERATE_CXX_PCH_COMMAND(${TARGET_NAME} "${INCLUDE_FLAGS}" ${PCH_HEADER} ${PCH_SOURCE} ${PCH_HEADER_OUT})
SET_TARGET_PROPERTIES(
${TARGET_NAME} PROPERTIES
COMPILE_FLAGS "-include ${CMAKE_CURRENT_BINARY_DIR}/${PCH_HEADER_NAME}"
)
GENERATE_CXX_PCH_COMMAND("${TARGET_NAME_LIST}" "${INCLUDE_FLAGS}" ${PCH_HEADER} ${PCH_SOURCE} ${PCH_HEADER_OUT})
FOREACH(TARGET_NAME ${TARGET_NAME_LIST})
SET_TARGET_PROPERTIES(
${TARGET_NAME} PROPERTIES
COMPILE_FLAGS "-include ${CMAKE_CURRENT_BINARY_DIR}/${PCH_HEADER_NAME}"
)
ENDFOREACH()
ENDFUNCTION(ADD_CXX_PCH_GCC)
FUNCTION(ADD_CXX_PCH_CLANG TARGET_NAME PCH_HEADER PCH_SOURCE)
FUNCTION(ADD_CXX_PCH_CLANG TARGET_NAME_LIST PCH_HEADER PCH_SOURCE)
GET_COMMON_PCH_PARAMS(${PCH_HEADER} "pch" "-I")
GENERATE_CXX_PCH_COMMAND(${TARGET_NAME} "${INCLUDE_FLAGS}" ${PCH_HEADER} ${PCH_SOURCE} ${PCH_HEADER_OUT})
SET_TARGET_PROPERTIES(
${TARGET_NAME} PROPERTIES
COMPILE_FLAGS "-include-pch ${PCH_HEADER_OUT}"
)
GENERATE_CXX_PCH_COMMAND("${TARGET_NAME_LIST}" "${INCLUDE_FLAGS}" ${PCH_HEADER} ${PCH_SOURCE} ${PCH_HEADER_OUT})
FOREACH(TARGET_NAME ${TARGET_NAME_LIST})
SET_TARGET_PROPERTIES(
${TARGET_NAME} PROPERTIES
COMPILE_FLAGS "-include-pch ${PCH_HEADER_OUT}"
)
ENDFOREACH()
ENDFUNCTION(ADD_CXX_PCH_CLANG)
FUNCTION(ADD_CXX_PCH_MSVC TARGET_NAME PCH_HEADER PCH_SOURCE)
FUNCTION(ADD_CXX_PCH_MSVC TARGET_NAME_LIST PCH_HEADER PCH_SOURCE)
GET_COMMON_PCH_PARAMS(${PCH_HEADER} "pch" "/I")
SET_TARGET_PROPERTIES(
${TARGET_NAME} PROPERTIES
COMPILE_FLAGS "/FI${PCH_HEADER_NAME} /Yu${PCH_HEADER_NAME}"
)
FOREACH(TARGET_NAME ${TARGET_NAME_LIST})
SET_TARGET_PROPERTIES(
${TARGET_NAME} PROPERTIES
COMPILE_FLAGS "/FI${PCH_HEADER_NAME} /Yu${PCH_HEADER_NAME}"
)
ENDFOREACH()
SET_SOURCE_FILES_PROPERTIES(
${PCH_SOURCE} PROPERTIES
COMPILE_FLAGS "/Yc${PCH_HEADER_NAME}"
)
ENDFUNCTION(ADD_CXX_PCH_MSVC)
FUNCTION(ADD_CXX_PCH TARGET_NAME PCH_HEADER PCH_SOURCE)
IF (MSVC)
ADD_CXX_PCH_MSVC(${TARGET_NAME} ${PCH_HEADER} ${PCH_SOURCE})
ELSEIF ("${CMAKE_GENERATOR}" MATCHES "Xcode")
SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
FUNCTION(ADD_CXX_PCH_XCODE TARGET_NAME_LIST PCH_HEADER PCH_SOURCE)
FOREACH(TARGET_NAME ${TARGET_NAME_LIST})
SET_TARGET_PROPERTIES("${TARGET_NAME}" PROPERTIES
XCODE_ATTRIBUTE_GCC_PRECOMPILE_PREFIX_HEADER YES
XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/${PCH_HEADER}"
)
ENDFOREACH()
ENDFUNCTION(ADD_CXX_PCH_XCODE)
FUNCTION(ADD_CXX_PCH TARGET_NAME_LIST PCH_HEADER PCH_SOURCE)
IF (MSVC)
ADD_CXX_PCH_MSVC("${TARGET_NAME_LIST}" ${PCH_HEADER} ${PCH_SOURCE})
ELSEIF ("${CMAKE_GENERATOR}" MATCHES "Xcode")
ADD_CXX_PCH_XCODE("${TARGET_NAME_LIST}" ${PCH_HEADER} ${PCH_SOURCE})
ELSEIF ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
ADD_CXX_PCH_CLANG(${TARGET_NAME} ${PCH_HEADER} ${PCH_SOURCE})
ADD_CXX_PCH_CLANG("${TARGET_NAME_LIST}" ${PCH_HEADER} ${PCH_SOURCE})
ELSEIF ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
ADD_CXX_PCH_GCC(${TARGET_NAME} ${PCH_HEADER} ${PCH_SOURCE})
ADD_CXX_PCH_GCC("${TARGET_NAME_LIST}" ${PCH_HEADER} ${PCH_SOURCE})
ENDIF ()
ENDFUNCTION(ADD_CXX_PCH)
+51
View File
@@ -0,0 +1,51 @@
@ECHO OFF
CLS
:MENU
ECHO.
ECHO ...............................................
ECHO Trinitycore dbc/db2, maps, vmaps, mmaps extractor
ECHO ...............................................
ECHO PRESS 1, 2, 3 OR 4 to select your task, or 5 to EXIT.
ECHO ...............................................
ECHO.
ECHO 1 - Extract dbc/db2 and maps
ECHO 2 - Extract vmaps (needs maps to be extracted before you run this)
ECHO 3 - Extract mmaps (needs vmaps to be extracted before you run this, may take hours)
ECHO 4 - Extract all (may take hours)
ECHO 5 - EXIT
ECHO.
SET /P M=Type 1, 2, 3, 4 or 5 then press ENTER:
IF %M%==1 GOTO MAPS
IF %M%==2 GOTO VMAPS
IF %M%==3 GOTO MMAPS
IF %M%==4 GOTO ALL
IF %M%==5 GOTO EOF
:MAPS
start mapextractor.exe
pause
GOTO MENU
:VMAPS
start vmap4extractor.exe
md vmaps
start vmap4assembler.exe Buildings vmaps
pause
GOTO MENU
:MMAPS
md mmaps
start mmaps_generator.exe
pause
GOTO MENU
:ALL
start mapextractor.exe
ECHO wait before mapextractor.exe closes before continue
pause
start vmap4extractor.exe
md vmaps
start vmap4assembler.exe Buildings vmaps
rmdir Buildings /s /q
ECHO wait before vmap4assembler.exe closes before continue
pause
md mmaps
start mmaps_generator.exe
pause
GOTO MENU
+2 -2
View File
@@ -3,7 +3,9 @@
#define _HASH "@rev_hash@"
#define _DATE "@rev_date@"
#define _BRANCH "@rev_branch@"
#define _CMAKE_COMMAND "@CMAKE_COMMAND@"
#define _SOURCE_DIRECTORY "@CMAKE_SOURCE_DIR@"
#define _BUILD_DIRECTORY "@BUILDDIR@"
#define _MYSQL_EXECUTABLE "@MYSQL_EXECUTABLE@"
#define _FULL_DATABASE "TDB_full_434.10_2015_07_28.sql"
#define VER_COMPANYNAME_STR "TrinityCore Developers"
@@ -12,6 +14,4 @@
#define VER_FILEVERSION_STR "@rev_hash@ @rev_date@ (@rev_branch@ branch)"
#define VER_PRODUCTVERSION VER_FILEVERSION
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#define COMPILER_C_FLAGS "@CMAKE_C_FLAGS@"
#define COMPILER_CXX_FLAGS "@CMAKE_CXX_FLAGS@"
#endif // __REVISION_DATA_H__
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BuiltInConfig.h"
#include "Config.h"
#include "GitRevision.h"
template<typename Fn>
static std::string GetStringWithDefaultValueFromFunction(
std::string const& key, Fn getter)
{
std::string const value = sConfigMgr->GetStringDefault(key, "");
return value.empty() ? getter() : value;
}
std::string BuiltInConfig::GetCMakeCommand()
{
return GetStringWithDefaultValueFromFunction(
"CMakeCommand", GitRevision::GetCMakeCommand);
}
std::string BuiltInConfig::GetBuildDirectory()
{
return GetStringWithDefaultValueFromFunction(
"BuildDirectory", GitRevision::GetBuildDirectory);
}
std::string BuiltInConfig::GetSourceDirectory()
{
return GetStringWithDefaultValueFromFunction(
"SourceDirectory", GitRevision::GetSourceDirectory);
}
std::string BuiltInConfig::GetMySQLExecutable()
{
return GetStringWithDefaultValueFromFunction(
"MySQLExecutable", GitRevision::GetMySQLExecutable);
}
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BUILT_IN_CONFIG_H
#define BUILT_IN_CONFIG_H
#include <string>
/// Provides helper functions to access built-in values
/// which can be overwritten in config
namespace BuiltInConfig
{
/// Returns the CMake command when any is specified in the config,
/// returns the built-in path otherwise
std::string GetCMakeCommand();
/// Returns the build directory path when any is specified in the config,
/// returns the built-in one otherwise
std::string GetBuildDirectory();
/// Returns the source directory path when any is specified in the config,
/// returns the built-in one otherwise
std::string GetSourceDirectory();
/// Returns the path to the mysql executable (`mysql`) when any is specified
/// in the config, returns the built-in one otherwise
std::string GetMySQLExecutable();
} // namespace BuiltInConfig
#endif // BUILT_IN_CONFIG_H
+4 -4
View File
@@ -61,7 +61,7 @@ bool ConfigMgr::Reload(std::string& error)
return LoadInitial(_filename, error);
}
std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def)
std::string ConfigMgr::GetStringDefault(std::string const& name, const std::string& def) const
{
std::string value = _config.get<std::string>(ptree::path_type(name, '/'), def);
@@ -70,7 +70,7 @@ std::string ConfigMgr::GetStringDefault(std::string const& name, const std::stri
return value;
}
bool ConfigMgr::GetBoolDefault(std::string const& name, bool def)
bool ConfigMgr::GetBoolDefault(std::string const& name, bool def) const
{
try
{
@@ -84,12 +84,12 @@ bool ConfigMgr::GetBoolDefault(std::string const& name, bool def)
}
}
int ConfigMgr::GetIntDefault(std::string const& name, int def)
int ConfigMgr::GetIntDefault(std::string const& name, int def) const
{
return _config.get<int>(ptree::path_type(name, '/'), def);
}
float ConfigMgr::GetFloatDefault(std::string const& name, float def)
float ConfigMgr::GetFloatDefault(std::string const& name, float def) const
{
return _config.get<float>(ptree::path_type(name, '/'), def);
}
+4 -4
View File
@@ -41,10 +41,10 @@ public:
bool Reload(std::string& error);
std::string GetStringDefault(std::string const& name, const std::string& def);
bool GetBoolDefault(std::string const& name, bool def);
int GetIntDefault(std::string const& name, int def);
float GetFloatDefault(std::string const& name, float def);
std::string GetStringDefault(std::string const& name, const std::string& def) const;
bool GetBoolDefault(std::string const& name, bool def) const;
int GetIntDefault(std::string const& name, int def) const;
float GetFloatDefault(std::string const& name, float def) const;
std::string const& GetFilename();
std::list<std::string> GetKeysByString(std::string const& name);
+10 -10
View File
@@ -17,6 +17,16 @@ char const* GitRevision::GetBranch()
return _BRANCH;
}
char const* GitRevision::GetCMakeCommand()
{
return _CMAKE_COMMAND;
}
char const* GitRevision::GetBuildDirectory()
{
return _BUILD_DIRECTORY;
}
char const* GitRevision::GetSourceDirectory()
{
return _SOURCE_DIRECTORY;
@@ -66,13 +76,3 @@ char const* GitRevision::GetProductVersionStr()
{
return VER_PRODUCTVERSION_STR;
}
char const* GitRevision::GetCompilerCFlags()
{
return COMPILER_C_FLAGS;
}
char const* GitRevision::GetCompilerCXXFlags()
{
return COMPILER_CXX_FLAGS;
}
+2 -2
View File
@@ -25,6 +25,8 @@ namespace GitRevision
char const* GetHash();
char const* GetDate();
char const* GetBranch();
char const* GetCMakeCommand();
char const* GetBuildDirectory();
char const* GetSourceDirectory();
char const* GetMySQLExecutable();
char const* GetFullDatabase();
@@ -33,8 +35,6 @@ namespace GitRevision
char const* GetLegalCopyrightStr();
char const* GetFileVersionStr();
char const* GetProductVersionStr();
char const* GetCompilerCFlags();
char const* GetCompilerCXXFlags();
}
#endif
+6 -6
View File
@@ -214,13 +214,13 @@ void Log::ReadLoggersFromConfig()
AppenderConsole* appender = new AppenderConsole(NextAppenderId(), "Console", LOG_LEVEL_DEBUG, APPENDER_FLAGS_NONE, ExtraAppenderArgs());
appenders[appender->getId()] = appender;
Logger& logger = loggers[LOGGER_ROOT];
logger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR);
logger.addAppender(appender->getId(), appender);
Logger& rootLogger = loggers[LOGGER_ROOT];
rootLogger.Create(LOGGER_ROOT, LOG_LEVEL_ERROR);
rootLogger.addAppender(appender->getId(), appender);
logger = loggers["server"];
logger.Create("server", LOG_LEVEL_ERROR);
logger.addAppender(appender->getId(), appender);
Logger& serverLogger = loggers["server"];
serverLogger.Create("server", LOG_LEVEL_INFO);
serverLogger.addAppender(appender->getId(), appender);
}
}
+8
View File
@@ -61,6 +61,14 @@ float frand(float min, float max)
return float(GetRng()->Random() * (max - min) + min);
}
Milliseconds randtime(Milliseconds const& min, Milliseconds const& max)
{
long long diff = max.count() - min.count();
ASSERT(diff >= 0);
ASSERT(diff <= (uint32)-1);
return min + Milliseconds(urand(0, diff));
}
uint32 rand32()
{
return GetRng()->BRandom();
+4
View File
@@ -19,6 +19,7 @@
#define Random_h__
#include "Define.h"
#include "Duration.h"
#include <limits>
#include <random>
@@ -34,6 +35,9 @@ uint32 urandms(uint32 min, uint32 max);
/* Return a random number in the range 0 .. UINT32_MAX. */
uint32 rand32();
/* Return a random time in the range min..max (up to millisecond precision). Only works for values where millisecond difference is a valid uint32. */
Milliseconds randtime(Milliseconds const& min, Milliseconds const& max);
/* Return a random number in the range min..max */
float frand(float min, float max);
+2 -2
View File
@@ -25,8 +25,8 @@ set(sources_windows_Debugging
add_subdirectory(database)
add_subdirectory(shared)
add_subdirectory(game)
add_subdirectory(ipc)
add_subdirectory(authserver)
add_subdirectory(ipc)
add_subdirectory(bnetserver)
add_subdirectory(bnetserver)
add_subdirectory(scripts)
add_subdirectory(worldserver)
+3 -2
View File
@@ -57,6 +57,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/database
${CMAKE_SOURCE_DIR}/src/server/database/Database
${CMAKE_SOURCE_DIR}/src/server/database/Logging
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Networking
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Service
@@ -79,10 +80,10 @@ if( NOT WIN32 )
endif()
target_link_libraries(authserver
common
shared
format
database
common
format
${MYSQL_LIBRARY}
${OPENSSL_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
+3 -1
View File
@@ -134,7 +134,7 @@ int main(int argc, char** argv)
// Get the list of realms for the server
sRealmList->Initialize(*_ioService, sConfigMgr->GetIntDefault("RealmsStateUpdateDelay", 20));
if (sRealmList->size() == 0)
if (sRealmList->GetRealms().empty())
{
TC_LOG_ERROR("server.authserver", "No valid realms specified.");
StopDB();
@@ -194,6 +194,8 @@ int main(int argc, char** argv)
sAuthSocketMgr.StopNetwork();
sRealmList->Close();
// Close the Database Pool and library
StopDB();
+54 -73
View File
@@ -16,104 +16,62 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/asio/ip/tcp.hpp>
#include "Common.h"
#include "RealmList.h"
#include "Database/DatabaseEnv.h"
#include "Util.h"
#include "RealmList.h"
#include <boost/asio/ip/tcp.hpp>
ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const
{
ip::address realmIp;
// Attempt to send best address for client
if (clientAddr.is_loopback())
{
// Try guessing if realm is also connected locally
if (LocalAddress.is_loopback() || ExternalAddress.is_loopback())
realmIp = clientAddr;
else
{
// Assume that user connecting from the machine that authserver is located on
// has all realms available in his local network
realmIp = LocalAddress;
}
}
else
{
if (clientAddr.is_v4() &&
(clientAddr.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong()) ==
(LocalAddress.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong()))
{
realmIp = LocalAddress;
}
else
realmIp = ExternalAddress;
}
ip::tcp::endpoint endpoint(realmIp, port);
// Return external IP
return endpoint;
}
RealmList::RealmList() : m_UpdateInterval(0), m_NextUpdateTime(time(NULL)), _resolver(nullptr)
{
}
namespace boost { namespace asio { namespace ip { class address; } } }
RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr) { }
RealmList::~RealmList()
{
delete _resolver;
delete _updateTimer;
}
// Load the realm list from the database
void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInterval)
{
_updateInterval = updateInterval;
_updateTimer = new boost::asio::deadline_timer(ioService);
_resolver = new boost::asio::ip::tcp::resolver(ioService);
m_UpdateInterval = updateInterval;
// Get the content of the realmlist table in the database
UpdateRealms(true);
UpdateRealms(true, boost::system::error_code());
}
void RealmList::UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr,
ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build)
void RealmList::Close()
{
_updateTimer->cancel();
}
void RealmList::UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, const std::string& name, ip::address const& address, ip::address const& localAddr,
ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel,
float population)
{
// Create new if not exist or update existed
Realm& realm = m_realms[name];
realm.m_ID = id;
realm.name = name;
realm.icon = icon;
realm.flag = flag;
realm.timezone = timezone;
realm.allowedSecurityLevel = allowedSecurityLevel;
realm.populationLevel = population;
Realm& realm = _realms[id];
realm.Id = id;
realm.Build = build;
realm.Name = name;
realm.Type = icon;
realm.Flags = flag;
realm.Timezone = timezone;
realm.AllowedSecurityLevel = allowedSecurityLevel;
realm.PopulationLevel = population;
realm.ExternalAddress = address;
realm.LocalAddress = localAddr;
realm.LocalSubnetMask = localSubmask;
realm.port = port;
realm.gamebuild = build;
realm.Port = port;
}
void RealmList::UpdateIfNeed()
void RealmList::UpdateRealms(bool init, boost::system::error_code const& error)
{
// maybe disabled or updated recently
if (!m_UpdateInterval || m_NextUpdateTime > time(NULL))
if (error)
return;
m_NextUpdateTime = time(NULL) + m_UpdateInterval;
// Clears Realm list
m_realms.clear();
// Get the content of the realmlist table in the database
UpdateRealms();
}
void RealmList::UpdateRealms(bool init)
{
TC_LOG_INFO("server.authserver", "Updating Realm List...");
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST);
@@ -165,17 +123,25 @@ void RealmList::UpdateRealms(bool init)
uint16 port = fields[5].GetUInt16();
uint8 icon = fields[6].GetUInt8();
if (icon == REALM_TYPE_FFA_PVP)
icon = REALM_TYPE_PVP;
if (icon >= MAX_CLIENT_REALM_TYPE)
icon = REALM_TYPE_NORMAL;
RealmFlags flag = RealmFlags(fields[7].GetUInt8());
uint8 timezone = fields[8].GetUInt8();
uint8 allowedSecurityLevel = fields[9].GetUInt8();
float pop = fields[10].GetFloat();
uint32 build = fields[11].GetUInt32();
uint8 region = fields[12].GetUInt8();
uint8 battlegroup = fields[13].GetUInt8();
UpdateRealm(realmId, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone,
(allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop, build);
Battlenet::RealmHandle id{ region, battlegroup, realmId };
UpdateRealm(id, build, name, externalAddress, localAddress, localSubmask, port, icon, flag,
timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
if (init)
TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), m_realms[name].ExternalAddress.to_string().c_str(), port);
TC_LOG_INFO("server.authserver", "Added realm \"%s\" at %s:%u.", name.c_str(), externalAddress.to_string().c_str(), port);
}
catch (std::exception& ex)
{
@@ -185,4 +151,19 @@ void RealmList::UpdateRealms(bool init)
}
while (result->NextRow());
}
if (_updateInterval)
{
_updateTimer->expires_from_now(boost::posix_time::seconds(_updateInterval));
_updateTimer->async_wait(std::bind(&RealmList::UpdateRealms, this, false, std::placeholders::_1));
}
}
Realm const* RealmList::GetRealm(Battlenet::RealmHandle const& id) const
{
auto itr = _realms.find(id);
if (itr != _realms.end())
return &itr->second;
return NULL;
}
+13 -47
View File
@@ -19,50 +19,20 @@
#ifndef _REALMLIST_H
#define _REALMLIST_H
#include "Common.h"
#include "Realm/Realm.h"
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/io_service.hpp>
#include "Common.h"
#include <boost/asio/deadline_timer.hpp>
using namespace boost::asio;
enum RealmFlags
{
REALM_FLAG_NONE = 0x00,
REALM_FLAG_INVALID = 0x01,
REALM_FLAG_OFFLINE = 0x02,
REALM_FLAG_SPECIFYBUILD = 0x04,
REALM_FLAG_UNK1 = 0x08,
REALM_FLAG_UNK2 = 0x10,
REALM_FLAG_RECOMMENDED = 0x20,
REALM_FLAG_NEW = 0x40,
REALM_FLAG_FULL = 0x80
};
// Storage object for a realm
struct Realm
{
ip::address ExternalAddress;
ip::address LocalAddress;
ip::address LocalSubnetMask;
uint16 port;
std::string name;
uint8 icon;
RealmFlags flag;
uint8 timezone;
uint32 m_ID;
AccountTypes allowedSecurityLevel;
float populationLevel;
uint32 gamebuild;
ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const;
};
/// Storage object for the list of realms on the server
class RealmList
{
public:
typedef std::map<std::string, Realm> RealmMap;
typedef std::map<Battlenet::RealmHandle, Realm> RealmMap;
static RealmList* instance()
{
@@ -73,25 +43,21 @@ public:
~RealmList();
void Initialize(boost::asio::io_service& ioService, uint32 updateInterval);
void Close();
void UpdateIfNeed();
void AddRealm(const Realm& NewRealm) { m_realms[NewRealm.name] = NewRealm; }
RealmMap::const_iterator begin() const { return m_realms.begin(); }
RealmMap::const_iterator end() const { return m_realms.end(); }
uint32 size() const { return m_realms.size(); }
RealmMap const& GetRealms() const { return _realms; }
Realm const* GetRealm(Battlenet::RealmHandle const& id) const;
private:
RealmList();
void UpdateRealms(bool init = false);
void UpdateRealm(uint32 id, const std::string& name, ip::address const& address, ip::address const& localAddr,
ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population, uint32 build);
void UpdateRealms(bool init, boost::system::error_code const& error);
void UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, const std::string& name, ip::address const& address, ip::address const& localAddr,
ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population);
RealmMap m_realms;
uint32 m_UpdateInterval;
time_t m_NextUpdateTime;
RealmMap _realms;
uint32 _updateInterval;
boost::asio::deadline_timer* _updateTimer;
boost::asio::ip::tcp::resolver* _resolver;
};
+15 -15
View File
@@ -571,6 +571,8 @@ bool AuthSession::HandleLogonProof()
TC_LOG_DEBUG("server.authserver", "'%s:%d' User '%s' successfully authenticated", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo.Login.c_str());
// Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
// No SQL injection (escaped user name) and IP address as received by socket
PreparedStatement *stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
stmt->setString(0, K.AsHexStr());
stmt->setString(1, GetRemoteIpAddress().to_string().c_str());
@@ -842,22 +844,19 @@ void AuthSession::RealmListCallback(PreparedQueryResult result)
} while (result->NextRow());
}
// Update realm list if need
sRealmList->UpdateIfNeed();
// Circle through realms in the RealmList and construct the return packet (including # of user characters in each realm)
ByteBuffer pkt;
size_t RealmListSize = 0;
for (RealmList::RealmMap::const_iterator i = sRealmList->begin(); i != sRealmList->end(); ++i)
for (RealmList::RealmMap::value_type const& i : sRealmList->GetRealms())
{
const Realm &realm = i->second;
const Realm &realm = i.second;
// don't work with realms which not compatible with the client
bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.gamebuild == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.gamebuild));
bool okBuild = ((_expversion & POST_BC_EXP_FLAG) && realm.Build == _build) || ((_expversion & PRE_BC_EXP_FLAG) && !AuthHelper::IsPreBCAcceptedClientBuild(realm.Build));
// No SQL injection. id of realm is controlled by the database.
uint32 flag = realm.flag;
RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.gamebuild);
uint32 flag = realm.Flags;
RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm.Build);
if (!okBuild)
{
if (!buildInfo)
@@ -869,7 +868,7 @@ void AuthSession::RealmListCallback(PreparedQueryResult result)
if (!buildInfo)
flag &= ~REALM_FLAG_SPECIFYBUILD;
std::string name = i->first;
std::string name = realm.Name;
if (_expversion & PRE_BC_EXP_FLAG && flag & REALM_FLAG_SPECIFYBUILD)
{
std::ostringstream ss;
@@ -877,19 +876,19 @@ void AuthSession::RealmListCallback(PreparedQueryResult result)
name = ss.str();
}
uint8 lock = (realm.allowedSecurityLevel > _accountInfo.SecurityLevel) ? 1 : 0;
uint8 lock = (realm.AllowedSecurityLevel > _accountInfo.SecurityLevel) ? 1 : 0;
pkt << uint8(realm.icon); // realm type
pkt << uint8(realm.Type); // realm type
if (_expversion & POST_BC_EXP_FLAG) // only 2.x and 3.x clients
pkt << uint8(lock); // if 1, then realm locked
pkt << uint8(flag); // RealmFlags
pkt << name;
pkt << boost::lexical_cast<std::string>(realm.GetAddressForClient(GetRemoteIpAddress()));
pkt << float(realm.populationLevel);
pkt << uint8(characterCounts[realm.m_ID]);
pkt << uint8(realm.timezone); // realm category
pkt << float(realm.PopulationLevel);
pkt << uint8(characterCounts[realm.Id.Realm]);
pkt << uint8(realm.Timezone); // realm category
if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
pkt << uint8(realm.m_ID);
pkt << uint8(realm.Id.Realm);
else
pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients
@@ -953,6 +952,7 @@ void AuthSession::SetVSFields(const std::string& rI)
x.SetBinary(sha.GetDigest(), sha.GetLength());
v = g.ModExp(x, N);
// No SQL injection (username escaped)
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS);
stmt->setString(0, v.AsHexStr());
stmt->setString(1, s.AsHexStr());
+20 -20
View File
@@ -137,6 +137,26 @@ WrongPass.Logging = 0
BanExpiryCheckInterval = 60
#
# SourceDirectory
# Description: The path to your TrinityCore source directory.
# If the path is left empty, the built-in CMAKE_SOURCE_DIR is used.
# Example: "../TrinityCore"
# Default: ""
SourceDirectory = ""
#
# MySQLExecutable
# Description: The path to your mysql cli binary.
# If the path is left empty, built-in path from cmake is used.
# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe"
# "mysql.exe"
# "/usr/bin/mysql"
# Default: ""
MySQLExecutable = ""
#
###################################################################################################
@@ -180,26 +200,6 @@ LoginDatabase.WorkerThreads = 1
Updates.EnableDatabases = 0
#
# Updates.SourcePath
# Description: The path to your TrinityCore source directory.
# If the path is left empty, built-in CMAKE_SOURCE_DIR is used.
# Example: "../TrinityCore"
# Default: ""
Updates.SourcePath = ""
#
# Updates.MySqlCLIPath
# Description: The path to your mysql cli binary.
# If the path is left empty, built-in path from cmake is used.
# Example: "C:/Program Files/MySQL/MySQL Server 5.6/bin/mysql.exe"
# "mysql.exe"
# "/usr/bin/mysql"
# Default: ""
Updates.MySqlCLIPath = ""
#
# Updates.AutoSetup
# Description: Auto populate empty databases.
+5 -5
View File
@@ -47,9 +47,9 @@ include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/Authentication
${CMAKE_CURRENT_SOURCE_DIR}/Packets
${CMAKE_CURRENT_SOURCE_DIR}/Realms
${CMAKE_CURRENT_SOURCE_DIR}/Server
${CMAKE_CURRENT_SOURCE_DIR}/Packets
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/zmqpp
${CMAKE_SOURCE_DIR}/src/common
@@ -64,9 +64,9 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/database/Database
${CMAKE_SOURCE_DIR}/src/server/database/Logging
${CMAKE_SOURCE_DIR}/src/server/ipc
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Networking
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Realm
${CMAKE_SOURCE_DIR}/src/server/shared/Service
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
@@ -86,12 +86,12 @@ if( NOT WIN32 )
endif()
target_link_libraries(bnetserver
common
shared
database
ipc
shared
format
common
zmqpp
format
${MYSQL_LIBRARY}
${OPENSSL_LIBRARIES}
${ZMQ_LIBRARY}
@@ -42,8 +42,8 @@ void Battlenet::WoWRealm::ListUnsubscribe::CallHandler(Session* session)
void Battlenet::WoWRealm::JoinRequestV2::Read()
{
Realm.Battlegroup = _stream.Read<uint8>(8);
Realm.Index = _stream.Read<uint32>(32);
Realm.Site = _stream.Read<uint8>(8);
Realm.Realm = _stream.Read<uint32>(32);
Realm.Region = _stream.Read<uint8>(8);
ClientSeed = _stream.Read<uint32>(32);
}
@@ -51,7 +51,7 @@ void Battlenet::WoWRealm::JoinRequestV2::Read()
std::string Battlenet::WoWRealm::JoinRequestV2::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::WoWRealm::JoinRequestV2 ClientSeed " << ClientSeed << " Region " << uint32(Realm.Region) << " Battlegroup " << uint32(Realm.Battlegroup) << " Index " << Realm.Index;
stream << "Battlenet::WoWRealm::JoinRequestV2 ClientSeed " << ClientSeed << " Region " << uint32(Realm.Region) << " Battlegroup " << uint32(Realm.Site) << " Index " << Realm.Realm;
return stream.str().c_str();
}
@@ -74,8 +74,8 @@ void Battlenet::WoWRealm::ListSubscribeResponse::Write()
_stream.Write(CharacterCounts.size(), 7);
for (CharacterCountEntry const& entry : CharacterCounts)
{
_stream.Write(entry.Realm.Battlegroup, 8);
_stream.Write(entry.Realm.Index, 32);
_stream.Write(entry.Realm.Site, 8);
_stream.Write(entry.Realm.Realm, 32);
_stream.Write(entry.Realm.Region, 8);
_stream.Write(entry.CharacterCount, 16);
}
@@ -100,7 +100,7 @@ std::string Battlenet::WoWRealm::ListSubscribeResponse::ToString() const
stream << " Realms " << CharacterCounts.size();
for (CharacterCountEntry const& entry : CharacterCounts)
stream << std::endl << "Region " << uint32(entry.Realm.Region) << " Battlegroup " << uint32(entry.Realm.Region) << " Index " << entry.Realm.Index << " Characters " << entry.CharacterCount;
stream << std::endl << "Region " << uint32(entry.Realm.Region) << " Battlegroup " << uint32(entry.Realm.Region) << " Index " << entry.Realm.Realm << " Characters " << entry.CharacterCount;
for (ServerPacket* realmData : RealmData)
stream << std::endl << realmData->ToString();
@@ -125,7 +125,7 @@ void Battlenet::WoWRealm::ListUpdate::Write()
if (!Version.empty())
{
_stream.WriteString(Version, 5);
_stream.Write(Id.Build, 32);
_stream.Write(Build, 32);
boost::asio::ip::address_v4::bytes_type ip = Address.address().to_v4().to_bytes();
uint16 port = Address.port();
@@ -140,8 +140,8 @@ void Battlenet::WoWRealm::ListUpdate::Write()
_stream.WriteString(Name, 10);
}
_stream.Write(Id.Battlegroup, 8);
_stream.Write(Id.Index, 32);
_stream.Write(Id.Site, 8);
_stream.Write(Id.Realm, 32);
_stream.Write(Id.Region, 8);
}
@@ -152,13 +152,13 @@ std::string Battlenet::WoWRealm::ListUpdate::ToString() const
if (UpdateState == UPDATE)
{
stream << " Timezone: " << Timezone << " Population: " << Population << " Lock: " << uint32(Lock) << " Type: " << Type << " Name: " << Name
<< " Flags: " << uint32(Flags) << " Region: " << uint32(Id.Region) << " Battlegroup: " << uint32(Id.Battlegroup) << " Index: " << Id.Index;
<< " Flags: " << uint32(Flags) << " Region: " << uint32(Id.Region) << " Battlegroup: " << uint32(Id.Site) << " Index: " << Id.Realm;
if (!Version.empty())
stream << " Version: " << Version;
}
else
stream << " Delete realm [Region: " << uint32(Id.Region) << " Battlegroup : " << uint32(Id.Battlegroup) << " Index : " << Id.Index << "]";
stream << " Delete realm [Region: " << uint32(Id.Region) << " Battlegroup : " << uint32(Id.Site) << " Index : " << Id.Realm << "]";
return stream.str().c_str();
}
@@ -167,7 +167,7 @@ void Battlenet::WoWRealm::ToonReady::Write()
{
_stream.Write(Realm.Region, 8);
_stream.WriteFourCC(Game);
uint32 realmAddress = ((Realm.Battlegroup << 16) & 0xFF0000) | uint16(Realm.Index);
uint32 realmAddress = ((Realm.Site << 16) & 0xFF0000) | uint16(Realm.Realm);
_stream.Write(realmAddress, 32);
_stream.WriteString(Name, 7, -2);
_stream.WriteSkip(7);
@@ -185,7 +185,7 @@ std::string Battlenet::WoWRealm::ToonReady::ToString() const
{
std::ostringstream stream;
stream << "Battlenet::WoWRealm::ToonReady" << " Game: " << Game
<< ", Region: " << uint32(Realm.Region) << ", Battlegroup: " << uint32(Realm.Battlegroup) << ", Index: " << Realm.Index
<< ", Region: " << uint32(Realm.Region) << ", Battlegroup: " << uint32(Realm.Site) << ", Index: " << Realm.Realm
<< ", Guid: " << Guid << ", Name: " << Name;
return stream.str().c_str();
@@ -79,7 +79,7 @@ namespace Battlenet
void CallHandler(Session* session) override;
uint32 ClientSeed;
RealmId Realm;
Battlenet::RealmHandle Realm;
};
class ListSubscribeResponse final : public ServerPacket
@@ -100,7 +100,7 @@ namespace Battlenet
struct CharacterCountEntry
{
RealmId Realm;
Battlenet::RealmHandle Realm;
uint32 CharacterCount;
};
@@ -139,7 +139,8 @@ namespace Battlenet
std::string Version;
tcp::endpoint Address;
uint8 Flags;
RealmId Id;
Battlenet::RealmHandle Id;
uint32 Build;
};
class ListComplete final : public ServerPacket
@@ -164,7 +165,7 @@ namespace Battlenet
std::string ToString() const override;
std::string Game;
RealmId Realm;
Battlenet::RealmHandle Realm;
uint64 Guid;
std::string Name;
};
+14 -51
View File
@@ -24,49 +24,6 @@
#include "RealmList.h"
#include <boost/asio/ip/tcp.hpp>
Battlenet::RealmId& Battlenet::RealmId::operator=(Battlenet::RealmHandle const& handle)
{
Region = handle.Region;
Battlegroup = handle.Battlegroup;
Index = handle.Index;
return *this;
}
ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const
{
ip::address realmIp;
// Attempt to send best address for client
if (clientAddr.is_loopback())
{
// Try guessing if realm is also connected locally
if (LocalAddress.is_loopback() || ExternalAddress.is_loopback())
realmIp = clientAddr;
else
{
// Assume that user connecting from the machine that bnetserver is located on
// has all realms available in his local network
realmIp = LocalAddress;
}
}
else
{
if (clientAddr.is_v4() &&
(clientAddr.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong()) ==
(LocalAddress.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong()))
{
realmIp = LocalAddress;
}
else
realmIp = ExternalAddress;
}
ip::tcp::endpoint endpoint(realmIp, Port);
// Return external IP
return endpoint;
}
RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr), _worldListener(nullptr)
{
}
@@ -95,6 +52,7 @@ void RealmList::Initialize(boost::asio::io_service& ioService, uint32 updateInte
void RealmList::Close()
{
_worldListener->End();
_updateTimer->cancel();
}
template<typename FieldType>
@@ -107,7 +65,7 @@ inline void UpdateField(FieldType& out, FieldType const& in, bool& changed)
}
}
void RealmList::UpdateRealm(Battlenet::RealmId const& id, const std::string& name, ip::address const& address, ip::address const& localAddr,
void RealmList::UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, const std::string& name, ip::address const& address, ip::address const& localAddr,
ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel,
float population)
{
@@ -117,6 +75,7 @@ void RealmList::UpdateRealm(Battlenet::RealmId const& id, const std::string& nam
realm.Keep = true;
realm.Id = id;
UpdateField(realm.Build, build, realm.Updated);
UpdateField(realm.Name, name, realm.Updated);
UpdateField(realm.Type, icon, realm.Updated);
UpdateField(realm.Flags, flag, realm.Updated);
@@ -184,6 +143,10 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
uint16 port = fields[5].GetUInt16();
uint8 icon = fields[6].GetUInt8();
if (icon == REALM_TYPE_FFA_PVP)
icon = REALM_TYPE_PVP;
if (icon >= MAX_CLIENT_REALM_TYPE)
icon = REALM_TYPE_NORMAL;
RealmFlags flag = RealmFlags(fields[7].GetUInt8());
uint8 timezone = fields[8].GetUInt8();
uint8 allowedSecurityLevel = fields[9].GetUInt8();
@@ -193,24 +156,24 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
uint8 region = fields[12].GetUInt8();
uint8 battlegroup = fields[13].GetUInt8();
Battlenet::RealmId id{ region, battlegroup, realmId, build };
Battlenet::RealmHandle id{ region, battlegroup, realmId };
UpdateRealm(id, name, externalAddress, localAddress, localSubmask, port, icon, flag, timezone,
(allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
UpdateRealm(id, build, name, externalAddress, localAddress, localSubmask, port, icon, flag,
timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
TC_LOG_TRACE("realmlist", "Realm \"%s\" at %s:%u.", name.c_str(), externalAddress.to_string().c_str(), port);
}
catch (std::exception& ex)
{
TC_LOG_ERROR("realmlist", "Realmlist::UpdateRealms has thrown an exception: %s", ex.what());
ASSERT(false);
ABORT();
}
}
while (result->NextRow());
}
std::vector<Realm const*> updatedRealms;
std::vector<Battlenet::RealmId> deletedRealms;
std::vector<Battlenet::RealmHandle> deletedRealms;
for (RealmMap::value_type& pair : _realms)
{
@@ -223,7 +186,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
pair.second.Keep = false;
}
for (Battlenet::RealmId const& deleted : deletedRealms)
for (Battlenet::RealmHandle const& deleted : deletedRealms)
_realms.erase(deleted);
if (!updatedRealms.empty() || !deletedRealms.empty())
@@ -242,7 +205,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
}
}
Realm const* RealmList::GetRealm(Battlenet::RealmId const& id) const
Realm const* RealmList::GetRealm(Battlenet::RealmHandle const& id) const
{
auto itr = _realms.find(id);
if (itr != _realms.end())
+4 -64
View File
@@ -20,6 +20,7 @@
#define _REALMLIST_H
#include "Common.h"
#include "Realm/Realm.h"
#include "WorldListener.h"
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/tcp.hpp>
@@ -28,72 +29,11 @@
using namespace boost::asio;
enum RealmFlags
{
REALM_FLAG_NONE = 0x00,
REALM_FLAG_INVALID = 0x01,
REALM_FLAG_OFFLINE = 0x02,
REALM_FLAG_SPECIFYBUILD = 0x04,
REALM_FLAG_UNK1 = 0x08,
REALM_FLAG_UNK2 = 0x10,
REALM_FLAG_RECOMMENDED = 0x20,
REALM_FLAG_NEW = 0x40,
REALM_FLAG_FULL = 0x80
};
#pragma pack(push, 1)
namespace Battlenet
{
struct RealmHandle;
struct RealmId
{
RealmId() : Region(0), Battlegroup(0), Index(0), Build(0) { }
RealmId(uint8 region, uint8 battlegroup, uint32 index, uint32 build)
: Region(region), Battlegroup(battlegroup), Index(index), Build(build) { }
uint8 Region;
uint8 Battlegroup;
uint32 Index;
uint32 Build;
bool operator<(RealmId const& r) const
{
return memcmp(this, &r, sizeof(RealmId) - sizeof(Build)) < 0;
}
RealmId& operator=(RealmHandle const& handle);
};
}
#pragma pack(pop)
// Storage object for a realm
struct Realm
{
Battlenet::RealmId Id;
ip::address ExternalAddress;
ip::address LocalAddress;
ip::address LocalSubnetMask;
uint16 Port;
std::string Name;
uint8 Type;
RealmFlags Flags;
uint8 Timezone;
AccountTypes AllowedSecurityLevel;
float PopulationLevel;
bool Updated;
bool Keep;
ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const;
};
/// Storage object for the list of realms on the server
class RealmList
{
public:
typedef std::map<Battlenet::RealmId, Realm> RealmMap;
typedef std::map<Battlenet::RealmHandle, Realm> RealmMap;
static RealmList* instance()
{
@@ -107,13 +47,13 @@ public:
void Close();
RealmMap const& GetRealms() const { return _realms; }
Realm const* GetRealm(Battlenet::RealmId const& id) const;
Realm const* GetRealm(Battlenet::RealmHandle const& id) const;
private:
RealmList();
void UpdateRealms(boost::system::error_code const& error);
void UpdateRealm(Battlenet::RealmId const& id, const std::string& name, ip::address const& address, ip::address const& localAddr,
void UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, const std::string& name, ip::address const& address, ip::address const& localAddr,
ip::address const& localSubmask, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population);
RealmMap _realms;
@@ -76,7 +76,7 @@ void WorldListener::HandleClose()
void WorldListener::Dispatch(zmqpp::message& msg) const
{
Battlenet::Header ipcHeader;
IPC::BattlenetComm::Header ipcHeader;
msg >> ipcHeader;
if (ipcHeader.Ipc.Channel != IPC_CHANNEL_BNET)
@@ -88,7 +88,7 @@ void WorldListener::Dispatch(zmqpp::message& msg) const
void WorldListener::HandleToonOnlineStatusChange(Battlenet::RealmHandle const& realm, zmqpp::message& msg) const
{
Battlenet::ToonHandle toonHandle;
IPC::BattlenetComm::ToonHandle toonHandle;
bool online;
msg >> toonHandle;
msg >> online;
+8 -7
View File
@@ -470,7 +470,7 @@ void Battlenet::Session::HandleListSubscribeRequestCallback(PreparedQueryResult
{
Field* fields = result->Fetch();
uint32 build = fields[4].GetUInt32();
listSubscribeResponse->CharacterCounts.push_back({ RealmId(fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32(), (_build != build ? build : 0)), fields[0].GetUInt8() });
listSubscribeResponse->CharacterCounts.push_back({ Battlenet::RealmHandle(fields[2].GetUInt8(), fields[3].GetUInt8(), fields[1].GetUInt32()), fields[0].GetUInt8() });
} while (result->NextRow());
}
@@ -493,7 +493,7 @@ void Battlenet::Session::HandleJoinRequestV2(WoWRealm::JoinRequestV2 const& join
{
WoWRealm::JoinResponseV2* joinResponse = new WoWRealm::JoinResponseV2();
Realm const* realm = sRealmList->GetRealm(joinRequest.Realm);
if (!realm || realm->Flags & (REALM_FLAG_INVALID | REALM_FLAG_OFFLINE))
if (!realm || realm->Flags & (REALM_FLAG_VERSION_MISMATCH | REALM_FLAG_OFFLINE))
{
joinResponse->Response = WoWRealm::JoinResponseV2::FAILURE;
AsyncWrite(joinResponse);
@@ -1114,12 +1114,12 @@ bool Battlenet::Session::UnhandledModule(BitStream* /*dataStream*/, ServerPacket
return false;
}
void Battlenet::Session::UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmId>& deletedRealms)
void Battlenet::Session::UpdateRealms(std::vector<Realm const*>& realms, std::vector<Battlenet::RealmHandle>& deletedRealms)
{
for (Realm const* realm : realms)
AsyncWrite(BuildListUpdate(realm));
for (RealmId& deleted : deletedRealms)
for (Battlenet::RealmHandle& deleted : deletedRealms)
{
WoWRealm::ListUpdate* listUpdate = new WoWRealm::ListUpdate();
listUpdate->UpdateState = WoWRealm::ListUpdate::DELETED;
@@ -1131,10 +1131,10 @@ void Battlenet::Session::UpdateRealms(std::vector<Realm const*>& realms, std::ve
Battlenet::WoWRealm::ListUpdate* Battlenet::Session::BuildListUpdate(Realm const* realm) const
{
uint32 flag = realm->Flags & ~REALM_FLAG_SPECIFYBUILD;
RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm->Id.Build);
if (realm->Id.Build != _build)
RealmBuildInfo const* buildInfo = AuthHelper::GetBuildInfo(realm->Build);
if (realm->Build != _build)
{
flag |= REALM_FLAG_INVALID;
flag |= REALM_FLAG_VERSION_MISMATCH;
if (buildInfo)
flag |= REALM_FLAG_SPECIFYBUILD; // tell the client what build the realm is for
}
@@ -1153,6 +1153,7 @@ Battlenet::WoWRealm::ListUpdate* Battlenet::Session::BuildListUpdate(Realm const
listUpdate->Version = version.str();
listUpdate->Address = realm->GetAddressForClient(GetRemoteIpAddress());
listUpdate->Build = realm->Build;
}
listUpdate->Flags = flag;
+1 -1
View File
@@ -115,7 +115,7 @@ namespace Battlenet
void Start() override;
bool Update() override;
void UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmId>& deletedRealms);
void UpdateRealms(std::vector<Realm const*>& realms, std::vector<RealmHandle>& deletedRealms);
uint32 GetAccountId() const { return _accountInfo->Id; }
uint32 GetGameAccountId() const { return _gameAccountInfo->Id; }
+29 -38
View File
@@ -32,7 +32,7 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
{
bool const updatesEnabledForThis = DBUpdater<T>::IsEnabled(_updateFlags);
_open.push(std::make_pair([this, name, updatesEnabledForThis, &pool]() -> bool
_open.push([this, name, updatesEnabledForThis, &pool]() -> bool
{
std::string const dbString = sConfigMgr->GetStringDefault(name + "DatabaseInfo", "");
if (dbString.empty())
@@ -71,12 +71,13 @@ DatabaseLoader& DatabaseLoader::AddDatabase(DatabaseWorkerPool<T>& pool, std::st
return false;
}
}
// Add the close operation
_close.push([&pool]
{
pool.Close();
});
return true;
},
[&pool]()
{
pool.Close();
}));
});
// Populate and update only if updates are enabled for this pool
if (updatesEnabledForThis)
@@ -137,38 +138,7 @@ bool DatabaseLoader::Load()
bool DatabaseLoader::OpenDatabases()
{
while (!_open.empty())
{
std::pair<Predicate, std::function<void()>> const load = _open.top();
if (load.first())
_close.push(load.second);
else
{
// Close all loaded databases
while (!_close.empty())
{
_close.top()();
_close.pop();
}
return false;
}
_open.pop();
}
return true;
}
// Processes the elements of the given stack until a predicate returned false.
bool DatabaseLoader::Process(std::stack<Predicate>& stack)
{
while (!stack.empty())
{
if (!stack.top()())
return false;
stack.pop();
}
return true;
return Process(_open);
}
bool DatabaseLoader::PopulateDatabases()
@@ -186,6 +156,27 @@ bool DatabaseLoader::PrepareStatements()
return Process(_prepare);
}
bool DatabaseLoader::Process(std::queue<Predicate>& queue)
{
while (!queue.empty())
{
if (!queue.front()())
{
// Close all open databases which have a registered close operation
while (!_close.empty())
{
_close.top()();
_close.pop();
}
return false;
}
queue.pop();
}
return true;
}
template
DatabaseLoader& DatabaseLoader::AddDatabase<LoginDatabaseConnection>(DatabaseWorkerPool<LoginDatabaseConnection>& pool, std::string const& name);
template
@@ -21,8 +21,9 @@
#include "DatabaseWorkerPool.h"
#include "DatabaseEnv.h"
#include <stack>
#include <functional>
#include <stack>
#include <queue>
// A helper class to initiate all database worker pools,
// handles updating, delays preparing of statements and cleans up on failure.
@@ -56,16 +57,18 @@ private:
bool PrepareStatements();
using Predicate = std::function<bool()>;
using Closer = std::function<void()>;
static bool Process(std::stack<Predicate>& stack);
// Invokes all functions in the given queue and closes the databases on errors.
// Returns false when there was an error.
bool Process(std::queue<Predicate>& queue);
std::string const _logger;
bool const _autoSetup;
uint32 const _updateFlags;
std::stack<std::pair<Predicate, std::function<void()>>> _open;
std::stack<std::function<void()>> _close;
std::stack<Predicate> _populate, _update, _prepare;
std::queue<Predicate> _open, _populate, _update, _prepare;
std::stack<Closer> _close;
};
#endif // DatabaseLoader_h__
@@ -0,0 +1,322 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DatabaseWorkerPool.h"
#include "DatabaseEnv.h"
#define MIN_MYSQL_SERVER_VERSION 50100u
#define MIN_MYSQL_CLIENT_VERSION 50100u
template <class T>
DatabaseWorkerPool<T>::DatabaseWorkerPool()
: _queue(new ProducerConsumerQueue<SQLOperation*>()),
_async_threads(0), _synch_threads(0)
{
WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below 5.1");
WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s) does not match the version used to compile TrinityCore (%s).",
mysql_get_client_info(), MYSQL_SERVER_VERSION);
}
template <class T>
void DatabaseWorkerPool<T>::SetConnectionInfo(std::string const& infoString,
uint8 const asyncThreads, uint8 const synchThreads)
{
_connectionInfo = Trinity::make_unique<MySQLConnectionInfo>(infoString);
_async_threads = asyncThreads;
_synch_threads = synchThreads;
}
template <class T>
uint32 DatabaseWorkerPool<T>::Open()
{
WPFatal(_connectionInfo.get(), "Connection info was not set!");
TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. "
"Asynchronous connections: %u, synchronous connections: %u.",
GetDatabaseName(), _async_threads, _synch_threads);
uint32 error = OpenConnections(IDX_ASYNC, _async_threads);
if (error)
return error;
error = OpenConnections(IDX_SYNCH, _synch_threads);
if (!error)
{
TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. " SZFMTD
" total connections running.", GetDatabaseName(),
(_connections[IDX_SYNCH].size() + _connections[IDX_ASYNC].size()));
}
return error;
}
template <class T>
void DatabaseWorkerPool<T>::Close()
{
TC_LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName());
//! Closes the actualy MySQL connection.
_connections[IDX_ASYNC].clear();
TC_LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. "
"Proceeding with synchronous connections.",
GetDatabaseName());
//! Shut down the synchronous connections
//! There's no need for locking the connection, because DatabaseWorkerPool<>::Close
//! should only be called after any other thread tasks in the core have exited,
//! meaning there can be no concurrent access at this point.
_connections[IDX_SYNCH].clear();
TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName());
}
template <class T>
bool DatabaseWorkerPool<T>::PrepareStatements()
{
for (auto& connections : _connections)
for (auto& connection : connections)
{
connection->LockIfReady();
if (!connection->PrepareStatements())
{
connection->Unlock();
Close();
return false;
}
else
connection->Unlock();
}
return true;
}
template <class T>
QueryResult DatabaseWorkerPool<T>::Query(const char* sql, T* connection /*= nullptr*/)
{
if (!connection)
connection = GetFreeConnection();
ResultSet* result = connection->Query(sql);
connection->Unlock();
if (!result || !result->GetRowCount() || !result->NextRow())
{
delete result;
return QueryResult(NULL);
}
return QueryResult(result);
}
template <class T>
PreparedQueryResult DatabaseWorkerPool<T>::Query(PreparedStatement* stmt)
{
auto connection = GetFreeConnection();
PreparedResultSet* ret = connection->Query(stmt);
connection->Unlock();
//! Delete proxy-class. Not needed anymore
delete stmt;
if (!ret || !ret->GetRowCount())
{
delete ret;
return PreparedQueryResult(NULL);
}
return PreparedQueryResult(ret);
}
template <class T>
QueryResultFuture DatabaseWorkerPool<T>::AsyncQuery(const char* sql)
{
BasicStatementTask* task = new BasicStatementTask(sql, true);
// Store future result before enqueueing - task might get already processed and deleted before returning from this method
QueryResultFuture result = task->GetFuture();
Enqueue(task);
return result;
}
template <class T>
PreparedQueryResultFuture DatabaseWorkerPool<T>::AsyncQuery(PreparedStatement* stmt)
{
PreparedStatementTask* task = new PreparedStatementTask(stmt, true);
// Store future result before enqueueing - task might get already processed and deleted before returning from this method
PreparedQueryResultFuture result = task->GetFuture();
Enqueue(task);
return result;
}
template <class T>
QueryResultHolderFuture DatabaseWorkerPool<T>::DelayQueryHolder(SQLQueryHolder* holder)
{
SQLQueryHolderTask* task = new SQLQueryHolderTask(holder);
// Store future result before enqueueing - task might get already processed and deleted before returning from this method
QueryResultHolderFuture result = task->GetFuture();
Enqueue(task);
return result;
}
template <class T>
void DatabaseWorkerPool<T>::CommitTransaction(SQLTransaction transaction)
{
#ifdef TRINITY_DEBUG
//! Only analyze transaction weaknesses in Debug mode.
//! Ideally we catch the faults in Debug mode and then correct them,
//! so there's no need to waste these CPU cycles in Release mode.
switch (transaction->GetSize())
{
case 0:
TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing.");
return;
case 1:
TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
break;
default:
break;
}
#endif // TRINITY_DEBUG
Enqueue(new TransactionTask(transaction));
}
template <class T>
void DatabaseWorkerPool<T>::DirectCommitTransaction(SQLTransaction& transaction)
{
T* connection = GetFreeConnection();
int errorCode = connection->ExecuteTransaction(transaction);
if (!errorCode)
{
connection->Unlock(); // OK, operation succesful
return;
}
//! Handle MySQL Errno 1213 without extending deadlock to the core itself
/// @todo More elegant way
if (errorCode == ER_LOCK_DEADLOCK)
{
uint8 loopBreaker = 5;
for (uint8 i = 0; i < loopBreaker; ++i)
{
if (!connection->ExecuteTransaction(transaction))
break;
}
}
//! Clean up now.
transaction->Cleanup();
connection->Unlock();
}
template <class T>
void DatabaseWorkerPool<T>::EscapeString(std::string& str)
{
if (str.empty())
return;
char* buf = new char[str.size() * 2 + 1];
EscapeString(buf, str.c_str(), str.size());
str = buf;
delete[] buf;
}
template <class T>
void DatabaseWorkerPool<T>::KeepAlive()
{
//! Ping synchronous connections
for (auto& connection : _connections[IDX_SYNCH])
{
if (connection->LockIfReady())
{
connection->Ping();
connection->Unlock();
}
}
//! Assuming all worker threads are free, every worker thread will receive 1 ping operation request
//! If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter
//! as the sole purpose is to prevent connections from idling.
auto const count = _connections[IDX_ASYNC].size();
for (uint8 i = 0; i < count; ++i)
Enqueue(new PingOperation);
}
template <class T>
uint32 DatabaseWorkerPool<T>::OpenConnections(InternalIndex type, uint8 numConnections)
{
for (uint8 i = 0; i < numConnections; ++i)
{
// Create the connection
auto connection = [&] {
switch (type)
{
case IDX_ASYNC:
return Trinity::make_unique<T>(_queue.get(), *_connectionInfo);
case IDX_SYNCH:
return Trinity::make_unique<T>(*_connectionInfo);
default:
ABORT();
}
}();
if (uint32 error = connection->Open())
{
// Failed to open a connection or invalid version, abort and cleanup
_connections[type].clear();
return error;
}
else if (mysql_get_server_version(connection->GetHandle()) < MIN_MYSQL_SERVER_VERSION)
{
TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1");
return 1;
}
else
{
_connections[type].push_back(std::move(connection));
}
}
// Everything is fine
return 0;
}
template <class T>
T* DatabaseWorkerPool<T>::GetFreeConnection()
{
uint8 i = 0;
auto const num_cons = _connections[IDX_SYNCH].size();
T* connection = nullptr;
//! Block forever until a connection is free
for (;;)
{
connection = _connections[IDX_SYNCH][++i % num_cons].get();
//! Must be matched with t->Unlock() or you will get deadlocks
if (connection->LockIfReady())
break;
}
return connection;
}
template class DatabaseWorkerPool<LoginDatabaseConnection>;
template class DatabaseWorkerPool<WorldDatabaseConnection>;
template class DatabaseWorkerPool<CharacterDatabaseConnection>;
+26 -287
View File
@@ -32,9 +32,7 @@
#include <mysqld_error.h>
#include <memory>
#define MIN_MYSQL_SERVER_VERSION 50100u
#define MIN_MYSQL_CLIENT_VERSION 50100u
#include <array>
class PingOperation : public SQLOperation
{
@@ -59,97 +57,21 @@ class DatabaseWorkerPool
public:
/* Activity state */
DatabaseWorkerPool() : _queue(new ProducerConsumerQueue<SQLOperation*>()),
_async_threads(0), _synch_threads(0)
{
memset(_connectionCount, 0, sizeof(_connectionCount));
_connections.resize(IDX_SIZE);
WPFatal(mysql_thread_safe(), "Used MySQL library isn't thread-safe.");
WPFatal(mysql_get_client_version() >= MIN_MYSQL_CLIENT_VERSION, "TrinityCore does not support MySQL versions below 5.1");
WPFatal(mysql_get_client_version() == MYSQL_VERSION_ID, "Used MySQL library version (%s) does not match the version used to compile TrinityCore (%s).",
mysql_get_client_info(), MYSQL_SERVER_VERSION);
}
DatabaseWorkerPool();
~DatabaseWorkerPool()
{
_queue->Cancel();
}
void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads)
{
_connectionInfo.reset(new MySQLConnectionInfo(infoString));
void SetConnectionInfo(std::string const& infoString, uint8 const asyncThreads, uint8 const synchThreads);
_async_threads = asyncThreads;
_synch_threads = synchThreads;
}
uint32 Open();
uint32 Open()
{
WPFatal(_connectionInfo.get(), "Connection info was not set!");
TC_LOG_INFO("sql.driver", "Opening DatabasePool '%s'. Asynchronous connections: %u, synchronous connections: %u.",
GetDatabaseName(), _async_threads, _synch_threads);
uint32 error = OpenConnections(IDX_ASYNC, _async_threads);
if (error)
return error;
error = OpenConnections(IDX_SYNCH, _synch_threads);
if (!error)
{
TC_LOG_INFO("sql.driver", "DatabasePool '%s' opened successfully. %u total connections running.", GetDatabaseName(),
(_connectionCount[IDX_SYNCH] + _connectionCount[IDX_ASYNC]));
}
return error;
}
void Close()
{
TC_LOG_INFO("sql.driver", "Closing down DatabasePool '%s'.", GetDatabaseName());
for (uint8 i = 0; i < _connectionCount[IDX_ASYNC]; ++i)
{
T* t = _connections[IDX_ASYNC][i];
t->Close(); //! Closes the actualy MySQL connection.
}
TC_LOG_INFO("sql.driver", "Asynchronous connections on DatabasePool '%s' terminated. Proceeding with synchronous connections.",
GetDatabaseName());
//! Shut down the synchronous connections
//! There's no need for locking the connection, because DatabaseWorkerPool<>::Close
//! should only be called after any other thread tasks in the core have exited,
//! meaning there can be no concurrent access at this point.
for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i)
_connections[IDX_SYNCH][i]->Close();
TC_LOG_INFO("sql.driver", "All connections on DatabasePool '%s' closed.", GetDatabaseName());
}
void Close();
//! Prepares all prepared statements
bool PrepareStatements()
{
for (uint8 i = 0; i < IDX_SIZE; ++i)
for (uint32 c = 0; c < _connectionCount[i]; ++c)
{
T* t = _connections[i][c];
t->LockIfReady();
if (!t->PrepareStatements())
{
t->Unlock();
Close();
return false;
}
else
t->Unlock();
}
return true;
}
bool PrepareStatements();
inline MySQLConnectionInfo const* GetConnectionInfo() const
{
@@ -201,9 +123,9 @@ class DatabaseWorkerPool
if (!sql)
return;
T* t = GetFreeConnection();
t->Execute(sql);
t->Unlock();
T* connection = GetFreeConnection();
connection->Execute(sql);
connection->Unlock();
}
//! Directly executes a one-way SQL operation in string format -with variable args-, that will block the calling thread until finished.
@@ -221,9 +143,9 @@ class DatabaseWorkerPool
//! Statement must be prepared with the CONNECTION_SYNCH flag.
void DirectExecute(PreparedStatement* stmt)
{
T* t = GetFreeConnection();
t->Execute(stmt);
t->Unlock();
T* connection = GetFreeConnection();
connection->Execute(stmt);
connection->Unlock();
//! Delete proxy-class. Not needed anymore
delete stmt;
@@ -235,21 +157,7 @@ class DatabaseWorkerPool
//! Directly executes an SQL query in string format that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
QueryResult Query(const char* sql, T* conn = nullptr)
{
if (!conn)
conn = GetFreeConnection();
ResultSet* result = conn->Query(sql);
conn->Unlock();
if (!result || !result->GetRowCount() || !result->NextRow())
{
delete result;
return QueryResult(NULL);
}
return QueryResult(result);
}
QueryResult Query(const char* sql, T* connection = nullptr);
//! Directly executes an SQL query in string format -with variable args- that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
@@ -276,23 +184,7 @@ class DatabaseWorkerPool
//! Directly executes an SQL query in prepared format that will block the calling thread until finished.
//! Returns reference counted auto pointer, no need for manual memory management in upper level code.
//! Statement must be prepared with CONNECTION_SYNCH flag.
PreparedQueryResult Query(PreparedStatement* stmt)
{
T* t = GetFreeConnection();
PreparedResultSet* ret = t->Query(stmt);
t->Unlock();
//! Delete proxy-class. Not needed anymore
delete stmt;
if (!ret || !ret->GetRowCount())
{
delete ret;
return PreparedQueryResult(NULL);
}
return PreparedQueryResult(ret);
}
PreparedQueryResult Query(PreparedStatement* stmt);
/**
Asynchronous query (with resultset) methods.
@@ -300,14 +192,7 @@ class DatabaseWorkerPool
//! Enqueues a query in string format that will set the value of the QueryResultFuture return object as soon as the query is executed.
//! The return value is then processed in ProcessQueryCallback methods.
QueryResultFuture AsyncQuery(const char* sql)
{
BasicStatementTask* task = new BasicStatementTask(sql, true);
// Store future result before enqueueing - task might get already processed and deleted before returning from this method
QueryResultFuture result = task->GetFuture();
Enqueue(task);
return result;
}
QueryResultFuture AsyncQuery(const char* sql);
//! Enqueues a query in string format -with variable args- that will set the value of the QueryResultFuture return object as soon as the query is executed.
//! The return value is then processed in ProcessQueryCallback methods.
@@ -320,27 +205,13 @@ class DatabaseWorkerPool
//! Enqueues a query in prepared format that will set the value of the PreparedQueryResultFuture return object as soon as the query is executed.
//! The return value is then processed in ProcessQueryCallback methods.
//! Statement must be prepared with CONNECTION_ASYNC flag.
PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt)
{
PreparedStatementTask* task = new PreparedStatementTask(stmt, true);
// Store future result before enqueueing - task might get already processed and deleted before returning from this method
PreparedQueryResultFuture result = task->GetFuture();
Enqueue(task);
return result;
}
PreparedQueryResultFuture AsyncQuery(PreparedStatement* stmt);
//! Enqueues a vector of SQL operations (can be both adhoc and prepared) that will set the value of the QueryResultHolderFuture
//! return object as soon as the query is executed.
//! The return value is then processed in ProcessQueryCallback methods.
//! Any prepared statements added to this holder need to be prepared with the CONNECTION_ASYNC flag.
QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder)
{
SQLQueryHolderTask* task = new SQLQueryHolderTask(holder);
// Store future result before enqueueing - task might get already processed and deleted before returning from this method
QueryResultHolderFuture result = task->GetFuture();
Enqueue(task);
return result;
}
QueryResultHolderFuture DelayQueryHolder(SQLQueryHolder* holder);
/**
Transaction context methods.
@@ -354,57 +225,11 @@ class DatabaseWorkerPool
//! Enqueues a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations
//! were appended to the transaction will be respected during execution.
void CommitTransaction(SQLTransaction transaction)
{
#ifdef TRINITY_DEBUG
//! Only analyze transaction weaknesses in Debug mode.
//! Ideally we catch the faults in Debug mode and then correct them,
//! so there's no need to waste these CPU cycles in Release mode.
switch (transaction->GetSize())
{
case 0:
TC_LOG_DEBUG("sql.driver", "Transaction contains 0 queries. Not executing.");
return;
case 1:
TC_LOG_DEBUG("sql.driver", "Warning: Transaction only holds 1 query, consider removing Transaction context in code.");
break;
default:
break;
}
#endif // TRINITY_DEBUG
Enqueue(new TransactionTask(transaction));
}
void CommitTransaction(SQLTransaction transaction);
//! Directly executes a collection of one-way SQL operations (can be both adhoc and prepared). The order in which these operations
//! were appended to the transaction will be respected during execution.
void DirectCommitTransaction(SQLTransaction& transaction)
{
T* con = GetFreeConnection();
int errorCode = con->ExecuteTransaction(transaction);
if (!errorCode)
{
con->Unlock(); // OK, operation succesful
return;
}
//! Handle MySQL Errno 1213 without extending deadlock to the core itself
/// @todo More elegant way
if (errorCode == ER_LOCK_DEADLOCK)
{
uint8 loopBreaker = 5;
for (uint8 i = 0; i < loopBreaker; ++i)
{
if (!con->ExecuteTransaction(transaction))
break;
}
}
//! Clean up now.
transaction->Cleanup();
con->Unlock();
}
void DirectCommitTransaction(SQLTransaction& transaction);
//! Method used to execute prepared statements in a diverse context.
//! Will be wrapped in a transaction if valid object is present, otherwise executed standalone.
@@ -441,90 +266,21 @@ class DatabaseWorkerPool
}
//! Apply escape string'ing for current collation. (utf8)
void EscapeString(std::string& str)
{
if (str.empty())
return;
char* buf = new char[str.size() * 2 + 1];
EscapeString(buf, str.c_str(), str.size());
str = buf;
delete[] buf;
}
void EscapeString(std::string& str);
//! Keeps all our MySQL connections alive, prevent the server from disconnecting us.
void KeepAlive()
{
//! Ping synchronous connections
for (uint8 i = 0; i < _connectionCount[IDX_SYNCH]; ++i)
{
T* t = _connections[IDX_SYNCH][i];
if (t->LockIfReady())
{
t->Ping();
t->Unlock();
}
}
//! Assuming all worker threads are free, every worker thread will receive 1 ping operation request
//! If one or more worker threads are busy, the ping operations will not be split evenly, but this doesn't matter
//! as the sole purpose is to prevent connections from idling.
for (size_t i = 0; i < _connections[IDX_ASYNC].size(); ++i)
Enqueue(new PingOperation);
}
void KeepAlive();
private:
uint32 OpenConnections(InternalIndex type, uint8 numConnections)
{
_connections[type].resize(numConnections);
for (uint8 i = 0; i < numConnections; ++i)
{
T* t;
if (type == IDX_ASYNC)
t = new T(_queue.get(), *_connectionInfo);
else if (type == IDX_SYNCH)
t = new T(*_connectionInfo);
else
ABORT();
_connections[type][i] = t;
++_connectionCount[type];
uint32 error = t->Open();
if (!error)
{
if (mysql_get_server_version(t->GetHandle()) < MIN_MYSQL_SERVER_VERSION)
{
TC_LOG_ERROR("sql.driver", "TrinityCore does not support MySQL versions below 5.1");
error = 1;
}
}
// Failed to open a connection or invalid version, abort and cleanup
if (error)
{
while (_connectionCount[type] != 0)
{
t = _connections[type][i--];
delete t;
--_connectionCount[type];
}
return error;
}
}
// Everything is fine
return 0;
}
uint32 OpenConnections(InternalIndex type, uint8 numConnections);
unsigned long EscapeString(char *to, const char *from, unsigned long length)
{
if (!to || !from || !length)
return 0;
return mysql_real_escape_string(_connections[IDX_SYNCH][0]->GetHandle(), to, from, length);
return mysql_real_escape_string(
_connections[IDX_SYNCH].front()->GetHandle(), to, from, length);
}
void Enqueue(SQLOperation* op)
@@ -534,22 +290,7 @@ class DatabaseWorkerPool
//! Gets a free connection in the synchronous connection pool.
//! Caller MUST call t->Unlock() after touching the MySQL context to prevent deadlocks.
T* GetFreeConnection()
{
uint8 i = 0;
size_t num_cons = _connectionCount[IDX_SYNCH];
T* t = NULL;
//! Block forever until a connection is free
for (;;)
{
t = _connections[IDX_SYNCH][++i % num_cons];
//! Must be matched with t->Unlock() or you will get deadlocks
if (t->LockIfReady())
break;
}
return t;
}
T* GetFreeConnection();
char const* GetDatabaseName() const
{
@@ -558,9 +299,7 @@ class DatabaseWorkerPool
//! Queue shared by async worker threads.
std::unique_ptr<ProducerConsumerQueue<SQLOperation*>> _queue;
std::vector<std::vector<T*>> _connections;
//! Counter of MySQL connections;
uint32 _connectionCount[IDX_SIZE];
std::array<std::vector<std::unique_ptr<T>>, IDX_SIZE> _connections;
std::unique_ptr<MySQLConnectionInfo> _connectionInfo;
uint8 _async_threads, _synch_threads;
};
@@ -37,7 +37,6 @@ MySQLConnection::MySQLConnection(MySQLConnectionInfo& connInfo) :
m_reconnecting(false),
m_prepareError(false),
m_queue(NULL),
m_worker(NULL),
m_Mysql(NULL),
m_connectionInfo(connInfo),
m_connectionFlags(CONNECTION_SYNCH) { }
@@ -50,24 +49,26 @@ m_Mysql(NULL),
m_connectionInfo(connInfo),
m_connectionFlags(CONNECTION_ASYNC)
{
m_worker = new DatabaseWorker(m_queue, this);
m_worker = Trinity::make_unique<DatabaseWorker>(m_queue, this);
}
MySQLConnection::~MySQLConnection()
{
delete m_worker;
for (size_t i = 0; i < m_stmts.size(); ++i)
delete m_stmts[i];
if (m_Mysql)
mysql_close(m_Mysql);
Close();
}
void MySQLConnection::Close()
{
/// Only close us if we're not operating
delete this;
// Stop the worker thread before the statements are cleared
m_worker.reset();
m_stmts.clear();
if (m_Mysql)
{
mysql_close(m_Mysql);
m_Mysql = nullptr;
}
}
uint32 MySQLConnection::Open()
@@ -412,7 +413,7 @@ int MySQLConnection::ExecuteTransaction(SQLTransaction& transaction)
MySQLPreparedStatement* MySQLConnection::GetPreparedStatement(uint32 index)
{
ASSERT(index < m_stmts.size());
MySQLPreparedStatement* ret = m_stmts[index];
MySQLPreparedStatement* ret = m_stmts[index].get();
if (!ret)
TC_LOG_ERROR("sql.sql", "Could not fetch prepared statement %u on database `%s`, connection type: %s.",
index, m_connectionInfo.database.c_str(), (m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
@@ -424,16 +425,12 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection
{
m_queries.insert(PreparedStatementMap::value_type(index, std::make_pair(sql, flags)));
// For reconnection case
if (m_reconnecting)
delete m_stmts[index];
// Check if specified query should be prepared on this connection
// i.e. don't prepare async statements on synchronous connections
// to save memory that will not be used.
if (!(m_connectionFlags & flags))
{
m_stmts[index] = NULL;
m_stmts[index].reset();
return;
}
@@ -455,8 +452,7 @@ void MySQLConnection::PrepareStatement(uint32 index, const char* sql, Connection
}
else
{
MySQLPreparedStatement* mStmt = new MySQLPreparedStatement(stmt);
m_stmts[index] = mStmt;
m_stmts[index] = Trinity::make_unique<MySQLPreparedStatement>(stmt);
}
}
}
@@ -477,7 +473,7 @@ PreparedResultSet* MySQLConnection::Query(PreparedStatement* stmt)
return new PreparedResultSet(stmt->m_stmt->GetSTMT(), result, rowCount, fieldCount);
}
bool MySQLConnection::_HandleMySQLErrno(uint32 errNo)
bool MySQLConnection::_HandleMySQLErrno(uint32 errNo, uint8 attempts /*= 5*/)
{
switch (errNo)
{
@@ -486,9 +482,21 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo)
case CR_INVALID_CONN_HANDLE:
case CR_SERVER_LOST_EXTENDED:
{
if (m_Mysql)
{
TC_LOG_ERROR("sql.sql", "Lost the connection to the MySQL server!");
mysql_close(GetHandle());
m_Mysql = nullptr;
}
/*no break*/
}
case CR_CONN_HOST_ERROR:
{
TC_LOG_INFO("sql.sql", "Attempting to reconnect to the MySQL server...");
m_reconnecting = true;
uint64 oldThreadId = mysql_thread_id(GetHandle());
mysql_close(GetHandle());
uint32 const lErrno = Open();
if (!lErrno)
@@ -496,24 +504,37 @@ bool MySQLConnection::_HandleMySQLErrno(uint32 errNo)
// Don't remove 'this' pointer unless you want to skip loading all prepared statements...
if (!this->PrepareStatements())
{
TC_LOG_ERROR("sql.sql", "Could not re-prepare statements!");
Close();
return false;
TC_LOG_FATAL("sql.sql", "Could not re-prepare statements!");
std::this_thread::sleep_for(std::chrono::seconds(10));
std::abort();
}
TC_LOG_INFO("sql.sql", "Connection to the MySQL server is active.");
if (oldThreadId != mysql_thread_id(GetHandle()))
TC_LOG_INFO("sql.sql", "Successfully reconnected to %s @%s:%s (%s).",
m_connectionInfo.database.c_str(), m_connectionInfo.host.c_str(), m_connectionInfo.port_or_socket.c_str(),
(m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
TC_LOG_INFO("sql.sql", "Successfully reconnected to %s @%s:%s (%s).",
m_connectionInfo.database.c_str(), m_connectionInfo.host.c_str(), m_connectionInfo.port_or_socket.c_str(),
(m_connectionFlags & CONNECTION_ASYNC) ? "asynchronous" : "synchronous");
m_reconnecting = false;
return true;
}
// It's possible this attempted reconnect throws 2006 at us. To prevent crazy recursive calls, sleep here.
std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds
return _HandleMySQLErrno(lErrno); // Call self (recursive)
if ((--attempts) == 0)
{
// Shut down the server when the mysql server isn't
// reachable for some time
TC_LOG_FATAL("sql.sql", "Failed to reconnect to the MySQL server, "
"terminating the server to prevent data corruption!");
// We could also initiate a shutdown through using std::raise(SIGTERM)
std::this_thread::sleep_for(std::chrono::seconds(10));
std::abort();
}
else
{
// It's possible this attempted reconnect throws 2006 at us.
// To prevent crazy recursive calls, sleep here.
std::this_thread::sleep_for(std::chrono::seconds(3)); // Sleep 3 seconds
return _HandleMySQLErrno(lErrno, attempts); // Call self (recursive)
}
}
case ER_LOCK_DEADLOCK:
@@ -116,18 +116,18 @@ class MySQLConnection
virtual void DoPrepareStatements() = 0;
protected:
std::vector<MySQLPreparedStatement*> m_stmts; //! PreparedStatements storage
std::vector<std::unique_ptr<MySQLPreparedStatement>> m_stmts; //! PreparedStatements storage
PreparedStatementMap m_queries; //! Query storage
bool m_reconnecting; //! Are we reconnecting?
bool m_prepareError; //! Was there any error while preparing statements?
private:
bool _HandleMySQLErrno(uint32 errNo);
bool _HandleMySQLErrno(uint32 errNo, uint8 attempts = 5);
private:
ProducerConsumerQueue<SQLOperation*>* m_queue; //! Queue shared with other asynchronous connections.
DatabaseWorker* m_worker; //! Core worker task.
MYSQL * m_Mysql; //! MySQL Handle.
std::unique_ptr<DatabaseWorker> m_worker; //! Core worker task.
MYSQL* m_Mysql; //! MySQL Handle.
MySQLConnectionInfo& m_connectionInfo; //! Connection info (used for logging)
ConnectionFlags m_connectionFlags; //! Connection flags (for preparing relevant statements)
std::mutex m_Mutex;
+10 -23
View File
@@ -21,6 +21,7 @@
#include "UpdateFetcher.h"
#include "DatabaseLoader.h"
#include "Config.h"
#include "BuiltInConfig.h"
#include <fstream>
#include <iostream>
@@ -35,23 +36,17 @@ using namespace boost::process;
using namespace boost::process::initializers;
using namespace boost::iostreams;
std::string DBUpdaterUtil::GetMySqlCli()
std::string DBUpdaterUtil::GetCorrectedMySQLExecutable()
{
if (!corrected_path().empty())
return corrected_path();
else
{
std::string const entry = sConfigMgr->GetStringDefault("Updates.MySqlCLIPath", "");
if (!entry.empty())
return entry;
else
return GitRevision::GetMySQLExecutable();
}
return BuiltInConfig::GetMySQLExecutable();
}
bool DBUpdaterUtil::CheckExecutable()
{
boost::filesystem::path exe(GetMySqlCli());
boost::filesystem::path exe(GetCorrectedMySQLExecutable());
if (!exists(exe))
{
exe.clear();
@@ -85,16 +80,6 @@ std::string& DBUpdaterUtil::corrected_path()
return path;
}
template<class T>
std::string DBUpdater<T>::GetSourceDirectory()
{
std::string const entry = sConfigMgr->GetStringDefault("Updates.SourcePath", "");
if (!entry.empty())
return entry;
else
return GitRevision::GetSourceDirectory();
}
// Auth Database
template<>
std::string DBUpdater<LoginDatabaseConnection>::GetConfigEntry()
@@ -111,7 +96,8 @@ std::string DBUpdater<LoginDatabaseConnection>::GetTableName()
template<>
std::string DBUpdater<LoginDatabaseConnection>::GetBaseFile()
{
return DBUpdater<LoginDatabaseConnection>::GetSourceDirectory() + "/sql/base/auth_database.sql";
return BuiltInConfig::GetSourceDirectory() +
"/sql/base/auth_database.sql";
}
template<>
@@ -169,7 +155,8 @@ std::string DBUpdater<CharacterDatabaseConnection>::GetTableName()
template<>
std::string DBUpdater<CharacterDatabaseConnection>::GetBaseFile()
{
return DBUpdater<CharacterDatabaseConnection>::GetSourceDirectory() + "/sql/base/characters_database.sql";
return BuiltInConfig::GetSourceDirectory() +
"/sql/base/characters_database.sql";
}
template<>
@@ -239,7 +226,7 @@ bool DBUpdater<T>::Update(DatabaseWorkerPool<T>& pool)
TC_LOG_INFO("sql.updates", "Updating %s database...", DBUpdater<T>::GetTableName().c_str());
Path const sourceDirectory(GetSourceDirectory());
Path const sourceDirectory(BuiltInConfig::GetSourceDirectory());
if (!is_directory(sourceDirectory))
{
@@ -410,7 +397,7 @@ void DBUpdater<T>::ApplyFile(DatabaseWorkerPool<T>& pool, std::string const& hos
boost::process::pipe errPipe = create_pipe();
child c = execute(run_exe(
boost::filesystem::absolute(DBUpdaterUtil::GetMySqlCli()).generic_string()),
boost::filesystem::absolute(DBUpdaterUtil::GetCorrectedMySQLExecutable()).generic_string()),
set_args(args), bind_stdin(source), throw_on_error(),
bind_stdout(file_descriptor_sink(outPipe.sink, close_handle)),
bind_stderr(file_descriptor_sink(errPipe.sink, close_handle)));
+1 -3
View File
@@ -57,7 +57,7 @@ struct UpdateResult
class DBUpdaterUtil
{
public:
static std::string GetMySqlCli();
static std::string GetCorrectedMySQLExecutable();
static bool CheckExecutable();
@@ -71,8 +71,6 @@ class DBUpdater
public:
using Path = boost::filesystem::path;
static std::string GetSourceDirectory();
static inline std::string GetConfigEntry();
static inline std::string GetTableName();
+19 -10
View File
@@ -137,22 +137,33 @@ UpdateFetcher::AppliedFileStorage UpdateFetcher::ReceiveAppliedFiles() const
return map;
}
UpdateFetcher::SQLUpdate UpdateFetcher::ReadSQLUpdate(boost::filesystem::path const& file) const
std::string UpdateFetcher::ReadSQLUpdate(boost::filesystem::path const& file) const
{
std::ifstream in(file.c_str());
WPFatal(in.is_open(), "Could not read an update file.");
if (!in.is_open())
{
TC_LOG_FATAL("sql.updates", "Failed to open the sql update \"%s\" for reading! "
"Stopping the server to keep the database integrity, "
"try to identify and solve the issue or disabled the database updater.",
file.generic_string().c_str());
throw UpdateException("Opening the sql update failed!");
}
auto update = [&in] {
std::ostringstream ss;
ss << in.rdbuf();
return Trinity::make_unique<std::string>(ss.str());
return ss.str();
}();
in.close();
return update;
}
UpdateResult UpdateFetcher::Update(bool const redundancyChecks, bool const allowRehash, bool const archivedRedundancy, int32 const cleanDeadReferencesMaxCount) const
UpdateResult UpdateFetcher::Update(bool const redundancyChecks,
bool const allowRehash,
bool const archivedRedundancy,
int32 const cleanDeadReferencesMaxCount) const
{
LocaleFileStorage const available = GetFileList();
AppliedFileStorage applied = ReceiveAppliedFiles();
@@ -198,11 +209,9 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, bool const allow
}
}
// Read update from file
SQLUpdate const update = ReadSQLUpdate(availableQuery.first);
// Calculate hash
std::string const hash = CalculateHash(update);
std::string const hash =
CalculateHash(ReadSQLUpdate(availableQuery.first));
UpdateMode mode = MODE_APPLY;
@@ -325,11 +334,11 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, bool const allow
return UpdateResult(importedUpdates, countRecentUpdates, countArchivedUpdates);
}
std::string UpdateFetcher::CalculateHash(SQLUpdate const& query) const
std::string UpdateFetcher::CalculateHash(std::string const& query) const
{
// Calculate a Sha1 hash based on query content.
unsigned char digest[SHA_DIGEST_LENGTH];
SHA1((unsigned char*)query->c_str(), query->length(), (unsigned char*)&digest);
SHA1((unsigned char*)query.c_str(), query.length(), (unsigned char*)&digest);
return ByteArrayToHexStr(digest, SHA_DIGEST_LENGTH);
}
+4 -4
View File
@@ -103,16 +103,16 @@ private:
typedef std::unordered_map<std::string, std::string> HashToFileNameStorage;
typedef std::unordered_map<std::string, AppliedFileEntry> AppliedFileStorage;
typedef std::vector<UpdateFetcher::DirectoryEntry> DirectoryStorage;
typedef std::unique_ptr<std::string> SQLUpdate;
LocaleFileStorage GetFileList() const;
void FillFileListRecursively(Path const& path, LocaleFileStorage& storage, State const state, uint32 const depth) const;
void FillFileListRecursively(Path const& path, LocaleFileStorage& storage,
State const state, uint32 const depth) const;
DirectoryStorage ReceiveIncludedDirectories() const;
AppliedFileStorage ReceiveAppliedFiles() const;
SQLUpdate ReadSQLUpdate(Path const& file) const;
std::string CalculateHash(SQLUpdate const& query) const;
std::string ReadSQLUpdate(Path const& file) const;
std::string CalculateHash(std::string const& query) const;
uint32 Apply(Path const& path) const;
-30
View File
@@ -259,36 +259,6 @@ void UnitAI::FillAISpellInfo()
}
}
//Enable PlayerAI when charmed
void PlayerAI::OnCharmed(bool apply)
{
me->IsAIEnabled = apply;
}
void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/)
{
Creature* charmer = me->GetCharmer()->ToCreature();
//kill self if charm aura has infinite duration
if (charmer->IsInEvadeMode())
{
Unit::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
for (Unit::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
{
charmer->Kill(me);
return;
}
}
if (!charmer->IsInCombat())
me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, me->GetFollowAngle());
Unit* target = me->GetVictim();
if (!target || !charmer->IsValidAttackTarget(target))
AttackStart(charmer->SelectNearestTargetInAttackDistance());
}
SpellTargetSelector::SpellTargetSelector(Unit* caster, uint32 spellId) :
_caster(caster), _spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(sSpellMgr->GetSpellInfo(spellId), caster))
{
-17
View File
@@ -268,21 +268,4 @@ class UnitAI
UnitAI& operator=(UnitAI const& right) = delete;
};
class PlayerAI : public UnitAI
{
protected:
Player* const me;
public:
explicit PlayerAI(Player* player) : UnitAI((Unit*)player), me(player) { }
void OnCharmed(bool apply) override;
};
class SimpleCharmedAI : public PlayerAI
{
public:
void UpdateAI(uint32 diff) override;
SimpleCharmedAI(Player* player): PlayerAI(player) { }
};
#endif
+6
View File
@@ -28,6 +28,7 @@ class WorldObject;
class Unit;
class Creature;
class Player;
class PlayerAI;
class SpellInfo;
#define TIME_INTERVAL_LOOK 5000
@@ -186,6 +187,11 @@ class CreatureAI : public UnitAI
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
// Called when a player is charmed by the creature
// If a PlayerAI* is returned, that AI is placed on the player instead of the default charm AI
// Object destruction is handled by Unit::RemoveCharmedBy
virtual PlayerAI* GetAIForCharmedPlayer(Player* /*who*/) { return nullptr; }
// intended for encounter design/debugging. do not use for other purposes. expensive.
int32 VisualizeBoundary(uint32 duration, Unit* owner=nullptr, bool fill=false) const;
virtual bool CheckInRoom();
+226
View File
@@ -0,0 +1,226 @@
/*
* Copyright (C) 2016-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PlayerAI.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
enum Spells
{
/* Generic */
SPELL_AUTO_SHOT = 75,
SPELL_SHOOT = 3018,
SPELL_THROW = 2764,
SPELL_SHOOT_WAND = 5019,
/* Paladin */
PASSIVE_ILLUMINATION = 20215,
/* Priest */
SPELL_SOUL_WARDING = 63574,
SPELL_SPIRIT_REDEMPTION = 20711,
SPELL_SHADOWFORM = 15473,
/* Shaman */
SPELL_TIDAL_FORCE = 582,
SPELL_MANA_TIDE_TOTEM = 590,
SPELL_SHA_NATURE_SWIFT = 591,
SPELL_STORMSTRIKE = 17364,
/* Druid */
SPELL_MOONKIN_FORM = 24858,
SPELL_SWIFTMEND = 18562,
SPELL_DRU_NATURE_SWIFT = 17116,
SPELL_TREE_OF_LIFE = 33891
};
bool PlayerAI::IsPlayerHealer(Player const* who)
{
switch (who->getClass())
{
case CLASS_WARRIOR:
case CLASS_HUNTER:
case CLASS_ROGUE:
case CLASS_DEATH_KNIGHT:
case CLASS_MAGE:
case CLASS_WARLOCK:
default:
return false;
case CLASS_PALADIN:
return who->HasSpell(PASSIVE_ILLUMINATION);
case CLASS_PRIEST:
return who->HasSpell(SPELL_SOUL_WARDING) || who->HasSpell(SPELL_SPIRIT_REDEMPTION);
case CLASS_SHAMAN:
return who->HasSpell(SPELL_MANA_TIDE_TOTEM) || who->HasSpell(SPELL_SHA_NATURE_SWIFT) || who->HasSpell(SPELL_TIDAL_FORCE);
case CLASS_DRUID:
return who->HasSpell(SPELL_SWIFTMEND) || who->HasSpell(SPELL_DRU_NATURE_SWIFT) || who->HasSpell(SPELL_TREE_OF_LIFE);
}
}
bool PlayerAI::IsPlayerRangedAttacker(Player const* who)
{
switch (who->getClass())
{
case CLASS_WARRIOR:
case CLASS_PALADIN:
case CLASS_ROGUE:
case CLASS_DEATH_KNIGHT:
default:
return false;
case CLASS_MAGE:
case CLASS_WARLOCK:
return true;
case CLASS_HUNTER:
{
// check if we have a ranged weapon equipped
Item const* rangedSlot = who->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
if (ItemTemplate const* rangedTemplate = rangedSlot ? rangedSlot->GetTemplate() : nullptr)
if ((1 << rangedTemplate->SubClass) & ITEM_SUBCLASS_MASK_WEAPON_RANGED)
return true;
return false;
}
case CLASS_PRIEST:
return who->HasSpell(SPELL_SHADOWFORM);
case CLASS_SHAMAN:
return !who->HasSpell(SPELL_STORMSTRIKE);
case CLASS_DRUID:
return who->HasSpell(SPELL_MOONKIN_FORM);
}
}
void PlayerAI::DoRangedAttackIfReady()
{
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (!me->isAttackReady(RANGED_ATTACK))
return;
Unit* victim = me->GetVictim();
if (!victim)
return;
uint32 rangedAttackSpell = 0;
Item const* rangedItem = me->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
if (ItemTemplate const* rangedTemplate = rangedItem ? rangedItem->GetTemplate() : nullptr)
{
switch (rangedTemplate->SubClass)
{
case ITEM_SUBCLASS_WEAPON_BOW:
case ITEM_SUBCLASS_WEAPON_GUN:
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
rangedAttackSpell = SPELL_SHOOT;
break;
case ITEM_SUBCLASS_WEAPON_THROWN:
rangedAttackSpell = SPELL_THROW;
break;
case ITEM_SUBCLASS_WEAPON_WAND:
rangedAttackSpell = SPELL_SHOOT_WAND;
break;
}
}
if (!rangedAttackSpell)
return;
me->CastSpell(victim, rangedAttackSpell, TRIGGERED_CAST_DIRECTLY);
me->resetAttackTimer(RANGED_ATTACK);
}
void PlayerAI::DoAutoAttackIfReady()
{
if (IsRangedAttacker())
DoRangedAttackIfReady();
else
DoMeleeAttackIfReady();
}
struct UncontrolledTargetSelectPredicate : public std::unary_function<Unit*, bool>
{
bool operator()(Unit const* target) const
{
return !target->HasBreakableByDamageCrowdControlAura();
}
};
Unit* SimpleCharmedPlayerAI::SelectAttackTarget() const
{
if (Unit* charmer = me->GetCharmer())
return charmer->IsAIEnabled ? charmer->GetAI()->SelectTarget(SELECT_TARGET_RANDOM, 0, UncontrolledTargetSelectPredicate()) : charmer->GetVictim();
return nullptr;
}
void SimpleCharmedPlayerAI::UpdateAI(const uint32 /*diff*/)
{
Creature* charmer = me->GetCharmer() ? me->GetCharmer()->ToCreature() : nullptr;
if (!charmer)
return;
//kill self if charm aura has infinite duration
if (charmer->IsInEvadeMode())
{
Player::AuraEffectList const& auras = me->GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
for (Player::AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
{
me->Kill(me);
return;
}
}
if (charmer->IsInCombat())
{
Unit* target = me->GetVictim();
if (!target || !charmer->IsValidAttackTarget(target) || target->HasBreakableByDamageCrowdControlAura())
{
target = SelectAttackTarget();
if (!target)
return;
if (IsRangedAttacker())
AttackStartCaster(target, 28.0f);
else
AttackStart(target);
}
DoAutoAttackIfReady();
}
else
{
me->AttackStop();
me->CastStop();
me->StopMoving();
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
}
}
void SimpleCharmedPlayerAI::OnCharmed(bool apply)
{
if (apply)
{
me->CastStop();
me->AttackStop();
}
else
{
me->CastStop();
me->AttackStop();
// @todo only voluntary movement (don't cancel stuff like death grip or charge mid-animation)
me->GetMotionMaster()->Clear();
me->StopMoving();
}
}
+60
View File
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2016-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_PLAYERAI_H
#define TRINITY_PLAYERAI_H
#include "UnitAI.h"
#include "Player.h"
#include "Creature.h"
class PlayerAI : public UnitAI
{
public:
explicit PlayerAI(Player* player) : UnitAI(static_cast<Unit*>(player)), me(player), _isSelfHealer(PlayerAI::IsPlayerHealer(player)), _isSelfRangedAttacker(PlayerAI::IsPlayerRangedAttacker(player)) { }
void OnCharmed(bool /*apply*/) override { } // charm AI application for players is handled by Unit::SetCharmedBy / Unit::RemoveCharmedBy
// helper functions to determine player info
static bool IsPlayerHealer(Player const* who);
bool IsHealer(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfHealer : IsPlayerHealer(who); }
static bool IsPlayerRangedAttacker(Player const* who);
bool IsRangedAttacker(Player const* who = nullptr) const { return (!who || who == me) ? _isSelfRangedAttacker : IsPlayerRangedAttacker(who); }
protected:
Player* const me;
void SetIsRangedAttacker(bool state) { _isSelfRangedAttacker = state; } // this allows overriding of the default ranged attacker detection
virtual Unit* SelectAttackTarget() const { return me->GetCharmer() ? me->GetCharmer()->GetVictim() : nullptr; }
void DoRangedAttackIfReady();
void DoAutoAttackIfReady();
private:
bool _isSelfHealer;
bool _isSelfRangedAttacker;
};
class SimpleCharmedPlayerAI : public PlayerAI
{
public:
SimpleCharmedPlayerAI(Player* player) : PlayerAI(player) { }
void UpdateAI(uint32 diff) override;
void OnCharmed(bool apply) override;
Unit* SelectAttackTarget() const override;
};
#endif
@@ -2340,6 +2340,21 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
}
}
case SMART_ACTION_SET_CORPSE_DELAY:
{
ObjectList* targets = GetTargets(e, unit);
if (!targets)
break;
for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr)
{
if (IsCreature(*itr))
(*itr)->ToCreature()->SetCorpseDelay(e.action.corpseDelay.timer);
}
delete targets;
break;
}
default:
TC_LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Unhandled Action type %u", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;
@@ -1251,6 +1251,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_REMOVE_GO_FLAG:
case SMART_ACTION_SUMMON_CREATURE_GROUP:
case SMART_ACTION_RISE_UP:
case SMART_ACTION_SET_CORPSE_DELAY:
break;
default:
TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
@@ -552,8 +552,9 @@ enum SMART_ACTION
SMART_ACTION_START_CLOSEST_WAYPOINT = 113, // wp1, wp2, wp3, wp4, wp5, wp6, wp7
SMART_ACTION_RISE_UP = 114, // distance
SMART_ACTION_RANDOM_SOUND = 115, // soundId1, soundId2, soundId3, soundId4, soundId5, onlySelf
SMART_ACTION_SET_CORPSE_DELAY = 116, // timer
SMART_ACTION_END = 116
SMART_ACTION_END = 117
};
struct SmartAction
@@ -1042,6 +1043,11 @@ struct SmartAction
uint32 onlySelf;
} randomSound;
struct
{
uint32 timer;
} corpseDelay;
//! Note for any new future actions
//! All parameters must have type uint32
+1 -1
View File
@@ -446,7 +446,7 @@ void AccountMgr::LoadRBAC()
while (result->NextRow());
TC_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading default permissions");
result = LoginDatabase.PQuery("SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = %u OR realmId = -1) ORDER BY secId ASC", realmHandle.Index);
result = LoginDatabase.PQuery("SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = %u OR realmId = -1) ORDER BY secId ASC", realm.Id.Realm);
if (!result)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty.");
+2 -2
View File
@@ -679,8 +679,8 @@ enum RBACPermissions
RBAC_PERM_COMMAND_WP_UNLOAD = 772,
RBAC_PERM_COMMAND_WP_RELOAD = 773,
RBAC_PERM_COMMAND_WP_SHOW = 774,
RBAC_PERM_COMMAND_MODIFY_CURRENCY = 775, // only 4.3.4
RBAC_PERM_COMMAND_DEBUG_PHASE = 776, // only 4.3.4
RBAC_PERM_COMMAND_MODIFY_CURRENCY = 775, // only 6.x
RBAC_PERM_COMMAND_DEBUG_PHASE = 776, // only 6.x
RBAC_PERM_COMMAND_MAILBOX = 777,
RBAC_PERM_COMMAND_AHBOT = 778,
RBAC_PERM_COMMAND_AHBOT_ITEMS = 779,
@@ -130,7 +130,7 @@ void AuctionHouseMgr::SendAuctionWonMail(AuctionEntry* auction, SQLTransaction&
else
{
bidderAccId = sObjectMgr->GetPlayerAccountIdByGUID(bidderGuid);
logGmTrade = AccountMgr::HasPermission(bidderAccId, rbac::RBAC_PERM_LOG_GM_TRADE, realmHandle.Index);
logGmTrade = AccountMgr::HasPermission(bidderAccId, rbac::RBAC_PERM_LOG_GM_TRADE, realm.Id.Realm);
if (logGmTrade && !sObjectMgr->GetPlayerNameByGUID(bidderGuid, bidderName))
bidderName = sObjectMgr->GetTrinityStringForDBCLocale(LANG_UNKNOWN);
+2
View File
@@ -108,6 +108,7 @@ include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/Addons
${CMAKE_CURRENT_SOURCE_DIR}/AI
${CMAKE_CURRENT_SOURCE_DIR}/AI/CoreAI
${CMAKE_CURRENT_SOURCE_DIR}/AI/PlayerAI
${CMAKE_CURRENT_SOURCE_DIR}/AI/ScriptedAI
${CMAKE_CURRENT_SOURCE_DIR}/AI/SmartScripts
${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouse
@@ -198,6 +199,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference
${CMAKE_SOURCE_DIR}/src/server/shared/Networking
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Realm
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
${VALGRIND_INCLUDE_DIR}
+1 -1
View File
@@ -109,7 +109,7 @@ bool ChatHandler::HasLowerSecurityAccount(WorldSession* target, uint32 target_ac
if (target)
target_sec = target->GetSecurity();
else if (target_account)
target_sec = AccountMgr::GetSecurity(target_account, realmHandle.Index);
target_sec = AccountMgr::GetSecurity(target_account, realm.Id.Realm);
else
return true; // caller must report error for (target == nullptr && target_account == 0)
+4 -1
View File
@@ -335,7 +335,7 @@ HostileReference* ThreatContainer::selectNextVictim(Creature* attacker, HostileR
{
// current victim is a second choice target, so don't compare threat with it below
if (currentRef == currentVictim)
currentVictim = NULL;
currentVictim = nullptr;
++iter;
continue;
}
@@ -437,12 +437,15 @@ void ThreatManager::_addThreat(Unit* victim, float threat)
if (!ref) // there was no ref => create a new one
{
bool isFirst = iThreatContainer.empty();
// threat has to be 0 here
HostileReference* hostileRef = new HostileReference(victim, this, 0);
iThreatContainer.addReference(hostileRef);
hostileRef->addThreat(threat); // now we add the real threat
if (victim->GetTypeId() == TYPEID_PLAYER && victim->ToPlayer()->IsGameMaster())
hostileRef->setOnlineOfflineState(false); // GM is always offline
else if (isFirst)
setCurrentVictim(hostileRef);
}
}
+1 -1
View File
@@ -169,7 +169,7 @@ class ThreatContainer
HostileReference* getMostHated() const
{
return iThreatList.empty() ? NULL : iThreatList.front();
return iThreatList.empty() ? nullptr : iThreatList.front();
}
HostileReference* getReferenceByTarget(Unit* victim) const;
+46 -8
View File
@@ -102,7 +102,8 @@ ConditionMgr::ConditionTypeInfo const ConditionMgr::StaticConditionTypeData[COND
{ "Health Pct", true, true, false },
{ "Realm Achievement", true, false, false },
{ "In Water", false, false, false },
{ "Terrain Swap", true, false, false }
{ "Terrain Swap", true, false, false },
{ "Sit/stand state", true, true, false }
};
// Checks if object meets the condition
@@ -439,6 +440,19 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) const
condMeets = unit->IsInWater();
break;
}
case CONDITION_STAND_STATE:
{
if (Unit* unit = object->ToUnit())
{
if (ConditionValue1 == 0)
condMeets = (unit->getStandState() == ConditionValue2);
else if (ConditionValue2 == 0)
condMeets = unit->IsStandState();
else if (ConditionValue2 == 1)
condMeets = unit->IsSitState();
}
break;
}
default:
condMeets = false;
break;
@@ -617,6 +631,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() const
case CONDITION_IN_WATER:
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
break;
case CONDITION_STAND_STATE:
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
break;
default:
ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
break;
@@ -839,7 +856,6 @@ bool ConditionMgr::IsObjectMeetingNotGroupedConditions(ConditionSourceType sourc
bool ConditionMgr::HasConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry) const
{
ConditionContainer spellCond;
if (sourceType > CONDITION_SOURCE_TYPE_NONE && sourceType < CONDITION_SOURCE_TYPE_MAX)
if (ConditionStore[sourceType].find(entry) != ConditionStore[sourceType].end())
return true;
@@ -1738,7 +1754,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const
{
if (cond->ConditionType == CONDITION_NONE || cond->ConditionType >= CONDITION_MAX)
{
TC_LOG_ERROR("sql.sql", "%s Invalid ConditionType in `condition` table, ignoring.", cond->ToString().c_str());
TC_LOG_ERROR("sql.sql", "%s Invalid ConditionType in `condition` table, ignoring.", cond->ToString(true).c_str());
return false;
}
@@ -2191,6 +2207,28 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const
}
case CONDITION_IN_WATER:
break;
case CONDITION_STAND_STATE:
{
bool valid = false;
switch (cond->ConditionValue1)
{
case 0:
valid = cond->ConditionValue2 <= UNIT_STAND_STATE_SUBMERGED;
break;
case 1:
valid = cond->ConditionValue2 <= 1;
break;
default:
valid = false;
break;
}
if (!valid)
{
TC_LOG_ERROR("sql.sql", "%s has non-existing stand state (%u,%u), skipped.", cond->ToString(true).c_str(), cond->ConditionValue1, cond->ConditionValue2);
return false;
}
break;
}
default:
break;
}
@@ -2212,17 +2250,17 @@ void ConditionMgr::LogUselessConditionValue(Condition* cond, uint8 index, uint32
void ConditionMgr::Clean()
{
for (ConditionReferenceContainer::iterator it = ConditionReferenceStore.begin(); it != ConditionReferenceStore.end(); ++it)
for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
delete *i;
for (ConditionReferenceContainer::iterator itr = ConditionReferenceStore.begin(); itr != ConditionReferenceStore.end(); ++itr)
for (ConditionContainer::const_iterator it = itr->second.begin(); it != itr->second.end(); ++it)
delete *it;
ConditionReferenceStore.clear();
for (uint32 i = 0; i < CONDITION_SOURCE_TYPE_MAX; ++i)
{
for (ConditionsByEntryMap::iterator it = ConditionStore[i].begin(); it != ConditionStore[i].end(); ++it)
for (ConditionContainer::const_iterator i = it->second.begin(); i != it->second.end(); ++i)
delete *i;
for (ConditionContainer::const_iterator itr = it->second.begin(); itr != it->second.end(); ++itr)
delete *itr;
ConditionStore[i].clear();
}
+2 -1
View File
@@ -72,7 +72,8 @@ enum ConditionTypes
CONDITION_REALM_ACHIEVEMENT = 39, // achievement_id 0 0 true if realm achievement is complete
CONDITION_IN_WATER = 40, // 0 0 0 true if unit in water
CONDITION_TERRAIN_SWAP = 41, // terrainSwap 0 0 true if object is in terrainswap
CONDITION_MAX = 42 // MAX
CONDITION_STAND_STATE = 42, // stateType state 0 true if unit matches specified sitstate (0,x: has exactly state x; 1,0: any standing state; 1,1: any sitting state;)
CONDITION_MAX = 43 // MAX
};
/*! Documentation on implementing a new ConditionSourceType:
@@ -579,7 +579,8 @@ void Creature::Update(uint32 diff)
IsAIEnabled = true;
if (!IsInEvadeMode() && LastCharmerGUID)
if (Unit* charmer = ObjectAccessor::GetUnit(*this, LastCharmerGUID))
i_AI->AttackStart(charmer);
if (CanStartAttack(charmer, true))
i_AI->AttackStart(charmer);
LastCharmerGUID.Clear();
}
+1 -1
View File
@@ -487,7 +487,7 @@ class Creature : public Unit, public GridObject<Creature>, public MapObject
bool AIM_Initialize(CreatureAI* ai = NULL);
void Motion_Initialize();
CreatureAI* AI() const { return (CreatureAI*)i_AI; }
CreatureAI* AI() const { return reinterpret_cast<CreatureAI*>(i_AI); }
SpellSchoolMask GetMeleeDamageSchoolMask() const override { return m_meleeDamageSchoolMask; }
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
@@ -228,6 +228,11 @@ void TempSummon::InitSummon()
}
}
void TempSummon::UpdateObjectVisibilityOnCreate()
{
WorldObject::UpdateObjectVisibility(true);
}
void TempSummon::SetTempSummonType(TempSummonType type)
{
m_type = type;
@@ -45,6 +45,7 @@ class TempSummon : public Creature
void Update(uint32 time) override;
virtual void InitStats(uint32 lifetime);
virtual void InitSummon();
void UpdateObjectVisibilityOnCreate() override;
virtual void UnSummon(uint32 msTime = 0);
void RemoveFromWorld() override;
void SetTempSummonType(TempSummonType type);
+3 -1
View File
@@ -2053,7 +2053,9 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert
AddToMap(summon->ToCreature());
summon->InitSummon();
//ObjectAccessor::UpdateObjectVisibility(summon);
// call MoveInLineOfSight for nearby creatures
Trinity::AIRelocationNotifier notifier(*summon);
summon->VisitNearbyObject(GetVisibilityRange(), notifier);
return summon;
}
+5
View File
@@ -589,6 +589,11 @@ class WorldObject : public Object, public WorldLocation
void DestroyForNearbyPlayers();
virtual void UpdateObjectVisibility(bool forced = true);
virtual void UpdateObjectVisibilityOnCreate()
{
UpdateObjectVisibility(true);
}
void BuildUpdate(UpdateDataMapType&) override;
void AddToObjectUpdate() override;
+10 -38
View File
@@ -1233,10 +1233,14 @@ void Player::Update(uint32 p_time)
UpdateAfkReport(now);
if (IsCharmed())
if (Unit* charmer = GetCharmer())
if (charmer->GetTypeId() == TYPEID_UNIT && charmer->IsAlive())
UpdateCharmedAI();
if (IsAIEnabled && GetAI())
GetAI()->UpdateAI(p_time);
else if (NeedChangeAI)
{
UpdateCharmAI();
NeedChangeAI = false;
IsAIEnabled = (GetAI() != nullptr);
}
// Update items that have just a limited lifetime
if (now > m_Last_tick)
@@ -14067,14 +14071,14 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
if (!optionBroadcastText)
{
/// Find localizations from database.
if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, menuId)))
if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, itr->second.OptionIndex)))
ObjectMgr::GetLocaleString(gossipMenuLocale->OptionText, locale, strOptionText);
}
if (!boxBroadcastText)
{
/// Find localizations from database.
if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, menuId)))
if (GossipMenuItemsLocale const* gossipMenuLocale = sObjectMgr->GetGossipMenuItemsLocale(MAKE_PAIR32(menuId, itr->second.OptionIndex)))
ObjectMgr::GetLocaleString(gossipMenuLocale->BoxText, locale, strBoxText);
}
}
@@ -24619,38 +24623,6 @@ bool Player::isTotalImmunity()
return false;
}
void Player::UpdateCharmedAI()
{
//This should only called in Player::Update
Creature* charmer = GetCharmer()->ToCreature();
//kill self if charm aura has infinite duration
if (charmer->IsInEvadeMode())
{
AuraEffectList const& auras = GetAuraEffectsByType(SPELL_AURA_MOD_CHARM);
for (AuraEffectList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
if ((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->GetBase()->IsPermanent())
{
charmer->DealDamage(this, GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
return;
}
}
if (!charmer->IsInCombat())
GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
Unit* target = GetVictim();
if (!target || !charmer->IsValidAttackTarget(target))
{
target = charmer->SelectNearestTarget();
if (!target)
return;
GetMotionMaster()->MoveChase(target);
Attack(target, true);
}
}
uint32 Player::GetRuneTypeBaseCooldown(RuneType runeType) const
{
float cooldown = RUNE_BASE_COOLDOWN;
+3 -2
View File
@@ -55,6 +55,7 @@ class PlayerMenu;
class PlayerSocial;
class SpellCastTargets;
class UpdateMask;
class PlayerAI;
struct CharacterCustomizeInfo;
@@ -1171,6 +1172,8 @@ class Player : public Unit, public GridObject<Player>
explicit Player(WorldSession* session);
~Player();
PlayerAI* AI() const { return reinterpret_cast<PlayerAI*>(i_AI); }
void CleanupsBeforeDelete(bool finalCleanup = true) override;
void AddToWorld() override;
@@ -2769,8 +2772,6 @@ class Player : public Unit, public GridObject<Player>
MapReference m_mapRef;
void UpdateCharmedAI();
uint32 m_lastFallTime;
float m_lastFallZ;
+157 -24
View File
@@ -44,6 +44,7 @@
#include "PetAI.h"
#include "Pet.h"
#include "Player.h"
#include "PlayerAI.h"
#include "QuestDef.h"
#include "ReputationMgr.h"
#include "SpellAuraEffects.h"
@@ -3521,6 +3522,77 @@ void Unit::RemoveAura(Aura* aura, AuraRemoveMode mode)
RemoveAura(aurApp, mode);
}
void Unit::RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check)
{
for (AuraApplicationMap::iterator iter = m_appliedAuras.begin(); iter != m_appliedAuras.end();)
{
if (check(iter->second))
{
RemoveAura(iter);
continue;
}
++iter;
}
}
void Unit::RemoveOwnedAuras(std::function<bool(Aura const*)> const& check)
{
for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
{
if (check(iter->second))
{
RemoveOwnedAura(iter);
continue;
}
++iter;
}
}
void Unit::RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check)
{
for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
{
if (check(iter->second))
{
RemoveAura(iter);
continue;
}
++iter;
}
}
void Unit::RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check)
{
for (AuraMap::iterator iter = m_ownedAuras.lower_bound(spellId); iter != m_ownedAuras.upper_bound(spellId);)
{
if (check(iter->second))
{
RemoveOwnedAura(iter);
continue;
}
++iter;
}
}
void Unit::RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check)
{
for (AuraEffectList::iterator iter = m_modAuras[auraType].begin(); iter != m_modAuras[auraType].end();)
{
Aura* aura = (*iter)->GetBase();
AuraApplication * aurApp = aura->GetApplicationOfTarget(GetGUID());
ASSERT(aurApp);
++iter;
if (check(aurApp))
{
uint32 removedAuras = m_removedAurasCount;
RemoveAura(aurApp);
if (m_removedAurasCount > removedAuras + 1)
iter = m_modAuras[auraType].begin();
}
}
}
void Unit::RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID, uint8 reqEffMask, AuraRemoveMode removeMode)
{
for (AuraApplicationMap::iterator iter = m_appliedAuras.lower_bound(spellId); iter != m_appliedAuras.upper_bound(spellId);)
@@ -7605,10 +7677,10 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
if (GetTypeId() == TYPEID_UNIT && !IsPet())
{
// should not let player enter combat by right clicking target - doesn't helps
AddThreat(victim, 0.0f);
SetInCombatWith(victim);
if (victim->GetTypeId() == TYPEID_PLAYER)
victim->SetInCombatWith(this);
AddThreat(victim, 0.0f);
ToCreature()->SendAIReaction(AI_REACTION_HOSTILE);
ToCreature()->CallAssistance();
@@ -7852,7 +7924,7 @@ Unit* Unit::GetCharmer() const
if (ObjectGuid charmerGUID = GetCharmerGUID())
return ObjectAccessor::GetUnit(*this, charmerGUID);
return NULL;
return nullptr;
}
Player* Unit::GetCharmerOrOwnerPlayerOrPlayerItself() const
@@ -10798,7 +10870,7 @@ void Unit::UpdateSpeed(UnitMoveType mtype, bool forced)
if (Creature* creature = ToCreature())
{
uint32 immuneMask = creature->GetCreatureTemplate()->MechanicImmuneMask;
if (immuneMask & (1 << MECHANIC_SNARE) || immuneMask & (1 << MECHANIC_DAZE))
if (immuneMask & (1 << (MECHANIC_SNARE - 1)) || immuneMask & (1 << (MECHANIC_DAZE - 1)))
break;
}
@@ -12084,28 +12156,76 @@ void Unit::CleanupsBeforeDelete(bool finalCleanup)
void Unit::UpdateCharmAI()
{
if (GetTypeId() == TYPEID_PLAYER)
return;
if (i_disabledAI) // disabled AI must be primary AI
switch (GetTypeId())
{
if (!IsCharmed())
{
delete i_AI;
i_AI = i_disabledAI;
i_disabledAI = NULL;
}
}
else
{
if (IsCharmed())
{
i_disabledAI = i_AI;
if (isPossessed() || IsVehicle())
i_AI = new PossessedAI(ToCreature());
case TYPEID_UNIT:
if (i_disabledAI) // disabled AI must be primary AI
{
if (!IsCharmed())
{
delete i_AI;
i_AI = i_disabledAI;
i_disabledAI = nullptr;
}
}
else
i_AI = new PetAI(ToCreature());
{
if (IsCharmed())
{
i_disabledAI = i_AI;
if (isPossessed() || IsVehicle())
i_AI = new PossessedAI(ToCreature());
else
i_AI = new PetAI(ToCreature());
}
}
break;
case TYPEID_PLAYER:
{
if (IsCharmed()) // if we are currently being charmed, then we should apply charm AI
{
i_disabledAI = i_AI;
UnitAI* newAI = nullptr;
// first, we check if the creature's own AI specifies an override playerai for its owned players
if (Unit* charmer = GetCharmer())
{
if (Creature* creatureCharmer = charmer->ToCreature())
{
if (PlayerAI* charmAI = creatureCharmer->IsAIEnabled ? creatureCharmer->AI()->GetAIForCharmedPlayer(ToPlayer()) : nullptr)
newAI = charmAI;
}
else
{
TC_LOG_ERROR("misc", "Attempt to assign charm AI to player %s who is charmed by non-creature %s.", GetGUID().ToString().c_str(), GetCharmerGUID().ToString().c_str());
}
}
if (!newAI) // otherwise, we default to the generic one
newAI = new SimpleCharmedPlayerAI(ToPlayer());
i_AI = newAI;
}
else
{
if (i_AI)
{
// we allow the charmed PlayerAI to clean up
i_AI->OnCharmed(false);
// then delete it
delete i_AI;
}
else
{
TC_LOG_ERROR("misc", "Attempt to remove charm AI from player %s who doesn't currently have charm AI.", GetGUID().ToString().c_str());
}
// and restore our previous PlayerAI (if we had one)
i_AI = i_disabledAI;
i_disabledAI = nullptr;
// IsAIEnabled gets handled in the caller
}
break;
}
default:
TC_LOG_ERROR("misc", "Attempt to update charm AI for unit %s, which is neither player nor creature.", GetGUID().ToString().c_str());
}
}
@@ -14360,11 +14480,17 @@ bool Unit::SetCharmedBy(Unit* charmer, CharmType type, AuraApplication const* au
ToCreature()->AI()->OnCharmed(true);
GetMotionMaster()->MoveIdle();
}
else
else if (Player* player = ToPlayer())
{
Player* player = ToPlayer();
if (player->isAFK())
player->ToggleAFK();
if (charmer->GetTypeId() == TYPEID_UNIT) // we are charmed by a creature
{
// change AI to charmed AI on next Update tick
NeedChangeAI = true;
IsAIEnabled = false;
}
player->SetClientControl(this, false);
}
@@ -14522,7 +14648,14 @@ void Unit::RemoveCharmedBy(Unit* charmer)
}
if (Player* player = ToPlayer())
{
if (charmer->GetTypeId() == TYPEID_UNIT) // charmed by a creature, this means we had PlayerAI
{
NeedChangeAI = true;
IsAIEnabled = false;
}
player->SetClientControl(this, true);
}
// a guardian should always have charminfo
if (playerCharmer && this != charmer->GetFirstControlled())
+10
View File
@@ -1719,6 +1719,16 @@ class Unit : public WorldObject
void RemoveAura(AuraApplication * aurApp, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
void RemoveAura(Aura* aur, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
// Convenience methods removing auras by predicate
void RemoveAppliedAuras(std::function<bool(AuraApplication const*)> const& check);
void RemoveOwnedAuras(std::function<bool(Aura const*)> const& check);
// Optimized overloads taking advantage of map key
void RemoveAppliedAuras(uint32 spellId, std::function<bool(AuraApplication const*)> const& check);
void RemoveOwnedAuras(uint32 spellId, std::function<bool(Aura const*)> const& check);
void RemoveAurasByType(AuraType auraType, std::function<bool(AuraApplication const*)> const& check);
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, uint8 reqEffMask = 0, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID = ObjectGuid::Empty, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT);
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint32 dispellerSpellId, ObjectGuid casterGUID, Unit* dispeller, uint8 chargesRemoved = 1);
@@ -654,13 +654,13 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM);
stmt->setUInt32(0, GetAccountId());
stmt->setUInt32(1, realmHandle.Index);
stmt->setUInt32(1, realm.Id.Realm);
trans->Append(stmt);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS);
stmt->setUInt32(0, createInfo->CharCount);
stmt->setUInt32(1, GetAccountId());
stmt->setUInt32(2, realmHandle.Index);
stmt->setUInt32(2, realm.Id.Realm);
trans->Append(stmt);
LoginDatabase.CommitTransaction(trans);
+1 -1
View File
@@ -599,7 +599,7 @@ void WorldSession::HandleAddFriendOpcodeCallBack(PreparedQueryResult result, std
team = Player::TeamForRace(fields[1].GetUInt8());
friendAccountId = fields[2].GetUInt32();
if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realmHandle.Index)))
if (HasPermission(rbac::RBAC_PERM_ALLOW_GM_FRIEND) || AccountMgr::IsPlayerAccount(AccountMgr::GetSecurity(friendAccountId, realm.Id.Realm)))
{
if (friendGuid)
{
+1 -1
View File
@@ -590,7 +590,7 @@ bool Map::AddToMap(T* obj)
//something, such as vehicle, needs to be update immediately
//also, trigger needs to cast spell, if not update, cannot see visual
obj->UpdateObjectVisibility(true);
obj->UpdateObjectVisibilityOnCreate();
return true;
}
File diff suppressed because it is too large. Load diff
-13
View File
@@ -19,18 +19,5 @@
#define SC_SCRIPTLOADER_H
void AddScripts();
void AddSpellScripts();
void AddCommandScripts();
void AddWorldScripts();
void AddEasternKingdomsScripts();
void AddKalimdorScripts();
void AddOutlandScripts();
void AddNorthrendScripts();
void AddMaelstromScripts();
void AddEventScripts();
void AddPetScripts();
void AddBattlegroundScripts();
void AddOutdoorPvPScripts();
void AddCustomScripts();
#endif
@@ -20,7 +20,7 @@
#include "ZmqContext.h"
#include "BattlenetServerManager.h"
void Battlenet::ServerManager::InitializeConnection()
void IPC::BattlenetComm::ServerManager::InitializeConnection()
{
std::string bnetserverAddress = sConfigMgr->GetStringDefault("BnetServer.Address", "127.0.0.1");
int32 bnetserverPort = sConfigMgr->GetIntDefault("BnetServer.Port", 1118);
@@ -28,23 +28,29 @@ void Battlenet::ServerManager::InitializeConnection()
_socket->Start();
}
void Battlenet::ServerManager::CloseConnection()
void IPC::BattlenetComm::ServerManager::CloseConnection()
{
_socket->End();
delete _socket;
_socket = nullptr;
}
Battlenet::Header Battlenet::ServerManager::CreateHeader(BnetCommands command)
IPC::BattlenetComm::ServerManager& IPC::BattlenetComm::ServerManager::Instance()
{
static ServerManager instance;
return instance;
}
IPC::BattlenetComm::Header IPC::BattlenetComm::ServerManager::CreateHeader(BnetCommands command)
{
Header header;
header.Ipc.Channel = IPC_CHANNEL_BNET;
header.Ipc.Command = command;
header.Realm = realmHandle;
header.Realm = realm.Id;
return header;
}
void Battlenet::ServerManager::SendChangeToonOnlineState(uint32 battlenetAccountId, uint32 gameAccountId, ObjectGuid guid, std::string const& name, bool online)
void IPC::BattlenetComm::ServerManager::SendChangeToonOnlineState(uint32 battlenetAccountId, uint32 gameAccountId, ObjectGuid guid, std::string const& name, bool online)
{
// Do nothing for Grunt login
if (!battlenetAccountId)
@@ -54,7 +60,7 @@ void Battlenet::ServerManager::SendChangeToonOnlineState(uint32 battlenetAccount
ToonHandle toon;
toon.AccountId = battlenetAccountId;
toon.GameAccountId = gameAccountId;
toon.Guid = guid;
toon.Guid = guid.GetCounter();
toon.Name = name;
zmqpp::message msg;
@@ -62,5 +68,13 @@ void Battlenet::ServerManager::SendChangeToonOnlineState(uint32 battlenetAccount
msg << toon;
msg << online;
_socket->Send(&msg);
Send(&msg);
}
void IPC::BattlenetComm::ServerManager::Send(zmqpp::message* msg)
{
if (!_socket)
return;
_socket->Send(msg);
}
+20 -18
View File
@@ -24,32 +24,34 @@
namespace zmqpp
{
class socket;
class message;
}
namespace Battlenet
namespace IPC
{
class ServerManager
namespace BattlenetComm
{
ServerManager() : _socket(nullptr) { }
public:
void InitializeConnection();
void CloseConnection();
static ServerManager& Instance()
class ServerManager
{
static ServerManager instance;
return instance;
}
ServerManager() : _socket(nullptr) { }
void SendChangeToonOnlineState(uint32 battlenetAccountId, uint32 gameAccountId, ObjectGuid guid, std::string const& name, bool online);
public:
void InitializeConnection();
void CloseConnection();
private:
static Header CreateHeader(BnetCommands command);
ZmqMux* _socket;
};
static ServerManager& Instance();
void SendChangeToonOnlineState(uint32 battlenetAccountId, uint32 gameAccountId, ObjectGuid guid, std::string const& name, bool online);
private:
void Send(zmqpp::message* msg);
static Header CreateHeader(BnetCommands command);
ZmqMux* _socket;
};
}
}
#define sBattlenetServer Battlenet::ServerManager::Instance()
#define sBattlenetServer IPC::BattlenetComm::ServerManager::Instance()
#endif // BattlenetMgr_h__
+5 -5
View File
@@ -1160,7 +1160,7 @@ void WorldSession::LoadPermissions()
uint32 id = GetAccountId();
uint8 secLevel = GetSecurity();
_RBACData = new rbac::RBACData(id, _accountName, realmHandle.Index, secLevel);
_RBACData = new rbac::RBACData(id, _accountName, realm.Id.Realm, secLevel);
_RBACData->LoadFromDB();
}
@@ -1170,9 +1170,9 @@ PreparedQueryResultFuture WorldSession::LoadPermissionsAsync()
uint8 secLevel = GetSecurity();
TC_LOG_DEBUG("rbac", "WorldSession::LoadPermissions [AccountId: %u, Name: %s, realmId: %d, secLevel: %u]",
id, _accountName.c_str(), realmHandle.Index, secLevel);
id, _accountName.c_str(), realm.Id.Realm, secLevel);
_RBACData = new rbac::RBACData(id, _accountName, realmHandle.Index, secLevel);
_RBACData = new rbac::RBACData(id, _accountName, realm.Id.Realm, secLevel);
return _RBACData->LoadFromDBAsync();
}
@@ -1250,7 +1250,7 @@ bool WorldSession::HasPermission(uint32 permission)
bool hasPermission = _RBACData->HasPermission(permission);
TC_LOG_DEBUG("rbac", "WorldSession::HasPermission [AccountId: %u, Name: %s, realmId: %d]",
_RBACData->GetId(), _RBACData->GetName().c_str(), realmHandle.Index);
_RBACData->GetId(), _RBACData->GetName().c_str(), realm.Id.Realm);
return hasPermission;
}
@@ -1258,7 +1258,7 @@ bool WorldSession::HasPermission(uint32 permission)
void WorldSession::InvalidateRBACData()
{
TC_LOG_DEBUG("rbac", "WorldSession::Invalidaterbac::RBACData [AccountId: %u, Name: %s, realmId: %d]",
_RBACData->GetId(), _RBACData->GetName().c_str(), realmHandle.Index);
_RBACData->GetId(), _RBACData->GetName().c_str(), realm.Id.Realm);
delete _RBACData;
_RBACData = NULL;
}
+2 -2
View File
@@ -513,7 +513,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
authSession->Account = recvPacket.ReadString(accountNameLength);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME);
stmt->setInt32(0, realmHandle.Index);
stmt->setInt32(0, int32(realm.Id.Realm));
stmt->setString(1, authSession->Account);
_queryCallback = std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1);
@@ -556,7 +556,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes
return;
}
if (authSession->RealmID != realmHandle.Index)
if (authSession->RealmID != realm.Id.Realm)
{
SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND);
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm).");
+1 -1
View File
@@ -153,7 +153,7 @@ bool Weather::ReGenerate()
uint32 chance2 = chance1+ m_weatherChances->data[season].snowChance;
uint32 chance3 = chance2+ m_weatherChances->data[season].stormChance;
uint32 rnd = urand(0, 99);
uint32 rnd = urand(1, 100);
if (rnd <= chance1)
m_type = WEATHER_TYPE_RAIN;
else if (rnd <= chance2)
+6 -6
View File
@@ -1411,7 +1411,7 @@ void World::SetInitialWorldSettings()
uint32 server_type = IsFFAPvPRealm() ? uint32(REALM_TYPE_PVP) : getIntConfig(CONFIG_GAME_TYPE);
uint32 realm_zone = getIntConfig(CONFIG_REALM_ZONE);
LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmHandle.Index); // One-time query
LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realm.Id.Realm); // One-time query
///- Load the DBC files
TC_LOG_INFO("server.loading", "Initialize data stores...");
@@ -1860,7 +1860,7 @@ void World::SetInitialWorldSettings()
m_startTime = m_gameTime;
LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES(%u, %u, 0, '%s')",
realmHandle.Index, uint32(m_startTime), GitRevision::GetFullVersion()); // One-time query
realm.Id.Realm, uint32(m_startTime), GitRevision::GetFullVersion()); // One-time query
m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
@@ -2146,7 +2146,7 @@ void World::Update(uint32 diff)
stmt->setUInt32(0, tmpDiff);
stmt->setUInt16(1, uint16(maxOnlinePlayers));
stmt->setUInt32(2, realmHandle.Index);
stmt->setUInt32(2, realm.Id.Realm);
stmt->setUInt32(3, uint32(m_startTime));
LoginDatabase.Execute(stmt);
@@ -2876,13 +2876,13 @@ void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount)
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS_BY_REALM);
stmt->setUInt32(0, accountId);
stmt->setUInt32(1, realmHandle.Index);
stmt->setUInt32(1, realm.Id.Realm);
LoginDatabase.Execute(stmt);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS);
stmt->setUInt8(0, charCount);
stmt->setUInt32(1, accountId);
stmt->setUInt32(2, realmHandle.Index);
stmt->setUInt32(2, realm.Id.Realm);
LoginDatabase.Execute(stmt);
}
}
@@ -3051,7 +3051,7 @@ void World::ResetCurrencyWeekCap()
void World::LoadDBAllowedSecurityLevel()
{
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL);
stmt->setInt32(0, int32(realmHandle.Index));
stmt->setInt32(0, int32(realm.Id.Realm));
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (result)
+2 -13
View File
@@ -30,6 +30,7 @@
#include "SharedDefines.h"
#include "QueryResult.h"
#include "Callback.h"
#include "Realm/Realm.h"
#include <atomic>
#include <map>
@@ -464,18 +465,6 @@ enum BillingPlanFlags
SESSION_ENABLE_CAIS = 0x80
};
/// Type of server, this is values from second column of Cfg_Configs.dbc
enum RealmType
{
REALM_TYPE_NORMAL = 0,
REALM_TYPE_PVP = 1,
REALM_TYPE_NORMAL2 = 4,
REALM_TYPE_RP = 6,
REALM_TYPE_RPPVP = 8,
REALM_TYPE_FFA_PVP = 16 // custom, free for all pvp mode like arena PvP in all zones except rest activated places and sanctuaries
// replaced by REALM_PVP in realm list
};
enum RealmZone
{
REALM_ZONE_UNKNOWN = 0, // any language
@@ -904,7 +893,7 @@ class World
std::deque<std::future<PreparedQueryResult>> m_realmCharCallbacks;
};
extern Battlenet::RealmHandle realmHandle;
extern Realm realm;
#define sWorld World::instance()
#endif
+2 -1
View File
@@ -17,7 +17,8 @@ set(ipc_SRCS
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/zmqpp
${CMAKE_SOURCE_DIR}/src/common/
${CMAKE_SOURCE_DIR}/src/common
${CMAKE_SOURCE_DIR}/src/server/shared
${ZMQ_INCLUDE_DIR}
)
+11 -11
View File
@@ -18,7 +18,7 @@
#include "Commands.h"
#include <zmqpp/message.hpp>
zmqpp::message& operator>>(zmqpp::message& msg, IPCHeader& header)
zmqpp::message& operator>>(zmqpp::message& msg, IPC::Header& header)
{
msg >> header.Channel;
msg >> header.Command;
@@ -28,19 +28,19 @@ zmqpp::message& operator>>(zmqpp::message& msg, IPCHeader& header)
zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::RealmHandle& realm)
{
msg >> realm.Region;
msg >> realm.Battlegroup;
msg >> realm.Index;
msg >> realm.Site;
msg >> realm.Realm;
return msg;
}
zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::Header& header)
zmqpp::message& operator>>(zmqpp::message& msg, IPC::BattlenetComm::Header& header)
{
msg >> header.Ipc;
msg >> header.Realm;
return msg;
}
zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::ToonHandle& toonHandle)
zmqpp::message& operator>>(zmqpp::message& msg, IPC::BattlenetComm::ToonHandle& toonHandle)
{
msg >> toonHandle.AccountId;
msg >> toonHandle.GameAccountId;
@@ -49,29 +49,29 @@ zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::ToonHandle& toonHandl
return msg;
}
zmqpp::message& operator<<(zmqpp::message& msg, IPCHeader& header)
zmqpp::message& operator<<(zmqpp::message& msg, IPC::Header const& header)
{
msg << header.Channel;
msg << header.Command;
return msg;
}
zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::RealmHandle& realm)
zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::RealmHandle const& realm)
{
msg << realm.Region;
msg << realm.Battlegroup;
msg << realm.Index;
msg << realm.Site;
msg << realm.Realm;
return msg;
}
zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::Header& header)
zmqpp::message& operator<<(zmqpp::message& msg, IPC::BattlenetComm::Header const& header)
{
msg << header.Ipc;
msg << header.Realm;
return msg;
}
zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::ToonHandle& toonHandle)
zmqpp::message& operator<<(zmqpp::message& msg, IPC::BattlenetComm::ToonHandle const& toonHandle)
{
msg << toonHandle.AccountId;
msg << toonHandle.GameAccountId;
+26 -29
View File
@@ -19,6 +19,7 @@
#define _COMMANDS_H
#include "Define.h"
#include "Realm/Realm.h"
#include <string>
enum Channels
@@ -35,34 +36,30 @@ enum BnetCommands
IPC_BNET_MAX_COMMAND
};
struct IPCHeader
namespace IPC
{
uint8 Channel;
uint8 Command;
};
namespace Battlenet
{
struct RealmHandle
{
uint8 Region;
uint8 Battlegroup;
uint32 Index;
};
struct Header
{
IPCHeader Ipc;
RealmHandle Realm;
uint8 Channel;
uint8 Command;
};
struct ToonHandle
namespace BattlenetComm
{
uint32 AccountId;
uint32 GameAccountId;
uint64 Guid;
std::string Name;
};
struct Header
{
IPC::Header Ipc;
Battlenet::RealmHandle Realm;
};
struct ToonHandle
{
uint32 AccountId;
uint32 GameAccountId;
uint64 Guid;
std::string Name;
};
}
}
namespace zmqpp
@@ -70,14 +67,14 @@ namespace zmqpp
class message;
}
zmqpp::message& operator>>(zmqpp::message& msg, IPCHeader& header);
zmqpp::message& operator>>(zmqpp::message& msg, IPC::Header& header);
zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::RealmHandle& realm);
zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::Header& header);
zmqpp::message& operator>>(zmqpp::message& msg, Battlenet::ToonHandle& toonHandle);
zmqpp::message& operator>>(zmqpp::message& msg, IPC::BattlenetComm::Header& header);
zmqpp::message& operator>>(zmqpp::message& msg, IPC::BattlenetComm::ToonHandle& toonHandle);
zmqpp::message& operator<<(zmqpp::message& msg, IPCHeader& header);
zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::RealmHandle& realm);
zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::Header& header);
zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::ToonHandle& toonHandle);
zmqpp::message& operator<<(zmqpp::message& msg, IPC::Header const& header);
zmqpp::message& operator<<(zmqpp::message& msg, Battlenet::RealmHandle const& realm);
zmqpp::message& operator<<(zmqpp::message& msg, IPC::BattlenetComm::Header const& header);
zmqpp::message& operator<<(zmqpp::message& msg, IPC::BattlenetComm::ToonHandle const& toonHandle);
#endif // _COMMANDS_H
+22 -12
View File
@@ -16,9 +16,15 @@ if (USE_SCRIPTPCH)
endif ()
message(STATUS "SCRIPT PREPARATIONS")
include(Spells/CMakeLists.txt)
include(Commands/CMakeLists.txt)
macro(PrepareScripts name out)
file(GLOB_RECURSE found
${name}/*.h
${name}/*.cpp
)
list(APPEND ${out} ${found})
message(STATUS " -> Prepared: ${name}")
endmacro(PrepareScripts)
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
@@ -28,17 +34,20 @@ set(scripts_STAT_SRCS
../game/Maps/AreaBoundary.cpp
)
PrepareScripts(Spells scripts_STAT_SRCS)
PrepareScripts(Commands scripts_STAT_SRCS)
if(SCRIPTS)
include(Custom/CMakeLists.txt)
include(World/CMakeLists.txt)
include(OutdoorPvP/CMakeLists.txt)
include(EasternKingdoms/CMakeLists.txt)
include(Kalimdor/CMakeLists.txt)
include(Outland/CMakeLists.txt)
include(Northrend/CMakeLists.txt)
include(Maelstrom/CMakeLists.txt)
include(Events/CMakeLists.txt)
include(Pet/CMakeLists.txt)
PrepareScripts(Custom scripts_STAT_SRCS)
PrepareScripts(World scripts_STAT_SRCS)
PrepareScripts(OutdoorPvP scripts_STAT_SRCS)
PrepareScripts(EasternKingdoms scripts_STAT_SRCS)
PrepareScripts(Kalimdor scripts_STAT_SRCS)
PrepareScripts(Outland scripts_STAT_SRCS)
PrepareScripts(Northrend scripts_STAT_SRCS)
PrepareScripts(Maelstrom scripts_STAT_SRCS)
PrepareScripts(Events scripts_STAT_SRCS)
PrepareScripts(Pet scripts_STAT_SRCS)
endif()
message(STATUS "SCRIPT PREPARATION COMPLETE")
@@ -65,6 +74,7 @@ include_directories(
${CMAKE_SOURCE_DIR}/src/server/game/Addons
${CMAKE_SOURCE_DIR}/src/server/game/AI
${CMAKE_SOURCE_DIR}/src/server/game/AI/CoreAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/PlayerAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI
${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts
${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse
@@ -1,18 +0,0 @@
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
file(GLOB_RECURSE sources_Commands Commands/*.cpp Commands/*.h)
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
${sources_Commands}
)
message(" -> Prepared: Commands")
+1 -1
View File
@@ -161,7 +161,7 @@ public:
///- Get the accounts with GM Level >0
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_GM_ACCOUNTS);
stmt->setUInt8(0, uint8(SEC_MODERATOR));
stmt->setInt32(1, int32(realmHandle.Index));
stmt->setInt32(1, int32(realm.Id.Realm));
PreparedQueryResult result = LoginDatabase.Query(stmt);
if (result)
+1 -1
View File
@@ -1603,7 +1603,7 @@ public:
// Query the prepared statement for login data
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO);
stmt->setInt32(0, int32(realmHandle.Index));
stmt->setInt32(0, int32(realm.Id.Realm));
stmt->setUInt32(1, accId);
PreparedQueryResult result = LoginDatabase.Query(stmt);
+6 -6
View File
@@ -474,7 +474,7 @@ public:
return false;
}
handler->PSendSysMessage(LANG_YOU_CHANGE_ASPEED, ASpeed, targetNameLink.c_str());
handler->PSendSysMessage(LANG_YOU_CHANGE_ASPEED, targetNameLink.c_str(), ASpeed);
if (handler->needReportToTarget(target))
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_ASPEED_CHANGED, handler->GetNameLink().c_str(), ASpeed);
@@ -522,7 +522,7 @@ public:
return false;
}
handler->PSendSysMessage(LANG_YOU_CHANGE_SPEED, Speed, targetNameLink.c_str());
handler->PSendSysMessage(LANG_YOU_CHANGE_SPEED, targetNameLink.c_str(), Speed);
if (handler->needReportToTarget(target))
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_SPEED_CHANGED, handler->GetNameLink().c_str(), Speed);
@@ -567,7 +567,7 @@ public:
return false;
}
handler->PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, Swim, targetNameLink.c_str());
handler->PSendSysMessage(LANG_YOU_CHANGE_SWIM_SPEED, targetNameLink.c_str(), Swim);
if (handler->needReportToTarget(target))
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_SWIM_SPEED_CHANGED, handler->GetNameLink().c_str(), Swim);
@@ -612,7 +612,7 @@ public:
return false;
}
handler->PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, BSpeed, targetNameLink.c_str());
handler->PSendSysMessage(LANG_YOU_CHANGE_BACK_SPEED, targetNameLink.c_str(), BSpeed);
if (handler->needReportToTarget(target))
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_BACK_SPEED_CHANGED, handler->GetNameLink().c_str(), BSpeed);
@@ -648,7 +648,7 @@ public:
if (handler->HasLowerSecurity(target, ObjectGuid::Empty))
return false;
handler->PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, FSpeed, handler->GetNameLink(target).c_str());
handler->PSendSysMessage(LANG_YOU_CHANGE_FLY_SPEED, handler->GetNameLink(target).c_str(), FSpeed);
if (handler->needReportToTarget(target))
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOURS_FLY_SPEED_CHANGED, handler->GetNameLink().c_str(), FSpeed);
@@ -685,7 +685,7 @@ public:
if (handler->HasLowerSecurity(player, ObjectGuid::Empty))
return false;
handler->PSendSysMessage(LANG_YOU_CHANGE_SIZE, Scale, handler->GetNameLink(player).c_str());
handler->PSendSysMessage(LANG_YOU_CHANGE_SIZE, handler->GetNameLink(player).c_str(), Scale);
if (handler->needReportToTarget(player))
ChatHandler(player->GetSession()).PSendSysMessage(LANG_YOURS_SIZE_CHANGED, handler->GetNameLink().c_str(), Scale);
}
+1 -1
View File
@@ -157,7 +157,7 @@ public:
if (!rdata)
{
data->rbac = new rbac::RBACData(accountId, accountName, realmHandle.Index, AccountMgr::GetSecurity(accountId, realmHandle.Index));
data->rbac = new rbac::RBACData(accountId, accountName, realm.Id.Realm, AccountMgr::GetSecurity(accountId, realm.Id.Realm));
data->rbac->LoadFromDB();
data->needDelete = true;
}
@@ -0,0 +1,106 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// This is where scripts' loading functions should be declared:
void AddSC_account_commandscript();
void AddSC_achievement_commandscript();
void AddSC_ahbot_commandscript();
void AddSC_arena_commandscript();
void AddSC_ban_commandscript();
void AddSC_battlenet_account_commandscript();
void AddSC_bf_commandscript();
void AddSC_cast_commandscript();
void AddSC_character_commandscript();
void AddSC_cheat_commandscript();
void AddSC_debug_commandscript();
void AddSC_deserter_commandscript();
void AddSC_disable_commandscript();
void AddSC_event_commandscript();
void AddSC_gm_commandscript();
void AddSC_go_commandscript();
void AddSC_gobject_commandscript();
void AddSC_group_commandscript();
void AddSC_guild_commandscript();
void AddSC_honor_commandscript();
void AddSC_instance_commandscript();
void AddSC_learn_commandscript();
void AddSC_lfg_commandscript();
void AddSC_list_commandscript();
void AddSC_lookup_commandscript();
void AddSC_message_commandscript();
void AddSC_misc_commandscript();
void AddSC_mmaps_commandscript();
void AddSC_modify_commandscript();
void AddSC_npc_commandscript();
void AddSC_pet_commandscript();
void AddSC_quest_commandscript();
void AddSC_rbac_commandscript();
void AddSC_reload_commandscript();
void AddSC_reset_commandscript();
void AddSC_send_commandscript();
void AddSC_server_commandscript();
void AddSC_tele_commandscript();
void AddSC_ticket_commandscript();
void AddSC_titles_commandscript();
void AddSC_wp_commandscript();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddCommandsScripts()
{
AddSC_account_commandscript();
AddSC_achievement_commandscript();
AddSC_ahbot_commandscript();
AddSC_arena_commandscript();
AddSC_ban_commandscript();
AddSC_battlenet_account_commandscript();
AddSC_bf_commandscript();
AddSC_cast_commandscript();
AddSC_character_commandscript();
AddSC_cheat_commandscript();
AddSC_debug_commandscript();
AddSC_deserter_commandscript();
AddSC_disable_commandscript();
AddSC_event_commandscript();
AddSC_gm_commandscript();
AddSC_go_commandscript();
AddSC_gobject_commandscript();
AddSC_group_commandscript();
AddSC_guild_commandscript();
AddSC_honor_commandscript();
AddSC_instance_commandscript();
AddSC_learn_commandscript();
AddSC_lookup_commandscript();
AddSC_lfg_commandscript();
AddSC_list_commandscript();
AddSC_message_commandscript();
AddSC_misc_commandscript();
AddSC_mmaps_commandscript();
AddSC_modify_commandscript();
AddSC_npc_commandscript();
AddSC_quest_commandscript();
AddSC_pet_commandscript();
AddSC_rbac_commandscript();
AddSC_reload_commandscript();
AddSC_reset_commandscript();
AddSC_send_commandscript();
AddSC_server_commandscript();
AddSC_tele_commandscript();
AddSC_ticket_commandscript();
AddSC_titles_commandscript();
AddSC_wp_commandscript();
}
+3 -3
View File
@@ -98,7 +98,7 @@ public:
ObjectGuid targetGuid = sObjectMgr->GetPlayerGUIDByName(target);
uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(targetGuid);
// Target must exist and have administrative rights
if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realmHandle.Index))
if (!AccountMgr::HasPermission(accountId, rbac::RBAC_PERM_COMMANDS_BE_ASSIGNED_TICKET, realm.Id.Realm))
{
handler->SendSysMessage(LANG_COMMAND_TICKETASSIGNERROR_A);
return true;
@@ -122,7 +122,7 @@ public:
// Assign ticket
SQLTransaction trans = SQLTransaction(NULL);
ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realmHandle.Index)));
ticket->SetAssignedTo(targetGuid, AccountMgr::IsAdminAccount(AccountMgr::GetSecurity(accountId, realm.Id.Realm)));
ticket->SaveToDB(trans);
sTicketMgr->UpdateLastChange();
@@ -390,7 +390,7 @@ public:
{
ObjectGuid guid = ticket->GetAssignedToGUID();
uint32 accountId = sObjectMgr->GetPlayerAccountIdByGUID(guid);
security = AccountMgr::GetSecurity(accountId, realmHandle.Index);
security = AccountMgr::GetSecurity(accountId, realm.Id.Realm);
}
// Check security
+43 -64
View File
@@ -564,29 +564,24 @@ public:
// -> variable lowguid is filled with the GUID of the NPC
uint32 pathid = 0;
uint32 point = 0;
uint32 wpGuid = 0;
Creature* target = handler->getSelectedCreature();
PreparedStatement* stmt = NULL;
// User did select a visual waypoint?
if (!target || target->GetEntry() != VISUAL_WAYPOINT)
{
handler->SendSysMessage("|cffff33ffERROR: You must select a waypoint.|r");
return false;
}
// The visual waypoint
wpGuid = target->GetGUID().GetCounter();
// User did select a visual waypoint?
// Check the creature
stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_WAYPOINT_DATA_BY_WPGUID);
stmt->setUInt32(0, wpGuid);
stmt->setUInt32(0, target->GetSpawnId());
PreparedQueryResult result = WorldDatabase.Query(stmt);
if (!result)
{
handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUID().GetCounter());
handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetSpawnId());
// Select waypoint number from database
// Since we compare float values, we have to deal with
// some difficulties.
@@ -602,11 +597,11 @@ public:
stmt->setString(3, maxDiff);
stmt->setFloat(4, target->GetPositionZ());
stmt->setString(5, maxDiff);
PreparedQueryResult queryResult = WorldDatabase.Query(stmt);
result = WorldDatabase.Query(stmt);
if (!queryResult)
if (!result)
{
handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid);
handler->PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetSpawnId());
return true;
}
}
@@ -634,13 +629,8 @@ public:
{
handler->PSendSysMessage("|cff00ff00DEBUG: wp modify del, PathID: |r|cff00ffff%u|r", pathid);
if (wpGuid != 0)
if (Creature* wpCreature = handler->GetSession()->GetPlayer()->GetMap()->GetCreature(ObjectGuid(HighGuid::Unit, VISUAL_WAYPOINT, wpGuid)))
{
wpCreature->CombatStop();
wpCreature->DeleteFromDB();
wpCreature->AddObjectToRemoveList();
}
target->DeleteFromDB();
target->AddObjectToRemoveList();
stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_WAYPOINT_DATA);
stmt->setUInt32(0, pathid);
@@ -662,53 +652,42 @@ public:
Player* chr = handler->GetSession()->GetPlayer();
Map* map = chr->GetMap();
// What to do:
// Move the visual spawnpoint
// Respawn the owner of the waypoints
target->DeleteFromDB();
target->AddObjectToRemoveList();
// re-create
Creature* wpCreature = new Creature();
if (!wpCreature->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMask(), VISUAL_WAYPOINT, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()))
{
// What to do:
// Move the visual spawnpoint
// Respawn the owner of the waypoints
if (wpGuid != 0)
{
if (Creature* wpCreature = map->GetCreature(ObjectGuid(HighGuid::Unit, VISUAL_WAYPOINT, wpGuid)))
{
wpCreature->CombatStop();
wpCreature->DeleteFromDB();
wpCreature->AddObjectToRemoveList();
}
// re-create
Creature* wpCreature2 = new Creature();
if (!wpCreature2->Create(map->GenerateLowGuid<HighGuid::Unit>(), map, chr->GetPhaseMask(), VISUAL_WAYPOINT, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation()))
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
delete wpCreature2;
wpCreature2 = NULL;
return false;
}
wpCreature2->CopyPhaseFrom(chr);
wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask());
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
/// @todo Should we first use "Create" then use "LoadFromDB"?
if (!wpCreature2->LoadCreatureFromDB(wpCreature2->GetSpawnId(), map))
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
delete wpCreature2;
wpCreature2 = NULL;
return false;
}
//sMapMgr->GetMap(npcCreature->GetMapId())->Add(wpCreature2);
}
stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_POSITION);
stmt->setFloat(0, chr->GetPositionX());
stmt->setFloat(1, chr->GetPositionY());
stmt->setFloat(2, chr->GetPositionZ());
stmt->setUInt32(3, pathid);
stmt->setUInt32(4, point);
WorldDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_WAYPOINT_CHANGED);
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
delete wpCreature;
return false;
}
wpCreature->CopyPhaseFrom(chr);
wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask());
// To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
/// @todo Should we first use "Create" then use "LoadFromDB"?
if (!wpCreature->LoadCreatureFromDB(wpCreature->GetSpawnId(), map))
{
handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
delete wpCreature;
return false;
}
stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_POSITION);
stmt->setFloat(0, chr->GetPositionX());
stmt->setFloat(1, chr->GetPositionY());
stmt->setFloat(2, chr->GetPositionZ());
stmt->setUInt32(3, pathid);
stmt->setUInt32(4, point);
WorldDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_WAYPOINT_CHANGED);
return true;
} // move
@@ -906,7 +885,7 @@ public:
// Set "wpguid" column to the visual waypoint
stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID);
stmt->setInt32(0, int32(wpCreature->GetGUID().GetCounter()));
stmt->setInt32(0, int32(wpCreature->GetSpawnId()));
stmt->setUInt32(1, pathid);
stmt->setUInt32(2, point);
WorldDatabase.Execute(stmt);
-18
View File
@@ -1,18 +0,0 @@
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# file(GLOB_RECURSE sources_Custom Custom/*.cpp Custom/*.h)
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
# ${sources_Custom}
)
message(" -> Prepared: Custom")
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// This is where scripts' loading functions should be declared:
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddCustomScripts()
{
}
@@ -508,19 +508,11 @@ public:
};
// npc_lokhtos_darkbargainer
enum LokhtosItems
enum Lokhtos
{
QUEST_A_BINDING_CONTRACT = 7604,
ITEM_SULFURON_INGOT = 17203,
ITEM_THRORIUM_BROTHERHOOD_CONTRACT = 18628,
ITEM_SULFURON_INGOT = 17203
};
enum LokhtosQuests
{
QUEST_A_BINDING_CONTRACT = 7604
};
enum LokhtosSpells
{
SPELL_CREATE_THORIUM_BROTHERHOOD_CONTRACT_DND = 23059
};
@@ -570,67 +562,12 @@ public:
}
};
// npc_dughal_stormwing
enum DughalQuests
{
QUEST_JAIL_BREAK = 4322
};
#define SAY_DUGHAL_FREE "Thank you, $N! I'm free!!!"
#define GOSSIP_DUGHAL "You're free, Dughal! Get out of here!"
// npc_marshal_windsor
#define SAY_WINDSOR_AGGRO1 "You locked up the wrong Marshal. Prepare to be destroyed!"
#define SAY_WINDSOR_AGGRO2 "I bet you're sorry now, aren't you !?!!"
#define SAY_WINDSOR_AGGRO3 "You better hold me back $N or they are going to feel some prison house beatings."
#define SAY_WINDSOR_1 "Let's get a move on. My gear should be in the storage area up this way..."
#define SAY_WINDSOR_4_1 "Check that cell, $N. If someone is alive in there, we need to get them out."
#define SAY_WINDSOR_4_2 "Get him out of there!"
#define SAY_WINDSOR_4_3 "Good work! We're almost there, $N. This way."
#define SAY_WINDSOR_6 "This is it, $N. My stuff should be in that room. Cover me, I'm going in!"
#define SAY_WINDSOR_9 "Ah, there it is!"
enum MarshalWindsor
{
NPC_REGINALD_WINDSOR = 9682
};
// npc_marshal_reginald_windsor
#define SAY_REGINALD_WINDSOR_0_1 "Can you feel the power, $N??? It's time to ROCK!"
#define SAY_REGINALD_WINDSOR_0_2 "Now we just have to free Tobias and we can get out of here. This way!"
#define SAY_REGINALD_WINDSOR_5_1 "Open it."
#define SAY_REGINALD_WINDSOR_5_2 "I never did like those two. Let's get moving."
#define SAY_REGINALD_WINDSOR_7_1 "Open it and be careful this time!"
#define SAY_REGINALD_WINDSOR_7_2 "That intolerant dirtbag finally got what was coming to him. Good riddance!"
#define SAY_REGINALD_WINDSOR_7_3 "Alright, let's go."
#define SAY_REGINALD_WINDSOR_13_1 "Open it. We need to hurry up. I can smell those Dark Irons coming a mile away and I can tell you one thing, they're COMING!"
#define SAY_REGINALD_WINDSOR_13_2 "Administering fists of fury on Crest Killer!"
#define SAY_REGINALD_WINDSOR_13_3 "He has to be in the last cell. Unless... they killed him."
#define SAY_REGINALD_WINDSOR_14_1 "Get him out of there!"
#define SAY_REGINALD_WINDSOR_14_2 "Excellent work, $N. Let's find the exit. I think I know the way. Follow me!"
#define SAY_REGINALD_WINDSOR_20_1 "We made it!"
#define SAY_REGINALD_WINDSOR_20_2 "Meet me at Maxwell's encampment. We'll go over the next stages of the plan there and figure out a way to decode my tablets without the decryption ring."
enum MarshalReginaldWindor
{
NPC_SHILL_DINGER = 9678,
NPC_CREST_KILLER = 9680
};
// npc_rocknot
enum RocknotSays
enum Rocknot
{
SAY_GOT_BEER = 0
};
enum RocknotSpells
{
SPELL_DRUNKEN_RAGE = 14872
};
enum RocknotQuests
{
QUEST_ALE = 4295
SAY_GOT_BEER = 0,
QUEST_ALE = 4295,
SPELL_DRUNKEN_RAGE = 14872
};
class npc_rocknot : public CreatureScript
@@ -1,212 +0,0 @@
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
set(scripts_STAT_SRCS
${scripts_STAT_SRCS}
EasternKingdoms/zone_ghostlands.cpp
EasternKingdoms/AlteracValley/boss_galvangar.cpp
EasternKingdoms/AlteracValley/boss_balinda.cpp
EasternKingdoms/AlteracValley/boss_drekthar.cpp
EasternKingdoms/AlteracValley/boss_vanndar.cpp
EasternKingdoms/AlteracValley/alterac_valley.cpp
EasternKingdoms/BaradinHold/boss_alizabal.cpp
EasternKingdoms/BaradinHold/boss_occuthar.cpp
EasternKingdoms/BaradinHold/boss_pit_lord_argaloth.cpp
EasternKingdoms/BaradinHold/instance_baradin_hold.cpp
EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_romogg_bonecrusher.cpp
EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_corla.cpp
EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_karsh_steelbender.cpp
EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_beauty.cpp
EasternKingdoms/BlackrockMountain/BlackrockCaverns/boss_ascendant_lord_obsidius.cpp
EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.cpp
EasternKingdoms/BlackrockMountain/BlackrockCaverns/instance_blackrock_caverns.cpp
EasternKingdoms/BlackrockMountain/BlackrockCaverns/blackrock_caverns.h
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_high_interrogator_gerstahn.cpp
EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.cpp
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_tomb_of_seven.cpp
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_general_angerforge.cpp
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_ambassador_flamelash.cpp
EasternKingdoms/BlackrockMountain/BlackrockDepths/instance_blackrock_depths.cpp
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_moira_bronzebeard.cpp
EasternKingdoms/BlackrockMountain/BlackrockDepths/blackrock_depths.h
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_emperor_dagran_thaurissan.cpp
EasternKingdoms/BlackrockMountain/BlackrockDepths/boss_magmus.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_chromaggus.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_razorgore.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_firemaw.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_broodlord_lashlayer.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_ebonroc.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/instance_blackwing_lair.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_vaelastrasz.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_nefarian.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/boss_flamegor.cpp
EasternKingdoms/BlackrockMountain/BlackwingLair/blackwing_lair.h
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_pyroguard_emberseer.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_drakkisath.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_warmaster_voone.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_mother_smolderweb.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_quartermaster_zigris.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_halycon.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_overlord_wyrmthalak.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_shadow_hunter_voshgajin.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gyth.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_rend_blackhand.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_highlord_omokk.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_the_beast.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_gizrul_the_slavener.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_urok_doomhowl.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/boss_lord_valthalak.cpp
EasternKingdoms/BlackrockMountain/BlackrockSpire/blackrock_spire.h
EasternKingdoms/BlackrockMountain/BlackrockSpire/instance_blackrock_spire.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_gehennas.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_lucifron.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_golemagg.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_majordomo_executus.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_baron_geddon.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_ragnaros.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_garr.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/molten_core.h
EasternKingdoms/BlackrockMountain/MoltenCore/instance_molten_core.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_sulfuron_harbinger.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_magmadar.cpp
EasternKingdoms/BlackrockMountain/MoltenCore/boss_shazzrah.cpp
EasternKingdoms/Scholomance/boss_the_ravenian.cpp
EasternKingdoms/Scholomance/boss_instructor_malicia.cpp
EasternKingdoms/Scholomance/boss_death_knight_darkreaver.cpp
EasternKingdoms/Scholomance/boss_illucia_barov.cpp
EasternKingdoms/Scholomance/scholomance.h
EasternKingdoms/Scholomance/boss_vectus.cpp
EasternKingdoms/Scholomance/boss_jandice_barov.cpp
EasternKingdoms/Scholomance/boss_kormok.cpp
EasternKingdoms/Scholomance/boss_lord_alexei_barov.cpp
EasternKingdoms/Scholomance/boss_doctor_theolen_krastinov.cpp
EasternKingdoms/Scholomance/boss_darkmaster_gandling.cpp
EasternKingdoms/Scholomance/instance_scholomance.cpp
EasternKingdoms/Scholomance/boss_lorekeeper_polkelt.cpp
EasternKingdoms/Scholomance/boss_ras_frostwhisper.cpp
EasternKingdoms/Scholomance/boss_kirtonos_the_herald.cpp
EasternKingdoms/zone_isle_of_queldanas.cpp
EasternKingdoms/ZulGurub/boss_grilek.cpp
EasternKingdoms/ZulGurub/boss_hazzarah.cpp
EasternKingdoms/ZulGurub/boss_jindo_the_godbreaker.cpp
EasternKingdoms/ZulGurub/boss_kilnara.cpp
EasternKingdoms/ZulGurub/boss_mandokir.cpp
EasternKingdoms/ZulGurub/boss_renataki.cpp
EasternKingdoms/ZulGurub/boss_venoxis.cpp
EasternKingdoms/ZulGurub/boss_wushoolay.cpp
EasternKingdoms/ZulGurub/boss_zanzil.cpp
EasternKingdoms/ZulGurub/instance_zulgurub.cpp
EasternKingdoms/ZulGurub/zulgurub.h
EasternKingdoms/zone_wetlands.cpp
EasternKingdoms/zone_arathi_highlands.cpp
EasternKingdoms/Gnomeregan/instance_gnomeregan.cpp
EasternKingdoms/Gnomeregan/gnomeregan.cpp
EasternKingdoms/Gnomeregan/gnomeregan.h
EasternKingdoms/zone_redridge_mountains.cpp
EasternKingdoms/ScarletEnclave/chapter2.cpp
EasternKingdoms/ScarletEnclave/chapter5.cpp
EasternKingdoms/ScarletEnclave/chapter1.cpp
EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp
EasternKingdoms/zone_eastern_plaguelands.cpp
EasternKingdoms/Stratholme/boss_baroness_anastari.cpp
EasternKingdoms/Stratholme/boss_nerubenkan.cpp
EasternKingdoms/Stratholme/instance_stratholme.cpp
EasternKingdoms/Stratholme/boss_dathrohan_balnazzar.cpp
EasternKingdoms/Stratholme/boss_timmy_the_cruel.cpp
EasternKingdoms/Stratholme/boss_baron_rivendare.cpp
EasternKingdoms/Stratholme/boss_magistrate_barthilas.cpp
EasternKingdoms/Stratholme/boss_order_of_silver_hand.cpp
EasternKingdoms/Stratholme/boss_ramstein_the_gorger.cpp
EasternKingdoms/Stratholme/boss_cannon_master_willey.cpp
EasternKingdoms/Stratholme/boss_maleki_the_pallid.cpp
EasternKingdoms/Stratholme/boss_postmaster_malown.cpp
EasternKingdoms/Stratholme/stratholme.h
EasternKingdoms/Stratholme/stratholme.cpp
EasternKingdoms/zone_tirisfal_glades.cpp
EasternKingdoms/SunkenTemple/sunken_temple.cpp
EasternKingdoms/SunkenTemple/sunken_temple.h
EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp
EasternKingdoms/MagistersTerrace/boss_felblood_kaelthas.cpp
EasternKingdoms/MagistersTerrace/magisters_terrace.h
EasternKingdoms/MagistersTerrace/boss_priestess_delrissa.cpp
EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp
EasternKingdoms/MagistersTerrace/boss_selin_fireheart.cpp
EasternKingdoms/MagistersTerrace/boss_vexallus.cpp
EasternKingdoms/MagistersTerrace/magisters_terrace.cpp
EasternKingdoms/Uldaman/uldaman.cpp
EasternKingdoms/Uldaman/boss_ironaya.cpp
EasternKingdoms/Uldaman/uldaman.h
EasternKingdoms/Uldaman/instance_uldaman.cpp
EasternKingdoms/Uldaman/boss_archaedas.cpp
EasternKingdoms/zone_swamp_of_sorrows.cpp
EasternKingdoms/SunwellPlateau/boss_eredar_twins.cpp
EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp
EasternKingdoms/SunwellPlateau/sunwell_plateau.h
EasternKingdoms/SunwellPlateau/boss_muru.cpp
EasternKingdoms/SunwellPlateau/instance_sunwell_plateau.cpp
EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp
EasternKingdoms/SunwellPlateau/boss_brutallus.cpp
EasternKingdoms/SunwellPlateau/sunwell_plateau.cpp
EasternKingdoms/SunwellPlateau/boss_felmyst.cpp
EasternKingdoms/zone_stranglethorn_vale.cpp
EasternKingdoms/Deadmines/deadmines.h
EasternKingdoms/Deadmines/deadmines.cpp
EasternKingdoms/Deadmines/boss_mr_smite.cpp
EasternKingdoms/Deadmines/instance_deadmines.cpp
EasternKingdoms/zone_duskwood.cpp
EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp
EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp
EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp
EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp
EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp
EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp
EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp
EasternKingdoms/ScarletMonastery/scarlet_monastery.h
EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp
EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp
EasternKingdoms/ScarletMonastery/boss_herod.cpp
EasternKingdoms/ScarletMonastery/boss_scorn.cpp
EasternKingdoms/zone_undercity.cpp
EasternKingdoms/zone_loch_modan.cpp
EasternKingdoms/ShadowfangKeep/shadowfang_keep.cpp
EasternKingdoms/ShadowfangKeep/instance_shadowfang_keep.cpp
EasternKingdoms/ShadowfangKeep/shadowfang_keep.h
EasternKingdoms/zone_burning_steppes.cpp
EasternKingdoms/zone_blasted_lands.cpp
EasternKingdoms/zone_stormwind_city.cpp
EasternKingdoms/ZulAman/boss_halazzi.cpp
EasternKingdoms/ZulAman/boss_hexlord.cpp
EasternKingdoms/ZulAman/boss_daakara.cpp
EasternKingdoms/ZulAman/boss_akilzon.cpp
EasternKingdoms/ZulAman/instance_zulaman.cpp
EasternKingdoms/ZulAman/boss_janalai.cpp
EasternKingdoms/ZulAman/boss_nalorakk.cpp
EasternKingdoms/ZulAman/zulaman.cpp
EasternKingdoms/ZulAman/zulaman.h
EasternKingdoms/zone_hinterlands.cpp
EasternKingdoms/zone_western_plaguelands.cpp
EasternKingdoms/zone_silverpine_forest.cpp
EasternKingdoms/Karazhan/instance_karazhan.cpp
EasternKingdoms/Karazhan/boss_nightbane.cpp
EasternKingdoms/Karazhan/karazhan.cpp
EasternKingdoms/Karazhan/boss_curator.cpp
EasternKingdoms/Karazhan/boss_shade_of_aran.cpp
EasternKingdoms/Karazhan/boss_netherspite.cpp
EasternKingdoms/Karazhan/boss_maiden_of_virtue.cpp
EasternKingdoms/Karazhan/boss_midnight.cpp
EasternKingdoms/Karazhan/boss_prince_malchezaar.cpp
EasternKingdoms/Karazhan/bosses_opera.cpp
EasternKingdoms/Karazhan/boss_moroes.cpp
EasternKingdoms/Karazhan/boss_terestian_illhoof.cpp
EasternKingdoms/Karazhan/karazhan.h
EasternKingdoms/TheStockade/instance_the_stockade.cpp
)
message(" -> Prepared: Eastern Kingdoms")
@@ -59,6 +59,7 @@ class instance_deadmines : public InstanceMapScript
State = CANNON_NOT_USED;
CannonBlast_Timer = 0;
PiratesDelay_Timer = 0;
SmiteAlarmDelay_Timer = 0;
}
ObjectGuid FactoryDoorGUID;
@@ -50,19 +50,9 @@ class boss_maiden_of_virtue : public CreatureScript
public:
boss_maiden_of_virtue() : CreatureScript("boss_maiden_of_virtue") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new boss_maiden_of_virtueAI(creature);
}
struct boss_maiden_of_virtueAI : public BossAI
{
boss_maiden_of_virtueAI(Creature* creature) : BossAI(creature, TYPE_MAIDEN) { }
void Reset() override
{
_Reset();
}
boss_maiden_of_virtueAI(Creature* creature) : BossAI(creature, DATA_MAIDEN_OF_VIRTUE) { }
void KilledUnit(Unit* /*Victim*/) override
{
@@ -132,6 +122,11 @@ public:
DoMeleeAttackIfReady();
}
};
CreatureAI* GetAI(Creature* creature) const override
{
return new boss_maiden_of_virtueAI(creature);
}
};
void AddSC_boss_maiden_of_virtue()
@@ -26,6 +26,7 @@ EndScriptData */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellInfo.h"
#include "karazhan.h"
enum Midnight
{
@@ -109,6 +110,9 @@ public:
Talk(SAY_DEATH);
if (Unit* midnight = ObjectAccessor::GetUnit(*me, Midnight))
midnight->KillSelf();
if (InstanceScript* instance = me->GetInstanceScript())
instance->SetBossState(DATA_ATTUMEN, DONE);
}
void UpdateAI(uint32 diff) override;
@@ -157,7 +161,11 @@ public:
me->SetVisible(true);
}
void EnterCombat(Unit* /*who*/) override { }
void EnterCombat(Unit* /*who*/) override
{
if (InstanceScript* instance = me->GetInstanceScript())
instance->SetBossState(DATA_ATTUMEN, IN_PROGRESS);
}
void KilledUnit(Unit* /*victim*/) override
{
@@ -143,12 +143,12 @@ public:
if (me->IsAlive())
SpawnAdds();
instance->SetData(TYPE_MOROES, NOT_STARTED);
instance->SetBossState(DATA_MOROES, NOT_STARTED);
}
void StartEvent()
{
instance->SetData(TYPE_MOROES, IN_PROGRESS);
instance->SetBossState(DATA_MOROES, IN_PROGRESS);
DoZoneInCombat();
}
@@ -171,7 +171,7 @@ public:
{
Talk(SAY_DEATH);
instance->SetData(TYPE_MOROES, DONE);
instance->SetBossState(DATA_MOROES, DONE);
DeSpawnAdds();
@@ -257,12 +257,6 @@ public:
if (!UpdateVictim())
return;
if (!instance->GetData(TYPE_MOROES))
{
EnterEvadeMode();
return;
}
if (!Enrage && HealthBelowPct(30))
{
DoCast(me, SPELL_FRENZY);
@@ -347,7 +341,7 @@ struct boss_moroes_guestAI : public ScriptedAI
void Reset() override
{
instance->SetData(TYPE_MOROES, NOT_STARTED);
instance->SetBossState(DATA_MOROES, NOT_STARTED);
}
void AcquireGUID()
@@ -373,7 +367,7 @@ struct boss_moroes_guestAI : public ScriptedAI
void UpdateAI(uint32 /*diff*/) override
{
if (!instance->GetData(TYPE_MOROES))
if (instance->GetBossState(DATA_MOROES) != IN_PROGRESS)
EnterEvadeMode();
DoMeleeAttackIfReady();
@@ -143,10 +143,10 @@ public:
me->SetWalk(false);
me->setActive(true);
if (instance->GetData(TYPE_NIGHTBANE) == DONE || instance->GetData(TYPE_NIGHTBANE) == IN_PROGRESS)
if (instance->GetBossState(DATA_NIGHTBANE) == DONE || instance->GetBossState(DATA_NIGHTBANE) == IN_PROGRESS)
me->DisappearAndDie();
else
instance->SetData(TYPE_NIGHTBANE, NOT_STARTED);
instance->SetBossState(DATA_NIGHTBANE, NOT_STARTED);
HandleTerraceDoors(true);
@@ -165,10 +165,10 @@ public:
void EnterCombat(Unit* /*who*/) override
{
instance->SetData(TYPE_NIGHTBANE, IN_PROGRESS);
instance->SetBossState(DATA_NIGHTBANE, IN_PROGRESS);
HandleTerraceDoors(false);
Talk(YELL_AGGRO);
Talk(YELL_AGGRO);
}
void AttackStart(Unit* who) override
@@ -179,7 +179,7 @@ public:
void JustDied(Unit* /*killer*/) override
{
instance->SetData(TYPE_NIGHTBANE, DONE);
instance->SetBossState(DATA_NIGHTBANE, DONE);
HandleTerraceDoors(true);
}
@@ -154,7 +154,7 @@ public:
Initialize();
// Not in progress
instance->SetData(TYPE_ARAN, NOT_STARTED);
instance->SetBossState(DATA_ARAN, NOT_STARTED);
instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), true);
}
@@ -167,7 +167,7 @@ public:
{
Talk(SAY_DEATH);
instance->SetData(TYPE_ARAN, DONE);
instance->SetBossState(DATA_ARAN, DONE);
instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), true);
}
@@ -175,7 +175,7 @@ public:
{
Talk(SAY_AGGRO);
instance->SetData(TYPE_ARAN, IN_PROGRESS);
instance->SetBossState(DATA_ARAN, IN_PROGRESS);
instance->HandleGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR), false);
}
@@ -61,7 +61,6 @@ enum Creatures
NPC_DEMONCHAINS = 17248,
NPC_FIENDISHIMP = 17267,
NPC_PORTAL = 17265,
NPC_KILREK = 17229
};
class npc_kilrek : public CreatureScript
@@ -315,7 +314,7 @@ public:
Initialize();
instance->SetData(TYPE_TERESTIAN, NOT_STARTED);
instance->SetBossState(DATA_TERESTIAN, NOT_STARTED);
me->RemoveAurasDueToSpell(SPELL_BROKEN_PACT);
@@ -370,7 +369,7 @@ public:
Talk(SAY_DEATH);
instance->SetData(TYPE_TERESTIAN, DONE);
instance->SetBossState(DATA_TERESTIAN, DONE);
}
void UpdateAI(uint32 diff) override
Loaded 100 of 143 files, more files were not shown because too many files have changed in this diff. Show more