d70529bc19
* Removed global realm variable from World and use RealmList everywhere * Match auth build key with client version * Restored allowedSecurityLevel checks for realmlist packet building * Restored updating population field Port From (https://github.com/TrinityCore/TrinityCore/commit/c4b710446d62c95eb8124175203fa5f394912594)
452 lines
18 KiB
C#
452 lines
18 KiB
C#
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
|
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
|
|
|
using Framework.Configuration;
|
|
using Framework.Constants;
|
|
using Framework.Database;
|
|
using Framework.IO;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace Game.Chat
|
|
{
|
|
[CommandGroup("server")]
|
|
class ServerCommands
|
|
{
|
|
[Command("corpses", RBACPermissions.CommandServerCorpses, true)]
|
|
static bool HandleServerCorpsesCommand(CommandHandler handler)
|
|
{
|
|
Global.WorldMgr.RemoveOldCorpses();
|
|
return true;
|
|
}
|
|
|
|
[Command("debug", RBACPermissions.CommandServerCorpses, true)]
|
|
static bool HandleServerDebugCommand(CommandHandler handler)
|
|
{
|
|
string dbPortOutput;
|
|
|
|
var currentRealm = Global.RealmMgr.GetCurrentRealm();
|
|
if (currentRealm != null)
|
|
dbPortOutput = $"Realmlist (Realm Id: {currentRealm.Id.Index}) configured in port {currentRealm.Port}";
|
|
else
|
|
dbPortOutput = $"Realm Id: {Global.RealmMgr.GetCurrentRealmId().Index} not found in `realmlist` table. Please check your setup";
|
|
|
|
DatabaseTypeFlags updateFlags = ConfigMgr.GetDefaultValue("Updates.EnableDatabases", DatabaseTypeFlags.None);
|
|
if (updateFlags == 0)
|
|
handler.SendSysMessage("Automatic database updates are disabled for all databases!");
|
|
else
|
|
handler.SendSysMessage($"Automatic database updates are enabled for the following databases: {updateFlags}");
|
|
|
|
handler.SendSysMessage($"Worldserver listening connections on port {WorldConfig.GetIntValue(WorldCfg.PortWorld)}");
|
|
handler.SendSysMessage(dbPortOutput);
|
|
|
|
bool vmapIndoorCheck = WorldConfig.GetBoolValue(WorldCfg.VmapIndoorCheck);
|
|
bool vmapLOSCheck = Global.VMapMgr.IsLineOfSightCalcEnabled();
|
|
bool vmapHeightCheck = Global.VMapMgr.IsHeightCalcEnabled();
|
|
|
|
bool mmapEnabled = WorldConfig.GetBoolValue(WorldCfg.EnableMmaps);
|
|
|
|
string dataDir = Global.WorldMgr.GetDataPath();
|
|
List<string> subDirs = new();
|
|
subDirs.Add("/maps");
|
|
if (vmapIndoorCheck || vmapLOSCheck || vmapHeightCheck)
|
|
{
|
|
handler.SendSysMessage($"VMAPs status: Enabled. LineOfSight: {vmapLOSCheck}, getHeight: {vmapHeightCheck}, indoorCheck: {vmapIndoorCheck}");
|
|
subDirs.Add("/vmaps");
|
|
}
|
|
else
|
|
handler.SendSysMessage("VMAPs status: Disabled");
|
|
|
|
if (mmapEnabled)
|
|
{
|
|
handler.SendSysMessage("MMAPs status: Enabled");
|
|
subDirs.Add("/mmaps");
|
|
}
|
|
else
|
|
handler.SendSysMessage("MMAPs status: Disabled");
|
|
|
|
foreach (string subDir in subDirs)
|
|
{
|
|
if (!File.Exists(dataDir + subDir))
|
|
{
|
|
handler.SendSysMessage($"{subDir} directory doesn't exist!. Using path: {dataDir + subDir}");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
Locale defaultLocale = Global.WorldMgr.GetDefaultDbcLocale();
|
|
uint availableLocalesMask = (1u << (int)defaultLocale);
|
|
|
|
for (Locale locale = 0; locale < Locale.Total; ++locale)
|
|
{
|
|
if (locale == defaultLocale)
|
|
continue;
|
|
|
|
if (Global.WorldMgr.GetAvailableDbcLocale(locale) != defaultLocale)
|
|
availableLocalesMask |= (1u << (int)locale);
|
|
}
|
|
|
|
string availableLocales = "";
|
|
for (Locale locale = 0; locale < Locale.Total; ++locale)
|
|
{
|
|
if ((availableLocalesMask & (1 << (int)locale)) == 0)
|
|
continue;
|
|
|
|
availableLocales += locale;
|
|
if (locale != Locale.Total - 1)
|
|
availableLocales += " ";
|
|
}
|
|
|
|
handler.SendSysMessage($"Using {defaultLocale} DBC Locale as default. All available DBC locales: {availableLocales}");
|
|
|
|
handler.SendSysMessage($"Using World DB: {Global.WorldMgr.GetDBVersion()}");
|
|
return true;
|
|
}
|
|
|
|
[Command("exit", RBACPermissions.CommandServerExit, true)]
|
|
static bool HandleServerExitCommand(CommandHandler handler)
|
|
{
|
|
handler.SendSysMessage(CypherStrings.CommandExit);
|
|
Global.WorldMgr.StopNow(ShutdownExitCode.Shutdown);
|
|
return true;
|
|
}
|
|
|
|
[Command("info", RBACPermissions.CommandServerInfo, true)]
|
|
static bool HandleServerInfoCommand(CommandHandler handler)
|
|
{
|
|
uint playersNum = Global.WorldMgr.GetPlayerCount();
|
|
uint maxPlayersNum = Global.WorldMgr.GetMaxPlayerCount();
|
|
int activeClientsNum = Global.WorldMgr.GetActiveSessionCount();
|
|
int queuedClientsNum = Global.WorldMgr.GetQueuedSessionCount();
|
|
uint maxActiveClientsNum = Global.WorldMgr.GetMaxActiveSessionCount();
|
|
uint maxQueuedClientsNum = Global.WorldMgr.GetMaxQueuedSessionCount();
|
|
string uptime = Time.secsToTimeString(GameTime.GetUptime());
|
|
uint updateTime = Global.WorldMgr.GetWorldUpdateTime().GetLastUpdateTime();
|
|
|
|
handler.SendSysMessage(CypherStrings.ConnectedPlayers, playersNum, maxPlayersNum);
|
|
handler.SendSysMessage(CypherStrings.ConnectedUsers, activeClientsNum, maxActiveClientsNum, queuedClientsNum, maxQueuedClientsNum);
|
|
handler.SendSysMessage(CypherStrings.Uptime, uptime);
|
|
handler.SendSysMessage(CypherStrings.UpdateDiff, updateTime);
|
|
// Can't use Global.WorldMgr.ShutdownMsg here in case of console command
|
|
if (Global.WorldMgr.IsShuttingDown())
|
|
handler.SendSysMessage(CypherStrings.ShutdownTimeleft, Time.secsToTimeString(Global.WorldMgr.GetShutDownTimeLeft()));
|
|
|
|
return true;
|
|
}
|
|
|
|
[Command("motd", RBACPermissions.CommandServerMotd, true)]
|
|
static bool HandleServerMotdCommand(CommandHandler handler)
|
|
{
|
|
string motd = "";
|
|
foreach (var line in Global.WorldMgr.GetMotd())
|
|
motd += line;
|
|
|
|
handler.SendSysMessage(CypherStrings.MotdCurrent, motd);
|
|
return true;
|
|
}
|
|
|
|
[Command("plimit", RBACPermissions.CommandServerPlimit, true)]
|
|
static bool HandleServerPLimitCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
if (!args.Empty())
|
|
{
|
|
string paramStr = args.NextString();
|
|
if (string.IsNullOrEmpty(paramStr))
|
|
return false;
|
|
|
|
switch (paramStr.ToLower())
|
|
{
|
|
case "player":
|
|
Global.WorldMgr.SetPlayerSecurityLimit(AccountTypes.Player);
|
|
break;
|
|
case "moderator":
|
|
Global.WorldMgr.SetPlayerSecurityLimit(AccountTypes.Moderator);
|
|
break;
|
|
case "gamemaster":
|
|
Global.WorldMgr.SetPlayerSecurityLimit(AccountTypes.GameMaster);
|
|
break;
|
|
case "administrator":
|
|
Global.WorldMgr.SetPlayerSecurityLimit(AccountTypes.Administrator);
|
|
break;
|
|
case "reset":
|
|
Global.WorldMgr.SetPlayerAmountLimit(ConfigMgr.GetDefaultValue<uint>("PlayerLimit", 100));
|
|
Global.WorldMgr.LoadDBAllowedSecurityLevel();
|
|
break;
|
|
default:
|
|
if (!int.TryParse(paramStr, out int value))
|
|
return false;
|
|
|
|
if (value < 0)
|
|
Global.WorldMgr.SetPlayerSecurityLimit((AccountTypes)(-value));
|
|
else
|
|
Global.WorldMgr.SetPlayerAmountLimit((uint)value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint playerAmountLimit = Global.WorldMgr.GetPlayerAmountLimit();
|
|
AccountTypes allowedAccountType = Global.WorldMgr.GetPlayerSecurityLimit();
|
|
string secName;
|
|
switch (allowedAccountType)
|
|
{
|
|
case AccountTypes.Player:
|
|
secName = "Player";
|
|
break;
|
|
case AccountTypes.Moderator:
|
|
secName = "Moderator";
|
|
break;
|
|
case AccountTypes.GameMaster:
|
|
secName = "Gamemaster";
|
|
break;
|
|
case AccountTypes.Administrator:
|
|
secName = "Administrator";
|
|
break;
|
|
default:
|
|
secName = "<unknown>";
|
|
break;
|
|
}
|
|
handler.SendSysMessage("Player limits: amount {0}, min. security level {1}.", playerAmountLimit, secName);
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool IsOnlyUser(WorldSession mySession)
|
|
{
|
|
// check if there is any session connected from a different address
|
|
string myAddr = mySession != null ? mySession.GetRemoteAddress() : "";
|
|
var sessions = Global.WorldMgr.GetAllSessions();
|
|
foreach (var session in sessions)
|
|
if (session != null && myAddr != session.GetRemoteAddress())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static bool ParseExitCode(string exitCodeStr, out int exitCode)
|
|
{
|
|
if (!int.TryParse(exitCodeStr, out exitCode))
|
|
return false;
|
|
|
|
// Handle atoi() errors
|
|
if (exitCode == 0 && (exitCodeStr[0] != '0' || (exitCodeStr.Length > 1 && exitCodeStr[1] != '\0')))
|
|
return false;
|
|
|
|
// Exit code should be in range of 0-125, 126-255 is used
|
|
// in many shells for their own return codes and code > 255
|
|
// is not supported in many others
|
|
if (exitCode < 0 || exitCode > 125)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool ShutdownServer(StringArguments args, CommandHandler handler, ShutdownMask shutdownMask, ShutdownExitCode defaultExitCode)
|
|
{
|
|
if (args.Empty())
|
|
return false;
|
|
|
|
string delayStr = args.NextString();
|
|
if (delayStr.IsEmpty())
|
|
return false;
|
|
|
|
int delay;
|
|
if (int.TryParse(delayStr, out delay))
|
|
{
|
|
// Prevent interpret wrong arg value as 0 secs shutdown time
|
|
if ((delay == 0 && (delayStr[0] != '0' || delayStr.Length > 1 && delayStr[1] != '\0')) || delay < 0)
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
delay = (int)Time.TimeStringToSecs(delayStr);
|
|
|
|
if (delay == 0)
|
|
return false;
|
|
}
|
|
|
|
string reason = "";
|
|
string exitCodeStr = "";
|
|
string nextToken;
|
|
while (!(nextToken = args.NextString()).IsEmpty())
|
|
{
|
|
if (nextToken.IsNumber())
|
|
exitCodeStr = nextToken;
|
|
else
|
|
{
|
|
reason = nextToken;
|
|
reason += args.NextString("\0");
|
|
break;
|
|
}
|
|
}
|
|
|
|
int exitCode = (int)defaultExitCode;
|
|
if (!exitCodeStr.IsEmpty())
|
|
if (!ParseExitCode(exitCodeStr, out exitCode))
|
|
return false;
|
|
|
|
// Override parameter "delay" with the configuration value if there are still players connected and "force" parameter was not specified
|
|
if (delay < WorldConfig.GetIntValue(WorldCfg.ForceShutdownThreshold) && !shutdownMask.HasAnyFlag(ShutdownMask.Force) && !IsOnlyUser(handler.GetSession()))
|
|
{
|
|
delay = WorldConfig.GetIntValue(WorldCfg.ForceShutdownThreshold);
|
|
handler.SendSysMessage(CypherStrings.ShutdownDelayed, delay);
|
|
}
|
|
|
|
Global.WorldMgr.ShutdownServ((uint)delay, shutdownMask, (ShutdownExitCode)exitCode, reason);
|
|
|
|
return true;
|
|
}
|
|
|
|
[CommandGroup("idleRestart")]
|
|
class IdleRestartCommands
|
|
{
|
|
[Command("", RBACPermissions.CommandServerIdlerestart, true)]
|
|
static bool HandleServerIdleRestartCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
return ShutdownServer(args, handler, ShutdownMask.Restart | ShutdownMask.Idle, ShutdownExitCode.Restart);
|
|
}
|
|
|
|
[Command("cancel", RBACPermissions.CommandServerIdlerestartCancel, true)]
|
|
static bool HandleServerShutDownCancelCommand(CommandHandler handler)
|
|
{
|
|
uint timer = Global.WorldMgr.ShutdownCancel();
|
|
if (timer != 0)
|
|
handler.SendSysMessage(CypherStrings.ShutdownCancelled, timer);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
[CommandGroup("idleshutdown")]
|
|
class IdleshutdownCommands
|
|
{
|
|
[Command("", RBACPermissions.CommandServerIdleshutdown, true)]
|
|
static bool HandleServerIdleShutDownCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
return ShutdownServer(args, handler, ShutdownMask.Idle, ShutdownExitCode.Shutdown);
|
|
}
|
|
|
|
[Command("cancel", RBACPermissions.CommandServerIdleshutdownCancel, true)]
|
|
static bool HandleServerShutDownCancelCommand(CommandHandler handler)
|
|
{
|
|
uint timer = Global.WorldMgr.ShutdownCancel();
|
|
if (timer != 0)
|
|
handler.SendSysMessage(CypherStrings.ShutdownCancelled, timer);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
[CommandGroup("restart")]
|
|
class RestartCommands
|
|
{
|
|
[Command("", RBACPermissions.CommandServerRestart, true)]
|
|
static bool HandleServerRestartCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
return ShutdownServer(args, handler, ShutdownMask.Restart, ShutdownExitCode.Restart);
|
|
}
|
|
|
|
[Command("cancel", RBACPermissions.CommandServerRestartCancel, true)]
|
|
static bool HandleServerShutDownCancelCommand(CommandHandler handler)
|
|
{
|
|
uint timer = Global.WorldMgr.ShutdownCancel();
|
|
if (timer != 0)
|
|
handler.SendSysMessage(CypherStrings.ShutdownCancelled, timer);
|
|
|
|
return true;
|
|
}
|
|
|
|
[Command("force", RBACPermissions.CommandServerRestartCancel, true)]
|
|
static bool HandleServerForceRestartCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
return ShutdownServer(args, handler, ShutdownMask.Force | ShutdownMask.Restart, ShutdownExitCode.Restart);
|
|
}
|
|
}
|
|
|
|
[CommandGroup("shutdown")]
|
|
class ShutdownCommands
|
|
{
|
|
[Command("", RBACPermissions.CommandServerShutdown, true)]
|
|
static bool HandleServerShutDownCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
return ShutdownServer(args, handler, 0, ShutdownExitCode.Shutdown);
|
|
}
|
|
|
|
[Command("cancel", RBACPermissions.CommandServerShutdownCancel, true)]
|
|
static bool HandleServerShutDownCancelCommand(CommandHandler handler)
|
|
{
|
|
uint timer = Global.WorldMgr.ShutdownCancel();
|
|
if (timer != 0)
|
|
handler.SendSysMessage(CypherStrings.ShutdownCancelled, timer);
|
|
|
|
return true;
|
|
}
|
|
|
|
[Command("force", RBACPermissions.CommandServerShutdownCancel, true)]
|
|
static bool HandleServerForceShutDownCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
return ShutdownServer(args, handler, ShutdownMask.Force, ShutdownExitCode.Shutdown);
|
|
}
|
|
}
|
|
|
|
[CommandGroup("set")]
|
|
class SetCommands
|
|
{
|
|
[Command("difftime", RBACPermissions.CommandServerSetDifftime, true)]
|
|
static bool HandleServerSetDiffTimeCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
if (args.Empty())
|
|
return false;
|
|
|
|
string newTimeStr = args.NextString();
|
|
if (newTimeStr.IsEmpty())
|
|
return false;
|
|
|
|
if (!int.TryParse(newTimeStr, out int newTime) || newTime < 0)
|
|
return false;
|
|
|
|
//Global.WorldMgr.SetRecordDiffInterval(newTime);
|
|
//printf("Record diff every %i ms\n", newTime);
|
|
|
|
return true;
|
|
}
|
|
|
|
[Command("loglevel", RBACPermissions.CommandServerSetLoglevel, true)]
|
|
static bool HandleServerSetLogLevelCommand(CommandHandler handler, string type, string name, int level)
|
|
{
|
|
if (name.IsEmpty() || level < 0 || (type != "a" && type != "l"))
|
|
return false;
|
|
|
|
return Log.SetLogLevel(name, level, type == "l");
|
|
}
|
|
|
|
[Command("motd", RBACPermissions.CommandServerSetMotd, true)]
|
|
static bool HandleServerSetMotdCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
Global.WorldMgr.SetMotd(args.NextString(""));
|
|
handler.SendSysMessage(CypherStrings.MotdNew, args.GetString());
|
|
return true;
|
|
}
|
|
|
|
[Command("closed", RBACPermissions.CommandServerSetClosed, true)]
|
|
static bool HandleServerSetClosedCommand(CommandHandler handler, StringArguments args)
|
|
{
|
|
string arg1 = args.NextString();
|
|
if (arg1.Equals("on", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
handler.SendSysMessage(CypherStrings.WorldClosed);
|
|
Global.WorldMgr.SetClosed(true);
|
|
return true;
|
|
}
|
|
else if (arg1.Equals("off", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
handler.SendSysMessage(CypherStrings.WorldOpened);
|
|
Global.WorldMgr.SetClosed(false);
|
|
return true;
|
|
}
|
|
|
|
handler.SendSysMessage(CypherStrings.UseBol);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|