RigsofRods
Soft-body Physics Simulation
ScriptEngine.cpp
Go to the documentation of this file.
1 /*
2  This source file is part of Rigs of Rods
3  Copyright 2005-2012 Pierre-Michel Ricordel
4  Copyright 2007-2012 Thomas Fischer
5  Copyright 2013-2020 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
25 
26 #include "ScriptEngine.h"
27 
28 // AS addons start
29 #include "scriptstdstring/scriptstdstring.h"
30 #include "scriptmath/scriptmath.h"
31 #include "scriptany/scriptany.h"
32 #include "scriptarray/scriptarray.h"
33 #include "scripthelper/scripthelper.h"
34 // AS addons end
35 
36 #ifdef USE_CURL
37 #include <stdio.h>
38 #include <curl/curl.h>
39 //#include <curl/types.h>
40 #include <curl/easy.h>
41 #endif //USE_CURL
42 
43 #include <cfloat>
44 
45 #include "Application.h"
46 #include "Actor.h"
47 #include "ActorManager.h"
48 #include "Collisions.h"
49 #include "Console.h"
50 #include "GameContext.h"
51 #include "GameScript.h"
52 #include "LocalStorage.h"
53 #include "OgreScriptBuilder.h"
54 #include "PlatformUtils.h"
55 #include "ScriptEvents.h"
56 #include "ScriptUtils.h"
57 #include "Utils.h"
58 #include "VehicleAI.h"
59 
60 #include "InputEngine.h"
61 
62 using namespace Ogre;
63 using namespace RoR;
64 using namespace AngelScript;
65 
67 {
68  switch (c)
69  {
70  case ScriptCategory::INVALID: return "INVALID";
71  case ScriptCategory::ACTOR: return "ACTOR";
72  case ScriptCategory::TERRAIN: return "TERRAIN";
73  case ScriptCategory::CUSTOM: return "CUSTOM";
74  default: return "";
75  }
76 }
77 
78 ScriptUnit::ScriptUnit()
79 {
80  // Constructs `ActorPtr` - doesn't compile without `#include Actor.h` - not pretty if in header (even if auto-generated by C++).
81 }
82 
83 ScriptUnit::~ScriptUnit()
84 {
85  // Destructs `ActorPtr` - doesn't compile without `#include Actor.h` - not pretty if in header (even if auto-generated by C++).
86 }
87 
88 // some hacky functions
89 
90 void logString(const std::string &str)
91 {
92  App::GetScriptEngine()->SLOG(str);
93 }
94 
95 // the class implementation
96 
97 ScriptEngine::ScriptEngine() :
98  context(0)
99  , engine(0)
100  , scriptLog(0)
101 {
102  scriptLog = LogManager::getSingleton().createLog(PathCombine(App::sys_logs_dir->getStr(), "Angelscript.log"), false);
103  this->init();
104 }
105 
107 {
108  // Clean up
109  if (engine) engine->Release();
110  if (context) context->Release();
111 }
112 
113 void ScriptEngine::messageLogged( const String& message, LogMessageLevel lml, bool maskDebug, const String &logName, bool& skipThisMessage)
114 {
116 }
117 
118 // continue with initializing everything
120 {
121  SLOG("ScriptEngine initializing ...");
122  int result;
123 
124  // Create the script engine
125  engine = AngelScript::asCreateScriptEngine(ANGELSCRIPT_VERSION);
126 
127  engine->SetEngineProperty(AngelScript::asEP_ALLOW_UNSAFE_REFERENCES, true); // Needed for ImGui
128 
129  // Set the message callback to receive information on errors in human readable form.
130  // It's recommended to do this right after the creation of the engine, because if
131  // some registration fails the engine may send valuable information to the message
132  // stream.
133  result = engine->SetMessageCallback(AngelScript::asMETHOD(ScriptEngine,msgCallback), this, AngelScript::asCALL_THISCALL);
134  if (result < 0)
135  {
136  if (result == AngelScript::asINVALID_ARG)
137  {
138  SLOG("One of the arguments is incorrect, e.g. obj is null for a class method.");
139  return;
140  }
141  else if (result == AngelScript::asNOT_SUPPORTED)
142  {
143  SLOG(" The arguments are not supported, e.g. asCALL_GENERIC.");
144  return;
145  }
146  SLOG("Unkown error while setting up message callback");
147  return;
148  }
149 
150  // AngelScript doesn't have a built-in string type, as there is no definite standard
151  // string type for C++ applications. Every developer is free to register it's own string type.
152  // The SDK do however provide a standard add-on for registering a string type, so it's not
153  // necessary to register your own string type if you don't want to.
154  AngelScript::RegisterScriptArray(engine, true);
155  AngelScript::RegisterStdString(engine);
156  AngelScript::RegisterStdStringUtils(engine);
157  AngelScript::RegisterScriptMath(engine);
158  static float SCRIPT_FLT_MAX = FLT_MAX;
159  static int SCRIPT_INT_MAX = INT_MAX;
160  result = engine->RegisterGlobalProperty("const float FLT_MAX", &SCRIPT_FLT_MAX); ROR_ASSERT( result >= 0 );
161  result = engine->RegisterGlobalProperty("const int INT_MAX", &SCRIPT_INT_MAX); ROR_ASSERT(result >= 0);
162  AngelScript::RegisterScriptAny(engine);
163  AngelScript::RegisterScriptDictionary(engine);
164 
165  // some useful global functions
166  result = engine->RegisterGlobalFunction("void log(const string &in)", AngelScript::asFUNCTION(logString), AngelScript::asCALL_CDECL); ROR_ASSERT( result >= 0 );
167  result = engine->RegisterGlobalFunction("void print(const string &in)", AngelScript::asFUNCTION(logString), AngelScript::asCALL_CDECL); ROR_ASSERT( result >= 0 );
168 
169  RegisterOgreObjects(engine); // vector2/3, degree, radian, quaternion, color
170  RegisterLocalStorage(engine); // LocalStorage
171  RegisterInputEngine(engine); // InputEngineClass, inputEvents
172  RegisterImGuiBindings(engine); // ImGUi::
173  RegisterVehicleAi(engine); // VehicleAIClass, aiEvents, AiValues
174  RegisterConsole(engine); // ConsoleClass, CVarClass, CVarFlags
175  RegisterActor(engine); // BeamClass
176  RegisterProceduralRoad(engine);// procedural_point, ProceduralRoadClass, ProceduralObjectClass, ProceduralManagerClass
177  RegisterTerrain(engine); // TerrainClass
178  RegisterMessageQueue(engine); // enum MsgType
179  RegisterSoundScript(engine); // SoundTriggers, ModulationSource, SoundScriptTemplate...
180  RegisterGameScript(engine); // GameScriptClass
181  RegisterScriptEvents(engine); // scriptEvents
182  RegisterGenericFileFormat(engine); // TokenType, GenericDocumentClass, GenericDocReaderClass
183  RegisterCacheSystem(engine); // LoaderType, CacheEntryClass, CacheSystemClass
184 
185  // now the global instances
186  result = engine->RegisterGlobalProperty("GameScriptClass game", &m_game_script); ROR_ASSERT(result>=0);
187  result = engine->RegisterGlobalProperty("ConsoleClass console", App::GetConsole()); ROR_ASSERT(result>=0);
188  result = engine->RegisterGlobalProperty("InputEngineClass inputs", App::GetInputEngine()); ROR_ASSERT(result>=0);
189  result = engine->RegisterGlobalProperty("CacheSystemClass modcache", App::GetCacheSystem()); ROR_ASSERT(result>=0);
190 
191  SLOG("Type registrations done. If you see no error above everything should be working");
192 
193  context = engine->CreateContext();
194 }
195 
196 void ScriptEngine::msgCallback(const AngelScript::asSMessageInfo *msg)
197 {
198  const char *type = "Error";
199  if ( msg->type == AngelScript::asMSGTYPE_INFORMATION )
200  type = "Info";
201  else if ( msg->type == AngelScript::asMSGTYPE_WARNING )
202  type = "Warning";
203 
204  char tmp[1024]="";
205  sprintf(tmp, "%s (%d, %d): %s = %s", msg->section, msg->row, msg->col, type, msg->message);
206  SLOG(tmp);
207 
209  m_currently_executing_script_unit, msg->type, msg->row, msg->col, // ints
210  msg->section, msg->message); // strings
211 }
212 
213 std::string ptr2str(const char* ptr) { if (ptr) return ptr; else return ""; }
214 
215 void ScriptEngine::lineCallback(AngelScript::asIScriptContext* ctx)
216 {
217  std::string funcName, funcObjTypeName, objName;
218  if (ctx->GetFunction())
219  {
220  funcName = ptr2str(ctx->GetFunction()->GetName());
221  objName = ptr2str(ctx->GetFunction()->GetObjectName());
222  if (ctx->GetFunction()->GetObjectType())
223  funcObjTypeName = ptr2str(ctx->GetFunction()->GetObjectType()->GetName());
224  }
226  // ints
227  m_currently_executing_script_unit, ctx->GetLineNumber(), ctx->GetCallstackSize(), 0,
228  // strings
229  funcName, funcObjTypeName, objName
230  );
231 }
232 
233 void ScriptEngine::exceptionCallback(AngelScript::asIScriptContext* ctx)
234 {
235  //Disabled, too noisy//this->logExceptionDetails();
236  std::string funcName;
237  if (ctx->GetExceptionFunction())
238  {
239  funcName = ptr2str(ctx->GetExceptionFunction()->GetName());
240  }
242  m_currently_executing_script_unit, 0, ctx->GetExceptionLineNumber(), 0, // ints
243  funcName, ctx->GetExceptionString()); // strings
244 }
245 
246 void ScriptEngine::forwardExceptionAsScriptEvent(const std::string& from)
247 {
248  // Forwards useful info from C++ exceptions to script in the form of game event.
249  // AngelScript doesn't have exceptions in the `try{}catch{}` sense
250  // (in AS jargon, 'Exception' means basically 'panic' as in Lua/Rust...)
251  // and most exceptions this game encounters (`Ogre::Exception`) are trivially recoverable,
252  // so it doesn't make sense to panic AngelScript when they happen.
253  // =======================================================================================
254 
255  try { throw; } // Rethrow
256 
257  // OGRE
258  catch (Ogre::IOException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "IOException", e.getDescription()); }
259  catch (Ogre::InvalidStateException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "InvalidStateException", e.getDescription()); }
260  catch (Ogre::InvalidParametersException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "InvalidParametersException", e.getDescription()); }
261  catch (Ogre::RenderingAPIException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "RenderingAPIException", e.getDescription()); }
262  catch (Ogre::ItemIdentityException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "ItemIdentityException", e.getDescription()); }
263  catch (Ogre::FileNotFoundException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "FileNotFoundException", e.getDescription()); }
264  catch (Ogre::InternalErrorException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "InternalErrorException", e.getDescription()); }
265  catch (Ogre::RuntimeAssertionException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "RuntimeAssertionException", e.getDescription()); }
266  catch (Ogre::UnimplementedException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "UnimplementedException", e.getDescription()); }
267  catch (Ogre::InvalidCallException& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "InvalidCallException", e.getDescription()); }
268  catch (Ogre::Exception& e ) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "Exception", e.getDescription()); }
269 
270  // STD
271  catch (std::exception& e) { TRIGGER_EVENT_ASYNC(SE_GENERIC_EXCEPTION_CAUGHT, m_currently_executing_script_unit,0,0,0, from, "std::exception", e.what()); }
272 
273  // Unrecognized
275 }
276 
278 {
279  // Helper for executing any script function/snippet;
280  // * sets LineCallback (on demand - when script registers for SE_ANGELSCRIPT_LINECALLBACK event)
281  // * sets ExceptionCallback (on demand - when script registers for SE_ANGELSCRIPT_EXCEPTIONCALLBACK event)
282  // * sets currently executed NID;
283  // IMPORTANT: The `asIScriptContext::Prepare()` must be already done (this enables programmer to set args).
284  // IMPORTANT: `m_currently_executing_event_trigger` must be set externally!
285  // =========================================================================================================
286 
287  // Automatically attach the LineCallback if the script registered for the event.
288  // (except if we're about to run that callback - that would trap us in loop)
290  && m_script_units[nid].eventMask & SE_ANGELSCRIPT_LINECALLBACK)
291  {
292  int result = context->SetLineCallback(asMETHOD(ScriptEngine, lineCallback), this, asCALL_THISCALL);
293  if (result < 0)
294  {
295  SLOG(fmt::format("Warning: Could not attach LineCallback to NID {}, error code {}; continuing without it...", result, nid));
296  }
297  }
298 
299  // Attach the ExceptionCallback if the script registered for the event.
301  {
302  int result = context->SetExceptionCallback(asMETHOD(ScriptEngine, exceptionCallback), this, asCALL_THISCALL);
303  if (result < 0)
304  {
305  SLOG(fmt::format("Warning: Could not attach ExceptionCallback to NID {}, error code {}; continuing without it...", result, nid));
306  }
307  }
308 
309  // Run the script
311  int result = context->Execute();
313 
314  if ( result != AngelScript::asEXECUTION_FINISHED )
315  {
316  // The execution didn't complete as expected. Determine what happened.
317  if ( result == AngelScript::asEXECUTION_ABORTED )
318  {
319  SLOG("The script was aborted before it could finish. Probably it timed out.");
320  }
321  else if ( result == AngelScript::asEXECUTION_EXCEPTION )
322  {
323  // An exception occurred, let the script writer know what happened so it can be corrected.
324  // NOTE: this result is only reported if exception callback is not registered, see `SetExceptionCallback()`
325  SLOG("The script ended with exception; details below:");
326  // Write some information about the script exception
327  SLOG("\tcontext.ExceptionLineNumber: " + TOSTRING(context->GetExceptionLineNumber()));
328  SLOG("\tcontext.ExceptionString: " + ptr2str(context->GetExceptionString()));
329  AngelScript::asIScriptFunction* func = context->GetExceptionFunction();
330  if (func)
331  {
332  SLOG("\tcontext.ExceptionFunction.Declaration: " + ptr2str(func->GetDeclaration()));
333  SLOG("\tcontext.ExceptionFunction.ModuleName: " + ptr2str(func->GetModuleName()));
334  SLOG("\tcontext.ExceptionFunction.ScriptSectionName: " + ptr2str(func->GetScriptSectionName()));
335  SLOG("\tcontext.ExceptionFunction.ObjectName: " + ptr2str(func->GetObjectName()));
336  }
337  }
338  else if (result == AngelScript::asCONTEXT_NOT_PREPARED)
339  {
340  if (context->GetFunction())
341  {
342  SLOG(fmt::format("The script ended with error code asCONTEXT_NOT_PREPARED; Function to execute: {},currently triggered event: {}, NID: {}",
343  context->GetFunction()->GetName(), fmt::underlying(m_currently_executing_event_trigger), nid));
344  }
345  else
346  {
347  SLOG(fmt::format("The script ended with error code asCONTEXT_NOT_PREPARED; Function to execute NOT SET,currently triggered event: {}, NID: {}",
348  fmt::underlying(m_currently_executing_event_trigger), nid));
349  }
350  }
351  else
352  {
353  SLOG("The script ended for some unforeseen reason " + TOSTRING(result));
354  }
355  }
356 
357  // Clear the callbacks so they don't intercept unrelated operations.
358  context->ClearLineCallback();
359  context->ClearExceptionCallback();
360 
361  return result;
362 }
363 
365 {
366  asIScriptFunction* scriptFunc = this->engine->GetFunctionById(asFunctionID);
367  if (!scriptFunc)
368  {
369  SLOG(fmt::format("Cannot execute script function with ID {} - not found", asFunctionID));
370  return false;
371  }
372 
373  int result = this->context->Prepare(scriptFunc);
374  if (result < 0)
375  {
376  SLOG(fmt::format("Cannot execute script function '{}': `AngelScript::Context::Prepare()` reported error code {}",
377  scriptFunc->GetName(), result));
378  return false;
379  }
380 
381  return true;
382 }
383 
385 {
386  // Check if we need to execute any strings
387  std::vector<String> tmpQueue;
388  stringExecutionQueue.pull(tmpQueue);
389  std::vector<String>::iterator it;
390  for (it=tmpQueue.begin(); it!=tmpQueue.end();it++)
391  {
392  executeString(*it);
393  }
394 
395  // framestep stuff below
396  if (!engine || !context) return;
397 
398  for (auto& pair: m_script_units)
399  {
400  ScriptUnitId_t nid = pair.first;
401  if (m_script_units[nid].frameStepFunctionPtr)
402  {
403  // Set the function pointer and arguments
404  context->Prepare(m_script_units[nid].frameStepFunctionPtr);
405  context->SetArgFloat(0, dt);
406 
407  // Run the context via helper
409  }
410  }
411 }
412 
413 int ScriptEngine::fireEvent(std::string instanceName, float intensity)
414 {
415  if (!engine || !context)
416  return 0;
417 
418  for (auto& pair: m_script_units)
419  {
420  ScriptUnitId_t id = pair.first;
421  AngelScript::asIScriptFunction* func = m_script_units[id].scriptModule->GetFunctionByDecl(
422  "void fireEvent(string, float)"); // TODO: this shouldn't be hard coded --neorej16
423 
424  context->Prepare(func);
425 
426  // Set the function arguments
427  context->SetArgObject(0, &instanceName);
428  context->SetArgFloat (1, intensity);
429 
431  int r = context->Execute();
433  if ( r == AngelScript::asEXECUTION_FINISHED )
434  {
435  // The return value is only valid if the execution finished successfully
436  AngelScript::asDWORD ret = context->GetReturnDWord();
437  }
438  }
439 
440  return 0;
441 }
442 
443 void ScriptEngine::envokeCallback(int _functionId, eventsource_t *source, NodeNum_t nodenum, int type)
444 {
445  // THIS IS OBSOLETE - Use `eventCallbackEx()` and `SE_EVENTBOX_ENTER` instead.
446  // ################
447  // Legacy eventbox handler, specified by name in .TOBJ file or in call to `game.spawnObject()`
448  // ===========================================================================================
449  if (!engine || !context)
450  return;
451 
452  for (auto& pair: m_script_units)
453  {
454  ScriptUnitId_t id = pair.first;
455  int functionId = _functionId;
456  if (functionId <= 0 && (m_script_units[id].defaultEventCallbackFunctionPtr != nullptr))
457  {
458  // use the default event handler instead then
459  functionId = m_script_units[id].defaultEventCallbackFunctionPtr->GetId();
460  }
461 
462  if (this->prepareContextAndHandleErrors(id, functionId))
463  {
464  // Set the function arguments
465  context->SetArgDWord (0, type);
466  context->SetArgObject(1, &source->es_instance_name);
467  context->SetArgObject(2, &source->es_box_name);
468  if (nodenum != NODENUM_INVALID)
469  context->SetArgDWord (3, static_cast<AngelScript::asDWORD>(nodenum));
470  else
471  context->SetArgDWord (3, static_cast<AngelScript::asDWORD>(-1));
472 
474  }
475  }
476 }
477 
478 void ScriptEngine::queueStringForExecution(const String command)
479 {
480  stringExecutionQueue.push(command);
481 }
482 
483 int ScriptEngine::executeString(String command)
484 {
485  if (!engine || !context)
486  return 1;
487 
488  // Only works with terrain script module (classic behavior)
490  return 1;
491 
492  AngelScript::asIScriptModule *mod = m_script_units[m_terrain_script_unit].scriptModule;
493  int result = ExecuteString(engine, command.c_str(), mod, context);
494  if (result < 0)
495  {
496  SLOG("error " + TOSTRING(result) + " while executing string: " + command + ".");
497  }
498  return result;
499 }
500 
501 int ScriptEngine::addFunction(const String &arg)
502 {
503  if (!engine || !context)
504  return 1;
505 
506  if (!context)
507 
508 
509  // Only works with terrain script module (classic behavior)
511  return 1;
512 
513  AngelScript::asIScriptModule *mod = m_script_units[m_terrain_script_unit].scriptModule;
514 
515  AngelScript::asIScriptFunction *func = 0;
516  int r = mod->CompileFunction("addfunc", arg.c_str(), 0, AngelScript::asCOMP_ADD_TO_MODULE, &func);
517 
518  if ( r < 0 )
519  {
520  char tmp[512] = "";
521  snprintf(tmp, 512, "An error occurred while trying to add a function ('%s') to script module '%s'.", arg.c_str(), mod->GetName());
522  SLOG(tmp);
523  }
524  else
525  {
526  // successfully added function; Check if we added a "special" function
527 
528  if (func == mod->GetFunctionByDecl("void frameStep(float)"))
529  {
530  if (m_script_units[m_terrain_script_unit].frameStepFunctionPtr == nullptr)
531  m_script_units[m_terrain_script_unit].frameStepFunctionPtr = func;
532  }
533  else if (func == mod->GetFunctionByDecl("void eventCallback(int, int)"))
534  {
535  if (m_script_units[m_terrain_script_unit].eventCallbackFunctionPtr == nullptr)
536  m_script_units[m_terrain_script_unit].eventCallbackFunctionPtr = func;
537  }
538  else if (func == mod->GetFunctionByDecl("void eventCallbackEx(scriptEvents, int, int, int, int, string, string, string, string)"))
539  {
540  if (m_script_units[m_terrain_script_unit].eventCallbackExFunctionPtr == nullptr)
541  m_script_units[m_terrain_script_unit].eventCallbackExFunctionPtr = func;
542  }
543  // THIS IS OBSOLETE - Use `eventCallbackEx()` and `SE_EVENTBOX_ENTER` instead. See commentary in `envokeCallback()`
544  else if (func == this->getFunctionByDeclAndLogCandidates(
547  {
548  if (m_script_units[m_terrain_script_unit].defaultEventCallbackFunctionPtr == nullptr)
549  m_script_units[m_terrain_script_unit].defaultEventCallbackFunctionPtr = func;
550  }
551  }
552 
553  // We must release the function object
554  if ( func )
555  func->Release();
556 
557  return r;
558 }
559 
560 int ScriptEngine::functionExists(const String &arg)
561 {
562  if (!engine || !context) // WTF? If the scripting engine failed to start, how would it invoke this function?
563  return -1; // ... OK, I guess the author wanted the fn. to be usable both within script and C++, but IMO that's bad design (generally good, but bad for a game.. bad for RoR), really ~ only_a_ptr, 09/2017
564 
565  // Only works with terrain script module (classic behavior)
567  return -1;
568 
569  AngelScript::asIScriptModule *mod = m_script_units[m_terrain_script_unit].scriptModule;
570 
571  if (mod == 0)
572  {
573  return AngelScript::asNO_FUNCTION; // Nope, it's an internal error, not a "function not found" case ~ only_a_ptr, 09/2017
574  }
575  else
576  {
577  AngelScript::asIScriptFunction* fn = mod->GetFunctionByDecl(arg.c_str());
578  if (fn != nullptr)
579  return fn->GetId();
580  else
581  return AngelScript::asNO_FUNCTION;
582  }
583 }
584 
585 int ScriptEngine::deleteFunction(const String &arg)
586 {
587  if (!engine || !context)
588  return AngelScript::asERROR;
589 
590  // Only works with terrain script module (classic behavior)
592  return -1;
593 
594  AngelScript::asIScriptModule *mod = m_script_units[m_terrain_script_unit].scriptModule;
595 
596  if ( mod->GetFunctionCount() == 0 )
597  {
598  char tmp[512] = "";
599  sprintf(tmp, "An error occurred while trying to remove a function ('%s') from script module '%s': No functions have been added (and consequently: the function does not exist).", arg.c_str(), mod->GetName());
600  SLOG(tmp);
601  return AngelScript::asNO_FUNCTION;
602  }
603 
604  AngelScript::asIScriptFunction* func = mod->GetFunctionByDecl(arg.c_str());
605  if (func != nullptr)
606  {
607  // Warning: The function is not destroyed immediately, only when no more references point to it.
608  mod->RemoveFunction(func);
609 
610  // Since functions can be recursive, we'll call the garbage
611  // collector to make sure the object is really freed
612  engine->GarbageCollect();
613 
614  // Check if we removed a "special" function
615 
616  if ( m_script_units[m_terrain_script_unit].frameStepFunctionPtr == func )
617  m_script_units[m_terrain_script_unit].frameStepFunctionPtr = nullptr;
618 
619  if ( m_script_units[m_terrain_script_unit].eventCallbackFunctionPtr == func )
620  m_script_units[m_terrain_script_unit].eventCallbackFunctionPtr = nullptr;
621 
622  if (m_script_units[m_terrain_script_unit].eventCallbackExFunctionPtr == func)
623  m_script_units[m_terrain_script_unit].eventCallbackExFunctionPtr = nullptr;
624 
625  if ( m_script_units[m_terrain_script_unit].defaultEventCallbackFunctionPtr == func )
626  m_script_units[m_terrain_script_unit].defaultEventCallbackFunctionPtr = nullptr;
627 
628  return func->GetId();
629  }
630  else
631  {
632  char tmp[512] = "";
633  sprintf(tmp, "An error occurred while trying to remove a function ('%s') from script module '%s'.", arg.c_str(), mod->GetName());
634  SLOG(tmp);
635  return AngelScript::asERROR;
636  }
637 }
638 
639 int ScriptEngine::addVariable(const String &arg)
640 {
641  if (!engine || !context) return 1;
642  // Only works with terrain script module (classic behavior)
644  return 1;
645 
646  AngelScript::asIScriptModule *mod = m_script_units[m_terrain_script_unit].scriptModule;
647 
648  int r = mod->CompileGlobalVar("addvar", arg.c_str(), 0);
649  if ( r < 0 )
650  {
651  char tmp[512] = "";
652  sprintf(tmp, "An error occurred while trying to add a variable ('%s') to script module '%s'.", arg.c_str(), mod->GetName());
653  SLOG(tmp);
654  }
655 
656  return r;
657 }
658 
659 int ScriptEngine::deleteVariable(const String &arg)
660 {
661  if (!engine || !context) return 1;
662  // Only works with terrain script module (classic behavior)
664  return 1;
665  AngelScript::asIScriptModule *mod = m_script_units[m_terrain_script_unit].scriptModule;
666 
667  if ( mod == 0 || mod->GetGlobalVarCount() == 0 )
668  {
669  char tmp[512] = "";
670  sprintf(tmp, "An error occurred while trying to remove a variable ('%s') from script module '%s': No variables have been added (and consequently: the variable does not exist).", arg.c_str(), mod->GetName());
671  SLOG(tmp);
672  return AngelScript::asNO_GLOBAL_VAR;
673  }
674 
675  int index = mod->GetGlobalVarIndexByName(arg.c_str());
676  if ( index >= 0 )
677  {
678  index = mod->RemoveGlobalVar(index);
679  }
680  else
681  {
682  char tmp[512] = "";
683  sprintf(tmp, "An error occurred while trying to remove a variable ('%s') from script module '%s'.", arg.c_str(), mod->GetName());
684  SLOG(tmp);
685  }
686 
687  return index;
688 }
689 
690 asIScriptFunction* ScriptEngine::getFunctionByDeclAndLogCandidates(ScriptUnitId_t nid, GetFuncFlags_t flags, const std::string& funcName, const std::string& fmtFuncDecl)
691 {
692  std::string decl = fmt::format(fmtFuncDecl, funcName);
693  asIScriptFunction* retval = m_script_units[nid].scriptModule->GetFunctionByDecl(decl.c_str());
694  if (!retval)
695  {
696  asIScriptFunction* candidate = m_script_units[nid].scriptModule->GetFunctionByName(funcName.c_str());
697  if (candidate && BITMASK_IS_0(flags, GETFUNCFLAG_SILENT))
698  {
699  SLOG(fmt::format("Warning: a callback function with signature '{}' was not found"
700  " but a function with given name exists: '{}' - did you make a typo in arguments?",
701  decl, candidate->GetDeclaration()));
702  }
703  else if (!candidate && BITMASK_IS_1(flags, GETFUNCFLAG_REQUIRED))
704  {
705  SLOG(fmt::format("Warning: a callback function with signature '{}' was not found",
706  decl));
707  }
708  }
709  return retval;
710 }
711 
712 void ScriptEngine::triggerEvent(scriptEvents eventnum, int arg1, int arg2ex, int arg3ex, int arg4ex, std::string arg5ex, std::string arg6ex, std::string arg7ex, std::string arg8ex)
713 {
714  if (!engine || !context || !m_events_enabled) return;
715 
716  for (auto& pair: m_script_units)
717  {
718  ScriptUnitId_t id = pair.first;
719  asIScriptFunction* callback = m_script_units[id].eventCallbackExFunctionPtr;
720  if (!callback)
721  callback = m_script_units[id].eventCallbackFunctionPtr;
722  if (!callback)
723  continue;
724 
725  if (m_script_units[id].eventMask & eventnum)
726  {
727  // script registered for that event, so sent it
728  if (this->prepareContextAndHandleErrors(id, callback->GetId()))
729  {
730 
731  // Set the function arguments
732  context->SetArgDWord(0, eventnum);
733  context->SetArgDWord(1, arg1);
734  if (callback == m_script_units[id].eventCallbackExFunctionPtr)
735  {
736  // Extended arguments
737  context->SetArgDWord(2, arg2ex);
738  context->SetArgDWord(3, arg3ex);
739  context->SetArgDWord(4, arg4ex);
740  context->SetArgObject(5, &arg5ex);
741  context->SetArgObject(6, &arg6ex);
742  context->SetArgObject(7, &arg7ex);
743  context->SetArgObject(8, &arg8ex);
744  }
745  }
746 
750  }
751  }
752 }
753 
754 String ScriptEngine::composeModuleName(String const& scriptName, ScriptCategory origin, ScriptUnitId_t id)
755 {
756  return fmt::format("{}(category:{},unique ID:{})", scriptName, ScriptCategoryToString(origin), id);
757 }
758 
760  String scriptName, ScriptCategory category/* = ScriptCategory::TERRAIN*/,
761  ActorPtr associatedActor /*= nullptr*/, std::string buffer /* =""*/)
762 {
763  // This function creates a new script unit, tries to set it up and removes it if setup fails.
764  // -----------------------------------------------------------------------------------------
765  // A script unit is how Rigs of Rods organizes scripts from various sources.
766  // Because the script is executed during loading, it's wrapping unit must
767  // be created early, and removed if setup fails.
768  static ScriptUnitId_t id_counter = 0;
769 
770  ScriptUnitId_t unit_id = id_counter++;
771  auto itor_pair = m_script_units.insert(std::make_pair(unit_id, ScriptUnit()));
772  m_script_units[unit_id].uniqueId = unit_id;
773  m_script_units[unit_id].scriptName = scriptName;
774  m_script_units[unit_id].scriptCategory = category;
775  m_script_units[unit_id].scriptBuffer = buffer;
776  if (category == ScriptCategory::TERRAIN)
777  {
778  m_terrain_script_unit = unit_id;
779  }
780  else if (category == ScriptCategory::ACTOR)
781  {
782  m_script_units[unit_id].associatedActor = associatedActor;
783  }
784 
785  // Perform the actual script loading, building and running main().
786  int result = this->setupScriptUnit(unit_id);
787 
788  // Regardless of result, add to recent script list. Running scripts are filtered out when displaying.
789  if (category == ScriptCategory::CUSTOM && buffer == "")
790  {
792  }
793 
794  // If setup failed, remove the unit.
795  if (result != 0)
796  {
797  m_script_units.erase(itor_pair.first);
798  if (category == ScriptCategory::TERRAIN)
799  {
801  }
802  return SCRIPTUNITID_INVALID;
803  }
804 
805  return unit_id;
806 }
807 
809 {
810  int result=0;
811 
812  String moduleName = this->composeModuleName(
813  m_script_units[unit_id].scriptName, m_script_units[unit_id].scriptCategory, m_script_units[unit_id].uniqueId);
814 
815  // The builder is a helper class that will load the script file,
816  // search for #include directives, and load any included files as
817  // well.
818  OgreScriptBuilder builder;
819 
820  // A script module is how AngelScript organizes scripts.
821  // It contains the script loaded by user plus all `#include`-d scripts.
822  result = builder.StartNewModule(engine, moduleName.c_str());
823  if ( result < 0 )
824  {
826  fmt::format("Could not load script '{}' - failed to create module.", moduleName));
827  return result;
828  }
829  m_script_units[unit_id].scriptModule = engine->GetModule(moduleName.c_str(), AngelScript::asGM_ONLY_IF_EXISTS);
830 
831  // For actor scripts, add global var `thisActor` to the module
832  if (m_script_units[unit_id].scriptCategory == ScriptCategory::ACTOR)
833  {
834  result = m_script_units[unit_id].scriptModule->AddScriptSection(m_script_units[unit_id].scriptName.c_str(), "BeamClass@ thisActor;");
835  if (result < 0)
836  {
838  fmt::format("Could not load script '{}' - failed to create global variable `thisActor`.", moduleName));
839  return result;
840  }
841  }
842 
843  // add global var `thisScript` to the module (initialized in place).
844  result = m_script_units[unit_id].scriptModule->AddScriptSection(m_script_units[unit_id].scriptName.c_str(),
845  fmt::format("const int thisScript = {};", unit_id).c_str());
846  if (result < 0)
847  {
849  fmt::format("Could not load script '{}' - failed to create global variable `thisScript`.", moduleName));
850  return result;
851  }
852 
853  // If buffer is non-empty, load from memory; otherwise from filesystem as usual.
854  if (m_script_units[unit_id].scriptBuffer != "")
855  {
856  result = builder.AddSectionFromMemory(m_script_units[unit_id].scriptName.c_str(), m_script_units[unit_id].scriptBuffer.c_str());
857  if (result < 0)
858  {
860  fmt::format("Could not load script '{}' from buffer", moduleName));
861  return result;
862  }
863  }
864  else
865  {
866  // Load the script from the file system.
867  result = builder.AddSectionFromFile(m_script_units[unit_id].scriptName.c_str());
868  if ( result < 0 )
869  {
871  fmt::format("Could not load script '{}' - failed to process file.", moduleName));
872  return result;
873  }
874  }
875 
876  // Build the AngelScript module - this loads `#include`-d scripts
877  // and runs any global statements, for example constructors of
878  // global objects like raceManager in 'races.as'. For this reason,
879  // the game must already be aware of the script, but only temporarily.
880  m_currently_executing_script_unit = unit_id; // for `BuildModule()` below.
881  result = builder.BuildModule();
883  if ( result < 0 )
884  {
886  fmt::format("Could not load script '{}' - failed to build module. See 'Angelscript.log' for more info.", moduleName));
887  return result;
888  }
889 
890  String scriptHash;
891  if (m_script_units[unit_id].scriptCategory == ScriptCategory::TERRAIN) // Classic behavior
892  scriptHash = builder.GetHash();
893 
894  // get some other optional functions
895  m_script_units[unit_id].frameStepFunctionPtr = m_script_units[unit_id].scriptModule->GetFunctionByDecl("void frameStep(float)");
896 
897  m_script_units[unit_id].eventCallbackFunctionPtr = m_script_units[unit_id].scriptModule->GetFunctionByDecl("void eventCallback(int, int)");
898  m_script_units[unit_id].eventCallbackExFunctionPtr = m_script_units[unit_id].scriptModule->GetFunctionByDecl("void eventCallbackEx(scriptEvents, int, int, int, int, string, string, string, string)");
899 
900  // THIS IS OBSOLETE - Use `eventCallbackEx()` and `SE_EVENTBOX_ENTER` instead. See commentary in `envokeCallback()`
901  m_script_units[unit_id].defaultEventCallbackFunctionPtr = this->getFunctionByDeclAndLogCandidates(
903 
904  // Find the function that is to be called.
905  auto main_func = m_script_units[unit_id].scriptModule->GetFunctionByDecl("void main()");
906  if ( main_func == nullptr )
907  {
908  // The function couldn't be found. Continue without invoking it - other callbacks like `frameStep()` can still run.
909  return 0;
910  }
911 
912  // Prepare the script context with the function we wish to execute. Prepare()
913  // must be called on the context before each new script function that will be
914  // executed. Note, that if you intend to execute the same function several
915  // times, it might be a good idea to store the function id returned by
916  // GetFunctionIDByDecl(), so that this relatively slow call can be skipped.
917  result = context->Prepare(main_func);
918  if (result < 0)
919  {
921  fmt::format("Could not load script '{}' - failed to build module.", moduleName));
922  context->Release();
923  return -1;
924  }
925 
926  // For actor scripts, initialize the global var `thisActor`
927  if (m_script_units[unit_id].scriptCategory == ScriptCategory::ACTOR)
928  {
929  int var_index = m_script_units[unit_id].scriptModule->GetGlobalVarIndexByName("thisActor");
930  if (var_index < 0)
931  {
932  SLOG("Could not find global var `thisActor`");
933  return -1;
934  }
935 
936  // Example: https://www.gamedev.net/forums/topic/644188-angelscript-2263-global-property-issues-solved/5069638/
937  Actor** thisActorAddr = (Actor**)m_script_units[unit_id].scriptModule->GetAddressOfGlobalVar(var_index);
938  if (thisActorAddr == nullptr)
939  {
940  SLOG("Could not retrieve address of global var `thisActor`");
941  return -1;
942  }
943  *thisActorAddr = m_script_units[unit_id].associatedActor.GetRef();
944  (*thisActorAddr)->AddRef();
945  }
946 
947  // Execute the `main()` function in the script.
948  // The function must have full access to the game API.
949  SLOG(fmt::format("Executing main() in {}", moduleName));
950  int mainfunc_result = this->executeContextAndHandleErrors(unit_id);
951  if ( mainfunc_result != AngelScript::asEXECUTION_FINISHED )
952  {
954  fmt::format("Could not load script '{}' - error running function `main()`, check AngelScript.log", moduleName));
955  }
956  else
957  {
958  SLOG("The script finished successfully.");
959  }
960 
961  return mainfunc_result;
962 }
963 
965 {
966  if (this->scriptUnitExists(nid))
967  {
968  if (m_script_units[nid].scriptModule != nullptr)
969  {
970  engine->DiscardModule(m_script_units[nid].scriptModule->GetName());
971  m_script_units[nid].scriptModule = nullptr;
972  }
973  m_script_units.erase(nid);
974  }
975 
976  if (m_terrain_script_unit == nid)
977  {
979  }
980 }
981 
983 {
984  // Always remove right away, to avoid attaching twice
985  scriptLog->removeListener(this);
986 
987  // Re-attach if requested
988  if (doForward)
989  {
990  scriptLog->addListener(this);
991  }
992 }
993 
995 {
996  return nid != SCRIPTUNITID_INVALID
997  && m_script_units.find(nid) != m_script_units.end();
998 }
999 
1001 {
1002  ROR_ASSERT(this->scriptUnitExists(nid));
1003  return m_script_units[nid];
1004 }
RoR::ScriptUnit
Represents a loaded script and all associated resources/handles.
Definition: ScriptEngine.h:69
ROR_ASSERT
#define ROR_ASSERT(_EXPR)
Definition: Application.h:40
GameContext.h
Game state manager and message-queue provider.
RoR::ScriptEngine::msgCallback
void msgCallback(const AngelScript::asSMessageInfo *msg)
Optional (but very recommended!) callback providing diagnostic info when things fail to start (most n...
Definition: ScriptEngine.cpp:196
RoR::ScriptEngine::exceptionCallback
void exceptionCallback(AngelScript::asIScriptContext *ctx)
Optional callback invoked when the script critically fails, allowing debugging.
Definition: ScriptEngine.cpp:233
RoR::ScriptEngine
This class represents the angelscript scripting interface.
Definition: ScriptEngine.h:119
RoR::RegisterOgreObjects
void RegisterOgreObjects(AngelScript::asIScriptEngine *engine)
defined in OgreAngelscript.cpp
Definition: OgreAngelscript.cpp:683
RoR::Actor
Softbody object; can be anything from soda can to a space shuttle Constructed from a truck definition...
Definition: Actor.h:49
RoR::ScriptEngine::scriptUnitExists
bool scriptUnitExists(ScriptUnitId_t unique_id)
Definition: ScriptEngine.cpp:994
OgreScriptBuilder
Definition: OgreScriptBuilder.h:39
RoR::RegisterLocalStorage
void RegisterLocalStorage(AngelScript::asIScriptEngine *engine)
Registers RoR::LocalStorage, defined in LocalStorageAngelscript.cpp.
RoR::ScriptEngine::composeModuleName
Ogre::String composeModuleName(Ogre::String const &scriptName, ScriptCategory origin, ScriptUnitId_t id)
Packs name + important info to one string, for logging and reporting purposes.
Definition: ScriptEngine.cpp:754
RoR::GETFUNCFLAG_OPTIONAL
const GetFuncFlags_t GETFUNCFLAG_OPTIONAL
Only logs warning if candidate is found, to help modder find a typo.
Definition: ScriptEngine.h:107
RoR::RegisterVehicleAi
void RegisterVehicleAi(AngelScript::asIScriptEngine *engine)
defined in VehicleAiAngelscript.cpp
VehicleAI.h
Simple waypoint AI.
OgreScriptBuilder::GetHash
Ogre::String GetHash()
Definition: OgreScriptBuilder.h:42
RoR::RegisterCacheSystem
void RegisterCacheSystem(AngelScript::asIScriptEngine *engine)
defined in CacheSystemAngelscript.cpp
RoR::RegisterConsole
void RegisterConsole(AngelScript::asIScriptEngine *engine)
Registers RoR::Console, defined in ConsoleAngelscript.cpp.
RoR::eventsource_t::es_instance_name
std::string es_instance_name
Specified by user when calling "GameScript::spawnObject()".
Definition: Collisions.h:42
RoR::ScriptEngine::setupScriptUnit
int setupScriptUnit(int unit_id)
Helper for loadScript(), does the actual building without worry about unit management.
Definition: ScriptEngine.cpp:808
RoR::eventsource_t
< Scripting
Definition: Collisions.h:40
RoR::SE_ANGELSCRIPT_LINECALLBACK
@ SE_ANGELSCRIPT_LINECALLBACK
The diagnostic info directly from AngelScript engine (see SetLineCallback()), args: #1 ScriptUnitID,...
Definition: ScriptEvents.h:56
RoR::NODENUM_INVALID
static const NodeNum_t NODENUM_INVALID
Definition: ForwardDeclarations.h:53
format
Truck file format(technical spec)
RoR::ScriptEngine::executeContextAndHandleErrors
int executeContextAndHandleErrors(ScriptUnitId_t nid)
Helper for executing any script function/snippet; registers Line/Exception callbacks (on demand) and ...
Definition: ScriptEngine.cpp:277
RoR::TRIGGER_EVENT_ASYNC
void TRIGGER_EVENT_ASYNC(scriptEvents type, int arg1, int arg2ex=0, int arg3ex=0, int arg4ex=0, std::string arg5ex="", std::string arg6ex="", std::string arg7ex="", std::string arg8ex="")
Asynchronously (via MSG_SIM_SCRIPT_EVENT_TRIGGERED) invoke script function eventCallbackEx(),...
Definition: ScriptEngine.h:51
OgreScriptBuilder.h
RoR::ScriptCategoryToString
const char * ScriptCategoryToString(ScriptCategory c)
Definition: ScriptEngine.cpp:66
RoR::ScriptEngine::addVariable
int addVariable(const Ogre::String &arg)
Adds a global variable to the script.
Definition: ScriptEngine.cpp:639
Console.h
RoR::ScriptEngine::executeString
int executeString(Ogre::String command)
executes a string (useful for the console)
Definition: ScriptEngine.cpp:483
RoR::Console::putMessage
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition: Console.cpp:97
RoR::ScriptEngine::setForwardScriptLogToConsole
void setForwardScriptLogToConsole(bool doForward)
Definition: ScriptEngine.cpp:982
RoR::ScriptEngine::forwardExceptionAsScriptEvent
void forwardExceptionAsScriptEvent(const std::string &from)
Forwards useful info from C++ try{}catch{} exceptions to script in the form of game event.
Definition: ScriptEngine.cpp:246
RoR::GetFuncFlags_t
BitMask_t GetFuncFlags_t
Flags for RoR::ScriptEngine::getFunctionByDeclAndLogCandidates()
Definition: ScriptEngine.h:106
RoR::ScriptEngine::loadScript
ScriptUnitId_t loadScript(Ogre::String scriptname, ScriptCategory category=ScriptCategory::TERRAIN, ActorPtr associatedActor=nullptr, std::string buffer="")
Loads a script.
Definition: ScriptEngine.cpp:759
RoR::ScriptEngine::queueStringForExecution
void queueStringForExecution(const Ogre::String command)
Queues a string for execution.
Definition: ScriptEngine.cpp:478
RoR::App::sys_logs_dir
CVar * sys_logs_dir
Definition: Application.cpp:167
Utils.h
RoR::ScriptEngine::framestep
void framestep(Ogre::Real dt)
Calls the script's framestep function to be able to use timed things inside the script.
Definition: ScriptEngine.cpp:384
RefCountingObjectPtr< Actor >
RoR::ScriptEngine::deleteVariable
int deleteVariable(const Ogre::String &arg)
Deletes a global variable from the script.
Definition: ScriptEngine.cpp:659
RoR::Console::CONSOLE_SYSTEM_ERROR
@ CONSOLE_SYSTEM_ERROR
Definition: Console.h:52
ActorManager.h
Actor.h
RoR::App::GetScriptEngine
ScriptEngine * GetScriptEngine()
Definition: Application.cpp:279
RoR::GETFUNC_DEFAULTEVENTCALLBACK_NAME
const std::string GETFUNC_DEFAULTEVENTCALLBACK_NAME
Definition: ScriptEngine.h:113
RoR::RegisterTerrain
void RegisterTerrain(AngelScript::asIScriptEngine *engine)
Registers RoR::Terrain, defined in TerrainAngelscript.cpp.
RoR::SCRIPTUNITID_INVALID
static const ScriptUnitId_t SCRIPTUNITID_INVALID
Definition: ForwardDeclarations.h:41
RoR::RegisterProceduralRoad
void RegisterProceduralRoad(AngelScript::asIScriptEngine *engine)
defined in ProceduralRoadAngelscript.cpp
RoR::ScriptEngine::prepareContextAndHandleErrors
bool prepareContextAndHandleErrors(ScriptUnitId_t nid, int asFunctionID)
Helper for executing any script function/snippet; does asIScriptContext::Prepare() and reports any er...
Definition: ScriptEngine.cpp:364
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
BITMASK_IS_0
#define BITMASK_IS_0(VAR, FLAGS)
Definition: BitFlags.h:13
RoR::RegisterGameScript
void RegisterGameScript(AngelScript::asIScriptEngine *engine)
Registers RoR::GameScript, defined in GameScriptAngelscript.cpp.
RoR::ScriptEngine::init
void init()
This function initialzies the engine and registeres all types.
Definition: ScriptEngine.cpp:119
RoR::NodeNum_t
uint16_t NodeNum_t
Node position within Actor::ar_nodes; use RoR::NODENUM_INVALID as empty value.
Definition: ForwardDeclarations.h:52
RoR::eventsource_t::es_box_name
std::string es_box_name
Specified in ODEF file as "event".
Definition: Collisions.h:43
RoR::ScriptEngine::unloadScript
void unloadScript(ScriptUnitId_t unique_id)
Unloads a script.
Definition: ScriptEngine.cpp:964
RoR::PathCombine
std::string PathCombine(std::string a, std::string b)
Definition: PlatformUtils.h:48
id_counter
static int id_counter
Definition: ProceduralRoad.cpp:36
RoR::RegisterGenericFileFormat
void RegisterGenericFileFormat(AngelScript::asIScriptEngine *engine)
defined in GenericFileFormatAngelscript.cpp
RoR::RegisterScriptEvents
void RegisterScriptEvents(AngelScript::asIScriptEngine *engine)
Registers enum scriptEvents, defined in ScriptEventsAngelscript.cpp.
BITMASK_IS_1
#define BITMASK_IS_1(VAR, FLAGS)
Definition: BitFlags.h:14
RoR::RegisterActor
void RegisterActor(AngelScript::asIScriptEngine *engine)
defined in ActorAngelscript.cpp
ScriptEngine.h
RoR::Console::forwardLogMessage
void forwardLogMessage(MessageArea area, std::string const &msg, Ogre::LogMessageLevel lml)
Definition: Console.cpp:40
RoR::ScriptUnitId_t
int ScriptUnitId_t
Unique sequentially generated ID of a loaded and running scriptin session. Use ScriptEngine::getScrip...
Definition: ForwardDeclarations.h:40
RoR::ScriptEngine::envokeCallback
void envokeCallback(int functionId, eventsource_t *source, NodeNum_t nodenum=NODENUM_INVALID, int type=0)
Definition: ScriptEngine.cpp:443
PlatformUtils.h
Platform-specific utilities. We use narrow UTF-8 encoded strings as paths. Inspired by http://utf8eve...
RoR::SE_NO_EVENTS
@ SE_NO_EVENTS
Definition: ScriptEvents.h:67
RoR::ScriptEngine::lineCallback
void lineCallback(AngelScript::asIScriptContext *ctx)
Optional callback which receives diagnostic info for every executed statement.
Definition: ScriptEngine.cpp:215
RoR::ScriptEngine::~ScriptEngine
~ScriptEngine()
Definition: ScriptEngine.cpp:106
RoR::SE_GENERIC_EXCEPTION_CAUGHT
@ SE_GENERIC_EXCEPTION_CAUGHT
Triggered when C++ exception (usually Ogre::Exception) is thrown; #1 ScriptUnitID,...
Definition: ScriptEvents.h:61
logString
void logString(const std::string &str)
Definition: ScriptEngine.cpp:90
RoR::ScriptEngine::scriptLog
Ogre::Log * scriptLog
Definition: ScriptEngine.h:296
Application.h
Central state/object manager and communications hub.
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:270
RoR::SE_ANGELSCRIPT_MSGCALLBACK
@ SE_ANGELSCRIPT_MSGCALLBACK
The diagnostic info directly from AngelScript engine (see asSMessageInfo), args: #1 ScriptUnitID,...
Definition: ScriptEvents.h:55
RoR::ScriptEngine::m_currently_executing_script_unit
ScriptUnitId_t m_currently_executing_script_unit
Definition: ScriptEngine.h:300
GameScript.h
RoR::ScriptEngine::m_currently_executing_event_trigger
scriptEvents m_currently_executing_event_trigger
Definition: ScriptEngine.h:301
RoR::ScriptEngine::m_events_enabled
bool m_events_enabled
Hack to enable fast shutdown without cleanup.
Definition: ScriptEngine.h:302
RoR::ScriptEngine::triggerEvent
void triggerEvent(scriptEvents eventnum, int arg1=0, int arg2ex=0, int arg3ex=0, int arg4ex=0, std::string arg5ex="", std::string arg6ex="", std::string arg7ex="", std::string arg8ex="")
triggers an event; Not to be used by the end-user.
Definition: ScriptEngine.cpp:712
RoR::ScriptEngine::getFunctionByDeclAndLogCandidates
AngelScript::asIScriptFunction * getFunctionByDeclAndLogCandidates(ScriptUnitId_t nid, GetFuncFlags_t flags, const std::string &funcName, const std::string &fmtFuncDecl)
Finds a function by full declaration, and if not found, finds candidates by name and logs them to Ang...
Definition: ScriptEngine.cpp:690
ptr2str
std::string ptr2str(const char *ptr)
Definition: ScriptEngine.cpp:213
RoR::ScriptEngine::engine
AngelScript::asIScriptEngine * engine
instance of the scripting engine
Definition: ScriptEngine.h:294
RoR::CvarAddFileToList
void CvarAddFileToList(CVar *cvar, const std::string &filename)
Definition: Utils.cpp:206
RoR::ScriptCategory::TERRAIN
@ TERRAIN
Defined in terrn2 file under '[Scripts]', receives terrain eventbox notifications.
RoR::ScriptEngine::m_terrain_script_unit
ScriptUnitId_t m_terrain_script_unit
Definition: ScriptEngine.h:299
LocalStorage.h
RoR::GETFUNC_DEFAULTEVENTCALLBACK_SIGFMT
const std::string GETFUNC_DEFAULTEVENTCALLBACK_SIGFMT
Definition: ScriptEngine.h:112
RoR::App::GetCacheSystem
CacheSystem * GetCacheSystem()
Definition: Application.cpp:272
RoR::ScriptEngine::fireEvent
int fireEvent(std::string instanceName, float intensity)
Definition: ScriptEngine.cpp:413
RoR::App::app_recent_scripts
CVar * app_recent_scripts
Definition: Application.cpp:93
RoR::RegisterImGuiBindings
void RegisterImGuiBindings(AngelScript::asIScriptEngine *engine)
defined in ImGuiAngelscript.cpp
Definition: ImGuiAngelscript.cpp:53
RoR::GETFUNCFLAG_REQUIRED
const GetFuncFlags_t GETFUNCFLAG_REQUIRED
Always logs warning that function was not found.
Definition: ScriptEngine.h:108
RoR::RegisterMessageQueue
void RegisterMessageQueue(AngelScript::asIScriptEngine *engine)
Registers enum MsgType, defined in MsgQueueAngelscript.cpp.
InterThreadStoreVector::push
void push(T v)
Definition: InterThreadStoreVector.h:33
RoR::RegisterSoundScript
void RegisterSoundScript(AngelScript::asIScriptEngine *engine)
defined in SoundScriptAngelscript.cpp
Definition: SoundScriptAngelscript.cpp:30
RoR::RegisterInputEngine
void RegisterInputEngine(AngelScript::asIScriptEngine *engine)
Registers RoR::InputEngine, defined in InputEngineAngelscript.cpp.
RoR::ScriptEngine::context
AngelScript::asIScriptContext * context
context in which all scripting happens
Definition: ScriptEngine.h:295
ScriptEvents.h
RoR::ScriptEngine::m_script_units
ScriptUnitMap m_script_units
Definition: ScriptEngine.h:298
RoR::ScriptEngine::functionExists
int functionExists(const Ogre::String &arg)
Checks if a global function exists.
Definition: ScriptEngine.cpp:560
RoR::App::GetInputEngine
InputEngine * GetInputEngine()
Definition: Application.cpp:271
RoR::ScriptCategory::ACTOR
@ ACTOR
Defined in truck file under 'scripts', contains global variable BeamClass@ thisActor.
RoR::ScriptEngine::m_game_script
GameScript m_game_script
Definition: ScriptEngine.h:297
RoR::ScriptEngine::stringExecutionQueue
InterThreadStoreVector< Ogre::String > stringExecutionQueue
The string execution queue.
Definition: ScriptEngine.h:304
InputEngine.h
Handles controller inputs from player. Defines input events and binding mechanism,...
Ogre
Definition: ExtinguishableFireAffector.cpp:35
ScriptUtils.h
RoR::Console::CONSOLE_MSGTYPE_INFO
@ CONSOLE_MSGTYPE_INFO
Generic message.
Definition: Console.h:60
RoR::Console::CONSOLE_MSGTYPE_SCRIPT
@ CONSOLE_MSGTYPE_SCRIPT
Messages sent from scripts.
Definition: Console.h:62
RoR::ScriptCategory
ScriptCategory
Note: Either of these can be loaded from script using game.pushMessage(MSG_APP_LOAD_SCRIPT_REQUESTED....
Definition: ScriptEngine.h:58
Collisions.h
RoR::scriptEvents
scriptEvents
This enum describes what events are existing. The script can register to receive events.
Definition: ScriptEvents.h:30
RoR::ScriptEngine::getScriptUnit
ScriptUnit & getScriptUnit(ScriptUnitId_t unique_id)
Definition: ScriptEngine.cpp:1000
RoR::SE_ANGELSCRIPT_EXCEPTIONCALLBACK
@ SE_ANGELSCRIPT_EXCEPTIONCALLBACK
The diagnostic info directly from AngelScript engine (see SetExceptionCallback()),...
Definition: ScriptEvents.h:57
RoR
Definition: AppContext.h:36
RoR::ScriptCategory::CUSTOM
@ CUSTOM
Loaded by user via either: A) ingame console 'loadscript'; B) RoR.cfg 'app_custom_scripts'; C) comman...
InterThreadStoreVector::pull
void pull(std::vector< T > &res)
Definition: InterThreadStoreVector.h:39
RoR::ScriptEngine::deleteFunction
int deleteFunction(const Ogre::String &arg)
Deletes a global function from the script.
Definition: ScriptEngine.cpp:585
RoR::ScriptEngine::addFunction
int addFunction(const Ogre::String &arg)
Adds a global function to the script.
Definition: ScriptEngine.cpp:501
RoR::GETFUNCFLAG_SILENT
const GetFuncFlags_t GETFUNCFLAG_SILENT
Never logs.
Definition: ScriptEngine.h:109
RoR::ScriptEngine::messageLogged
void messageLogged(const Ogre::String &message, Ogre::LogMessageLevel lml, bool maskDebug, const Ogre::String &logName, bool &skipThisMessage)
Definition: ScriptEngine.cpp:113