diff options
-rw-r--r-- | sql/updates/world/master/2022_06_26_02_world.sql | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 18 | ||||
-rw-r--r-- | src/server/game/World/WorldStates/WorldStateDefines.h | 1 | ||||
-rw-r--r-- | src/server/game/World/WorldStates/WorldStateMgr.cpp | 64 | ||||
-rw-r--r-- | src/server/game/World/WorldStates/WorldStateMgr.h | 2 |
6 files changed, 82 insertions, 8 deletions
diff --git a/sql/updates/world/master/2022_06_26_02_world.sql b/sql/updates/world/master/2022_06_26_02_world.sql new file mode 100644 index 00000000000..31f3cdf533f --- /dev/null +++ b/sql/updates/world/master/2022_06_26_02_world.sql @@ -0,0 +1,3 @@ +ALTER TABLE `world_state` ADD `AreaIDs` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL AFTER `MapIDs`; + +UPDATE `world_state` SET `MapIDs`='571,2118',`AreaIDs`='4197,10176' WHERE `ID` IN (3490,3491,3680,3681,3698,3699,3700,3701,3702,3703,3704,3705,3706,3710,3711,3712,3713,3714,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3781,3801,3802,3803,4022,4023,4024,4025,4354); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 56380e7adf7..6d7eead1e2b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -9215,7 +9215,7 @@ void Player::SendInitWorldStates(uint32 zoneId, uint32 areaId) packet.AreaID = zoneId; packet.SubareaID = areaId; - sWorldStateMgr->FillInitialWorldStates(packet, GetMap()); + sWorldStateMgr->FillInitialWorldStates(packet, GetMap(), areaId); packet.Worldstates.emplace_back(2264, 0); // SCOURGE_EVENT_WORLDSTATE_EASTERN_PLAGUELANDS packet.Worldstates.emplace_back(2263, 0); // SCOURGE_EVENT_WORLDSTATE_TANARIS diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 7771fe6198e..acf5a1a035c 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -702,14 +702,28 @@ void Map::SetWorldStateValue(int32 worldStateId, int32 value) int32 oldValue = itr->second; itr->second = value; - if (WorldStateTemplate const* worldStateTemplate = sWorldStateMgr->GetWorldStateTemplate(worldStateId)) + WorldStateTemplate const* worldStateTemplate = sWorldStateMgr->GetWorldStateTemplate(worldStateId); + if (worldStateTemplate) sScriptMgr->OnWorldStateValueChange(worldStateTemplate, oldValue, value, this); // Broadcast update to all players on the map WorldPackets::WorldState::UpdateWorldState updateWorldState; updateWorldState.VariableID = worldStateId; updateWorldState.Value = value; - SendToPlayers(updateWorldState.Write()); + updateWorldState.Write(); + + for (MapReference const& mapReference : m_mapRefManager) + { + if (worldStateTemplate && !worldStateTemplate->AreaIds.empty()) + { + bool isInAllowedArea = std::any_of(worldStateTemplate->AreaIds.begin(), worldStateTemplate->AreaIds.end(), + [playerAreaId = mapReference.GetSource()->GetAreaId()](uint32 requiredAreaId) { return DB2Manager::IsInArea(playerAreaId, requiredAreaId); }); + if (!isInAllowedArea) + continue; + } + + mapReference.GetSource()->SendDirectMessage(updateWorldState.GetRawPacket()); + } } template<class T> diff --git a/src/server/game/World/WorldStates/WorldStateDefines.h b/src/server/game/World/WorldStates/WorldStateDefines.h index 97966fb5ce2..410ce8f5580 100644 --- a/src/server/game/World/WorldStates/WorldStateDefines.h +++ b/src/server/game/World/WorldStates/WorldStateDefines.h @@ -29,6 +29,7 @@ struct WorldStateTemplate uint32 ScriptId = 0; std::unordered_set<uint32> MapIds; + std::unordered_set<uint32> AreaIds; }; using WorldStateValueContainer = std::unordered_map<int32 /*worldStateId*/, int32 /*value*/>; diff --git a/src/server/game/World/WorldStates/WorldStateMgr.cpp b/src/server/game/World/WorldStates/WorldStateMgr.cpp index 13fee84bcad..9867b3a0123 100644 --- a/src/server/game/World/WorldStates/WorldStateMgr.cpp +++ b/src/server/game/World/WorldStates/WorldStateMgr.cpp @@ -39,8 +39,8 @@ void WorldStateMgr::LoadFromDB() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 - QueryResult result = WorldDatabase.Query("SELECT ID, DefaultValue, MapIDs, ScriptName FROM world_state"); + // 0 1 2 3 4 + QueryResult result = WorldDatabase.Query("SELECT ID, DefaultValue, MapIDs, AreaIDs, ScriptName FROM world_state"); if (!result) return; @@ -81,7 +81,51 @@ void WorldStateMgr::LoadFromDB() continue; } - worldState.ScriptId = sObjectMgr->GetScriptId(fields[3].GetString()); + std::string_view areaIds = fields[3].GetStringView(); + if (!worldState.MapIds.empty()) + { + for (std::string_view areaIdToken : Trinity::Tokenize(areaIds, ',', false)) + { + Optional<uint32> areaId = Trinity::StringTo<uint32>(areaIdToken); + if (!areaId) + { + TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %u with non-integer AreaID (" STRING_VIEW_FMT "), area ignored", + id, STRING_VIEW_FMT_ARG(areaIdToken)); + continue; + } + + AreaTableEntry const* areaTableEntry = sAreaTableStore.LookupEntry(*areaId); + if (!areaTableEntry) + { + TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %u with invalid AreaID (%u), area ignored", + id, *areaId); + continue; + } + + if (worldState.MapIds.find(areaTableEntry->ContinentID) == worldState.MapIds.end()) + { + TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %u with AreaID (%u) not on any of required maps, area ignored", + id, *areaId); + continue; + } + + worldState.AreaIds.insert(*areaId); + } + + if (!areaIds.empty() && worldState.AreaIds.empty()) + { + TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %u with nonempty AreaIDs (" STRING_VIEW_FMT ") but no valid area id was found, ignored", + id, STRING_VIEW_FMT_ARG(areaIds)); + continue; + } + } + else if (!areaIds.empty()) + { + TC_LOG_ERROR("sql.sql", "Table `world_state` contains a world state %u with nonempty AreaIDs (" STRING_VIEW_FMT ") but is a realm wide world state, area requirement ignored", + id, STRING_VIEW_FMT_ARG(areaIds)); + } + + worldState.ScriptId = sObjectMgr->GetScriptId(fields[4].GetString()); if (!worldState.MapIds.empty()) { @@ -153,13 +197,25 @@ WorldStateValueContainer WorldStateMgr::GetInitialWorldStatesForMap(Map const* m return initialValues; } -void WorldStateMgr::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& initWorldStates, Map const* map) const +void WorldStateMgr::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& initWorldStates, Map const* map, uint32 playerAreaId) const { for (auto const& [worldStateId, value] : _realmWorldStateValues) initWorldStates.Worldstates.emplace_back(worldStateId, value); for (auto const& [worldStateId, value] : map->GetWorldStateValues()) + { + WorldStateTemplate const* worldStateTemplate = GetWorldStateTemplate(worldStateId); + if (worldStateTemplate && !worldStateTemplate->AreaIds.empty()) + { + bool isInAllowedArea = std::any_of(worldStateTemplate->AreaIds.begin(), worldStateTemplate->AreaIds.end(), + [=](uint32 requiredAreaId) { return DB2Manager::IsInArea(playerAreaId, requiredAreaId); }); + if (!isInAllowedArea) + continue; + } + + initWorldStates.Worldstates.emplace_back(worldStateId, value); + } } WorldStateMgr* WorldStateMgr::instance() diff --git a/src/server/game/World/WorldStates/WorldStateMgr.h b/src/server/game/World/WorldStates/WorldStateMgr.h index 18ce38afd2f..ae9e72f9f5a 100644 --- a/src/server/game/World/WorldStates/WorldStateMgr.h +++ b/src/server/game/World/WorldStates/WorldStateMgr.h @@ -42,7 +42,7 @@ public: WorldStateValueContainer GetInitialWorldStatesForMap(Map const* map) const; - void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& initWorldStates, Map const* map) const; + void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& initWorldStates, Map const* map, uint32 playerAreaId) const; }; #define sWorldStateMgr WorldStateMgr::instance() |