diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 7fdbb4f19..fb56b2610 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -66,7 +66,6 @@ #include "QueryHolder.h" #include "ReputationMgr.h" #include "Realm.h" -#include "SavingSystem.h" #include "ScriptMgr.h" #include "SocialMgr.h" #include "Spell.h" @@ -192,7 +191,6 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this) m_needZoneUpdate = false; - m_nextSave = SavingSystemMgr::IncreaseSavingMaxValue(1); m_additionalSaveTimer = 0; m_additionalSaveMask = 0; m_hostileReferenceCheckTimer = 15000; diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp index bfec5dc78..7f64681ed 100644 --- a/src/server/game/Entities/Player/PlayerStorage.cpp +++ b/src/server/game/Entities/Player/PlayerStorage.cpp @@ -58,7 +58,6 @@ #include "QueryHolder.h" #include "QuestDef.h" #include "ReputationMgr.h" -#include "SavingSystem.h" #include "ScriptMgr.h" #include "SocialMgr.h" #include "Spell.h" @@ -7176,16 +7175,6 @@ void Player::SaveToDB(CharacterDatabaseTransaction trans, bool create, bool logo // save pet (hunter pet level and experience and all type pets health/mana). if (Pet* pet = GetPet()) pet->SavePetToDB(PET_SAVE_AS_CURRENT, logout); - - // our: saving system - if (!create && !logout) - { - // pussywizard: if it was not yet our time to save, be we are saved (additional save after important changes) - // pussywizard: then free our original ticket in saving queue, so saving is fluent with no gaps - SavingSystemMgr::InsertToSavingSkipListIfNeeded(m_nextSave); - - m_nextSave = SavingSystemMgr::IncreaseSavingMaxValue(1); - } } // fast save function for item/money cheating preventing - save only inventory and money state diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp index 6e129e946..bbf0383bd 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -28,7 +28,6 @@ #include "OutdoorPvPMgr.h" #include "Pet.h" #include "Player.h" -#include "SavingSystem.h" #include "ScriptMgr.h" #include "SkillDiscovery.h" #include "SpellAuraEffects.h" @@ -316,35 +315,18 @@ void Player::Update(uint32 p_time) if (m_deathState == JUST_DIED) KillPlayer(); - if (m_nextSave <= SavingSystemMgr::GetSavingCurrentValue() && - !GetSession()->isLogingOut()) - SaveToDB(false, false); - else if (m_additionalSaveTimer && !GetSession()->isLogingOut()) // pussywizard: + if (m_nextSave) { - if (m_additionalSaveTimer <= p_time) + if (p_time >= m_nextSave) { - CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); - - if (m_additionalSaveMask & ADDITIONAL_SAVING_INVENTORY_AND_GOLD) - SaveInventoryAndGoldToDB(trans); - if (m_additionalSaveMask & ADDITIONAL_SAVING_QUEST_STATUS) - { - _SaveQuestStatus(trans); - - // xinef: if nothing changed, nothing will happen - _SaveDailyQuestStatus(trans); - _SaveWeeklyQuestStatus(trans); - _SaveSeasonalQuestStatus(trans); - _SaveMonthlyQuestStatus(trans); - } - - CharacterDatabase.CommitTransaction(trans); - - m_additionalSaveTimer = 0; - m_additionalSaveMask = 0; + // m_nextSave reset in SaveToDB call + SaveToDB(false, false); + FMT_LOG_DEBUG("entities.player", "Player::Update: Player '{}' ({}) saved", GetName(), GetGUID().ToString()); } else - m_additionalSaveTimer -= p_time; + { + m_nextSave -= p_time; + } } // Handle Water/drowning diff --git a/src/server/game/Misc/SavingSystem.cpp b/src/server/game/Misc/SavingSystem.cpp deleted file mode 100644 index f59fa4368..000000000 --- a/src/server/game/Misc/SavingSystem.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of the AzerothCore 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 Affero General Public License as published by the - * Free Software Foundation; either version 3 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 Affero 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 . - */ - -#include "SavingSystem.h" -#include "World.h" - -uint32 SavingSystemMgr::m_savingCurrentValue = 0; -uint32 SavingSystemMgr::m_savingMaxValueAssigned = 0; -uint32 SavingSystemMgr::m_savingDiffSum = 0; -std::list SavingSystemMgr::m_savingSkipList; -std::mutex SavingSystemMgr::_savingLock; - -void SavingSystemMgr::Update(uint32 diff) -{ - if (GetSavingMaxValue() > GetSavingCurrentValue()) - { - const uint32 step = 120; - - float multiplicator; - uint32 playerCount = sWorld->GetPlayerCount(); - if (!playerCount) - { - m_savingCurrentValue = 0; - m_savingMaxValueAssigned = 0; - m_savingDiffSum = 0; - m_savingSkipList.clear(); - return; - } - - if (GetSavingMaxValue() - GetSavingCurrentValue() > playerCount + m_savingSkipList.size()) // this should not happen, but just in case - m_savingMaxValueAssigned = m_savingCurrentValue + playerCount + m_savingSkipList.size(); - - if (playerCount <= 1500) // every 2min - multiplicator = 1000.0f / playerCount; - else if (playerCount <= 2500) // every 3min - multiplicator = 1500.0f / playerCount; - else if (playerCount <= 2750) // every 4min - multiplicator = 2000.0f / playerCount; - else if (playerCount <= 3000) // every 6min - multiplicator = 3000.0f / playerCount; - else if (playerCount <= 3250) // every 7min - multiplicator = 3500.0f / playerCount; - else // every 8min - multiplicator = 4000.0f / playerCount; - - m_savingDiffSum += diff; - while (m_savingDiffSum >= (uint32)(step * multiplicator)) - { - IncreaseSavingCurrentValue(1); - - while (m_savingSkipList.size() && *(m_savingSkipList.begin()) <= GetSavingCurrentValue()) - { - IncreaseSavingCurrentValue(1); - m_savingSkipList.pop_front(); - } - - m_savingDiffSum -= (uint32)(step * multiplicator); - - if (GetSavingCurrentValue() > GetSavingMaxValue()) - { - m_savingDiffSum = 0; - break; - } - - if (m_savingDiffSum > 60000) - m_savingDiffSum = 60000; - } - } -} diff --git a/src/server/game/Misc/SavingSystem.h b/src/server/game/Misc/SavingSystem.h deleted file mode 100644 index 4da8d5047..000000000 --- a/src/server/game/Misc/SavingSystem.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * This file is part of the AzerothCore 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 Affero General Public License as published by the - * Free Software Foundation; either version 3 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 Affero 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 . - */ - -#ifndef __SAVINGSYSTEM_H -#define __SAVINGSYSTEM_H - -#include "Common.h" -#include -#include - -// to evenly distribute saving players to db - -class SavingSystemMgr -{ -public: - static void Update(uint32 diff); - - static uint32 GetSavingCurrentValue() { return m_savingCurrentValue; } // modified only during single thread - static uint32 GetSavingMaxValue() { return m_savingMaxValueAssigned; } // modified only during single thread - static void IncreaseSavingCurrentValue(uint32 inc) { m_savingCurrentValue += inc; } // used and modified only during single thread - static uint32 IncreaseSavingMaxValue(uint32 inc) { std::lock_guard guard(_savingLock); return (m_savingMaxValueAssigned += inc); } - static void InsertToSavingSkipListIfNeeded(uint32 id) { if (id > m_savingCurrentValue) { std::lock_guard guard(_savingLock); m_savingSkipList.push_back(id); } } - -protected: - static uint32 m_savingCurrentValue; - static uint32 m_savingMaxValueAssigned; - static uint32 m_savingDiffSum; - static std::list m_savingSkipList; - static std::mutex _savingLock; -}; - -#endif diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index dade8e205..45fc8cc0e 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -39,7 +39,6 @@ #include "Pet.h" #include "Player.h" #include "QueryHolder.h" -#include "SavingSystem.h" #include "ScriptMgr.h" #include "SocialMgr.h" #include "Transport.h" @@ -632,7 +631,6 @@ void WorldSession::LogoutPlayer(bool save) ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) - SavingSystemMgr::InsertToSavingSkipListIfNeeded(_player->GetNextSave()); // pussywizard if (save) { uint32 eslot; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 89c74d603..80a24c951 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -68,7 +68,6 @@ #include "Player.h" #include "PoolMgr.h" #include "Realm.h" -#include "SavingSystem.h" #include "ScriptMgr.h" #include "ServerMotd.h" #include "SkillDiscovery.h" @@ -89,9 +88,15 @@ #include "WhoListCacheMgr.h" #include "WorldPacket.h" #include "WorldSession.h" +#include "TaskScheduler.h" #include #include +namespace +{ + TaskScheduler playersSaveScheduler; +} + std::atomic_long World::m_stopEvent = false; uint8 World::m_ExitCode = SHUTDOWN_EXIT_CODE; uint32 World::m_worldLoopCounter = 0; @@ -2453,8 +2458,8 @@ void World::Update(uint32 diff) } { - METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update saving system")); - SavingSystemMgr::Update(diff); + METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update playersSaveScheduler")); + playersSaveScheduler.Update(diff); } { @@ -2705,6 +2710,33 @@ void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode, const std: m_ShutdownMask = options; m_ExitCode = exitcode; + auto const& playersOnline = GetActiveSessionCount(); + + if (time < 5 && playersOnline) + { + // Set time to 5s for save all players + time = 5; + } + + playersSaveScheduler.CancelAll(); + + if (time >= 5) + { + playersSaveScheduler.Schedule(Seconds(time - 5), [this](TaskContext /*context*/) + { + if (!GetActiveSessionCount()) + { + LOG_INFO("server", "> No players online. Skip save before shutdown"); + return; + } + + LOG_INFO("server", "> Save players before shutdown server"); + ObjectAccessor::SaveAllPlayers(); + }); + } + + FMT_LOG_WARN("server", "Time left until shutdown/restart: {}", time); + ///- If the shutdown time is 0, set m_stopEvent (except if shutdown is 'idle' with remaining sessions) if (time == 0) {