Skip to content

Commit 7950aed

Browse files
authored
Merge 7e93ed8 into 0933ac2
2 parents 0933ac2 + 7e93ed8 commit 7950aed

7 files changed

Lines changed: 667 additions & 57 deletions

File tree

src/game/WorldHandlers/World.cpp

Lines changed: 251 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,11 @@
8888
#include "LFGMgr.h"
8989
#include "DisableMgr.h"
9090
#include "Language.h"
91-
#include "CommandMgr.h"
92-
#include "GitRevision.h"
93-
#include "UpdateTime.h"
94-
#include "GameTime.h"
91+
#include "CommandMgr.h"
92+
#include "GitRevision.h"
93+
#include "UpdateTime.h"
94+
#include "GameTime.h"
95+
#include "ScheduledExit.h"
9596

9697
#ifdef ENABLE_ELUNA
9798
#include "LuaEngine.h"
@@ -108,8 +109,8 @@
108109
// WARDEN
109110
#include "WardenCheckMgr.h"
110111

111-
#include <iostream>
112-
#include <sstream>
112+
#include <iostream>
113+
#include <sstream>
113114

114115
INSTANTIATE_SINGLETON_1(World);
115116

@@ -157,8 +158,10 @@ World::World()
157158
m_startTime = m_gameTime;
158159
m_maxActiveSessionCount = 0;
159160
m_maxQueuedSessionCount = 0;
160-
m_MaintenanceTimeChecker = 0;
161-
m_broadcastEnable = false;
161+
m_MaintenanceTimeChecker = 0;
162+
m_scheduledExitDelay = 0;
163+
m_scheduledExitCountdownActive = false;
164+
m_broadcastEnable = false;
162165
m_broadcastList.clear();
163166
m_broadcastWeight = 0;
164167

@@ -578,7 +581,7 @@ void World::LoadConfigSettings(bool reload)
578581
setConfig(CONFIG_UINT32_MAX_WHOLIST_RETURNS, "MaxWhoListReturns", 49);
579582
setConfig(CONFIG_UINT32_AUTOBROADCAST_INTERVAL, "AutoBroadcast", 600);
580583

581-
if (getConfig(CONFIG_UINT32_AUTOBROADCAST_INTERVAL) > 0)
584+
if (getConfig(CONFIG_UINT32_AUTOBROADCAST_INTERVAL) > 0)
582585
{
583586
m_broadcastEnable = true;
584587
}
@@ -590,9 +593,11 @@ void World::LoadConfigSettings(bool reload)
590593
if (reload && m_broadcastEnable)
591594
{
592595
m_broadcastTimer.SetInterval(getConfig(CONFIG_UINT32_AUTOBROADCAST_INTERVAL) * IN_MILLISECONDS);
593-
}
594-
595-
std::string forceLoadGridOnMaps = sConfig.GetStringDefault("LoadAllGridsOnMaps", "");
596+
}
597+
598+
LoadScheduledExitConfig();
599+
600+
std::string forceLoadGridOnMaps = sConfig.GetStringDefault("LoadAllGridsOnMaps", "");
596601
if (!forceLoadGridOnMaps.empty())
597602
{
598603
unsigned int pos = 0;
@@ -2182,7 +2187,7 @@ void World::_UpdateGameTime()
21822187
m_gameTime = thisTime;
21832188

21842189
///- if there is a shutdown timer
2185-
if (!m_stopEvent && m_ShutdownTimer > 0 && elapsed > 0)
2190+
if (!m_stopEvent && m_ShutdownTimer > 0 && elapsed > 0)
21862191
{
21872192
///- ... and it is overdue, stop the world (set m_stopEvent)
21882193
if (m_ShutdownTimer <= elapsed)
@@ -2197,17 +2202,30 @@ void World::_UpdateGameTime()
21972202
} // minimum timer value to wait idle state
21982203
}
21992204
///- ... else decrease it and if necessary display a shutdown countdown to the users
2200-
else
2201-
{
2202-
m_ShutdownTimer -= elapsed;
2203-
2204-
ShutdownMsg();
2205-
}
2206-
}
2207-
}
2205+
else
2206+
{
2207+
m_ShutdownTimer -= elapsed;
2208+
2209+
MaNGOS::ScheduledExitCountdownActions actions =
2210+
MaNGOS::GetScheduledExitCountdownActions(
2211+
m_scheduledExitCountdownActive);
2212+
if (actions.sendShutdownTimer)
2213+
{
2214+
ShutdownMsg();
2215+
}
2216+
2217+
if (actions.sendConfiguredWarnings)
2218+
{
2219+
SendScheduledExitWarnings();
2220+
}
2221+
}
2222+
}
2223+
2224+
CheckScheduledExit();
2225+
}
22082226

22092227
/// Shutdown the server
2210-
void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode)
2228+
void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode)
22112229
{
22122230
// ignore if server shutdown at next tick
22132231
if (m_stopEvent)
@@ -2235,8 +2253,8 @@ void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode)
22352253
else
22362254
{
22372255
m_ShutdownTimer = time;
2238-
ShutdownMsg(true);
2239-
}
2256+
ShutdownMsg(true);
2257+
}
22402258

22412259
#ifdef ENABLE_PLAYERBOTS
22422260
sRandomPlayerbotMgr.LogoutAllBots();
@@ -2249,14 +2267,210 @@ void World::ShutdownServ(uint32 time, uint32 options, uint8 exitcode)
22492267
e->OnShutdownInitiate(ShutdownExitCode(exitcode), ShutdownMask(options));
22502268
}
22512269
#endif /* ENABLE_ELUNA */
2252-
}
2253-
2254-
/// Display a shutdown message to the user(s)
2255-
void World::ShutdownMsg(bool show /*= false*/, Player* player /*= NULL*/)
2256-
{
2257-
// not show messages for idle shutdown mode
2258-
if (m_ShutdownMask & SHUTDOWN_MASK_IDLE)
2259-
{
2270+
}
2271+
2272+
void World::LoadScheduledExitConfig()
2273+
{
2274+
m_scheduledExit = MaNGOS::ScheduledExitSchedule();
2275+
m_scheduledExitDelay = 0;
2276+
m_scheduledExitWarnings.clear();
2277+
m_scheduledExitCountdownActive = false;
2278+
2279+
if (!sConfig.GetBoolDefault("ScheduledExit.Enable", false))
2280+
{
2281+
sLog.outString("ScheduledExit: disabled");
2282+
return;
2283+
}
2284+
2285+
std::string dayText = sConfig.GetStringDefault("ScheduledExit.DayOfWeek", "3");
2286+
uint32 dayOfWeek = 0;
2287+
if (!MaNGOS::ParseScheduledExitUInt32(dayText, dayOfWeek) || dayOfWeek > 6)
2288+
{
2289+
sLog.outError("ScheduledExit: invalid ScheduledExit.DayOfWeek '%s'; "
2290+
"disabling scheduled exit", dayText.c_str());
2291+
return;
2292+
}
2293+
2294+
std::string timeText = sConfig.GetStringDefault("ScheduledExit.Time", "05:00");
2295+
uint32 hour = 0;
2296+
uint32 minute = 0;
2297+
if (!MaNGOS::ParseScheduledExitTime(timeText, hour, minute))
2298+
{
2299+
sLog.outError("ScheduledExit: invalid ScheduledExit.Time '%s'; "
2300+
"disabling scheduled exit", timeText.c_str());
2301+
return;
2302+
}
2303+
2304+
std::string modeText = sConfig.GetStringDefault("ScheduledExit.Mode", "restart");
2305+
MaNGOS::ScheduledExitMode mode = MaNGOS::SCHEDULED_EXIT_MODE_RESTART;
2306+
if (!MaNGOS::ParseScheduledExitMode(modeText, mode))
2307+
{
2308+
sLog.outError("ScheduledExit: invalid ScheduledExit.Mode '%s'; "
2309+
"disabling scheduled exit", modeText.c_str());
2310+
return;
2311+
}
2312+
2313+
std::string delayText = sConfig.GetStringDefault("ScheduledExit.Delay", "900");
2314+
uint32 delay = 0;
2315+
if (!MaNGOS::ParseScheduledExitUInt32(delayText, delay))
2316+
{
2317+
sLog.outError("ScheduledExit: invalid ScheduledExit.Delay '%s'; "
2318+
"disabling scheduled exit", delayText.c_str());
2319+
return;
2320+
}
2321+
2322+
std::vector<std::string> warningErrors;
2323+
std::vector<uint32> warningTimes = MaNGOS::ParseScheduledExitWarningTimes(
2324+
sConfig.GetStringDefault("ScheduledExit.WarningTimes", "900,600,300,60"),
2325+
delay, warningErrors);
2326+
2327+
for (std::vector<std::string>::const_iterator itr = warningErrors.begin();
2328+
itr != warningErrors.end(); ++itr)
2329+
{
2330+
sLog.outError("ScheduledExit: ignoring %s", itr->c_str());
2331+
}
2332+
2333+
for (std::vector<uint32>::const_iterator itr = warningTimes.begin();
2334+
itr != warningTimes.end(); ++itr)
2335+
{
2336+
if (*itr == 0)
2337+
{
2338+
sLog.outError("ScheduledExit: ignoring warning milestone 0");
2339+
continue;
2340+
}
2341+
2342+
std::ostringstream configKey;
2343+
configKey << "ScheduledExit.WarningText." << *itr;
2344+
2345+
ScheduledExitWarning warning;
2346+
warning.remainingSeconds = *itr;
2347+
warning.text = sConfig.GetStringDefault(configKey.str().c_str(), "");
2348+
if (warning.text.empty())
2349+
{
2350+
warning.text = MaNGOS::BuildScheduledExitWarningText(mode, *itr);
2351+
}
2352+
warning.sent = false;
2353+
m_scheduledExitWarnings.push_back(warning);
2354+
}
2355+
2356+
m_scheduledExit.enabled = true;
2357+
m_scheduledExit.dayOfWeek = dayOfWeek;
2358+
m_scheduledExit.hour = hour;
2359+
m_scheduledExit.minute = minute;
2360+
m_scheduledExit.mode = mode;
2361+
m_scheduledExitDelay = delay;
2362+
2363+
if (MaNGOS::MarkScheduledExitHandledIfMatching(
2364+
m_scheduledExit, safe_localtime(time(NULL)), m_scheduledExitState))
2365+
{
2366+
sLog.outString("ScheduledExit: startup minute matches configured schedule; "
2367+
"suppressing this minute to avoid restart loop");
2368+
}
2369+
2370+
std::ostringstream milestones;
2371+
for (std::vector<ScheduledExitWarning>::const_iterator itr =
2372+
m_scheduledExitWarnings.begin();
2373+
itr != m_scheduledExitWarnings.end(); ++itr)
2374+
{
2375+
if (itr != m_scheduledExitWarnings.begin())
2376+
{
2377+
milestones << ",";
2378+
}
2379+
milestones << itr->remainingSeconds;
2380+
}
2381+
2382+
sLog.outString("ScheduledExit: enabled day=%u time=%02u:%02u mode=%s delay=%u warningTimes=%s",
2383+
m_scheduledExit.dayOfWeek, m_scheduledExit.hour, m_scheduledExit.minute,
2384+
MaNGOS::ScheduledExitModeToString(m_scheduledExit.mode), m_scheduledExitDelay,
2385+
milestones.str().c_str());
2386+
}
2387+
2388+
void World::CheckScheduledExit()
2389+
{
2390+
if (!m_scheduledExit.enabled || m_stopEvent)
2391+
{
2392+
return;
2393+
}
2394+
2395+
if (!MaNGOS::CheckAndMarkScheduledExit(
2396+
m_scheduledExit, safe_localtime(m_gameTime), m_scheduledExitState))
2397+
{
2398+
return;
2399+
}
2400+
2401+
if (m_ShutdownTimer > 0)
2402+
{
2403+
sLog.outString("ScheduledExit: %s scheduled for day=%u time=%02u:%02u "
2404+
"skipped because shutdown/restart is already in progress",
2405+
MaNGOS::ScheduledExitModeToString(m_scheduledExit.mode),
2406+
m_scheduledExit.dayOfWeek, m_scheduledExit.hour,
2407+
m_scheduledExit.minute);
2408+
return;
2409+
}
2410+
2411+
StartScheduledExit();
2412+
}
2413+
2414+
void World::StartScheduledExit()
2415+
{
2416+
uint32 mask = m_scheduledExit.mode == MaNGOS::SCHEDULED_EXIT_MODE_RESTART
2417+
? SHUTDOWN_MASK_RESTART : SHUTDOWN_MASK_STOP;
2418+
uint8 exitCode = m_scheduledExit.mode == MaNGOS::SCHEDULED_EXIT_MODE_RESTART
2419+
? RESTART_EXIT_CODE : SHUTDOWN_EXIT_CODE;
2420+
2421+
sLog.outString("ScheduledExit: firing scheduled %s with delay %u seconds",
2422+
MaNGOS::ScheduledExitModeToString(m_scheduledExit.mode), m_scheduledExitDelay);
2423+
2424+
ResetScheduledExitWarnings();
2425+
m_scheduledExitCountdownActive = m_scheduledExitDelay > 0;
2426+
ShutdownServ(m_scheduledExitDelay, mask, exitCode);
2427+
2428+
if (m_scheduledExitCountdownActive)
2429+
{
2430+
SendScheduledExitWarnings();
2431+
}
2432+
}
2433+
2434+
void World::ResetScheduledExitWarnings()
2435+
{
2436+
for (std::vector<ScheduledExitWarning>::iterator itr =
2437+
m_scheduledExitWarnings.begin();
2438+
itr != m_scheduledExitWarnings.end(); ++itr)
2439+
{
2440+
itr->sent = false;
2441+
}
2442+
}
2443+
2444+
void World::SendScheduledExitWarnings()
2445+
{
2446+
if (!m_scheduledExitCountdownActive || !m_ShutdownTimer)
2447+
{
2448+
return;
2449+
}
2450+
2451+
for (std::vector<ScheduledExitWarning>::iterator itr =
2452+
m_scheduledExitWarnings.begin();
2453+
itr != m_scheduledExitWarnings.end(); ++itr)
2454+
{
2455+
if (!itr->sent && m_ShutdownTimer <= itr->remainingSeconds)
2456+
{
2457+
SendScheduledExitWarning(*itr);
2458+
}
2459+
}
2460+
}
2461+
2462+
void World::SendScheduledExitWarning(ScheduledExitWarning& warning)
2463+
{
2464+
warning.sent = true;
2465+
SendServerMessage(SERVER_MSG_CUSTOM, warning.text.c_str());
2466+
}
2467+
2468+
/// Display a shutdown message to the user(s)
2469+
void World::ShutdownMsg(bool show /*= false*/, Player* player /*= NULL*/)
2470+
{
2471+
// not show messages for idle shutdown mode
2472+
if (m_ShutdownMask & SHUTDOWN_MASK_IDLE)
2473+
{
22602474
return;
22612475
}
22622476

@@ -2278,7 +2492,7 @@ void World::ShutdownMsg(bool show /*= false*/, Player* player /*= NULL*/)
22782492
}
22792493

22802494
/// Cancel a planned server shutdown
2281-
void World::ShutdownCancel()
2495+
void World::ShutdownCancel()
22822496
{
22832497
// nothing cancel or too later
22842498
if (!m_ShutdownTimer || m_stopEvent)
@@ -2288,8 +2502,10 @@ void World::ShutdownCancel()
22882502

22892503
ServerMessageType msgid = (m_ShutdownMask & SHUTDOWN_MASK_RESTART) ? SERVER_MSG_RESTART_CANCELLED : SERVER_MSG_SHUTDOWN_CANCELLED;
22902504

2291-
m_ShutdownMask = 0;
2292-
m_ShutdownTimer = 0;
2505+
m_ShutdownMask = 0;
2506+
m_ShutdownTimer = 0;
2507+
m_scheduledExitCountdownActive = false;
2508+
ResetScheduledExitWarnings();
22932509
m_ExitCode = SHUTDOWN_EXIT_CODE; // to default value
22942510
SendServerMessage(msgid);
22952511

0 commit comments

Comments
 (0)