NLS Engine  v0.1
The Next Logical Step in game engine design.
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines
ModuleManager.cpp
Go to the documentation of this file.
00001 
00012 #include "ModuleManager.h"
00013 
00014 // Standard Includes
00015 
00016 // Library Includes
00017 #include <boost/function.hpp>
00018 #include <boost/any.hpp>
00019 
00020 // Local Includes
00021 #include "../sharedbase/ModuleInterface.h"
00022 #include "../sharedbase/EventLogger.h"
00023 #include "../sharedbase/EntityList.h"
00024 #include "../sharedbase/Envelope.h"
00025 #include "../sharedbase/OSInterface.h"
00026 #include "EntityFactory.h"
00027 
00028 // Static class member initialization
00029 
00030 // Class methods in the order they are defined within the class header
00031 
00032 
00033 ModuleManager::ModuleManager( PropertyMap* gprops, MessageRouter* msgrouter, EntityList* emgr) : gprops(gprops), msgrouter(msgrouter), emgr(emgr) {
00034 
00035   std::shared_ptr<Subscriber> screate(new Subscriber(boost::bind(&ModuleManager::CreateEntity, this, _1)));
00036   this->msgrouter->Subscribe(CORE_MESSAGE::CREATE, screate);
00037   std::shared_ptr<Subscriber> sload(new Subscriber(boost::bind(&ModuleManager::LoadFromMessage, this, _1)));
00038   this->msgrouter->Subscribe(CORE_MESSAGE::LOADLIBRARY, sload);
00039   std::shared_ptr<Subscriber> suload(new Subscriber(boost::bind(&ModuleManager::UnloadFromMessage, this, _1)));
00040   this->msgrouter->Subscribe(1234, suload);
00041 }
00042 
00043 void ModuleManager::Load(std::string name) {
00044   char buf[256];
00045   
00046   if (this->libraries.find(name) == this->libraries.end()) {
00047     std::string libFileName = name;
00048     
00049     // Load the DLL ONLY if the libary has not already been loaded in the past.
00050 #ifdef _WIN32
00051     libFileName += ".dll";
00052     HMODULE libdll = LoadLibrary(libFileName.c_str());
00053 #else
00054     libFileName += ".so";
00055     void * libdll = dlopen(libFileName.c_str(), RTLD_LAZY);
00056 #endif
00057     if (libdll != NULL) {
00058       this->libraries[name] = libdll;
00059       
00060       LOG(LOG_PRIORITY::FLOW, "Loaded library '" + name + "' successfully.");
00061     }
00062     else {
00063 #ifdef _WIN32
00064       DWORD errcode = GetLastError();
00065       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errcode, 0, buf, 256, NULL);
00066 #else
00067       buf = "Error loading library: " + name;
00068 #endif
00069       LOG(LOG_PRIORITY::RESTART, buf);
00070       
00071       LOG(LOG_PRIORITY::RESTART, "Module loading aborted due to error.");
00072       return; // *NOTE: This early return may be considered bad style, but was added to maintain modularity between the DLL loader code and the module facotry loading code.
00073     }
00074   }
00075   else {
00076     LOG(LOG_PRIORITY::CONFIG, "Library '" + name + "' already loaded, not reloading.");
00077   }
00078 
00079   {
00080     ModuleInstanceFactory fact;
00081 #ifdef _WIN32
00082     fact = (ModuleInstanceFactory)GetProcAddress(this->libraries[name], "ModuleFactory");
00083 #else
00084     fact = (ModuleInstanceFactory)dlsym(this->libraries[name], "ModuleFactory");
00085 #endif
00086 
00087     if (fact != nullptr) {
00088       LOG(LOG_PRIORITY::FLOW, "Module factory acquired successfully.");
00089       
00090       OSInterfaceSPTR os(OSInterface::GetOS());
00091       ModuleInterface* module = fact(this->gprops, this->msgrouter, this->emgr, EventLogger::GetEventLogger(), os);
00092       this->modules[name] = module;
00093     }
00094     else {
00095 #ifdef _WIN32
00096       DWORD errcode = GetLastError();
00097       FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errcode, 0, buf, 256, NULL);
00098 #else
00099       buf = "Error loading module factory";
00100 #endif
00101       LOG(LOG_PRIORITY::RESTART, buf);
00102       
00103       LOG(LOG_PRIORITY::RESTART, "Module loading aborted due to error.");
00104       
00105       Unload(name);
00106       
00107       return;
00108     }
00109   }
00110 }
00111 
00112 void ModuleManager::Unload( std::string name /*= ""*/ ) {
00113   if (this->libraries.find(name) != this->libraries.end()) { // Lib WAS found
00114     if (this->modules.find(name) != this->modules.end()) { // Mod WAS found
00115       //Shutdown(name);
00116     }
00117     
00118 #ifdef _WIN32
00119     if (FreeLibrary(this->libraries[name]) != 0) {
00120 #else
00121     if (dlclose(this->libraries[name])) {
00122 #endif
00123       this->libraries.erase(name);
00124     }
00125     else {
00126       LOG(LOG_PRIORITY::RESTART, "Unable to unload the library '" + name + "'!");
00127     }
00128   }
00129 }
00130 
00131 void ModuleManager::Update( double dt /*= 0.0f*/ ) {
00132   for (auto it = this->modules.begin(); it != this->modules.end(); ++it) {
00133     (*it).second->Update(dt);
00134   }
00135 }
00136 
00137 void ModuleManager::CreateEntity( EnvelopeSPTR e ) {
00138   EntitySPTR ent(boost::any_cast<EntitySPTR>(e->GetData(1)));
00139   std::map< std::string, std::map<std::string, boost::any> > comps = boost::any_cast<std::map< std::string, std::map<std::string, boost::any> > >(e->GetData(2));
00140     
00141   for (auto itr = this->modules.begin(); itr != this->modules.end(); ++itr) {
00142     for (auto itr2 = comps.begin(); itr2 != comps.end(); ++itr2) {
00143       (*itr).second->CreateComponent((*itr2).first, (*itr2).second, ent);
00144     }
00145   }
00146 }
00147 
00148 void ModuleManager::LoadFromMessage( EnvelopeSPTR e ) {
00149   unsigned int count = boost::any_cast<unsigned int>(e->GetData(0));
00150   for (unsigned int i = 0; i < count; ++i) {
00151     this->Load(boost::any_cast<std::string>(e->GetData(i+1)));
00152   }
00153 }
00154 
00155 void ModuleManager::UnloadFromMessage( EnvelopeSPTR e  ) {
00156   unsigned int count = boost::any_cast<unsigned int>(e->GetData(0));
00157   for (unsigned int i = 0; i < count; ++i) {
00158     this->Unload(boost::any_cast<std::string>(e->GetData(i+1)));
00159   }
00160 }
00161 void ModuleManager::Shutdown() {
00162   for (auto itr = this->modules.begin(); itr != this->modules.end(); ++itr) {
00163     LOG(LOG_PRIORITY::INFO, "Deleting module '" + itr->first + "'!");
00164     delete itr->second;
00165   }
00166 
00167   for (auto itr = this->libraries.begin(); itr != this->libraries.end(); ++itr) {
00168     LOG(LOG_PRIORITY::INFO, "Unloading library '" + itr->first + "'!");
00169 #ifdef _WIN32
00170     if (FreeLibrary(this->libraries[itr->first]) != 0) {
00171 #else
00172     if (dlclose(this->libraries[name])) {
00173 #endif
00174     }
00175   }
00176 }