Skip to content

Commit 2723973

Browse files
committed
MAJOR CHANGE: Torch can install and update its own DS installation! Full changelog: https://pastebin.com/ybqDM4HP
1 parent 3760c4a commit 2723973

37 files changed

Lines changed: 915 additions & 314 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
:: This script creates a symlink to the game binaries to account for different installation directories on different systems.
2+
3+
@echo off
4+
set /p path="Please enter the folder location of your SpaceEngineersDedicated.exe: "
5+
cd %~dp0
6+
mklink /D GameBinaries %path%
7+
if errorlevel 1 goto Error
8+
echo Done! You can now open the Torch solution without issue.
9+
goto End
10+
:Error
11+
echo An error occured creating the symlink.
12+
:End
13+
pause

‎Torch.API/ITorchConfig.cs‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
{
33
public interface ITorchConfig
44
{
5-
//bool AutoRestart { get; set; }
6-
//int Autosave { get; set; }
75
string InstanceName { get; set; }
86
string InstancePath { get; set; }
9-
//bool LogChat { get; set; }
107
bool RedownloadPlugins { get; set; }
11-
bool EnableAutomaticUpdates { get; set; }
8+
bool AutomaticUpdates { get; set; }
9+
bool RestartOnCrash { get; set; }
1210

1311
bool Save(string path = null);
1412
}

‎Torch.API/ModAPI/TorchAPI.cs‎

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Torch.API.ModAPI
8+
{
9+
/* TODO: this without causing a circular dependency
10+
public static class TorchAPIGateway
11+
{
12+
public static Version Version => TorchBase.Instance.TorchVersion;
13+
14+
public static IMultiplayer Multiplayer => TorchBase.Instance.Multiplayer;
15+
16+
public static IPluginManager Plugins => TorchBase.Instance.Plugins;
17+
}*/
18+
}

‎Torch.API/Torch.API.csproj‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,6 @@
8383
<Reference Include="System.Data" />
8484
<Reference Include="System.Net.Http" />
8585
<Reference Include="System.Xml" />
86-
<Reference Include="Torch">
87-
<HintPath>..\Torch.Server\bin\x64\Release\Torch.dll</HintPath>
88-
</Reference>
8986
<Reference Include="VRage">
9087
<HintPath>..\GameBinaries\VRage.dll</HintPath>
9188
</Reference>
@@ -147,7 +144,7 @@
147144
<Compile Include="ITorchBase.cs" />
148145
<Compile Include="Plugins\IWpfPlugin.cs" />
149146
<Compile Include="ModAPI\Ingame\GridExtensions.cs" />
150-
<Compile Include="ModAPI\TorchAPI.cs" />
147+
<Compile Include="ModAPI\TorchAPIGateway.cs" />
151148
<Compile Include="Plugins\PluginAttribute.cs" />
152149
<Compile Include="Properties\AssemblyInfo.cs" />
153150
<Compile Include="ServerState.cs" />
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
using System.Reflection;
22

3-
[assembly: AssemblyVersion("1.0.153.575")]
4-
[assembly: AssemblyFileVersion("1.0.153.575")]
3+
[assembly: AssemblyVersion("1.0.167.670")]
4+
[assembly: AssemblyFileVersion("1.0.167.670")]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Sandbox.Engine.Utils;
8+
using Torch.Server.ViewModels;
9+
using VRage.Game;
10+
11+
namespace Torch.Server.Managers
12+
{
13+
public class DSConfigManager
14+
{
15+
public ConfigDedicatedViewModel Config { get; set; }
16+
private ConfigDedicatedViewModel _viewModel;
17+
18+
public DSConfigManager()
19+
{
20+
//Config.
21+
}
22+
23+
/// <summary>
24+
/// Creates a skeleton of a DS instance folder at the given directory.
25+
/// </summary>
26+
/// <param name="path"></param>
27+
public void CreateInstance(string path)
28+
{
29+
if (Directory.Exists(path))
30+
return;
31+
32+
Directory.CreateDirectory(path);
33+
var saves = Path.Combine(path, "Saves");
34+
Directory.CreateDirectory(saves);
35+
var mods = Path.Combine(path, "Mods");
36+
Directory.CreateDirectory(mods);
37+
}
38+
}
39+
}

‎Torch.Server/Program.cs‎

Lines changed: 170 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,35 @@
1919
using Sandbox.ModAPI;
2020
using Torch;
2121
using Torch.API;
22+
using Torch.Server.Views;
2223
using VRage.Game.ModAPI;
24+
using System.IO.Compression;
25+
using System.Net;
26+
using Torch.Server.Managers;
27+
using VRage.FileSystem;
2328

2429
namespace Torch.Server
2530
{
2631
public static class Program
2732
{
2833
private static ITorchServer _server;
2934
private static Logger _log = LogManager.GetLogger("Torch");
35+
private static bool _restartOnCrash;
36+
public static bool IsManualInstall;
37+
private static TorchCli _cli;
3038

39+
/// <summary>
40+
/// This method must *NOT* load any types/assemblies from the vanilla game, otherwise automatic updates will fail.
41+
/// </summary>
3142
[STAThread]
3243
public static void Main(string[] args)
3344
{
45+
IsManualInstall = Directory.GetCurrentDirectory().Contains("DedicatedServer64");
46+
if (!IsManualInstall)
47+
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
48+
49+
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
50+
3451
if (!Environment.UserInteractive)
3552
{
3653
using (var service = new TorchService())
@@ -40,7 +57,7 @@ public static void Main(string[] args)
4057
return;
4158
}
4259

43-
var configName = /*args.FirstOrDefault() ??*/ "TorchConfig.xml";
60+
var configName = "TorchConfig.xml";
4461
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
4562
TorchConfig options;
4663
if (File.Exists(configName))
@@ -52,22 +69,122 @@ public static void Main(string[] args)
5269
{
5370
_log.Info($"Generating default config at {configPath}");
5471
options = new TorchConfig();
72+
73+
if (!IsManualInstall)
74+
{
75+
new DSConfigManager().CreateInstance("Instance");
76+
options.InstancePath = Path.GetFullPath("Instance");
77+
78+
_log.Warn("Would you like to enable automatic updates? (Y/n):");
79+
80+
var input = Console.ReadLine() ?? "";
81+
var autoUpdate = !input.Equals("n", StringComparison.InvariantCultureIgnoreCase);
82+
options.AutomaticUpdates = autoUpdate;
83+
if (autoUpdate)
84+
_log.Info("Automatic updates enabled.");
85+
}
86+
87+
//var setupDialog = new FirstTimeSetup { DataContext = options };
88+
//setupDialog.ShowDialog();
5589
options.Save(configPath);
5690
}
5791

58-
bool gui = true;
59-
foreach (var arg in args)
92+
_cli = new TorchCli { Config = options };
93+
if (!_cli.Parse(args))
94+
return;
95+
96+
_log.Debug(_cli.ToString());
97+
98+
if (!string.IsNullOrEmpty(_cli.WaitForPID))
99+
{
100+
try
101+
{
102+
var pid = int.Parse(_cli.WaitForPID);
103+
var waitProc = Process.GetProcessById(pid);
104+
_log.Warn($"Waiting for process {pid} to exit.");
105+
waitProc.WaitForExit();
106+
}
107+
catch
108+
{
109+
// ignored
110+
}
111+
}
112+
113+
_restartOnCrash = _cli.RestartOnCrash;
114+
115+
if (options.AutomaticUpdates || _cli.Update)
60116
{
61-
switch (arg)
117+
if (IsManualInstall)
118+
_log.Warn("Detected manual install, won't attempt to update DS");
119+
else
62120
{
63-
case "-noupdate":
64-
options.EnableAutomaticUpdates = false;
65-
break;
66-
case "-nogui":
67-
gui = false;
68-
break;
121+
RunSteamCmd();
69122
}
70123
}
124+
RunServer(options, _cli);
125+
}
126+
127+
private const string STEAMCMD_DIR = "steamcmd";
128+
private const string STEAMCMD_ZIP = "temp.zip";
129+
private static readonly string STEAMCMD_PATH = $"{STEAMCMD_DIR}\\steamcmd.exe";
130+
private static readonly string RUNSCRIPT_PATH = $"{STEAMCMD_DIR}\\runscript.txt";
131+
private const string RUNSCRIPT = @"force_install_dir ../
132+
login anonymous
133+
app_update 298740
134+
quit";
135+
136+
public static void RunSteamCmd()
137+
{
138+
var log = LogManager.GetLogger("SteamCMD");
139+
140+
if (!Directory.Exists(STEAMCMD_DIR))
141+
{
142+
Directory.CreateDirectory(STEAMCMD_DIR);
143+
}
144+
145+
if (!File.Exists(RUNSCRIPT_PATH))
146+
File.WriteAllText(RUNSCRIPT_PATH, RUNSCRIPT);
147+
148+
if (!File.Exists(STEAMCMD_PATH))
149+
{
150+
try
151+
{
152+
log.Info("Downloading SteamCMD.");
153+
using (var client = new WebClient())
154+
client.DownloadFile("https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip", STEAMCMD_ZIP);
155+
156+
ZipFile.ExtractToDirectory(STEAMCMD_ZIP, STEAMCMD_DIR);
157+
File.Delete(STEAMCMD_ZIP);
158+
log.Info("SteamCMD downloaded successfully!");
159+
}
160+
catch
161+
{
162+
log.Error("Failed to download SteamCMD, unable to update the DS.");
163+
return;
164+
}
165+
}
166+
167+
log.Info("Checking for DS updates.");
168+
var steamCmdProc = new ProcessStartInfo(STEAMCMD_PATH, "+runscript runscript.txt")
169+
{
170+
WorkingDirectory = Path.Combine(Directory.GetCurrentDirectory(), STEAMCMD_DIR),
171+
UseShellExecute = false,
172+
RedirectStandardOutput = true,
173+
StandardOutputEncoding = Encoding.ASCII
174+
};
175+
var cmd = Process.Start(steamCmdProc);
176+
177+
// ReSharper disable once PossibleNullReferenceException
178+
while (!cmd.HasExited)
179+
{
180+
log.Info(cmd.StandardOutput.ReadLine());
181+
Thread.Sleep(100);
182+
}
183+
}
184+
185+
public static void RunServer(TorchConfig options, TorchCli cli)
186+
{
187+
71188

72189
/*
73190
if (!parser.ParseArguments(args, options))
@@ -132,16 +249,57 @@ public static void Main(string[] args)
132249

133250
_server = new TorchServer(options);
134251
_server.Init();
135-
if (gui)
252+
253+
if (!cli.NoGui)
136254
{
137255
var ui = new TorchUI((TorchServer)_server);
138256
ui.LoadConfig(options);
139257
ui.ShowDialog();
140258
}
141-
else
259+
260+
if (cli.NoGui || cli.Autostart)
142261
{
143262
_server.Start();
144263
}
145264
}
265+
266+
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
267+
{
268+
try
269+
{
270+
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location) ?? AppDomain.CurrentDomain.BaseDirectory;
271+
string asmPath = Path.Combine(basePath, "DedicatedServer64", new AssemblyName(args.Name).Name + ".dll");
272+
if (File.Exists(asmPath))
273+
return Assembly.LoadFrom(asmPath);
274+
275+
}
276+
catch
277+
{
278+
// ignored
279+
}
280+
281+
return null;
282+
}
283+
284+
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
285+
{
286+
var ex = (Exception)e.ExceptionObject;
287+
_log.Fatal(ex);
288+
if (_restartOnCrash)
289+
{
290+
/* Throws an exception somehow and I'm too lazy to debug it.
291+
try
292+
{
293+
if (MySession.Static != null && MySession.Static.AutoSaveInMinutes > 0)
294+
MySession.Static.Save();
295+
}
296+
catch { }*/
297+
298+
var exe = typeof(Program).Assembly.Location;
299+
_cli.WaitForPID = Process.GetCurrentProcess().Id.ToString();
300+
Process.Start(exe, _cli.ToString());
301+
}
302+
Environment.Exit(-1);
303+
}
146304
}
147305
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
using System.Reflection;
22

3-
[assembly: AssemblyVersion("1.0.153.575")]
4-
[assembly: AssemblyFileVersion("1.0.153.575")]
3+
[assembly: AssemblyVersion("1.0.167.670")]
4+
[assembly: AssemblyFileVersion("1.0.167.670")]

0 commit comments

Comments
 (0)