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:
parent
76a9729f61
commit
55ae0f8778
9 changed files with 216 additions and 160 deletions
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue