diff --git a/Torch.API/ITorchConfig.cs b/Torch.API/ITorchConfig.cs index ae7e99d..73a24bf 100644 --- a/Torch.API/ITorchConfig.cs +++ b/Torch.API/ITorchConfig.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Torch.API; namespace Torch { @@ -24,7 +25,11 @@ namespace Torch string ChatColor { get; set; } string TestPlugin { get; set; } bool DisconnectOnRestart { get; set; } + int WindowWidth { get; set; } + int WindowHeight { get; set; } + int FontSize { get; set; } + UGCServiceType UgcServiceType { get; set; } - bool Save(string path = null); + void Save(string path = null); } } \ No newline at end of file diff --git a/Torch.API/Torch.API.csproj b/Torch.API/Torch.API.csproj index 8ebcaaa..fc502c2 100644 --- a/Torch.API/Torch.API.csproj +++ b/Torch.API/Torch.API.csproj @@ -184,8 +184,8 @@ + - diff --git a/Torch.API/UGCServiceType.cs b/Torch.API/UGCServiceType.cs new file mode 100644 index 0000000..ce84588 --- /dev/null +++ b/Torch.API/UGCServiceType.cs @@ -0,0 +1,8 @@ +namespace Torch.API +{ + public enum UGCServiceType + { + Steam, + EOS + } +} \ No newline at end of file diff --git a/Torch.Server/Commands/WhitelistCommands.cs b/Torch.Server/Commands/WhitelistCommands.cs index de8ccf5..729c6cc 100644 --- a/Torch.Server/Commands/WhitelistCommands.cs +++ b/Torch.Server/Commands/WhitelistCommands.cs @@ -41,8 +41,9 @@ namespace Torch.Server.Commands [Command("add", "Add a Steam ID to the whitelist.")] public void Add(ulong steamId) { - if (Config.Whitelist.Add(steamId)) + if (!Config.Whitelist.Contains(steamId)) { + Config.Whitelist.Add(steamId); Context.Respond($"Added {steamId} to the whitelist."); Config.Save(); } diff --git a/Torch.Server/Initializer.cs b/Torch.Server/Initializer.cs index e13aaf0..eb661a3 100644 --- a/Torch.Server/Initializer.cs +++ b/Torch.Server/Initializer.cs @@ -21,6 +21,9 @@ namespace Torch.Server { public class Initializer { + [Obsolete("It's hack. Do not use it!")] + internal static Initializer Instance { get; private set; } + private static readonly Logger Log = LogManager.GetLogger(nameof(Initializer)); private bool _init; private const string STEAMCMD_DIR = "steamcmd"; @@ -32,17 +35,17 @@ namespace Torch.Server login anonymous app_update 298740 quit"; - - private TorchConfig _config; private TorchServer _server; private string _basePath; - public TorchConfig Config => _config; + internal Persistent ConfigPersistent { get; private set; } + public TorchConfig Config => ConfigPersistent?.Data; public TorchServer Server => _server; public Initializer(string basePath) { _basePath = basePath; + Instance = this; } public bool Initialize(string[] args) @@ -94,15 +97,15 @@ quit"; File.Copy(havokSource, havokTarget); } - _config = InitConfig(); - if (!_config.Parse(args)) + InitConfig(); + if (!Config.Parse(args)) return false; - if (!string.IsNullOrEmpty(_config.WaitForPID)) + if (!string.IsNullOrEmpty(Config.WaitForPID)) { try { - var pid = int.Parse(_config.WaitForPID); + var pid = int.Parse(Config.WaitForPID); var waitProc = Process.GetProcessById(pid); Log.Info("Continuing in 5 seconds."); Log.Warn($"Waiting for process {pid} to close"); @@ -124,9 +127,9 @@ quit"; public void Run() { - _server = new TorchServer(_config); + _server = new TorchServer(Config); - if (_config.NoGui) + if (Config.NoGui) { _server.Init(); _server.Start(); @@ -134,7 +137,7 @@ quit"; else { #if !DEBUG - if (!_config.IndependentConsole) + if (!Config.IndependentConsole) { Console.SetOut(TextWriter.Null); NativeMethods.FreeConsole(); @@ -145,9 +148,9 @@ quit"; { _server.Init(); - if (_config.Autostart || _config.TempAutostart) + if (Config.Autostart || Config.TempAutostart) { - _config.TempAutostart = false; + Config.TempAutostart = false; _server.Start(); } }); @@ -159,22 +162,19 @@ quit"; } } - private TorchConfig InitConfig() + private void 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); + Log.Info($"Loading config {configName}"); } else { Log.Info($"Generating default config at {configPath}"); - var config = new TorchConfig {InstancePath = Path.GetFullPath("Instance")}; - config.Save(configPath); - return config; } + ConfigPersistent = Persistent.Load(configPath); } public static void RunSteamCmd() @@ -267,13 +267,13 @@ quit"; //MyMiniDump.Write(path, options, MyMiniDump.ExceptionInfo.Present); } LogManager.Flush(); - if (_config.RestartOnCrash) + if (Config.RestartOnCrash) { Console.WriteLine("Restarting in 5 seconds."); Thread.Sleep(5000); var exe = typeof(Program).Assembly.Location; - _config.WaitForPID = Process.GetCurrentProcess().Id.ToString(); - Process.Start(exe, _config.ToString()); + Config.WaitForPID = Process.GetCurrentProcess().Id.ToString(); + Process.Start(exe, Config.ToString()); } else { diff --git a/Torch.Server/Torch.Server.csproj b/Torch.Server/Torch.Server.csproj index 2728f66..ed48101 100644 --- a/Torch.Server/Torch.Server.csproj +++ b/Torch.Server/Torch.Server.csproj @@ -521,7 +521,6 @@ false - diff --git a/Torch.Server/TorchConfig.cs b/Torch.Server/TorchConfig.cs index 12905c3..2889674 100644 --- a/Torch.Server/TorchConfig.cs +++ b/Torch.Server/TorchConfig.cs @@ -1,57 +1,60 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.IO; +using System.Runtime.CompilerServices; using System.Windows; using System.Xml.Serialization; using Newtonsoft.Json; using NLog; +using Torch.API; +using Torch.Views; using VRage.Game; namespace Torch.Server { // TODO: redesign this gerbage - public class TorchConfig : CommandLine, ITorchConfig + public class TorchConfig : CommandLine, ITorchConfig, INotifyPropertyChanged { private static Logger _log = LogManager.GetLogger("Config"); public bool ShouldUpdatePlugins => (GetPluginUpdates && !NoUpdate) || ForceUpdate; public bool ShouldUpdateTorch => (GetTorchUpdates && !NoUpdate) || ForceUpdate; + private string _instancePath = Path.GetFullPath("Instance"); + private string _instanceName = "Instance"; + private bool _autostart; + private bool _restartOnCrash; + private bool _noGui; + private bool _getPluginUpdates = true; + private bool _getTorchUpdates = true; + private int _tickTimeout = 60; + private bool _localPlugins; + private bool _disconnectOnRestart; + private string _chatName = "Server"; + private string _chatColor = "Red"; + private bool _enableWhitelist = false; + private List _whitelist = new List(); + private int _windowWidth = 980; + private int _windowHeight = 588; + private bool _independentConsole = false; + private bool _enableAsserts = false; + private int _fontSize = 16; + private UGCServiceType _ugcServiceType = UGCServiceType.Steam; + + /// [Arg("instancename", "The name of the Torch instance.")] - public string InstanceName { get; set; } - - - private string _instancePath; + [Display(Name = "Instance Name", Description = "The name of the Torch instance.", GroupName = "Server")] + public string InstanceName { get => _instanceName; set => Set(value, ref _instanceName); } /// [Arg("instancepath", "Server data folder where saves and mods are stored.")] + [Display(Name = "Instance Path", Description = "Server data folder where saves and mods are stored.", GroupName = "Server")] public string InstancePath { get => _instancePath; - set - { - if(String.IsNullOrEmpty(value)) - { - _instancePath = value; - return; - } - try - { - if(value.Contains("\"")) - throw new InvalidOperationException(); - - var s = Path.GetFullPath(value); - Console.WriteLine(s); //prevent compiler opitmization - just in case - } - catch (Exception ex) - { - _log.Error(ex, "Invalid path assigned to InstancePath! Please report this immediately! Value: " + value); - //throw; - } - - _instancePath = value; - } + set => Set(value, ref _instancePath); } /// @@ -65,7 +68,8 @@ namespace Torch.Server /// /// Permanent flag to ALWAYS automatically start the server /// - public bool Autostart { get; set; } + [Display(Name = "Auto Start", Description = "Permanent flag to ALWAYS automatically start the server.", GroupName = "Server")] + public bool Autostart { get => _autostart; set => Set(value, ref _autostart); } /// /// Temporary flag to automatically start the server only on the next run @@ -76,44 +80,69 @@ namespace Torch.Server /// [Arg("restartoncrash", "Automatically restart the server if it crashes.")] - public bool RestartOnCrash { get; set; } + [Display(Name = "Restart On Crash", Description = "Automatically restart the server if it crashes.", GroupName = "Server")] + public bool RestartOnCrash { get => _restartOnCrash; set => Set(value, ref _restartOnCrash); } /// [Arg("nogui", "Do not show the Torch UI.")] - public bool NoGui { get; set; } + [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; } /// - public bool GetTorchUpdates { get; set; } = true; + [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); } /// - public bool GetPluginUpdates { get; set; } = true; + [Display(Name = "Update Plugins", Description = "Check every start for new versions of plugins.", GroupName = "Server")] + public bool GetPluginUpdates { get => _getPluginUpdates; set => Set(value, ref _getPluginUpdates); } /// - public int TickTimeout { get; set; } = 60; + [Display(Name = "Watchdog Timeout", Description = "Watchdog timeout (in seconds).", GroupName = "Server")] + public int TickTimeout { get => _tickTimeout; set => Set(value, ref _tickTimeout); } /// [Arg("plugins", "Starts Torch with the given plugin GUIDs (space delimited).")] public List Plugins { get; set; } = new List(); [Arg("localplugins", "Loads all pluhins from disk, ignores the plugins defined in config.")] - public bool LocalPlugins { get; set; } + [Display(Name = "Local Plugins", Description = "Loads all pluhins from disk, ignores the plugins defined in config.", GroupName = "In-Game")] + public bool LocalPlugins { get => _localPlugins; set => Set(value, ref _localPlugins); } - [Arg("disconnect", "When server restarts, all clients are rejected to main menu to prevent auto rejoin")] - public bool DisconnectOnRestart { get; set; } + [Arg("disconnect", "When server restarts, all clients are rejected to main menu to prevent auto rejoin.")] + [Display(Name = "Auto Disconnect", Description = "When server restarts, all clients are rejected to main menu to prevent auto rejoin.", GroupName = "In-Game")] + public bool DisconnectOnRestart { get => _disconnectOnRestart; set => Set(value, ref _disconnectOnRestart); } - public string ChatName { get; set; } = "Server"; + [Display(Name = "Chat Name", Description = "Default name for chat from gui, broadcasts etc..", GroupName = "In-Game")] + public string ChatName { get => _chatName; set => Set(value, ref _chatName); } - public string ChatColor { get; set; } = "Red"; + [Display(Name = "Chat Color", Description = "Default color for chat from gui, broadcasts etc.. (Red, Blue, White, Green)", GroupName = "In-Game")] + public string ChatColor { get => _chatColor; set => Set(value, ref _chatColor); } - public bool EnableWhitelist { get; set; } = false; - public HashSet Whitelist { get; set; } = new HashSet(); + [Display(Name = "Enable Whitelist", Description = "Enable Whitelist to prevent random players join while maintance, tests or other.", GroupName = "In-Game")] + public bool EnableWhitelist { get => _enableWhitelist; set => Set(value, ref _enableWhitelist); } - public Point WindowSize { get; set; } = new Point(800, 600); - public Point WindowPosition { get; set; } = new Point(); + [Display(Name = "Whitelist", Description = "Collection of whitelisted steam ids.", GroupName = "In-Game")] + public List Whitelist { get => _whitelist; set => Set(value, ref _whitelist); } + + [Display(Name = "Width", Description = "Default window width.", GroupName = "Window")] + public int WindowWidth { get => _windowWidth; set => Set(value, ref _windowWidth); } + + [Display(Name = "Height", Description = "Default window height", GroupName = "Window")] + public int WindowHeight { get => _windowHeight; set => Set(value, ref _windowHeight); } + + [Display(Name = "Font Size", Description = "Font size for logging text box. (default is 16)", GroupName = "Window")] + public int FontSize { get => _fontSize; set => Set(value, ref _fontSize); } + + [Display(Name = "UGC Service Type", Description = "Service for downloading mods", GroupName = "Server")] + public UGCServiceType UgcServiceType + { + get => _ugcServiceType; + set => Set(value, ref _ugcServiceType); + } public string LastUsedTheme { get; set; } = "Torch Theme"; @@ -122,64 +151,28 @@ namespace Torch.Server private bool ShouldSerializeReservedPlayers() => false; [Arg("console", "Keeps a separate console window open after the main UI loads.")] - public bool IndependentConsole { get; set; } = false; + [Display(Name = "Independent Console", Description = "Keeps a separate console window open after the main UI loads.", GroupName = "Window")] + public bool IndependentConsole { get => _independentConsole; set => Set(value, ref _independentConsole); } [XmlIgnore] [Arg("testplugin", "Path to a plugin to debug. For development use only.")] public string TestPlugin { get; set; } [Arg("asserts", "Enable Keen's assert logging.")] - public bool EnableAsserts { get; set; } = false; + [Display(Name = "Enable Asserts", Description = "Enable Keen's assert logging.", GroupName = "Server")] + public bool EnableAsserts { get => _enableAsserts; set => Set(value, ref _enableAsserts); } - [XmlIgnore] - private string _path; + public event PropertyChangedEventHandler PropertyChanged; - public TorchConfig() : this("Torch") { } + public TorchConfig() { } - public TorchConfig(string instanceName = "Torch", string instancePath = null) + protected void Set(T value, ref T field, [CallerMemberName] string callerName = default) { - InstanceName = instanceName; - InstancePath = instancePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SpaceEngineersDedicated"); + field = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(callerName)); } - public static TorchConfig LoadFrom(string path) - { - try - { - var ser = new XmlSerializer(typeof(TorchConfig)); - using (var f = File.OpenRead(path)) - { - var config = (TorchConfig)ser.Deserialize(f); - config._path = path; - return config; - } - } - catch (Exception e) - { - _log.Error(e); - return null; - } - } - - public bool Save(string path = null) - { - if (path == null) - path = _path; - else - _path = path; - - try - { - var ser = new XmlSerializer(typeof(TorchConfig)); - using (var f = File.Create(path)) - ser.Serialize(f, this); - return true; - } - catch (Exception e) - { - _log.Error(e); - return false; - } - } + // for backward compatibility + public void Save(string path = null) => Initializer.Instance?.ConfigPersistent?.Save(path); } } diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs index 6806127..1872064 100644 --- a/Torch.Server/TorchServer.cs +++ b/Torch.Server/TorchServer.cs @@ -57,13 +57,12 @@ namespace Torch.Server private bool _simDirty; /// - public TorchServer(TorchConfig config = null) + public TorchServer(TorchConfig config) : base(config) { DedicatedInstance = new InstanceManager(this); AddManager(DedicatedInstance); AddManager(new EntityControlManager(this)); AddManager(new RemoteAPIManager(this)); - Config = config ?? new TorchConfig(); var sessionManager = Managers.GetManager(); sessionManager.AddFactory(x => new MultiplayerManagerDedicated(this)); diff --git a/Torch.Server/Views/ConfigControl.xaml b/Torch.Server/Views/ConfigControl.xaml index 79c856f..798c4af 100644 --- a/Torch.Server/Views/ConfigControl.xaml +++ b/Torch.Server/Views/ConfigControl.xaml @@ -131,7 +131,15 @@ /// Thrown if a TorchBase instance already exists. - protected TorchBase() + protected TorchBase(ITorchConfig config) { RegisterCoreAssembly(GetType().Assembly); if (Instance != null) throw new InvalidOperationException("A TorchBase instance already exists."); Instance = this; + Config = config; var versionString = Assembly.GetEntryAssembly() .GetCustomAttribute() diff --git a/Torch.API/Utils/ModItemUtils.cs b/Torch/Utils/ModItemUtils.cs similarity index 53% rename from Torch.API/Utils/ModItemUtils.cs rename to Torch/Utils/ModItemUtils.cs index 77aafa2..30d7909 100644 --- a/Torch.API/Utils/ModItemUtils.cs +++ b/Torch/Utils/ModItemUtils.cs @@ -11,6 +11,16 @@ namespace Torch.Utils } //because KEEEN! - public static string GetDefaultServiceName() => "Steam"; + public static string GetDefaultServiceName() + { + try + { + return MyGameService.GetDefaultUGC().ServiceName; + } + catch + { + return TorchBase.Instance.Config.UgcServiceType.ToString(); + } + } } } \ No newline at end of file diff --git a/Torch/VRageGame.cs b/Torch/VRageGame.cs index acf4572..06304bb 100644 --- a/Torch/VRageGame.cs +++ b/Torch/VRageGame.cs @@ -23,15 +23,18 @@ using Sandbox.Graphics.GUI; using SpaceEngineers.Game; using SpaceEngineers.Game.GUI; using Steamworks; +using Torch.API; using Torch.Utils; using VRage; using VRage.Audio; using VRage.Dedicated; +using VRage.EOS; using VRage.FileSystem; using VRage.Game; using VRage.Game.ObjectBuilder; using VRage.Game.SessionComponents; using VRage.GameServices; +using VRage.Mod.Io; using VRage.Plugins; using VRage.Scripting; using VRage.Steam; @@ -156,18 +159,45 @@ namespace Torch MyFileSystem.Reset(); MyInitializer.InvokeBeforeRun(_appSteamId, _appName, _userDataPath); - - _log.Info("Initializing services"); - var service = MySteamGameService.Create(true, _appSteamId); + //Type.GetType("VRage.Steam.MySteamService, VRage.Steam").GetProperty("IsActive").GetSetMethod(true).Invoke(service, new object[] {SteamAPI.Init()}); + _log.Info("Initializing UGC services"); + IMyGameService service; + IMyUGCService serviceInstance; + if (TorchBase.Instance.Config.UgcServiceType == UGCServiceType.Steam) + { + service = MySteamGameService.Create(dedicated, _appSteamId); + serviceInstance = MySteamUgcService.Create(_appSteamId, service); + MySteamGameService.InitNetworking(dedicated, service, (MyServerDiscoveryAggregator) MyGameService.ServerDiscovery); + } + else + { + service = MyEOSService.Create(); + + serviceInstance = MyModIoService.Create(service, "spaceengineers", "264", + "1fb4489996a5e8ffc6ec1135f9985b5b", "331", "f2b64abe55452252b030c48adc0c1f0e", + MyPlatformGameSettings.UGC_TEST_ENVIRONMENT); + + MyEOSService.InitNetworking(dedicated, + dedicated ? MyPerServerSettings.GameDSName : MyPerServerSettings.GameNameSafe, service, + "xyza7891A4WeGrpP85BTlBa3BSfUEABN", "ZdHZVevSVfIajebTnTmh5MVi3KPHflszD9hJB7mRkgg", + "24b1cd652a18461fa9b3d533ac8d6b5b", "1958fe26c66d4151a327ec162e4d49c8", + "07c169b3b641401496d352cad1c905d6", "https://retail.epicgames.com/", MyEOSService.CreatePlatform(), + MySandboxGame.ConfigDedicated.VerboseNetworkLogging, null, null, null); + + var mockingInventory = new MyMockingInventory(service); + MyServiceManager.Instance.AddService(mockingInventory); + } MyServiceManager.Instance.AddService(service); - var serviceInstance = MySteamUgcService.Create(_appSteamId, service); MyServiceManager.Instance.AddService(serviceInstance); + MyGameService.WorkshopService.AddAggregate(serviceInstance); + + _log.Info("Initializing services"); MyServiceManager.Instance.AddService(new MyNullMicrophone()); - MySteamGameService.InitNetworking(dedicated, service, (MyServerDiscoveryAggregator) MyGameService.ServerDiscovery); + if (!MyGameService.HasGameServer) { - _log.Warn("Steam service is not running! Please reinstall dedicated server."); + _log.Warn("Network service is not running! Please reinstall dedicated server."); return; } @@ -182,7 +212,7 @@ namespace Torch if (!MySandboxGame.IsReloading) MyFileSystem.InitUserSpecific(dedicated ? null : MyGameService.UserId.ToString()); MySandboxGame.IsReloading = dedicated; - + // render init { IMyRender renderer = null; @@ -291,7 +321,7 @@ namespace Torch return; } MyObjectBuilder_Checkpoint checkpoint = MyLocalCache.LoadCheckpoint(sessionPath, out ulong checkpointSize); - if (MySession.IsCompatibleVersion(checkpoint)) + /*if (MySession.IsCompatibleVersion(checkpoint)) { var downloadResult = MyWorkshop.DownloadWorldModsBlocking(checkpoint.Mods.Select(b => { @@ -314,7 +344,7 @@ namespace Torch } else MyLog.Default.WriteLineAndConsole(MyTexts.Get(MyCommonTexts.DialogTextIncompatibleWorldVersion) - .ToString()); + .ToString());*/ } private void DoJoinSession(ulong lobbyId) diff --git a/Torch/Views/PropertyGrid.xaml.cs b/Torch/Views/PropertyGrid.xaml.cs index 81e104b..f6073be 100644 --- a/Torch/Views/PropertyGrid.xaml.cs +++ b/Torch/Views/PropertyGrid.xaml.cs @@ -81,7 +81,7 @@ namespace Torch.Views //If not found and IgnoreDisplay is not set, fall back to system DisplayAttribute if (a == null && !IgnoreDisplay) a = property.GetCustomAttribute(); - if (a?.Visible == false) + if (!IgnoreDisplay && a == null || a?.Visible == false) continue; descriptors[property] = a; string category = a?.GroupName ?? "Misc";