From 7b79bf031616e2cd178f4ce3db6f47bd299776e4 Mon Sep 17 00:00:00 2001 From: Ben Carter Date: Fri, 20 Sep 2024 23:28:58 -0400 Subject: [PATCH] Added Creature Map tracking and improved performance on storage --- src/AllCreatureScript.cpp | 78 ++++++++++++++++----------------- src/AllMapScript.cpp | 58 ++++++++----------------- src/CommandScript.cpp | 2 + src/GroupScript.cpp | 7 +-- src/MpDataStore.cpp | 31 ++++++++++---- src/MpDataStore.h | 64 ++++++++++++++++++++++++---- src/MythicPlus.cpp | 90 ++++++++++++++++++++++++++++++++++++++- src/MythicPlus.h | 10 +++++ 8 files changed, 238 insertions(+), 102 deletions(-) diff --git a/src/AllCreatureScript.cpp b/src/AllCreatureScript.cpp index 51559f0..e010618 100644 --- a/src/AllCreatureScript.cpp +++ b/src/AllCreatureScript.cpp @@ -63,42 +63,35 @@ public: void OnCreatureAddWorld(Creature* creature) override { - uint8 level; - Map* map = creature->GetMap(); if (!sMythicPlus->IsMapEligible(map)) { // MpLogger::debug("Map: {} is not eligible to adjust so creature was skipped: Creature {}", map->GetMapName(), creature->GetName()); return; } - // bail if the creature is not eligible to be scaled - if (!sMythicPlus->IsCreatureEligible(creature)) { - MpLogger::debug("Creature: {} Entry: {} is not eligible to adjust so creature was skipped.", creature->GetName(), creature->GetEntry()); - return; - } + sMythicPlus->AddCreatureForScaling(creature); - MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId()); - if(!instanceData) { - MpLogger::debug("Creature: {} Could not find instance data for Map {} and InstanceId: {}", creature->GetName(), map->GetMapName(), map->GetInstanceId()); - return; - } + // MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId()); + // if(!instanceData) { + // MpLogger::debug("Creature: {} Could not find instance data for Map {} and InstanceId: {}", creature->GetName(), map->GetMapName(), map->GetInstanceId()); + // return; + // } - if (creature->IsDungeonBoss()) { - level = instanceData->boss.avgLevel; - } else { - level = uint8(urand(instanceData->creature.avgLevel-1, instanceData->creature.avgLevel+1)); - } + // if (creature->IsDungeonBoss()) { + // level = instanceData->boss.avgLevel; + // } else { + // level = uint8(urand(instanceData->creature.avgLevel-1, instanceData->creature.avgLevel+1)); + // } - // Scale the creature to its new level - sMythicPlus->ScaleCreature(level, creature); + // // Scale the creature to its new level + // sMythicPlus->ScaleCreature(level, creature); - MpLogger::debug("SetLevel and Updateded Creature {} Entry {} Id {} level from {} to {}", + MpLogger::debug("SetLevel and Updateded Creature {} Entry {} Id {} level from {}", creature->GetName(), creature->GetEntry(), creature->GetGUID().GetCounter(), - creature->GetLevel(), - level + creature->GetLevel() ); @@ -110,6 +103,31 @@ public: // } } + void OnAllCreatureUpdate(Creature* creature, uint32 diff) override + { + if (!sMythicPlus->IsMapEligible(creature->GetMap())) { + return; + } + + sMythicPlus->ScaleOnUpdate(creature, diff); + + // If the config is out of date and the creature was reset, run modify against it + // if (ResetCreatureIfNeeded(creature)) + // { + // LOG_DEBUG("module.MythicPlus", + // "MythicPlus_AllCreatureScript::OnAllCreatureUpdate(): Creature {} ({}) is reset to its original stats.", + // creature->GetName(), + // creature->GetLevel() + // ); + + // // Update the map's level if it is out of date + // sMythicPlus->UpdateMapLevelIfNeeded(creature->GetMap()); + + // ModifyCreatureAttributes(creature); + // } + } + + // void OnCreatureRemoveWorld(Creature* creature) override // { // Map* map = creature->GetMap(); @@ -161,23 +179,7 @@ public: // ); // } - // void OnAllCreatureUpdate(Creature* creature, uint32 /*diff*/) override - // { - // // If the config is out of date and the creature was reset, run modify against it - // // if (ResetCreatureIfNeeded(creature)) - // // { - // // LOG_DEBUG("module.MythicPlus", - // // "MythicPlus_AllCreatureScript::OnAllCreatureUpdate(): Creature {} ({}) is reset to its original stats.", - // // creature->GetName(), - // // creature->GetLevel() - // // ); - // // // Update the map's level if it is out of date - // // sMythicPlus->UpdateMapLevelIfNeeded(creature->GetMap()); - - // // ModifyCreatureAttributes(creature); - // // } - // } bool UpdateCreature(Creature* creature) { diff --git a/src/AllMapScript.cpp b/src/AllMapScript.cpp index fcf735f..e21f215 100644 --- a/src/AllMapScript.cpp +++ b/src/AllMapScript.cpp @@ -14,51 +14,21 @@ public: { } - void OnCreateMap(Map* map) - { - if (!sMythicPlus->IsMapEligible(map)) { - return; - } - - // Attempt to cast map to InstanceMap, making sure it is not null - InstanceMap* instance = dynamic_cast(sMapMgr->FindMap(map->GetId(), map->GetInstanceId())); - if (!instance) - { - MpLogger::error("Failed to find InstanceMap for map ID {} and instance ID {}.", map->GetId(), map->GetInstanceId()); - return; - } - - Map::PlayerList playerList = instance->GetPlayers(); - - if (!playerList.IsEmpty()) { - for (auto i = playerList.begin(); i != playerList.end(); ++i) { - - if (Player* iPlayer = i->GetSource()) { - Group* group = iPlayer->GetGroup(); - - if (group) { - MpLogger::debug("Player {} entered map {} in groupLeader {}", iPlayer->GetName(), map->GetMapName(), group->GetLeaderName()); - } else { - return; - } - } - } - } else { - MpLogger::debug("No players found in map {}", map->GetMapName()); - } - } + void OnCreateMap(Map* map) { } /** * When a player enters the map check it needs to set up the instance data */ void OnPlayerEnterAll(Map* map, Player* player) { - MpLogger::debug("AllMapScript::OnPlayerEnterAll(): {}", map->GetMapName()); - if (!sMythicPlus->IsMapEligible(map)) { return; } + if(!sMythicPlus->IsDifficultySet(player)) { + return; + } + Group* group = player->GetGroup(); if (group) { MpLogger::debug("Player {} entered map {} in groupLeader {}", player->GetName(), map->GetMapName(), group->GetLeaderName()); @@ -72,11 +42,23 @@ public: return; } + // Check if we already have mythic instance data set for this map and group + MpInstanceData* existingData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId()); + if (existingData) { + if(player->GetName() == group->GetLeaderName()) { + MpLogger::debug("Instance data already set for Map: {} InstanceId: {} for GroupLeader: {} ", + map->GetMapName(), + map->GetInstanceId(), + group->GetLeaderName() + ); + } + return; + } + uint8 avgLevel = 0; MpInstanceData instanceData; switch(groupData->difficulty) { case MP_DIFFICULTY_MYTHIC: - MpLogger::debug("Setting up Mythic instance data for group {}", group->GetGUID().GetCounter()); instanceData.boss = sMythicPlus->mythicBossModifiers; instanceData.creature = sMythicPlus->mythicDungeonModifiers; instanceData.itemRewards = sMythicPlus->EnableItemRewards; @@ -84,7 +66,6 @@ public: instanceData.itemOffset = sMythicPlus->mythicItemOffset; break; case MP_DIFFICULTY_LEGENDARY: - MpLogger::debug("Setting up Legendary instance data for group {}", group->GetGUID().GetCounter()); instanceData.boss = sMythicPlus->legendaryBossModifiers; instanceData.creature = sMythicPlus->legendaryDungeonModifiers; instanceData.itemRewards = sMythicPlus->EnableItemRewards; @@ -92,7 +73,6 @@ public: instanceData.itemOffset = sMythicPlus->legendaryItemOffset; break; case MP_DIFFICULTY_ASCENDANT: - MpLogger::debug("Setting up Ascendant instance data for group {}", group->GetGUID().GetCounter()); instanceData.boss = sMythicPlus->ascendantBossModifiers; instanceData.creature = sMythicPlus->ascendantDungeonModifiers; instanceData.itemRewards = sMythicPlus->EnableItemRewards; @@ -129,8 +109,6 @@ public: if (!sMythicPlus->IsMapEligible(map)) { return; } - - MpLogger::debug("AllMapScript::OnDestroyInstance(): {}", map->GetMapName()); sMpDataStore->RemoveInstanceData(map->GetId(), map->GetInstanceId()); } }; diff --git a/src/CommandScript.cpp b/src/CommandScript.cpp index 635f441..65f85e5 100644 --- a/src/CommandScript.cpp +++ b/src/CommandScript.cpp @@ -142,6 +142,8 @@ public: " Group Deaths: %u\n", groupData->difficulty, groupData->deaths); + } else { + status += " Group Difficulty: Not Set\n"; } } diff --git a/src/GroupScript.cpp b/src/GroupScript.cpp index f014727..219a0be 100644 --- a/src/GroupScript.cpp +++ b/src/GroupScript.cpp @@ -23,12 +23,7 @@ class MythicPlus_GroupScript : public GroupScript } void OnDisband(Group* group) override { - if (!group) { - return; - } - - // MpDataStore* mpds = MpDataStore::instance(); - // mpds->RemoveGroupData(group->GetGUID()); + sMpDataStore->RemoveGroupData(group); } }; diff --git a/src/MpDataStore.cpp b/src/MpDataStore.cpp index a46d2c6..bb37944 100644 --- a/src/MpDataStore.cpp +++ b/src/MpDataStore.cpp @@ -4,10 +4,10 @@ #include "Player.h" MpDataStore::MpDataStore() { - _groupData = new std::map(); - _playerData = new std::map(); - _instanceData = new std::map, MpInstanceData>(); - _instanceCreatureData = new std::map(); + _groupData = new std::unordered_map(); + _playerData = new std::unordered_map(); + _instanceData = new std::unordered_map, MpInstanceData>(); + _instanceCreatureData = new std::unordered_map(); } MpDataStore::~MpDataStore() { @@ -30,7 +30,6 @@ void MpDataStore::AddGroupData(Group *group, MpGroupData groupData) { MpLogger::error("AddGroupData called with invalid difficulty"); return; } - // if we already have data override it if (_groupData->contains(guid)) { _groupData->at(guid) = groupData; @@ -46,6 +45,13 @@ void MpDataStore::AddGroupData(Group *group, MpGroupData groupData) { ); } +MpGroupData* MpDataStore::GetGroupData(Group* group) { + + if (auto it = _groupData->find(group->GetGUID()); it != _groupData->end()) { + return &(it->second); + } +} + /** * This keeps track of instance keys (mapId, instanceId) for a group this can be used to * reset instance settings in the instanceData store when a difficulty is changed by the group leader. @@ -107,12 +113,21 @@ void MpDataStore::RemoveInstanceData(uint32 mapId, uint32 instanceId) { _instanceData->erase(GetInstanceDataKey(mapId, instanceId)); } -void MpDataStore::AddInstanceCreatureData(ObjectGuid guid, MapCreatureData mcd) { +void MpDataStore::AddCreatureData(ObjectGuid guid, MpCreatureData creatureData) { MpLogger::debug("AddInstanceCreatureData for creature {}", guid.GetCounter()); - _instanceCreatureData->insert({guid, mcd}); + _instanceCreatureData->insert({guid, creatureData}); } -void MpDataStore::RemoveInstanceCreatureData(ObjectGuid guid) { +MpCreatureData* MpDataStore::GetCreatureData(ObjectGuid guid) { + if (!_instanceCreatureData->contains(guid)) { + MpLogger::debug("No instance creature data found for creature {}", guid.GetCounter()); + return nullptr; + } + + return &_instanceCreatureData->at(guid); +} + +void MpDataStore::RemoveCreatureData(ObjectGuid guid) { MpLogger::debug("RemoveInstanceCreatureData data for creature {}", guid.GetCounter()); _instanceCreatureData->erase(guid); } diff --git a/src/MpDataStore.h b/src/MpDataStore.h index 7978b60..0738033 100644 --- a/src/MpDataStore.h +++ b/src/MpDataStore.h @@ -78,10 +78,45 @@ struct MpInstanceData }; -struct MapCreatureData +/** + * Simple struct for managing information about creatures that + * are in a mythic+ instance. + */ +struct MpCreatureData { Creature* creature; - MapEntry* instance; + bool scaled; + + // Original information about the creature that was altered. + uint8 originalLevel; + CreatureBaseStats const* originalStats; + + // Custom difficulty modifiers to creatures at higher difficulties. + std::vector auras; + std::vector affixes; + + MpCreatureData(Creature* creature) + : creature(creature), scaled(false) + { + if(creature) { + originalLevel = creature->GetLevel(); + + CreatureBaseStats const* originalStats = sObjectMgr->GetCreatureBaseStats( + originalLevel, + creature->GetCreatureTemplate()->unit_class + ); + } + } + + void SetScaled(bool scaled) { + this->scaled = scaled; + } + + bool IsScaled() { + return scaled; + } + + /**@todo Add Affixes and Aura Spell methods */ }; class MpDataStore { @@ -89,10 +124,16 @@ private: MpDataStore(); ~MpDataStore(); - std::map* _groupData; - std::map* _playerData; - std::map,MpInstanceData>* _instanceData; - std::map* _instanceCreatureData; + std::unordered_map* _playerData; + + // Instance Data map key is unique instance pair and values are modifiers of instance + std::unordered_map,MpInstanceData>* _instanceData; + + // Group Data map key is group guid and values are mythic settings set by group leader + std::unordered_map* _groupData; + + // Instance Creature Data map key is creature guid and values are creature itself from a mythic instance + std::unordered_map* _instanceCreatureData; public: @@ -122,25 +163,30 @@ public: }; // Set and remove difficluty settig for a group - void AddGroupData(Group *group, MpGroupData gd); + void AddGroupData(Group *group, MpGroupData groupData); void RemoveGroupData(Group *group); + MpGroupData* GetGroupData(Group *group); void PushGroupInstanceKey(Group *group, uint32 mapId, uint32 instanceId); void AddPlayerData(ObjectGuid guid, MpPlayerData pd); void RemovePlayerData(ObjectGuid guid); + // Each Map/Instance is a unique key that contains scaling information based on difficulty void AddInstanceData(uint32 mapId, uint32 instanceId, MpInstanceData ); MpInstanceData* GetInstanceData(uint32 mapId, uint32 instanceId); void RemoveInstanceData(uint32 mapId, uint32 instanceId); - void AddInstanceCreatureData(ObjectGuid guid, MapCreatureData mcd); - void RemoveInstanceCreatureData(ObjectGuid guid); + // Methods for interacting with the map of creatures in a mythic instances + void AddCreatureData(ObjectGuid guid, MpCreatureData creatureData); + MpCreatureData* GetCreatureData(ObjectGuid guid); + void RemoveCreatureData(ObjectGuid guid); // creates a unique instance key into the instance data store auto GetInstanceDataKey(uint32 mapId, uint32 instanceId) { return std::make_pair(mapId, instanceId); } + // accessor for this singleton static MpDataStore* instance() { static MpDataStore instance; return &instance; diff --git a/src/MythicPlus.cpp b/src/MythicPlus.cpp index fe622c9..5ac5bdf 100644 --- a/src/MythicPlus.cpp +++ b/src/MythicPlus.cpp @@ -1,4 +1,6 @@ #include "MythicPlus.h" +#include "MpDataStore.h" +#include "MpLogger.h" #include "ObjectMgr.h" #include "MapMgr.h" @@ -15,6 +17,22 @@ bool MythicPlus::IsMapEligible(Map* map) return false; } +bool MythicPlus::IsDifficultySet(Player* player) +{ + Group* group = player->GetGroup(); + if (!group) { + return false; + } + + MpGroupData const* groupData = sMpDataStore->GetGroupData(group->GetGUID()); + if (!groupData) { + return false; + } + + return true; +} + + bool MythicPlus::IsDifficultyEnabled(std::string difficulty) { return std::find(enabledDifficulties.begin(), enabledDifficulties.end(), difficulty) != enabledDifficulties.end(); @@ -63,6 +81,76 @@ bool MythicPlus::IsCreatureEligible(Creature* creature) return true; } +void MythicPlus::AddCreatureForScaling(Creature* creature) +{ + if (!IsCreatureEligible(creature)) { + return; + } + + sMpDataStore->AddCreatureData(creature->GetGUID(), MpCreatureData(creature)); + MpLogger::debug("Added creature {} to instance data for instance {}", + creature->GetName(), + creature->GetMap()->GetMapName() + ); +} + +void MythicPlus::ScaleOnUpdate(Creature* creature, uint32 diff) +{ + // Check to see if the creature is in our list to be scaled to mythic+ levels + MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID()); + if (!creatureData) { + return; + } + + // if it has already been scaled then do nothing. + if (creatureData->IsScaled()) { + MpLogger::debug("Creature {} Entry {} Id {} already scaled in ScaleOnUpdate()", + creature->GetName(), + creature->GetEntry(), + creature->GetGUID().GetCounter() + ); + return; + } + + // Otherwise we handle scaling the stats of the creature based on map difficulty set + Map* map = creature->GetMap(); + if(!map) { + MpLogger::warn("Map is null for creature {} Entry {} Id {} could not scale in ScaleOnUpdate()", + creature->GetName(), + creature->GetEntry(), + creature->GetGUID().GetCounter() + ); + return; + } + + // The instance data for this map determines how to scale the creature by difficulty set + MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId()); + if (!instanceData) { + MpLogger::warn("Instance data is null for creature {} Entry {} Id {} could not scale in ScaleOnUpdate()", + creature->GetName(), + creature->GetEntry(), + creature->GetGUID().GetCounter() + ); + return; + } + + // allow small variance in level for non-boss creatures + uint8 level = uint8(urand(instanceData->creature.avgLevel - 1, instanceData->creature.avgLevel + 1)); + if(creature->IsDungeonBoss()) { + level = instanceData->boss.avgLevel; + } + ScaleCreature(level, creature); + creatureData->SetScaled(true); // Since updates happen frequently set the flag so we do not re-scale + + MpLogger::debug("Sca Creature {} Entry {} Id {} level from {} to {}", + creature->GetName(), + creature->GetEntry(), + creature->GetGUID().GetCounter(), + creature->GetLevel(), + level + ); +} + void MythicPlus::ScaleCreature(uint8 level, Creature* creature) { creature->SetLevel(level); @@ -118,7 +206,7 @@ void MythicPlus::ScaleCreature(uint8 level, Creature* creature) */ float GetHealthModifier(int32 Rank) { - switch (Rank) // define rates for each elite rank + switch (Rank) { case CREATURE_ELITE_NORMAL: return sWorld->getRate(RATE_CREATURE_NORMAL_HP); diff --git a/src/MythicPlus.h b/src/MythicPlus.h index ce8dbb6..65cf613 100644 --- a/src/MythicPlus.h +++ b/src/MythicPlus.h @@ -52,6 +52,9 @@ public: // Map is eligible for mythic+ scaling bool IsMapEligible(Map* map); + // If a player difficulty is set that is eligible for mythic+ scaling + bool IsDifficultySet(Player* player); + // Check is difficulty is enabled in the configuration bool IsDifficultyEnabled(std::string difficulty); @@ -61,6 +64,13 @@ public: // The creature should be given Mythic+ scaling and powers check for pets, npcs, etc bool IsCreatureEligible(Creature* creature); + // Adds the creature if eligible to be scaled + void AddCreatureForScaling(Creature* creature); + + // Will make determination on if this creature needs to be scaled and will do so + // the diff time is used to determine the last time the creature was modified. + void ScaleOnUpdate(Creature* creature, uint32 diff); + // Scales the creature based on the level and the creature base stats void ScaleCreature(uint8 level, Creature* creature);