Skip to content

Instantly share code, notes, and snippets.

@aybe
Forked from aethercowboy/ExampleGame.cs
Created September 29, 2022 22:26
Show Gist options
  • Select an option

  • Save aybe/a5ffe40c2d77361d81d281fd2d6e2c09 to your computer and use it in GitHub Desktop.

Select an option

Save aybe/a5ffe40c2d77361d81d281fd2d6e2c09 to your computer and use it in GitHub Desktop.

Revisions

  1. @aethercowboy aethercowboy revised this gist Mar 27, 2020. 1 changed file with 11 additions and 1 deletion.
    12 changes: 11 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -2,4 +2,14 @@

    Here's a basic structure for a Monogame project making use of the ASP.NET Core HostedService technologies.

    This lets you easily make use of DI within your game, but also include pluggable architecture.
    This lets you easily make use of DI within your game, but also include pluggable architecture.

    # Files

    * **Program.cs** - The entrypoint to your application. Uses dotnet core's CreateDefaultBuilder to make the DI setup easier.
    * **Worker.cs** - The main game service. Handles the buildup/teardown of the the game class.
    * **ServiceCollectionExtensions.cs** - A collection of extension methods to set up base DI defs and allow for adding plugins.
    * **IGame.cs** - An interface that defines the layout of the main Game class. Implemented by your game class. Ideally should include all the Properties/Methods/Events of the base Game classs.
    * **ExampleGame.cs** - An example of how to use the IGame interface.
    * **IStartupProvider.cs** - An interface that defines how your plugin defines its DI and (possibly) additiona HostedServices.
    * **ExampleStartupProvider.cs** - An example of how to use IStartupProvider so MEF detects it. Put the DLL in your executable directory and your program will automatically detect it and load it.
  2. @aethercowboy aethercowboy revised this gist Mar 27, 2020. 2 changed files with 9 additions and 1 deletion.
    8 changes: 8 additions & 0 deletions ExampleStartupProvider.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    [Export(typeof(IStartupProvider))]
    public class StartupProvider : IStartupProvider
    {
    void IStartupProvider.ConfigureServices(IServiceCollection services)
    {
    // plugin DI def here
    }
    }
    2 changes: 1 addition & 1 deletion ServiceCollectionExtensions.cs
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    public static void AddGameConfiguration(this IServiceCollection services)
    {
    // your base DI here
    // your base DI def here
    }

    public static void AddPlugins(this IServiceCollection services)
  3. @aethercowboy aethercowboy revised this gist Mar 27, 2020. 1 changed file with 13 additions and 0 deletions.
    13 changes: 13 additions & 0 deletions ExampleGame.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    public class ExampleGame : Game, IGame
    {
    public Game Game => this;

    private readonly ISomeDependency _someDependency;

    public ExampleGame(ISomeDependency someDependency)
    {
    _someDependency = someDependency;
    }

    // ... implementation here
    }
  4. @aethercowboy aethercowboy revised this gist Mar 27, 2020. 2 changed files with 3 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions IGame.cs
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,8 @@
    public interface IGame : IDisposable
    {
    Game Game { get; }

    // include all the Properties/Methods that you'd want to use on your Game class below.
    GameWindow Window { get; }

    event EventHandler<EventArgs> Exiting;
    1 change: 1 addition & 0 deletions Program.cs
    Original file line number Diff line number Diff line change
    @@ -12,5 +12,6 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
    {
    services.AddHostedService<Worker>();
    services.AddGameConfiguration();
    services.AddPlugins();
    });
    }
  5. @aethercowboy aethercowboy revised this gist Mar 27, 2020. 1 changed file with 1 addition and 5 deletions.
    6 changes: 1 addition & 5 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -2,8 +2,4 @@

    Here's a basic structure for a Monogame project making use of the ASP.NET Core HostedService technologies.

    This lets you easily make use of DI within your game, but also include pluggable architecture.

    ## Todo

    1. Figure out a way to use something like HostingStartup files with project.
    This lets you easily make use of DI within your game, but also include pluggable architecture.
  6. @aethercowboy aethercowboy revised this gist Mar 27, 2020. 2 changed files with 47 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions IStartupProvider.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,4 @@
    public interface IStartupProvider
    {
    void ConfigureServices(IServiceCollection services);
    }
    43 changes: 43 additions & 0 deletions ServiceCollectionExtensions.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    public static void AddGameConfiguration(this IServiceCollection services)
    {
    // your base DI here
    }

    public static void AddPlugins(this IServiceCollection services)
    {
    var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

    var dirCat = new DirectoryCatalog(path);
    var importDef = BuildImportDefinition();

    try
    {
    using var aggregateCatalog = new AggregateCatalog();
    aggregateCatalog.Catalogs.Add(dirCat);

    using var compositionContainer = new CompositionContainer(aggregateCatalog);
    var exports = compositionContainer.GetExports(importDef);

    foreach (var module in exports
    .Select(x => x.Value as IStartupProvider)
    .Where(x => x != null))
    {
    module.ConfigureServices(services);
    }
    }
    catch (ReflectionTypeLoadException e)
    {
    var builder = new StringBuilder();
    foreach (var loaderException in e.LoaderExceptions)
    {
    builder.AppendFormat("{0}\n", loaderException.Message);
    }

    throw new TypeLoadException(builder.ToString(), e);
    }
    }

    private static ImportDefinition BuildImportDefinition()
    {
    return new ImportDefinition(x => true, typeof(IStartupProvider).FullName, ImportCardinality.ZeroOrMore, false, false);
    }
  7. @aethercowboy aethercowboy created this gist Mar 27, 2020.
    10 changes: 10 additions & 0 deletions IGame.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    public interface IGame : IDisposable
    {
    Game Game { get; }
    GameWindow Window { get; }

    event EventHandler<EventArgs> Exiting;

    void Run();
    void Exit();
    }
    16 changes: 16 additions & 0 deletions Program.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    public static class Program
    {
    [STAThread]
    private static void Main(string[] args)
    {
    CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
    services.AddHostedService<Worker>();
    services.AddGameConfiguration();
    });
    }
    9 changes: 9 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    # Monogame with IHostedService / DI

    Here's a basic structure for a Monogame project making use of the ASP.NET Core HostedService technologies.

    This lets you easily make use of DI within your game, but also include pluggable architecture.

    ## Todo

    1. Figure out a way to use something like HostingStartup files with project.
    51 changes: 51 additions & 0 deletions Worker.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,51 @@
    public class Worker : IHostedService
    {
    public static GraphicsDeviceManager Graphics { get; private set; }

    private readonly IGame _game;
    private readonly IHostApplicationLifetime _appLifetime;

    public Worker(IGame game, IHostApplicationLifetime appLifetime)
    {
    _game = game;
    _appLifetime = appLifetime;

    Graphics = new GraphicsDeviceManager(game.Game);
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
    _appLifetime.ApplicationStarted.Register(OnStarted);
    _appLifetime.ApplicationStopping.Register(OnStopping);
    _appLifetime.ApplicationStopped.Register(OnStopped);

    _game.Exiting += OnGameExiting;

    return Task.CompletedTask;
    }

    private void OnGameExiting(object sender, System.EventArgs e)
    {
    StopAsync(new CancellationToken());
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
    _appLifetime.StopApplication();

    return Task.CompletedTask;
    }

    private void OnStarted()
    {
    _game.Run();
    }

    private void OnStopping()
    {
    }

    private void OnStopped()
    {
    }
    }