Leviathan  0.8.0.0
Leviathan game engine
Leviathan::GameModuleLoader Class Reference

Manages loading GameModule objects to make sure that each is loaded only once. More...

#include <GameModuleLoader.h>

+ Inheritance diagram for Leviathan::GameModuleLoader:

Public Member Functions

DLLEXPORT GameModuleLoader ()
 
DLLEXPORT ~GameModuleLoader ()
 
DLLEXPORT void Init ()
 Finds the names of all modules and which files they are in. This is safe to call again if changes to module files are detected. More...
 
DLLEXPORT GameModule::pointer Load (const std::string &modulename, const char *requiredby)
 Returns a module by name. More...
 
- Public Member Functions inherited from Leviathan::ThreadSafeGeneric< MutexType >
DLLEXPORT ThreadSafeGeneric ()
 
DLLEXPORT ~ThreadSafeGeneric ()
 
FORCE_INLINE void VerifyLock (RecursiveLock &guard) const
 
FORCE_INLINE void VerifyLock (Lock &lockit) const
 

Protected Member Functions

void GameModuleReportDestruction (GameModule &module)
 Used by GameModule to report that it is going to be deleted. More...
 

Additional Inherited Members

- Public Types inherited from Leviathan::ThreadSafeGeneric< MutexType >
using LockT = typename LockTypeResolver< MutexType >::LType
 
- Protected Attributes inherited from Leviathan::ThreadSafeGeneric< MutexType >
MutexType ObjectsLock
 

Detailed Description

Manages loading GameModule objects to make sure that each is loaded only once.

Note
This is ThreadSafeRecursive to allow the loaded modules to load their required modules without deadlocking
Todo:
Module unloading needs some trick

Definition at line 16 of file GameModuleLoader.h.

Constructor & Destructor Documentation

◆ GameModuleLoader()

DLLEXPORT GameModuleLoader::GameModuleLoader ( )

Definition at line 12 of file GameModuleLoader.cpp.

12 {}

◆ ~GameModuleLoader()

DLLEXPORT GameModuleLoader::~GameModuleLoader ( )

Definition at line 14 of file GameModuleLoader.cpp.

15 {
16  // We need to be careful about the delete order as the module will unregister from us
17  for(auto& [key, value] : LoadedModules) {
18 
19  UNUSED(key);
20 
21  if(value == nullptr)
22  continue;
23 
24  // But as we don't keep a reference any still alive modules have outside references
25  // This check is quaranteed to be true as the object is alive if it isn't null
26  if(value->GetRefCount() > 0) {
27 
28  LOG_ERROR("GameModuleLoader: module \"" + value->GetName() +
29  "\" still has outside references. It won't be unloaded!");
30  }
31  }
32 
33  // This isn't really needed
34  LoadedModules.clear();
35 }
#define LOG_ERROR(x)
Definition: Define.h:94
#define UNUSED(x)
Definition: Define.h:183

Member Function Documentation

◆ GameModuleReportDestruction()

void GameModuleLoader::GameModuleReportDestruction ( GameModule module)
protected

Used by GameModule to report that it is going to be deleted.

Definition at line 154 of file GameModuleLoader.cpp.

155 {
156  GUARD_LOCK();
157 
158  const auto iter = LoadedModules.find(module.GetName());
159 
160  if(iter == LoadedModules.end()) {
161 
162  LOG_WARNING(
163  "GameModuleLoader: unknown module reported destruction: " + module.GetName());
164  return;
165  }
166 
167  if(iter->second != &module) {
168 
169  LOG_ERROR("GameModuleLoader: module with mismatching name and address reported "
170  "destruction: " +
171  module.GetName() + ". Is there a module with duplicate name?");
172  return;
173  }
174 
175  iter->second = nullptr;
176 }
#define LOG_ERROR(x)
Definition: Define.h:94
#define LOG_WARNING(x)
Definition: Define.h:93
DLLEXPORT const auto & GetName() const
Definition: GameModule.h:72
#define GUARD_LOCK()
Definition: ThreadSafe.h:111

◆ Init()

DLLEXPORT void GameModuleLoader::Init ( )

Finds the names of all modules and which files they are in. This is safe to call again if changes to module files are detected.

Definition at line 37 of file GameModuleLoader.cpp.

38 {
39  GUARD_LOCK();
40 
41  const auto modules =
42  FileSystem::Get()->FindAllMatchingFiles(FILEGROUP_SCRIPT, ".*", "levgm", false);
43 
44  LOG_INFO("GameModuleLoader: detected following module files: ");
45 
46  for(const auto& file : modules) {
47 
48  std::string error;
49  std::string moduleName;
50 
51  if(!_LoadInfoFromModuleFile(file->RelativePath, moduleName, error)) {
52  LOG_INFO("\t" + file->RelativePath + " which is invalid: " + error);
53  continue;
54  } else {
55  LOG_INFO(
56  "\t" + file->RelativePath + " which contains module \"" + moduleName + "\"");
57  }
58 
59  if(ModuleNameToPath.find(moduleName) != ModuleNameToPath.end()) {
60 
61  LOG_ERROR(
62  "GameModuleLoader: detected duplicate module name \"" + moduleName +
63  "\" at path: " + file->RelativePath +
64  " earlier version was loaded from path: " + ModuleNameToPath[moduleName]);
65  continue;
66  }
67 
68  ModuleNameToPath[moduleName] = file->RelativePath;
69  }
70 }
DLLEXPORT std::vector< std::shared_ptr< FileDefinitionType > > FindAllMatchingFiles(FILEGROUP which, const std::string &regexname, const std::string &extensions, bool searchall=true)
Returns all matching files.
Definition: FileSystem.cpp:737
#define LOG_INFO(x)
Definition: Define.h:92
#define LOG_ERROR(x)
Definition: Define.h:94
static DLLEXPORT FileSystem * Get()
Definition: FileSystem.cpp:74
#define GUARD_LOCK()
Definition: ThreadSafe.h:111

◆ Load()

DLLEXPORT GameModule::pointer GameModuleLoader::Load ( const std::string &  modulename,
const char *  requiredby 
)

Returns a module by name.

This returns a loaded module or loads a module with the given name (or file name)

Parameters
requiredbyIs used for debugging the loading hierarchies of modules. You should use an unique string here. This is taken as a const char to avoid constructing unused string objects
Exceptions
NotFoundif not found
Todo:
Allow loading by relative path (right now must just have the exact module name)

Definition at line 72 of file GameModuleLoader.cpp.

74 {
75  GUARD_LOCK();
76 
77  const auto found = LoadedModules.find(moduleorfilename);
78 
79  if(found != LoadedModules.end()) {
80 
81  // Just return module if it is still loaded
82  // auto locked = found->second.lock();
83  auto locked = found->second;
84 
85  if(locked) {
86  // But detect circular dependencies
87  if(locked->IsInitializing()) {
88 
89  LOG_ERROR("GameModuleLoader: Load: circular dependency detected, module: " +
90  moduleorfilename +
91  " is being loaded by: " + std::string(requiredby) +
92  ", but it is still currently initializing, returning null");
93  throw NotFound("circular loading detected");
94  }
95 
96  return GameModule::pointer(locked);
97  }
98 
99  const auto pathIter = ModuleNameToPath.find(moduleorfilename);
100 
101  if(pathIter == ModuleNameToPath.end()) {
102 
103  LOG_WARNING("GameModuleLoader: no path found for now unloaded module: " +
104  moduleorfilename);
105  throw NotFound("unknown path for unloaded module: " + moduleorfilename);
106  }
107 
108  // Reload module
109  LOG_INFO("GameModuleLoader: reloading unloaded module");
110 
111  try {
112  return _LoadModuleFromFile(ModuleNameToPath[moduleorfilename], requiredby);
113  } catch(const NotFound& e) {
114 
115  throw NotFound("module file no longer exists: " + moduleorfilename +
116  " from path: " + pathIter->second +
117  ", inner exception: " + e.what());
118  }
119  }
120 
121  // Load it //
122  const auto pathIter = ModuleNameToPath.find(moduleorfilename);
123 
124  if(pathIter == ModuleNameToPath.end()) {
125 
126  // Searching code from GameModule
127  // // Find the actual file //
128  // file =
129  // FileSystem::Get()->SearchForFile(FILEGROUP_SCRIPT, modulename, extension,
130  // false);
131 
132  // if(file.size() == 0) {
133 
134  // // One more search attempt //
135  // file = FileSystem::Get()->SearchForFile(FILEGROUP_SCRIPT,
136  // StringOperations::RemoveExtension(modulename), extension, false);
137  // }
138 
139 
140  LOG_ERROR("GameModuleLoader: module with name doesn't exist: " + moduleorfilename);
141  throw NotFound(
142  "no module found with name (hint: remove extension): " + moduleorfilename);
143  }
144 
145  try {
146  return _LoadModuleFromFile(ModuleNameToPath[moduleorfilename], requiredby);
147  } catch(const NotFound& e) {
148 
149  throw NotFound("module failed initial loading: " + moduleorfilename +
150  " from path: " + pathIter->second + ", inner exception: " + e.what());
151  }
152 }
#define LOG_INFO(x)
Definition: Define.h:92
#define LOG_ERROR(x)
Definition: Define.h:94
#define LOG_WARNING(x)
Definition: Define.h:93
DLLEXPORT const char * what() const noexcept override
Definition: Exceptions.cpp:29
#define GUARD_LOCK()
Definition: ThreadSafe.h:111

The documentation for this class was generated from the following files: