diff --git a/Torch.API/ITorchConfig.cs b/Torch.API/ITorchConfig.cs index 077d7b9..34107bc 100644 --- a/Torch.API/ITorchConfig.cs +++ b/Torch.API/ITorchConfig.cs @@ -22,7 +22,6 @@ namespace Torch bool ShouldUpdatePlugins { get; } bool ShouldUpdateTorch { get; } int TickTimeout { get; set; } - string WaitForPID { get; set; } string ChatName { get; set; } string ChatColor { get; set; } string TestPlugin { get; set; } diff --git a/Torch.Server/Initializer.cs b/Torch.Server/Initializer.cs index 83616e9..40ef110 100644 --- a/Torch.Server/Initializer.cs +++ b/Torch.Server/Initializer.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; +using Microsoft.Extensions.Configuration; using NLog; using NLog.Targets; using Sandbox.Engine.Utils; @@ -42,7 +43,7 @@ namespace Torch.Server ConfigPersistent = torchConfig; } - public bool Initialize(string[] args) + public bool Initialize(IConfiguration configuration) { if (_init) return false; @@ -54,16 +55,15 @@ namespace Torch.Server LogManager.ReconfigExistingLoggers(); Log.Debug("Debug logging enabled."); #endif - - // This is what happens when Keen is bad and puts extensions into the System namespace. - if (!Enumerable.Contains(args, "-noupdate")) + + if (!configuration.GetValue("noupdate", false)) RunSteamCmd(); - if (!string.IsNullOrEmpty(Config.WaitForPID)) + if (configuration.GetSection("waitForPid") is { } processPid) { try { - var pid = int.Parse(Config.WaitForPID); + var pid = processPid.Get(); var waitProc = Process.GetProcessById(pid); Log.Info("Continuing in 5 seconds."); Log.Warn($"Waiting for process {pid} to close"); diff --git a/Torch.Server/Program.cs b/Torch.Server/Program.cs index 74e14d1..382ff88 100644 --- a/Torch.Server/Program.cs +++ b/Torch.Server/Program.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Xml; using NLog; using NLog.Config; using NLog.Targets; @@ -13,31 +15,21 @@ namespace Torch.Server [STAThread] public static void Main(string[] args) { - var context = CreateApplicationContext(); - - SetupLogging(); - - var oldTorchCfg = Path.Combine(context.TorchDirectory.FullName, "Torch.cfg"); - var torchCfg = Path.Combine(context.InstanceDirectory.FullName, "Torch.cfg"); + var configurationBuilder = new ConfigurationBuilder() + .AddEnvironmentVariables("TORCH") + .AddCommandLine(args); + var configuration = configurationBuilder.Build(); - if (File.Exists(oldTorchCfg)) - File.Move(oldTorchCfg, torchCfg); + var context = CreateApplicationContext(configuration); - var config = Persistent.Load(torchCfg); - config.Data.InstanceName = context.InstanceName; - config.Data.InstancePath = context.InstanceDirectory.FullName; + SetupLogging(context); + var config = SetupConfiguration(context, configurationBuilder); - if (!config.Data.Parse(args)) - { - Console.WriteLine("Invalid arguments"); - Environment.Exit(1); - } - var handler = new UnhandledExceptionHandler(config.Data); AppDomain.CurrentDomain.UnhandledException += handler.OnUnhandledException; var initializer = new Initializer(config); - if (!initializer.Initialize(args)) + if (!initializer.Initialize(configuration)) Environment.Exit(1); #if DEBUG @@ -46,63 +38,14 @@ namespace Torch.Server TorchLauncher.Launch(context.TorchDirectory.FullName, Path.Combine(context.TorchDirectory.FullName, "torch64"), context.GameBinariesDirectory.FullName); #endif - - CopyNative(); - + initializer.Run(); } - private static void CopyNative() + private static void SetupLogging(IApplicationContext context) { - var log = LogManager.GetLogger("TorchLauncher"); - - if (ApplicationContext.Current.GameFilesDirectory.Attributes.HasFlag(FileAttributes.ReadOnly)) - { - log.Warn("Torch directory is readonly. You should copy steam_api64.dll, Havok.dll from bin manually"); - return; - } - - try - { - var apiSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "steam_api64.dll"); - var apiTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "steam_api64.dll"); - if (!File.Exists(apiTarget)) - { - File.Copy(apiSource, apiTarget); - } - else if (File.GetLastWriteTime(apiTarget) < ApplicationContext.Current.GameBinariesDirectory.LastWriteTime) - { - File.Delete(apiTarget); - File.Copy(apiSource, apiTarget); - } - - var havokSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "Havok.dll"); - var havokTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "Havok.dll"); - - if (!File.Exists(havokTarget)) - { - File.Copy(havokSource, havokTarget); - } - else if (File.GetLastWriteTime(havokTarget) < File.GetLastWriteTime(havokSource)) - { - File.Delete(havokTarget); - File.Copy(havokSource, havokTarget); - } - } - catch (UnauthorizedAccessException) - { - // file is being used by another process, probably previous torch has not been closed yet - } - catch (Exception e) - { - log.Error(e); - } - } - - private static void SetupLogging() - { - var oldNlog = Path.Combine(ApplicationContext.Current.TorchDirectory.FullName, "NLog.config"); - var newNlog = Path.Combine(ApplicationContext.Current.InstanceDirectory.FullName, "NLog.config"); + var oldNlog = Path.Combine(context.TorchDirectory.FullName, "NLog.config"); + var newNlog = Path.Combine(context.InstanceDirectory.FullName, "NLog.config"); if (File.Exists(oldNlog) && !File.ReadAllText(oldNlog).Contains("FlowDocument")) File.Move(oldNlog, newNlog); else if (!File.Exists(newNlog)) @@ -111,22 +54,47 @@ namespace Torch.Server Target.Register(nameof(LogViewerTarget)); TorchLogManager.RegisterTargets(Environment.GetEnvironmentVariable("TORCH_LOG_EXTENSIONS_PATH") ?? - Path.Combine(ApplicationContext.Current.InstanceDirectory.FullName, "LoggingExtensions")); + Path.Combine(context.InstanceDirectory.FullName, "LoggingExtensions")); TorchLogManager.SetConfiguration(new XmlLoggingConfiguration(newNlog)); } - private static IApplicationContext CreateApplicationContext() + private static Persistent SetupConfiguration(IApplicationContext context, IConfigurationBuilder builder) { - var isService = Environment.GetEnvironmentVariable("TORCH_SERVICE") - ?.Equals(bool.TrueString, StringComparison.OrdinalIgnoreCase) ?? false; + var oldTorchCfg = Path.Combine(context.TorchDirectory.FullName, "Torch.cfg"); + var torchCfg = Path.Combine(context.InstanceDirectory.FullName, "Torch.cfg"); + + if (File.Exists(oldTorchCfg)) + File.Move(oldTorchCfg, torchCfg); + + var configurationSource = new XmlConfigurationSource + { + Path = torchCfg + }; + + configurationSource.ResolveFileProvider(); + builder.Sources.Insert(0, configurationSource); + + var configuration = builder.Build(); + + var config = new Persistent(torchCfg, configuration.Get()); + config.Data.InstanceName = context.InstanceName; + config.Data.InstancePath = context.InstanceDirectory.FullName; + + return config; + } + + private static IApplicationContext CreateApplicationContext(IConfiguration configuration) + { + var isService = configuration.GetValue("service", false); var workingDir = AppContext.BaseDirectory; - var gamePath = Environment.GetEnvironmentVariable("TORCH_GAME_PATH") ?? workingDir; + var gamePath = configuration.GetValue("gamePath", workingDir); var binDir = Path.Combine(gamePath, "DedicatedServer64"); + Directory.SetCurrentDirectory(gamePath); - var instanceName = Environment.GetEnvironmentVariable("TORCH_INSTANCE") ?? "Instance"; + var instanceName = configuration.GetValue("instanceName", "Instance"); string instancePath; if (Path.IsPathRooted(instanceName)) @@ -136,7 +104,7 @@ namespace Torch.Server } else { - instancePath = Directory.CreateDirectory(instanceName).FullName; + instancePath = Directory.CreateDirectory(instanceName!).FullName; } return new ApplicationContext(new(workingDir), new(gamePath), new(binDir), diff --git a/Torch.Server/Torch.Server.csproj b/Torch.Server/Torch.Server.csproj index 5b84758..991eb54 100644 --- a/Torch.Server/Torch.Server.csproj +++ b/Torch.Server/Torch.Server.csproj @@ -38,6 +38,10 @@ + + + + diff --git a/Torch.Server/TorchConfig.cs b/Torch.Server/TorchConfig.cs index 9068afe..6eb644f 100644 --- a/Torch.Server/TorchConfig.cs +++ b/Torch.Server/TorchConfig.cs @@ -71,10 +71,6 @@ namespace Torch.Server [Display(Name = "No GUI", Description = "Do not show the Torch UI.", GroupName = "Window")] public bool NoGui { get => _noGui; set => Set(value, ref _noGui); } - /// - [XmlIgnore, Arg("waitforpid", "Makes Torch wait for another process to exit.")] - public string WaitForPID { get; set; } - /// [Display(Name = "Update Torch", Description = "Check every start for new versions of torch.", GroupName = "Server")] public bool GetTorchUpdates { get => _getTorchUpdates; set => Set(value, ref _getTorchUpdates); } diff --git a/Torch/Utils/TorchLauncher.cs b/Torch/Utils/TorchLauncher.cs index e26a22b..6945ccd 100644 --- a/Torch/Utils/TorchLauncher.cs +++ b/Torch/Utils/TorchLauncher.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using NLog; using Torch.Event; using Torch.Managers.PatchManager; using VRage.Collections; @@ -11,11 +12,14 @@ namespace Torch.Utils { public static class TorchLauncher { + private static readonly ILogger Log = LogManager.GetCurrentClassLogger(); private static readonly MyConcurrentHashSet RegisteredAssemblies = new(); private static readonly Dictionary Assemblies = new(); public static void Launch(params string[] binaryPaths) { + CopyNative(); + foreach (var file in binaryPaths.SelectMany(path => Directory.EnumerateFiles(path, "*.dll"))) { try @@ -41,6 +45,51 @@ namespace Torch.Utils EventManager.AddDispatchShims(assembly); PatchManager.AddPatchShims(assembly); } + + private static void CopyNative() + { + if (ApplicationContext.Current.GameFilesDirectory.Attributes.HasFlag(FileAttributes.ReadOnly)) + { + Log.Warn("Torch directory is readonly. You should copy steam_api64.dll, Havok.dll from bin manually"); + return; + } + + try + { + var apiSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "steam_api64.dll"); + var apiTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "steam_api64.dll"); + if (!File.Exists(apiTarget)) + { + File.Copy(apiSource, apiTarget); + } + else if (File.GetLastWriteTime(apiTarget) < ApplicationContext.Current.GameBinariesDirectory.LastWriteTime) + { + File.Delete(apiTarget); + File.Copy(apiSource, apiTarget); + } + + var havokSource = Path.Combine(ApplicationContext.Current.GameBinariesDirectory.FullName, "Havok.dll"); + var havokTarget = Path.Combine(ApplicationContext.Current.GameFilesDirectory.FullName, "Havok.dll"); + + if (!File.Exists(havokTarget)) + { + File.Copy(havokSource, havokTarget); + } + else if (File.GetLastWriteTime(havokTarget) < File.GetLastWriteTime(havokSource)) + { + File.Delete(havokTarget); + File.Copy(havokSource, havokTarget); + } + } + catch (UnauthorizedAccessException) + { + // file is being used by another process, probably previous torch has not been closed yet + } + catch (Exception e) + { + Log.Error(e); + } + } private static Assembly CurrentDomainOnAssemblyResolve(object sender, ResolveEventArgs args) {