diff --git a/Torch.Server/Initializer.cs b/Torch.Server/Initializer.cs
new file mode 100644
index 0000000..933d683
--- /dev/null
+++ b/Torch.Server/Initializer.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Net;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using NLog;
+using Torch.Utils;
+
+namespace Torch.Server
+{
+ public class Initializer
+ {
+ private static readonly Logger Log = LogManager.GetLogger(nameof(Initializer));
+ private bool _init;
+ private const string STEAMCMD_DIR = "steamcmd";
+ private const string STEAMCMD_ZIP = "temp.zip";
+ private static readonly string STEAMCMD_PATH = $"{STEAMCMD_DIR}\\steamcmd.exe";
+ private static readonly string RUNSCRIPT_PATH = $"{STEAMCMD_DIR}\\runscript.txt";
+ private const string RUNSCRIPT = @"force_install_dir ../
+login anonymous
+app_update 298740
+quit";
+
+ private TorchAssemblyResolver _resolver;
+ private TorchConfig _config;
+ private TorchServer _server;
+ private string _basePath;
+
+ public TorchConfig Config => _config;
+ public TorchServer Server => _server;
+
+ public Initializer(string basePath)
+ {
+ _basePath = basePath;
+ }
+
+ public bool Initialize(string[] args)
+ {
+ if (_init)
+ return false;
+
+ AppDomain.CurrentDomain.UnhandledException += HandleException;
+
+ if (!args.Contains("-noupdate"))
+ RunSteamCmd();
+
+ _resolver = new TorchAssemblyResolver(Path.Combine(_basePath, "DedicatedServer64"));
+ _config = InitConfig();
+ if (!_config.Parse(args))
+ return false;
+
+ if (!string.IsNullOrEmpty(_config.WaitForPID))
+ {
+ try
+ {
+ var pid = int.Parse(_config.WaitForPID);
+ var waitProc = Process.GetProcessById(pid);
+ Log.Info("Continuing in 5 seconds.");
+ Thread.Sleep(5000);
+ if (!waitProc.HasExited)
+ {
+ Log.Warn($"Killing old process {pid}.");
+ waitProc.Kill();
+ }
+
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+
+ _init = true;
+ return true;
+ }
+
+ public void Run()
+ {
+ _server = new TorchServer(_config);
+ _server.Init();
+
+ if (_config.NoGui || _config.Autostart)
+ {
+ new Thread(_server.Start).Start();
+ }
+
+ if (!_config.NoGui)
+ {
+ new TorchUI(_server).ShowDialog();
+ }
+
+ _resolver?.Dispose();
+ }
+
+ private TorchConfig InitConfig()
+ {
+ var configName = "Torch.cfg";
+ var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
+ if (File.Exists(configName))
+ {
+ Log.Info($"Loading config {configPath}");
+ return TorchConfig.LoadFrom(configPath);
+ }
+ else
+ {
+ Log.Info($"Generating default config at {configPath}");
+ var config = new TorchConfig { InstancePath = Path.GetFullPath("Instance") };
+ config.Save(configPath);
+ return config;
+ }
+ }
+
+ private static void RunSteamCmd()
+ {
+ var log = LogManager.GetLogger("SteamCMD");
+
+ if (!Directory.Exists(STEAMCMD_DIR))
+ {
+ Directory.CreateDirectory(STEAMCMD_DIR);
+ }
+
+ if (!File.Exists(RUNSCRIPT_PATH))
+ File.WriteAllText(RUNSCRIPT_PATH, RUNSCRIPT);
+
+ if (!File.Exists(STEAMCMD_PATH))
+ {
+ try
+ {
+ log.Info("Downloading SteamCMD.");
+ using (var client = new WebClient())
+ client.DownloadFile("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip", STEAMCMD_ZIP);
+
+ ZipFile.ExtractToDirectory(STEAMCMD_ZIP, STEAMCMD_DIR);
+ File.Delete(STEAMCMD_ZIP);
+ log.Info("SteamCMD downloaded successfully!");
+ }
+ catch
+ {
+ log.Error("Failed to download SteamCMD, unable to update the DS.");
+ return;
+ }
+ }
+
+ log.Info("Checking for DS updates.");
+ var steamCmdProc = new ProcessStartInfo(STEAMCMD_PATH, "+runscript runscript.txt")
+ {
+ WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), STEAMCMD_DIR),
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ StandardOutputEncoding = Encoding.ASCII
+ };
+ var cmd = Process.Start(steamCmdProc);
+
+ // ReSharper disable once PossibleNullReferenceException
+ while (!cmd.HasExited)
+ {
+ log.Info(cmd.StandardOutput.ReadLine());
+ Thread.Sleep(100);
+ }
+ }
+
+
+ private void HandleException(object sender, UnhandledExceptionEventArgs e)
+ {
+ var ex = (Exception)e.ExceptionObject;
+ Log.Fatal(ex);
+ Console.WriteLine("Exiting in 5 seconds.");
+ Thread.Sleep(5000);
+ if (_config.RestartOnCrash)
+ {
+ var exe = typeof(Program).Assembly.Location;
+ _config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
+ Process.Start(exe, _config.ToString());
+ }
+ //1627 = Function failed during execution.
+ Environment.Exit(1627);
+ }
+ }
+}
diff --git a/Torch.Server/Program.cs b/Torch.Server/Program.cs
index 4a4fac9..efcc40a 100644
--- a/Torch.Server/Program.cs
+++ b/Torch.Server/Program.cs
@@ -25,6 +25,7 @@ using System.IO.Compression;
using System.Net;
using System.Security.Policy;
using Torch.Server.Managers;
+using Torch.Utils;
using VRage.FileSystem;
using VRageRender;
@@ -32,268 +33,32 @@ namespace Torch.Server
{
internal static class Program
{
- private static ITorchServer _server;
- private static Logger _log = LogManager.GetLogger("Torch");
- private static bool _restartOnCrash;
- private static TorchConfig _config;
- private static bool _steamCmdDone;
-
- ///
+ ///
/// This method must *NOT* load any types/assemblies from the vanilla game, otherwise automatic updates will fail.
- ///
+ ///
[STAThread]
public static void Main(string[] args)
{
//Ensures that all the files are downloaded in the Torch directory.
- Directory.SetCurrentDirectory(new FileInfo(typeof(Program).Assembly.Location).Directory.ToString());
-
- foreach (var file in Directory.GetFiles(Directory.GetCurrentDirectory(), "*.old"))
- File.Delete(file);
-
- AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ var workingDir = new FileInfo(typeof(Program).Assembly.Location).Directory.ToString();
+ var binDir = Path.Combine(workingDir, "DedicatedServer64");
+ Directory.SetCurrentDirectory(workingDir);
if (!Environment.UserInteractive)
{
using (var service = new TorchService())
+ using (new TorchAssemblyResolver(binDir))
{
ServiceBase.Run(service);
}
return;
}
- //CommandLine reflection triggers assembly loading, so DS update must be completely separated.
- if (!args.Contains("-noupdate"))
- {
- if (!Directory.Exists("DedicatedServer64"))
- {
- _log.Error("Game libraries not found. Press the Enter key to install the dedicated server.");
- Console.ReadLine();
- }
- RunSteamCmd();
- }
-
- InitConfig();
-
- if (!_config.Parse(args))
+ var initializer = new Initializer(workingDir);
+ if (!initializer.Initialize(args))
return;
- if (!string.IsNullOrEmpty(_config.WaitForPID))
- {
- try
- {
- var pid = int.Parse(_config.WaitForPID);
- var waitProc = Process.GetProcessById(pid);
- _log.Info("Continuing in 5 seconds.");
- Thread.Sleep(5000);
- if (!waitProc.HasExited)
- {
- _log.Warn($"Killing old process {pid}.");
- waitProc.Kill();
- }
-
- }
- catch
- {
- // ignored
- }
- }
-
- _restartOnCrash = _config.RestartOnCrash;
- RunServer(_config);
- }
-
- public static void InitConfig()
- {
- var configName = "Torch.cfg";
- var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
- if (File.Exists(configName))
- {
- _log.Info($"Loading config {configPath}");
- _config = TorchConfig.LoadFrom(configPath);
- }
- else
- {
- _log.Info($"Generating default config at {configPath}");
- _config = new TorchConfig { InstancePath = Path.GetFullPath("Instance") };
- _config.Save(configPath);
- }
- }
-
- private const string STEAMCMD_DIR = "steamcmd";
- private const string STEAMCMD_ZIP = "temp.zip";
- private static readonly string STEAMCMD_PATH = $"{STEAMCMD_DIR}\\steamcmd.exe";
- private static readonly string RUNSCRIPT_PATH = $"{STEAMCMD_DIR}\\runscript.txt";
- private const string RUNSCRIPT = @"force_install_dir ../
-login anonymous
-app_update 298740
-quit";
-
- public static void RunSteamCmd()
- {
- if (_steamCmdDone)
- return;
-
- var log = LogManager.GetLogger("SteamCMD");
-
- if (!Directory.Exists(STEAMCMD_DIR))
- {
- Directory.CreateDirectory(STEAMCMD_DIR);
- }
-
- if (!File.Exists(RUNSCRIPT_PATH))
- File.WriteAllText(RUNSCRIPT_PATH, RUNSCRIPT);
-
- if (!File.Exists(STEAMCMD_PATH))
- {
- try
- {
- log.Info("Downloading SteamCMD.");
- using (var client = new WebClient())
- client.DownloadFile("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip", STEAMCMD_ZIP);
-
- ZipFile.ExtractToDirectory(STEAMCMD_ZIP, STEAMCMD_DIR);
- File.Delete(STEAMCMD_ZIP);
- log.Info("SteamCMD downloaded successfully!");
- }
- catch
- {
- log.Error("Failed to download SteamCMD, unable to update the DS.");
- return;
- }
- }
-
- log.Info("Checking for DS updates.");
- var steamCmdProc = new ProcessStartInfo(STEAMCMD_PATH, "+runscript runscript.txt")
- {
- WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), STEAMCMD_DIR),
- UseShellExecute = false,
- RedirectStandardOutput = true,
- StandardOutputEncoding = Encoding.ASCII
- };
- var cmd = Process.Start(steamCmdProc);
-
- // ReSharper disable once PossibleNullReferenceException
- while (!cmd.HasExited)
- {
- log.Info(cmd.StandardOutput.ReadLine());
- Thread.Sleep(100);
- }
-
- _steamCmdDone = true;
- }
-
- public static void RunServer(TorchConfig config)
- {
-
-
- /*
- if (!parser.ParseArguments(args, config))
- {
- _log.Error($"Parsing arguments failed: {string.Join(" ", args)}");
- return;
- }
-
- if (!string.IsNullOrEmpty(config.Config) && File.Exists(config.Config))
- {
- config = ServerConfig.LoadFrom(config.Config);
- parser.ParseArguments(args, config);
- }*/
-
- //RestartOnCrash autostart autosave=15
- //gamepath ="C:\Program Files\Space Engineers DS" instance="Hydro Survival" instancepath="C:\ProgramData\SpaceEngineersDedicated\Hydro Survival"
-
- /*
- if (config.InstallService)
- {
- var serviceName = $"\"Torch - {config.InstanceName}\"";
- // Working on installing the service properly instead of with sc.exe
- _log.Info($"Installing service '{serviceName}");
- var exePath = $"\"{Assembly.GetExecutingAssembly().Location}\"";
- var createInfo = new ServiceCreateInfo
- {
- Name = config.InstanceName,
- BinaryPath = exePath,
- };
- _log.Info("Service Installed");
-
- var runArgs = string.Join(" ", args.Skip(1));
- _log.Info($"Installing Torch as a service with arguments '{runArgs}'");
- var startInfo = new ProcessStartInfo
- {
- FileName = "sc.exe",
- Arguments = $"create Torch binPath=\"{Assembly.GetExecutingAssembly().Location} {runArgs}\"",
- CreateNoWindow = true,
- UseShellExecute = true,
- Verb = "runas"
- };
- Process.Start(startInfo).WaitForExit();
- _log.Info("Torch service installed");
- return;
- }
-
- if (config.UninstallService)
- {
- _log.Info("Uninstalling Torch service");
- var startInfo = new ProcessStartInfo
- {
- FileName = "sc.exe",
- Arguments = "delete Torch",
- CreateNoWindow = true,
- UseShellExecute = true,
- Verb = "runas"
- };
- Process.Start(startInfo).WaitForExit();
- _log.Info("Torch service uninstalled");
- return;
- }*/
-
- _server = new TorchServer(config);
-
- _server.Init();
- if (config.NoGui || config.Autostart)
- {
- new Thread(() => _server.Start()).Start();
- }
-
- if (!config.NoGui)
- {
- var ui = new TorchUI((TorchServer)_server);
- ui.ShowDialog();
- }
- }
-
- private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
- {
- try
- {
- var basePath = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location), "DedicatedServer64");
- string asmPath = Path.Combine(basePath, new AssemblyName(args.Name).Name + ".dll");
- if (File.Exists(asmPath))
- return Assembly.LoadFrom(asmPath);
- }
- catch
- {
- // ignored
- }
-
- return null;
- }
-
- private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- var ex = (Exception)e.ExceptionObject;
- _log.Fatal(ex);
- Console.WriteLine("Exiting in 5 seconds.");
- Thread.Sleep(5000);
- if (_restartOnCrash)
- {
- var exe = typeof(Program).Assembly.Location;
- _config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
- Process.Start(exe, _config.ToString());
- }
- //1627 = Function failed during execution.
- Environment.Exit(1627);
+ initializer.Run();
}
}
}
diff --git a/Torch.Server/Torch.Server.csproj b/Torch.Server/Torch.Server.csproj
index 4d85e77..0f6489f 100644
--- a/Torch.Server/Torch.Server.csproj
+++ b/Torch.Server/Torch.Server.csproj
@@ -193,6 +193,7 @@
AssemblyInfo.tt
+
diff --git a/Torch.Server/TorchConfig.cs b/Torch.Server/TorchConfig.cs
index 669f145..bb1c8ad 100644
--- a/Torch.Server/TorchConfig.cs
+++ b/Torch.Server/TorchConfig.cs
@@ -8,6 +8,7 @@ using NLog;
namespace Torch.Server
{
+ // TODO: redesign this gerbage
public class TorchConfig : CommandLine, ITorchConfig
{
private static Logger _log = LogManager.GetLogger("Config");
diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs
index ca1ee43..c5ae5a2 100644
--- a/Torch.Server/TorchServer.cs
+++ b/Torch.Server/TorchServer.cs
@@ -144,9 +144,17 @@ namespace Torch.Server
VRage.Service.ExitListenerSTA.OnExit += delegate { MySandboxGame.Static?.Exit(); };
base.Start();
- //Stops RunInternal from calling MyFileSystem.InitUserSpecific(null), we call it in InstanceManager.
+ // Stops RunInternal from calling MyFileSystem.InitUserSpecific(null), we call it in InstanceManager.
MySandboxGame.IsReloading = true;
- _dsRunInternal.Invoke();
+ try
+ {
+ _dsRunInternal.Invoke();
+ }
+ catch (TargetInvocationException e)
+ {
+ // Makes log formatting a little nicer.
+ throw e.InnerException ?? e;
+ }
MySandboxGame.Log.Close();
State = ServerState.Stopped;
diff --git a/Torch.Server/TorchService.cs b/Torch.Server/TorchService.cs
index ca8edc7..e33fda3 100644
--- a/Torch.Server/TorchService.cs
+++ b/Torch.Server/TorchService.cs
@@ -14,13 +14,15 @@ namespace Torch.Server
{
public const string Name = "Torch (SEDS)";
private TorchServer _server;
- private static Logger _log = LogManager.GetLogger("Torch");
+ private Initializer _initializer;
public TorchService()
{
- ServiceName = Name;
+ var workingDir = new FileInfo(typeof(TorchService).Assembly.Location).Directory.ToString();
+ Directory.SetCurrentDirectory(workingDir);
+ _initializer = new Initializer(workingDir);
- CanHandlePowerEvent = true;
+ ServiceName = Name;
CanHandleSessionChangeEvent = false;
CanPauseAndContinue = false;
CanStop = true;
@@ -31,17 +33,8 @@ namespace Torch.Server
{
base.OnStart(args);
- string configName = args.Length > 0 ? args[0] : "Torch.cfg";
- var options = new TorchConfig("Torch");
- if (File.Exists(configName))
- options = TorchConfig.LoadFrom(configName);
- else
- options.Save(configName);
-
- _server = new TorchServer(options);
- _server.Init();
- _server.RunArgs = args;
- Task.Run(() => _server.Start());
+ _initializer.Initialize(args);
+ _initializer.Run();
}
///
@@ -50,17 +43,5 @@ namespace Torch.Server
_server.Stop();
base.OnStop();
}
-
- ///
- protected override void OnShutdown()
- {
- base.OnShutdown();
- }
-
- ///
- protected override bool OnPowerEvent(PowerBroadcastStatus powerStatus)
- {
- return base.OnPowerEvent(powerStatus);
- }
}
}
diff --git a/Torch/Commands/Command.cs b/Torch/Commands/Command.cs
index dc95c51..7aedcab 100644
--- a/Torch/Commands/Command.cs
+++ b/Torch/Commands/Command.cs
@@ -62,7 +62,7 @@ namespace Torch.Commands
_parameters = commandMethod.GetParameters();
var sb = new StringBuilder();
- sb.Append($"/{string.Join(" ", Path)} ");
+ sb.Append($"!{string.Join(" ", Path)} ");
for (var i = 0; i < _parameters.Length; i++)
{
var param = _parameters[i];
diff --git a/Torch/Managers/UpdateManager.cs b/Torch/Managers/UpdateManager.cs
index 8702299..02d0a2a 100644
--- a/Torch/Managers/UpdateManager.cs
+++ b/Torch/Managers/UpdateManager.cs
@@ -108,6 +108,9 @@ namespace Torch.Managers
private async void CheckAndUpdateTorch()
{
+ // Doesn't work properly or reliably, TODO update when Jenkins is fully configured
+ return;
+
if (!Torch.Config.GetTorchUpdates)
return;
diff --git a/Torch/TorchBase.cs b/Torch/TorchBase.cs
index 7bdc650..3c6d361 100644
--- a/Torch/TorchBase.cs
+++ b/Torch/TorchBase.cs
@@ -57,14 +57,19 @@ namespace Torch
///
public string[] RunArgs { get; set; }
///
+ [Obsolete("Use GetManager() or the [Dependency] attribute.")]
public IPluginManager Plugins { get; protected set; }
///
+ [Obsolete("Use GetManager() or the [Dependency] attribute.")]
public IMultiplayerManager Multiplayer { get; protected set; }
///
+ [Obsolete("Use GetManager() or the [Dependency] attribute.")]
public EntityManager Entities { get; protected set; }
///
+ [Obsolete("Use GetManager() or the [Dependency] attribute.")]
public INetworkManager Network { get; protected set; }
///
+ [Obsolete("Use GetManager() or the [Dependency] attribute.")]
public CommandManager Commands { get; protected set; }
///
public event Action SessionLoading;