2 * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "Database/DatabaseEnv.h"
25 #include "Config/ConfigEnv.h"
26 #include "SystemConfig.h"
29 #include "WorldSession.h"
30 #include "WorldPacket.h"
34 #include "SkillExtraItems.h"
35 #include "SkillDiscovery.h"
37 #include "AccountMgr.h"
38 #include "AchievementMgr.h"
39 #include "AuctionHouseMgr.h"
40 #include "ObjectMgr.h"
41 #include "CreatureEventAIMgr.h"
44 #include "DBCStores.h"
46 #include "ItemEnchantmentMgr.h"
47 #include "MapManager.h"
48 #include "ScriptCalls.h"
49 #include "CreatureAIRegistry.h"
50 #include "Policies/SingletonImp.h"
51 #include "BattleGroundMgr.h"
52 #include "TemporarySummon.h"
53 #include "VMapFactory.h"
54 #include "GameEventMgr.h"
55 #include "PoolManager.h"
56 #include "Database/DatabaseImpl.h"
57 #include "GridNotifiersImpl.h"
59 #include "InstanceSaveMgr.h"
60 #include "WaypointManager.h"
61 #include "GMTicketMgr.h"
63 #include "CharacterDatabaseCleaner.h"
65 INSTANTIATE_SINGLETON_1( World
);
67 volatile bool World::m_stopEvent
= false;
68 uint8
World::m_ExitCode
= SHUTDOWN_EXIT_CODE
;
69 volatile uint32
World::m_worldLoopCounter
= 0;
71 float World::m_MaxVisibleDistanceOnContinents
= DEFAULT_VISIBILITY_DISTANCE
;
72 float World::m_MaxVisibleDistanceInInctances
= DEFAULT_VISIBILITY_INSTANCE
;
73 float World::m_MaxVisibleDistanceInBGArenas
= DEFAULT_VISIBILITY_BGARENAS
;
74 float World::m_MaxVisibleDistanceForObject
= DEFAULT_VISIBILITY_DISTANCE
;
76 float World::m_MaxVisibleDistanceInFlight
= DEFAULT_VISIBILITY_DISTANCE
;
77 float World::m_VisibleUnitGreyDistance
= 0;
78 float World::m_VisibleObjectGreyDistance
= 0;
84 m_allowMovement
= true;
87 m_gameTime
=time(NULL
);
88 m_startTime
=m_gameTime
;
89 m_maxActiveSessionCount
= 0;
90 m_maxQueuedSessionCount
= 0;
92 m_NextDailyQuestReset
= 0;
93 m_NextWeeklyQuestReset
= 0;
94 m_scheduledScripts
= 0;
96 m_defaultDbcLocale
= LOCALE_enUS
;
97 m_availableDbcLocaleMask
= 0;
99 for(int i
= 0; i
< CONFIG_UINT32_VALUE_COUNT
; ++i
)
100 m_configUint32Values
[i
] = 0;
102 for(int i
= 0; i
< CONFIG_INT32_VALUE_COUNT
; ++i
)
103 m_configInt32Values
[i
] = 0;
105 for(int i
= 0; i
< CONFIG_FLOAT_VALUE_COUNT
; ++i
)
106 m_configFloatValues
[i
] = 0.0f
;
108 for(int i
= 0; i
< CONFIG_BOOL_VALUE_COUNT
; ++i
)
109 m_configBoolValues
[i
] = false;
115 ///- Empty the kicked session set
116 while (!m_sessions
.empty())
118 // not remove from queue, prevent loading new sessions
119 delete m_sessions
.begin()->second
;
120 m_sessions
.erase(m_sessions
.begin());
123 ///- Empty the WeatherMap
124 for (WeatherMap::const_iterator itr
= m_weathers
.begin(); itr
!= m_weathers
.end(); ++itr
)
129 CliCommandHolder
* command
;
130 while (cliCmdQueue
.next(command
))
133 VMAP::VMapFactory::clear();
135 if(m_resultQueue
) delete m_resultQueue
;
137 //TODO free addSessQueue
140 /// Find a player in a specified zone
141 Player
* World::FindPlayerInZone(uint32 zone
)
143 ///- circle through active sessions and return the first player found in the zone
144 SessionMap::const_iterator itr
;
145 for (itr
= m_sessions
.begin(); itr
!= m_sessions
.end(); ++itr
)
149 Player
*player
= itr
->second
->GetPlayer();
152 if( player
->IsInWorld() && player
->GetZoneId() == zone
)
154 // Used by the weather system. We return the player to broadcast the change weather message to him and all players in the zone.
161 /// Find a session by its id
162 WorldSession
* World::FindSession(uint32 id
) const
164 SessionMap::const_iterator itr
= m_sessions
.find(id
);
166 if(itr
!= m_sessions
.end())
167 return itr
->second
; // also can return NULL for kicked session
172 /// Remove a given session
173 bool World::RemoveSession(uint32 id
)
175 ///- Find the session, kick the user, but we can't delete session at this moment to prevent iterator invalidation
176 SessionMap::const_iterator itr
= m_sessions
.find(id
);
178 if(itr
!= m_sessions
.end() && itr
->second
)
180 if (itr
->second
->PlayerLoading())
182 itr
->second
->KickPlayer();
188 void World::AddSession(WorldSession
* s
)
194 World::AddSession_ (WorldSession
* s
)
198 //NOTE - Still there is race condition in WorldSession* being used in the Sockets
200 ///- kick already loaded player with same account (if any) and remove session
201 ///- if player is in loading and want to load again, return
202 if (!RemoveSession (s
->GetAccountId ()))
205 delete s
; // session not added yet in session list, so not listed in queue
209 // decrease session counts only at not reconnection case
210 bool decrease_session
= true;
212 // if session already exist, prepare to it deleting at next world update
213 // NOTE - KickPlayer() should be called on "old" in RemoveSession()
215 SessionMap::const_iterator old
= m_sessions
.find(s
->GetAccountId ());
217 if(old
!= m_sessions
.end())
219 // prevent decrease sessions count if session queued
220 if(RemoveQueuedPlayer(old
->second
))
221 decrease_session
= false;
222 // not remove replaced session form queue if listed
227 m_sessions
[s
->GetAccountId ()] = s
;
229 uint32 Sessions
= GetActiveAndQueuedSessionCount ();
230 uint32 pLimit
= GetPlayerAmountLimit ();
231 uint32 QueueSize
= GetQueueSize (); //number of players in the queue
233 //so we don't count the user trying to
234 //login as a session and queue the socket that we are using
238 if (pLimit
> 0 && Sessions
>= pLimit
&& s
->GetSecurity () == SEC_PLAYER
)
241 UpdateMaxSessionCounters ();
242 DETAIL_LOG("PlayerQueue: Account id %u is in Queue Position (%u).", s
->GetAccountId (), ++QueueSize
);
246 WorldPacket
packet(SMSG_AUTH_RESPONSE
, 1 + 4 + 1 + 4 + 1);
247 packet
<< uint8 (AUTH_OK
);
248 packet
<< uint32 (0); // BillingTimeRemaining
249 packet
<< uint8 (0); // BillingPlanFlags
250 packet
<< uint32 (0); // BillingTimeRested
251 packet
<< uint8 (s
->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
252 s
->SendPacket (&packet
);
256 WorldPacket
pkt(SMSG_CLIENTCACHE_VERSION
, 4);
257 pkt
<< uint32(getConfig(CONFIG_UINT32_CLIENTCACHE_VERSION
));
260 s
->SendTutorialsData();
262 UpdateMaxSessionCounters ();
264 // Updates the population
267 float popu
= float(GetActiveSessionCount()); // updated number of users on the server
270 loginDatabase
.PExecute ("UPDATE realmlist SET population = '%f' WHERE id = '%d'", popu
, realmID
);
271 DETAIL_LOG("Server Population (%f).", popu
);
275 int32
World::GetQueuePos(WorldSession
* sess
)
279 for(Queue::const_iterator iter
= m_QueuedPlayer
.begin(); iter
!= m_QueuedPlayer
.end(); ++iter
, ++position
)
286 void World::AddQueuedPlayer(WorldSession
* sess
)
288 sess
->SetInQueue(true);
289 m_QueuedPlayer
.push_back (sess
);
291 // The 1st SMSG_AUTH_RESPONSE needs to contain other info too.
292 WorldPacket
packet (SMSG_AUTH_RESPONSE
, 1 + 4 + 1 + 4 + 1 + 4 + 1);
293 packet
<< uint8 (AUTH_WAIT_QUEUE
);
294 packet
<< uint32 (0); // BillingTimeRemaining
295 packet
<< uint8 (0); // BillingPlanFlags
296 packet
<< uint32 (0); // BillingTimeRested
297 packet
<< uint8 (sess
->Expansion()); // 0 - normal, 1 - TBC, must be set in database manually for each account
298 packet
<< uint32(GetQueuePos (sess
)); // position in queue
299 packet
<< uint8(0); // unk 3.3.0
300 sess
->SendPacket (&packet
);
303 bool World::RemoveQueuedPlayer(WorldSession
* sess
)
305 // sessions count including queued to remove (if removed_session set)
306 uint32 sessions
= GetActiveSessionCount();
309 Queue::iterator iter
= m_QueuedPlayer
.begin();
311 // search to remove and count skipped positions
314 for(;iter
!= m_QueuedPlayer
.end(); ++iter
, ++position
)
318 sess
->SetInQueue(false);
319 iter
= m_QueuedPlayer
.erase(iter
);
320 found
= true; // removing queued session
325 // iter point to next socked after removed or end()
326 // position store position of removed socket and then new position next socket after removed
328 // if session not queued then we need decrease sessions count
329 if(!found
&& sessions
)
332 // accept first in queue
333 if( (!m_playerLimit
|| (int32
)sessions
< m_playerLimit
) && !m_QueuedPlayer
.empty() )
335 WorldSession
* pop_sess
= m_QueuedPlayer
.front();
336 pop_sess
->SetInQueue(false);
337 pop_sess
->SendAuthWaitQue(0);
338 pop_sess
->SendAddonsInfo();
340 WorldPacket
pkt(SMSG_CLIENTCACHE_VERSION
, 4);
341 pkt
<< uint32(getConfig(CONFIG_UINT32_CLIENTCACHE_VERSION
));
342 pop_sess
->SendPacket(&pkt
);
344 pop_sess
->SendAccountDataTimes(GLOBAL_CACHE_MASK
);
345 pop_sess
->SendTutorialsData();
347 m_QueuedPlayer
.pop_front();
349 // update iter to point first queued socket or end() if queue is empty now
350 iter
= m_QueuedPlayer
.begin();
354 // update position from iter to end()
355 // iter point to first not updated socket, position store new position
356 for(; iter
!= m_QueuedPlayer
.end(); ++iter
, ++position
)
357 (*iter
)->SendAuthWaitQue(position
);
362 /// Find a Weather object by the given zoneid
363 Weather
* World::FindWeather(uint32 id
) const
365 WeatherMap::const_iterator itr
= m_weathers
.find(id
);
367 if(itr
!= m_weathers
.end())
373 /// Remove a Weather object for the given zoneid
374 void World::RemoveWeather(uint32 id
)
376 // not called at the moment. Kept for completeness
377 WeatherMap::iterator itr
= m_weathers
.find(id
);
379 if(itr
!= m_weathers
.end())
382 m_weathers
.erase(itr
);
386 /// Add a Weather object to the list
387 Weather
* World::AddWeather(uint32 zone_id
)
389 WeatherZoneChances
const* weatherChances
= sObjectMgr
.GetWeatherChances(zone_id
);
391 // zone not have weather, ignore
395 Weather
* w
= new Weather(zone_id
,weatherChances
);
396 m_weathers
[w
->GetZone()] = w
;
402 /// Initialize config values
403 void World::LoadConfigSettings(bool reload
)
407 if(!sConfig
.Reload())
409 sLog
.outError("World settings reload fail: can't read settings from %s.",sConfig
.GetFilename().c_str());
414 ///- Read the version of the configuration file and warn the user in case of emptiness or mismatch
415 uint32 confVersion
= sConfig
.GetIntDefault("ConfVersion", 0);
418 sLog
.outError("*****************************************************************************");
419 sLog
.outError(" WARNING: mangosd.conf does not include a ConfVersion variable.");
420 sLog
.outError(" Your configuration file may be out of date!");
421 sLog
.outError("*****************************************************************************");
422 Log::WaitBeforeContinueIfNeed();
426 if (confVersion
< _MANGOSDCONFVERSION
)
428 sLog
.outError("*****************************************************************************");
429 sLog
.outError(" WARNING: Your mangosd.conf version indicates your conf file is out of date!");
430 sLog
.outError(" Please check for updates, as your current default values may cause");
431 sLog
.outError(" unexpected behavior.");
432 sLog
.outError("*****************************************************************************");
433 Log::WaitBeforeContinueIfNeed();
437 ///- Read the player limit and the Message of the day from the config file
438 SetPlayerLimit( sConfig
.GetIntDefault("PlayerLimit", DEFAULT_PLAYER_LIMIT
), true );
439 SetMotd( sConfig
.GetStringDefault("Motd", "Welcome to the Massive Network Game Object Server." ) );
441 ///- Read all rates from the config file
442 setConfigPos(CONFIG_FLOAT_RATE_HEALTH
, "Rate.Health", 1.0f
);
443 setConfigPos(CONFIG_FLOAT_RATE_POWER_MANA
, "Rate.Mana", 1.0f
);
444 setConfig(CONFIG_FLOAT_RATE_POWER_RAGE_INCOME
, "Rate.Rage.Income", 1.0f
);
445 setConfigPos(CONFIG_FLOAT_RATE_POWER_RAGE_LOSS
, "Rate.Rage.Loss", 1.0f
);
446 setConfig(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_INCOME
, "Rate.RunicPower.Income", 1.0f
);
447 setConfigPos(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_LOSS
, "Rate.RunicPower.Loss", 1.0f
);
448 setConfig(CONFIG_FLOAT_RATE_POWER_FOCUS
, "Rate.Focus", 1.0f
);
449 setConfigPos(CONFIG_FLOAT_RATE_SKILL_DISCOVERY
, "Rate.Skill.Discovery", 1.0f
);
450 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_POOR
, "Rate.Drop.Item.Poor", 1.0f
);
451 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_NORMAL
, "Rate.Drop.Item.Normal", 1.0f
);
452 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_UNCOMMON
, "Rate.Drop.Item.Uncommon", 1.0f
);
453 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_RARE
, "Rate.Drop.Item.Rare", 1.0f
);
454 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_EPIC
, "Rate.Drop.Item.Epic", 1.0f
);
455 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_LEGENDARY
, "Rate.Drop.Item.Legendary", 1.0f
);
456 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_ARTIFACT
, "Rate.Drop.Item.Artifact", 1.0f
);
457 setConfigPos(CONFIG_FLOAT_RATE_DROP_ITEM_REFERENCED
, "Rate.Drop.Item.Referenced", 1.0f
);
458 setConfigPos(CONFIG_FLOAT_RATE_DROP_MONEY
, "Rate.Drop.Money", 1.0f
);
459 setConfig(CONFIG_FLOAT_RATE_XP_KILL
, "Rate.XP.Kill", 1.0f
);
460 setConfig(CONFIG_FLOAT_RATE_XP_QUEST
, "Rate.XP.Quest", 1.0f
);
461 setConfig(CONFIG_FLOAT_RATE_XP_EXPLORE
, "Rate.XP.Explore", 1.0f
);
462 setConfig(CONFIG_FLOAT_RATE_REPUTATION_GAIN
, "Rate.Reputation.Gain", 1.0f
);
463 setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_KILL
, "Rate.Reputation.LowLevel.Kill", 1.0f
);
464 setConfig(CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_QUEST
, "Rate.Reputation.LowLevel.Quest", 1.0f
);
465 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_DAMAGE
, "Rate.Creature.Normal.Damage", 1.0f
);
466 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_DAMAGE
, "Rate.Creature.Elite.Elite.Damage", 1.0f
);
467 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_DAMAGE
, "Rate.Creature.Elite.RAREELITE.Damage", 1.0f
);
468 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_DAMAGE
, "Rate.Creature.Elite.WORLDBOSS.Damage", 1.0f
);
469 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_DAMAGE
, "Rate.Creature.Elite.RARE.Damage", 1.0f
);
470 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_HP
, "Rate.Creature.Normal.HP", 1.0f
);
471 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_HP
, "Rate.Creature.Elite.Elite.HP", 1.0f
);
472 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_HP
, "Rate.Creature.Elite.RAREELITE.HP", 1.0f
);
473 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_HP
, "Rate.Creature.Elite.WORLDBOSS.HP", 1.0f
);
474 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_HP
, "Rate.Creature.Elite.RARE.HP", 1.0f
);
475 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_NORMAL_SPELLDAMAGE
, "Rate.Creature.Normal.SpellDamage", 1.0f
);
476 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_ELITE_SPELLDAMAGE
, "Rate.Creature.Elite.Elite.SpellDamage", 1.0f
);
477 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RAREELITE_SPELLDAMAGE
, "Rate.Creature.Elite.RAREELITE.SpellDamage", 1.0f
);
478 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_WORLDBOSS_SPELLDAMAGE
, "Rate.Creature.Elite.WORLDBOSS.SpellDamage", 1.0f
);
479 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_ELITE_RARE_SPELLDAMAGE
, "Rate.Creature.Elite.RARE.SpellDamage", 1.0f
);
480 setConfigPos(CONFIG_FLOAT_RATE_CREATURE_AGGRO
, "Rate.Creature.Aggro", 1.0f
);
481 setConfig(CONFIG_FLOAT_RATE_REST_INGAME
, "Rate.Rest.InGame", 1.0f
);
482 setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_TAVERN_OR_CITY
, "Rate.Rest.Offline.InTavernOrCity", 1.0f
);
483 setConfig(CONFIG_FLOAT_RATE_REST_OFFLINE_IN_WILDERNESS
, "Rate.Rest.Offline.InWilderness", 1.0f
);
484 setConfigPos(CONFIG_FLOAT_RATE_DAMAGE_FALL
, "Rate.Damage.Fall", 1.0f
);
485 setConfigPos(CONFIG_FLOAT_RATE_AUCTION_TIME
, "Rate.Auction.Time", 1.0f
);
486 setConfig(CONFIG_FLOAT_RATE_AUCTION_DEPOSIT
, "Rate.Auction.Deposit", 1.0f
);
487 setConfig(CONFIG_FLOAT_RATE_AUCTION_CUT
, "Rate.Auction.Cut", 1.0f
);
488 setConfig(CONFIG_FLOAT_RATE_HONOR
, "Rate.Honor",1.0f
);
489 setConfigPos(CONFIG_FLOAT_RATE_MINING_AMOUNT
, "Rate.Mining.Amount", 1.0f
);
490 setConfigPos(CONFIG_FLOAT_RATE_MINING_NEXT
, "Rate.Mining.Next", 1.0f
);
491 setConfigPos(CONFIG_FLOAT_RATE_INSTANCE_RESET_TIME
, "Rate.InstanceResetTime", 1.0f
);
492 setConfigPos(CONFIG_FLOAT_RATE_TALENT
, "Rate.Talent", 1.0f
);
493 setConfigPos(CONFIG_FLOAT_RATE_CORPSE_DECAY_LOOTED
, "Rate.Corpse.Decay.Looted", 0.1f
);
495 setConfigMinMax(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE
, "TargetPosRecalculateRange", 1.5f
, CONTACT_DISTANCE
, ATTACK_DISTANCE
);
497 setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_DAMAGE
, "DurabilityLossChance.Damage", 0.5f
);
498 setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_ABSORB
, "DurabilityLossChance.Absorb", 0.5f
);
499 setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_PARRY
, "DurabilityLossChance.Parry", 0.05f
);
500 setConfigPos(CONFIG_FLOAT_RATE_DURABILITY_LOSS_BLOCK
, "DurabilityLossChance.Block", 0.05f
);
502 setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_SAY
, "ListenRange.Say", 25.0f
);
503 setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_YELL
, "ListenRange.Yell", 300.0f
);
504 setConfigPos(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE
, "ListenRange.TextEmote", 25.0f
);
506 setConfigPos(CONFIG_FLOAT_GROUP_XP_DISTANCE
, "MaxGroupXPDistance", 74.0f
);
507 setConfigPos(CONFIG_FLOAT_SIGHT_GUARDER
, "GuarderSight", 50.0f
);
508 setConfigPos(CONFIG_FLOAT_SIGHT_MONSTER
, "MonsterSight", 50.0f
);
510 setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS
, "CreatureFamilyAssistanceRadius", 10.0f
);
511 setConfigPos(CONFIG_FLOAT_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS
, "CreatureFamilyFleeAssistanceRadius", 30.0f
);
513 ///- Read other configuration items from the config file
514 setConfigMinMax(CONFIG_UINT32_COMPRESSION
, "Compression", 1, 1, 9);
515 setConfig(CONFIG_BOOL_ADDON_CHANNEL
, "AddonChannel", true);
516 setConfig(CONFIG_BOOL_CLEAN_CHARACTER_DB
, "CleanCharacterDB", true);
517 setConfig(CONFIG_BOOL_GRID_UNLOAD
, "GridUnload", true);
518 setConfigPos(CONFIG_UINT32_INTERVAL_SAVE
, "PlayerSave.Interval", 15 * MINUTE
* IN_MILLISECONDS
);
519 setConfigMinMax(CONFIG_UINT32_MIN_LEVEL_STAT_SAVE
, "PlayerSave.Stats.MinLevel", 0, 0, MAX_LEVEL
);
520 setConfig(CONFIG_BOOL_STATS_SAVE_ONLY_ON_LOGOUT
, "PlayerSave.Stats.SaveOnlyOnLogout", true);
522 setConfigMin(CONFIG_UINT32_INTERVAL_GRIDCLEAN
, "GridCleanUpDelay", 5 * MINUTE
* IN_MILLISECONDS
, MIN_GRID_DELAY
);
524 sMapMgr
.SetGridCleanUpDelay(getConfig(CONFIG_UINT32_INTERVAL_GRIDCLEAN
));
526 setConfigMin(CONFIG_UINT32_INTERVAL_MAPUPDATE
, "MapUpdateInterval", 100, MIN_MAP_UPDATE_DELAY
);
528 sMapMgr
.SetMapUpdateInterval(getConfig(CONFIG_UINT32_INTERVAL_MAPUPDATE
));
530 setConfig(CONFIG_UINT32_INTERVAL_CHANGEWEATHER
, "ChangeWeatherInterval", 10 * MINUTE
* IN_MILLISECONDS
);
532 if (configNoReload(reload
, CONFIG_UINT32_PORT_WORLD
, "WorldServerPort", DEFAULT_WORLDSERVER_PORT
))
533 setConfig(CONFIG_UINT32_PORT_WORLD
, "WorldServerPort", DEFAULT_WORLDSERVER_PORT
);
535 if (configNoReload(reload
, CONFIG_UINT32_SOCKET_SELECTTIME
, "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME
))
536 setConfig(CONFIG_UINT32_SOCKET_SELECTTIME
, "SocketSelectTime", DEFAULT_SOCKET_SELECT_TIME
);
538 if (configNoReload(reload
, CONFIG_UINT32_GAME_TYPE
, "GameType", 0))
539 setConfig(CONFIG_UINT32_GAME_TYPE
, "GameType", 0);
541 if (configNoReload(reload
, CONFIG_UINT32_REALM_ZONE
, "RealmZone", REALM_ZONE_DEVELOPMENT
))
542 setConfig(CONFIG_UINT32_REALM_ZONE
, "RealmZone", REALM_ZONE_DEVELOPMENT
);
544 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ACCOUNTS
, "AllowTwoSide.Accounts", true);
545 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHAT
, "AllowTwoSide.Interaction.Chat", false);
546 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_CHANNEL
, "AllowTwoSide.Interaction.Channel", false);
547 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GROUP
, "AllowTwoSide.Interaction.Group", false);
548 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GUILD
, "AllowTwoSide.Interaction.Guild", false);
549 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_AUCTION
, "AllowTwoSide.Interaction.Auction", false);
550 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_MAIL
, "AllowTwoSide.Interaction.Mail", false);
551 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_WHO_LIST
, "AllowTwoSide.WhoList", false);
552 setConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_ADD_FRIEND
, "AllowTwoSide.AddFriend", false);
554 setConfig(CONFIG_UINT32_STRICT_PLAYER_NAMES
, "StrictPlayerNames", 0);
555 setConfig(CONFIG_UINT32_STRICT_CHARTER_NAMES
, "StrictCharterNames", 0);
556 setConfig(CONFIG_UINT32_STRICT_PET_NAMES
, "StrictPetNames", 0);
558 setConfigMinMax(CONFIG_UINT32_MIN_PLAYER_NAME
, "MinPlayerName", 2, 1, MAX_PLAYER_NAME
);
559 setConfigMinMax(CONFIG_UINT32_MIN_CHARTER_NAME
, "MinCharterName", 2, 1, MAX_CHARTER_NAME
);
560 setConfigMinMax(CONFIG_UINT32_MIN_PET_NAME
, "MinPetName", 2, 1, MAX_PET_NAME
);
562 setConfig(CONFIG_UINT32_CHARACTERS_CREATING_DISABLED
, "CharactersCreatingDisabled", 0);
564 setConfigMinMax(CONFIG_UINT32_CHARACTERS_PER_REALM
, "CharactersPerRealm", 10, 1, 10);
566 // must be after CONFIG_UINT32_CHARACTERS_PER_REALM
567 setConfigMin(CONFIG_UINT32_CHARACTERS_PER_ACCOUNT
, "CharactersPerAccount", 50, getConfig(CONFIG_UINT32_CHARACTERS_PER_REALM
));
569 setConfigMinMax(CONFIG_UINT32_HEROIC_CHARACTERS_PER_REALM
, "HeroicCharactersPerRealm", 1, 1, 10);
571 setConfig(CONFIG_UINT32_MIN_LEVEL_FOR_HEROIC_CHARACTER_CREATING
, "MinLevelForHeroicCharacterCreating", 55);
573 setConfigMinMax(CONFIG_UINT32_SKIP_CINEMATICS
, "SkipCinematics", 0, 0, 2);
575 if (configNoReload(reload
, CONFIG_UINT32_MAX_PLAYER_LEVEL
, "MaxPlayerLevel", DEFAULT_MAX_LEVEL
))
576 setConfigMinMax(CONFIG_UINT32_MAX_PLAYER_LEVEL
, "MaxPlayerLevel", DEFAULT_MAX_LEVEL
, 1, DEFAULT_MAX_LEVEL
);
578 setConfigMinMax(CONFIG_UINT32_START_PLAYER_LEVEL
, "StartPlayerLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL
));
579 setConfigMinMax(CONFIG_UINT32_START_HEROIC_PLAYER_LEVEL
, "StartHeroicPlayerLevel", 55, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL
));
581 setConfigMinMax(CONFIG_UINT32_START_PLAYER_MONEY
, "StartPlayerMoney", 0, 0, MAX_MONEY_AMOUNT
);
583 setConfigPos(CONFIG_UINT32_MAX_HONOR_POINTS
, "MaxHonorPoints", 75000);
585 setConfigMinMax(CONFIG_UINT32_START_HONOR_POINTS
, "StartHonorPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_HONOR_POINTS
));
587 setConfigPos(CONFIG_UINT32_MAX_ARENA_POINTS
, "MaxArenaPoints", 5000);
589 setConfigMinMax(CONFIG_UINT32_START_ARENA_POINTS
, "StartArenaPoints", 0, 0, getConfig(CONFIG_UINT32_MAX_ARENA_POINTS
));
591 setConfig(CONFIG_BOOL_ALL_TAXI_PATHS
, "AllFlightPaths", false);
593 setConfig(CONFIG_BOOL_INSTANCE_IGNORE_LEVEL
, "Instance.IgnoreLevel", false);
594 setConfig(CONFIG_BOOL_INSTANCE_IGNORE_RAID
, "Instance.IgnoreRaid", false);
596 setConfig(CONFIG_BOOL_CAST_UNSTUCK
, "CastUnstuck", true);
597 setConfig(CONFIG_UINT32_MAX_SPELL_CASTS_IN_CHAIN
, "MaxSpellCastsInChain", 10);
598 setConfig(CONFIG_UINT32_INSTANCE_RESET_TIME_HOUR
, "Instance.ResetTimeHour", 4);
599 setConfig(CONFIG_UINT32_INSTANCE_UNLOAD_DELAY
, "Instance.UnloadDelay", 30 * MINUTE
* IN_MILLISECONDS
);
601 setConfig(CONFIG_UINT32_MAX_PRIMARY_TRADE_SKILL
, "MaxPrimaryTradeSkill", 2);
602 setConfigMinMax(CONFIG_UINT32_MIN_PETITION_SIGNS
, "MinPetitionSigns", 9, 0, 9);
604 setConfig(CONFIG_UINT32_GM_LOGIN_STATE
, "GM.LoginState", 2);
605 setConfig(CONFIG_UINT32_GM_VISIBLE_STATE
, "GM.Visible", 2);
606 setConfig(CONFIG_UINT32_GM_ACCEPT_TICKETS
, "GM.AcceptTickets", 2);
607 setConfig(CONFIG_UINT32_GM_CHAT
, "GM.Chat", 2);
608 setConfig(CONFIG_UINT32_GM_WISPERING_TO
, "GM.WhisperingTo", 2);
610 setConfig(CONFIG_UINT32_GM_LEVEL_IN_GM_LIST
, "GM.InGMList.Level", SEC_ADMINISTRATOR
);
611 setConfig(CONFIG_UINT32_GM_LEVEL_IN_WHO_LIST
, "GM.InWhoList.Level", SEC_ADMINISTRATOR
);
612 setConfig(CONFIG_BOOL_GM_LOG_TRADE
, "GM.LogTrade", false);
614 setConfigMinMax(CONFIG_UINT32_START_GM_LEVEL
, "GM.StartLevel", 1, getConfig(CONFIG_UINT32_START_PLAYER_LEVEL
), MAX_LEVEL
);
615 setConfig(CONFIG_BOOL_GM_LOWER_SECURITY
, "GM.LowerSecurity", false);
616 setConfig(CONFIG_BOOL_GM_ALLOW_ACHIEVEMENT_GAINS
, "GM.AllowAchievementGain", true);
618 setConfig(CONFIG_UINT32_GROUP_VISIBILITY
, "Visibility.GroupMode", 0);
620 setConfig(CONFIG_UINT32_MAIL_DELIVERY_DELAY
, "MailDeliveryDelay", HOUR
);
622 setConfigPos(CONFIG_UINT32_UPTIME_UPDATE
, "UpdateUptimeInterval", 10);
625 m_timers
[WUPDATE_UPTIME
].SetInterval(getConfig(CONFIG_UINT32_UPTIME_UPDATE
)*MINUTE
*IN_MILLISECONDS
);
626 m_timers
[WUPDATE_UPTIME
].Reset();
629 setConfig(CONFIG_UINT32_SKILL_CHANCE_ORANGE
, "SkillChance.Orange", 100);
630 setConfig(CONFIG_UINT32_SKILL_CHANCE_YELLOW
, "SkillChance.Yellow", 75);
631 setConfig(CONFIG_UINT32_SKILL_CHANCE_GREEN
, "SkillChance.Green", 25);
632 setConfig(CONFIG_UINT32_SKILL_CHANCE_GREY
, "SkillChance.Grey", 0);
634 setConfigPos(CONFIG_UINT32_SKILL_CHANCE_MINING_STEPS
, "SkillChance.MiningSteps", 75);
635 setConfigPos(CONFIG_UINT32_SKILL_CHANCE_SKINNING_STEPS
, "SkillChance.SkinningSteps", 75);
637 setConfig(CONFIG_BOOL_SKILL_PROSPECTING
, "SkillChance.Prospecting", false);
638 setConfig(CONFIG_BOOL_SKILL_MILLING
, "SkillChance.Milling", false);
640 setConfigPos(CONFIG_UINT32_SKILL_GAIN_CRAFTING
, "SkillGain.Crafting", 1);
641 setConfigPos(CONFIG_UINT32_SKILL_GAIN_DEFENSE
, "SkillGain.Defense", 1);
642 setConfigPos(CONFIG_UINT32_SKILL_GAIN_GATHERING
, "SkillGain.Gathering", 1);
643 setConfig(CONFIG_UINT32_SKILL_GAIN_WEAPON
, "SkillGain.Weapon", 1);
645 setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS
, "MaxOverspeedPings", 2);
646 if (getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS
) != 0 && getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS
) < 2)
648 sLog
.outError("MaxOverspeedPings (%i) must be in range 2..infinity (or 0 to disable check). Set to 2.", getConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS
));
649 setConfig(CONFIG_UINT32_MAX_OVERSPEED_PINGS
, 2);
652 setConfig(CONFIG_BOOL_SAVE_RESPAWN_TIME_IMMEDIATLY
, "SaveRespawnTimeImmediately", true);
653 setConfig(CONFIG_BOOL_WEATHER
, "ActivateWeather", true);
655 setConfig(CONFIG_BOOL_ALWAYS_MAX_SKILL_FOR_LEVEL
, "AlwaysMaxSkillForLevel", false);
657 if (configNoReload(reload
, CONFIG_UINT32_EXPANSION
, "Expansion", MAX_EXPANSION
))
658 setConfigMinMax(CONFIG_UINT32_EXPANSION
, "Expansion", MAX_EXPANSION
, 0, MAX_EXPANSION
);
660 setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_COUNT
, "ChatFlood.MessageCount", 10);
661 setConfig(CONFIG_UINT32_CHATFLOOD_MESSAGE_DELAY
, "ChatFlood.MessageDelay", 1);
662 setConfig(CONFIG_UINT32_CHATFLOOD_MUTE_TIME
, "ChatFlood.MuteTime", 10);
664 setConfig(CONFIG_BOOL_EVENT_ANNOUNCE
, "Event.Announce", false);
666 setConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY
, "CreatureFamilyAssistanceDelay", 1500);
667 setConfig(CONFIG_UINT32_CREATURE_FAMILY_FLEE_DELAY
, "CreatureFamilyFleeDelay", 7000);
669 setConfig(CONFIG_UINT32_WORLD_BOSS_LEVEL_DIFF
, "WorldBossLevelDiff", 3);
671 // note: disable value (-1) will assigned as 0xFFFFFFF, to prevent overflow at calculations limit it to max possible player level MAX_LEVEL(100)
672 setConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF
, "Quests.LowLevelHideDiff", 4);
673 if (getConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF
) > MAX_LEVEL
)
674 setConfig(CONFIG_UINT32_QUEST_LOW_LEVEL_HIDE_DIFF
, MAX_LEVEL
);
675 setConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF
, "Quests.HighLevelHideDiff", 7);
676 if (getConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF
) > MAX_LEVEL
)
677 setConfig(CONFIG_UINT32_QUEST_HIGH_LEVEL_HIDE_DIFF
, MAX_LEVEL
);
679 setConfigMinMax(CONFIG_UINT32_QUEST_DAILY_RESET_HOUR
, "Quests.Daily.ResetHour", 6, 0, 23);
680 setConfigMinMax(CONFIG_UINT32_QUEST_WEEKLY_RESET_WEEK_DAY
, "Quests.Weekly.ResetWeekDay", 3, 0, 6);
681 setConfigMinMax(CONFIG_UINT32_QUEST_WEEKLY_RESET_HOUR
, "Quests.Weekly.ResetHour", 6, 0 , 23);
683 setConfig(CONFIG_BOOL_DETECT_POS_COLLISION
, "DetectPosCollision", true);
685 setConfig(CONFIG_BOOL_RESTRICTED_LFG_CHANNEL
, "Channel.RestrictedLfg", true);
686 setConfig(CONFIG_BOOL_SILENTLY_GM_JOIN_TO_CHANNEL
, "Channel.SilentlyGMJoin", false);
688 setConfig(CONFIG_BOOL_TALENTS_INSPECTING
, "TalentsInspecting", true);
689 setConfig(CONFIG_BOOL_CHAT_FAKE_MESSAGE_PREVENTING
, "ChatFakeMessagePreventing", false);
691 setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_SEVERITY
, "ChatStrictLinkChecking.Severity", 0);
692 setConfig(CONFIG_UINT32_CHAT_STRICT_LINK_CHECKING_KICK
, "ChatStrictLinkChecking.Kick", 0);
694 setConfig(CONFIG_BOOL_CORPSE_EMPTY_LOOT_SHOW
, "Corpse.EmptyLootShow", true);
695 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_NORMAL
, "Corpse.Decay.NORMAL", 60);
696 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_RARE
, "Corpse.Decay.RARE", 300);
697 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_ELITE
, "Corpse.Decay.ELITE", 300);
698 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_RAREELITE
, "Corpse.Decay.RAREELITE", 300);
699 setConfigPos(CONFIG_UINT32_CORPSE_DECAY_WORLDBOSS
, "Corpse.Decay.WORLDBOSS", 3600);
701 setConfig(CONFIG_INT32_DEATH_SICKNESS_LEVEL
, "Death.SicknessLevel", 11);
703 setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVP
, "Death.CorpseReclaimDelay.PvP", true);
704 setConfig(CONFIG_BOOL_DEATH_CORPSE_RECLAIM_DELAY_PVE
, "Death.CorpseReclaimDelay.PvE", true);
705 setConfig(CONFIG_BOOL_DEATH_BONES_WORLD
, "Death.Bones.World", true);
706 setConfig(CONFIG_BOOL_DEATH_BONES_BG_OR_ARENA
, "Death.Bones.BattlegroundOrArena", true);
708 setConfig(CONFIG_FLOAT_THREAT_RADIUS
, "ThreatRadius", 100.0f
);
710 // always use declined names in the russian client
711 if (getConfig(CONFIG_UINT32_REALM_ZONE
) == REALM_ZONE_RUSSIAN
)
712 setConfig(CONFIG_BOOL_DECLINED_NAMES_USED
, true);
714 setConfig(CONFIG_BOOL_DECLINED_NAMES_USED
, "DeclinedNames", false);
716 setConfig(CONFIG_BOOL_BATTLEGROUND_CAST_DESERTER
, "Battleground.CastDeserter", true);
717 setConfigMinMax(CONFIG_UINT32_BATTLEGROUND_QUEUE_ANNOUNCER_JOIN
, "Battleground.QueueAnnouncer.Join", 0, 0, 2);
718 setConfig(CONFIG_BOOL_BATTLEGROUND_QUEUE_ANNOUNCER_START
, "Battleground.QueueAnnouncer.Start", false);
719 setConfig(CONFIG_UINT32_BATTLEGROUND_INVITATION_TYPE
, "Battleground.InvitationType", 0);
720 setConfig(CONFIG_UINT32_BATTLEGROUND_PREMATURE_FINISH_TIMER
, "BattleGround.PrematureFinishTimer", 5 * MINUTE
* IN_MILLISECONDS
);
721 setConfig(CONFIG_UINT32_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH
, "BattleGround.PremadeGroupWaitForMatch", 30 * MINUTE
* IN_MILLISECONDS
);
722 setConfig(CONFIG_UINT32_ARENA_MAX_RATING_DIFFERENCE
, "Arena.MaxRatingDifference", 150);
723 setConfig(CONFIG_UINT32_ARENA_RATING_DISCARD_TIMER
, "Arena.RatingDiscardTimer", 10 * MINUTE
* IN_MILLISECONDS
);
724 setConfig(CONFIG_BOOL_ARENA_AUTO_DISTRIBUTE_POINTS
, "Arena.AutoDistributePoints", false);
725 setConfig(CONFIG_UINT32_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS
, "Arena.AutoDistributeInterval", 7);
726 setConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_JOIN
, "Arena.QueueAnnouncer.Join", false);
727 setConfig(CONFIG_BOOL_ARENA_QUEUE_ANNOUNCER_EXIT
, "Arena.QueueAnnouncer.Exit", false);
728 setConfig(CONFIG_UINT32_ARENA_SEASON_ID
, "Arena.ArenaSeason.ID", 1);
729 setConfig(CONFIG_BOOL_ARENA_SEASON_IN_PROGRESS
, "Arena.ArenaSeason.InProgress", true);
731 setConfig(CONFIG_BOOL_OFFHAND_CHECK_AT_TALENTS_RESET
, "OffhandCheckAtTalentsReset", false);
733 setConfig(CONFIG_BOOL_KICK_PLAYER_ON_BAD_PACKET
, "Network.KickOnBadPacket", false);
735 if(int clientCacheId
= sConfig
.GetIntDefault("ClientCacheVersion", 0))
737 // overwrite DB/old value
738 if(clientCacheId
> 0)
740 setConfig(CONFIG_UINT32_CLIENTCACHE_VERSION
, clientCacheId
);
741 sLog
.outString("Client cache version set to: %u", clientCacheId
);
744 sLog
.outError("ClientCacheVersion can't be negative %d, ignored.", clientCacheId
);
747 setConfig(CONFIG_UINT32_INSTANT_LOGOUT
, "InstantLogout", SEC_MODERATOR
);
749 setConfigMin(CONFIG_UINT32_GUILD_EVENT_LOG_COUNT
, "Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS
, GUILD_EVENTLOG_MAX_RECORDS
);
750 setConfigMin(CONFIG_UINT32_GUILD_BANK_EVENT_LOG_COUNT
, "Guild.BankEventLogRecordsCount", GUILD_BANK_MAX_LOGS
, GUILD_BANK_MAX_LOGS
);
752 setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_GMLEVEL
, "TimerBar.Fatigue.GMLevel", SEC_CONSOLE
);
753 setConfig(CONFIG_UINT32_TIMERBAR_FATIGUE_MAX
, "TimerBar.Fatigue.Max", 60);
754 setConfig(CONFIG_UINT32_TIMERBAR_BREATH_GMLEVEL
, "TimerBar.Breath.GMLevel", SEC_CONSOLE
);
755 setConfig(CONFIG_UINT32_TIMERBAR_BREATH_MAX
, "TimerBar.Breath.Max", 180);
756 setConfig(CONFIG_UINT32_TIMERBAR_FIRE_GMLEVEL
, "TimerBar.Fire.GMLevel", SEC_CONSOLE
);
757 setConfig(CONFIG_UINT32_TIMERBAR_FIRE_MAX
, "TimerBar.Fire.Max", 1);
759 m_VisibleUnitGreyDistance
= sConfig
.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
760 if(m_VisibleUnitGreyDistance
> MAX_VISIBILITY_DISTANCE
)
762 sLog
.outError("Visibility.Distance.Grey.Unit can't be greater %f",MAX_VISIBILITY_DISTANCE
);
763 m_VisibleUnitGreyDistance
= MAX_VISIBILITY_DISTANCE
;
765 m_VisibleObjectGreyDistance
= sConfig
.GetFloatDefault("Visibility.Distance.Grey.Object", 10);
766 if(m_VisibleObjectGreyDistance
> MAX_VISIBILITY_DISTANCE
)
768 sLog
.outError("Visibility.Distance.Grey.Object can't be greater %f",MAX_VISIBILITY_DISTANCE
);
769 m_VisibleObjectGreyDistance
= MAX_VISIBILITY_DISTANCE
;
772 //visibility on continents
773 m_MaxVisibleDistanceOnContinents
= sConfig
.GetFloatDefault("Visibility.Distance.Continents", DEFAULT_VISIBILITY_DISTANCE
);
774 if(m_MaxVisibleDistanceOnContinents
< 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
))
776 sLog
.outError("Visibility.Distance.Continents can't be less max aggro radius %f", 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
));
777 m_MaxVisibleDistanceOnContinents
= 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
);
779 else if(m_MaxVisibleDistanceOnContinents
+ m_VisibleUnitGreyDistance
> MAX_VISIBILITY_DISTANCE
)
781 sLog
.outError("Visibility.Distance.Continents can't be greater %f",MAX_VISIBILITY_DISTANCE
- m_VisibleUnitGreyDistance
);
782 m_MaxVisibleDistanceOnContinents
= MAX_VISIBILITY_DISTANCE
- m_VisibleUnitGreyDistance
;
785 //visibility in instances
786 m_MaxVisibleDistanceInInctances
= sConfig
.GetFloatDefault("Visibility.Distance.Instances", DEFAULT_VISIBILITY_INSTANCE
);
787 if(m_MaxVisibleDistanceInInctances
< 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
))
789 sLog
.outError("Visibility.Distance.Instances can't be less max aggro radius %f",45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
));
790 m_MaxVisibleDistanceInInctances
= 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
);
792 else if(m_MaxVisibleDistanceInInctances
+ m_VisibleUnitGreyDistance
> MAX_VISIBILITY_DISTANCE
)
794 sLog
.outError("Visibility.Distance.Instances can't be greater %f",MAX_VISIBILITY_DISTANCE
- m_VisibleUnitGreyDistance
);
795 m_MaxVisibleDistanceInInctances
= MAX_VISIBILITY_DISTANCE
- m_VisibleUnitGreyDistance
;
798 //visibility in BG/Arenas
799 m_MaxVisibleDistanceInBGArenas
= sConfig
.GetFloatDefault("Visibility.Distance.BGArenas", DEFAULT_VISIBILITY_BGARENAS
);
800 if(m_MaxVisibleDistanceInBGArenas
< 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
))
802 sLog
.outError("Visibility.Distance.BGArenas can't be less max aggro radius %f",45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
));
803 m_MaxVisibleDistanceInBGArenas
= 45*getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO
);
805 else if(m_MaxVisibleDistanceInBGArenas
+ m_VisibleUnitGreyDistance
> MAX_VISIBILITY_DISTANCE
)
807 sLog
.outError("Visibility.Distance.BGArenas can't be greater %f",MAX_VISIBILITY_DISTANCE
- m_VisibleUnitGreyDistance
);
808 m_MaxVisibleDistanceInBGArenas
= MAX_VISIBILITY_DISTANCE
- m_VisibleUnitGreyDistance
;
811 m_MaxVisibleDistanceForObject
= sConfig
.GetFloatDefault("Visibility.Distance.Object", DEFAULT_VISIBILITY_DISTANCE
);
812 if(m_MaxVisibleDistanceForObject
< INTERACTION_DISTANCE
)
814 sLog
.outError("Visibility.Distance.Object can't be less max aggro radius %f",float(INTERACTION_DISTANCE
));
815 m_MaxVisibleDistanceForObject
= INTERACTION_DISTANCE
;
817 else if(m_MaxVisibleDistanceForObject
+ m_VisibleObjectGreyDistance
> MAX_VISIBILITY_DISTANCE
)
819 sLog
.outError("Visibility.Distance.Object can't be greater %f",MAX_VISIBILITY_DISTANCE
-m_VisibleObjectGreyDistance
);
820 m_MaxVisibleDistanceForObject
= MAX_VISIBILITY_DISTANCE
- m_VisibleObjectGreyDistance
;
822 m_MaxVisibleDistanceInFlight
= sConfig
.GetFloatDefault("Visibility.Distance.InFlight", DEFAULT_VISIBILITY_DISTANCE
);
823 if(m_MaxVisibleDistanceInFlight
+ m_VisibleObjectGreyDistance
> MAX_VISIBILITY_DISTANCE
)
825 sLog
.outError("Visibility.Distance.InFlight can't be greater %f",MAX_VISIBILITY_DISTANCE
-m_VisibleObjectGreyDistance
);
826 m_MaxVisibleDistanceInFlight
= MAX_VISIBILITY_DISTANCE
- m_VisibleObjectGreyDistance
;
829 ///- Load the CharDelete related config options
830 setConfigMinMax(CONFIG_UINT32_CHARDELETE_METHOD
, "CharDelete.Method", 0, 0, 1);
831 setConfigMinMax(CONFIG_UINT32_CHARDELETE_MIN_LEVEL
, "CharDelete.MinLevel", 0, 0, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL
));
832 setConfigPos(CONFIG_UINT32_CHARDELETE_KEEP_DAYS
, "CharDelete.KeepDays", 30);
834 ///- Read the "Data" directory from the config file
835 std::string dataPath
= sConfig
.GetStringDefault("DataDir","./");
836 if( dataPath
.at(dataPath
.length()-1)!='/' && dataPath
.at(dataPath
.length()-1)!='\\' )
837 dataPath
.append("/");
841 if(dataPath
!=m_dataPath
)
842 sLog
.outError("DataDir option can't be changed at mangosd.conf reload, using current value (%s).",m_dataPath
.c_str());
846 m_dataPath
= dataPath
;
847 sLog
.outString("Using DataDir %s",m_dataPath
.c_str());
850 bool enableLOS
= sConfig
.GetBoolDefault("vmap.enableLOS", false);
851 bool enableHeight
= sConfig
.GetBoolDefault("vmap.enableHeight", false);
852 std::string ignoreMapIds
= sConfig
.GetStringDefault("vmap.ignoreMapIds", "");
853 std::string ignoreSpellIds
= sConfig
.GetStringDefault("vmap.ignoreSpellIds", "");
854 VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS
);
855 VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight
);
856 VMAP::VMapFactory::createOrGetVMapManager()->preventMapsFromBeingUsed(ignoreMapIds
.c_str());
857 VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds
.c_str());
858 sLog
.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i",enableLOS
, enableHeight
);
859 sLog
.outString( "WORLD: VMap data directory is: %svmaps",m_dataPath
.c_str());
860 sLog
.outString( "WORLD: VMap config keys are: vmap.enableLOS, vmap.enableHeight, vmap.ignoreMapIds, vmap.ignoreSpellIds");
863 /// Initialize the World
864 void World::SetInitialWorldSettings()
866 ///- Initialize the random number generator
867 srand((unsigned int)time(NULL
));
869 ///- Time server startup
870 uint32 uStartTime
= getMSTime();
872 ///- Initialize config settings
873 LoadConfigSettings();
875 ///- Init highest guids before any table loading to prevent using not initialized guids in some code.
876 sObjectMgr
.SetHighestGuids();
878 ///- Check the existence of the map files for all races' startup areas.
879 if( !MapManager::ExistMapAndVMap(0,-6240.32f
, 331.033f
)
880 ||!MapManager::ExistMapAndVMap(0,-8949.95f
,-132.493f
)
881 ||!MapManager::ExistMapAndVMap(0,-8949.95f
,-132.493f
)
882 ||!MapManager::ExistMapAndVMap(1,-618.518f
,-4251.67f
)
883 ||!MapManager::ExistMapAndVMap(0, 1676.35f
, 1677.45f
)
884 ||!MapManager::ExistMapAndVMap(1, 10311.3f
, 832.463f
)
885 ||!MapManager::ExistMapAndVMap(1,-2917.58f
,-257.98f
)
886 ||m_configUint32Values
[CONFIG_UINT32_EXPANSION
] && (
887 !MapManager::ExistMapAndVMap(530,10349.6f
,-6357.29f
) || !MapManager::ExistMapAndVMap(530,-3961.64f
,-13931.2f
) ) )
889 sLog
.outError("Correct *.map files not found in path '%smaps' or *.vmap/*vmdir files in '%svmaps'. Please place *.map/*.vmap/*.vmdir files in appropriate directories or correct the DataDir value in the mangosd.conf file.",m_dataPath
.c_str(),m_dataPath
.c_str());
893 ///- Loading strings. Getting no records means core load has to be canceled because no error message can be output.
895 sLog
.outString("Loading MaNGOS strings...");
896 if (!sObjectMgr
.LoadMangosStrings())
897 exit(1); // Error message displayed in function already
899 ///- Update the realm entry in the database with the realm type from the config file
900 //No SQL injection as values are treated as integers
902 // not send custom type REALM_FFA_PVP to realm list
903 uint32 server_type
= IsFFAPvPRealm() ? REALM_TYPE_PVP
: getConfig(CONFIG_UINT32_GAME_TYPE
);
904 uint32 realm_zone
= getConfig(CONFIG_UINT32_REALM_ZONE
);
905 loginDatabase
.PExecute("UPDATE realmlist SET icon = %u, timezone = %u WHERE id = '%d'", server_type
, realm_zone
, realmID
);
907 ///- Remove the bones (they should not exist in DB though) and old corpses after a restart
908 CharacterDatabase
.PExecute("DELETE FROM corpse WHERE corpse_type = '0' OR time < (UNIX_TIMESTAMP()-'%u')", 3*DAY
);
910 ///- Load the DBC files
911 sLog
.outString("Initialize data stores...");
912 LoadDBCStores(m_dataPath
);
915 sLog
.outString( "Loading Script Names...");
916 sObjectMgr
.LoadScriptNames();
918 sLog
.outString( "Loading InstanceTemplate..." );
919 sObjectMgr
.LoadInstanceTemplate();
921 sLog
.outString( "Loading SkillLineAbilityMultiMap Data..." );
922 sSpellMgr
.LoadSkillLineAbilityMap();
924 ///- Clean up and pack instances
925 sLog
.outString( "Cleaning up instances..." );
926 sInstanceSaveMgr
.CleanupInstances(); // must be called before `creature_respawn`/`gameobject_respawn` tables
928 sLog
.outString( "Packing instances..." );
929 sInstanceSaveMgr
.PackInstances();
931 sLog
.outString( "Packing groups..." );
932 sObjectMgr
.PackGroupIds();
935 sLog
.outString( "Loading Localization strings..." );
936 sObjectMgr
.LoadCreatureLocales();
937 sObjectMgr
.LoadGameObjectLocales();
938 sObjectMgr
.LoadItemLocales();
939 sObjectMgr
.LoadQuestLocales();
940 sObjectMgr
.LoadNpcTextLocales();
941 sObjectMgr
.LoadPageTextLocales();
942 sObjectMgr
.LoadGossipMenuItemsLocales();
943 sObjectMgr
.LoadPointOfInterestLocales();
944 sObjectMgr
.SetDBCLocaleIndex(GetDefaultDbcLocale()); // Get once for all the locale index of DBC language (console/broadcasts)
945 sLog
.outString( ">>> Localization strings loaded" );
948 sLog
.outString( "Loading Page Texts..." );
949 sObjectMgr
.LoadPageTexts();
951 sLog
.outString( "Loading Game Object Templates..." ); // must be after LoadPageTexts
952 sObjectMgr
.LoadGameobjectInfo();
954 sLog
.outString( "Loading Spell Chain Data..." );
955 sSpellMgr
.LoadSpellChains();
957 sLog
.outString( "Loading Spell Elixir types..." );
958 sSpellMgr
.LoadSpellElixirs();
960 sLog
.outString( "Loading Spell Learn Skills..." );
961 sSpellMgr
.LoadSpellLearnSkills(); // must be after LoadSpellChains
963 sLog
.outString( "Loading Spell Learn Spells..." );
964 sSpellMgr
.LoadSpellLearnSpells();
966 sLog
.outString( "Loading Spell Proc Event conditions..." );
967 sSpellMgr
.LoadSpellProcEvents();
969 sLog
.outString( "Loading Spell Bonus Data..." );
970 sSpellMgr
.LoadSpellBonuses(); // must be after LoadSpellChains
972 sLog
.outString( "Loading Spell Proc Item Enchant..." );
973 sSpellMgr
.LoadSpellProcItemEnchant(); // must be after LoadSpellChains
975 sLog
.outString( "Loading Aggro Spells Definitions...");
976 sSpellMgr
.LoadSpellThreats();
978 sLog
.outString( "Loading NPC Texts..." );
979 sObjectMgr
.LoadGossipText();
981 sLog
.outString( "Loading Item Random Enchantments Table..." );
982 LoadRandomEnchantmentsTable();
984 sLog
.outString( "Loading Items..." ); // must be after LoadRandomEnchantmentsTable and LoadPageTexts
985 sObjectMgr
.LoadItemPrototypes();
987 sLog
.outString( "Loading Creature Model Based Info Data..." );
988 sObjectMgr
.LoadCreatureModelInfo();
990 sLog
.outString( "Loading Equipment templates...");
991 sObjectMgr
.LoadEquipmentTemplates();
993 sLog
.outString( "Loading Creature templates..." );
994 sObjectMgr
.LoadCreatureTemplates();
996 sLog
.outString( "Loading SpellsScriptTarget...");
997 sSpellMgr
.LoadSpellScriptTarget(); // must be after LoadCreatureTemplates and LoadGameobjectInfo
999 sLog
.outString( "Loading ItemRequiredTarget...");
1000 sObjectMgr
.LoadItemRequiredTarget();
1002 sLog
.outString( "Loading Creature Reputation OnKill Data..." );
1003 sObjectMgr
.LoadReputationOnKill();
1005 sLog
.outString( "Loading Points Of Interest Data..." );
1006 sObjectMgr
.LoadPointsOfInterest();
1008 sLog
.outString( "Loading Creature Data..." );
1009 sObjectMgr
.LoadCreatures();
1011 sLog
.outString( "Loading pet levelup spells..." );
1012 sSpellMgr
.LoadPetLevelupSpellMap();
1014 sLog
.outString( "Loading pet default spell additional to levelup spells..." );
1015 sSpellMgr
.LoadPetDefaultSpells();
1017 sLog
.outString( "Loading Creature Addon Data..." );
1019 sObjectMgr
.LoadCreatureAddons(); // must be after LoadCreatureTemplates() and LoadCreatures()
1020 sLog
.outString( ">>> Creature Addon Data loaded" );
1023 sLog
.outString( "Loading Creature Respawn Data..." ); // must be after PackInstances()
1024 sObjectMgr
.LoadCreatureRespawnTimes();
1026 sLog
.outString( "Loading Gameobject Data..." );
1027 sObjectMgr
.LoadGameobjects();
1029 sLog
.outString( "Loading Gameobject Respawn Data..." ); // must be after PackInstances()
1030 sObjectMgr
.LoadGameobjectRespawnTimes();
1032 sLog
.outString( "Loading Objects Pooling Data...");
1033 sPoolMgr
.LoadFromDB();
1035 sLog
.outString( "Loading Game Event Data...");
1037 sGameEventMgr
.LoadFromDB();
1038 sLog
.outString( ">>> Game Event Data loaded" );
1041 sLog
.outString( "Loading Weather Data..." );
1042 sObjectMgr
.LoadWeatherZoneChances();
1044 sLog
.outString( "Loading Quests..." );
1045 sObjectMgr
.LoadQuests(); // must be loaded after DBCs, creature_template, item_template, gameobject tables
1047 sLog
.outString( "Loading Quest POI" );
1048 sObjectMgr
.LoadQuestPOI();
1050 sLog
.outString( "Loading Quests Relations..." );
1052 sObjectMgr
.LoadQuestRelations(); // must be after quest load
1053 sLog
.outString( ">>> Quests Relations loaded" );
1056 sLog
.outString( "Loading UNIT_NPC_FLAG_SPELLCLICK Data..." );
1057 sObjectMgr
.LoadNPCSpellClickSpells();
1059 sLog
.outString( "Loading SpellArea Data..." ); // must be after quest load
1060 sSpellMgr
.LoadSpellAreas();
1062 sLog
.outString( "Loading AreaTrigger definitions..." );
1063 sObjectMgr
.LoadAreaTriggerTeleports(); // must be after item template load
1065 sLog
.outString( "Loading Quest Area Triggers..." );
1066 sObjectMgr
.LoadQuestAreaTriggers(); // must be after LoadQuests
1068 sLog
.outString( "Loading Tavern Area Triggers..." );
1069 sObjectMgr
.LoadTavernAreaTriggers();
1071 sLog
.outString( "Loading AreaTrigger script names..." );
1072 sObjectMgr
.LoadAreaTriggerScripts();
1074 sLog
.outString( "Loading Graveyard-zone links...");
1075 sObjectMgr
.LoadGraveyardZones();
1077 sLog
.outString( "Loading Spell target coordinates..." );
1078 sSpellMgr
.LoadSpellTargetPositions();
1080 sLog
.outString( "Loading spell pet auras..." );
1081 sSpellMgr
.LoadSpellPetAuras();
1083 sLog
.outString( "Loading Player Create Info & Level Stats..." );
1085 sObjectMgr
.LoadPlayerInfo();
1086 sLog
.outString( ">>> Player Create Info & Level Stats loaded" );
1089 sLog
.outString( "Loading Exploration BaseXP Data..." );
1090 sObjectMgr
.LoadExplorationBaseXP();
1092 sLog
.outString( "Loading Pet Name Parts..." );
1093 sObjectMgr
.LoadPetNames();
1095 CharacterDatabaseCleaner::CleanDatabase();
1097 sLog
.outString( "Loading the max pet number..." );
1098 sObjectMgr
.LoadPetNumber();
1100 sLog
.outString( "Loading pet level stats..." );
1101 sObjectMgr
.LoadPetLevelInfo();
1103 sLog
.outString( "Loading Player Corpses..." );
1104 sObjectMgr
.LoadCorpses();
1106 sLog
.outString( "Loading Player level dependent mail rewards..." );
1107 sObjectMgr
.LoadMailLevelRewards();
1109 sLog
.outString( "Loading Loot Tables..." );
1112 sLog
.outString( ">>> Loot Tables loaded" );
1115 sLog
.outString( "Loading Skill Discovery Table..." );
1116 LoadSkillDiscoveryTable();
1118 sLog
.outString( "Loading Skill Extra Item Table..." );
1119 LoadSkillExtraItemTable();
1121 sLog
.outString( "Loading Skill Fishing base level requirements..." );
1122 sObjectMgr
.LoadFishingBaseSkillLevel();
1124 sLog
.outString( "Loading Achievements..." );
1126 sAchievementMgr
.LoadAchievementReferenceList();
1127 sAchievementMgr
.LoadAchievementCriteriaList();
1128 sAchievementMgr
.LoadAchievementCriteriaRequirements();
1129 sAchievementMgr
.LoadRewards();
1130 sAchievementMgr
.LoadRewardLocales();
1131 sAchievementMgr
.LoadCompletedAchievements();
1132 sLog
.outString( ">>> Achievements loaded" );
1135 ///- Load dynamic data tables from the database
1136 sLog
.outString( "Loading Auctions..." );
1138 sAuctionMgr
.LoadAuctionItems();
1139 sAuctionMgr
.LoadAuctions();
1140 sLog
.outString( ">>> Auctions loaded" );
1143 sLog
.outString( "Loading Guilds..." );
1144 sObjectMgr
.LoadGuilds();
1146 sLog
.outString( "Loading ArenaTeams..." );
1147 sObjectMgr
.LoadArenaTeams();
1149 sLog
.outString( "Loading Groups..." );
1150 sObjectMgr
.LoadGroups();
1152 sLog
.outString( "Loading ReservedNames..." );
1153 sObjectMgr
.LoadReservedPlayersNames();
1155 sLog
.outString( "Loading GameObjects for quests..." );
1156 sObjectMgr
.LoadGameObjectForQuests();
1158 sLog
.outString( "Loading BattleMasters..." );
1159 sBattleGroundMgr
.LoadBattleMastersEntry();
1161 sLog
.outString( "Loading BattleGround event indexes..." );
1162 sBattleGroundMgr
.LoadBattleEventIndexes();
1164 sLog
.outString( "Loading GameTeleports..." );
1165 sObjectMgr
.LoadGameTele();
1167 sLog
.outString( "Loading Npc Text Id..." );
1168 sObjectMgr
.LoadNpcTextId(); // must be after load Creature and NpcText
1170 sLog
.outString( "Loading Gossip scripts..." );
1171 sObjectMgr
.LoadGossipScripts(); // must be before gossip menu options
1173 sLog
.outString( "Loading Gossip menus..." );
1174 sObjectMgr
.LoadGossipMenu();
1176 sLog
.outString( "Loading Gossip menu options..." );
1177 sObjectMgr
.LoadGossipMenuItems();
1179 sLog
.outString( "Loading Vendors..." );
1180 sObjectMgr
.LoadVendors(); // must be after load CreatureTemplate and ItemTemplate
1182 sLog
.outString( "Loading Trainers..." );
1183 sObjectMgr
.LoadTrainerSpell(); // must be after load CreatureTemplate
1185 sLog
.outString( "Loading Waypoint scripts..." ); // before loading from creature_movement
1186 sObjectMgr
.LoadCreatureMovementScripts();
1188 sLog
.outString( "Loading Waypoints..." );
1190 sWaypointMgr
.Load();
1192 sLog
.outString( "Loading GM tickets...");
1193 sTicketMgr
.LoadGMTickets();
1195 ///- Handle outdated emails (delete/return)
1196 sLog
.outString( "Returning old mails..." );
1197 sObjectMgr
.ReturnOrDeleteOldMails(false);
1199 ///- Load and initialize scripts
1200 sLog
.outString( "Loading Scripts..." );
1202 sObjectMgr
.LoadQuestStartScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
1203 sObjectMgr
.LoadQuestEndScripts(); // must be after load Creature/Gameobject(Template/Data) and QuestTemplate
1204 sObjectMgr
.LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data)
1205 sObjectMgr
.LoadGameObjectScripts(); // must be after load Creature/Gameobject(Template/Data)
1206 sObjectMgr
.LoadEventScripts(); // must be after load Creature/Gameobject(Template/Data)
1207 sLog
.outString( ">>> Scripts loaded" );
1210 sLog
.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls
1211 sObjectMgr
.LoadDbScriptStrings();
1213 sLog
.outString( "Loading CreatureEventAI Texts...");
1214 sEventAIMgr
.LoadCreatureEventAI_Texts(false); // false, will checked in LoadCreatureEventAI_Scripts
1216 sLog
.outString( "Loading CreatureEventAI Summons...");
1217 sEventAIMgr
.LoadCreatureEventAI_Summons(false); // false, will checked in LoadCreatureEventAI_Scripts
1219 sLog
.outString( "Loading CreatureEventAI Scripts...");
1220 sEventAIMgr
.LoadCreatureEventAI_Scripts();
1222 sLog
.outString( "Initializing Scripts..." );
1223 if(!LoadScriptingModule())
1226 ///- Initialize game time and timers
1227 sLog
.outString( "DEBUG:: Initialize game time and timers" );
1228 m_gameTime
= time(NULL
);
1229 m_startTime
=m_gameTime
;
1234 local
=*(localtime(&curr
)); // dereference and assign
1236 sprintf( isoDate
, "%04d-%02d-%02d %02d:%02d:%02d",
1237 local
.tm_year
+1900, local
.tm_mon
+1, local
.tm_mday
, local
.tm_hour
, local
.tm_min
, local
.tm_sec
);
1239 loginDatabase
.PExecute("INSERT INTO uptime (realmid, starttime, startstring, uptime) VALUES('%u', " UI64FMTD
", '%s', 0)",
1240 realmID
, uint64(m_startTime
), isoDate
);
1242 m_timers
[WUPDATE_OBJECTS
].SetInterval(0);
1243 m_timers
[WUPDATE_SESSIONS
].SetInterval(0);
1244 m_timers
[WUPDATE_WEATHERS
].SetInterval(1*IN_MILLISECONDS
);
1245 m_timers
[WUPDATE_AUCTIONS
].SetInterval(MINUTE
*IN_MILLISECONDS
);
1246 m_timers
[WUPDATE_UPTIME
].SetInterval(m_configUint32Values
[CONFIG_UINT32_UPTIME_UPDATE
]*MINUTE
*IN_MILLISECONDS
);
1247 //Update "uptime" table based on configuration entry in minutes.
1248 m_timers
[WUPDATE_CORPSES
].SetInterval(3*HOUR
*IN_MILLISECONDS
);
1249 m_timers
[WUPDATE_DELETECHARS
].SetInterval(DAY
*IN_MILLISECONDS
); // check for chars to delete every day
1251 //to set mailtimer to return mails every day between 4 and 5 am
1252 //mailtimer is increased when updating auctions
1253 //one second is 1000 -(tested on win system)
1254 mail_timer
= uint32((((localtime( &m_gameTime
)->tm_hour
+ 20) % 24)* HOUR
* IN_MILLISECONDS
) / m_timers
[WUPDATE_AUCTIONS
].GetInterval() );
1256 mail_timer_expires
= uint32( (DAY
* IN_MILLISECONDS
) / (m_timers
[WUPDATE_AUCTIONS
].GetInterval()));
1257 DEBUG_LOG("Mail timer set to: %u, mail return is called every %u minutes", mail_timer
, mail_timer_expires
);
1259 ///- Initialize static helper structures
1260 AIRegistry::Initialize();
1261 Player::InitVisibleBits();
1263 ///- Initialize MapManager
1264 sLog
.outString( "Starting Map System" );
1265 sMapMgr
.Initialize();
1267 ///- Initialize Battlegrounds
1268 sLog
.outString( "Starting BattleGround System" );
1269 sBattleGroundMgr
.CreateInitialBattleGrounds();
1270 sBattleGroundMgr
.InitAutomaticArenaPointDistribution();
1272 //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager
1273 sLog
.outString( "Loading Transports..." );
1274 sMapMgr
.LoadTransports();
1276 sLog
.outString("Deleting expired bans..." );
1277 loginDatabase
.Execute("DELETE FROM ip_banned WHERE unbandate<=UNIX_TIMESTAMP() AND unbandate<>bandate");
1279 sLog
.outString("Calculate next daily quest reset time..." );
1280 InitDailyQuestResetTime();
1282 sLog
.outString("Calculate next weekly quest reset time..." );
1283 InitWeeklyQuestResetTime();
1285 sLog
.outString("Starting objects Pooling system..." );
1286 sPoolMgr
.Initialize();
1288 sLog
.outString("Starting Game Event system..." );
1289 uint32 nextGameEvent
= sGameEventMgr
.Initialize();
1290 m_timers
[WUPDATE_EVENTS
].SetInterval(nextGameEvent
); //depend on next event
1292 // Delete all characters which have been deleted X days before
1293 Player::DeleteOldCharacters();
1295 sLog
.outString( "WORLD: World initialized" );
1297 uint32 uStartInterval
= getMSTimeDiff(uStartTime
, getMSTime());
1298 sLog
.outString( "SERVER STARTUP TIME: %i minutes %i seconds", uStartInterval
/ 60000, (uStartInterval
% 60000) / 1000 );
1301 void World::DetectDBCLang()
1303 uint32 m_lang_confid
= sConfig
.GetIntDefault("DBC.Locale", 255);
1305 if(m_lang_confid
!= 255 && m_lang_confid
>= MAX_LOCALE
)
1307 sLog
.outError("Incorrect DBC.Locale! Must be >= 0 and < %d (set to 0)",MAX_LOCALE
);
1308 m_lang_confid
= LOCALE_enUS
;
1311 ChrRacesEntry
const* race
= sChrRacesStore
.LookupEntry(1);
1313 std::string availableLocalsStr
;
1315 int default_locale
= MAX_LOCALE
;
1316 for (int i
= MAX_LOCALE
-1; i
>= 0; --i
)
1318 if ( strlen(race
->name
[i
]) > 0) // check by race names
1321 m_availableDbcLocaleMask
|= (1 << i
);
1322 availableLocalsStr
+= localeNames
[i
];
1323 availableLocalsStr
+= " ";
1327 if( default_locale
!= m_lang_confid
&& m_lang_confid
< MAX_LOCALE
&&
1328 (m_availableDbcLocaleMask
& (1 << m_lang_confid
)) )
1330 default_locale
= m_lang_confid
;
1333 if(default_locale
>= MAX_LOCALE
)
1335 sLog
.outError("Unable to determine your DBC Locale! (corrupt DBC?)");
1339 m_defaultDbcLocale
= LocaleConstant(default_locale
);
1341 sLog
.outString("Using %s DBC Locale as default. All available DBC locales: %s",localeNames
[m_defaultDbcLocale
],availableLocalsStr
.empty() ? "<none>" : availableLocalsStr
.c_str());
1345 /// Update the World !
1346 void World::Update(uint32 diff
)
1348 ///- Update the different timers
1349 for(int i
= 0; i
< WUPDATE_COUNT
; ++i
)
1351 if (m_timers
[i
].GetCurrent()>=0)
1352 m_timers
[i
].Update(diff
);
1354 m_timers
[i
].SetCurrent(0);
1357 ///- Update the game time and check for shutdown time
1360 /// Handle daily quests reset time
1361 if (m_gameTime
> m_NextDailyQuestReset
)
1364 /// Handle weekly quests reset time
1365 if (m_gameTime
> m_NextWeeklyQuestReset
)
1366 ResetWeeklyQuests();
1368 /// <ul><li> Handle auctions when the timer has passed
1369 if (m_timers
[WUPDATE_AUCTIONS
].Passed())
1371 m_timers
[WUPDATE_AUCTIONS
].Reset();
1373 ///- Update mails (return old mails with item, or delete them)
1374 //(tested... works on win)
1375 if (++mail_timer
> mail_timer_expires
)
1378 sObjectMgr
.ReturnOrDeleteOldMails(true);
1381 ///- Handle expired auctions
1382 sAuctionMgr
.Update();
1385 /// <li> Handle session updates when the timer has passed
1386 if (m_timers
[WUPDATE_SESSIONS
].Passed())
1388 m_timers
[WUPDATE_SESSIONS
].Reset();
1390 UpdateSessions(diff
);
1393 /// <li> Handle weather updates when the timer has passed
1394 if (m_timers
[WUPDATE_WEATHERS
].Passed())
1396 m_timers
[WUPDATE_WEATHERS
].Reset();
1398 ///- Send an update signal to Weather objects
1399 WeatherMap::iterator itr
, next
;
1400 for (itr
= m_weathers
.begin(); itr
!= m_weathers
.end(); itr
= next
)
1405 ///- and remove Weather objects for zones with no player
1406 //As interval > WorldTick
1407 if(!itr
->second
->Update(m_timers
[WUPDATE_WEATHERS
].GetInterval()))
1410 m_weathers
.erase(itr
);
1414 /// <li> Update uptime table
1415 if (m_timers
[WUPDATE_UPTIME
].Passed())
1417 uint32 tmpDiff
= uint32(m_gameTime
- m_startTime
);
1418 uint32 maxClientsNum
= GetMaxActiveSessionCount();
1420 m_timers
[WUPDATE_UPTIME
].Reset();
1421 loginDatabase
.PExecute("UPDATE uptime SET uptime = %u, maxplayers = %u WHERE realmid = %u AND starttime = " UI64FMTD
, tmpDiff
, maxClientsNum
, realmID
, uint64(m_startTime
));
1424 /// <li> Handle all other objects
1425 if (m_timers
[WUPDATE_OBJECTS
].Passed())
1427 m_timers
[WUPDATE_OBJECTS
].Reset();
1428 ///- Update objects when the timer has passed (maps, transport, creatures,...)
1429 sMapMgr
.Update(diff
); // As interval = 0
1431 sBattleGroundMgr
.Update(diff
);
1434 ///- Delete all characters which have been deleted X days before
1435 if (m_timers
[WUPDATE_DELETECHARS
].Passed())
1437 m_timers
[WUPDATE_DELETECHARS
].Reset();
1438 Player::DeleteOldCharacters();
1441 // execute callbacks from sql queries that were queued recently
1442 UpdateResultQueue();
1444 ///- Erase corpses once every 20 minutes
1445 if (m_timers
[WUPDATE_CORPSES
].Passed())
1447 m_timers
[WUPDATE_CORPSES
].Reset();
1449 sObjectAccessor
.RemoveOldCorpses();
1452 ///- Process Game events when necessary
1453 if (m_timers
[WUPDATE_EVENTS
].Passed())
1455 m_timers
[WUPDATE_EVENTS
].Reset(); // to give time for Update() to be processed
1456 uint32 nextGameEvent
= sGameEventMgr
.Update();
1457 m_timers
[WUPDATE_EVENTS
].SetInterval(nextGameEvent
);
1458 m_timers
[WUPDATE_EVENTS
].Reset();
1462 ///- Move all creatures with "delayed move" and remove and delete all objects with "delayed remove"
1463 sMapMgr
.RemoveAllObjectsInRemoveList();
1465 // update the instance reset times
1466 sInstanceSaveMgr
.Update();
1468 // And last, but not least handle the issued cli commands
1469 ProcessCliCommands();
1472 /// Send a packet to all players (except self if mentioned)
1473 void World::SendGlobalMessage(WorldPacket
*packet
, WorldSession
*self
, uint32 team
)
1475 SessionMap::const_iterator itr
;
1476 for (itr
= m_sessions
.begin(); itr
!= m_sessions
.end(); ++itr
)
1479 itr
->second
->GetPlayer() &&
1480 itr
->second
->GetPlayer()->IsInWorld() &&
1481 itr
->second
!= self
&&
1482 (team
== 0 || itr
->second
->GetPlayer()->GetTeam() == team
) )
1484 itr
->second
->SendPacket(packet
);
1491 class WorldWorldTextBuilder
1494 typedef std::vector
<WorldPacket
*> WorldPacketList
;
1495 explicit WorldWorldTextBuilder(int32 textId
, va_list* args
= NULL
) : i_textId(textId
), i_args(args
) {}
1496 void operator()(WorldPacketList
& data_list
, int32 loc_idx
)
1498 char const* text
= sObjectMgr
.GetMangosString(i_textId
,loc_idx
);
1502 // we need copy va_list before use or original va_list will corrupted
1504 va_copy(ap
,*i_args
);
1507 vsnprintf(str
,2048,text
, ap
);
1510 do_helper(data_list
,&str
[0]);
1513 do_helper(data_list
,(char*)text
);
1516 char* lineFromMessage(char*& pos
) { char* start
= strtok(pos
,"\n"); pos
= NULL
; return start
; }
1517 void do_helper(WorldPacketList
& data_list
, char* text
)
1521 while(char* line
= lineFromMessage(pos
))
1523 WorldPacket
* data
= new WorldPacket();
1525 uint32 lineLength
= (line
? strlen(line
) : 0) + 1;
1527 data
->Initialize(SMSG_MESSAGECHAT
, 100); // guess size
1528 *data
<< uint8(CHAT_MSG_SYSTEM
);
1529 *data
<< uint32(LANG_UNIVERSAL
);
1531 *data
<< uint32(0); // can be chat msg group or something
1533 *data
<< uint32(lineLength
);
1537 data_list
.push_back(data
);
1544 } // namespace MaNGOS
1546 /// Send a System Message to all players (except self if mentioned)
1547 void World::SendWorldText(int32 string_id
, ...)
1550 va_start(ap
, string_id
);
1552 MaNGOS::WorldWorldTextBuilder
wt_builder(string_id
, &ap
);
1553 MaNGOS::LocalizedPacketListDo
<MaNGOS::WorldWorldTextBuilder
> wt_do(wt_builder
);
1554 for(SessionMap::const_iterator itr
= m_sessions
.begin(); itr
!= m_sessions
.end(); ++itr
)
1556 if(!itr
->second
|| !itr
->second
->GetPlayer() || !itr
->second
->GetPlayer()->IsInWorld() )
1559 wt_do(itr
->second
->GetPlayer());
1565 /// DEPRICATED, only for debug purpose. Send a System Message to all players (except self if mentioned)
1566 void World::SendGlobalText(const char* text
, WorldSession
*self
)
1570 // need copy to prevent corruption by strtok call in LineFromMessage original string
1571 char* buf
= mangos_strdup(text
);
1574 while(char* line
= ChatHandler::LineFromMessage(pos
))
1576 ChatHandler::FillMessageData(&data
, NULL
, CHAT_MSG_SYSTEM
, LANG_UNIVERSAL
, NULL
, 0, line
, NULL
);
1577 SendGlobalMessage(&data
, self
);
1583 /// Send a packet to all players (or players selected team) in the zone (except self if mentioned)
1584 void World::SendZoneMessage(uint32 zone
, WorldPacket
*packet
, WorldSession
*self
, uint32 team
)
1586 SessionMap::const_iterator itr
;
1587 for (itr
= m_sessions
.begin(); itr
!= m_sessions
.end(); ++itr
)
1590 itr
->second
->GetPlayer() &&
1591 itr
->second
->GetPlayer()->IsInWorld() &&
1592 itr
->second
->GetPlayer()->GetZoneId() == zone
&&
1593 itr
->second
!= self
&&
1594 (team
== 0 || itr
->second
->GetPlayer()->GetTeam() == team
) )
1596 itr
->second
->SendPacket(packet
);
1601 /// Send a System Message to all players in the zone (except self if mentioned)
1602 void World::SendZoneText(uint32 zone
, const char* text
, WorldSession
*self
, uint32 team
)
1605 ChatHandler::FillMessageData(&data
, NULL
, CHAT_MSG_SYSTEM
, LANG_UNIVERSAL
, NULL
, 0, text
, NULL
);
1606 SendZoneMessage(zone
, &data
, self
,team
);
1609 /// Kick (and save) all players
1610 void World::KickAll()
1612 m_QueuedPlayer
.clear(); // prevent send queue update packet and login queued sessions
1614 // session not removed at kick and will removed in next update tick
1615 for (SessionMap::const_iterator itr
= m_sessions
.begin(); itr
!= m_sessions
.end(); ++itr
)
1616 itr
->second
->KickPlayer();
1619 /// Kick (and save) all players with security level less `sec`
1620 void World::KickAllLess(AccountTypes sec
)
1622 // session not removed at kick and will removed in next update tick
1623 for (SessionMap::const_iterator itr
= m_sessions
.begin(); itr
!= m_sessions
.end(); ++itr
)
1624 if(itr
->second
->GetSecurity() < sec
)
1625 itr
->second
->KickPlayer();
1628 /// Ban an account or ban an IP address, duration will be parsed using TimeStringToSecs if it is positive, otherwise permban
1629 BanReturn
World::BanAccount(BanMode mode
, std::string nameOrIP
, std::string duration
, std::string reason
, std::string author
)
1631 loginDatabase
.escape_string(nameOrIP
);
1632 loginDatabase
.escape_string(reason
);
1633 std::string safe_author
=author
;
1634 loginDatabase
.escape_string(safe_author
);
1636 uint32 duration_secs
= TimeStringToSecs(duration
);
1637 QueryResult
*resultAccounts
= NULL
; //used for kicking
1639 ///- Update the database with ban information
1643 //No SQL injection as strings are escaped
1644 resultAccounts
= loginDatabase
.PQuery("SELECT id FROM account WHERE last_ip = '%s'",nameOrIP
.c_str());
1645 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());
1648 //No SQL injection as string is escaped
1649 resultAccounts
= loginDatabase
.PQuery("SELECT id FROM account WHERE username = '%s'",nameOrIP
.c_str());
1652 //No SQL injection as string is escaped
1653 resultAccounts
= CharacterDatabase
.PQuery("SELECT account FROM characters WHERE name = '%s'",nameOrIP
.c_str());
1656 return BAN_SYNTAX_ERROR
;
1662 return BAN_SUCCESS
; // ip correctly banned but nobody affected (yet)
1664 return BAN_NOTFOUND
; // Nobody to ban
1667 ///- Disconnect all affected players (for IP it can be several)
1670 Field
* fieldsAccount
= resultAccounts
->Fetch();
1671 uint32 account
= fieldsAccount
->GetUInt32();
1675 //No SQL injection as strings are escaped
1676 loginDatabase
.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+%u, '%s', '%s', '1')",
1677 account
,duration_secs
,safe_author
.c_str(),reason
.c_str());
1680 if (WorldSession
* sess
= FindSession(account
))
1681 if(std::string(sess
->GetPlayerName()) != author
)
1684 while( resultAccounts
->NextRow() );
1686 delete resultAccounts
;
1690 /// Remove a ban from an account or IP address
1691 bool World::RemoveBanAccount(BanMode mode
, std::string nameOrIP
)
1695 loginDatabase
.escape_string(nameOrIP
);
1696 loginDatabase
.PExecute("DELETE FROM ip_banned WHERE ip = '%s'",nameOrIP
.c_str());
1701 if (mode
== BAN_ACCOUNT
)
1702 account
= sAccountMgr
.GetId (nameOrIP
);
1703 else if (mode
== BAN_CHARACTER
)
1704 account
= sObjectMgr
.GetPlayerAccountIdByPlayerName (nameOrIP
);
1709 //NO SQL injection as account is uint32
1710 loginDatabase
.PExecute("UPDATE account_banned SET active = '0' WHERE id = '%u'",account
);
1715 /// Update the game time
1716 void World::_UpdateGameTime()
1718 ///- update the time
1719 time_t thisTime
= time(NULL
);
1720 uint32 elapsed
= uint32(thisTime
- m_gameTime
);
1721 m_gameTime
= thisTime
;
1723 ///- if there is a shutdown timer
1724 if(!m_stopEvent
&& m_ShutdownTimer
> 0 && elapsed
> 0)
1726 ///- ... and it is overdue, stop the world (set m_stopEvent)
1727 if( m_ShutdownTimer
<= elapsed
)
1729 if(!(m_ShutdownMask
& SHUTDOWN_MASK_IDLE
) || GetActiveAndQueuedSessionCount()==0)
1730 m_stopEvent
= true; // exist code already set
1732 m_ShutdownTimer
= 1; // minimum timer value to wait idle state
1734 ///- ... else decrease it and if necessary display a shutdown countdown to the users
1737 m_ShutdownTimer
-= elapsed
;
1744 /// Shutdown the server
1745 void World::ShutdownServ(uint32 time
, uint32 options
, uint8 exitcode
)
1747 // ignore if server shutdown at next tick
1751 m_ShutdownMask
= options
;
1752 m_ExitCode
= exitcode
;
1754 ///- If the shutdown time is 0, set m_stopEvent (except if shutdown is 'idle' with remaining sessions)
1757 if(!(options
& SHUTDOWN_MASK_IDLE
) || GetActiveAndQueuedSessionCount()==0)
1758 m_stopEvent
= true; // exist code already set
1760 m_ShutdownTimer
= 1; //So that the session count is re-evaluated at next world tick
1762 ///- Else set the shutdown timer and warn users
1765 m_ShutdownTimer
= time
;
1770 /// Display a shutdown message to the user(s)
1771 void World::ShutdownMsg(bool show
, Player
* player
)
1773 // not show messages for idle shutdown mode
1774 if(m_ShutdownMask
& SHUTDOWN_MASK_IDLE
)
1777 ///- Display a message every 12 hours, hours, 5 minutes, minute, 5 seconds and finally seconds
1779 (m_ShutdownTimer
< 10) ||
1780 // < 30 sec; every 5 sec
1781 (m_ShutdownTimer
<30 && (m_ShutdownTimer
% 5 )==0) ||
1782 // < 5 min ; every 1 min
1783 (m_ShutdownTimer
<5*MINUTE
&& (m_ShutdownTimer
% MINUTE
)==0) ||
1784 // < 30 min ; every 5 min
1785 (m_ShutdownTimer
<30*MINUTE
&& (m_ShutdownTimer
% (5*MINUTE
))==0) ||
1786 // < 12 h ; every 1 h
1787 (m_ShutdownTimer
<12*HOUR
&& (m_ShutdownTimer
% HOUR
)==0) ||
1788 // > 12 h ; every 12 h
1789 (m_ShutdownTimer
>12*HOUR
&& (m_ShutdownTimer
% (12*HOUR
) )==0))
1791 std::string str
= secsToTimeString(m_ShutdownTimer
);
1793 ServerMessageType msgid
= (m_ShutdownMask
& SHUTDOWN_MASK_RESTART
) ? SERVER_MSG_RESTART_TIME
: SERVER_MSG_SHUTDOWN_TIME
;
1795 SendServerMessage(msgid
,str
.c_str(),player
);
1796 DEBUG_LOG("Server is %s in %s",(m_ShutdownMask
& SHUTDOWN_MASK_RESTART
? "restart" : "shuttingdown"),str
.c_str());
1800 /// Cancel a planned server shutdown
1801 void World::ShutdownCancel()
1803 // nothing cancel or too later
1804 if(!m_ShutdownTimer
|| m_stopEvent
)
1807 ServerMessageType msgid
= (m_ShutdownMask
& SHUTDOWN_MASK_RESTART
) ? SERVER_MSG_RESTART_CANCELLED
: SERVER_MSG_SHUTDOWN_CANCELLED
;
1810 m_ShutdownTimer
= 0;
1811 m_ExitCode
= SHUTDOWN_EXIT_CODE
; // to default value
1812 SendServerMessage(msgid
);
1814 DEBUG_LOG("Server %s cancelled.",(m_ShutdownMask
& SHUTDOWN_MASK_RESTART
? "restart" : "shuttingdown"));
1817 /// Send a server message to the user(s)
1818 void World::SendServerMessage(ServerMessageType type
, const char *text
, Player
* player
)
1820 WorldPacket
data(SMSG_SERVER_MESSAGE
, 50); // guess size
1821 data
<< uint32(type
);
1822 if(type
<= SERVER_MSG_STRING
)
1826 player
->GetSession()->SendPacket(&data
);
1828 SendGlobalMessage( &data
);
1831 void World::UpdateSessions( uint32 diff
)
1833 ///- Add new sessions
1835 while(addSessQueue
.next(sess
))
1838 ///- Then send an update signal to remaining ones
1839 for (SessionMap::iterator itr
= m_sessions
.begin(), next
; itr
!= m_sessions
.end(); itr
= next
)
1843 ///- and remove not active sessions from the list
1844 if(!itr
->second
->Update(diff
)) // As interval = 0
1846 RemoveQueuedPlayer (itr
->second
);
1848 m_sessions
.erase(itr
);
1853 // This handles the issued and queued CLI/RA commands
1854 void World::ProcessCliCommands()
1856 CliCommandHolder::Print
* zprint
= NULL
;
1857 void* callbackArg
= NULL
;
1858 CliCommandHolder
* command
;
1859 while (cliCmdQueue
.next(command
))
1861 DEBUG_LOG("CLI command under processing...");
1862 zprint
= command
->m_print
;
1863 callbackArg
= command
->m_callbackArg
;
1864 CliHandler
handler(command
->m_cliAccountId
, command
->m_cliAccessLevel
, callbackArg
, zprint
);
1865 handler
.ParseCommands(command
->m_command
);
1867 if(command
->m_commandFinished
)
1868 command
->m_commandFinished(callbackArg
, !handler
.HasSentErrorMessage());
1874 void World::InitResultQueue()
1876 m_resultQueue
= new SqlResultQueue
;
1877 CharacterDatabase
.SetResultQueue(m_resultQueue
);
1880 void World::UpdateResultQueue()
1882 m_resultQueue
->Update();
1885 void World::UpdateRealmCharCount(uint32 accountId
)
1887 CharacterDatabase
.AsyncPQuery(this, &World::_UpdateRealmCharCount
, accountId
,
1888 "SELECT COUNT(guid) FROM characters WHERE account = '%u'", accountId
);
1891 void World::_UpdateRealmCharCount(QueryResult
*resultCharCount
, uint32 accountId
)
1893 if (resultCharCount
)
1895 Field
*fields
= resultCharCount
->Fetch();
1896 uint32 charCount
= fields
[0].GetUInt32();
1897 delete resultCharCount
;
1898 loginDatabase
.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", accountId
, realmID
);
1899 loginDatabase
.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charCount
, accountId
, realmID
);
1903 void World::InitWeeklyQuestResetTime()
1905 QueryResult
* result
= CharacterDatabase
.Query("SELECT NextWeeklyQuestResetTime FROM saved_variables");
1907 m_NextWeeklyQuestReset
= time_t(time(NULL
)); // game time not yet init
1909 m_NextWeeklyQuestReset
= time_t((*result
)[0].GetUInt64());
1911 // generate time by config
1912 time_t curTime
= time(NULL
);
1913 tm localTm
= *localtime(&curTime
);
1915 int week_day_offset
= localTm
.tm_wday
- int(getConfig(CONFIG_UINT32_QUEST_WEEKLY_RESET_WEEK_DAY
));
1917 // current week reset time
1918 localTm
.tm_hour
= getConfig(CONFIG_UINT32_QUEST_WEEKLY_RESET_HOUR
);
1921 time_t nextWeekResetTime
= mktime(&localTm
);
1922 nextWeekResetTime
-= week_day_offset
* DAY
; // move time to proper day
1924 // next reset time before current moment
1925 if (curTime
>= nextWeekResetTime
)
1926 nextWeekResetTime
+= WEEK
;
1928 // normalize reset time
1929 m_NextWeeklyQuestReset
= m_NextWeeklyQuestReset
< curTime
? nextWeekResetTime
- WEEK
: nextWeekResetTime
;
1932 CharacterDatabase
.PExecute("INSERT INTO saved_variables (NextWeeklyQuestResetTime) VALUES ('"UI64FMTD
"')", uint64(m_NextWeeklyQuestReset
));
1937 void World::InitDailyQuestResetTime()
1939 QueryResult
* result
= CharacterDatabase
.Query("SELECT NextDailyQuestResetTime FROM saved_variables");
1941 m_NextDailyQuestReset
= time_t(time(NULL
)); // game time not yet init
1943 m_NextDailyQuestReset
= time_t((*result
)[0].GetUInt64());
1945 // generate time by config
1946 time_t curTime
= time(NULL
);
1947 tm localTm
= *localtime(&curTime
);
1948 localTm
.tm_hour
= getConfig(CONFIG_UINT32_QUEST_DAILY_RESET_HOUR
);
1952 // current day reset time
1953 time_t nextDayResetTime
= mktime(&localTm
);
1955 // next reset time before current moment
1956 if (curTime
>= nextDayResetTime
)
1957 nextDayResetTime
+= DAY
;
1959 // normalize reset time
1960 m_NextDailyQuestReset
= m_NextDailyQuestReset
< curTime
? nextDayResetTime
- DAY
: nextDayResetTime
;
1963 CharacterDatabase
.PExecute("INSERT INTO saved_variables (NextDailyQuestResetTime) VALUES ('"UI64FMTD
"')", uint64(m_NextDailyQuestReset
));
1968 void World::ResetDailyQuests()
1970 DETAIL_LOG("Daily quests reset for all characters.");
1971 CharacterDatabase
.Execute("DELETE FROM character_queststatus_daily");
1972 for(SessionMap::const_iterator itr
= m_sessions
.begin(); itr
!= m_sessions
.end(); ++itr
)
1973 if (itr
->second
->GetPlayer())
1974 itr
->second
->GetPlayer()->ResetDailyQuestStatus();
1976 m_NextDailyQuestReset
= time_t(m_NextDailyQuestReset
+ DAY
);
1977 CharacterDatabase
.PExecute("UPDATE saved_variables SET NextDailyQuestResetTime = '"UI64FMTD
"'", uint64(m_NextDailyQuestReset
));
1980 void World::ResetWeeklyQuests()
1982 DETAIL_LOG("Weekly quests reset for all characters.");
1983 CharacterDatabase
.Execute("DELETE FROM character_queststatus_weekly");
1984 for(SessionMap::const_iterator itr
= m_sessions
.begin(); itr
!= m_sessions
.end(); ++itr
)
1985 if (itr
->second
->GetPlayer())
1986 itr
->second
->GetPlayer()->ResetWeeklyQuestStatus();
1988 m_NextWeeklyQuestReset
= time_t(m_NextWeeklyQuestReset
+ WEEK
);
1989 CharacterDatabase
.PExecute("UPDATE saved_variables SET NextWeeklyQuestResetTime = '"UI64FMTD
"'", uint64(m_NextWeeklyQuestReset
));
1992 void World::SetPlayerLimit( int32 limit
, bool needUpdate
)
1994 if (limit
< -SEC_ADMINISTRATOR
)
1995 limit
= -SEC_ADMINISTRATOR
;
1998 bool db_update_need
= needUpdate
|| (limit
< 0) != (m_playerLimit
< 0) || (limit
< 0 && m_playerLimit
< 0 && limit
!= m_playerLimit
);
2000 m_playerLimit
= limit
;
2003 loginDatabase
.PExecute("UPDATE realmlist SET allowedSecurityLevel = '%u' WHERE id = '%d'",uint8(GetPlayerSecurityLimit()),realmID
);
2006 void World::UpdateMaxSessionCounters()
2008 m_maxActiveSessionCount
= std::max(m_maxActiveSessionCount
,uint32(m_sessions
.size()-m_QueuedPlayer
.size()));
2009 m_maxQueuedSessionCount
= std::max(m_maxQueuedSessionCount
,uint32(m_QueuedPlayer
.size()));
2012 void World::LoadDBVersion()
2014 QueryResult
* result
= WorldDatabase
.Query("SELECT version, creature_ai_version, cache_id FROM db_version LIMIT 1");
2017 Field
* fields
= result
->Fetch();
2019 m_DBVersion
= fields
[0].GetCppString();
2020 m_CreatureEventAIVersion
= fields
[1].GetCppString();
2022 // will be overwrite by config values if different and non-0
2023 setConfig(CONFIG_UINT32_CLIENTCACHE_VERSION
, fields
[2].GetUInt32());
2027 if(m_DBVersion
.empty())
2028 m_DBVersion
= "Unknown world database.";
2030 if(m_CreatureEventAIVersion
.empty())
2031 m_CreatureEventAIVersion
= "Unknown creature EventAI.";
2034 void World::setConfig(eConfigUInt32Values index
, char const* fieldname
, uint32 defvalue
)
2036 setConfig(index
, sConfig
.GetIntDefault(fieldname
,defvalue
));
2039 void World::setConfig(eConfigInt32Values index
, char const* fieldname
, int32 defvalue
)
2041 setConfig(index
, sConfig
.GetIntDefault(fieldname
,defvalue
));
2044 void World::setConfig(eConfigFloatValues index
, char const* fieldname
, float defvalue
)
2046 setConfig(index
, sConfig
.GetFloatDefault(fieldname
,defvalue
));
2049 void World::setConfig( eConfigBoolValues index
, char const* fieldname
, bool defvalue
)
2051 setConfig(index
, sConfig
.GetBoolDefault(fieldname
,defvalue
));
2054 void World::setConfigPos(eConfigUInt32Values index
, char const* fieldname
, uint32 defvalue
)
2056 setConfig(index
, fieldname
, defvalue
);
2057 if (int32(getConfig(index
)) < 0)
2059 sLog
.outError("%s (%i) can't be negative. Using %u instead.", fieldname
, int32(getConfig(index
)), defvalue
);
2060 setConfig(index
, defvalue
);
2064 void World::setConfigPos(eConfigFloatValues index
, char const* fieldname
, float defvalue
)
2066 setConfig(index
, fieldname
, defvalue
);
2067 if (getConfig(index
) < 0.0f
)
2069 sLog
.outError("%s (%f) can't be negative. Using %f instead.", fieldname
, getConfig(index
), defvalue
);
2070 setConfig(index
, defvalue
);
2074 void World::setConfigMin(eConfigUInt32Values index
, char const* fieldname
, uint32 defvalue
, uint32 minvalue
)
2076 setConfig(index
, fieldname
, defvalue
);
2077 if (getConfig(index
) < minvalue
)
2079 sLog
.outError("%s (%u) must be >= %u. Using %u instead.", fieldname
, getConfig(index
), minvalue
, minvalue
);
2080 setConfig(index
, minvalue
);
2084 void World::setConfigMin(eConfigInt32Values index
, char const* fieldname
, int32 defvalue
, int32 minvalue
)
2086 setConfig(index
, fieldname
, defvalue
);
2087 if (getConfig(index
) < minvalue
)
2089 sLog
.outError("%s (%i) must be >= %i. Using %i instead.", fieldname
, getConfig(index
), minvalue
, minvalue
);
2090 setConfig(index
, minvalue
);
2094 void World::setConfigMin(eConfigFloatValues index
, char const* fieldname
, float defvalue
, float minvalue
)
2096 setConfig(index
, fieldname
, defvalue
);
2097 if (getConfig(index
) < minvalue
)
2099 sLog
.outError("%s (%f) must be >= %f. Using %f instead.", fieldname
, getConfig(index
), minvalue
, minvalue
);
2100 setConfig(index
, minvalue
);
2104 void World::setConfigMinMax(eConfigUInt32Values index
, char const* fieldname
, uint32 defvalue
, uint32 minvalue
, uint32 maxvalue
)
2106 setConfig(index
, fieldname
, defvalue
);
2107 if (getConfig(index
) < minvalue
)
2109 sLog
.outError("%s (%u) must be in range %u...%u. Using %u instead.", fieldname
, getConfig(index
), minvalue
, maxvalue
, minvalue
);
2110 setConfig(index
, minvalue
);
2112 else if (getConfig(index
) > maxvalue
)
2114 sLog
.outError("%s (%u) must be in range %u...%u. Using %u instead.", fieldname
, getConfig(index
), minvalue
, maxvalue
, maxvalue
);
2115 setConfig(index
, maxvalue
);
2119 void World::setConfigMinMax(eConfigInt32Values index
, char const* fieldname
, int32 defvalue
, int32 minvalue
, int32 maxvalue
)
2121 setConfig(index
, fieldname
, defvalue
);
2122 if (getConfig(index
) < minvalue
)
2124 sLog
.outError("%s (%i) must be in range %i...%i. Using %i instead.", fieldname
, getConfig(index
), minvalue
, maxvalue
, minvalue
);
2125 setConfig(index
, minvalue
);
2127 else if (getConfig(index
) > maxvalue
)
2129 sLog
.outError("%s (%i) must be in range %i...%i. Using %i instead.", fieldname
, getConfig(index
), minvalue
, maxvalue
, maxvalue
);
2130 setConfig(index
, maxvalue
);
2134 void World::setConfigMinMax(eConfigFloatValues index
, char const* fieldname
, float defvalue
, float minvalue
, float maxvalue
)
2136 setConfig(index
, fieldname
, defvalue
);
2137 if (getConfig(index
) < minvalue
)
2139 sLog
.outError("%s (%f) must be in range %f...%f. Using %f instead.", fieldname
, getConfig(index
), minvalue
, maxvalue
, minvalue
);
2140 setConfig(index
, minvalue
);
2142 else if (getConfig(index
) > maxvalue
)
2144 sLog
.outError("%s (%f) must be in range %f...%f. Using %f instead.", fieldname
, getConfig(index
), minvalue
, maxvalue
, maxvalue
);
2145 setConfig(index
, maxvalue
);
2149 bool World::configNoReload(bool reload
, eConfigUInt32Values index
, char const* fieldname
, uint32 defvalue
)
2154 uint32 val
= sConfig
.GetIntDefault(fieldname
, defvalue
);
2155 if (val
!= getConfig(index
))
2156 sLog
.outError("%s option can't be changed at mangosd.conf reload, using current value (%u).", fieldname
, getConfig(index
));
2161 bool World::configNoReload(bool reload
, eConfigInt32Values index
, char const* fieldname
, int32 defvalue
)
2166 int32 val
= sConfig
.GetIntDefault(fieldname
, defvalue
);
2167 if (val
!= getConfig(index
))
2168 sLog
.outError("%s option can't be changed at mangosd.conf reload, using current value (%i).", fieldname
, getConfig(index
));
2173 bool World::configNoReload(bool reload
, eConfigFloatValues index
, char const* fieldname
, float defvalue
)
2178 float val
= sConfig
.GetFloatDefault(fieldname
, defvalue
);
2179 if (val
!= getConfig(index
))
2180 sLog
.outError("%s option can't be changed at mangosd.conf reload, using current value (%f).", fieldname
, getConfig(index
));
2185 bool World::configNoReload(bool reload
, eConfigBoolValues index
, char const* fieldname
, bool defvalue
)
2190 bool val
= sConfig
.GetBoolDefault(fieldname
, defvalue
);
2191 if (val
!= getConfig(index
))
2192 sLog
.outError("%s option can't be changed at mangosd.conf reload, using current value (%s).", fieldname
, getConfig(index
) ? "'true'" : "'false'");