2010-10-07 15:35:36 +02:00
/*
2011-01-01 15:01:13 +01:00
* Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 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, see <http://www.gnu.org/licenses/>.
2008-10-02 16:23:55 -05:00
*/
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
#include "MapManager.h"
#include "InstanceSaveMgr.h"
2010-06-08 16:13:55 -06:00
#include "DatabaseEnv.h"
2008-10-02 16:23:55 -05:00
#include "Log.h"
#include "ObjectAccessor.h"
2010-06-07 15:59:21 -06:00
#include "Transport.h"
2008-10-02 16:23:55 -05:00
#include "GridDefines.h"
#include "MapInstanced.h"
2010-08-08 22:54:58 +06:00
#include "InstanceScript.h"
2008-10-02 16:23:55 -05:00
#include "DestinationHolderImp.h"
2010-07-29 01:22:45 +02:00
#include "Config.h"
2008-10-02 16:23:55 -05:00
#include "World.h"
#include "CellImpl.h"
#include "Corpse.h"
#include "ObjectMgr.h"
2009-04-07 18:01:22 +02:00
#include "Language.h"
2010-04-27 09:45:43 +02:00
#include "WorldPacket.h"
2010-11-29 07:50:31 +01:00
#include "Group.h"
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
extern GridState * si_GridStates []; // debugging code, should be deleted some day
2009-10-17 15:51:44 -07:00
2009-12-21 07:58:19 +01:00
MapManager :: MapManager ()
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
i_gridCleanUpDelay = sWorld -> getIntConfig ( CONFIG_INTERVAL_GRIDCLEAN );
i_timer . SetInterval ( sWorld -> getIntConfig ( CONFIG_INTERVAL_MAPUPDATE ));
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
MapManager ::~ MapManager ()
{
}
2009-10-17 15:51:44 -07:00
2009-12-21 07:58:19 +01:00
void MapManager :: Initialize ()
2008-10-02 16:23:55 -05:00
{
Map :: InitStateMachine ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// debugging code, should be deleted some day
{
2009-11-22 19:56:48 -08:00
for ( uint8 i = 0 ; i < MAX_GRID_STATE ; ++ i )
2009-12-21 07:58:19 +01:00
i_GridStates [ i ] = si_GridStates [ i ];
2009-11-22 19:56:48 -08:00
2008-10-02 16:23:55 -05:00
i_GridStateErrorCount = 0 ;
}
2010-12-23 23:25:44 +01:00
int num_threads ( sWorld -> getIntConfig ( CONFIG_NUMTHREADS ));
2009-12-17 07:34:00 +01:00
// Start mtmaps if needed.
2009-12-21 07:58:19 +01:00
if ( num_threads > 0 && m_updater . activate ( num_threads ) == - 1 )
2009-12-17 07:34:00 +01:00
abort ();
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
InitMaxInstanceId ();
}
2009-10-17 15:51:44 -07:00
2009-09-27 02:24:25 -07:00
void MapManager :: InitializeVisibilityDistanceInfo ()
{
2009-12-17 11:30:18 +01:00
for ( MapMapType :: iterator iter = i_maps . begin (); iter != i_maps . end (); ++ iter )
2009-09-27 02:24:25 -07:00
( * iter ). second -> InitVisibilityDistance ();
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
// debugging code, should be deleted some day
void MapManager :: checkAndCorrectGridStatesArray ()
{
bool ok = true ;
2009-12-17 11:30:18 +01:00
for ( int i = 0 ; i < MAX_GRID_STATE ; i ++ )
2008-10-02 16:23:55 -05:00
{
2009-12-21 07:58:19 +01:00
if ( i_GridStates [ i ] != si_GridStates [ i ])
2008-10-02 16:23:55 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outError ( "MapManager::checkGridStates(), GridState: si_GridStates is currupt !!!" );
2008-10-02 16:23:55 -05:00
ok = false ;
si_GridStates [ i ] = i_GridStates [ i ];
}
2008-10-14 11:57:03 -05:00
#ifdef TRINITY_DEBUG
2008-10-02 16:23:55 -05:00
// inner class checking only when compiled with debug
2009-12-21 07:58:19 +01:00
if ( ! si_GridStates [ i ] -> checkMagic ())
2008-10-02 16:23:55 -05:00
{
ok = false ;
si_GridStates [ i ] -> setMagic ();
}
#endif
}
2009-12-21 07:58:19 +01:00
if ( ! ok )
2008-10-02 16:23:55 -05:00
++ i_GridStateErrorCount ;
}
2009-10-17 15:51:44 -07:00
2009-12-21 07:58:19 +01:00
Map * MapManager :: _createBaseMap ( uint32 id )
2008-10-02 16:23:55 -05:00
{
Map * m = _findMap ( id );
2009-10-17 15:51:44 -07:00
2009-12-21 07:58:19 +01:00
if ( m == NULL )
2008-10-02 16:23:55 -05:00
{
2010-06-25 00:18:01 +02:00
ACE_GUARD_RETURN ( ACE_Thread_Mutex , Guard , Lock , NULL );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
const MapEntry * entry = sMapStore . LookupEntry ( id );
2008-10-05 08:48:32 -05:00
if ( entry && entry -> Instanceable ())
2008-10-02 16:23:55 -05:00
{
2008-11-18 19:40:06 -06:00
m = new MapInstanced ( id , i_gridCleanUpDelay );
2008-10-02 16:23:55 -05:00
}
2009-08-03 12:52:31 +02:00
else
{
2009-12-17 11:30:18 +01:00
m = new Map ( id , i_gridCleanUpDelay , 0 , REGULAR_DIFFICULTY );
2009-08-03 12:52:31 +02:00
}
2008-10-02 16:23:55 -05:00
i_maps [ id ] = m ;
}
2009-10-17 15:51:44 -07:00
2010-07-30 20:04:28 +02:00
ASSERT ( m != NULL );
2008-10-02 16:23:55 -05:00
return m ;
}
2009-10-17 15:51:44 -07:00
2010-04-19 09:26:37 +02:00
Map * MapManager :: CreateMap ( uint32 id , const WorldObject * obj , uint32 /*instanceId*/ )
2008-10-02 16:23:55 -05:00
{
2009-06-16 11:19:59 -05:00
ASSERT ( obj );
2010-12-23 23:25:44 +01:00
//if (!obj->IsInWorld()) sLog->outError("GetMap: called for map %d with object (typeid %d, guid %d, mapid %d, instanceid %d) who is not in world!", id, obj->GetTypeId(), obj->GetGUIDLow(), obj->GetMapId(), obj->GetInstanceId());
2009-06-16 11:19:59 -05:00
Map * m = _createBaseMap ( id );
2009-10-17 15:51:44 -07:00
2009-12-17 11:30:18 +01:00
if ( m && ( obj -> GetTypeId () == TYPEID_PLAYER ) && m -> Instanceable ()) m = (( MapInstanced * ) m ) -> CreateInstance ( id , ( Player * ) obj );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
return m ;
}
2009-10-17 15:51:44 -07:00
2009-06-16 11:19:59 -05:00
Map * MapManager :: FindMap ( uint32 mapid , uint32 instanceId ) const
2008-10-02 16:23:55 -05:00
{
2009-06-16 11:19:59 -05:00
Map * map = _findMap ( mapid );
2009-12-21 07:58:19 +01:00
if ( ! map )
2009-06-16 11:19:59 -05:00
return NULL ;
2009-10-17 15:51:44 -07:00
2009-12-21 07:58:19 +01:00
if ( ! map -> Instanceable ())
2009-06-16 11:19:59 -05:00
return instanceId == 0 ? map : NULL ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
return (( MapInstanced * ) map ) -> FindMap ( instanceId );
}
2009-10-17 15:51:44 -07:00
2010-05-04 18:25:30 +02:00
bool MapManager :: CanPlayerEnter ( uint32 mapid , Player * player , bool loginCheck )
2008-10-02 16:23:55 -05:00
{
2011-01-24 11:20:30 +01:00
MapEntry const * entry = sMapStore . LookupEntry ( mapid );
2010-04-07 19:14:10 +02:00
if ( ! entry )
2009-12-21 07:58:19 +01:00
return false ;
2010-05-04 19:21:01 +02:00
if ( ! entry -> IsDungeon ())
return true ;
2010-12-22 20:23:47 +01:00
InstanceTemplate const * instance = ObjectMgr :: GetInstanceTemplate ( mapid );
2010-06-26 14:06:29 +02:00
if ( ! instance )
return false ;
2010-07-29 18:11:41 +02:00
Difficulty targetDifficulty = player -> GetDifficulty ( entry -> IsRaid ());
2010-06-26 14:06:29 +02:00
//The player has a heroic mode and tries to enter into instance which has no a heroic mode
2010-07-29 18:11:41 +02:00
MapDifficulty const * mapDiff = GetMapDifficultyData ( entry -> MapID , targetDifficulty );
2010-06-26 14:06:29 +02:00
if ( ! mapDiff )
{
2010-07-29 18:11:41 +02:00
// Send aborted message for dungeons
if ( entry -> IsNonRaidDungeon ())
{
player -> SendTransferAborted ( mapid , TRANSFER_ABORT_DIFFICULTY , player -> GetDungeonDifficulty ());
return false ;
}
else // attempt to downscale
mapDiff = GetDownscaledMapDifficultyData ( entry -> MapID , targetDifficulty );
2010-06-26 14:06:29 +02:00
}
//Bypass checks for GMs
if ( player -> isGameMaster ())
return true ;
2011-01-24 11:20:30 +01:00
char const * mapName = entry -> name [ player -> GetSession () -> GetSessionDbcLocale ()];
2009-10-17 15:51:44 -07:00
2011-01-24 11:20:30 +01:00
Group * group = player -> GetGroup ();
2010-05-04 19:21:01 +02:00
if ( entry -> IsRaid ())
2008-10-02 16:23:55 -05:00
{
2010-05-04 19:21:01 +02:00
// can only enter in a raid group
2011-01-24 11:20:30 +01:00
if (( ! group || ! group -> isRaidGroup ()) && ! sWorld -> getBoolConfig ( CONFIG_INSTANCE_IGNORE_RAID ))
2008-10-02 16:23:55 -05:00
{
2010-05-04 19:21:01 +02:00
// probably there must be special opcode, because client has this string constant in GlobalStrings.lua
// TODO: this is not a good place to send the message
player -> GetSession () -> SendAreaTriggerMessage ( player -> GetSession () -> GetTrinityString ( LANG_INSTANCE_RAID_GROUP_ONLY ), mapName );
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_MAPS , "MAP: Player '%s' must be in a raid group to enter instance '%s'" , player -> GetName (), mapName );
2008-10-02 16:23:55 -05:00
return false ;
}
2010-05-04 19:21:01 +02:00
}
if ( ! player -> isAlive ())
{
2011-01-24 11:20:30 +01:00
if ( Corpse * corpse = player -> GetCorpse ())
2008-10-02 16:23:55 -05:00
{
2010-05-04 19:21:01 +02:00
// let enter in ghost mode in instance that connected to inner instance with corpse
2011-01-24 11:20:30 +01:00
uint32 corpseMap = corpse -> GetMapId ();
2010-05-04 19:21:01 +02:00
do
2008-10-02 16:23:55 -05:00
{
2011-01-24 11:20:30 +01:00
if ( corpseMap == mapid )
2010-05-04 19:21:01 +02:00
break ;
2009-10-17 15:51:44 -07:00
2011-01-24 11:20:30 +01:00
InstanceTemplate const * instance = ObjectMgr :: GetInstanceTemplate ( corpseMap );
corpseMap = instance ? instance -> parent : 0 ;
} while ( corpseMap );
2010-05-04 19:21:01 +02:00
2011-01-24 11:20:30 +01:00
if ( ! corpseMap )
2008-10-02 16:23:55 -05:00
{
2010-05-04 19:21:01 +02:00
WorldPacket data ( SMSG_CORPSE_NOT_IN_INSTANCE );
player -> GetSession () -> SendPacket ( & data );
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_MAPS , "MAP: Player '%s' does not have a corpse in instance '%s' and cannot enter." , player -> GetName (), mapName );
2010-05-04 19:21:01 +02:00
return false ;
2008-10-02 16:23:55 -05:00
}
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_MAPS , "MAP: Player '%s' has corpse in instance '%s' and can enter." , player -> GetName (), mapName );
2008-10-02 16:23:55 -05:00
}
2010-05-04 19:21:01 +02:00
else
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_MAPS , "Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!" , player -> GetName ());
2010-05-04 19:21:01 +02:00
}
2009-12-18 13:41:30 -08:00
2010-05-04 19:21:01 +02:00
//Get instance where player's group is bound & its map
2011-01-24 11:20:30 +01:00
if ( group )
2010-05-04 19:21:01 +02:00
{
2011-01-24 11:20:30 +01:00
InstanceGroupBind * boundInstance = group -> GetBoundInstance ( entry );
if ( boundInstance && boundInstance -> save )
if ( Map * boundMap = sMapMgr -> FindMap ( mapid , boundInstance -> save -> GetInstanceId ()))
if ( ! loginCheck && ! boundMap -> CanEnter ( player ))
2010-06-28 20:31:20 +02:00
return false ;
/*
This check has to be moved to InstanceMap::CanEnter()
2010-05-04 19:21:01 +02:00
// Player permanently bounded to different instance than groups one
2010-06-26 13:32:24 +02:00
InstancePlayerBind* playerBoundedInstance = player->GetBoundInstance(mapid, player->GetDifficulty(entry->IsRaid()));
2010-05-04 19:21:01 +02:00
if (playerBoundedInstance && playerBoundedInstance->perm && playerBoundedInstance->save &&
boundedInstance->save->GetInstanceId() != playerBoundedInstance->save->GetInstanceId())
2009-10-22 13:05:52 +02:00
{
2010-05-04 19:21:01 +02:00
//TODO: send some kind of error message to the player
return false;
2010-06-28 20:31:20 +02:00
}*/
2008-10-02 16:23:55 -05:00
}
2010-05-04 19:21:01 +02:00
2011-01-24 11:20:30 +01:00
// players are only allowed to enter 5 instances per hour
if ( entry -> IsDungeon () && ( ! player -> GetGroup () || ( player -> GetGroup () && ! player -> GetGroup () -> isLFGGroup ())))
{
uint32 instaceIdToCheck = 0 ;
if ( InstanceSave * save = player -> GetInstanceSave ( mapid , entry -> IsRaid ()))
instaceIdToCheck = save -> GetInstanceId ();
// instanceId can never be 0 - will not be found
if ( ! player -> CheckInstanceCount ( instaceIdToCheck ))
{
player -> SendTransferAborted ( mapid , TRANSFER_ABORT_TOO_MANY_INSTANCES );
return false ;
}
}
2010-05-04 19:21:01 +02:00
//Other requirements
2010-12-22 21:25:23 +01:00
return player -> Satisfy ( sObjectMgr -> GetAccessRequirement ( mapid , targetDifficulty ), mapid , true );
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2009-12-21 07:58:19 +01:00
void MapManager :: Update ( uint32 diff )
2008-10-02 16:23:55 -05:00
{
i_timer . Update ( diff );
2009-10-30 22:52:37 -07:00
if ( ! i_timer . Passed ())
2008-10-02 16:23:55 -05:00
return ;
2009-10-17 15:51:44 -07:00
2009-10-30 22:52:37 -07:00
MapMapType :: iterator iter = i_maps . begin ();
2009-10-30 22:56:20 -07:00
for (; iter != i_maps . end (); ++ iter )
2009-06-18 19:27:17 -05:00
{
2010-07-29 19:48:40 +02:00
if ( m_updater . activated ())
2010-09-03 22:40:16 -07:00
m_updater . schedule_update ( * iter -> second , uint32 ( i_timer . GetCurrent ()));
2010-07-29 19:48:40 +02:00
else
2010-09-03 22:40:16 -07:00
iter -> second -> Update ( uint32 ( i_timer . GetCurrent ()));
2008-10-02 16:23:55 -05:00
}
2009-12-21 07:58:19 +01:00
if ( m_updater . activated ())
2010-07-29 19:48:40 +02:00
m_updater . wait ();
2009-10-17 15:51:44 -07:00
2009-10-30 22:57:25 -07:00
for ( iter = i_maps . begin (); iter != i_maps . end (); ++ iter )
2010-09-03 22:40:16 -07:00
iter -> second -> DelayedUpdate ( uint32 ( i_timer . GetCurrent ()));
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sObjectAccessor -> Update ( uint32 ( i_timer . GetCurrent ()));
2008-10-02 16:23:55 -05:00
for ( TransportSet :: iterator iter = m_Transports . begin (); iter != m_Transports . end (); ++ iter )
2010-09-03 22:40:16 -07:00
( * iter ) -> Update ( uint32 ( i_timer . GetCurrent ()));
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
i_timer . SetCurrent ( 0 );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
void MapManager :: DoDelayedMovesAndRemoves ()
{
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
bool MapManager :: ExistMapAndVMap ( uint32 mapid , float x , float y )
{
2008-10-14 11:57:03 -05:00
GridPair p = Trinity :: ComputeGridPair ( x , y );
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
int gx = 63 - p . x_coord ;
int gy = 63 - p . y_coord ;
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
return Map :: ExistMap ( mapid , gx , gy ) && Map :: ExistVMap ( mapid , gx , gy );
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
bool MapManager :: IsValidMAP ( uint32 mapid )
{
MapEntry const * mEntry = sMapStore . LookupEntry ( mapid );
2010-12-22 21:56:43 +01:00
return mEntry && ( ! mEntry -> IsDungeon () || ObjectMgr :: GetInstanceTemplate ( mapid ));
2008-12-24 09:58:26 -06:00
// TODO: add check for battleground template
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
void MapManager :: UnloadAll ()
{
2011-01-16 00:08:52 +01:00
for ( TransportSet :: iterator i = m_Transports . begin (); i != m_Transports . end (); ++ i )
{
( * i ) -> RemoveFromWorld ();
delete * i ;
}
2009-10-17 15:51:44 -07:00
2011-01-16 00:08:52 +01:00
for ( MapMapType :: iterator iter = i_maps . begin (); iter != i_maps . end ();)
2008-10-02 16:23:55 -05:00
{
2011-01-16 00:08:52 +01:00
iter -> second -> UnloadAll ();
delete iter -> second ;
i_maps . erase ( iter ++ );
2008-10-02 16:23:55 -05:00
}
2009-12-17 07:34:00 +01:00
if ( m_updater . activated ())
m_updater . deactivate ();
2011-01-16 00:08:52 +01:00
Map :: DeleteStateMachine ();
2008-10-02 16:23:55 -05:00
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
void MapManager :: InitMaxInstanceId ()
{
i_MaxInstanceId = 0 ;
2009-10-17 15:51:44 -07:00
2010-09-11 21:10:54 +02:00
QueryResult result = CharacterDatabase . Query ( "SELECT MAX(id) FROM instance" );
2009-12-21 07:58:19 +01:00
if ( result )
2008-10-02 16:23:55 -05:00
i_MaxInstanceId = result -> Fetch ()[ 0 ]. GetUInt32 ();
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 MapManager :: GetNumInstances ()
{
2010-06-25 00:18:01 +02:00
ACE_GUARD_RETURN ( ACE_Thread_Mutex , Guard , Lock , NULL );
2009-12-17 07:34:00 +01:00
2008-10-02 16:23:55 -05:00
uint32 ret = 0 ;
2009-10-17 16:20:24 -07:00
for ( MapMapType :: iterator itr = i_maps . begin (); itr != i_maps . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Map * map = itr -> second ;
2009-12-21 07:58:19 +01:00
if ( ! map -> Instanceable ())
continue ;
2008-10-02 16:23:55 -05:00
MapInstanced :: InstancedMaps & maps = (( MapInstanced * ) map ) -> GetInstancedMaps ();
2009-10-17 16:20:24 -07:00
for ( MapInstanced :: InstancedMaps :: iterator mitr = maps . begin (); mitr != maps . end (); ++ mitr )
2010-04-07 19:14:10 +02:00
if ( mitr -> second -> IsDungeon ()) ret ++ ;
2008-10-02 16:23:55 -05:00
}
return ret ;
}
2009-10-17 15:51:44 -07:00
2008-10-02 16:23:55 -05:00
uint32 MapManager :: GetNumPlayersInInstances ()
{
2010-06-25 00:18:01 +02:00
ACE_GUARD_RETURN ( ACE_Thread_Mutex , Guard , Lock , NULL );
2009-12-17 07:34:00 +01:00
2008-10-02 16:23:55 -05:00
uint32 ret = 0 ;
2009-10-17 16:20:24 -07:00
for ( MapMapType :: iterator itr = i_maps . begin (); itr != i_maps . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Map * map = itr -> second ;
2009-12-21 07:58:19 +01:00
if ( ! map -> Instanceable ())
continue ;
2008-10-02 16:23:55 -05:00
MapInstanced :: InstancedMaps & maps = (( MapInstanced * ) map ) -> GetInstancedMaps ();
2009-10-17 16:20:24 -07:00
for ( MapInstanced :: InstancedMaps :: iterator mitr = maps . begin (); mitr != maps . end (); ++ mitr )
2009-12-21 07:58:19 +01:00
if ( mitr -> second -> IsDungeon ())
2008-11-18 19:40:06 -06:00
ret += (( InstanceMap * ) mitr -> second ) -> GetPlayers (). getSize ();
2008-10-02 16:23:55 -05:00
}
return ret ;
}