Skip to content

Instantly share code, notes, and snippets.

@MrSmith33
Created October 22, 2014 21:08
Show Gist options
  • Save MrSmith33/4a21a1e7e46fa6c0ac22 to your computer and use it in GitHub Desktop.
Save MrSmith33/4a21a1e7e46fa6c0ac22 to your computer and use it in GitHub Desktop.
Modular
module modular.modules.eventdispatchermodule;
import modular;
// Basic event
abstract class Event
{
bool continuePropagation = true;
}
void subscribeToEvent(E : Event)(EventDispatcherModule dispatcher, void delegate(E event) handler)
{
dispatcher.subscribe(typeid(E), cast(EventHandler)handler);
}
void postEvent(E : Event)(EventDispatcherModule dispatcher, E event)
{
dispatcher.post(typeid(E), cast(Event)event);
}
private alias EventHandler = void delegate(Event event);
/// Event
class EventDispatcherModule : IModule
{
override string name() @property { return "EventDispatcherModule"; }
override string semver() @property { return "0.1.0"; }
override void load() { }
override void init(IModuleManager moduleman) {}
void subscribe(TypeInfo evtype, void delegate(Event event) handler)
{
_eventHandlers[evtype] ~= handler;
}
void post(TypeInfo evtype, Event event)
{
auto handlers = evtype in _eventHandlers;
if (!handlers) return;
foreach(handler; *handlers)
{
handler(event);
if (!event.continuePropagation) return;
}
}
private:
EventHandler[][TypeInfo] _eventHandlers;
}
module modular.imodule;
import modular;
/// Basic module interface.
interface IModule
{
// i.e. "Test Module"
string name() @property;
// valid semver version string. i.e. 0.1.0-rc.1
string semver() @property;
// load/create needed resources
void load();
// get references to other modules
void init(IModuleManager moduleman);
}
module modular.imodulemanager;
import modular;
interface IModuleManager
{
/// Returns reference to module instance if moduleName was registered.
IModule findModule(string moduleName);
}
M getModule(M)(IModuleManager modman, string moduleName = M.stringof)
{
import std.exception : enforce;
IModule mod = modman.findModule(moduleName);
M exactModule = cast(M)mod;
enforce(exactModule);
return exactModule;
}
module modular.modules.mainloopmodule;
import modular;
import modular.modules.eventdispatchermodule;
/// Updatable module interaface.
/// Look at MainLoopModule.registerUpdatableModule(IUpdatableModule)
interface IUpdatableModule
{
/// Will be called by MainLoopModule every frame
void update(double delta);
}
interface IMainLoopModule
{
void registerUpdatableModule(IUpdatableModule updatableModule);
bool isRunning() @property;
bool isRunning(bool newIsRunning) @property;
}
class GameStopEvent : Event
{
}
/// Module where the main loop is located
class MainLoopModule : IMainLoopModule, IModule
{
override string name() @property { return "MainLoopModule"; }
override string semver() @property { return "0.1.0"; }
override void load() {}
override void init(IModuleManager moduleman)
{
evdisp = moduleman.getModule!EventDispatcherModule();
}
private:
EventDispatcherModule evdisp;
IUpdatableModule[] updatableModules;
bool _isRunning;
public:
// There is an option to auto-register all modules found in IModuleManager
// if they can be cast to IUpdatableModule
override void registerUpdatableModule(IUpdatableModule updatableModule)
{
updatableModules ~= updatableModule;
}
/// Main loop execution condition. Will run if true.
override bool isRunning() @property
{
return _isRunning;
}
/// ditto
override bool isRunning(bool newIsRunning) @property
{
return _isRunning = newIsRunning;
}
/// Simple main loop
void mainLoop()
{
import std.datetime : TickDuration, Clock, msecs, usecs;
import core.thread : Thread;
isRunning = true;
TickDuration lastTime = Clock.currAppTick;
TickDuration newTime = TickDuration.from!"seconds"(0);
while(isRunning)
{
newTime = Clock.currAppTick;
double delta = (newTime - lastTime).usecs / 1_000_000.0;
lastTime = newTime;
update(delta);
Thread.sleep(10.msecs);
}
// loop stop
// event example
evdisp.postEvent(new GameStopEvent);
}
private void update(double delta)
{
foreach(mod; updatableModules)
{
mod.update(delta);
}
}
}
module modular.modulemanager;
import modular;
/// Simple implementation of IModuleManager
// See GameModule for example usage
class ModuleManager : IModuleManager
{
IModule[string] modules;
void registerModule(IModule moduleInstance)
{
assert(moduleInstance);
modules[moduleInstance.name] = moduleInstance;
}
void loadModules()
{
foreach(IModule m; modules)
{
m.load();
writefln("Loaded module %s %s", m.name, m.semver);
}
}
void initModules()
{
foreach(IModule m; modules)
{
m.init(this);
writefln("Inited module %s %s", m.name, m.semver);
}
}
override IModule findModule(string moduleName)
{
return modules[moduleName];
}
}
module modular.modules.networkmodule;
import modular;
import modular.modules.mainloopmodule;
class NetworkModule : IModule, IUpdatableModule
{
override string name() @property { return "NetworkModule"; }
override string semver() @property { return "0.1.0"; }
override void load()
{
// load enet
registerPacket!PacketMapPacket();
}
override void init(IModuleManager moduleman)
{
mainmod = moduleman.getModule!MainLoopModule("MainLoopModule");
mainmod.registerUpdatableModule(this);
}
override void update(double delta)
{
// enet_host_service
}
//
void registerPacket(P)()
{
packets ~= typeid(P);
}
private:
MainLoopModule mainmod;
TypeInfo[] packets;
}
struct PacketMapPacket
{
string[] packets;
}
module sharedmodule;
import modular;
import modular.modules.mainloopmodule;
import modular.modules.eventdispatchermodule;
class SharedModule : IModule, IUpdatableModule
{
override string name() @property { return "SharedModule"; }
override string semver() @property { return "0.1.0"; }
override void load() {}
override void init(IModuleManager moduleman)
{
mainmod = moduleman.getModule!MainLoopModule();
IModule mainmodule = moduleman.findModule("MainLoopModule");
mainmod = cast(IMainLoopModule)mainmodule;
writefln("%s", mainmod is null);
mainmod.registerUpdatableModule(this);
evdisp = moduleman.getModule!EventDispatcherModule();
subscribeToEvent!GameStopEvent(evdisp, &onGameStop);
}
override void update(double delta)
{
counter++;
}
private:
IMainLoopModule mainmod;
EventDispatcherModule evdisp;
uint counter;
void onGameStop(GameStopEvent event)
{
writefln("Shared module onGameStop. Done updates %s", counter);
}
}
export extern(C) IModule getModuleInstance()
{
return new SharedModule;
}
module modular.sharedmoduleloader;
import modular;
IModule loadSharedModule(string file)
{
import std.c.windows.windows;
import core.runtime;
HMODULE handle;
FARPROC farproc;
handle = cast(HMODULE) Runtime.loadLibrary(file);
if (handle is null)
{
writeln("Error loading sharedmodule.dll");
return null;
}
farproc = GetProcAddress(handle, "getModuleInstance");
if (farproc is null)
{
writeln("Error loading symbol getModuleInstance()");
return null;
}
alias ModuleFactory = IModule function();
return (*cast(ModuleFactory)farproc)();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment