#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