RigsofRods
Soft-body Physics Simulation
GameScript.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 
22 #include "GameScript.h"
23 
24 #ifdef USE_CURL
25 # include <curl/curl.h>
26 # include <curl/easy.h>
27 #endif //USE_CURL
28 
29 // AS addons start
30 #include "scriptany/scriptany.h"
31 #include "scriptarray/scriptarray.h"
32 #include "scripthelper/scripthelper.h"
33 #include "scriptmath/scriptmath.h"
34 #include "scriptstdstring/scriptstdstring.h"
35 // AS addons end
36 
37 #include "AppContext.h"
38 #include "Actor.h"
39 #include "ActorManager.h"
40 #include "CacheSystem.h"
41 #include "Character.h"
42 #include "ChatSystem.h"
43 #include "Collisions.h"
44 #include "Console.h"
45 #include "CurlHelpers.h"
46 #include "EngineSim.h"
47 #include "GameContext.h"
48 #include "GfxScene.h"
49 #include "GUIManager.h"
50 #include "GUI_TopMenubar.h"
51 #include "Language.h"
52 #include "PlatformUtils.h"
53 #include "Network.h"
54 #include "RoRVersion.h"
55 #include "ScriptEngine.h"
56 #include "ScriptUtils.h"
57 #include "SkyManager.h"
58 #include "SoundScriptManager.h"
59 #include "Terrain.h"
60 #include "TerrainGeometryManager.h"
61 #include "TerrainObjectManager.h"
62 #include "Utils.h"
63 #include "VehicleAI.h"
64 #include "Water.h"
65 
66 #include <rapidjson/document.h>
67 #include <rapidjson/writer.h>
68 
69 using namespace Ogre;
70 using namespace RoR;
71 using namespace AngelScript;
72 
73 // GUIDELINE: Make functions safe from invoking in wrong circumstances,
74 // i.e. when server script calls function using SimController while in main menu.
75 // --> Getter functions should silently return zero/empty value.
76 // --> Functions performing simulation changes should log warning and do nothing.
77 
78 
79 
80 void GameScript::log(const String& msg)
81 {
82  App::GetScriptEngine()->SLOG(msg);
83 }
84 
85 void GameScript::logFormat(const char* format, ...)
86 {
87  char buffer[4000] = {};
88  sprintf(buffer, "[RoR|Script] "); // Length: 13 characters
89  char* buffer_pos = buffer + 13;
90 
91  va_list args;
92  va_start(args, format);
93  vsprintf(buffer_pos, format, args);
94  va_end(args);
95 
96  App::GetScriptEngine()->SLOG(buffer);
97 }
98 
99 void GameScript::activateAllVehicles()
100 {
102 }
103 
104 void GameScript::setTrucksForcedAwake(bool forceActive)
105 {
107 }
108 
109 float GameScript::getTime()
110 {
112 }
113 
114 void GameScript::setPersonPosition(const Vector3& vec)
115 {
116  if (!this->HavePlayerAvatar(__FUNCTION__))
117  return;
118 
120 }
121 
122 void GameScript::loadTerrain(const String& terrain)
123 {
125 }
126 
127 Vector3 GameScript::getPersonPosition()
128 {
129  Vector3 result(Vector3::ZERO);
130  if (App::GetGameContext()->GetPlayerCharacter())
132  return result;
133 }
134 
135 void GameScript::movePerson(const Vector3& vec)
136 {
137  if (!this->HavePlayerAvatar(__FUNCTION__))
138  return;
139 
141 }
142 
143 void GameScript::setPersonRotation(const Radian& rot)
144 {
145  if (!this->HavePlayerAvatar(__FUNCTION__))
146  return;
147 
149 }
150 
151 Radian GameScript::getPersonRotation()
152 {
153  Radian result(0);
154  if (App::GetGameContext()->GetPlayerCharacter())
156  return result;
157 }
158 
159 String GameScript::getCaelumTime()
160 {
161  String result = "";
162 #ifdef USE_CAELUM
163  if (App::GetGameContext()->GetTerrain())
164  {
165  result = App::GetGameContext()->GetTerrain()->getSkyManager()->GetPrettyTime();
166  }
167 #endif // USE_CAELUM
168  return result;
169 }
170 
171 void GameScript::setCaelumTime(float value)
172 {
173 #ifdef USE_CAELUM
174  if (!this->HaveSimTerrain(__FUNCTION__))
175  return;
176 
177  App::GetGameContext()->GetTerrain()->getSkyManager()->SetSkyTimeFactor(value);
178 #endif // USE_CAELUM
179 }
180 
181 bool GameScript::getCaelumAvailable()
182 {
183  bool result = false;
184 #ifdef USE_CAELUM
185  if (App::GetGameContext()->GetTerrain())
186  result = App::GetGameContext()->GetTerrain()->getSkyManager() != 0;
187 #endif // USE_CAELUM
188  return result;
189 }
190 
191 void GameScript::stopTimer()
192 {
194 }
195 
196 void GameScript::startTimer(int id)
197 {
199 }
200 
201 void GameScript::setTimeDiff(float diff)
202 {
204 }
205 
206 void GameScript::setBestLapTime(float time)
207 {
209 }
210 
211 void GameScript::setWaterHeight(float value)
212 {
213  if (!this->HaveSimTerrain(__FUNCTION__))
214  return;
215 
216  if (App::GetGameContext()->GetTerrain()->getWater())
217  {
219  water->SetStaticWaterHeight(value);
220  water->UpdateWater();
221  }
222 }
223 
224 float GameScript::getGroundHeight(Vector3& v)
225 {
226  float result = -1.0f;
227  if (App::GetGameContext()->GetTerrain())
228  result = App::GetGameContext()->GetTerrain()->GetHeightAt(v.x, v.z);
229  return result;
230 }
231 
232 float GameScript::getWaterHeight()
233 {
234  float result = 0.0f;
235  if (App::GetGameContext()->GetTerrain() && App::GetGameContext()->GetTerrain()->getWater())
237  return result;
238 }
239 
240 ActorPtr GameScript::getCurrentTruck()
241 {
243 }
244 
245 float GameScript::getGravity()
246 {
247  float result = 0.f;
248  if (App::GetGameContext()->GetTerrain())
249  {
250  result = App::GetGameContext()->GetTerrain()->getGravity();
251  }
252  return result;
253 }
254 
255 void GameScript::setGravity(float value)
256 {
257  if (!this->HaveSimTerrain(__FUNCTION__))
258  return;
259 
261 }
262 
263 ActorPtr GameScript::getTruckByNum(int num)
264 {
266 }
267 
268 int GameScript::getNumTrucksByFlag(int flag)
269 {
270  int result = 0;
271  for (ActorPtr& actor : App::GetGameContext()->GetActorManager()->GetActors())
272  {
273  if (!flag || static_cast<int>(actor->ar_state) == flag)
274  result++;
275  }
276  return result;
277 }
278 
279 int GameScript::getCurrentTruckNumber()
280 {
282  return (actor != nullptr) ? actor->ar_instance_id : -1;
283 }
284 
285 void GameScript::registerForEvent(int eventValue)
286 {
287  if (App::GetScriptEngine())
288  {
289  ScriptUnitId_t unit_id = App::GetScriptEngine()->getCurrentlyExecutingScriptUnit();
290  if (unit_id != SCRIPTUNITID_INVALID)
291  {
292  App::GetScriptEngine()->getScriptUnit(unit_id).eventMask |= eventValue;
293  }
294  }
295 }
296 
297 void GameScript::unRegisterEvent(int eventValue)
298 {
299  if (App::GetScriptEngine())
300  {
301  ScriptUnitId_t unit_id = App::GetScriptEngine()->getCurrentlyExecutingScriptUnit();
302  if (unit_id != SCRIPTUNITID_INVALID)
303  {
304  App::GetScriptEngine()->getScriptUnit(unit_id).eventMask &= ~eventValue;
305  }
306  }
307 }
308 
309 BitMask_t GameScript::getRegisteredEventsMask(ScriptUnitId_t nid)
310 {
311  if (App::GetScriptEngine()->scriptUnitExists(nid))
313  else
314  return BitMask_t(0);
315 }
316 
317 void GameScript::setRegisteredEventsMask(ScriptUnitId_t nid, BitMask_t eventMask)
318 {
319  if (App::GetScriptEngine()->scriptUnitExists(nid))
320  App::GetScriptEngine()->getScriptUnit(nid).eventMask = eventMask;
321 }
322 
323 void GameScript::flashMessage(String& txt, float time, float charHeight)
324 {
325  RoR::App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_SCRIPT, Console::CONSOLE_SYSTEM_NOTICE, txt, "script_code_red.png");
326 }
327 
328 void GameScript::message(String& txt, String& icon)
329 {
330  RoR::App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_SCRIPT, Console::CONSOLE_SYSTEM_NOTICE, txt, icon);
331 }
332 
333 void GameScript::updateDirectionArrow(String& text, Vector3& vec)
334 {
335  App::GetGameContext()->GetRaceSystem().UpdateDirectionArrow(const_cast<char*>(text.c_str()), Vector3(vec.x, vec.y, vec.z));
336 }
337 
338 int GameScript::getChatFontSize()
339 {
340  return 0; //NETCHAT.getFontSize();
341 }
342 
343 void GameScript::setChatFontSize(int size)
344 {
345  //NETCHAT.setFontSize(size);
346 }
347 
348 void GameScript::showChooser(const String& type, const String& instance, const String& box)
349 {
350  LoaderType ntype = LT_None;
351 
352  if (type == "airplane")
353  ntype = LT_Airplane;
354  if (type == "all")
355  ntype = LT_AllBeam;
356  if (type == "boat")
357  ntype = LT_Boat;
358  if (type == "car")
359  ntype = LT_Car;
360  if (type == "extension")
361  ntype = LT_Extension;
362  if (type == "heli")
363  ntype = LT_Airplane;
364  if (type == "load")
365  ntype = LT_Load;
366  if (type == "trailer")
367  ntype = LT_Trailer;
368  if (type == "train")
369  ntype = LT_Train;
370  if (type == "truck")
371  ntype = LT_Truck;
372  if (type == "vehicle")
373  ntype = LT_Vehicle;
374 
375  if (ntype != LT_None)
376  {
378  }
379 
380 }
381 
382 void GameScript::repairVehicle(const String& instance, const String& box, bool keepPosition)
383 {
384  App::GetGameContext()->GetActorManager()->RepairActor(App::GetGameContext()->GetTerrain()->GetCollisions(), instance, box, keepPosition);
385 }
386 
387 void GameScript::removeVehicle(const String& event_source_instance_name, const String& event_source_box_name)
388 {
389  ActorPtr actor = App::GetGameContext()->FindActorByCollisionBox(event_source_instance_name, event_source_box_name);
390  if (actor)
391  {
393  }
394 }
395 
396 void GameScript::destroyObject(const String& instanceName)
397 {
398  if (!this->HaveSimTerrain(__FUNCTION__))
399  return;
400 
401  if (App::GetGameContext()->GetTerrain()->getObjectManager())
402  {
404  }
405 }
406 
407 void GameScript::moveObjectVisuals(const String& instanceName, const Vector3& pos)
408 {
409  if (!this->HaveSimTerrain(__FUNCTION__))
410  return;
411 
412  if (App::GetGameContext()->GetTerrain()->getObjectManager())
413  {
415  }
416 }
417 
418 void GameScript::spawnObject(const String& objectName, const String& instanceName, const Vector3& pos, const Vector3& rot, const String& eventhandler, bool uniquifyMaterials)
419 {
420  if (!this->HaveSimTerrain(__FUNCTION__))
421  return;
422 
423  if ((App::GetGameContext()->GetTerrain()->getObjectManager() == nullptr))
424  {
425  this->logFormat("spawnObject(): Cannot spawn object, no terrain loaded!");
426  return;
427  }
428 
429  if (App::GetScriptEngine()->getTerrainScriptUnit() == -1)
430  {
431  this->logFormat("spawnObject(): Cannot spawn object, no terrain script loaded!");
432  return;
433  }
434 
435  try
436  {
437  AngelScript::asIScriptModule* module = App::GetScriptEngine()->getScriptUnit(App::GetScriptEngine()->getTerrainScriptUnit()).scriptModule;
438  if (module == nullptr)
439  {
440  this->logFormat("spawnObject(): Failed to fetch/create script module");
441  return;
442  }
443 
444  int handler_func_id = -1; // no function
445  if (!eventhandler.empty())
446  {
447  // Let script author know (via Angelscript.log) there's a better alternative.
449  App::GetScriptEngine()->SLOG(
450  "spawnObject(): Specifying event handler function in `game.spawnObject()` (or .TOBJ file) is obsolete and only works with terrain scripts;"
451  " Use `eventCallbackEx()` with event `SE_EVENTBOX_ENTER` instead, it does the same job and works with any script."
452  " Just pass an empty string to the `game.spawnObject()` parameter.");
454 
455  // Look up the function and log if not found or found with bad arguments (probably a typo).
456  AngelScript::asIScriptFunction* handler_func = App::GetScriptEngine()->getFunctionByDeclAndLogCandidates(
457  App::GetScriptEngine()->getTerrainScriptUnit(), GETFUNCFLAG_REQUIRED,
459  if (handler_func != nullptr)
460  {
461  handler_func_id = handler_func->GetId();
462  }
463  }
464 
465  const String type = "";
466  App::GetGameContext()->GetTerrain()->getObjectManager()->LoadTerrainObject(objectName, pos, rot, instanceName, type, /*rendering_distance=*/0, true, handler_func_id, uniquifyMaterials);
467  }
468  catch (...)
469  {
470  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::spawnObject()");
471  return;
472  }
473 }
474 
475 void GameScript::hideDirectionArrow()
476 {
478 }
479 
480 bool GameScript::getScreenPosFromWorldPos(Ogre::Vector3 const& world_pos, Ogre::Vector2& out_screen)
481 {
482  ImVec2 screen_size = ImGui::GetIO().DisplaySize;
483  World2ScreenConverter world2screen(
484  App::GetCameraManager()->GetCamera()->getViewMatrix(true), App::GetCameraManager()->GetCamera()->getProjectionMatrix(), Ogre::Vector2(screen_size.x, screen_size.y));
485  Ogre::Vector3 pos_xyz = world2screen.Convert(world_pos);
486  if (pos_xyz.z < 0.f)
487  {
488  out_screen.x = pos_xyz.x;
489  out_screen.y = pos_xyz.y;
490  return true;
491  }
492  return false;
493 }
494 
495 Ogre::Vector2 GameScript::getDisplaySize()
496 {
497  ImVec2 size = ImGui::GetIO().DisplaySize;
498  return Vector2(size.x, size.y);
499 }
500 
501 Ogre::Vector2 GameScript::getMouseScreenPosition()
502 {
503  ImVec2 pos = ImGui::GetIO().MousePos;
504  return Vector2(pos.x, pos.y);
505 }
506 
507 int GameScript::setMaterialAmbient(const String& materialName, float red, float green, float blue)
508 {
509  try
510  {
511  MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
512  if (m.isNull())
513  return 0;
514  m->setAmbient(red, green, blue);
515  }
516  catch (...)
517  {
518  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialAmbient()");
519  return 0;
520  }
521  return 1;
522 }
523 
524 int GameScript::setMaterialDiffuse(const String& materialName, float red, float green, float blue, float alpha)
525 {
526  try
527  {
528  MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
529  if (m.isNull())
530  return 0;
531  m->setDiffuse(red, green, blue, alpha);
532  }
533  catch (...)
534  {
535  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialDiffuse()");
536  return 0;
537  }
538  return 1;
539 }
540 
541 int GameScript::setMaterialSpecular(const String& materialName, float red, float green, float blue, float alpha)
542 {
543  try
544  {
545  MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
546  if (m.isNull())
547  return 0;
548  m->setSpecular(red, green, blue, alpha);
549  }
550  catch (...)
551  {
552  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialSpecular()");
553  return 0;
554  }
555  return 1;
556 }
557 
558 int GameScript::setMaterialEmissive(const String& materialName, float red, float green, float blue)
559 {
560  try
561  {
562  MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
563  if (m.isNull())
564  return 0;
565  m->setSelfIllumination(red, green, blue);
566  }
567  catch (...)
568  {
569  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialEmissive()");
570  return 0;
571  }
572  return 1;
573 }
574 
575 int GameScript::getTextureUnitState(TextureUnitState** tu, const String materialName, int techniqueNum, int passNum, int textureUnitNum)
576 {
577  // Internal helper - propagate exceptions outside so that correct function names appear in exception-events
578  // ========================================================================================================
579 
580  MaterialPtr m = MaterialManager::getSingleton().getByName(materialName);
581  if (m.isNull())
582  return 1;
583 
584  // verify technique
585  if (techniqueNum < 0 || techniqueNum > m->getNumTechniques())
586  return 2;
587  Technique* t = m->getTechnique(techniqueNum);
588  if (!t)
589  return 2;
590 
591  //verify pass
592  if (passNum < 0 || passNum > t->getNumPasses())
593  return 3;
594  Pass* p = t->getPass(passNum);
595  if (!p)
596  return 3;
597 
598  //verify texture unit
599  if (textureUnitNum < 0 || textureUnitNum > p->getNumTextureUnitStates())
600  return 4;
601  TextureUnitState* tut = p->getTextureUnitState(textureUnitNum);
602  if (!tut)
603  return 4;
604 
605  *tu = tut;
606  return 0;
607 }
608 
609 int GameScript::setMaterialTextureName(const String& materialName, int techniqueNum, int passNum, int textureUnitNum, const String& textureName)
610 {
611  try
612  {
613  TextureUnitState* tu = 0;
614  int res = getTextureUnitState(&tu, materialName, techniqueNum, passNum, textureUnitNum);
615  if (res == 0 && tu != 0)
616  {
617  // finally, set it
618  tu->setTextureName(textureName);
619  }
620  return res;
621  }
622  catch (...)
623  {
624  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialTextureName()");
625  return 0;
626  }
627 }
628 
629 int GameScript::setMaterialTextureRotate(const String& materialName, int techniqueNum, int passNum, int textureUnitNum, float rotation)
630 {
631  try
632  {
633  TextureUnitState* tu = 0;
634  int res = getTextureUnitState(&tu, materialName, techniqueNum, passNum, textureUnitNum);
635  if (res == 0 && tu != 0)
636  {
637  tu->setTextureRotate(Degree(rotation));
638  }
639  return res;
640  }
641  catch (...)
642  {
643  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialTextureRotate()");
644  return 0;
645  }
646 }
647 
648 int GameScript::setMaterialTextureScroll(const String& materialName, int techniqueNum, int passNum, int textureUnitNum, float sx, float sy)
649 {
650  try
651  {
652  TextureUnitState* tu = 0;
653  int res = getTextureUnitState(&tu, materialName, techniqueNum, passNum, textureUnitNum);
654  if (res == 0 && tu != 0)
655  {
656  tu->setTextureScroll(sx, sy);
657  }
658  return res;
659  }
660  catch (...)
661  {
662  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialTextureScroll()");
663  return 0;
664  }
665 }
666 
667 int GameScript::setMaterialTextureScale(const String& materialName, int techniqueNum, int passNum, int textureUnitNum, float u, float v)
668 {
669  try
670  {
671  TextureUnitState* tu = 0;
672  int res = getTextureUnitState(&tu, materialName, techniqueNum, passNum, textureUnitNum);
673  if (res == 0 && tu != 0)
674  {
675  tu->setTextureScale(u, v);
676  }
677  return res;
678  }
679  catch (...)
680  {
681  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialTextureScale()");
682  return 0;
683  }
684 }
685 
686 float GameScript::rangeRandom(float from, float to)
687 {
688  return Math::RangeRandom(from, to);
689 }
690 
691 int GameScript::getLoadedTerrain(String& result)
692 {
693  String terrainName = "";
694 
695  if (App::GetGameContext()->GetTerrain())
696  {
697  terrainName = App::GetGameContext()->GetTerrain()->getTerrainName();
698  result = terrainName;
699  }
700 
701  return !terrainName.empty();
702 }
703 
704 RoR::TerrainPtr GameScript::getTerrain()
705 {
706  return App::GetGameContext()->GetTerrain();
707 }
708 
709 void GameScript::clearEventCache()
710 {
711  if (!this->HaveSimTerrain(__FUNCTION__))
712  return;
713 
714  if (App::GetGameContext()->GetTerrain()->GetCollisions() == nullptr)
715  {
716  this->logFormat("Cannot execute '%s', collisions not ready", __FUNCTION__);
717  return;
718  }
719 
721 }
722 
723 void GameScript::setCameraPosition(const Vector3& pos)
724 {
725  if (!this->HaveMainCamera(__FUNCTION__))
726  return;
727 
728  App::GetCameraManager()->GetCameraNode()->setPosition(Vector3(pos.x, pos.y, pos.z));
729 }
730 
731 void GameScript::setCameraDirection(const Vector3& rot)
732 {
733  if (!this->HaveMainCamera(__FUNCTION__))
734  return;
735 
736  App::GetCameraManager()->GetCameraNode()->setDirection(Vector3(rot.x, rot.y, rot.z), Ogre::Node::TS_WORLD);
737 }
738 
739 void GameScript::setCameraOrientation(const Quaternion& q)
740 {
741  if (!this->HaveMainCamera(__FUNCTION__))
742  return;
743 
744  App::GetCameraManager()->GetCameraNode()->setOrientation(Quaternion(q.w, q.x, q.y, q.z));
745 }
746 
747 void GameScript::setCameraYaw(float rotX)
748 {
749  if (!this->HaveMainCamera(__FUNCTION__))
750  return;
751 
752  App::GetCameraManager()->GetCameraNode()->yaw(Degree(rotX), Ogre::Node::TS_WORLD);
753 }
754 
755 void GameScript::setCameraPitch(float rotY)
756 {
757  if (!this->HaveMainCamera(__FUNCTION__))
758  return;
759 
760  App::GetCameraManager()->GetCameraNode()->pitch(Degree(rotY));
761 }
762 
763 void GameScript::setCameraRoll(float rotZ)
764 {
765  if (!this->HaveMainCamera(__FUNCTION__))
766  return;
767 
768  App::GetCameraManager()->GetCameraNode()->roll(Degree(rotZ));
769 }
770 
771 Vector3 GameScript::getCameraPosition()
772 {
773  Vector3 result(Vector3::ZERO);
774  if (App::GetCameraManager()->GetCameraNode())
775  result = App::GetCameraManager()->GetCameraNode()->getPosition();
776  return result;
777 }
778 
779 Vector3 GameScript::getCameraDirection()
780 {
781  Vector3 result(Vector3::ZERO);
782  if (App::GetCameraManager()->GetCameraNode())
783  {
784  // Direction points down -Z by default (adapted from Ogre::Camera)
785  result = App::GetCameraManager()->GetCameraNode()->getOrientation() * -Ogre::Vector3::UNIT_Z;
786  }
787  return result;
788 }
789 
790 Quaternion GameScript::getCameraOrientation()
791 {
792  Quaternion result(Quaternion::ZERO);
793  if (App::GetCameraManager()->GetCameraNode())
794  result = App::GetCameraManager()->GetCameraNode()->getOrientation();
795  return result;
796 }
797 
798 void GameScript::cameraLookAt(const Vector3& pos)
799 {
800  if (!this->HaveMainCamera(__FUNCTION__))
801  return;
802 
803  App::GetCameraManager()->GetCameraNode()->lookAt(Vector3(pos.x, pos.y, pos.z), Ogre::Node::TS_WORLD);
804 }
805 
806 int GameScript::useOnlineAPI(const String& apiquery, const AngelScript::CScriptDictionary& dict, String& result)
807 {
808  if (App::app_disable_online_api->getBool())
809  return 0;
810 
811  ScriptUnitId_t unit_id = App::GetScriptEngine()->getCurrentlyExecutingScriptUnit();
812  if (unit_id == SCRIPTUNITID_INVALID)
813  return 2;
814 
815  ActorPtr player_actor = App::GetGameContext()->GetPlayerActor();
816 
817  if (player_actor == nullptr)
818  return 1;
819 
820  std::string hashtok = Sha1Hash(App::mp_player_name->getStr());
821  std::string url = App::mp_api_url->getStr() + apiquery;
822  std::string user = std::string("RoR-Api-User: ") + App::mp_player_name->getStr();
823  std::string token = std::string("RoR-Api-User-Token: ") + hashtok;
824 
825  std::string terrain_name = App::GetGameContext()->GetTerrain()->getTerrainName();
826 
827  std::string script_name = App::GetScriptEngine()->getScriptUnit(unit_id).scriptName;
828  std::string script_hash = App::GetScriptEngine()->getScriptUnit(unit_id).scriptHash;
829 
830  rapidjson::Document j_doc;
831  j_doc.SetObject();
832 
833  j_doc.AddMember("user-name", rapidjson::StringRef(App::mp_player_name->getStr().c_str()), j_doc.GetAllocator());
834  j_doc.AddMember("user-country", rapidjson::StringRef(App::app_country->getStr().c_str()), j_doc.GetAllocator());
835  j_doc.AddMember("user-token", rapidjson::StringRef(hashtok.c_str()), j_doc.GetAllocator());
836 
837  j_doc.AddMember("terrain-name", rapidjson::StringRef(terrain_name.c_str()), j_doc.GetAllocator());
838  j_doc.AddMember("terrain-filename", rapidjson::StringRef(App::sim_terrain_name->getStr().c_str()), j_doc.GetAllocator());
839 
840  j_doc.AddMember("script-name", rapidjson::StringRef(script_name.c_str()), j_doc.GetAllocator());
841  j_doc.AddMember("script-hash", rapidjson::StringRef(script_hash.c_str()), j_doc.GetAllocator());
842 
843  j_doc.AddMember("actor-name", rapidjson::StringRef(player_actor->ar_design_name.c_str()), j_doc.GetAllocator());
844  j_doc.AddMember("actor-filename", rapidjson::StringRef(player_actor->ar_filename.c_str()), j_doc.GetAllocator());
845  j_doc.AddMember("actor-hash", rapidjson::StringRef(player_actor->ar_filehash.c_str()), j_doc.GetAllocator());
846 
847  rapidjson::Value j_linked_actors(rapidjson::kArrayType);
848  for (ActorPtr& actor : player_actor->ar_linked_actors)
849  {
850  rapidjson::Value j_actor(rapidjson::kObjectType);
851  j_actor.AddMember("actor-name", rapidjson::StringRef(actor->ar_design_name.c_str()), j_doc.GetAllocator());
852  j_actor.AddMember("actor-filename", rapidjson::StringRef(actor->ar_filename.c_str()), j_doc.GetAllocator());
853  j_actor.AddMember("actor-hash", rapidjson::StringRef(actor->ar_filehash.c_str()), j_doc.GetAllocator());
854  j_linked_actors.PushBack(j_actor, j_doc.GetAllocator());
855  }
856  j_doc.AddMember("linked-actors", j_linked_actors, j_doc.GetAllocator());
857 
858  j_doc.AddMember("avg-fps", getAvgFPS(), j_doc.GetAllocator());
859  j_doc.AddMember("ror-version", rapidjson::StringRef(ROR_VERSION_STRING), j_doc.GetAllocator());
860 
861  for (auto item : dict)
862  {
863  const std::string& key = item.GetKey();
864  const std::string* value = (std::string *)item.GetAddressOfValue();
865  j_doc.AddMember(rapidjson::StringRef(key.c_str()), rapidjson::StringRef(value->c_str()), j_doc.GetAllocator());
866  }
867 
868  rapidjson::StringBuffer buffer;
869  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
870  j_doc.Accept(writer);
871  std::string json = buffer.GetString();
872 
873 #if USE_CURL
874  RoR::App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE,
875  _L("using Online API..."), "information.png");
876 
877  LOG("[RoR|GameScript] Submitting race results to '" + url + "'");
878 
879  std::thread([url, user, token, json]()
880  {
881  long response_code = 0;
882 
883  struct curl_slist *slist = NULL;
884  slist = curl_slist_append(slist, "Accept: application/json");
885  slist = curl_slist_append(slist, "Content-Type: application/json");
886  slist = curl_slist_append(slist, user.c_str());
887  slist = curl_slist_append(slist, token.c_str());
888 
889  CURL *curl = curl_easy_init();
890  curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
891  curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
892  curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
893 
894  CURLcode curl_result = curl_easy_perform(curl);
895  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
896 
897  if (curl_result != CURLE_OK || response_code != 200)
898  {
899  Ogre::LogManager::getSingleton().stream()
900  << "[RoR|GameScript] `useOnlineAPI()` failed to submit data;"
901  << " Error: '" << curl_easy_strerror(curl_result) << "'; HTTP status code: " << response_code;
902  }
903 
904  curl_easy_cleanup(curl);
905  curl = nullptr;
906  curl_slist_free_all(slist);
907  slist = NULL;
908  }).detach();
909 #else // USE_CURL
910  RoR::App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_WARNING,
911  _L("Cannot use Online API in this build (CURL not available)"));
912 #endif // USE_CURL
913 
914  return 0;
915 }
916 
917 void GameScript::openUrlInDefaultBrowser(const std::string& url)
918 {
919  RoR::OpenUrlInDefaultBrowser(url); // PlatformUtils.h
920 }
921 
922 void GameScript::fetchUrlAsStringAsync(const std::string& url, const std::string& display_filename)
923 {
924 #if defined(USE_CURL)
925  CurlTaskContext task;
926  task.ctc_url = url;
927  task.ctc_displayname = display_filename;
928  // Messages to post // See `RoR::angelScriptThreadStatus`
929  task.ctc_msg_progress = MSG_APP_SCRIPT_THREAD_STATUS; // `RoR::ASTHREADSTATUS_CURLSTRING_PROGRESS`
930  task.ctc_msg_success = MSG_APP_SCRIPT_THREAD_STATUS; // `RoR::ASTHREADSTATUS_CURLSTRING_SUCCESS`
931  task.ctc_msg_failure = MSG_APP_SCRIPT_THREAD_STATUS; // `RoR::ASTHREADSTATUS_CURLSTRING_FAILURE`
932 
933  std::packaged_task<void(CurlTaskContext)> pktask(GetUrlAsStringMQ);
934  std::thread(std::move(pktask), task).detach();
935 #endif // defined(USE_CURL)
936 }
937 
938 void GameScript::boostCurrentTruck(float factor)
939 {
941  if (actor && actor->ar_engine)
942  {
943  float rpm = actor->ar_engine->GetEngineRpm();
944  rpm += 2000.0f * factor;
945  actor->ar_engine->SetEngineRpm(rpm);
946  }
947 }
948 
949 int GameScript::addScriptFunction(const String& arg)
950 {
951  return App::GetScriptEngine()->addFunction(arg);
952 }
953 
954 int GameScript::scriptFunctionExists(const String& arg)
955 {
956  return App::GetScriptEngine()->functionExists(arg);
957 }
958 
959 int GameScript::deleteScriptFunction(const String& arg)
960 {
961  return App::GetScriptEngine()->deleteFunction(arg);
962 }
963 
964 int GameScript::addScriptVariable(const String& arg)
965 {
966  return App::GetScriptEngine()->addVariable(arg);
967 }
968 
969 int GameScript::deleteScriptVariable(const String& arg)
970 {
971  return App::GetScriptEngine()->deleteVariable(arg);
972 }
973 
974 int GameScript::sendGameCmd(const String& message)
975 {
976 #ifdef USE_SOCKETW
977  if (RoR::App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
978  {
979  App::GetNetwork()->AddPacket(0, RoRnet::MSG2_GAME_CMD, (int)message.size(), const_cast<char*>(message.c_str()));
980  return 0;
981  }
982 #endif // USE_SOCKETW
983 
984  return -11;
985 }
986 
987 AngelScript::CScriptArray* GameScript::getRunningScripts()
988 {
989  std::vector<ScriptUnitId_t> ids;
990  for (auto& pair: App::GetScriptEngine()->getScriptUnits())
991  ids.push_back(pair.first);
992 
993  return VectorToScriptArray(ids, "int");
994 }
995 
996 
997 AngelScript::CScriptDictionary* GameScript::getScriptDetails(ScriptUnitId_t nid)
998 {
999  if (!App::GetScriptEngine()->scriptUnitExists(nid))
1000  return nullptr;
1001 
1003  AngelScript::CScriptDictionary* dict = AngelScript::CScriptDictionary::Create(App::GetScriptEngine()->getEngine());
1004  int stringTypeid = App::GetScriptEngine()->getEngine()->GetTypeIdByDecl("string");
1005  int scriptCategoryTypeid = App::GetScriptEngine()->getEngine()->GetTypeIdByDecl("ScriptCategory");
1006 
1007  dict->Set("uniqueId", (asINT64)info.uniqueId);
1008  dict->Set("scriptName", new std::string(info.scriptName), stringTypeid);
1009  dict->Set("scriptCategory", &info.scriptCategory, scriptCategoryTypeid);
1010  dict->Set("eventMask", (asINT64)info.eventMask);
1011  dict->Set("scriptBuffer", new std::string(info.scriptBuffer), stringTypeid);
1012 
1013  // TBD Some other time...
1014  //AngelScript::asIScriptModule* scriptModule = nullptr;
1015  //AngelScript::asIScriptFunction* frameStepFunctionPtr = nullptr; //!< script function pointer to the frameStep function
1016  //AngelScript::asIScriptFunction* eventCallbackFunctionPtr = nullptr; //!< script function pointer to the event callback function
1017  //AngelScript::asIScriptFunction* eventCallbackExFunctionPtr = nullptr; //!< script function pointer to the event callback function
1018  //AngelScript::asIScriptFunction* defaultEventCallbackFunctionPtr = nullptr; //!< script function pointer for spawner events
1019  //ActorPtr associatedActor; //!< For ScriptCategory::ACTOR
1020  //Ogre::String scriptHash;
1021 
1022  return dict;
1023 }
1024 
1025 VehicleAIPtr GameScript::getCurrentTruckAI()
1026 {
1027  VehicleAIPtr result = nullptr;
1028  if (App::GetGameContext()->GetPlayerActor())
1029  {
1031  }
1032  return result;
1033 }
1034 
1035 VehicleAIPtr GameScript::getTruckAIByNum(int num)
1036 {
1037  VehicleAIPtr result = nullptr;
1039  if (actor != nullptr)
1040  {
1041  result = actor->ar_vehicle_ai;
1042  }
1043  return result;
1044 }
1045 
1046 ActorPtr GameScript::spawnTruck(Ogre::String& truckName, Ogre::Vector3& pos, Ogre::Vector3& rot)
1047 {
1048  ActorSpawnRequest rq;
1049  rq.asr_position = pos;
1050  rq.asr_rotation = Quaternion(Degree(rot.x), Vector3::UNIT_X) * Quaternion(Degree(rot.y), Vector3::UNIT_Y) * Quaternion(Degree(rot.z), Vector3::UNIT_Z);
1051  rq.asr_filename = truckName;
1052  return App::GetGameContext()->SpawnActor(rq);
1053 }
1054 
1055 ActorPtr GameScript::spawnTruckAI(Ogre::String& truckName, Ogre::Vector3& pos, Ogre::String& truckSectionConfig, std::string& truckSkin, int x)
1056 {
1057  try
1058  {
1059  ActorSpawnRequest rq;
1060  rq.asr_position = pos;
1061 
1062  // Set rotation based on first two waypoints
1063  std::vector<Ogre::Vector3> waypoints;
1064  for (int i = 0; i < App::GetGuiManager()->TopMenubar.ai_waypoints.size(); i++)
1065  {
1066  waypoints.push_back(App::GetGuiManager()->TopMenubar.ai_waypoints[i].position);
1067  }
1068  if (App::GetGuiManager()->TopMenubar.ai_mode == 3 && x == 1) // Crash driving mode
1069  {
1070  std::reverse(waypoints.begin(), waypoints.end());
1071  }
1072 
1073  // Check if we have enough waypoints
1074  Ogre::Vector3 dir = Ogre::Vector3::ZERO;
1075  if (waypoints.size() >= 2)
1076  dir = waypoints[0] - waypoints[1];
1077  else if (waypoints.size() >= 1)
1078  dir = waypoints[0];
1079  dir.y = 0;
1080  rq.asr_rotation = Ogre::Vector3::UNIT_X.getRotationTo(dir, Ogre::Vector3::UNIT_Y);
1081 
1082  rq.asr_filename = truckName;
1083  rq.asr_config = truckSectionConfig;
1086  return App::GetGameContext()->SpawnActor(rq);
1087  }
1088  catch (...)
1089  {
1090  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::setMaterialTextureScale()");
1091  return ActorPtr();
1092  }
1093 }
1094 
1095 AngelScript::CScriptArray* GameScript::getWaypoints(int x)
1096 {
1097  std::vector<Ogre::Vector3> vec;
1098  for (int i = 0; i < App::GetGuiManager()->TopMenubar.ai_waypoints.size(); i++)
1099  {
1100  vec.push_back(App::GetGuiManager()->TopMenubar.ai_waypoints[i].position);
1101  }
1102  if (App::GetGuiManager()->TopMenubar.ai_mode == 3 && x == 1) // Crash driving mode
1103  {
1104  std::reverse(vec.begin(), vec.end());
1105  }
1106 
1107  AngelScript::CScriptArray* arr = AngelScript::CScriptArray::Create(AngelScript::asGetActiveContext()->GetEngine()->GetTypeInfoByDecl("array<vector3>"), vec.size());
1108 
1109  for(AngelScript::asUINT i = 0; i < arr->GetSize(); i++)
1110  {
1111  // Set the value of each element
1112  arr->SetValue(i, &vec[i]);
1113  }
1114 
1115  return arr;
1116 }
1117 
1118 AngelScript::CScriptArray* GameScript::getAllTrucks()
1119 {
1121  AngelScript::CScriptArray* arr = AngelScript::CScriptArray::Create(AngelScript::asGetActiveContext()->GetEngine()->GetTypeInfoByDecl("array<BeamClass@>"), actors.size());
1122 
1123  for (AngelScript::asUINT i = 0; i < arr->GetSize(); i++)
1124  {
1125  // Set the value of each element
1126  arr->SetValue(i, &actors[i]);
1127  }
1128 
1129  return arr;
1130 }
1131 
1132 void GameScript::addWaypoint(const Ogre::Vector3& pos)
1133 {
1134  std::vector<Ogre::Vector3> waypoints;
1135  for (int i = 0; i < App::GetGuiManager()->TopMenubar.ai_waypoints.size(); i++)
1136  {
1137  waypoints.push_back(App::GetGuiManager()->TopMenubar.ai_waypoints[i].position);
1138  }
1139 }
1140 
1141 AngelScript::CScriptArray* GameScript::getWaypointsSpeed()
1142 {
1143  std::vector<int> vec;
1144  for (int i = 0; i < App::GetGuiManager()->TopMenubar.ai_waypoints.size(); i++)
1145  {
1146  vec.push_back(App::GetGuiManager()->TopMenubar.ai_waypoints[i].speed);
1147  }
1148 
1149  AngelScript::CScriptArray* arr = AngelScript::CScriptArray::Create(AngelScript::asGetActiveContext()->GetEngine()->GetTypeInfoByDecl("array<int>"), vec.size());
1150 
1151  for(AngelScript::asUINT i = 0; i < arr->GetSize(); i++)
1152  {
1153  // Set the value of each element
1154  arr->SetValue(i, &vec[i]);
1155  }
1156 
1157  return arr;
1158 }
1159 
1160 int GameScript::getAIVehicleCount()
1161 {
1162  int num = App::GetGuiManager()->TopMenubar.ai_num;
1163  return num;
1164 }
1165 
1166 int GameScript::getAIVehicleDistance()
1167 {
1169  return dist;
1170 }
1171 
1172 int GameScript::getAIVehiclePositionScheme()
1173 {
1175  return scheme;
1176 }
1177 
1178 int GameScript::getAIVehicleSpeed()
1179 {
1180  int speed = App::GetGuiManager()->TopMenubar.ai_speed;
1181  return speed;
1182 }
1183 
1184 Ogre::String GameScript::getAIVehicleName(int x)
1185 {
1186  if ((App::GetGuiManager()->TopMenubar.ai_mode == 2 || App::GetGuiManager()->TopMenubar.ai_mode == 3) && x == 1) // Drag Race or Crash driving mode
1187  {
1188  Ogre::String name = App::GetGuiManager()->TopMenubar.ai_fname2;
1189  return name;
1190  }
1191  else
1192  {
1193  Ogre::String name = App::GetGuiManager()->TopMenubar.ai_fname;
1194  return name;
1195  }
1196 }
1197 
1198 Ogre::String GameScript::getAIVehicleSectionConfig(int x)
1199 {
1200  if ((App::GetGuiManager()->TopMenubar.ai_mode == 2 || App::GetGuiManager()->TopMenubar.ai_mode == 3) && x == 1) // Drag Race or Crash driving mode
1201  {
1202  Ogre::String config = App::GetGuiManager()->TopMenubar.ai_sectionconfig2;
1203  return config;
1204  }
1205  else
1206  {
1207  Ogre::String config = App::GetGuiManager()->TopMenubar.ai_sectionconfig;
1208  return config;
1209  }
1210 }
1211 
1212 std::string GameScript::getAIVehicleSkin(int x)
1213 {
1214  if ((App::GetGuiManager()->TopMenubar.ai_mode == 2 || App::GetGuiManager()->TopMenubar.ai_mode == 3) && x == 1) // Drag Race or Crash driving mode
1215  {
1216  std::string skin = App::GetGuiManager()->TopMenubar.ai_skin2;
1217  return skin;
1218  }
1219  else
1220  {
1221  std::string skin = App::GetGuiManager()->TopMenubar.ai_skin;
1222  return skin;
1223  }
1224 }
1225 
1226 int GameScript::getAIRepeatTimes()
1227 {
1228  int times = App::GetGuiManager()->TopMenubar.ai_times;
1229  return times;
1230 }
1231 
1232 int GameScript::getAIMode()
1233 {
1234  int mode = App::GetGuiManager()->TopMenubar.ai_mode;
1235  return mode;
1236 }
1237 
1238 // AI: set
1239 
1240 void GameScript::setAIVehicleCount(int num)
1241 {
1243 }
1244 
1245 void GameScript::setAIVehicleDistance(int dist)
1246 {
1248 }
1249 
1250 void GameScript::setAIVehiclePositionScheme(int scheme)
1251 {
1253 }
1254 
1255 void GameScript::setAIVehicleSpeed(int speed)
1256 {
1258 }
1259 
1260 void GameScript::setAIVehicleName(int x, std::string name)
1261 {
1262  if ((App::GetGuiManager()->TopMenubar.ai_mode == 2 || App::GetGuiManager()->TopMenubar.ai_mode == 3) && x == 1) // Drag Race or Crash driving mode
1263  {
1265  }
1266  else
1267  {
1269  }
1270 }
1271 
1272 void GameScript::setAIVehicleSectionConfig(int x, std::string config)
1273 {
1274  switch (x)
1275  {
1276  case 0:
1278  break;
1279  case 1:
1281  break;
1282  default:
1283  this->log(fmt::format("setAIVehicleSectionConfig: ERROR, valid 'x' is 0 or 1, got {}", x));
1284  break;
1285  }
1286 }
1287 
1288 void GameScript::setAIVehicleSkin(int x, std::string skin)
1289 {
1290  switch (x)
1291  {
1292  case 0:
1294  break;
1295  case 1:
1297  break;
1298  default:
1299  this->log(fmt::format("setAIVehicleSkin: ERROR, valid 'x' is 0 or 1, got {}", x));
1300  break;
1301  }
1302 }
1303 
1304 void GameScript::setAIRepeatTimes(int times)
1305 {
1307 }
1308 
1309 void GameScript::setAIMode(int mode)
1310 {
1312 }
1313 
1314 void GameScript::showMessageBox(Ogre::String& title, Ogre::String& text, bool use_btn1, Ogre::String& btn1_text, bool allow_close, bool use_btn2, Ogre::String& btn2_text)
1315 {
1316  // Sanitize inputs
1317  const char* btn1_cstr = nullptr; // = Button disabled
1318  const char* btn2_cstr = nullptr;
1319 
1320  if (use_btn1)
1321  {
1322  btn1_cstr = (btn1_text.empty() ? "~1~" : btn1_text.c_str());
1323  }
1324  if (use_btn2)
1325  {
1326  btn2_cstr = (btn2_text.empty() ? "~2~" : btn2_text.c_str());
1327  }
1328 
1329  RoR::App::GetGuiManager()->ShowMessageBox(title.c_str(), text.c_str(), allow_close, btn1_cstr, btn2_cstr);
1330 }
1331 
1332 void GameScript::backToMenu()
1333 {
1336 }
1337 
1338 void GameScript::quitGame()
1339 {
1341 }
1342 
1343 float GameScript::getFPS()
1344 {
1345  return App::GetAppContext()->GetRenderWindow()->getStatistics().lastFPS;
1346 }
1347 
1348 float GameScript::getAvgFPS()
1349 {
1350  return App::GetAppContext()->GetRenderWindow()->getStatistics().avgFPS;
1351 }
1352 
1353 bool GameScript::getMousePositionOnTerrain(Ogre::Vector3& out_pos)
1354 {
1355  if (!HaveSimTerrain(__FUNCTION__))
1356  return false;
1357 
1358  Ogre::Vector2 mouse_npos = App::GetInputEngine()->getMouseNormalizedScreenPos();
1359  Ogre::Ray ray = App::GetCameraManager()->GetCamera()->getCameraToViewportRay(mouse_npos.x, mouse_npos.y);
1360  Ogre::TerrainGroup::RayResult ray_result = App::GetGameContext()->GetTerrain()->getGeometryManager()->getTerrainGroup()->rayIntersects(ray);
1361  if (ray_result.hit)
1362  {
1363  out_pos = ray_result.position;
1364  }
1365  return ray_result.hit;
1366 }
1367 
1368 Ogre::SceneManager* GameScript::getSceneManager()
1369 {
1370  return App::GetGfxScene()->GetSceneManager();
1371 }
1372 
1373 bool GameScript::pushMessage(MsgType type, AngelScript::CScriptDictionary* dict)
1374 {
1375  Message m(type);
1376  std::string log_msg = fmt::format("`pushMessage({})`", MsgTypeToString(type));
1377 
1378  switch (type)
1379  {
1380  // -- NOT ALLOWED --
1381 
1382  // Application
1384  // Networking
1389  case MSG_NET_SERVER_KICK:
1391  case MSG_NET_RECV_ERROR:
1397  // GUI
1402  // Editing
1404  this->log(fmt::format("{} is not allowed.", log_msg));
1405  return false;
1406 
1407 
1408  // -- SOME ASSEMBLY REQUIRED --
1409 
1410  // Application
1412  {
1414  bool has_filename = GetValueFromScriptDict(log_msg, dict, /*required:*/false, "filename", "string", rq->lsr_filename);
1415  bool has_buffer = GetValueFromScriptDict(log_msg, dict, /*required:*/false, "buffer", "string", rq->lsr_buffer);
1416  if (!has_filename && !has_buffer)
1417  {
1418  this->log(fmt::format("{}: ERROR, either 'filename' or 'buffer' must be set!", log_msg));
1419  delete rq;
1420  return false;
1421  }
1422  GetValueFromScriptDict(log_msg, dict, /*required:*/false, "category", "ScriptCategory", rq->lsr_category);
1423  if (rq->lsr_category == ScriptCategory::ACTOR)
1424  {
1425  int64_t instance_id; // AngelScript's `Dictionary` converts all ints int `int64`
1426  if (!GetValueFromScriptDict(log_msg, dict, /*required:*/true, "associated_actor", "int64", instance_id))
1427  {
1428  this->log(fmt::format("{}: WARNING, category 'ACTOR' specified but 'associated_actor' not given.", log_msg, rq->lsr_filename));
1429  delete rq;
1430  return false;
1431  }
1432  }
1433  m.payload = rq;
1434  break;
1435  }
1436 
1438  {
1439  int64_t id; // AngelScript's `Dictionary` converts all ints int `int64`
1440  if (!GetValueFromScriptDict(log_msg, dict, /*required:*/true, "id", "int64", id))
1441  {
1442  return false;
1443  }
1444  m.payload = new ScriptUnitId_t(static_cast<ScriptUnitId_t>(id));
1445  break;
1446  }
1447 
1448  // Simulation
1450  if (!GetValueFromScriptDict(log_msg, dict, /*required:*/true, "filename", "string", m.description))
1451  {
1452  return false;
1453  }
1454  break;
1455 
1457  if (!GetValueFromScriptDict(log_msg, dict, /*required:*/true, "filename", "string", m.description))
1458  {
1459  return false;
1460  }
1461  break;
1462 
1464  {
1466 
1467  // Get required params
1468  if (GetValueFromScriptDict(log_msg, dict, /*required:*/true, "filename", "string", rq->asr_filename) &&
1469  GetValueFromScriptDict(log_msg, dict, /*required:*/true, "position", "vector3", rq->asr_position) &&
1470  GetValueFromScriptDict(log_msg, dict, /*required:*/true, "rotation", "quaternion", rq->asr_rotation))
1471  {
1473  if (!rq->asr_cache_entry)
1474  {
1475  this->log(fmt::format("{}: WARNING, vehicle '{}' is not installed.", log_msg, rq->asr_filename));
1476  delete rq;
1477  return false;
1478  }
1479 
1480  // Set sectionconfig
1481  GetValueFromScriptDict(log_msg, dict, /*required:*/false, "config", "string", rq->asr_config);
1482  // Make sure config exists
1483  if (rq->asr_config != "")
1484  {
1485  auto result = std::find(rq->asr_cache_entry->sectionconfigs.begin(), rq->asr_cache_entry->sectionconfigs.end(), rq->asr_config);
1486  if (result == rq->asr_cache_entry->sectionconfigs.end())
1487  {
1488  this->log(fmt::format("{}: WARNING, configuration '{}' does not exist in '{}'.", log_msg, rq->asr_config, rq->asr_filename));
1489  rq->asr_config = "";
1490  }
1491  }
1492  // If no config given (or was invalid), use the first available (classic behavior).
1493  if (rq->asr_config == "" && rq->asr_cache_entry->sectionconfigs.size() > 0)
1494  {
1496  }
1497 
1498  // Enter or not?
1499  GetValueFromScriptDict(log_msg, dict, /*required:*/false, "enter", "bool", rq->asr_enter);
1500 
1501  // Get skin
1502  std::string skin_name;
1503  if (GetValueFromScriptDict(log_msg, dict, /*required:*/false, "skin", "string", skin_name))
1504  {
1506  if (!rq->asr_skin_entry)
1507  this->log(fmt::format("{}: WARNING, skin '{}' is not installed.", log_msg, skin_name));
1508  }
1509 
1510  m.payload = rq;
1511  }
1512  else
1513  {
1514  delete rq;
1515  return false;
1516  }
1517  break;
1518  }
1519 
1521  {
1522  ActorModifyRequest::Type modify_type;
1523  // `dictionary` converts all primitives to `double` or `int64`, see 'scriptdictionary.cpp', function `Set()`
1524  int64_t instance_id = -1;
1525  if (GetValueFromScriptDict(log_msg, dict, /*required:*/true, "type", "ActorModifyRequestType", modify_type) &&
1526  GetValueFromScriptDict(log_msg, dict, /*required:*/true, "instance_id", "int64", instance_id))
1527  {
1529  rq->amr_type = modify_type;
1530  rq->amr_actor = static_cast<ActorInstanceID_t>(instance_id);
1531  m.payload = rq;
1532  }
1533  else
1534  {
1535  return false;
1536  }
1537  break;
1538  }
1539 
1543  {
1544  // `dictionary` converts all primitives to `double` or `int64`, see 'scriptdictionary.cpp', function `Set()`
1545  int64_t instance_id = -1;
1546  if (GetValueFromScriptDict(log_msg, dict, /*required:*/true, "instance_id", "int64", instance_id))
1547  {
1548  ActorPtr actor = App::GetGameContext()->GetActorManager()->GetActorById(instance_id);
1549  if (actor)
1550  {
1551  m.payload = new ActorPtr(actor);
1552  }
1553  else
1554  {
1555  this->log(fmt::format("{}: Actor with instance ID '{}' not found!", log_msg, instance_id));
1556  return false;
1557  }
1558  }
1559  else
1560  {
1561  return false;
1562  }
1563  break;
1564  }
1565 
1567  {
1568  // `dictionary` converts all primitives to `double` or `int64`, see 'scriptdictionary.cpp', function `Set()`
1569  int64_t instance_id = -1;
1570  ActorPtr actor;
1571  if (GetValueFromScriptDict(log_msg, dict, /*required:*/true, "instance_id", "int64", instance_id)
1572  && instance_id > -1)
1573  {
1574  actor = App::GetGameContext()->GetActorManager()->GetActorById(instance_id);
1575  }
1576  m.payload = new ActorPtr(actor);
1577  break;
1578  }
1579 
1581  {
1582  Ogre::Vector3 position;
1583  if (GetValueFromScriptDict(log_msg, dict, /*required:*/true, "position", "vector3", position))
1584  {
1585  m.payload = new Ogre::Vector3(position);
1586  }
1587  else
1588  {
1589  return false;
1590  }
1591  break;
1592  }
1593 
1597  {
1598  CacheEntryPtr entry;
1599  if (GetValueFromScriptDict(log_msg, dict, /*required*/true, "cache_entry", "CacheEntryClass@", entry))
1600  {
1601  m.payload = new CacheEntryPtr(entry);
1602  }
1603  else
1604  {
1605  return false;
1606  }
1607  break;
1608  }
1609 
1611  {
1612  CreateProjectRequest* request = new CreateProjectRequest();
1613  if (GetValueFromScriptDict(log_msg, dict, /*required:*/true, "name", "string", request->cpr_name) &&
1614  GetValueFromScriptDict(log_msg, dict, /*required:*/true, "source_entry", "CacheEntryClass@", request->cpr_source_entry))
1615  {
1616  m.payload = request;
1617  }
1618  else
1619  {
1620  delete request;
1621  return false;
1622  }
1623  break;
1624  }
1625 
1626  default:;
1627  }
1628 
1630  return true;
1631 }
1632 
1633 // --------------------------------
1634 // Audio
1635 
1636 CScriptArray* GameScript::getAllSoundScriptTemplates()
1637 {
1638  return MapToScriptArray(App::GetSoundScriptManager()->getAllTemplates(), "SoundScriptTemplateClass@");
1639 }
1640 
1641 SoundScriptTemplatePtr GameScript::getSoundScriptTemplate(const std::string& name)
1642 {
1643  return App::GetSoundScriptManager()->getTemplate(name);
1644 }
1645 
1646 AngelScript::CScriptArray* GameScript::getAllSoundScriptInstances()
1647 {
1648  return VectorToScriptArray(App::GetSoundScriptManager()->getAllInstances(), "SoundScriptInstanceClass@");
1649 }
1650 
1651 SoundPtr GameScript::createSoundFromResource(const std::string& filename, const std::string& resource_group_name)
1652 {
1653  return App::GetSoundScriptManager()->getSoundManager()->createSound(filename, resource_group_name);
1654 }
1655 
1656 SoundScriptInstancePtr GameScript::createSoundScriptInstance(const std::string& template_name, int actor_instance_id = SoundScriptInstance::ACTOR_ID_UNKNOWN)
1657 {
1658  return App::GetSoundScriptManager()->createInstance(template_name, actor_instance_id);
1659 }
1660 
1661 bool GameScript::checkResourceExists(const std::string& filename, const std::string& resource_group)
1662 {
1663  try
1664  {
1665  std::string resource_name = this->CheckFileAccess("checkResourceExists()", filename, resource_group);
1666  if (resource_name == "")
1667  return false; // Access denied - error already logged
1668 
1669  // Actually check for the resource
1670  return Ogre::ResourceGroupManager::getSingleton().resourceExists(resource_group, resource_name);
1671  }
1672  catch (...)
1673  {
1674  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::checkResourceExists()");
1675  return false;
1676  }
1677 }
1678 
1679 bool GameScript::deleteResource(const std::string& filename, const std::string& resource_group)
1680 {
1681  try
1682  {
1683  std::string resource_name = this->CheckFileAccess("deleteResource()", filename, resource_group);
1684  if (resource_name == "")
1685  return false; // Access denied - error already logged
1686 
1687  // Actually delete the resource
1688  Ogre::ResourceGroupManager::getSingleton().deleteResource(resource_name, resource_group);
1689  return true;
1690  }
1691  catch (...)
1692  {
1693  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::deleteResource()");
1694  return false;
1695  }
1696 }
1697 
1698 std::string GameScript::loadTextResourceAsString(const std::string& filename, const std::string& resource_group)
1699 {
1700  try
1701  {
1702  std::string resource_name = this->CheckFileAccess("loadTextResourceAsString()", filename, resource_group);
1703  if (resource_name == "")
1704  return ""; // Access denied - error already logged
1705 
1706  Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(resource_name, resource_group);
1707 
1708  if (stream.isNull() || !stream->isReadable())
1709  {
1710  App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_SCRIPT, Console::CONSOLE_SYSTEM_ERROR,
1711  fmt::format("loadTextResourceAsString() could not read resource '{}' in group '{}'",
1712  resource_name, resource_group));
1713  return "";
1714  }
1715 
1716 #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
1717  // WORKAROUND: apparently `getAsString()` has some Linux-x64 issues (`eof()` triggers SIGINT):
1718  // https://discord.com/channels/136544456244461568/189904947649708032/1155952230130778262
1719  // Observed with OGRE 1.11.6
1720  std::string str;
1721  const size_t BUF_LEN = 4000;
1722  char buf[BUF_LEN] = {};
1723  bool eof = false;
1724  while (!eof)
1725  {
1726  size_t read_len = stream->read(buf, BUF_LEN);
1727  if (read_len < BUF_LEN)
1728  {
1729  buf[read_len] = 0;
1730  eof = true;
1731  }
1732  str.append(buf, read_len);
1733  }
1734  return str;
1735 #else
1736  return stream->getAsString();
1737 #endif
1738  }
1739  catch (...)
1740  {
1741  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::loadTextResourceAsString()");
1742  return "";
1743  }
1744 }
1745 
1746 bool GameScript::createTextResourceFromString(const std::string& data, const std::string& filename, const std::string& resource_group, bool overwrite/*=false*/)
1747 {
1748  try
1749  {
1750  std::string resource_name = this->CheckFileAccess("createTextResourceFromString()", filename, resource_group);
1751  if (resource_name == "")
1752  return false; // Access denied - error already logged
1753 
1754  Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().createResource(resource_name, resource_group, overwrite);
1755 
1756  if (stream.isNull() || !stream->isWriteable())
1757  {
1758  App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_SCRIPT, Console::CONSOLE_SYSTEM_ERROR,
1759  fmt::format("createTextResourceFromString() could not create resource '{}' in group '{}'",
1760  resource_name, resource_group));
1761  return false;
1762  }
1763 
1764  stream->write(data.data(), data.size());
1765  return true;
1766  }
1767  catch (...)
1768  {
1769  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::createTextResourceFromString()");
1770  return false;
1771  }
1772 }
1773 
1774 AngelScript::CScriptArray* GameScript::findResourceFileInfo(const std::string& resource_group, const std::string& pattern, bool dirs /*= false*/)
1775 {
1776  try
1777  {
1778  // Search the file system
1779  Ogre::FileInfoListPtr fileInfoList
1780  = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo(resource_group, pattern, dirs);
1781 
1782  // Put results to array
1783  AngelScript::asITypeInfo* typeinfo = App::GetScriptEngine()->getEngine()->GetTypeInfoByDecl("array<dictionary>");
1784  AngelScript::CScriptArray* arr = AngelScript::CScriptArray::Create(typeinfo);
1785  int stringTypeid = App::GetScriptEngine()->getEngine()->GetTypeIdByDecl("string");
1786  for (const Ogre::FileInfo& fileinfo: *fileInfoList)
1787  {
1788  AngelScript::CScriptDictionary* dict = AngelScript::CScriptDictionary::Create(App::GetScriptEngine()->getEngine());
1789  dict->Set("filename", new std::string(fileinfo.filename), stringTypeid);
1790  dict->Set("basename", new std::string(fileinfo.basename), stringTypeid);
1791  dict->Set("compressedSize", (asINT64)fileinfo.compressedSize);
1792  dict->Set("uncompressedSize", (asINT64)fileinfo.uncompressedSize);
1793 
1794  arr->InsertLast(dict);
1795  }
1796  return arr;
1797  }
1798  catch (...)
1799  {
1800  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::findResourceFileInfo()");
1801  return nullptr;
1802  }
1803 }
1804 
1805 Ogre::Image GameScript::loadImageResource(const std::string& filename, const std::string& resource_group)
1806 {
1807  try
1808  {
1809  std::string resource_name = this->CheckFileAccess("loadImageResource()", filename, resource_group);
1810  if (resource_name == "")
1811  return Ogre::Image(); // Access denied - error already logged
1812 
1813  Ogre::Image img;
1814  return img.load(resource_name, resource_group);
1815  }
1816  catch (...)
1817  {
1818  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::loadImageResource()");
1819  return Ogre::Image();
1820  }
1821 }
1822 
1823 bool GameScript::serializeMeshResource(const std::string& filename, const std::string& resource_group, const Ogre::MeshPtr& mesh)
1824 {
1825  try
1826  {
1827  std::string resource_name = this->CheckFileAccess("serializeMeshResource()", filename, resource_group);
1828  if (resource_name == "")
1829  return false; // Access denied - error already logged
1830 
1831  Ogre::MeshSerializer ser;
1832  Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().createResource(resource_name, resource_group);
1833  ser.exportMesh(mesh.get(), stream);
1834  return true;
1835  }
1836  catch (...)
1837  {
1838  App::GetScriptEngine()->forwardExceptionAsScriptEvent("GameScript::serializeMeshResource()");
1839  return false;
1840  }
1841 }
1842 
1843 // ------------------------
1844 // Helpers:
1845 
1846 bool GameScript::HaveSimTerrain(const char* func_name)
1847 {
1848  if (App::GetGameContext()->GetTerrain() == nullptr)
1849  {
1850  this->logFormat("Cannot execute '%s', terrain not ready", func_name);
1851  return false;
1852  }
1853  return true;
1854 }
1855 
1856 bool GameScript::HavePlayerAvatar(const char* func_name)
1857 {
1858  if (App::GetGameContext()->GetPlayerCharacter() == nullptr)
1859  {
1860  this->logFormat("Cannot execute '%s', player avatar not ready", func_name);
1861  return false;
1862  }
1863  return true;
1864 }
1865 
1866 bool GameScript::HaveMainCamera(const char* func_name)
1867 {
1868  if (App::GetCameraManager()->GetCamera() == nullptr)
1869  {
1870  this->logFormat("Cannot execute '%s', main camera not ready", func_name);
1871  return false;
1872  }
1873  return true;
1874 }
1875 
1876 std::string GameScript::CheckFileAccess(const char* func_name, const std::string& filename, const std::string& resource_group)
1877 {
1878  // Extract filename and extension from the input, because OGRE allows absolute paths in resource system.
1879  // -----------------------------------------------------------------------------------------------------
1880 
1881  std::string basename, extension, path;
1882  Ogre::StringUtil::splitFullFilename(filename, basename, extension, path);
1883  if (path != "")
1884  {
1885  App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_SCRIPT, Console::CONSOLE_SYSTEM_ERROR,
1886  fmt::format("{}: access denied to '{}' with group '{}' - file paths are not allowed",
1887  func_name, filename, resource_group));
1888  return "";
1889  }
1890  else
1891  {
1892  return basename + "." + extension;
1893  }
1894 }
RoR::ScriptUnit
Represents a loaded script and all associated resources/handles.
Definition: ScriptEngine.h:69
GameContext.h
Game state manager and message-queue provider.
RoR::MSG_SIM_LOAD_TERRN_REQUESTED
@ MSG_SIM_LOAD_TERRN_REQUESTED
Definition: Application.h:107
RoR::Character::getRotation
Ogre::Radian getRotation() const
Definition: Character.h:54
RoR::IWater::GetStaticWaterHeight
virtual float GetStaticWaterHeight()=0
Returns static water level configured in 'terrn2'.
RoR::App::GetNetwork
Network * GetNetwork()
Definition: Application.cpp:283
RoR::Character::setPosition
void setPosition(Ogre::Vector3 position)
Definition: Character.cpp:85
RoR::LoadScriptRequest::lsr_filename
std::string lsr_filename
Load from resource (file). If buffer is supplied, use this as display name only.
Definition: ScriptEngine.h:92
RoR::App::GetSoundScriptManager
SoundScriptManager * GetSoundScriptManager()
Definition: Application.cpp:276
Script2Game::log
void log(const string message)
This is an alias for game.log(string message).
RoR::MSG_GUI_SHOW_MESSAGE_BOX_REQUESTED
@ MSG_GUI_SHOW_MESSAGE_BOX_REQUESTED
Payload = MessageBoxConfig* (owner)
Definition: Application.h:126
RoR::EngineSim::SetEngineRpm
void SetEngineRpm(float rpm)
Set current engine RPM.
Definition: EngineSim.cpp:918
RoR::GUI::TopMenubar::ai_fname2
Ogre::String ai_fname2
Definition: GUI_TopMenubar.h:87
RoR::Actor::ar_vehicle_ai
VehicleAIPtr ar_vehicle_ai
Definition: Actor.h:386
RoR::VectorToScriptArray
AngelScript::CScriptArray * VectorToScriptArray(const std::vector< T > &vec, const std::string &decl)
Definition: ScriptUtils.h:42
RoR::GUI::TopMenubar::ai_fname
Ogre::String ai_fname
Definition: GUI_TopMenubar.h:76
RoR::GUI::TopMenubar::ai_num
int ai_num
Definition: GUI_TopMenubar.h:70
RoR::MSG_SIM_MODIFY_ACTOR_REQUESTED
@ MSG_SIM_MODIFY_ACTOR_REQUESTED
Payload = RoR::ActorModifyRequest* (owner)
Definition: Application.h:111
RoR::MSG_EDI_RELOAD_BUNDLE_REQUESTED
@ MSG_EDI_RELOAD_BUNDLE_REQUESTED
Payload = RoR::CacheEntryPtr* (owner)
Definition: Application.h:134
RoR::OpenUrlInDefaultBrowser
void OpenUrlInDefaultBrowser(std::string const &url)
Definition: PlatformUtils.cpp:199
RoR::Actor::ar_filename
std::string ar_filename
Attribute; filled at spawn.
Definition: Actor.h:414
RoR::MpState::CONNECTED
@ CONNECTED
RoR::CurlTaskContext::ctc_msg_progress
MsgType ctc_msg_progress
Definition: CurlHelpers.h:39
RoR::RaceSystem::UpdateDirectionArrow
void UpdateDirectionArrow(char *text, Ogre::Vector3 position)
Definition: RaceSystem.cpp:31
RoR::MSG_NET_USER_DISCONNECT
@ MSG_NET_USER_DISCONNECT
Definition: Application.h:96
RoR::App::GetCameraManager
CameraManager * GetCameraManager()
Definition: Application.cpp:274
RoR::ActorSpawnRequest::asr_origin
Origin asr_origin
Definition: SimData.h:814
RoR::CacheEntryPtr
RefCountingObjectPtr< CacheEntry > CacheEntryPtr
Definition: ForwardDeclarations.h:184
VehicleAI.h
Simple waypoint AI.
RoR::App::GetGuiManager
GUIManager * GetGuiManager()
Definition: Application.cpp:268
RoR::App::mp_api_url
CVar * mp_api_url
Definition: Application.cpp:126
RoR::MSG_EDI_CREATE_PROJECT_REQUESTED
@ MSG_EDI_CREATE_PROJECT_REQUESTED
Payload = RoR::CreateProjectRequest* (owner)
Definition: Application.h:136
RoR::ScriptUnit::eventMask
unsigned int eventMask
filter mask for script events
Definition: ScriptEngine.h:76
RoR::GUI::TopMenubar::ai_position_scheme
int ai_position_scheme
Definition: GUI_TopMenubar.h:75
RoR::Actor::ar_linked_actors
ActorPtrVec ar_linked_actors
Sim state; other actors linked using 'hooks'.
Definition: Actor.h:304
RoR::MSG_EDI_UNLOAD_BUNDLE_REQUESTED
@ MSG_EDI_UNLOAD_BUNDLE_REQUESTED
Payload = RoR::CacheEntryPtr* (owner)
Definition: Application.h:135
RoR::App::mp_player_name
CVar * mp_player_name
Definition: Application.cpp:124
RoR::Actor::ar_instance_id
ActorInstanceID_t ar_instance_id
Static attr; session-unique ID.
Definition: Actor.h:365
RoR::CacheSystem::FindEntryByFilename
CacheEntryPtr FindEntryByFilename(RoR::LoaderType type, bool partial, const std::string &filename)
Returns NULL if none found.
Definition: CacheSystem.cpp:177
SkyManager.h
RoR::MSG_SIM_UNLOAD_TERRN_REQUESTED
@ MSG_SIM_UNLOAD_TERRN_REQUESTED
Definition: Application.h:109
GUI_TopMenubar.h
RoR::AppContext::GetRenderWindow
Ogre::RenderWindow * GetRenderWindow()
Definition: AppContext.h:67
RoR::App::GetAppContext
AppContext * GetAppContext()
Definition: Application.cpp:265
RoR::GUI::TopMenubar::ai_skin2
std::string ai_skin2
Definition: GUI_TopMenubar.h:90
format
Truck file format(technical spec)
RoR::Terrain::getObjectManager
TerrainObjectManager * getObjectManager()
Definition: Terrain.h:77
RoR::RaceSystem::SetRaceBestTime
void SetRaceBestTime(float time)
Definition: RaceSystem.h:43
RoR::Terrain::getSkyManager
SkyManager * getSkyManager()
Definition: Terrain.cpp:545
RoR::MSG_NET_CONNECT_STARTED
@ MSG_NET_CONNECT_STARTED
Definition: Application.h:90
RoR::MSG_GUI_DOWNLOAD_PROGRESS
@ MSG_GUI_DOWNLOAD_PROGRESS
Definition: Application.h:127
TerrainGeometryManager.h
RoR::Collisions::clearEventCache
void clearEventCache()
Definition: Collisions.h:201
RoR::GameContext::GetPlayerCharacter
Character * GetPlayerCharacter()
Definition: GameContext.cpp:879
RoR::Terrain::setGravity
void setGravity(float value)
Definition: Terrain.cpp:513
RoR::Actor::ar_engine
EngineSim * ar_engine
Definition: Actor.h:368
RoR::SoundScriptManager::getSoundManager
SoundManager * getSoundManager()
Definition: SoundScriptManager.h:336
RoR::IWater
< TODO: Mixed gfx+physics (waves) - must be separated ~ only_a_ptr, 02/2018
Definition: IWater.h:32
RoR::MsgTypeToString
const char * MsgTypeToString(MsgType type)
Definition: Application.cpp:500
RoR::CurlTaskContext::ctc_msg_failure
MsgType ctc_msg_failure
Sent on failure; Payload: RoR::ScriptEventArgs (see 'gameplay/ScriptEvents.h') with args for RoR::SE_...
Definition: CurlHelpers.h:41
RoR::ScriptEngine::addVariable
int addVariable(const Ogre::String &arg)
Adds a global variable to the script.
Definition: ScriptEngine.cpp:639
AppContext.h
System integration layer; inspired by OgreBites::ApplicationContext.
RoR::MSG_NET_REFRESH_SERVERLIST_FAILURE
@ MSG_NET_REFRESH_SERVERLIST_FAILURE
Payload = RoR::CurlFailInfo* (owner)
Definition: Application.h:99
Console.h
RoR::ScriptEngine::getEngine
AngelScript::asIScriptEngine * getEngine()
Definition: ScriptEngine.h:223
RoR::Console::putMessage
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition: Console.cpp:97
RoR::LoadScriptRequest::lsr_buffer
std::string lsr_buffer
Load from memory buffer.
Definition: ScriptEngine.h:93
RoR::MSG_NET_RECV_ERROR
@ MSG_NET_RECV_ERROR
Definition: Application.h:97
RoR::GetValueFromScriptDict
bool GetValueFromScriptDict(const std::string &log_msg, AngelScript::CScriptDictionary *dict, bool required, std::string const &key, const char *decl, T &out_value)
Definition: ScriptUtils.h:108
RoR::LT_Load
@ LT_Load
Definition: Application.h:286
RoR::ActorManager::GetActors
ActorPtrVec & GetActors()
Definition: ActorManager.h:107
RoR::LT_Airplane
@ LT_Airplane
Definition: Application.h:283
RoR::ScriptEngine::setForwardScriptLogToConsole
void setForwardScriptLogToConsole(bool doForward)
Definition: ScriptEngine.cpp:1009
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::GetUrlAsStringMQ
bool GetUrlAsStringMQ(CurlTaskContext task)
Definition: CurlHelpers.cpp:106
RoR::MSG_APP_LOAD_SCRIPT_REQUESTED
@ MSG_APP_LOAD_SCRIPT_REQUESTED
Payload = RoR::LoadScriptRequest* (owner)
Definition: Application.h:85
RoR::GUI::TopMenubar::ai_waypoints
std::vector< ai_events > ai_waypoints
Definition: GUI_TopMenubar.h:66
RoR::App::app_country
CVar * app_country
Definition: Application.cpp:81
RoR::TerrainObjectManager::LoadTerrainObject
bool LoadTerrainObject(const Ogre::String &name, const Ogre::Vector3 &pos, const Ogre::Vector3 &rot, const Ogre::String &instancename, const Ogre::String &type, float rendering_distance=0, bool enable_collisions=true, int scripthandler=-1, bool uniquifyMaterial=false)
Definition: TerrainObjectManager.cpp:549
RoR::LT_Car
@ LT_Car
Definition: Application.h:281
RoR::CacheEntry::sectionconfigs
std::vector< Ogre::String > sectionconfigs
Definition: CacheSystem.h:135
RoR::CameraManager::GetCameraNode
Ogre::SceneNode * GetCameraNode()
Definition: CameraManager.h:63
Utils.h
RoR::App::app_disable_online_api
CVar * app_disable_online_api
Definition: Application.cpp:90
RoR::ActorSpawnRequest::asr_filename
std::string asr_filename
Definition: SimData.h:806
Language.h
RoR::LT_Extension
@ LT_Extension
Definition: Application.h:287
TerrainObjectManager.h
RoR::SoundScriptManager::getTemplate
SoundScriptTemplatePtr getTemplate(Ogre::String name)
Definition: SoundScriptManager.h:308
RefCountingObjectPtr< Actor >
RoR::World2ScreenConverter::Convert
Ogre::Vector3 Convert(Ogre::Vector3 world_pos)
Definition: Utils.h:89
RoR::ScriptEngine::deleteVariable
int deleteVariable(const Ogre::String &arg)
Deletes a global variable from the script.
Definition: ScriptEngine.cpp:659
RoR::MSG_NET_SERVER_KICK
@ MSG_NET_SERVER_KICK
Definition: Application.h:94
GUIManager.h
RoR::CreateProjectRequest::cpr_source_entry
CacheEntryPtr cpr_source_entry
The original mod to copy files from.
Definition: CacheSystem.h:218
ActorManager.h
Actor.h
RoR::CreateProjectRequest::cpr_name
std::string cpr_name
Directory and also the mod file (without extension).
Definition: CacheSystem.h:216
RoR::TerrainObjectManager::MoveObjectVisuals
void MoveObjectVisuals(const Ogre::String &instancename, const Ogre::Vector3 &pos)
Definition: TerrainObjectManager.cpp:461
RoR::App::GetScriptEngine
ScriptEngine * GetScriptEngine()
Definition: Application.cpp:278
RoR::Terrain::getTerrainName
std::string getTerrainName() const
Definition: Terrain.h:52
RoR::GfxScene::GetSceneManager
Ogre::SceneManager * GetSceneManager()
Definition: GfxScene.h:64
RoR::ActorSpawnRequest
Definition: SimData.h:789
EngineSim.h
RoR::GameContext::GetRaceSystem
RaceSystem & GetRaceSystem()
Definition: GameContext.h:168
RoR::SoundManager::createSound
SoundPtr createSound(Ogre::String filename, Ogre::String resource_group_name="")
Definition: SoundManager.cpp:354
RoR::ActorManager::GetTotalTime
float GetTotalTime() const
Definition: ActorManager.h:85
RoR::GameContext::SpawnActor
ActorPtr SpawnActor(ActorSpawnRequest &rq)
Definition: GameContext.cpp:191
RoR::Terrain::GetHeightAt
float GetHeightAt(float x, float z)
Definition: Terrain.cpp:535
RoR::IWater::UpdateWater
virtual void UpdateWater()=0
RoR::LT_Boat
@ LT_Boat
Definition: Application.h:282
RoR::MSG_NET_REFRESH_SERVERLIST_SUCCESS
@ MSG_NET_REFRESH_SERVERLIST_SUCCESS
Payload = GUI::MpServerInfoVec* (owner)
Definition: Application.h:98
RoR::App::mp_state
CVar * mp_state
Definition: Application.cpp:115
RoR::MSG_GUI_DOWNLOAD_FINISHED
@ MSG_GUI_DOWNLOAD_FINISHED
Definition: Application.h:128
RoR::GUI::TopMenubar::ai_speed
int ai_speed
Definition: GUI_TopMenubar.h:71
RoR::ActorModifyRequest::amr_actor
ActorInstanceID_t amr_actor
Definition: SimData.h:843
RoR::SCRIPTUNITID_INVALID
static const ScriptUnitId_t SCRIPTUNITID_INVALID
Definition: ForwardDeclarations.h:41
RoR::LT_Truck
@ LT_Truck
Definition: Application.h:280
RoR::LoadScriptRequest::lsr_category
ScriptCategory lsr_category
Definition: ScriptEngine.h:94
RoR::ActorSpawnRequest::asr_config
Ogre::String asr_config
Definition: SimData.h:807
RoR::MapToScriptArray
AngelScript::CScriptArray * MapToScriptArray(std::map< T, U > &map, const std::string &decl)
Definition: ScriptUtils.h:59
RoR::CameraManager::GetCamera
Ogre::Camera * GetCamera()
Definition: CameraManager.h:64
RoR::InputEngine::getMouseNormalizedScreenPos
Ogre::Vector2 getMouseNormalizedScreenPos()
Returns XY position in range from 0 (top/left) to 1 (bottom/right)
Definition: InputEngine.cpp:1660
RoR::ActorInstanceID_t
int ActorInstanceID_t
Unique sequentially generated ID of an actor in session. Use ActorManager::GetActorById()
Definition: ForwardDeclarations.h:37
RoR::RaceSystem::StopRaceTimer
void StopRaceTimer()
Definition: RaceSystem.cpp:53
RoRnet::MSG2_GAME_CMD
@ MSG2_GAME_CMD
Script message. Can be sent in both directions.
Definition: RoRnet.h:56
RoR::CVar::getStr
std::string const & getStr() const
Definition: CVar.h:95
RoR::Character::move
void move(Ogre::Vector3 offset)
Definition: Character.cpp:401
RoR::ActorModifyRequest
Definition: SimData.h:827
RoR::ScriptUnit::scriptName
Ogre::String scriptName
Definition: ScriptEngine.h:83
RoR::MSG_SIM_SEAT_PLAYER_REQUESTED
@ MSG_SIM_SEAT_PLAYER_REQUESTED
Payload = RoR::ActorPtr (owner) | nullptr.
Definition: Application.h:113
CacheSystem.h
A database of user-installed content alias 'mods' (vehicles, terrains...)
RoR::ActorPtrVec
std::vector< ActorPtr > ActorPtrVec
Definition: ForwardDeclarations.h:197
CurlHelpers.h
RoR::GUI::TopMenubar::ai_times
int ai_times
Definition: GUI_TopMenubar.h:72
RoR::ActorSpawnRequest::asr_cache_entry
CacheEntryPtr asr_cache_entry
Optional, overrides 'asr_filename' and 'asr_cache_entry_num'.
Definition: SimData.h:805
ScriptEngine.h
RoR::World2ScreenConverter
< Keeps data close for faster access.
Definition: Utils.h:81
RoR::ScriptUnit::scriptCategory
ScriptCategory scriptCategory
Definition: ScriptEngine.h:75
RoR::GameContext::PushMessage
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
Definition: GameContext.cpp:66
RoR::Terrain::getGeometryManager
TerrainGeometryManager * getGeometryManager()
Definition: Terrain.h:75
RoR::ScriptUnitId_t
int ScriptUnitId_t
Unique sequentially generated ID of a loaded and running scriptin session. Use ScriptEngine::getScrip...
Definition: ForwardDeclarations.h:40
ChatSystem.h
RoR::App::sim_terrain_name
CVar * sim_terrain_name
Definition: Application.cpp:97
RoR::Terrain::GetCollisions
Collisions * GetCollisions()
Definition: Terrain.h:83
GfxScene.h
PlatformUtils.h
Platform-specific utilities. We use narrow UTF-8 encoded strings as paths. Inspired by http://utf8eve...
RoR::MSG_NET_REFRESH_REPOLIST_FAILURE
@ MSG_NET_REFRESH_REPOLIST_FAILURE
Payload = RoR::CurlFailInfo* (owner)
Definition: Application.h:102
Character.h
RoR::MSG_GUI_OPEN_SELECTOR_REQUESTED
@ MSG_GUI_OPEN_SELECTOR_REQUESTED
Payload = LoaderType* (owner), Description = GUID | empty.
Definition: Application.h:123
RoR::LT_Vehicle
@ LT_Vehicle
Definition: Application.h:279
RoR::LT_Trailer
@ LT_Trailer
Definition: Application.h:284
RoR::MSG_SIM_HIDE_NET_ACTOR_REQUESTED
@ MSG_SIM_HIDE_NET_ACTOR_REQUESTED
Payload = ActorPtr* (owner)
Definition: Application.h:115
RoR::SoundScriptManager::createInstance
SoundScriptInstancePtr createInstance(Ogre::String templatename, int actor_id, int soundLinkType=SL_DEFAULT, int soundLinkItemId=-1)
Definition: SoundScriptManager.cpp:356
RoR::LoaderType
LoaderType
< Search mode for ModCache::Query() & Operation mode for GUI::MainSelector
Definition: Application.h:275
RoR::EngineSim::GetEngineRpm
float GetEngineRpm() const
Definition: EngineSim.h:102
RoR::MsgType
MsgType
Global gameplay message loop, see struct Message in GameContext.h.
Definition: Application.h:74
RoR::GUI::TopMenubar::ai_skin
std::string ai_skin
Definition: GUI_TopMenubar.h:79
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:269
RoR::MSG_NET_OPEN_RESOURCE_SUCCESS
@ MSG_NET_OPEN_RESOURCE_SUCCESS
Payload = GUI::ResourcesCollection* (owner)
Definition: Application.h:101
SoundScriptManager.h
RoR::MSG_APP_MODCACHE_LOAD_REQUESTED
@ MSG_APP_MODCACHE_LOAD_REQUESTED
Definition: Application.h:82
RoR::Message::payload
void * payload
Definition: GameContext.h:59
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:279
GameScript.h
RoR::Character::getPosition
Ogre::Vector3 getPosition()
Definition: Character.cpp:92
RoR::MSG_NET_REFRESH_REPOLIST_SUCCESS
@ MSG_NET_REFRESH_REPOLIST_SUCCESS
Payload = GUI::ResourcesCollection* (owner)
Definition: Application.h:100
RoRVersion.h
RoR::ActorSpawnRequest::asr_skin_entry
CacheEntryPtr asr_skin_entry
Definition: SimData.h:811
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
RoR::LoadScriptRequest
Definition: ScriptEngine.h:90
ROR_VERSION_STRING
const char *const ROR_VERSION_STRING
RoR::MSG_SIM_TELEPORT_PLAYER_REQUESTED
@ MSG_SIM_TELEPORT_PLAYER_REQUESTED
Payload = Ogre::Vector3* (owner)
Definition: Application.h:114
RoR::Message::description
std::string description
Definition: GameContext.h:58
RoR::RaceSystem::StartRaceTimer
void StartRaceTimer(int id)
Definition: RaceSystem.cpp:46
RoR::CurlTaskContext::ctc_url
std::string ctc_url
Definition: CurlHelpers.h:37
RoR::GUIManager::TopMenubar
GUI::TopMenubar TopMenubar
Definition: GUIManager.h:123
RoR::GUI::TopMenubar::ai_sectionconfig2
Ogre::String ai_sectionconfig2
Definition: GUI_TopMenubar.h:89
RoR::MSG_EDI_LOAD_BUNDLE_REQUESTED
@ MSG_EDI_LOAD_BUNDLE_REQUESTED
Payload = RoR::CacheEntryPtr* (owner)
Definition: Application.h:133
RoR::MSG_NET_CONNECT_SUCCESS
@ MSG_NET_CONNECT_SUCCESS
Definition: Application.h:92
RoR::CreateProjectRequest
Creates subdirectory in 'My Games\Rigs of Rods\projects', pre-populates it with files and adds modcac...
Definition: CacheSystem.h:211
RoR::ScriptUnit::scriptHash
Ogre::String scriptHash
Definition: ScriptEngine.h:84
RoR::App::GetCacheSystem
CacheSystem * GetCacheSystem()
Definition: Application.cpp:271
RoR::GETFUNC_DEFAULTEVENTCALLBACK_SIGFMT
const std::string GETFUNC_DEFAULTEVENTCALLBACK_SIGFMT
Definition: ScriptEngine.h:112
RoR::Sha1Hash
std::string Sha1Hash(std::string const &data)
Definition: Utils.cpp:138
RoR::CacheSystem::FetchSkinByName
CacheEntryPtr FetchSkinByName(std::string const &skin_name)
Definition: CacheSystem.cpp:1458
RoR::GUI::TopMenubar::ai_mode
int ai_mode
Definition: GUI_TopMenubar.h:82
RoR::CurlTaskContext::ctc_displayname
std::string ctc_displayname
Definition: CurlHelpers.h:36
instance
or anywhere else will not be considered a but parsed as regular data ! Each line is treated as values separated by separators Possible i e animators Multiline description Single instance
Definition: ReadMe.txt:53
RoR::GETFUNCFLAG_REQUIRED
const GetFuncFlags_t GETFUNCFLAG_REQUIRED
Always logs warning that function was not found.
Definition: ScriptEngine.h:108
RoR::Message
Unified game event system - all requests and state changes are reported using a message.
Definition: GameContext.h:51
RoR::MSG_GUI_OPEN_MENU_REQUESTED
@ MSG_GUI_OPEN_MENU_REQUESTED
Definition: Application.h:121
_L
#define _L
Definition: ErrorUtils.cpp:34
RoR::LT_None
@ LT_None
Definition: Application.h:277
RoR::GUIManager::ShowMessageBox
void ShowMessageBox(const char *title, const char *text, bool allow_close=true, const char *btn1_text="OK", const char *btn2_text=nullptr)
Definition: GUIManager.cpp:440
RoR::ActorManager::SetTrucksForcedAwake
void SetTrucksForcedAwake(bool forced)
Definition: ActorManager.h:79
RoR::MSG_SIM_SPAWN_ACTOR_REQUESTED
@ MSG_SIM_SPAWN_ACTOR_REQUESTED
Payload = RoR::ActorSpawnRequest* (owner)
Definition: Application.h:110
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:270
RoR::ActorPtr
RefCountingObjectPtr< Actor > ActorPtr
Definition: ForwardDeclarations.h:181
RoR::MSG_NET_CONNECT_FAILURE
@ MSG_NET_CONNECT_FAILURE
Definition: Application.h:93
RoR::MSG_SIM_DELETE_ACTOR_REQUESTED
@ MSG_SIM_DELETE_ACTOR_REQUESTED
Payload = RoR::ActorPtr* (owner)
Definition: Application.h:112
RoR::Terrain::getGravity
float getGravity() const
Definition: Terrain.h:96
RoR::LT_AllBeam
@ LT_AllBeam
Definition: Application.h:289
RoR::TerrainObjectManager::unloadObject
void unloadObject(const Ogre::String &instancename)
Definition: TerrainObjectManager.cpp:477
RoR::MSG_APP_SCRIPT_THREAD_STATUS
@ MSG_APP_SCRIPT_THREAD_STATUS
Payload = RoR::ScriptEventArgs* (owner)
Definition: Application.h:87
RoR::MSG_EDI_MODIFY_GROUNDMODEL_REQUESTED
@ MSG_EDI_MODIFY_GROUNDMODEL_REQUESTED
Payload = RoR::ground_model_t* (weak)
Definition: Application.h:130
Terrain.h
RoR::GameContext::ShowLoaderGUI
void ShowLoaderGUI(int type, const Ogre::String &instance, const Ogre::String &box)
Definition: GameContext.cpp:646
BitMask_t
uint32_t BitMask_t
Definition: BitFlags.h:7
Ogre
Definition: ExtinguishableFireAffector.cpp:35
ScriptUtils.h
RoR::CurlTaskContext
Definition: CurlHelpers.h:34
RoR::Actor::ar_design_name
Ogre::String ar_design_name
Name of the vehicle/machine/object this actor represents.
Definition: Actor.h:335
RoR::MSG_SIM_UNHIDE_NET_ACTOR_REQUESTED
@ MSG_SIM_UNHIDE_NET_ACTOR_REQUESTED
Payload = ActorPtr* (owner)
Definition: Application.h:116
RoR::ActorManager::RepairActor
void RepairActor(Collisions *collisions, const Ogre::String &inst, const Ogre::String &box, bool keepPosition=false)
Definition: ActorManager.cpp:867
RoR::MSG_APP_UNLOAD_SCRIPT_REQUESTED
@ MSG_APP_UNLOAD_SCRIPT_REQUESTED
Payload = RoR::ScriptUnitId_t* (owner)
Definition: Application.h:86
RoR::ActorSpawnRequest::asr_position
Ogre::Vector3 asr_position
Definition: SimData.h:808
RoR::IWater::SetStaticWaterHeight
virtual void SetStaticWaterHeight(float value)=0
RoR::Actor::ar_filehash
std::string ar_filehash
Attribute; filled at spawn.
Definition: Actor.h:415
RoR::GUI::TopMenubar::ai_sectionconfig
Ogre::String ai_sectionconfig
Definition: GUI_TopMenubar.h:78
RoR::ActorManager::WakeUpAllActors
void WakeUpAllActors()
Definition: ActorManager.cpp:824
RoR::MSG_NET_CONNECT_PROGRESS
@ MSG_NET_CONNECT_PROGRESS
Definition: Application.h:91
Collisions.h
RoR::ScriptUnit::scriptBuffer
Ogre::String scriptBuffer
Definition: ScriptEngine.h:85
RoR::ScriptUnit::scriptModule
AngelScript::asIScriptModule * scriptModule
Definition: ScriptEngine.h:77
RoR::GameContext::GetPlayerActor
const ActorPtr & GetPlayerActor()
Definition: GameContext.h:134
RoR::AI
@ AI
machine controlled by an Artificial Intelligence
Definition: SimData.h:108
RoR::ScriptEngine::getScriptUnit
ScriptUnit & getScriptUnit(ScriptUnitId_t unique_id)
Definition: ScriptEngine.cpp:1027
RoR::MSG_SIM_LOAD_SAVEGAME_REQUESTED
@ MSG_SIM_LOAD_SAVEGAME_REQUESTED
Definition: Application.h:108
RoR::Network::AddPacket
void AddPacket(int streamid, int type, int len, const char *content)
Definition: Network.cpp:606
RoR::ActorModifyRequest::amr_type
Type amr_type
Definition: SimData.h:844
RoR::ActorSpawnRequest::asr_rotation
Ogre::Quaternion asr_rotation
Definition: SimData.h:809
RoR::RaceSystem::SetRaceTimeDiff
void SetRaceTimeDiff(float diff)
Definition: RaceSystem.h:40
RoR
Definition: AppContext.h:36
Network.h
RoR::ActorManager::GetActorById
const ActorPtr & GetActorById(ActorInstanceID_t actor_id)
Definition: ActorManager.cpp:1167
x
float x
Definition: (ValueTypes) quaternion.h:5
RoR::CurlTaskContext::ctc_msg_success
MsgType ctc_msg_success
Definition: CurlHelpers.h:40
RoR::ActorSpawnRequest::asr_enter
bool asr_enter
Definition: SimData.h:821
Water.h
RoR::App::GetGfxScene
GfxScene * GetGfxScene()
Definition: Application.cpp:275
RoR::GameContext::GetActorManager
ActorManager * GetActorManager()
Definition: GameContext.h:127
RoR::ActorModifyRequest::Type
Type
Definition: SimData.h:832
RoR::GameContext::FindActorByCollisionBox
ActorPtr FindActorByCollisionBox(std::string const &ev_src_instance_name, std::string const &box_name)
Definition: GameContext.cpp:591
RoR::ScriptUnit::uniqueId
ScriptUnitId_t uniqueId
Definition: ScriptEngine.h:74
RoR::LT_Train
@ LT_Train
Definition: Application.h:285
RoR::ScriptEngine::deleteFunction
int deleteFunction(const Ogre::String &arg)
Deletes a global function from the script.
Definition: ScriptEngine.cpp:585
RoR::MSG_APP_SHUTDOWN_REQUESTED
@ MSG_APP_SHUTDOWN_REQUESTED
Definition: Application.h:78
RoR::ScriptEngine::addFunction
int addFunction(const Ogre::String &arg)
Adds a global function to the script.
Definition: ScriptEngine.cpp:501
RoR::GUI::TopMenubar::ai_distance
int ai_distance
Definition: GUI_TopMenubar.h:74
RoR::Terrain::getWater
IWater * getWater()
Definition: Terrain.h:84
RoR::TerrainGeometryManager::getTerrainGroup
Ogre::TerrainGroup * getTerrainGroup()
Definition: TerrainGeometryManager.h:46
RoR::Character::setRotation
void setRotation(Ogre::Radian rotation)
Definition: Character.cpp:98
RoR::GameContext::GetTerrain
const TerrainPtr & GetTerrain()
Definition: GameContext.h:117