static void Initialize(Arguments args) { var engineDirArg = args.GetValue("Engine.EngineDir", null); if (!string.IsNullOrEmpty(engineDirArg)) { Platform.OverrideEngineDir(engineDirArg); } var supportDirArg = args.GetValue("Engine.SupportDir", null); if (!string.IsNullOrEmpty(supportDirArg)) { Platform.OverrideSupportDir(supportDirArg); } Console.WriteLine("Platform is {0}", Platform.CurrentPlatform); // Load the engine version as early as possible so it can be written to exception logs try { EngineVersion = File.ReadAllText(Path.Combine(Platform.EngineDir, "VERSION")).Trim(); } catch { } if (string.IsNullOrEmpty(EngineVersion)) { EngineVersion = "Unknown"; } Console.WriteLine("Engine version is {0}", EngineVersion); Console.WriteLine("Runtime: {0}", Platform.RuntimeVersion); // Special case handling of Game.Mod argument: if it matches a real filesystem path // then we use this to override the mod search path, and replace it with the mod id var modID = args.GetValue("Game.Mod", null); var explicitModPaths = new string[0]; if (modID != null && (File.Exists(modID) || Directory.Exists(modID))) { explicitModPaths = new[] { modID }; modID = Path.GetFileNameWithoutExtension(modID); } InitializeSettings(args); Log.AddChannel("perf", "perf.log"); Log.AddChannel("debug", "debug.log"); Log.AddChannel("server", "server.log", true); Log.AddChannel("sound", "sound.log"); Log.AddChannel("graphics", "graphics.log"); Log.AddChannel("geoip", "geoip.log"); Log.AddChannel("nat", "nat.log"); Log.AddChannel("client", "client.log"); var platforms = new[] { Settings.Game.Platform, "Default", null }; foreach (var p in platforms) { if (p == null) { throw new InvalidOperationException("Failed to initialize platform-integration library. Check graphics.log for details."); } Settings.Game.Platform = p; try { var rendererPath = Path.Combine(Platform.BinDir, "OpenRA.Platforms." + p + ".dll"); #if !MONO var loader = new AssemblyLoader(rendererPath); var platformType = loader.LoadDefaultAssembly().GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t)); #else var assembly = Assembly.LoadFile(rendererPath); var platformType = assembly.GetTypes().SingleOrDefault(t => typeof(IPlatform).IsAssignableFrom(t)); #endif if (platformType == null) { throw new InvalidOperationException("Platform dll must include exactly one IPlatform implementation."); } var platform = (IPlatform)platformType.GetConstructor(Type.EmptyTypes).Invoke(null); Renderer = new Renderer(platform, Settings.Graphics); Sound = new Sound(platform, Settings.Sound); break; } catch (Exception e) { Log.Write("graphics", "{0}", e); Console.WriteLine("Renderer initialization failed. Check graphics.log for details."); Renderer?.Dispose(); Sound?.Dispose(); } } Nat.Initialize(); var modSearchArg = args.GetValue("Engine.ModSearchPaths", null); var modSearchPaths = modSearchArg != null? FieldLoader.GetValue <string[]>("Engine.ModsPath", modSearchArg) : new[] { Path.Combine(Platform.EngineDir, "mods") }; Mods = new InstalledMods(modSearchPaths, explicitModPaths); Console.WriteLine("Internal mods:"); foreach (var mod in Mods) { Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Metadata.Title, mod.Value.Metadata.Version); } modLaunchWrapper = args.GetValue("Engine.LaunchWrapper", null); ExternalMods = new ExternalMods(); if (modID != null && Mods.TryGetValue(modID, out _)) { var launchPath = args.GetValue("Engine.LaunchPath", null); var launchArgs = new List <string>(); // Sanitize input from platform-specific launchers // Process.Start requires paths to not be quoted, even if they contain spaces if (launchPath != null && launchPath.First() == '"' && launchPath.Last() == '"') { launchPath = launchPath.Substring(1, launchPath.Length - 2); } if (launchPath == null) { // When launching the assembly directly we must propagate the Engine.EngineDir argument if defined // Platform-specific launchers are expected to manage this internally. launchPath = Assembly.GetEntryAssembly().Location; if (!string.IsNullOrEmpty(engineDirArg)) { launchArgs.Add("Engine.EngineDir=\"" + engineDirArg + "\""); } } ExternalMods.Register(Mods[modID], launchPath, launchArgs, ModRegistration.User); if (ExternalMods.TryGetValue(ExternalMod.MakeKey(Mods[modID]), out var activeMod)) { ExternalMods.ClearInvalidRegistrations(activeMod, ModRegistration.User); } } Console.WriteLine("External mods:"); foreach (var mod in ExternalMods) { Console.WriteLine("\t{0}: {1} ({2})", mod.Key, mod.Value.Title, mod.Value.Version); } InitializeMod(modID, args); Ui.InitializeTranslation(); }
static void Run(string[] args) { var arguments = new Arguments(args); var engineDirArg = arguments.GetValue("Engine.EngineDir", null); if (!string.IsNullOrEmpty(engineDirArg)) { Platform.OverrideEngineDir(engineDirArg); } var supportDirArg = arguments.GetValue("Engine.SupportDir", null); if (!string.IsNullOrEmpty(supportDirArg)) { Platform.OverrideSupportDir(supportDirArg); } Log.AddChannel("debug", "dedicated-debug.log", true); Log.AddChannel("perf", "dedicated-perf.log", true); Log.AddChannel("server", "dedicated-server.log", true); Log.AddChannel("nat", "dedicated-nat.log", true); Log.AddChannel("geoip", "dedicated-geoip.log", true); // Special case handling of Game.Mod argument: if it matches a real filesystem path // then we use this to override the mod search path, and replace it with the mod id var modID = arguments.GetValue("Game.Mod", null); var explicitModPaths = new string[0]; if (modID != null && (File.Exists(modID) || Directory.Exists(modID))) { explicitModPaths = new[] { modID }; modID = Path.GetFileNameWithoutExtension(modID); } if (modID == null) { throw new InvalidOperationException("Game.Mod argument missing or mod could not be found."); } // HACK: The engine code assumes that Game.Settings is set. // This isn't nearly as bad as ModData, but is still not very nice. Game.InitializeSettings(arguments); var settings = Game.Settings.Server; Nat.Initialize(); var envModSearchPaths = Environment.GetEnvironmentVariable("MOD_SEARCH_PATHS"); var modSearchPaths = !string.IsNullOrWhiteSpace(envModSearchPaths) ? FieldLoader.GetValue <string[]>("MOD_SEARCH_PATHS", envModSearchPaths) : new[] { Path.Combine(Platform.EngineDir, "mods") }; var mods = new InstalledMods(modSearchPaths, explicitModPaths); Console.WriteLine("[{0}] Starting dedicated server for mod: {1}", DateTime.Now.ToString(settings.TimestampFormat), modID); while (true) { // HACK: The engine code *still* assumes that Game.ModData is set var modData = Game.ModData = new ModData(mods[modID], mods); modData.MapCache.LoadMaps(); settings.Map = modData.MapCache.ChooseInitialMap(settings.Map, new MersenneTwister()); var endpoints = new List <IPEndPoint> { new IPEndPoint(IPAddress.IPv6Any, settings.ListenPort), new IPEndPoint(IPAddress.Any, settings.ListenPort) }; var server = new Server(endpoints, settings, modData, ServerType.Dedicated); GC.Collect(); while (true) { Thread.Sleep(1000); if (server.State == ServerState.GameStarted && server.Conns.Count < 1) { Console.WriteLine("[{0}] No one is playing, shutting down...", DateTime.Now.ToString(settings.TimestampFormat)); server.Shutdown(); break; } } modData.Dispose(); Console.WriteLine("[{0}] Starting a new server instance...", DateTime.Now.ToString(settings.TimestampFormat)); } }