Leviathan  0.8.0.0
Leviathan game engine
ScriptExecutor.h
Go to the documentation of this file.
1 // Leviathan Game Engine
2 // Copyright (c) 2012-2018 Henri Hyyryläinen
3 #pragma once
4 #include "Define.h"
5 // ------------------------------------ //
7 #include "Common/ThreadSafe.h"
8 #include "Handlers/IDFactory.h"
11 #include "Script/ScriptScript.h"
13 
14 #include <memory>
15 #include <string>
16 #include <vector>
17 
18 // angelscript //
19 //#define ANGELSCRIPT_DLL_LIBRARY_IMPORT
20 #include "angelscript.h"
21 
22 
23 #if ANGELSCRIPT_VERSION >= 23300
24 #define ANGELSCRIPT_HAS_TRANSLATE_CALLBACK
25 #endif
26 
27 namespace Leviathan {
28 
29 class ScriptExecutor;
30 
35  friend ScriptExecutor;
36 
37 public:
39  inline CustomScriptRun(ScriptExecutor* exec) : Exec(exec){};
41 
43  asIScriptFunction* Func;
44  asIScriptContext* Context;
45  std::shared_ptr<ScriptModule> Module;
46 
47  // For keeping track of parameter number (not used by ScriptExecutor but is used by helpers
48  // in CustomScriptRunHelpers.h)
49  asUINT PassedIndex = 0;
50 
51 private:
52  ScriptExecutor* Exec;
53 };
54 
57  friend CustomScriptRun;
58  friend asIScriptContext* RequestContextCallback(asIScriptEngine* engine, void* userdata);
59  friend void ReturnContextCallback(
60  asIScriptEngine* engine, asIScriptContext* context, void* userdata);
61 
62 public:
65 
66  // ------------------------------------ //
67  // module managing
68  DLLEXPORT std::weak_ptr<ScriptModule> CreateNewModule(const std::string& name,
69  const std::string& source, const int& modulesid = IDFactory::GetID());
70 
71  DLLEXPORT void DeleteModule(ScriptModule* ptrtomatch);
73  DLLEXPORT std::weak_ptr<ScriptModule> GetModule(const int& ID);
74  DLLEXPORT std::weak_ptr<ScriptModule> GetModuleByAngelScriptName(const char* nameofmodule);
75 
83  template<typename ReturnT, class... Args>
84  ScriptRunResult<ReturnT> RunScript(const std::shared_ptr<ScriptModule>& module,
85  ScriptRunningSetup& parameters, Args&&... args)
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  }
92 
96  template<typename ReturnT, class... Args>
97  ScriptRunResult<ReturnT> RunScript(asIScriptFunction* func,
98  std::shared_ptr<ScriptModule> module, ScriptRunningSetup& parameters, Args&&... args)
99  {
100  if(!func)
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");
117  }
118 
119  if(!_PrepareContextForPassingParameters(
120  func, scriptContext, parameters, module.get())) {
121 
122  _DoneWithContext(scriptContext);
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);
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  }
149 
155  template<typename ReturnT, class... Args>
157  ScriptRunningSetup& parameters, asIScriptFunction* func, void* obj, Args&&... args)
158  {
159  if(!func || !obj)
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");
173  }
174 
175  if(!_PrepareContextForPassingParameters(
176  func, scriptContext, parameters, module.get())) {
177 
178  _DoneWithContext(scriptContext);
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);
189  }
190 
191  // Pass the object instance //
192  if(scriptContext->SetObject(obj) < 0) {
193 
194  _DoneWithContext(scriptContext);
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  }
212 
214  DLLEXPORT std::unique_ptr<CustomScriptRun> PrepareCustomScriptRun(
215  asIScriptFunction* func, ScriptRunningSetup extraoptions = ScriptRunningSetup());
216 
220  template<typename ReturnT>
221  ScriptRunResult<ReturnT> ExecuteCustomRun(const std::unique_ptr<CustomScriptRun>& run)
222  {
223  if(!run)
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  }
241 
242 
248  DLLEXPORT void RunReleaseRefOnObject(void* obj, int objid);
249 
253  DLLEXPORT std::shared_ptr<ScriptModule> GetScriptModuleByFunction(
254  asIScriptFunction* func, bool reporterror);
255 
260  DLLEXPORT asIScriptFunction* GetFunctionFromModule(
261  ScriptModule* module, ScriptRunningSetup& parameters);
262 
266  DLLEXPORT int ResolveStringToASID(const char* str) const;
267 
269  DLLEXPORT asITypeInfo* GetTypeInfo(int type) const;
270 
272  DLLEXPORT asITypeInfo* GetTypeInfoByDecl(const char* str) const;
273 
274  DLLEXPORT inline asIScriptEngine* GetASEngine()
275  {
276  return engine;
277  }
278 
280  DLLEXPORT void CollectGarbage();
281 
283  DLLEXPORT static void PrintExceptionInfo(asIScriptContext* ctx, LErrorReporter& output,
284  asIScriptFunction* func = nullptr, ScriptModule* scrptmodule = nullptr);
285 
286  DLLEXPORT static void PrintCallstack(asIScriptContext* ctx, LErrorReporter& output);
287 
289  DLLEXPORT static ScriptExecutor* Get();
290 
291 private:
292 
295  template<class CurrentT, class... Args>
296  bool _DoPassEachParameter(asUINT parameterc, asUINT& i, asIScriptContext* scriptcontext,
297  ScriptRunningSetup& setup, ScriptModule* module, asIScriptFunction* func,
298  const CurrentT& current, Args&&... args)
299  {
300  // Finished passing parameters //
301  if(i >= parameterc)
302  return true;
303 
304  // Try to pass based on type //
305  int r = 0;
306 
307  // Check that type matches //
308  int wantedTypeID;
309  asDWORD flags;
310  if(func->GetParam(i, &wantedTypeID, &flags) < 0) {
311 
312  LOG_ERROR("ScriptExecutor: failed to get param type from as: " +
313  std::to_string(i) + ", for func: " + func->GetName());
314  return false;
315  }
316 
317 
318  // if constexpr(CanTypeRepresentAngelScriptTypes<CurrentT>()) {
319 
320  // } else {
321  // }
322 
323 
324  const auto parameterType = AngelScriptTypeIDResolver<CurrentT>::Get(this);
325  if(wantedTypeID != parameterType) {
326 
327  // Compatibility checks //
328  // This is not the most optimal as this results in a duplicate call to
329  // func->GetParam
330  // TODO: is there a better way than to have this mess here?
331 
332  if(wantedTypeID == AngelScriptTypeIDResolver<int32_t>::Get(this)) {
333 
334  if constexpr(std::is_convertible_v<CurrentT, int32_t>) {
335  return _DoPassEachParameter(parameterc, i, scriptcontext, setup, module,
336  func, static_cast<int32_t>(current), std::forward<Args>(args)...);
337  }
338  } else if(wantedTypeID == AngelScriptTypeIDResolver<uint32_t>::Get(this)) {
339 
340  if constexpr(std::is_convertible_v<CurrentT, uint32_t>) {
341  return _DoPassEachParameter(parameterc, i, scriptcontext, setup, module,
342  func, static_cast<uint32_t>(current), std::forward<Args>(args)...);
343  }
344  } else if(wantedTypeID == AngelScriptTypeIDResolver<uint64_t>::Get(this)) {
345 
346  if constexpr(std::is_convertible_v<CurrentT, uint64_t>) {
347  return _DoPassEachParameter(parameterc, i, scriptcontext, setup, module,
348  func, static_cast<uint64_t>(current), std::forward<Args>(args)...);
349  }
350  } else if(wantedTypeID == AngelScriptTypeIDResolver<int64_t>::Get(this)) {
351 
352  if constexpr(std::is_convertible_v<CurrentT, int64_t>) {
353  return _DoPassEachParameter(parameterc, i, scriptcontext, setup, module,
354  func, static_cast<int64_t>(current), std::forward<Args>(args)...);
355  }
356  } else if(wantedTypeID == AngelScriptTypeIDResolver<int8_t>::Get(this)) {
357 
358  if constexpr(std::is_convertible_v<CurrentT, int8_t>) {
359  return _DoPassEachParameter(parameterc, i, scriptcontext, setup, module,
360  func, static_cast<int8_t>(current), std::forward<Args>(args)...);
361  }
362 
363  } else if(wantedTypeID == AngelScriptTypeIDResolver<uint8_t>::Get(this)) {
364 
365  if constexpr(std::is_convertible_v<CurrentT, uint8_t>) {
366  return _DoPassEachParameter(parameterc, i, scriptcontext, setup, module,
367  func, static_cast<uint8_t>(current), std::forward<Args>(args)...);
368  }
369  } else if(wantedTypeID == AngelScriptTypeIDResolver<float>::Get(this)) {
370 
371  if constexpr(std::is_convertible_v<CurrentT, float>) {
372  return _DoPassEachParameter(parameterc, i, scriptcontext, setup, module,
373  func, static_cast<float>(current), std::forward<Args>(args)...);
374  }
375 
376  } else if(wantedTypeID == AngelScriptTypeIDResolver<double>::Get(this)) {
377 
378  if constexpr(std::is_convertible_v<CurrentT, double>) {
379  return _DoPassEachParameter(parameterc, i, scriptcontext, setup, module,
380  func, static_cast<double>(current), std::forward<Args>(args)...);
381  }
382  }
383 
384  // No conversion possible //
385  return _DoPassParameterTypeError(setup, module, i, wantedTypeID, parameterType);
386  }
387 
388  if constexpr(std::is_same_v<CurrentT, int32_t> || std::is_same_v<CurrentT, uint32_t>) {
389 
390  r = scriptcontext->SetArgDWord(i, current);
391  } else if constexpr(std::is_same_v<CurrentT, int64_t> ||
392  std::is_same_v<CurrentT, uint64_t>) {
393 
394  r = scriptcontext->SetArgQWord(i, current);
395  } else if constexpr(std::is_same_v<CurrentT, float>) {
396 
397  r = scriptcontext->SetArgFloat(i, current);
398  } else if constexpr(std::is_same_v<CurrentT, double>) {
399 
400  r = scriptcontext->SetArgDouble(i, current);
401  } else if constexpr(std::is_same_v<CurrentT, char> ||
402  std::is_same_v<CurrentT, int8_t> ||
403  std::is_same_v<CurrentT, bool>) {
404 
405  r = scriptcontext->SetArgByte(i, current);
406 
408  } else if constexpr(std::is_same_v<CurrentT, std::wstring>) {
409 
410  static_assert(!std::is_same_v<CurrentT, std::wstring>,
411  "wstring would have to be saved as a string that can then be passed");
412 
413  } else {
414  // Non-primitive type //
415 
416  // Checks for pointers and references to things with type id verification //
417  if constexpr(std::is_pointer_v<CurrentT>) {
418 
420 
421  r = scriptcontext->SetArgAddress(i, current);
422  } else if constexpr(std::is_lvalue_reference_v<CurrentT>) {
423 
425 
426  r = scriptcontext->SetArgAddress(i, &current);
427  } else if constexpr(std::is_class_v<CurrentT>) {
428 
429  // Has to be a class that isn't a handle type
430  // So make sure it isn't
431  static_assert(!std::is_base_of_v<CurrentT, ReferenceCounted>,
432  "Trying to pass an object of reference type by value to script, call new "
433  "on the argument");
434 
435  // If this is by reference, then it must be const
436  if((flags & asTM_OUTREF)) {
437 
438  LOG_ERROR(
439  "ScriptExecutor: script wants to take parameter: " +
440  std::to_string(i) +
441  " as an outref which isn't supported, for func: " + func->GetName());
442  return false;
443 
444  } else if((flags & asTM_INREF) && !(flags & asTM_CONST)) {
445 
446  LOG_ERROR(
447  "ScriptExecutor: script wants to take parameter: " +
448  std::to_string(i) +
449  " as non-const inref which isn't supported (add const), for func: " +
450  func->GetName());
451  return false;
452 
453  } else {
454 
455  r = scriptcontext->SetArgObject(i, const_cast<CurrentT*>(&current));
456  }
457 
458  } else {
459 
460  static_assert(std::is_same_v<CurrentT, void> == std::is_same_v<CurrentT, int>,
461  "Tried to pass some very weird type to a script function");
462  }
463  }
464 
465  // Move to next parameter for the next recursive call //
466  ++i;
467 
468  // Error check //
469  if(r < 0) {
470  LOG_ERROR("ScriptExecutor: failed to pass parameter number: " +
471  std::to_string(i - 1) + ", for func: " + func->GetName());
472  return false;
473  }
474 
475  // Call other parameters //
476  return _DoPassEachParameter(
477  parameterc, i, scriptcontext, setup, module, func, std::forward<Args>(args)...);
478  }
479 
480 
484  template<typename ReturnT>
485  ScriptRunResult<ReturnT> _HandleEndedScriptExecution(int retcode,
486  asIScriptContext* scriptcontext, ScriptRunningSetup& setup, asIScriptFunction* func,
487  ScriptModule* module)
488  {
489  // Check the return type //
490  if(retcode != asEXECUTION_FINISHED) {
491  // something went wrong //
492 
493  // The execution didn't finish as we had planned. Determine why.
494  switch(retcode) {
495  // script caused an exception //
496  case asEXECUTION_EXCEPTION:
497  PrintExceptionInfo(scriptcontext, *Logger::Get(),
498  scriptcontext->GetExceptionFunction(), module);
499  [[fallthrough]];
500  default:
501  // code took too long //
502  case asEXECUTION_ABORTED:
503  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
504  case asEXECUTION_SUSPENDED:
505  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Suspended);
506  }
507  }
508 
509  // Successfully executed, try to fetch return value //
510 
511  const auto returnType = func->GetReturnTypeId();
512 
513  // Script didn't return anything
514  if(returnType == ANGELSCRIPT_VOID_TYPEID) {
515 
516  // Set the return value to default if it isn't void //
517  if constexpr(std::is_void_v<ReturnT>) {
518  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Success);
519  } else {
520 
521  if(setup.PrintErrors) {
522 
523  if constexpr(std::is_same_v<asIScriptObject*, ReturnT>) {
524 
525  LOG_ERROR(
526  "ScriptExecutor: script return value is void, but application "
527  "expected a value of type: any script object implementing the "
528  "wanted interface");
529 
530  } else if constexpr(std::is_same_v<asIScriptFunction*, ReturnT>) {
531 
532  LOG_ERROR(
533  "ScriptExecutor: script return value is void, but application "
534  "expected a value of type: any script function matching the "
535  "wanted funcdef");
536 
537  } else if constexpr(CanTypeRepresentAngelScriptTypes<ReturnT>()) {
538  LOG_ERROR(
539  "ScriptExecutor: script return value is void, but application "
540  "expected a value of type: other class that can have many "
541  "angelscript types represented by it");
542  } else {
543  LOG_ERROR(
544  "ScriptExecutor: script return value is void, but application "
545  "expected a value of type: " +
546  std::string(typeid(ReturnT).name()) + " id: " +
547  std::to_string(AngelScriptTypeIDResolver<ReturnT>::Get(this)));
548  }
549 
550  LOG_INFO(
551  "ScriptExecutor: while running function: " +
552  (func ? std::string(func->GetDeclaration()) : setup.Entryfunction));
553  }
554 
555  // Rely on 0 being a valid value for pointer etc.
556  if constexpr(std::is_pointer_v<ReturnT> || !std::is_class_v<ReturnT>) {
557  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Success, 0);
558  } else {
559 
560  // Default constructor needs to be available
561  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Success, ReturnT());
562  }
563  }
564  }
565 
566  // script return type isn't void //
567  if constexpr(std::is_same_v<ReturnT, void>) {
568 
569  const auto parameterType = AngelScriptTypeIDResolver<ReturnT>::Get(this);
570 
571  // Success, no return value wanted //
572  if(setup.PrintErrors && (returnType != parameterType)) {
573 
574  LOG_WARNING("ScriptExecutor: application ignoring script return value");
575  }
576 
577  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Success);
578 
579  } else {
580 
581  if constexpr(CanTypeRepresentAngelScriptTypes<ReturnT>()) {
582 
583  // We are getting a generic asIScriptObject or asIScriptFunction
584  asITypeInfo* info = GetTypeInfo(returnType);
585  const auto flags = info->GetFlags();
586 
587  // Verify type //
588  if constexpr(std::is_same_v<ReturnT, asIScriptObject*>) {
589 
590  if(!(flags & asOBJ_SCRIPT_OBJECT)) {
591 
592  LOG_ERROR("ScriptExecutor: application expected a script object but "
593  "script returned: " +
594  std::string(info->GetName()));
595  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
596  }
597 
598  } else if constexpr(std::is_same_v<ReturnT, asIScriptFunction*>) {
599 
600  if(!(flags & asOBJ_FUNCDEF)) {
601 
602  LOG_ERROR("ScriptExecutor: application expected a script function but "
603  "script returned: " +
604  std::string(info->GetName()));
605  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
606  }
607 
608  } else {
609 
610  LOG_FATAL("Unkown angelscript multi type class");
611  }
612 
613  ReturnT obj = static_cast<ReturnT>(scriptcontext->GetReturnObject());
614 
616  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Success, std::move(obj));
617 
618  } else {
619 
620  const auto parameterType = AngelScriptTypeIDResolver<ReturnT>::Get(this);
621 
622  // TODO: conversions between compatible types
623  if(returnType != parameterType) {
624 
625  return _ReturnedTypeDidntMatch<ReturnT>(
626  scriptcontext, setup, func, module, parameterType, returnType);
627  }
628 
629  if constexpr(std::is_same_v<ReturnT, int32_t> ||
630  std::is_same_v<ReturnT, uint32_t>) {
631 
632  return ScriptRunResult<ReturnT>(
633  SCRIPT_RUN_RESULT::Success, scriptcontext->GetReturnDWord());
634  } else if constexpr(std::is_same_v<ReturnT, int64_t> ||
635  std::is_same_v<ReturnT, uint64_t>) {
636 
637  return ScriptRunResult<ReturnT>(
638  SCRIPT_RUN_RESULT::Success, scriptcontext->GetReturnQWord());
639  } else if constexpr(std::is_same_v<ReturnT, float>) {
640 
641  return ScriptRunResult<ReturnT>(
642  SCRIPT_RUN_RESULT::Success, scriptcontext->GetReturnFloat());
643  } else if constexpr(std::is_same_v<ReturnT, double>) {
644 
645  return ScriptRunResult<ReturnT>(
646  SCRIPT_RUN_RESULT::Success, scriptcontext->GetReturnDouble());
647  } else if constexpr(std::is_same_v<ReturnT, char> ||
648  std::is_same_v<ReturnT, int8_t> ||
649  std::is_same_v<ReturnT, bool>) {
650 
651  return ScriptRunResult<ReturnT>(
652  SCRIPT_RUN_RESULT::Success, scriptcontext->GetReturnByte());
653  } else {
654 
655  // This is a class type and we need to do a copy if it was
656  // by value or this isn't a handle type
657 
658  // According to AS documentation the return object is
659  // deleted when the context is recycled, so we need to
660  // increase ref or make a copy
661 
662  if constexpr(std::is_pointer_v<ReturnT>) {
663 
664  // We have already done type checks, so this should be fine to cast //
665  ReturnT obj = static_cast<ReturnT>(scriptcontext->GetReturnObject());
666 
668  return ScriptRunResult<ReturnT>(
669  SCRIPT_RUN_RESULT::Success, std::move(obj));
670 
671  } else if constexpr(std::is_lvalue_reference_v<ReturnT>) {
672 
673  static_assert(!std::is_class_v<ReturnT>,
674  "Returning by reference from scripts doesn't work");
675 
676  } else if constexpr(std::is_class_v<ReturnT>) {
677 
678  // We have already done type checks, so this should be fine to cast //
679  ReturnT* obj = static_cast<ReturnT*>(scriptcontext->GetReturnObject());
680  return ScriptRunResult<ReturnT>(
681  SCRIPT_RUN_RESULT::Success, std::move(*obj));
682  } else {
683 
684  static_assert(
685  std::is_same_v<ReturnT, void> == std::is_same_v<ReturnT, int>,
686  "Tried to return some very weird type from a script function");
687  }
688  }
689  }
690  }
691  }
692 
700  template<class... Args>
701  bool _PassParametersToScript(asIScriptContext* scriptcontext, ScriptRunningSetup& setup,
702  ScriptModule* module, asIScriptFunction* func, Args&&... args)
703  {
704  // Get the number of parameters expected //
705  auto parameterc = func->GetParamCount();
706  asUINT i = 0;
707 
708  // Start passing the parameters provided by the application //
709  if(!_DoPassEachParameter(
710  parameterc, i, scriptcontext, setup, module, func, std::forward<Args>(args)...))
711  return false;
712 
713  // Check that we passed enough parameters for the script (we
714  // don't care if the script took less parameters than we gave
715  // it)
716  if(i < parameterc) {
717  // We didn't have enough parameters
718  if(setup.PrintErrors) {
719  LOG_ERROR("ScriptExecutor: not enough parameters to pass to script function");
720  }
721 
722  return false;
723  }
724 
725  return true;
726  }
727 
728  // End condition for the variadic template
729  bool _DoPassEachParameter(asUINT parameterc, asUINT& i, asIScriptContext* scriptcontext,
730  ScriptRunningSetup& setup, ScriptModule* module, asIScriptFunction* func)
731  {
732  return true;
733  }
734 
736  template<typename ReturnT>
737  ScriptRunResult<ReturnT> _ReturnedTypeDidntMatch(asIScriptContext* scriptcontext,
738  ScriptRunningSetup& setup, asIScriptFunction* func, ScriptModule* module,
739  int parameterType, int returnType)
740  {
741  _DoReceiveParameterTypeError(setup, module, parameterType, returnType);
742  return ScriptRunResult<ReturnT>(SCRIPT_RUN_RESULT::Error);
743  }
744 
750  DLLEXPORT bool _DoPassParameterTypeError(ScriptRunningSetup& setup, ScriptModule* module,
751  int i, int scriptwanted, int provided);
752 
755  DLLEXPORT void _DoReceiveParameterTypeError(
756  ScriptRunningSetup& setup, ScriptModule* module, int applicationwanted, int scripthad);
757 
758 
759 
763  void _CallBehaviourReleaseIfNeeded(void* obj, int returnTypeID)
764  {
765  // TODO: this should instead call engine->ReleaseScriptObject
766  asITypeInfo* info = GetASEngine()->GetTypeInfoById(returnTypeID);
767 
768  const auto flags = info->GetFlags();
769  if((flags & asOBJ_REF) && !(flags & asOBJ_NOCOUNT)) {
770 
771  LOG_INFO("ScriptExecutor: attempting to release ref through angelscript");
772 
773  RunReleaseRefOnObject(obj, returnTypeID);
774 
775  LOG_INFO("Success calling behaviour release");
776  }
777  }
778 
779 
780  // ------------------------------------ //
781 
783  DLLEXPORT bool _CheckScriptFunctionPtr(
784  asIScriptFunction* func, ScriptRunningSetup& parameters, ScriptModule* scrptmodule);
785 
787  DLLEXPORT bool _PrepareContextForPassingParameters(asIScriptFunction* func,
788  asIScriptContext* ScriptContext, ScriptRunningSetup& parameters,
789  ScriptModule* scriptmodule);
790 
791 protected:
794  DLLEXPORT asIScriptContext* _GetContextForExecution();
795 
798  DLLEXPORT void _DoneWithContext(asIScriptContext* context);
799 
800 private:
801  // AngelScript engine script executing part //
802  asIScriptEngine* engine;
803 
804  // list of modules that have been created, some might only have this as reference, and
805  // could potentially be released
806  std::vector<std::shared_ptr<ScriptModule>> AllocatedScriptModules;
807 
808  Mutex ModulesLock;
809 
811  std::vector<asIScriptContext*> ContextPool;
812 
814  Mutex ContextPoolLock;
815 
816  static ScriptExecutor* instance;
817 };
818 
819 } // namespace Leviathan
DLLEXPORT int ResolveStringToASID(const char *str) const
Converts a string to angelscript type id. Returns -1 on error.
ScriptRunResult< ReturnT > RunScript(const std::shared_ptr< ScriptModule > &module, ScriptRunningSetup &parameters, Args &&... args)
Runs a function in a script.
ScriptRunningSetup Setup
DLLEXPORT asIScriptFunction * GetFunctionFromModule(ScriptModule *module, ScriptRunningSetup &parameters)
Finds a script function in module matching setup.
DLLEXPORT asIScriptEngine * GetASEngine()
#define LOG_INFO(x)
Definition: Define.h:81
ScriptRunResult< ReturnT > ExecuteCustomRun(const std::unique_ptr< CustomScriptRun > &run)
Ends a custom script run by actually executing the script and returning a value.
friend void ReturnContextCallback(asIScriptEngine *engine, asIScriptContext *context, void *userdata)
#define LOG_ERROR(x)
Definition: Define.h:83
DLLEXPORT std::shared_ptr< ScriptModule > GetScriptModuleByFunction(asIScriptFunction *func, bool reporterror)
Returns module in which script function was defined in.
static int Get(ScriptExecutor *resolver)
DLLEXPORT void RunReleaseRefOnObject(void *obj, int objid)
Finds release ref behaviour on object and calls it.
#define LOG_FATAL(x)
Definition: Define.h:85
constexpr auto ANGELSCRIPT_VOID_TYPEID
This has to be constant (and luckily so far it has been)
DLLEXPORT std::weak_ptr< ScriptModule > GetModuleByAngelScriptName(const char *nameofmodule)
DLLEXPORT asITypeInfo * GetTypeInfo(int type) const
Returns an asITypeInfo object for type id or null.
CustomScriptRun(ScriptExecutor *exec)
Handles ScriptModule creation and AngelScript code execution.
DLLEXPORT void CollectGarbage()
Does a full garbage collection cycle.
static int GetID()
Definition: IDFactory.h:17
static DLLEXPORT void PrintCallstack(asIScriptContext *ctx, LErrorReporter &output)
static DLLEXPORT void PrintExceptionInfo(asIScriptContext *ctx, LErrorReporter &output, asIScriptFunction *func=nullptr, ScriptModule *scrptmodule=nullptr)
Prints exception info and stacktrace to a logger.
#define LOG_WARNING(x)
Definition: Define.h:82
DLLEXPORT std::weak_ptr< ScriptModule > CreateNewModule(const std::string &name, const std::string &source, const int &modulesid=IDFactory::GetID())
Holds a result of the new script run method.
static DLLEXPORT ScriptExecutor * Get()
DLLEXPORT bool DeleteModuleIfNoExternalReferences(int ID)
Contains data for script runs where arguments are passed manually.
std::shared_ptr< ScriptModule > Module
std::mutex Mutex
Definition: ThreadSafe.h:14
DLLEXPORT asITypeInfo * GetTypeInfoByDecl(const char *str) const
Returns an asITypeInfo object for type name or null.
static DLLEXPORT Logger * Get()
Definition: Logger.cpp:106
ScriptRunResult< ReturnT > RunScriptMethod(ScriptRunningSetup &parameters, asIScriptFunction *func, void *obj, Args &&... args)
Runs a method in a script.
asIScriptFunction * Func
#define DLLEXPORT
Definition: Include.h:115
DLLEXPORT void _DoneWithContext(asIScriptContext *context)
Called after a script has been executed and the context is no longer needed.
DLLEXPORT std::unique_ptr< CustomScriptRun > PrepareCustomScriptRun(asIScriptFunction *func, ScriptRunningSetup extraoptions=ScriptRunningSetup())
Starts a script run that supports custom argument passing.
DLLEXPORT std::weak_ptr< ScriptModule > GetModule(const int &ID)
DLLEXPORT void DeleteModule(ScriptModule *ptrtomatch)
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
ScriptRunResult< ReturnT > RunScript(asIScriptFunction *func, std::shared_ptr< ScriptModule > module, ScriptRunningSetup &parameters, Args &&... args)
Runs a function in a script (that is known already)
friend asIScriptContext * RequestContextCallback(asIScriptEngine *engine, void *userdata)
static void IncrementRefCountIfRefCountedType(T *current)
Increments refcount of obj if it is derived from ReferenceCounted or an angelscript type...
DLLEXPORT asIScriptContext * _GetContextForExecution()
Called when a context is required for script execution.
asIScriptContext * Context