diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 252b1b78a..91043ffe1 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -715,6 +715,8 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this) m_zoneUpdateId = uint32(-1); m_zoneUpdateTimer = 0; + m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE); + m_areaUpdateId = 0; m_team = TEAM_NEUTRAL; @@ -18116,6 +18118,10 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder) // since last logout (in seconds) uint32 time_diff = uint32(now - logoutTime); //uint64 is excessive for a time_diff in seconds.. uint32 allows for 136~ year difference. + // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE] + // this must help in case next save after mass player load after server startup + m_nextSave = urand(m_nextSave / 2, m_nextSave * 3 / 2); + // set value, including drunk invisibility detection // calculate sobering. after 15 minutes logged out, the player will be sober again uint8 newDrunkValue = 0; @@ -19657,6 +19663,9 @@ bool Player::_LoadHomeBind(PreparedQueryResult result) void Player::SaveToDB(bool create, bool logout) { + // delay auto save at any saves (manual, in code, or autosave) + m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE); + //lets allow only players in world to be saved if (IsBeingTeleportedFar()) { diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index c50c4cdd9..b1442bbef 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2391,8 +2391,8 @@ class Player : public Unit, public GridObject void StopCastingCharm(); void StopCastingBindSight(); - //uint32 GetSaveTimer() const { return m_nextSave; } - //void SetSaveTimer(uint32 timer) { m_nextSave = timer; } + uint32 GetSaveTimer() const { return m_nextSave; } + void SetSaveTimer(uint32 timer) { m_nextSave = timer; } // Recall position uint32 m_recallMap; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index a29e432e5..7960a51d1 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -647,6 +647,7 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_ALLOW_PLAYER_COMMANDS] = sConfigMgr->GetBoolDefault("AllowPlayerCommands", 1); m_bool_configs[CONFIG_PRESERVE_CUSTOM_CHANNELS] = sConfigMgr->GetBoolDefault("PreserveCustomChannels", false); m_int_configs[CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION] = sConfigMgr->GetIntDefault("PreserveCustomChannelDuration", 14); + m_int_configs[CONFIG_INTERVAL_SAVE] = sConfigMgr->GetIntDefault("PlayerSaveInterval", 15 * MINUTE * IN_MILLISECONDS); m_int_configs[CONFIG_INTERVAL_DISCONNECT_TOLERANCE] = sConfigMgr->GetIntDefault("DisconnectToleranceInterval", 0); m_bool_configs[CONFIG_STATS_SAVE_ONLY_ON_LOGOUT] = sConfigMgr->GetBoolDefault("PlayerSave.Stats.SaveOnlyOnLogout", true); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 1397f050b..7c20db50e 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -205,6 +205,7 @@ enum WorldIntConfigs CONFIG_INTERVAL_MAPUPDATE, CONFIG_INTERVAL_CHANGEWEATHER, CONFIG_INTERVAL_DISCONNECT_TOLERANCE, + CONFIG_INTERVAL_SAVE, CONFIG_PORT_WORLD, CONFIG_SOCKET_TIMEOUTTIME, CONFIG_SESSION_ADD_DELAY, diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index a7aa2cd80..71b858ac9 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1085,9 +1085,32 @@ public: return true; } - static bool HandleSaveCommand(ChatHandler* /*handler*/, char const* /*args*/) + static bool HandleSaveCommand(ChatHandler* handler, char const* /*args*/) { - // pussywizard: fully disabled on 28.12.2011, but disabled it "silently" + Player* player = handler->GetSession()->GetPlayer(); + + // save GM account without delay and output message + if (handler->GetSession()->GetSecurity() >= SEC_GAMEMASTER) + { + if (Player* target = handler->getSelectedPlayer()) + { + target->SaveToDB(true, false); + } + else + { + player->SaveToDB(true, false); + } + handler->SendSysMessage(LANG_PLAYER_SAVED); + return true; + } + + // save if the player has last been saved over 20 seconds ago + uint32 saveInterval = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE); + if (saveInterval == 0 || (saveInterval > 20 * IN_MILLISECONDS && player->GetSaveTimer() <= saveInterval - 20 * IN_MILLISECONDS)) + { + player->SaveToDB(true, false); + } + return true; }