Building a Plugin Architecture

Post your questions, suggestions and experiences regarding game design, integration of external libraries here. For irrEdit, irrXML and irrKlang, see the
ambiera forums
Post Reply
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Building a Plugin Architecture

Post by Halifax »

Alright, just a little background information. I am building a plugin architecture that I will be using for my projects to come, and I don't like to put down code before I research and obtain opinions. So I am looking for suggestions, and what you think.

It is built to only work with Win32 so far, in theory, but I would like to find someone who works with linux to port it once I actually get the code written down.

I would like to give a diagram just to show the interaction, although it may not be correctly built: http://i177.photobucket.com/albums/w235 ... iagram.png

Now onto the notes that I have:
PluginArchitectureNotes
=======================

- Functions that the plugins must define in order to interface with the API
typedef void ( *PFPLUGINREGISTER )( const PluginManager& );
typedef void* ( *PFNPLUGINCREATE )( void );
typedef void ( *PFNPLUGINDESTROY )( void* );

- Unified structure for plugins
struct SPlugin {
PFNPLUGINREGISTER register;
PFNPLUGINCREATE create;
PFNPLUGINDESTROY destroy;
};

- Enumeration for plugins to use
enum EPluginType {
EPT_RENDER_SYSTEM,
EPT_PHYSIC_SYSTEM,
EPT_AUDIO_SYSTEM
};

- The actual plugin manager
class PluginManager {
bool loadPlugin( const String& name );
void unloadPlugin( const String& name );

bool registerPlugin( enum EPluginType pType, const String& pName );

RenderSystem* createRenderSystem( const String& rsName );
PhysicSystem* createPhysicSystem( const String& psName );
AudioSystem* createAudioSystem( const String& asName );

void destroyRenderSystem( RenderSystem* );
void destroyPhysicSystem( PhysicSystem* );
void destroyAudioSystem( AudioSystem* );
};

- Usage
PluginManager* pluginMgr = new PluginManager;

pluginMgr->loadPlugin( "OpenGL2.1RS.dll" );
pluginMgr->loadPlugin( "BulletPS.dll" );
pluginMgr->loadPlugin( "OpenALAS.dll" );

RenderSystem* rsOpenGL = pluginMgr->createRenderSystem("OpenGL2.1");
PhysicSystem* psBullet = pluginMgr->createPhysicSystem("Bullet");
AudioSystem* asOpenAL = pluginMgr->createAudioSystem("OpenAL");

rsOpenGL->beginScene();
rsOpenGL->beginBatch();
rsOpenGL->endBatch();
rsOpenGL->endScene();

pluginMgr->unloadPlugin( "OpenGL2.1RS.dll" );
pluginMgr->unloadPlugin( "BulletPS.dll" );
pluginMgr->unloadPlugin( "OpenALAS.dll" );
Now I will give a little explanation. I did not give the details of the underlying managing structure because this is just a specification. But in case your interested, SPlugin is internally managed.

The methods are setup to allow dynamic functionality, and to facilitate management of memory. So loadPlugin() loads the DLL into memory, but doesn't not create the actual plugin's data. This is good for deferred loading, or to detect whether the plugin is even available, etc.

In loadPlugin() it gets the DLL from memory, and obtains the three pointer functions needed. Then it calls the PFNPLUGINREGISTER function and passes a reference to itself, PluginManager. The plugin then uses registerPlugin() with its type, and its name. (Note: The name is used by the client later on by the create*() methods.)

Now the create*() methods look up the plugin's registered name, and attempt to create an instance with the plugin's create function. If successful, it passes back an abstract interface which defines what the client may use.

Everything else is self-explanatory. But if you still have questions, then feel free to ask. Please provide comments, improvements, suggestions, and criticisms. Thanks.
TheQuestion = 2B || !2B
Dorth
Posts: 931
Joined: Sat May 26, 2007 11:03 pm

Post by Dorth »

Just a head's up Halifax ;)
This design has been tried time and again. It succeeds pretty well up to now in an industrial setting. However, I have yet to see this used as a proper base for a game. Doesn't mean it can't be done, just that the answer will probably not be a low-hanging fruit ^^

Well, good luck.
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

OK, we're at the how. Can we rewind back two steps?

* Why are you doing this?
* What is it intended to achieve?
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Trefall
Posts: 45
Joined: Tue Dec 05, 2006 8:49 pm

Post by Trefall »

Looks like a plugin-based framework/engine to me. Ogre3D and OSG have this implemented, so might be worth checking out how they did it (though you might already have done so). Here at work we used OSG's plugin loader to load other dlls, not just for those plugging in with OSG, and that works really well.

I'm going down this path myself in my framework, though I haven't really started on this particular point just yet. Interesting to see your plans! My reason for doing this level of abstraction, is to maintain a thirdparty independent framework that can be plugged together with any rendering engine, any physics engine, any audio engine, etc, where you'd only need to write a wrapper dll to add support for something new. It forces me to keep the framework clean and not clutter it with tons of thirdparty code.

I'm focusing 100% on building a framework, and not on building a game though, so I can spend time implementing features like these and want to achieve this level of flexibility that any potential user won't be turned away because there wasn't support for the toolset she felt comfortable using.
torleif
Posts: 188
Joined: Mon Jun 30, 2008 4:53 am

Post by torleif »

rogerborg is right. You might want to take a step back and think why you want to add plugins to your game. Remember the best answer to a problem is the most simple.

The most tried and tested way to expand your game is to use a scripting language. This way you don't have to worry about cross compatibility and compiler quirks. I recommend luabind it's easy to implement and runs lightning fast. With this you can customize the hell out of your game, and still have the control over what happens.
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

Dorth wrote:Just a head's up Halifax ;)
This design has been tried time and again. It succeeds pretty well up to now in an industrial setting. However, I have yet to see this used as a proper base for a game. Doesn't mean it can't be done, just that the answer will probably not be a low-hanging fruit ^^

Well, good luck.
Yeah, thanks for the advice Dorth. But no, it's not being used for a game actually, but rather my new 2D engine.
rogerborg wrote:* Why are you doing this?
I am doing this because it reduces compile-time, by actually separating the specific modules. Also, it makes it easier for third-party developers to add-on to the system without the need for the base code, but instead just the specification of the interface.
rogerborg wrote:* What is it intended to achieve?
I highly modular system, that can be extended in the future, and gives the user more control over how their memory is managed. They don't have to recompile the engine to get rid of DX support, and reduce the memory used, they just have to not load the plugin.

@Trefall: Exactly, that is another great reason for a plugin architecture I believe. You don't have to spend needless time integrating third-party software that the user may not even use. And same here, I'm 100% on this framework because I have found no existing solutions that fit my needs. But I have never heard of OSG. I guess I will have to check it out, especially if it is cross-platform.

@torleif: Yeah, I guess I should have mentioned that this was for an engine, and not a game. And I have given thought to the scripting engine, and I actually plan to use AngelCode.

Thanks for all the input guys, I hope I answered your questions.
TheQuestion = 2B || !2B
Dorth
Posts: 931
Joined: Sat May 26, 2007 11:03 pm

Post by Dorth »

Second head's up:
AngelCode doesn't support natively inheritance. There's an ok article on GameDev about how you can do a pseudo inheritance though. Just some food for the brain. Also, if you make a modular engine, why not have the scripting engine be modular? Give it the hook you'd normally give your scripting engine and there you go :P
rogerborg
Admin
Posts: 3590
Joined: Mon Oct 09, 2006 9:36 am
Location: Scotland - gonnae no slag aff mah Engleesh
Contact:

Post by rogerborg »

Halifax wrote:
rogerborg wrote:* Why are you doing this?
I am doing this because it reduces compile-time, by actually separating the specific modules.
OK, but if they're implemented independently (which they'd have to be in order to be plugins), then they wouldn't be recompiled anyway, so you're only saving a little link time.

Halifax wrote:Also, it makes it easier for third-party developers to add-on to the system without the need for the base code, but instead just the specification of the interface.
Fair enough. That's planning to succeed, which is always reassuring.

Halifax wrote:
rogerborg wrote:* What is it intended to achieve?
I highly modular system, that can be extended in the future, and gives the user more control over how their memory is managed. They don't have to recompile the engine to get rid of DX support, and reduce the memory used, they just have to not load the plugin.
If there's no references to any public symbols in a given module, then the linker will drop it anyway (unless you tell it not to).

All that said, it looks like a reasonable implementation.
Please upload candidate patches to the tracker.
Need help now? IRC to #irrlicht on irc.freenode.net
How To Ask Questions The Smart Way
Trefall
Posts: 45
Joined: Tue Dec 05, 2006 8:49 pm

Post by Trefall »

Halifax wrote: @Trefall: Exactly, that is another great reason for a plugin architecture I believe. You don't have to spend needless time integrating third-party software that the user may not even use. And same here, I'm 100% on this framework because I have found no existing solutions that fit my needs. But I have never heard of OSG. I guess I will have to check it out, especially if it is cross-platform.
OSG is the Open Scene Graph, which is, if I'm not mistaken, the leading rendering engine / scenegraph in the industrial visualization arena. It's designed much more towards OpenGL Performar and the old school scenegraphs though than Irrlicht and Ogre3D, but it's a very feature-rich and stable scenegraph for sure! I must admit I prefer the scenegraph system of Irrlicht and Ogre3D over the OSG one though. It gets a little messy for my taste.

To comment on the part of dividing up the different parts of the engine in different modules, it also makes sense to do so with collaborative work in mind. One programmer can mess with the renderer while the other guy rewrites the entity system. Of course, you could always branch using source control and mess around like that too, which probably is better anyway... but I was still trying to make a point here about something :P Flavien Brebion does it for his Infinity charged engine, that alone is reason enough to do it for me :P

From my experience, there's one thing I'd make sure was in place though, and that is post-build copying of all dlls into the dependency folders, so that the dependencies are up to date at all times from the location you're running the framework. Due to some CMAKEing and seperating different module types in different solutions all together here at work, I've had some bad experience with this gone wrong. Using old dlls or using a release dll when you should be using a debug dll, etc can quickly get messy...
Dorth wrote: Also, if you make a modular engine, why not have the scripting engine be modular? Give it the hook you'd normally give your scripting engine and there you go
But of course you'd want to be able to have script languages pluggable as well. The way I balance my script language integration with the C++ side of the framework, you should be able to even mix different script languages. Of course, I have no idea why you would want to do that...
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

I'm too tired to read right now. But if you do a plugin framework it's worth taking a look at Dr. Dobbs (www.drdobbs.com) and searching there for "Building Your Own Plugin Framework". It's a very nice series about building platform independent c++ plugin framework.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

@Trefall: Yeah, definitely. I have a post-build option, and it even puts the DLLs in system32 for me.

@CuteAlien: Hey thanks for that article. I just scanned it real quick (because I don't have time now), and it looked pretty good. Once I get home I will definitely have a read through it.

Also, there's another thing I like about the plugin architecture. Say someone releases a game, but they only include the ability for you to use the OpenGL render system and not D3D9. If you had a D3D9 render system compiled, then you could just rename it to the name of the OpenGL render system, and use that. (It may be a slight hack, but I consider it a benefit.)
TheQuestion = 2B || !2B
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post by sudi »

Halifax wrote: Also, there's another thing I like about the plugin architecture. Say someone releases a game, but they only include the ability for you to use the OpenGL render system and not D3D9. If you had a D3D9 render system compiled, then you could just rename it to the name of the OpenGL render system, and use that. (It may be a slight hack, but I consider it a benefit.)
well thats stupid.....bc if he uses opengl together with glsl then the shaders and maybe even the whole game won't work....and why in the world would u want to use d3d instead of opengl when the game isdeveloped with opengl....really only a programmer would do that not the average gamer..
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Trefall
Posts: 45
Joined: Tue Dec 05, 2006 8:49 pm

Post by Trefall »

But if you turned it around, and said that the game was built with only D3D9 available, but you're on linux and you're a programmer, and this game is so awesome that you have to play it... then maybe it would be cool to be able to just replace the D3D9 plugin with your own compiler OpenGL plugin ;) Of course, that wouldn't support shaders, so if you want this benefit, you'd need to build some kind of shader interpreter interface that could plug in shader syntax as well, so that you could swap the compiled hlsl shaders with your own glsl shaders... this is quickly starting to become a little over exagurated though imo. For me, the plugin architecture is to benefit the developer with flexibility and not the end user of the game the developer created.
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

Yeah, you can read into the example if you want, but would a 2D engine really be using shaders. Once again, it's possible to read into that, but whatever. A counter statement, such as Trefall's, could be formulated, but then it's just caviling over a simple example. And as Trefall said, it's possible that they won't even be using GLSL or HLSL.

At any rate, the benefits of a plugin system outweigh other options in my mind. This topic wasn't created with the idea of discussing the benefits, but it's fine. I just wanted feedback on whether my system would work, and was sensible, and I received that, so it's cool.
TheQuestion = 2B || !2B
Post Reply