Core/GameObject: implemented gameobject_overrides table to change faction and flags values on a per-spawn basis

Updates #20957
Closes #20958

(cherry picked from commit 34967e9c32)
This commit is contained in:
ariel-
2018-02-24 20:57:55 -03:00
committed by funjoker
parent 4c8a49302f
commit 67a1a1d29b
10 changed files with 117 additions and 32 deletions

View File

@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS `gameobject_overrides` (
`spawnId` bigint(20) unsigned NOT NULL DEFAULT '0',
`faction` smallint(5) unsigned NOT NULL DEFAULT '0',
`flags` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`spawnId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

View File

@@ -318,11 +318,14 @@ bool GameObject::Create(uint32 entry, Map* map, Position const& pos, QuaternionD
SetObjectScale(goInfo->size);
if (GameObjectOverride const* goOverride = GetGameObjectOverride())
{
SetFaction(goOverride->Faction);
SetFlags(GameObjectFlags(goOverride->Flags));
}
if (m_goTemplateAddon)
{
SetFaction(m_goTemplateAddon->faction);
SetFlags(GameObjectFlags(m_goTemplateAddon->flags));
if (m_goTemplateAddon->WorldEffectID)
{
m_updateFlag.GameObject = true;
@@ -871,14 +874,14 @@ void GameObject::Update(uint32 diff)
SetGoState(GO_STATE_READY);
//any return here in case battleground traps
if (GameObjectTemplateAddon const* addon = GetTemplateAddon())
if (addon->flags & GO_FLAG_NODESPAWN)
if (GameObjectOverride const* goOverride = GetGameObjectOverride())
if (goOverride->Flags & GO_FLAG_NODESPAWN)
return;
}
loot.clear();
//! If this is summoned by a spell with ie. SPELL_EFFECT_SUMMON_OBJECT_WILD, with or without owner, we check respawn criteria based on spell
//! If this is summoned by a spell with ie. SPELL_EFFECT_SUMMON_OBJECT_WILD, with or without owner, we check respawn criteria based on speSendObjectDeSpawnAnim(GetGUID());ll
//! The GetOwnerGUID() check is mostly for compatibility with hacky scripts - 99% of the time summoning should be done trough spells.
if (GetSpellId() || !GetOwnerGUID().IsEmpty())
{
@@ -894,8 +897,8 @@ void GameObject::Update(uint32 diff)
{
SendGameObjectDespawn();
//reset flags
if (GameObjectTemplateAddon const* addon = GetTemplateAddon())
SetFlags(GameObjectFlags(addon->flags));
if (GameObjectOverride const* goOverride = GetGameObjectOverride())
SetFlags(GameObjectFlags(goOverride->Flags));
}
if (!m_respawnDelayTime)
@@ -938,6 +941,17 @@ void GameObject::Update(uint32 diff)
}
}
GameObjectOverride const* GameObject::GetGameObjectOverride() const
{
if (m_spawnId)
{
if (GameObjectOverride const* goOverride = sObjectMgr->GetGameObjectOverride(m_spawnId))
return goOverride;
}
return m_goTemplateAddon;
}
void GameObject::Refresh()
{
// Do not refresh despawned GO from spellcast (GO's from spellcast are destroyed after despawn)
@@ -982,8 +996,8 @@ void GameObject::Delete()
SetGoState(GO_STATE_READY);
if (GameObjectTemplateAddon const* addon = GetTemplateAddon())
SetFlags(GameObjectFlags(addon->flags));
if (GameObjectOverride const* goOverride = GetGameObjectOverride())
SetFlags(GameObjectFlags(goOverride->Flags));
uint32 poolid = GetSpawnId() ? sPoolMgr->IsPartOfAPool<GameObject>(GetSpawnId()) : 0;
if (poolid)

View File

@@ -106,6 +106,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void Update(uint32 p_time) override;
GameObjectTemplate const* GetGOInfo() const { return m_goInfo; }
GameObjectTemplateAddon const* GetTemplateAddon() const { return m_goTemplateAddon; }
GameObjectOverride const* GetGameObjectOverride() const;
GameObjectData const* GetGameObjectData() const { return m_goData; }
GameObjectValue const* GetGOValue() const { return &m_goValue; }

View File

@@ -1040,13 +1040,18 @@ struct GameObjectTemplate
WorldPacket BuildQueryData(LocaleConstant loc) const;
};
// From `gameobject_template_addon`
struct GameObjectTemplateAddon
// From `gameobject_template_addon`, `gameobject_overrides`
struct GameObjectOverride
{
uint32 faction;
uint32 flags;
uint32 mingold;
uint32 maxgold;
uint32 Faction;
uint32 Flags;
};
// From `gameobject_template_addon`
struct GameObjectTemplateAddon : public GameObjectOverride
{
uint32 Mingold;
uint32 Maxgold;
uint32 WorldEffectID;
uint32 AIAnimKitID;
};

View File

@@ -8802,7 +8802,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type, bool aeLooting/* = fa
if (go->GetLootMode() > 0)
if (GameObjectTemplateAddon const* addon = go->GetTemplateAddon())
loot->generateMoneyLoot(addon->mingold, addon->maxgold);
loot->generateMoneyLoot(addon->Mingold, addon->Maxgold);
if (loot_type == LOOT_FISHING)
go->getFishLoot(loot, this);

View File

@@ -86,10 +86,10 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid,
_triggeredArrivalEvent = false;
_triggeredDepartureEvent = false;
if (m_goTemplateAddon)
if (GameObjectOverride const* goOverride = GetGameObjectOverride())
{
SetFaction(m_goTemplateAddon->faction);
SetFlags(GameObjectFlags(m_goTemplateAddon->flags));
SetFaction(goOverride->Faction);
SetFlags(GameObjectFlags(goOverride->Flags));
}
m_goValue.Transport.PathProgress = 0;

View File

@@ -7432,18 +7432,18 @@ void ObjectMgr::LoadGameObjectTemplateAddons()
}
GameObjectTemplateAddon& gameObjectAddon = _gameObjectTemplateAddonStore[entry];
gameObjectAddon.faction = uint32(fields[1].GetUInt16());
gameObjectAddon.flags = fields[2].GetUInt32();
gameObjectAddon.mingold = fields[3].GetUInt32();
gameObjectAddon.maxgold = fields[4].GetUInt32();
gameObjectAddon.Faction = uint32(fields[1].GetUInt16());
gameObjectAddon.Flags = fields[2].GetUInt32();
gameObjectAddon.Mingold = fields[3].GetUInt32();
gameObjectAddon.Maxgold = fields[4].GetUInt32();
gameObjectAddon.WorldEffectID = fields[5].GetUInt32();
gameObjectAddon.AIAnimKitID = fields[6].GetUInt32();
// checks
if (gameObjectAddon.faction && !sFactionTemplateStore.LookupEntry(gameObjectAddon.faction))
TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u) has invalid faction (%u) defined in `gameobject_template_addon`.", entry, gameObjectAddon.faction);
if (gameObjectAddon.Faction && !sFactionTemplateStore.LookupEntry(gameObjectAddon.Faction))
TC_LOG_ERROR("sql.sql", "GameObject (Entry: %u) has invalid faction (%u) defined in `gameobject_template_addon`.", entry, gameObjectAddon.Faction);
if (gameObjectAddon.maxgold > 0)
if (gameObjectAddon.Maxgold > 0)
{
switch (got->type)
{
@@ -7475,6 +7475,44 @@ void ObjectMgr::LoadGameObjectTemplateAddons()
TC_LOG_INFO("server.loading", ">> Loaded %u game object template addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadGameObjectOverrides()
{
uint32 oldMSTime = getMSTime();
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT spawnId, faction, flags FROM gameobject_overrides");
if (!result)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 gameobject faction and flags overrides. DB table `gameobject_overrides` is empty.");
return;
}
uint32 count = 0;
do
{
Field* fields = result->Fetch();
ObjectGuid::LowType spawnId = fields[0].GetUInt64();
GameObjectData const* goData = GetGameObjectData(spawnId);
if (!goData)
{
TC_LOG_ERROR("sql.sql", "GameObject (SpawnId: " UI64FMTD ") does not exist but has a record in `gameobject_overrides`", spawnId);
continue;
}
GameObjectOverride& gameObjectOverride = _gameObjectOverrideStore[spawnId];
gameObjectOverride.Faction = fields[1].GetUInt32();
gameObjectOverride.Flags = fields[2].GetUInt32();
if (gameObjectOverride.Faction && !sFactionTemplateStore.LookupEntry(gameObjectOverride.Faction))
TC_LOG_ERROR("sql.sql", "GameObject (SpawnId: " UI64FMTD ") has invalid faction (%u) defined in `gameobject_overrides`.", spawnId, gameObjectOverride.Faction);
++count;
} while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u gameobject faction and flags overrides in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadExplorationBaseXP()
{
uint32 oldMSTime = getMSTime();
@@ -9934,6 +9972,11 @@ GameObjectTemplateAddon const* ObjectMgr::GetGameObjectTemplateAddon(uint32 entr
return nullptr;
}
GameObjectOverride const* ObjectMgr::GetGameObjectOverride(ObjectGuid::LowType spawnId) const
{
return Trinity::Containers::MapGetValuePtr(_gameObjectOverrideStore, spawnId);
}
CreatureTemplate const* ObjectMgr::GetCreatureTemplate(uint32 entry) const
{
return Trinity::Containers::MapGetValuePtr(_creatureTemplateStore, entry);

View File

@@ -505,6 +505,7 @@ typedef std::unordered_map<uint32, CreatureModelInfo> CreatureModelContainer;
typedef std::unordered_map<uint32, std::vector<uint32>> CreatureQuestItemMap;
typedef std::unordered_map<uint32, GameObjectTemplate> GameObjectTemplateContainer;
typedef std::unordered_map<uint32, GameObjectTemplateAddon> GameObjectTemplateAddonContainer;
typedef std::unordered_map<ObjectGuid::LowType, GameObjectOverride> GameObjectOverrideContainer;
typedef std::unordered_map<ObjectGuid::LowType, GameObjectData> GameObjectDataContainer;
typedef std::unordered_map<ObjectGuid::LowType, GameObjectAddon> GameObjectAddonContainer;
typedef std::unordered_map<uint32, std::vector<uint32>> GameObjectQuestItemMap;
@@ -1034,6 +1035,7 @@ class TC_GAME_API ObjectMgr
void LoadGameObjectTemplate();
void LoadGameObjectTemplateAddons();
void LoadGameObjectOverrides();
CreatureTemplate const* GetCreatureTemplate(uint32 entry) const;
CreatureTemplateContainer const& GetCreatureTemplates() const { return _creatureTemplateStore; }
@@ -1045,6 +1047,7 @@ class TC_GAME_API ObjectMgr
CreatureAddon const* GetCreatureAddon(ObjectGuid::LowType lowguid) const;
GameObjectAddon const* GetGameObjectAddon(ObjectGuid::LowType lowguid) const;
GameObjectTemplateAddon const* GetGameObjectTemplateAddon(uint32 entry) const;
GameObjectOverride const* GetGameObjectOverride(ObjectGuid::LowType spawnId) const;
CreatureAddon const* GetCreatureTemplateAddon(uint32 entry) const;
ItemTemplate const* GetItemTemplate(uint32 entry) const;
ItemTemplateContainer const& GetItemTemplateStore() const { return _itemTemplateStore; }
@@ -1800,6 +1803,7 @@ class TC_GAME_API ObjectMgr
GameObjectLocaleContainer _gameObjectLocaleStore;
GameObjectTemplateContainer _gameObjectTemplateStore;
GameObjectTemplateAddonContainer _gameObjectTemplateAddonStore;
GameObjectOverrideContainer _gameObjectOverrideStore;
SpawnGroupDataContainer _spawnGroupDataStore;
SpawnGroupLinkContainer _spawnGroupMapStore;
InstanceSpawnGroupContainer _instanceSpawnGroupStore;

View File

@@ -1929,7 +1929,10 @@ void World::SetInitialWorldSettings()
sObjectMgr->LoadSpawnGroups();
TC_LOG_INFO("server.loading", "Loading GameObject Addon Data...");
sObjectMgr->LoadGameObjectAddons(); // must be after LoadGameObjectTemplate() and LoadGameObjects()
sObjectMgr->LoadGameObjectAddons(); // must be after LoadGameObjects()
TC_LOG_INFO("server.loading", "Loading GameObject faction and flags overrides...");
sObjectMgr->LoadGameObjectOverrides(); // must be after LoadGameObjects()
TC_LOG_INFO("server.loading", "Loading GameObject Quest Items...");
sObjectMgr->LoadGameObjectQuestItems();

View File

@@ -605,14 +605,15 @@ public:
if (!param1)
return false;
ObjectGuid::LowType spawnId = 0;
if (strcmp(param1, "guid") == 0)
{
char* tail = strtok(nullptr, "");
char* cValue = handler->extractKeyFromLink(tail, "Hgameobject");
if (!cValue)
return false;
ObjectGuid::LowType guidLow = atoull(cValue);
GameObjectData const* data = sObjectMgr->GetGameObjectData(guidLow);
spawnId = atoull(cValue);
GameObjectData const* data = sObjectMgr->GetGameObjectData(spawnId);
if (!data)
return false;
entry = data->id;
@@ -672,8 +673,16 @@ public:
handler->PSendSysMessage(LANG_GOINFO_NAME, name.c_str());
handler->PSendSysMessage(LANG_GOINFO_SIZE, gameObjectInfo->size);
if (GameObjectTemplateAddon const* addon = sObjectMgr->GetGameObjectTemplateAddon(entry))
handler->PSendSysMessage(LANG_GOINFO_ADDON, addon->faction, addon->flags);
GameObjectOverride const* goOverride = nullptr;
if (spawnId)
if (GameObjectOverride const* ovr = sObjectMgr->GetGameObjectOverride(spawnId))
goOverride = ovr;
if (!goOverride)
goOverride = sObjectMgr->GetGameObjectTemplateAddon(entry);
if (goOverride)
handler->PSendSysMessage(LANG_GOINFO_ADDON, goOverride->Faction, goOverride->Flags);
handler->PSendSysMessage(LANG_OBJECTINFO_AIINFO, gameObjectInfo->AIName.c_str(), sObjectMgr->GetScriptName(gameObjectInfo->ScriptId).c_str());