diff --git a/Torch.API/ITorchBase.cs b/Torch.API/ITorchBase.cs
index f9fb84e..23a6313 100644
--- a/Torch.API/ITorchBase.cs
+++ b/Torch.API/ITorchBase.cs
@@ -13,6 +13,7 @@ namespace Torch.API
event Action SessionLoaded;
event Action SessionUnloading;
event Action SessionUnloaded;
+ ITorchConfig Config { get; }
IMultiplayer Multiplayer { get; }
IPluginManager Plugins { get; }
Version TorchVersion { get; }
@@ -28,9 +29,7 @@ namespace Torch.API
public interface ITorchServer : ITorchBase
{
- bool IsRunning { get; }
string InstancePath { get; }
- void Start(IMyConfigDedicated config);
}
public interface ITorchClient : ITorchBase
diff --git a/Torch.API/ITorchConfig.cs b/Torch.API/ITorchConfig.cs
new file mode 100644
index 0000000..52f4db8
--- /dev/null
+++ b/Torch.API/ITorchConfig.cs
@@ -0,0 +1,15 @@
+namespace Torch
+{
+ public interface ITorchConfig
+ {
+ //bool AutoRestart { get; set; }
+ //int Autosave { get; set; }
+ string InstanceName { get; set; }
+ string InstancePath { get; set; }
+ //bool LogChat { get; set; }
+ bool RedownloadPlugins { get; set; }
+ bool EnableAutomaticUpdates { get; set; }
+
+ bool Save(string path = null);
+ }
+}
\ No newline at end of file
diff --git a/Torch.API/ServerState.cs b/Torch.API/ServerState.cs
new file mode 100644
index 0000000..b80e8e2
--- /dev/null
+++ b/Torch.API/ServerState.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Torch.API
+{
+ public enum ServerState
+ {
+ Stopped,
+ Starting,
+ Running,
+ Error
+ }
+}
diff --git a/Torch.API/Torch.API.csproj b/Torch.API/Torch.API.csproj
index d66de92..1438964 100644
--- a/Torch.API/Torch.API.csproj
+++ b/Torch.API/Torch.API.csproj
@@ -141,6 +141,7 @@
+
@@ -149,6 +150,7 @@
+
diff --git a/Torch.Client/Properties/AssemblyInfo.cs b/Torch.Client/Properties/AssemblyInfo.cs
index 7aa4672..490fc9c 100644
--- a/Torch.Client/Properties/AssemblyInfo.cs
+++ b/Torch.Client/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-[assembly: AssemblyVersion("1.0.105.498")]
-[assembly: AssemblyFileVersion("1.0.105.498")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.0.119.399")]
+[assembly: AssemblyFileVersion("1.0.119.399")]
\ No newline at end of file
diff --git a/Torch.Client/TorchClient.cs b/Torch.Client/TorchClient.cs
index d164f31..92b26b6 100644
--- a/Torch.Client/TorchClient.cs
+++ b/Torch.Client/TorchClient.cs
@@ -43,7 +43,7 @@ namespace Torch.Client
return;
var appDataPath = _startup.GetAppDataPath();
- MyInitializer.InvokeBeforeRun(APP_ID, MyPerGameSettings.BasicGameInfo.ApplicationName, appDataPath, false);
+ MyInitializer.InvokeBeforeRun(APP_ID, MyPerGameSettings.BasicGameInfo.ApplicationName, appDataPath);
MyInitializer.InitCheckSum();
if (!_startup.Check64Bit())
return;
diff --git a/Torch.Server/Program.cs b/Torch.Server/Program.cs
index f2e62e4..da85f5e 100644
--- a/Torch.Server/Program.cs
+++ b/Torch.Server/Program.cs
@@ -40,7 +40,7 @@ namespace Torch.Server
return;
}
- var configName = args.FirstOrDefault() ?? "TorchConfig.xml";
+ var configName = /*args.FirstOrDefault() ??*/ "TorchConfig.xml";
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
TorchConfig options;
if (File.Exists(configName))
@@ -55,6 +55,20 @@ namespace Torch.Server
options.Save(configPath);
}
+ bool gui = true;
+ foreach (var arg in args)
+ {
+ switch (arg)
+ {
+ case "-noupdate":
+ options.EnableAutomaticUpdates = false;
+ break;
+ case "-nogui":
+ gui = false;
+ break;
+ }
+ }
+
/*
if (!parser.ParseArguments(args, options))
{
@@ -118,9 +132,16 @@ namespace Torch.Server
_server = new TorchServer(options);
_server.Init();
- var ui = new TorchUI((TorchServer)_server);
- ui.LoadConfig(options);
- ui.ShowDialog();
+ if (gui)
+ {
+ var ui = new TorchUI((TorchServer)_server);
+ ui.LoadConfig(options);
+ ui.ShowDialog();
+ }
+ else
+ {
+ _server.Start();
+ }
}
}
}
diff --git a/Torch.Server/Properties/AssemblyInfo.cs b/Torch.Server/Properties/AssemblyInfo.cs
index 7aa4672..490fc9c 100644
--- a/Torch.Server/Properties/AssemblyInfo.cs
+++ b/Torch.Server/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@
using System.Reflection;
-[assembly: AssemblyVersion("1.0.105.498")]
-[assembly: AssemblyFileVersion("1.0.105.498")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.0.119.399")]
+[assembly: AssemblyFileVersion("1.0.119.399")]
\ No newline at end of file
diff --git a/Torch.Server/ServerStatistics.cs b/Torch.Server/ServerStatistics.cs
new file mode 100644
index 0000000..c3cd6a2
--- /dev/null
+++ b/Torch.Server/ServerStatistics.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Torch.Collections;
+
+namespace Torch.Server
+{
+ public class ServerStatistics
+ {
+ public RollingAverage SimSpeed { get; } = new RollingAverage(30);
+ }
+}
diff --git a/Torch.Server/Torch.Server.csproj b/Torch.Server/Torch.Server.csproj
index 571a865..3cceeb1 100644
--- a/Torch.Server/Torch.Server.csproj
+++ b/Torch.Server/Torch.Server.csproj
@@ -167,7 +167,7 @@
AssemblyInfo.tt
-
+
Component
diff --git a/Torch.Server/TorchServer.cs b/Torch.Server/TorchServer.cs
index 7df9b2d..03bef53 100644
--- a/Torch.Server/TorchServer.cs
+++ b/Torch.Server/TorchServer.cs
@@ -1,40 +1,27 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-using NLog;
-using Torch;
-using Sandbox;
-using Sandbox.Engine.Analytics;
-using Sandbox.Engine.Multiplayer;
+using Sandbox;
using Sandbox.Engine.Utils;
using Sandbox.Game;
-using Sandbox.Game.Gui;
using Sandbox.Game.World;
-using SpaceEngineers.Game;
+using System;
+using System.IO;
+using System.Reflection;
+using System.Threading;
+using System.Xml.Serialization;
using SteamSDK;
using Torch.API;
using VRage.Dedicated;
using VRage.FileSystem;
using VRage.Game;
-using VRage.Game.ModAPI;
using VRage.Game.ObjectBuilder;
using VRage.Game.SessionComponents;
-using VRage.Profiler;
+using VRage.Plugins;
namespace Torch.Server
{
public class TorchServer : TorchBase, ITorchServer
{
public Thread GameThread { get; private set; }
- public bool IsRunning { get; private set; }
- public TorchConfig Config { get; }
+ public ServerState State { get; private set; }
public string InstanceName => Config?.InstanceName;
public string InstancePath => Config?.InstancePath;
@@ -49,7 +36,7 @@ namespace Torch.Server
{
base.Init();
- Log.Info($"Init server instance '{Config.InstanceName}' at path '{Config.InstancePath}'");
+ Log.Info($"Init server '{Config.InstanceName}' at '{Config.InstancePath}'");
MyFakes.ENABLE_INFINARIO = false;
MyPerGameSettings.SendLogToKeen = false;
@@ -60,21 +47,19 @@ namespace Torch.Server
MySessionComponentExtDebug.ForceDisable = true;
MyPerServerSettings.AppId = 244850;
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion;
- //MyGlobalTypeMetadata.Static.Init();
- //TODO: Allows players to filter servers for Torch in the server browser. Need to init Steam before this
- //SteamServerAPI.Instance.GameServer.SetKeyValue("SM", "Torch");
- }
+ MyPlugins.RegisterGameAssemblyFile(MyPerGameSettings.GameModAssembly);
+ MyPlugins.RegisterGameObjectBuildersAssemblyFile(MyPerGameSettings.GameModObjBuildersAssembly);
+ MyPlugins.RegisterSandboxAssemblyFile(MyPerGameSettings.SandboxAssembly);
+ MyPlugins.RegisterSandboxGameAssemblyFile(MyPerGameSettings.SandboxGameAssembly);
+ MyPlugins.Load();
- public void SetConfig(IMyConfigDedicated config)
- {
- MySandboxGame.ConfigDedicated = config;
- }
+ MyGlobalTypeMetadata.Static.Init();
+ MyInitializer.InvokeBeforeRun(
+ MyPerServerSettings.AppId,
+ MyPerServerSettings.GameDSName,
+ InstancePath, DedicatedServer.AddDateToLog);
- public void Start(IMyConfigDedicated config)
- {
- SetConfig(config);
- Start();
}
///
@@ -82,26 +67,35 @@ namespace Torch.Server
///
public override void Start()
{
- if (IsRunning)
+ if (State > 0)
throw new InvalidOperationException("Server is already running.");
Config.Save();
- IsRunning = true;
+ State = ServerState.Starting;
Log.Info("Starting server.");
+ var runInternal = typeof(DedicatedServer).GetMethod("RunInternal", BindingFlags.Static | BindingFlags.NonPublic);
+
MySandboxGame.IsDedicated = true;
Environment.SetEnvironmentVariable("SteamAppId", MyPerServerSettings.AppId.ToString());
- Log.Trace("Invoking RunMain");
- try { Reflection.InvokeStaticMethod(typeof(DedicatedServer), "RunMain", Config.InstanceName, Config.InstancePath, false, true); }
- catch (Exception e)
+ VRage.Service.ExitListenerSTA.OnExit += delegate { MySandboxGame.Static?.Exit(); };
+
+ do
{
- Log.Error("Error running server.");
- Log.Error(e);
- throw;
- }
- Log.Trace("RunMain completed");
- IsRunning = false;
+ runInternal.Invoke(null, null);
+ } while (MySandboxGame.IsReloading);
+
+ MyInitializer.InvokeAfterRun();
+ State = ServerState.Stopped;
+ }
+
+ ///
+ public override void Init(object gameInstance)
+ {
+ base.Init(gameInstance);
+ State = ServerState.Running;
+ SteamServerAPI.Instance.GameServer.SetKeyValue("SM", "Torch");
}
///
@@ -109,7 +103,7 @@ namespace Torch.Server
///
public override void Stop()
{
- if (!IsRunning)
+ if (State == ServerState.Stopped)
Log.Error("Server is already stopped");
if (Thread.CurrentThread.ManagedThreadId != GameThread?.ManagedThreadId && MySandboxGame.Static.IsRunning)
@@ -125,31 +119,14 @@ namespace Torch.Server
//Unload all the static junk.
//TODO: Finish unloading all server data so it's in a completely clean state.
- VRage.FileSystem.MyFileSystem.Reset();
+ MyFileSystem.Reset();
VRage.Input.MyGuiGameControlsHelpers.Reset();
VRage.Input.MyInput.UnloadData();
//CleanupProfilers();
Log.Info("Server stopped.");
_stopHandle.Set();
- IsRunning = false;
+ State = ServerState.Stopped;
}
-
- /*
- private string GetInstancePath(bool isService = false, string instanceName = "Torch")
- {
- if (isService)
- return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), MyPerServerSettings.GameDSName, instanceName);
-
- return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), MyPerServerSettings.GameDSName);
- }*/
-
- /*
- private void CleanupProfilers()
- {
- typeof(MyRenderProfiler).GetField("m_threadProfiler", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, null);
- typeof(MyRenderProfiler).GetField("m_gpuProfiler", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, null);
- (typeof(MyRenderProfiler).GetField("m_threadProfilers", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as List).Clear();
- }*/
}
}
diff --git a/Torch.Server/ViewModels/SessionSettingsViewModel.cs b/Torch.Server/ViewModels/SessionSettingsViewModel.cs
index 60e2da4..a4ee779 100644
--- a/Torch.Server/ViewModels/SessionSettingsViewModel.cs
+++ b/Torch.Server/ViewModels/SessionSettingsViewModel.cs
@@ -331,5 +331,10 @@ namespace Torch.Server.ViewModels
get { return _settings.ViewDistance; }
set { _settings.WorldSizeKm = value; OnPropertyChanged(); }
}
+
+ public static implicit operator MyObjectBuilder_SessionSettings(SessionSettingsViewModel viewModel)
+ {
+ return viewModel._settings;
+ }
}
}
diff --git a/Torch.Server/Views/ConfigControl.xaml.cs b/Torch.Server/Views/ConfigControl.xaml.cs
index 482528d..56ee760 100644
--- a/Torch.Server/Views/ConfigControl.xaml.cs
+++ b/Torch.Server/Views/ConfigControl.xaml.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -14,8 +15,12 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
+using NLog;
+using Sandbox;
+using Sandbox.Engine.Networking;
using Sandbox.Engine.Utils;
using Torch.Server.ViewModels;
+using VRage.Dedicated;
using VRage.Game;
using Path = System.IO.Path;
@@ -38,10 +43,31 @@ namespace Torch.Server.Views
public void SaveConfig()
{
Config.Save(_configPath);
+ //TODO: make this work
+ try
+ {
+ var checkpoint = MyLocalCache.LoadCheckpoint(_viewModel.LoadWorld, out ulong size);
+ checkpoint.SessionName = _viewModel.WorldName;
+ checkpoint.Settings = _viewModel.SessionSettings;
+ checkpoint.Mods.Clear();
+ foreach (var modId in _viewModel.Mods)
+ checkpoint.Mods.Add(new MyObjectBuilder_Checkpoint.ModItem(modId));
+
+ Debug.Assert(checkpoint != null);
+ Debug.Assert(_viewModel.LoadWorld != null);
+ MyLocalCache.SaveCheckpoint(checkpoint, _viewModel.LoadWorld);
+ }
+ catch (Exception e)
+ {
+ var log = LogManager.GetLogger("Torch");
+ log.Error("Failed to overwrite sandbox config, changes will not appear on server");
+ log.Error(e);
+ }
}
public void LoadDedicatedConfig(TorchConfig torchConfig)
{
+ MySandboxGame.Config = new MyConfig(MyPerServerSettings.GameNameSafe + ".cfg");
var path = Path.Combine(torchConfig.InstancePath, "SpaceEngineers-Dedicated.cfg");
if (!File.Exists(path))
diff --git a/Torch.Server/Views/TorchUI.xaml b/Torch.Server/Views/TorchUI.xaml
index c8dd984..80a53fa 100644
--- a/Torch.Server/Views/TorchUI.xaml
+++ b/Torch.Server/Views/TorchUI.xaml
@@ -20,7 +20,7 @@
-
+
diff --git a/Torch.Server/Views/TorchUI.xaml.cs b/Torch.Server/Views/TorchUI.xaml.cs
index f21f6f5..548e02f 100644
--- a/Torch.Server/Views/TorchUI.xaml.cs
+++ b/Torch.Server/Views/TorchUI.xaml.cs
@@ -38,7 +38,7 @@ namespace Torch.Server
public TorchUI(TorchServer server)
{
- _config = server.Config;
+ _config = (TorchConfig)server.Config;
_server = server;
InitializeComponent();
_startTime = DateTime.Now;
@@ -84,7 +84,7 @@ namespace Torch.Server
BtnStop.IsEnabled = true;
_uiUpdate.Start();
ConfigControl.SaveConfig();
- new Thread(() => _server.Start(ConfigControl.Config)).Start();
+ new Thread(_server.Start).Start();
}
private void BtnStop_Click(object sender, RoutedEventArgs e)
@@ -100,7 +100,7 @@ namespace Torch.Server
protected override void OnClosing(CancelEventArgs e)
{
- if (_server?.IsRunning ?? false)
+ if (_server?.State == ServerState.Running)
_server.Stop();
}
diff --git a/Torch/Collections/RollingAverage.cs b/Torch/Collections/RollingAverage.cs
new file mode 100644
index 0000000..3254657
--- /dev/null
+++ b/Torch/Collections/RollingAverage.cs
@@ -0,0 +1,56 @@
+using System;
+using System.CodeDom;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Torch.Collections
+{
+ public class RollingAverage
+ {
+ private readonly double[] _array;
+ private int _idx;
+ private bool _full;
+
+ public RollingAverage(int size)
+ {
+ _array = new double[size];
+ }
+
+ ///
+ /// Adds a new value and removes the oldest if necessary.
+ ///
+ ///
+ public void Add(double value)
+ {
+ if (_idx >= _array.Length - 1)
+ {
+ _full = true;
+ _idx = 0;
+ }
+
+ _array[_idx] = value;
+ _idx++;
+ }
+
+ public double GetAverage()
+ {
+ return _array.Sum() / (_full ? _array.Length : (_idx + 1));
+ }
+
+ ///
+ /// Resets the rolling average.
+ ///
+ public void Clear()
+ {
+ _idx = 0;
+ _full = false;
+ }
+
+ public static implicit operator double(RollingAverage avg)
+ {
+ return avg.GetAverage();
+ }
+ }
+}
diff --git a/Torch/Managers/EntityManager.cs b/Torch/Managers/EntityManager.cs
index 672c503..05478ac 100644
--- a/Torch/Managers/EntityManager.cs
+++ b/Torch/Managers/EntityManager.cs
@@ -17,6 +17,7 @@ using Sandbox.ModAPI;
using SpaceEngineers.Game.Entities.Blocks;
using SpaceEngineers.Game.ModAPI;
using Torch.API;
+using Torch.API.Plugins;
using VRage;
using VRage.Collections;
using VRage.Game;
diff --git a/Torch/Managers/MultiplayerManager.cs b/Torch/Managers/MultiplayerManager.cs
index f7be1d2..4a50620 100644
--- a/Torch/Managers/MultiplayerManager.cs
+++ b/Torch/Managers/MultiplayerManager.cs
@@ -177,7 +177,7 @@ namespace Torch.Managers
{
_log.Info($"Game owner {ownerSteamID} is banned. Banning and rejecting client {steamID}...");
UserRejected(steamID, JoinResult.BannedByAdmins);
- BanPlayer(steamID, true);
+ BanPlayer(steamID);
}
}
diff --git a/Torch/Managers/NetworkManager/NetworkManager.cs b/Torch/Managers/NetworkManager/NetworkManager.cs
index ab81614..41b157d 100644
--- a/Torch/Managers/NetworkManager/NetworkManager.cs
+++ b/Torch/Managers/NetworkManager/NetworkManager.cs
@@ -120,17 +120,15 @@ namespace Torch.Managers
CallSite site;
- IMyNetObject sendAs;
object obj;
if (networkId.IsInvalid) // Static event
{
site = m_typeTable.StaticEventTable.Get(eventId);
- sendAs = null;
obj = null;
}
else // Instance event
{
- sendAs = ((MyReplicationLayer)MyMultiplayer.ReplicationLayer).GetObjectByNetworkId(networkId);
+ var sendAs = ((MyReplicationLayer)MyMultiplayer.ReplicationLayer).GetObjectByNetworkId(networkId);
if (sendAs == null)
{
return;
@@ -165,7 +163,7 @@ namespace Torch.Managers
//ApplicationLog.Error(ex.ToString());
_log.Error(ex);
}
- };
+ }
//one of the handlers wants us to discard this packet
if (discard)
@@ -278,7 +276,7 @@ namespace Torch.Managers
for (var j = args.Length + 4; j < 10; j++)
arguments[j] = e;
- arguments[10] = (IMyEventOwner)null;
+ arguments[10] = null;
//create an array of Types so we can create a generic method
var argTypes = new Type[8];
@@ -336,8 +334,7 @@ namespace Torch.Managers
private CallSite TryGetStaticCallSite(MethodInfo method)
{
var methodLookup = (Dictionary)typeof(MyEventTable).GetField("m_methodInfoLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(m_typeTable.StaticEventTable);
- CallSite result;
- if(!methodLookup.TryGetValue(method, out result))
+ if (!methodLookup.TryGetValue(method, out CallSite result))
throw new MissingMemberException("Provided event target not found!");
return result;
}
@@ -346,8 +343,7 @@ namespace Torch.Managers
{
var typeInfo = m_typeTable.Get(arg.GetType());
var methodLookup = (Dictionary)typeof(MyEventTable).GetField("m_methodInfoLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(typeInfo.EventTable);
- CallSite result;
- if (!methodLookup.TryGetValue(method, out result))
+ if (!methodLookup.TryGetValue(method, out CallSite result))
throw new MissingMemberException("Provided event target not found!");
return result;
}
diff --git a/Torch/Managers/PluginManager.cs b/Torch/Managers/PluginManager.cs
index c7b2ac6..995e15c 100644
--- a/Torch/Managers/PluginManager.cs
+++ b/Torch/Managers/PluginManager.cs
@@ -16,17 +16,18 @@ using Torch.API;
using Torch.API.Plugins;
using Torch.Commands;
using Torch.Managers;
+using Torch.Updater;
using VRage.Plugins;
using VRage.Collections;
using VRage.Library.Collections;
namespace Torch.Managers
{
- public class PluginManager : IPluginManager, IPlugin
+ public class PluginManager : IPluginManager
{
private readonly ITorchBase _torch;
private static Logger _log = LogManager.GetLogger(nameof(PluginManager));
- public const string PluginDir = "Plugins";
+ public readonly string PluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
public List Plugins { get; } = new List();
public CommandManager Commands { get; private set; }
@@ -42,21 +43,6 @@ namespace Torch.Managers
if (!Directory.Exists(PluginDir))
Directory.CreateDirectory(PluginDir);
-
- InitUpdater();
- }
-
- ///
- /// Adds the plugin manager "plugin" to VRage's plugin system.
- ///
- private void InitUpdater()
- {
- var fieldName = "m_plugins";
- var pluginList = typeof(MyPlugins).GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as List;
- if (pluginList == null)
- throw new TypeLoadException($"{fieldName} field not found in {nameof(MyPlugins)}");
-
- pluginList.Add(this);
}
///
@@ -81,18 +67,48 @@ namespace Torch.Managers
Plugins.Clear();
}
+ private void DownloadPlugins()
+ {
+ _log.Info("Downloading plugins");
+ var updater = new PluginUpdater(this);
+
+ var folders = Directory.GetDirectories(PluginDir);
+ var taskList = new List();
+ if (_torch.Config.RedownloadPlugins)
+ _log.Warn("Force downloading all plugins because the RedownloadPlugins flag is set in the config");
+
+ foreach (var folder in folders)
+ {
+ var manifestPath = Path.Combine(folder, "manifest.xml");
+ if (!File.Exists(manifestPath))
+ {
+ _log.Info($"No manifest in {folder}, skipping");
+ continue;
+ }
+
+ _log.Info($"Checking for updates for {folder}");
+ var manifest = PluginManifest.Load(manifestPath);
+ taskList.Add(updater.CheckAndUpdate(manifest, _torch.Config.RedownloadPlugins));
+ }
+
+ Task.WaitAll(taskList.ToArray());
+ _torch.Config.RedownloadPlugins = false;
+ }
+
///
/// Loads and creates instances of all plugins in the folder.
///
public void Init()
{
- ((TorchBase)_torch).Network.Init();
- ChatManager.Instance.Init();
Commands = new CommandManager(_torch);
+ if (_torch.Config.EnableAutomaticUpdates)
+ DownloadPlugins();
+ else
+ _log.Warn("Automatic plugin updates are disabled.");
+
_log.Info("Loading plugins");
- var pluginsPath = Path.Combine(Directory.GetCurrentDirectory(), PluginDir);
- var dlls = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories);
+ var dlls = Directory.GetFiles(PluginDir, "*.dll", SearchOption.AllDirectories);
foreach (var dllPath in dlls)
{
var asm = Assembly.UnsafeLoadFrom(dllPath);
@@ -135,20 +151,5 @@ namespace Torch.Managers
{
return GetEnumerator();
}
-
- void IPlugin.Init(object obj)
- {
- Init();
- }
-
- void IPlugin.Update()
- {
- UpdatePlugins();
- }
-
- public void Dispose()
- {
- DisposePlugins();
- }
}
}
diff --git a/Torch/PluginManifest.cs b/Torch/PluginManifest.cs
deleted file mode 100644
index ea739dc..0000000
--- a/Torch/PluginManifest.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Torch
-{
- public class PluginManifest
- {
- public string Repository { get; set; }
- public string Version { get; set; }
- }
-}
diff --git a/Torch/PluginOptions.cs b/Torch/PluginOptions.cs
deleted file mode 100644
index 16d9a44..0000000
--- a/Torch/PluginOptions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Torch
-{
- public class PluginOptions
- {
- public virtual string Save()
- {
- return null;
- }
-
- public virtual void Load(string data)
- {
-
- }
- }
-}
diff --git a/Torch/SteamService.cs b/Torch/SteamService.cs
index 63830d8..7dff154 100644
--- a/Torch/SteamService.cs
+++ b/Torch/SteamService.cs
@@ -16,24 +16,23 @@ namespace Torch
///
public class SteamService : MySteamService
{
- public SteamService(bool isDedicated, uint appId)
- : base(true, appId)
+ public SteamService(bool isDedicated, uint appId) : base(true, appId)
{
// TODO: Add protection for this mess... somewhere
- SteamSDK.SteamServerAPI.Instance.Dispose();
- var steam = typeof(Sandbox.MySteamService);
+ SteamServerAPI.Instance.Dispose();
+ var steam = typeof(MySteamService);
steam.GetField("SteamServerAPI").SetValue(this, null);
steam.GetProperty("AppId").GetSetMethod(true).Invoke(this, new object[] { appId });
if (isDedicated)
{
- steam.GetField("SteamServerAPI").SetValue(this, SteamSDK.SteamServerAPI.Instance);
+ steam.GetField("SteamServerAPI").SetValue(this, SteamServerAPI.Instance);
}
else
{
- var steamApi = SteamSDK.SteamAPI.Instance;
- steam.GetField("SteamAPI").SetValue(this, SteamSDK.SteamAPI.Instance);
- steam.GetProperty("IsActive").GetSetMethod(true).Invoke(this, new object[] { SteamSDK.SteamAPI.Instance != null });
+ var steamApi = SteamAPI.Instance;
+ steam.GetField("SteamAPI").SetValue(this, SteamAPI.Instance);
+ steam.GetProperty("IsActive").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.Instance != null });
if (steamApi != null)
{
diff --git a/Torch/Torch.csproj b/Torch/Torch.csproj
index de99fba..6feda09 100644
--- a/Torch/Torch.csproj
+++ b/Torch/Torch.csproj
@@ -116,6 +116,7 @@
+
@@ -131,8 +132,8 @@
-
-
+
+
diff --git a/Torch/TorchBase.cs b/Torch/TorchBase.cs
index dea5825..7897658 100644
--- a/Torch/TorchBase.cs
+++ b/Torch/TorchBase.cs
@@ -18,18 +18,20 @@ using SpaceEngineers.Game;
using Torch.API;
using Torch.Managers;
using VRage.FileSystem;
+using VRage.Plugins;
using VRage.Scripting;
using VRage.Utils;
namespace Torch
{
- public abstract class TorchBase : ITorchBase
+ public abstract class TorchBase : ViewModel, ITorchBase, IPlugin
{
///
/// Hack because *keen*.
/// Use only if necessary, prefer dependency injection.
///
public static ITorchBase Instance { get; private set; }
+ public ITorchConfig Config { get; protected set; }
protected static Logger Log { get; } = LogManager.GetLogger("Torch");
public Version TorchVersion { get; protected set; }
public Version GameVersion { get; private set; }
@@ -186,10 +188,25 @@ namespace Torch
MySession.AfterLoading += () => SessionLoaded?.Invoke();
MySession.OnUnloading += () => SessionUnloading?.Invoke();
MySession.OnUnloaded += () => SessionUnloaded?.Invoke();
+ InitUpdater();
_init = true;
}
+ ///
+ /// Hook into the VRage plugin system for updates.
+ ///
+ private void InitUpdater()
+ {
+ var fieldName = "m_plugins";
+ var pluginList = typeof(MyPlugins).GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as List;
+ if (pluginList == null)
+ throw new TypeLoadException($"{fieldName} field not found in {nameof(MyPlugins)}");
+
+ pluginList.Add(this);
+ }
+
+
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = (Exception)e.ExceptionObject;
@@ -205,5 +222,25 @@ namespace Torch
public abstract void Start();
public abstract void Stop();
+
+ ///
+ public virtual void Dispose()
+ {
+ Plugins.DisposePlugins();
+ }
+
+ ///
+ public virtual void Init(object gameInstance)
+ {
+ Network.Init();
+ ChatManager.Instance.Init();
+ Plugins.Init();
+ }
+
+ ///
+ public virtual void Update()
+ {
+ Plugins.UpdatePlugins();
+ }
}
}
diff --git a/Torch.Server/TorchConfig.cs b/Torch/TorchConfig.cs
similarity index 84%
rename from Torch.Server/TorchConfig.cs
rename to Torch/TorchConfig.cs
index 4a09a1d..4ca5fdf 100644
--- a/Torch.Server/TorchConfig.cs
+++ b/Torch/TorchConfig.cs
@@ -10,15 +10,17 @@ using Sandbox.ModAPI.Ingame;
namespace Torch
{
- public class TorchConfig
+ public class TorchConfig : ITorchConfig
{
private static Logger _log = LogManager.GetLogger("Config");
public string InstancePath { get; set; }
public string InstanceName { get; set; }
- public int Autosave { get; set; }
- public bool AutoRestart { get; set; }
- public bool LogChat { get; set; }
+ //public int Autosave { get; set; }
+ //public bool AutoRestart { get; set; }
+ //public bool LogChat { get; set; }
+ public bool EnableAutomaticUpdates { get; set; } = true;
+ public bool RedownloadPlugins { get; set; }
[NonSerialized]
private string _path;
@@ -28,8 +30,8 @@ namespace Torch
{
InstanceName = instanceName;
InstancePath = instancePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Torch", InstanceName);
- Autosave = autosaveInterval;
- AutoRestart = autoRestart;
+ //Autosave = autosaveInterval;
+ //AutoRestart = autoRestart;
}
public static TorchConfig LoadFrom(string path)
diff --git a/Torch/Updater/PluginManifest.cs b/Torch/Updater/PluginManifest.cs
new file mode 100644
index 0000000..6f13cb4
--- /dev/null
+++ b/Torch/Updater/PluginManifest.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Serialization;
+
+namespace Torch
+{
+ public class PluginManifest
+ {
+ public string Repository { get; set; } = "Jimmacle/notarealrepo";
+ public string Version { get; set; } = "1.0";
+
+ public void Save(string path)
+ {
+ using (var f = File.OpenWrite(path))
+ {
+ var ser = new XmlSerializer(typeof(PluginManifest));
+ ser.Serialize(f, this);
+ }
+ }
+
+ public static PluginManifest Load(string path)
+ {
+ using (var f = File.OpenRead(path))
+ {
+ var ser = new XmlSerializer(typeof(PluginManifest));
+ return (PluginManifest)ser.Deserialize(f);
+ }
+ }
+ }
+}
diff --git a/Torch/Updater/PluginUpdater.cs b/Torch/Updater/PluginUpdater.cs
index 5a86593..a5f4985 100644
--- a/Torch/Updater/PluginUpdater.cs
+++ b/Torch/Updater/PluginUpdater.cs
@@ -1,30 +1,93 @@
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
{
- public async Task CheckForUpdate(PluginManifest manifest)
+ 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]);
+
+ 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 (Exception e)
+ {
+ 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);
+ 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);
+ 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;
- var client = new GitHubClient(new ProductHeaderValue("Torch"));
- var releases = await client.Repository.Release.GetAll(split[0], split[1]);
- var currentVersion = new Version(manifest.Version);
- var latestVersion = new Version(releases[0].TagName);
-
- if (latestVersion > currentVersion)
- {
- //update
- }
+ MyZipArchive.ExtractToDirectory(zipName, _pluginManager.PluginDir);
}
}
}