Fixes exiting/crash handling/ctrl+c (#237)

- [X] Fixes handling of CTRL+C
- [X] Fixes crash guard (but should really be rewritten
- [X] Fixes exiting/restarting

Bumps release version
This commit is contained in:
Kamron Batman 2020-09-12 00:05:38 -07:00 committed by GitHub
parent 76a9729f61
commit 55ae0f8778
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 216 additions and 160 deletions

View file

@ -85,7 +85,6 @@ namespace Server.Tests.Network.Packets
public void TestHuedEffect() public void TestHuedEffect()
{ {
var effectType = EffectType.Moving; var effectType = EffectType.Moving;
Serial serial = 0x4000;
Serial from = 0x1000; Serial from = 0x1000;
Serial to = 0x2000; Serial to = 0x2000;
var itemId = 0x100; var itemId = 0x100;

View file

@ -111,9 +111,7 @@ namespace Server
public static string EnsureDirectory(string dir) public static string EnsureDirectory(string dir)
{ {
var path = Path.Combine(Core.BaseDirectory, dir); var path = Path.Combine(Core.BaseDirectory, dir);
Directory.CreateDirectory(path);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
return path; return path;
} }

View file

@ -1,22 +1,17 @@
/*************************************************************************** /*************************************************************************
* Main.cs * ModernUO *
* ------------------- * Copyright (C) 2019-2020 - ModernUO Development Team *
* begin : May 1, 2002 * Email: hi@modernuo.com *
* copyright : (C) The RunUO Software Team * File: Main.cs *
* email : info@runuo.com * *
* * This program is free software: you can redistribute it and/or modify *
* $Id$ * it under the terms of the GNU General Public License as published by *
* * the Free Software Foundation, either version 3 of the License, or *
***************************************************************************/ * (at your option) any later version. *
* *
/*************************************************************************** * You should have received a copy of the GNU General Public License *
* * along with this program. If not, see <http://www.gnu.org/licenses/>. *
* This program is free software; you can redistribute it and/or modify *************************************************************************/
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -42,7 +37,6 @@ namespace Server
private static bool m_Crashed; private static bool m_Crashed;
private static Thread timerThread; private static Thread timerThread;
private static string m_BaseDirectory; private static string m_BaseDirectory;
private static string m_ExePath;
private static bool m_Profiling; private static bool m_Profiling;
private static DateTime m_ProfileStart; private static DateTime m_ProfileStart;
@ -62,8 +56,6 @@ namespace Server
private static readonly double m_HighFrequency = 1000.0 / Stopwatch.Frequency; private static readonly double m_HighFrequency = 1000.0 / Stopwatch.Frequency;
private static readonly double m_LowFrequency = 1000.0 / TimeSpan.TicksPerSecond; private static readonly double m_LowFrequency = 1000.0 / TimeSpan.TicksPerSecond;
internal static ConsoleEventHandler m_ConsoleEventHandler;
private static int m_CycleIndex = 1; private static int m_CycleIndex = 1;
private static readonly float[] m_CyclesPerSecond = new float[100]; private static readonly float[] m_CyclesPerSecond = new float[100];
@ -138,8 +130,6 @@ namespace Server
public static int ProcessorCount { get; private set; } public static int ProcessorCount { get; private set; }
public static string ExePath => m_ExePath ??= Assembly.Location;
public static string BaseDirectory public static string BaseDirectory
{ {
get get
@ -148,7 +138,7 @@ namespace Server
{ {
try try
{ {
m_BaseDirectory = ExePath; m_BaseDirectory = Assembly.Location;
if (m_BaseDirectory.Length > 0) if (m_BaseDirectory.Length > 0)
{ {
@ -165,7 +155,9 @@ namespace Server
} }
} }
public static bool Closing { get; private set; } public static CancellationTokenSource ClosingTokenSource { get; } = new CancellationTokenSource();
public static bool Closing => ClosingTokenSource.IsCancellationRequested;
public static float CyclesPerSecond => m_CyclesPerSecond[(m_CycleIndex - 1) % m_CyclesPerSecond.Length]; public static float CyclesPerSecond => m_CyclesPerSecond[(m_CycleIndex - 1) % m_CyclesPerSecond.Length];
@ -279,15 +271,6 @@ namespace Server
if (!close) if (!close)
{ {
try
{
// Close all listeners
}
catch
{
// ignored
}
Console.WriteLine("This exception is fatal, press return to exit"); Console.WriteLine("This exception is fatal, press return to exit");
Console.ReadLine(); Console.ReadLine();
} }
@ -296,30 +279,56 @@ namespace Server
} }
} }
private static bool OnConsoleEvent(ConsoleEventType type)
{
if (World.Saving || type == ConsoleEventType.CTRL_LOGOFF_EVENT)
{
return true;
}
Kill(); // Kill -> HandleClosed will handle waiting for the completion of flushing to disk
return true;
}
private static void CurrentDomain_ProcessExit(object sender, EventArgs e) private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{ {
HandleClosed(); if (!Closing)
{
HandleClosed();
}
}
private static void Console_CancelKeyPressed(object sender, ConsoleCancelEventArgs e)
{
var keypress = e.SpecialKey switch
{
ConsoleSpecialKey.ControlBreak => "CTRL+BREAK",
_ => "CTRL+C"
};
Console.WriteLine("Core: Detected {0} pressed.", keypress);
e.Cancel = true;
Kill();
} }
public static void Kill(bool restart = false) public static void Kill(bool restart = false)
{ {
if (Closing)
{
return;
}
HandleClosed(); HandleClosed();
if (restart) if (restart)
{ {
Process.Start(ExePath, Arguments); if (IsWindows)
{
Process.Start("dotnet", Assembly.Location);
}
else
{
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "dotnet",
Arguments = Assembly.Location,
UseShellExecute = true
}
};
process.Start();
}
} }
Process.Kill(); Process.Kill();
@ -327,14 +336,9 @@ namespace Server
private static void HandleClosed() private static void HandleClosed()
{ {
if (Closing) ClosingTokenSource.Cancel();
{
return;
}
Closing = true; Console.Write("Core: Shutting down...");
Console.Write("Exiting...");
World.WaitForWriteCompletion(); World.WaitForWriteCompletion();
@ -426,11 +430,7 @@ namespace Server
Console.WriteLine("Core: Optimizing for {0} processor{1}", ProcessorCount, ProcessorCount == 1 ? "" : "s"); Console.WriteLine("Core: Optimizing for {0} processor{1}", ProcessorCount, ProcessorCount == 1 ? "" : "s");
} }
if (IsWindows) Console.CancelKeyPress += Console_CancelKeyPressed;
{
m_ConsoleEventHandler = OnConsoleEvent;
UnsafeNativeMethods.SetConsoleCtrlHandler(m_ConsoleEventHandler, true);
}
if (GCSettings.IsServerGC) if (GCSettings.IsServerGC)
{ {
@ -472,13 +472,14 @@ namespace Server
EventSink.InvokeServerStarted(); EventSink.InvokeServerStarted();
// Start net socket server // Start net socket server
var host = TcpServer.CreateWebHostBuilder().Build(); _tcpHost = TcpServer.CreateWebHostBuilder().Build();
var life = host.Services.GetRequiredService<IHostApplicationLifetime>();
life.ApplicationStopping.Register(() => { Kill(); });
host.Run(); // Run indefinitely and block
_tcpHost.RunAsync(ClosingTokenSource.Token).Wait();
} }
private static IWebHost _tcpHost;
public static void RunEventLoop(IMessagePumpService messagePumpService) public static void RunEventLoop(IMessagePumpService messagePumpService)
{ {
try try
@ -542,7 +543,10 @@ namespace Server
{ {
var isItem = type.IsSubclassOf(typeof(Item)); var isItem = type.IsSubclassOf(typeof(Item));
if (!isItem && !type.IsSubclassOf(typeof(Mobile))) return; if (!isItem && !type.IsSubclassOf(typeof(Mobile)))
{
return;
}
if (isItem) if (isItem)
{ {
@ -595,22 +599,5 @@ namespace Server
Parallel.ForEach(assembly.GetTypes(), VerifyType); Parallel.ForEach(assembly.GetTypes(), VerifyType);
} }
} }
internal enum ConsoleEventType
{
CTRL_C_EVENT,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
internal delegate bool ConsoleEventHandler(ConsoleEventType type);
internal static class UnsafeNativeMethods
{
[DllImport("Kernel32")]
internal static extern bool SetConsoleCtrlHandler(ConsoleEventHandler callback, bool add);
}
} }
} }

View file

@ -40,7 +40,9 @@ namespace Server.Network
while (!m_WorkQueue.IsEmpty && count++ < 250) while (!m_WorkQueue.IsEmpty && count++ < 250)
{ {
if (!m_WorkQueue.TryDequeue(out var work)) if (!m_WorkQueue.TryDequeue(out var work))
{
break; break;
}
var seq = new ReadOnlySequence<byte>(work.MemoryOwner.Memory.Slice(0, work.Length)); var seq = new ReadOnlySequence<byte>(work.MemoryOwner.Memory.Slice(0, work.Length));
work.OnReceive(work.State, new PacketReader(seq)); work.OnReceive(work.State, new PacketReader(seq));

View file

@ -181,36 +181,71 @@ namespace Server.Network
m_Version = value; m_Version = value;
if (value >= m_Version70610) if (value >= m_Version70610)
{
ProtocolChanges = ProtocolChanges.Version70610; ProtocolChanges = ProtocolChanges.Version70610;
}
if (value >= m_Version70500) if (value >= m_Version70500)
{
ProtocolChanges = ProtocolChanges.Version70500; ProtocolChanges = ProtocolChanges.Version70500;
}
if (value >= m_Version704565) if (value >= m_Version704565)
{
ProtocolChanges = ProtocolChanges.Version704565; ProtocolChanges = ProtocolChanges.Version704565;
}
else if (value >= m_Version70331) else if (value >= m_Version70331)
{
ProtocolChanges = ProtocolChanges.Version70331; ProtocolChanges = ProtocolChanges.Version70331;
}
else if (value >= m_Version70300) else if (value >= m_Version70300)
{
ProtocolChanges = ProtocolChanges.Version70300; ProtocolChanges = ProtocolChanges.Version70300;
}
else if (value >= m_Version70160) else if (value >= m_Version70160)
{
ProtocolChanges = ProtocolChanges.Version70160; ProtocolChanges = ProtocolChanges.Version70160;
}
else if (value >= m_Version70130) else if (value >= m_Version70130)
{
ProtocolChanges = ProtocolChanges.Version70130; ProtocolChanges = ProtocolChanges.Version70130;
}
else if (value >= m_Version7090) else if (value >= m_Version7090)
{
ProtocolChanges = ProtocolChanges.Version7090; ProtocolChanges = ProtocolChanges.Version7090;
}
else if (value >= m_Version7000) else if (value >= m_Version7000)
{
ProtocolChanges = ProtocolChanges.Version7000; ProtocolChanges = ProtocolChanges.Version7000;
}
else if (value >= m_Version60142) else if (value >= m_Version60142)
{
ProtocolChanges = ProtocolChanges.Version60142; ProtocolChanges = ProtocolChanges.Version60142;
}
else if (value >= m_Version6017) else if (value >= m_Version6017)
{
ProtocolChanges = ProtocolChanges.Version6017; ProtocolChanges = ProtocolChanges.Version6017;
}
else if (value >= m_Version6000) else if (value >= m_Version6000)
{
ProtocolChanges = ProtocolChanges.Version6000; ProtocolChanges = ProtocolChanges.Version6000;
}
else if (value >= m_Version502b) else if (value >= m_Version502b)
{
ProtocolChanges = ProtocolChanges.Version502b; ProtocolChanges = ProtocolChanges.Version502b;
}
else if (value >= m_Version500a) else if (value >= m_Version500a)
{
ProtocolChanges = ProtocolChanges.Version500a; ProtocolChanges = ProtocolChanges.Version500a;
}
else if (value >= m_Version407a) else if (value >= m_Version407a)
{
ProtocolChanges = ProtocolChanges.Version407a; ProtocolChanges = ProtocolChanges.Version407a;
else if (value >= m_Version400a) ProtocolChanges = ProtocolChanges.Version400a; }
else if (value >= m_Version400a)
{
ProtocolChanges = ProtocolChanges.Version400a;
}
} }
} }
@ -275,7 +310,9 @@ namespace Server.Network
var info = ExpansionInfo.Table[i]; var info = ExpansionInfo.Table[i];
if (info.RequiredClient != null && Version >= info.RequiredClient || (Flags & info.ClientFlags) != 0) if (info.RequiredClient != null && Version >= info.RequiredClient || (Flags & info.ClientFlags) != 0)
{
return info; return info;
}
} }
return ExpansionInfo.GetInfo(Expansion.None); return ExpansionInfo.GetInfo(Expansion.None);
@ -292,21 +329,31 @@ namespace Server.Network
{ {
for (var i = Trades.Count - 1; i >= 0; --i) for (var i = Trades.Count - 1; i >= 0; --i)
{ {
if (i >= Trades.Count) continue; if (i >= Trades.Count)
{
continue;
}
var trade = Trades[i]; var trade = Trades[i];
if (trade.From.Mobile.Deleted || trade.To.Mobile.Deleted || !trade.From.Mobile.Alive || if (trade.From.Mobile.Deleted || trade.To.Mobile.Deleted || !trade.From.Mobile.Alive ||
!trade.To.Mobile.Alive || !trade.From.Mobile.InRange(trade.To.Mobile, 2) || !trade.To.Mobile.Alive || !trade.From.Mobile.InRange(trade.To.Mobile, 2) ||
trade.From.Mobile.Map != trade.To.Mobile.Map) trade.Cancel(); trade.From.Mobile.Map != trade.To.Mobile.Map)
{
trade.Cancel();
}
} }
} }
public void CancelAllTrades() public void CancelAllTrades()
{ {
for (var i = Trades.Count - 1; i >= 0; --i) for (var i = Trades.Count - 1; i >= 0; --i)
{
if (i < Trades.Count) if (i < Trades.Count)
{
Trades[i].Cancel(); Trades[i].Cancel();
}
}
} }
public void RemoveTrade(SecureTrade trade) public void RemoveTrade(SecureTrade trade)
@ -320,7 +367,10 @@ namespace Server.Network
{ {
var trade = Trades[i]; var trade = Trades[i];
if (trade.From.Mobile == m || trade.To.Mobile == m) return trade; if (trade.From.Mobile == m || trade.To.Mobile == m)
{
return trade;
}
} }
return null; return null;
@ -335,9 +385,15 @@ namespace Server.Network
var from = trade.From; var from = trade.From;
var to = trade.To; var to = trade.To;
if (from.Mobile == Mobile && to.Mobile == m) return from.Container; if (from.Mobile == Mobile && to.Mobile == m)
{
return @from.Container;
}
if (from.Mobile == m && to.Mobile == Mobile) return to.Container; if (from.Mobile == m && to.Mobile == Mobile)
{
return to.Container;
}
} }
return null; return null;
@ -521,21 +577,29 @@ namespace Server.Network
while (true) while (true)
{ {
if (AsyncState.Paused) if (AsyncState.Paused)
{
continue; continue;
}
var result = await inPipe.ReadAsync(); var result = await inPipe.ReadAsync();
if (result.IsCanceled || result.IsCompleted) if (result.IsCanceled || result.IsCompleted)
{
return; return;
}
var seq = result.Buffer; var seq = result.Buffer;
if (seq.IsEmpty) if (seq.IsEmpty)
{
break; break;
}
var pos = PacketHandlers.ProcessPacket(messagePumpService, this, seq); var pos = PacketHandlers.ProcessPacket(messagePumpService, this, seq);
if (pos <= 0) if (pos <= 0)
{
break; break;
}
inPipe.AdvanceTo(seq.Slice(0, pos).End); inPipe.AdvanceTo(seq.Slice(0, pos).End);
} }
@ -545,9 +609,9 @@ namespace Server.Network
Console.WriteLine(ex); Console.WriteLine(ex);
TraceException(ex); TraceException(ex);
} }
catch (Exception ex) catch
{ {
Console.WriteLine(ex); // Console.WriteLine(ex);
} }
finally finally
{ {
@ -595,7 +659,9 @@ namespace Server.Network
{ {
var disposing = Interlocked.Exchange(ref m_Disposing, 1); var disposing = Interlocked.Exchange(ref m_Disposing, 1);
if (disposing == 1) if (disposing == 1)
{
return; return;
}
try try
{ {
@ -620,7 +686,9 @@ namespace Server.Network
while (breakout++ < 200) while (breakout++ < 200)
{ {
if (!m_Disposed.TryDequeue(out var ns)) if (!m_Disposed.TryDequeue(out var ns))
{
break; break;
}
var m = ns.Mobile; var m = ns.Mobile;
var a = ns.Account; var a = ns.Account;
@ -639,9 +707,13 @@ namespace Server.Network
ns.CityInfo = null; ns.CityInfo = null;
if (a != null) if (a != null)
{
ns.WriteConsole("Disconnected. [{0} Online] [{1}]", TcpServer.Instances.Count, a); ns.WriteConsole("Disconnected. [{0} Online] [{1}]", TcpServer.Instances.Count, a);
}
else else
{
ns.WriteConsole("Disconnected. [{0} Online]", TcpServer.Instances.Count); ns.WriteConsole("Disconnected. [{0} Online]", TcpServer.Instances.Count);
}
} }
} }

View file

@ -54,15 +54,21 @@ namespace Server.Network
public static IPAddress[] GetListeningAddresses(IPEndPoint ipep) public static IPAddress[] GetListeningAddresses(IPEndPoint ipep)
{ {
if (m_ListeningAddresses != null) if (m_ListeningAddresses != null)
{
return m_ListeningAddresses; return m_ListeningAddresses;
}
var list = new List<IPAddress>(); var list = new List<IPAddress>();
foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces()) foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces())
{ {
var properties = adapter.GetIPProperties(); var properties = adapter.GetIPProperties();
foreach (var unicast in properties.UnicastAddresses) foreach (var unicast in properties.UnicastAddresses)
{
if (ipep.AddressFamily == unicast.Address.AddressFamily) if (ipep.AddressFamily == unicast.Address.AddressFamily)
{
list.Add(unicast.Address); list.Add(unicast.Address);
}
}
} }
return list.ToArray(); return list.ToArray();
@ -71,10 +77,16 @@ namespace Server.Network
private static void DisplayListener(IPEndPoint ipep) private static void DisplayListener(IPEndPoint ipep)
{ {
if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any)) if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any))
{
foreach (var ip in m_ListeningAddresses) foreach (var ip in m_ListeningAddresses)
{
Console.WriteLine("Listening: {0}:{1}", ip, ipep.Port); Console.WriteLine("Listening: {0}:{1}", ip, ipep.Port);
}
}
else else
{
Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port); Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port);
}
} }
} }
} }

View file

@ -24,7 +24,9 @@ namespace Server.Misc
m_RestartTime = DateTime.UtcNow.Date + RestartTime; m_RestartTime = DateTime.UtcNow.Date + RestartTime;
if (m_RestartTime < DateTime.UtcNow) if (m_RestartTime < DateTime.UtcNow)
{
m_RestartTime += TimeSpan.FromDays(1.0); m_RestartTime += TimeSpan.FromDays(1.0);
}
} }
public static bool Restarting { get; private set; } public static bool Restarting { get; private set; }
@ -49,12 +51,12 @@ namespace Server.Misc
} }
} }
private void Warning_Callback() private static void Warning_Callback()
{ {
World.Broadcast(0x22, true, "The server is going down shortly."); World.Broadcast(0x22, true, "The server is going down shortly.");
} }
private void Restart_Callback() private static void Restart_Callback()
{ {
Core.Kill(true); Core.Kill(true);
} }
@ -62,10 +64,14 @@ namespace Server.Misc
protected override void OnTick() protected override void OnTick()
{ {
if (Restarting || !Enabled) if (Restarting || !Enabled)
{
return; return;
}
if (DateTime.UtcNow < m_RestartTime) if (DateTime.UtcNow < m_RestartTime)
{
return; return;
}
if (WarningDelay > TimeSpan.Zero) if (WarningDelay > TimeSpan.Zero)
{ {

View file

@ -22,14 +22,14 @@ namespace Server.Misc
public static void EventSink_Shutdown() public static void EventSink_Shutdown()
{ {
/* try try
{ {
World.Broadcast(0x35, true, "The server has shut down."); World.Broadcast(0x35, true, "The server has shut down.");
} }
catch catch
{ {
// ignored // ignored
}*/ }
} }
} }
} }

View file

@ -8,32 +8,38 @@ namespace Server.Misc
{ {
public static class CrashGuard public static class CrashGuard
{ {
private static readonly bool Enabled = true; // TODO: Make this configurable
private static readonly bool SaveBackup = true; private const bool Enabled = true;
private static readonly bool RestartServer = true; private const bool SaveBackup = true;
private static readonly bool GenerateReport = true; private const bool RestartServer = true;
private const bool GenerateReport = true;
public static void Initialize() public static void Initialize()
{ {
if (Enabled) // If enabled, register our crash event handler if (Enabled)
{
EventSink.ServerCrashed += CrashGuard_OnCrash; EventSink.ServerCrashed += CrashGuard_OnCrash;
}
} }
public static void CrashGuard_OnCrash(ServerCrashedEventArgs e) public static void CrashGuard_OnCrash(ServerCrashedEventArgs e)
{ {
if (GenerateReport) if (GenerateReport)
{
GenerateCrashReport(e); GenerateCrashReport(e);
}
World.WaitForWriteCompletion(); World.WaitForWriteCompletion();
if (SaveBackup) if (SaveBackup)
{
Backup(); Backup();
}
/*if (Core.Service)
e.Close = true;
else */
if (RestartServer) if (RestartServer)
{
Restart(e); Restart(e);
}
} }
private static void SendEmail(string filePath) private static void SendEmail(string filePath)
@ -43,29 +49,13 @@ namespace Server.Misc
Email.SendCrashEmail(filePath); Email.SendCrashEmail(filePath);
} }
private static string GetRoot()
{
try
{
return Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
}
catch
{
return "";
}
}
private static string Combine(string path1, string path2) => path1.Length == 0 ? path2 : Path.Combine(path1, path2);
private static void Restart(ServerCrashedEventArgs e) private static void Restart(ServerCrashedEventArgs e)
{ {
var root = GetRoot();
Console.Write("Crash: Restarting..."); Console.Write("Crash: Restarting...");
try try
{ {
Process.Start(Core.ExePath, Core.Arguments); Process.Start(Core.Assembly.Location, Core.Arguments);
Console.WriteLine("done"); Console.WriteLine("done");
e.Close = true; e.Close = true;
@ -76,26 +66,20 @@ namespace Server.Misc
} }
} }
private static void CreateDirectory(string path)
{
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
private static void CreateDirectory(string path1, string path2)
{
CreateDirectory(Combine(path1, path2));
}
private static void CopyFile(string rootOrigin, string rootBackup, string path) private static void CopyFile(string rootOrigin, string rootBackup, string path)
{ {
var originPath = Combine(rootOrigin, path); var originPath = Path.Combine(rootOrigin, path);
var backupPath = Combine(rootBackup, path); if (!File.Exists(originPath))
{
return;
}
var backupPath = Path.Combine(rootBackup, path);
Directory.CreateDirectory(Path.GetDirectoryName(backupPath));
try try
{ {
if (File.Exists(originPath)) File.Copy(originPath, backupPath);
File.Copy(originPath, backupPath);
} }
catch catch
{ {
@ -111,17 +95,9 @@ namespace Server.Misc
{ {
var timeStamp = GetTimeStamp(); var timeStamp = GetTimeStamp();
var root = GetRoot(); var root = Core.BaseDirectory;
var rootBackup = Combine(root, $"Backups/Crashed/{timeStamp}/"); var rootBackup = Path.Combine(root, $"Backups/Crashed/{timeStamp}/");
var rootOrigin = Combine(root, "Saves/"); var rootOrigin = Path.Combine(root, "Saves/");
// Create new directories
CreateDirectory(rootBackup);
CreateDirectory(rootBackup, "Accounts/");
CreateDirectory(rootBackup, "Items/");
CreateDirectory(rootBackup, "Mobiles/");
CreateDirectory(rootBackup, "Guilds/");
CreateDirectory(rootBackup, "Regions/");
// Copy files // Copy files
CopyFile(rootOrigin, rootBackup, "Accounts/Accounts.xml"); CopyFile(rootOrigin, rootBackup, "Accounts/Accounts.xml");
@ -157,12 +133,12 @@ namespace Server.Misc
var timeStamp = GetTimeStamp(); var timeStamp = GetTimeStamp();
var fileName = $"Crash {timeStamp}.log"; var fileName = $"Crash {timeStamp}.log";
var root = GetRoot(); var root = Core.BaseDirectory;
var filePath = Combine(root, fileName); var filePath = Path.Combine(root, fileName);
using (var op = new StreamWriter(filePath)) using (var op = new StreamWriter(filePath))
{ {
var ver = Core.Assembly.GetName().Version ?? new Version("0.0.0.0"); var ver = Core.Version;
op.WriteLine("Server Crash Report"); op.WriteLine("Server Crash Report");
op.WriteLine("==================="); op.WriteLine("===================");
@ -170,7 +146,7 @@ namespace Server.Misc
op.WriteLine($"ModernUO Version {ver.Major}.{ver.Minor}, Build {ver.Build}.{ver.Revision}"); op.WriteLine($"ModernUO Version {ver.Major}.{ver.Minor}, Build {ver.Build}.{ver.Revision}");
op.WriteLine("Operating System: {0}", Environment.OSVersion); op.WriteLine("Operating System: {0}", Environment.OSVersion);
op.WriteLine(".NET Framework: {0}", Environment.Version); op.WriteLine(".NET Framework: {0}", Environment.Version);
op.WriteLine("Time: {0}", DateTime.UtcNow); op.WriteLine("Time: {0}", timeStamp);
try try
{ {
@ -209,12 +185,16 @@ namespace Server.Misc
op.Write("+ {0}:", state); op.Write("+ {0}:", state);
if (state.Account is Account a) if (state.Account is Account a)
{
op.Write(" (account = {0})", a.Username); op.Write(" (account = {0})", a.Username);
}
var m = state.Mobile; var m = state.Mobile;
if (m != null) if (m != null)
{
op.Write(" (mobile = 0x{0:X} '{1}')", m.Serial.Value, m.Name); op.Write(" (mobile = 0x{0:X} '{1}')", m.Serial.Value, m.Name);
}
op.WriteLine(); op.WriteLine();
} }