Core/Weather: Fixed weather updates to be thread safe

(cherry picked from commit 6eb9973947)
This commit is contained in:
Shauren
2017-09-14 22:33:40 +02:00
parent 9a9af3cc5f
commit 6eecb685ce
10 changed files with 88 additions and 120 deletions
+4 -7
View File
@@ -7056,13 +7056,10 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
return; return;
if (sWorld->getBoolConfig(CONFIG_WEATHER)) if (sWorld->getBoolConfig(CONFIG_WEATHER))
{ GetMap()->GetOrGenerateZoneDefaultWeather(newZone);
if (Weather* weather = WeatherMgr::FindWeather(zone->ID))
weather->SendWeatherUpdateToPlayer(this); GetMap()->SendZoneDynamicInfo(newZone, this);
else if (!WeatherMgr::AddWeather(zone->ID))
// send fine weather packet to remove old zone's weather
WeatherMgr::SendFineWeatherUpdateToPlayer(this);
}
// in PvP, any not controlled zone (except zone->team == 6, default case) // in PvP, any not controlled zone (except zone->team == 6, default case)
// in PvE, only opposition team capital // in PvE, only opposition team capital
+61 -22
View File
@@ -45,6 +45,7 @@
#include "Vehicle.h" #include "Vehicle.h"
#include "VMapFactory.h" #include "VMapFactory.h"
#include "Weather.h" #include "Weather.h"
#include "WeatherMgr.h"
#include "World.h" #include "World.h"
#include <unordered_set> #include <unordered_set>
#include <vector> #include <vector>
@@ -65,7 +66,7 @@ static uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
GridState* si_GridStates[MAX_GRID_STATE]; GridState* si_GridStates[MAX_GRID_STATE];
ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), WeatherId(WEATHER_STATE_FINE), ZoneDynamicInfo::ZoneDynamicInfo() : MusicId(0), DefaultWeather(nullptr), WeatherId(WEATHER_STATE_FINE),
WeatherGrade(0.0f), OverrideLightId(0), LightFadeInTime(0) { } WeatherGrade(0.0f), OverrideLightId(0), LightFadeInTime(0) { }
Map::~Map() Map::~Map()
@@ -288,6 +289,8 @@ i_scriptLock(false), _respawnCheckTimer(0), _defaultLight(GetDefaultMapLight(id)
//lets initialize visibility distance for map //lets initialize visibility distance for map
Map::InitVisibilityDistance(); Map::InitVisibilityDistance();
_weatherUpdateTimer.SetInterval(time_t(1 * IN_MILLISECONDS));
sScriptMgr->OnCreateMap(this); sScriptMgr->OnCreateMap(this);
} }
@@ -589,7 +592,6 @@ bool Map::AddPlayerToMap(Player* player)
SendInitSelf(player); SendInitSelf(player);
SendInitTransports(player); SendInitTransports(player);
SendZoneDynamicInfo(player);
player->m_clientGUIDs.clear(); player->m_clientGUIDs.clear();
player->UpdateObjectVisibility(false); player->UpdateObjectVisibility(false);
@@ -858,6 +860,15 @@ void Map::Update(uint32 t_diff)
i_scriptLock = false; i_scriptLock = false;
} }
if (_weatherUpdateTimer.Passed())
{
for (auto&& zoneInfo : _zoneDynamicInfo)
if (zoneInfo.second.DefaultWeather && !zoneInfo.second.DefaultWeather->Update(_weatherUpdateTimer.GetInterval()))
zoneInfo.second.DefaultWeather.reset();
_weatherUpdateTimer.Reset();
}
MoveAllCreaturesInMoveList(); MoveAllCreaturesInMoveList();
MoveAllGameObjectsInMoveList(); MoveAllGameObjectsInMoveList();
@@ -4559,10 +4570,9 @@ void Map::RemoveOldCorpses()
} }
} }
void Map::SendZoneDynamicInfo(Player* player) void Map::SendZoneDynamicInfo(uint32 zoneId, Player* player) const
{ {
uint32 zoneId = GetZoneId(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ()); auto itr = _zoneDynamicInfo.find(zoneId);
ZoneDynamicInfoMap::const_iterator itr = _zoneDynamicInfo.find(zoneId);
if (itr == _zoneDynamicInfo.end()) if (itr == _zoneDynamicInfo.end())
return; return;
@@ -4573,11 +4583,7 @@ void Map::SendZoneDynamicInfo(Player* player)
player->SendDirectMessage(&data); player->SendDirectMessage(&data);
} }
if (WeatherState weatherId = itr->second.WeatherId) SendZoneWeather(itr->second, player);
{
WorldPackets::Misc::Weather weather(weatherId, itr->second.WeatherGrade);
player->SendDirectMessage(weather.Write());
}
if (uint32 overrideLight = itr->second.OverrideLightId) if (uint32 overrideLight = itr->second.OverrideLightId)
{ {
@@ -4589,11 +4595,32 @@ void Map::SendZoneDynamicInfo(Player* player)
} }
} }
void Map::SendZoneWeather(uint32 zoneId, Player* player) const
{
auto itr = _zoneDynamicInfo.find(zoneId);
if (itr == _zoneDynamicInfo.end())
return;
SendZoneWeather(itr->second, player);
}
void Map::SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const
{
if (WeatherState weatherId = zoneDynamicInfo.WeatherId)
{
WorldPackets::Misc::Weather weather(weatherId, zoneDynamicInfo.WeatherGrade);
player->SendDirectMessage(weather.Write());
}
else if (zoneDynamicInfo.DefaultWeather)
{
zoneDynamicInfo.DefaultWeather->SendWeatherUpdateToPlayer(player);
}
else
Weather::SendFineWeatherUpdateToPlayer(player);
}
void Map::SetZoneMusic(uint32 zoneId, uint32 musicId) void Map::SetZoneMusic(uint32 zoneId, uint32 musicId)
{ {
if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end())
_zoneDynamicInfo.insert(ZoneDynamicInfoMap::value_type(zoneId, ZoneDynamicInfo()));
_zoneDynamicInfo[zoneId].MusicId = musicId; _zoneDynamicInfo[zoneId].MusicId = musicId;
Map::PlayerList const& players = GetPlayers(); Map::PlayerList const& players = GetPlayers();
@@ -4609,37 +4636,49 @@ void Map::SetZoneMusic(uint32 zoneId, uint32 musicId)
} }
} }
Weather* Map::GetOrGenerateZoneDefaultWeather(uint32 zoneId)
{
WeatherData const* weatherData = WeatherMgr::GetWeatherData(zoneId);
if (!weatherData)
return nullptr;
ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
if (!info.DefaultWeather)
{
info.DefaultWeather = Trinity::make_unique<Weather>(zoneId, weatherData);
info.DefaultWeather->ReGenerate();
info.DefaultWeather->UpdateWeather();
}
return info.DefaultWeather.get();
}
void Map::SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade) void Map::SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade)
{ {
if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end())
_zoneDynamicInfo.insert(ZoneDynamicInfoMap::value_type(zoneId, ZoneDynamicInfo()));
ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId]; ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
info.WeatherId = weatherId; info.WeatherId = weatherId;
info.WeatherGrade = weatherGrade; info.WeatherGrade = weatherGrade;
Map::PlayerList const& players = GetPlayers();
Map::PlayerList const& players = GetPlayers();
if (!players.isEmpty()) if (!players.isEmpty())
{ {
WorldPackets::Misc::Weather weather(weatherId, weatherGrade); WorldPackets::Misc::Weather weather(weatherId, weatherGrade);
weather.Write();
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
if (Player* player = itr->GetSource()) if (Player* player = itr->GetSource())
if (player->GetZoneId() == zoneId) if (player->GetZoneId() == zoneId)
player->SendDirectMessage(weather.Write()); player->SendDirectMessage(weather.GetRawPacket());
} }
} }
void Map::SetZoneOverrideLight(uint32 zoneId, uint32 lightId, uint32 fadeInTime) void Map::SetZoneOverrideLight(uint32 zoneId, uint32 lightId, uint32 fadeInTime)
{ {
if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end())
_zoneDynamicInfo.insert(ZoneDynamicInfoMap::value_type(zoneId, ZoneDynamicInfo()));
ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId]; ZoneDynamicInfo& info = _zoneDynamicInfo[zoneId];
info.OverrideLightId = lightId; info.OverrideLightId = lightId;
info.LightFadeInTime = fadeInTime; info.LightFadeInTime = fadeInTime;
Map::PlayerList const& players = GetPlayers();
Map::PlayerList const& players = GetPlayers();
if (!players.isEmpty()) if (!players.isEmpty())
{ {
WorldPacket data(SMSG_OVERRIDE_LIGHT, 4 + 4 + 1); WorldPacket data(SMSG_OVERRIDE_LIGHT, 4 + 4 + 1);
+7 -1
View File
@@ -53,6 +53,7 @@ class Player;
class TempSummon; class TempSummon;
class Transport; class Transport;
class Unit; class Unit;
class Weather;
class WorldObject; class WorldObject;
class WorldPacket; class WorldPacket;
struct MapDifficulty; struct MapDifficulty;
@@ -264,6 +265,7 @@ struct ZoneDynamicInfo
ZoneDynamicInfo(); ZoneDynamicInfo();
uint32 MusicId; uint32 MusicId;
std::unique_ptr<Weather> DefaultWeather;
WeatherState WeatherId; WeatherState WeatherId;
float WeatherGrade; float WeatherGrade;
uint32 OverrideLightId; uint32 OverrideLightId;
@@ -595,9 +597,12 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
void SendInitTransports(Player* player); void SendInitTransports(Player* player);
void SendRemoveTransports(Player* player); void SendRemoveTransports(Player* player);
void SendZoneDynamicInfo(Player* player); void SendZoneDynamicInfo(uint32 zoneId, Player* player) const;
void SendZoneWeather(uint32 zoneId, Player* player) const;
void SendZoneWeather(ZoneDynamicInfo const& zoneDynamicInfo, Player* player) const;
void SetZoneMusic(uint32 zoneId, uint32 musicId); void SetZoneMusic(uint32 zoneId, uint32 musicId);
Weather* GetOrGenerateZoneDefaultWeather(uint32 zoneId);
void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade); void SetZoneWeather(uint32 zoneId, WeatherState weatherId, float weatherGrade);
void SetZoneOverrideLight(uint32 zoneId, uint32 lightId, uint32 fadeInTime); void SetZoneOverrideLight(uint32 zoneId, uint32 lightId, uint32 fadeInTime);
@@ -856,6 +861,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
std::unordered_map<uint32, uint32> _zonePlayerCountMap; std::unordered_map<uint32, uint32> _zonePlayerCountMap;
ZoneDynamicInfoMap _zoneDynamicInfo; ZoneDynamicInfoMap _zoneDynamicInfo;
IntervalTimer _weatherUpdateTimer;
uint32 _defaultLight; uint32 _defaultLight;
template<HighGuid high> template<HighGuid high>
+6 -2
View File
@@ -29,8 +29,6 @@
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "Util.h" #include "Util.h"
#include "World.h" #include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
/// Create the Weather object /// Create the Weather object
Weather::Weather(uint32 zone, WeatherData const* weatherChances) Weather::Weather(uint32 zone, WeatherData const* weatherChances)
@@ -199,6 +197,12 @@ void Weather::SendWeatherUpdateToPlayer(Player* player)
player->SendDirectMessage(weather.Write()); player->SendDirectMessage(weather.Write());
} }
void Weather::SendFineWeatherUpdateToPlayer(Player* player)
{
WorldPackets::Misc::Weather weather(WEATHER_STATE_FINE);
player->SendDirectMessage(weather.Write());
}
/// Send the new weather to all players in the zone /// Send the new weather to all players in the zone
bool Weather::UpdateWeather() bool Weather::UpdateWeather()
{ {
+1
View File
@@ -75,6 +75,7 @@ class TC_GAME_API Weather
bool UpdateWeather(); bool UpdateWeather();
void SendWeatherUpdateToPlayer(Player* player); void SendWeatherUpdateToPlayer(Player* player);
static void SendFineWeatherUpdateToPlayer(Player* player);
void SetWeather(WeatherType type, float grade); void SetWeather(WeatherType type, float grade);
/// For which zone is this weather? /// For which zone is this weather?
+6 -67
View File
@@ -21,12 +21,12 @@
*/ */
#include "WeatherMgr.h" #include "WeatherMgr.h"
#include "Containers.h"
#include "DatabaseEnv.h" #include "DatabaseEnv.h"
#include "Log.h" #include "Log.h"
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "Player.h" #include "Timer.h"
#include "Weather.h" #include "Weather.h"
#include "WorldSession.h"
#include "MiscPackets.h" #include "MiscPackets.h"
namespace WeatherMgr namespace WeatherMgr
@@ -34,51 +34,12 @@ namespace WeatherMgr
namespace namespace
{ {
typedef std::unordered_map<uint32, std::shared_ptr<Weather> > WeatherMap; std::unordered_map<uint32, WeatherData> _weatherData;
typedef std::unordered_map<uint32, WeatherData> WeatherZoneMap;
WeatherMap m_weathers;
WeatherZoneMap mWeatherZoneMap;
WeatherData const* GetWeatherData(uint32 zone_id)
{
WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id);
return (itr != mWeatherZoneMap.end()) ? &itr->second : nullptr;
}
} }
/// Find a Weather object by the given zoneid WeatherData const* GetWeatherData(uint32 zone_id)
Weather* FindWeather(uint32 id)
{ {
WeatherMap::const_iterator itr = m_weathers.find(id); return Trinity::Containers::MapGetValuePtr(_weatherData, zone_id);
return (itr != m_weathers.end()) ? itr->second.get() : nullptr;
}
/// Remove a Weather object for the given zoneid
void RemoveWeather(uint32 id)
{
// not called at the moment. Kept for completeness
WeatherMap::iterator itr = m_weathers.find(id);
if (itr != m_weathers.end())
m_weathers.erase(itr);
}
/// Add a Weather object to the list
Weather* AddWeather(uint32 zone_id)
{
WeatherData const* weatherChances = GetWeatherData(zone_id);
// zone does not have weather, ignore
if (!weatherChances)
return nullptr;
Weather* w = new Weather(zone_id, weatherChances);
m_weathers[w->GetZone()].reset(w);
w->ReGenerate();
w->UpdateWeather();
return w;
} }
void LoadWeatherData() void LoadWeatherData()
@@ -106,7 +67,7 @@ void LoadWeatherData()
uint32 zone_id = fields[0].GetUInt32(); uint32 zone_id = fields[0].GetUInt32();
WeatherData& wzc = mWeatherZoneMap[zone_id]; WeatherData& wzc = _weatherData[zone_id];
for (uint8 season = 0; season < WEATHER_SEASONS; ++season) for (uint8 season = 0; season < WEATHER_SEASONS; ++season)
{ {
@@ -142,26 +103,4 @@ void LoadWeatherData()
TC_LOG_INFO("server.loading", ">> Loaded %u weather definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); TC_LOG_INFO("server.loading", ">> Loaded %u weather definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
} }
void SendFineWeatherUpdateToPlayer(Player* player)
{
WorldPackets::Misc::Weather weather(WEATHER_STATE_FINE);
player->SendDirectMessage(weather.Write());
}
void Update(uint32 diff)
{
///- Send an update signal to Weather objects
WeatherMap::iterator itr, next;
for (itr = m_weathers.begin(); itr != m_weathers.end(); itr = next)
{
next = itr;
++next;
///- and remove Weather objects for zones with no player
// As interval > WorldTick
if (!itr->second->Update(diff))
m_weathers.erase(itr);
}
}
} // namespace } // namespace
+2 -8
View File
@@ -27,18 +27,12 @@
class Weather; class Weather;
class Player; class Player;
struct WeatherData;
namespace WeatherMgr namespace WeatherMgr
{ {
TC_GAME_API void LoadWeatherData(); TC_GAME_API void LoadWeatherData();
TC_GAME_API WeatherData const* GetWeatherData(uint32 zone_id);
TC_GAME_API Weather* FindWeather(uint32 id);
TC_GAME_API Weather* AddWeather(uint32 zone_id);
TC_GAME_API void RemoveWeather(uint32 zone_id);
TC_GAME_API void SendFineWeatherUpdateToPlayer(Player* player);
TC_GAME_API void Update(uint32 diff);
} }
#endif #endif
-8
View File
@@ -2041,7 +2041,6 @@ void World::SetInitialWorldSettings()
LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES(%u, %u, 0, '%s')", LoginDatabase.PExecute("INSERT INTO uptime (realmid, starttime, uptime, revision) VALUES(%u, %u, 0, '%s')",
realm.Id.Realm, uint32(GameTime::GetStartTime()), GitRevision::GetFullVersion()); // One-time query realm.Id.Realm, uint32(GameTime::GetStartTime()), GitRevision::GetFullVersion()); // One-time query
m_timers[WUPDATE_WEATHERS].SetInterval(1*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS); m_timers[WUPDATE_AUCTIONS].SetInterval(MINUTE*IN_MILLISECONDS);
m_timers[WUPDATE_AUCTIONS_PENDING].SetInterval(250); m_timers[WUPDATE_AUCTIONS_PENDING].SetInterval(250);
m_timers[WUPDATE_UPTIME].SetInterval(m_int_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS); m_timers[WUPDATE_UPTIME].SetInterval(m_int_configs[CONFIG_UPTIME_UPDATE]*MINUTE*IN_MILLISECONDS);
@@ -2330,13 +2329,6 @@ void World::Update(uint32 diff)
UpdateSessions(diff); UpdateSessions(diff);
sWorldUpdateTime.RecordUpdateTimeDuration("UpdateSessions"); sWorldUpdateTime.RecordUpdateTimeDuration("UpdateSessions");
/// <li> Handle weather updates when the timer has passed
if (m_timers[WUPDATE_WEATHERS].Passed())
{
m_timers[WUPDATE_WEATHERS].Reset();
WeatherMgr::Update(uint32(m_timers[WUPDATE_WEATHERS].GetInterval()));
}
/// <li> Update uptime table /// <li> Update uptime table
if (m_timers[WUPDATE_UPTIME].Passed()) if (m_timers[WUPDATE_UPTIME].Passed())
{ {
-1
View File
@@ -71,7 +71,6 @@ enum WorldTimers
{ {
WUPDATE_AUCTIONS, WUPDATE_AUCTIONS,
WUPDATE_AUCTIONS_PENDING, WUPDATE_AUCTIONS_PENDING,
WUPDATE_WEATHERS,
WUPDATE_UPTIME, WUPDATE_UPTIME,
WUPDATE_CORPSES, WUPDATE_CORPSES,
WUPDATE_EVENTS, WUPDATE_EVENTS,
+1 -4
View File
@@ -1401,10 +1401,7 @@ public:
Player* player = handler->GetSession()->GetPlayer(); Player* player = handler->GetSession()->GetPlayer();
uint32 zoneid = player->GetZoneId(); uint32 zoneid = player->GetZoneId();
Weather* weather = WeatherMgr::FindWeather(zoneid); Weather* weather = player->GetMap()->GetOrGenerateZoneDefaultWeather(zoneid);
if (!weather)
weather = WeatherMgr::AddWeather(zoneid);
if (!weather) if (!weather)
{ {
handler->SendSysMessage(LANG_NO_WEATHER); handler->SendSysMessage(LANG_NO_WEATHER);