#region CPL License /* Nuclex Framework Copyright (C) 2002-2009 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using System.Diagnostics; using Ninject; using Ninject.Activation; using Ninject.Modules; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace Nuclex.Ninject.Xna { /// Sets up service bindings for XNA games public class XnaModule : NinjectModule { /// Called when the module is loaded into the kernel public override void Load() { // // Register these explicitly, because otherwise, Ninject would just create // a new game component collection and adding anything to it would have no // effect because the game is using its own, separate collection. // Kernel.Bind().ToMethod( getGameComponentCollection ).InSingletonScope(); Kernel.Bind().ToMethod( getGameServiceContainer ).InSingletonScope(); Kernel.Bind().ToMethod( getGameServiceContainer ).InSingletonScope(); Kernel.Bind().ToMethod( getGameGraphicsDeviceService ).InSingletonScope(); Kernel.Bind().ToMethod( getGameGraphicsDeviceManager ).InSingletonScope(); Kernel.Bind().ToMethod( getConcreteGameGraphicsDeviceManager ).InSingletonScope(); // This is a bit icky - normally components should only access services // or the game through its IGame interface. Some XNA classes, like GameComponent // and DrawableGameComponent, however, require a Game instance and Ninject would // create a second, unpopulated Game instance if this wasn't set up. Kernel.Bind().ToMethod(getNinjectGame).InSingletonScope(); Kernel.Bind().ToMethod(getNinjectGame).InSingletonScope(); // Provide a globally shared sprite batch to the game. If you can, only use // the ISpriteBatch interface as this guarantees that your components can be // provided with a mocked sprite batch for unit testing. The SpriteBatch // binding is only provided to support existing components that rely directly // on the sprite batch (meaning unit tests would have to create a graphics device) Kernel.Bind().ToSelf().InSingletonScope(); // internal class :) Kernel.Bind().ToMethod(getSharedSpriteBatch).InSingletonScope(); Kernel.Bind().ToMethod(getSharedSpriteBatch).InSingletonScope(); // Provide access to the Game class' built-in content manager. Whenever possible, // use the IContentManager interface instead of requesting a ContentManager // directly. This has the advantage of allowing unit tests to pass mocks of // the IContentManager interface to your class. Kernel.Bind().ToMethod(getGameContentManager).InSingletonScope(); Kernel.Bind().To().InSingletonScope(); } /// Gets the XNA game from the game instance /// /// Context containing the kernel and informations about the request /// /// The XNA game private static NinjectGame getNinjectGame(IContext context) { ensureNinjectGameCreated(context); // This downcast is safe because the XnaModule class already enforces that // the concrete implementation of IGame must be derived from NinjectGame. // It's not nice, however, but a little negligence in the design of XNA's // GameComponent and DrawableGameComponent classes forces us to do this. var game = context.Kernel.Get() as NinjectGame; return game; } /// Gets the game's content manager from the game instance /// /// Context containing the kernel and informations about the request /// /// The game's content manager private static ContentManager getGameContentManager(IContext context) { ensureNinjectGameCreated(context); return context.Kernel.Get(); } /// Gets the game component collection from the game instance /// /// Context containing the kernel and informations about the request /// /// The game component collection private static GameComponentCollection getGameComponentCollection(IContext context) { ensureNinjectGameCreated(context); return context.Kernel.Get(); } /// Gets the game service container from the game instance /// /// Context containing the kernel and informations about the request /// /// The game service container private static GameServiceContainer getGameServiceContainer(IContext context) { ensureNinjectGameCreated(context); return context.Kernel.Get(); } /// Gets the graphics device manager from the game instance /// /// Context containing the kernel and informations about the request /// /// The graphics device manager private static IGraphicsDeviceManager getGameGraphicsDeviceManager(IContext context) { ensureNinjectGameCreated(context); return context.Kernel.Get(); } /// Gets the graphics device service from the game instance /// /// Context containing the kernel and informations about the request /// /// The graphics device service private static IGraphicsDeviceService getGameGraphicsDeviceService(IContext context) { ensureNinjectGameCreated(context); return context.Kernel.Get(); } /// Gets the concrete graphics device manager from the game instance /// /// Context containing the kernel and informations about the request /// /// The concrete graphics device manager private static GraphicsDeviceManager getConcreteGameGraphicsDeviceManager(IContext context) { ensureNinjectGameCreated(context); return context.Kernel.Get(); } /// Gets the shared sprite batch for the game instance /// /// Context containing the kernel and informations about the request /// /// The shared sprite batch private static SharedSpriteBatch getSharedSpriteBatch(IContext context) { return context.Kernel.Get(); } /// Enforces that an instance of the the Game is created /// /// Context containing the kernel and informations about the request /// /// /// Enforces that an instance of the XNA Game class has been created and /// that it is based on the class to ensure its /// GameServiceContainer and GameComponentCollection have been bound /// to Ninject. /// [Conditional("DEBUG")] private static void ensureNinjectGameCreated(IContext context) { if(!(context.Kernel.Get() is NinjectGame)) { throw new InvalidOperationException( "IGame implementation is not derived from the NinjectGame class\r\n" + "\r\n" + "The concrete class bound to the IGame service does not derive from " + "the NinjectGame class, meaning that we cannot guarantee the game " + "component collection will be rebound to the one in the Game class." ); } } } } // namespace Nuclex.Ninject.Xna