public Engine(HostType hostType, ICommandLine commandLine, string gameDirectory, EngineConfiguration engineConfiguration, ILogger logger, ForwardingTextWriter forwardingTextWriter) { _hostType = hostType; CommandLine = commandLine ?? throw new ArgumentNullException(nameof(commandLine)); GameDirectory = gameDirectory ?? throw new ArgumentNullException(nameof(gameDirectory)); EngineConfiguration = engineConfiguration ?? throw new ArgumentNullException(nameof(engineConfiguration)); Log.Logger = Logger = logger ?? throw new ArgumentNullException(nameof(logger)); LogTextWriter = forwardingTextWriter ?? throw new ArgumentNullException(nameof(forwardingTextWriter)); FileSystem = new DiskFileSystem(); SetupFileSystem(GameDirectory); CommandSystem = new SharpLife.CommandSystem.CommandSystem(Logger, CultureInfo.InvariantCulture); EngineContext = CommandSystem.CreateContext("EngineContext"); var startupState = new EngineStartupState(Logger, GameDirectory, new IModelFormatProvider[] { new SpriteModelFormatProvider(), new StudioModelFormatProvider(), //BSP loader comes last due to not having a way to positively recognize the format new BSPModelFormatProvider(Framework.BSPModelNamePrefix) }); //Add the engine assembly so builtin data gets added startupState.EntitySystemMetaData.AddAssembly(typeof(Engine).Assembly); //create the game window if this is a client if (_hostType == HostType.Client) { Client = new EngineClient(this, startupState); } Server = new EngineServer(this, Logger, startupState); PluginManager = startupState.PluginManager.Build(); //Automatically add in all plugin assemblies to the entity system foreach (var pluginAssembly in PluginManager.Assemblies) { startupState.EntitySystemMetaData.AddAssembly(pluginAssembly); } var renderer = (IRenderer)Client?.UserInterface.Renderer ?? new ServerRenderer(); World = new WorldState( Logger, EventSystem, FileSystem, startupState.EntitySystemMetaData.Build(), renderer, startupState.ModelFormats); _engineTimeStopwatch.Start(); EngineContext.AddStuffCmds(Logger, CommandLine); EngineContext.AddExec(Logger, FileSystem, ExecPathIDs); EngineContext.AddEcho(Logger); EngineContext.AddAlias(Logger); EngineContext.AddFind(Logger); EngineContext.AddHelp(Logger); _fpsMax = EngineContext.RegisterVariable( new VirtualVariableInfo <uint>("fps_max", DefaultFPS) .WithHelpInfo("Sets the maximum frames per second") .WithChangeHandler((ref VariableChangeEvent <uint> @event) => { @event.Value = Math.Min(@event.Value, MaximumFPS); var desiredFPS = @event.Value; if (desiredFPS == 0) { desiredFPS = MaximumFPS; } _desiredFrameLengthSeconds = 1.0 / desiredFPS; })); EngineContext.RegisterVariable("engine_builddate", () => BuildDate, "The engine's build date"); EngineContext.RegisterCommand(new CommandInfo("map", StartNewMap).WithHelpInfo("Loads the specified map")); //Get the build date from the generated resource file var assembly = typeof(Engine).Assembly; using (var reader = new StreamReader(assembly.GetManifestResourceStream($"{assembly.GetName().Name}.Resources.BuildDate.txt"))) { string buildTimestamp = reader.ReadToEnd(); BuildDate = DateTimeOffset.Parse(buildTimestamp); Logger.Information($"Exe: {BuildDate.ToString("HH:mm:ss MMM dd yyyy")}"); } //TODO: initialize subsystems }