Leviathan  0.8.0.0
Leviathan game engine
Leviathan::GameModule Class Reference

Represents a scriptable part of a program. More...

#include <GameModule.h>

+ Inheritance diagram for Leviathan::GameModule:

Public Member Functions

DLLEXPORT ~GameModule ()
 
DLLEXPORT void ReleaseScript ()
 Releases the script. More...
 
DLLEXPORT auto GetScriptModule ()
 
template<typename ReturnT , class... Args>
ScriptRunResult< ReturnT > ExecuteOnModule (ScriptRunningSetup &setup, bool passself, Args &&... args)
 
DLLEXPORT std::string GetDescription (bool full)
 
DLLEXPORT const auto & GetName () const
 
DLLEXPORT const auto & GetExportFiles () const
 
DLLEXPORT bool IsInitializing () const
 Used to detect circular dependencies by GameModuleLoader. More...
 
 REFERENCE_COUNTED_PTR_TYPE (GameModule)
 
- Public Member Functions inherited from Leviathan::ReferenceCounted
 ReferenceCounted (const ReferenceCounted &other)=delete
 
ReferenceCountedoperator= (const ReferenceCounted &other)=delete
 
FORCE_INLINE void AddRef ()
 
FORCE_INLINE void Release ()
 removes a reference and deletes the object if reference count reaches zero More...
 
int32_t GetRefCount () const
 Returns the reference count. More...
 

Protected Member Functions

DLLEXPORT GameModule (const std::string &filepath, const std::string &ownername, GameModuleLoader *loadedthrough)
 
DLLEXPORT bool Init ()
 Makes the scripts usable. More...
 
virtual ScriptRunResult< int > _DoCallWithParams (ScriptRunningSetup &sargs, Event *event, GenericEvent *event2) override
 
- Protected Member Functions inherited from Leviathan::ReferenceCounted
DLLEXPORT ReferenceCounted ()
 
virtual DLLEXPORT ~ReferenceCounted ()
 

Additional Inherited Members

- Public Types inherited from Leviathan::ReferenceCounted
using basepointer = boost::intrusive_ptr< ReferenceCounted >
 
using refcountedpointer = boost::intrusive_ptr< ReferenceCounted >
 
- Static Public Member Functions inherited from Leviathan::ReferenceCounted
template<class ActualType >
static boost::intrusive_ptr< ActualType > WrapPtr (ActualType *ptr)
 Creates an intrusive_ptr from raw pointer. More...
 
template<class ActualType , class... Args>
static boost::intrusive_ptr< ActualType > MakeShared (Args &&... args)
 Constructs a new instance and wraps it. More...
 

Detailed Description

Represents a scriptable part of a program.

Note
Create instances through GameModuleLoader::Load

Definition at line 18 of file GameModule.h.

Constructor & Destructor Documentation

◆ GameModule()

DLLEXPORT GameModule::GameModule ( const std::string &  filepath,
const std::string &  ownername,
GameModuleLoader loadedthrough 
)
protected

Definition at line 13 of file GameModule.cpp.

14  :
15  EventableScriptObject(nullptr),
16  OwnerName(ownername), Loader(loadedthrough)
17 {
18  std::string file = filepath;
19 
20  if(!boost::filesystem::is_regular_file(file)) {
21 
22  // Couldn't find file //
23  throw InvalidArgument("File doesn't exist '" + filepath + "'");
24  }
25 
26  LoadedFromFile = file;
27 
28  // Load the file //
30 
31  if(!ofile) {
32 
33  throw InvalidArgument("File is invalid");
34  }
35 
36  // Process the objects //
37  if(ofile->GetTotalObjectCount() != 1) {
38 
39  throw InvalidArgument("File contains invalid number of objects, single GameModule "
40  "expected");
41  }
42 
43  // Get various data from the header //
44  ObjectFileProcessor::LoadValueFromNamedVars<std::string>(
45  ofile->GetVariables(), "Version", Name, "-1", Logger::Get(), "GameModule:");
46 
47  auto gmobject = ofile->GetObjectFromIndex(0);
48 
49  Name = gmobject->GetName();
50 
51  // Handle the single object //
52  ObjectFileList* properties = gmobject->GetListWithName("properties");
53  ObjectFileTextBlock* sources = gmobject->GetTextBlockWithName("sourcefiles");
54  ObjectFileTextBlock* exports = gmobject->GetTextBlockWithName("export");
55  ObjectFileTextBlock* imports = gmobject->GetTextBlockWithName("import");
56 
57  if(!properties || !sources) {
58 
59  throw InvalidArgument("File contains invalid GameModule, properties or "
60  "sourcefiles not found");
61  }
62 
63  // Copy data //
64  if(sources->GetLineCount() < 1) {
65 
66  throw InvalidArgument("At least one source file expected in sourcefiles (even if this "
67  "module only consists of public definitions)");
68  }
69 
70  const std::string moduleFilePath =
71  boost::filesystem::path(StringOperations::GetPath(LoadedFromFile)).generic_string();
72 
73  // Resolve all files to their actual paths //
74  for(size_t i = 0; i < sources->GetLineCount(); ++i) {
75 
76  // Skip empty lines to allow commenting out things //
77  if(sources->GetLine(i).empty())
78  continue;
79 
80  const std::string codeFile =
81  ScriptModule::ResolvePathToScriptFile(sources->GetLine(i), moduleFilePath);
82 
83  if(codeFile.empty()) {
84  throw InvalidArgument("GameModule(" + LoadedFromFile +
85  ") can't find "
86  "source file: " +
87  sources->GetLine(i));
88  } else {
89 
90  SourceFiles.push_back(codeFile);
91  }
92  }
93 
94  // Resolve export files
95  if(exports) {
96 
97  for(size_t i = 0; i < exports->GetLineCount(); ++i) {
98 
99  // Skip empty lines to allow commenting out things //
100  if(exports->GetLine(i).empty())
101  continue;
102 
103  const std::string codeFile =
104  ScriptModule::ResolvePathToScriptFile(exports->GetLine(i), moduleFilePath);
105 
106  if(codeFile.empty()) {
107  throw InvalidArgument("GameModule(" + LoadedFromFile +
108  ") can't find "
109  "exported file: " +
110  exports->GetLine(i));
111  } else {
112 
113  ExportFiles.push_back(codeFile);
114  }
115  }
116  }
117 
118  // Read properties //
119  if(auto* data = properties->GetVariables().GetValueDirectRaw("ExtraAccess");
120  data != nullptr) {
121 
122  std::string flags;
123  if(data->GetVariableCount() != 1 ||
124  !data->GetValue().ConvertAndAssingToVariable(flags)) {
125 
126  throw InvalidArgument(
127  "GameModule(" + LoadedFromFile +
128  ") has an invalid value for property 'ExtraAccess': not string");
129  }
130 
131  try {
132  ExtraAccess = ParseScriptAccess(flags);
133  } catch(const InvalidArgument& e) {
134  throw InvalidArgument(
135  "GameModule(" + LoadedFromFile +
136  ") has an invalid value for property 'ExtraAccess': " + e.what());
137  }
138  }
139 
140  // Import modules just need to be copied
141  if(imports) {
142 
143  for(size_t i = 0; i < imports->GetLineCount(); ++i) {
144  if(imports->GetLine(i).empty())
145  continue;
146 
147  ImportModules.push_back(imports->GetLine(i));
148  }
149  }
150 
151  LEVIATHAN_ASSERT(!SourceFiles.empty(), "GameModule: empty source files");
152 }
Interface for object file lists to implement.
Definition: ObjectFile.h:21
virtual DLLEXPORT size_t GetLineCount() const =0
Returns the number of text lines.
static const StringTypeN GetPath(const StringTypeN &filepath)
Returns the path part of a path+filename.
static DLLEXPORT std::unique_ptr< ObjectFile > ProcessObjectFile(const std::string &file, LErrorReporter *reporterror)
Reads an ObjectFile to an in-memory data structure.
Interface for object file text blocks to implement.
Definition: ObjectFile.h:71
virtual DLLEXPORT const std::string & GetLine(size_t index) const =0
Gets a line from index ExceptionInvalidArgument when the index is out of bounds. ...
DLLEXPORT const char * what() const noexcept override
Definition: Exceptions.cpp:29
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:92
static DLLEXPORT std::string ResolvePathToScriptFile(const std::string &inputfilename, const std::string &relativepath, bool checkworkdirrelative=true)
Finds a path to source file or returns an empty string.
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
virtual DLLEXPORT NamedVars & GetVariables()=0
Gets a reference to the underlying variables.
DLLEXPORT NamedVariableList * GetValueDirectRaw(const std::string &name) const
Definition: NamedVars.cpp:1096
DLLEXPORT AccessFlags ParseScriptAccess(std::string_view flagstring)
Parses a string for access flags.
Definition: AccessMask.cpp:7

◆ ~GameModule()

DLLEXPORT GameModule::~GameModule ( )

Definition at line 154 of file GameModule.cpp.

155 {
156  LoadedImportedModules.clear();
157 
158  ReleaseScript();
159 
160  UnRegisterAllEvents();
161 
162  Loader->GameModuleReportDestruction(*this);
163 
164  // // This would be a bit inconvenient with the new way modules are kept loaded
165  // if(Scripting) {
166 
167  // LOG_FATAL("GameModule: 'ReleaseScript' not called before destructor");
168  // }
169 }
void GameModuleReportDestruction(GameModule &module)
Used by GameModule to report that it is going to be deleted.
DLLEXPORT void ReleaseScript()
Releases the script.
Definition: GameModule.cpp:285

Member Function Documentation

◆ _DoCallWithParams()

ScriptRunResult< int > GameModule::_DoCallWithParams ( ScriptRunningSetup sargs,
Event event,
GenericEvent event2 
)
overrideprotectedvirtual

Definition at line 310 of file GameModule.cpp.

312 {
313  if(event)
314  return ScriptExecutor::Get()->RunScript<int>(
315  Scripting->GetModuleSafe(), sargs, this, event);
316  else
317  return ScriptExecutor::Get()->RunScript<int>(
318  Scripting->GetModuleSafe(), sargs, this, event2);
319 }
ScriptRunResult< ReturnT > RunScript(const std::shared_ptr< ScriptModule > &module, ScriptRunningSetup &parameters, Args &&... args)
Runs a function in a script.
static DLLEXPORT ScriptExecutor * Get()

◆ ExecuteOnModule()

template<typename ReturnT , class... Args>
ScriptRunResult<ReturnT> Leviathan::GameModule::ExecuteOnModule ( ScriptRunningSetup setup,
bool  passself,
Args &&...  args 
)
inline

Executes something on the module and returns the result. Adds the module as first parameter and existed is set to true if something was executed pasself If true this object is added as the first parameter

Definition at line 52 of file GameModule.h.

54  {
55  if(!Scripting)
56  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
57 
58  if(passself) {
59  return ScriptExecutor::Get()->RunScript<ReturnT>(
60  Scripting->GetModuleSafe(), setup, this, std::forward<Args>(args)...);
61  } else {
62  return ScriptExecutor::Get()->RunScript<ReturnT>(
63  Scripting->GetModuleSafe(), setup, std::forward<Args>(args)...);
64  }
65  }
ScriptRunResult< ReturnT > RunScript(const std::shared_ptr< ScriptModule > &module, ScriptRunningSetup &parameters, Args &&... args)
Runs a function in a script.
static DLLEXPORT ScriptExecutor * Get()

◆ GetDescription()

DLLEXPORT std::string GameModule::GetDescription ( bool  full)
Returns
A string describing this module

Definition at line 303 of file GameModule.cpp.

304 {
305  return "GameModule(" + Name + (full ? " v" + Version + ") " : ") ") +
306  " owned by: " + OwnerName +
307  (full ? ", loaded from file: " + LoadedFromFile + "." : ".");
308 }
Definition: lz4.c:260

◆ GetExportFiles()

DLLEXPORT const auto& Leviathan::GameModule::GetExportFiles ( ) const
inline
Returns
The list of export files from this module

Definition at line 78 of file GameModule.h.

79  {
80  return ExportFiles;
81  }

◆ GetName()

DLLEXPORT const auto& Leviathan::GameModule::GetName ( ) const
inline
Returns
The name of this module

Definition at line 72 of file GameModule.h.

73  {
74  return Name;
75  }

◆ GetScriptModule()

DLLEXPORT auto Leviathan::GameModule::GetScriptModule ( )
inline
Returns
The script module

Definition at line 41 of file GameModule.h.

42  {
43  return ScriptMain;
44  }

◆ Init()

DLLEXPORT bool GameModule::Init ( )
protected

Makes the scripts usable.

Definition at line 171 of file GameModule.cpp.

172 {
173  IsCurrentlyInitializing = true;
174 
175  // Resolve imports first
176  if(!ImportModules.empty()) {
177 
178  const auto desc = GetDescription(true);
179 
180  for(const auto& import : ImportModules) {
181 
182  // Load the dependency module. We give our full description to make debugging the
183  // chain easier
184  try {
185  auto imported = Loader->Load(import, desc.c_str());
186 
187  LoadedImportedModules.push_back(imported);
188  } catch(const NotFound& e) {
189 
190  LOG_ERROR("GameModule: Init: module \"" + import +
191  "\" could not be loaded by: " + desc + ", exception:");
192  e.PrintToLog();
193  return false;
194  }
195  }
196  }
197 
198  // Compile a new module //
199  ScriptModule* mod = NULL;
200 
201  LEVIATHAN_ASSERT(!Scripting, "GameModule may not already have Script instance created");
202 
203  Scripting =
204  std::shared_ptr<ScriptScript>(new ScriptScript(ScriptExecutor::Get()->CreateNewModule(
205  "GameModule(" + Name + ") ScriptModule", LoadedFromFile)));
206 
207  // Get the newly created module //
208  mod = Scripting->GetModule();
209 
210  for(const auto& file : SourceFiles) {
211  mod->AddScriptSegmentFromFile(file);
212  }
213 
214  // Also add imported files
215  for(const auto& import : LoadedImportedModules) {
216  const auto& fileList = import->GetExportFiles();
217 
218  if(fileList.empty()) {
219 
220  LOG_WARNING("GameModule: Init: imported module \"" + import->GetName() +
221  "\" doesn't specify any exports");
222  continue;
223  }
224 
225  for(const auto& file : import->GetExportFiles()) {
226  mod->AddScriptSegmentFromFile(file);
227  }
228  }
229 
230  // Set access flags //
231  if(ExtraAccess != 0)
232  mod->AddAccessRight(ExtraAccess);
233 
234  // Build the module (by creating a callback list) //
235  std::vector<std::shared_ptr<ValidListenerData>> containedlisteners;
236 
237  mod->GetListOfListeners(containedlisteners);
238 
239  if(mod->GetModule() == nullptr) {
240  // Fail to build //
241  Logger::Get()->Error("GameModule: Init: failed to build AngelScript module");
242  return false;
243  }
244 
245  RegisterStandardScriptEvents(containedlisteners);
246 
247  for(size_t i = 0; i < containedlisteners.size(); i++) {
248  // Bind generic event //
249  if(containedlisteners[i]->GenericTypeName &&
250  containedlisteners[i]->GenericTypeName->size() > 0) {
251 
252  // Registered in RegisterStandardScriptEvents
253  continue;
254  }
255 
256  // Skip global events
257  EVENT_TYPE etype = ResolveStringToType(*containedlisteners[i]->ListenerName);
258 
259  // Skip types that we handle ourselves //
260  if(etype == EVENT_TYPE_ERROR)
261  etype = GetCommonEventType(*containedlisteners[i]->ListenerName);
262 
263  if(etype != EVENT_TYPE_ERROR) {
264 
265  continue;
266  }
267 
268  Logger::Get()->Warning("GameModule: unknown event type " +
269  *containedlisteners[i]->ListenerName +
270  ", did you intent to use Generic type?");
271  }
272 
273  // Call init callbacks //
274 
275  // fire an event //
276  Event* initEvent = new Event(EVENT_TYPE_INIT, nullptr);
277  OnEvent(initEvent);
278  // Release our initial reference
279  initEvent->Release();
280 
281  IsCurrentlyInitializing = false;
282  return true;
283 }
DLLEXPORT asIScriptModule * GetModule(Lock &guard)
Builds the script if applicable.
Class that represents a statically defined event.
Definition: Event.h:138
DLLEXPORT GameModule::pointer Load(const std::string &modulename, const char *requiredby)
Returns a module by name.
#define LOG_ERROR(x)
Definition: Define.h:84
EVENT_TYPE
Engine events that are triggered at certain times.
Definition: Event.h:12
DLLEXPORT std::string GetDescription(bool full)
Definition: GameModule.cpp:303
#define LOG_WARNING(x)
Definition: Define.h:83
static DLLEXPORT ScriptExecutor * Get()
DLLEXPORT void Warning(const std::string &data) override
Definition: Logger.cpp:190
FORCE_INLINE void Release()
removes a reference and deletes the object if reference count reaches zero
#define LEVIATHAN_ASSERT(x, msg)
Definition: Define.h:92
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
DLLEXPORT void Error(const std::string &data) override
Definition: Logger.cpp:177
virtual DLLEXPORT void PrintToLog() const noexcept
Definition: Exceptions.cpp:35

◆ IsInitializing()

DLLEXPORT bool Leviathan::GameModule::IsInitializing ( ) const
inline

Used to detect circular dependencies by GameModuleLoader.

Definition at line 84 of file GameModule.h.

85  {
86  return IsCurrentlyInitializing;
87  }

◆ REFERENCE_COUNTED_PTR_TYPE()

Leviathan::GameModule::REFERENCE_COUNTED_PTR_TYPE ( GameModule  )

◆ ReleaseScript()

DLLEXPORT void GameModule::ReleaseScript ( )

Releases the script.

Use to release script before releasing any other objects

Note
GameModuleLoader will call this automatically but this is provided to allow controlling the release order

Definition at line 285 of file GameModule.cpp.

286 {
287  if(Scripting) {
288  // Call release callback and destroy everything //
289  // fire an event //
290  Event* releaseEvent = new Event(EVENT_TYPE_RELEASE, nullptr);
291  OnEvent(releaseEvent);
292  // Release our initial reference
293  releaseEvent->Release();
294 
295  // Remove our reference //
296  int tmpid = Scripting->GetModule()->GetID();
297  Scripting.reset();
298 
300  }
301 }
Class that represents a statically defined event.
Definition: Event.h:138
static DLLEXPORT ScriptExecutor * Get()
DLLEXPORT bool DeleteModuleIfNoExternalReferences(int ID)
FORCE_INLINE void Release()
removes a reference and deletes the object if reference count reaches zero

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