1919using Sandbox . ModAPI ;
2020using Torch ;
2121using Torch . API ;
22+ using Torch . Server . Views ;
2223using VRage . Game . ModAPI ;
24+ using System . IO . Compression ;
25+ using System . Net ;
26+ using Torch . Server . Managers ;
27+ using VRage . FileSystem ;
2328
2429namespace 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}
0 commit comments