Add GitHub plugin updater, refactor game update hook to TorchBase instead of PluginManager, fix world config not applying
This commit is contained in:
@@ -13,6 +13,7 @@ namespace Torch.API
|
|||||||
event Action SessionLoaded;
|
event Action SessionLoaded;
|
||||||
event Action SessionUnloading;
|
event Action SessionUnloading;
|
||||||
event Action SessionUnloaded;
|
event Action SessionUnloaded;
|
||||||
|
ITorchConfig Config { get; }
|
||||||
IMultiplayer Multiplayer { get; }
|
IMultiplayer Multiplayer { get; }
|
||||||
IPluginManager Plugins { get; }
|
IPluginManager Plugins { get; }
|
||||||
Version TorchVersion { get; }
|
Version TorchVersion { get; }
|
||||||
@@ -28,9 +29,7 @@ namespace Torch.API
|
|||||||
|
|
||||||
public interface ITorchServer : ITorchBase
|
public interface ITorchServer : ITorchBase
|
||||||
{
|
{
|
||||||
bool IsRunning { get; }
|
|
||||||
string InstancePath { get; }
|
string InstancePath { get; }
|
||||||
void Start(IMyConfigDedicated config);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ITorchClient : ITorchBase
|
public interface ITorchClient : ITorchBase
|
||||||
|
15
Torch.API/ITorchConfig.cs
Normal file
15
Torch.API/ITorchConfig.cs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
16
Torch.API/ServerState.cs
Normal file
16
Torch.API/ServerState.cs
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
@@ -141,6 +141,7 @@
|
|||||||
<Compile Include="IChatMessage.cs" />
|
<Compile Include="IChatMessage.cs" />
|
||||||
<Compile Include="IMultiplayer.cs" />
|
<Compile Include="IMultiplayer.cs" />
|
||||||
<Compile Include="IPluginManager.cs" />
|
<Compile Include="IPluginManager.cs" />
|
||||||
|
<Compile Include="ITorchConfig.cs" />
|
||||||
<Compile Include="Plugins\ITorchPlugin.cs" />
|
<Compile Include="Plugins\ITorchPlugin.cs" />
|
||||||
<Compile Include="IServerControls.cs" />
|
<Compile Include="IServerControls.cs" />
|
||||||
<Compile Include="ITorchBase.cs" />
|
<Compile Include="ITorchBase.cs" />
|
||||||
@@ -149,6 +150,7 @@
|
|||||||
<Compile Include="ModAPI\TorchAPI.cs" />
|
<Compile Include="ModAPI\TorchAPI.cs" />
|
||||||
<Compile Include="Plugins\PluginAttribute.cs" />
|
<Compile Include="Plugins\PluginAttribute.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="ServerState.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.105.498")]
|
[assembly: AssemblyVersion("1.0.119.399")]
|
||||||
[assembly: AssemblyFileVersion("1.0.105.498")]
|
[assembly: AssemblyFileVersion("1.0.119.399")]
|
@@ -43,7 +43,7 @@ namespace Torch.Client
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var appDataPath = _startup.GetAppDataPath();
|
var appDataPath = _startup.GetAppDataPath();
|
||||||
MyInitializer.InvokeBeforeRun(APP_ID, MyPerGameSettings.BasicGameInfo.ApplicationName, appDataPath, false);
|
MyInitializer.InvokeBeforeRun(APP_ID, MyPerGameSettings.BasicGameInfo.ApplicationName, appDataPath);
|
||||||
MyInitializer.InitCheckSum();
|
MyInitializer.InitCheckSum();
|
||||||
if (!_startup.Check64Bit())
|
if (!_startup.Check64Bit())
|
||||||
return;
|
return;
|
||||||
|
@@ -40,7 +40,7 @@ namespace Torch.Server
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var configName = args.FirstOrDefault() ?? "TorchConfig.xml";
|
var configName = /*args.FirstOrDefault() ??*/ "TorchConfig.xml";
|
||||||
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
|
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
|
||||||
TorchConfig options;
|
TorchConfig options;
|
||||||
if (File.Exists(configName))
|
if (File.Exists(configName))
|
||||||
@@ -55,6 +55,20 @@ namespace Torch.Server
|
|||||||
options.Save(configPath);
|
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))
|
if (!parser.ParseArguments(args, options))
|
||||||
{
|
{
|
||||||
@@ -118,9 +132,16 @@ namespace Torch.Server
|
|||||||
|
|
||||||
_server = new TorchServer(options);
|
_server = new TorchServer(options);
|
||||||
_server.Init();
|
_server.Init();
|
||||||
var ui = new TorchUI((TorchServer)_server);
|
if (gui)
|
||||||
ui.LoadConfig(options);
|
{
|
||||||
ui.ShowDialog();
|
var ui = new TorchUI((TorchServer)_server);
|
||||||
|
ui.LoadConfig(options);
|
||||||
|
ui.ShowDialog();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_server.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.105.498")]
|
[assembly: AssemblyVersion("1.0.119.399")]
|
||||||
[assembly: AssemblyFileVersion("1.0.105.498")]
|
[assembly: AssemblyFileVersion("1.0.119.399")]
|
14
Torch.Server/ServerStatistics.cs
Normal file
14
Torch.Server/ServerStatistics.cs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
@@ -167,7 +167,7 @@
|
|||||||
<DependentUpon>AssemblyInfo.tt</DependentUpon>
|
<DependentUpon>AssemblyInfo.tt</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Properties\AssemblyInfo1.cs" />
|
<Compile Include="Properties\AssemblyInfo1.cs" />
|
||||||
<Compile Include="TorchConfig.cs" />
|
<Compile Include="ServerStatistics.cs" />
|
||||||
<Compile Include="TorchService.cs">
|
<Compile Include="TorchService.cs">
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@@ -1,40 +1,27 @@
|
|||||||
using System;
|
using Sandbox;
|
||||||
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.Engine.Utils;
|
using Sandbox.Engine.Utils;
|
||||||
using Sandbox.Game;
|
using Sandbox.Game;
|
||||||
using Sandbox.Game.Gui;
|
|
||||||
using Sandbox.Game.World;
|
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 SteamSDK;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using VRage.Dedicated;
|
using VRage.Dedicated;
|
||||||
using VRage.FileSystem;
|
using VRage.FileSystem;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
using VRage.Game.ModAPI;
|
|
||||||
using VRage.Game.ObjectBuilder;
|
using VRage.Game.ObjectBuilder;
|
||||||
using VRage.Game.SessionComponents;
|
using VRage.Game.SessionComponents;
|
||||||
using VRage.Profiler;
|
using VRage.Plugins;
|
||||||
|
|
||||||
namespace Torch.Server
|
namespace Torch.Server
|
||||||
{
|
{
|
||||||
public class TorchServer : TorchBase, ITorchServer
|
public class TorchServer : TorchBase, ITorchServer
|
||||||
{
|
{
|
||||||
public Thread GameThread { get; private set; }
|
public Thread GameThread { get; private set; }
|
||||||
public bool IsRunning { get; private set; }
|
public ServerState State { get; private set; }
|
||||||
public TorchConfig Config { get; }
|
|
||||||
public string InstanceName => Config?.InstanceName;
|
public string InstanceName => Config?.InstanceName;
|
||||||
public string InstancePath => Config?.InstancePath;
|
public string InstancePath => Config?.InstancePath;
|
||||||
|
|
||||||
@@ -49,7 +36,7 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
base.Init();
|
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;
|
MyFakes.ENABLE_INFINARIO = false;
|
||||||
MyPerGameSettings.SendLogToKeen = false;
|
MyPerGameSettings.SendLogToKeen = false;
|
||||||
@@ -60,21 +47,19 @@ namespace Torch.Server
|
|||||||
MySessionComponentExtDebug.ForceDisable = true;
|
MySessionComponentExtDebug.ForceDisable = true;
|
||||||
MyPerServerSettings.AppId = 244850;
|
MyPerServerSettings.AppId = 244850;
|
||||||
MyFinalBuildConstants.APP_VERSION = MyPerGameSettings.BasicGameInfo.GameVersion;
|
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
|
MyPlugins.RegisterGameAssemblyFile(MyPerGameSettings.GameModAssembly);
|
||||||
//SteamServerAPI.Instance.GameServer.SetKeyValue("SM", "Torch");
|
MyPlugins.RegisterGameObjectBuildersAssemblyFile(MyPerGameSettings.GameModObjBuildersAssembly);
|
||||||
}
|
MyPlugins.RegisterSandboxAssemblyFile(MyPerGameSettings.SandboxAssembly);
|
||||||
|
MyPlugins.RegisterSandboxGameAssemblyFile(MyPerGameSettings.SandboxGameAssembly);
|
||||||
|
MyPlugins.Load();
|
||||||
|
|
||||||
public void SetConfig(IMyConfigDedicated config)
|
MyGlobalTypeMetadata.Static.Init();
|
||||||
{
|
MyInitializer.InvokeBeforeRun(
|
||||||
MySandboxGame.ConfigDedicated = config;
|
MyPerServerSettings.AppId,
|
||||||
}
|
MyPerServerSettings.GameDSName,
|
||||||
|
InstancePath, DedicatedServer.AddDateToLog);
|
||||||
|
|
||||||
public void Start(IMyConfigDedicated config)
|
|
||||||
{
|
|
||||||
SetConfig(config);
|
|
||||||
Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -82,26 +67,35 @@ namespace Torch.Server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Start()
|
public override void Start()
|
||||||
{
|
{
|
||||||
if (IsRunning)
|
if (State > 0)
|
||||||
throw new InvalidOperationException("Server is already running.");
|
throw new InvalidOperationException("Server is already running.");
|
||||||
|
|
||||||
Config.Save();
|
Config.Save();
|
||||||
IsRunning = true;
|
State = ServerState.Starting;
|
||||||
Log.Info("Starting server.");
|
Log.Info("Starting server.");
|
||||||
|
|
||||||
|
var runInternal = typeof(DedicatedServer).GetMethod("RunInternal", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
MySandboxGame.IsDedicated = true;
|
MySandboxGame.IsDedicated = true;
|
||||||
Environment.SetEnvironmentVariable("SteamAppId", MyPerServerSettings.AppId.ToString());
|
Environment.SetEnvironmentVariable("SteamAppId", MyPerServerSettings.AppId.ToString());
|
||||||
|
|
||||||
Log.Trace("Invoking RunMain");
|
VRage.Service.ExitListenerSTA.OnExit += delegate { MySandboxGame.Static?.Exit(); };
|
||||||
try { Reflection.InvokeStaticMethod(typeof(DedicatedServer), "RunMain", Config.InstanceName, Config.InstancePath, false, true); }
|
|
||||||
catch (Exception e)
|
do
|
||||||
{
|
{
|
||||||
Log.Error("Error running server.");
|
runInternal.Invoke(null, null);
|
||||||
Log.Error(e);
|
} while (MySandboxGame.IsReloading);
|
||||||
throw;
|
|
||||||
}
|
MyInitializer.InvokeAfterRun();
|
||||||
Log.Trace("RunMain completed");
|
State = ServerState.Stopped;
|
||||||
IsRunning = false;
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void Init(object gameInstance)
|
||||||
|
{
|
||||||
|
base.Init(gameInstance);
|
||||||
|
State = ServerState.Running;
|
||||||
|
SteamServerAPI.Instance.GameServer.SetKeyValue("SM", "Torch");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -109,7 +103,7 @@ namespace Torch.Server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Stop()
|
public override void Stop()
|
||||||
{
|
{
|
||||||
if (!IsRunning)
|
if (State == ServerState.Stopped)
|
||||||
Log.Error("Server is already stopped");
|
Log.Error("Server is already stopped");
|
||||||
|
|
||||||
if (Thread.CurrentThread.ManagedThreadId != GameThread?.ManagedThreadId && MySandboxGame.Static.IsRunning)
|
if (Thread.CurrentThread.ManagedThreadId != GameThread?.ManagedThreadId && MySandboxGame.Static.IsRunning)
|
||||||
@@ -125,31 +119,14 @@ namespace Torch.Server
|
|||||||
|
|
||||||
//Unload all the static junk.
|
//Unload all the static junk.
|
||||||
//TODO: Finish unloading all server data so it's in a completely clean state.
|
//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.MyGuiGameControlsHelpers.Reset();
|
||||||
VRage.Input.MyInput.UnloadData();
|
VRage.Input.MyInput.UnloadData();
|
||||||
//CleanupProfilers();
|
//CleanupProfilers();
|
||||||
|
|
||||||
Log.Info("Server stopped.");
|
Log.Info("Server stopped.");
|
||||||
_stopHandle.Set();
|
_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<MyProfiler>).Clear();
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -331,5 +331,10 @@ namespace Torch.Server.ViewModels
|
|||||||
get { return _settings.ViewDistance; }
|
get { return _settings.ViewDistance; }
|
||||||
set { _settings.WorldSizeKm = value; OnPropertyChanged(); }
|
set { _settings.WorldSizeKm = value; OnPropertyChanged(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static implicit operator MyObjectBuilder_SessionSettings(SessionSettingsViewModel viewModel)
|
||||||
|
{
|
||||||
|
return viewModel._settings;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -14,8 +15,12 @@ using System.Windows.Media;
|
|||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
using NLog;
|
||||||
|
using Sandbox;
|
||||||
|
using Sandbox.Engine.Networking;
|
||||||
using Sandbox.Engine.Utils;
|
using Sandbox.Engine.Utils;
|
||||||
using Torch.Server.ViewModels;
|
using Torch.Server.ViewModels;
|
||||||
|
using VRage.Dedicated;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
@@ -38,10 +43,31 @@ namespace Torch.Server.Views
|
|||||||
public void SaveConfig()
|
public void SaveConfig()
|
||||||
{
|
{
|
||||||
Config.Save(_configPath);
|
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)
|
public void LoadDedicatedConfig(TorchConfig torchConfig)
|
||||||
{
|
{
|
||||||
|
MySandboxGame.Config = new MyConfig(MyPerServerSettings.GameNameSafe + ".cfg");
|
||||||
var path = Path.Combine(torchConfig.InstancePath, "SpaceEngineers-Dedicated.cfg");
|
var path = Path.Combine(torchConfig.InstancePath, "SpaceEngineers-Dedicated.cfg");
|
||||||
|
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
<DockPanel>
|
<DockPanel>
|
||||||
<DockPanel DockPanel.Dock="Top">
|
<DockPanel DockPanel.Dock="Top">
|
||||||
<Label Content="Instance Path: " Margin="3"/>
|
<Label Content="Instance Path: " Margin="3"/>
|
||||||
<TextBox x:Name="InstancePathBox" Margin="3" Height="20" TextChanged="InstancePathBox_OnTextChanged"/>
|
<TextBox x:Name="InstancePathBox" Margin="3" Height="20" 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"/>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
@@ -38,7 +38,7 @@ namespace Torch.Server
|
|||||||
|
|
||||||
public TorchUI(TorchServer server)
|
public TorchUI(TorchServer server)
|
||||||
{
|
{
|
||||||
_config = server.Config;
|
_config = (TorchConfig)server.Config;
|
||||||
_server = server;
|
_server = server;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_startTime = DateTime.Now;
|
_startTime = DateTime.Now;
|
||||||
@@ -84,7 +84,7 @@ namespace Torch.Server
|
|||||||
BtnStop.IsEnabled = true;
|
BtnStop.IsEnabled = true;
|
||||||
_uiUpdate.Start();
|
_uiUpdate.Start();
|
||||||
ConfigControl.SaveConfig();
|
ConfigControl.SaveConfig();
|
||||||
new Thread(() => _server.Start(ConfigControl.Config)).Start();
|
new Thread(_server.Start).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -100,7 +100,7 @@ namespace Torch.Server
|
|||||||
|
|
||||||
protected override void OnClosing(CancelEventArgs e)
|
protected override void OnClosing(CancelEventArgs e)
|
||||||
{
|
{
|
||||||
if (_server?.IsRunning ?? false)
|
if (_server?.State == ServerState.Running)
|
||||||
_server.Stop();
|
_server.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
56
Torch/Collections/RollingAverage.cs
Normal file
56
Torch/Collections/RollingAverage.cs
Normal file
@@ -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];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new value and removes the oldest if necessary.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the rolling average.
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
_idx = 0;
|
||||||
|
_full = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator double(RollingAverage avg)
|
||||||
|
{
|
||||||
|
return avg.GetAverage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,6 +17,7 @@ using Sandbox.ModAPI;
|
|||||||
using SpaceEngineers.Game.Entities.Blocks;
|
using SpaceEngineers.Game.Entities.Blocks;
|
||||||
using SpaceEngineers.Game.ModAPI;
|
using SpaceEngineers.Game.ModAPI;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
|
using Torch.API.Plugins;
|
||||||
using VRage;
|
using VRage;
|
||||||
using VRage.Collections;
|
using VRage.Collections;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
|
@@ -177,7 +177,7 @@ namespace Torch.Managers
|
|||||||
{
|
{
|
||||||
_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, true);
|
BanPlayer(steamID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -120,17 +120,15 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
|
|
||||||
CallSite site;
|
CallSite site;
|
||||||
IMyNetObject sendAs;
|
|
||||||
object obj;
|
object obj;
|
||||||
if (networkId.IsInvalid) // Static event
|
if (networkId.IsInvalid) // Static event
|
||||||
{
|
{
|
||||||
site = m_typeTable.StaticEventTable.Get(eventId);
|
site = m_typeTable.StaticEventTable.Get(eventId);
|
||||||
sendAs = null;
|
|
||||||
obj = null;
|
obj = null;
|
||||||
}
|
}
|
||||||
else // Instance event
|
else // Instance event
|
||||||
{
|
{
|
||||||
sendAs = ((MyReplicationLayer)MyMultiplayer.ReplicationLayer).GetObjectByNetworkId(networkId);
|
var sendAs = ((MyReplicationLayer)MyMultiplayer.ReplicationLayer).GetObjectByNetworkId(networkId);
|
||||||
if (sendAs == null)
|
if (sendAs == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -165,7 +163,7 @@ namespace Torch.Managers
|
|||||||
//ApplicationLog.Error(ex.ToString());
|
//ApplicationLog.Error(ex.ToString());
|
||||||
_log.Error(ex);
|
_log.Error(ex);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
//one of the handlers wants us to discard this packet
|
//one of the handlers wants us to discard this packet
|
||||||
if (discard)
|
if (discard)
|
||||||
@@ -278,7 +276,7 @@ namespace Torch.Managers
|
|||||||
for (var j = args.Length + 4; j < 10; j++)
|
for (var j = args.Length + 4; j < 10; j++)
|
||||||
arguments[j] = e;
|
arguments[j] = e;
|
||||||
|
|
||||||
arguments[10] = (IMyEventOwner)null;
|
arguments[10] = null;
|
||||||
|
|
||||||
//create an array of Types so we can create a generic method
|
//create an array of Types so we can create a generic method
|
||||||
var argTypes = new Type[8];
|
var argTypes = new Type[8];
|
||||||
@@ -336,8 +334,7 @@ namespace Torch.Managers
|
|||||||
private CallSite TryGetStaticCallSite(MethodInfo method)
|
private CallSite TryGetStaticCallSite(MethodInfo method)
|
||||||
{
|
{
|
||||||
var methodLookup = (Dictionary<MethodInfo, CallSite>)typeof(MyEventTable).GetField("m_methodInfoLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(m_typeTable.StaticEventTable);
|
var methodLookup = (Dictionary<MethodInfo, CallSite>)typeof(MyEventTable).GetField("m_methodInfoLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(m_typeTable.StaticEventTable);
|
||||||
CallSite result;
|
if (!methodLookup.TryGetValue(method, out CallSite result))
|
||||||
if(!methodLookup.TryGetValue(method, out result))
|
|
||||||
throw new MissingMemberException("Provided event target not found!");
|
throw new MissingMemberException("Provided event target not found!");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -346,8 +343,7 @@ namespace Torch.Managers
|
|||||||
{
|
{
|
||||||
var typeInfo = m_typeTable.Get(arg.GetType());
|
var typeInfo = m_typeTable.Get(arg.GetType());
|
||||||
var methodLookup = (Dictionary<MethodInfo, CallSite>)typeof(MyEventTable).GetField("m_methodInfoLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(typeInfo.EventTable);
|
var methodLookup = (Dictionary<MethodInfo, CallSite>)typeof(MyEventTable).GetField("m_methodInfoLookup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(typeInfo.EventTable);
|
||||||
CallSite result;
|
if (!methodLookup.TryGetValue(method, out CallSite result))
|
||||||
if (!methodLookup.TryGetValue(method, out result))
|
|
||||||
throw new MissingMemberException("Provided event target not found!");
|
throw new MissingMemberException("Provided event target not found!");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -16,17 +16,18 @@ using Torch.API;
|
|||||||
using Torch.API.Plugins;
|
using Torch.API.Plugins;
|
||||||
using Torch.Commands;
|
using Torch.Commands;
|
||||||
using Torch.Managers;
|
using Torch.Managers;
|
||||||
|
using Torch.Updater;
|
||||||
using VRage.Plugins;
|
using VRage.Plugins;
|
||||||
using VRage.Collections;
|
using VRage.Collections;
|
||||||
using VRage.Library.Collections;
|
using VRage.Library.Collections;
|
||||||
|
|
||||||
namespace Torch.Managers
|
namespace Torch.Managers
|
||||||
{
|
{
|
||||||
public class PluginManager : IPluginManager, IPlugin
|
public class PluginManager : IPluginManager
|
||||||
{
|
{
|
||||||
private readonly ITorchBase _torch;
|
private readonly ITorchBase _torch;
|
||||||
private static Logger _log = LogManager.GetLogger(nameof(PluginManager));
|
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<ITorchPlugin> Plugins { get; } = new List<ITorchPlugin>();
|
public List<ITorchPlugin> Plugins { get; } = new List<ITorchPlugin>();
|
||||||
public CommandManager Commands { get; private set; }
|
public CommandManager Commands { get; private set; }
|
||||||
@@ -42,21 +43,6 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
if (!Directory.Exists(PluginDir))
|
if (!Directory.Exists(PluginDir))
|
||||||
Directory.CreateDirectory(PluginDir);
|
Directory.CreateDirectory(PluginDir);
|
||||||
|
|
||||||
InitUpdater();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the plugin manager "plugin" to VRage's plugin system.
|
|
||||||
/// </summary>
|
|
||||||
private void InitUpdater()
|
|
||||||
{
|
|
||||||
var fieldName = "m_plugins";
|
|
||||||
var pluginList = typeof(MyPlugins).GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as List<IPlugin>;
|
|
||||||
if (pluginList == null)
|
|
||||||
throw new TypeLoadException($"{fieldName} field not found in {nameof(MyPlugins)}");
|
|
||||||
|
|
||||||
pluginList.Add(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -81,18 +67,48 @@ namespace Torch.Managers
|
|||||||
Plugins.Clear();
|
Plugins.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DownloadPlugins()
|
||||||
|
{
|
||||||
|
_log.Info("Downloading plugins");
|
||||||
|
var updater = new PluginUpdater(this);
|
||||||
|
|
||||||
|
var folders = Directory.GetDirectories(PluginDir);
|
||||||
|
var taskList = new List<Task>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads and creates instances of all plugins in the <see cref="PluginDir"/> folder.
|
/// Loads and creates instances of all plugins in the <see cref="PluginDir"/> folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
((TorchBase)_torch).Network.Init();
|
|
||||||
ChatManager.Instance.Init();
|
|
||||||
Commands = new CommandManager(_torch);
|
Commands = new CommandManager(_torch);
|
||||||
|
|
||||||
|
if (_torch.Config.EnableAutomaticUpdates)
|
||||||
|
DownloadPlugins();
|
||||||
|
else
|
||||||
|
_log.Warn("Automatic plugin updates are disabled.");
|
||||||
|
|
||||||
_log.Info("Loading plugins");
|
_log.Info("Loading plugins");
|
||||||
var pluginsPath = Path.Combine(Directory.GetCurrentDirectory(), PluginDir);
|
var dlls = Directory.GetFiles(PluginDir, "*.dll", SearchOption.AllDirectories);
|
||||||
var dlls = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories);
|
|
||||||
foreach (var dllPath in dlls)
|
foreach (var dllPath in dlls)
|
||||||
{
|
{
|
||||||
var asm = Assembly.UnsafeLoadFrom(dllPath);
|
var asm = Assembly.UnsafeLoadFrom(dllPath);
|
||||||
@@ -135,20 +151,5 @@ namespace Torch.Managers
|
|||||||
{
|
{
|
||||||
return GetEnumerator();
|
return GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IPlugin.Init(object obj)
|
|
||||||
{
|
|
||||||
Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void IPlugin.Update()
|
|
||||||
{
|
|
||||||
UpdatePlugins();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
DisposePlugins();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
@@ -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)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -16,24 +16,23 @@ namespace Torch
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SteamService : MySteamService
|
public class SteamService : MySteamService
|
||||||
{
|
{
|
||||||
public SteamService(bool isDedicated, uint appId)
|
public SteamService(bool isDedicated, uint appId) : base(true, appId)
|
||||||
: base(true, appId)
|
|
||||||
{
|
{
|
||||||
// TODO: Add protection for this mess... somewhere
|
// TODO: Add protection for this mess... somewhere
|
||||||
SteamSDK.SteamServerAPI.Instance.Dispose();
|
SteamServerAPI.Instance.Dispose();
|
||||||
var steam = typeof(Sandbox.MySteamService);
|
var steam = typeof(MySteamService);
|
||||||
steam.GetField("SteamServerAPI").SetValue(this, null);
|
steam.GetField("SteamServerAPI").SetValue(this, null);
|
||||||
|
|
||||||
steam.GetProperty("AppId").GetSetMethod(true).Invoke(this, new object[] { appId });
|
steam.GetProperty("AppId").GetSetMethod(true).Invoke(this, new object[] { appId });
|
||||||
if (isDedicated)
|
if (isDedicated)
|
||||||
{
|
{
|
||||||
steam.GetField("SteamServerAPI").SetValue(this, SteamSDK.SteamServerAPI.Instance);
|
steam.GetField("SteamServerAPI").SetValue(this, SteamServerAPI.Instance);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var steamApi = SteamSDK.SteamAPI.Instance;
|
var steamApi = SteamAPI.Instance;
|
||||||
steam.GetField("SteamAPI").SetValue(this, SteamSDK.SteamAPI.Instance);
|
steam.GetField("SteamAPI").SetValue(this, SteamAPI.Instance);
|
||||||
steam.GetProperty("IsActive").GetSetMethod(true).Invoke(this, new object[] { SteamSDK.SteamAPI.Instance != null });
|
steam.GetProperty("IsActive").GetSetMethod(true).Invoke(this, new object[] { SteamAPI.Instance != null });
|
||||||
|
|
||||||
if (steamApi != null)
|
if (steamApi != null)
|
||||||
{
|
{
|
||||||
|
@@ -116,6 +116,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ChatMessage.cs" />
|
<Compile Include="ChatMessage.cs" />
|
||||||
<Compile Include="Collections\KeyTree.cs" />
|
<Compile Include="Collections\KeyTree.cs" />
|
||||||
|
<Compile Include="Collections\RollingAverage.cs" />
|
||||||
<Compile Include="Commands\CategoryAttribute.cs" />
|
<Compile Include="Commands\CategoryAttribute.cs" />
|
||||||
<Compile Include="Commands\Command.cs" />
|
<Compile Include="Commands\Command.cs" />
|
||||||
<Compile Include="Commands\CommandAttribute.cs" />
|
<Compile Include="Commands\CommandAttribute.cs" />
|
||||||
@@ -131,8 +132,8 @@
|
|||||||
<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="PluginManifest.cs" />
|
<Compile Include="TorchConfig.cs" />
|
||||||
<Compile Include="PluginOptions.cs" />
|
<Compile Include="Updater\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" />
|
||||||
|
@@ -18,18 +18,20 @@ using SpaceEngineers.Game;
|
|||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.Managers;
|
using Torch.Managers;
|
||||||
using VRage.FileSystem;
|
using VRage.FileSystem;
|
||||||
|
using VRage.Plugins;
|
||||||
using VRage.Scripting;
|
using VRage.Scripting;
|
||||||
using VRage.Utils;
|
using VRage.Utils;
|
||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
public abstract class TorchBase : ITorchBase
|
public abstract class TorchBase : ViewModel, ITorchBase, IPlugin
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hack because *keen*.
|
/// Hack because *keen*.
|
||||||
/// 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; }
|
||||||
|
public ITorchConfig Config { get; protected set; }
|
||||||
protected static Logger Log { get; } = LogManager.GetLogger("Torch");
|
protected static Logger Log { get; } = LogManager.GetLogger("Torch");
|
||||||
public Version TorchVersion { get; protected set; }
|
public Version TorchVersion { get; protected set; }
|
||||||
public Version GameVersion { get; private set; }
|
public Version GameVersion { get; private set; }
|
||||||
@@ -186,10 +188,25 @@ namespace Torch
|
|||||||
MySession.AfterLoading += () => SessionLoaded?.Invoke();
|
MySession.AfterLoading += () => SessionLoaded?.Invoke();
|
||||||
MySession.OnUnloading += () => SessionUnloading?.Invoke();
|
MySession.OnUnloading += () => SessionUnloading?.Invoke();
|
||||||
MySession.OnUnloaded += () => SessionUnloaded?.Invoke();
|
MySession.OnUnloaded += () => SessionUnloaded?.Invoke();
|
||||||
|
InitUpdater();
|
||||||
|
|
||||||
_init = true;
|
_init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hook into the VRage plugin system for updates.
|
||||||
|
/// </summary>
|
||||||
|
private void InitUpdater()
|
||||||
|
{
|
||||||
|
var fieldName = "m_plugins";
|
||||||
|
var pluginList = typeof(MyPlugins).GetField(fieldName, BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null) as List<IPlugin>;
|
||||||
|
if (pluginList == null)
|
||||||
|
throw new TypeLoadException($"{fieldName} field not found in {nameof(MyPlugins)}");
|
||||||
|
|
||||||
|
pluginList.Add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
var ex = (Exception)e.ExceptionObject;
|
var ex = (Exception)e.ExceptionObject;
|
||||||
@@ -205,5 +222,25 @@ namespace Torch
|
|||||||
|
|
||||||
public abstract void Start();
|
public abstract void Start();
|
||||||
public abstract void Stop();
|
public abstract void Stop();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
Plugins.DisposePlugins();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void Init(object gameInstance)
|
||||||
|
{
|
||||||
|
Network.Init();
|
||||||
|
ChatManager.Instance.Init();
|
||||||
|
Plugins.Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public virtual void Update()
|
||||||
|
{
|
||||||
|
Plugins.UpdatePlugins();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,15 +10,17 @@ using Sandbox.ModAPI.Ingame;
|
|||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
public class TorchConfig
|
public class TorchConfig : ITorchConfig
|
||||||
{
|
{
|
||||||
private static Logger _log = LogManager.GetLogger("Config");
|
private static Logger _log = LogManager.GetLogger("Config");
|
||||||
|
|
||||||
public string InstancePath { get; set; }
|
public string InstancePath { get; set; }
|
||||||
public string InstanceName { get; set; }
|
public string InstanceName { get; set; }
|
||||||
public int Autosave { get; set; }
|
//public int Autosave { get; set; }
|
||||||
public bool AutoRestart { get; set; }
|
//public bool AutoRestart { get; set; }
|
||||||
public bool LogChat { get; set; }
|
//public bool LogChat { get; set; }
|
||||||
|
public bool EnableAutomaticUpdates { get; set; } = true;
|
||||||
|
public bool RedownloadPlugins { get; set; }
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
private string _path;
|
private string _path;
|
||||||
|
|
||||||
@@ -28,8 +30,8 @@ namespace Torch
|
|||||||
{
|
{
|
||||||
InstanceName = instanceName;
|
InstanceName = instanceName;
|
||||||
InstancePath = instancePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Torch", InstanceName);
|
InstancePath = instancePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Torch", InstanceName);
|
||||||
Autosave = autosaveInterval;
|
//Autosave = autosaveInterval;
|
||||||
AutoRestart = autoRestart;
|
//AutoRestart = autoRestart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TorchConfig LoadFrom(string path)
|
public static TorchConfig LoadFrom(string path)
|
34
Torch/Updater/PluginManifest.cs
Normal file
34
Torch/Updater/PluginManifest.cs
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,30 +1,93 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NLog;
|
||||||
using Octokit;
|
using Octokit;
|
||||||
|
using Torch.API;
|
||||||
|
using Torch.Managers;
|
||||||
|
using VRage.Compression;
|
||||||
|
|
||||||
namespace Torch.Updater
|
namespace Torch.Updater
|
||||||
{
|
{
|
||||||
public class PluginUpdater
|
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('/');
|
var split = manifest.Repository.Split('/');
|
||||||
|
|
||||||
if (split.Length != 2)
|
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;
|
return;
|
||||||
|
|
||||||
var client = new GitHubClient(new ProductHeaderValue("Torch"));
|
MyZipArchive.ExtractToDirectory(zipName, _pluginManager.PluginDir);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user