Merge branch 'master' into master
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -8,37 +8,105 @@ using VRage.Game.ModAPI;
|
|||||||
|
|
||||||
namespace Torch.API
|
namespace Torch.API
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// API for Torch functions shared between client and server.
|
||||||
|
/// </summary>
|
||||||
public interface ITorchBase
|
public interface ITorchBase
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when the session begins loading.
|
||||||
|
/// </summary>
|
||||||
event Action SessionLoading;
|
event Action SessionLoading;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when the session finishes loading.
|
||||||
|
/// </summary>
|
||||||
event Action SessionLoaded;
|
event Action SessionLoaded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fires when the session begins unloading.
|
||||||
|
/// </summary>
|
||||||
event Action SessionUnloading;
|
event Action SessionUnloading;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when the session finishes unloading.
|
||||||
|
/// </summary>
|
||||||
event Action SessionUnloaded;
|
event Action SessionUnloaded;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration for the current instance.
|
||||||
|
/// </summary>
|
||||||
ITorchConfig Config { get; }
|
ITorchConfig Config { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IMultiplayerManager"/>
|
||||||
IMultiplayerManager Multiplayer { get; }
|
IMultiplayerManager Multiplayer { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IPluginManager"/>
|
||||||
IPluginManager Plugins { get; }
|
IPluginManager Plugins { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The binary version of the current instance.
|
||||||
|
/// </summary>
|
||||||
Version TorchVersion { get; }
|
Version TorchVersion { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoke an action on the game thread.
|
||||||
|
/// </summary>
|
||||||
void Invoke(Action action);
|
void Invoke(Action action);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoke an action on the game thread and block until it has completed.
|
||||||
|
/// If this is called on the game thread the action will execute immediately.
|
||||||
|
/// </summary>
|
||||||
void InvokeBlocking(Action action);
|
void InvokeBlocking(Action action);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoke an action on the game thread asynchronously.
|
||||||
|
/// </summary>
|
||||||
Task InvokeAsync(Action action);
|
Task InvokeAsync(Action action);
|
||||||
string[] RunArgs { get; set; }
|
|
||||||
bool IsOnGameThread();
|
/// <summary>
|
||||||
|
/// Start the Torch instance.
|
||||||
|
/// </summary>
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stop the Torch instance.
|
||||||
|
/// </summary>
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a save of the game.
|
/// Initializes a save of the game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="callerId">Id of the player who initiated the save.</param>
|
/// <param name="callerId">Id of the player who initiated the save.</param>
|
||||||
void Save(long callerId);
|
void Save(long callerId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialize the Torch instance.
|
||||||
|
/// </summary>
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get an <see cref="IManager"/> that is part of the Torch instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Manager type</typeparam>
|
||||||
T GetManager<T>() where T : class, IManager;
|
T GetManager<T>() where T : class, IManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// API for the Torch server.
|
||||||
|
/// </summary>
|
||||||
public interface ITorchServer : ITorchBase
|
public interface ITorchServer : ITorchBase
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Path of the dedicated instance folder.
|
||||||
|
/// </summary>
|
||||||
string InstancePath { get; }
|
string InstancePath { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// API for the Torch client.
|
||||||
|
/// </summary>
|
||||||
public interface ITorchClient : ITorchBase
|
public interface ITorchClient : ITorchBase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@@ -1,14 +1,47 @@
|
|||||||
namespace Torch
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Torch
|
||||||
{
|
{
|
||||||
public interface ITorchConfig
|
public interface ITorchConfig
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// (server) Name of the instance.
|
||||||
|
/// </summary>
|
||||||
string InstanceName { get; set; }
|
string InstanceName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// (server) Dedicated instance path.
|
||||||
|
/// </summary>
|
||||||
string InstancePath { get; set; }
|
string InstancePath { get; set; }
|
||||||
bool RedownloadPlugins { get; set; }
|
|
||||||
bool AutomaticUpdates { get; set; }
|
/// <summary>
|
||||||
|
/// Enable automatic Torch updates.
|
||||||
|
/// </summary>
|
||||||
|
bool GetTorchUpdates { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable automatic Torch updates.
|
||||||
|
/// </summary>
|
||||||
|
bool GetPluginUpdates { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restart Torch automatically if it crashes.
|
||||||
|
/// </summary>
|
||||||
bool RestartOnCrash { get; set; }
|
bool RestartOnCrash { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Time-out in seconds for the Torch watchdog (to detect a hung session).
|
||||||
|
/// </summary>
|
||||||
int TickTimeout { get; set; }
|
int TickTimeout { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of plugins that should be installed.
|
||||||
|
/// </summary>
|
||||||
|
List<string> Plugins { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Saves the config.
|
||||||
|
/// </summary>
|
||||||
bool Save(string path = null);
|
bool Save(string path = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -6,8 +6,14 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Torch.API.Managers
|
namespace Torch.API.Managers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base interface for Torch managers.
|
||||||
|
/// </summary>
|
||||||
public interface IManager
|
public interface IManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the manager. Called after Torch is initialized.
|
||||||
|
/// </summary>
|
||||||
void Init();
|
void Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,17 +6,56 @@ using VRage.Game.ModAPI;
|
|||||||
|
|
||||||
namespace Torch.API.Managers
|
namespace Torch.API.Managers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Delegate for received messages.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message data.</param>
|
||||||
|
/// <param name="sendToOthers">Flag to broadcast message to other players.</param>
|
||||||
public delegate void MessageReceivedDel(IChatMessage message, ref bool sendToOthers);
|
public delegate void MessageReceivedDel(IChatMessage message, ref bool sendToOthers);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// API for multiplayer related functions.
|
||||||
|
/// </summary>
|
||||||
public interface IMultiplayerManager : IManager
|
public interface IMultiplayerManager : IManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a player joins.
|
||||||
|
/// </summary>
|
||||||
event Action<IPlayer> PlayerJoined;
|
event Action<IPlayer> PlayerJoined;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a player disconnects.
|
||||||
|
/// </summary>
|
||||||
event Action<IPlayer> PlayerLeft;
|
event Action<IPlayer> PlayerLeft;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when a chat message is received.
|
||||||
|
/// </summary>
|
||||||
event MessageReceivedDel MessageReceived;
|
event MessageReceivedDel MessageReceived;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a chat message to all or one specific player.
|
||||||
|
/// </summary>
|
||||||
void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Blue);
|
void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Blue);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Kicks the player from the game.
|
||||||
|
/// </summary>
|
||||||
void KickPlayer(ulong steamId);
|
void KickPlayer(ulong steamId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bans or unbans a player from the game.
|
||||||
|
/// </summary>
|
||||||
void BanPlayer(ulong steamId, bool banned = true);
|
void BanPlayer(ulong steamId, bool banned = true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a player by their Steam64 ID or returns null if the player isn't found.
|
||||||
|
/// </summary>
|
||||||
IMyPlayer GetPlayerBySteamId(ulong id);
|
IMyPlayer GetPlayerBySteamId(ulong id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a player by their display name or returns null if the player isn't found.
|
||||||
|
/// </summary>
|
||||||
IMyPlayer GetPlayerByName(string name);
|
IMyPlayer GetPlayerByName(string name);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,14 +9,30 @@ using VRage.Network;
|
|||||||
|
|
||||||
namespace Torch.API.Managers
|
namespace Torch.API.Managers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// API for the network intercept.
|
||||||
|
/// </summary>
|
||||||
public interface INetworkManager : IManager
|
public interface INetworkManager : IManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Register a network handler.
|
||||||
|
/// </summary>
|
||||||
void RegisterNetworkHandler(INetworkHandler handler);
|
void RegisterNetworkHandler(INetworkHandler handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handler for multiplayer network messages.
|
||||||
|
/// </summary>
|
||||||
public interface INetworkHandler
|
public interface INetworkHandler
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns if the handler can process the call site.
|
||||||
|
/// </summary>
|
||||||
bool CanHandle(CallSite callSite);
|
bool CanHandle(CallSite callSite);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Processes a network message.
|
||||||
|
/// </summary>
|
||||||
bool Handle(ulong remoteUserId, CallSite site, BitStream stream, object obj, MyPacket packet);
|
bool Handle(ulong remoteUserId, CallSite site, BitStream stream, object obj, MyPacket packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,11 +6,29 @@ using VRage.Plugins;
|
|||||||
|
|
||||||
namespace Torch.API.Managers
|
namespace Torch.API.Managers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// API for the Torch plugin manager.
|
||||||
|
/// </summary>
|
||||||
public interface IPluginManager : IManager, IEnumerable<ITorchPlugin>
|
public interface IPluginManager : IManager, IEnumerable<ITorchPlugin>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Fired when plugins are loaded.
|
||||||
|
/// </summary>
|
||||||
event Action<List<ITorchPlugin>> PluginsLoaded;
|
event Action<List<ITorchPlugin>> PluginsLoaded;
|
||||||
List<ITorchPlugin> Plugins { get; }
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collection of loaded plugins.
|
||||||
|
/// </summary>
|
||||||
|
ObservableCollection<ITorchPlugin> Plugins { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates all loaded plugins.
|
||||||
|
/// </summary>
|
||||||
void UpdatePlugins();
|
void UpdatePlugins();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes all loaded plugins.
|
||||||
|
/// </summary>
|
||||||
void DisposePlugins();
|
void DisposePlugins();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -6,11 +6,29 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Torch.API
|
namespace Torch.API
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used to indicate the state of the dedicated server.
|
||||||
|
/// </summary>
|
||||||
public enum ServerState
|
public enum ServerState
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The server is not running.
|
||||||
|
/// </summary>
|
||||||
Stopped,
|
Stopped,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The server is starting/loading the session.
|
||||||
|
/// </summary>
|
||||||
Starting,
|
Starting,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The server is running.
|
||||||
|
/// </summary>
|
||||||
Running,
|
Running,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The server encountered an error.
|
||||||
|
/// </summary>
|
||||||
Error
|
Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.182.329")]
|
[assembly: AssemblyVersion("1.0.186.642")]
|
||||||
[assembly: AssemblyFileVersion("1.0.182.329")]
|
[assembly: AssemblyFileVersion("1.0.186.642")]
|
@@ -45,6 +45,10 @@
|
|||||||
<HintPath>..\packages\NLog.4.4.1\lib\net45\NLog.dll</HintPath>
|
<HintPath>..\packages\NLog.4.4.1\lib\net45\NLog.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Sandbox.Common, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\GameBinaries\Sandbox.Common.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Sandbox.Game">
|
<Reference Include="Sandbox.Game">
|
||||||
<HintPath>..\GameBinaries\Sandbox.Game.dll</HintPath>
|
<HintPath>..\GameBinaries\Sandbox.Game.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
|
@@ -9,6 +9,7 @@ using Sandbox;
|
|||||||
using Sandbox.Engine.Platform;
|
using Sandbox.Engine.Platform;
|
||||||
using Sandbox.Engine.Utils;
|
using Sandbox.Engine.Utils;
|
||||||
using Sandbox.Game;
|
using Sandbox.Game;
|
||||||
|
using Sandbox.ModAPI;
|
||||||
using SpaceEngineers.Game;
|
using SpaceEngineers.Game;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using VRage.FileSystem;
|
using VRage.FileSystem;
|
||||||
|
@@ -34,8 +34,8 @@ namespace Torch.Server
|
|||||||
private static ITorchServer _server;
|
private static ITorchServer _server;
|
||||||
private static Logger _log = LogManager.GetLogger("Torch");
|
private static Logger _log = LogManager.GetLogger("Torch");
|
||||||
private static bool _restartOnCrash;
|
private static bool _restartOnCrash;
|
||||||
public static bool IsManualInstall;
|
private static TorchConfig _config;
|
||||||
private static TorchCli _cli;
|
private static bool _steamCmdDone;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This method must *NOT* load any types/assemblies from the vanilla game, otherwise automatic updates will fail.
|
/// This method must *NOT* load any types/assemblies from the vanilla game, otherwise automatic updates will fail.
|
||||||
@@ -46,10 +46,10 @@ namespace Torch.Server
|
|||||||
//Ensures that all the files are downloaded in the Torch directory.
|
//Ensures that all the files are downloaded in the Torch directory.
|
||||||
Directory.SetCurrentDirectory(new FileInfo(typeof(Program).Assembly.Location).Directory.ToString());
|
Directory.SetCurrentDirectory(new FileInfo(typeof(Program).Assembly.Location).Directory.ToString());
|
||||||
|
|
||||||
IsManualInstall = File.Exists("SpaceEngineersDedicated.exe");
|
foreach (var file in Directory.GetFiles(Directory.GetCurrentDirectory(), "*.old"))
|
||||||
if (!IsManualInstall)
|
File.Delete(file);
|
||||||
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
|
|
||||||
|
|
||||||
|
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
|
||||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
|
|
||||||
if (!Environment.UserInteractive)
|
if (!Environment.UserInteractive)
|
||||||
@@ -63,50 +63,40 @@ namespace Torch.Server
|
|||||||
|
|
||||||
var configName = "TorchConfig.xml";
|
var configName = "TorchConfig.xml";
|
||||||
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
|
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
|
||||||
TorchConfig options;
|
|
||||||
if (File.Exists(configName))
|
if (File.Exists(configName))
|
||||||
{
|
{
|
||||||
_log.Info($"Loading config {configPath}");
|
_log.Info($"Loading config {configPath}");
|
||||||
options = TorchConfig.LoadFrom(configPath);
|
_config = TorchConfig.LoadFrom(configPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_log.Info($"Generating default config at {configPath}");
|
_log.Info($"Generating default config at {configPath}");
|
||||||
options = new TorchConfig();
|
_config = new TorchConfig {InstancePath = Path.GetFullPath("Instance")};
|
||||||
|
|
||||||
if (!IsManualInstall)
|
|
||||||
{
|
|
||||||
//new ConfigManager().CreateInstance("Instance");
|
|
||||||
options.InstancePath = Path.GetFullPath("Instance");
|
|
||||||
|
|
||||||
_log.Warn("Would you like to enable automatic updates? (Y/n):");
|
_log.Warn("Would you like to enable automatic updates? (Y/n):");
|
||||||
|
|
||||||
var input = Console.ReadLine() ?? "";
|
var input = Console.ReadLine() ?? "";
|
||||||
var autoUpdate = !input.Equals("n", StringComparison.InvariantCultureIgnoreCase);
|
var autoUpdate = string.IsNullOrEmpty(input) || input.Equals("y", StringComparison.InvariantCultureIgnoreCase);
|
||||||
options.AutomaticUpdates = autoUpdate;
|
_config.GetTorchUpdates = _config.GetPluginUpdates = autoUpdate;
|
||||||
if (autoUpdate)
|
if (autoUpdate)
|
||||||
{
|
{
|
||||||
_log.Info("Automatic updates enabled, updating server.");
|
_log.Info("Automatic updates enabled.");
|
||||||
RunSteamCmd();
|
RunSteamCmd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_config.Save(configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
//var setupDialog = new FirstTimeSetup { DataContext = options };
|
if (!_config.Parse(args))
|
||||||
//setupDialog.ShowDialog();
|
|
||||||
options.Save(configPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
_cli = new TorchCli { Config = options };
|
|
||||||
if (!_cli.Parse(args))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_log.Debug(_cli.ToString());
|
_log.Debug(_config.ToString());
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_cli.WaitForPID))
|
if (!string.IsNullOrEmpty(_config.WaitForPID))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var pid = int.Parse(_cli.WaitForPID);
|
var pid = int.Parse(_config.WaitForPID);
|
||||||
var waitProc = Process.GetProcessById(pid);
|
var waitProc = Process.GetProcessById(pid);
|
||||||
_log.Warn($"Waiting for process {pid} to exit.");
|
_log.Warn($"Waiting for process {pid} to exit.");
|
||||||
waitProc.WaitForExit();
|
waitProc.WaitForExit();
|
||||||
@@ -117,18 +107,13 @@ namespace Torch.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_restartOnCrash = _cli.RestartOnCrash;
|
_restartOnCrash = _config.RestartOnCrash;
|
||||||
|
|
||||||
if (options.AutomaticUpdates || _cli.Update)
|
if (_config.GetTorchUpdates || _config.Update)
|
||||||
{
|
|
||||||
if (IsManualInstall)
|
|
||||||
_log.Warn("Detected manual install, won't attempt to update DS");
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
RunSteamCmd();
|
RunSteamCmd();
|
||||||
}
|
}
|
||||||
}
|
RunServer(_config);
|
||||||
RunServer(options, _cli);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string STEAMCMD_DIR = "steamcmd";
|
private const string STEAMCMD_DIR = "steamcmd";
|
||||||
@@ -142,6 +127,9 @@ quit";
|
|||||||
|
|
||||||
public static void RunSteamCmd()
|
public static void RunSteamCmd()
|
||||||
{
|
{
|
||||||
|
if (_steamCmdDone)
|
||||||
|
return;
|
||||||
|
|
||||||
var log = LogManager.GetLogger("SteamCMD");
|
var log = LogManager.GetLogger("SteamCMD");
|
||||||
|
|
||||||
if (!Directory.Exists(STEAMCMD_DIR))
|
if (!Directory.Exists(STEAMCMD_DIR))
|
||||||
@@ -187,38 +175,40 @@ quit";
|
|||||||
log.Info(cmd.StandardOutput.ReadLine());
|
log.Info(cmd.StandardOutput.ReadLine());
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_steamCmdDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RunServer(TorchConfig options, TorchCli cli)
|
public static void RunServer(TorchConfig config)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (!parser.ParseArguments(args, options))
|
if (!parser.ParseArguments(args, config))
|
||||||
{
|
{
|
||||||
_log.Error($"Parsing arguments failed: {string.Join(" ", args)}");
|
_log.Error($"Parsing arguments failed: {string.Join(" ", args)}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(options.Config) && File.Exists(options.Config))
|
if (!string.IsNullOrEmpty(config.Config) && File.Exists(config.Config))
|
||||||
{
|
{
|
||||||
options = ServerConfig.LoadFrom(options.Config);
|
config = ServerConfig.LoadFrom(config.Config);
|
||||||
parser.ParseArguments(args, options);
|
parser.ParseArguments(args, config);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
//RestartOnCrash autostart autosave=15
|
//RestartOnCrash autostart autosave=15
|
||||||
//gamepath ="C:\Program Files\Space Engineers DS" instance="Hydro Survival" instancepath="C:\ProgramData\SpaceEngineersDedicated\Hydro Survival"
|
//gamepath ="C:\Program Files\Space Engineers DS" instance="Hydro Survival" instancepath="C:\ProgramData\SpaceEngineersDedicated\Hydro Survival"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if (options.InstallService)
|
if (config.InstallService)
|
||||||
{
|
{
|
||||||
var serviceName = $"\"Torch - {options.InstanceName}\"";
|
var serviceName = $"\"Torch - {config.InstanceName}\"";
|
||||||
// Working on installing the service properly instead of with sc.exe
|
// Working on installing the service properly instead of with sc.exe
|
||||||
_log.Info($"Installing service '{serviceName}");
|
_log.Info($"Installing service '{serviceName}");
|
||||||
var exePath = $"\"{Assembly.GetExecutingAssembly().Location}\"";
|
var exePath = $"\"{Assembly.GetExecutingAssembly().Location}\"";
|
||||||
var createInfo = new ServiceCreateInfo
|
var createInfo = new ServiceCreateInfo
|
||||||
{
|
{
|
||||||
Name = options.InstanceName,
|
Name = config.InstanceName,
|
||||||
BinaryPath = exePath,
|
BinaryPath = exePath,
|
||||||
};
|
};
|
||||||
_log.Info("Service Installed");
|
_log.Info("Service Installed");
|
||||||
@@ -238,7 +228,7 @@ quit";
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.UninstallService)
|
if (config.UninstallService)
|
||||||
{
|
{
|
||||||
_log.Info("Uninstalling Torch service");
|
_log.Info("Uninstalling Torch service");
|
||||||
var startInfo = new ProcessStartInfo
|
var startInfo = new ProcessStartInfo
|
||||||
@@ -254,18 +244,18 @@ quit";
|
|||||||
return;
|
return;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
_server = new TorchServer(options);
|
_server = new TorchServer(config);
|
||||||
_server.Init();
|
_server.Init();
|
||||||
|
|
||||||
if (cli.NoGui || cli.Autostart)
|
if (config.NoGui || config.Autostart)
|
||||||
{
|
{
|
||||||
new Thread(() => _server.Start()).Start();
|
new Thread(() => _server.Start()).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cli.NoGui)
|
if (!config.NoGui)
|
||||||
{
|
{
|
||||||
var ui = new TorchUI((TorchServer)_server);
|
var ui = new TorchUI((TorchServer)_server);
|
||||||
ui.LoadConfig(options);
|
ui.LoadConfig(config);
|
||||||
ui.ShowDialog();
|
ui.ShowDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -295,17 +285,9 @@ quit";
|
|||||||
Thread.Sleep(5000);
|
Thread.Sleep(5000);
|
||||||
if (_restartOnCrash)
|
if (_restartOnCrash)
|
||||||
{
|
{
|
||||||
/* Throws an exception somehow and I'm too lazy to debug it.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (MySession.Static != null && MySession.Static.AutoSaveInMinutes > 0)
|
|
||||||
MySession.Static.Save();
|
|
||||||
}
|
|
||||||
catch { }*/
|
|
||||||
|
|
||||||
var exe = typeof(Program).Assembly.Location;
|
var exe = typeof(Program).Assembly.Location;
|
||||||
_cli.WaitForPID = Process.GetCurrentProcess().Id.ToString();
|
_config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
|
||||||
Process.Start(exe, _cli.ToString());
|
Process.Start(exe, _config.ToString());
|
||||||
}
|
}
|
||||||
//1627 = Function failed during execution.
|
//1627 = Function failed during execution.
|
||||||
Environment.Exit(1627);
|
Environment.Exit(1627);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.182.329")]
|
[assembly: AssemblyVersion("1.0.186.642")]
|
||||||
[assembly: AssemblyFileVersion("1.0.182.329")]
|
[assembly: AssemblyFileVersion("1.0.186.642")]
|
@@ -184,7 +184,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Managers\ConfigManager.cs" />
|
<Compile Include="Managers\ConfigManager.cs" />
|
||||||
<Compile Include="TorchCli.cs" />
|
|
||||||
<Compile Include="NativeMethods.cs" />
|
<Compile Include="NativeMethods.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
|
@@ -1,41 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Torch.Server
|
|
||||||
{
|
|
||||||
public class TorchCli : CommandLine
|
|
||||||
{
|
|
||||||
public TorchConfig Config { get; set; }
|
|
||||||
|
|
||||||
[Arg("instancepath", "Server data folder where saves and mods are stored.")]
|
|
||||||
public string InstancePath { get => Config.InstancePath; set => Config.InstancePath = value; }
|
|
||||||
|
|
||||||
[Arg("noupdate", "Disable automatically downloading game and plugin updates.")]
|
|
||||||
public bool NoUpdate { get => !Config.AutomaticUpdates; set => Config.AutomaticUpdates = !value; }
|
|
||||||
|
|
||||||
[Arg("update", "Manually check for and install updates.")]
|
|
||||||
public bool Update { get; set; }
|
|
||||||
|
|
||||||
//TODO: backend code for this
|
|
||||||
//[Arg("worldpath", "Path to the game world folder to load.")]
|
|
||||||
public string WorldPath { get; set; }
|
|
||||||
|
|
||||||
[Arg("autostart", "Start the server immediately.")]
|
|
||||||
public bool Autostart { get; set; }
|
|
||||||
|
|
||||||
[Arg("restartoncrash", "Automatically restart the server if it crashes.")]
|
|
||||||
public bool RestartOnCrash { get => Config.RestartOnCrash; set => Config.RestartOnCrash = value; }
|
|
||||||
|
|
||||||
[Arg("nogui", "Do not show the Torch UI.")]
|
|
||||||
public bool NoGui { get; set; }
|
|
||||||
|
|
||||||
[Arg("silent", "Do not show the Torch UI or the command line.")]
|
|
||||||
public bool Silent { get; set; }
|
|
||||||
|
|
||||||
[Arg("waitforpid", "Makes Torch wait for another process to exit.")]
|
|
||||||
public string WaitForPID { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
@@ -7,25 +7,54 @@ using NLog;
|
|||||||
|
|
||||||
namespace Torch.Server
|
namespace Torch.Server
|
||||||
{
|
{
|
||||||
public class TorchConfig : ITorchConfig
|
public class TorchConfig : CommandLine, ITorchConfig
|
||||||
{
|
{
|
||||||
private static Logger _log = LogManager.GetLogger("Config");
|
private static Logger _log = LogManager.GetLogger("Config");
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[Arg("instancepath", "Server data folder where saves and mods are stored.")]
|
||||||
public string InstancePath { get; set; }
|
public string InstancePath { get; set; }
|
||||||
public string InstanceName { get; set; }
|
|
||||||
#warning World Path not implemented
|
/// <inheritdoc />
|
||||||
public string WorldPath { get; set; }
|
[XmlIgnore, Arg("noupdate", "Disable automatically downloading game and plugin updates.")]
|
||||||
public bool AutomaticUpdates { get; set; } = true;
|
public bool NoUpdate { get => false; set => GetTorchUpdates = GetPluginUpdates = !value; }
|
||||||
public bool RedownloadPlugins { get; set; }
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[XmlIgnore, Arg("update", "Manually check for and install updates.")]
|
||||||
|
public bool Update { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[XmlIgnore, Arg("autostart", "Start the server immediately.")]
|
||||||
|
public bool Autostart { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[Arg("restartoncrash", "Automatically restart the server if it crashes.")]
|
||||||
public bool RestartOnCrash { get; set; }
|
public bool RestartOnCrash { get; set; }
|
||||||
/// <summary>
|
|
||||||
/// How long in seconds to wait before automatically resetting a frozen server.
|
/// <inheritdoc />
|
||||||
/// </summary>
|
[XmlIgnore, Arg("nogui", "Do not show the Torch UI.")]
|
||||||
|
public bool NoGui { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[XmlIgnore, Arg("waitforpid", "Makes Torch wait for another process to exit.")]
|
||||||
|
public string WaitForPID { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[Arg("instancename", "The name of the Torch instance.")]
|
||||||
|
public string InstanceName { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool GetTorchUpdates { get; set; } = true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool GetPluginUpdates { get; set; } = true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public int TickTimeout { get; set; } = 60;
|
public int TickTimeout { get; set; } = 60;
|
||||||
/// <summary>
|
|
||||||
/// A list of plugins to install or update. TODO
|
/// <inheritdoc />
|
||||||
/// </summary>
|
|
||||||
public List<string> Plugins { get; set; } = new List<string>();
|
public List<string> Plugins { get; set; } = new List<string>();
|
||||||
|
|
||||||
internal Point WindowSize { get; set; } = new Point(800, 600);
|
internal Point WindowSize { get; set; } = new Point(800, 600);
|
||||||
internal Point WindowPosition { get; set; } = new Point();
|
internal Point WindowPosition { get; set; } = new Point();
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
|
@@ -16,6 +16,7 @@ using Sandbox.Game.Multiplayer;
|
|||||||
using Sandbox.ModAPI;
|
using Sandbox.ModAPI;
|
||||||
using SteamSDK;
|
using SteamSDK;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
|
using Torch.Managers;
|
||||||
using VRage.Dedicated;
|
using VRage.Dedicated;
|
||||||
using VRage.FileSystem;
|
using VRage.FileSystem;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
@@ -37,7 +38,9 @@ namespace Torch.Server
|
|||||||
public Thread GameThread { get; private set; }
|
public Thread GameThread { get; private set; }
|
||||||
public ServerState State { get => _state; private set { _state = value; OnPropertyChanged(); } }
|
public ServerState State { get => _state; private set { _state = value; OnPropertyChanged(); } }
|
||||||
public bool IsRunning { get => _isRunning; set { _isRunning = value; OnPropertyChanged(); } }
|
public bool IsRunning { get => _isRunning; set { _isRunning = value; OnPropertyChanged(); } }
|
||||||
|
/// <inheritdoc />
|
||||||
public string InstanceName => Config?.InstanceName;
|
public string InstanceName => Config?.InstanceName;
|
||||||
|
/// <inheritdoc />
|
||||||
public string InstancePath => Config?.InstancePath;
|
public string InstancePath => Config?.InstancePath;
|
||||||
|
|
||||||
private bool _isRunning;
|
private bool _isRunning;
|
||||||
@@ -53,6 +56,7 @@ namespace Torch.Server
|
|||||||
MyFakes.ENABLE_INFINARIO = false;
|
MyFakes.ENABLE_INFINARIO = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
base.Init();
|
base.Init();
|
||||||
@@ -81,7 +85,7 @@ namespace Torch.Server
|
|||||||
RuntimeHelpers.RunClassConstructor(typeof(MyObjectBuilder_Base).TypeHandle);
|
RuntimeHelpers.RunClassConstructor(typeof(MyObjectBuilder_Base).TypeHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InvokeBeforeRun()
|
private void InvokeBeforeRun()
|
||||||
{
|
{
|
||||||
|
|
||||||
var contentPath = "Content";
|
var contentPath = "Content";
|
||||||
@@ -91,16 +95,7 @@ namespace Torch.Server
|
|||||||
Log.Debug("MyFileSystem already initialized");
|
Log.Debug("MyFileSystem already initialized");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Program.IsManualInstall)
|
MyFileSystem.ExePath = Path.Combine(GetManager<FilesystemManager>().TorchDirectory, "DedicatedServer64");
|
||||||
{
|
|
||||||
var rootPath = new FileInfo(MyFileSystem.ExePath).Directory.FullName;
|
|
||||||
contentPath = Path.Combine(rootPath, "Content");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MyFileSystem.ExePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DedicatedServer64");
|
|
||||||
}
|
|
||||||
|
|
||||||
MyFileSystem.Init(contentPath, InstancePath);
|
MyFileSystem.Init(contentPath, InstancePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,14 +127,13 @@ namespace Torch.Server
|
|||||||
MySandboxGame.Config.Load();
|
MySandboxGame.Config.Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Start server on the current thread.
|
|
||||||
/// </summary>
|
|
||||||
public override void Start()
|
public override void Start()
|
||||||
{
|
{
|
||||||
if (State != ServerState.Stopped)
|
if (State != ServerState.Stopped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
IsRunning = true;
|
||||||
GameThread = Thread.CurrentThread;
|
GameThread = Thread.CurrentThread;
|
||||||
Config.Save();
|
Config.Save();
|
||||||
State = ServerState.Starting;
|
State = ServerState.Starting;
|
||||||
@@ -196,9 +190,7 @@ namespace Torch.Server
|
|||||||
Log.Debug("Server watchdog responded");
|
Log.Debug("Server watchdog responded");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Stop the server.
|
|
||||||
/// </summary>
|
|
||||||
public override void Stop()
|
public override void Stop()
|
||||||
{
|
{
|
||||||
if (State == ServerState.Stopped)
|
if (State == ServerState.Stopped)
|
||||||
@@ -220,6 +212,12 @@ namespace Torch.Server
|
|||||||
Log.Info("Server stopped.");
|
Log.Info("Server stopped.");
|
||||||
_stopHandle.Set();
|
_stopHandle.Set();
|
||||||
State = ServerState.Stopped;
|
State = ServerState.Stopped;
|
||||||
|
IsRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Restart()
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -41,6 +42,17 @@ namespace Torch.Server
|
|||||||
_server = (TorchBase)server;
|
_server = (TorchBase)server;
|
||||||
_multiplayer = (MultiplayerManager)server.Multiplayer;
|
_multiplayer = (MultiplayerManager)server.Multiplayer;
|
||||||
DataContext = _multiplayer;
|
DataContext = _multiplayer;
|
||||||
|
_multiplayer.ChatHistory.CollectionChanged += ChatHistory_CollectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChatHistory_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (VisualTreeHelper.GetChildrenCount(ChatItems) > 0)
|
||||||
|
{
|
||||||
|
Border border = (Border)VisualTreeHelper.GetChild(ChatItems, 0);
|
||||||
|
ScrollViewer scrollViewer = (ScrollViewer)VisualTreeHelper.GetChild(border, 0);
|
||||||
|
scrollViewer.ScrollToBottom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendButton_Click(object sender, RoutedEventArgs e)
|
private void SendButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
@@ -5,14 +5,18 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:Torch.Server"
|
xmlns:local="clr-namespace:Torch.Server"
|
||||||
xmlns:views="clr-namespace:Torch.Server.Views"
|
xmlns:views="clr-namespace:Torch.Server.Views"
|
||||||
|
xmlns:converters="clr-namespace:Torch.Server.Views.Converters"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Torch">
|
Title="Torch">
|
||||||
|
<Window.Resources>
|
||||||
|
<converters:InverseBooleanConverter x:Key="inverseBool"/>
|
||||||
|
</Window.Resources>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<StackPanel DockPanel.Dock="Top" Margin="5,5,5,5" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Top" Margin="5,5,5,5" Orientation="Horizontal">
|
||||||
<Button x:Name="BtnStart" Content="Start" Height="24" Width="75" Margin="5,0,5,0"
|
<Button x:Name="BtnStart" Content="Start" Height="24" Width="75" Margin="5,0,5,0"
|
||||||
HorizontalAlignment="Left" Click="BtnStart_Click" IsDefault="True" />
|
HorizontalAlignment="Left" Click="BtnStart_Click" IsDefault="True" IsEnabled="{Binding IsRunning, Converter={StaticResource inverseBool}}"/>
|
||||||
<Button x:Name="BtnStop" Content="Stop" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left"
|
<Button x:Name="BtnStop" Content="Stop" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left"
|
||||||
Click="BtnStop_Click" IsEnabled="False" />
|
Click="BtnStop_Click" IsEnabled="{Binding IsRunning}" />
|
||||||
<Label>
|
<Label>
|
||||||
<Label.Content>
|
<Label.Content>
|
||||||
<TextBlock Text="{Binding State, StringFormat=Status: {0}}"></TextBlock>
|
<TextBlock Text="{Binding State, StringFormat=Status: {0}}"></TextBlock>
|
||||||
@@ -37,13 +41,13 @@
|
|||||||
<TextBox x:Name="InstancePathBox" Margin="3" Height="20"
|
<TextBox x:Name="InstancePathBox" Margin="3" Height="20"
|
||||||
TextChanged="InstancePathBox_OnTextChanged" IsEnabled="False" />
|
TextChanged="InstancePathBox_OnTextChanged" IsEnabled="False" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<views:ConfigControl x:Name="ConfigControl" Margin="3" DockPanel.Dock="Bottom" />
|
<views:ConfigControl x:Name="ConfigControl" Margin="3" DockPanel.Dock="Bottom" IsEnabled="{Binding IsRunning, Converter={StaticResource inverseBool}}"/>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="Chat/Players">
|
<TabItem Header="Chat/Players">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<local:PlayerListControl x:Name="PlayerList" DockPanel.Dock="Right" Width="250" />
|
<local:PlayerListControl x:Name="PlayerList" DockPanel.Dock="Right" Width="250" />
|
||||||
<local:ChatControl x:Name="Chat" />
|
<local:ChatControl x:Name="Chat" IsEnabled="{Binding IsRunning}"/>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="Entity Manager">
|
<TabItem Header="Entity Manager">
|
||||||
|
@@ -65,18 +65,12 @@ namespace Torch.Server
|
|||||||
private void BtnStart_Click(object sender, RoutedEventArgs e)
|
private void BtnStart_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_config.Save();
|
_config.Save();
|
||||||
((Button) sender).IsEnabled = false;
|
|
||||||
BtnStop.IsEnabled = true;
|
|
||||||
ConfigControl.SaveConfig();
|
ConfigControl.SaveConfig();
|
||||||
new Thread(_server.Start).Start();
|
new Thread(_server.Start).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_config.Save();
|
|
||||||
((Button) sender).IsEnabled = false;
|
|
||||||
//HACK: Uncomment when restarting is possible.
|
|
||||||
//BtnStart.IsEnabled = true;
|
|
||||||
_server.Stop();
|
_server.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@ using VRage.Network;
|
|||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
public struct ChatMessage : IChatMessage
|
public class ChatMessage : IChatMessage
|
||||||
{
|
{
|
||||||
public DateTime Timestamp { get; }
|
public DateTime Timestamp { get; }
|
||||||
public ulong SteamId { get; }
|
public ulong SteamId { get; }
|
||||||
|
@@ -9,6 +9,7 @@ using System.Windows.Threading;
|
|||||||
|
|
||||||
namespace Torch.Collections
|
namespace Torch.Collections
|
||||||
{
|
{
|
||||||
|
[Serializable]
|
||||||
public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
|
public class ObservableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
51
Torch/Managers/FilesystemManager.cs
Normal file
51
Torch/Managers/FilesystemManager.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Torch.API;
|
||||||
|
|
||||||
|
namespace Torch.Managers
|
||||||
|
{
|
||||||
|
public class FilesystemManager : Manager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Temporary directory for Torch that is cleared every time the program is started.
|
||||||
|
/// </summary>
|
||||||
|
public string TempDirectory { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Directory that contains the current Torch assemblies.
|
||||||
|
/// </summary>
|
||||||
|
public string TorchDirectory { get; }
|
||||||
|
|
||||||
|
public FilesystemManager(ITorchBase torchInstance) : base(torchInstance)
|
||||||
|
{
|
||||||
|
var temp = Path.Combine(Path.GetTempPath(), "Torch");
|
||||||
|
TempDirectory = Directory.CreateDirectory(temp).FullName;
|
||||||
|
var torch = new FileInfo(typeof(FilesystemManager).Assembly.Location).Directory.FullName;
|
||||||
|
TorchDirectory = torch;
|
||||||
|
|
||||||
|
ClearTemp();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearTemp()
|
||||||
|
{
|
||||||
|
foreach (var file in Directory.GetFiles(TempDirectory, "*", SearchOption.AllDirectories))
|
||||||
|
File.Delete(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Move the given file (if it exists) to a temporary directory that will be cleared the next time the application starts.
|
||||||
|
/// </summary>
|
||||||
|
public void SoftDelete(string file)
|
||||||
|
{
|
||||||
|
if (!File.Exists(file))
|
||||||
|
return;
|
||||||
|
var rand = Path.GetRandomFileName();
|
||||||
|
var dest = Path.Combine(TempDirectory, rand);
|
||||||
|
File.Move(file, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -33,20 +33,21 @@ using VRage.Utils;
|
|||||||
|
|
||||||
namespace Torch.Managers
|
namespace Torch.Managers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Provides a proxy to the game's multiplayer-related functions.
|
|
||||||
/// </summary>
|
|
||||||
public class MultiplayerManager : Manager, IMultiplayerManager
|
public class MultiplayerManager : Manager, IMultiplayerManager
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
public event Action<IPlayer> PlayerJoined;
|
public event Action<IPlayer> PlayerJoined;
|
||||||
|
/// <inheritdoc />
|
||||||
public event Action<IPlayer> PlayerLeft;
|
public event Action<IPlayer> PlayerLeft;
|
||||||
|
/// <inheritdoc />
|
||||||
public event MessageReceivedDel MessageReceived;
|
public event MessageReceivedDel MessageReceived;
|
||||||
|
|
||||||
public MTObservableCollection<IChatMessage> ChatHistory { get; } = new MTObservableCollection<IChatMessage>();
|
public MTObservableCollection<IChatMessage> ChatHistory { get; } = new MTObservableCollection<IChatMessage>();
|
||||||
public ObservableDictionary<ulong, PlayerViewModel> Players { get; } = new ObservableDictionary<ulong, PlayerViewModel>();
|
public ObservableDictionary<ulong, PlayerViewModel> Players { get; } = new ObservableDictionary<ulong, PlayerViewModel>();
|
||||||
public IMyPlayer LocalPlayer => MySession.Static.LocalHumanPlayer;
|
public IMyPlayer LocalPlayer => MySession.Static.LocalHumanPlayer;
|
||||||
private static readonly Logger _log = LogManager.GetLogger(nameof(MultiplayerManager));
|
private static readonly Logger Log = LogManager.GetLogger(nameof(MultiplayerManager));
|
||||||
private static readonly Logger _chatLog = LogManager.GetLogger("Chat");
|
private static readonly Logger ChatLog = LogManager.GetLogger("Chat");
|
||||||
private Dictionary<MyPlayer.PlayerId, MyPlayer> _onlinePlayers;
|
private Dictionary<MyPlayer.PlayerId, MyPlayer> _onlinePlayers;
|
||||||
|
|
||||||
internal MultiplayerManager(ITorchBase torch) : base(torch)
|
internal MultiplayerManager(ITorchBase torch) : base(torch)
|
||||||
@@ -65,12 +66,14 @@ namespace Torch.Managers
|
|||||||
{
|
{
|
||||||
var message = ChatMessage.FromChatMsg(msg);
|
var message = ChatMessage.FromChatMsg(msg);
|
||||||
ChatHistory.Add(message);
|
ChatHistory.Add(message);
|
||||||
_chatLog.Info($"{message.Name}: {message.Message}");
|
ChatLog.Info($"{message.Name}: {message.Message}");
|
||||||
MessageReceived?.Invoke(message, ref sendToOthers);
|
MessageReceived?.Invoke(message, ref sendToOthers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public void KickPlayer(ulong steamId) => Torch.Invoke(() => MyMultiplayer.Static.KickClient(steamId));
|
public void KickPlayer(ulong steamId) => Torch.Invoke(() => MyMultiplayer.Static.KickClient(steamId));
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public void BanPlayer(ulong steamId, bool banned = true)
|
public void BanPlayer(ulong steamId, bool banned = true)
|
||||||
{
|
{
|
||||||
Torch.Invoke(() =>
|
Torch.Invoke(() =>
|
||||||
@@ -81,12 +84,14 @@ namespace Torch.Managers
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IMyPlayer GetPlayerByName(string name)
|
public IMyPlayer GetPlayerByName(string name)
|
||||||
{
|
{
|
||||||
ValidateOnlinePlayersList();
|
ValidateOnlinePlayersList();
|
||||||
return _onlinePlayers.FirstOrDefault(x => x.Value.DisplayName == name).Value;
|
return _onlinePlayers.FirstOrDefault(x => x.Value.DisplayName == name).Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public IMyPlayer GetPlayerBySteamId(ulong steamId)
|
public IMyPlayer GetPlayerBySteamId(ulong steamId)
|
||||||
{
|
{
|
||||||
ValidateOnlinePlayersList();
|
ValidateOnlinePlayersList();
|
||||||
@@ -94,14 +99,13 @@ namespace Torch.Managers
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public string GetSteamUsername(ulong steamId)
|
public string GetSteamUsername(ulong steamId)
|
||||||
{
|
{
|
||||||
return MyMultiplayer.Static.GetMemberName(steamId);
|
return MyMultiplayer.Static.GetMemberName(steamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Send a message in chat.
|
|
||||||
/// </summary>
|
|
||||||
public void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Red)
|
public void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Red)
|
||||||
{
|
{
|
||||||
ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", message));
|
ChatHistory.Add(new ChatMessage(DateTime.Now, 0, "Server", message));
|
||||||
@@ -126,7 +130,7 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
private void OnSessionLoaded()
|
private void OnSessionLoaded()
|
||||||
{
|
{
|
||||||
_log.Info("Initializing Steam auth");
|
Log.Info("Initializing Steam auth");
|
||||||
MyMultiplayer.Static.ClientKicked += OnClientKicked;
|
MyMultiplayer.Static.ClientKicked += OnClientKicked;
|
||||||
MyMultiplayer.Static.ClientLeft += OnClientLeft;
|
MyMultiplayer.Static.ClientLeft += OnClientLeft;
|
||||||
|
|
||||||
@@ -138,7 +142,7 @@ namespace Torch.Managers
|
|||||||
SteamServerAPI.Instance.GameServer.UserGroupStatus += UserGroupStatus;
|
SteamServerAPI.Instance.GameServer.UserGroupStatus += UserGroupStatus;
|
||||||
_members = (List<ulong>)typeof(MyDedicatedServerBase).GetField("m_members", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(MyMultiplayer.Static);
|
_members = (List<ulong>)typeof(MyDedicatedServerBase).GetField("m_members", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(MyMultiplayer.Static);
|
||||||
_waitingForGroup = (HashSet<ulong>)typeof(MyDedicatedServerBase).GetField("m_waitingForGroup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(MyMultiplayer.Static);
|
_waitingForGroup = (HashSet<ulong>)typeof(MyDedicatedServerBase).GetField("m_waitingForGroup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(MyMultiplayer.Static);
|
||||||
_log.Info("Steam auth initialized");
|
Log.Info("Steam auth initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnClientKicked(ulong steamId)
|
private void OnClientKicked(ulong steamId)
|
||||||
@@ -151,7 +155,7 @@ namespace Torch.Managers
|
|||||||
Players.TryGetValue(steamId, out PlayerViewModel vm);
|
Players.TryGetValue(steamId, out PlayerViewModel vm);
|
||||||
if (vm == null)
|
if (vm == null)
|
||||||
vm = new PlayerViewModel(steamId);
|
vm = new PlayerViewModel(steamId);
|
||||||
_log.Info($"{vm.Name} ({vm.SteamId}) {(ConnectionState)stateChange}.");
|
Log.Info($"{vm.Name} ({vm.SteamId}) {(ConnectionState)stateChange}.");
|
||||||
PlayerLeft?.Invoke(vm);
|
PlayerLeft?.Invoke(vm);
|
||||||
Players.Remove(steamId);
|
Players.Remove(steamId);
|
||||||
}
|
}
|
||||||
@@ -178,7 +182,7 @@ namespace Torch.Managers
|
|||||||
if (handle.Method.Name == "GameServer_ValidateAuthTicketResponse")
|
if (handle.Method.Name == "GameServer_ValidateAuthTicketResponse")
|
||||||
{
|
{
|
||||||
SteamServerAPI.Instance.GameServer.ValidateAuthTicketResponse -= handle as ValidateAuthTicketResponse;
|
SteamServerAPI.Instance.GameServer.ValidateAuthTicketResponse -= handle as ValidateAuthTicketResponse;
|
||||||
_log.Debug("Removed GameServer_ValidateAuthTicketResponse");
|
Log.Debug("Removed GameServer_ValidateAuthTicketResponse");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,7 +195,7 @@ namespace Torch.Managers
|
|||||||
if (handle.Method.Name == "GameServer_UserGroupStatus")
|
if (handle.Method.Name == "GameServer_UserGroupStatus")
|
||||||
{
|
{
|
||||||
SteamServerAPI.Instance.GameServer.UserGroupStatus -= handle as UserGroupStatus;
|
SteamServerAPI.Instance.GameServer.UserGroupStatus -= handle as UserGroupStatus;
|
||||||
_log.Debug("Removed GameServer_UserGroupStatus");
|
Log.Debug("Removed GameServer_UserGroupStatus");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,16 +204,16 @@ namespace Torch.Managers
|
|||||||
//Largely copied from SE
|
//Largely copied from SE
|
||||||
private void ValidateAuthTicketResponse(ulong steamID, AuthSessionResponseEnum response, ulong ownerSteamID)
|
private void ValidateAuthTicketResponse(ulong steamID, AuthSessionResponseEnum response, ulong ownerSteamID)
|
||||||
{
|
{
|
||||||
_log.Info($"Server ValidateAuthTicketResponse ({response}), owner: {ownerSteamID}");
|
Log.Info($"Server ValidateAuthTicketResponse ({response}), owner: {ownerSteamID}");
|
||||||
|
|
||||||
if (steamID != ownerSteamID)
|
if (steamID != ownerSteamID)
|
||||||
{
|
{
|
||||||
_log.Info($"User {steamID} is using a game owned by {ownerSteamID}. Tracking...");
|
Log.Info($"User {steamID} is using a game owned by {ownerSteamID}. Tracking...");
|
||||||
_gameOwnerIds[steamID] = ownerSteamID;
|
_gameOwnerIds[steamID] = ownerSteamID;
|
||||||
|
|
||||||
if (MySandboxGame.ConfigDedicated.Banned.Contains(ownerSteamID))
|
if (MySandboxGame.ConfigDedicated.Banned.Contains(ownerSteamID))
|
||||||
{
|
{
|
||||||
_log.Info($"Game owner {ownerSteamID} is banned. Banning and rejecting client {steamID}...");
|
Log.Info($"Game owner {ownerSteamID} is banned. Banning and rejecting client {steamID}...");
|
||||||
UserRejected(steamID, JoinResult.BannedByAdmins);
|
UserRejected(steamID, JoinResult.BannedByAdmins);
|
||||||
BanPlayer(steamID);
|
BanPlayer(steamID);
|
||||||
}
|
}
|
||||||
@@ -306,7 +310,7 @@ namespace Torch.Managers
|
|||||||
{
|
{
|
||||||
typeof(MyDedicatedServerBase).GetMethod("UserAccepted", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(MyMultiplayer.Static, new object[] {steamId});
|
typeof(MyDedicatedServerBase).GetMethod("UserAccepted", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(MyMultiplayer.Static, new object[] {steamId});
|
||||||
var vm = new PlayerViewModel(steamId) {State = ConnectionState.Connected};
|
var vm = new PlayerViewModel(steamId) {State = ConnectionState.Connected};
|
||||||
_log.Info($"Player {vm.Name} joined ({vm.SteamId})");
|
Log.Info($"Player {vm.Name} joined ({vm.SteamId})");
|
||||||
Players.Add(steamId, vm);
|
Players.Add(steamId, vm);
|
||||||
PlayerJoined?.Invoke(vm);
|
PlayerJoined?.Invoke(vm);
|
||||||
}
|
}
|
||||||
|
@@ -64,6 +64,11 @@ namespace Torch.Managers
|
|||||||
/// Loads the network intercept system
|
/// Loads the network intercept system
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Init()
|
public override void Init()
|
||||||
|
{
|
||||||
|
Torch.SessionLoaded += OnSessionLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSessionLoaded()
|
||||||
{
|
{
|
||||||
if (_init)
|
if (_init)
|
||||||
return;
|
return;
|
||||||
|
@@ -5,42 +5,30 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox;
|
|
||||||
using Sandbox.ModAPI;
|
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.API.Plugins;
|
using Torch.API.Plugins;
|
||||||
using Torch.Commands;
|
using Torch.Commands;
|
||||||
using Torch.Managers;
|
|
||||||
using Torch.Updater;
|
|
||||||
using VRage.Plugins;
|
|
||||||
using VRage.Collections;
|
using VRage.Collections;
|
||||||
using VRage.Library.Collections;
|
|
||||||
|
|
||||||
namespace Torch.Managers
|
namespace Torch.Managers
|
||||||
{
|
{
|
||||||
public class PluginManager : IPluginManager
|
/// <inheritdoc />
|
||||||
|
public class PluginManager : Manager, IPluginManager
|
||||||
{
|
{
|
||||||
private readonly ITorchBase _torch;
|
|
||||||
private static Logger _log = LogManager.GetLogger(nameof(PluginManager));
|
private static Logger _log = LogManager.GetLogger(nameof(PluginManager));
|
||||||
public readonly string PluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
|
public readonly string PluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
|
||||||
|
private UpdateManager _updateManager;
|
||||||
|
|
||||||
public List<ITorchPlugin> Plugins { get; } = new List<ITorchPlugin>();
|
/// <inheritdoc />
|
||||||
|
public ObservableCollection<ITorchPlugin> Plugins { get; } = new ObservableCollection<ITorchPlugin>();
|
||||||
public float LastUpdateMs => _lastUpdateMs;
|
|
||||||
private volatile float _lastUpdateMs;
|
|
||||||
|
|
||||||
public event Action<List<ITorchPlugin>> PluginsLoaded;
|
public event Action<List<ITorchPlugin>> PluginsLoaded;
|
||||||
|
|
||||||
public PluginManager(ITorchBase torch)
|
public PluginManager(ITorchBase torchInstance) : base(torchInstance)
|
||||||
{
|
{
|
||||||
_torch = torch;
|
|
||||||
|
|
||||||
if (!Directory.Exists(PluginDir))
|
if (!Directory.Exists(PluginDir))
|
||||||
Directory.CreateDirectory(PluginDir);
|
Directory.CreateDirectory(PluginDir);
|
||||||
}
|
}
|
||||||
@@ -50,11 +38,8 @@ namespace Torch.Managers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdatePlugins()
|
public void UpdatePlugins()
|
||||||
{
|
{
|
||||||
var s = Stopwatch.StartNew();
|
|
||||||
foreach (var plugin in Plugins)
|
foreach (var plugin in Plugins)
|
||||||
plugin.Update();
|
plugin.Update();
|
||||||
s.Stop();
|
|
||||||
_lastUpdateMs = (float)s.Elapsed.TotalMilliseconds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -70,40 +55,42 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
private void DownloadPlugins()
|
private void DownloadPlugins()
|
||||||
{
|
{
|
||||||
_log.Info("Downloading plugins");
|
|
||||||
var updater = new PluginUpdater(this);
|
|
||||||
|
|
||||||
var folders = Directory.GetDirectories(PluginDir);
|
var folders = Directory.GetDirectories(PluginDir);
|
||||||
var taskList = new List<Task>();
|
var taskList = new List<Task>();
|
||||||
if (_torch.Config.RedownloadPlugins)
|
|
||||||
_log.Warn("Force downloading all plugins because the RedownloadPlugins flag is set in the config");
|
//Copy list because we don't want to modify the config.
|
||||||
|
var toDownload = Torch.Config.Plugins.ToList();
|
||||||
|
|
||||||
foreach (var folder in folders)
|
foreach (var folder in folders)
|
||||||
{
|
{
|
||||||
var manifestPath = Path.Combine(folder, "manifest.xml");
|
var manifestPath = Path.Combine(folder, "manifest.xml");
|
||||||
if (!File.Exists(manifestPath))
|
if (!File.Exists(manifestPath))
|
||||||
{
|
{
|
||||||
_log.Info($"No manifest in {folder}, skipping");
|
_log.Debug($"No manifest in {folder}, skipping");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_log.Info($"Checking for updates for {folder}");
|
|
||||||
var manifest = PluginManifest.Load(manifestPath);
|
var manifest = PluginManifest.Load(manifestPath);
|
||||||
taskList.Add(updater.CheckAndUpdate(manifest, _torch.Config.RedownloadPlugins));
|
toDownload.Remove(manifest.Repository);
|
||||||
|
taskList.Add(_updateManager.CheckAndUpdatePlugin(manifest));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var repository in toDownload)
|
||||||
|
{
|
||||||
|
var manifest = new PluginManifest {Repository = repository, Version = "0.0"};
|
||||||
|
taskList.Add(_updateManager.CheckAndUpdatePlugin(manifest));
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.WaitAll(taskList.ToArray());
|
Task.WaitAll(taskList.ToArray());
|
||||||
_torch.Config.RedownloadPlugins = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Loads and creates instances of all plugins in the <see cref="PluginDir"/> folder.
|
public override void Init()
|
||||||
/// </summary>
|
|
||||||
public void Init()
|
|
||||||
{
|
{
|
||||||
var commands = ((TorchBase)_torch).Commands;
|
_updateManager = Torch.GetManager<UpdateManager>();
|
||||||
|
var commands = Torch.GetManager<CommandManager>();
|
||||||
|
|
||||||
if (_torch.Config.AutomaticUpdates)
|
if (Torch.Config.GetPluginUpdates)
|
||||||
DownloadPlugins();
|
DownloadPlugins();
|
||||||
else
|
else
|
||||||
_log.Warn("Automatic plugin updates are disabled.");
|
_log.Warn("Automatic plugin updates are disabled.");
|
||||||
@@ -129,7 +116,7 @@ namespace Torch.Managers
|
|||||||
throw new TypeLoadException($"Plugin '{type.FullName}' is missing a {nameof(PluginAttribute)}");
|
throw new TypeLoadException($"Plugin '{type.FullName}' is missing a {nameof(PluginAttribute)}");
|
||||||
|
|
||||||
_log.Info($"Loading plugin {plugin.Name} ({plugin.Version})");
|
_log.Info($"Loading plugin {plugin.Name} ({plugin.Version})");
|
||||||
plugin.StoragePath = _torch.Config.InstancePath;
|
plugin.StoragePath = Torch.Config.InstancePath;
|
||||||
Plugins.Add(plugin);
|
Plugins.Add(plugin);
|
||||||
|
|
||||||
commands.RegisterPluginCommands(plugin);
|
commands.RegisterPluginCommands(plugin);
|
||||||
@@ -143,8 +130,8 @@ namespace Torch.Managers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Plugins.ForEach(p => p.Init(_torch));
|
Plugins.ForEach(p => p.Init(Torch));
|
||||||
PluginsLoaded?.Invoke(Plugins);
|
PluginsLoaded?.Invoke(Plugins.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<ITorchPlugin> GetEnumerator()
|
public IEnumerator<ITorchPlugin> GetEnumerator()
|
||||||
|
@@ -1,28 +1,128 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.IO.Packaging;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NLog;
|
||||||
|
using Octokit;
|
||||||
using SteamSDK;
|
using SteamSDK;
|
||||||
|
using Torch.API;
|
||||||
|
|
||||||
namespace Torch.Managers
|
namespace Torch.Managers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles updating of the DS and Torch plugins.
|
/// Handles updating of the DS and Torch plugins.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UpdateManager : IDisposable
|
public class UpdateManager : Manager, IDisposable
|
||||||
{
|
{
|
||||||
private Timer _updatePollTimer;
|
private Timer _updatePollTimer;
|
||||||
|
private GitHubClient _gitClient = new GitHubClient(new ProductHeaderValue("Torch"));
|
||||||
|
private string _torchDir = new FileInfo(typeof(UpdateManager).Assembly.Location).DirectoryName;
|
||||||
|
private Logger _log = LogManager.GetLogger(nameof(UpdateManager));
|
||||||
|
private FilesystemManager _fsManager;
|
||||||
|
|
||||||
public UpdateManager()
|
public UpdateManager(ITorchBase torchInstance) : base(torchInstance)
|
||||||
{
|
{
|
||||||
_updatePollTimer = new Timer(CheckForUpdates, this, TimeSpan.Zero, TimeSpan.FromMinutes(5));
|
//_updatePollTimer = new Timer(TimerElapsed, this, TimeSpan.Zero, TimeSpan.FromMinutes(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckForUpdates(object state)
|
/// <inheritdoc />
|
||||||
|
public override void Init()
|
||||||
{
|
{
|
||||||
|
_fsManager = Torch.GetManager<FilesystemManager>();
|
||||||
|
CheckAndUpdateTorch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimerElapsed(object state)
|
||||||
|
{
|
||||||
|
CheckAndUpdateTorch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Tuple<Version, string>> GetLatestRelease(string owner, string name)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var latest = await _gitClient.Repository.Release.GetLatest(owner, name).ConfigureAwait(false);
|
||||||
|
if (latest == null)
|
||||||
|
return new Tuple<Version, string>(new Version(), null);
|
||||||
|
|
||||||
|
var zip = latest.Assets.FirstOrDefault(x => x.Name.Contains(".zip"));
|
||||||
|
return new Tuple<Version, string>(new Version(latest.TagName ?? "0"), zip?.BrowserDownloadUrl);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_log.Error($"An error occurred getting release information for '{owner}/{name}'");
|
||||||
|
return new Tuple<Version, string>(new Version(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CheckAndUpdatePlugin(PluginManifest manifest)
|
||||||
|
{
|
||||||
|
if (!Torch.Config.GetPluginUpdates)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var name = manifest.Repository.Split('/');
|
||||||
|
if (name.Length != 2)
|
||||||
|
{
|
||||||
|
_log.Error($"'{manifest.Repository}' is not a valid GitHub repository.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentVersion = new Version(manifest.Version);
|
||||||
|
var releaseInfo = await GetLatestRelease(name[0], name[1]).ConfigureAwait(false);
|
||||||
|
if (releaseInfo.Item1 > currentVersion)
|
||||||
|
{
|
||||||
|
_log.Warn($"Updating {manifest.Repository} from version {currentVersion} to version {releaseInfo.Item1}");
|
||||||
|
var updateName = Path.Combine(_fsManager.TempDirectory, $"{name[0]}_{name[1]}.zip");
|
||||||
|
var updatePath = Path.Combine(_torchDir, "Plugins");
|
||||||
|
await new WebClient().DownloadFileTaskAsync(new Uri(releaseInfo.Item2), updateName).ConfigureAwait(false);
|
||||||
|
UpdateFromZip(updateName, updatePath);
|
||||||
|
File.Delete(updateName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_log.Info($"{manifest.Repository} is up to date. ({currentVersion})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void CheckAndUpdateTorch()
|
||||||
|
{
|
||||||
|
if (!Torch.Config.GetTorchUpdates)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var releaseInfo = await GetLatestRelease("TorchAPI", "Torch").ConfigureAwait(false);
|
||||||
|
if (releaseInfo.Item1 > Torch.TorchVersion)
|
||||||
|
{
|
||||||
|
_log.Warn($"Updating Torch from version {Torch.TorchVersion} to version {releaseInfo.Item1}");
|
||||||
|
var updateName = Path.Combine(_fsManager.TempDirectory, "torchupdate.zip");
|
||||||
|
new WebClient().DownloadFile(new Uri(releaseInfo.Item2), updateName);
|
||||||
|
UpdateFromZip(updateName, _torchDir);
|
||||||
|
File.Delete(updateName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_log.Info("Torch is up to date.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateFromZip(string zipFile, string extractPath)
|
||||||
|
{
|
||||||
|
using (var zip = ZipFile.OpenRead(zipFile))
|
||||||
|
{
|
||||||
|
foreach (var file in zip.Entries)
|
||||||
|
{
|
||||||
|
_log.Debug($"Unzipping {file.FullName}");
|
||||||
|
var targetFile = Path.Combine(extractPath, file.FullName);
|
||||||
|
_fsManager.SoftDelete(targetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
zip.ExtractToDirectory(extractPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
@@ -10,12 +12,14 @@ namespace Torch
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Simple class that manages saving <see cref="Persistent{T}.Data"/> to disk using JSON serialization.
|
/// Simple class that manages saving <see cref="Persistent{T}.Data"/> to disk using JSON serialization.
|
||||||
|
/// Can automatically save on changes by implementing <see cref="INotifyPropertyChanged"/> in the data class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T">Data class type</typeparam>
|
/// <typeparam name="T">Data class type</typeparam>
|
||||||
public sealed class Persistent<T> : IDisposable where T : new()
|
public sealed class Persistent<T> : IDisposable where T : new()
|
||||||
{
|
{
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
public T Data { get; private set; }
|
public T Data { get; private set; }
|
||||||
|
private Timer _saveTimer;
|
||||||
|
|
||||||
~Persistent()
|
~Persistent()
|
||||||
{
|
{
|
||||||
@@ -24,8 +28,21 @@ namespace Torch
|
|||||||
|
|
||||||
public Persistent(string path, T data = default(T))
|
public Persistent(string path, T data = default(T))
|
||||||
{
|
{
|
||||||
|
_saveTimer = new Timer(Callback);
|
||||||
Path = path;
|
Path = path;
|
||||||
Data = data;
|
Data = data;
|
||||||
|
if (Data is INotifyPropertyChanged npc)
|
||||||
|
npc.PropertyChanged += OnPropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_saveTimer.Change(5000, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Callback(object state)
|
||||||
|
{
|
||||||
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(string path = null)
|
public void Save(string path = null)
|
||||||
@@ -65,6 +82,9 @@ namespace Torch
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (Data is INotifyPropertyChanged npc)
|
||||||
|
npc.PropertyChanged -= OnPropertyChanged;
|
||||||
|
_saveTimer.Dispose();
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@@ -81,6 +81,8 @@
|
|||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.IO.Compression" />
|
||||||
|
<Reference Include="System.IO.Compression.FileSystem" />
|
||||||
<Reference Include="System.Xaml" />
|
<Reference Include="System.Xaml" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
@@ -161,19 +163,19 @@
|
|||||||
<Compile Include="Commands\TorchCommands.cs" />
|
<Compile Include="Commands\TorchCommands.cs" />
|
||||||
<Compile Include="Managers\ChatManager.cs" />
|
<Compile Include="Managers\ChatManager.cs" />
|
||||||
<Compile Include="Managers\EntityManager.cs" />
|
<Compile Include="Managers\EntityManager.cs" />
|
||||||
|
<Compile Include="Managers\FilesystemManager.cs" />
|
||||||
<Compile Include="Managers\Manager.cs" />
|
<Compile Include="Managers\Manager.cs" />
|
||||||
<Compile Include="Managers\NetworkManager\NetworkHandlerBase.cs" />
|
<Compile Include="Managers\NetworkManager\NetworkHandlerBase.cs" />
|
||||||
<Compile Include="Managers\NetworkManager\NetworkManager.cs" />
|
<Compile Include="Managers\NetworkManager\NetworkManager.cs" />
|
||||||
<Compile Include="Managers\MultiplayerManager.cs" />
|
<Compile Include="Managers\MultiplayerManager.cs" />
|
||||||
<Compile Include="Managers\UpdateManager.cs" />
|
<Compile Include="Managers\UpdateManager.cs" />
|
||||||
<Compile Include="Persistent.cs" />
|
<Compile Include="Persistent.cs" />
|
||||||
<Compile Include="Updater\PluginManifest.cs" />
|
<Compile Include="PluginManifest.cs" />
|
||||||
<Compile Include="Reflection.cs" />
|
<Compile Include="Reflection.cs" />
|
||||||
<Compile Include="Managers\ScriptingManager.cs" />
|
<Compile Include="Managers\ScriptingManager.cs" />
|
||||||
<Compile Include="TorchBase.cs" />
|
<Compile Include="TorchBase.cs" />
|
||||||
<Compile Include="SteamService.cs" />
|
<Compile Include="SteamService.cs" />
|
||||||
<Compile Include="TorchPluginBase.cs" />
|
<Compile Include="TorchPluginBase.cs" />
|
||||||
<Compile Include="Updater\PluginUpdater.cs" />
|
|
||||||
<Compile Include="ViewModels\ModViewModel.cs" />
|
<Compile Include="ViewModels\ModViewModel.cs" />
|
||||||
<Compile Include="Collections\MTObservableCollection.cs" />
|
<Compile Include="Collections\MTObservableCollection.cs" />
|
||||||
<Compile Include="Extensions\MyPlayerCollectionExtensions.cs" />
|
<Compile Include="Extensions\MyPlayerCollectionExtensions.cs" />
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -41,22 +41,38 @@ namespace Torch
|
|||||||
/// Use only if necessary, prefer dependency injection.
|
/// Use only if necessary, prefer dependency injection.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ITorchBase Instance { get; private set; }
|
public static ITorchBase Instance { get; private set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public ITorchConfig Config { get; protected set; }
|
public ITorchConfig Config { get; protected set; }
|
||||||
protected static Logger Log { get; } = LogManager.GetLogger("Torch");
|
/// <inheritdoc />
|
||||||
public Version TorchVersion { get; protected set; }
|
public Version TorchVersion { get; protected set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public Version GameVersion { get; private set; }
|
public Version GameVersion { get; private set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public string[] RunArgs { get; set; }
|
public string[] RunArgs { get; set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public IPluginManager Plugins { get; protected set; }
|
public IPluginManager Plugins { get; protected set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public IMultiplayerManager Multiplayer { get; protected set; }
|
public IMultiplayerManager Multiplayer { get; protected set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public EntityManager Entities { get; protected set; }
|
public EntityManager Entities { get; protected set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public INetworkManager Network { get; protected set; }
|
public INetworkManager Network { get; protected set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public CommandManager Commands { get; protected set; }
|
public CommandManager Commands { get; protected set; }
|
||||||
|
/// <inheritdoc />
|
||||||
public event Action SessionLoading;
|
public event Action SessionLoading;
|
||||||
|
/// <inheritdoc />
|
||||||
public event Action SessionLoaded;
|
public event Action SessionLoaded;
|
||||||
|
/// <inheritdoc />
|
||||||
public event Action SessionUnloading;
|
public event Action SessionUnloading;
|
||||||
|
/// <inheritdoc />
|
||||||
public event Action SessionUnloaded;
|
public event Action SessionUnloaded;
|
||||||
private readonly List<IManager> _managers;
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Common log for the Torch instance.
|
||||||
|
/// </summary>
|
||||||
|
protected static Logger Log { get; } = LogManager.GetLogger("Torch");
|
||||||
|
private readonly List<IManager> _managers;
|
||||||
private bool _init;
|
private bool _init;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -79,22 +95,25 @@ namespace Torch
|
|||||||
Network = new NetworkManager(this);
|
Network = new NetworkManager(this);
|
||||||
Commands = new CommandManager(this);
|
Commands = new CommandManager(this);
|
||||||
|
|
||||||
_managers = new List<IManager> {Network, Commands, Plugins, Multiplayer, Entities, new ChatManager(this)};
|
_managers = new List<IManager> { new FilesystemManager(this), new UpdateManager(this), Network, Commands, Plugins, Multiplayer, Entities, new ChatManager(this), };
|
||||||
|
|
||||||
|
|
||||||
TorchAPI.Instance = this;
|
TorchAPI.Instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public ListReader<IManager> GetManagers()
|
public ListReader<IManager> GetManagers()
|
||||||
{
|
{
|
||||||
return new ListReader<IManager>(_managers);
|
return new ListReader<IManager>(_managers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public T GetManager<T>() where T : class, IManager
|
public T GetManager<T>() where T : class, IManager
|
||||||
{
|
{
|
||||||
return _managers.FirstOrDefault(m => m is T) as T;
|
return _managers.FirstOrDefault(m => m is T) as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public bool AddManager<T>(T manager) where T : class, IManager
|
public bool AddManager<T>(T manager) where T : class, IManager
|
||||||
{
|
{
|
||||||
if (_managers.Any(x => x is T))
|
if (_managers.Any(x => x is T))
|
||||||
@@ -208,6 +227,7 @@ namespace Torch
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public virtual void Init()
|
public virtual void Init()
|
||||||
{
|
{
|
||||||
Debug.Assert(!_init, "Torch instance is already initialized.");
|
Debug.Assert(!_init, "Torch instance is already initialized.");
|
||||||
@@ -243,15 +263,14 @@ namespace Torch
|
|||||||
MySession.OnUnloading += OnSessionUnloading;
|
MySession.OnUnloading += OnSessionUnloading;
|
||||||
MySession.OnUnloaded += OnSessionUnloaded;
|
MySession.OnUnloaded += OnSessionUnloaded;
|
||||||
RegisterVRagePlugin();
|
RegisterVRagePlugin();
|
||||||
|
foreach (var manager in _managers)
|
||||||
|
manager.Init();
|
||||||
_init = true;
|
_init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSessionLoading()
|
private void OnSessionLoading()
|
||||||
{
|
{
|
||||||
Log.Debug("Session loading");
|
Log.Debug("Session loading");
|
||||||
foreach (var manager in _managers)
|
|
||||||
manager.Init();
|
|
||||||
SessionLoading?.Invoke();
|
SessionLoading?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,11 +311,13 @@ namespace Torch
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc
|
||||||
public virtual void Start()
|
public virtual void Start()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public virtual void Stop() { }
|
public virtual void Stop() { }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@@ -1,93 +0,0 @@
|
|||||||
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.Tasks;
|
|
||||||
using NLog;
|
|
||||||
using Octokit;
|
|
||||||
using Torch.API;
|
|
||||||
using Torch.Managers;
|
|
||||||
using VRage.Compression;
|
|
||||||
|
|
||||||
namespace Torch.Updater
|
|
||||||
{
|
|
||||||
public class PluginUpdater
|
|
||||||
{
|
|
||||||
private readonly PluginManager _pluginManager;
|
|
||||||
private static readonly Logger Log = LogManager.GetLogger("PluginUpdater");
|
|
||||||
|
|
||||||
public PluginUpdater(PluginManager pm)
|
|
||||||
{
|
|
||||||
_pluginManager = pm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CheckAndUpdate(PluginManifest manifest, bool force = false)
|
|
||||||
{
|
|
||||||
Log.Info($"Checking for update at {manifest.Repository}");
|
|
||||||
var split = manifest.Repository.Split('/');
|
|
||||||
|
|
||||||
if (split.Length != 2)
|
|
||||||
{
|
|
||||||
Log.Warn($"Manifest has an invalid repository name: {manifest.Repository}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var gitClient = new GitHubClient(new ProductHeaderValue("Torch"));
|
|
||||||
var releases = await gitClient.Repository.Release.GetAll(split[0], split[1]).ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (releases.Count == 0)
|
|
||||||
{
|
|
||||||
Log.Debug("No releases in repo");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Version currentVersion;
|
|
||||||
Version latestVersion;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
currentVersion = new Version(manifest.Version);
|
|
||||||
latestVersion = new Version(releases[0].TagName);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Log.Warn("Invalid version number on manifest or GitHub release");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (force || latestVersion > currentVersion)
|
|
||||||
{
|
|
||||||
var webClient = new WebClient();
|
|
||||||
var assets = await gitClient.Repository.Release.GetAllAssets(split[0], split[1], releases[0].Id).ConfigureAwait(false);
|
|
||||||
foreach (var asset in assets)
|
|
||||||
{
|
|
||||||
if (asset.Name.EndsWith(".zip"))
|
|
||||||
{
|
|
||||||
Log.Debug(asset.BrowserDownloadUrl);
|
|
||||||
var localPath = Path.Combine(Path.GetTempPath(), asset.Name);
|
|
||||||
await webClient.DownloadFileTaskAsync(new Uri(asset.BrowserDownloadUrl), localPath).ConfigureAwait(false);
|
|
||||||
UnzipPlugin(localPath);
|
|
||||||
Log.Info($"Downloaded update for {manifest.Repository}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.Info($"{manifest.Repository} is up to date.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnzipPlugin(string zipName)
|
|
||||||
{
|
|
||||||
if (!File.Exists(zipName))
|
|
||||||
return;
|
|
||||||
|
|
||||||
MyZipArchive.ExtractToDirectory(zipName, _pluginManager.PluginDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user