Skip to content

Commit

Permalink
[10089] Change in event system work with pool system.
Browse files Browse the repository at this point in the history
* `game_event_pool` dropped and related in momory data generated
  based by another pool tables content.

* Pool work with spawed at event and despawned at event object now different.
  - If object listed in `game_event_*` as spawned at event start and it's part of some pool
    then all other pool object must be listed as spawned with this event start, and more,
    if pool has mother pool, then all mother pool members must have objects spawned at this
    event start. More short: all object of some top (not have mother pool) mitbe or listed for some event start spawn,
    or not listed for any event start spawn.
  - If object listed in `game_event_*` as DEspawned at event start and it's part of some pool
    then nothing special required for other pool objects. Event systemwil command to pool system exclude for spawning and despawn referenced
    object until event end.

* Many checks has been added at event/pool data loading.
* Changes fix crashes related to event/pool common work.

Thanks to NoFantasy for help in research original problems and ways for improve code.
  • Loading branch information
VladimirMangos committed Jun 21, 2010
1 parent 5c2d1a0 commit 0219b08
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 109 deletions.
26 changes: 3 additions & 23 deletions sql/mangos.sql
Expand Up @@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_10086_01_mangos_command` bit(1) default NULL
`required_10089_01_mangos_game_event_pool` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';

--
Expand Down Expand Up @@ -1572,7 +1572,7 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `game_event_creature`;
CREATE TABLE `game_event_creature` (
`guid` int(10) unsigned NOT NULL,
`event` smallint(6) NOT NULL default '0' COMMENT 'Put negatives values to remove during event',
`event` smallint(6) NOT NULL default '0' COMMENT 'Negatives value to remove during event and ignore pool grouping, positive value for spawn during event and if guid is part of pool then al pool memebers must be listed as part of event spawn.',
PRIMARY KEY (`guid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Expand Down Expand Up @@ -1613,7 +1613,7 @@ UNLOCK TABLES;
DROP TABLE IF EXISTS `game_event_gameobject`;
CREATE TABLE `game_event_gameobject` (
`guid` int(10) unsigned NOT NULL,
`event` smallint(6) NOT NULL default '0' COMMENT 'Put negatives values to remove during event',
`event` smallint(6) NOT NULL default '0' COMMENT 'Negatives value to remove during event and ignore pool grouping, positive value for spawn during event and if guid is part of pool then al pool memebers must be listed as part of event spawn.',
PRIMARY KEY (`guid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Expand Down Expand Up @@ -1648,26 +1648,6 @@ LOCK TABLES `game_event_model_equip` WRITE;
/*!40000 ALTER TABLE `game_event_model_equip` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `game_event_pool`
--

DROP TABLE IF EXISTS `game_event_pool`;
CREATE TABLE `game_event_pool` (
`pool_entry` mediumint(8) unsigned NOT NULL default '0' COMMENT 'Id of the pool',
`event` smallint(6) NOT NULL default '0' COMMENT 'Put negatives values to remove during event',
PRIMARY KEY (`pool_entry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

--
-- Dumping data for table `game_event_pool`
--

LOCK TABLES `game_event_pool` WRITE;
/*!40000 ALTER TABLE `game_event_pool` DISABLE KEYS */;
/*!40000 ALTER TABLE `game_event_pool` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `game_graveyard_zone`
--
Expand Down
3 changes: 3 additions & 0 deletions sql/updates/10089_01_mangos_game_event_pool.sql
@@ -0,0 +1,3 @@
ALTER TABLE db_version CHANGE COLUMN required_10086_01_mangos_command required_10089_01_mangos_game_event_pool bit;

DROP TABLE IF EXISTS `game_event_pool`;
2 changes: 2 additions & 0 deletions sql/updates/Makefile.am
Expand Up @@ -90,6 +90,7 @@ pkgdata_DATA = \
10051_01_characters_character_aura.sql \
10056_01_mangos_spell_proc_event.sql \
10086_01_mangos_command.sql \
10089_01_mangos_game_event_pool.sql \
README

## Additional files to include when running 'make dist'
Expand Down Expand Up @@ -160,4 +161,5 @@ EXTRA_DIST = \
10051_01_characters_character_aura.sql \
10056_01_mangos_spell_proc_event.sql \
10086_01_mangos_command.sql \
10089_01_mangos_game_event_pool.sql \
README
211 changes: 147 additions & 64 deletions src/game/GameEventMgr.cpp
Expand Up @@ -171,6 +171,13 @@ void GameEventMgr::LoadFromDB()
sLog.outString( ">> Loaded %u game events", count );
}

std::map<uint16,int16> pool2event; // for check unique spawn event associated with pool
std::map<uint32,int16> creature2event; // for check unique spawn event associated with creature
std::map<uint32,int16> go2event; // for check unique spawn event associated with gameobject

// list only positive event top pools, filled at creature/gameobject loading
mGameEventSpawnPoolIds.resize(mGameEvent.size());

mGameEventCreatureGuids.resize(mGameEvent.size()*2-1);
// 1 2
result = WorldDatabase.Query("SELECT creature.guid, game_event_creature.event "
Expand Down Expand Up @@ -198,6 +205,12 @@ void GameEventMgr::LoadFromDB()
uint32 guid = fields[0].GetUInt32();
int16 event_id = fields[1].GetInt16();

if (event_id == 0)
{
sLog.outErrorDb("`game_event_creature` game event id (%i) not allowed",event_id);
continue;
}

int32 internal_event_id = mGameEvent.size() + event_id - 1;

if(internal_event_id < 0 || (size_t)internal_event_id >= mGameEventCreatureGuids.size())
Expand All @@ -207,6 +220,32 @@ void GameEventMgr::LoadFromDB()
}

++count;

// spawn objects at event can be grouped in pools and then affected pools have stricter requirements for this case
if (event_id > 0)
{
creature2event[guid] = event_id;

// not list explicitly creatures from pools in event creature list
if (uint16 topPoolId = sPoolMgr.IsPartOfTopPool<Creature>(guid))
{
int16& eventRef = pool2event[topPoolId];
if (eventRef != 0)
{
if (eventRef != event_id)
sLog.outErrorDb("`game_event_creature` have creature (GUID: %u) for event %i from pool or subpool of pool (ID: %u) but pool have already content from event %i. Pool don't must have content for different events!", guid, event_id, topPoolId, eventRef);
}
else
{
eventRef = event_id;
mGameEventSpawnPoolIds[event_id].push_back(topPoolId);
sPoolMgr.RemoveAutoSpawnForPool(topPoolId);
}

continue;
}
}

GuidList& crelist = mGameEventCreatureGuids[internal_event_id];
crelist.push_back(guid);

Expand Down Expand Up @@ -244,6 +283,12 @@ void GameEventMgr::LoadFromDB()
uint32 guid = fields[0].GetUInt32();
int16 event_id = fields[1].GetInt16();

if (event_id == 0)
{
sLog.outErrorDb("`game_event_gameobject` game event id (%i) not allowed",event_id);
continue;
}

int32 internal_event_id = mGameEvent.size() + event_id - 1;

if(internal_event_id < 0 || (size_t)internal_event_id >= mGameEventGameobjectGuids.size())
Expand All @@ -253,6 +298,32 @@ void GameEventMgr::LoadFromDB()
}

++count;

// spawn objects at event can be grouped in pools and then affected pools have stricter requirements for this case
if (event_id > 0)
{
go2event[guid] = event_id;

// not list explicitly gameobjects from pools in event gameobject list
if (uint16 topPoolId = sPoolMgr.IsPartOfTopPool<GameObject>(guid))
{
int16& eventRef = pool2event[topPoolId];
if (eventRef != 0)
{
if (eventRef != event_id)
sLog.outErrorDb("`game_event_gameobject` have gameobject (GUID: %u) for event %i from pool or subpool of pool (ID: %u) but pool have already content from event %i. Pool don't must have content for different events!", guid, event_id, topPoolId, eventRef);
}
else
{
eventRef = event_id;
mGameEventSpawnPoolIds[event_id].push_back(topPoolId);
sPoolMgr.RemoveAutoSpawnForPool(topPoolId);
}

continue;
}
}

GuidList& golist = mGameEventGameobjectGuids[internal_event_id];
golist.push_back(guid);

Expand All @@ -263,6 +334,15 @@ void GameEventMgr::LoadFromDB()
sLog.outString( ">> Loaded %u gameobjects in game events", count );
}

// now recheck that all eventPools linked with events after our skip pools with parents
for(std::map<uint16,int16>::const_iterator itr = pool2event.begin(); itr != pool2event.end(); ++itr)
{
uint16 pool_id = itr->first;
int16 event_id = itr->second;

sPoolMgr.CheckEventLinkAndReport(pool_id, event_id, creature2event, go2event);
}

mGameEventModelEquip.resize(mGameEvent.size());
// 0 1 2
result = WorldDatabase.Query("SELECT creature.guid, game_event_model_equip.event, game_event_model_equip.modelid,"
Expand Down Expand Up @@ -365,57 +445,6 @@ void GameEventMgr::LoadFromDB()
sLog.outString();
sLog.outString( ">> Loaded %u quests additions in game events", count );
}

mGameEventPoolIds.resize(mGameEvent.size()*2-1);
// 1 2
result = WorldDatabase.Query("SELECT pool_template.entry, game_event_pool.event "
"FROM pool_template JOIN game_event_pool ON pool_template.entry = game_event_pool.pool_entry");

count = 0;
if( !result )
{
barGoLink bar2(1);
bar2.step();

sLog.outString();
sLog.outString(">> Loaded %u pools in game events", count );
}
else
{

barGoLink bar2( (int)result->GetRowCount() );
do
{
Field *fields = result->Fetch();

bar2.step();

uint32 entry = fields[0].GetUInt16();
int16 event_id = fields[1].GetInt16();

int32 internal_event_id = mGameEvent.size() + event_id - 1;

if (internal_event_id < 0 || (size_t)internal_event_id >= mGameEventPoolIds.size())
{
sLog.outErrorDb("`game_event_pool` game event id (%i) is out of range compared to max event id in `game_event`",event_id);
continue;
}

if (!sPoolMgr.CheckPool(entry))
{
sLog.outErrorDb("Pool Id (%u) has all creatures or gameobjects with explicit chance sum <>100 and no equal chance defined. The pool system cannot pick one to spawn.", entry);
continue;
}

++count;
IdList& poollist = mGameEventPoolIds[internal_event_id];
poollist.push_back(entry);

} while( result->NextRow() );
sLog.outString();
sLog.outString( ">> Loaded %u pools in game events", count );
delete result;
}
}

uint32 GameEventMgr::Initialize() // return the next event delay in ms
Expand Down Expand Up @@ -516,6 +545,18 @@ void GameEventMgr::GameEventSpawn(int16 event_id)
CreatureData const* data = sObjectMgr.GetCreatureData(*itr);
if (data)
{
// negative event id for pool element meaning allow be used in next pool spawn
if (event_id < 0)
{
if (uint16 pool_id = sPoolMgr.IsPartOfAPool<Creature>(*itr))
{
// will have chance at next pool update
sPoolMgr.SetExcludeObject<Creature>(pool_id, *itr, false);
sPoolMgr.UpdatePool<Creature>(pool_id);
continue;
}
}

sObjectMgr.AddCreatureToGrid(*itr, data);

// Spawn if necessary (loaded grids only)
Expand Down Expand Up @@ -549,7 +590,20 @@ void GameEventMgr::GameEventSpawn(int16 event_id)
GameObjectData const* data = sObjectMgr.GetGOData(*itr);
if (data)
{
// negative event id for pool element meaning allow be used in next pool spawn
if (event_id < 0)
{
if (uint16 pool_id = sPoolMgr.IsPartOfAPool<GameObject>(*itr))
{
// will have chance at next pool update
sPoolMgr.SetExcludeObject<GameObject>(pool_id, *itr, false);
sPoolMgr.UpdatePool<GameObject>(pool_id);
continue;
}
}

sObjectMgr.AddGameobjectToGrid(*itr, data);

// Spawn if necessary (loaded grids only)
// this base map checked as non-instanced and then only existed
Map* map = const_cast<Map*>(sMapMgr.CreateBaseMap(data->mapid));
Expand All @@ -571,14 +625,17 @@ void GameEventMgr::GameEventSpawn(int16 event_id)
}
}

if (internal_event_id < 0 || (size_t)internal_event_id >= mGameEventPoolIds.size())
if (event_id > 0)
{
sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventPoolIds element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventPoolIds.size());
return;
}
if((size_t)event_id >= mGameEventSpawnPoolIds.size())
{
sLog.outError("GameEventMgr::GameEventSpawn attempt access to out of range mGameEventSpawnPoolIds element %i (size: " SIZEFMTD ")", event_id, mGameEventSpawnPoolIds.size());
return;
}

for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin();itr != mGameEventPoolIds[internal_event_id].end();++itr)
sPoolMgr.SpawnPool(*itr, true);
for (IdList::iterator itr = mGameEventSpawnPoolIds[event_id].begin();itr != mGameEventSpawnPoolIds[event_id].end();++itr)
sPoolMgr.SpawnPool(*itr, true);
}
}

void GameEventMgr::GameEventUnspawn(int16 event_id)
Expand All @@ -596,6 +653,17 @@ void GameEventMgr::GameEventUnspawn(int16 event_id)
// Remove the creature from grid
if( CreatureData const* data = sObjectMgr.GetCreatureData(*itr) )
{
// negative event id for pool element meaning unspawn in pool and exclude for next spawns
if (event_id < 0)
{
if (uint16 poolid = sPoolMgr.IsPartOfAPool<Creature>(*itr))
{
sPoolMgr.SetExcludeObject<Creature>(poolid, *itr, true);
sPoolMgr.UpdatePool<Creature>(poolid, *itr);
continue;
}
}

sObjectMgr.RemoveCreatureFromGrid(*itr, data);

if (Creature* pCreature = ObjectAccessor::GetCreatureInWorld(ObjectGuid(HIGHGUID_UNIT, data->id, *itr)))
Expand All @@ -614,21 +682,36 @@ void GameEventMgr::GameEventUnspawn(int16 event_id)
// Remove the gameobject from grid
if(GameObjectData const* data = sObjectMgr.GetGOData(*itr))
{
// negative event id for pool element meaning unspawn in pool and exclude for next spawns
if (event_id < 0)
{
if (uint16 poolid = sPoolMgr.IsPartOfAPool<GameObject>(*itr))
{
sPoolMgr.SetExcludeObject<GameObject>(poolid, *itr, true);
sPoolMgr.UpdatePool<GameObject>(poolid, *itr);
continue;
}
}

sObjectMgr.RemoveGameobjectFromGrid(*itr, data);

if( GameObject* pGameobject = ObjectAccessor::GetGameObjectInWorld(ObjectGuid(HIGHGUID_GAMEOBJECT, data->id, *itr)) )
pGameobject->AddObjectToRemoveList();
}
}
if (internal_event_id < 0 || (size_t)internal_event_id >= mGameEventPoolIds.size())
{
sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventPoolIds element %i (size: " SIZEFMTD ")",internal_event_id,mGameEventPoolIds.size());
return;
}

for (IdList::iterator itr = mGameEventPoolIds[internal_event_id].begin();itr != mGameEventPoolIds[internal_event_id].end();++itr)
if (event_id > 0)
{
sPoolMgr.DespawnPool(*itr);
if ((size_t)event_id >= mGameEventSpawnPoolIds.size())
{
sLog.outError("GameEventMgr::GameEventUnspawn attempt access to out of range mGameEventSpawnPoolIds element %i (size: " SIZEFMTD ")", event_id, mGameEventSpawnPoolIds.size());
return;
}

for (IdList::iterator itr = mGameEventSpawnPoolIds[event_id].begin();itr != mGameEventSpawnPoolIds[event_id].end();++itr)
{
sPoolMgr.DespawnPool(*itr);
}
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/game/GameEventMgr.h
Expand Up @@ -88,11 +88,11 @@ class GameEventMgr
typedef std::pair<uint32, uint32> QuestRelation;
typedef std::list<QuestRelation> QuestRelList;
typedef std::vector<QuestRelList> GameEventQuestMap;
GameEventQuestMap mGameEventQuests;
GameEventModelEquipMap mGameEventModelEquip;
GameEventGuidMap mGameEventCreatureGuids;
GameEventGuidMap mGameEventGameobjectGuids;
GameEventIdMap mGameEventPoolIds;
GameEventQuestMap mGameEventQuests; // events*2-1
GameEventModelEquipMap mGameEventModelEquip; // events*2-1
GameEventGuidMap mGameEventCreatureGuids; // events*2-1
GameEventGuidMap mGameEventGameobjectGuids; // events*2-1
GameEventIdMap mGameEventSpawnPoolIds; // events size, only positive event case
GameEventDataMap mGameEvent;
ActiveEvents m_ActiveEvents;
bool m_IsGameEventsInit;
Expand Down

0 comments on commit 0219b08

Please sign in to comment.