Compare commits

..

4 Commits
1.4.0 ... 1.4.3

Author SHA1 Message Date
zznty
a9c9a0de68 refactor restart and config handling 2022-10-12 16:36:25 +07:00
zznty
9a967345b9 skip obfuscated assemblies from compatibility fixes 2022-10-10 20:31:59 +07:00
zznty
98a4be655f fix plugins download 2022-10-10 20:31:10 +07:00
zznty
76de8f3d0b fix ci zipping 2022-10-09 20:34:22 +07:00
6 changed files with 122 additions and 283 deletions

View File

@@ -34,7 +34,7 @@ jobs:
- name: Build
run: dotnet build Torch.Server/Torch.Server.csproj --no-restore -c $env:BUILD_CONFIGURATION /p:AssemblyVersion=$env:VERSION /p:Version=$env:VERSION
- name: Publish
run: dotnet publish Torch.Server/Torch.Server.csproj --no-build -r win-x64 --sc -c $env:BUILD_CONFIGURATION
run: dotnet publish Torch.Server/Torch.Server.csproj --no-build -r win-x64 --sc -c $env:BUILD_CONFIGURATION -o ./publish
- uses: vimtor/action-zip@v1
name: Zip Release
with:

View File

@@ -14,7 +14,7 @@ namespace Torch.API.WebAPI
public class PluginQuery
{
private const string ALL_QUERY = "https://torchapi.com/api/plugins/";
private const string PLUGIN_QUERY = "https://torchapi.com/api/plugins/?guid={0}";
private const string PLUGIN_QUERY = "https://torchapi.com/api/plugins/search/{0}";
private readonly HttpClient _client;
private static readonly Logger Log = LogManager.GetCurrentClassLogger();

View File

@@ -1,167 +1,114 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Xml.Serialization;
using NLog;
using Torch.API;
using Torch.Views;
namespace Torch.Server
namespace Torch.Server;
public class TorchConfig : ViewModel, ITorchConfig
{
// TODO: redesign this gerbage
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;
public bool ShouldUpdatePlugins => (GetPluginUpdates && !NoUpdate) || ForceUpdate;
public bool ShouldUpdateTorch => (GetTorchUpdates && !NoUpdate) || ForceUpdate;
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<ulong> _whitelist = new List<ulong>();
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;
private bool _entityManagerEnabled = true;
/// <inheritdoc />
[XmlIgnore]
public bool NoUpdate { get; set; }
/// <inheritdoc />
[XmlIgnore, Arg("noupdate", "Disable automatically downloading game and plugin updates.")]
public bool NoUpdate { get; set; }
/// <inheritdoc />
[XmlIgnore]
public bool ForceUpdate { get; set; }
/// <inheritdoc />
[XmlIgnore, Arg("forceupdate", "Manually check for and install updates.")]
public bool ForceUpdate { get; set; }
/// <summary>
/// Permanent flag to ALWAYS automatically start the server
/// </summary>
[Display(Name = "Auto Start", Description = "Permanent flag to ALWAYS automatically start the server.", GroupName = "Server")]
public bool Autostart { get; set; }
/// <summary>
/// Permanent flag to ALWAYS automatically start the server
/// </summary>
[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); }
/// <summary>
/// Temporary flag to automatically start the server only on the next run
/// </summary>
[XmlIgnore]
public bool TempAutostart { get; set; }
/// <summary>
/// Temporary flag to automatically start the server only on the next run
/// </summary>
[Arg("autostart", "Start the server immediately.")]
[XmlIgnore]
public bool TempAutostart { get; set; }
/// <inheritdoc />
[Display(Name = "Restart On Crash", Description = "Automatically restart the server if it crashes.", GroupName = "Server")]
public bool RestartOnCrash { get; set; }
/// <inheritdoc />
[Arg("restartoncrash", "Automatically restart the server if it crashes.")]
[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); }
public string InstancePath { get; set; }
public string InstancePath { get; set; }
/// <inheritdoc />
[Display(Name = "No GUI", Description = "Do not show the Torch UI.", GroupName = "Window")]
public bool NoGui { get; set; }
/// <inheritdoc />
[Arg("nogui", "Do not show the Torch UI.")]
[Display(Name = "No GUI", Description = "Do not show the Torch UI.", GroupName = "Window")]
public bool NoGui { get => _noGui; set => Set(value, ref _noGui); }
/// <inheritdoc />
[Display(Name = "Update Torch", Description = "Check every start for new versions of torch.",
GroupName = "Server")]
public bool GetTorchUpdates { get; set; } = true;
/// <inheritdoc />
[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 string InstanceName { get; set; }
public string InstanceName { get; set; }
/// <inheritdoc />
[Display(Name = "Update Plugins", Description = "Check every start for new versions of plugins.",
GroupName = "Server")]
public bool GetPluginUpdates { get; set; } = true;
/// <inheritdoc />
[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); }
/// <inheritdoc />
[Display(Name = "Watchdog Timeout", Description = "Watchdog timeout (in seconds).", GroupName = "Server")]
public int TickTimeout { get; set; } = 60;
/// <inheritdoc />
[Display(Name = "Watchdog Timeout", Description = "Watchdog timeout (in seconds).", GroupName = "Server")]
public int TickTimeout { get => _tickTimeout; set => Set(value, ref _tickTimeout); }
/// <inheritdoc />
public List<Guid> Plugins { get; set; } = new();
/// <inheritdoc />
[Arg("plugins", "Starts Torch with the given plugin GUIDs (space delimited).")]
public List<Guid> Plugins { get; set; } = new List<Guid>();
[Display(Name = "Local Plugins", Description = "Loads all pluhins from disk, ignores the plugins defined in config.", GroupName = "In-Game")]
public bool LocalPlugins { get; set; }
[Arg("localplugins", "Loads all pluhins from disk, ignores the plugins defined in config.")]
[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); }
[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; 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); }
[Display(Name = "Chat Name", Description = "Default name for chat from gui, broadcasts etc..",
GroupName = "In-Game")]
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); }
[Display(Name = "Chat Color",
Description = "Default color for chat from gui, broadcasts etc.. (Red, Blue, White, Green)",
GroupName = "In-Game")]
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); }
[Display(Name = "Enable Whitelist", Description = "Enable Whitelist to prevent random players join while maintance, tests or other.", GroupName = "In-Game")]
public bool EnableWhitelist { get; set; }
[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); }
[Display(Name = "Whitelist", Description = "Collection of whitelisted steam ids.", GroupName = "In-Game")]
public List<ulong> Whitelist { get; set; } = new();
[Display(Name = "Whitelist", Description = "Collection of whitelisted steam ids.", GroupName = "In-Game")]
public List<ulong> Whitelist { get => _whitelist; set => Set(value, ref _whitelist); }
[Display(Name = "Width", Description = "Default window width.", GroupName = "Window")]
public int WindowWidth { get; set; } = 980;
[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; set; } = 588;
[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; set; } = 16;
[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; set; } = UGCServiceType.Steam;
[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";
public string LastUsedTheme { get; set; } = "Torch Theme";
[Display(Name = "Independent Console", Description = "Keeps a separate console window open after the main UI loads.", GroupName = "Window")]
public bool IndependentConsole { get; set; }
//Prevent reserved players being written to disk, but allow it to be read
//remove this when ReservedPlayers is removed
private bool ShouldSerializeReservedPlayers() => false;
[XmlIgnore]
public string TestPlugin { get; set; }
[Arg("console", "Keeps a separate console window open after the main UI loads.")]
[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); }
[Display(Name = "Enable Asserts", Description = "Enable Keen's assert logging.", GroupName = "Server")]
public bool EnableAsserts { get; set; }
[XmlIgnore]
[Arg("testplugin", "Path to a plugin to debug. For development use only.")]
public string TestPlugin { get; set; }
[Display(Name = "Enable Entity Manager", Description = "Enable Entity Manager tab. (can affect performance)",
GroupName = "Server")]
public bool EntityManagerEnabled { get; set; } = true;
[Arg("asserts", "Enable Keen's assert logging.")]
[Display(Name = "Enable Asserts", Description = "Enable Keen's assert logging.", GroupName = "Server")]
public bool EnableAsserts { get => _enableAsserts; set => Set(value, ref _enableAsserts); }
[Display(Name = "Enable Entity Manager", Description = "Enable Entity Manager tab. (can affect performance)",
GroupName = "Server")]
public bool EntityManagerEnabled
{
get => _entityManagerEnabled;
set => Set(value, ref _entityManagerEnabled);
}
public event PropertyChangedEventHandler PropertyChanged;
public TorchConfig() { }
protected void Set<T>(T value, ref T field, [CallerMemberName] string callerName = default)
{
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(callerName));
}
// for backward compatibility
public void Save(string path = null) => Initializer.Instance?.ConfigPersistent?.Save(path);
}
}
// for backward compatibility
public void Save(string path = null) => Initializer.Instance?.ConfigPersistent?.Save(path);
}

View File

@@ -205,16 +205,30 @@ namespace Torch.Server
new Thread(() =>
{
StopInternal();
var config = (TorchConfig)Config;
LogManager.Flush();
string exe = Assembly.GetExecutingAssembly().Location.Replace("dll", "exe");
config.TempAutostart = true;
Process.Start(exe, $"-waitForPid {Environment.ProcessId} {config}");
#if DEBUG
Environment.Exit(0);
#endif
var exe = Assembly.GetExecutingAssembly().Location.Replace("dll", "exe");
var args = Environment.GetCommandLineArgs();
for (var i = 0; i < args.Length; i++)
{
if (args[i].Contains(' '))
args[i] = $"\"{args[i]}\"";
if (!args[i].Contains("--tempAutostart", StringComparison.InvariantCultureIgnoreCase) &&
!args[i].Contains("--waitForPid", StringComparison.InvariantCultureIgnoreCase))
continue;
args[i] = string.Empty;
args[++i] = string.Empty;
}
Process.Start(exe, $"--waitForPid {Environment.ProcessId} --tempAutostart true {string.Join(" ", args)}");
})
{
Name = "Restart thread"

View File

@@ -1,138 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using NLog;
namespace Torch
{
/// <summary>
/// Base class that adds tools for setting type properties through the command line.
/// </summary>
public abstract class CommandLine
{
private readonly string _argPrefix;
private readonly Dictionary<ArgAttribute, PropertyInfo> _args = new Dictionary<ArgAttribute, PropertyInfo>();
private readonly Logger _log = LogManager.GetCurrentClassLogger();
protected CommandLine(string argPrefix = "-")
{
_argPrefix = argPrefix;
foreach (var prop in GetType().GetProperties())
{
var attr = prop.GetCustomAttribute<ArgAttribute>();
if (attr == null)
continue;
_args.Add(attr, prop);
}
}
public string GetHelp()
{
var sb = new StringBuilder();
foreach (var property in _args)
{
var attr = property.Key;
sb.AppendLine($"{_argPrefix}{attr.Name.PadRight(24)}{attr.Description}");
}
return sb.ToString();
}
public override string ToString()
{
var args = new List<string>();
foreach (var prop in _args)
{
var attr = prop.Key;
if (prop.Value.PropertyType == typeof(bool) && (bool)prop.Value.GetValue(this))
{
args.Add($"{_argPrefix}{attr.Name}");
}
else if (prop.Value.PropertyType == typeof(string))
{
var str = (string)prop.Value.GetValue(this);
if (string.IsNullOrEmpty(str))
continue;
args.Add($"{_argPrefix}{attr.Name} \"{str}\"");
}
}
return string.Join(" ", args);
}
public bool Parse(string[] args)
{
if (args.Length == 0)
return true;
if (args[0] == $"{_argPrefix}help")
{
Console.WriteLine(GetHelp());
return false;
}
for (var i = 0; i < args.Length; i++)
{
if (!args[i].StartsWith(_argPrefix))
continue;
foreach (var property in _args)
{
var argName = property.Key.Name;
if (argName == null)
continue;
try
{
if (string.Compare(argName, 0, args[i], 1, argName.Length, StringComparison.InvariantCultureIgnoreCase) == 0)
{
if (property.Value.PropertyType == typeof(bool))
property.Value.SetValue(this, true);
if (property.Value.PropertyType == typeof(string))
property.Value.SetValue(this, args[++i]);
if (property.Value.PropertyType == typeof(List<Guid>))
{
i++;
var l = new List<Guid>(16);
while (i < args.Length && !args[i].StartsWith(_argPrefix))
{
if (Guid.TryParse(args[i], out Guid g))
{
l.Add(g);
_log.Info($"added plugin {g}");
}
else
_log.Warn($"Failed to parse GUID {args[i]}");
i++;
}
property.Value.SetValue(this, l);
}
}
}
catch
{
Console.WriteLine($"Error parsing arg {argName}");
}
}
}
return true;
}
public class ArgAttribute : Attribute
{
public string Name { get; }
public string Description { get; }
public ArgAttribute(string name, string description)
{
Name = name;
Description = description;
}
}
}
}

View File

@@ -1,14 +1,17 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using Mono.Cecil;
using NLog;
namespace Torch.Plugins;
internal static class AssemblyRewriter
{
private static readonly ILogger Log = LogManager.GetCurrentClassLogger();
private static readonly ZipResolver _zipResolver;
private static readonly DefaultAssemblyResolver _defaultResolver;
@@ -23,12 +26,25 @@ internal static class AssemblyRewriter
public static Assembly ProcessWeavers(this Stream stream, ZipArchive archive)
{
_zipResolver.Archive = archive;
using var assStream = new MemoryStream();
stream.CopyTo(assStream);
assStream.Position = 0;
var ass = ProcessInternal(assStream, _zipResolver);
_zipResolver.Archive = null;
return ass;
try
{
var ass = ProcessInternal(assStream, _zipResolver);
return ass;
}
catch (Exception e)
{
Log.Error(e, "Unable to process assembly, skipping");
return Assembly.Load(assStream.ToArray());
}
finally
{
_zipResolver.Archive = null;
}
}
public static Assembly ProcessWeavers(this Stream stream, string path)