aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/master/2022_06_25_01_world.sql19
-rw-r--r--src/server/game/Entities/Player/Player.cpp3
-rw-r--r--src/server/game/Maps/Map.cpp28
-rw-r--r--src/server/game/Maps/Map.h12
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp23
-rw-r--r--src/server/game/Scripting/ScriptMgr.h19
-rw-r--r--src/server/game/World/World.cpp4
-rw-r--r--src/server/game/World/WorldStates/WorldStateDefines.h36
-rw-r--r--src/server/game/World/WorldStates/WorldStateMgr.cpp137
-rw-r--r--src/server/game/World/WorldStates/WorldStateMgr.h50
10 files changed, 331 insertions, 0 deletions
diff --git a/sql/updates/world/master/2022_06_25_01_world.sql b/sql/updates/world/master/2022_06_25_01_world.sql
new file mode 100644
index 00000000000..72693acf060
--- /dev/null
+++ b/sql/updates/world/master/2022_06_25_01_world.sql
@@ -0,0 +1,19 @@
+--
+-- Table structure for table `world_state`
+--
+DROP TABLE IF EXISTS `world_state`;
+CREATE TABLE `world_state` (
+ `ID` int NOT NULL,
+ `DefaultValue` int NOT NULL,
+ `MapID` int unsigned DEFAULT NULL,
+ `ScriptName` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
+ `Comment` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
+ PRIMARY KEY (`ID`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
+
+INSERT INTO `world_state` (`ID`, `DefaultValue`, `MapID`, `Comment`) VALUES
+(5644, 0, 669, 'Blackwing Descent - Omnotron Defense System - Achieve-a-tron'),
+(5645, 0, 669, 'Blackwing Descent - Omnotron Defense System - Achieve-a-tron'),
+(5646, 0, 669, 'Blackwing Descent - Omnotron Defense System - Achieve-a-tron'),
+(5647, 0, 669, 'Blackwing Descent - Omnotron Defense System - Achieve-a-tron'),
+(5117, 0, 670, 'Grim Batol - Erudax - Don\'t need to Break Eggs to Make an Omelet');
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 2e46042d19a..5394a667d6c 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -124,6 +124,7 @@
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
+#include "WorldStateMgr.h"
#include "WorldStatePackets.h"
#include <G3D/g3dmath.h>
#include <sstream>
@@ -9214,6 +9215,8 @@ void Player::SendInitWorldStates(uint32 zoneId, uint32 areaId)
packet.AreaID = zoneId;
packet.SubareaID = areaId;
+ sWorldStateMgr->FillInitialWorldStates(packet, GetMap());
+
packet.Worldstates.emplace_back(2264, 0); // SCOURGE_EVENT_WORLDSTATE_EASTERN_PLAGUELANDS
packet.Worldstates.emplace_back(2263, 0); // SCOURGE_EVENT_WORLDSTATE_TANARIS
packet.Worldstates.emplace_back(2262, 0); // SCOURGE_EVENT_WORLDSTATE_BURNING_STEPPES
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index e9fe8caffc3..7771fe6198e 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -56,6 +56,8 @@
#include "WeatherMgr.h"
#include "World.h"
#include "WorldSession.h"
+#include "WorldStateMgr.h"
+#include "WorldStatePackets.h"
#include <sstream>
#include "Hacks/boost_1_74_fibonacci_heap.h"
@@ -371,6 +373,8 @@ i_scriptLock(false), _respawnCheckTimer(0)
MMAP::MMapFactory::createOrGetMMapManager()->loadMapInstance(sWorld->GetDataPath(), GetId(), i_InstanceId);
+ _worldStateValues = sWorldStateMgr->GetInitialWorldStatesForMap(this);
+
sScriptMgr->OnCreateMap(this);
}
@@ -684,6 +688,30 @@ void Map::UpdatePersonalPhasesForPlayer(Player const* player)
GetMultiPersonalPhaseTracker().OnOwnerPhaseChanged(player, getNGrid(cell.GridX(), cell.GridY()), this, cell);
}
+int32 Map::GetWorldStateValue(int32 worldStateId) const
+{
+ if (int32 const* value = Trinity::Containers::MapGetValuePtr(_worldStateValues, worldStateId))
+ return *value;
+
+ return 0;
+}
+
+void Map::SetWorldStateValue(int32 worldStateId, int32 value)
+{
+ auto itr = _worldStateValues.try_emplace(worldStateId, 0).first;
+ int32 oldValue = itr->second;
+ itr->second = value;
+
+ if (WorldStateTemplate const* worldStateTemplate = sWorldStateMgr->GetWorldStateTemplate(worldStateId))
+ 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());
+}
+
template<class T>
void Map::InitializeObject(T* /*obj*/) { }
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index f589ce9e0e3..1d795edfdd5 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -35,6 +35,7 @@
#include "SharedDefines.h"
#include "SpawnData.h"
#include "Timer.h"
+#include "WorldStateDefines.h"
#include <boost/heap/fibonacci_heap.hpp>
#include <bitset>
#include <list>
@@ -918,6 +919,17 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
private:
MultiPersonalPhaseTracker _multiPersonalPhaseTracker;
+
+ /*********************************************************/
+ /*** WorldStates ***/
+ /*********************************************************/
+ public:
+ int32 GetWorldStateValue(int32 worldStateId) const;
+ void SetWorldStateValue(int32 worldStateId, int32 value);
+ WorldStateValueContainer const& GetWorldStateValues() const { return _worldStateValues; }
+
+ private:
+ WorldStateValueContainer _worldStateValues;
};
enum InstanceResetMethod
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 795b8e997eb..c911afdad87 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -133,6 +133,10 @@ template<>
struct is_script_database_bound<QuestScript>
: std::true_type { };
+template<>
+struct is_script_database_bound<WorldStateScript>
+ : std::true_type { };
+
enum Spells
{
SPELL_HOTSWAP_VISUAL_SPELL_EFFECT = 40162 // 59084
@@ -2322,6 +2326,7 @@ void ScriptMgr::OnSceneComplete(Player* player, uint32 sceneInstanceID, SceneTem
tmpscript->OnSceneComplete(player, sceneInstanceID, sceneTemplate);
}
+// Quest
void ScriptMgr::OnQuestStatusChange(Player* player, Quest const* quest, QuestStatus oldStatus, QuestStatus newStatus)
{
ASSERT(player);
@@ -2349,6 +2354,15 @@ void ScriptMgr::OnQuestObjectiveChange(Player* player, Quest const* quest, Quest
tmpscript->OnQuestObjectiveChange(player, quest, objective, oldAmount, newAmount);
}
+// WorldState
+void ScriptMgr::OnWorldStateValueChange(WorldStateTemplate const* worldStateTemplate, int32 oldValue, int32 newValue, Map const* map)
+{
+ ASSERT(worldStateTemplate);
+
+ GET_SCRIPT(WorldStateScript, worldStateTemplate->ScriptId, tmpscript);
+ tmpscript->OnValueChange(worldStateTemplate->Id, oldValue, newValue, map);
+}
+
SpellScriptLoader::SpellScriptLoader(char const* name)
: ScriptObject(name)
{
@@ -2638,6 +2652,14 @@ QuestScript::QuestScript(char const* name)
QuestScript::~QuestScript() = default;
+WorldStateScript::WorldStateScript(char const* name)
+ : ScriptObject(name)
+{
+ ScriptRegistry<WorldStateScript>::Instance()->AddScript(this);
+}
+
+WorldStateScript::~WorldStateScript() = default;
+
// Specialize for each script type class like so:
template class TC_GAME_API ScriptRegistry<SpellScriptLoader>;
template class TC_GAME_API ScriptRegistry<ServerScript>;
@@ -2671,3 +2693,4 @@ template class TC_GAME_API ScriptRegistry<AreaTriggerEntityScript>;
template class TC_GAME_API ScriptRegistry<ConversationScript>;
template class TC_GAME_API ScriptRegistry<SceneScript>;
template class TC_GAME_API ScriptRegistry<QuestScript>;
+template class TC_GAME_API ScriptRegistry<WorldStateScript>;
diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h
index 32ecfb431c7..e5fd8bee5b9 100644
--- a/src/server/game/Scripting/ScriptMgr.h
+++ b/src/server/game/Scripting/ScriptMgr.h
@@ -77,6 +77,7 @@ struct MapEntry;
struct Position;
struct QuestObjective;
struct SceneTemplate;
+struct WorldStateTemplate;
namespace Trinity::ChatCommands { struct ChatCommandBuilder; }
@@ -987,6 +988,20 @@ class TC_GAME_API QuestScript : public ScriptObject
virtual void OnQuestObjectiveChange(Player* /*player*/, Quest const* /*quest*/, QuestObjective const& /*objective*/, int32 /*oldAmount*/, int32 /*newAmount*/) { }
};
+class TC_GAME_API WorldStateScript : public ScriptObject
+{
+ protected:
+
+ WorldStateScript(char const* name);
+
+ public:
+
+ ~WorldStateScript();
+
+ // Called when worldstate changes value, map is optional
+ virtual void OnValueChange([[maybe_unused]] int32 worldStateId, [[maybe_unused]] int32 oldValue, [[maybe_unused]] int32 newValue, [[maybe_unused]] Map const* map) { }
+};
+
// Manages registration, loading, and execution of scripts.
class TC_GAME_API ScriptMgr
{
@@ -1289,6 +1304,10 @@ class TC_GAME_API ScriptMgr
void OnQuestAcknowledgeAutoAccept(Player* player, Quest const* quest);
void OnQuestObjectiveChange(Player* player, Quest const* quest, QuestObjective const& objective, int32 oldAmount, int32 newAmount);
+ public: /* WorldStateScript */
+
+ void OnWorldStateValueChange(WorldStateTemplate const* worldStateTemplate, int32 oldValue, int32 newValue, Map const* map);
+
private:
uint32 _scriptCount;
bool _scriptIdUpdated;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 5a3ef8104f3..94b36940189 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -100,6 +100,7 @@
#include "WhoListStorage.h"
#include "WorldSession.h"
#include "WorldSocket.h"
+#include "WorldStateMgr.h"
#include <boost/algorithm/string.hpp>
@@ -2241,6 +2242,9 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Creature Formations...");
sFormationMgr->LoadCreatureFormations();
+ TC_LOG_INFO("server.loading", "Loading World State templates...");
+ sWorldStateMgr->LoadFromDB();
+
TC_LOG_INFO("server.loading", "Loading World States..."); // must be loaded before battleground, outdoor PvP and conditions
LoadWorldStates();
diff --git a/src/server/game/World/WorldStates/WorldStateDefines.h b/src/server/game/World/WorldStates/WorldStateDefines.h
new file mode 100644
index 00000000000..3b85a36d1e4
--- /dev/null
+++ b/src/server/game/World/WorldStates/WorldStateDefines.h
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef WorldStateDefines_h__
+#define WorldStateDefines_h__
+
+#include "Define.h"
+#include "Optional.h"
+#include <unordered_map>
+
+struct WorldStateTemplate
+{
+ int32 Id = 0;
+ int32 DefaultValue = 0;
+ uint32 ScriptId = 0;
+
+ Optional<uint32> MapId;
+};
+
+using WorldStateValueContainer = std::unordered_map<int32 /*worldStateId*/, int32 /*value*/>;
+
+#endif // WorldStateDefines_h__
diff --git a/src/server/game/World/WorldStates/WorldStateMgr.cpp b/src/server/game/World/WorldStates/WorldStateMgr.cpp
new file mode 100644
index 00000000000..b9ed79f951a
--- /dev/null
+++ b/src/server/game/World/WorldStates/WorldStateMgr.cpp
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "WorldStateMgr.h"
+#include "Containers.h"
+#include "DatabaseEnv.h"
+#include "Log.h"
+#include "Map.h"
+#include "ObjectMgr.h"
+#include "ScriptMgr.h"
+#include "World.h"
+#include "WorldStatePackets.h"
+
+namespace
+{
+std::unordered_map<int32, WorldStateTemplate> _worldStateTemplates;
+WorldStateValueContainer _realmWorldStateValues;
+std::unordered_map<uint32, WorldStateValueContainer> _worldStatesByMap;
+}
+
+void WorldStateMgr::LoadFromDB()
+{
+ uint32 oldMSTime = getMSTime();
+
+ // 0 1 2 3
+ QueryResult result = WorldDatabase.Query("SELECT ID, DefaultValue, MapID, ScriptName FROM world_state");
+ if (!result)
+ return;
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ int32 id = fields[0].GetInt32();
+ WorldStateTemplate& worldState = _worldStateTemplates[id];
+ worldState.Id = id;
+ worldState.DefaultValue = fields[1].GetInt32();
+ if (!fields[2].IsNull())
+ worldState.MapId = fields[2].GetUInt32();
+
+ worldState.ScriptId = sObjectMgr->GetScriptId(fields[3].GetString());
+
+ if (worldState.MapId)
+ _worldStatesByMap[*worldState.MapId][id] = worldState.DefaultValue;
+ else
+ _realmWorldStateValues[id] = worldState.DefaultValue;
+
+ } while (result->NextRow());
+
+ TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " world state templates %u ms", _worldStateTemplates.size(), GetMSTimeDiffToNow(oldMSTime));
+}
+
+WorldStateTemplate const* WorldStateMgr::GetWorldStateTemplate(int32 worldStateId) const
+{
+ return Trinity::Containers::MapGetValuePtr(_worldStateTemplates, worldStateId);
+}
+
+int32 WorldStateMgr::GetValue(int32 worldStateId, Map const* map) const
+{
+ WorldStateTemplate const* worldStateTemplate = GetWorldStateTemplate(worldStateId);
+ if (!worldStateTemplate || !worldStateTemplate->MapId)
+ {
+ if (int32 const* value = Trinity::Containers::MapGetValuePtr(_realmWorldStateValues, worldStateId))
+ return *value;
+
+ return 0;
+ }
+
+ if (map->GetId() != worldStateTemplate->MapId)
+ return 0;
+
+ return map->GetWorldStateValue(worldStateId);
+}
+
+void WorldStateMgr::SetValue(int32 worldStateId, int32 value, Map* map)
+{
+ WorldStateTemplate const* worldStateTemplate = GetWorldStateTemplate(worldStateId);
+ if (!worldStateTemplate || !worldStateTemplate->MapId)
+ {
+ auto itr = _realmWorldStateValues.try_emplace(worldStateId, 0).first;
+ int32 oldValue = itr->second;
+ itr->second = value;
+
+ if (worldStateTemplate)
+ sScriptMgr->OnWorldStateValueChange(worldStateTemplate, oldValue, value, nullptr);
+
+ // Broadcast update to all players on the server
+ WorldPackets::WorldState::UpdateWorldState updateWorldState;
+ updateWorldState.VariableID = worldStateId;
+ updateWorldState.Value = value;
+ sWorld->SendGlobalMessage(updateWorldState.Write());
+ return;
+ }
+
+ if (map->GetId() != worldStateTemplate->MapId)
+ return;
+
+ map->SetWorldStateValue(worldStateId, value);
+}
+
+WorldStateValueContainer WorldStateMgr::GetInitialWorldStatesForMap(Map const* map) const
+{
+ WorldStateValueContainer initialValues;
+ if (WorldStateValueContainer const* valuesTemplate = Trinity::Containers::MapGetValuePtr(_worldStatesByMap, map->GetId()))
+ initialValues = *valuesTemplate;
+
+ return initialValues;
+}
+
+void WorldStateMgr::FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& initWorldStates, Map const* map) const
+{
+ for (auto const& [worldStateId, value] : _realmWorldStateValues)
+ initWorldStates.Worldstates.emplace_back(worldStateId, value);
+
+ for (auto const& [worldStateId, value] : map->GetWorldStateValues())
+ initWorldStates.Worldstates.emplace_back(worldStateId, value);
+}
+
+WorldStateMgr* WorldStateMgr::instance()
+{
+ static WorldStateMgr instance;
+ return &instance;
+}
diff --git a/src/server/game/World/WorldStates/WorldStateMgr.h b/src/server/game/World/WorldStates/WorldStateMgr.h
new file mode 100644
index 00000000000..18ce38afd2f
--- /dev/null
+++ b/src/server/game/World/WorldStates/WorldStateMgr.h
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef WorldStateMgr_h__
+#define WorldStateMgr_h__
+
+#include "Define.h"
+#include "WorldStateDefines.h"
+
+class Map;
+
+namespace WorldPackets::WorldState
+{
+ class InitWorldStates;
+}
+
+class TC_GAME_API WorldStateMgr
+{
+public:
+ static WorldStateMgr* instance();
+
+ void LoadFromDB();
+
+ WorldStateTemplate const* GetWorldStateTemplate(int32 worldStateId) const;
+
+ int32 GetValue(int32 worldStateId, Map const* map) const;
+ void SetValue(int32 worldStateId, int32 value, Map* map);
+
+ WorldStateValueContainer GetInitialWorldStatesForMap(Map const* map) const;
+
+ void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& initWorldStates, Map const* map) const;
+};
+
+#define sWorldStateMgr WorldStateMgr::instance()
+
+#endif