Plugin System¶
Gsage Engine supports plugins, which can be installed at the runtime. Each plugin can be wrapped into dynamically linked library or shared library (.so/.dynlib/.dll)
Plugin loader is borrowed from the Ogre project DynLib.h
.
All plugins installed into the system should have unique id.
Gsage::GsageFacade::loadPlugin()
can be used to install plugin from a shared library.Gsage::GsageFacade::installPlugin()
can be called with instantiated plugin object.Gsage::GsageFacade::uninstallPlugin()
removes installed plugin.Gsage::GsageFacade::unloadPlugin()
unloads shared library.
Writing a Plugin¶
Each plugin should implement IPlugin
interface.
Abstract Methods¶
Gsage::IPlugin::getName()
- this method should return unique string id of the plugin.Gsage::IPlugin::installImpl()
- should contain plugin initialization logic.Gsage::IPlugin::uninstallImpl()
- should contain plugin destruction logic.
installImpl
can register UI/Window manager factories, add new SystemFactories or add a system to the Engine.
uninstallImpl
should properly uninstall plugin from the facade: remove the system, unregister lua bindings or unregister UI/Window manager.
Important
Though it is possible to define bindings in the installImpl
method, there is another method for this: Gsage::IPlugin::setupLuaBindings()
.
Bindings may work properly if defined in installImpl
, but if Lua state will be recreated by the LuaInterface
, bindings will be lost.
While implementing a plugin, you should also add couple extern "C"
methods, which will be called from the GsageFacade
after plugin dynamic library was loaded:
dllStartPlugin
.dllStopPlugin
.
Example:
// from OgrePlugin.h
...
#if GSAGE_PLATFORM == GSAGE_WIN32
#ifdef PLUGIN_EXPORT
#define PluginExport __declspec (dllexport)
#else
#define PluginExport __declspec (dllimport)
#endif
#else
#define PluginExport
#endif
...
// from OgrePlugin.cpp
...
bool OgrePlugin::installImpl()
{
mEngine->addSystem<OgreRenderSystem>();
mEngine->addSystem<RecastMovementSystem>();
return true;
}
void OgrePlugin::uninstallImpl()
{
mEngine->removeSystem("render");
mEngine->removeSystem("movement");
}
OgrePlugin* ogrePlugin = NULL;
extern "C" bool PluginExport dllStartPlugin(GsageFacade* facade)
{
if(ogrePlugin != NULL)
{
return false;
}
ogrePlugin = new OgrePlugin();
return facade->installPlugin(ogrePlugin);
}
extern "C" bool PluginExport dllStopPlugin(GsageFacade* facade)
{
if(ogrePlugin == NULL)
return true;
bool res = facade->uninstallPlugin(ogrePlugin);
if(!res)
return false;
delete ogrePlugin;
ogrePlugin = NULL;
return true;
}
...
Set Up Lua Bindings¶
Gsage::IPlugin::setupLuaBindings()
- should contain all Lua bindings.
This method will be called again if lua_State
was recreated.
Example:
...
void OgrePlugin::setupLuaBindings() {
if (mLuaInterface && mLuaInterface->getState())
{
sol::state_view lua = *mLuaInterface->getSolState();
// Ogre Wrappers
lua.new_usertype<OgreObject>("OgreObject",
"type", sol::property(&OgreObject::getType)
);
...
lua.new_usertype<Ogre::Quaternion>("Quaternion",
sol::constructors<sol::types<const Ogre::Real&, const Ogre::Real&, const Ogre::Real&, const Ogre::Real&>, sol::types<const Ogre::Radian&, const Ogre::Vector3&>>(),
"w", &Ogre::Quaternion::w,
"x", &Ogre::Quaternion::x,
"y", &Ogre::Quaternion::y,
"z", &Ogre::Quaternion::z,
sol::meta_function::multiplication, (Ogre::Quaternion(Ogre::Quaternion::*)(const Ogre::Quaternion&)const) &Ogre::Quaternion::operator*
);
lua.new_usertype<Ogre::Radian>("Radian",
sol::constructors<sol::types<float>>()
);
lua.new_usertype<OgreSelectEvent>("OgreSelectEvent",
sol::base_classes, sol::bases<Event, SelectEvent>(),
"intersection", sol::property(&OgreSelectEvent::getIntersection),
"cast", cast<const Event&, const OgreSelectEvent&>
);
lua["Engine"]["render"] = &Engine::getSystem<OgreRenderSystem>;
lua["Engine"]["movement"] = &Engine::getSystem<RecastMovementSystem>;
lua["Entity"]["render"] = &Entity::getComponent<RenderComponent>;
lua["Entity"]["movement"] = &Entity::getComponent<MovementComponent>;
...
}
}
...