Server LuaCsForBarotrauma
Program.cs
1 #region Using Statements
2 
3 using Barotrauma.Steam;
4 using System;
5 using System.Diagnostics;
6 using Barotrauma.IO;
7 using System.Linq;
8 using System.Text;
9 using System.Threading;
10 using Barotrauma.Debugging;
12 #if LINUX
13 using System.Runtime.InteropServices;
14 #endif
15 
16 #endregion
17 
18 namespace Barotrauma
19 {
23  public static class Program
24  {
25 #if LINUX
29  [DllImport("linux_steam_env", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
30  private static extern void setLinuxEnv();
31 #endif
32 
33  public static bool TryStartChildServerRelay(string[] commandLineArgs)
34  {
35  for (int i = 0; i < commandLineArgs.Length; i++)
36  {
37  switch (commandLineArgs[i].Trim())
38  {
39  case "-pipes":
40  ChildServerRelay.Start(commandLineArgs[i + 2], commandLineArgs[i + 1]);
41  return true;
42  }
43  }
44  return false;
45  }
46 
50  [STAThread]
51  static void Main(string[] args)
52  {
53  AppDomain currentDomain = AppDomain.CurrentDomain;
54  currentDomain.ProcessExit += OnProcessExit;
55 #if !DEBUG
56  currentDomain.UnhandledException += new UnhandledExceptionEventHandler(CrashHandler);
57 #endif
58  TryStartChildServerRelay(args);
59 
60 #if LINUX
61  setLinuxEnv();
62  AppDomain.CurrentDomain.ProcessExit += (s, e) =>
63  {
64  GameMain.ShouldRun = false;
65  };
66 #endif
67  Console.WriteLine("Barotrauma Dedicated Server " + GameMain.Version +
68  " (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")");
69  if (Console.IsOutputRedirected)
70  {
71  Console.WriteLine("Output redirection detected; colored text and command input will be disabled.");
72  }
73  if (Console.IsInputRedirected)
74  {
75  Console.WriteLine("Redirected input is detected but is not supported by this application. Input will be ignored.");
76  }
77 
78  string executableDir = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
79  if (!File.Exists(Path.Combine(executableDir, "workshop.txt")))
80  {
81  Directory.SetCurrentDirectory(executableDir);
82  }
83 
84  DebugConsoleCore.Init(
85  newMessage: (s, c) => DebugConsole.NewMessage(s, c),
86  log: DebugConsole.Log);
87  Game = new GameMain(args);
88 
89  Game.Run();
90  ShutDown();
91  }
92 
93  private static bool hasShutDown = false;
94  private static void ShutDown()
95  {
96  if (hasShutDown) { return; }
97  hasShutDown = true;
98 
99  if (GameAnalyticsManager.SendUserStatistics) { GameAnalyticsManager.ShutDown(); }
100  SteamManager.ShutDown();
101 
102  // Gracefully exit EOS by ticking until the session is closed
103  EosInterface.Core.CleanupAndQuit();
104  while (EosInterface.Core.IsInitialized)
105  {
106  EosInterface.Core.Update();
107  TaskPool.Update();
108  Thread.Sleep(16);
109  }
110  }
111 
112  private static void OnProcessExit(object sender, EventArgs e)
113  {
114  ShutDown();
115  }
116 
117  static GameMain Game;
118 
119  private static void NotifyCrash(string reportFilePath, Exception e)
120  {
121  string errorMsg = $"{reportFilePath}||\n{e.Message} ({e.GetType().Name}) {e.StackTrace}";
122  if (e.InnerException != null)
123  {
124  var innerMost = e.GetInnermost();
125  errorMsg += $"\nInner exception: {innerMost.Message} ({innerMost.GetType().Name}) {e.StackTrace}";
126  }
127  if (errorMsg.Length > ushort.MaxValue) { errorMsg = errorMsg[..ushort.MaxValue]; }
128  ChildServerRelay.NotifyCrash(errorMsg);
129  GameMain.Server?.NotifyCrash();
130  }
131 
132  private static void CrashHandler(object sender, UnhandledExceptionEventArgs args)
133  {
134  static void swallowExceptions(Action action)
135  {
136  try
137  {
138  action();
139  }
140  catch
141  {
142  //discard exceptions and keep going
143  }
144  }
145 
146  Exception unhandledException = args.ExceptionObject as Exception;
147  string reportFilePath = "";
148  try
149  {
150  reportFilePath = "servercrashreport.log";
151  CrashDump(ref reportFilePath, unhandledException);
152  }
153  catch (Exception exceptionHandlerError)
154  {
155  Debug.WriteLine(exceptionHandlerError.Message);
156  string slimCrashReport = "Exception handler failed: " + exceptionHandlerError.Message + "\n" + exceptionHandlerError.StackTrace;
157  if (unhandledException != null)
158  {
159  slimCrashReport += "\n\nInitial exception: " + unhandledException.Message + "\n" + unhandledException.StackTrace;
160  }
161  File.WriteAllText("servercrashreportslim.log", slimCrashReport);
162  reportFilePath = "";
163  }
164  swallowExceptions(() => NotifyCrash(reportFilePath, unhandledException));
165  swallowExceptions(() => Game?.Exit());
166  }
167 
168  static void CrashDump(ref string filePath, Exception exception)
169  {
170  try
171  {
172  GameMain.Server?.ServerSettings?.SaveSettings();
173  GameMain.Server?.ServerSettings?.BanList.Save();
174  if (GameMain.Server?.ServerSettings?.KarmaPreset == "custom")
175  {
176  GameMain.Server?.KarmaManager?.SaveCustomPreset();
177  GameMain.Server?.KarmaManager?.Save();
178  }
179  }
180  catch (Exception e)
181  {
182  //couldn't save, whatever
183  }
184 
185  int existingFiles = 0;
186  string originalFilePath = filePath;
187  while (File.Exists(filePath))
188  {
189  existingFiles++;
190  filePath = Path.GetFileNameWithoutExtension(originalFilePath) + " (" + (existingFiles + 1) + ")" + Path.GetExtension(originalFilePath);
191  }
192 
193  StringBuilder sb = new StringBuilder();
194  sb.AppendLine("Barotrauma Dedicated Server crash report (generated on " + DateTime.Now + ")");
195  sb.AppendLine("\n");
196  sb.AppendLine("Barotrauma seems to have crashed. Sorry for the inconvenience! ");
197  sb.AppendLine("\n");
198  sb.AppendLine("Game version " + GameMain.Version + " (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")");
199  sb.AppendLine("Language: " + GameSettings.CurrentConfig.Language);
200  if (ContentPackageManager.EnabledPackages.All != null)
201  {
202  sb.AppendLine("Selected content packages: " +
203  (!ContentPackageManager.EnabledPackages.All.Any() ?
204  "None" :
205  string.Join(", ", ContentPackageManager.EnabledPackages.All.Select(c => $"{c.Name} ({c.Hash?.ShortRepresentation ?? "unknown"})"))));
206  }
207  sb.AppendLine("Level seed: " + ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed));
208  sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash + ")"));
209  sb.AppendLine("Selected screen: " + (Screen.Selected == null ? "None" : Screen.Selected.ToString()));
210 
211  if (GameMain.Server != null)
212  {
213  sb.AppendLine("Server (" + (GameMain.Server.GameStarted ? "Round had started)" : "Round hadn't been started)"));
214  }
215 
216  sb.AppendLine("\n");
217  sb.AppendLine("System info:");
218  sb.AppendLine(" Operating system: " + System.Environment.OSVersion + (System.Environment.Is64BitOperatingSystem ? " 64 bit" : " x86"));
219  sb.AppendLine("\n");
220  sb.AppendLine("Exception: " + exception.Message + " (" + exception.GetType().ToString() + ")");
221  sb.AppendLine("Target site: " +exception.TargetSite.ToString());
222  if (exception.StackTrace != null)
223  {
224  sb.AppendLine("Stack trace: ");
225  sb.AppendLine(exception.StackTrace.CleanupStackTrace());
226  sb.AppendLine("\n");
227  }
228 
229  if (exception.InnerException != null)
230  {
231  sb.AppendLine("InnerException: " + exception.InnerException.Message);
232  if (exception.InnerException.TargetSite != null)
233  {
234  sb.AppendLine("Target site: " + exception.InnerException.TargetSite.ToString());
235  }
236  if (exception.InnerException.StackTrace != null)
237  {
238  sb.AppendLine("Stack trace: ");
239  sb.AppendLine(exception.InnerException.StackTrace.CleanupStackTrace());
240  }
241  }
242 
243  if (GameAnalyticsManager.SendUserStatistics)
244  {
245  //send crash report before appending debug console messages (which may contain non-anonymous information)
246  GameAnalyticsManager.AddErrorEvent(GameAnalyticsManager.ErrorSeverity.Critical, sb.ToString());
247  GameAnalyticsManager.ShutDown();
248  }
249 
250  sb.AppendLine("Last debug messages:");
251  DebugConsole.Clear();
252  for (int i = DebugConsole.Messages.Count - 1; i > 0 && i > DebugConsole.Messages.Count - 15; i--)
253  {
254  sb.AppendLine(" " + DebugConsole.Messages[i].Time + " - " + DebugConsole.Messages[i].Text);
255  }
256 
257  string crashReport = sb.ToString();
258 
259  if (!Console.IsOutputRedirected)
260  {
261  Console.ForegroundColor = ConsoleColor.Red;
262  }
263  Console.Write(crashReport);
264 
265  File.WriteAllText(filePath, sb.ToString());
266 
267  if (GameSettings.CurrentConfig.SaveDebugConsoleLogs
268  || GameSettings.CurrentConfig.VerboseLogging) { DebugConsole.SaveLogs(); }
269 
270  if (GameAnalyticsManager.SendUserStatistics)
271  {
272  Console.Write("A crash report (\"servercrashreport.log\") was saved in the root folder of the game and sent to the developers.");
273  }
274  else
275  {
276  Console.Write("A crash report(\"servercrashreport.log\") was saved in the root folder of the game. The error was not sent to the developers because user statistics have been disabled, but" +
277  " if you'd like to help fix this bug, you may post it on Barotrauma's GitHub issue tracker: https://github.com/Regalis11/Barotrauma/issues/");
278  }
279  SteamManager.ShutDown();
280  }
281  }
282 }