Leviathan  0.8.0.0
Leviathan game engine
Leviathan::ScriptExecutor Class Reference

Handles ScriptModule creation and AngelScript code execution. More...

#include <ScriptExecutor.h>

Public Member Functions

DLLEXPORT ScriptExecutor ()
 
DLLEXPORT ~ScriptExecutor ()
 
DLLEXPORT std::weak_ptr< ScriptModuleCreateNewModule (const std::string &name, const std::string &source, const int &modulesid=IDFactory::GetID())
 
DLLEXPORT void DeleteModule (ScriptModule *ptrtomatch)
 
DLLEXPORT bool DeleteModuleIfNoExternalReferences (int ID)
 
DLLEXPORT std::weak_ptr< ScriptModuleGetModule (const int &ID)
 
DLLEXPORT std::weak_ptr< ScriptModuleGetModuleByAngelScriptName (const char *nameofmodule)
 
template<typename ReturnT , class... Args>
ScriptRunResult< ReturnT > RunScript (const std::shared_ptr< ScriptModule > &module, ScriptRunningSetup &parameters, Args &&... args)
 Runs a function in a script. More...
 
template<typename ReturnT , class... Args>
ScriptRunResult< ReturnT > RunScript (asIScriptFunction *func, std::shared_ptr< ScriptModule > module, ScriptRunningSetup &parameters, Args &&... args)
 Runs a function in a script (that is known already) More...
 
template<typename ReturnT , class... Args>
ScriptRunResult< ReturnT > RunScriptMethod (ScriptRunningSetup &parameters, asIScriptFunction *func, void *obj, Args &&... args)
 Runs a method in a script. More...
 
DLLEXPORT std::unique_ptr< CustomScriptRunPrepareCustomScriptRun (asIScriptFunction *func, ScriptRunningSetup extraoptions=ScriptRunningSetup())
 Starts a script run that supports custom argument passing. More...
 
template<typename ReturnT >
ScriptRunResult< ReturnT > ExecuteCustomRun (const std::unique_ptr< CustomScriptRun > &run)
 Ends a custom script run by actually executing the script and returning a value. More...
 
DLLEXPORT void RunReleaseRefOnObject (void *obj, int objid)
 Finds release ref behaviour on object and calls it. More...
 
DLLEXPORT std::shared_ptr< ScriptModuleGetScriptModuleByFunction (asIScriptFunction *func, bool reporterror)
 Returns module in which script function was defined in. More...
 
DLLEXPORT asIScriptFunction * GetFunctionFromModule (ScriptModule *module, ScriptRunningSetup &parameters)
 Finds a script function in module matching setup. More...
 
DLLEXPORT int ResolveStringToASID (const char *str, bool constversion=false) const
 Converts a string to angelscript type id. Returns -1 on error. More...
 
DLLEXPORT asITypeInfo * GetTypeInfo (int type) const
 Returns an asITypeInfo object for type id or null. More...
 
DLLEXPORT std::string GetTypeName (int type) const
 
DLLEXPORT asITypeInfo * GetTypeInfoByDecl (const char *str) const
 Returns an asITypeInfo object for type name or null. More...
 
DLLEXPORT asIScriptEngine * GetASEngine ()
 
DLLEXPORT void CollectGarbage ()
 Does a full garbage collection cycle. More...
 

Static Public Member Functions

static DLLEXPORT void PrintExceptionInfo (asIScriptContext *ctx, LErrorReporter &output, asIScriptFunction *func=nullptr, ScriptModule *scrptmodule=nullptr)
 Prints exception info and stacktrace to a logger. More...
 
static DLLEXPORT void PrintCallstack (asIScriptContext *ctx, LErrorReporter &output)
 
static DLLEXPORT ScriptExecutorGet ()
 

Protected Member Functions

DLLEXPORT asIScriptContext * _GetContextForExecution ()
 Called when a context is required for script execution. More...
 
DLLEXPORT void _DoneWithContext (asIScriptContext *context)
 Called after a script has been executed and the context is no longer needed. More...
 

Friends

asIScriptContext * RequestContextCallback (asIScriptEngine *engine, void *userdata)
 
void ReturnContextCallback (asIScriptEngine *engine, asIScriptContext *context, void *userdata)
 

Detailed Description

Handles ScriptModule creation and AngelScript code execution.

Definition at line 56 of file ScriptExecutor.h.

Constructor & Destructor Documentation

◆ ScriptExecutor()

ScriptExecutor::ScriptExecutor ( )

Definition at line 105 of file ScriptExecutor.cpp.

105  : engine(nullptr), AllocatedScriptModules()
106 {
107  instance = this;
108 
109  // Initialize AngelScript //
110  engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
111  if(engine == nullptr) {
112 
113  Logger::Get()->Error("ScriptExecutor: Init: asCreateScriptEngine failed");
114  Logger::Get()->Info("ScriptExecutor: tried to init angelscript version " +
115  Convert::ToString(ANGELSCRIPT_VERSION));
116  Logger::Get()->Write("Did you use a wrong angelscript version when compiling?");
117  throw Exception("Failed to init angelscript");
118  }
119 
120  // set callback to error report function //
121  engine->SetMessageCallback(asFUNCTION(ScriptMessageCallback), 0, asCALL_CDECL);
122 
123  // The ScriptExecutor can be retrieved from asIScriptEngine user data
124  engine->SetUserData(this);
125 
126 #ifdef ANGELSCRIPT_HAS_TRANSLATE_CALLBACK
127  // Set error translation callback
128  engine->SetTranslateAppExceptionCallback(
129  asFUNCTION(ScriptTranslateExceptionCallback), nullptr, asCALL_CDECL);
130 #endif // ANGELSCRIPT_HAS_TRANSLATE_CALLBACK
131 
132  // Context pool usage callbacks
133  engine->SetContextCallbacks(RequestContextCallback, ReturnContextCallback, this);
134 
135 
136  // Builtins are in this access group //
137  const auto initialMask =
138  engine->SetDefaultAccessMask(static_cast<AccessFlags>(ScriptAccess::Builtin));
139 
140  // math functions //
141  RegisterScriptMath(engine);
142  RegisterScriptMathComplex(engine);
143 
144  // register script string type //
145  RegisterStdString(engine);
146  RegisterScriptArray(engine, true);
147  // register other script extensions //
148  RegisterStdStringUtils(engine);
149 
150 
151  RegisterScriptDateTime(engine);
152 
153  // register dictionary object //
154  RegisterScriptDictionary(engine);
155 
156  // Register the grid addon //
157  RegisterScriptGrid(engine);
158 
159  // Register reference handles //
160  RegisterScriptHandle(engine);
161 
162  RegisterScriptWeakRef(engine);
163 
164  RegisterScriptAny(engine);
165 
166  // Put the extended standard stuff also in Builtin access mask
167 
168  if(!BindStandardFunctions(engine))
169  throw Exception("BindStandardFunctions failed");
170 
171  // All normal engine stuff is in the DefaultEngine access mask //
172  engine->SetDefaultAccessMask(static_cast<AccessFlags>(ScriptAccess::DefaultEngine));
173 
174  if(!BindTypes(engine))
175  throw Exception("BindTypes failed");
176 
177  if(!BindPhysics(engine))
178  throw Exception("BindNewton failed");
179 
180  if(!BindEngineCommon(engine))
181  throw Exception("BindEngineCommon failed");
182 
183  if(!BindRendering(engine))
184  throw Exception("BindRendering failed");
185 
186  if(!BindGUI(engine))
187  throw Exception("BindGUI failed");
188 
189  if(!BindEntity(engine))
190  throw Exception("BindEntity failed");
191 
192  // Bind notifiers //
193  if(!RegisterNotifiersWithAngelScript(engine)) {
194  // failed //
195  LOG_ERROR("ScriptExecutor: Init: AngelScript: register Notifier types failed");
196  throw Exception("Script bind failed");
197  }
198 
199  // Restore the default mask to let the application do what it wants with the masks
200  engine->SetDefaultAccessMask(initialMask);
201 
202  // bind application specific //
203  auto leviathanengine = Engine::GetEngine();
204 
205  if(leviathanengine) {
206 
207  if(!leviathanengine->GetOwningApplication()->InitLoadCustomScriptTypes(engine)) {
208 
209  LOG_ERROR("ScriptExecutor: Init: AngelScript: application register failed");
210  throw Exception("Script bind failed");
211  }
212  }
213 
214  // Verify void type //
215  const auto actualVoid = engine->GetTypeIdByDecl("void");
216  if(actualVoid != ANGELSCRIPT_VOID_TYPEID) {
217 
218  LOG_FATAL("ScriptExecutor: angelscript void type has changed! expected " +
219  std::to_string(ANGELSCRIPT_VOID_TYPEID) +
220  " (constexpr) == " + std::to_string(actualVoid) + " (actual value)");
221  }
222 }
Access to the builtin types like string and math functions.
DLLEXPORT void Write(const std::string &data) override
Definition: Logger.cpp:113
friend void ReturnContextCallback(asIScriptEngine *engine, asIScriptContext *context, void *userdata)
DLLEXPORT void Info(const std::string &data) override
Definition: Logger.cpp:164
#define LOG_ERROR(x)
Definition: Define.h:92
#define LOG_FATAL(x)
Definition: Define.h:94
constexpr auto ANGELSCRIPT_VOID_TYPEID
This has to be constant (and luckily so far it has been)
bool RegisterNotifiersWithAngelScript(asIScriptEngine *engine)
bool BindRendering(asIScriptEngine *engine)
bool BindEngineCommon(asIScriptEngine *engine)
Base class for all exceptions thrown by Leviathan.
Definition: Exceptions.h:10
bool BindStandardFunctions(asIScriptEngine *engine)
Binds standard and other utilities like: std::min, std::max etc.
bool BindTypes(asIScriptEngine *engine)
Definition: TypesBind.cpp:1152
Default mask for engine classes (some things are accessible even with this off)
static std::string ToString(const T &val)
Definition: Convert.h:72
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
bool BindGUI(asIScriptEngine *engine)
void ScriptMessageCallback(const asSMessageInfo *msg, void *param)
static DLLEXPORT Engine * GetEngine()
Definition: Engine.cpp:81
bool BindPhysics(asIScriptEngine *engine)
friend asIScriptContext * RequestContextCallback(asIScriptEngine *engine, void *userdata)
bool BindEntity(asIScriptEngine *engine)
Definition: EntityBind.cpp:565
DLLEXPORT void Error(const std::string &data) override
Definition: Logger.cpp:177

◆ ~ScriptExecutor()

ScriptExecutor::~ScriptExecutor ( )

Definition at line 223 of file ScriptExecutor.cpp.

224 {
225  {
226  Lock lock(ModulesLock);
227  auto end = AllocatedScriptModules.end();
228  for(auto iter = AllocatedScriptModules.begin(); iter != end; ++iter) {
229 
230  (*iter)->Release();
231  }
232 
233  // release/delete all modules //
234  AllocatedScriptModules.clear();
235  }
236 
237  // Release all context objects
238  for(asIScriptContext* context : ContextPool) {
239  context->Release();
240  }
241 
242  ContextPool.clear();
243 
244  // release AngelScript //
245  if(engine) {
246 
247  engine->Release();
248  engine = nullptr;
249  }
250 
251  instance = nullptr;
252 }
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18

Member Function Documentation

◆ _DoneWithContext()

DLLEXPORT void Leviathan::ScriptExecutor::_DoneWithContext ( asIScriptContext *  context)
protected

Called after a script has been executed and the context is no longer needed.

Note
Also called from CustomScriptRun

Definition at line 474 of file ScriptExecutor.cpp.

475 {
476  Lock guard(ContextPoolLock);
477 
478  // Only keep 1000 contexts at most
479  if(ContextPool.size() < 1000) {
480 
481  ContextPool.push_back(context);
482  context->Unprepare();
483 
484  } else {
485 
486  context->Release();
487  }
488 }
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18

◆ _GetContextForExecution()

DLLEXPORT asIScriptContext * Leviathan::ScriptExecutor::_GetContextForExecution ( )
protected

Called when a context is required for script execution.

Todo:
Allow recursive calls

Definition at line 449 of file ScriptExecutor.cpp.

450 {
451  // TODO: check for recursive call
452 
453  Lock guard(ContextPoolLock);
454 
455  // Get from pool if possible
456  if(!ContextPool.empty()) {
457  auto* ptr = ContextPool.back();
458  ContextPool.pop_back();
459  return ptr;
460  }
461 
462  // Needs more contexts
463  asIScriptContext* scriptContext = engine->CreateContext();
464 
465  if(!scriptContext) {
466 
467  LOG_ERROR("ScriptExecutor: _GetContextForExecution: Failed to create a new context");
468  return nullptr;
469  }
470 
471  return scriptContext;
472 }
#define LOG_ERROR(x)
Definition: Define.h:92
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18

◆ CollectGarbage()

DLLEXPORT void ScriptExecutor::CollectGarbage ( )

Does a full garbage collection cycle.

Definition at line 729 of file ScriptExecutor.cpp.

730 {
731  engine->GarbageCollect(asGC_FULL_CYCLE);
732 }

◆ CreateNewModule()

DLLEXPORT std::weak_ptr< ScriptModule > Leviathan::ScriptExecutor::CreateNewModule ( const std::string &  name,
const std::string &  source,
const int &  modulesid = IDFactory::GetID() 
)

Definition at line 520 of file ScriptExecutor.cpp.

523 {
524  // create new module to a smart pointer //
525  auto tmpptr = std::make_shared<ScriptModule>(engine, name, modulesid, source);
526 
527  // add to vector and return //
528  Lock lock(ModulesLock);
529  AllocatedScriptModules.push_back(tmpptr);
530  return tmpptr;
531 }
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18

◆ DeleteModule()

DLLEXPORT void Leviathan::ScriptExecutor::DeleteModule ( ScriptModule ptrtomatch)

Definition at line 533 of file ScriptExecutor.cpp.

534 {
535 
536  Lock lock(ModulesLock);
537 
538  // find module based on pointer and remove //
539  for(size_t i = 0; i < AllocatedScriptModules.size(); i++) {
540  if(AllocatedScriptModules[i].get() == ptrtomatch) {
541 
542  AllocatedScriptModules[i]->Release();
543  // remove //
544  AllocatedScriptModules.erase(AllocatedScriptModules.begin() + i);
545  return;
546  }
547  }
548 }
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18

◆ DeleteModuleIfNoExternalReferences()

DLLEXPORT bool Leviathan::ScriptExecutor::DeleteModuleIfNoExternalReferences ( int  ID)

Definition at line 550 of file ScriptExecutor.cpp.

551 {
552 
553  Lock lock(ModulesLock);
554 
555  // Find based on the id //
556  for(size_t i = 0; i < AllocatedScriptModules.size(); i++) {
557  if(AllocatedScriptModules[i]->GetID() == ID) {
558  // Check reference count //
559  if(AllocatedScriptModules[i].use_count() != 1) {
560  // Other references exist //
561  return false;
562  }
563 
564  AllocatedScriptModules[i]->Release();
565 
566  // remove //
567  AllocatedScriptModules.erase(AllocatedScriptModules.begin() + i);
568  return true;
569  }
570  }
571  // Nothing found //
572  return false;
573 }
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18

◆ ExecuteCustomRun()

template<typename ReturnT >
ScriptRunResult<ReturnT> Leviathan::ScriptExecutor::ExecuteCustomRun ( const std::unique_ptr< CustomScriptRun > &  run)
inline

Ends a custom script run by actually executing the script and returning a value.

Note
You MUST manually pass arguments before calling this! Use RunScript if you don't need custom argument passing

Definition at line 221 of file ScriptExecutor.h.

222  {
223  if(!run)
224  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
225 
226  // Run the script //
227  // TODO: timeout and debugging registering with linecallbacks here //
228  int retcode = run->Context->Execute();
229 
230  // Get the return value //
231  auto returnvalue = _HandleEndedScriptExecution<ReturnT>(
232  retcode, run->Context, run->Setup, run->Func, run->Module.get());
233 
234  // Release the context //
235  _DoneWithContext(run->Context);
236  run->Context = nullptr;
237 
238  // Return the returned value //
239  return returnvalue;
240  }
DLLEXPORT void _DoneWithContext(asIScriptContext *context)
Called after a script has been executed and the context is no longer needed.

◆ Get()

DLLEXPORT ScriptExecutor * Leviathan::ScriptExecutor::Get ( )
static
Note
Alternative way to get ScriptExecutor is from asIScriptEngine::GetUserData

Definition at line 254 of file ScriptExecutor.cpp.

255 {
256  return instance;
257 }

◆ GetASEngine()

DLLEXPORT asIScriptEngine* Leviathan::ScriptExecutor::GetASEngine ( )
inline

Definition at line 278 of file ScriptExecutor.h.

279  {
280  return engine;
281  }

◆ GetFunctionFromModule()

DLLEXPORT asIScriptFunction * ScriptExecutor::GetFunctionFromModule ( ScriptModule module,
ScriptRunningSetup parameters 
)

Finds a script function in module matching setup.

Returns
The function or null if not found or module is invalid

Sets the function existed in the parameters

Definition at line 261 of file ScriptExecutor.cpp.

263 {
264  if(!module) {
265 
266  if(parameters.PrintErrors) {
267  Logger::Get()->Error("ScriptExecutor: GetFunctionFromModule: module is nullptr");
268  }
269 
270  return nullptr;
271  }
272 
273  asIScriptFunction* func;
274 
275  asIScriptModule* asModule = module->GetModule();
276 
277  if(!asModule) {
278 
279  if(parameters.PrintErrors) {
280  Logger::Get()->Error(
281  "ScriptExecutor: GetFunctionFromModule: cannot get function from "
282  "an invalid script module: " +
283  module->GetInfoString());
284  }
285 
286  return nullptr;
287  }
288 
289  // Get the entry function from the module //
290  if(!parameters.FullDeclaration) {
291 
292  func = asModule->GetFunctionByName(parameters.Entryfunction.c_str());
293 
294  } else {
295 
296  func = asModule->GetFunctionByDecl(parameters.Entryfunction.c_str());
297  }
298 
299  if(!_CheckScriptFunctionPtr(func, parameters, module)) {
300 
301  return nullptr;
302  }
303 
304  return func;
305 }
DLLEXPORT asIScriptModule * GetModule(Lock &guard)
Builds the script if applicable.
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
DLLEXPORT void Error(const std::string &data) override
Definition: Logger.cpp:177
DLLEXPORT std::string GetInfoString()

◆ GetModule()

DLLEXPORT std::weak_ptr< ScriptModule > Leviathan::ScriptExecutor::GetModule ( const int &  ID)

Definition at line 490 of file ScriptExecutor.cpp.

491 {
492  // loop modules and return a ptr to matching id //
493  Lock lock(ModulesLock);
494 
495  for(size_t i = 0; i < AllocatedScriptModules.size(); i++) {
496  if(AllocatedScriptModules[i]->GetID() == ID)
497  return AllocatedScriptModules[i];
498  }
499 
500  return std::shared_ptr<ScriptModule>(nullptr);
501 }
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18

◆ GetModuleByAngelScriptName()

DLLEXPORT std::weak_ptr< ScriptModule > Leviathan::ScriptExecutor::GetModuleByAngelScriptName ( const char *  nameofmodule)

Definition at line 503 of file ScriptExecutor.cpp.

505 {
506  // Find a matching name //
507  std::string module(nameofmodule);
508 
509  Lock lock(ModulesLock);
510 
511  // TODO: check could this be checked by comparing pointers
512  for(size_t i = 0; i < AllocatedScriptModules.size(); i++) {
513  if(AllocatedScriptModules[i]->GetModuleName() == module)
514  return AllocatedScriptModules[i];
515  }
516 
517  return std::shared_ptr<ScriptModule>(nullptr);
518 }
std::unique_lock< std::mutex > Lock
Definition: ThreadSafe.h:18

◆ GetScriptModuleByFunction()

DLLEXPORT std::shared_ptr< ScriptModule > ScriptExecutor::GetScriptModuleByFunction ( asIScriptFunction *  func,
bool  reporterror 
)

Returns module in which script function was defined in.

Todo:
When module is null find the module by AngelScript module pointer (set the userdata pointer on the module to point to the ScriptModule object) for faster finding

Definition at line 375 of file ScriptExecutor.cpp.

377 {
378  const char* nameStr = func->GetModuleName();
379 
380  if(!nameStr || strlen(nameStr) <= 1)
381  return nullptr;
382 
383  // static_cast<ScriptModule*>(func->GetModule()->GetUserData());
384  // then find by pointer in valid script modules
385 
386  std::shared_ptr<ScriptModule> module =
387  GetModuleByAngelScriptName(func->GetModuleName()).lock();
388 
389  if(!module) {
390 
391  if(reporterror) {
392  LOG_WARNING("ScriptExecutor: GetScriptModuleByFunction: the module is no longer "
393  "available: " +
394  std::string(func->GetModuleName()));
395  }
396  }
397 
398  return module;
399 }
DLLEXPORT std::weak_ptr< ScriptModule > GetModuleByAngelScriptName(const char *nameofmodule)
#define LOG_WARNING(x)
Definition: Define.h:91

◆ GetTypeInfo()

DLLEXPORT asITypeInfo * ScriptExecutor::GetTypeInfo ( int  type) const

Returns an asITypeInfo object for type id or null.

Definition at line 681 of file ScriptExecutor.cpp.

682 {
683  if(type < 0)
684  return nullptr;
685 
686  return engine->GetTypeInfoById(type);
687 }

◆ GetTypeInfoByDecl()

DLLEXPORT asITypeInfo* Leviathan::ScriptExecutor::GetTypeInfoByDecl ( const char *  str) const

Returns an asITypeInfo object for type name or null.

◆ GetTypeName()

DLLEXPORT std::string ScriptExecutor::GetTypeName ( int  type) const
Returns
A string declaration of type or 'error'

Definition at line 689 of file ScriptExecutor.cpp.

690 {
691  if(type < 0)
692  return "error";
693 
694  asITypeInfo* typeInfo = engine->GetTypeInfoById(type);
695 
696  if(!typeInfo)
697  return "error";
698 
699  const auto name = typeInfo->GetName();
700 
701  if(!name)
702  return "error";
703 
704  const auto ns = typeInfo->GetNamespace();
705 
706  std::string result = (ns ? ns : "") + std::string(name);
707 
708  if(type & asTYPEID_OBJHANDLE)
709  result += "@";
710 
711  if(type & asTYPEID_HANDLETOCONST)
712  result = "const " + result;
713 
714  if(type & asTYPEID_MASK_OBJECT)
715  result += " (OBJ)";
716 
717  if(type & asTYPEID_APPOBJECT)
718  result += " (APP)";
719 
720  if(type & asTYPEID_SCRIPTOBJECT)
721  result += " (SCRIPT)";
722 
723  if(type & asTYPEID_TEMPLATE)
724  result = "template " + result;
725 
726  return result;
727 }

◆ PrepareCustomScriptRun()

DLLEXPORT std::unique_ptr< CustomScriptRun > ScriptExecutor::PrepareCustomScriptRun ( asIScriptFunction *  func,
ScriptRunningSetup  extraoptions = ScriptRunningSetup() 
)

Starts a script run that supports custom argument passing.

Definition at line 342 of file ScriptExecutor.cpp.

344 {
345  if(!func)
346  return nullptr;
347 
348  auto run = std::make_unique<CustomScriptRun>(this);
349  run->Setup = extraoptions;
350  run->Func = func;
351 
352  // // TODO: this is a performance waste if there are no errors
353  // std::shared_ptr<ScriptModule> module =
354  // GetScriptModuleByFunction(func, run->Setup.PrintErrors);
355 
356  // Create a running context for the function //
357  run->Context = _GetContextForExecution();
358 
359  if(!run->Context) {
360  // Should this be fatal?
361  LOG_ERROR("ScriptExecutor: PrepareCustomScriptRun: failed to create a new context");
362  return nullptr;
363  }
364 
365  if(!_PrepareContextForPassingParameters(
366  func, run->Context, run->Setup, run->Module.get())) {
367 
368  _DoneWithContext(run->Context);
369  return nullptr;
370  }
371 
372  return run;
373 }
#define LOG_ERROR(x)
Definition: Define.h:92
DLLEXPORT void _DoneWithContext(asIScriptContext *context)
Called after a script has been executed and the context is no longer needed.
DLLEXPORT asIScriptContext * _GetContextForExecution()
Called when a context is required for script execution.

◆ PrintCallstack()

DLLEXPORT void ScriptExecutor::PrintCallstack ( asIScriptContext *  ctx,
LErrorReporter output 
)
static

Definition at line 633 of file ScriptExecutor.cpp.

634 {
635 
636  // Print callstack as additional information //
637  output.WriteLine("// ------------------ CallStack ------------------ //");
638 
639  // Loop the stack starting from the frame below the current function
640  // (actually might be nice to print the top frame too)
641  for(asUINT n = 0; n < ctx->GetCallstackSize(); n++) {
642 
643  // Get the function object //
644  const asIScriptFunction* function = ctx->GetFunction(n);
645 
646  // If the function doesn't exist this frame is used internally by the script engine //
647  if(function) {
648 
649  // Check function type //
650  if(function->GetFuncType() == asFUNC_SCRIPT) {
651 
652  // Print info about the script function //
653  output.WriteLine(std::string("\t> ") + function->GetScriptSectionName() + ":" +
654  std::to_string(ctx->GetLineNumber(n)) + " " +
655  function->GetDeclaration());
656 
657  } else {
658  // Info about the application functions //
659  // The context is being reused by the application for a nested call
660  output.WriteLine(
661  std::string("\t> {...Application...}: ") + function->GetDeclaration());
662  }
663  } else {
664  // The context is being reused by the script engine for a nested call
665  output.WriteLine("\t> {...Script internal...}");
666  }
667  }
668 }
virtual void WriteLine(const std::string &Text)=0

◆ PrintExceptionInfo()

DLLEXPORT void ScriptExecutor::PrintExceptionInfo ( asIScriptContext *  ctx,
LErrorReporter output,
asIScriptFunction *  func = nullptr,
ScriptModule scrptmodule = nullptr 
)
static

Prints exception info and stacktrace to a logger.

Definition at line 604 of file ScriptExecutor.cpp.

607 {
608 
609  std::string declaration = ctx->GetExceptionFunction()->GetDeclaration() ?
610  ctx->GetExceptionFunction()->GetDeclaration() :
611  "unknown function";
612 
613  std::string section = ctx->GetExceptionFunction()->GetScriptSectionName() ?
614  ctx->GetExceptionFunction()->GetScriptSectionName() :
615  "unknown";
616 
617  std::string exception =
618  ctx->GetExceptionString() ? ctx->GetExceptionString() : "unknown exception";
619 
620  std::string funcDeclaration =
621  func ? (func->GetDeclaration() ? func->GetDeclaration() : "unknown function") : "";
622 
623  output.Error(
624  std::string("[SCRIPT][EXCEPTION] ") + exception +
625  (func ? std::string(", while running function: ") + funcDeclaration : std::string()) +
626  "\n\t in function " + declaration + " defined in " + section + "(" +
627  std::to_string(ctx->GetExceptionLineNumber()) + ") " +
628  (scriptmodule ? scriptmodule->GetInfoString() : std::string()));
629 
630  PrintCallstack(ctx, output);
631 }
static DLLEXPORT void PrintCallstack(asIScriptContext *ctx, LErrorReporter &output)
virtual void Error(const std::string &Text)=0

◆ ResolveStringToASID()

DLLEXPORT int ScriptExecutor::ResolveStringToASID ( const char *  str,
bool  constversion = false 
) const

Converts a string to angelscript type id. Returns -1 on error.

Replaces GetAngelScriptTypeID

Parameters
constversionIf true prepends 'const' to the type str

Definition at line 670 of file ScriptExecutor.cpp.

672 {
673  if(!constversion) {
674  return engine->GetTypeIdByDecl(str);
675  } else {
676  // TODO: it would be nice to not have to allocate memory here
677  return engine->GetTypeIdByDecl((std::string("const ") + str).c_str());
678  }
679 }

◆ RunReleaseRefOnObject()

DLLEXPORT void ScriptExecutor::RunReleaseRefOnObject ( void *  obj,
int  objid 
)

Finds release ref behaviour on object and calls it.

Exceptions
Exceptionif it didn't work
Note
Should only be called if the object of type has asOBJ_REF and no asOBJ_NOCOUNT
Todo:
This is actually a method in the angelscript engine, so use that, but this is a good example how to run any behaviour

Definition at line 307 of file ScriptExecutor.cpp.

308 {
309  asITypeInfo* info = engine->GetTypeInfoById(objid);
310 
311  asUINT count = info->GetBehaviourCount();
312 
313  for(asUINT i = 0; i < count; ++i) {
314 
315  asEBehaviours behaviour;
316  asIScriptFunction* func = info->GetBehaviourByIndex(i, &behaviour);
317 
318  if(!func) {
319 
320  LOG_ERROR("ScriptExecutor: RunReleaseRefOnObject: failed to get behaviour");
321  continue;
322  }
323 
324  if(behaviour == asBEHAVE_RELEASE) {
325 
326  LOG_INFO(
327  "ScriptExecutor: RunReleaseRefOnObject: Found asBEHAVE_RELEASE, calling it");
328 
329  ScriptRunningSetup ssetup;
330  const auto result = RunScriptMethod<void>(ssetup, func, obj);
331 
332  if(result.Result != SCRIPT_RUN_RESULT::Success)
333  throw Exception("Failed to run release behaviour");
334 
335  return;
336  }
337  }
338 
339  throw Exception("Didn't find release ref behaviour on object type");
340 }
#define LOG_INFO(x)
Definition: Define.h:90
#define LOG_ERROR(x)
Definition: Define.h:92
Base class for all exceptions thrown by Leviathan.
Definition: Exceptions.h:10

◆ RunScript() [1/2]

template<typename ReturnT , class... Args>
ScriptRunResult<ReturnT> Leviathan::ScriptExecutor::RunScript ( const std::shared_ptr< ScriptModule > &  module,
ScriptRunningSetup parameters,
Args &&...  args 
)
inline

Runs a function in a script.

Note
This is the recommended way to run scripts (other than GameModule that has its own method)
Todo:

Allow recursive calls and more context reuse. Also wrap context in an object that automatically returns it in case of expections (_HandleEndedScriptExecution can throw)

Also make all the script module using functions automatically get it if they need for error reporting

Definition at line 84 of file ScriptExecutor.h.

86  {
87  // This calls _CheckScriptFunctionPtr
88  asIScriptFunction* func = GetFunctionFromModule(module.get(), parameters);
89 
90  return RunScript<ReturnT>(func, module, parameters, std::forward<Args>(args)...);
91  }
DLLEXPORT asIScriptFunction * GetFunctionFromModule(ScriptModule *module, ScriptRunningSetup &parameters)
Finds a script function in module matching setup.

◆ RunScript() [2/2]

template<typename ReturnT , class... Args>
ScriptRunResult<ReturnT> Leviathan::ScriptExecutor::RunScript ( asIScriptFunction *  func,
std::shared_ptr< ScriptModule module,
ScriptRunningSetup parameters,
Args &&...  args 
)
inline

Runs a function in a script (that is known already)

Todo:
Wrap context in an object that automatically returns it in case of expections (_HandleEndedScriptExecution can throw)

Definition at line 97 of file ScriptExecutor.h.

99  {
100  if(!func)
101  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
102 
103  if(!module) {
104  // TODO: this is a performance waste if there are no errors
105  // Find the right module //
106  module = GetScriptModuleByFunction(func, parameters.PrintErrors);
107  }
108 
109 
110  // Create a running context for the function //
111  asIScriptContext* scriptContext = _GetContextForExecution();
112 
113  if(!scriptContext) {
114  // Should this be fatal?
115  LOG_ERROR("ScriptExecutor: RunScript: failed to create a new context");
116  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
117  }
118 
119  if(!_PrepareContextForPassingParameters(
120  func, scriptContext, parameters, module.get())) {
121 
122  _DoneWithContext(scriptContext);
123  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
124  }
125 
126  // Pass the parameters //
127  if(!_PassParametersToScript(
128  scriptContext, parameters, module.get(), func, std::forward<Args>(args)...)) {
129 
130  // Failed passing the parameters //
131  _DoneWithContext(scriptContext);
132  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
133  }
134 
135  // Run the script //
136  // TODO: timeout and debugging registering with linecallbacks here //
137  int retcode = scriptContext->Execute();
138 
139  // Get the return value //
140  auto returnvalue = _HandleEndedScriptExecution<ReturnT>(
141  retcode, scriptContext, parameters, func, module.get());
142 
143  // Release the context //
144  _DoneWithContext(scriptContext);
145 
146  // Return the returned value //
147  return returnvalue;
148  }
#define LOG_ERROR(x)
Definition: Define.h:92
DLLEXPORT std::shared_ptr< ScriptModule > GetScriptModuleByFunction(asIScriptFunction *func, bool reporterror)
Returns module in which script function was defined in.
DLLEXPORT void _DoneWithContext(asIScriptContext *context)
Called after a script has been executed and the context is no longer needed.
DLLEXPORT asIScriptContext * _GetContextForExecution()
Called when a context is required for script execution.

◆ RunScriptMethod()

template<typename ReturnT , class... Args>
ScriptRunResult<ReturnT> Leviathan::ScriptExecutor::RunScriptMethod ( ScriptRunningSetup parameters,
asIScriptFunction *  func,
void *  obj,
Args &&...  args 
)
inline

Runs a method in a script.

Note
This doesn't verify that the object type is correct for the function. The caller is responsible for making sure that func is part of the class of obj
The parameters object is largely ignored (function name)
Todo:
Merge common parts with RunScript

Definition at line 156 of file ScriptExecutor.h.

158  {
159  if(!func || !obj)
160  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
161 
162  // TODO: this is a performance waste if there are no errors
163  std::shared_ptr<ScriptModule> module =
164  GetScriptModuleByFunction(func, parameters.PrintErrors);
165 
166  // Create a running context for the function //
167  asIScriptContext* scriptContext = _GetContextForExecution();
168 
169  if(!scriptContext) {
170  // Should this be fatal?
171  LOG_ERROR("ScriptExecutor: RunScriptMethod: failed to create a new context");
172  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
173  }
174 
175  if(!_PrepareContextForPassingParameters(
176  func, scriptContext, parameters, module.get())) {
177 
178  _DoneWithContext(scriptContext);
179  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
180  }
181 
182  // Pass the parameters //
183  if(!_PassParametersToScript(
184  scriptContext, parameters, module.get(), func, std::forward<Args>(args)...)) {
185 
186  // Failed passing the parameters //
187  _DoneWithContext(scriptContext);
188  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
189  }
190 
191  // Pass the object instance //
192  if(scriptContext->SetObject(obj) < 0) {
193 
194  _DoneWithContext(scriptContext);
195  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
196  }
197 
198  // Run the script //
199  // TODO: timeout and debugging registering with linecallbacks here //
200  int retcode = scriptContext->Execute();
201 
202  // Get the return value //
203  auto returnvalue = _HandleEndedScriptExecution<ReturnT>(
204  retcode, scriptContext, parameters, func, module.get());
205 
206  // Release the context //
207  _DoneWithContext(scriptContext);
208 
209  // Return the returned value //
210  return returnvalue;
211  }
#define LOG_ERROR(x)
Definition: Define.h:92
DLLEXPORT std::shared_ptr< ScriptModule > GetScriptModuleByFunction(asIScriptFunction *func, bool reporterror)
Returns module in which script function was defined in.
DLLEXPORT void _DoneWithContext(asIScriptContext *context)
Called after a script has been executed and the context is no longer needed.
DLLEXPORT asIScriptContext * _GetContextForExecution()
Called when a context is required for script execution.

Friends And Related Function Documentation

◆ RequestContextCallback

asIScriptContext* RequestContextCallback ( asIScriptEngine *  engine,
void *  userdata 
)
friend

Definition at line 93 of file ScriptExecutor.cpp.

94 {
95  return static_cast<ScriptExecutor*>(userdata)->_GetContextForExecution();
96 }

◆ ReturnContextCallback

void ReturnContextCallback ( asIScriptEngine *  engine,
asIScriptContext *  context,
void *  userdata 
)
friend

Definition at line 98 of file ScriptExecutor.cpp.

99 {
100  static_cast<ScriptExecutor*>(userdata)->_DoneWithContext(context);
101 }

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