server/src/game/World.cpp
VladimirMangos e219ee99bb [10688] New version of patch for send real diff from last update.
In new version last update time stopred for specific Cell that store all world objects
placed in it. All objects of Cell updated (or not updated) in same time.

Original version provided by ciphercom.
2010-11-06 22:59:54 +03:00

2286 lines
93 KiB
C++

/*
* Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** \file
\ingroup world
*/
#include "World.h"
#include "Database/DatabaseEnv.h"
#include "Config/Config.h"
#include "SystemConfig.h"
#include "Log.h"
#include "Opcodes.h"
#include "WorldSession.h"
#include "WorldPacket.h"
#include "Weather.h"
#include "Player.h"
#include "Vehicle.h"
#include "SkillExtraItems.h"
#include "SkillDiscovery.h"
#include "AccountMgr.h"
#include "AchievementMgr.h"
#include "AuctionHouseMgr.h"
#include "ObjectMgr.h"
#include "CreatureEventAIMgr.h"
#include "SpellMgr.h"
#include "Chat.h"
#include "DBCStores.h"
#include "LootMgr.h"
#include "ItemEnchantmentMgr.h"
#include "MapManager.h"
#include "ScriptCalls.h"
#include "CreatureAIRegistry.h"
#include "Policies/SingletonImp.h"
#include "BattleGroundMgr.h"
#include "TemporarySummon.h"
#include "VMapFactory.h"
#include "GameEventMgr.h"
#include "PoolManager.h"
#include "Database/DatabaseImpl.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "InstanceSaveMgr.h"
#include "WaypointManager.h"
#include "GMTicketMgr.h"
#include "Util.h"
#include "CharacterDatabaseCleaner.h"
INSTANTIATE_SINGLETON_1( World );
volatile bool World::m_stopEvent = false;
uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE;
volatile uint32 World::m_worldLoopCounter = 0;
float World::m_MaxVisibleDistanceOnContinents = DEFAULT_VISIBILITY_DISTANCE;
float World::m_MaxVisibleDistanceInInstances = DEFAULT_VISIBILITY_INSTANCE;
float World::m_MaxVisibleDistanceInBGArenas = DEFAULT_VISIBILITY_BGARENAS;
float World::m_MaxVisibleDistanceForObject = DEFAULT_VISIBILITY_DISTANCE;
float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
float World::m_VisibleUnitGreyDistance = 0;
float World::m_VisibleObjectGreyDistance = 0;
/// World constructor
World::World()
{
m_playerLimit = 0;
m_allowMovement = true;
m_ShutdownMask = 0;
m_ShutdownTimer = 0;
m_gameTime=time(NULL);
m_startTime=m_gameTime;
m_maxActiveSessionCount = 0;
m_maxQueuedSessionCount = 0;
m_resultQueue = NULL;
m_NextDailyQuestReset = 0;
m_NextWeeklyQuestReset = 0;
m_scheduledScripts = 0;
m_defaultDbcLocale = LOCALE_enUS;
m_availableDbcLocaleMask = 0;
for(int i = 0; i < CONFIG_UINT32_VALUE_COUNT; ++i)
m_configUint32Values[i] = 0;
for(int i = 0; i < CONFIG_INT32_VALUE_COUNT; ++i)
m_configInt32Values[i] = 0;
for(int i = 0; i < CONFIG_FLOAT_VALUE_COUNT; ++i)
m_configFloatValues[i] = 0.0f;
for(int i = 0; i < CONFIG_BOOL_VALUE_COUNT; ++i)
m_configBoolValues[i] = false;
}
/// World destructor
World::~World()
{
///- Empty the kicked session set
while (!m_sessions.empty())
{
// not remove from queue, prevent loading new sessions
delete m_sessions.begin()->second;
m_sessions.erase(m_sessions.begin());
}
///- Empty the WeatherMap
for (WeatherMap::const_iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr)
delete itr->second;
m_weathers.clear();
CliCommandHolder* command;
while (cliCmdQueue.next(command))
delete command;
VMAP::VMapFactory::clear();
if(m_resultQueue) delete m_resultQueue;
//TODO free addSessQueue
}
/// Find a player in a specified zone
Player* World::FindPlayerInZone(uint32 zone)
{
///- circle through active sessions and return the first player found in the zone
SessionMap::const_iterator itr;
for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if(!itr->second)
continue;
Player *player = itr->second->GetPlayer();
if(!player)
continue;
if( player->IsInWorld() && player->GetZoneId() == zone )
{
// Used by the weather system. We return the player to broadcast the change weather message to him and all players in the zone.
return player;
}
}
return NULL;
}
/// Find a session by its id
WorldSession* World::FindSession(uint32 id) const
{
SessionMap::const_iterator itr = m_sessions.find(id);
if(itr != m_sessions.end())
return itr->second; // also can return NULL for kicked session
else
return NULL;
}
/// Remove a given session
bool World::RemoveSession(uint32 id)
{
///- Find the session, kick the user, but we can't delete session at this moment to prevent iterator invalidation
SessionMap::const_iterator itr = m_sessions.find(id);
if(itr != m_sessions.end() && itr->second)
{
if (itr->second->PlayerLoading())
return false;
itr->second->KickPlayer();
}
return true;
}
void World::AddSession(WorldSession* s)
{
addSessQueue.add(s);
}
void
World::AddSession_ (WorldSession* s)
{
MANGOS_ASSERT (s);
//NOTE - Still there is race condition in WorldSession* being used in the Sockets
///- kick already loaded player with same account (if any) and remove session
///- if player is in loading and want to load again, return
if (!RemoveSession (s->GetAccountId ()))
{
s->KickPlayer ();
delete s; // session not added yet in session list, so not listed in queue
return;
}
// decrease session counts only at not reconnection case
bool decrease_session = true;
// if session already exist, prepare to it deleting at next world update
// NOTE - KickPlayer() should be called on "old" in RemoveSession()
{
SessionMap::const_iterator old = m_sessions.find(s->GetAccountId ());
if(old != m_sessions.end())
{
// prevent decrease sessions count if session queued
if(RemoveQueuedPlayer(old->second))
decrease_session = false;
// not remove replaced session form queue if listed
delete old->second;
}
}
m_sessions[s->GetAccountId ()] = s;
uint32 Sessions = GetActiveAndQueuedSessionCount ();
uint32 pLimit = GetPlayerAmountLimit ();
uint32 QueueSize = GetQueueSize (); //number of players in the queue
//so we don't count the user trying to
//login as a session and queue the socket that we are using
if(decrease_session)
--Sessions;
if (pLimit > 0 && Sessions >= pLimit && s->GetSecurity () == SEC_PLAYER )
{
AddQueuedPlayer (s);
UpdateMaxSessionCounters ();
DETAIL_LOG("PlayerQueue: Account id %u is in Queue Position (%u).", s->GetAccountId (), ++QueueSize);
return;
}
WorldPacket packet(SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1);
packet << uint8 (AUTH_OK);
packet << uint32 (0); // BillingTimeRemaining
packet << uint8 (0); // BillingPlanFlags
packet << uint32 (0); // BillingTimeRested
packet << uint8 (s->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
s->SendPacket (&packet);
s->SendAddonsInfo();
WorldPacket pkt(SMSG_CLIENTCACHE_VERSION, 4);
pkt << uint32(getConfig(CONFIG_UINT32_CLIENTCACHE_VERSION));
s->SendPacket(&pkt);
s->SendTutorialsData();
UpdateMaxSessionCounters ();
// Updates the population
if (pLimit > 0)
{
float popu = float(GetActiveSessionCount()); // updated number of users on the server
popu /= pLimit;
popu *= 2;
LoginDatabase.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu, realmID);
DETAIL_LOG("Server Population (%f).", popu);
}
}
int32 World::GetQueuePos(WorldSession* sess)
{
uint32 position = 1;
for(Queue::const_iterator iter = m_QueuedPlayer.begin(); iter != m_QueuedPlayer.end(); ++iter, ++position)
if((*iter) == sess)
return position;
return 0;
}
void World::AddQueuedPlayer(WorldSession* sess)
{
sess->SetInQueue(true);
m_QueuedPlayer.push_back (sess);
// The 1st SMSG_AUTH_RESPONSE needs to contain other info too.
WorldPacket packet (SMSG_AUTH_RESPONSE, 1 + 4 + 1 + 4 + 1 + 4 + 1);
packet << uint8 (AUTH_WAIT_QUEUE);
packet << uint32 (0); // BillingTimeRemaining
packet << uint8 (0); // BillingPlanFlags
packet << uint32 (0); // BillingTimeRested
packet << uint8 (sess->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
packet << uint32(GetQueuePos (sess)); // position in queue
packet << uint8(0); // unk 3.3.0
sess->SendPacket (&packet);
}
bool World::RemoveQueuedPlayer(WorldSession* sess)
{
// sessions count including queued to remove (if removed_session set)
uint32 sessions = GetActiveSessionCount();
uint32 position = 1;
Queue::iterator iter = m_QueuedPlayer.begin();
// search to remove and count skipped positions
bool found = false;
for(;iter != m_QueuedPlayer.end(); ++iter, ++position)
{
if(*iter==sess)
{
sess->SetInQueue(false);
iter = m_QueuedPlayer.erase(iter);
found = true; // removing queued session
break;
}
}
// iter point to next socked after removed or end()
// position store position of removed socket and then new position next socket after removed
// if session not queued then we need decrease sessions count
if(!found && sessions)
--sessions;
// accept first in queue
if( (!m_playerLimit || (int32)sessions < m_playerLimit) && !m_QueuedPlayer.empty() )
{
WorldSession* pop_sess = m_QueuedPlayer.front();
pop_sess->SetInQueue(false);
pop_sess->SendAuthWaitQue(0);
pop_sess->SendAddonsInfo();
WorldPacket pkt(SMSG_CLIENTCACHE_VERSION, 4);
pkt << uint32(getConfig(CONFIG_UINT32_CLIENTCACHE_VERSION));
pop_sess->SendPacket(&pkt);
pop_sess->SendAccountDataTimes(GLOBAL_CACHE_MASK);
pop_sess->SendTutorialsData();
m_QueuedPlayer.pop_front();
// update iter to point first queued socket or end() if queue is empty now
iter = m_QueuedPlayer.begin();
position = 1;
}
// update position from iter to end()
// iter point to first not updated socket, position store new position
for(; iter != m_QueuedPlayer.end(); ++iter, ++position)
(*iter)->SendAuthWaitQue(position);
return found;
}
/// Find a Weather object by the given zoneid
Weather* World::FindWeather(uint32 id) const
{
WeatherMap::const_iterator itr = m_weathers.find(id);
if(itr != m_weathers.end())
return itr->second;
else
return 0;
}
/// Remove a Weather object for the given zoneid
void World::RemoveWeather(uint32 id)
{
// not called at the moment. Kept for completeness
WeatherMap::iterator itr = m_weathers.find(id);
if(itr != m_weathers.end())
{
delete itr->second;
m_weathers.erase(itr);
}
}
/// Add a Weather object to the list
Weather* World::AddWeather(uint32 zone_id)
{
WeatherZoneChances const* weatherChances = sObjectMgr.GetWeatherChances(zone_id);
// zone not have weather, ignore
if(!weatherChances)
return NULL;
Weather* w = new Weather(zone_id,weatherChances);
m_weathers[w->GetZone()] = w;
w->ReGenerate();
w->UpdateWeather();
return w;
}
/// Initialize config values
void World::LoadConfigSettings(bool reload)
{
if (reload)
{
if (!sConfig.Reload())
{
sLog.outError("World settings reload fail: can't read settings from %s.",sConfig.GetFilename().c_str());
return;
}
}
///- Read the version of the configuration file and warn the user in case of emptiness or mismatch
uint32 confVersion = sConfig.GetIntDefault("ConfVersion", 0);
if (!confVersion)
{
sLog.outError("*****************************************************************************");
sLog.outError(" WARNING: mangosd.conf does not include a ConfVersion variable.");
sLog.outError(" Your configuration file may be out of date!");
sLog.outError("*****************************************************************************");
Log::WaitBeforeContinueIfNeed();
}
else
{
if (confVersion < _MANGOSDCONFVERSION)
{
sLog.outError("*****************************************************************************");
sLog.outError(" WARNING: Your mangosd.conf version indicates your conf file is out of date!");
sLog.outError(" Please check for updates, as your current default values may cause");
sLog.outError(" unexpected behavior.");
sLog.outError("*****************************************************************************");
Log::WaitBeforeContinueIfNeed();
}
}
///- Read the player limit and the Message of the day from the config file
SetPlayerLimit( sConfig.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT), true );
SetMotd( sConfig.GetStringDefault("Motd", "Welcome to the Massive Network Game Object Server." ) );
///- Read all rates from the config file
setConfigPos(CONFIG_FLOAT_RATE_HEALTH, "Rate.Health", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_POWER_MANA, "Rate.Mana", 1.0f);
setConfig(CONFIG_FLOAT_RATE_POWER_RAGE_INCOME, "Rate.Rage.Income", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_POWER_RAGE_LOSS, "Rate.Rage.Loss", 1.0f);
setConfig(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_INCOME, "Rate.RunicPower.Income", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_LOSS,"Rate.RunicPower.Loss", 1.0f);
setConfig(CONFIG_FLOAT_RATE_POWER_FOCUS, "Rate.Focus", 1.0f);
setConfig(CONFIG_FLOAT_RATE_POWER_ENERGY, "Rate.Energy", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_SKILL_DISCOVERY, "Rate.Skill.Discovery", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_POOR, "Rate.Drop.Item.Poor", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_NORMAL, "Rate.Drop.Item.Normal", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_UNCOMMON, "Rate.Drop.Item.Uncommon", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_RARE, "Rate.Drop.Item.Rare", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_EPIC, "Rate.Drop.Item.Epic", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY, "Rate.Drop.Item.Legendary", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT, "Rate.Drop.Item.Artifact", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED, "Rate.Drop.Item.Referenced", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY, "Rate.Drop.Money", 1.0f);
setConfig(CONFIG_FLOAT_RATE_XP_KILL, "Rate.XP.Kill", 1.0f);
setConfig(CONFIG_FLOAT_RATE_XP_QUEST, "Rate.XP.Quest", 1.0f);
setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE, "Rate.XP.Explore", 1.0f);
setConfig(CONFIG_FLOAT_RATE_REPUTATION_GAIN, "Rate.Reputation.Gain", 1.0f);
setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_KILL, "Rate.Reputation.LowLevel.Kill", 1.0f);
setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_QUEST, "Rate.Reputation.LowLevel.Quest", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_DAMAGE, "Rate.Creature.Normal.Damage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_DAMAGE, "Rate.Creature.Elite.Elite.Damage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_DAMAGE, "Rate.Creature.Elite.RAREELITE.Damage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE, "Rate.Creature.Elite.WORLDBOSS.Damage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_DAMAGE, "Rate.Creature.Elite.RARE.Damage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_HP, "Rate.Creature.Normal.HP", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_HP, "Rate.Creature.Elite.Elite.HP", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_HP, "Rate.Creature.Elite.RAREELITE.HP", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_HP, "Rate.Creature.Elite.WORLDBOSS.HP", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_HP, "Rate.Creature.Elite.RARE.HP", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_SPELLDAMAGE, "Rate.Creature.Normal.SpellDamage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE, "Rate.Creature.Elite.Elite.SpellDamage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE, "Rate.Creature.Elite.RAREELITE.SpellDamage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE, "Rate.Creature.Elite.WORLDBOSS.SpellDamage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_SPELLDAMAGE, "Rate.Creature.Elite.RARE.SpellDamage", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CREATURE_AGGRO, "Rate.Creature.Aggro", 1.0f);
setConfig(CONFIG_FLOAT_RATE_REST_INGAME, "Rate.Rest.InGame", 1.0f);
setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_TAVERN_OR_CITY, "Rate.Rest.Offline.InTavernOrCity", 1.0f);
setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_WILDERNESS, "Rate.Rest.Offline.InWilderness", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_DAMAGE_FALL, "Rate.Damage.Fall", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_AUCTION_TIME, "Rate.Auction.Time", 1.0f);
setConfig(CONFIG_FLOAT_RATE_AUCTION_DEPOSIT, "Rate.Auction.Deposit", 1.0f);
setConfig(CONFIG_FLOAT_RATE_AUCTION_CUT, "Rate.Auction.Cut", 1.0f);
setConfigPos(CONFIG_UINT32_AUCTION_DEPOSIT_MIN, "Auction.Deposit.Min", SILVER);
setConfig(CONFIG_FLOAT_RATE_HONOR, "Rate.Honor",1.0f);
setConfigPos(CONFIG_FLOAT_RATE_MINING_AMOUNT, "Rate.Mining.Amount", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_MINING_NEXT, "Rate.Mining.Next", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_INSTANCE_RESET_TIME, "Rate.InstanceResetTime", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_TALENT, "Rate.Talent", 1.0f);
setConfigPos(CONFIG_FLOAT_RATE_CORPSE_DECAY_LOOTED, "Rate.Corpse.Decay.Looted", 0.0f);
setConfigMinMax(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE, "TargetPosRecalculateRange", 1.5f, CONTACT_DISTANCE, ATTACK_DISTANCE);
setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE, "DurabilityLossChance.Damage", 0.5f);
setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_ABSORB, "DurabilityLossChance.Absorb", 0.5f);
setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_PARRY, "DurabilityLossChance.Parry", 0.05f);
setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_BLOCK, "DurabilityLossChance.Block", 0.05f);
setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_SAY, "ListenRange.Say", 25.0f);
setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_YELL, "ListenRange.Yell", 300.0f);
setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE, "ListenRange.TextEmote", 25.0f);
setConfigPos(CONFIG_FLOAT_GROUP_XP_DISTANCE, "MaxGroupXPDistance", 74.0f);
setConfigPos(CONFIG_FLOAT_SIGHT_GUARDER, "GuarderSight", 50.0f);
setConfigPos(CONFIG_FLOAT_SIGHT_MONSTER, "MonsterSight", 50.0f);
setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS, "CreatureFamilyAssistanceRadius", 10.0f);
setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS, "CreatureFamilyFleeAssistanceRadius", 30.0f);
///- Read other configuration items from the config file
setConfigMinMax(CONFIG_UINT32_COMPRESSION, "Compression", 1, 1, 9);
setConfig(CONFIG_BOOL_ADDON_CHANNEL, "AddonChannel", true);
setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB, "CleanCharacterDB", true);
setConfig(CONFIG_BOOL_GRID_UNLOAD, "GridUnload", true);
setConfigPos(CONFIG_UINT32_INTERVAL_SAVE, "PlayerSave.Interval", 15 * MINUTE * IN_MILLISECONDS);
setConfigMinMax(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE, "PlayerSave.Stats.MinLevel", 0, 0, MAX_LEVEL);
setConfig(CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT, "PlayerSave.Stats.SaveOnlyOnLogout", true);
setConfigMin(CONFIG_UINT32_INTERVAL_GRIDCLEAN, "GridCleanUpDelay", 5 * MINUTE * IN_MILLISECONDS, MIN_GRID_DELAY);
if (reload)
sMapMgr.SetGridCleanUpDelay(getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN));
setConfigMin(CONFIG_UINT32_INTERVAL_MAPUPDATE, "MapUpdateInterval", 100, MIN_MAP_UPDATE_DELAY);
if (reload)
sMapMgr.SetMapUpdateInterval(getConfig(CONFIG_UINT32_INTERVAL_MAPUPDATE));
setConfig(CONFIG_UINT32_INTERVAL_CHANGEWEATHER, "ChangeWeatherInterval", 10 * MINUTE * IN_MILLISECONDS);
if (configNoReload(reload, CONFIG_UINT32_PORT_WORLD, "WorldServerPort", DEFAULT_WORLDSERVER_PORT))
setConfig(CONFIG_UINT32_PORT_WORLD, "WorldServerPort", DEFAULT_WORLDSERVER_PORT);
if (configNoReload(reload, CONFIG_UINT32_SOCKET_SELECTTIME, "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME))
setConfig(CONFIG_UINT32_SOCKET_SELECTTIME, "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME);
if (configNoReload(reload, CONFIG_UINT32_GAME_TYPE, "GameType", 0))
setConfig(CONFIG_UINT32_GAME_TYPE, "GameType", 0);
if (configNoReload(reload, CONFIG_UINT32_REALM_ZONE, "RealmZone", REALM_ZONE_DEVELOPMENT))
setConfig(CONFIG_UINT32_REALM_ZONE, "RealmZone", REALM_ZONE_DEVELOPMENT);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ACCOUNTS, "AllowTwoSide.Accounts", true);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT, "AllowTwoSide.Interaction.Chat", false);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL, "AllowTwoSide.Interaction.Channel", false);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GROUP, "AllowTwoSide.Interaction.Group", false);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GUILD, "AllowTwoSide.Interaction.Guild", false);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_AUCTION, "AllowTwoSide.Interaction.Auction", false);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL, "AllowTwoSide.Interaction.Mail", false);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST, "AllowTwoSide.WhoList", false);
setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ADD_FRIEND, "AllowTwoSide.AddFriend", false);
setConfig(CONFIG_UINT32_STRICT_PLAYER_NAMES, "StrictPlayerNames", 0);
setConfig(CONFIG_UINT32_STRICT_CHARTER_NAMES, "StrictCharterNames", 0);
setConfig(CONFIG_UINT32_STRICT_PET_NAMES, "StrictPetNames", 0);
setConfigMinMax(CONFIG_UINT32_MIN_PLAYER_NAME, "MinPlayerName", 2, 1, MAX_PLAYER_NAME);
setConfigMinMax(CONFIG_UINT32_MIN_CHARTER_NAME, "MinCharterName", 2, 1, MAX_CHARTER_NAME);
setConfigMinMax(CONFIG_UINT32_MIN_PET_NAME, "MinPetName", 2, 1, MAX_PET_NAME);
setConfig(CONFIG_UINT32_CHARACTERS_CREATING_DISABLED, "CharactersCreatingDisabled", 0);
setConfigMinMax(CONFIG_UINT32_CHARACTERS_PER_REALM, "CharactersPerRealm", 10, 1, 10);
// must be after CONFIG_UINT32_CHARACTERS_PER_REALM
setConfigMin(CONFIG_UINT32_CHARACTERS_PER_ACCOUNT, "CharactersPerAccount", 50, getConfig(CONFIG_UINT32_CHARACTERS_PER_REALM));
setConfigMinMax(CONFIG_UINT32_HEROIC_CHARACTERS_PER_REALM, "HeroicCharactersPerRealm", 1, 1, 10);
setConfig(CONFIG_UINT32_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING, "MinLevelForHeroicCharacterCreating", 55);
setConfigMinMax(CONFIG_UINT32_SKIP_CINEMATICS, "SkipCinematics", 0, 0, 2);
if (configNoReload(reload, CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL))
setConfigMinMax(CONFIG_UINT32_MAX_PLAYER_LEVEL, "MaxPlayerLevel", DEFAULT_MAX_LEVEL, 1, DEFAULT_MAX_LEVEL);
setConfigMinMax(CONFIG_UINT32_START_PLAYER_LEVEL, "StartPlayerLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
setConfigMinMax(CONFIG_UINT32_START_HEROIC_PLAYER_LEVEL, "StartHeroicPlayerLevel", 55, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
setConfigMinMax(CONFIG_UINT32_START_PLAYER_MONEY, "StartPlayerMoney", 0, 0, MAX_MONEY_AMOUNT);
setConfigPos(CONFIG_UINT32_MAX_HONOR_POINTS, "MaxHonorPoints", 75000);
setConfigMinMax(CONFIG_UINT32_START_HONOR_POINTS, "StartHonorPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_HONOR_POINTS));
setConfigPos(CONFIG_UINT32_MAX_ARENA_POINTS, "MaxArenaPoints", 5000);
setConfigMinMax(CONFIG_UINT32_START_ARENA_POINTS, "StartArenaPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_ARENA_POINTS));
setConfig(CONFIG_BOOL_ALL_TAXI_PATHS, "AllFlightPaths", false);
setConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL, "Instance.IgnoreLevel", false);
setConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID, "Instance.IgnoreRaid", false);
setConfig(CONFIG_BOOL_CAST_UNSTUCK, "CastUnstuck", true);
setConfig(CONFIG_UINT32_MAX_SPELL_CASTS_IN_CHAIN, "MaxSpellCastsInChain", 10);
setConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR, "Instance.ResetTimeHour", 4);
setConfig(CONFIG_UINT32_INSTANCE_UNLOAD_DELAY, "Instance.UnloadDelay", 30 * MINUTE * IN_MILLISECONDS);
setConfig(CONFIG_UINT32_MAX_PRIMARY_TRADE_SKILL, "MaxPrimaryTradeSkill", 2);
setConfigMinMax(CONFIG_UINT32_MIN_PETITION_SIGNS, "MinPetitionSigns", 9, 0, 9);
setConfig(CONFIG_UINT32_GM_LOGIN_STATE, "GM.LoginState", 2);
setConfig(CONFIG_UINT32_GM_VISIBLE_STATE, "GM.Visible", 2);
setConfig(CONFIG_UINT32_GM_ACCEPT_TICKETS, "GM.AcceptTickets", 2);
setConfig(CONFIG_UINT32_GM_CHAT, "GM.Chat", 2);
setConfig(CONFIG_UINT32_GM_WISPERING_TO, "GM.WhisperingTo", 2);
setConfig(CONFIG_UINT32_GM_LEVEL_IN_GM_LIST, "GM.InGMList.Level", SEC_ADMINISTRATOR);
setConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST, "GM.InWhoList.Level", SEC_ADMINISTRATOR);
setConfig(CONFIG_BOOL_GM_LOG_TRADE, "GM.LogTrade", false);
setConfigMinMax(CONFIG_UINT32_START_GM_LEVEL, "GM.StartLevel", 1, getConfig(CONFIG_UINT32_START_PLAYER_LEVEL), MAX_LEVEL);
setConfig(CONFIG_BOOL_GM_LOWER_SECURITY, "GM.LowerSecurity", false);
setConfig(CONFIG_BOOL_GM_ALLOW_ACHIEVEMENT_GAINS, "GM.AllowAchievementGain", true);
setConfig(CONFIG_UINT32_GROUP_VISIBILITY, "Visibility.GroupMode", 0);
setConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY, "MailDeliveryDelay", HOUR);
setConfigPos(CONFIG_UINT32_UPTIME_UPDATE, "UpdateUptimeInterval", 10);
if (reload)
{
m_timers[WUPDATE_UPTIME].SetInterval(getConfig(CONFIG_UINT32_UPTIME_UPDATE)*MINUTE*IN_MILLISECONDS);
m_timers[WUPDATE_UPTIME].Reset();
}
setConfig(CONFIG_UINT32_SKILL_CHANCE_ORANGE, "SkillChance.Orange", 100);
setConfig(CONFIG_UINT32_SKILL_CHANCE_YELLOW, "SkillChance.Yellow", 75);
setConfig(CONFIG_UINT32_SKILL_CHANCE_GREEN, "SkillChance.Green", 25);
setConfig(CONFIG_UINT32_SKILL_CHANCE_GREY, "SkillChance.Grey", 0);
setConfigPos(CONFIG_UINT32_SKILL_CHANCE_MINING_STEPS, "SkillChance.MiningSteps", 75);
setConfigPos(CONFIG_UINT32_SKILL_CHANCE_SKINNING_STEPS, "SkillChance.SkinningSteps", 75);
setConfig(CONFIG_BOOL_SKILL_PROSPECTING, "SkillChance.Prospecting", false);
setConfig(CONFIG_BOOL_SKILL_MILLING, "SkillChance.Milling", false);
setConfigPos(CONFIG_UINT32_SKILL_GAIN_CRAFTING, "SkillGain.Crafting", 1);
setConfigPos(CONFIG_UINT32_SKILL_GAIN_DEFENSE, "SkillGain.Defense", 1);
setConfigPos(CONFIG_UINT32_SKILL_GAIN_GATHERING, "SkillGain.Gathering", 1);
setConfig(CONFIG_UINT32_SKILL_GAIN_WEAPON, "SkillGain.Weapon", 1);
setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS, "MaxOverspeedPings", 2);
if (getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS) != 0 && getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS) < 2)
{
sLog.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check). Set to 2.", getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS));
setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS, 2);
}
setConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY, "SaveRespawnTimeImmediately", true);
setConfig(CONFIG_BOOL_WEATHER, "ActivateWeather", true);
setConfig(CONFIG_BOOL_ALWAYS_MAX_SKILL_FOR_LEVEL, "AlwaysMaxSkillForLevel", false);
if (configNoReload(reload, CONFIG_UINT32_EXPANSION, "Expansion", MAX_EXPANSION))
setConfigMinMax(CONFIG_UINT32_EXPANSION, "Expansion", MAX_EXPANSION, 0, MAX_EXPANSION);
setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_COUNT, "ChatFlood.MessageCount", 10);
setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_DELAY, "ChatFlood.MessageDelay", 1);
setConfig(CONFIG_UINT32_CHATFLOOD_MUTE_TIME, "ChatFlood.MuteTime", 10);
setConfig(CONFIG_BOOL_EVENT_ANNOUNCE, "Event.Announce", false);
setConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY, "CreatureFamilyAssistanceDelay", 1500);
setConfig(CONFIG_UINT32_CREATURE_FAMILY_FLEE_DELAY, "CreatureFamilyFleeDelay", 7000);
setConfig(CONFIG_UINT32_WORLD_BOSS_LEVEL_DIFF, "WorldBossLevelDiff", 3);
// note: disable value (-1) will assigned as 0xFFFFFFF, to prevent overflow at calculations limit it to max possible player level MAX_LEVEL(100)
setConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF, "Quests.LowLevelHideDiff", 4);
if (getConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF) > MAX_LEVEL)
setConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF, MAX_LEVEL);
setConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF, "Quests.HighLevelHideDiff", 7);
if (getConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF) > MAX_LEVEL)
setConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF, MAX_LEVEL);
setConfigMinMax(CONFIG_UINT32_QUEST_DAILY_RESET_HOUR, "Quests.Daily.ResetHour", 6, 0, 23);
setConfigMinMax(CONFIG_UINT32_QUEST_WEEKLY_RESET_WEEK_DAY, "Quests.Weekly.ResetWeekDay", 3, 0, 6);
setConfigMinMax(CONFIG_UINT32_QUEST_WEEKLY_RESET_HOUR, "Quests.Weekly.ResetHour", 6, 0 , 23);
setConfig(CONFIG_BOOL_QUEST_IGNORE_RAID, "Quests.IgnoreRaid", false);
setConfig(CONFIG_BOOL_DETECT_POS_COLLISION, "DetectPosCollision", true);
setConfig(CONFIG_BOOL_RESTRICTED_LFG_CHANNEL, "Channel.RestrictedLfg", true);
setConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL, "Channel.SilentlyGMJoin", false);
setConfig(CONFIG_BOOL_TALENTS_INSPECTING, "TalentsInspecting", true);
setConfig(CONFIG_BOOL_CHAT_FAKE_MESSAGE_PREVENTING, "ChatFakeMessagePreventing", false);
setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY, "ChatStrictLinkChecking.Severity", 0);
setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_KICK, "ChatStrictLinkChecking.Kick", 0);
setConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW, "Corpse.EmptyLootShow", true);
setConfigPos(CONFIG_UINT32_CORPSE_DECAY_NORMAL, "Corpse.Decay.NORMAL", 300);
setConfigPos(CONFIG_UINT32_CORPSE_DECAY_RARE, "Corpse.Decay.RARE", 900);
setConfigPos(CONFIG_UINT32_CORPSE_DECAY_ELITE, "Corpse.Decay.ELITE", 600);
setConfigPos(CONFIG_UINT32_CORPSE_DECAY_RAREELITE, "Corpse.Decay.RAREELITE", 1200);
setConfigPos(CONFIG_UINT32_CORPSE_DECAY_WORLDBOSS, "Corpse.Decay.WORLDBOSS", 3600);
setConfig(CONFIG_INT32_DEATH_SICKNESS_LEVEL, "Death.SicknessLevel", 11);
setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVP, "Death.CorpseReclaimDelay.PvP", true);
setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVE, "Death.CorpseReclaimDelay.PvE", true);
setConfig(CONFIG_BOOL_DEATH_BONES_WORLD, "Death.Bones.World", true);
setConfig(CONFIG_BOOL_DEATH_BONES_BG_OR_ARENA, "Death.Bones.BattlegroundOrArena", true);
setConfig(CONFIG_FLOAT_THREAT_RADIUS, "ThreatRadius", 100.0f);
// always use declined names in the russian client
if (getConfig(CONFIG_UINT32_REALM_ZONE) == REALM_ZONE_RUSSIAN)
setConfig(CONFIG_BOOL_DECLINED_NAMES_USED, true);
else
setConfig(CONFIG_BOOL_DECLINED_NAMES_USED, "DeclinedNames", false);
setConfig(CONFIG_BOOL_BATTLEGROUND_CAST_DESERTER, "Battleground.CastDeserter", true);
setConfigMinMax(CONFIG_UINT32_BATTLEGROUND_QUEUE_ANNOUNCER_JOIN, "Battleground.QueueAnnouncer.Join", 0, 0, 2);
setConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START, "Battleground.QueueAnnouncer.Start", false);
setConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE, "Battleground.InvitationType", 0);
setConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER, "BattleGround.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS);
setConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH, "BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILLISECONDS);
setConfig(CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE, "Arena.MaxRatingDifference", 150);
setConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER, "Arena.RatingDiscardTimer", 10 * MINUTE * IN_MILLISECONDS);
setConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS, "Arena.AutoDistributePoints", false);
setConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS, "Arena.AutoDistributeInterval", 7);
setConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_JOIN, "Arena.QueueAnnouncer.Join", false);
setConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_EXIT, "Arena.QueueAnnouncer.Exit", false);
setConfig(CONFIG_UINT32_ARENA_SEASON_ID, "Arena.ArenaSeason.ID", 1);
setConfig(CONFIG_UINT32_ARENA_SEASON_PREVIOUS_ID, "Arena.ArenaSeasonPrevious.ID", 0);
setConfigMin(CONFIG_INT32_ARENA_STARTRATING, "Arena.StartRating", -1, -1);
setConfigMin(CONFIG_INT32_ARENA_STARTPERSONALRATING, "Arena.StartPersonalRating", -1, -1);
setConfig(CONFIG_BOOL_OFFHAND_CHECK_AT_TALENTS_RESET, "OffhandCheckAtTalentsReset", false);
setConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET, "Network.KickOnBadPacket", false);
if(int clientCacheId = sConfig.GetIntDefault("ClientCacheVersion", 0))
{
// overwrite DB/old value
if(clientCacheId > 0)
{
setConfig(CONFIG_UINT32_CLIENTCACHE_VERSION, clientCacheId);
sLog.outString("Client cache version set to: %u", clientCacheId);
}
else
sLog.outError("ClientCacheVersion can't be negative %d, ignored.", clientCacheId);
}
setConfig(CONFIG_UINT32_INSTANT_LOGOUT, "InstantLogout", SEC_MODERATOR);
setConfigMin(CONFIG_UINT32_GUILD_EVENT_LOG_COUNT, "Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS, GUILD_EVENTLOG_MAX_RECORDS);
setConfigMin(CONFIG_UINT32_GUILD_BANK_EVENT_LOG_COUNT, "Guild.BankEventLogRecordsCount", GUILD_BANK_MAX_LOGS, GUILD_BANK_MAX_LOGS);
setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_GMLEVEL, "TimerBar.Fatigue.GMLevel", SEC_CONSOLE);
setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_MAX, "TimerBar.Fatigue.Max", 60);
setConfig(CONFIG_UINT32_TIMERBAR_BREATH_GMLEVEL, "TimerBar.Breath.GMLevel", SEC_CONSOLE);
setConfig(CONFIG_UINT32_TIMERBAR_BREATH_MAX, "TimerBar.Breath.Max", 180);
setConfig(CONFIG_UINT32_TIMERBAR_FIRE_GMLEVEL, "TimerBar.Fire.GMLevel", SEC_CONSOLE);
setConfig(CONFIG_UINT32_TIMERBAR_FIRE_MAX, "TimerBar.Fire.Max", 1);
setConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT, "PetUnsummonAtMount", true);
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
{
sLog.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE);
m_VisibleUnitGreyDistance = MAX_VISIBILITY_DISTANCE;
}
m_VisibleObjectGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Object", 10);
if(m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
{
sLog.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE);
m_VisibleObjectGreyDistance = MAX_VISIBILITY_DISTANCE;
}
//visibility on continents
m_MaxVisibleDistanceOnContinents = sConfig.GetFloatDefault("Visibility.Distance.Continents", DEFAULT_VISIBILITY_DISTANCE);
if(m_MaxVisibleDistanceOnContinents < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
{
sLog.outError("Visibility.Distance.Continents can't be less max aggro radius %f", 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
m_MaxVisibleDistanceOnContinents = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
}
else if(m_MaxVisibleDistanceOnContinents + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
{
sLog.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
m_MaxVisibleDistanceOnContinents = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
}
//visibility in instances
m_MaxVisibleDistanceInInstances = sConfig.GetFloatDefault("Visibility.Distance.Instances", DEFAULT_VISIBILITY_INSTANCE);
if(m_MaxVisibleDistanceInInstances < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
{
sLog.outError("Visibility.Distance.Instances can't be less max aggro radius %f",45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
m_MaxVisibleDistanceInInstances = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
}
else if(m_MaxVisibleDistanceInInstances + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
{
sLog.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
m_MaxVisibleDistanceInInstances = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
}
//visibility in BG/Arenas
m_MaxVisibleDistanceInBGArenas = sConfig.GetFloatDefault("Visibility.Distance.BGArenas", DEFAULT_VISIBILITY_BGARENAS);
if(m_MaxVisibleDistanceInBGArenas < 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO))
{
sLog.outError("Visibility.Distance.BGArenas can't be less max aggro radius %f",45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO));
m_MaxVisibleDistanceInBGArenas = 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
}
else if(m_MaxVisibleDistanceInBGArenas + m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
{
sLog.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance);
m_MaxVisibleDistanceInBGArenas = MAX_VISIBILITY_DISTANCE - m_VisibleUnitGreyDistance;
}
m_MaxVisibleDistanceForObject = sConfig.GetFloatDefault("Visibility.Distance.Object", DEFAULT_VISIBILITY_DISTANCE);
if(m_MaxVisibleDistanceForObject < INTERACTION_DISTANCE)
{
sLog.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE));
m_MaxVisibleDistanceForObject = INTERACTION_DISTANCE;
}
else if(m_MaxVisibleDistanceForObject + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
{
sLog.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance);
m_MaxVisibleDistanceForObject = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
}
m_MaxVisibleDistanceInFlight = sConfig.GetFloatDefault("Visibility.Distance.InFlight", DEFAULT_VISIBILITY_DISTANCE);
if(m_MaxVisibleDistanceInFlight + m_VisibleObjectGreyDistance > MAX_VISIBILITY_DISTANCE)
{
sLog.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE-m_VisibleObjectGreyDistance);
m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
}
///- Load the CharDelete related config options
setConfigMinMax(CONFIG_UINT32_CHARDELETE_METHOD, "CharDelete.Method", 0, 0, 1);
setConfigMinMax(CONFIG_UINT32_CHARDELETE_MIN_LEVEL, "CharDelete.MinLevel", 0, 0, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL));
setConfigPos(CONFIG_UINT32_CHARDELETE_KEEP_DAYS, "CharDelete.KeepDays", 30);
///- Read the "Data" directory from the config file
std::string dataPath = sConfig.GetStringDefault("DataDir","./");
if( dataPath.at(dataPath.length()-1)!='/' && dataPath.at(dataPath.length()-1)!='\\' )
dataPath.append("/");
if(reload)
{
if(dataPath!=m_dataPath)
sLog.outError("DataDir option can't be changed at mangosd.conf reload, using current value (%s).",m_dataPath.c_str());
}
else
{
m_dataPath = dataPath;
sLog.outString("Using DataDir %s",m_dataPath.c_str());
}
setConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK, "vmap.enableIndoorCheck", true);
bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false);
bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false);
std::string ignoreSpellIds = sConfig.GetStringDefault("vmap.ignoreSpellIds", "");
if (!enableHeight)
sLog.outError("VMAP height use disabled! Creatures movements and other things will be in broken state.");
VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str());
sLog.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i, indoorCheck:%i",
enableLOS, enableHeight, getConfig(CONFIG_BOOL_VMAP_INDOOR_CHECK) ? 1 : 0);
sLog.outString( "WORLD: VMap data directory is: %svmaps",m_dataPath.c_str());
}
/// Initialize the World
void World::SetInitialWorldSettings()
{
///- Initialize the random number generator
srand((unsigned int)time(NULL));
///- Time server startup
uint32 uStartTime = getMSTime();
///- Initialize config settings
LoadConfigSettings();
///- Check the existence of the map files for all races' startup areas.
if( !MapManager::ExistMapAndVMap(0,-6240.32f, 331.033f)
||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f)
||!MapManager::ExistMapAndVMap(0,-8949.95f,-132.493f)
||!MapManager::ExistMapAndVMap(1,-618.518f,-4251.67f)
||!MapManager::ExistMapAndVMap(0, 1676.35f, 1677.45f)
||!MapManager::ExistMapAndVMap(1, 10311.3f, 832.463f)
||!MapManager::ExistMapAndVMap(1,-2917.58f,-257.98f)
||m_configUint32Values[CONFIG_UINT32_EXPANSION] && (
!MapManager::ExistMapAndVMap(530,10349.6f,-6357.29f) || !MapManager::ExistMapAndVMap(530,-3961.64f,-13931.2f) ) )
{
sLog.outError("Correct *.map files not found in path '%smaps' or *.vmtree/*.vmtile files in '%svmaps'. Please place *.map and vmap files in appropriate directories or correct the DataDir value in the mangosd.conf file.",m_dataPath.c_str(),m_dataPath.c_str());
Log::WaitBeforeContinueIfNeed();
exit(1);
}
///- Loading strings. Getting no records means core load has to be canceled because no error message can be output.
sLog.outString();
sLog.outString("Loading MaNGOS strings...");
if (!sObjectMgr.LoadMangosStrings())
{
Log::WaitBeforeContinueIfNeed();
exit(1); // Error message displayed in function already
}
///- Update the realm entry in the database with the realm type from the config file
//No SQL injection as values are treated as integers
// not send custom type REALM_FFA_PVP to realm list
uint32 server_type = IsFFAPvPRealm() ? REALM_TYPE_PVP : getConfig(CONFIG_UINT32_GAME_TYPE);
uint32 realm_zone = getConfig(CONFIG_UINT32_REALM_ZONE);
LoginDatabase.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type, realm_zone, realmID);
///- Remove the bones (they should not exist in DB though) and old corpses after a restart
CharacterDatabase.PExecute("DELETE FROM corpse WHERE corpse_type = '0' OR time < (UNIX_TIMESTAMP()-'%u')", 3*DAY);
///- Load the DBC files
sLog.outString("Initialize data stores...");
LoadDBCStores(m_dataPath);
DetectDBCLang();
sLog.outString( "Loading Script Names...");
sObjectMgr.LoadScriptNames();
sLog.outString( "Loading InstanceTemplate..." );
sObjectMgr.LoadInstanceTemplate();
sLog.outString( "Loading SkillLineAbilityMultiMap Data..." );
sSpellMgr.LoadSkillLineAbilityMap();
///- Clean up and pack instances
sLog.outString( "Cleaning up instances..." );
sInstanceSaveMgr.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables
sLog.outString( "Packing instances..." );
sInstanceSaveMgr.PackInstances();
sLog.outString( "Packing groups..." );
sObjectMgr.PackGroupIds(); // must be after CleanupInstances
///- Init highest guids before any guid using table loading to prevent using not initialized guids in some code.
sObjectMgr.SetHighestGuids(); // must be after packing instances
sLog.outString();
sLog.outString( "Loading Localization strings..." );
sObjectMgr.LoadCreatureLocales();
sObjectMgr.LoadGameObjectLocales();
sObjectMgr.LoadItemLocales();
sObjectMgr.LoadQuestLocales();
sObjectMgr.LoadNpcTextLocales();
sObjectMgr.LoadPageTextLocales();
sObjectMgr.LoadGossipMenuItemsLocales();
sObjectMgr.LoadPointOfInterestLocales();
sObjectMgr.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts)
sLog.outString( ">>> Localization strings loaded" );
sLog.outString();
sLog.outString( "Loading Page Texts..." );
sObjectMgr.LoadPageTexts();
sLog.outString( "Loading Game Object Templates..." ); // must be after LoadPageTexts
sObjectMgr.LoadGameobjectInfo();
sLog.outString( "Loading Spell Chain Data..." );
sSpellMgr.LoadSpellChains();
sLog.outString( "Loading Spell Elixir types..." );
sSpellMgr.LoadSpellElixirs();
sLog.outString( "Loading Spell Learn Skills..." );
sSpellMgr.LoadSpellLearnSkills(); // must be after LoadSpellChains
sLog.outString( "Loading Spell Learn Spells..." );
sSpellMgr.LoadSpellLearnSpells();
sLog.outString( "Loading Spell Proc Event conditions..." );
sSpellMgr.LoadSpellProcEvents();
sLog.outString( "Loading Spell Bonus Data..." );
sSpellMgr.LoadSpellBonuses(); // must be after LoadSpellChains
sLog.outString( "Loading Spell Proc Item Enchant..." );
sSpellMgr.LoadSpellProcItemEnchant(); // must be after LoadSpellChains
sLog.outString( "Loading Aggro Spells Definitions...");
sSpellMgr.LoadSpellThreats();
sLog.outString( "Loading NPC Texts..." );
sObjectMgr.LoadGossipText();
sLog.outString( "Loading Item Random Enchantments Table..." );
LoadRandomEnchantmentsTable();
sLog.outString( "Loading Items..." ); // must be after LoadRandomEnchantmentsTable and LoadPageTexts
sObjectMgr.LoadItemPrototypes();
sLog.outString( "Loading Item converts..." ); // must be after LoadItemPrototypes
sObjectMgr.LoadItemConverts();
sLog.outString( "Loading Creature Model Based Info Data..." );
sObjectMgr.LoadCreatureModelInfo();
sLog.outString( "Loading Equipment templates...");
sObjectMgr.LoadEquipmentTemplates();
sLog.outString( "Loading Creature templates..." );
sObjectMgr.LoadCreatureTemplates();
sLog.outString( "Loading Creature Model for race..." ); // must be after creature templates
sObjectMgr.LoadCreatureModelRace();
sLog.outString( "Loading SpellsScriptTarget...");
sSpellMgr.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo
sLog.outString( "Loading ItemRequiredTarget...");
sObjectMgr.LoadItemRequiredTarget();
sLog.outString( "Loading Reputation Reward Rates...");
sObjectMgr.LoadReputationRewardRate();
sLog.outString( "Loading Creature Reputation OnKill Data..." );
sObjectMgr.LoadReputationOnKill();
sLog.outString( "Loading Reputation Spillover Data..." );
sObjectMgr.LoadReputationSpilloverTemplate();
sLog.outString( "Loading Points Of Interest Data..." );
sObjectMgr.LoadPointsOfInterest();
sLog.outString( "Loading Creature Data..." );
sObjectMgr.LoadCreatures();
sLog.outString( "Loading pet levelup spells..." );
sSpellMgr.LoadPetLevelupSpellMap();
sLog.outString( "Loading pet default spell additional to levelup spells..." );
sSpellMgr.LoadPetDefaultSpells();
sLog.outString( "Loading Creature Addon Data..." );
sLog.outString();
sObjectMgr.LoadCreatureAddons(); // must be after LoadCreatureTemplates() and LoadCreatures()
sLog.outString( ">>> Creature Addon Data loaded" );
sLog.outString();
sLog.outString( "Loading Creature Respawn Data..." ); // must be after PackInstances()
sObjectMgr.LoadCreatureRespawnTimes();
sLog.outString( "Loading Gameobject Data..." );
sObjectMgr.LoadGameobjects();
sLog.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances()
sObjectMgr.LoadGameobjectRespawnTimes();
sLog.outString( "Loading Objects Pooling Data...");
sPoolMgr.LoadFromDB();
sLog.outString( "Loading Weather Data..." );
sObjectMgr.LoadWeatherZoneChances();
sLog.outString( "Loading Quests..." );
sObjectMgr.LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables
sLog.outString( "Loading Quest POI" );
sObjectMgr.LoadQuestPOI();
sLog.outString( "Loading Quests Relations..." );
sLog.outString();
sObjectMgr.LoadQuestRelations(); // must be after quest load
sLog.outString( ">>> Quests Relations loaded" );
sLog.outString();
sLog.outString( "Loading Game Event Data..."); // must be after sPoolMgr.LoadFromDB and quests to properly load pool events and quests for events
sLog.outString();
sGameEventMgr.LoadFromDB();
sLog.outString( ">>> Game Event Data loaded" );
sLog.outString();
sLog.outString( "Loading UNIT_NPC_FLAG_SPELLCLICK Data..." );
sObjectMgr.LoadNPCSpellClickSpells();
sLog.outString( "Loading SpellArea Data..." ); // must be after quest load
sSpellMgr.LoadSpellAreas();
sLog.outString( "Loading AreaTrigger definitions..." );
sObjectMgr.LoadAreaTriggerTeleports(); // must be after item template load
sLog.outString( "Loading Quest Area Triggers..." );
sObjectMgr.LoadQuestAreaTriggers(); // must be after LoadQuests
sLog.outString( "Loading Tavern Area Triggers..." );
sObjectMgr.LoadTavernAreaTriggers();
sLog.outString( "Loading AreaTrigger script names..." );
sObjectMgr.LoadAreaTriggerScripts();
sLog.outString( "Loading event id script names..." );
sObjectMgr.LoadEventIdScripts();
sLog.outString( "Loading Graveyard-zone links...");
sObjectMgr.LoadGraveyardZones();
sLog.outString( "Loading Spell target coordinates..." );
sSpellMgr.LoadSpellTargetPositions();
sLog.outString( "Loading spell pet auras..." );
sSpellMgr.LoadSpellPetAuras();
sLog.outString( "Loading Player Create Info & Level Stats..." );
sLog.outString();
sObjectMgr.LoadPlayerInfo();
sLog.outString( ">>> Player Create Info & Level Stats loaded" );
sLog.outString();
sLog.outString( "Loading Exploration BaseXP Data..." );
sObjectMgr.LoadExplorationBaseXP();
sLog.outString( "Loading Pet Name Parts..." );
sObjectMgr.LoadPetNames();
CharacterDatabaseCleaner::CleanDatabase();
sLog.outString( "Loading the max pet number..." );
sObjectMgr.LoadPetNumber();
sLog.outString( "Loading pet level stats..." );
sObjectMgr.LoadPetLevelInfo();
sLog.outString( "Loading Player Corpses..." );
sObjectMgr.LoadCorpses();
sLog.outString( "Loading Player level dependent mail rewards..." );
sObjectMgr.LoadMailLevelRewards();
sLog.outString( "Loading Loot Tables..." );
sLog.outString();
LoadLootTables();
sLog.outString( ">>> Loot Tables loaded" );
sLog.outString();
sLog.outString( "Loading Skill Discovery Table..." );
LoadSkillDiscoveryTable();
sLog.outString( "Loading Skill Extra Item Table..." );
LoadSkillExtraItemTable();
sLog.outString( "Loading Skill Fishing base level requirements..." );
sObjectMgr.LoadFishingBaseSkillLevel();
sLog.outString( "Loading Achievements..." );
sLog.outString();
sAchievementMgr.LoadAchievementReferenceList();
sAchievementMgr.LoadAchievementCriteriaList();
sAchievementMgr.LoadAchievementCriteriaRequirements();
sAchievementMgr.LoadRewards();
sAchievementMgr.LoadRewardLocales();
sAchievementMgr.LoadCompletedAchievements();
sLog.outString( ">>> Achievements loaded" );
sLog.outString();
///- Load dynamic data tables from the database
sLog.outString( "Loading Auctions..." );
sLog.outString();
sAuctionMgr.LoadAuctionItems();
sAuctionMgr.LoadAuctions();
sLog.outString( ">>> Auctions loaded" );
sLog.outString();
sLog.outString( "Loading Guilds..." );
sObjectMgr.LoadGuilds();
sLog.outString( "Loading ArenaTeams..." );
sObjectMgr.LoadArenaTeams();
sLog.outString( "Loading Groups..." );
sObjectMgr.LoadGroups();
sLog.outString( "Loading ReservedNames..." );
sObjectMgr.LoadReservedPlayersNames();
sLog.outString( "Loading GameObjects for quests..." );
sObjectMgr.LoadGameObjectForQuests();
sLog.outString( "Loading BattleMasters..." );
sBattleGroundMgr.LoadBattleMastersEntry();
sLog.outString( "Loading BattleGround event indexes..." );
sBattleGroundMgr.LoadBattleEventIndexes();
sLog.outString( "Loading GameTeleports..." );
sObjectMgr.LoadGameTele();
sLog.outString( "Loading Npc Text Id..." );
sObjectMgr.LoadNpcTextId(); // must be after load Creature and NpcText
sLog.outString( "Loading Gossip scripts..." );
sObjectMgr.LoadGossipScripts(); // must be before gossip menu options
sLog.outString( "Loading Gossip menus..." );
sObjectMgr.LoadGossipMenu();
sLog.outString( "Loading Gossip menu options..." );
sObjectMgr.LoadGossipMenuItems();
sLog.outString( "Loading Vendors..." );
sObjectMgr.LoadVendorTemplates(); // must be after load ItemTemplate
sObjectMgr.LoadVendors(); // must be after load CreatureTemplate, VendorTemplate, and ItemTemplate
sLog.outString( "Loading Trainers..." );
sObjectMgr.LoadTrainerSpell(); // must be after load CreatureTemplate
sLog.outString( "Loading Waypoint scripts..." ); // before loading from creature_movement
sObjectMgr.LoadCreatureMovementScripts();
sLog.outString( "Loading Waypoints..." );
sLog.outString();
sWaypointMgr.Load();
sLog.outString( "Loading GM tickets...");
sTicketMgr.LoadGMTickets();
///- Handle outdated emails (delete/return)
sLog.outString( "Returning old mails..." );
sObjectMgr.ReturnOrDeleteOldMails(false);
///- Load and initialize scripts
sLog.outString( "Loading Scripts..." );
sLog.outString();
sObjectMgr.LoadQuestStartScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
sObjectMgr.LoadQuestEndScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
sObjectMgr.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data)
sObjectMgr.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data)
sObjectMgr.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data)
sLog.outString( ">>> Scripts loaded" );
sLog.outString();
sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls
sObjectMgr.LoadDbScriptStrings();
sLog.outString( "Loading CreatureEventAI Texts...");
sEventAIMgr.LoadCreatureEventAI_Texts(false); // false, will checked in LoadCreatureEventAI_Scripts
sLog.outString( "Loading CreatureEventAI Summons...");
sEventAIMgr.LoadCreatureEventAI_Summons(false); // false, will checked in LoadCreatureEventAI_Scripts
sLog.outString( "Loading CreatureEventAI Scripts...");
sEventAIMgr.LoadCreatureEventAI_Scripts();
sLog.outString( "Initializing Scripts..." );
if(!LoadScriptingModule())
{
Log::WaitBeforeContinueIfNeed();
exit(1); // Error message displayed in function already
}
///- Initialize game time and timers
sLog.outString( "DEBUG:: Initialize game time and timers" );
m_gameTime = time(NULL);
m_startTime=m_gameTime;
tm local;
time_t curr;
time(&curr);
local=*(localtime(&curr)); // dereference and assign
char isoDate[128];
sprintf( isoDate, "%04d-%02d-%02d %02d:%02d:%02d",
local.tm_year+1900, local.tm_mon+1, local.tm_mday, local.tm_hour, local.tm_min, local.tm_sec);
LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD ", '%s', 0)",
realmID, uint64(m_startTime), isoDate);
m_timers[WUPDATE_OBJECTS].SetInterval(0);
m_timers[WUPDATE_SESSIONS].SetInterval(0);
m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
m_timers[WUPDATE_UPTIME].SetInterval(getConfig(CONFIG_UINT32_UPTIME_UPDATE)*MINUTE*IN_MILLISECONDS);
//Update "uptime" table based on configuration entry in minutes.
m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*IN_MILLISECONDS);
m_timers[WUPDATE_DELETECHARS].SetInterval(DAY*IN_MILLISECONDS); // check for chars to delete every day
//to set mailtimer to return mails every day between 4 and 5 am
//mailtimer is increased when updating auctions
//one second is 1000 -(tested on win system)
mail_timer = uint32((((localtime( &m_gameTime )->tm_hour + 20) % 24)* HOUR * IN_MILLISECONDS) / m_timers[WUPDATE_AUCTIONS].GetInterval() );
//1440
mail_timer_expires = (DAY * IN_MILLISECONDS) / m_timers[WUPDATE_AUCTIONS].GetInterval();
DEBUG_LOG("Mail timer set to: %u, mail return is called every %u minutes", mail_timer, mail_timer_expires);
///- Initialize static helper structures
AIRegistry::Initialize();
Player::InitVisibleBits();
///- Initialize MapManager
sLog.outString( "Starting Map System" );
sMapMgr.Initialize();
///- Initialize Battlegrounds
sLog.outString( "Starting BattleGround System" );
sBattleGroundMgr.CreateInitialBattleGrounds();
sBattleGroundMgr.InitAutomaticArenaPointDistribution();
//Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager
sLog.outString( "Loading Transports..." );
sMapMgr.LoadTransports();
sLog.outString("Deleting expired bans..." );
LoginDatabase.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
sLog.outString("Calculate next daily quest reset time..." );
InitDailyQuestResetTime();
sLog.outString("Calculate next weekly quest reset time..." );
InitWeeklyQuestResetTime();
sLog.outString("Calculate next monthly quest reset time..." );
SetMonthlyQuestResetTime();
sLog.outString("Starting objects Pooling system..." );
sPoolMgr.Initialize();
sLog.outString("Starting Game Event system..." );
uint32 nextGameEvent = sGameEventMgr.Initialize();
m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent); //depend on next event
// Delete all characters which have been deleted X days before
Player::DeleteOldCharacters();
sLog.outString( "WORLD: World initialized" );
uint32 uStartInterval = getMSTimeDiff(uStartTime, getMSTime());
sLog.outString( "SERVER STARTUP TIME: %i minutes %i seconds", uStartInterval / 60000, (uStartInterval % 60000) / 1000 );
}
void World::DetectDBCLang()
{
uint32 m_lang_confid = sConfig.GetIntDefault("DBC.Locale", 255);
if(m_lang_confid != 255 && m_lang_confid >= MAX_LOCALE)
{
sLog.outError("Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)",MAX_LOCALE);
m_lang_confid = LOCALE_enUS;
}
ChrRacesEntry const* race = sChrRacesStore.LookupEntry(1);
std::string availableLocalsStr;
int default_locale = MAX_LOCALE;
for (int i = MAX_LOCALE-1; i >= 0; --i)
{
if ( strlen(race->name[i]) > 0) // check by race names
{
default_locale = i;
m_availableDbcLocaleMask |= (1 << i);
availableLocalsStr += localeNames[i];
availableLocalsStr += " ";
}
}
if( default_locale != m_lang_confid && m_lang_confid < MAX_LOCALE &&
(m_availableDbcLocaleMask & (1 << m_lang_confid)) )
{
default_locale = m_lang_confid;
}
if(default_locale >= MAX_LOCALE)
{
sLog.outError("Unable to determine your DBC Locale! (corrupt DBC?)");
Log::WaitBeforeContinueIfNeed();
exit(1);
}
m_defaultDbcLocale = LocaleConstant(default_locale);
sLog.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames[m_defaultDbcLocale],availableLocalsStr.empty() ? "<none>" : availableLocalsStr.c_str());
sLog.outString();
}
/// Update the World !
void World::Update(uint32 time_, uint32 diff)
{
///- Update the different timers
for(int i = 0; i < WUPDATE_COUNT; ++i)
m_timers[i].Update(diff);
///- Update the game time and check for shutdown time
_UpdateGameTime();
/// Handle daily quests reset time
if (m_gameTime > m_NextDailyQuestReset)
ResetDailyQuests();
/// Handle weekly quests reset time
if (m_gameTime > m_NextWeeklyQuestReset)
ResetWeeklyQuests();
/// Handle monthly quests reset time
if (m_gameTime > m_NextMonthlyQuestReset)
ResetMonthlyQuests();
/// <ul><li> Handle auctions when the timer has passed
if (m_timers[WUPDATE_AUCTIONS].Passed())
{
m_timers[WUPDATE_AUCTIONS].Reset();
///- Update mails (return old mails with item, or delete them)
//(tested... works on win)
if (++mail_timer > mail_timer_expires)
{
mail_timer = 0;
sObjectMgr.ReturnOrDeleteOldMails(true);
}
///- Handle expired auctions
sAuctionMgr.Update();
}
/// <li> Handle session updates when the timer has passed
if (m_timers[WUPDATE_SESSIONS].Passed())
{
m_timers[WUPDATE_SESSIONS].Reset();
UpdateSessions(diff);
}
/// <li> Handle weather updates when the timer has passed
if (m_timers[WUPDATE_WEATHERS].Passed())
{
///- Send an update signal to Weather objects
for (WeatherMap::iterator itr = m_weathers.begin(); itr != m_weathers.end(); )
{
///- and remove Weather objects for zones with no player
//As interval > WorldTick
if(!itr->second->Update(m_timers[WUPDATE_WEATHERS].GetInterval()))
{
delete itr->second;
m_weathers.erase(itr++);
}
else
++itr;
}
m_timers[WUPDATE_WEATHERS].SetCurrent(0);
}
/// <li> Update uptime table
if (m_timers[WUPDATE_UPTIME].Passed())
{
uint32 tmpDiff = uint32(m_gameTime - m_startTime);
uint32 maxClientsNum = GetMaxActiveSessionCount();
m_timers[WUPDATE_UPTIME].Reset();
LoginDatabase.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " UI64FMTD, tmpDiff, maxClientsNum, realmID, uint64(m_startTime));
}
/// <li> Handle all other objects
if (m_timers[WUPDATE_OBJECTS].Passed())
{
m_timers[WUPDATE_OBJECTS].Reset();
///- Update objects when the timer has passed (maps, transport, creatures,...)
sMapMgr.Update(time_, diff); // As interval = 0
sBattleGroundMgr.Update(diff);
}
///- Delete all characters which have been deleted X days before
if (m_timers[WUPDATE_DELETECHARS].Passed())
{
m_timers[WUPDATE_DELETECHARS].Reset();
Player::DeleteOldCharacters();
}
// execute callbacks from sql queries that were queued recently
UpdateResultQueue();
///- Erase corpses once every 20 minutes
if (m_timers[WUPDATE_CORPSES].Passed())
{
m_timers[WUPDATE_CORPSES].Reset();
sObjectAccessor.RemoveOldCorpses();
}
///- Process Game events when necessary
if (m_timers[WUPDATE_EVENTS].Passed())
{
m_timers[WUPDATE_EVENTS].Reset(); // to give time for Update() to be processed
uint32 nextGameEvent = sGameEventMgr.Update();
m_timers[WUPDATE_EVENTS].SetInterval(nextGameEvent);
m_timers[WUPDATE_EVENTS].Reset();
}
/// </ul>
///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove"
sMapMgr.RemoveAllObjectsInRemoveList();
// update the instance reset times
sInstanceSaveMgr.Update();
// And last, but not least handle the issued cli commands
ProcessCliCommands();
}
/// Send a packet to all players (except self if mentioned)
void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team)
{
SessionMap::const_iterator itr;
for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (itr->second &&
itr->second->GetPlayer() &&
itr->second->GetPlayer()->IsInWorld() &&
itr->second != self &&
(team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
{
itr->second->SendPacket(packet);
}
}
}
namespace MaNGOS
{
class WorldWorldTextBuilder
{
public:
typedef std::vector<WorldPacket*> WorldPacketList;
explicit WorldWorldTextBuilder(int32 textId, va_list* args = NULL) : i_textId(textId), i_args(args) {}
void operator()(WorldPacketList& data_list, int32 loc_idx)
{
char const* text = sObjectMgr.GetMangosString(i_textId,loc_idx);
if(i_args)
{
// we need copy va_list before use or original va_list will corrupted
va_list ap;
va_copy(ap,*i_args);
char str [2048];
vsnprintf(str,2048,text, ap );
va_end(ap);
do_helper(data_list,&str[0]);
}
else
do_helper(data_list,(char*)text);
}
private:
char* lineFromMessage(char*& pos) { char* start = strtok(pos,"\n"); pos = NULL; return start; }
void do_helper(WorldPacketList& data_list, char* text)
{
char* pos = text;
while(char* line = lineFromMessage(pos))
{
WorldPacket* data = new WorldPacket();
uint32 lineLength = (line ? strlen(line) : 0) + 1;
data->Initialize(SMSG_MESSAGECHAT, 100); // guess size
*data << uint8(CHAT_MSG_SYSTEM);
*data << uint32(LANG_UNIVERSAL);
*data << uint64(0);
*data << uint32(0); // can be chat msg group or something
*data << uint64(0);
*data << uint32(lineLength);
*data << line;
*data << uint8(0);
data_list.push_back(data);
}
}
int32 i_textId;
va_list* i_args;
};
} // namespace MaNGOS
/// Send a System Message to all players (except self if mentioned)
void World::SendWorldText(int32 string_id, ...)
{
va_list ap;
va_start(ap, string_id);
MaNGOS::WorldWorldTextBuilder wt_builder(string_id, &ap);
MaNGOS::LocalizedPacketListDo<MaNGOS::WorldWorldTextBuilder> wt_do(wt_builder);
for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if(!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() )
continue;
wt_do(itr->second->GetPlayer());
}
va_end(ap);
}
/// DEPRICATED, only for debug purpose. Send a System Message to all players (except self if mentioned)
void World::SendGlobalText(const char* text, WorldSession *self)
{
WorldPacket data;
// need copy to prevent corruption by strtok call in LineFromMessage original string
char* buf = mangos_strdup(text);
char* pos = buf;
while(char* line = ChatHandler::LineFromMessage(pos))
{
ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, line, NULL);
SendGlobalMessage(&data, self);
}
delete [] buf;
}
/// Send a packet to all players (or players selected team) in the zone (except self if mentioned)
void World::SendZoneMessage(uint32 zone, WorldPacket *packet, WorldSession *self, uint32 team)
{
SessionMap::const_iterator itr;
for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (itr->second &&
itr->second->GetPlayer() &&
itr->second->GetPlayer()->IsInWorld() &&
itr->second->GetPlayer()->GetZoneId() == zone &&
itr->second != self &&
(team == 0 || itr->second->GetPlayer()->GetTeam() == team) )
{
itr->second->SendPacket(packet);
}
}
}
/// Send a System Message to all players in the zone (except self if mentioned)
void World::SendZoneText(uint32 zone, const char* text, WorldSession *self, uint32 team)
{
WorldPacket data;
ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, 0, text, NULL);
SendZoneMessage(zone, &data, self,team);
}
/// Kick (and save) all players
void World::KickAll()
{
m_QueuedPlayer.clear(); // prevent send queue update packet and login queued sessions
// session not removed at kick and will removed in next update tick
for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
itr->second->KickPlayer();
}
/// Kick (and save) all players with security level less `sec`
void World::KickAllLess(AccountTypes sec)
{
// session not removed at kick and will removed in next update tick
for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
if(itr->second->GetSecurity() < sec)
itr->second->KickPlayer();
}
/// Ban an account or ban an IP address, duration_secs if it is positive used, otherwise permban
BanReturn World::BanAccount(BanMode mode, std::string nameOrIP, uint32 duration_secs, std::string reason, std::string author)
{
LoginDatabase.escape_string(nameOrIP);
LoginDatabase.escape_string(reason);
std::string safe_author=author;
LoginDatabase.escape_string(safe_author);
QueryResult *resultAccounts = NULL; //used for kicking
///- Update the database with ban information
switch(mode)
{
case BAN_IP:
//No SQL injection as strings are escaped
resultAccounts = LoginDatabase.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP.c_str());
LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP()+%u,'%s','%s')",nameOrIP.c_str(),duration_secs,safe_author.c_str(),reason.c_str());
break;
case BAN_ACCOUNT:
//No SQL injection as string is escaped
resultAccounts = LoginDatabase.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP.c_str());
break;
case BAN_CHARACTER:
//No SQL injection as string is escaped
resultAccounts = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP.c_str());
break;
default:
return BAN_SYNTAX_ERROR;
}
if(!resultAccounts)
{
if(mode==BAN_IP)
return BAN_SUCCESS; // ip correctly banned but nobody affected (yet)
else
return BAN_NOTFOUND; // Nobody to ban
}
///- Disconnect all affected players (for IP it can be several)
do
{
Field* fieldsAccount = resultAccounts->Fetch();
uint32 account = fieldsAccount->GetUInt32();
if(mode!=BAN_IP)
{
//No SQL injection as strings are escaped
LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
account,duration_secs,safe_author.c_str(),reason.c_str());
}
if (WorldSession* sess = FindSession(account))
if(std::string(sess->GetPlayerName()) != author)
sess->KickPlayer();
}
while( resultAccounts->NextRow() );
delete resultAccounts;
return BAN_SUCCESS;
}
/// Remove a ban from an account or IP address
bool World::RemoveBanAccount(BanMode mode, std::string nameOrIP)
{
if (mode == BAN_IP)
{
LoginDatabase.escape_string(nameOrIP);
LoginDatabase.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP.c_str());
}
else
{
uint32 account = 0;
if (mode == BAN_ACCOUNT)
account = sAccountMgr.GetId (nameOrIP);
else if (mode == BAN_CHARACTER)
account = sObjectMgr.GetPlayerAccountIdByPlayerName (nameOrIP);
if (!account)
return false;
//NO SQL injection as account is uint32
LoginDatabase.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account);
}
return true;
}
/// Update the game time
void World::_UpdateGameTime()
{
///- update the time
time_t thisTime = time(NULL);
uint32 elapsed = uint32(thisTime - m_gameTime);
m_gameTime = thisTime;
///- if there is a shutdown timer
if(!m_stopEvent && m_ShutdownTimer > 0 && elapsed > 0)
{
///- ... and it is overdue, stop the world (set m_stopEvent)
if( m_ShutdownTimer <= elapsed )
{
if(!(m_ShutdownMask & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0)
m_stopEvent = true; // exist code already set
else
m_ShutdownTimer = 1; // minimum timer value to wait idle state
}
///- ... else decrease it and if necessary display a shutdown countdown to the users
else
{
m_ShutdownTimer -= elapsed;
ShutdownMsg();
}
}
}
/// Shutdown the server
void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode)
{
// ignore if server shutdown at next tick
if(m_stopEvent)
return;
m_ShutdownMask = options;
m_ExitCode = exitcode;
///- If the shutdown time is 0, set m_stopEvent (except if shutdown is 'idle' with remaining sessions)
if(time==0)
{
if(!(options & SHUTDOWN_MASK_IDLE) || GetActiveAndQueuedSessionCount()==0)
m_stopEvent = true; // exist code already set
else
m_ShutdownTimer = 1; //So that the session count is re-evaluated at next world tick
}
///- Else set the shutdown timer and warn users
else
{
m_ShutdownTimer = time;
ShutdownMsg(true);
}
}
/// Display a shutdown message to the user(s)
void World::ShutdownMsg(bool show, Player* player)
{
// not show messages for idle shutdown mode
if(m_ShutdownMask & SHUTDOWN_MASK_IDLE)
return;
///- Display a message every 12 hours, hours, 5 minutes, minute, 5 seconds and finally seconds
if ( show ||
(m_ShutdownTimer < 10) ||
// < 30 sec; every 5 sec
(m_ShutdownTimer<30 && (m_ShutdownTimer % 5 )==0) ||
// < 5 min ; every 1 min
(m_ShutdownTimer<5*MINUTE && (m_ShutdownTimer % MINUTE )==0) ||
// < 30 min ; every 5 min
(m_ShutdownTimer<30*MINUTE && (m_ShutdownTimer % (5*MINUTE))==0) ||
// < 12 h ; every 1 h
(m_ShutdownTimer<12*HOUR && (m_ShutdownTimer % HOUR )==0) ||
// > 12 h ; every 12 h
(m_ShutdownTimer>12*HOUR && (m_ShutdownTimer % (12*HOUR) )==0))
{
std::string str = secsToTimeString(m_ShutdownTimer);
ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_TIME : SERVER_MSG_SHUTDOWN_TIME;
SendServerMessage(msgid,str.c_str(),player);
DEBUG_LOG("Server is %s in %s",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shutting down"),str.c_str());
}
}
/// Cancel a planned server shutdown
void World::ShutdownCancel()
{
// nothing cancel or too later
if(!m_ShutdownTimer || m_stopEvent)
return;
ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED;
m_ShutdownMask = 0;
m_ShutdownTimer = 0;
m_ExitCode = SHUTDOWN_EXIT_CODE; // to default value
SendServerMessage(msgid);
DEBUG_LOG("Server %s cancelled.",(m_ShutdownMask & SHUTDOWN_MASK_RESTART ? "restart" : "shutdown"));
}
/// Send a server message to the user(s)
void World::SendServerMessage(ServerMessageType type, const char *text, Player* player)
{
WorldPacket data(SMSG_SERVER_MESSAGE, 50); // guess size
data << uint32(type);
if(type <= SERVER_MSG_STRING)
data << text;
if(player)
player->GetSession()->SendPacket(&data);
else
SendGlobalMessage( &data );
}
void World::UpdateSessions( uint32 diff )
{
///- Add new sessions
WorldSession* sess;
while(addSessQueue.next(sess))
AddSession_ (sess);
///- Then send an update signal to remaining ones
for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next)
{
next = itr;
++next;
///- and remove not active sessions from the list
if(!itr->second->Update(diff)) // As interval = 0
{
RemoveQueuedPlayer (itr->second);
delete itr->second;
m_sessions.erase(itr);
}
}
}
// This handles the issued and queued CLI/RA commands
void World::ProcessCliCommands()
{
CliCommandHolder::Print* zprint = NULL;
void* callbackArg = NULL;
CliCommandHolder* command;
while (cliCmdQueue.next(command))
{
DEBUG_LOG("CLI command under processing...");
zprint = command->m_print;
callbackArg = command->m_callbackArg;
CliHandler handler(command->m_cliAccountId, command->m_cliAccessLevel, callbackArg, zprint);
handler.ParseCommands(command->m_command);
if(command->m_commandFinished)
command->m_commandFinished(callbackArg, !handler.HasSentErrorMessage());
delete command;
}
}
void World::InitResultQueue()
{
m_resultQueue = new SqlResultQueue;
CharacterDatabase.SetResultQueue(m_resultQueue);
}
void World::UpdateResultQueue()
{
m_resultQueue->Update();
}
void World::UpdateRealmCharCount(uint32 accountId)
{
CharacterDatabase.AsyncPQuery(this, &World::_UpdateRealmCharCount, accountId,
"SELECT COUNT(guid) FROM characters WHERE account = '%u'", accountId);
}
void World::_UpdateRealmCharCount(QueryResult *resultCharCount, uint32 accountId)
{
if (resultCharCount)
{
Field *fields = resultCharCount->Fetch();
uint32 charCount = fields[0].GetUInt32();
delete resultCharCount;
LoginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId, realmID);
LoginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount, accountId, realmID);
}
}
void World::InitWeeklyQuestResetTime()
{
QueryResult * result = CharacterDatabase.Query("SELECT NextWeeklyQuestResetTime FROM saved_variables");
if (!result)
m_NextWeeklyQuestReset = time_t(time(NULL)); // game time not yet init
else
m_NextWeeklyQuestReset = time_t((*result)[0].GetUInt64());
// generate time by config
time_t curTime = time(NULL);
tm localTm = *localtime(&curTime);
int week_day_offset = localTm.tm_wday - int(getConfig(CONFIG_UINT32_QUEST_WEEKLY_RESET_WEEK_DAY));
// current week reset time
localTm.tm_hour = getConfig(CONFIG_UINT32_QUEST_WEEKLY_RESET_HOUR);
localTm.tm_min = 0;
localTm.tm_sec = 0;
time_t nextWeekResetTime = mktime(&localTm);
nextWeekResetTime -= week_day_offset * DAY; // move time to proper day
// next reset time before current moment
if (curTime >= nextWeekResetTime)
nextWeekResetTime += WEEK;
// normalize reset time
m_NextWeeklyQuestReset = m_NextWeeklyQuestReset < curTime ? nextWeekResetTime - WEEK : nextWeekResetTime;
if (!result)
CharacterDatabase.PExecute("INSERT INTO saved_variables (NextWeeklyQuestResetTime) VALUES ('"UI64FMTD"')", uint64(m_NextWeeklyQuestReset));
else
delete result;
}
void World::InitDailyQuestResetTime()
{
QueryResult * result = CharacterDatabase.Query("SELECT NextDailyQuestResetTime FROM saved_variables");
if (!result)
m_NextDailyQuestReset = time_t(time(NULL)); // game time not yet init
else
m_NextDailyQuestReset = time_t((*result)[0].GetUInt64());
// generate time by config
time_t curTime = time(NULL);
tm localTm = *localtime(&curTime);
localTm.tm_hour = getConfig(CONFIG_UINT32_QUEST_DAILY_RESET_HOUR);
localTm.tm_min = 0;
localTm.tm_sec = 0;
// current day reset time
time_t nextDayResetTime = mktime(&localTm);
// next reset time before current moment
if (curTime >= nextDayResetTime)
nextDayResetTime += DAY;
// normalize reset time
m_NextDailyQuestReset = m_NextDailyQuestReset < curTime ? nextDayResetTime - DAY : nextDayResetTime;
if (!result)
CharacterDatabase.PExecute("INSERT INTO saved_variables (NextDailyQuestResetTime) VALUES ('"UI64FMTD"')", uint64(m_NextDailyQuestReset));
else
delete result;
}
void World::SetMonthlyQuestResetTime(bool initialize)
{
if (initialize)
{
QueryResult * result = CharacterDatabase.Query("SELECT NextMonthlyQuestResetTime FROM saved_variables");
if (!result)
m_NextMonthlyQuestReset = time_t(time(NULL));
else
m_NextMonthlyQuestReset = time_t((*result)[0].GetUInt64());
delete result;
}
// generate time
time_t currentTime = time(NULL);
tm localTm = *localtime(&currentTime);
int month = localTm.tm_mon;
int year = localTm.tm_year;
++month;
// month 11 is december, next is january (0)
if (month > 11)
{
month = 0;
year += 1;
}
// reset time for next month
localTm.tm_year = year;
localTm.tm_mon = month;
localTm.tm_mday = 1; // don't know if we really need config option for day/hour
localTm.tm_hour = 0;
localTm.tm_min = 0;
localTm.tm_sec = 0;
time_t nextMonthResetTime = mktime(&localTm);
m_NextMonthlyQuestReset = (initialize && m_NextMonthlyQuestReset < nextMonthResetTime) ? m_NextMonthlyQuestReset : nextMonthResetTime;
// Row must exist for this to work. Currently row is added by InitDailyQuestResetTime(), called before this function
CharacterDatabase.PExecute("UPDATE saved_variables SET NextMonthlyQuestResetTime = '"UI64FMTD"'", uint64(m_NextMonthlyQuestReset));
}
void World::ResetDailyQuests()
{
DETAIL_LOG("Daily quests reset for all characters.");
CharacterDatabase.Execute("DELETE FROM character_queststatus_daily");
for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
if (itr->second->GetPlayer())
itr->second->GetPlayer()->ResetDailyQuestStatus();
m_NextDailyQuestReset = time_t(m_NextDailyQuestReset + DAY);
CharacterDatabase.PExecute("UPDATE saved_variables SET NextDailyQuestResetTime = '"UI64FMTD"'", uint64(m_NextDailyQuestReset));
}
void World::ResetWeeklyQuests()
{
DETAIL_LOG("Weekly quests reset for all characters.");
CharacterDatabase.Execute("DELETE FROM character_queststatus_weekly");
for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
if (itr->second->GetPlayer())
itr->second->GetPlayer()->ResetWeeklyQuestStatus();
m_NextWeeklyQuestReset = time_t(m_NextWeeklyQuestReset + WEEK);
CharacterDatabase.PExecute("UPDATE saved_variables SET NextWeeklyQuestResetTime = '"UI64FMTD"'", uint64(m_NextWeeklyQuestReset));
}
void World::ResetMonthlyQuests()
{
DETAIL_LOG("Monthly quests reset for all characters.");
CharacterDatabase.Execute("TRUNCATE character_queststatus_monthly");
for(SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
if (itr->second->GetPlayer())
itr->second->GetPlayer()->ResetMonthlyQuestStatus();
SetMonthlyQuestResetTime(false);
}
void World::SetPlayerLimit( int32 limit, bool needUpdate )
{
if (limit < -SEC_ADMINISTRATOR)
limit = -SEC_ADMINISTRATOR;
// lock update need
bool db_update_need = needUpdate || (limit < 0) != (m_playerLimit < 0) || (limit < 0 && m_playerLimit < 0 && limit != m_playerLimit);
m_playerLimit = limit;
if (db_update_need)
LoginDatabase.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID);
}
void World::UpdateMaxSessionCounters()
{
m_maxActiveSessionCount = std::max(m_maxActiveSessionCount,uint32(m_sessions.size()-m_QueuedPlayer.size()));
m_maxQueuedSessionCount = std::max(m_maxQueuedSessionCount,uint32(m_QueuedPlayer.size()));
}
void World::LoadDBVersion()
{
QueryResult* result = WorldDatabase.Query("SELECT version, creature_ai_version, cache_id FROM db_version LIMIT 1");
if(result)
{
Field* fields = result->Fetch();
m_DBVersion = fields[0].GetCppString();
m_CreatureEventAIVersion = fields[1].GetCppString();
// will be overwrite by config values if different and non-0
setConfig(CONFIG_UINT32_CLIENTCACHE_VERSION, fields[2].GetUInt32());
delete result;
}
if(m_DBVersion.empty())
m_DBVersion = "Unknown world database.";
if(m_CreatureEventAIVersion.empty())
m_CreatureEventAIVersion = "Unknown creature EventAI.";
}
void World::setConfig(eConfigUInt32Values index, char const* fieldname, uint32 defvalue)
{
setConfig(index, sConfig.GetIntDefault(fieldname,defvalue));
}
void World::setConfig(eConfigInt32Values index, char const* fieldname, int32 defvalue)
{
setConfig(index, sConfig.GetIntDefault(fieldname,defvalue));
}
void World::setConfig(eConfigFloatValues index, char const* fieldname, float defvalue)
{
setConfig(index, sConfig.GetFloatDefault(fieldname,defvalue));
}
void World::setConfig( eConfigBoolValues index, char const* fieldname, bool defvalue )
{
setConfig(index, sConfig.GetBoolDefault(fieldname,defvalue));
}
void World::setConfigPos(eConfigUInt32Values index, char const* fieldname, uint32 defvalue)
{
setConfig(index, fieldname, defvalue);
if (int32(getConfig(index)) < 0)
{
sLog.outError("%s (%i) can't be negative. Using %u instead.", fieldname, int32(getConfig(index)), defvalue);
setConfig(index, defvalue);
}
}
void World::setConfigPos(eConfigFloatValues index, char const* fieldname, float defvalue)
{
setConfig(index, fieldname, defvalue);
if (getConfig(index) < 0.0f)
{
sLog.outError("%s (%f) can't be negative. Using %f instead.", fieldname, getConfig(index), defvalue);
setConfig(index, defvalue);
}
}
void World::setConfigMin(eConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 minvalue)
{
setConfig(index, fieldname, defvalue);
if (getConfig(index) < minvalue)
{
sLog.outError("%s (%u) must be >= %u. Using %u instead.", fieldname, getConfig(index), minvalue, minvalue);
setConfig(index, minvalue);
}
}
void World::setConfigMin(eConfigInt32Values index, char const* fieldname, int32 defvalue, int32 minvalue)
{
setConfig(index, fieldname, defvalue);
if (getConfig(index) < minvalue)
{
sLog.outError("%s (%i) must be >= %i. Using %i instead.", fieldname, getConfig(index), minvalue, minvalue);
setConfig(index, minvalue);
}
}
void World::setConfigMin(eConfigFloatValues index, char const* fieldname, float defvalue, float minvalue)
{
setConfig(index, fieldname, defvalue);
if (getConfig(index) < minvalue)
{
sLog.outError("%s (%f) must be >= %f. Using %f instead.", fieldname, getConfig(index), minvalue, minvalue);
setConfig(index, minvalue);
}
}
void World::setConfigMinMax(eConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 minvalue, uint32 maxvalue)
{
setConfig(index, fieldname, defvalue);
if (getConfig(index) < minvalue)
{
sLog.outError("%s (%u) must be in range %u...%u. Using %u instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue);
setConfig(index, minvalue);
}
else if (getConfig(index) > maxvalue)
{
sLog.outError("%s (%u) must be in range %u...%u. Using %u instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue);
setConfig(index, maxvalue);
}
}
void World::setConfigMinMax(eConfigInt32Values index, char const* fieldname, int32 defvalue, int32 minvalue, int32 maxvalue)
{
setConfig(index, fieldname, defvalue);
if (getConfig(index) < minvalue)
{
sLog.outError("%s (%i) must be in range %i...%i. Using %i instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue);
setConfig(index, minvalue);
}
else if (getConfig(index) > maxvalue)
{
sLog.outError("%s (%i) must be in range %i...%i. Using %i instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue);
setConfig(index, maxvalue);
}
}
void World::setConfigMinMax(eConfigFloatValues index, char const* fieldname, float defvalue, float minvalue, float maxvalue)
{
setConfig(index, fieldname, defvalue);
if (getConfig(index) < minvalue)
{
sLog.outError("%s (%f) must be in range %f...%f. Using %f instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue);
setConfig(index, minvalue);
}
else if (getConfig(index) > maxvalue)
{
sLog.outError("%s (%f) must be in range %f...%f. Using %f instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue);
setConfig(index, maxvalue);
}
}
bool World::configNoReload(bool reload, eConfigUInt32Values index, char const* fieldname, uint32 defvalue)
{
if (!reload)
return true;
uint32 val = sConfig.GetIntDefault(fieldname, defvalue);
if (val != getConfig(index))
sLog.outError("%s option can't be changed at mangosd.conf reload, using current value (%u).", fieldname, getConfig(index));
return false;
}
bool World::configNoReload(bool reload, eConfigInt32Values index, char const* fieldname, int32 defvalue)
{
if (!reload)
return true;
int32 val = sConfig.GetIntDefault(fieldname, defvalue);
if (val != getConfig(index))
sLog.outError("%s option can't be changed at mangosd.conf reload, using current value (%i).", fieldname, getConfig(index));
return false;
}
bool World::configNoReload(bool reload, eConfigFloatValues index, char const* fieldname, float defvalue)
{
if (!reload)
return true;
float val = sConfig.GetFloatDefault(fieldname, defvalue);
if (val != getConfig(index))
sLog.outError("%s option can't be changed at mangosd.conf reload, using current value (%f).", fieldname, getConfig(index));
return false;
}
bool World::configNoReload(bool reload, eConfigBoolValues index, char const* fieldname, bool defvalue)
{
if (!reload)
return true;
bool val = sConfig.GetBoolDefault(fieldname, defvalue);
if (val != getConfig(index))
sLog.outError("%s option can't be changed at mangosd.conf reload, using current value (%s).", fieldname, getConfig(index) ? "'true'" : "'false'");
return false;
}