Pull out game loop initialization from OpenRA.Program into OpenRA.Game and exception handling into its own class under OpenRA.Game/Support
This commit is contained in:
@@ -249,7 +249,14 @@ namespace OpenRA
|
|||||||
Settings = new Settings(Platform.ResolvePath(Path.Combine("^", "settings.yaml")), args);
|
Settings = new Settings(Platform.ResolvePath(Path.Combine("^", "settings.yaml")), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Initialize(Arguments args)
|
public static RunStatus InitializeAndRun(string[] args)
|
||||||
|
{
|
||||||
|
Initialize(new Arguments(args));
|
||||||
|
GC.Collect();
|
||||||
|
return Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Initialize(Arguments args)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Platform is {0}", Platform.CurrentPlatform);
|
Console.WriteLine("Platform is {0}", Platform.CurrentPlatform);
|
||||||
|
|
||||||
@@ -790,7 +797,7 @@ namespace OpenRA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static RunStatus Run()
|
static RunStatus Run()
|
||||||
{
|
{
|
||||||
if (Settings.Graphics.MaxFramerate < 1)
|
if (Settings.Graphics.MaxFramerate < 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -176,6 +176,7 @@
|
|||||||
<Compile Include="Server\ServerOrder.cs" />
|
<Compile Include="Server\ServerOrder.cs" />
|
||||||
<Compile Include="Server\TraitInterfaces.cs" />
|
<Compile Include="Server\TraitInterfaces.cs" />
|
||||||
<Compile Include="Support\Arguments.cs" />
|
<Compile Include="Support\Arguments.cs" />
|
||||||
|
<Compile Include="Support\ExceptionHandler.cs" />
|
||||||
<Compile Include="Support\LaunchArguments.cs" />
|
<Compile Include="Support\LaunchArguments.cs" />
|
||||||
<Compile Include="Support\PerfHistory.cs" />
|
<Compile Include="Support\PerfHistory.cs" />
|
||||||
<Compile Include="Support\Program.cs" />
|
<Compile Include="Support\Program.cs" />
|
||||||
|
|||||||
93
OpenRA.Game/Support/ExceptionHandler.cs
Normal file
93
OpenRA.Game/Support/ExceptionHandler.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OpenRA
|
||||||
|
{
|
||||||
|
public static class ExceptionHandler
|
||||||
|
{
|
||||||
|
public static void HandleFatalError(Exception ex)
|
||||||
|
{
|
||||||
|
var exceptionName = "exception-" + DateTime.UtcNow.ToString("yyyy-MM-ddTHHmmssZ", CultureInfo.InvariantCulture) + ".log";
|
||||||
|
Log.AddChannel("exception", exceptionName);
|
||||||
|
|
||||||
|
if (Game.EngineVersion != null)
|
||||||
|
Log.Write("exception", "OpenRA engine version {0}", Game.EngineVersion);
|
||||||
|
|
||||||
|
if (Game.ModData != null)
|
||||||
|
{
|
||||||
|
var mod = Game.ModData.Manifest.Metadata;
|
||||||
|
Log.Write("exception", "{0} mod version {1}", mod.Title, mod.Version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Game.OrderManager != null && Game.OrderManager.World != null && Game.OrderManager.World.Map != null)
|
||||||
|
{
|
||||||
|
var map = Game.OrderManager.World.Map;
|
||||||
|
Log.Write("exception", "on map {0} ({1} by {2}).", map.Uid, map.Title, map.Author);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Write("exception", "Date: {0:u}", DateTime.UtcNow);
|
||||||
|
Log.Write("exception", "Operating System: {0} ({1})", Platform.CurrentPlatform, Environment.OSVersion);
|
||||||
|
Log.Write("exception", "Runtime Version: {0}", Platform.RuntimeVersion);
|
||||||
|
var rpt = BuildExceptionReport(ex).ToString();
|
||||||
|
Log.Write("exception", "{0}", rpt);
|
||||||
|
Console.Error.WriteLine(rpt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringBuilder BuildExceptionReport(Exception ex)
|
||||||
|
{
|
||||||
|
return BuildExceptionReport(ex, new StringBuilder(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringBuilder AppendIndentedFormatLine(this StringBuilder sb, int indent, string format, params object[] args)
|
||||||
|
{
|
||||||
|
return sb.Append(new string(' ', indent * 2)).AppendFormat(format, args).AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringBuilder BuildExceptionReport(Exception ex, StringBuilder sb, int indent)
|
||||||
|
{
|
||||||
|
if (ex == null)
|
||||||
|
return sb;
|
||||||
|
|
||||||
|
sb.AppendIndentedFormatLine(indent, "Exception of type `{0}`: {1}", ex.GetType().FullName, ex.Message);
|
||||||
|
|
||||||
|
var tle = ex as TypeLoadException;
|
||||||
|
var oom = ex as OutOfMemoryException;
|
||||||
|
if (tle != null)
|
||||||
|
{
|
||||||
|
sb.AppendIndentedFormatLine(indent, "TypeName=`{0}`", tle.TypeName);
|
||||||
|
}
|
||||||
|
else if (oom != null)
|
||||||
|
{
|
||||||
|
var gcMemoryBeforeCollect = GC.GetTotalMemory(false);
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
|
GC.Collect();
|
||||||
|
sb.AppendIndentedFormatLine(indent, "GC Memory (post-collect)={0:N0}", GC.GetTotalMemory(false));
|
||||||
|
sb.AppendIndentedFormatLine(indent, "GC Memory (pre-collect)={0:N0}", gcMemoryBeforeCollect);
|
||||||
|
|
||||||
|
using (var p = Process.GetCurrentProcess())
|
||||||
|
{
|
||||||
|
sb.AppendIndentedFormatLine(indent, "Working Set={0:N0}", p.WorkingSet64);
|
||||||
|
sb.AppendIndentedFormatLine(indent, "Private Memory={0:N0}", p.PrivateMemorySize64);
|
||||||
|
sb.AppendIndentedFormatLine(indent, "Virtual Memory={0:N0}", p.VirtualMemorySize64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: more exception types
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ex.InnerException != null)
|
||||||
|
{
|
||||||
|
sb.AppendIndentedFormatLine(indent, "Inner");
|
||||||
|
BuildExceptionReport(ex.InnerException, sb, indent + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendIndentedFormatLine(indent, "{0}", ex.StackTrace);
|
||||||
|
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,10 +11,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace OpenRA
|
namespace OpenRA
|
||||||
{
|
{
|
||||||
@@ -31,109 +28,19 @@ namespace OpenRA
|
|||||||
static int Main(string[] args)
|
static int Main(string[] args)
|
||||||
{
|
{
|
||||||
if (Debugger.IsAttached || args.Contains("--just-die"))
|
if (Debugger.IsAttached || args.Contains("--just-die"))
|
||||||
return (int)Run(args);
|
return (int)Game.InitializeAndRun(args);
|
||||||
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += (_, e) => FatalError((Exception)e.ExceptionObject);
|
AppDomain.CurrentDomain.UnhandledException += (_, e) => ExceptionHandler.HandleFatalError((Exception)e.ExceptionObject);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return (int)Run(args);
|
return (int)Game.InitializeAndRun(args);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
FatalError(e);
|
ExceptionHandler.HandleFatalError(e);
|
||||||
return (int)RunStatus.Error;
|
return (int)RunStatus.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void FatalError(Exception ex)
|
|
||||||
{
|
|
||||||
var exceptionName = "exception-" + DateTime.UtcNow.ToString("yyyy-MM-ddTHHmmssZ", CultureInfo.InvariantCulture) + ".log";
|
|
||||||
Log.AddChannel("exception", exceptionName);
|
|
||||||
|
|
||||||
if (Game.EngineVersion != null)
|
|
||||||
Log.Write("exception", "OpenRA engine version {0}", Game.EngineVersion);
|
|
||||||
|
|
||||||
if (Game.ModData != null)
|
|
||||||
{
|
|
||||||
var mod = Game.ModData.Manifest.Metadata;
|
|
||||||
Log.Write("exception", "{0} mod version {1}", mod.Title, mod.Version);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Game.OrderManager != null && Game.OrderManager.World != null && Game.OrderManager.World.Map != null)
|
|
||||||
{
|
|
||||||
var map = Game.OrderManager.World.Map;
|
|
||||||
Log.Write("exception", "on map {0} ({1} by {2}).", map.Uid, map.Title, map.Author);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Write("exception", "Date: {0:u}", DateTime.UtcNow);
|
|
||||||
Log.Write("exception", "Operating System: {0} ({1})", Platform.CurrentPlatform, Environment.OSVersion);
|
|
||||||
Log.Write("exception", "Runtime Version: {0}", Platform.RuntimeVersion);
|
|
||||||
var rpt = BuildExceptionReport(ex).ToString();
|
|
||||||
Log.Write("exception", "{0}", rpt);
|
|
||||||
Console.Error.WriteLine(rpt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static StringBuilder BuildExceptionReport(Exception ex)
|
|
||||||
{
|
|
||||||
return BuildExceptionReport(ex, new StringBuilder(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static StringBuilder AppendIndentedFormatLine(this StringBuilder sb, int indent, string format, params object[] args)
|
|
||||||
{
|
|
||||||
return sb.Append(new string(' ', indent * 2)).AppendFormat(format, args).AppendLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
static StringBuilder BuildExceptionReport(Exception ex, StringBuilder sb, int indent)
|
|
||||||
{
|
|
||||||
if (ex == null)
|
|
||||||
return sb;
|
|
||||||
|
|
||||||
sb.AppendIndentedFormatLine(indent, "Exception of type `{0}`: {1}", ex.GetType().FullName, ex.Message);
|
|
||||||
|
|
||||||
var tle = ex as TypeLoadException;
|
|
||||||
var oom = ex as OutOfMemoryException;
|
|
||||||
if (tle != null)
|
|
||||||
{
|
|
||||||
sb.AppendIndentedFormatLine(indent, "TypeName=`{0}`", tle.TypeName);
|
|
||||||
}
|
|
||||||
else if (oom != null)
|
|
||||||
{
|
|
||||||
var gcMemoryBeforeCollect = GC.GetTotalMemory(false);
|
|
||||||
GC.Collect();
|
|
||||||
GC.WaitForPendingFinalizers();
|
|
||||||
GC.Collect();
|
|
||||||
sb.AppendIndentedFormatLine(indent, "GC Memory (post-collect)={0:N0}", GC.GetTotalMemory(false));
|
|
||||||
sb.AppendIndentedFormatLine(indent, "GC Memory (pre-collect)={0:N0}", gcMemoryBeforeCollect);
|
|
||||||
|
|
||||||
using (var p = Process.GetCurrentProcess())
|
|
||||||
{
|
|
||||||
sb.AppendIndentedFormatLine(indent, "Working Set={0:N0}", p.WorkingSet64);
|
|
||||||
sb.AppendIndentedFormatLine(indent, "Private Memory={0:N0}", p.PrivateMemorySize64);
|
|
||||||
sb.AppendIndentedFormatLine(indent, "Virtual Memory={0:N0}", p.VirtualMemorySize64);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: more exception types
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ex.InnerException != null)
|
|
||||||
{
|
|
||||||
sb.AppendIndentedFormatLine(indent, "Inner");
|
|
||||||
BuildExceptionReport(ex.InnerException, sb, indent + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.AppendIndentedFormatLine(indent, "{0}", ex.StackTrace);
|
|
||||||
|
|
||||||
return sb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static RunStatus Run(string[] args)
|
|
||||||
{
|
|
||||||
Game.Initialize(new Arguments(args));
|
|
||||||
GC.Collect();
|
|
||||||
return Game.Run();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user