diff --git a/Source/Framework/Constants/SharedConst.cs b/Source/Framework/Constants/SharedConst.cs index c19792892..1880b2ae2 100644 --- a/Source/Framework/Constants/SharedConst.cs +++ b/Source/Framework/Constants/SharedConst.cs @@ -3081,15 +3081,5 @@ namespace Framework.Constants WarModeHordeBuffValue = 17042, WarModeAllianceBuffValue = 17043, - - CurrencyResetTime = 20001, // Next Arena Distribution Time - WeeklyQuestResetTime = 20002, // Next Weekly Quest Reset Time - BgDailyResetTime = 20003, // Next Daily Bg Reset Time - CleaningFlags = 20004, // Cleaning Flags - GuildDailyResetTime = 20006, // Next Guild Cap Reset Time - MonthlyQuestResetTime = 20007, // Next Monthly Quest Reset Time - DailyQuestResetTime = 20008, // Next Daily Quest Reset Time - DailyCalendarDeletionOldEventsTime = 20009, // Next Daily Calendar Deletions Of Old Events Time - GuildWeeklyResetTime = 20050, // Next Guild Week Reset Time } } diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index 99dc8d084..036eba040 100644 --- a/Source/Framework/Database/Databases/CharacterDatabase.cs +++ b/Source/Framework/Database/Databases/CharacterDatabase.cs @@ -510,8 +510,8 @@ namespace Framework.Database PrepareStatement(CharStatements.UPD_GLOBAL_INSTANCE_RESETTIME, "UPDATE instance_reset SET resettime = ? WHERE mapid = ? AND difficulty = ?"); PrepareStatement(CharStatements.UPD_CHAR_ONLINE, "UPDATE characters SET online = 1 WHERE guid = ?"); PrepareStatement(CharStatements.UPD_CHAR_NAME_AT_LOGIN, "UPDATE characters SET name = ?, at_login = ? WHERE guid = ?"); - PrepareStatement(CharStatements.UPD_WORLDSTATE, "UPDATE worldstates SET value = ? WHERE entry = ?"); - PrepareStatement(CharStatements.INS_WORLDSTATE, "INSERT INTO worldstates (entry, value) VALUES (?, ?)"); + PrepareStatement(CharStatements.REP_WORLD_STATE, "REPLACE INTO world_state_value (Id, Value) VALUES (?, ?)"); + PrepareStatement(CharStatements.REP_WORLD_VARIABLE, "REPLACE INTO world_variable (Id, Value) VALUES (?, ?)"); PrepareStatement(CharStatements.DEL_CHAR_INSTANCE_BY_INSTANCE_GUID, "DELETE FROM character_instance WHERE guid = ? AND instance = ?"); PrepareStatement(CharStatements.UPD_CHAR_INSTANCE, "UPDATE character_instance SET instance = ?, permanent = ?, extendState = ? WHERE guid = ? AND instance = ?"); PrepareStatement(CharStatements.INS_CHAR_INSTANCE, "INSERT INTO character_instance (guid, instance, permanent, extendState) VALUES (?, ?, ?, ?)"); @@ -1157,8 +1157,8 @@ namespace Framework.Database UPD_GLOBAL_INSTANCE_RESETTIME, UPD_CHAR_ONLINE, UPD_CHAR_NAME_AT_LOGIN, - UPD_WORLDSTATE, - INS_WORLDSTATE, + REP_WORLD_STATE, + REP_WORLD_VARIABLE, DEL_CHAR_INSTANCE_BY_INSTANCE_GUID, UPD_CHAR_INSTANCE, INS_CHAR_INSTANCE, diff --git a/Source/Game/Chat/Commands/DebugCommands.cs b/Source/Game/Chat/Commands/DebugCommands.cs index b1d96c47f..287145841 100644 --- a/Source/Game/Chat/Commands/DebugCommands.cs +++ b/Source/Game/Chat/Commands/DebugCommands.cs @@ -799,18 +799,18 @@ namespace Game.Chat long now = GameTime.GetGameTime(); if (daily) { - Global.WorldMgr.SetNextDailyQuestsResetTime(now); - handler.SendSysMessage("Daily quest reset scheduled for next tick."); + Global.WorldMgr.DailyReset(); + handler.SendSysMessage($"Daily quests have been reset. Next scheduled reset: {Time.UnixTimeToDateTime(Global.WorldMgr.GetPersistentWorldVariable(WorldManager.NextDailyQuestResetTimeVarId)).ToShortTimeString()}"); } if (weekly) { - Global.WorldMgr.SetNextWeeklyQuestsResetTime(now); - handler.SendSysMessage("Weekly quest reset scheduled for next tick."); + Global.WorldMgr.ResetWeeklyQuests(); + handler.SendSysMessage($"Weekly quests have been reset. Next scheduled reset: {Time.UnixTimeToDateTime(Global.WorldMgr.GetPersistentWorldVariable(WorldManager.NextWeeklyQuestResetTimeVarId)).ToShortTimeString()}"); } if (monthly) { - Global.WorldMgr.SetNextMonthlyQuestsResetTime(now); - handler.SendSysMessage("Monthly quest reset scheduled for next tick."); + Global.WorldMgr.ResetMonthlyQuests(); + handler.SendSysMessage($"Monthly quests have been reset. Next scheduled reset: {Time.UnixTimeToDateTime(Global.WorldMgr.GetPersistentWorldVariable(WorldManager.NextMonthlyQuestResetTimeVarId)).ToShortTimeString()}"); } return true; diff --git a/Source/Game/Tools/CharacterDatabaseCleaner.cs b/Source/Game/Tools/CharacterDatabaseCleaner.cs index f6b076208..3a720e96c 100644 --- a/Source/Game/Tools/CharacterDatabaseCleaner.cs +++ b/Source/Game/Tools/CharacterDatabaseCleaner.cs @@ -37,12 +37,7 @@ namespace Game uint oldMSTime = Time.GetMSTime(); - // check flags which clean ups are necessary - SQLResult result = DB.Characters.Query("SELECT value FROM worldstates WHERE entry = {0}", (uint)WorldStates.CleaningFlags); - if (result.IsEmpty()) - return; - - CleaningFlags flags = (CleaningFlags)result.Read(0); + CleaningFlags flags = (CleaningFlags)Global.WorldMgr.GetPersistentWorldVariable(WorldManager.CharacterDatabaseCleaningFlagsVarId); // clean up if (flags.HasAnyFlag(CleaningFlags.AchievementProgress)) @@ -63,7 +58,7 @@ namespace Game // NOTE: In order to have persistentFlags be set in worldstates for the next cleanup, // you need to define them at least once in worldstates. flags &= (CleaningFlags)WorldConfig.GetIntValue(WorldCfg.PersistentCharacterCleanFlags); - DB.Characters.DirectExecute("UPDATE worldstates SET value = {0} WHERE entry = {1}", flags, (uint)WorldStates.CleaningFlags); + Global.WorldMgr.SetPersistentWorldVariable(WorldManager.CharacterDatabaseCleaningFlagsVarId, (int)flags); Global.WorldMgr.SetCleaningFlags(flags); diff --git a/Source/Game/World/WorldManager.cs b/Source/Game/World/WorldManager.cs index a48a15a54..2dd4ee539 100644 --- a/Source/Game/World/WorldManager.cs +++ b/Source/Game/World/WorldManager.cs @@ -39,6 +39,16 @@ namespace Game { public class WorldManager : Singleton { + public const string NextCurrencyResetTimeVarId = "NextCurrencyResetTime"; + public const string NextWeeklyQuestResetTimeVarId = "NextWeeklyQuestResetTime"; + public const string NextBGRandomDailyResetTimeVarId = "NextBGRandomDailyResetTime"; + public const string CharacterDatabaseCleaningFlagsVarId = "PersistentCharacterCleanFlags"; + public const string NextGuildDailyResetTimeVarId = "NextGuildDailyResetTime"; + public const string NextMonthlyQuestResetTimeVarId = "NextMonthlyQuestResetTime"; + public const string NextDailyQuestResetTimeVarId = "NextDailyQuestResetTime"; + public const string NextOldCalendarEventDeletionTimeVarId = "NextOldCalendarEventDeletionTime"; + public const string NextGuildWeeklyResetTimeVarId = "NextGuildWeeklyResetTime"; + WorldManager() { foreach (WorldTimers timer in Enum.GetValues(typeof(WorldTimers))) @@ -890,16 +900,13 @@ namespace Game FormationMgr.LoadCreatureFormations(); Log.outInfo(LogFilter.ServerLoading, "Loading World State templates..."); - Global.WorldStateMgr.LoadFromDB(); + Global.WorldStateMgr.LoadFromDB(); // must be loaded before battleground, outdoor PvP and conditions - Log.outInfo(LogFilter.ServerLoading, "Loading World States..."); // must be loaded before Battleground, outdoor PvP and conditions - LoadWorldStates(); + Log.outInfo(LogFilter.ServerLoading, "Loading Persistend World Variables..."); // must be loaded before Battleground, outdoor PvP and conditions + LoadPersistentWorldVariables(); Global.WorldStateMgr.SetValue(WorldStates.CurrentPvpSeasonId, WorldConfig.GetBoolValue(WorldCfg.ArenaSeasonInProgress) ? WorldConfig.GetIntValue(WorldCfg.ArenaSeasonId) : 0, false, null); Global.WorldStateMgr.SetValue(WorldStates.PreviousPvpSeasonId, WorldConfig.GetIntValue(WorldCfg.ArenaSeasonId) - (WorldConfig.GetBoolValue(WorldCfg.ArenaSeasonInProgress) ? 1 : 0), false, null); - // TODO: this is temporary until custom world states are purged from old world state saved values - Global.WorldStateMgr.SetValue(WorldStates.WarModeHordeBuffValue, (int)GetWorldState(WorldStates.WarModeHordeBuffValue), false, null); - Global.WorldStateMgr.SetValue(WorldStates.WarModeAllianceBuffValue, (int)GetWorldState(WorldStates.WarModeAllianceBuffValue), false, null); Global.ObjectMgr.LoadPhases(); @@ -1260,12 +1267,8 @@ namespace Game public void SetForcedWarModeFactionBalanceState(int team, int reward = 0) { - Global.WorldStateMgr.SetValue(WorldStates.WarModeHordeBuffValue, 10 + (team == TeamId.Alliance ? reward : 0), false, null); - Global.WorldStateMgr.SetValue(WorldStates.WarModeAllianceBuffValue, 10 + (team == TeamId.Horde ? reward : 0), false, null); - - // save to db - SetWorldState(WorldStates.WarModeHordeBuffValue, Global.WorldStateMgr.GetValue(WorldStates.WarModeHordeBuffValue, null)); - SetWorldState(WorldStates.WarModeAllianceBuffValue, Global.WorldStateMgr.GetValue(WorldStates.WarModeAllianceBuffValue, null)); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.WarModeHordeBuffValue, 10 + (team == TeamId.Alliance ? reward : 0), false, null); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.WarModeAllianceBuffValue, 10 + (team == TeamId.Horde ? reward : 0), false, null); } public void DisableForcedWarModeFactionBalanceState() @@ -1975,7 +1978,7 @@ namespace Game } void UpdateRealmCharCount(SQLResult result) - { + { if (!result.IsEmpty()) { uint Id = result.Read(0); @@ -1991,9 +1994,9 @@ namespace Game void InitQuestResetTimes() { - m_NextDailyQuestReset = GetWorldState(WorldStates.DailyQuestResetTime); - m_NextWeeklyQuestReset = GetWorldState(WorldStates.WeeklyQuestResetTime); - m_NextMonthlyQuestReset = GetWorldState(WorldStates.MonthlyQuestResetTime); + m_NextDailyQuestReset = GetPersistentWorldVariable(NextDailyQuestResetTimeVarId); + m_NextWeeklyQuestReset = GetPersistentWorldVariable(NextWeeklyQuestResetTimeVarId); + m_NextMonthlyQuestReset = GetPersistentWorldVariable(NextMonthlyQuestResetTimeVarId); } static long GetNextDailyResetTime(long t) @@ -2001,7 +2004,7 @@ namespace Game return Time.GetLocalHourTimestamp(t, WorldConfig.GetUIntValue(WorldCfg.DailyQuestResetTimeHour), true); } - void DailyReset() + public void DailyReset() { // reset all saved quest status PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_DAILY); @@ -2031,7 +2034,7 @@ namespace Game Cypher.Assert(now < next); m_NextDailyQuestReset = next; - SetWorldState(WorldStates.DailyQuestResetTime, (ulong)next); + SetPersistentWorldVariable(NextDailyQuestResetTimeVarId, (int)next); Log.outInfo(LogFilter.Misc, "Daily quests for all characters have been reset."); } @@ -2048,7 +2051,7 @@ namespace Game return t; } - void ResetWeeklyQuests() + public void ResetWeeklyQuests() { // reset all saved quest status PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY); @@ -2070,7 +2073,7 @@ namespace Game Cypher.Assert(now < next); m_NextWeeklyQuestReset = next; - SetWorldState(WorldStates.WeeklyQuestResetTime, (ulong)next); + SetPersistentWorldVariable(NextWeeklyQuestResetTimeVarId, (int)next); Log.outInfo(LogFilter.Misc, "Weekly quests for all characters have been reset."); } @@ -2086,7 +2089,7 @@ namespace Game return Time.DateTimeToUnixTime(newDate); } - void ResetMonthlyQuests() + public void ResetMonthlyQuests() { // reset all saved quest status PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY); @@ -2108,7 +2111,7 @@ namespace Game Cypher.Assert(now < next); m_NextMonthlyQuestReset = next; - SetWorldState(WorldStates.MonthlyQuestResetTime, (ulong)next); + SetPersistentWorldVariable(NextMonthlyQuestResetTimeVarId, (int)next); Log.outInfo(LogFilter.Misc, "Monthly quests for all characters have been reset."); } @@ -2126,7 +2129,7 @@ namespace Game void InitRandomBGResetTime() { - long bgtime = GetWorldState(WorldStates.BgDailyResetTime); + long bgtime = GetPersistentWorldVariable(NextBGRandomDailyResetTimeVarId); if (bgtime == 0) m_NextRandomBGReset = GameTime.GetGameTime(); // game time not yet init @@ -2144,14 +2147,14 @@ namespace Game m_NextRandomBGReset = bgtime < curTime ? nextDayResetTime - Time.Day : nextDayResetTime; if (bgtime == 0) - SetWorldState(WorldStates.BgDailyResetTime, (ulong)m_NextRandomBGReset); + SetPersistentWorldVariable(NextBGRandomDailyResetTimeVarId, (int)m_NextRandomBGReset); } void InitCalendarOldEventsDeletionTime() { long now = GameTime.GetGameTime(); long nextDeletionTime = Time.GetLocalHourTimestamp(now, WorldConfig.GetUIntValue(WorldCfg.CalendarDeleteOldEventsHour)); - long currentDeletionTime = GetWorldState(WorldStates.DailyCalendarDeletionOldEventsTime); + long currentDeletionTime = GetPersistentWorldVariable(NextOldCalendarEventDeletionTimeVarId); // If the reset time saved in the worldstate is before now it means the server was offline when the reset was supposed to occur. // In this case we set the reset time in the past and next world update will do the reset and schedule next one in the future. @@ -2161,12 +2164,12 @@ namespace Game m_NextCalendarOldEventsDeletionTime = nextDeletionTime; if (currentDeletionTime == 0) - SetWorldState(WorldStates.DailyCalendarDeletionOldEventsTime, (ulong)m_NextCalendarOldEventsDeletionTime); + SetPersistentWorldVariable(NextOldCalendarEventDeletionTimeVarId, (int)m_NextCalendarOldEventsDeletionTime); } void InitGuildResetTime() { - long gtime = GetWorldState(WorldStates.GuildDailyResetTime); + long gtime = GetPersistentWorldVariable(NextGuildDailyResetTimeVarId); if (gtime == 0) m_NextGuildReset = GameTime.GetGameTime(); // game time not yet init @@ -2180,12 +2183,12 @@ namespace Game m_NextGuildReset = gtime < curTime ? nextDayResetTime - Time.Day : nextDayResetTime; if (gtime == 0) - SetWorldState(WorldStates.GuildDailyResetTime, (ulong)m_NextGuildReset); + SetPersistentWorldVariable(NextGuildDailyResetTimeVarId, (int)m_NextGuildReset); } void InitCurrencyResetTime() { - long currencytime = GetWorldState(WorldStates.CurrencyResetTime); + long currencytime = GetPersistentWorldVariable(NextCurrencyResetTimeVarId); if (currencytime == 0) m_NextCurrencyReset = GameTime.GetGameTime(); // game time not yet init @@ -2202,7 +2205,7 @@ namespace Game m_NextCurrencyReset = currencytime < curTime ? nextWeekResetTime - WorldConfig.GetIntValue(WorldCfg.CurrencyResetInterval) * Time.Day : nextWeekResetTime; if (currencytime == 0) - SetWorldState(WorldStates.CurrencyResetTime, (ulong)m_NextCurrencyReset); + SetPersistentWorldVariable(NextCurrencyResetTimeVarId, (int)m_NextCurrencyReset); } void ResetCurrencyWeekCap() @@ -2214,7 +2217,7 @@ namespace Game session.GetPlayer().ResetCurrencyWeekCap(); m_NextCurrencyReset += Time.Day * WorldConfig.GetIntValue(WorldCfg.CurrencyResetInterval); - SetWorldState(WorldStates.CurrencyResetTime, (ulong)m_NextCurrencyReset); + SetPersistentWorldVariable(NextCurrencyResetTimeVarId, (int)m_NextCurrencyReset); } public void ResetEventSeasonalQuests(ushort event_id, long eventStartTime) @@ -2240,7 +2243,7 @@ namespace Game session.GetPlayer().SetRandomWinner(false); m_NextRandomBGReset += Time.Day; - SetWorldState(WorldStates.BgDailyResetTime, (ulong)m_NextRandomBGReset); + SetPersistentWorldVariable(NextBGRandomDailyResetTimeVarId, (int)m_NextRandomBGReset); } void CalendarDeleteOldEvents() @@ -2248,19 +2251,19 @@ namespace Game Log.outInfo(LogFilter.Misc, "Calendar deletion of old events."); m_NextCalendarOldEventsDeletionTime = m_NextCalendarOldEventsDeletionTime + Time.Day; - SetWorldState(WorldStates.DailyCalendarDeletionOldEventsTime, (ulong)m_NextCalendarOldEventsDeletionTime); + SetPersistentWorldVariable(NextOldCalendarEventDeletionTimeVarId, (int)m_NextCalendarOldEventsDeletionTime); Global.CalendarMgr.DeleteOldEvents(); } void ResetGuildCap() { m_NextGuildReset += Time.Day; - SetWorldState(WorldStates.GuildDailyResetTime, (ulong)m_NextGuildReset); - ulong week = GetWorldState(WorldStates.GuildWeeklyResetTime); + SetPersistentWorldVariable(NextGuildDailyResetTimeVarId, (int)m_NextGuildReset); + int week = GetPersistentWorldVariable(NextGuildWeeklyResetTimeVarId); week = week < 7 ? week + 1 : 1; Log.outInfo(LogFilter.Server, "Guild Daily Cap reset. Week: {0}", week == 1); - SetWorldState(WorldStates.GuildWeeklyResetTime, week); + SetPersistentWorldVariable(NextGuildWeeklyResetTimeVarId, week); Global.GuildMgr.ResetTimes(week == 1); } @@ -2306,66 +2309,35 @@ namespace Game return false; } - void LoadWorldStates() + public int GetPersistentWorldVariable(string var) + { + return m_worldVariables.LookupByKey(var); + } + + public void SetPersistentWorldVariable(string var, int value) + { + m_worldVariables[var] = value; + + PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.REP_WORLD_VARIABLE); + stmt.AddValue(0, var); + stmt.AddValue(1, value); + DB.Characters.Execute(stmt); + } + + void LoadPersistentWorldVariables() { uint oldMSTime = Time.GetMSTime(); - SQLResult result = DB.Characters.Query("SELECT entry, value FROM worldstates"); - - if (result.IsEmpty()) + SQLResult result = DB.Characters.Query("SELECT ID, Value FROM world_variable"); + if (!result.IsEmpty()) { - Log.outInfo(LogFilter.ServerLoading, "Loaded 0 world states. DB table `worldstates` is empty!"); - return; + do + { + m_worldVariables[result.Read(0)] = result.Read(1); + } while (result.NextRow()); } - uint count = 0; - do - { - m_worldstates[result.Read(0)] = result.Read(1); - ++count; - } - while (result.NextRow()); - - Log.outInfo(LogFilter.ServerLoading, "Loaded {0} world states in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); - } - - public void SetWorldState(WorldStates index, object value) - { - SetWorldState((uint)index, value); - } - - public void SetWorldState(uint index, object value) - { - PreparedStatement stmt; - - if (m_worldstates.ContainsKey(index)) - { - if (m_worldstates[index] == Convert.ToUInt32(value)) - return; - - stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_WORLDSTATE); - stmt.AddValue(0, Convert.ToUInt32(value)); - stmt.AddValue(1, index); - } - else - { - stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_WORLDSTATE); - - stmt.AddValue(0, index); - stmt.AddValue(1, Convert.ToUInt32(value)); - } - DB.Characters.Execute(stmt); - m_worldstates[index] = Convert.ToUInt32(value); - } - - public uint GetWorldState(WorldStates index) - { - return GetWorldState((uint)index); - } - - public uint GetWorldState(uint index) - { - return m_worldstates.LookupByKey(index); + Log.outInfo(LogFilter.ServerLoading, $"Loaded {m_worldVariables.Count} world variables in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); } void ProcessQueryCallbacks() @@ -2535,12 +2507,8 @@ namespace Game outnumberedFactionReward = 5; } - Global.WorldStateMgr.SetValue(WorldStates.WarModeHordeBuffValue, 10 + (dominantFaction == TeamId.Alliance ? outnumberedFactionReward : 0), false, null); - Global.WorldStateMgr.SetValue(WorldStates.WarModeAllianceBuffValue, 10 + (dominantFaction == TeamId.Horde ? outnumberedFactionReward : 0), false, null); - - // save to db - SetWorldState(WorldStates.WarModeHordeBuffValue, Global.WorldStateMgr.GetValue(WorldStates.WarModeHordeBuffValue, null)); - SetWorldState(WorldStates.WarModeAllianceBuffValue, Global.WorldStateMgr.GetValue(WorldStates.WarModeAllianceBuffValue, null)); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.WarModeHordeBuffValue, 10 + (dominantFaction == TeamId.Alliance ? outnumberedFactionReward : 0), false, null); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.WarModeAllianceBuffValue, 10 + (dominantFaction == TeamId.Horde ? outnumberedFactionReward : 0), false, null); } public uint GetVirtualRealmAddress() @@ -2571,7 +2539,7 @@ namespace Game public bool IsGuidWarning() { return _guidWarn; } public bool IsGuidAlert() { return _guidAlert; } - + public WorldUpdateTime GetWorldUpdateTime() { return _worldUpdateTime; } #region Fields @@ -2609,7 +2577,7 @@ namespace Game uint m_PlayerCount; uint m_MaxPlayerCount; - Dictionary m_worldstates = new(); + Dictionary m_worldVariables = new(); uint m_playerLimit; AccountTypes m_allowedSecurityLevel; Locale m_defaultDbcLocale; // from config for one from loaded DBC locales diff --git a/Source/Game/World/WorldStateManager.cs b/Source/Game/World/WorldStateManager.cs index 3ff607fe1..cbcb2ee96 100644 --- a/Source/Game/World/WorldStateManager.cs +++ b/Source/Game/World/WorldStateManager.cs @@ -136,6 +136,39 @@ namespace Game } while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, $"Loaded {_worldStateTemplates.Count} world state templates {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); + + oldMSTime = Time.GetMSTime(); + + result = DB.Characters.Query("SELECT Id, Value FROM world_state_value"); + uint savedValueCount = 0; + if (!result.IsEmpty()) + { + do + { + int worldStateId = result.Read(0); + WorldStateTemplate worldState = _worldStateTemplates.LookupByKey(worldStateId); + if (worldState == null) + { + Log.outError(LogFilter.Sql, $"Table `world_state_value` contains a value for unknown world state {worldStateId}, ignored"); + continue; + } + + int value = result.Read(1); + + if (!worldState.MapIds.Empty()) + { + foreach (uint mapId in worldState.MapIds) + _worldStatesByMap[mapId][worldStateId] = value; + } + else + _realmWorldStateValues[worldStateId] = value; + + ++savedValueCount; + } + while (result.NextRow()); + } + + Log.outInfo(LogFilter.ServerLoading, $"Loaded {savedValueCount} saved world state values {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); } public WorldStateTemplate GetWorldStateTemplate(int worldStateId) @@ -203,6 +236,28 @@ namespace Game map.SetWorldStateValue(worldStateId, value, hidden); } + public void SaveValueInDb(int worldStateId, int value) + { + if (GetWorldStateTemplate(worldStateId) == null) + return; + + PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.REP_WORLD_VARIABLE); + stmt.AddValue(0, worldStateId); + stmt.AddValue(1, value); + DB.Characters.Execute(stmt); + } + + public void SetValueAndSaveInDb(WorldStates worldStateId, int value, bool hidden, Map map) + { + SetValueAndSaveInDb((int)worldStateId, value, hidden, map); + } + + public void SetValueAndSaveInDb(int worldStateId, int value, bool hidden, Map map) + { + SetValue(worldStateId, value, hidden, map); + SaveValueInDb(worldStateId, value); + } + public Dictionary GetInitialWorldStatesForMap(Map map) { if (_worldStatesByMap.TryGetValue(map.GetId(), out Dictionary initialValues)) diff --git a/Source/Scripts/BattleField/WinterGrasp.cs b/Source/Scripts/BattleField/WinterGrasp.cs index 826f7f35b..74f890324 100644 --- a/Source/Scripts/BattleField/WinterGrasp.cs +++ b/Source/Scripts/BattleField/WinterGrasp.cs @@ -60,40 +60,26 @@ namespace Game.BattleFields m_vehicles[team] = new List(); } - m_saveTimer = 60000; - // Load from db - if ((Global.WorldMgr.GetWorldState(WorldStates.BattlefieldWgShowTimeNextBattle) == 0) && (Global.WorldMgr.GetWorldState(WorldStates.BattlefieldWgDefender) == 0) && (Global.WorldMgr.GetWorldState(WGConst.ClockWorldState[0]) == 0)) + if (Global.WorldStateMgr.GetValue(WorldStates.BattlefieldWgShowTimeNextBattle, m_Map) == 0 && Global.WorldStateMgr.GetValue(WGConst.ClockWorldState[0], m_Map) == 0) { - Global.WorldMgr.SetWorldState(WorldStates.BattlefieldWgShowTimeNextBattle, 0); - Global.WorldMgr.SetWorldState(WorldStates.BattlefieldWgDefender, RandomHelper.URand(0, 1)); - Global.WorldMgr.SetWorldState(WGConst.ClockWorldState[0], m_NoWarBattleTime); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.BattlefieldWgShowTimeNextBattle, 0, false, m_Map); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.BattlefieldWgDefender, RandomHelper.IRand(0, 1), false, m_Map); + Global.WorldStateMgr.SetValueAndSaveInDb(WGConst.ClockWorldState[0], (int)(GameTime.GetGameTime() + m_NoWarBattleTime / Time.InMilliseconds), false, m_Map); } - m_isActive = Global.WorldMgr.GetWorldState(WorldStates.BattlefieldWgShowTimeNextBattle) == 0; - m_DefenderTeam = Global.WorldMgr.GetWorldState(WorldStates.BattlefieldWgDefender); + m_isActive = Global.WorldStateMgr.GetValue(WorldStates.BattlefieldWgShowTimeNextBattle, m_Map) == 0; + m_DefenderTeam = (uint)Global.WorldStateMgr.GetValue(WorldStates.BattlefieldWgDefender, m_Map); - m_Timer = Global.WorldMgr.GetWorldState(WGConst.ClockWorldState[0]); + m_Timer = (uint)(Global.WorldStateMgr.GetValue(WGConst.ClockWorldState[0], m_Map) - GameTime.GetGameTime()); if (m_isActive) { m_isActive = false; m_Timer = m_RestartAfterCrash; } - void loadSavedWorldState(WorldStates id) - { - Global.WorldStateMgr.SetValue(id, (int)Global.WorldMgr.GetWorldState(id), false, m_Map); - } - - loadSavedWorldState(WorldStates.BattlefieldWgShowTimeNextBattle); - loadSavedWorldState(WorldStates.BattlefieldWgDefender); Global.WorldStateMgr.SetValue(WorldStates.BattlefieldWgAttacker, (int)GetAttackerTeam(), false, m_Map); - Global.WorldStateMgr.SetValue(WGConst.ClockWorldState[0], (int)(GameTime.GetGameTime() + m_Timer / Time.InMilliseconds), false, m_Map); Global.WorldStateMgr.SetValue(WGConst.ClockWorldState[1], (int)(GameTime.GetGameTime() + m_Timer / Time.InMilliseconds), false, m_Map); - loadSavedWorldState(WorldStates.BattlefieldWgAttackedA); - loadSavedWorldState(WorldStates.BattlefieldWgDefendedA); - loadSavedWorldState(WorldStates.BattlefieldWgAttackedH); - loadSavedWorldState(WorldStates.BattlefieldWgDefendedH); foreach (var gy in WGConst.WGGraveYard) { @@ -170,31 +156,6 @@ namespace Game.BattleFields return true; } - public override bool Update(uint diff) - { - bool m_return = base.Update(diff); - if (m_saveTimer <= diff) - { - void saveWorldState(WorldStates id) - { - Global.WorldMgr.SetWorldState(id, Global.WorldStateMgr.GetValue((int)id, m_Map)); - } - - Global.WorldMgr.SetWorldState(WorldStates.BattlefieldWgShowTimeNextBattle, !m_isActive); - Global.WorldMgr.SetWorldState(WorldStates.BattlefieldWgDefender, m_DefenderTeam); - Global.WorldMgr.SetWorldState(WGConst.ClockWorldState[0], m_Timer); - saveWorldState(WorldStates.BattlefieldWgAttackedA); - saveWorldState(WorldStates.BattlefieldWgDefendedA); - saveWorldState(WorldStates.BattlefieldWgAttackedH); - saveWorldState(WorldStates.BattlefieldWgDefendedH); - m_saveTimer = 60 * Time.InMilliseconds; - } - else - m_saveTimer -= diff; - - return m_return; - } - public override void OnBattleStart() { // Spawn titan relic @@ -211,10 +172,10 @@ namespace Game.BattleFields Log.outError(LogFilter.Battlefield, "WG: Failed to spawn titan relic."); Global.WorldStateMgr.SetValue(WorldStates.BattlefieldWgAttacker, (int)GetAttackerTeam(), false, m_Map); - Global.WorldStateMgr.SetValue(WorldStates.BattlefieldWgDefender, (int)GetDefenderTeam(), false, m_Map); - Global.WorldStateMgr.SetValue(WorldStates.BattlefieldWgShowTimeNextBattle, 0, false, m_Map); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.BattlefieldWgDefender, (int)GetDefenderTeam(), false, m_Map); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.BattlefieldWgShowTimeNextBattle, 0, false, m_Map); Global.WorldStateMgr.SetValue(WorldStates.BattlefieldWgShowTimeBattleEnd, 1, false, m_Map); - Global.WorldStateMgr.SetValue(WGConst.ClockWorldState[0], (int)(GameTime.GetGameTime() + m_Timer / Time.InMilliseconds), false, m_Map); + Global.WorldStateMgr.SetValueAndSaveInDb(WGConst.ClockWorldState[0], (int)(GameTime.GetGameTime() + m_Timer / Time.InMilliseconds), false, m_Map); // Update tower visibility and update faction foreach (var guid in CanonList) @@ -316,10 +277,11 @@ namespace Game.BattleFields else worldStateId = GetDefenderTeam() == TeamId.Horde ? WorldStates.BattlefieldWgAttackedH : WorldStates.BattlefieldWgAttackedA; - Global.WorldStateMgr.SetValue(worldStateId, Global.WorldStateMgr.GetValue((int)worldStateId, m_Map) + 1, false, m_Map); + Global.WorldStateMgr.SetValueAndSaveInDb(worldStateId, Global.WorldStateMgr.GetValue((int)worldStateId, m_Map) + 1, false, m_Map); } - Global.WorldStateMgr.SetValue(WorldStates.BattlefieldWgShowTimeNextBattle, 1, false, m_Map); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.BattlefieldWgDefender, (int)GetDefenderTeam(), false, m_Map); + Global.WorldStateMgr.SetValueAndSaveInDb(WorldStates.BattlefieldWgShowTimeNextBattle, 1, false, m_Map); Global.WorldStateMgr.SetValue(WorldStates.BattlefieldWgShowTimeBattleEnd, 0, false, m_Map); Global.WorldStateMgr.SetValue(WGConst.ClockWorldState[1], (int)(GameTime.GetGameTime() + m_Timer / Time.InMilliseconds), false, m_Map); @@ -358,12 +320,6 @@ namespace Game.BattleFields portal.SetRespawnTime((int)BattlegroundConst.RespawnOneDay); } - // Saving data - foreach (var obj in BuildingsInZone) - obj.Save(); - foreach (var workShop in Workshops) - workShop.Save(); - foreach (var guid in m_PlayersInWar[GetDefenderTeam()]) { Player player = Global.ObjAccessor.FindPlayer(guid); @@ -1023,7 +979,6 @@ namespace Game.BattleFields int m_tenacityTeam; uint m_tenacityStack; - uint m_saveTimer; ObjectGuid m_titansRelicGUID; } @@ -1080,7 +1035,7 @@ namespace Game.BattleFields // Update worldstate _state = WGGameObjectState.AllianceIntact - ((int)_teamControl * 3); - Global.WorldStateMgr.SetValue(_worldState, (int)_state, false, _wg.GetMap()); + Global.WorldStateMgr.SetValueAndSaveInDb((int)_worldState, (int)_state, false, _wg.GetMap()); } UpdateCreatureAndGo(); build.SetFaction(WGConst.WintergraspFaction[_teamControl]); @@ -1106,7 +1061,7 @@ namespace Game.BattleFields { // Update worldstate _state = WGGameObjectState.AllianceDamage - ((int)_teamControl * 3); - Global.WorldStateMgr.SetValue(_worldState, (int)_state, false, _wg.GetMap()); + Global.WorldStateMgr.SetValueAndSaveInDb((int)_worldState, (int)_state, false, _wg.GetMap()); // Send warning message if (_staticTowerInfo != null) // tower damage + name @@ -1137,7 +1092,7 @@ namespace Game.BattleFields { // Update worldstate _state = WGGameObjectState.AllianceDestroy - ((int)_teamControl * 3); - Global.WorldStateMgr.SetValue(_worldState, (int)_state, false, _wg.GetMap()); + Global.WorldStateMgr.SetValueAndSaveInDb((int)_worldState, (int)_state, false, _wg.GetMap()); // Warn players if (_staticTowerInfo != null) @@ -1193,8 +1148,7 @@ namespace Game.BattleFields break; } - _state = (WGGameObjectState)Global.WorldMgr.GetWorldState(_worldState); - Global.WorldStateMgr.SetValue(_worldState, (int)_state, false, _wg.GetMap()); + _state = (WGGameObjectState)Global.WorldStateMgr.GetValue((int)_worldState, _wg.GetMap()); switch (_state) { case WGGameObjectState.NeutralIntact: @@ -1442,11 +1396,6 @@ namespace Game.BattleFields } } - public void Save() - { - Global.WorldMgr.SetWorldState(_worldState, (ulong)_state); - } - public ObjectGuid GetGUID() { return _buildGUID; } // WG object @@ -1505,7 +1454,7 @@ namespace Game.BattleFields { // Updating worldstate _state = WGGameObjectState.AllianceIntact; - Global.WorldStateMgr.SetValue(_staticInfo.WorldStateId, (int)_state, false, _wg.GetMap()); + Global.WorldStateMgr.SetValueAndSaveInDb(_staticInfo.WorldStateId, (int)_state, false, _wg.GetMap()); // Warning message if (!init) @@ -1525,7 +1474,7 @@ namespace Game.BattleFields { // Update worldstate _state = WGGameObjectState.HordeIntact; - Global.WorldStateMgr.SetValue(_staticInfo.WorldStateId, (int)_state, false, _wg.GetMap()); + Global.WorldStateMgr.SetValueAndSaveInDb(_staticInfo.WorldStateId, (int)_state, false, _wg.GetMap()); // Warning message if (!init) @@ -1556,11 +1505,6 @@ namespace Game.BattleFields GiveControlTo(_wg.GetDefenderTeam(), true); } - public void Save() - { - Global.WorldMgr.SetWorldState(_staticInfo.WorldStateId, (uint)_state); - } - public uint GetTeamControl() { return _teamControl; } BattlefieldWG _wg; // Pointer to wintergrasp diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 109c9f9e2..0358dfb89 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -3672,7 +3672,8 @@ INSERT INTO `updates` VALUES ('2022_03_06_00_characters.sql','474AAF9D03E6A56017899C968DC9875368301934','ARCHIVED','2022-03-06 15:12:24',0), ('2022_03_11_00_characters_2021_07_18_00_characters.sql','0BA579ED21F4E75AC2B4797421B5029568B3F6E2','RELEASED','2022-03-11 18:56:07',0), ('2022_06_01_00_characters.sql','582AC6E256F8365F83AB70BA165CCC8B218E19FF','RELEASED','2022-06-01 21:16:56',0), -('2022_07_03_00_characters.sql','D3F04078C0846BCF7C8330AC20C39B8C3AEE7002','RELEASED','2022-07-03 23:37:24',0); +('2022_07_03_00_characters.sql','D3F04078C0846BCF7C8330AC20C39B8C3AEE7002','RELEASED','2022-07-03 23:37:24',0), +('2022_07_14_00_characters.sql','2EAD57D77FC39F6678F2D2A7D9C24046E6B836D8','RELEASED','2022-07-14 21:44:35',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; @@ -3730,35 +3731,59 @@ LOCK TABLES `warden_action` WRITE; UNLOCK TABLES; -- --- Table structure for table `worldstates` +-- Table structure for table `world_state_value` -- -DROP TABLE IF EXISTS `worldstates`; +DROP TABLE IF EXISTS `world_state_value`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; -CREATE TABLE `worldstates` ( - `entry` int unsigned NOT NULL DEFAULT '0', - `value` int unsigned NOT NULL DEFAULT '0', - `comment` tinytext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci, - PRIMARY KEY (`entry`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Variable Saves'; +CREATE TABLE `world_state_value` ( + `Id` int NOT NULL, + `Value` int NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- --- Dumping data for table `worldstates` +-- Dumping data for table `world_state_value` -- -LOCK TABLES `worldstates` WRITE; -/*!40000 ALTER TABLE `worldstates` DISABLE KEYS */; -INSERT INTO `worldstates` VALUES -(20001,0,'NextArenaPointDistributionTime'), -(20002,0,'NextWeeklyQuestResetTime'), -(20003,0,'NextBGRandomDailyResetTime'), -(20004,0,'cleaning_flags'), -(20006,0,'NextGuildDailyResetTime'), -(20007,0,'NextMonthlyQuestResetTime'), -(20008,0,'NextDailyQuestResetTime'); -/*!40000 ALTER TABLE `worldstates` ENABLE KEYS */; +LOCK TABLES `world_state_value` WRITE; +/*!40000 ALTER TABLE `world_state_value` DISABLE KEYS */; +/*!40000 ALTER TABLE `world_state_value` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `world_variable` +-- + +DROP TABLE IF EXISTS `world_variable`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `world_variable` ( + `ID` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `Value` int NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `world_variable` +-- + +LOCK TABLES `world_variable` WRITE; +/*!40000 ALTER TABLE `world_variable` DISABLE KEYS */; +INSERT INTO `world_variable` VALUES +('NextCurrencyResetTime',0), +('NextWeeklyQuestResetTime',0), +('NextBGRandomDailyResetTime',0), +('PersistentCharacterCleanFlags',0), +('NextGuildDailyResetTime',0), +('NextMonthlyQuestResetTime',0), +('NextDailyQuestResetTime',0), +('NextOldCalendarEventDeletionTime',0), +('NextGuildWeeklyResetTime',0); +/*!40000 ALTER TABLE `world_variable` ENABLE KEYS */; UNLOCK TABLES; -- diff --git a/sql/updates/characters/master/2022_07_14_00_characters.sql b/sql/updates/characters/master/2022_07_14_00_characters.sql new file mode 100644 index 000000000..078ce489d --- /dev/null +++ b/sql/updates/characters/master/2022_07_14_00_characters.sql @@ -0,0 +1,33 @@ +-- +-- Table structure for table `world_state_value` +-- +DROP TABLE IF EXISTS `world_state_value`; +CREATE TABLE `world_state_value` ( + `Id` int NOT NULL, + `Value` int NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- +-- Table structure for table `world_state_value` +-- +DROP TABLE IF EXISTS `world_variable`; +CREATE TABLE `world_variable` ( + `ID` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL, + `Value` int NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +INSERT INTO `world_state_value` SELECT `entry`, `value` FROM `worldstates` WHERE `entry` NOT BETWEEN 20001 AND 20009 AND `entry` <> 20050; + +INSERT INTO `world_variable` SELECT 'NextCurrencyResetTime', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20001; +INSERT INTO `world_variable` SELECT 'NextWeeklyQuestResetTime', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20002; +INSERT INTO `world_variable` SELECT 'NextBGRandomDailyResetTime', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20003; +INSERT INTO `world_variable` SELECT 'PersistentCharacterCleanFlags', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20004; +INSERT INTO `world_variable` SELECT 'NextGuildDailyResetTime', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20006; +INSERT INTO `world_variable` SELECT 'NextMonthlyQuestResetTime', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20007; +INSERT INTO `world_variable` SELECT 'NextDailyQuestResetTime', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20008; +INSERT INTO `world_variable` SELECT 'NextOldCalendarEventDeletionTime', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20009; +INSERT INTO `world_variable` SELECT 'NextGuildWeeklyResetTime', ws.`value` FROM `worldstates` ws WHERE ws.entry = 20050; + +DROP TABLE `worldstates`;