views:

363

answers:

4

I'm trying to add plugins to my game and what I'm trying to implement is this:

  • Plugins will be either mine or 3rd party's so I would like a solution where crashing of the plugin would not mean crashing of the main application.

  • Methods of plugins are called very often (for example because of drawing of game objects).

What I've found so far:

Could you please comment on my findings? New approaches are also welcomed! Thanks!

+8  A: 

You can define a public interface which the plugin's must implement. Then with the use of reflection you can scan a "plugin" folder for any classes implementing that interface, then create an instance of that class.

From you're code just work on the interface and call the needed method's. About crashing, always make sure that calls to the "plugin" interface are always encapsulated in a try/catch block. If an exception occurs you can always dispose the plugin

Jasper
Thank you, you are talking about my point 1) which uses pretty the same as you told. I was thinking about try/catch blocks too (http://stackoverflow.com/questions/52312/what-is-the-real-overhead-of-try-catch-in-c - no significant overhead is needed).
MartyIX
@MartyIX Normally the best practice is to avoid using try/catch blocks for "normal" operations. But since you don't have any control over the plugin-code you can't trust it outside a try/catch block.
Jasper
+1  A: 

The generalized "secrect" to .NET extensibility is: Dynamic loading (to get the plugin into the AppDomain), Reflection (to verify it supports the methods/interface you specify), Attributes (to get Meta-Data for things like versioning), Late Binding (to actually use the plugin).

If your extensibility needs are very simple, or very unique, you should consider implementing it your way.

M.A. Hanin
+1  A: 

I used this tutorial as the basis for my own plug-in architecture a couple of years ago. My architecture was, I believe, a relatively simple architecture, but I hit some problems when it came to passing messages between plug-ins.

If you're intent on writing your own architecture, then fair enough, but I would warn against it. It's no small undertaking, and sooner or later you're going to run into some major design considerations, like message passing, which are non-trivial to solve (if admittedly simultaneously quite interesting and frustrating). There is a tremendous amount of value in using something like MEF that solves these problems for you, and provides a really nice API and framework upon which you can build you plug-ins.

Furthermore, MEF will end up being distributed as part of your application, so you don't need to get your users to download it separately; it's an "invisible" dependency as far as they're concerned, and a light-weight one for developers, including yourself. It's also the official plug-in architecture for Visual Studio 2010, so it has a lot of weight in the .NET community, and there will only ever be more developers able to write plug-ins for your app if you use it too.

Hope that makes some sense.

alastairs
Thanks for the link! Well, communication between plugins may be a problem but my game is not so much complicated (I hope :) ). I'll think about MEF.
MartyIX
+2  A: 

I suspect your two requirements of:

  1. fast performance with drawing objects and
  2. a plugin crash would not crash your app

are going to conflict.

To really ensure a buggy plugin doesn't crash your app, you have to load it in a separate AppDomain (as you've identified already). But you're going to take a performance hit, as the whole point of AppDomains is they isolate instances of objects. So you're, at minimum, going to have to serialize arguments to your plugins (possibly using MarshalByRef objects or Remoting). And I suspect that will mean serializing a good chunk of your game state (which sounds like it at least consists of some sort of image). On the plus side, AppDomains live in the same process space, so the overhead isn't as bad as cross-process communication.

Unloading plugins is as simple as unloading the AppDomain.

Because you have to serialise arguments, you can do validation of your game state after the plugin processes it.

I did some toying with AppDomains once. It takes a few seconds to construct one, in my experience. That may affect how many plugins you load into each AppDomain.

Thank you for your comment! It seems like too much overhead for my application. Using one AppDomain with try/catch blocks as Jasper suggested seems to be good for my game.
MartyIX