/*
* Ascent MMORPG Server
* Copyright (C) 2005-2007 Ascent Team
*
* 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 3 of the License, or
* 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 .
*
*/
//
// WorldCreator.cpp
//
#include "StdAfx.h"
initialiseSingleton( WorldCreator );
initialiseSingleton( FormationMgr );
//initialiseSingleton( InstanceSavingManagement );
WorldCreator::WorldCreator(TaskList * tl)
{
new FormationMgr;
// Create all non-instance type maps.
QueryResult *result;
m_InstanceHigh = 0;
result = CharacterDatabase.Query( "SELECT MAX(instanceid) FROM instances" );
if( result )
{
m_InstanceHigh = result->Fetch()[0].GetUInt32()+1;
delete result;
}
#ifndef CLUSTERING
StorageContainerIterator * itr = WorldMapInfoStorage.MakeIterator();
while(!itr->AtEnd())
{
MapInfo * pInfo = itr->Get();
if(pInfo->type == INSTANCE_NULL)
{
// Create it (we're a non-instance).
// Add a loading task for this map.
tl->AddTask(new Task(new CallbackP1(WorldCreator::getSingletonPtr(), &WorldCreator::CreateMap, pInfo->mapid)));
}
if(!itr->Inc())
break;
}
itr->Destruct();
#endif
}
WorldCreator::~WorldCreator()
{
std::map::iterator it;
for(it = _maps.begin(); it != _maps.end(); it++)
{
delete it->second;
}
delete FormationMgr::getSingletonPtr();
}
Map* WorldCreator::_CreateMap(uint32 mapid)
{
std::map::iterator it;
it = _maps.find(mapid);
ASSERT(it == _maps.end());
Map *newmap = new Map(mapid);
ASSERT(newmap);
_maps.insert( std::pair(mapid, newmap) );
return newmap;
}
Map* WorldCreator::GetMap(uint32 mapid)
{
std::map::iterator it;
it = _maps.find(mapid);
if (it != _maps.end())
return it->second;
else
return _CreateMap(mapid);
}
MapMgr* WorldCreator::GetInstance(uint32 mapid, Object* obj)
{
// check inactive instances.
if(obj->GetInstanceID() > 2)
{
InactiveInstance * ia = sInstanceSavingManager.GetInactiveInstance(obj->GetInstanceID());
if(ia != 0)
{
//create that inactive instance.
//extra, it now checks if the instance should expire.
MapInfo *pMapInfo = WorldMapInfoStorage.LookupEntry(ia->MapId);
if(pMapInfo)
{
if((uint32)time(NULL) > (ia->Creation) + (pMapInfo->cooldown ? pMapInfo->cooldown : 604800))
{
sInstanceSavingManager.RemoveSavedInstance(ia->MapId,ia->InstanceId,true);
sInstanceSavingManager.RemoveSavedInstance(ia->InstanceId);
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL, NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
obj->SetMapId(ia->MapId);
delete ia;
return dm;
}
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL, NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
obj->SetMapId(ia->MapId);
delete ia;
return dm;
}
}
}
Map* mp = GetMap(mapid);
if(!mp) return NULL;
return mp->GetInstance(obj);
}
MapMgr* WorldCreator::GetInstance(uint32 mapid, uint32 instanceId)
{
// check inactive instances.
if(instanceId > 2)
{
InactiveInstance * ia = sInstanceSavingManager.GetInactiveInstance(instanceId);
if(ia != 0)
{
// create that inactive instance.
MapInfo *pMapInfo = WorldMapInfoStorage.LookupEntry(ia->MapId);
if(pMapInfo)
{
if((uint32)time(NULL) > (ia->Creation) + (pMapInfo->cooldown ? pMapInfo->cooldown : 604800))
{
sInstanceSavingManager.RemoveSavedInstance(ia->MapId,ia->InstanceId,true);
sInstanceSavingManager.RemoveSavedInstance(ia->InstanceId);
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL, NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL, NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
}
Map* mp = GetMap(mapid);
if(!mp) return NULL;
return mp->GetInstance(instanceId);
}
MapMgr* WorldCreator::GetInstance(uint32 instanceId)
{
// check inactive instances.
if(instanceId > 2)
{
InactiveInstance * ia = sInstanceSavingManager.GetInactiveInstance(instanceId);
if(ia != 0)
{
// create that inactive instance.
MapInfo *pMapInfo = WorldMapInfoStorage.LookupEntry(ia->MapId);
if(pMapInfo)
{
if((uint32)time(NULL) > (ia->Creation) + (pMapInfo->cooldown ? pMapInfo->cooldown : 604800))
{
sInstanceSavingManager.RemoveSavedInstance(ia->MapId,ia->InstanceId,true);
sInstanceSavingManager.RemoveSavedInstance(ia->InstanceId);
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL, NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL, NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
}
std::map::iterator it;
MapMgr *instance;
for(it = _maps.begin(); it != _maps.end(); it++)
{
instance = it->second->InstanceExists(instanceId);
if(instance != NULL)
return instance;
}
return NULL;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Instance Manager
// instance creation and basic management
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++
bool WorldCreator::CheckInstanceForObject(Object *obj, MapInfo *pMapinfo)
{
WorldPacket data(4);
Player *_player = NULL;
if(obj->GetTypeId() == TYPEID_PLAYER)
{
_player = static_cast(obj);
}
if(pMapinfo && _player)
{
switch(pMapinfo->type)
{
case INSTANCE_NONRAID:
case INSTANCE_RAID:
case INSTANCE_MULTIMODE:
{
//instance creation detection types
//case 1, player is inside a group aka not soloing
//onoes: leader can be inside a instance already and make a group or its a fresh group, noone inside
if(_player->InGroup()) //group created, join leader instance.
{
Group *pGroup = _player->GetGroup();
if(pGroup)
{
//check if instance already exists(player solo created instance and made group after)
MapMgr *pInstance = sWorldCreator.GetInstanceByGroup(pGroup, _player, pMapinfo);
if(pInstance)
{
//INSTANCE_OK
if(pInstance->IsCombatInProgress())
{
WorldPacket msg;
msg.Initialize(SMSG_AREA_TRIGGER_MESSAGE);
msg << uint32(0) << "Encounter in progress." << uint8(0) << uint8(0);
_player->GetSession()->SendPacket(&msg);
return false;
}
if(pInstance->GetPlayerCount() >= pMapinfo->playerlimit)
{
data.Initialize(SMSG_TRANSFER_ABORTED);
data << uint32(INSTANCE_ABORT_FULL);
_player->GetSession()->SendPacket(&data);
return false;
}
_player->SetInstanceID(pInstance->GetInstanceID());
}
else
{
//group leader didnt made any instance yet, create instance for this group.
uint32 id = sWorldCreator.CreateInstance(pGroup, pGroup->GetLeader(), pMapinfo->mapid);
// again, NULL might not be 0
//if(id != NULL)
if(id != 0)
{
//INSTANCE CREATED
_player->SetInstanceID(id);
}
else
{
data.Initialize(SMSG_TRANSFER_ABORTED);
data << uint32(INSTANCE_ABORT_ERROR);
_player->GetSession()->SendPacket(&data);
return false;
}
}
}
else
{
data.Initialize(SMSG_TRANSFER_ABORTED);
data << uint32(INSTANCE_ABORT_ERROR);
_player->GetSession()->SendPacket(&data);
return false;
}
}
else
{
MapMgr *pInstance = sWorldCreator.GetInstanceByCreator(_player, pMapinfo);
if(pInstance)
{
//INSTANCE_OK
if(pInstance->IsCombatInProgress())
{
WorldPacket msg;
msg.Initialize(SMSG_AREA_TRIGGER_MESSAGE);
msg << uint32(0) << "Encounter in progress." << uint8(0) << uint8(0);
_player->GetSession()->SendPacket(&msg);
return false;
}
if(pInstance->GetPlayerCount() >= pMapinfo->playerlimit)
{
data.Initialize(SMSG_TRANSFER_ABORTED);
data << uint32(INSTANCE_ABORT_FULL);
_player->GetSession()->SendPacket(&data);
return false;
}
_player->SetInstanceID(pInstance->GetInstanceID());
}
else
{
uint32 id2 = sWorldCreator.CreateInstance(NULL, _player, pMapinfo->mapid);
//if(id2 != NULL)
if(id2 != 0)
{
_player->SetInstanceID(id2);
}
else
{
data.Initialize(SMSG_TRANSFER_ABORTED);
data << uint32(INSTANCE_ABORT_ERROR);
_player->GetSession()->SendPacket(&data);
return false;
}
}
}
}break;
}
}
return true;
}
uint32 WorldCreator::CreateInstance(Group *pGroup, Player *pPlayer, uint32 mapid, uint32 instanceid, uint32 creation, MapMgr ** destptr, uint32 difficulty)
{
if(pGroup == NULL && pPlayer == NULL && instanceid == 0)
{
return INSTANCE_ABORT_ERROR;
}
Map* instance_map = GetMap(mapid);
ASSERT(instance_map != NULL);
MapMgr * pInstance = instance_map->CreateMapMgrInstance(instanceid);
ASSERT(pInstance);
if(creation)
{
pInstance->SetNewExpireTime(creation);
}
if(pGroup)
{
pInstance->SetGroupSignature(pGroup->GetID());
pInstance->iInstanceMode = pGroup->GetLeader()->iInstanceType;
}
if(pPlayer)
{
pInstance->SetCreator(pPlayer);
pInstance->iInstanceMode = pPlayer->iInstanceType;
}
if(difficulty)
{
pInstance->iInstanceMode = difficulty;
}
//Capt: We do not realy need to store this one if we are not doing something with it.
sInstanceSavingManager.SaveInstance(pInstance); //first time instance saving holder
if(destptr)
*destptr = pInstance;
return pInstance->GetInstanceID();
}
uint32 WorldCreator::CreateInstance(uint32 mapid, uint32 instanceid, MapMgr ** destptr)
{
Map* instance_map = GetMap(mapid);
ASSERT(instance_map != NULL);
MapMgr * pInstance = instance_map->CreateMapMgrInstance(instanceid);
ASSERT(pInstance);
if(destptr)
*destptr = pInstance;
return pInstance->GetInstanceID();
}
MapMgr *WorldCreator::GetInstanceByGroup(Group *pGroup, Player *pPlayer, MapInfo *pMapInfo)
{
MapMgr * mgr = GetMap(pMapInfo->mapid)->GetInstanceByGroup(pGroup, pPlayer);
if(mgr)
{
return mgr;
}
else
{
bool result = sInstanceSavingManager.IsPlayerSavedToMap(pMapInfo->mapid, pPlayer);
if(result)
{
Instance_Map_InstanceId_Holder *p = sInstanceSavingManager.GetRaidAndMMInstance(pMapInfo->mapid, pPlayer);
if(p)
{
InactiveInstance * ia = sInstanceSavingManager.GetInactiveInstance(p->GetInstanceID());
if(ia != 0)
{
//create that inactive instance.
//extra, it now checks if the instance should expire.
MapInfo *pMapInfo = WorldMapInfoStorage.LookupEntry(ia->MapId);
if(pMapInfo)
{
if((uint32)time(NULL) > (ia->Creation) + (pMapInfo->cooldown ? pMapInfo->cooldown : 604800))
{
sInstanceSavingManager.RemoveSavedInstance(ia->MapId,ia->InstanceId,true);
sInstanceSavingManager.RemoveSavedInstance(ia->InstanceId);
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL,NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL,NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
}
}
}
return NULL;
}
MapMgr *WorldCreator::GetInstanceByCreator(Player *pCreator, MapInfo *pMapInfo)
{
MapMgr *mgr = GetMap(pMapInfo->mapid)->GetInstanceByCreator(pCreator);
if(mgr)
{
return mgr;
}
else
{
bool result = sInstanceSavingManager.IsPlayerSavedToMap(pMapInfo->mapid, pCreator);
if(result)
{
Instance_Map_InstanceId_Holder *p = sInstanceSavingManager.GetRaidAndMMInstance(pMapInfo->mapid, pCreator);
if(p)
{
InactiveInstance * ia = sInstanceSavingManager.GetInactiveInstance(p->GetInstanceID());
if(ia != 0)
{
//create that inactive instance.
//extra, it now checks if the instance should expire.
MapInfo *pMapInfo = WorldMapInfoStorage.LookupEntry(ia->MapId);
if(pMapInfo)
{
if((uint32)time(NULL) > (ia->Creation) + (pMapInfo->cooldown ? pMapInfo->cooldown : 604800))
{
sInstanceSavingManager.RemoveSavedInstance(ia->MapId,ia->InstanceId,true);
sInstanceSavingManager.RemoveSavedInstance(ia->InstanceId);
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL,NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL,NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
}
}
}
return NULL;
}
uint32 WorldCreator::GenerateInstanceID()
{
m_InstanceHigh++;
return m_InstanceHigh;
}
void WorldCreator::DeleteInstance(uint32 instanceid, uint32 mapid)
{
_busy.Acquire();
MapMgr * mapMgr = NULL;
mapMgr = GetMap(mapid)->GetRawInstance(instanceid);
if(mapMgr)
{
if(!mapMgr->HasPlayers())
{
GetMap(mapid)->DestroyMapMgrInstance(instanceid);
sLog.outDebug("Instance %i on map %i deleted with success\n", instanceid, mapid);
}
}
else
{
sLog.outDebug("Instance %i failed to be deleted, reason: Doesnt Exist\n", instanceid);
}
_busy.Release();
}
void WorldCreator::InstanceSoftReset(MapMgr *mMapMgr)
{
uint32 mapid = mMapMgr->GetMapId();
uint32 instanceid = mMapMgr->GetInstanceID();
//delete public instance WoWInstance to avoid "rats".
DeleteInstance(mMapMgr->GetInstanceID(), mapid);
//delete instance save data
sInstanceSavingManager.RemoveSavedInstance(mapid, instanceid, false);
}
void WorldCreator::InstanceHardReset(MapMgr *mMapMgr)
{
uint32 mapid = mMapMgr->GetMapId();
uint32 instanceid = mMapMgr->GetInstanceID();
//delete public instance WoWInstance to avoid "rats".
DeleteInstance(mMapMgr->GetInstanceID(), mapid);
//delete instance save data
sInstanceSavingManager.RemoveSavedInstance(mapid, instanceid, true);
}
// Only usable by Instance save manager when removing players from the manager.
MapMgr * WorldCreator::ISMGetInstanceBeforeRemoval(uint32 InstanceID, uint32 mapid, bool Lock)
{
if(InstanceID > 2)
{
InactiveInstance * ia = sInstanceSavingManager.GetInactiveInstance(InstanceID);
if(ia != 0)
{
// create that inactive instance.
MapInfo *pMapInfo = WorldMapInfoStorage.LookupEntry(ia->MapId);
if(pMapInfo)
{
if((uint32)time(NULL) > (ia->Creation) + (pMapInfo->cooldown ? pMapInfo->cooldown : 604800))
{
sInstanceSavingManager.RemoveSavedInstance(ia->InstanceId);
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL, NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
else
{
MapMgr * dm = 0;
CreateInstance(NULL, NULL, ia->MapId, ia->InstanceId, ia->Creation, &dm, ia->difficulty);
delete ia;
return dm;
}
}
}
return GetMap(mapid)->GetInstanceByGroupInstanceId(InstanceID, Lock);
}
void WorldCreator::BuildXMLStats(char * m_file)
{
_busy.Acquire();
map::iterator itr = _maps.begin();
for(; itr != _maps.end(); ++itr)
{
itr->second->BuildXMLStats(m_file);
}
_busy.Release();
}
FormationMgr::FormationMgr()
{
QueryResult * res = WorldDatabase.Query("SELECT * FROM creature_formations");
if(res)
{
Formation *f ;
do
{
f = new Formation;
f->fol = res->Fetch()[1].GetUInt32();
f->ang = res->Fetch()[2].GetFloat();
f->dist = res->Fetch()[3].GetFloat();
m_formations[res->Fetch()[0].GetUInt32()] = f;
} while(res->NextRow());
delete res;
}
}
FormationMgr::~FormationMgr()
{
FormationMap::iterator itr;
for(itr = m_formations.begin(); itr != m_formations.end(); ++itr)
delete itr->second;
}