public Engine Launch(string[] args, HostType hostType) { //This two stage setup is required to ensure that a logger always exists var commandLine = new CommandLine(args, CommandLineKeyPrefixes); var gameDirectory = commandLine.GetValue("-game"); //This can't actually happen since SharpLife loads from its own directory, so unless somebody placed the installation in the default game directory this isn't an issue //It's an easy way to verify that nothing went wrong during user setup though if (gameDirectory == null) { FatalError("No game directory specified, cannot continue"); } var engineConfiguration = LoadEngineConfiguration(gameDirectory); var logTextWriter = new ForwardingTextWriter(); Logger = CreateLogger(gameDirectory, engineConfiguration.LoggingConfiguration, logTextWriter); //Now that the logger has been set up the engine can take care of the rest return(new Engine(hostType, commandLine, gameDirectory, engineConfiguration, Logger, logTextWriter)); }
private ILogger CreateLogger(string gameDirectory, LoggingConfiguration loggingConfiguration, ForwardingTextWriter logTextWriter) { var config = new LoggerConfiguration(); config.MinimumLevel.Verbose(); ITextFormatter fileFormatter = null; switch (loggingConfiguration.LogFormat) { case LoggingConfiguration.Format.Text: { fileFormatter = new MessageTemplateTextFormatter("{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}", null); break; } case LoggingConfiguration.Format.CompactJSON: { fileFormatter = new CompactJsonFormatter(); break; } } //Invalid config setting for RetainedFileCountLimit will throw config .WriteTo.File(fileFormatter, $"{gameDirectory}/logs/engine.log", rollingInterval: RollingInterval.Day, retainedFileCountLimit: loggingConfiguration.RetainedFileCountLimit); //Use basic formatting for console output var logFormatter = new MessageTemplateTextFormatter("{Message:lj}{NewLine}{Exception}", null); if (logTextWriter != null) { config.WriteTo.TextWriter(logFormatter, logTextWriter); } return(config.CreateLogger()); }
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 }