Musings on Plugins

Published January 10, 2006
Advertisement
I've solved a horrible bug in GMGX thanks to Fluid Studios (again). I was building collision masks and randomly writing to bits of memory I didn't own - it was only when more started happening did we get random crashes.

The SDL renderer seems to be working very well, thanks to Joel Longanecker's SDL tutorials. I like dealing with SDL actually, I've never used it before except as a launching pad for OpenGL apps. I'm writing to the screen buffer and doing all the stuff I used to have to think about in 'the old days' of game coding. It's nice to see I'm not too rusty with it all! I'm concerned about the whole 'clear screen/redraw' approach I'm taking right now (thanks, OpenGL!) and the affect it might have on framerate later on.

And to respond to yesterday's comments:-

Quote:Original post by rick_appleton
Theoretically, this setup would allow me to compile for each and every platform with the same makefile (assuming it builds the to-build list from directory contents), but only changing a single, or possibly two defines.


I took a leaf out of your book and removed all the platform/API specific cpp files from my build process and instead included them with the help of a few defines. I was already defining my platform, so it wasn't a major change. It seems to be working nicely - thanks for the tip - it saves me building many different makefiles now :)

The following is a response to Jack's idea mentioned in my last entry...

An interesting approach for plugins... In theory, it's possible provided you supply a global ISystem class for each system to register to.

For example:

class ISystem;class IPlugin{public:    explicit IPlugin( ISystem *a_system )    {        // hash name        setHashedName( GetName() );    }    virtual ~IPlugin() { }    virtual const char *GetName() const = 0;    unsigned int GetSystemHandle() const;    void SetSystemHandle(unsigned int a_systemHandle);    unsigned int GetHashedName() const;protected:    ISystem     *m_system;    unsigned int m_hashedName;    unsigned int m_systemHandle;    void setHashedName( unsigned int a_hash ) { //generate a hash of 'name' and store; }};class ISystem{public:    virtual ~ISystem() { }    virtual IPlugin *LoadPlugin( const char *a_name ) = 0;    virtual void ReleasePlugin( IPlugin *a_plugin ) = 0;    virtual IPlugin *GetPlugin( const char *a_name ) = 0;};class System : public ISystem{public:    virtual ~System() { }    protected:    void registerPlugin( IPlugin *a_plugin )    {        // store in map for later retreival by name    }    // map of plugins, key is a hash of plugin name    std::map< int, IPlugin *>   m_plugins;};class Win32System : public System{public:    IPlugin *LoadPlugin( const char *a_name )    {        // Load module (a_name + .dll), look for 'CreatePlugin' function in DLL - store it in *p        IPlugin *plg = (*p)( this );        plg->SetSystemHandle( // hmodule handle );        registerPlugin( plg );        return plg;    };    void ReleasePlugin( IPlugin *a_plugin )    {        // get system handle from IPlugin, release it    }};



Or something along those lines. To use the system, you'd have to implement the plugin interface in your DLL:-

class HelloPlugin : public IPlugin{public:    explicit HelloPlugin( ISystem *a_system );    virtual ~HelloPlugin() { }        const char *GetName() const { return "hello"; }};// export__declspec(__dllexport) IPlugin *CreatePlugin( ISystem *a_system )  { return new HelloPlugin( a_system ); }


Then to consume the plugin you'd do something like:

int main(){#if defined( __WIN__ )    Win32System sys;#elif defined( __LINUX__ )    LinuxSystem sys;#else    #error "Unsupported platform"#end    IPlugin *plg = sys.LoadPlugin( "hello" );    // If you know what type of plugin to expect (eg: graphics, sound, etc)    // you can probably cast    HelloPlugin *hello = 0;    if ( ::stricmp( "hello", plg.GetName() ) == 0 )    {        hello = reinterpret_cast< HelloPlugin* >(plg);        // do stuff with hello...    }};


If you don't like the idea of casting on an assumption of name, you could probably have a set of standard "OnLoaded", "OnExecute", "OnReleased" type virtual event handlers to allow a certain amount of genericity (is that a word?). An extension of this would be to define a set of plugin 'types' in an enum - each of these types would have an associated interface:

Eg:

enum {  PLGT_UNKNOWN = 0,  PLGT_UTILITY,  PLGT_GRAPHICS,  PLGT_SOUND,  PLGT_SCRIPTING,  // etc};// Then the baseclasses:class IPlugin;class IUtilityPlugin : public IPlugin;          // Contains a generic utility interfaceclass IGraphicsPlugin : public IPlugin;         // Contains a generic graphics interfaceclass ISoundPlugin : public IPlugin;            // A generic sound interfaceclass IScriptingPlugin : public IPlugin;        // A generic script binding interface


The plugin would export its own class/typeid which would then let you (more) safely assume the baseclass for a plugin and cast to that.

Eg:

IPlugin *plg = sys.LoadPLugin( "glRenderer" );if (plg.GetType() != PLGT_GRAPHICS)    // Error, we were expecting this to be a graphics pluginIGraphicsPlugin *gfx = reinterpret_cast(plg);// then later on:-gfx->ClearScreen();gfx->BeginRender();// etc


Of course, this would require the engine and the plugins to always be in sync, but would allow for them to know 'something' about each other for inter-plugin/system communication.
Previous Entry Platform compatability
Next Entry GMScript 1.24c
0 likes 2 comments

Comments

rick_appleton
Glad you liked it [smile]

I got it from the Loki libraries I think.
January 10, 2006 06:08 AM
jollyjeffers
Quote:thanks to Fluid Studios (again)

I'm not sure what I'd do without that tool [grin]

Okay, I suppose I have the VS memory leak tools - but somehow they never seem to work as well.

Quote:The following is a response to Jack's idea mentioned in my last entry

What you described pretty much covers everything I intended - except yours makes sense!

I'm gonna have to try something like that one day..

Jack
January 10, 2006 06:15 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement