#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 Ninject;
using Ninject.Activation;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using XnaGame = Microsoft.Xna.Framework.Game;
namespace Nuclex.Ninject.Xna {
/// Ninject-based XNA game
public class NinjectGame : XnaGame, IGame, IGameInitializer {
/// Called when the game has begun the second stage initialization
public event EventHandler Initializing;
/// Initializes a new ninject-based XNA game
///
/// Kernel the dependency-injected components are managed in
///
public NinjectGame(IKernel kernel) {
//
// We register all services provided by the game here (and not through
// method bindings that forward to the game class) because otherwise,
// if the Game class ever tried to create a component through Ninject
// that depended on the Game class again, this would not be resolvable
// by Ninject (as it's already trying to construct a game at that time)
//
// All components are registered as 'singletons' to the kernel managing
// the game. This does not prevent you from setting up another kernel
// that does something entirely else, but for all purposes, having more
// than one XNA game active in the same process at the same time does
// not make much sense ;-)
//
// The game automatically creates a content manager as well. Through
// this binding, all components can access this content manager to
// store and retrieve any game-global content.
kernel.Rebind().ToConstant(Content).InSingletonScope();
// Bind XNA's service container (which is another IServiceProvider) to
// Ninject. Some game components will pull their dependencies exclusively
// from here, so components should be able to add themselves to it.
kernel.Rebind().ToConstant(Services).InSingletonScope();
kernel.Rebind().ToConstant(Services).InSingletonScope();
// By adding themselves to this collection, components can take part in
// the game's update and redraw cycles.
kernel.Rebind().ToConstant(Components).InSingletonScope();
// The graphics device service is probably the most important service
// for an XNA game, but XNA also leaves open the possibility of a Game
// not actually using the graphics device service at all, so we go through
// the GameServiceContainer, where it will register itself if it is created.
kernel.Rebind().ToMethod(
getGraphicsDeviceService
).InSingletonScope();
kernel.Rebind().ToMethod(
getGraphicsDeviceManager
).InSingletonScope();
// This binding should not be used normally. Components should access
// the graphics device manager through the IGraphicsDeviceService interface.
// Some existing components, like Sunburn's LightingSystemEditor, however,
// ask for the GraphicsDeviceManager itself, so this allows such components
// to be activated by attempting to downcast whatever component implements
// the IGraphicsDeviceManager service.
kernel.Rebind().ToMethod(
getConcreteGraphicsDeviceManager
).InSingletonScope();
}
///
/// Called after all components are initialized but before the first update in
/// the game loop.
///
protected override void Initialize() {
// Do not call base.Initialize() first here. It might seem to make more sense
// (initialize base before derived), but the way XNA's startup works, doing it
// the other way around will cause any game components added during this phase
// to not be initialized at all (they will be placed on the notYetInitialized
// list because inRun is still false, but the notYetInitialized list has already
// been processed at this time).
OnInitializing();
base.Initialize();
}
/// Fires the Initializing event
protected virtual void OnInitializing() {
if(Initializing != null) {
Initializing(this, EventArgs.Empty);
}
}
///
/// Looks up the graphics device service from the game's registered
/// service providers
///
///
/// Context containing the kernel and informations about the request
///
/// The graphics device service
///
/// Thrown if the game has not created a graphics device manager
///
private static IGraphicsDeviceService getGraphicsDeviceService(IContext context) {
var services = context.Kernel.GetService();
// Look up the game's graphics device service and display and bail out
// with a sane error message if the game does not provide that service.
IGraphicsDeviceService graphicsDeviceService;
if (!services.TryGetService(out graphicsDeviceService)) {
throw new ActivationException(
"No active graphics device service is registered for the game"
);
}
return graphicsDeviceService;
}
///
/// Looks up the graphics device manager from the game's registered
/// service providers
///
///
/// Context containing the kernel and informations about the request
///
/// The graphics device manager
///
/// Thrown if the game has not created a graphics device manager
///
private static IGraphicsDeviceManager getGraphicsDeviceManager(IContext context) {
var services = context.Kernel.GetService();
// Look up the game's graphics device service and display and bail out
// with a sane error message if the game does not provide that service.
IGraphicsDeviceManager graphicsDeviceManager;
if (!services.TryGetService(out graphicsDeviceManager)) {
throw new ActivationException(
"No active graphics device manager is registered for the game"
);
}
return graphicsDeviceManager;
}
///
/// Looks up the actual graphics device manager implementation class.
/// Should not be used under normal circumstances.
///
///
/// Context containing the kernel and informations about the request
///
/// The XNA graphics device manager instance
private static GraphicsDeviceManager getConcreteGraphicsDeviceManager(IContext context) {
var graphicsDeviceManager = getGraphicsDeviceManager(context);
var concrete = graphicsDeviceManager as GraphicsDeviceManager;
if(concrete == null) {
throw new ActivationException(
"Cannot access GraphicsDeviceManager because the game's IGraphicsDeviceManager " +
"service is provided by a custom component"
);
}
return concrete;
}
}
} // namespace Nuclex.Ninject.Xna