Split game initialization and starting into a separate thread and file.
This commit is contained in:
@@ -80,12 +80,12 @@ namespace Torch.API
|
||||
Task InvokeAsync(Action action, [CallerMemberName] string caller = "");
|
||||
|
||||
/// <summary>
|
||||
/// Start the Torch instance.
|
||||
/// Signals the torch instance to start, then blocks until it's started.
|
||||
/// </summary>
|
||||
void Start();
|
||||
|
||||
/// <summary>
|
||||
/// Stop the Torch instance.
|
||||
/// Signals the torch instance to stop, then blocks until it's stopped.
|
||||
/// </summary>
|
||||
void Stop();
|
||||
|
||||
|
@@ -90,7 +90,7 @@ quit";
|
||||
{
|
||||
var ui = new TorchUI(_server);
|
||||
if (_config.Autostart)
|
||||
new Thread(_server.Start).Start();
|
||||
_server.Start();
|
||||
ui.ShowDialog();
|
||||
}
|
||||
else
|
||||
|
@@ -146,6 +146,7 @@ namespace Torch.Server
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Start()
|
||||
{
|
||||
if (State != ServerState.Stopped)
|
||||
@@ -176,17 +177,19 @@ namespace Torch.Server
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restart the program. DOES NOT SAVE!
|
||||
/// Restart the program.
|
||||
/// </summary>
|
||||
public override void Restart()
|
||||
{
|
||||
Save(0).Wait();
|
||||
Stop();
|
||||
LogManager.Flush();
|
||||
|
||||
var exe = Assembly.GetExecutingAssembly().Location;
|
||||
((TorchConfig)Config).WaitForPID = Process.GetCurrentProcess().Id.ToString();
|
||||
Config.Autostart = true;
|
||||
Process.Start(exe, Config.ToString());
|
||||
Save(0).Wait();
|
||||
Stop();
|
||||
LogManager.Flush();
|
||||
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
|
||||
|
@@ -66,7 +66,7 @@ namespace Torch.Server
|
||||
private void BtnStart_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_server.GetManager<InstanceManager>().SaveConfig();
|
||||
new Thread(_server.Start).Start();
|
||||
_server.Start();
|
||||
}
|
||||
|
||||
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
||||
|
@@ -255,6 +255,7 @@
|
||||
<Compile Include="Views\CollectionEditor.xaml.cs">
|
||||
<DependentUpon>CollectionEditor.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="VRageGame.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Torch.API\Torch.API.csproj">
|
||||
|
@@ -343,7 +343,9 @@ namespace Torch
|
||||
Log.Info($"Executing assembly: {Assembly.GetEntryAssembly().FullName}");
|
||||
Log.Info($"Executing directory: {AppDomain.CurrentDomain.BaseDirectory}");
|
||||
|
||||
InitVRageInstance();
|
||||
_game = new VRageGame(this, TweakGameSettings, SteamAppName, SteamAppId, Config.InstancePath, RunArgs);
|
||||
if (!_game.WaitFor(VRageGame.GameState.Stopped, TimeSpan.FromMinutes(5)))
|
||||
Log.Warn("Failed to wait for game to be initialized");
|
||||
Managers.GetManager<PluginManager>().LoadPlugins();
|
||||
Managers.Attach();
|
||||
_init = true;
|
||||
@@ -357,95 +359,15 @@ namespace Torch
|
||||
public virtual void Dispose()
|
||||
{
|
||||
Managers.Detach();
|
||||
DisposeVRageInstance();
|
||||
_game.SignalDestroy();
|
||||
if (!_game.WaitFor(VRageGame.GameState.Destroyed, TimeSpan.FromSeconds(15)))
|
||||
Log.Warn("Failed to wait for the game to be destroyed");
|
||||
_game = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region VRage Instance Init/Destroy
|
||||
|
||||
#pragma warning disable 649
|
||||
[ReflectedGetter(Name = "m_plugins", Type = typeof(MyPlugins))]
|
||||
private static readonly Func<List<IPlugin>> _getVRagePluginList;
|
||||
#pragma warning restore 649
|
||||
|
||||
protected SpaceEngineersGame GameInstance { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets up the VRage instance.
|
||||
/// Any flags (ie <see cref="Sandbox.Engine.Platform.Game.IsDedicated"/>) must be set before this is called.
|
||||
/// </summary>
|
||||
protected virtual void InitVRageInstance()
|
||||
{
|
||||
bool dedicated = Sandbox.Engine.Platform.Game.IsDedicated;
|
||||
Environment.SetEnvironmentVariable("SteamAppId", SteamAppId.ToString());
|
||||
MyServiceManager.Instance.AddService<IMyGameService>(new MySteamService(dedicated, SteamAppId));
|
||||
if (dedicated && !MyGameService.HasGameServer)
|
||||
{
|
||||
Log.Warn("Steam service is not running! Please reinstall dedicated server.");
|
||||
return;
|
||||
}
|
||||
|
||||
SpaceEngineersGame.SetupBasicGameInfo();
|
||||
SpaceEngineersGame.SetupPerGameSettings();
|
||||
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion;
|
||||
MySessionComponentExtDebug.ForceDisable = true;
|
||||
MyPerGameSettings.SendLogToKeen = false;
|
||||
// SpaceEngineersGame.SetupAnalytics();
|
||||
|
||||
MyFileSystem.ExePath = Path.GetDirectoryName(typeof(SpaceEngineersGame).Assembly.Location);
|
||||
|
||||
TweakGameSettings();
|
||||
|
||||
MyInitializer.InvokeBeforeRun(SteamAppId, SteamAppName, Config.InstancePath);
|
||||
// MyInitializer.InitCheckSum();
|
||||
|
||||
|
||||
// Hook into the VRage plugin system for updates.
|
||||
_getVRagePluginList().Add(this);
|
||||
|
||||
if (!MySandboxGame.IsReloading)
|
||||
MyFileSystem.InitUserSpecific(dedicated ? null : MyGameService.UserId.ToString());
|
||||
MySandboxGame.IsReloading = dedicated;
|
||||
|
||||
// render init
|
||||
{
|
||||
IMyRender renderer = null;
|
||||
if (dedicated)
|
||||
{
|
||||
renderer = new MyNullRender();
|
||||
}
|
||||
else
|
||||
{
|
||||
MyPerformanceSettings preset = MyGuiScreenOptionsGraphics.GetPreset(MyRenderQualityEnum.NORMAL);
|
||||
MyRenderProxy.Settings.User = MyVideoSettingsManager.GetGraphicsSettingsFromConfig(ref preset)
|
||||
.PerformanceSettings.RenderSettings;
|
||||
MyStringId graphicsRenderer = MySandboxGame.Config.GraphicsRenderer;
|
||||
if (graphicsRenderer == MySandboxGame.DirectX11RendererKey)
|
||||
{
|
||||
renderer = new MyDX11Render(new MyRenderSettings?(MyRenderProxy.Settings));
|
||||
if (!renderer.IsSupported)
|
||||
{
|
||||
MySandboxGame.Log.WriteLine(
|
||||
"DirectX 11 renderer not supported. No renderer to revert back to.");
|
||||
renderer = null;
|
||||
}
|
||||
}
|
||||
if (renderer == null)
|
||||
{
|
||||
throw new MyRenderException(
|
||||
"The current version of the game requires a Dx11 card. \\n For more information please see : http://blog.marekrosa.org/2016/02/space-engineers-news-full-source-code_26.html",
|
||||
MyRenderExceptionEnum.GpuNotSupported);
|
||||
}
|
||||
MySandboxGame.Config.GraphicsRenderer = graphicsRenderer;
|
||||
}
|
||||
MyRenderProxy.Initialize(renderer);
|
||||
MyRenderProxy.GetRenderProfiler().SetAutocommit(false);
|
||||
MyRenderProxy.GetRenderProfiler().InitMemoryHack("MainEntryPoint");
|
||||
}
|
||||
|
||||
GameInstance = new SpaceEngineersGame(RunArgs);
|
||||
}
|
||||
private VRageGame _game;
|
||||
|
||||
/// <summary>
|
||||
/// Called after the basic game information is filled, but before the game is created.
|
||||
@@ -454,22 +376,6 @@ namespace Torch
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tears down the VRage instance
|
||||
/// </summary>
|
||||
protected virtual void DisposeVRageInstance()
|
||||
{
|
||||
GameInstance.Dispose();
|
||||
GameInstance = null;
|
||||
|
||||
MyGameService.ShutDown();
|
||||
|
||||
_getVRagePluginList().Remove(this);
|
||||
|
||||
MyInitializer.InvokeAfterRun();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual Task Save(long callerId)
|
||||
@@ -480,21 +386,17 @@ namespace Torch
|
||||
/// <inheritdoc/>
|
||||
public virtual void Start()
|
||||
{
|
||||
if (MySandboxGame.FatalErrorDuringInit)
|
||||
{
|
||||
Log.Warn($"Failed to start sandbox game: fatal error during init");
|
||||
return;
|
||||
}
|
||||
GameInstance.Run();
|
||||
_game.SignalStart();
|
||||
if (!_game.WaitFor(VRageGame.GameState.Running, TimeSpan.FromSeconds(15)))
|
||||
Log.Warn("Failed to wait for the game to be started");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void Stop()
|
||||
{
|
||||
if (IsOnGameThread())
|
||||
MySandboxGame.Static.Exit();
|
||||
else
|
||||
InvokeBlocking(MySandboxGame.Static.Exit);
|
||||
_game.SignalStop();
|
||||
if (!_game.WaitFor(VRageGame.GameState.Stopped, TimeSpan.FromSeconds(15)))
|
||||
Log.Warn("Failed to wait for the game to be stopped");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
268
Torch/VRageGame.cs
Normal file
268
Torch/VRageGame.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Havok;
|
||||
using NLog;
|
||||
using NLog.Fluent;
|
||||
using Sandbox;
|
||||
using Sandbox.Engine.Networking;
|
||||
using Sandbox.Engine.Platform.VideoMode;
|
||||
using Sandbox.Game;
|
||||
using SpaceEngineers.Game;
|
||||
using SpaceEngineers.Game.GUI;
|
||||
using Torch.Utils;
|
||||
using VRage;
|
||||
using VRage.FileSystem;
|
||||
using VRage.Game;
|
||||
using VRage.Game.SessionComponents;
|
||||
using VRage.GameServices;
|
||||
using VRage.Plugins;
|
||||
using VRage.Steam;
|
||||
using VRage.Utils;
|
||||
using VRageRender;
|
||||
|
||||
namespace Torch
|
||||
{
|
||||
public class VRageGame
|
||||
{
|
||||
private static readonly ILogger _log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
#pragma warning disable 649
|
||||
[ReflectedGetter(Name = "m_plugins", Type = typeof(MyPlugins))]
|
||||
private static readonly Func<List<IPlugin>> _getVRagePluginList;
|
||||
#pragma warning restore 649
|
||||
|
||||
private readonly TorchBase _torch;
|
||||
private readonly Action _tweakGameSettings;
|
||||
private readonly string _userDataPath;
|
||||
private readonly string _appName;
|
||||
private readonly uint _appSteamId;
|
||||
private readonly string[] _runArgs;
|
||||
private SpaceEngineersGame _game;
|
||||
private readonly Thread _updateThread;
|
||||
|
||||
private bool _startGame = false;
|
||||
private readonly AutoResetEvent _commandChanged = new AutoResetEvent(false);
|
||||
private bool _destroyGame = false;
|
||||
|
||||
private readonly AutoResetEvent _stateChangedEvent = new AutoResetEvent(false);
|
||||
private GameState _state;
|
||||
|
||||
public enum GameState
|
||||
{
|
||||
Creating,
|
||||
Stopped,
|
||||
Running,
|
||||
Destroyed
|
||||
}
|
||||
|
||||
internal VRageGame(TorchBase torch, Action tweakGameSettings, string appName, uint appSteamId,
|
||||
string userDataPath, string[] runArgs)
|
||||
{
|
||||
_torch = torch;
|
||||
_tweakGameSettings = tweakGameSettings;
|
||||
_appName = appName;
|
||||
_appSteamId = appSteamId;
|
||||
_userDataPath = userDataPath;
|
||||
_runArgs = runArgs;
|
||||
_updateThread = new Thread(Run);
|
||||
_updateThread.Start();
|
||||
}
|
||||
|
||||
private void StateChange(GameState s)
|
||||
{
|
||||
if (_state == s)
|
||||
return;
|
||||
_state = s;
|
||||
_stateChangedEvent.Set();
|
||||
}
|
||||
|
||||
private void Run()
|
||||
{
|
||||
StateChange(GameState.Creating);
|
||||
try
|
||||
{
|
||||
Create();
|
||||
_destroyGame = false;
|
||||
while (!_destroyGame)
|
||||
{
|
||||
StateChange(GameState.Stopped);
|
||||
_commandChanged.WaitOne();
|
||||
if (_startGame)
|
||||
{
|
||||
_startGame = false;
|
||||
DoStart();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Destroy();
|
||||
StateChange(GameState.Destroyed);
|
||||
}
|
||||
}
|
||||
|
||||
private void Create()
|
||||
{
|
||||
bool dedicated = Sandbox.Engine.Platform.Game.IsDedicated;
|
||||
Environment.SetEnvironmentVariable("SteamAppId", _appSteamId.ToString());
|
||||
MyServiceManager.Instance.AddService<IMyGameService>(new MySteamService(dedicated, _appSteamId));
|
||||
if (dedicated && !MyGameService.HasGameServer)
|
||||
{
|
||||
_log.Warn("Steam service is not running! Please reinstall dedicated server.");
|
||||
return;
|
||||
}
|
||||
|
||||
SpaceEngineersGame.SetupBasicGameInfo();
|
||||
SpaceEngineersGame.SetupPerGameSettings();
|
||||
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion;
|
||||
MySessionComponentExtDebug.ForceDisable = true;
|
||||
MyPerGameSettings.SendLogToKeen = false;
|
||||
// SpaceEngineersGame.SetupAnalytics();
|
||||
|
||||
MyFileSystem.ExePath = Path.GetDirectoryName(typeof(SpaceEngineersGame).Assembly.Location);
|
||||
|
||||
_tweakGameSettings();
|
||||
|
||||
MyFileSystem.Reset();
|
||||
MyInitializer.InvokeBeforeRun(_appSteamId, _appName, _userDataPath);
|
||||
// MyInitializer.InitCheckSum();
|
||||
|
||||
|
||||
// Hook into the VRage plugin system for updates.
|
||||
_getVRagePluginList().Add(_torch);
|
||||
|
||||
if (!MySandboxGame.IsReloading)
|
||||
MyFileSystem.InitUserSpecific(dedicated ? null : MyGameService.UserId.ToString());
|
||||
MySandboxGame.IsReloading = dedicated;
|
||||
|
||||
// render init
|
||||
{
|
||||
IMyRender renderer = null;
|
||||
if (dedicated)
|
||||
{
|
||||
renderer = new MyNullRender();
|
||||
}
|
||||
else
|
||||
{
|
||||
MyPerformanceSettings preset = MyGuiScreenOptionsGraphics.GetPreset(MyRenderQualityEnum.NORMAL);
|
||||
MyRenderProxy.Settings.User = MyVideoSettingsManager.GetGraphicsSettingsFromConfig(ref preset)
|
||||
.PerformanceSettings.RenderSettings;
|
||||
MyStringId graphicsRenderer = MySandboxGame.Config.GraphicsRenderer;
|
||||
if (graphicsRenderer == MySandboxGame.DirectX11RendererKey)
|
||||
{
|
||||
renderer = new MyDX11Render(new MyRenderSettings?(MyRenderProxy.Settings));
|
||||
if (!renderer.IsSupported)
|
||||
{
|
||||
MySandboxGame.Log.WriteLine(
|
||||
"DirectX 11 renderer not supported. No renderer to revert back to.");
|
||||
renderer = null;
|
||||
}
|
||||
}
|
||||
if (renderer == null)
|
||||
{
|
||||
throw new MyRenderException(
|
||||
"The current version of the game requires a Dx11 card. \\n For more information please see : http://blog.marekrosa.org/2016/02/space-engineers-news-full-source-code_26.html",
|
||||
MyRenderExceptionEnum.GpuNotSupported);
|
||||
}
|
||||
MySandboxGame.Config.GraphicsRenderer = graphicsRenderer;
|
||||
}
|
||||
MyRenderProxy.Initialize(renderer);
|
||||
MyRenderProxy.GetRenderProfiler().SetAutocommit(false);
|
||||
MyRenderProxy.GetRenderProfiler().InitMemoryHack("MainEntryPoint");
|
||||
}
|
||||
|
||||
_game = new SpaceEngineersGame(_runArgs);
|
||||
}
|
||||
|
||||
private void Destroy()
|
||||
{
|
||||
_game.Dispose();
|
||||
_game = null;
|
||||
|
||||
MyGameService.ShutDown();
|
||||
|
||||
_getVRagePluginList().Remove(_torch);
|
||||
|
||||
MyInitializer.InvokeAfterRun();
|
||||
}
|
||||
|
||||
private void DoStart()
|
||||
{
|
||||
if (MySandboxGame.FatalErrorDuringInit)
|
||||
{
|
||||
_log.Warn("Failed to start sandbox game: fatal error during init");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
StateChange(GameState.Running);
|
||||
_game.Run();
|
||||
}
|
||||
finally
|
||||
{
|
||||
StateChange(GameState.Stopped);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoStop()
|
||||
{
|
||||
ParallelTasks.Parallel.Scheduler.WaitForTasksToFinish(TimeSpan.FromSeconds(10.0));
|
||||
MySandboxGame.Static.Exit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals the game to stop itself.
|
||||
/// </summary>
|
||||
public void SignalStop()
|
||||
{
|
||||
_startGame = false;
|
||||
_game.Invoke(DoStop, $"{nameof(VRageGame)}::{nameof(SignalStop)}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals the game to start itself
|
||||
/// </summary>
|
||||
public void SignalStart()
|
||||
{
|
||||
_startGame = true;
|
||||
_commandChanged.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signals the game to destroy itself
|
||||
/// </summary>
|
||||
public void SignalDestroy()
|
||||
{
|
||||
_destroyGame = true;
|
||||
SignalStop();
|
||||
_commandChanged.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for the game to transition to the given state
|
||||
/// </summary>
|
||||
/// <param name="state">State to transition to</param>
|
||||
/// <param name="timeout">Timeout</param>
|
||||
/// <returns></returns>
|
||||
public bool WaitFor(GameState state, TimeSpan? timeout)
|
||||
{
|
||||
// Kinda icky, but we can't block the update and expect the state to change.
|
||||
if (Thread.CurrentThread == _updateThread)
|
||||
return _state == state;
|
||||
|
||||
DateTime? end = timeout.HasValue ? (DateTime?) (DateTime.Now + timeout.Value) : null;
|
||||
while (_state != state && (!end.HasValue || end > DateTime.Now + TimeSpan.FromSeconds(1)))
|
||||
if (end.HasValue)
|
||||
_stateChangedEvent.WaitOne(end.Value - DateTime.Now);
|
||||
else
|
||||
_stateChangedEvent.WaitOne();
|
||||
return _state == state;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user