RigsofRods  2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
RigDef_Parser.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-2021 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 "RigDef_Parser.h"
27 
28 #include "Actor.h"
29 #include "Application.h"
30 #include "DashBoardManager.h"
31 #include "SimConstants.h"
32 #include "CacheSystem.h"
33 #include "Console.h"
34 #include "RigDef_File.h"
35 #include "RigDef_Regexes.h"
36 #include "Utils.h"
37 
38 #include <OgreException.h>
39 #include <OgreString.h>
40 #include <OgreStringVector.h>
41 #include <OgreStringConverter.h>
42 
43 #include <algorithm>
44 
45 using namespace RoR;
46 
47 namespace RigDef
48 {
49 
50 inline bool IsWhitespace(char c)
51 {
52  return (c == ' ') || (c == '\t');
53 }
54 
55 inline bool IsSeparator(char c)
56 {
57  return IsWhitespace(c) || (c == ':') || (c == '|') || (c == ',');
58 }
59 
60 inline bool StrEqualsNocase(std::string const & s1, std::string const & s2)
61 {
62  if (s1.size() != s2.size()) { return false; }
63  for (size_t i = 0; i < s1.size(); ++i)
64  {
65  if (tolower(s1[i]) != tolower(s2[i])) { return false; }
66  }
67  return true;
68 }
69 
70 Parser::Parser()
71 {
72  // Push defaults
73  m_ror_default_inertia = std::shared_ptr<Inertia>(new Inertia);
74  m_ror_node_defaults = std::shared_ptr<NodeDefaults>(new NodeDefaults);
75 }
76 
77 void Parser::ProcessCurrentLine()
78 {
79  // First line in file (except blanks or comments) is the actor name
80  if (m_definition->name == "" && m_current_line != "")
81  {
82  m_definition->name = m_current_line; // Already trimmed
83  return;
84  }
85 
86  // Split line to tokens
87  if (m_current_block != Keyword::COMMENT &&
88  m_current_block != Keyword::DESCRIPTION)
89  {
90  this->TokenizeCurrentLine();
91  }
92 
93  // Detect keyword on current line
94  Keyword keyword = Keyword::INVALID;
95  // Quick check - keyword always starts with ASCII letter
96  char c = tolower(m_current_line[0]); // Note: line comes in trimmed
97  if (c >= 'a' && c <= 'z')
98  {
99  keyword = Parser::IdentifyKeyword(m_current_line);
100  }
101  m_log_keyword = keyword;
102  switch (keyword)
103  {
104  // No keyword - Continue below to process current block.
105  case Keyword::INVALID:
106  break; // << NOT RETURN.
107 
108  // Directives without arguments: just record, do not change current block.
109  case Keyword::DISABLEDEFAULTSOUNDS:
110  case Keyword::ENABLE_ADVANCED_DEFORMATION:
111  case Keyword::FORWARDCOMMANDS:
112  case Keyword::HIDEINCHOOSER:
113  case Keyword::IMPORTCOMMANDS:
114  case Keyword::LOCKGROUP_DEFAULT_NOLOCK:
115  case Keyword::RESCUER:
116  case Keyword::ROLLON:
117  case Keyword::SLIDENODE_CONNECT_INSTANTLY:
118  this->ProcessGlobalDirective(keyword);
119  return;
120  case Keyword::END_SECTION:
121  this->ProcessChangeModuleLine(keyword);
122  return;
123 
124  // Directives with arguments: process immediately, do not change current block.
125  case Keyword::ADD_ANIMATION:
126  this->ParseDirectiveAddAnimation();
127  return;
128  case Keyword::ANTILOCKBRAKES:
129  this->ParseAntiLockBrakes();
130  return;
131  case Keyword::AUTHOR:
132  this->ParseAuthor();
133  return;
134  case Keyword::BACKMESH:
135  this->ParseDirectiveBackmesh();
136  return;
137  case Keyword::CRUISECONTROL:
138  this->ParseCruiseControl();
139  return;
140  case Keyword::DEFAULT_SKIN:
141  this->ParseDirectiveDefaultSkin();
142  return;
143  case Keyword::DETACHER_GROUP:
144  this->ParseDirectiveDetacherGroup();
145  return;
146  case Keyword::EXTCAMERA:
147  this->ParseExtCamera();
148  return;
149  case Keyword::FILEFORMATVERSION:
150  this->ParseFileFormatVersion();
151  return;
152  case Keyword::FILEINFO:
153  this->ParseFileinfo();
154  return;
155  case Keyword::FLEXBODY_CAMERA_MODE:
156  this->ParseDirectiveFlexbodyCameraMode();
157  return;
158  case Keyword::FORSET:
159  this->ParseDirectiveForset();
160  return;
161  case Keyword::FORVERT:
162  this->ParseDirectiveForvert();
163  return;
164  case Keyword::GUID:
165  this->ParseGuid();
166  return;
167  case Keyword::PROP_CAMERA_MODE:
168  this->ParseDirectivePropCameraMode();
169  return;
170  case Keyword::SECTION:
171  this->ParseDirectiveSection();
172  return;
173  case Keyword::SET_BEAM_DEFAULTS:
174  this->ParseDirectiveSetBeamDefaults();
175  return;
176  case Keyword::SET_BEAM_DEFAULTS_SCALE:
177  this->ParseDirectiveSetBeamDefaultsScale();
178  return;
179  case Keyword::SET_COLLISION_RANGE:
180  this->ParseSetCollisionRange();
181  return;
182  case Keyword::SET_DEFAULT_MINIMASS:
183  this->ParseDirectiveSetDefaultMinimass();
184  return;
185  case Keyword::SET_INERTIA_DEFAULTS:
186  this->ParseDirectiveSetInertiaDefaults();
187  return;
188  case Keyword::SET_MANAGEDMATERIALS_OPTIONS:
189  this->ParseDirectiveSetManagedMaterialsOptions();
190  return;
191  case Keyword::SET_NODE_DEFAULTS:
192  this->ParseDirectiveSetNodeDefaults();
193  return;
194  case Keyword::SET_SKELETON_SETTINGS:
195  this->ParseSetSkeletonSettings();
196  return;
197  case Keyword::SPEEDLIMITER:
198  this->ParseSpeedLimiter();
199  return;
200  case Keyword::SUBMESH:
201  this->ParseDirectiveSubmesh();
202  return;
203  case Keyword::SUBMESH_GROUNDMODEL:
204  this->ParseSubmeshGroundModel();
205  return;
206  case Keyword::TRACTIONCONTROL:
207  this->ParseTractionControl();
208  return;
209 
210  // Keywords which end current block:
211  case Keyword::END_COMMENT:
212  case Keyword::END_DESCRIPTION:
213  case Keyword::END:
214  this->BeginBlock(Keyword::INVALID);
215  return;
216 
217  // Ignored keywords (obsolete):
218  case Keyword::ENVMAP:
219  case Keyword::HOOKGROUP:
220  case Keyword::NODECOLLISION:
221  case Keyword::RIGIDIFIERS:
222  return;
223 
224  // Keywords which start new block:
225  default:
226  this->BeginBlock(keyword);
227  return;
228  }
229 
230  // Block extent tracking - assumes single 'nodes[2]' and 'beams' block in file.
231  if ((keyword == Keyword::NODES || keyword == Keyword::NODES2) && m_current_module->_hint_nodes12_start_linenumber == -1)
232  {
233  m_current_module->_hint_nodes12_start_linenumber = (int)m_current_line_number;
234  }
235  else if (keyword == Keyword::BEAMS && m_current_module->_hint_beams_start_linenumber == -1)
236  {
237  m_current_module->_hint_beams_start_linenumber = (int)m_current_line_number;
238  }
239  else if (m_current_module->_hint_nodes12_end_linenumber == -1)
240  {
241  m_current_module->_hint_nodes12_start_linenumber = (int)m_current_line_number - 1;
242  }
243  else if (m_current_module->_hint_beams_end_linenumber == -1)
244  {
245  m_current_module->_hint_beams_start_linenumber = (int)m_current_line_number - 1;
246  }
247 
248  // Parse current block, if any
249  m_log_keyword = m_current_block;
250  switch (m_current_block)
251  {
252  case Keyword::AIRBRAKES: this->ParseAirbrakes(); return;
253  case Keyword::ANIMATORS: this->ParseAnimator(); return;
254  case Keyword::ASSETPACKS: this->ParseAssetpacks(); return;
255  case Keyword::AXLES: this->ParseAxles(); return;
256  case Keyword::BEAMS: this->ParseBeams(); return;
257  case Keyword::BRAKES: this->ParseBrakes(); return;
258  case Keyword::CAMERAS: this->ParseCameras(); return;
259  case Keyword::CAB: this->ParseCab(); return;
260  case Keyword::CAMERARAIL: this->ParseCameraRails(); return;
261  case Keyword::CINECAM: this->ParseCinecam(); return;
262  case Keyword::COMMANDS:
263  case Keyword::COMMANDS2: this->ParseCommandsUnified(); return;
264  case Keyword::COLLISIONBOXES: this->ParseCollisionBox(); return;
265  case Keyword::CONTACTERS: this->ParseContacter(); return;
266  case Keyword::CUSTOMDASHBOARDINPUTS:this->ParseCustomDashboardInputs(); return;
267  case Keyword::DESCRIPTION: this->ParseDescription(); return;
268  case Keyword::ENGINE: this->ParseEngine(); return;
269  case Keyword::ENGOPTION: this->ParseEngoption(); return;
270  case Keyword::ENGTURBO: this->ParseEngturbo(); return;
271  case Keyword::EXHAUSTS: this->ParseExhaust(); return;
272  case Keyword::FIXES: this->ParseFixes(); return;
273  case Keyword::FLARES:
274  case Keyword::FLARES2: this->ParseFlaresUnified(); return;
275  case Keyword::FLARES3: this->ParseFlares3(); return;
276  case Keyword::FLAREGROUPS_NO_IMPORT:this->ParseFlaregroupsNoImport(); return;
277  case Keyword::FLEXBODIES: this->ParseFlexbody(); return;
278  case Keyword::FLEXBODYWHEELS: this->ParseFlexBodyWheel(); return;
279  case Keyword::FUSEDRAG: this->ParseFusedrag(); return;
280  case Keyword::GLOBALS: this->ParseGlobals(); return;
281  case Keyword::GUISETTINGS: this->ParseGuiSettings(); return;
282  case Keyword::HELP: this->ParseHelp(); return;
283  case Keyword::HOOKS: this->ParseHook(); return;
284  case Keyword::HYDROS: this->ParseHydros(); return;
285  case Keyword::INTERAXLES: this->ParseInterAxles(); return;
286  case Keyword::LOCKGROUPS: this->ParseLockgroups(); return;
287  case Keyword::MANAGEDMATERIALS: this->ParseManagedMaterials(); return;
288  case Keyword::MATERIALFLAREBINDINGS:this->ParseMaterialFlareBindings(); return;
289  case Keyword::MESHWHEELS: this->ParseMeshWheel(); return;
290  case Keyword::MESHWHEELS2: this->ParseMeshWheel2(); return;
291  case Keyword::MINIMASS: this->ParseMinimass(); return;
292  case Keyword::NODES:
293  case Keyword::NODES2: this->ParseNodesUnified(); return;
294  case Keyword::PARTICLES: this->ParseParticles(); return;
295  case Keyword::PISTONPROPS: this->ParsePistonprops(); return;
296  case Keyword::PROPS: this->ParseProps(); return;
297  case Keyword::RAILGROUPS: this->ParseRailGroups(); return;
298  case Keyword::ROPABLES: this->ParseRopables(); return;
299  case Keyword::ROPES: this->ParseRopes(); return;
300  case Keyword::ROTATORS:
301  case Keyword::ROTATORS2: this->ParseRotatorsUnified(); return;
302  case Keyword::SCREWPROPS: this->ParseScrewprops(); return;
303  case Keyword::SCRIPTS: this->ParseScripts(); return;
304  case Keyword::SHOCKS: this->ParseShock(); return;
305  case Keyword::SHOCKS2: this->ParseShock2(); return;
306  case Keyword::SHOCKS3: this->ParseShock3(); return;
307  case Keyword::SLIDENODES: this->ParseSlidenodes(); return;
308  case Keyword::SOUNDSOURCES: this->ParseSoundsources(); return;
309  case Keyword::SOUNDSOURCES2: this->ParseSoundsources2(); return;
310  case Keyword::TEXCOORDS: this->ParseTexcoords(); return;
311  case Keyword::TIES: this->ParseTies(); return;
312  case Keyword::TORQUECURVE: this->ParseTorqueCurve(); return;
313  case Keyword::TRANSFERCASE: this->ParseTransferCase(); return;
314  case Keyword::TRIGGERS: this->ParseTriggers(); return;
315  case Keyword::TURBOJETS: this->ParseTurbojets(); return;
316  case Keyword::TURBOPROPS:
317  case Keyword::TURBOPROPS2: this->ParseTurbopropsUnified(); return;
318  case Keyword::VIDEOCAMERA: this->ParseVideoCamera(); return;
319  case Keyword::WHEELDETACHERS: this->ParseWheelDetachers(); return;
320  case Keyword::WHEELS: this->ParseWheel(); return;
321  case Keyword::WHEELS2: this->ParseWheel2(); return;
322  case Keyword::WINGS: this->ParseWing(); return;
323  default:;
324  };
325 }
326 
327 bool Parser::CheckNumArguments(int min_args)
328 {
329  if (min_args > m_num_args)
330  {
331  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
332  fmt::format("Not enough arguments (got {}, {} needed), skipping line", m_num_args, min_args));
333  return false;
334  }
335  return true;
336 }
337 
338 // --------------------------------------------------------------------------
339 // Parsing individual keywords
340 // --------------------------------------------------------------------------
341 
342 void Parser::ParseWing()
343 {
344  if (!this->CheckNumArguments(16)) { return; }
345 
346  Wing wing;
347 
348  for (int i = 0; i < 8; i++) { wing.nodes[i] = this->GetArgNodeRef (i); }
349  for (int i = 8; i < 16; i++) { wing.tex_coords[i-8] = this->GetArgFloat (i); }
350 
351  if (m_num_args > 16) { wing.control_surface = this->GetArgWingSurface (16); }
352  if (m_num_args > 17) { wing.chord_point = this->GetArgFloat (17); }
353  if (m_num_args > 18) { wing.min_deflection = this->GetArgFloat (18); }
354  if (m_num_args > 19) { wing.max_deflection = this->GetArgFloat (19); }
355  if (m_num_args > 20) { wing.airfoil = this->GetArgStr (20); }
356  if (m_num_args > 21) { wing.efficacy_coef = this->GetArgFloat (21); }
357 
358  m_current_module->wings.push_back(wing);
359  this->FlushPendingDocComment(m_current_module->wings.size(), RigDef::Keyword::WINGS);
360 }
361 
362 void Parser::ParseSetCollisionRange()
363 {
364  if (! this->CheckNumArguments(2)) { return; } // 2 items: keyword, arg
365 
366  CollisionRange cr;
367  cr.node_collision_range = this->GetArgFloat(1);
368 
369  m_current_module->set_collision_range.push_back(cr);
370  this->FlushPendingDocComment(m_current_module->set_collision_range.size(), RigDef::Keyword::SET_COLLISION_RANGE);
371 }
372 
373 void Parser::ParseWheel2()
374 {
375  if (!this->CheckNumArguments(17)) { return; }
376 
377  Wheel2 wheel_2;
378  wheel_2.node_defaults = m_user_node_defaults;
379  wheel_2.beam_defaults = m_user_beam_defaults;
380 
381  wheel_2.rim_radius = this->GetArgFloat ( 0);
382  wheel_2.tyre_radius = this->GetArgFloat ( 1);
383  wheel_2.width = this->GetArgFloat ( 2);
384  wheel_2.num_rays = this->GetArgInt ( 3);
385  wheel_2.nodes[0] = this->GetArgNodeRef ( 4);
386  wheel_2.nodes[1] = this->GetArgNodeRef ( 5);
387  wheel_2.rigidity_node = this->GetArgRigidityNode ( 6);
388  wheel_2.braking = this->GetArgBraking ( 7);
389  wheel_2.propulsion = this->GetArgPropulsion ( 8);
390  wheel_2.reference_arm_node = this->GetArgNodeRef ( 9);
391  wheel_2.mass = this->GetArgFloat (10);
392  wheel_2.rim_springiness = this->GetArgFloat (11);
393  wheel_2.rim_damping = this->GetArgFloat (12);
394  wheel_2.tyre_springiness = this->GetArgFloat (13);
395  wheel_2.tyre_damping = this->GetArgFloat (14);
396  wheel_2.face_material_name = this->GetArgStr (15);
397  wheel_2.band_material_name = this->GetArgStr (16);
398 
399  if (m_sequential_importer.IsEnabled())
400  {
401  m_sequential_importer.GenerateNodesForWheel(Keyword::WHEELS2, wheel_2.num_rays, wheel_2.rigidity_node.IsValidAnyState());
402  }
403 
404  m_current_module->wheels2.push_back(wheel_2);
405  this->FlushPendingDocComment(m_current_module->wheels2.size(), RigDef::Keyword::WHEELS2);
406 }
407 
408 void Parser::ParseWheel()
409 {
410  if (! this->CheckNumArguments(14)) { return; }
411 
412  Wheel wheel;
413  wheel.node_defaults = m_user_node_defaults;
414  wheel.beam_defaults = m_user_beam_defaults;
415 
416  wheel.radius = this->GetArgFloat ( 0);
417  wheel.width = this->GetArgFloat ( 1);
418  wheel.num_rays = this->GetArgInt ( 2);
419  wheel.nodes[0] = this->GetArgNodeRef ( 3);
420  wheel.nodes[1] = this->GetArgNodeRef ( 4);
421  wheel.rigidity_node = this->GetArgRigidityNode ( 5);
422  wheel.braking = this->GetArgBraking ( 6);
423  wheel.propulsion = this->GetArgPropulsion ( 7);
424  wheel.reference_arm_node = this->GetArgNodeRef ( 8);
425  wheel.mass = this->GetArgFloat ( 9);
426  wheel.springiness = this->GetArgFloat (10);
427  wheel.damping = this->GetArgFloat (11);
428  wheel.face_material_name = this->GetArgStr (12);
429  wheel.band_material_name = this->GetArgStr (13);
430 
431  if (m_sequential_importer.IsEnabled())
432  {
433  m_sequential_importer.GenerateNodesForWheel(Keyword::WHEELS, wheel.num_rays, wheel.rigidity_node.IsValidAnyState());
434  }
435 
436  m_current_module->wheels.push_back(wheel);
437  this->FlushPendingDocComment(m_current_module->wheels.size(), RigDef::Keyword::WHEELS);
438 }
439 
440 void Parser::ParseWheelDetachers()
441 {
442  if (! this->CheckNumArguments(2)) { return; }
443 
444  WheelDetacher wheeldetacher;
445 
446  wheeldetacher.wheel_id = this->GetArgInt(0);
447  wheeldetacher.detacher_group = this->GetArgInt(1);
448 
449  m_current_module->wheeldetachers.push_back(wheeldetacher);
450  this->FlushPendingDocComment(m_current_module->wheeldetachers.size(), RigDef::Keyword::WHEELDETACHERS);
451 }
452 
453 void Parser::ParseTractionControl()
454 {
455  Ogre::StringVector tokens = Ogre::StringUtil::split(m_current_line + 15, ","); // "TractionControl" = 15 characters
456  m_num_args = (int)tokens.size();
457  if (! this->CheckNumArguments(2)) { return; }
458 
459  TractionControl tc;
460  tc.regulation_force = this->ParseArgFloat(tokens[0].c_str());
461  tc.wheel_slip = this->ParseArgFloat(tokens[1].c_str());
462  if (tokens.size() > 2) { tc.fade_speed = this->ParseArgFloat(tokens[2].c_str()); }
463  if (tokens.size() > 3) { tc.pulse_per_sec = this->ParseArgFloat(tokens[3].c_str()); }
464 
465  for (unsigned int i=4; i<tokens.size(); i++)
466  {
467  Ogre::StringVector args2 = Ogre::StringUtil::split(tokens[i], ":");
468  Ogre::StringUtil::trim(args2[0]);
469  Ogre::StringUtil::toLowerCase(args2[0]);
470 
471  if (args2[0] == "mode" && args2.size() == 2)
472  {
473  Ogre::StringVector attrs = Ogre::StringUtil::split(args2[1], "&");
474  auto itor = attrs.begin();
475  auto endi = attrs.end();
476  for (; itor != endi; ++itor)
477  {
478  std::string attr = *itor;
479  Ogre::StringUtil::trim(attr);
480  Ogre::StringUtil::toLowerCase(attr);
481  if (strncmp(attr.c_str(), "nodash", 6) == 0) { tc.attr_no_dashboard = true; }
482  else if (strncmp(attr.c_str(), "notoggle", 8) == 0) { tc.attr_no_toggle = true; }
483  else if (strncmp(attr.c_str(), "on", 2) == 0) { tc.attr_is_on = true; }
484  else if (strncmp(attr.c_str(), "off", 3) == 0) { tc.attr_is_on = false; }
485  }
486  }
487  else
488  {
489  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "missing mode");
490  tc.attr_no_dashboard = false;
491  tc.attr_no_toggle = false;
492  tc.attr_is_on = true;
493  }
494  }
495 
496  m_current_module->tractioncontrol.push_back(tc);
497  this->FlushPendingDocComment(m_current_module->tractioncontrol.size(), RigDef::Keyword::TRACTIONCONTROL);
498 }
499 
500 void Parser::ParseTransferCase()
501 {
502  if (! this->CheckNumArguments(2)) { return; }
503 
504  TransferCase tc;
505 
506  tc.a1 = this->GetArgInt(0) - 1;
507  tc.a2 = this->GetArgInt(1) - 1;
508  if (m_num_args > 2) { tc.has_2wd = this->GetArgInt(2); }
509  if (m_num_args > 3) { tc.has_2wd_lo = this->GetArgInt(3); }
510  for (int i = 4; i < m_num_args; i++) { tc.gear_ratios.push_back(this->GetArgFloat(i)); }
511 
512  m_current_module->transfercase.push_back(tc);
513  this->FlushPendingDocComment(m_current_module->transfercase.size(), RigDef::Keyword::TRANSFERCASE);
514 }
515 
516 void Parser::ParseSubmeshGroundModel()
517 {
518  if (!this->CheckNumArguments(2)) { return; } // Items: keyword, arg
519 
520  m_current_module->submesh_groundmodel.push_back(this->GetArgStr(1));
521  this->FlushPendingDocComment(m_current_module->submesh_groundmodel.size(), RigDef::Keyword::SUBMESH_GROUNDMODEL);
522 }
523 
524 void Parser::ParseSpeedLimiter()
525 {
526  if (! this->CheckNumArguments(2)) { return; } // 2 items: keyword, arg
527 
528  SpeedLimiter sl;
529  sl.is_enabled = true;
530  sl.max_speed = this->GetArgFloat(1);
531 
532  m_current_module->speedlimiter.push_back(sl);
533  this->FlushPendingDocComment(m_current_module->speedlimiter.size(), RigDef::Keyword::SPEEDLIMITER);
534 }
535 
536 void Parser::ParseSetSkeletonSettings()
537 {
538  if (! this->CheckNumArguments(2)) { return; }
539 
540  if (m_current_module->set_skeleton_settings.size() == 0)
541  {
542  m_current_module->set_skeleton_settings.push_back(SkeletonSettings());
543  }
544 
545  SkeletonSettings& skel = m_current_module->set_skeleton_settings[0];
546  skel.visibility_range_meters = this->GetArgFloat(1);
547  if (m_num_args > 2) { skel.beam_thickness_meters = this->GetArgFloat(2); }
548 
549  // Defaults
550  if (skel.visibility_range_meters < 0.f) { skel.visibility_range_meters = 150.f; }
552 }
553 
554 void Parser::ParseDirectiveSetNodeDefaults()
555 {
556  if (!this->CheckNumArguments(2)) { return; }
557 
558  float load_weight = this->GetArgFloat(1);
559  float friction = (m_num_args > 2) ? this->GetArgFloat(2) : -1;
560  float volume = (m_num_args > 3) ? this->GetArgFloat(3) : -1;
561  float surface = (m_num_args > 4) ? this->GetArgFloat(4) : -1;
562 
563  m_user_node_defaults = std::shared_ptr<NodeDefaults>( new NodeDefaults(*m_user_node_defaults) );
564 
565  m_user_node_defaults->load_weight = (load_weight < 0) ? m_ror_node_defaults->load_weight : load_weight;
566  m_user_node_defaults->friction = (friction < 0) ? m_ror_node_defaults->friction : friction;
567  m_user_node_defaults->volume = (volume < 0) ? m_ror_node_defaults->volume : volume;
568  m_user_node_defaults->surface = (surface < 0) ? m_ror_node_defaults->surface : surface;
569 
570  if (m_num_args > 5) m_user_node_defaults->options = this->GetArgNodeOptions(5);
571 }
572 
573 void Parser::ParseDirectiveSetManagedMaterialsOptions()
574 {
575  if (! this->CheckNumArguments(2)) { return; } // 2 items: keyword, arg
576 
577  // Legacy behavior.
578  m_current_managed_material_options.double_sided = (this->GetArgChar(1) != '0');
579 }
580 
581 void Parser::ParseDirectiveSetBeamDefaultsScale()
582 {
583  if (! this->CheckNumArguments(5)) { return; }
584 
585  BeamDefaults* b = new BeamDefaults(*m_user_beam_defaults);
586  b->scale.springiness = this->GetArgFloat(1);
587 
588  if (m_num_args > 2) { b->scale.damping_constant = this->GetArgFloat(2); }
589  if (m_num_args > 3) { b->scale.deformation_threshold_constant = this->GetArgFloat(3); }
590  if (m_num_args > 4) { b->scale.breaking_threshold_constant = this->GetArgFloat(4); }
591 
592  m_user_beam_defaults = std::shared_ptr<BeamDefaults>(b);
593 }
594 
595 void Parser::ParseDirectiveSetBeamDefaults()
596 {
597  if (! this->CheckNumArguments(2)) { return; } // 2 items: keyword, arg
598 
599  BeamDefaults d(*m_user_beam_defaults);
600 
601  // What's the state of "enable_advanced_deformation" feature at this point?
602  // Directive "enable_advanced_deformation" alters the effects of BeamDefaults
603  // Since the old parser worked on-the-fly, only BeamDefaults defined after the directive were affected
604 
605  d._enable_advanced_deformation = m_definition->enable_advanced_deformation;
606 
607  d._is_user_defined = true; //The "_enable_advanced_deformation" must only be aplied to user-defined values, not defaults.
608  d.springiness = this->GetArgFloat(1);
609 
610  if (m_num_args > 2) { d.damping_constant = this->GetArgFloat(2); }
611  if (m_num_args > 3) { d.deformation_threshold = this->GetArgFloat(3); }
612  if (m_num_args > 4) { d.breaking_threshold = this->GetArgFloat(4); }
613  if (m_num_args > 5) { d.visual_beam_diameter = this->GetArgFloat(5); }
614  if (m_num_args > 6) { d.beam_material_name = this->GetArgStr (6); }
615  if (m_num_args > 7) { d.plastic_deform_coef = this->GetArgFloat(7); }
616 
617  if (m_num_args > 7 && d.plastic_deform_coef >= 0.0f) { d._is_plastic_deform_coef_user_defined = true; }
618 
619  if (d.springiness < 0.f) { d.springiness = DEFAULT_SPRING; }
620  if (d.damping_constant < 0.f) { d.damping_constant = DEFAULT_DAMP; }
622  if (d.breaking_threshold < 0.f) { d.breaking_threshold = BEAM_BREAK; }
625 
626  m_user_beam_defaults = std::shared_ptr<BeamDefaults>( new BeamDefaults(d) );
627  return;
628 }
629 
630 void Parser::ParseDirectivePropCameraMode()
631 {
632  if (! this->CheckNumArguments(2)) { return; } // 2 items: keyword, arg
633 
634  if (m_current_module->props.size() > 0)
635  {
636  m_current_module->props[m_current_module->props.size() - 1].camera_settings.mode = this->GetArgInt(1);
637  }
638  else
639  {
640  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "This line must come after a prop!");
641  }
642 }
643 
644 void Parser::ParseDirectiveSubmesh()
645 {
646  this->BeginBlock(Keyword::INVALID); // flush the current submesh
647  m_current_submesh = std::shared_ptr<Submesh>( new Submesh() );
648 }
649 
650 void Parser::ParseDirectiveBackmesh()
651 {
652  if (m_current_submesh)
653  {
654  m_current_submesh->backmesh = true;
655  }
656  else
657  {
658  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "must come after 'submesh'");
659  }
660 }
661 
662 void Parser::ProcessGlobalDirective(Keyword keyword) // Directives that should only appear in root module
663 {
664  switch (keyword)
665  {
666  case Keyword::DISABLEDEFAULTSOUNDS: m_definition->disable_default_sounds = true; return;
667  case Keyword::ENABLE_ADVANCED_DEFORMATION: m_definition->enable_advanced_deformation = true; return;
668  case Keyword::FORWARDCOMMANDS: m_definition->forward_commands = true; return;
669  case Keyword::IMPORTCOMMANDS: m_definition->import_commands = true; return;
670  case Keyword::HIDEINCHOOSER: m_definition->hide_in_chooser = true; return;
671  case Keyword::LOCKGROUP_DEFAULT_NOLOCK: m_definition->lockgroup_default_nolock = true; return;
672  case Keyword::RESCUER: m_definition->rescuer = true; return;
673  case Keyword::ROLLON: m_definition->rollon = true; return;
674  case Keyword::SLIDENODE_CONNECT_INSTANTLY: m_definition->slide_nodes_connect_instantly = true; return;
675 
676  default: return;
677  }
678 }
679 
680 void Parser::_ParseBaseMeshWheel(BaseMeshWheel& mesh_wheel)
681 {
682  mesh_wheel.node_defaults = m_user_node_defaults;
683  mesh_wheel.beam_defaults = m_user_beam_defaults;
684 
685  mesh_wheel.tyre_radius = this->GetArgFloat ( 0);
686  mesh_wheel.rim_radius = this->GetArgFloat ( 1);
687  mesh_wheel.width = this->GetArgFloat ( 2);
688  mesh_wheel.num_rays = this->GetArgInt ( 3);
689  mesh_wheel.nodes[0] = this->GetArgNodeRef ( 4);
690  mesh_wheel.nodes[1] = this->GetArgNodeRef ( 5);
691  mesh_wheel.rigidity_node = this->GetArgRigidityNode ( 6);
692  mesh_wheel.braking = this->GetArgBraking ( 7);
693  mesh_wheel.propulsion = this->GetArgPropulsion ( 8);
694  mesh_wheel.reference_arm_node = this->GetArgNodeRef ( 9);
695  mesh_wheel.mass = this->GetArgFloat (10);
696  mesh_wheel.spring = this->GetArgFloat (11);
697  mesh_wheel.damping = this->GetArgFloat (12);
698  mesh_wheel.side = this->GetArgWheelSide (13);
699  mesh_wheel.mesh_name = this->GetArgStr (14);
700  mesh_wheel.material_name = this->GetArgStr (15);
701 }
702 
703 void Parser::ParseMeshWheel()
704 {
705  if (! this->CheckNumArguments(16)) { return; }
706 
707  MeshWheel mesh_wheel;
708  this->_ParseBaseMeshWheel(mesh_wheel);
709 
710  if (m_sequential_importer.IsEnabled())
711  {
712  m_sequential_importer.GenerateNodesForWheel(Keyword::MESHWHEELS, mesh_wheel.num_rays, mesh_wheel.rigidity_node.IsValidAnyState());
713  }
714 
715  m_current_module->meshwheels.push_back(mesh_wheel);
716  this->FlushPendingDocComment(m_current_module->meshwheels.size(), RigDef::Keyword::MESHWHEELS);
717 }
718 
719 void Parser::ParseMeshWheel2()
720 {
721  if (! this->CheckNumArguments(16)) { return; }
722 
723  MeshWheel2 mesh_wheel;
724  this->_ParseBaseMeshWheel(mesh_wheel);
725 
726  if (m_sequential_importer.IsEnabled())
727  {
728  m_sequential_importer.GenerateNodesForWheel(Keyword::MESHWHEELS2, mesh_wheel.num_rays, mesh_wheel.rigidity_node.IsValidAnyState());
729  }
730 
731  m_current_module->meshwheels2.push_back(mesh_wheel);
732  this->FlushPendingDocComment(m_current_module->meshwheels2.size(), RigDef::Keyword::MESHWHEELS2);
733 }
734 
735 void Parser::ParseHook()
736 {
737  if (! this->CheckNumArguments(1)) { return; }
738 
739  Hook hook;
740  hook.node = this->GetArgNodeRef(0);
741 
742  int i = 1;
743  while (i < m_num_args)
744  {
745  std::string attr = this->GetArgStr(i);
746  Ogre::StringUtil::trim(attr);
747  const bool has_value = (i < (m_num_args - 1));
748 
749  // Values
750  if (has_value && (attr == "hookrange") ) { hook.option_hook_range = this->GetArgFloat(++i); }
751  else if (has_value && (attr == "speedcoef") ) { hook.option_speed_coef = this->GetArgFloat(++i); }
752  else if (has_value && (attr == "maxforce") ) { hook.option_max_force = this->GetArgFloat(++i); }
753  else if (has_value && (attr == "timer") ) { hook.option_timer = this->GetArgFloat(++i); }
754  else if (has_value && (attr == "hookgroup" || attr == "hgroup") ) { hook.option_hookgroup = this->GetArgInt (++i); }
755  else if (has_value && (attr == "lockgroup" || attr == "lgroup") ) { hook.option_lockgroup = this->GetArgInt (++i); }
756  else if (has_value && (attr == "shortlimit" || attr == "short_limit")) { hook.option_min_range_meters = this->GetArgFloat(++i); }
757  // Flags
758  else if ((attr == "selflock") ||(attr == "self-lock") ||(attr == "self_lock") ) { hook.flag_self_lock = true; }
759  else if ((attr == "autolock") ||(attr == "auto-lock") ||(attr == "auto_lock") ) { hook.flag_auto_lock = true; }
760  else if ((attr == "nodisable")||(attr == "no-disable")||(attr == "no_disable")) { hook.flag_no_disable = true; }
761  else if ((attr == "norope") ||(attr == "no-rope") ||(attr == "no_rope") ) { hook.flag_no_rope = true; }
762  else if ((attr == "visible") ||(attr == "vis") ) { hook.flag_visible = true; }
763  else
764  {
765  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, fmt::format("ignoring invalid option '{}'", attr));
766  }
767  i++;
768  }
769 
770  m_current_module->hooks.push_back(hook);
771  this->FlushPendingDocComment(m_current_module->hooks.size(), RigDef::Keyword::HOOKS);
772 }
773 
774 void Parser::ParseHelp()
775 {
776  Help h;
777  h.material = m_current_line; // already trimmed
778  m_current_module->help.push_back(h);
779 }
780 
781 void Parser::ParseGuiSettings()
782 {
783  if (! this->CheckNumArguments(2)) { return; }
784 
785  GuiSettings gs;
786  gs.key = this->GetArgStr(0);
787  gs.value = this->GetArgStr(1);
788 
789  m_current_module->guisettings.push_back(gs);
790  this->FlushPendingDocComment(m_current_module->guisettings.size(), RigDef::Keyword::GUISETTINGS);
791 }
792 
793 void Parser::ParseGuid()
794 {
795  if (! this->CheckNumArguments(2)) { return; }
796 
797  Guid g;
798  g.guid = this->GetArgStr(1);
799 
800  m_current_module->guid.push_back(g);
801  this->FlushPendingDocComment(m_current_module->guid.size(), RigDef::Keyword::GUID);
802 }
803 
804 void Parser::ParseGlobals()
805 {
806  if (! this->CheckNumArguments(2)) { return; }
807 
808  Globals globals;
809  globals.dry_mass = this->GetArgFloat(0);
810  globals.cargo_mass = this->GetArgFloat(1);
811 
812  if (m_num_args > 2) { globals.material_name = this->GetArgStr(2); }
813 
814  m_current_module->globals.push_back(globals);
815  this->FlushPendingDocComment(m_current_module->globals.size(), RigDef::Keyword::GLOBALS);
816 }
817 
818 void Parser::ParseFusedrag()
819 {
820  if (! this->CheckNumArguments(3)) { return; }
821 
822  Fusedrag fusedrag;
823  fusedrag.front_node = this->GetArgNodeRef(0);
824  fusedrag.rear_node = this->GetArgNodeRef(1);
825 
826  if (this->GetArgStr(2) == "autocalc")
827  {
828  fusedrag.autocalc = true;
829 
830  // Fusedrag autocalculation from truck size
831  if (m_num_args > 3) { fusedrag.area_coefficient = this->GetArgFloat(3); }
832  if (m_num_args > 4) { fusedrag.airfoil_name = this->GetArgStr (4); }
833  }
834  else
835  {
836  // Original calculation
837  fusedrag.approximate_width = this->GetArgFloat(2);
838 
839  if (m_num_args > 3) { fusedrag.airfoil_name = this->GetArgStr(3); }
840  }
841 
842  m_current_module->fusedrag.push_back(fusedrag);
843  this->FlushPendingDocComment(m_current_module->fusedrag.size(), RigDef::Keyword::FUSEDRAG);
844 }
845 
846 void Parser::ParseDirectiveFlexbodyCameraMode()
847 {
848  if (! this->CheckNumArguments(2)) { return; } // 2 items: keyword, arg
849 
850  if (m_current_module->flexbodies.size() > 0)
851  {
852  m_current_module->flexbodies[m_current_module->flexbodies.size() - 1].camera_settings.mode = this->GetArgInt(1);
853  }
854  else
855  {
856  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "This line must come after a flexbody!");
857  }
858 }
859 
860 void Parser::ParseCab()
861 {
862  if (! this->CheckNumArguments(3)) { return; }
863 
864  if (!m_current_submesh)
865  {
866  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "must come after 'submesh'");
867  return;
868  }
869 
870  Cab cab;
871  cab.nodes[0] = this->GetArgNodeRef(0);
872  cab.nodes[1] = this->GetArgNodeRef(1);
873  cab.nodes[2] = this->GetArgNodeRef(2);
874  if (m_num_args > 3) cab.options = this->GetArgCabOptions(3);
875 
876  m_current_submesh->cab_triangles.push_back(cab);
877  this->FlushPendingDocComment(m_current_submesh->cab_triangles.size(), RigDef::Keyword::CAB);
878 }
879 
880 void Parser::ParseTexcoords()
881 {
882  if (! this->CheckNumArguments(3)) { return; }
883 
884  if (!m_current_submesh)
885  {
886  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "must come after 'submesh'");
887  return;
888  }
889 
890  Texcoord texcoord;
891  texcoord.node = this->GetArgNodeRef(0);
892  texcoord.u = this->GetArgFloat (1);
893  texcoord.v = this->GetArgFloat (2);
894 
895  m_current_submesh->texcoords.push_back(texcoord);
896  this->FlushPendingDocComment(m_current_submesh->texcoords.size(), RigDef::Keyword::TEXCOORDS);
897 }
898 
899 void Parser::ParseFlexbody()
900 {
901  if (! this->CheckNumArguments(10)) { return; }
902 
903  Flexbody flexbody;
904  flexbody.reference_node = this->GetArgNodeRef (0);
905  flexbody.x_axis_node = this->GetArgNodeRef (1);
906  flexbody.y_axis_node = this->GetArgNodeRef (2);
907  flexbody.offset.x = this->GetArgFloat (3);
908  flexbody.offset.y = this->GetArgFloat (4);
909  flexbody.offset.z = this->GetArgFloat (5);
910  flexbody.rotation.x = this->GetArgFloat (6);
911  flexbody.rotation.y = this->GetArgFloat (7);
912  flexbody.rotation.z = this->GetArgFloat (8);
913  flexbody.mesh_name = this->GetArgStr (9);
914 
915  m_current_module->flexbodies.push_back(flexbody);
916  this->FlushPendingDocComment(m_current_module->flexbodies.size(), RigDef::Keyword::FLEXBODIES);
917 }
918 
919 void Parser::ParseDirectiveForset()
920 {
921  if (m_current_module->flexbodies.size() == 0)
922  {
923  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, "ignoring 'forset': no matching flexbody!");
924  return;
925  }
926 
927  Parser::ProcessForsetLine(m_current_module->flexbodies.back(), m_current_line, m_current_line_number);
928 }
929 
930 void Parser::ParseDirectiveForvert()
931 {
932  if (m_current_module->flexbodies.size() == 0)
933  {
934  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, "ignoring 'forvert': no matching flexbody!");
935  return;
936  }
937 
938  if (!this->CheckNumArguments(4)) { return; }
939 
940  Forvert forvert; // The temp object.
941  forvert.line_number = m_current_line_number;
942  forvert.node_ref = this->GetArgNodeRef(1);
943  forvert.node_x = this->GetArgNodeRef(2);
944  forvert.node_y = this->GetArgNodeRef(3);
945 
946  // Forver supports comma-separated vert ranges like "A-B, C, D-E"
947  // The code used with 'forset' is quirky, let's use a custom code.
948  const char* input_pos = std::strstr(m_current_line, "verts:");
949  if (!input_pos)
950  {
951  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, "ignoring 'forvert': missing 'verts:' portion.");
952  return;
953  }
954 
955  std::string input = input_pos;
956  std::regex pattern(R"((\d+)\s*-\s*(\d+)|(\d+))");
957  std::smatch matches;
958 
959  std::string::const_iterator searchStart(input.cbegin());
960  while (std::regex_search(searchStart, input.cend(), matches, pattern))
961  {
962  if (matches[1].matched && matches[2].matched)
963  {
964  // Range found - unroll it into the `Forvert` array.
965  int start = std::stoi(matches[1].str());
966  int end = std::stoi(matches[2].str());
967  for (int i = start; i <= end; ++i)
968  {
969  forvert.vert_index = i; // Update the temp object
970  m_current_module->flexbodies.back().forvert.push_back(forvert); // Copy the temp object
971  }
972  }
973  else if (matches[3].matched)
974  {
975  // Single number found
976  forvert.vert_index = std::stoi(matches[3].str()); // Update the temp object
977  m_current_module->flexbodies.back().forvert.push_back(forvert); // Copy the temp object
978  }
979  searchStart = matches.suffix().first;
980  }
981 }
982 
983 void Parser::ProcessForsetLine(RigDef::Flexbody& def, const std::string& _line, int line_number /*= -1*/)
984 {
985  // --------------------------------------------------------------------------------------------
986  // BEWARE OF QUIRKS in the following code (they must be preserved for backwards compatibility):
987  // - a space between the 'forset' keyword and arguments is optional.
988  // - garbage characters anywhere on the line will silently add node 0 to the set.
989  // - a separator at the end of line will silently add node 0 to the set.
990  // --------------------------------------------------------------------------------------------
991 
992  //parsing set definition
993  std::string line = _line;
994  char* pos = &line[0] + 6; // 'forset' = 6 characters
995  while (*pos == ' ' || *pos == ':' || *pos == ',') { pos++; } // Skip any separators
996  char* end = pos;
997  char endwas = 'G';
998  while (endwas != 0)
999  {
1000  int val1, val2; // Node numbers
1001  end = pos;
1002  while (*end != '-' && *end != ',' && *end != 0) end++;
1003  endwas = *end;
1004  *end = 0;
1005  val1 = strtoul(pos, 0, 10);
1006  if (endwas == '-')
1007  {
1008  pos = end + 1;
1009  end = pos;
1010  while (*end != ',' && *end != 0) end++;
1011  endwas = *end;
1012  *end = 0;
1013  val2 = strtoul(pos, 0, 10);
1014  // Add interval [val1-val2]
1015  def.node_list_to_import.push_back(
1016  Node::Range(
1017  Node::Ref(std::to_string(val1), val1, Node::Ref::IMPORT_STATE_IS_VALID, line_number),
1018  Node::Ref(std::to_string(val2), val2, Node::Ref::IMPORT_STATE_IS_VALID, line_number)));
1019  }
1020  else
1021  {
1022  // Add interval [val1-val1]
1023  Node::Range range_a = Node::Range(Node::Ref(std::to_string(val1), val1, Node::Ref::IMPORT_STATE_IS_VALID, line_number));
1024  def.node_list_to_import.push_back(range_a);
1025  }
1026  pos = end + 1;
1027  }
1028 }
1029 
1030 void Parser::ParseFlaresUnified()
1031 {
1032  const bool is_flares2 = (m_current_block == Keyword::FLARES2);
1033  if (! this->CheckNumArguments(is_flares2 ? 6 : 5)) { return; }
1034 
1035  Flare2 flare2;
1036  int pos = 0;
1037  flare2.reference_node = this->GetArgNodeRef(pos++);
1038  flare2.node_axis_x = this->GetArgNodeRef(pos++);
1039  flare2.node_axis_y = this->GetArgNodeRef(pos++);
1040  flare2.offset.x = this->GetArgFloat (pos++);
1041  flare2.offset.y = this->GetArgFloat (pos++);
1042 
1043  if (m_current_block == Keyword::FLARES2)
1044  {
1045  flare2.offset.z = this->GetArgFloat(pos++);
1046  }
1047 
1048  if (m_num_args > pos) { flare2.type = this->GetArgFlareType(pos++); }
1049 
1050  if (m_num_args > pos)
1051  {
1052  switch (flare2.type)
1053  {
1054  case FlareType::USER: flare2.control_number = this->GetArgInt(pos); break;
1055  case FlareType::DASHBOARD: flare2.dashboard_link = this->GetArgStr(pos); break;
1056  default: break;
1057  }
1058  pos++;
1059  }
1060 
1061  if (m_num_args > pos) { flare2.blink_delay_milis = this->GetArgInt (pos++); }
1062  if (m_num_args > pos) { flare2.size = this->GetArgFloat (pos++); }
1063  if (m_num_args > pos) { flare2.material_name = this->GetArgStr (pos++); }
1064 
1065  m_current_module->flares2.push_back(flare2);
1066  this->FlushPendingDocComment(m_current_module->flares2.size(), RigDef::Keyword::FLARES2);
1067 }
1068 
1069 void Parser::ParseFlares3()
1070 {
1071  const bool is_flares2 = (m_current_block == Keyword::FLARES2);
1072  if (! this->CheckNumArguments(is_flares2 ? 6 : 5)) { return; }
1073 
1074  Flare3 flare3;
1075  flare3.inertia_defaults = m_user_default_inertia;
1076 
1077  flare3.reference_node = this->GetArgNodeRef(0);
1078  flare3.node_axis_x = this->GetArgNodeRef(1);
1079  flare3.node_axis_y = this->GetArgNodeRef(2);
1080  flare3.offset.x = this->GetArgFloat(3);
1081  flare3.offset.y = this->GetArgFloat(4);
1082  flare3.offset.z = this->GetArgFloat(5);
1083  if (m_num_args > 6) { flare3.type = this->GetArgFlareType(6); }
1084 
1085  if (m_num_args > 7)
1086  {
1087  switch (flare3.type)
1088  {
1089  case FlareType::USER: flare3.control_number = this->GetArgInt(7); break;
1090  case FlareType::DASHBOARD: flare3.dashboard_link = this->GetArgStr(7); break;
1091  default: break;
1092  }
1093  }
1094 
1095  if (m_num_args > 8) { flare3.blink_delay_milis = this->GetArgInt (8); }
1096  if (m_num_args > 9) { flare3.size = this->GetArgFloat (9); }
1097  if (m_num_args > 10) { flare3.material_name = this->GetArgStr (10); }
1098 
1099  m_current_module->flares3.push_back(flare3);
1100  this->FlushPendingDocComment(m_current_module->flares3.size(), RigDef::Keyword::FLARES3);
1101 }
1102 
1103 void Parser::ParseFixes()
1104 {
1105  m_current_module->fixes.push_back(this->GetArgNodeRef(0));
1106 }
1107 
1108 void Parser::ParseExtCamera()
1109 {
1110  if (! this->CheckNumArguments(2)) { return; }
1111 
1112  ExtCamera extcam;
1113  extcam.mode = this->GetArgExtCameraMode(1);
1114  if (m_num_args > 2) { extcam.node = this->GetArgNodeRef(2); }
1115 
1116  m_current_module->extcamera.push_back(extcam);
1117  this->FlushPendingDocComment(m_current_module->extcamera.size(), RigDef::Keyword::EXTCAMERA);
1118 }
1119 
1120 void Parser::ParseExhaust()
1121 {
1122  if (! this->CheckNumArguments(2)) { return; }
1123 
1124  Exhaust exhaust;
1125  exhaust.reference_node = this->GetArgNodeRef(0);
1126  exhaust.direction_node = this->GetArgNodeRef(1);
1127 
1128  // Param [2] is unused
1129  if (m_num_args > 3) { exhaust.particle_name = this->GetArgStr(3); }
1130 
1131  m_current_module->exhausts.push_back(exhaust);
1132  this->FlushPendingDocComment(m_current_module->exhausts.size(), RigDef::Keyword::EXHAUSTS);
1133 }
1134 
1135 void Parser::ParseFileFormatVersion()
1136 {
1137  if (! this->CheckNumArguments(2)) { return; }
1138 
1139  FileFormatVersion ffv;
1140  ffv.version = this->GetArgInt(1);
1141 
1142  m_current_module->fileformatversion.push_back(ffv);
1143  m_current_block = Keyword::INVALID;
1144 }
1145 
1146 void Parser::ParseDirectiveDefaultSkin()
1147 {
1148  if (!this->CheckNumArguments(2)) { return; } // 2 items: keyword, param
1149 
1150  DefaultSkin data;
1151  data.skin_name = this->GetArgStr(1);
1152  std::replace(data.skin_name.begin(), data.skin_name.end(), '_', ' ');
1153 
1154  m_current_module->default_skin.push_back(data);
1155  this->FlushPendingDocComment(m_current_module->default_skin.size(), RigDef::Keyword::DEFAULT_SKIN);
1156 }
1157 
1158 void Parser::ParseDirectiveDetacherGroup()
1159 {
1160  if (! this->CheckNumArguments(2)) { return; } // 2 items: keyword, param
1161 
1162  if (this->GetArgStr(1) == "end")
1163  {
1164  m_current_detacher_group = 0;
1165  }
1166  else
1167  {
1168  m_current_detacher_group = this->GetArgInt(1);
1169  }
1170 }
1171 
1172 void Parser::ParseCruiseControl()
1173 {
1174  if (! this->CheckNumArguments(3)) { return; } // keyword + 2 params
1175 
1176  CruiseControl cruise_control;
1177  cruise_control.min_speed = this->GetArgFloat(1);
1178  cruise_control.autobrake = this->GetArgInt(2);
1179 
1180  m_current_module->cruisecontrol.push_back(cruise_control);
1181  this->FlushPendingDocComment(m_current_module->cruisecontrol.size(), RigDef::Keyword::CRUISECONTROL);
1182 }
1183 
1184 void Parser::ParseDescription()
1185 {
1186  m_current_module->description.push_back(m_current_line); // Already trimmed
1187 }
1188 
1189 void Parser::ParseDirectiveAddAnimation()
1190 {
1191  Ogre::StringVector tokens = Ogre::StringUtil::split(m_current_line + 14, ","); // "add_animation " = 14 characters
1192  m_num_args = (int)tokens.size();
1193  if (! this->CheckNumArguments(4)) { return; }
1194 
1195  if (m_current_module->props.size() == 0)
1196  {
1197  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, "'add_animation' must come after prop, ignoring...");
1198  return;
1199  }
1200 
1201  Animation animation;
1202  animation.ratio = this->ParseArgFloat(tokens[0].c_str());
1203  animation.lower_limit = this->ParseArgFloat(tokens[1].c_str());
1204  animation.upper_limit = this->ParseArgFloat(tokens[2].c_str());
1205 
1206  for (auto itor = tokens.begin() + 3; itor != tokens.end(); ++itor)
1207  {
1208  Ogre::StringVector entry = Ogre::StringUtil::split(*itor, ":");
1209  Ogre::StringUtil::trim(entry[0]);
1210  if (entry.size() > 1) Ogre::StringUtil::trim(entry[1]);
1211 
1212  const int WARN_LEN = 500;
1213  char warn_msg[WARN_LEN] = "";
1214 
1215  if (entry.size() == 1) // Single keyword
1216  {
1217  if (entry[0] == "autoanimate") { animation.mode |= Animation::MODE_AUTO_ANIMATE; }
1218  else if (entry[0] == "noflip") { animation.mode |= Animation::MODE_NO_FLIP; }
1219  else if (entry[0] == "bounce") { animation.mode |= Animation::MODE_BOUNCE; }
1220  else if (entry[0] == "eventlock") { animation.mode |= Animation::MODE_EVENT_LOCK; }
1221 
1222  else { snprintf(warn_msg, WARN_LEN, "Invalid keyword: %s", entry[0].c_str()); }
1223  }
1224  else if (entry.size() == 2 && (entry[0] == "mode" || entry[0] == "event" || entry[0] == "source" || entry[0] == "link"))
1225  {
1226  Ogre::StringVector values = Ogre::StringUtil::split(entry[1], "|");
1227  if (entry[0] == "mode")
1228  {
1229  for (auto itor = values.begin(); itor != values.end(); ++itor)
1230  {
1231  std::string value = *itor;
1232  Ogre::StringUtil::trim(value);
1233 
1234  if (value == "x-rotation") { animation.mode |= Animation::MODE_ROTATION_X; }
1235  else if (value == "y-rotation") { animation.mode |= Animation::MODE_ROTATION_Y; }
1236  else if (value == "z-rotation") { animation.mode |= Animation::MODE_ROTATION_Z; }
1237  else if (value == "x-offset" ) { animation.mode |= Animation::MODE_OFFSET_X; }
1238  else if (value == "y-offset" ) { animation.mode |= Animation::MODE_OFFSET_Y; }
1239  else if (value == "z-offset" ) { animation.mode |= Animation::MODE_OFFSET_Z; }
1240 
1241  else { snprintf(warn_msg, WARN_LEN, "Invalid 'mode': %s, ignoring...", entry[1].c_str()); }
1242  }
1243  }
1244  else if (entry[0] == "event")
1245  {
1246  animation.event_name = entry[1];
1247  Ogre::StringUtil::trim(animation.event_name);
1248  Ogre::StringUtil::toUpperCase(animation.event_name);
1249  }
1250  else if (entry[0] == "link")
1251  {
1252  animation.dash_link_name = entry[1];
1253  Ogre::StringUtil::trim(animation.dash_link_name);
1254  }
1255  else if (entry[0] == "source")
1256  {
1257  for (auto itor = values.begin(); itor != values.end(); ++itor)
1258  {
1259  std::string value = *itor;
1260  Ogre::StringUtil::trim(value);
1261 
1262  if (value == "airspeed") { animation.source |= Animation::SOURCE_AIRSPEED; }
1263  else if (value == "vvi") { animation.source |= Animation::SOURCE_VERTICAL_VELOCITY; }
1264  else if (value == "altimeter100k") { animation.source |= Animation::SOURCE_ALTIMETER_100K; }
1265  else if (value == "altimeter10k") { animation.source |= Animation::SOURCE_ALTIMETER_10K; }
1266  else if (value == "altimeter1k") { animation.source |= Animation::SOURCE_ALTIMETER_1K; }
1267  else if (value == "aoa") { animation.source |= Animation::SOURCE_ANGLE_OF_ATTACK; }
1268  else if (value == "flap") { animation.source |= Animation::SOURCE_FLAP; }
1269  else if (value == "airbrake") { animation.source |= Animation::SOURCE_AIR_BRAKE; }
1270  else if (value == "roll") { animation.source |= Animation::SOURCE_ROLL; }
1271  else if (value == "pitch") { animation.source |= Animation::SOURCE_PITCH; }
1272  else if (value == "brakes") { animation.source |= Animation::SOURCE_BRAKES; }
1273  else if (value == "accel") { animation.source |= Animation::SOURCE_ACCEL; }
1274  else if (value == "clutch") { animation.source |= Animation::SOURCE_CLUTCH; }
1275  else if (value == "speedo") { animation.source |= Animation::SOURCE_SPEEDO; }
1276  else if (value == "tacho") { animation.source |= Animation::SOURCE_TACHO; }
1277  else if (value == "turbo") { animation.source |= Animation::SOURCE_TURBO; }
1278  else if (value == "parking") { animation.source |= Animation::SOURCE_PARKING; }
1279  else if (value == "shifterman1") { animation.source |= Animation::SOURCE_SHIFT_LEFT_RIGHT; }
1280  else if (value == "shifterman2") { animation.source |= Animation::SOURCE_SHIFT_BACK_FORTH; }
1281  else if (value == "sequential") { animation.source |= Animation::SOURCE_SEQUENTIAL_SHIFT; }
1282  else if (value == "shifterlin") { animation.source |= Animation::SOURCE_SHIFTERLIN; }
1283  else if (value == "autoshifterlin"){ animation.source |= Animation::SOURCE_AUTOSHIFTERLIN; }
1284  else if (value == "torque") { animation.source |= Animation::SOURCE_TORQUE; }
1285  else if (value == "heading") { animation.source |= Animation::SOURCE_HEADING; }
1286  else if (value == "difflock") { animation.source |= Animation::SOURCE_DIFFLOCK; }
1287  else if (value == "rudderboat") { animation.source |= Animation::SOURCE_BOAT_RUDDER; }
1288  else if (value == "throttleboat") { animation.source |= Animation::SOURCE_BOAT_THROTTLE; }
1289  else if (value == "steeringwheel") { animation.source |= Animation::SOURCE_STEERING_WHEEL; }
1290  else if (value == "aileron") { animation.source |= Animation::SOURCE_AILERON; }
1291  else if (value == "elevator") { animation.source |= Animation::SOURCE_ELEVATOR; }
1292  else if (value == "rudderair") { animation.source |= Animation::SOURCE_AIR_RUDDER; }
1293  else if (value == "permanent") { animation.source |= Animation::SOURCE_PERMANENT; }
1294  else if (value == "event") { animation.source |= Animation::SOURCE_EVENT; }
1295  else if (value == "dashboard") { animation.source |= Animation::SOURCE_DASHBOARD; }
1296  else if (value == "signalstalk") { animation.source |= Animation::SOURCE_SIGNALSTALK; }
1297  else if (value == "gearreverse") { animation.source |= Animation::SOURCE_GEAR_REVERSE; }
1298  else if (value == "gearneutral") { animation.source |= Animation::SOURCE_GEAR_NEUTRAL; }
1299 
1300  else
1301  {
1302  Animation::MotorSource motor_source;
1303  // aeroengines...
1304  if (entry[1].compare(0, 8, "throttle") == 0)
1305  {
1306  motor_source.source = Animation::MotorSource::SOURCE_AERO_THROTTLE;
1307  motor_source.motor = this->ParseArgUint(entry[1].substr(8));
1308  }
1309  else if (entry[1].compare(0, 3, "rpm") == 0)
1310  {
1311  motor_source.source = Animation::MotorSource::SOURCE_AERO_RPM;
1312  motor_source.motor = this->ParseArgUint(entry[1].substr(3));
1313  }
1314  else if (entry[1].compare(0, 8, "aerotorq") == 0)
1315  {
1316  motor_source.source = Animation::MotorSource::SOURCE_AERO_TORQUE;
1317  motor_source.motor = this->ParseArgUint(entry[1].substr(8));
1318  }
1319  else if (entry[1].compare(0, 7, "aeropit") == 0)
1320  {
1321  motor_source.source = Animation::MotorSource::SOURCE_AERO_PITCH;
1322  motor_source.motor = this->ParseArgUint(entry[1].substr(7));
1323  }
1324  else if (entry[1].compare(0, 10, "aerostatus") == 0)
1325  {
1326  motor_source.source = Animation::MotorSource::SOURCE_AERO_STATUS;
1327  motor_source.motor = this->ParseArgUint(entry[1].substr(10));
1328  }
1329  // gears... (hack)
1330  else if (entry[1].compare(0, 4, "gear") == 0)
1331  {
1332  motor_source.source = Animation::MotorSource::SOURCE_GEAR_FORWARD;
1333  motor_source.motor = this->ParseArgUint(entry[1].substr(4));
1334  }
1335  else
1336  {
1337  snprintf(warn_msg, WARN_LEN, "Invalid 'source': %s, ignoring...", entry[1].c_str());
1338  continue;
1339  }
1340  animation.motor_sources.push_back(motor_source);
1341  }
1342  }
1343  }
1344  else
1345  {
1346  snprintf(warn_msg, WARN_LEN, "Invalid keyword: %s, ignoring...", entry[0].c_str());
1347  }
1348  }
1349  else
1350  {
1351  snprintf(warn_msg, WARN_LEN, "Invalid item: %s, ignoring...", entry[0].c_str());
1352  }
1353 
1354  if (warn_msg[0] != '\0')
1355  {
1356  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
1357  fmt::format("Ignoring invalid token '{}' ({})", itor->c_str(), warn_msg));
1358  }
1359  }
1360 
1361  m_current_module->props.back().animations.push_back(animation);
1362 }
1363 
1364 void Parser::ParseAntiLockBrakes()
1365 {
1366  AntiLockBrakes alb;
1367  Ogre::StringVector tokens = Ogre::StringUtil::split(m_current_line + 15, ","); // "AntiLockBrakes " = 15 characters
1368  m_num_args = (int)tokens.size();
1369  if (! this->CheckNumArguments(2)) { return; }
1370 
1371  alb.regulation_force = this->ParseArgFloat(tokens[0].c_str());
1372  alb.min_speed = this->ParseArgInt (tokens[1].c_str());
1373 
1374  if (tokens.size() > 3) { alb.pulse_per_sec = this->ParseArgFloat(tokens[2].c_str()); }
1375 
1376  for (unsigned int i=3; i<tokens.size(); i++)
1377  {
1378  Ogre::StringVector args2 = Ogre::StringUtil::split(tokens[i], ":");
1379  Ogre::StringUtil::trim(args2[0]);
1380  Ogre::StringUtil::toLowerCase(args2[0]);
1381  if (args2[0] == "mode" && args2.size() == 2)
1382  {
1383  Ogre::StringVector attrs = Ogre::StringUtil::split(args2[1], "&");
1384  auto itor = attrs.begin();
1385  auto endi = attrs.end();
1386  for (; itor != endi; ++itor)
1387  {
1388  std::string attr = *itor;
1389  Ogre::StringUtil::trim(attr);
1390  Ogre::StringUtil::toLowerCase(attr);
1391  if (strncmp(attr.c_str(), "nodash", 6) == 0) { alb.attr_no_dashboard = true; }
1392  else if (strncmp(attr.c_str(), "notoggle", 8) == 0) { alb.attr_no_toggle = true; }
1393  else if (strncmp(attr.c_str(), "on", 2) == 0) { alb.attr_is_on = true; }
1394  else if (strncmp(attr.c_str(), "off", 3) == 0) { alb.attr_is_on = false; }
1395  }
1396  }
1397  else
1398  {
1399  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "missing mode");
1400  alb.attr_no_dashboard = false;
1401  alb.attr_no_toggle = false;
1402  alb.attr_is_on = true;
1403  }
1404  }
1405 
1406  m_current_module->antilockbrakes.push_back(alb);
1407  this->FlushPendingDocComment(m_current_module->antilockbrakes.size(), RigDef::Keyword::ANTILOCKBRAKES);
1408 }
1409 
1410 void Parser::ParseEngoption()
1411 {
1412  if (! this->CheckNumArguments(1)) { return; }
1413 
1414  Engoption engoption;
1415  engoption.inertia = this->GetArgFloat(0);
1416 
1417  if (m_num_args > 1) { engoption.type = this->GetArgEngineType(1); }
1418  if (m_num_args > 2) { engoption.clutch_force = this->GetArgFloat(2); }
1419  if (m_num_args > 3) { engoption.shift_time = this->GetArgFloat(3); }
1420  if (m_num_args > 4) { engoption.clutch_time = this->GetArgFloat(4); }
1421  if (m_num_args > 5) { engoption.post_shift_time = this->GetArgFloat(5); }
1422  if (m_num_args > 6) { engoption.stall_rpm = this->GetArgFloat(6); }
1423  if (m_num_args > 7) { engoption.idle_rpm = this->GetArgFloat(7); }
1424  if (m_num_args > 8) { engoption.max_idle_mixture = this->GetArgFloat(8); }
1425  if (m_num_args > 9) { engoption.min_idle_mixture = this->GetArgFloat(9); }
1426  if (m_num_args > 10){ engoption.braking_torque = this->GetArgFloat(10);}
1427 
1428  m_current_module->engoption.push_back(engoption);
1429  this->FlushPendingDocComment(m_current_module->engoption.size(), RigDef::Keyword::ENGOPTION);
1430 }
1431 
1432 void Parser::ParseEngturbo()
1433 {
1434  if (! this->CheckNumArguments(4)) { return; }
1435 
1436  Engturbo engturbo;
1437  engturbo.version = this->GetArgInt ( 0);
1438  engturbo.tinertiaFactor = this->GetArgFloat( 1);
1439  engturbo.nturbos = this->GetArgInt ( 2);
1440  engturbo.param1 = this->GetArgFloat( 3);
1441 
1442  if (m_num_args > 4) { engturbo.param2 = this->GetArgFloat( 4); }
1443  if (m_num_args > 5) { engturbo.param3 = this->GetArgFloat( 5); }
1444  if (m_num_args > 6) { engturbo.param4 = this->GetArgFloat( 6); }
1445  if (m_num_args > 7) { engturbo.param5 = this->GetArgFloat( 7); }
1446  if (m_num_args > 8) { engturbo.param6 = this->GetArgFloat( 8); }
1447  if (m_num_args > 9) { engturbo.param7 = this->GetArgFloat( 9); }
1448  if (m_num_args > 10) { engturbo.param8 = this->GetArgFloat(10); }
1449  if (m_num_args > 11) { engturbo.param9 = this->GetArgFloat(11); }
1450  if (m_num_args > 12) { engturbo.param10 = this->GetArgFloat(12); }
1451  if (m_num_args > 13) { engturbo.param11 = this->GetArgFloat(13); }
1452 
1453  if (engturbo.nturbos > 4)
1454  {
1455  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, "You cannot have more than 4 turbos. Fallback: using 4 instead.");
1456  engturbo.nturbos = 4;
1457  }
1458 
1459  m_current_module->engturbo.push_back(engturbo);
1460  this->FlushPendingDocComment(m_current_module->engturbo.size(), RigDef::Keyword::ENGTURBO);
1461 }
1462 
1463 void Parser::ParseEngine()
1464 {
1465  if (! this->CheckNumArguments(6)) { return; }
1466 
1467  Engine engine;
1468  engine.shift_down_rpm = this->GetArgFloat(0);
1469  engine.shift_up_rpm = this->GetArgFloat(1);
1470  engine.torque = this->GetArgFloat(2);
1471  engine.global_gear_ratio = this->GetArgFloat(3);
1472  engine.reverse_gear_ratio = this->GetArgFloat(4);
1473  engine.neutral_gear_ratio = this->GetArgFloat(5);
1474 
1475  // Forward gears
1476  for (int i = 6; i < m_num_args; i++)
1477  {
1478  float ratio = this->GetArgFloat(i);
1479  if (ratio < 0.f)
1480  {
1481  break; // Optional terminator argument
1482  }
1483  engine.gear_ratios.push_back(ratio);
1484  }
1485 
1486  if (engine.gear_ratios.size() == 0)
1487  {
1488  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "no forward gear");
1489  return;
1490  }
1491 
1492  m_current_module->engine.push_back(engine);
1493  this->FlushPendingDocComment(m_current_module->engine.size(), RigDef::Keyword::ENGINE);
1494 }
1495 
1496 void Parser::ParseContacter()
1497 {
1498  if (! this->CheckNumArguments(1)) { return; }
1499 
1500  m_current_module->contacters.push_back(this->GetArgNodeRef(0));
1501  this->FlushPendingDocComment(m_current_module->contacters.size(), RigDef::Keyword::CONTACTERS);
1502 }
1503 
1504 void Parser::ParseCustomDashboardInputs()
1505 {
1506  if (!this->CheckNumArguments(2)) { return; }
1507 
1508  CustomDashboardInput dashVal;
1509  dashVal.name = this->GetArgStr(0);
1510  dashVal.data_type = this->GetArgDashboardInputDataType(1);
1511  if (dashVal.data_type == -1)
1512  {
1513  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR,
1514  fmt::format("Dashboard value \"{}\" has an invalid data type. Ignoring it.", dashVal.name));
1515  return;
1516  }
1517 
1518  m_current_module->customdashboardinputs.push_back(dashVal);
1519  this->FlushPendingDocComment(m_current_module->customdashboardinputs.size(), RigDef::Keyword::CUSTOMDASHBOARDINPUTS);
1520 }
1521 
1522 void Parser::ParseCommandsUnified()
1523 {
1524  const bool is_commands2 = (m_current_block == Keyword::COMMANDS2);
1525  const int max_args = (is_commands2 ? 8 : 7);
1526  if (! this->CheckNumArguments(max_args)) { return; }
1527 
1528  Command2 command2;
1529  command2.beam_defaults = m_user_beam_defaults;
1530  command2.detacher_group = m_current_detacher_group;
1531  command2.inertia_defaults = m_user_default_inertia;
1532 
1533  int pos = 0;
1534  command2.nodes[0] = this->GetArgNodeRef(pos++);
1535  command2.nodes[1] = this->GetArgNodeRef(pos++);
1536  command2.shorten_rate = this->GetArgFloat (pos++);
1537 
1538  if (is_commands2)
1539  {
1540  command2.lengthen_rate = this->GetArgFloat(pos++);
1541  }
1542  else
1543  {
1544  command2.lengthen_rate = command2.shorten_rate;
1545  }
1546 
1547  command2.max_contraction = this->GetArgFloat(pos++);
1548  command2.max_extension = this->GetArgFloat(pos++);
1549  command2.contract_key = this->GetArgInt (pos++);
1550  command2.extend_key = this->GetArgInt (pos++);
1551 
1552  if (m_num_args <= max_args) // No more args?
1553  {
1554  m_current_module->commands2.push_back(command2);
1555  return;
1556  }
1557 
1558  // Parse options
1559  std::string options_str = this->GetArgStr(pos++);
1560  char winner = 0;
1561  for (auto itor = options_str.begin(); itor != options_str.end(); ++itor)
1562  {
1563  const char c = *itor;
1564  if ((winner == 0) && (c == 'o' || c == 'p' || c == 'c')) { winner = c; }
1565 
1566  if (c == 'n') {} // Filler, does nothing
1567  else if (c == 'i') { command2.option_i_invisible = true; }
1568  else if (c == 'r') { command2.option_r_rope = true; }
1569  else if (c == 'f') { command2.option_f_not_faster = true; }
1570  else if (c == 'c') { command2.option_c_auto_center = true; }
1571  else if (c == 'p') { command2.option_p_1press = true; }
1572  else if (c == 'o') { command2.option_o_1press_center = true; }
1573  else
1574  {
1575  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
1576  fmt::format("ignoring unknown flag '{}'", c));
1577  }
1578  }
1579 
1580  // Resolve option conflicts
1581  if (command2.option_c_auto_center && winner != 'c' && winner != 0)
1582  {
1583  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, "Command cannot be one-pressed and self centering at the same time, ignoring flag 'c'");
1584  command2.option_c_auto_center = false;
1585  }
1586  char ignored = '\0';
1587  if (command2.option_o_1press_center && winner != 'o' && winner != 0)
1588  {
1589  command2.option_o_1press_center = false;
1590  ignored = 'o';
1591  }
1592  else if (command2.option_p_1press && winner != 'p' && winner != 0)
1593  {
1594  command2.option_p_1press = false;
1595  ignored = 'p';
1596  }
1597 
1598  // Report conflicts
1599  if (ignored != 0 && winner == 'c')
1600  {
1601  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
1602  "Command cannot be one-pressed and self centering at the same time, ignoring flag '%c'");
1603  }
1604  else if (ignored != 0 && (winner == 'o' || winner == 'p'))
1605  {
1606  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
1607  "Command already has a one-pressed c.mode, ignoring flag '%c'");
1608  }
1609 
1610  if (m_num_args > pos) { command2.description = this->GetArgStr (pos++);}
1611 
1612  if (m_num_args > pos) { ParseOptionalInertia(command2.inertia, pos); pos += 4; }
1613 
1614  if (m_num_args > pos) { command2.affect_engine = this->GetArgFloat(pos++);}
1615  if (m_num_args > pos) { command2.needs_engine = this->GetArgBool (pos++);}
1616  if (m_num_args > pos) { command2.plays_sound = this->GetArgBool (pos++);}
1617 
1618  m_current_module->commands2.push_back(command2);
1619  this->FlushPendingDocComment(m_current_module->commands2.size(), RigDef::Keyword::COMMANDS2);
1620 }
1621 
1622 void Parser::ParseCollisionBox()
1623 {
1624  CollisionBox collisionbox;
1625 
1626  Ogre::StringVector tokens = Ogre::StringUtil::split(m_current_line, ",");
1627  Ogre::StringVector::iterator iter = tokens.begin();
1628  for ( ; iter != tokens.end(); iter++)
1629  {
1630  collisionbox.nodes.push_back( this->_ParseNodeRef(*iter) );
1631  }
1632 
1633  m_current_module->collisionboxes.push_back(collisionbox);
1634  this->FlushPendingDocComment(m_current_module->collisionboxes.size(), RigDef::Keyword::COLLISIONBOXES);
1635 }
1636 
1637 void Parser::ParseCinecam()
1638 {
1639  if (! this->CheckNumArguments(11)) { return; }
1640 
1641  Cinecam cinecam;
1642  cinecam.beam_defaults = m_user_beam_defaults;
1643  cinecam.node_defaults = m_user_node_defaults;
1644 
1645  // Required arguments
1646  cinecam.position.x = this->GetArgFloat ( 0);
1647  cinecam.position.y = this->GetArgFloat ( 1);
1648  cinecam.position.z = this->GetArgFloat ( 2);
1649  cinecam.nodes[0] = this->GetArgNodeRef( 3);
1650  cinecam.nodes[1] = this->GetArgNodeRef( 4);
1651  cinecam.nodes[2] = this->GetArgNodeRef( 5);
1652  cinecam.nodes[3] = this->GetArgNodeRef( 6);
1653  cinecam.nodes[4] = this->GetArgNodeRef( 7);
1654  cinecam.nodes[5] = this->GetArgNodeRef( 8);
1655  cinecam.nodes[6] = this->GetArgNodeRef( 9);
1656  cinecam.nodes[7] = this->GetArgNodeRef(10);
1657 
1658  // Optional arguments
1659  if (m_num_args > 11) { cinecam.spring = this->GetArgFloat(11); }
1660  if (m_num_args > 12) { cinecam.damping = this->GetArgFloat(12); }
1661 
1662  if (m_num_args > 13)
1663  {
1664  float value = this->GetArgFloat(13);
1665  if (value > 0.f) // Invalid input (for example illegal trailing ";pseudo-comment") parses as 0
1666  cinecam.node_mass = value;
1667  }
1668 
1669  if (m_sequential_importer.IsEnabled())
1670  {
1671  m_sequential_importer.AddGeneratedNode(Keyword::CINECAM);
1672  }
1673 
1674  m_current_module->cinecam.push_back(cinecam);
1675  this->FlushPendingDocComment(m_current_module->cinecam.size(), RigDef::Keyword::CINECAM);
1676 }
1677 
1678 void Parser::ParseCameraRails()
1679 {
1680  m_current_camera_rail->nodes.push_back( this->GetArgNodeRef(0) );
1681 }
1682 
1683 void Parser::ParseBrakes()
1684 {
1685  if (!this->CheckNumArguments(1)) { return; }
1686 
1687  Brakes brakes;
1688  brakes.default_braking_force = this->GetArgFloat(0);
1689  if (m_num_args > 1)
1690  {
1691  brakes.parking_brake_force = this->GetArgFloat(1);
1692  }
1693  m_current_module->brakes.push_back(brakes);
1694  this->FlushPendingDocComment(m_current_module->brakes.size(), RigDef::Keyword::BRAKES);
1695 }
1696 
1697 void Parser::ParseAxles()
1698 {
1699  Axle axle;
1700 
1701  Ogre::StringVector tokens = Ogre::StringUtil::split(m_current_line, ",");
1702  Ogre::StringVector::iterator iter = tokens.begin();
1703  for ( ; iter != tokens.end(); iter++)
1704  {
1705  std::smatch results;
1706  if (! std::regex_search(*iter, results, Regexes::SECTION_AXLES_PROPERTY))
1707  {
1708  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "Invalid property, ignoring whole line...");
1709  return;
1710  }
1711  // NOTE: Positions in 'results' array match E_CAPTURE*() positions (starting with 1) in the respective regex.
1712 
1713  if (results[1].matched)
1714  {
1715  unsigned int wheel_index = PARSEINT(results[2]) - 1;
1716  axle.wheels[wheel_index][0] = _ParseNodeRef(results[3]);
1717  axle.wheels[wheel_index][1] = _ParseNodeRef(results[4]);
1718  }
1719  else if (results[5].matched)
1720  {
1721  this->_ParseDifferentialTypes(axle.options, results[6].str());
1722  }
1723  }
1724 
1725  m_current_module->axles.push_back(axle);
1726  this->FlushPendingDocComment(m_current_module->axles.size(), RigDef::Keyword::AXLES);
1727 }
1728 
1729 void Parser::ParseInterAxles()
1730 {
1731  auto args = Ogre::StringUtil::split(m_current_line, ",");
1732  if (args.size() < 2) { return; }
1733 
1734  InterAxle interaxle;
1735 
1736  interaxle.a1 = this->ParseArgInt(args[0].c_str()) - 1;
1737  interaxle.a2 = this->ParseArgInt(args[1].c_str()) - 1;
1738 
1739  std::smatch results;
1740  if (! std::regex_search(args[2], results, Regexes::SECTION_AXLES_PROPERTY))
1741  {
1742  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "Invalid property, ignoring whole line...");
1743  return;
1744  }
1745  // NOTE: Positions in 'results' array match E_CAPTURE*() positions (starting with 1) in the respective regex.
1746 
1747  if (results[5].matched)
1748  {
1749  this->_ParseDifferentialTypes(interaxle.options, results[6].str());
1750  }
1751 
1752  m_current_module->interaxles.push_back(interaxle);
1753  this->FlushPendingDocComment(m_current_module->interaxles.size(), RigDef::Keyword::INTERAXLES);
1754 }
1755 
1756 void Parser::ParseAirbrakes()
1757 {
1758  if (! this->CheckNumArguments(14)) { return; }
1759 
1760  Airbrake airbrake;
1761  airbrake.reference_node = this->GetArgNodeRef( 0);
1762  airbrake.x_axis_node = this->GetArgNodeRef( 1);
1763  airbrake.y_axis_node = this->GetArgNodeRef( 2);
1764  airbrake.aditional_node = this->GetArgNodeRef( 3);
1765  airbrake.offset.x = this->GetArgFloat ( 4);
1766  airbrake.offset.y = this->GetArgFloat ( 5);
1767  airbrake.offset.z = this->GetArgFloat ( 6);
1768  airbrake.width = this->GetArgFloat ( 7);
1769  airbrake.height = this->GetArgFloat ( 8);
1770  airbrake.max_inclination_angle = this->GetArgFloat ( 9);
1771  airbrake.texcoord_x1 = this->GetArgFloat (10);
1772  airbrake.texcoord_y1 = this->GetArgFloat (11);
1773  airbrake.texcoord_x2 = this->GetArgFloat (12);
1774  airbrake.texcoord_y2 = this->GetArgFloat (13);
1775 
1776  m_current_module->airbrakes.push_back(airbrake);
1777  this->FlushPendingDocComment(m_current_module->airbrakes.size(), Keyword::AIRBRAKES);
1778 }
1779 
1780 void Parser::ParseAssetpacks()
1781 {
1782  if (! this->CheckNumArguments(1)) { return; }
1783 
1784  Assetpack assetpack;
1785 
1786  assetpack.filename = this->GetArgStr(0);
1787 
1788  m_current_module->assetpacks.push_back(assetpack);
1789  this->FlushPendingDocComment(m_current_module->assetpacks.size(), Keyword::ASSETPACKS);
1790 }
1791 
1792 void Parser::ParseVideoCamera()
1793 {
1794  if (! this->CheckNumArguments(19)) { return; }
1795 
1796  VideoCamera videocamera;
1797 
1798  videocamera.reference_node = this->GetArgNodeRef ( 0);
1799  videocamera.left_node = this->GetArgNodeRef ( 1);
1800  videocamera.bottom_node = this->GetArgNodeRef ( 2);
1801  videocamera.alt_reference_node = this->GetArgNullableNode( 3);
1802  videocamera.alt_orientation_node = this->GetArgNullableNode( 4);
1803  videocamera.offset.x = this->GetArgFloat ( 5);
1804  videocamera.offset.y = this->GetArgFloat ( 6);
1805  videocamera.offset.z = this->GetArgFloat ( 7);
1806  videocamera.rotation.x = this->GetArgFloat ( 8);
1807  videocamera.rotation.y = this->GetArgFloat ( 9);
1808  videocamera.rotation.z = this->GetArgFloat (10);
1809  videocamera.field_of_view = this->GetArgFloat (11);
1810  videocamera.texture_width = this->GetArgInt (12);
1811  videocamera.texture_height = this->GetArgInt (13);
1812  videocamera.min_clip_distance = this->GetArgFloat (14);
1813  videocamera.max_clip_distance = this->GetArgFloat (15);
1814  videocamera.camera_role = this->GetArgVideoCamRole(16);
1815  videocamera.camera_mode = this->GetArgInt (17);
1816  videocamera.material_name = this->GetArgStr (18);
1817 
1818  if (m_num_args > 19) { videocamera.camera_name = this->GetArgStr(19); }
1819 
1820  m_current_module->videocameras.push_back(videocamera);
1821  this->FlushPendingDocComment(m_current_module->videocameras.size(), Keyword::VIDEOCAMERA);
1822 }
1823 
1824 void Parser::ParseCameras()
1825 {
1826  if (! this->CheckNumArguments(3)) { return; }
1827 
1828  Camera camera;
1829  camera.center_node = this->GetArgNodeRef(0);
1830  camera.back_node = this->GetArgNodeRef(1);
1831  camera.left_node = this->GetArgNodeRef(2);
1832 
1833  m_current_module->cameras.push_back(camera);
1834  this->FlushPendingDocComment(m_current_module->cameras.size(), Keyword::CAMERAS);
1835 }
1836 
1837 void Parser::ParseTurbopropsUnified()
1838 {
1839  bool is_turboprop_2 = m_current_block == Keyword::TURBOPROPS2;
1840 
1841  if (! this->CheckNumArguments(is_turboprop_2 ? 9 : 8)) { return; }
1842 
1843  Turboprop2 turboprop;
1844 
1845  turboprop.reference_node = this->GetArgNodeRef(0);
1846  turboprop.axis_node = this->GetArgNodeRef(1);
1847  turboprop.blade_tip_nodes[0] = this->GetArgNodeRef(2);
1848  turboprop.blade_tip_nodes[1] = this->GetArgNodeRef(3);
1849  turboprop.blade_tip_nodes[2] = this->GetArgNullableNode(4);
1850  turboprop.blade_tip_nodes[3] = this->GetArgNullableNode(5);
1851 
1852  int offset = 0;
1853 
1854  if (is_turboprop_2)
1855  {
1856  turboprop.couple_node = this->GetArgNullableNode(6);
1857 
1858  offset = 1;
1859  }
1860 
1861  turboprop.turbine_power_kW = this->GetArgFloat (6 + offset);
1862  turboprop.airfoil = this->GetArgStr (7 + offset);
1863 
1864  m_current_module->turboprops2.push_back(turboprop);
1865  this->FlushPendingDocComment(m_current_module->turboprops2.size(), Keyword::TURBOPROPS2);
1866 }
1867 
1868 void Parser::ParseTurbojets()
1869 {
1870  if (! this->CheckNumArguments(9)) { return; }
1871 
1872  Turbojet turbojet;
1873  turbojet.front_node = this->GetArgNodeRef(0);
1874  turbojet.back_node = this->GetArgNodeRef(1);
1875  turbojet.side_node = this->GetArgNodeRef(2);
1876  turbojet.is_reversable = this->GetArgInt (3);
1877  turbojet.dry_thrust = this->GetArgFloat (4);
1878  turbojet.wet_thrust = this->GetArgFloat (5);
1879  turbojet.front_diameter = this->GetArgFloat (6);
1880  turbojet.back_diameter = this->GetArgFloat (7);
1881  turbojet.nozzle_length = this->GetArgFloat (8);
1882 
1883  m_current_module->turbojets.push_back(turbojet);
1884  this->FlushPendingDocComment(m_current_module->turbojets.size(), Keyword::TURBOJETS);
1885 }
1886 
1887 void Parser::ParseTriggers()
1888 {
1889  if (! this->CheckNumArguments(6)) { return; }
1890 
1891  Trigger trigger;
1892  trigger.beam_defaults = m_user_beam_defaults;
1893  trigger.detacher_group = m_current_detacher_group;
1894  trigger.nodes[0] = this->GetArgNodeRef(0);
1895  trigger.nodes[1] = this->GetArgNodeRef(1);
1896  trigger.contraction_trigger_limit = this->GetArgFloat (2);
1897  trigger.expansion_trigger_limit = this->GetArgFloat (3);
1898  trigger.shortbound_trigger_action = this->GetArgInt (4);
1899  trigger.longbound_trigger_action = this->GetArgInt (5);
1900  if (m_num_args > 6) trigger.options = this->GetArgTriggerOptions(6);
1901  if (m_num_args > 7) trigger.boundary_timer = this->GetArgFloat(7);
1902 
1903  m_current_module->triggers.push_back(trigger);
1904  this->FlushPendingDocComment(m_current_module->triggers.size(), Keyword::TRIGGERS);
1905 }
1906 
1907 void Parser::ParseTorqueCurve()
1908 {
1909  if (m_current_module->torquecurve.size() == 0)
1910  {
1911  m_current_module->torquecurve.push_back(TorqueCurve());
1912  }
1913 
1914  Ogre::StringVector args = Ogre::StringUtil::split(m_current_line, ",");
1915 
1916  if (args.size() == 1u)
1917  {
1918  m_current_module->torquecurve[0].predefined_func_name = args[0];
1919  }
1920  else if (args.size() == 2u)
1921  {
1922  TorqueCurve::Sample sample;
1923  sample.power = this->ParseArgFloat(args[0].c_str());
1924  sample.torque_percent = this->ParseArgFloat(args[1].c_str());
1925  m_current_module->torquecurve[0].samples.push_back(sample);
1926  }
1927  else
1928  {
1929  // Consistent with 0.38's parser.
1930  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "too many arguments, skipping");
1931  }
1932 }
1933 
1934 void Parser::ParseTies()
1935 {
1936  if (! this->CheckNumArguments(5)) { return; }
1937 
1938  Tie tie;
1939  tie.beam_defaults = m_user_beam_defaults;
1940  tie.detacher_group = m_current_detacher_group;
1941 
1942  tie.root_node = this->GetArgNodeRef(0);
1943  tie.max_reach_length = this->GetArgFloat (1);
1944  tie.auto_shorten_rate = this->GetArgFloat (2);
1945  tie.min_length = this->GetArgFloat (3);
1946  tie.max_length = this->GetArgFloat (4);
1947 
1948  if (m_num_args > 5)
1949  {
1950  for (char c: this->GetArgStr(5))
1951  {
1952  switch (c)
1953  {
1954  case (char)TieOption::n_DUMMY:
1955  case (char)TieOption::v_DUMMY:
1956  break;
1957 
1958  case (char)TieOption::i_INVISIBLE:
1959  tie.options |= Tie::OPTION_i_INVISIBLE;
1960  break;
1961 
1962  case (char)TieOption::s_NO_SELF_LOCK:
1963  tie.options |= Tie::OPTION_s_DISABLE_SELF_LOCK;
1964  break;
1965 
1966  default:
1967  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
1968  fmt::format("ignoring invalid option '{}'", c));
1969  break;
1970  }
1971  }
1972  }
1973 
1974  if (m_num_args > 6) { tie.max_stress = this->GetArgFloat (6); }
1975  if (m_num_args > 7) { tie.group = this->GetArgInt (7); }
1976 
1977  m_current_module->ties.push_back(tie);
1978  this->FlushPendingDocComment(m_current_module->ties.size(), Keyword::TIES);
1979 }
1980 
1981 void Parser::ParseSoundsources()
1982 {
1983  if (! this->CheckNumArguments(2)) { return; }
1984 
1985  SoundSource soundsource;
1986  soundsource.node = this->GetArgNodeRef(0);
1987  soundsource.sound_script_name = this->GetArgStr(1);
1988 
1989  m_current_module->soundsources.push_back(soundsource);
1990  this->FlushPendingDocComment(m_current_module->soundsources.size(), Keyword::SOUNDSOURCES);
1991 }
1992 
1993 void Parser::ParseSoundsources2()
1994 {
1995  if (! this->CheckNumArguments(3)) { return; }
1996 
1997  SoundSource2 soundsource2;
1998  soundsource2.node = this->GetArgNodeRef(0);
1999  soundsource2.mode = this->GetArgInt(1);
2000  soundsource2.sound_script_name = this->GetArgStr(2);
2001 
2002  if (soundsource2.mode < -2)
2003  {
2004  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR,
2005  fmt::format("invalid mode {}, falling back to default -2", soundsource2.mode));
2006  soundsource2.mode = -2;
2007  }
2008 
2009  m_current_module->soundsources2.push_back(soundsource2);
2010  this->FlushPendingDocComment(m_current_module->soundsources2.size(), Keyword::SOUNDSOURCES2);
2011 }
2012 
2013 void Parser::ParseSlidenodes()
2014 {
2015  Ogre::StringVector args = Ogre::StringUtil::split(m_current_line, ", ");
2016  m_num_args = (int)args.size();
2017  if (! this->CheckNumArguments(2)) { return; }
2018 
2019  SlideNode slidenode;
2020  slidenode.slide_node = this->_ParseNodeRef(args[0]);
2021 
2022  bool in_rail_node_list = true;
2023 
2024  for (auto itor = args.begin() + 1; itor != args.end(); ++itor)
2025  {
2026  char c = toupper(itor->at(0));
2027  switch (c)
2028  {
2029  case 'S':
2030  slidenode.spring_rate = this->ParseArgFloat(itor->substr(1));
2031  slidenode._spring_rate_set = true;
2032  in_rail_node_list = false;
2033  break;
2034  case 'B':
2035  slidenode.break_force = this->ParseArgFloat(itor->substr(1));
2036  slidenode._break_force_set = true;
2037  in_rail_node_list = false;
2038  break;
2039  case 'T':
2040  slidenode.tolerance = this->ParseArgFloat(itor->substr(1));
2041  slidenode._tolerance_set = true;
2042  in_rail_node_list = false;
2043  break;
2044  case 'R':
2045  slidenode.attachment_rate = this->ParseArgFloat(itor->substr(1));
2046  slidenode._attachment_rate_set = true;
2047  in_rail_node_list = false;
2048  break;
2049  case 'G':
2050  slidenode.railgroup_id = this->ParseArgFloat(itor->substr(1));
2051  slidenode._railgroup_id_set = true;
2052  in_rail_node_list = false;
2053  break;
2054  case 'D':
2055  slidenode.max_attach_dist = this->ParseArgFloat(itor->substr(1));
2056  slidenode._max_attach_dist_set = true;
2057  in_rail_node_list = false;
2058  break;
2059  case 'C':
2060  switch (itor->at(1))
2061  {
2062  case 'a':
2063  BITMASK_SET_1(slidenode.constraint_flags, SlideNode::CONSTRAINT_ATTACH_ALL);
2064  break;
2065  case 'f':
2066  BITMASK_SET_1(slidenode.constraint_flags, SlideNode::CONSTRAINT_ATTACH_FOREIGN);
2067  break;
2068  case 's':
2069  BITMASK_SET_1(slidenode.constraint_flags, SlideNode::CONSTRAINT_ATTACH_SELF);
2070  break;
2071  case 'n':
2072  BITMASK_SET_1(slidenode.constraint_flags, SlideNode::CONSTRAINT_ATTACH_NONE);
2073  break;
2074  default:
2075  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
2076  fmt::format("Ignoring invalid option '{}'", itor->at(1)));
2077  break;
2078  }
2079  in_rail_node_list = false;
2080  break;
2081  default:
2082  if (in_rail_node_list)
2083  slidenode.rail_node_ranges.push_back( _ParseNodeRef(*itor));
2084  break;
2085  }
2086  }
2087 
2088  m_current_module->slidenodes.push_back(slidenode);
2089  this->FlushPendingDocComment(m_current_module->slidenodes.size(), Keyword::SLIDENODES);
2090 }
2091 
2092 void Parser::ParseShock3()
2093 {
2094  if (! this->CheckNumArguments(15)) { return; }
2095 
2096  Shock3 shock_3;
2097  shock_3.beam_defaults = m_user_beam_defaults;
2098  shock_3.detacher_group = m_current_detacher_group;
2099 
2100  shock_3.nodes[0] = this->GetArgNodeRef( 0);
2101  shock_3.nodes[1] = this->GetArgNodeRef( 1);
2102  shock_3.spring_in = this->GetArgFloat ( 2);
2103  shock_3.damp_in = this->GetArgFloat ( 3);
2104  shock_3.damp_in_slow = this->GetArgFloat ( 4);
2105  shock_3.split_vel_in = this->GetArgFloat ( 5);
2106  shock_3.damp_in_fast = this->GetArgFloat ( 6);
2107  shock_3.spring_out = this->GetArgFloat ( 7);
2108  shock_3.damp_out = this->GetArgFloat ( 8);
2109  shock_3.damp_out_slow = this->GetArgFloat ( 9);
2110  shock_3.split_vel_out = this->GetArgFloat (10);
2111  shock_3.damp_out_fast = this->GetArgFloat (11);
2112  shock_3.short_bound = this->GetArgFloat (12);
2113  shock_3.long_bound = this->GetArgFloat (13);
2114  shock_3.precompression = this->GetArgFloat (14);
2115 
2116  if (m_num_args > 15) shock_3.options = this->GetArgShock3Options(15);
2117 
2118  m_current_module->shocks3.push_back(shock_3);
2119  this->FlushPendingDocComment(m_current_module->shocks3.size(), Keyword::SHOCKS3);
2120 }
2121 
2122 void Parser::ParseShock2()
2123 {
2124  if (! this->CheckNumArguments(13)) { return; }
2125 
2126  Shock2 shock_2;
2127  shock_2.beam_defaults = m_user_beam_defaults;
2128  shock_2.detacher_group = m_current_detacher_group;
2129 
2130  shock_2.nodes[0] = this->GetArgNodeRef( 0);
2131  shock_2.nodes[1] = this->GetArgNodeRef( 1);
2132  shock_2.spring_in = this->GetArgFloat ( 2);
2133  shock_2.damp_in = this->GetArgFloat ( 3);
2134  shock_2.progress_factor_spring_in = this->GetArgFloat ( 4);
2135  shock_2.progress_factor_damp_in = this->GetArgFloat ( 5);
2136  shock_2.spring_out = this->GetArgFloat ( 6);
2137  shock_2.damp_out = this->GetArgFloat ( 7);
2138  shock_2.progress_factor_spring_out = this->GetArgFloat ( 8);
2139  shock_2.progress_factor_damp_out = this->GetArgFloat ( 9);
2140  shock_2.short_bound = this->GetArgFloat (10);
2141  shock_2.long_bound = this->GetArgFloat (11);
2142  shock_2.precompression = this->GetArgFloat (12);
2143 
2144  if (m_num_args > 13) shock_2.options = this->GetArgShock2Options(13);
2145 
2146  m_current_module->shocks2.push_back(shock_2);
2147  this->FlushPendingDocComment(m_current_module->shocks2.size(), Keyword::SHOCKS2);
2148 }
2149 
2150 void Parser::ParseShock()
2151 {
2152  if (! this->CheckNumArguments(7)) { return; }
2153 
2154  Shock shock;
2155  shock.beam_defaults = m_user_beam_defaults;
2156  shock.detacher_group = m_current_detacher_group;
2157 
2158  shock.nodes[0] = this->GetArgNodeRef(0);
2159  shock.nodes[1] = this->GetArgNodeRef(1);
2160  shock.spring_rate = this->GetArgFloat (2);
2161  shock.damping = this->GetArgFloat (3);
2162  shock.short_bound = this->GetArgFloat (4);
2163  shock.long_bound = this->GetArgFloat (5);
2164  shock.precompression = this->GetArgFloat (6);
2165  if (m_num_args > 7) shock.options = this->GetArgShockOptions(7);
2166 
2167  m_current_module->shocks.push_back(shock);
2168  this->FlushPendingDocComment(m_current_module->shocks.size(), Keyword::SHOCKS);
2169 }
2170 
2171 Node::Ref Parser::_ParseNodeRef(std::string const & node_id_str)
2172 {
2173  if (m_sequential_importer.IsEnabled())
2174  {
2175  // Import of legacy fileformatversion
2176  int node_id_num = PARSEINT(node_id_str);
2177  if (node_id_num < 0)
2178  {
2179  node_id_num *= -1;
2180  }
2181  // Since fileformatversion is not known from the beginning of parsing, 2 states must be kept
2182  // at the same time: IMPORT_STATE and REGULAR_STATE. The outer logic must make the right pick.
2183  unsigned int flags = Node::Ref::IMPORT_STATE_IS_VALID | // Import state
2184  Node::Ref::REGULAR_STATE_IS_VALID | Node::Ref::REGULAR_STATE_IS_NAMED; // Regular state (fileformatversion >= 450)
2185  if (m_any_named_node_defined)
2186  {
2187  flags |= Node::Ref::IMPORT_STATE_MUST_CHECK_NAMED_FIRST;
2188  }
2189  return Node::Ref(node_id_str, node_id_num, flags, m_current_line_number);
2190  }
2191  else
2192  {
2193  // fileformatversion >= 450, use named-only nodes
2194  return Node::Ref(node_id_str, 0, Node::Ref::REGULAR_STATE_IS_VALID | Node::Ref::REGULAR_STATE_IS_NAMED, m_current_line_number);
2195  }
2196 }
2197 
2198 void Parser::ParseDirectiveSetDefaultMinimass()
2199 {
2200  if (! this->CheckNumArguments(2)) { return; } // Directive name + parameter
2201 
2202  m_set_default_minimass = std::shared_ptr<DefaultMinimass>(new DefaultMinimass());
2203  m_set_default_minimass->min_mass_Kg = this->GetArgFloat(1);
2204 }
2205 
2206 void Parser::ParseFlaregroupsNoImport()
2207 {
2208  // ;flare_groups_no_import
2209  // ; <flaretype> <controlnumber 1-10>
2210  if (!this->CheckNumArguments(1)) { return; }
2211 
2212  FlaregroupNoImport fni;
2213  fni.type = this->GetArgFlareType(0);
2214  if (m_num_args > 1)
2215  {
2216  fni.control_number = this->GetArgInt(1);
2217  if (fni.control_number < 1)
2218  {
2219  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, fmt::format("flaregroup_no_import: parameter <control_number> must be 1-10; got {}, clamping to 1", fni.control_number));
2220  }
2221  if (fni.control_number > 10)
2222  {
2223  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, fmt::format("flaregroup_no_import: parameter <control_number> must be 1-10; got {}, clamping to 10", fni.control_number));
2224  }
2225  }
2226 
2227  LOG(fmt::format("[RoR|RigDef::Parser] parsed FlaregroupNoImport ({} {})", (char)fni.type, fni.control_number));
2228  m_current_module->flaregroups_no_import.push_back(fni);
2229 }
2230 
2231 void Parser::ParseDirectiveSetInertiaDefaults()
2232 {
2233  if (! this->CheckNumArguments(2)) { return; }
2234 
2235  float start_delay = this->GetArgFloat(1);
2236  float stop_delay = 0;
2237  if (m_num_args > 2) { stop_delay = this->GetArgFloat(2); }
2238 
2239  if (start_delay < 0 || stop_delay < 0)
2240  {
2241  m_user_default_inertia = m_ror_default_inertia; // Reset and return
2242  return;
2243  }
2244 
2245  // Create
2246  Inertia* i = new Inertia(*m_user_default_inertia.get());
2247  i->start_delay_factor = start_delay;
2248  i->stop_delay_factor = stop_delay;
2249 
2250  if (m_num_args > 3) { i->start_function = this->GetArgStr(3); }
2251  if (m_num_args > 4) { i->stop_function = this->GetArgStr(4); }
2252 
2253  m_user_default_inertia = std::shared_ptr<Inertia>(i);
2254 }
2255 
2256 void Parser::ParseScrewprops()
2257 {
2258  if (! this->CheckNumArguments(4)) { return; }
2259 
2260  Screwprop screwprop;
2261 
2262  screwprop.prop_node = this->GetArgNodeRef(0);
2263  screwprop.back_node = this->GetArgNodeRef(1);
2264  screwprop.top_node = this->GetArgNodeRef(2);
2265  screwprop.power = this->GetArgFloat (3);
2266 
2267  m_current_module->screwprops.push_back(screwprop);
2268  this->FlushPendingDocComment(m_current_module->screwprops.size(), Keyword::SCREWPROPS);
2269 }
2270 
2271 void Parser::ParseScripts()
2272 {
2273  if (!this->CheckNumArguments(1)) { return; }
2274 
2275  Script script;
2276 
2277  script.filename = this->GetArgStr(0);
2278 
2279  m_current_module->scripts.push_back(script);
2280  this->FlushPendingDocComment(m_current_module->scripts.size(), Keyword::SCRIPTS);
2281 }
2282 
2283 void Parser::ParseRotatorsUnified()
2284 {
2285  if (! this->CheckNumArguments(13)) { return; }
2286 
2287  Rotator2 rotator;
2288  rotator.inertia_defaults = m_user_default_inertia;
2289 
2290  rotator.axis_nodes[0] = this->GetArgNodeRef( 0);
2291  rotator.axis_nodes[1] = this->GetArgNodeRef( 1);
2292  rotator.base_plate_nodes[0] = this->GetArgNodeRef( 2);
2293  rotator.base_plate_nodes[1] = this->GetArgNodeRef( 3);
2294  rotator.base_plate_nodes[2] = this->GetArgNodeRef( 4);
2295  rotator.base_plate_nodes[3] = this->GetArgNodeRef( 5);
2296  rotator.rotating_plate_nodes[0] = this->GetArgNodeRef( 6);
2297  rotator.rotating_plate_nodes[1] = this->GetArgNodeRef( 7);
2298  rotator.rotating_plate_nodes[2] = this->GetArgNodeRef( 8);
2299  rotator.rotating_plate_nodes[3] = this->GetArgNodeRef( 9);
2300  rotator.rate = this->GetArgFloat (10);
2301  rotator.spin_left_key = this->GetArgInt (11);
2302  rotator.spin_right_key = this->GetArgInt (12);
2303 
2304  int offset = 0;
2305 
2306  if (m_current_block == Keyword::ROTATORS2)
2307  {
2308  if (! this->CheckNumArguments(16)) { return; }
2309  if (m_num_args > 13) { rotator.rotating_force = this->GetArgFloat(13); }
2310  if (m_num_args > 14) { rotator.tolerance = this->GetArgFloat(14); }
2311  if (m_num_args > 15) { rotator.description = this->GetArgStr (15); }
2312 
2313  offset = 3;
2314  }
2315 
2316  this->ParseOptionalInertia(rotator.inertia, 13 + offset);
2317  if (m_num_args > 17 + offset) { rotator.engine_coupling = this->GetArgFloat(17 + offset); }
2318  if (m_num_args > 18 + offset) { rotator.needs_engine = this->GetArgBool (18 + offset); }
2319 
2320  if (m_current_block == Keyword::ROTATORS2)
2321  {
2322  m_current_module->rotators2.push_back(rotator);
2323  this->FlushPendingDocComment(m_current_module->rotators2.size(), Keyword::ROTATORS2);
2324  }
2325  else
2326  {
2327  m_current_module->rotators.push_back(rotator);
2328  this->FlushPendingDocComment(m_current_module->rotators.size(), Keyword::ROTATORS);
2329  }
2330 }
2331 
2332 void Parser::ParseFileinfo()
2333 {
2334  if (! this->CheckNumArguments(2)) { return; }
2335 
2336  Fileinfo fileinfo;
2337 
2338  fileinfo.unique_id = this->GetArgStr(1);
2339  Ogre::StringUtil::trim(fileinfo.unique_id);
2340 
2341  if (m_num_args > 2) { fileinfo.category_id = this->GetArgInt(2); }
2342  if (m_num_args > 3) { fileinfo.file_version = this->GetArgInt(3); }
2343 
2344  m_current_module->fileinfo.push_back(fileinfo);
2345 
2346  m_current_block = Keyword::INVALID;
2347 }
2348 
2349 void Parser::ParseRopes()
2350 {
2351  if (! this->CheckNumArguments(2)) { return; }
2352 
2353  Rope rope;
2354  rope.beam_defaults = m_user_beam_defaults;
2355  rope.detacher_group = m_current_detacher_group;
2356  rope.root_node = this->GetArgNodeRef(0);
2357  rope.end_node = this->GetArgNodeRef(1);
2358 
2359  if (m_num_args > 2) { rope.invisible = (this->GetArgChar(2) == 'i'); }
2360 
2361  m_current_module->ropes.push_back(rope);
2362  this->FlushPendingDocComment(m_current_module->ropes.size(), Keyword::ROPES);
2363 }
2364 
2365 void Parser::ParseRopables()
2366 {
2367  if (! this->CheckNumArguments(1)) { return; }
2368 
2369  Ropable ropable;
2370  ropable.node = this->GetArgNodeRef(0);
2371 
2372  if (m_num_args > 1) { ropable.group = this->GetArgInt(1); }
2373  if (m_num_args > 2) { ropable.has_multilock = (this->GetArgInt(2) == 1); }
2374 
2375  m_current_module->ropables.push_back(ropable);
2376  this->FlushPendingDocComment(m_current_module->ropables.size(), Keyword::ROPABLES);
2377 }
2378 
2379 void Parser::ParseRailGroups()
2380 {
2381  Ogre::StringVector args = Ogre::StringUtil::split(m_current_line, ",");
2382  m_num_args = (int)args.size();
2383  if (! this->CheckNumArguments(3)) { return; }
2384 
2385  RailGroup railgroup;
2386  railgroup.id = this->ParseArgInt(args[0].c_str());
2387 
2388  for (auto itor = args.begin() + 1; itor != args.end(); itor++)
2389  {
2390  railgroup.node_list.push_back( this->_ParseNodeRef(*itor));
2391  }
2392 
2393  m_current_module->railgroups.push_back(railgroup);
2394  this->FlushPendingDocComment(m_current_module->railgroups.size(), Keyword::RAILGROUPS);
2395 }
2396 
2397 void Parser::ParseProps()
2398 {
2399  if (! this->CheckNumArguments(10)) { return; }
2400 
2401  Prop prop;
2402  prop.reference_node = this->GetArgNodeRef(0);
2403  prop.x_axis_node = this->GetArgNodeRef(1);
2404  prop.y_axis_node = this->GetArgNodeRef(2);
2405  prop.offset.x = this->GetArgFloat (3);
2406  prop.offset.y = this->GetArgFloat (4);
2407  prop.offset.z = this->GetArgFloat (5);
2408  prop.rotation.x = this->GetArgFloat (6);
2409  prop.rotation.y = this->GetArgFloat (7);
2410  prop.rotation.z = this->GetArgFloat (8);
2411  prop.mesh_name = this->GetArgStr(9);
2412  prop.special = Parser::IdentifySpecialProp(prop.mesh_name);
2413 
2414  if ((prop.special == SpecialProp::BEACON) && (m_num_args >= 14))
2415  {
2416  prop.special_prop_beacon.flare_material_name = this->GetArgStr(10);
2417  Ogre::StringUtil::trim(prop.special_prop_beacon.flare_material_name);
2418 
2419  prop.special_prop_beacon.color = Ogre::ColourValue(
2420  this->GetArgFloat(11), this->GetArgFloat(12), this->GetArgFloat(13));
2421  }
2422  else if (prop.special == SpecialProp::DASHBOARD_LEFT ||
2423  prop.special == SpecialProp::DASHBOARD_RIGHT)
2424  {
2425  if (m_num_args > 10) prop.special_prop_dashboard.mesh_name = this->GetArgStr(10);
2426  if (m_num_args > 13)
2427  {
2428  prop.special_prop_dashboard.offset = Ogre::Vector3(this->GetArgFloat(11), this->GetArgFloat(12), this->GetArgFloat(13));
2430  }
2431  if (m_num_args > 14) prop.special_prop_dashboard.rotation_angle = this->GetArgFloat(14);
2432  }
2433 
2434  m_current_module->props.push_back(prop);
2435  this->FlushPendingDocComment(m_current_module->props.size(), Keyword::PROPS);
2436 }
2437 
2438 void Parser::ParsePistonprops()
2439 {
2440  if (!this->CheckNumArguments(10)) { return; }
2441 
2442  Pistonprop pistonprop;
2443  pistonprop.reference_node = this->GetArgNodeRef (0);
2444  pistonprop.axis_node = this->GetArgNodeRef (1);
2445  pistonprop.blade_tip_nodes[0] = this->GetArgNodeRef (2);
2446  pistonprop.blade_tip_nodes[1] = this->GetArgNodeRef (3);
2447  pistonprop.blade_tip_nodes[2] = this->GetArgNullableNode(4);
2448  pistonprop.blade_tip_nodes[3] = this->GetArgNullableNode(5);
2449  pistonprop.couple_node = this->GetArgNullableNode(6);
2450  pistonprop.turbine_power_kW = this->GetArgFloat (7);
2451  pistonprop.pitch = this->GetArgFloat (8);
2452  pistonprop.airfoil = this->GetArgStr (9);
2453 
2454  m_current_module->pistonprops.push_back(pistonprop);
2455  this->FlushPendingDocComment(m_current_module->pistonprops.size(), Keyword::PISTONPROPS);
2456 }
2457 
2458 void Parser::ParseParticles()
2459 {
2460  if (!this->CheckNumArguments(3)) { return; }
2461 
2462  Particle particle;
2463  particle.emitter_node = this->GetArgNodeRef(0);
2464  particle.reference_node = this->GetArgNodeRef(1);
2465  particle.particle_system_name = this->GetArgStr (2);
2466 
2467  m_current_module->particles.push_back(particle);
2468  this->FlushPendingDocComment(m_current_module->particles.size(), Keyword::PARTICLES);
2469 }
2470 
2471 // Static
2472 void Parser::_TrimTrailingComments(std::string const & line_in, std::string & line_out)
2473 {
2474  // Trim trailing comment
2475  // We need to handle a case of lines as [keyword 1, 2, 3 ;;///// Comment!]
2476  int comment_start = static_cast<int>(line_in.find_first_of(";"));
2477  if (comment_start != Ogre::String::npos)
2478  {
2479  line_out = line_in.substr(0, comment_start);
2480  return;
2481  }
2482  // The [//Comment] is harder - the '/' character may also be present in DESCRIPTION arguments!
2483  comment_start = static_cast<int>(line_in.find_last_of("/"));
2484  if (comment_start != Ogre::String::npos)
2485  {
2486  while (comment_start >= 0)
2487  {
2488  char c = line_in[comment_start - 1];
2489  if (c != '/' && c != ' ' && c != '\t')
2490  {
2491  break; // Start of comment found
2492  }
2493  --comment_start;
2494  }
2495  line_out = line_in.substr(0, comment_start);
2496  return;
2497  }
2498  // No comment found
2499  line_out = line_in;
2500 }
2501 
2502 void Parser::ParseNodesUnified()
2503 {
2504  if (! this->CheckNumArguments(4)) { return; }
2505 
2506  Node node;
2507  node.node_defaults = m_user_node_defaults;
2508  node.beam_defaults = m_user_beam_defaults;
2509  node.default_minimass = m_set_default_minimass;
2510  node.detacher_group = m_current_detacher_group;
2511 
2512  if (m_current_block == Keyword::NODES2)
2513  {
2514  std::string node_name = this->GetArgStr(0);
2515  node.id.setStr(node_name);
2516  if (m_sequential_importer.IsEnabled())
2517  {
2518  m_sequential_importer.AddNamedNode(node_name);
2519  }
2520  m_any_named_node_defined = true; // For import logic
2521  }
2522  else
2523  {
2524  const unsigned int node_num = this->GetArgUint(0);
2525  node.id.SetNum(node_num);
2526  if (m_sequential_importer.IsEnabled())
2527  {
2528  m_sequential_importer.AddNumberedNode(node_num);
2529  }
2530  }
2531 
2532  node.position.x = this->GetArgFloat(1);
2533  node.position.y = this->GetArgFloat(2);
2534  node.position.z = this->GetArgFloat(3);
2535  if (m_num_args > 4)
2536  {
2537  node.options = this->GetArgNodeOptions(4);
2538  }
2539  if (m_num_args > 5)
2540  {
2541  if (node.options & Node::OPTION_l_LOAD_WEIGHT)
2542  {
2543  node.load_weight_override = this->GetArgFloat(5);
2544  node._has_load_weight_override = true;
2545  }
2546  else
2547  {
2548  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
2549  "Node has load-weight-override value specified, but option 'l' is not present. Ignoring value...");
2550  }
2551  }
2552 
2553  m_current_module->nodes.push_back(node);
2554  this->FlushPendingDocComment(m_current_module->nodes.size(), Keyword::NODES);
2555 }
2556 
2557 void Parser::ParseMinimass()
2558 {
2559  if (! this->CheckNumArguments(1)) { return; }
2560 
2561  Minimass mm;
2562  mm.global_min_mass_Kg = this->GetArgFloat(0);
2563  if (m_num_args > 1) { mm.option = this->GetArgMinimassOption(1); }
2564 
2565  m_current_module->minimass.push_back(mm);
2566  m_current_block = Keyword::INVALID;
2567 }
2568 
2569 void Parser::ParseFlexBodyWheel()
2570 {
2571  if (! this->CheckNumArguments(16)) { return; }
2572 
2573  FlexBodyWheel flexbody_wheel;
2574  flexbody_wheel.node_defaults = m_user_node_defaults;
2575  flexbody_wheel.beam_defaults = m_user_beam_defaults;
2576 
2577  flexbody_wheel.tyre_radius = this->GetArgFloat ( 0);
2578  flexbody_wheel.rim_radius = this->GetArgFloat ( 1);
2579  flexbody_wheel.width = this->GetArgFloat ( 2);
2580  flexbody_wheel.num_rays = this->GetArgInt ( 3);
2581  flexbody_wheel.nodes[0] = this->GetArgNodeRef ( 4);
2582  flexbody_wheel.nodes[1] = this->GetArgNodeRef ( 5);
2583  flexbody_wheel.rigidity_node = this->GetArgRigidityNode ( 6);
2584  flexbody_wheel.braking = this->GetArgBraking ( 7);
2585  flexbody_wheel.propulsion = this->GetArgPropulsion ( 8);
2586  flexbody_wheel.reference_arm_node = this->GetArgNodeRef ( 9);
2587  flexbody_wheel.mass = this->GetArgFloat (10);
2588  flexbody_wheel.tyre_springiness = this->GetArgFloat (11);
2589  flexbody_wheel.tyre_damping = this->GetArgFloat (12);
2590  flexbody_wheel.rim_springiness = this->GetArgFloat (13);
2591  flexbody_wheel.rim_damping = this->GetArgFloat (14);
2592  flexbody_wheel.side = this->GetArgWheelSide (15);
2593 
2594  if (m_num_args > 16) { flexbody_wheel.rim_mesh_name = this->GetArgStr(16); }
2595  if (m_num_args > 17) { flexbody_wheel.tyre_mesh_name = this->GetArgStr(17); }
2596 
2597  if (m_sequential_importer.IsEnabled())
2598  {
2599  m_sequential_importer.GenerateNodesForWheel(Keyword::FLEXBODYWHEELS, flexbody_wheel.num_rays, flexbody_wheel.rigidity_node.IsValidAnyState());
2600  }
2601 
2602  m_current_module->flexbodywheels.push_back(flexbody_wheel);
2603  this->FlushPendingDocComment(m_current_module->flexbodywheels.size(), Keyword::FLEXBODYWHEELS);
2604 }
2605 
2606 void Parser::ParseMaterialFlareBindings()
2607 {
2608  if (! this->CheckNumArguments(2)) { return; }
2609 
2610  MaterialFlareBinding binding;
2611  binding.flare_number = this->GetArgInt(0);
2612  binding.material_name = this->GetArgStr(1);
2613 
2614  m_current_module->materialflarebindings.push_back(binding);
2615  this->FlushPendingDocComment(m_current_module->materialflarebindings.size(), Keyword::MATERIALFLAREBINDINGS);
2616 }
2617 
2618 void Parser::ParseManagedMaterials()
2619 {
2620  if (! this->CheckNumArguments(2)) { return; }
2621 
2622  ManagedMaterial managed_mat;
2623  managed_mat.options = m_current_managed_material_options;
2624  managed_mat.name = this->GetArgStr(0);
2625  managed_mat.type = this->GetArgManagedMatType(1);
2626 
2627  if (managed_mat.type != ManagedMaterialType::INVALID)
2628  {
2629  if (! this->CheckNumArguments(3)) { return; }
2630 
2631  managed_mat.diffuse_map = this->GetArgStr(2);
2632 
2633  if (managed_mat.type == ManagedMaterialType::MESH_STANDARD ||
2634  managed_mat.type == ManagedMaterialType::MESH_TRANSPARENT)
2635  {
2636  if (m_num_args > 3) { managed_mat.specular_map = this->GetArgManagedTex(3); }
2637  }
2638  else if (managed_mat.type == ManagedMaterialType::FLEXMESH_STANDARD ||
2639  managed_mat.type == ManagedMaterialType::FLEXMESH_TRANSPARENT)
2640  {
2641  if (m_num_args > 3) { managed_mat.damaged_diffuse_map = this->GetArgManagedTex(3); }
2642  if (m_num_args > 4) { managed_mat.specular_map = this->GetArgManagedTex(4); }
2643  }
2644 
2645  m_current_module->managedmaterials.push_back(managed_mat);
2646  this->FlushPendingDocComment(m_current_module->managedmaterials.size(), Keyword::MANAGEDMATERIALS);
2647  }
2648 }
2649 
2650 void Parser::ParseLockgroups()
2651 {
2652  if (! this->CheckNumArguments(2)) { return; } // Lockgroup num. + at least 1 node...
2653 
2654  Lockgroup lockgroup;
2655  lockgroup.number = this->GetArgInt(0);
2656 
2657  for (int i = 1; i < m_num_args; ++i)
2658  {
2659  lockgroup.nodes.push_back(this->GetArgNodeRef(i));
2660  }
2661 
2662  m_current_module->lockgroups.push_back(lockgroup);
2663  this->FlushPendingDocComment(m_current_module->lockgroups.size(), Keyword::LOCKGROUPS);
2664 }
2665 
2666 void Parser::ParseHydros()
2667 {
2668  if (! this->CheckNumArguments(3)) { return; }
2669 
2670  Hydro hydro;
2671  hydro.inertia_defaults = m_user_default_inertia;
2672  hydro.detacher_group = m_current_detacher_group;
2673  hydro.beam_defaults = m_user_beam_defaults;
2674 
2675  hydro.nodes[0] = this->GetArgNodeRef(0);
2676  hydro.nodes[1] = this->GetArgNodeRef(1);
2677  hydro.lenghtening_factor = this->GetArgFloat (2);
2678 
2679  if (m_num_args > 3) { hydro.options = this->GetArgHydroOptions(3); }
2680 
2681  if (!hydro.options)
2682  {
2683  hydro.options |= Hydro::OPTION_n_INPUT_NORMAL;
2684  }
2685 
2686  this->ParseOptionalInertia(hydro.inertia, 4);
2687 
2688  m_current_module->hydros.push_back(hydro);
2689  this->FlushPendingDocComment(m_current_module->hydros.size(), Keyword::HYDROS);
2690 }
2691 
2692 void Parser::ParseOptionalInertia(Inertia & inertia, int index)
2693 {
2694  if (m_num_args > index) { inertia.start_delay_factor = this->GetArgFloat(index++); }
2695  if (m_num_args > index) { inertia.stop_delay_factor = this->GetArgFloat(index++); }
2696  if (m_num_args > index) { inertia.start_function = this->GetArgStr (index++); }
2697  if (m_num_args > index) { inertia.stop_function = this->GetArgStr (index++); }
2698 }
2699 
2700 void Parser::_ParseDifferentialTypes(DifferentialTypeVec& diff_types, std::string const& options_str)
2701 {
2702  for (char c: options_str)
2703  {
2704  switch(c)
2705  {
2706  case (char)DifferentialType::o_OPEN:
2707  case (char)DifferentialType::l_LOCKED:
2708  case (char)DifferentialType::s_SPLIT:
2709  case (char)DifferentialType::v_VISCOUS:
2710  diff_types.push_back(DifferentialType(c));
2711  break;
2712 
2713  default:
2714  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
2715  fmt::format("ignoring invalid differential type '{}'", c));
2716  break;
2717  }
2718  }
2719 }
2720 
2721 void Parser::ParseBeams()
2722 {
2723  if (! this->CheckNumArguments(2)) { return; }
2724 
2725  Beam beam;
2726  beam.defaults = m_user_beam_defaults;
2727  beam.detacher_group = m_current_detacher_group;
2728 
2729  beam.nodes[0] = this->GetArgNodeRef(0);
2730  beam.nodes[1] = this->GetArgNodeRef(1);
2731  if (m_num_args > 2) beam.options = this->GetArgBeamOptions(2);
2732 
2733  if ((m_num_args > 3) && BITMASK_IS_1(beam.options, Beam::OPTION_s_SUPPORT))
2734  {
2735  float support_break_limit = 0.0f;
2736  float support_break_factor = this->GetArgInt(3);
2737  if (support_break_factor > 0.0f)
2738  {
2739  support_break_limit = support_break_factor;
2740  }
2741  beam.extension_break_limit = support_break_limit;
2742  beam._has_extension_break_limit = true;
2743  }
2744 
2745  m_current_module->beams.push_back(beam);
2746  this->FlushPendingDocComment(m_current_module->beams.size(), Keyword::BEAMS);
2747 }
2748 
2749 void Parser::ParseAnimator()
2750 {
2751  auto args = Ogre::StringUtil::split(m_current_line, ",");
2752  if (args.size() < 4) { return; }
2753 
2754  Animator animator;
2755  animator.inertia_defaults = m_user_default_inertia;
2756  animator.beam_defaults = m_user_beam_defaults;
2757  animator.detacher_group = m_current_detacher_group;
2758 
2759  animator.nodes[0] = this->_ParseNodeRef(args[0]);
2760  animator.nodes[1] = this->_ParseNodeRef(args[1]);
2761  animator.lenghtening_factor = this->ParseArgFloat(args[2]);
2762 
2763  // Parse options; Just use the split/trim/compare method
2764  Ogre::StringVector attrs = Ogre::StringUtil::split(args[3], "|");
2765 
2766  auto itor = attrs.begin();
2767  auto endi = attrs.end();
2768  for (; itor != endi; ++itor)
2769  {
2770  Ogre::String token = *itor;
2771  Ogre::StringUtil::trim(token);
2772  std::smatch results;
2773  bool is_shortlimit = false;
2774 
2775  // Numbered keywords
2776  if (std::regex_search(token, results, Regexes::PARSE_ANIMATORS_NUMBERED_KEYWORD))
2777  {
2778  if (results[1] == "throttle") animator.aero_animator.flags |= AeroAnimator::OPTION_THROTTLE;
2779  else if (results[1] == "rpm") animator.aero_animator.flags |= AeroAnimator::OPTION_RPM;
2780  else if (results[1] == "aerotorq") animator.aero_animator.flags |= AeroAnimator::OPTION_TORQUE;
2781  else if (results[1] == "aeropit") animator.aero_animator.flags |= AeroAnimator::OPTION_PITCH;
2782  else if (results[1] == "aerostatus") animator.aero_animator.flags |= AeroAnimator::OPTION_STATUS;
2783 
2784  animator.aero_animator.engine_idx = this->ParseArgUint(results[2].str().c_str()) - 1;
2785  }
2786  else if ((is_shortlimit = (token.compare(0, 10, "shortlimit") == 0)) || (token.compare(0, 9, "longlimit") == 0))
2787  {
2788  Ogre::StringVector fields = Ogre::StringUtil::split(token, ":");
2789  if (fields.size() > 1)
2790  {
2791  if (is_shortlimit)
2792  {
2793  animator.short_limit = std::strtod(fields[1].c_str(), nullptr);
2794  animator.flags |= Animator::OPTION_SHORT_LIMIT;
2795  }
2796  else
2797  {
2798  animator.long_limit = std::strtod(fields[1].c_str(), nullptr);
2799  animator.flags |= Animator::OPTION_LONG_LIMIT;
2800  }
2801  }
2802  }
2803  else
2804  {
2805  // Standalone keywords
2806  if (token == "vis") animator.flags |= Animator::OPTION_VISIBLE;
2807  else if (token == "inv") animator.flags |= Animator::OPTION_INVISIBLE;
2808  else if (token == "airspeed") animator.flags |= Animator::OPTION_AIRSPEED;
2809  else if (token == "vvi") animator.flags |= Animator::OPTION_VERTICAL_VELOCITY;
2810  else if (token == "altimeter100k") animator.flags |= Animator::OPTION_ALTIMETER_100K;
2811  else if (token == "altimeter10k") animator.flags |= Animator::OPTION_ALTIMETER_10K;
2812  else if (token == "altimeter1k") animator.flags |= Animator::OPTION_ALTIMETER_1K;
2813  else if (token == "aoa") animator.flags |= Animator::OPTION_ANGLE_OF_ATTACK;
2814  else if (token == "flap") animator.flags |= Animator::OPTION_FLAP;
2815  else if (token == "airbrake") animator.flags |= Animator::OPTION_AIR_BRAKE;
2816  else if (token == "roll") animator.flags |= Animator::OPTION_ROLL;
2817  else if (token == "pitch") animator.flags |= Animator::OPTION_PITCH;
2818  else if (token == "brakes") animator.flags |= Animator::OPTION_BRAKES;
2819  else if (token == "accel") animator.flags |= Animator::OPTION_ACCEL;
2820  else if (token == "clutch") animator.flags |= Animator::OPTION_CLUTCH;
2821  else if (token == "speedo") animator.flags |= Animator::OPTION_SPEEDO;
2822  else if (token == "tacho") animator.flags |= Animator::OPTION_TACHO;
2823  else if (token == "turbo") animator.flags |= Animator::OPTION_TURBO;
2824  else if (token == "parking") animator.flags |= Animator::OPTION_PARKING;
2825  else if (token == "shifterman1") animator.flags |= Animator::OPTION_SHIFT_LEFT_RIGHT;
2826  else if (token == "shifterman2") animator.flags |= Animator::OPTION_SHIFT_BACK_FORTH;
2827  else if (token == "sequential") animator.flags |= Animator::OPTION_SEQUENTIAL_SHIFT;
2828  else if (token == "shifterlin") animator.flags |= Animator::OPTION_GEAR_SELECT;
2829  else if (token == "torque") animator.flags |= Animator::OPTION_TORQUE;
2830  else if (token == "difflock") animator.flags |= Animator::OPTION_DIFFLOCK;
2831  else if (token == "rudderboat") animator.flags |= Animator::OPTION_BOAT_RUDDER;
2832  else if (token == "throttleboat") animator.flags |= Animator::OPTION_BOAT_THROTTLE;
2833  }
2834  }
2835 
2836  m_current_module->animators.push_back(animator);
2837  this->FlushPendingDocComment(m_current_module->animators.size(), Keyword::ANIMATORS);
2838 }
2839 
2840 void Parser::ParseAuthor()
2841 {
2842  if (! this->CheckNumArguments(2)) { return; }
2843 
2844  Author author;
2845  if (m_num_args > 1) { author.type = this->GetArgStr(1); }
2846  if (m_num_args > 2) { author.forum_account_id = this->GetArgInt(2); author._has_forum_account = true; }
2847  if (m_num_args > 3) { author.name = this->GetArgStr(3); }
2848  if (m_num_args > 4) { author.email = this->GetArgStr(4); }
2849 
2850  m_current_module->author.push_back(author);
2851  this->FlushPendingDocComment(m_current_module->author.size(), Keyword::AUTHOR);
2852  m_current_block = Keyword::INVALID;
2853 }
2854 
2855 // --------------------------------------------------------------------------
2856 // Utilities
2857 // --------------------------------------------------------------------------
2858 
2859 void Parser::LogMessage(Console::MessageType type, std::string const& msg)
2860 {
2863  type,
2864  fmt::format("{}:{} ({}): {}",
2865  m_filename, m_current_line_number, KeywordToString(m_log_keyword), msg));
2866 }
2867 
2868 Keyword Parser::IdentifyKeyword(const std::string& line)
2869 {
2870  // Search and ignore lettercase
2871  std::smatch results;
2872  std::regex_search(line, results, Regexes::IDENTIFY_KEYWORD_IGNORE_CASE); // Always returns true.
2873 
2874  // The 'results' array contains a complete match at positon [0] and sub-matches starting with [1],
2875  // so we get exact positions in Regexes::IDENTIFY_KEYWORD, which again match Keyword enum members
2876  for (unsigned int i = 1; i < results.size(); i++)
2877  {
2878  std::ssub_match sub = results[i];
2879  if (sub.matched)
2880  {
2881  // Build enum value directly from result offset
2882  return Keyword(i);
2883  }
2884  }
2885 
2886  return Keyword::INVALID;
2887 }
2888 
2889 void Parser::Prepare()
2890 {
2891  m_current_block = Keyword::INVALID;
2892  m_current_line_number = 1;
2893  m_definition = RigDef::DocumentPtr(new Document());
2894  m_any_named_node_defined = false;
2895  m_current_detacher_group = 0; // Global detacher group
2896 
2897  m_user_default_inertia = m_ror_default_inertia;
2898  m_user_node_defaults = m_ror_node_defaults;
2899  m_current_managed_material_options = ManagedMaterialsOptions();
2900 
2901  m_user_beam_defaults = std::shared_ptr<BeamDefaults>(new BeamDefaults);
2902  m_user_beam_defaults->springiness = DEFAULT_SPRING;
2903  m_user_beam_defaults->damping_constant = DEFAULT_DAMP;
2904  m_user_beam_defaults->deformation_threshold = BEAM_DEFORM;
2905  m_user_beam_defaults->breaking_threshold = BEAM_BREAK;
2906  m_user_beam_defaults->visual_beam_diameter = DEFAULT_BEAM_DIAMETER;
2907 
2908  m_root_module = m_definition->root_module;
2909  m_current_module = m_definition->root_module;
2910 
2911  m_sequential_importer.Init(true); // Enabled=true
2912 }
2913 
2914 void Parser::BeginBlock(Keyword keyword)
2915 {
2916  if (keyword == Keyword::INVALID) // also means 'end'
2917  {
2918  // flush staged submesh, if any
2919  if (m_current_submesh != nullptr)
2920  {
2921  m_current_module->submeshes.push_back(*m_current_submesh);
2922  m_current_submesh.reset(); // Set to nullptr
2923  }
2924 
2925  // flush staged camerarail, if any
2926  if (m_current_camera_rail != nullptr)
2927  {
2928  if (m_current_camera_rail->nodes.size() == 0)
2929  {
2930  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING, "Empty section 'camerarail', ignoring...");
2931  }
2932  else
2933  {
2934  m_current_module->camerarail.push_back(*m_current_camera_rail);
2935  m_current_camera_rail.reset();
2936  }
2937  }
2938  }
2939  else if (keyword == Keyword::CAMERARAIL)
2940  {
2941  this->BeginBlock(Keyword::INVALID); // flush staged rail
2942  m_current_camera_rail = std::shared_ptr<CameraRail>( new CameraRail() );
2943  }
2944  m_current_block = keyword;
2945 }
2946 
2947 void Parser::ProcessChangeModuleLine(Keyword keyword)
2948 {
2949  // Determine and verify new module
2950  std::string new_module_name;
2951  if (keyword == Keyword::END_SECTION)
2952  {
2953  if (m_current_module == m_root_module)
2954  {
2955  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "Misplaced keyword 'end_section' (already in root module), ignoring...");
2956  return;
2957  }
2958  new_module_name = ROOT_MODULE_NAME;
2959  }
2960  else if (keyword == Keyword::SECTION)
2961  {
2962  if (!this->CheckNumArguments(3)) // Syntax: "section VERSION NAME"; VERSION is unused
2963  {
2964  return; // Error already reported
2965  }
2966 
2967  new_module_name = this->GetArgStr(2);
2968  if (new_module_name == m_current_module->name)
2969  {
2970  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR, "Attempt to re-enter current module, ignoring...");
2971  return;
2972  }
2973  }
2974 
2975  // Perform the switch
2976  this->BeginBlock(Keyword::INVALID);
2977 
2978  if (new_module_name == ROOT_MODULE_NAME)
2979  {
2980  m_current_module = m_root_module;
2981  return;
2982  }
2983 
2984  auto search_itor = m_definition->user_modules.find(new_module_name);
2985  if (search_itor != m_definition->user_modules.end())
2986  {
2987  m_current_module = search_itor->second;
2988  }
2989  else
2990  {
2991  m_current_module = std::make_shared<Document::Module>(new_module_name);
2992  m_definition->user_modules.insert(std::make_pair(new_module_name, m_current_module));
2993  }
2994 }
2995 
2996 void Parser::FlushPendingDocComment(size_t vectorlen, RigDef::Keyword keyword)
2997 {
2998  if (m_pending_doc_comment.comment_text == "" || vectorlen == 0)
2999  {
3000  return;
3001  }
3002 
3003  m_pending_doc_comment.commented_keyword = keyword;
3004  m_pending_doc_comment.commented_datapos = static_cast<int>(vectorlen - 1);
3005  m_current_module->_comments.push_back(m_pending_doc_comment);
3006 
3007  m_pending_doc_comment = DocComment();
3008 }
3009 
3010 void Parser::ParseDirectiveSection()
3011 {
3012  this->ProcessChangeModuleLine(Keyword::SECTION);
3013 }
3014 
3015 void Parser::ParseDirectiveSectionConfig()
3016 {
3017  // FIXME: restore this, see branch 'retro-0407'
3018 }
3019 
3020 void Parser::Finalize()
3021 {
3022  this->BeginBlock(Keyword::INVALID);
3023 
3024  if (m_sequential_importer.IsEnabled())
3025  {
3026  m_sequential_importer.Process( m_definition );
3027  }
3028 }
3029 
3030 std::string Parser::GetArgStr(int index)
3031 {
3032  return std::string(m_args[index].start, m_args[index].length);
3033 }
3034 
3035 char Parser::GetArgChar(int index)
3036 {
3037  return *(m_args[index].start);
3038 }
3039 
3040 WheelSide Parser::GetArgWheelSide(int index)
3041 {
3042  char c = this->GetArgChar(index);
3043  switch (c)
3044  {
3045  case (char)WheelSide::RIGHT:
3046  case (char)WheelSide::LEFT:
3047  return WheelSide(c);
3048 
3049  default:
3050  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3051  fmt::format("Bad arg~{} 'side' (value: {}), parsing as 'l' for backwards compatibility.", index + 1, c));
3052  return WheelSide::LEFT;
3053  }
3054 }
3055 
3056 long Parser::GetArgLong(int index)
3057 {
3058  errno = 0;
3059  char* out_end = nullptr;
3060  long res = std::strtol(m_args[index].start, &out_end, 10);
3061  if (errno != 0)
3062  {
3063  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR,
3064  fmt::format("Cannot parse argument [{}] as integer, errno: {}", index + 1, errno));
3065  return 0; // Compatibility
3066  }
3067  if (out_end == m_args[index].start)
3068  {
3069  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR,
3070  fmt::format("Argument [{}] is not valid integer", index + 1));
3071  return 0; // Compatibility
3072  }
3073  else if (out_end != (m_args[index].start + m_args[index].length))
3074  {;
3075  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3076  fmt::format("Integer argument [{}] has invalid trailing characters", index + 1));
3077  }
3078  return res;
3079 }
3080 
3081 int Parser::GetArgInt(int index)
3082 {
3083  return static_cast<int>(this->GetArgLong(index));
3084 }
3085 
3086 Node::Ref Parser::GetArgRigidityNode(int index)
3087 {
3088  std::string rigidity_node = this->GetArgStr(index);
3089  if (rigidity_node != "9999") // Special null value
3090  {
3091  return this->GetArgNodeRef(index);
3092  }
3093  return Node::Ref(); // Defaults to invalid ref
3094 }
3095 
3096 RoR::WheelPropulsion Parser::GetArgPropulsion(int index)
3097 {
3098  int p = this->GetArgInt(index);
3099  switch (p)
3100  {
3101  case (int)WheelPropulsion::NONE:
3102  case (int)WheelPropulsion::FORWARD:
3103  case (int)WheelPropulsion::BACKWARD:
3104  return WheelPropulsion(p);
3105 
3106  default:
3107  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR,
3108  fmt::format("Bad value of param ~{} (propulsion), using 0 (no propulsion)", index + 1));
3109  return WheelPropulsion::NONE;
3110  }
3111 }
3112 
3113 RoR::WheelBraking Parser::GetArgBraking(int index)
3114 {
3115  int b = this->GetArgInt(index);
3116  switch (b)
3117  {
3118  case (int)WheelBraking::NONE:
3119  case (int)WheelBraking::FOOT_HAND:
3122  case (int)WheelBraking::FOOT_ONLY:
3123  return WheelBraking(b);
3124 
3125  default:
3126  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR,
3127  fmt::format("Bad value of param ~{} (braking), using 0 (not braked)", index + 1));
3128  return WheelBraking::NONE;
3129  }
3130 }
3131 
3132 Node::Ref Parser::GetArgNodeRef(int index)
3133 {
3134  return this->_ParseNodeRef(this->GetArgStr(index));
3135 }
3136 
3137 Node::Ref Parser::GetArgNullableNode(int index)
3138 {
3139  if (! (Ogre::StringConverter::parseReal(this->GetArgStr(index)) == -1.f))
3140  {
3141  return this->GetArgNodeRef(index);
3142  }
3143  return Node::Ref(); // Defaults to empty ref.
3144 }
3145 
3146 unsigned Parser::GetArgUint(int index)
3147 {
3148  return static_cast<unsigned>(this->GetArgLong(index));
3149 }
3150 
3151 FlareType Parser::GetArgFlareType(int index)
3152 {
3153  char in = this->GetArgChar(index);
3154  switch (in)
3155  {
3156  // Front lights
3157  case (char)FlareType::HEADLIGHT:
3158  case (char)FlareType::HIGH_BEAM:
3159  case (char)FlareType::FOG_LIGHT:
3160  // Rear lighs
3161  case (char)FlareType::TAIL_LIGHT:
3162  case (char)FlareType::BRAKE_LIGHT:
3163  case (char)FlareType::REVERSE_LIGHT:
3164  // Special lights
3165  case (char)FlareType::SIDELIGHT:
3166  case (char)FlareType::BLINKER_LEFT:
3167  case (char)FlareType::BLINKER_RIGHT:
3168  case (char)FlareType::USER:
3169  case (char)FlareType::DASHBOARD:
3170  return FlareType(in);
3171 
3172  default:
3173  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3174  fmt::format("Invalid flare type '{}', falling back to type 'f' (front light)...", in));
3175  return FlareType::HEADLIGHT;
3176  }
3177 }
3178 
3179 ExtCameraMode Parser::GetArgExtCameraMode(int index)
3180 {
3181  std::string str = this->GetArgStr(index);
3182  if (str == "classic") return ExtCameraMode::CLASSIC;
3183  if (str == "cinecam") return ExtCameraMode::CINECAM;
3184  if (str == "node") return ExtCameraMode::NODE;
3185 
3186  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3187  fmt::format("Invalid ExtCameraMode '{}', falling back to type 'classic'...", str));
3188  return ExtCameraMode::CLASSIC;
3189 }
3190 
3191 float Parser::GetArgFloat(int index)
3192 {
3193  return (float) Ogre::StringConverter::parseReal(this->GetArgStr(index), 0.f);
3194 }
3195 
3196 float Parser::ParseArgFloat(const char* str)
3197 {
3198  return (float) Ogre::StringConverter::parseReal(str, 0.f);
3199 }
3200 
3201 float Parser::ParseArgFloat(std::string const & str)
3202 {
3203  return this->ParseArgFloat(str.c_str());
3204 }
3205 
3206 unsigned Parser::ParseArgUint(const char* str)
3207 {
3208  errno = 0;
3209  long res = std::strtol(str, nullptr, 10);
3210  if (errno != 0)
3211  {
3212  this->LogMessage(Console::CONSOLE_SYSTEM_ERROR,
3213  fmt::format("Cannot parse argument '{}' as int, errno: {}", str, errno));
3214  return 0.f; // Compatibility
3215  }
3216  return static_cast<unsigned>(res);
3217 }
3218 
3219 unsigned Parser::ParseArgUint(std::string const & str)
3220 {
3221  return this->ParseArgUint(str.c_str());
3222 }
3223 
3224 int Parser::ParseArgInt(const char* str)
3225 {
3226  return static_cast<int>(this->ParseArgUint(str));
3227 }
3228 
3229 bool Parser::GetArgBool(int index)
3230 {
3231  return Ogre::StringConverter::parseBool(this->GetArgStr(index));
3232 }
3233 
3234 WingControlSurface Parser::GetArgWingSurface(int index)
3235 {
3236  char c = this->GetArgChar(index);
3237  switch (c)
3238  {
3239  case (char)WingControlSurface::n_NONE:
3240  case (char)WingControlSurface::a_RIGHT_AILERON:
3241  case (char)WingControlSurface::b_LEFT_AILERON:
3242  case (char)WingControlSurface::f_FLAP:
3243  case (char)WingControlSurface::e_ELEVATOR:
3244  case (char)WingControlSurface::r_RUDDER:
3245  case (char)WingControlSurface::S_RIGHT_HAND_STABILATOR:
3246  case (char)WingControlSurface::T_LEFT_HAND_STABILATOR:
3247  case (char)WingControlSurface::c_RIGHT_ELEVON:
3248  case (char)WingControlSurface::d_LEFT_ELEVON:
3249  case (char)WingControlSurface::g_RIGHT_FLAPERON:
3250  case (char)WingControlSurface::h_LEFT_FLAPERON:
3251  case (char)WingControlSurface::U_RIGHT_HAND_TAILERON:
3252  case (char)WingControlSurface::V_LEFT_HAND_TAILERON:
3253  case (char)WingControlSurface::i_RIGHT_RUDDERVATOR:
3254  case (char)WingControlSurface::j_LEFT_RUDDERVATOR:
3255  return WingControlSurface(c);
3256 
3257  default:
3258  fmt::format("invalid WingControlSurface '{}', falling back to 'n' (none)", c);
3259  return WingControlSurface::n_NONE;
3260  }
3261 }
3262 
3263 std::string Parser::GetArgManagedTex(int index)
3264 {
3265  std::string tex_name = this->GetArgStr(index);
3266  return (tex_name.at(0) != '-') ? tex_name : "";
3267 }
3268 
3269 MinimassOption Parser::GetArgMinimassOption(int index)
3270 {
3271  switch (this->GetArgStr(index)[0])
3272  {
3273  case (char)MinimassOption::l_SKIP_LOADED:
3274  return MinimassOption::l_SKIP_LOADED;
3275 
3276  case (char)MinimassOption::n_DUMMY:
3277  return MinimassOption::n_DUMMY;
3278 
3279  default:
3280  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3281  fmt::format("Not a valid minimass option: {}, falling back to 'n' (dummy)", this->GetArgStr(index)));
3282  return MinimassOption::n_DUMMY;
3283  }
3284 }
3285 
3286 BitMask_t Parser::GetArgCabOptions(int index)
3287 {
3288  BitMask_t ret = 0;
3289  for (char c: this->GetArgStr(index))
3290  {
3291  switch (c)
3292  {
3293  case (char)CabOption::n_DUMMY: break;
3294  case (char)CabOption::c_CONTACT: ret |= Cab::OPTION_c_CONTACT ; break;
3295  case (char)CabOption::b_BUOYANT: ret |= Cab::OPTION_b_BUOYANT ; break;
3296  case (char)CabOption::p_10xTOUGHER: ret |= Cab::OPTION_p_10xTOUGHER ; break;
3297  case (char)CabOption::u_INVULNERABLE: ret |= Cab::OPTION_u_INVULNERABLE ; break;
3298  case (char)CabOption::s_BUOYANT_NO_DRAG: ret |= Cab::OPTION_s_BUOYANT_NO_DRAG ; break;
3299  case (char)CabOption::r_BUOYANT_ONLY_DRAG: ret |= Cab::OPTION_r_BUOYANT_ONLY_DRAG ; break;
3300  case (char)CabOption::D_CONTACT_BUOYANT: ret |= Cab::OPTION_D_CONTACT_BUOYANT ; break;
3301  case (char)CabOption::F_10xTOUGHER_BUOYANT: ret |= Cab::OPTION_F_10xTOUGHER_BUOYANT ; break;
3302  case (char)CabOption::S_INVULNERABLE_BUOYANT: ret |= Cab::OPTION_S_INVULNERABLE_BUOYANT; break;
3303 
3304  default:
3305  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3306  fmt::format("ignoring invalid flag '{}'", c));
3307  }
3308  }
3309  return ret;
3310 }
3311 
3312 BitMask_t Parser::GetArgTriggerOptions(int index)
3313 {
3314  BitMask_t ret = 0;
3315  for (char c: this->GetArgStr(index))
3316  {
3317  switch(c)
3318  {
3319  case (char)TriggerOption::i_INVISIBLE : ret |= Trigger::OPTION_i_INVISIBLE; break;
3320  case (char)TriggerOption::c_COMMAND_STYLE : ret |= Trigger::OPTION_c_COMMAND_STYLE; break;
3321  case (char)TriggerOption::x_START_DISABLED : ret |= Trigger::OPTION_x_START_DISABLED; break;
3322  case (char)TriggerOption::b_KEY_BLOCKER : ret |= Trigger::OPTION_b_KEY_BLOCKER; break;
3323  case (char)TriggerOption::B_TRIGGER_BLOCKER : ret |= Trigger::OPTION_B_TRIGGER_BLOCKER; break;
3324  case (char)TriggerOption::A_INV_TRIGGER_BLOCKER: ret |= Trigger::OPTION_A_INV_TRIGGER_BLOCKER; break;
3325  case (char)TriggerOption::s_CMD_NUM_SWITCH : ret |= Trigger::OPTION_s_CMD_NUM_SWITCH; break;
3326  case (char)TriggerOption::h_UNLOCKS_HOOK_GROUP : ret |= Trigger::OPTION_h_UNLOCKS_HOOK_GROUP; break;
3327  case (char)TriggerOption::H_LOCKS_HOOK_GROUP : ret |= Trigger::OPTION_H_LOCKS_HOOK_GROUP; break;
3328  case (char)TriggerOption::t_CONTINUOUS : ret |= Trigger::OPTION_t_CONTINUOUS; break;
3329  case (char)TriggerOption::E_ENGINE_TRIGGER : ret |= Trigger::OPTION_E_ENGINE_TRIGGER; break;
3330 
3331  default:
3332  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3333  fmt::format("ignoring invalid option '{}'", c));
3334  }
3335  }
3336  return ret;
3337 }
3338 
3339 BitMask_t Parser::GetArgBeamOptions(int index)
3340 {
3341  BitMask_t ret = 0;
3342  for (char c: this->GetArgStr(index))
3343  {
3344  switch (c)
3345  {
3346  case (char)BeamOption::i_INVISIBLE: ret |= Beam::OPTION_i_INVISIBLE; break;
3347  case (char)BeamOption::r_ROPE : ret |= Beam::OPTION_r_ROPE ; break;
3348  case (char)BeamOption::s_SUPPORT : ret |= Beam::OPTION_s_SUPPORT ; break;
3349 
3350  case (char)BeamOption::v_DUMMY: break;
3351 
3352  default:
3353  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3354  fmt::format("ignoring invalid option '{}'", c));
3355  }
3356  }
3357  return ret;
3358 }
3359 
3360 BitMask_t Parser::GetArgHydroOptions (int index)
3361 {
3362  BitMask_t ret = 0;
3363  for (char c: this->GetArgStr(index))
3364  {
3365  switch (c)
3366  {
3367  case (char)HydroOption::j_INVISIBLE : ret |= Hydro::OPTION_j_INVISIBLE ; break;
3368  case (char)HydroOption::s_DISABLE_ON_HIGH_SPEED : ret |= Hydro::OPTION_s_DISABLE_ON_HIGH_SPEED ; break;
3369  case (char)HydroOption::a_INPUT_AILERON : ret |= Hydro::OPTION_a_INPUT_AILERON ; break;
3370  case (char)HydroOption::r_INPUT_RUDDER : ret |= Hydro::OPTION_r_INPUT_RUDDER ; break;
3371  case (char)HydroOption::e_INPUT_ELEVATOR : ret |= Hydro::OPTION_e_INPUT_ELEVATOR ; break;
3372  case (char)HydroOption::u_INPUT_AILERON_ELEVATOR : ret |= Hydro::OPTION_u_INPUT_AILERON_ELEVATOR ; break;
3373  case (char)HydroOption::v_INPUT_InvAILERON_ELEVATOR: ret |= Hydro::OPTION_v_INPUT_InvAILERON_ELEVATOR; break;
3374  case (char)HydroOption::x_INPUT_AILERON_RUDDER : ret |= Hydro::OPTION_x_INPUT_AILERON_RUDDER ; break;
3375  case (char)HydroOption::y_INPUT_InvAILERON_RUDDER : ret |= Hydro::OPTION_y_INPUT_InvAILERON_RUDDER ; break;
3376  case (char)HydroOption::g_INPUT_ELEVATOR_RUDDER : ret |= Hydro::OPTION_g_INPUT_ELEVATOR_RUDDER ; break;
3377  case (char)HydroOption::h_INPUT_InvELEVATOR_RUDDER : ret |= Hydro::OPTION_h_INPUT_InvELEVATOR_RUDDER ; break;
3378  case (char)HydroOption::n_INPUT_NORMAL : ret |= Hydro::OPTION_n_INPUT_NORMAL ; break;
3379 
3380  case (char)HydroOption::i_INVISIBLE_INPUT_NORMAL:
3381  if (ret == 0)
3382  {
3383  // Original intent: when using 'i' flag alone, also force 'n' (steering input).
3384  // For backward compatibility, do it every time 'i' comes first, even if not alone.
3385  ret |= Hydro::OPTION_n_INPUT_NORMAL;
3386  }
3387  ret |= Hydro::OPTION_j_INVISIBLE;
3388  break;
3389 
3390  default:
3391  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3392  fmt::format("ignoring invalid option '{}'", c));
3393  }
3394  }
3395 
3396  return ret;
3397 }
3398 
3399 BitMask_t Parser::GetArgShockOptions(int index)
3400 {
3401  BitMask_t ret = 0;
3402  for (char c: this->GetArgStr(index))
3403  {
3404  switch (c)
3405  {
3406  case (char)ShockOption::i_INVISIBLE : ret |= Shock::OPTION_i_INVISIBLE ; break;
3407  case (char)ShockOption::L_ACTIVE_LEFT : ret |= Shock::OPTION_L_ACTIVE_LEFT ; break;
3408  case (char)ShockOption::R_ACTIVE_RIGHT : ret |= Shock::OPTION_R_ACTIVE_RIGHT; break;
3409  case (char)ShockOption::m_METRIC : ret |= Shock::OPTION_m_METRIC ; break;
3410 
3411  case (char)ShockOption::n_DUMMY: break;
3412  case (char)ShockOption::v_DUMMY: break;
3413 
3414  default:
3415  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3416  fmt::format("ignoring invalid option '{}'", c));
3417  }
3418  }
3419  return ret;
3420 }
3421 
3422 BitMask_t Parser::GetArgShock2Options(int index)
3423 {
3424  BitMask_t ret = 0;
3425  for (char c: this->GetArgStr(index))
3426  {
3427  switch (c)
3428  {
3429  case (char)Shock2Option::i_INVISIBLE: ret |= Shock2::OPTION_i_INVISIBLE; break;
3430  case (char)Shock2Option::s_SOFT_BUMP_BOUNDS: ret |= Shock2::OPTION_s_SOFT_BUMP_BOUNDS; break;
3431  case (char)Shock2Option::m_METRIC: ret |= Shock2::OPTION_m_METRIC; break;
3432  case (char)Shock2Option::M_ABSOLUTE_METRIC: ret |= Shock2::OPTION_M_ABSOLUTE_METRIC; break;
3433 
3434  case (char)Shock2Option::n_DUMMY: break;
3435  case (char)Shock2Option::v_DUMMY: break;
3436 
3437  default:
3438  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3439  fmt::format("ignoring invalid option '{}'", c));
3440  }
3441  }
3442  return ret;
3443 }
3444 
3445 BitMask_t Parser::GetArgShock3Options(int index)
3446 {
3447  BitMask_t ret = 0;
3448  for (char c: this->GetArgStr(index))
3449  {
3450  switch (c)
3451  {
3452  case (char)Shock3Option::i_INVISIBLE: ret |= Shock3::OPTION_i_INVISIBLE; break;
3453  case (char)Shock3Option::m_METRIC: ret |= Shock3::OPTION_m_METRIC; break;
3454  case (char)Shock3Option::M_ABSOLUTE_METRIC: ret |= Shock3::OPTION_M_ABSOLUTE_METRIC; break;
3455 
3456  case (char)Shock3Option::n_DUMMY: break;
3457  case (char)Shock3Option::v_DUMMY: break;
3458 
3459  default:
3460  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3461  fmt::format("ignoring invalid option '{}'", c));
3462  }
3463  }
3464  return ret;
3465 }
3466 
3467 BitMask_t Parser::GetArgNodeOptions(int index)
3468 {
3469  BitMask_t ret = 0;
3470  for (char c: this->GetArgStr(index))
3471  {
3472  switch (c)
3473  {
3474  case (char)NodeOption::m_NO_MOUSE_GRAB : ret |= Node::OPTION_m_NO_MOUSE_GRAB ; break;
3475  case (char)NodeOption::f_NO_SPARKS : ret |= Node::OPTION_f_NO_SPARKS ; break;
3476  case (char)NodeOption::x_EXHAUST_POINT : ret |= Node::OPTION_x_EXHAUST_POINT ; break;
3477  case (char)NodeOption::y_EXHAUST_DIRECTION : ret |= Node::OPTION_y_EXHAUST_DIRECTION ; break;
3478  case (char)NodeOption::c_NO_GROUND_CONTACT : ret |= Node::OPTION_c_NO_GROUND_CONTACT ; break;
3479  case (char)NodeOption::h_HOOK_POINT : ret |= Node::OPTION_h_HOOK_POINT ; break;
3480  case (char)NodeOption::e_TERRAIN_EDIT_POINT: ret |= Node::OPTION_e_TERRAIN_EDIT_POINT; break;
3481  case (char)NodeOption::b_EXTRA_BUOYANCY : ret |= Node::OPTION_b_EXTRA_BUOYANCY ; break;
3482  case (char)NodeOption::p_NO_PARTICLES : ret |= Node::OPTION_p_NO_PARTICLES ; break;
3483  case (char)NodeOption::L_LOG : ret |= Node::OPTION_L_LOG ; break;
3484  case (char)NodeOption::l_LOAD_WEIGHT : ret |= Node::OPTION_l_LOAD_WEIGHT ; break;
3485 
3486  case (char)NodeOption::n_DUMMY: break;
3487 
3488  default:
3489  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3490  fmt::format("ignoring invalid option '{}'", c));
3491  }
3492  }
3493  return ret;
3494 }
3495 
3496 SpecialProp Parser::IdentifySpecialProp(const std::string& str)
3497 {
3498  if (str.find("leftmirror" ) != std::string::npos) { return SpecialProp::MIRROR_LEFT; }
3499  if (str.find("rightmirror" ) != std::string::npos) { return SpecialProp::MIRROR_RIGHT; }
3500  if (str.find("dashboard-rh") != std::string::npos) { return SpecialProp::DASHBOARD_RIGHT; }
3501  if (str.find("dashboard" ) != std::string::npos) { return SpecialProp::DASHBOARD_LEFT; }
3502  if (Ogre::StringUtil::startsWith(str, "spinprop", false) ) { return SpecialProp::AERO_PROP_SPIN; }
3503  if (Ogre::StringUtil::startsWith(str, "pale", false) ) { return SpecialProp::AERO_PROP_BLADE; }
3504  if (Ogre::StringUtil::startsWith(str, "seat", false) ) { return SpecialProp::DRIVER_SEAT; }
3505  if (Ogre::StringUtil::startsWith(str, "seat2", false) ) { return SpecialProp::DRIVER_SEAT_2; }
3506  if (Ogre::StringUtil::startsWith(str, "beacon", false) ) { return SpecialProp::BEACON; }
3507  if (Ogre::StringUtil::startsWith(str, "redbeacon", false)) { return SpecialProp::REDBEACON; }
3508  if (Ogre::StringUtil::startsWith(str, "lightb", false) ) { return SpecialProp::LIGHTBAR; }
3509  return SpecialProp::NONE;
3510 }
3511 
3512 int Parser::GetArgDashboardInputDataType(int index)
3513 {
3514  std::string str = this->GetArgStr(index);
3515  if (str == "bool") return DC_BOOL;
3516  if (str == "int") return DC_INT;
3517  if (str == "float") return DC_FLOAT;
3518  if (str == "string") return DC_CHAR;
3519 
3520  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3521  fmt::format("Not a valid dashboard input data type: '{}'", str));
3522  return DC_INVALID;
3523 }
3524 
3525 EngineType Parser::GetArgEngineType(int index)
3526 {
3527  char c = this->GetArgChar(index);
3528  switch (c)
3529  {
3530  case (char)EngineType::t_TRUCK:
3531  case (char)EngineType::c_CAR:
3532  case (char)EngineType::e_ECAR:
3533  return EngineType(c);
3534 
3535  default:
3536  fmt::format("invalid EngineType '{}', falling back to 't' (truck)", c);
3537  return EngineType::t_TRUCK;
3538  }
3539 }
3540 
3541 ManagedMaterialType Parser::GetArgManagedMatType(int index)
3542 {
3543  std::string str = this->GetArgStr(index);
3544  if (str == "mesh_standard") return ManagedMaterialType::MESH_STANDARD;
3545  if (str == "mesh_transparent") return ManagedMaterialType::MESH_TRANSPARENT;
3546  if (str == "flexmesh_standard") return ManagedMaterialType::FLEXMESH_STANDARD;
3547  if (str == "flexmesh_transparent") return ManagedMaterialType::FLEXMESH_TRANSPARENT;
3548 
3549  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3550  fmt::format("Not a valid ManagedMaterialType: '{}'", str));
3551  return ManagedMaterialType::INVALID;
3552 }
3553 
3554 VideoCamRole Parser::GetArgVideoCamRole(int index)
3555 {
3556  int role = this->GetArgInt(index);
3557  switch (role)
3558  {
3561  case VCAM_ROLE_MIRROR: return VCAM_ROLE_MIRROR;
3563  default:
3564  this->LogMessage(Console::CONSOLE_SYSTEM_WARNING,
3565  fmt::format("Invalid value of 'camera role' ({}), videocamera will not work", role));
3566  return VCAM_ROLE_INVALID;
3567  }
3568 }
3569 
3570 int Parser::TokenizeCurrentLine()
3571 {
3572  int cur_arg = 0;
3573  const char* cur_char = m_current_line;
3574  int arg_len = 0;
3575  while ((*cur_char != '\0') && (cur_arg < Parser::LINE_MAX_ARGS))
3576  {
3577  const bool is_arg = !IsSeparator(*cur_char);
3578  if ((arg_len == 0) && is_arg)
3579  {
3580  m_args[cur_arg].start = cur_char;
3581  arg_len = 1;
3582  }
3583  else if ((arg_len > 0) && !is_arg)
3584  {
3585  m_args[cur_arg].length = arg_len;
3586  arg_len = 0;
3587  ++cur_arg;
3588  }
3589  else if (is_arg)
3590  {
3591  ++arg_len;
3592  }
3593  ++cur_char;
3594  }
3595  if (arg_len > 0)
3596  {
3597  m_args[cur_arg].length = arg_len;
3598  ++cur_arg;
3599  }
3600 
3601  m_num_args = cur_arg;
3602  return cur_arg;
3603 }
3604 
3605 void Parser::ProcessOgreStream(Ogre::DataStream* stream, Ogre::String resource_group)
3606 {
3607  m_resource_group = resource_group;
3608  m_filename = stream->getName();
3609 
3610  char raw_line_buf[LINE_BUFFER_LENGTH];
3611  while (!stream->eof())
3612  {
3613  try
3614  {
3615  stream->readLine(raw_line_buf, LINE_BUFFER_LENGTH - 1); // Ensure we don't overflow
3616  raw_line_buf[LINE_BUFFER_LENGTH - 1] = '\0'; // Null-terminate the buffer
3617  }
3618  catch (Ogre::Exception &ex)
3619  {
3621  fmt::format("Could not read truck file: {}", ex.getFullDescription()));
3622  break;
3623  }
3624 
3625  this->ProcessRawLine(raw_line_buf);
3626  }
3627 }
3628 
3629 void Parser::ProcessRawLine(const char* raw_line_buf)
3630 {
3631  const char* raw_start = raw_line_buf;
3632  const char* raw_end = raw_line_buf + strnlen(raw_line_buf, LINE_BUFFER_LENGTH);
3633 
3634  // Trim leading whitespace
3635  while (IsWhitespace(*raw_start) && (raw_start != raw_end))
3636  {
3637  ++raw_start;
3638  }
3639 
3640  // Skip empty lines
3641  if (raw_start == raw_end)
3642  {
3643  ++m_current_line_number;
3644  return;
3645  }
3646 
3647  // Record comment lines
3648  if ((*raw_start == ';') || (*raw_start == '/'))
3649  {
3650  m_pending_doc_comment.comment_text += raw_line_buf;
3651  m_pending_doc_comment.comment_text += '\n';
3652  ++m_current_line_number;
3653  return;
3654  }
3655 
3656  // Sanitize UTF-8
3657  memset(m_current_line, 0, LINE_BUFFER_LENGTH);
3658  char* out_start = m_current_line;
3659  utf8::replace_invalid(raw_start, raw_end, out_start, '?');
3660 
3661  // Process
3662  this->ProcessCurrentLine();
3663  ++m_current_line_number;
3664 }
3665 
3666 } // namespace RigDef
RigDef::Command2::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:641
RigDef::InterAxle::options
DifferentialTypeVec options
Order matters!
Definition: RigDef_File.h:894
RigDef::Engine::shift_up_rpm
float shift_up_rpm
Definition: RigDef_File.h:678
RigDef::Shock2::spring_out
float spring_out
spring value applied when shock extending
Definition: RigDef_File.h:1105
RigDef::Keyword::SPEEDLIMITER
@ SPEEDLIMITER
RigDef::FlexBodyWheel::rim_springiness
float rim_springiness
Definition: RigDef_File.h:803
RigDef::Shock3::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:1140
RoR::WheelBraking
WheelBraking
Definition: Application.h:525
RigDef::Airbrake::texcoord_x1
float texcoord_x1
Definition: RigDef_File.h:334
RigDef::SlideNode::constraint_flags
BitMask_t constraint_flags
Definition: RigDef_File.h:1159
RigDef::Engoption::min_idle_mixture
float min_idle_mixture
Definition: RigDef_File.h:697
RoR::WheelSide
WheelSide
Used by rig-def/addonpart/tuneup formats to specify wheel rim mesh orientation.
Definition: Application.h:546
RigDef::Wing::tex_coords
float tex_coords[8]
Definition: RigDef_File.h:1356
RigDef::DocComment
< Represents a comment (line starting with ';' or '//') that can be anywhere in the file.
Definition: RigDef_File.h:311
RigDef::Keyword::TEXCOORDS
@ TEXCOORDS
RigDef::MinimassOption
MinimassOption
Definition: RigDef_File.h:107
RigDef::MaterialFlareBinding::material_name
Ogre::String material_name
Definition: RigDef_File.h:927
RigDef::Shock3::damp_out_fast
float damp_out_fast
Damping value applied when shock is commpressing faster than split out velocity.
Definition: RigDef_File.h:1135
RigDef::Prop::DashboardSpecial::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:982
RigDef::Animation::MotorSource
Definition: RigDef_File.h:343
RigDef::Beam::extension_break_limit
float extension_break_limit
Definition: RigDef_File.h:499
RigDef::VideoCamera::left_node
Node::Ref left_node
Definition: RigDef_File.h:1313
RigDef::Turboprop2::blade_tip_nodes
Node::Ref blade_tip_nodes[4]
Definition: RigDef_File.h:1304
RigDef::BaseWheel2::rim_radius
float rim_radius
Definition: RigDef_File.h:292
RigDef::Wheel
Definition: RigDef_File.h:1330
RoR::FlareType::FOG_LIGHT
@ FOG_LIGHT
RigDef::SlideNode::_railgroup_id_set
bool _railgroup_id_set
Definition: RigDef_File.h:1166
RigDef::GuiSettings
Definition: RigDef_File.h:833
RigDef::SlideNode::tolerance
float tolerance
Definition: RigDef_File.h:1164
RigDef::Turboprop2::axis_node
Node::Ref axis_node
Definition: RigDef_File.h:1303
BEAM_SKELETON_DIAMETER
static const float BEAM_SKELETON_DIAMETER
Definition: SimConstants.h:57
RigDef::Rope::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:1030
RigDef::ExtCamera::node
Node::Ref node
Definition: RigDef_File.h:731
RigDef::InterAxle::a2
int a2
Definition: RigDef_File.h:893
RigDef::Node::Ref
Legacy parser resolved references on-the-fly and the condition to check named nodes was "are there an...
Definition: RigDef_Node.h:77
RoR::DC_FLOAT
@ DC_FLOAT
Definition: DashBoardManager.h:64
RigDef::Command2::inertia_defaults
std::shared_ptr< Inertia > inertia_defaults
Definition: RigDef_File.h:642
RigDef::Hydro::inertia
Inertia inertia
Definition: RigDef_File.h:884
RigDef::Command2::option_f_not_faster
bool option_f_not_faster
Definition: RigDef_File.h:648
RigDef::Prop
Definition: RigDef_File.h:971
RigDef::WheelDetacher::wheel_id
int wheel_id
Definition: RigDef_File.h:1349
Keyword
Keyword
Definition: Bench_TruckParser_IdentifyKeyword.cpp:6
RigDef::FlareBase::dashboard_link
std::string dashboard_link
Only 'd' type flares.
Definition: RigDef_File.h:754
RoR::VCAM_ROLE_TRACKING_VIDEOCAM
@ VCAM_ROLE_TRACKING_VIDEOCAM
Definition: Application.h:599
RigDef::BeamDefaultsScale::breaking_threshold_constant
float breaking_threshold_constant
Definition: RigDef_File.h:517
RigDef::Keyword::FUSEDRAG
@ FUSEDRAG
RigDef::Tie::group
int group
Definition: RigDef_File.h:1220
RigDef::TractionControl::fade_speed
float fade_speed
Definition: RigDef_File.h:1246
RigDef::Hydro::inertia_defaults
std::shared_ptr< Inertia > inertia_defaults
Definition: RigDef_File.h:885
RigDef::Prop::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:1002
RigDef::Camera::left_node
Node::Ref left_node
Definition: RigDef_File.h:593
RigDef::Engine::neutral_gear_ratio
float neutral_gear_ratio
Definition: RigDef_File.h:682
RigDef::Brakes::default_braking_force
float default_braking_force
Definition: RigDef_File.h:569
RigDef::Command2::option_o_1press_center
bool option_o_1press_center
Definition: RigDef_File.h:650
RigDef::SpecialProp
SpecialProp
Definition: RigDef_File.h:62
RigDef::Cinecam::position
Ogre::Vector3 position
Definition: RigDef_File.h:608
RigDef::Cinecam::node_defaults
std::shared_ptr< NodeDefaults > node_defaults
Definition: RigDef_File.h:614
RigDef::FlaregroupNoImport::control_number
int control_number
Only 'u' type flares.
Definition: RigDef_File.h:772
RigDef::VideoCamera::min_clip_distance
float min_clip_distance
Definition: RigDef_File.h:1322
RigDef::Animation::lower_limit
float lower_limit
Definition: RigDef_File.h:410
RigDef::Wing::control_surface
WingControlSurface control_surface
Definition: RigDef_File.h:1357
RigDef::Rotator::needs_engine
bool needs_engine
Definition: RigDef_File.h:1045
RigDef::CollisionRange
Definition: RigDef_File.h:622
RigDef::ManagedMaterial::diffuse_map
Ogre::String diffuse_map
Definition: RigDef_File.h:917
RigDef::Hook::option_hookgroup
int option_hookgroup
Definition: RigDef_File.h:852
RigDef::TractionControl::attr_no_dashboard
bool attr_no_dashboard
Definition: RigDef_File.h:1249
RigDef::Animation::MotorSource::motor
unsigned int motor
Definition: RigDef_File.h:355
RigDef::Inertia::start_function
Ogre::String start_function
Definition: RigDef_File.h:307
RigDef::IsSeparator
bool IsSeparator(char c)
Definition: RigDef_Parser.cpp:55
RigDef::Engturbo
Definition: RigDef_File.h:701
RigDef::Keyword::BRAKES
@ BRAKES
RigDef::VideoCamera::texture_width
unsigned int texture_width
Definition: RigDef_File.h:1320
RigDef::Animator::long_limit
float long_limit
Definition: RigDef_File.h:457
RigDef::Node::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_Node.h:165
RoR::VCAM_ROLE_INVALID
@ VCAM_ROLE_INVALID
Definition: Application.h:610
RigDef::Keyword::TRANSFERCASE
@ TRANSFERCASE
RigDef::Author
Definition: RigDef_File.h:476
RigDef::Engoption::post_shift_time
float post_shift_time
Seconds.
Definition: RigDef_File.h:693
RigDef::Shock::long_bound
float long_bound
Maximum extension. The longest length a shock can be, as a proportion of its original length....
Definition: RigDef_File.h:1084
RigDef::SoundSource2::mode
int mode
A special constant or cinecam index.
Definition: RigDef_File.h:1181
RigDef::Airbrake::texcoord_y1
float texcoord_y1
Definition: RigDef_File.h:336
RigDef::Engoption::shift_time
float shift_time
Seconds.
Definition: RigDef_File.h:691
RigDef::Animation
Definition: RigDef_File.h:341
BEAM_DEFORM
static const float BEAM_DEFORM
Definition: SimConstants.h:61
RigDef::AntiLockBrakes::attr_no_dashboard
bool attr_no_dashboard
Definition: RigDef_File.h:472
RigDef::Keyword::GUID
@ GUID
RigDef::Command2::max_extension
float max_extension
Definition: RigDef_File.h:633
RigDef::Animator::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:453
RigDef::Engine::gear_ratios
std::vector< float > gear_ratios
Definition: RigDef_File.h:683
RigDef::Tie::auto_shorten_rate
float auto_shorten_rate
Definition: RigDef_File.h:1213
RigDef::MaterialFlareBinding::flare_number
unsigned int flare_number
Definition: RigDef_File.h:926
RoR::DC_BOOL
@ DC_BOOL
Definition: DashBoardManager.h:62
DashBoardManager.h
RigDef::Tie::min_length
float min_length
Definition: RigDef_File.h:1214
RigDef::Node::Id::SetNum
void SetNum(unsigned int id_num)
Definition: RigDef_Node.cpp:55
RigDef::Turboprop2::airfoil
Ogre::String airfoil
Definition: RigDef_File.h:1306
RigDef::Flare3
Definition: RigDef_File.h:764
RigDef::Prop::DashboardSpecial::mesh_name
Ogre::String mesh_name
Definition: RigDef_File.h:985
RigDef::FlaregroupNoImport::type
RoR::FlareType type
Definition: RigDef_File.h:771
RigDef::SkeletonSettings
Definition: RigDef_File.h:1144
RigDef::SpeedLimiter::is_enabled
bool is_enabled
Definition: RigDef_File.h:1187
RigDef::Engine::global_gear_ratio
float global_gear_ratio
Definition: RigDef_File.h:680
RigDef::Texcoord::node
Node::Ref node
Definition: RigDef_File.h:1201
RigDef::RailGroup
Definition: RigDef_File.h:1012
RigDef::Shock3::split_vel_out
float split_vel_out
Split velocity in (m/s) - threshold for slow / fast damping during extension.
Definition: RigDef_File.h:1134
RoR::FlareType::TAIL_LIGHT
@ TAIL_LIGHT
RigDef::VideoCamera::camera_mode
int camera_mode
Definition: RigDef_File.h:1325
RigDef::Hook::flag_auto_lock
bool flag_auto_lock
Definition: RigDef_File.h:857
RigDef::Engturbo::param3
float param3
Definition: RigDef_File.h:710
RigDef::Assetpack::filename
std::string filename
Definition: RigDef_File.h:262
RigDef::Fusedrag::approximate_width
float approximate_width
Definition: RigDef_File.h:816
RigDef::Command2::detacher_group
int detacher_group
Definition: RigDef_File.h:643
RigDef::Prop::rotation
Ogre::Vector3 rotation
Definition: RigDef_File.h:1003
RigDef::Fusedrag::autocalc
bool autocalc
Definition: RigDef_File.h:813
RigDef::Engturbo::version
int version
Definition: RigDef_File.h:705
RigDef::ManagedMaterial::damaged_diffuse_map
Ogre::String damaged_diffuse_map
Definition: RigDef_File.h:918
RigDef::Engoption::type
EngineType type
Definition: RigDef_File.h:689
RigDef::Rotator::rate
float rate
Definition: RigDef_File.h:1039
RigDef::Wheel::radius
float radius
Definition: RigDef_File.h:1332
format
Truck file format(technical spec)
RigDef::BeamDefaults::deformation_threshold
float deformation_threshold
Definition: RigDef_File.h:556
RigDef::Screwprop::back_node
Node::Ref back_node
Definition: RigDef_File.h:1058
RigDef::Keyword::HOOKS
@ HOOKS
RigDef::Particle::particle_system_name
Ogre::String particle_system_name
Definition: RigDef_File.h:957
RigDef::Camera
Definition: RigDef_File.h:589
RigDef::Hydro
Definition: RigDef_File.h:863
RigDef::Shock::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:1087
RigDef::FlareBase::size
float size
Definition: RigDef_File.h:756
RoR::WheelBraking::NONE
@ NONE
= no footbrake, no handbrake, no direction control – wheel is unbraked
RigDef::CollisionBox
Definition: RigDef_File.h:617
RigDef::SlideNode::break_force
float break_force
Definition: RigDef_File.h:1163
RigDef::Command2::shorten_rate
float shorten_rate
Definition: RigDef_File.h:630
RigDef::Ropable
Definition: RigDef_File.h:1018
RigDef::Trigger::longbound_trigger_action
int longbound_trigger_action
Definition: RigDef_File.h:1284
RoR::WheelBraking::FOOT_ONLY
@ FOOT_ONLY
= yes footbrake, no handbrake, no direction control – footbrake only, such as with the front wheels o...
RigDef::SlideNode::attachment_rate
float attachment_rate
Definition: RigDef_File.h:1165
RigDef::BaseMeshWheel::side
RoR::WheelSide side
Definition: RigDef_File.h:281
RoR::WheelSide::RIGHT
@ RIGHT
RigDef::SoundSource::node
Node::Ref node
Definition: RigDef_File.h:1172
RigDef::Wing::chord_point
float chord_point
Definition: RigDef_File.h:1358
RigDef::Keyword::GLOBALS
@ GLOBALS
RigDef::Shock2::spring_in
float spring_in
Spring value applied when the shock is compressing.
Definition: RigDef_File.h:1101
RigDef::BaseWheel::width
float width
Definition: RigDef_File.h:267
RigDef::Flexbody::rotation
Ogre::Vector3 rotation
Definition: RigDef_File.h:791
RigDef::Airbrake
Definition: RigDef_File.h:322
RigDef::Keyword::INTERAXLES
@ INTERAXLES
SimConstants.h
RigDef::Flexbody::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:790
RigDef::Tie::options
BitMask_t options
Definition: RigDef_File.h:1216
RigDef::Flare2
Definition: RigDef_File.h:760
RigDef::Help
Definition: RigDef_File.h:839
RigDef::DifferentialType
DifferentialType
Definition: RigDef_File.h:97
RigDef::SlideNode::rail_node_ranges
std::vector< Node::Range > rail_node_ranges
Definition: RigDef_File.h:1158
RigDef::GuiSettings::key
std::string key
Definition: RigDef_File.h:835
RigDef::Cinecam::spring
float spring
Definition: RigDef_File.h:610
RigDef::Trigger
Definition: RigDef_File.h:1262
RigDef::CollisionBox::nodes
std::vector< Node::Ref > nodes
Definition: RigDef_File.h:619
RigDef::Shock3::precompression
float precompression
Changes compression or extension of the suspension when the truck spawns. This can be used to "level"...
Definition: RigDef_File.h:1138
RigDef::Engturbo::param8
float param8
Definition: RigDef_File.h:715
RigDef::BeamDefaults::springiness
float springiness
Definition: RigDef_File.h:554
Console.h
RigDef::Command2::description
Ogre::String description
Definition: RigDef_File.h:636
RoR::Console::putMessage
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition: Console.cpp:103
DEFAULT_BEAM_DIAMETER
static const float DEFAULT_BEAM_DIAMETER
5 centimeters default beam width
Definition: SimConstants.h:52
RigDef::CustomDashboardInput::name
Ogre::String name
Definition: RigDef_File.h:661
RigDef::Pistonprop
Definition: RigDef_File.h:960
RoR::VCAM_ROLE_VIDEOCAM
@ VCAM_ROLE_VIDEOCAM
Definition: Application.h:598
RigDef::Trigger::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:1276
RigDef::Axle::wheels
Node::Ref wheels[2][2]
Definition: RigDef_File.h:487
RigDef::Rotator::spin_right_key
unsigned int spin_right_key
Definition: RigDef_File.h:1041
RoR::DC_INVALID
@ DC_INVALID
Definition: DashBoardManager.h:66
RigDef::Keyword::ENGOPTION
@ ENGOPTION
RigDef::Screwprop::power
float power
Definition: RigDef_File.h:1060
RigDef::BeamDefaults
Definition: RigDef_File.h:520
RigDef::BaseWheel::propulsion
RoR::WheelPropulsion propulsion
Definition: RigDef_File.h:272
RigDef::Shock::detacher_group
int detacher_group
Definition: RigDef_File.h:1088
RigDef::FlaregroupNoImport
Definition: RigDef_File.h:769
BEAM_PLASTIC_COEF_DEFAULT
static const float BEAM_PLASTIC_COEF_DEFAULT
Definition: SimConstants.h:63
RigDef::VideoCamera::rotation
Ogre::Vector3 rotation
Definition: RigDef_File.h:1318
RigDef::Airbrake::y_axis_node
Node::Ref y_axis_node
Definition: RigDef_File.h:328
RigDef::FlexBodyWheel
Definition: RigDef_File.h:800
RigDef::Turboprop2::turbine_power_kW
float turbine_power_kW
Definition: RigDef_File.h:1305
RigDef::SlideNode::_spring_rate_set
bool _spring_rate_set
Definition: RigDef_File.h:1162
RigDef::Tie::detacher_group
int detacher_group
Definition: RigDef_File.h:1219
RigDef::Engturbo::param6
float param6
Definition: RigDef_File.h:713
RigDef::Particle
Definition: RigDef_File.h:953
RigDef::Engine::shift_down_rpm
float shift_down_rpm
Definition: RigDef_File.h:677
RigDef::Texcoord::v
float v
Definition: RigDef_File.h:1203
RigDef::Node::Range
Definition: RigDef_Node.h:114
RigDef::CameraRail
Definition: RigDef_File.h:596
RigDef::Animator::detacher_group
int detacher_group
Definition: RigDef_File.h:461
RigDef::Engoption::braking_torque
float braking_torque
Definition: RigDef_File.h:698
RigDef::SkeletonSettings::beam_thickness_meters
float beam_thickness_meters
Definition: RigDef_File.h:1147
Utils.h
RigDef::Flexbody::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:787
RigDef::BeamDefaults::breaking_threshold
float breaking_threshold
Definition: RigDef_File.h:557
RigDef::ManagedMaterialType
ManagedMaterialType
Definition: RigDef_File.h:78
RigDef::Animator::short_limit
float short_limit
Definition: RigDef_File.h:456
RigDef::SlideNode::_tolerance_set
bool _tolerance_set
Definition: RigDef_File.h:1164
RoR::DC_CHAR
@ DC_CHAR
Definition: DashBoardManager.h:65
RigDef::Wheel::damping
float damping
Definition: RigDef_File.h:1334
RigDef::Shock2::long_bound
float long_bound
Maximum extension limit, in percentage ( 1.00 = 100% )
Definition: RigDef_File.h:1110
RigDef::WingControlSurface
WingControlSurface
Definition: RigDef_File.h:113
RigDef::Node::Ref::IsValidAnyState
bool IsValidAnyState() const
Definition: RigDef_Node.h:101
RigDef::BeamDefaults::_is_plastic_deform_coef_user_defined
bool _is_plastic_deform_coef_user_defined
Definition: RigDef_File.h:562
RigDef::Rotator::axis_nodes
Node::Ref axis_nodes[2]
Definition: RigDef_File.h:1036
RigDef::Trigger::options
BitMask_t options
Definition: RigDef_File.h:1279
RigDef::NodeDefaults
Definition: RigDef_File.h:942
RigDef::Hook
Definition: RigDef_File.h:844
RigDef::Hydro::options
BitMask_t options
Definition: RigDef_File.h:883
RigDef::Pistonprop::airfoil
Ogre::String airfoil
Definition: RigDef_File.h:968
RoR::Console::CONSOLE_SYSTEM_ERROR
@ CONSOLE_SYSTEM_ERROR
Definition: Console.h:52
RigDef::AntiLockBrakes
Definition: RigDef_File.h:464
RigDef::InterAxle::a1
int a1
Definition: RigDef_File.h:892
RigDef::Tie::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:1218
RoR::WheelBraking::FOOT_HAND
@ FOOT_HAND
= yes footbrake, yes handbrake, no direction control
RigDef::CustomDashboardInput
Definition: RigDef_File.h:659
RigDef::FlareBase::control_number
int control_number
Only 'u' type flares.
Definition: RigDef_File.h:753
RigDef::TorqueCurve::Sample
Definition: RigDef_File.h:1225
RigDef::Ropable::has_multilock
bool has_multilock
Definition: RigDef_File.h:1022
RigDef::Keyword::AXLES
@ AXLES
Actor.h
RigDef::Ropable::node
Node::Ref node
Definition: RigDef_File.h:1020
RigDef::TractionControl::pulse_per_sec
float pulse_per_sec
Definition: RigDef_File.h:1247
RigDef::Command2::extend_key
RoR::CommandkeyID_t extend_key
Definition: RigDef_File.h:635
RigDef::Shock3::damp_in
float damp_in
Damping value applied when the shock is compressing.
Definition: RigDef_File.h:1127
RigDef::Shock2::damp_out
float damp_out
damping value applied when shock extending
Definition: RigDef_File.h:1106
RigDef::Engoption::clutch_time
float clutch_time
Seconds.
Definition: RigDef_File.h:692
RigDef::Shock3::spring_out
float spring_out
Spring value applied when shock extending.
Definition: RigDef_File.h:1128
RigDef::Brakes
Definition: RigDef_File.h:567
RigDef::Command2
Definition: RigDef_File.h:627
RigDef::Tie::max_stress
float max_stress
Definition: RigDef_File.h:1217
RigDef::SlideNode::max_attach_dist
float max_attach_dist
Definition: RigDef_File.h:1167
RigDef::Engturbo::param9
float param9
Definition: RigDef_File.h:716
RigDef::SoundSource2
Definition: RigDef_File.h:1176
RoR::WheelPropulsion::BACKWARD
@ BACKWARD
BEAM_BREAK
static const float BEAM_BREAK
Definition: SimConstants.h:60
RigDef::Particle::emitter_node
Node::Ref emitter_node
Definition: RigDef_File.h:955
RigDef::Author::name
Ogre::String name
Definition: RigDef_File.h:480
RigDef::Command2::option_r_rope
bool option_r_rope
Definition: RigDef_File.h:646
RigDef::VideoCamera::camera_role
RoR::VideoCamRole camera_role
Definition: RigDef_File.h:1324
RigDef::BaseMeshWheel::rim_radius
float rim_radius
Definition: RigDef_File.h:284
RigDef::FlexBodyWheel::tyre_mesh_name
Ogre::String tyre_mesh_name
Definition: RigDef_File.h:806
RigDef::FlareBase::node_axis_x
Node::Ref node_axis_x
Definition: RigDef_File.h:749
RigDef::Node::position
Ogre::Vector3 position
Definition: RigDef_Node.h:159
RigDef::Fileinfo
Definition: RigDef_File.h:739
RigDef::Shock::short_bound
float short_bound
Maximum contraction. The shortest length the shock can be, as a proportion of its original length....
Definition: RigDef_File.h:1083
RigDef::BeamDefaults::damping_constant
float damping_constant
Definition: RigDef_File.h:555
RoR::FlareType::BLINKER_LEFT
@ BLINKER_LEFT
RigDef::BaseMeshWheel::spring
float spring
Definition: RigDef_File.h:286
RigDef::VideoCamera::alt_reference_node
Node::Ref alt_reference_node
Definition: RigDef_File.h:1315
RigDef::AeroAnimator::flags
BitMask_t flags
Definition: RigDef_File.h:256
RigDef::Shock::spring_rate
float spring_rate
The 'stiffness' of the shock. The higher the value, the less the shock will move for a given bump.
Definition: RigDef_File.h:1081
RigDef::Fileinfo::unique_id
Ogre::String unique_id
Definition: RigDef_File.h:741
RigDef::Engoption::max_idle_mixture
float max_idle_mixture
Definition: RigDef_File.h:696
RigDef::Keyword::WINGS
@ WINGS
RigDef::FlareBase::blink_delay_milis
int blink_delay_milis
Definition: RigDef_File.h:755
RigDef::BeamDefaults::_enable_advanced_deformation
bool _enable_advanced_deformation
Informs whether "enable_advanced_deformation" directive preceded these defaults.
Definition: RigDef_File.h:561
RoR::ExtCameraMode::CINECAM
@ CINECAM
RigDef::Command2::option_p_1press
bool option_p_1press
Definition: RigDef_File.h:649
RigDef::Command2::inertia
Inertia inertia
Definition: RigDef_File.h:637
RigDef::ManagedMaterial::type
ManagedMaterialType type
Definition: RigDef_File.h:915
RigDef::Command2::plays_sound
bool plays_sound
Definition: RigDef_File.h:640
PARSEINT
#define PARSEINT(x)
Definition: Application.h:58
RigDef::ManagedMaterial::options
ManagedMaterialsOptions options
Definition: RigDef_File.h:916
RigDef::ManagedMaterial::name
Ogre::String name
Definition: RigDef_File.h:914
RigDef::Prop::special
SpecialProp special
Definition: RigDef_File.h:1007
RigDef::Screwprop::top_node
Node::Ref top_node
Definition: RigDef_File.h:1059
RigDef::AntiLockBrakes::attr_no_toggle
bool attr_no_toggle
Definition: RigDef_File.h:473
RigDef::Wheel2::rim_damping
float rim_damping
Definition: RigDef_File.h:1342
RigDef::BaseWheel::mass
float mass
Definition: RigDef_File.h:274
RigDef::Camera::back_node
Node::Ref back_node
Definition: RigDef_File.h:592
RigDef::Forvert::node_x
Node::Ref node_x
Definition: RigDef_File.h:779
RigDef::Pistonprop::couple_node
Node::Ref couple_node
Definition: RigDef_File.h:965
RigDef::Node::_has_load_weight_override
bool _has_load_weight_override
Definition: RigDef_Node.h:162
RigDef::Engoption
Definition: RigDef_File.h:686
RigDef::FlareBase::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:748
RigDef::Turbojet::front_node
Node::Ref front_node
Definition: RigDef_File.h:1289
RigDef::Turbojet::back_diameter
float back_diameter
Definition: RigDef_File.h:1296
RigDef::Beam::_has_extension_break_limit
bool _has_extension_break_limit
Definition: RigDef_File.h:500
RigDef::CruiseControl::min_speed
float min_speed
Definition: RigDef_File.h:655
RigDef::Keyword::FLARES3
@ FLARES3
RigDef::Author::_has_forum_account
bool _has_forum_account
Definition: RigDef_File.h:482
RigDef::Turboprop2::couple_node
Node::Ref couple_node
Definition: RigDef_File.h:1307
RigDef::AntiLockBrakes::min_speed
unsigned int min_speed
Definition: RigDef_File.h:469
RigDef::BaseWheel::braking
RoR::WheelBraking braking
Definition: RigDef_File.h:271
RigDef::VideoCamera::texture_height
unsigned int texture_height
Definition: RigDef_File.h:1321
RigDef::SlideNode::spring_rate
float spring_rate
Definition: RigDef_File.h:1162
RigDef::Globals::dry_mass
float dry_mass
Definition: RigDef_File.h:823
RigDef::Wheel2::band_material_name
Ogre::String band_material_name
Definition: RigDef_File.h:1344
RigDef::Shock2
Definition: RigDef_File.h:1091
RigDef::BaseWheel::num_rays
unsigned int num_rays
Definition: RigDef_File.h:268
RoR::ExtCameraMode
ExtCameraMode
Definition: Application.h:555
RigDef::Inertia::stop_delay_factor
float stop_delay_factor
Definition: RigDef_File.h:306
RigDef::DefaultMinimass
Definition: RigDef_File.h:665
RigDef::Pistonprop::axis_node
Node::Ref axis_node
Definition: RigDef_File.h:963
RigDef::BaseWheel::rigidity_node
Node::Ref rigidity_node
Definition: RigDef_File.h:270
CacheSystem.h
A database of user-installed content alias 'mods' (vehicles, terrains...)
RigDef::Forvert
Manually specified (vert => node) bindings for flexbody deformation (overrides 'forset').
Definition: RigDef_File.h:776
RigDef::Hydro::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:881
RigDef::FileFormatVersion
Definition: RigDef_File.h:734
keyword
static int keyword
Definition: Bench_TruckParser_IdentifyKeyword.cpp:1448
RigDef
Definition: Application.cpp:706
RigDef::Keyword::WHEELDETACHERS
@ WHEELDETACHERS
RigDef::Node::load_weight_override
float load_weight_override
Definition: RigDef_Node.h:161
RigDef::Wheel2
Definition: RigDef_File.h:1339
RigDef::CruiseControl::autobrake
int autobrake
Definition: RigDef_File.h:656
RigDef::TractionControl
Definition: RigDef_File.h:1240
BITMASK_IS_1
#define BITMASK_IS_1(VAR, FLAGS)
Definition: BitFlags.h:14
RigDef::SlideNode::slide_node
Node::Ref slide_node
Definition: RigDef_File.h:1157
RigDef::Rotator::inertia_defaults
std::shared_ptr< Inertia > inertia_defaults
Definition: RigDef_File.h:1043
RigDef::Help::material
std::string material
Definition: RigDef_File.h:841
RigDef::Wing::max_deflection
float max_deflection
Definition: RigDef_File.h:1360
RigDef::Node::id
Id id
Definition: RigDef_Node.h:158
RigDef::VideoCamera::alt_orientation_node
Node::Ref alt_orientation_node
Definition: RigDef_File.h:1316
RigDef::VideoCamera::bottom_node
Node::Ref bottom_node
Definition: RigDef_File.h:1314
RigDef::Engine::torque
float torque
Definition: RigDef_File.h:679
BITMASK_SET_1
#define BITMASK_SET_1(VAR, FLAGS)
Definition: BitFlags.h:17
strnlen
#define strnlen(str, len)
Definition: InputEngine.cpp:400
RigDef::Keyword::SUBMESH_GROUNDMODEL
@ SUBMESH_GROUNDMODEL
RigDef::Trigger::detacher_group
int detacher_group
Definition: RigDef_File.h:1282
RigDef::Tie::max_length
float max_length
Definition: RigDef_File.h:1215
RigDef::Guid::guid
std::string guid
Definition: RigDef_File.h:830
RigDef::ManagedMaterial::specular_map
Ogre::String specular_map
Definition: RigDef_File.h:919
RigDef::FlareBase::node_axis_y
Node::Ref node_axis_y
Definition: RigDef_File.h:750
RigDef::Keyword::MESHWHEELS
@ MESHWHEELS
RigDef::Cinecam
Definition: RigDef_File.h:606
RigDef::Fileinfo::file_version
int file_version
Definition: RigDef_File.h:743
RigDef::SlideNode::railgroup_id
int railgroup_id
Definition: RigDef_File.h:1166
RigDef::IsWhitespace
bool IsWhitespace(char c)
Definition: RigDef_Parser.cpp:50
RigDef::Keyword::CAB
@ CAB
RigDef::Shock2::short_bound
float short_bound
Maximum contraction limit, in percentage ( 1.00 = 100% )
Definition: RigDef_File.h:1109
RoR::Console::MessageType
MessageType
Definition: Console.h:46
RigDef::FlexBodyWheel::rim_mesh_name
Ogre::String rim_mesh_name
Definition: RigDef_File.h:805
RigDef::FlareBase::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:751
RigDef::Airbrake::height
float height
Definition: RigDef_File.h:332
RigDef::Shock3::spring_in
float spring_in
Spring value applied when the shock is compressing.
Definition: RigDef_File.h:1126
RigDef::Shock2::precompression
float precompression
Changes compression or extension of the suspension when the truck spawns. This can be used to "level"...
Definition: RigDef_File.h:1111
RigDef::Tie::max_reach_length
float max_reach_length
Definition: RigDef_File.h:1212
RigDef::FlareBase::material_name
Ogre::String material_name
Definition: RigDef_File.h:757
RigDef::Prop::DashboardSpecial::_offset_is_set
bool _offset_is_set
Definition: RigDef_File.h:983
RigDef::Document
Definition: RigDef_File.h:1368
RigDef::Wing::nodes
Node::Ref nodes[8]
Definition: RigDef_File.h:1355
RoR::ExtCameraMode::NODE
@ NODE
RigDef::Engturbo::param11
float param11
Definition: RigDef_File.h:718
RoR::FlareType::SIDELIGHT
@ SIDELIGHT
RigDef::Airbrake::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:326
RigDef::Engturbo::param1
float param1
Definition: RigDef_File.h:708
RigDef::Flexbody::node_list_to_import
std::vector< Node::Range > node_list_to_import
Definition: RigDef_File.h:794
RigDef::Guid
Definition: RigDef_File.h:828
RigDef::MeshWheel
Definition: RigDef_File.h:936
RigDef::ManagedMaterial
Definition: RigDef_File.h:912
RigDef::TransferCase::a1
int a1
Definition: RigDef_File.h:1255
RigDef::Airbrake::aditional_node
Node::Ref aditional_node
Definition: RigDef_File.h:329
RigDef::Keyword::CRUISECONTROL
@ CRUISECONTROL
RoR::FlareType::DASHBOARD
@ DASHBOARD
RigDef::BeamDefaults::scale
BeamDefaultsScale scale
Definition: RigDef_File.h:564
RoR::VCAM_ROLE_MIRROR_NOFLIP
@ VCAM_ROLE_MIRROR_NOFLIP
Same as VCAM_ROLE_MIRROR, but without flipping the texture horizontally (expects texcoords to be alre...
Definition: Application.h:601
RigDef::InterAxle
Definition: RigDef_File.h:890
RigDef::Node::detacher_group
int detacher_group
Definition: RigDef_Node.h:166
RigDef::Shock2::progress_factor_spring_out
float progress_factor_spring_out
Progression factor springout, 0 = disabled, 1...x as multipliers, example:maximum springrate == sprin...
Definition: RigDef_File.h:1107
RigDef::Engoption::clutch_force
float clutch_force
Definition: RigDef_File.h:690
RigDef::Trigger::expansion_trigger_limit
float expansion_trigger_limit
Definition: RigDef_File.h:1278
Application.h
Central state/object manager and communications hub.
RigDef::Shock3::long_bound
float long_bound
Maximum extension limit, in percentage ( 1.00 = 100% )
Definition: RigDef_File.h:1137
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:289
RigDef::SlideNode::_break_force_set
bool _break_force_set
Definition: RigDef_File.h:1163
RigDef::Turbojet::wet_thrust
float wet_thrust
Definition: RigDef_File.h:1294
RigDef::Animator::flags
BitMask_t flags
Definition: RigDef_File.h:455
RoR::FlareType
FlareType
Definition: Application.h:504
RoR::VCAM_ROLE_MIRROR
@ VCAM_ROLE_MIRROR
Flips the video output and when not in driver cam, acts like a natural mirror, not a screen.
Definition: Application.h:600
RigDef::Flexbody::mesh_name
Ogre::String mesh_name
Definition: RigDef_File.h:792
RigDef::Keyword::DEFAULT_SKIN
@ DEFAULT_SKIN
RigDef::TorqueCurve::Sample::torque_percent
float torque_percent
Definition: RigDef_File.h:1233
RigDef::Screwprop::prop_node
Node::Ref prop_node
Definition: RigDef_File.h:1057
RigDef::AntiLockBrakes::attr_is_on
bool attr_is_on
Definition: RigDef_File.h:471
RigDef::Engturbo::param4
float param4
Definition: RigDef_File.h:711
RigDef::DefaultSkin
Definition: RigDef_File.h:670
RigDef::Shock3::detacher_group
int detacher_group
Definition: RigDef_File.h:1141
RigDef::Engturbo::param2
float param2
Definition: RigDef_File.h:709
RigDef::Flare3::inertia_defaults
std::shared_ptr< Inertia > inertia_defaults
Definition: RigDef_File.h:766
RigDef::TransferCase::gear_ratios
std::vector< float > gear_ratios
Definition: RigDef_File.h:1259
RigDef::Submesh
Definition: RigDef_File.h:1192
RigDef::Shock3::damp_in_fast
float damp_in_fast
Damping value applied when shock is commpressing faster than split in velocity.
Definition: RigDef_File.h:1132
RigDef::Shock3::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:1125
RigDef::Hook::flag_no_disable
bool flag_no_disable
Definition: RigDef_File.h:858
RigDef::KeywordToString
const char * KeywordToString(RigDef::Keyword keyword)
Definition: Application.cpp:709
RigDef::Animation::ratio
float ratio
Definition: RigDef_File.h:409
RigDef::Airbrake::max_inclination_angle
float max_inclination_angle
Definition: RigDef_File.h:333
RigDef::Wing::min_deflection
float min_deflection
Definition: RigDef_File.h:1359
RigDef::Inertia
Definition: RigDef_File.h:298
RigDef::Animator::aero_animator
AeroAnimator aero_animator
Definition: RigDef_File.h:458
RigDef::Animation::mode
BitMask_t mode
Definition: RigDef_File.h:414
RigDef::Axle::options
DifferentialTypeVec options
Order matters!
Definition: RigDef_File.h:488
RigDef::BaseMeshWheel::damping
float damping
Definition: RigDef_File.h:287
RigDef::Shock
Definition: RigDef_File.h:1073
RigDef::Command2::lengthen_rate
float lengthen_rate
Definition: RigDef_File.h:631
RigDef::BaseMeshWheel
Definition: RigDef_File.h:279
RigDef::Keyword::CONTACTERS
@ CONTACTERS
RigDef::TorqueCurve::Sample::power
float power
Definition: RigDef_File.h:1232
RigDef::Shock2::progress_factor_spring_in
float progress_factor_spring_in
Progression factor for springin. A value of 0 disables this option. 1...x as multipliers,...
Definition: RigDef_File.h:1103
RigDef::Trigger::shortbound_trigger_action
int shortbound_trigger_action
Definition: RigDef_File.h:1283
RigDef::Rotator::engine_coupling
float engine_coupling
Definition: RigDef_File.h:1044
RigDef::Keyword::MESHWHEELS2
@ MESHWHEELS2
RigDef::Hook::option_hook_range
float option_hook_range
Definition: RigDef_File.h:849
RigDef::Hydro::detacher_group
int detacher_group
Definition: RigDef_File.h:887
RigDef::BeamDefaults::visual_beam_diameter
float visual_beam_diameter
Definition: RigDef_File.h:558
RoR::WheelSide::LEFT
@ LEFT
RigDef::BaseWheel2::tyre_damping
float tyre_damping
Definition: RigDef_File.h:295
RigDef::Shock3::options
BitMask_t options
Definition: RigDef_File.h:1139
RigDef::Engturbo::param5
float param5
Definition: RigDef_File.h:712
RigDef::Forvert::vert_index
int vert_index
Definition: RigDef_File.h:781
RigDef::Engoption::stall_rpm
float stall_rpm
Definition: RigDef_File.h:695
RigDef::Cab
Definition: RigDef_File.h:573
RigDef::Engturbo::tinertiaFactor
float tinertiaFactor
Definition: RigDef_File.h:706
RigDef::MaterialFlareBinding
Definition: RigDef_File.h:924
RigDef::Prop::mesh_name
Ogre::String mesh_name
Definition: RigDef_File.h:1004
RigDef::VideoCamera::field_of_view
float field_of_view
Definition: RigDef_File.h:1319
RigDef::Rope::invisible
bool invisible
Definition: RigDef_File.h:1029
RigDef::SpeedLimiter
Definition: RigDef_File.h:1184
RigDef::Keyword::COLLISIONBOXES
@ COLLISIONBOXES
RigDef::Beam::defaults
std::shared_ptr< BeamDefaults > defaults
Definition: RigDef_File.h:502
RigDef::Lockgroup
Definition: RigDef_File.h:897
RigDef::Hook::option_max_force
float option_max_force
Definition: RigDef_File.h:851
RigDef::BaseWheel2::tyre_springiness
float tyre_springiness
Definition: RigDef_File.h:294
RigDef::Animator
Definition: RigDef_File.h:421
RigDef::FileFormatVersion::version
int version
Definition: RigDef_File.h:736
RigDef::Turbojet::front_diameter
float front_diameter
Definition: RigDef_File.h:1295
RigDef::Wheel2::face_material_name
Ogre::String face_material_name
Definition: RigDef_File.h:1343
RigDef::SpeedLimiter::max_speed
float max_speed
Definition: RigDef_File.h:1186
RigDef::Forvert::node_ref
Node::Ref node_ref
Definition: RigDef_File.h:778
RigDef::DefaultSkin::skin_name
std::string skin_name
Definition: RigDef_File.h:672
RigDef::Brakes::parking_brake_force
float parking_brake_force
Definition: RigDef_File.h:570
RigDef::Author::email
Ogre::String email
Definition: RigDef_File.h:481
RigDef::Rope::end_node
Node::Ref end_node
Definition: RigDef_File.h:1028
RigDef::FlareBase::type
RoR::FlareType type
Definition: RigDef_File.h:752
RigDef::Flexbody
Definition: RigDef_File.h:785
RigDef::Keyword::WHEELS
@ WHEELS
RigDef::Hook::option_min_range_meters
float option_min_range_meters
Definition: RigDef_File.h:855
RigDef::Engturbo::param10
float param10
Definition: RigDef_File.h:717
RigDef::Keyword::SET_COLLISION_RANGE
@ SET_COLLISION_RANGE
RigDef::Command2::option_i_invisible
bool option_i_invisible
Definition: RigDef_File.h:645
RigDef::VideoCamera
Definition: RigDef_File.h:1310
RigDef::Shock2::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:1100
RigDef::TransferCase
Definition: RigDef_File.h:1253
RigDef::Rotator::inertia
Inertia inertia
Definition: RigDef_File.h:1042
RigDef::BeamDefaults::_is_user_defined
bool _is_user_defined
Informs whether these data were read from "set_beam_defaults" directive or filled in by the parser on...
Definition: RigDef_File.h:563
RoR::ExtCameraMode::CLASSIC
@ CLASSIC
RigDef::FlexBodyWheel::side
RoR::WheelSide side
Definition: RigDef_File.h:802
RoR::WheelBraking::FOOT_HAND_SKID_LEFT
@ FOOT_HAND_SKID_LEFT
= yes footbrake, yes handbrake, yes direction control (braked when vehicle steers to the left)
RigDef::Wing::airfoil
Ogre::String airfoil
Definition: RigDef_File.h:1361
RigDef::Shock::precompression
float precompression
Changes compression or extension of the suspension when the truck spawns. This can be used to "level"...
Definition: RigDef_File.h:1085
RigDef::Shock2::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:1113
RigDef::Turboprop2
Definition: RigDef_File.h:1300
RigDef::TractionControl::wheel_slip
float wheel_slip
Definition: RigDef_File.h:1245
RigDef::Cinecam::node_mass
float node_mass
Definition: RigDef_File.h:612
RigDef::Inertia::start_delay_factor
float start_delay_factor
Definition: RigDef_File.h:305
RigDef::Prop::y_axis_node
Node::Ref y_axis_node
Definition: RigDef_File.h:1001
RigDef::TractionControl::attr_is_on
bool attr_is_on
Definition: RigDef_File.h:1248
RigDef::Fusedrag::front_node
Node::Ref front_node
Definition: RigDef_File.h:814
RigDef::BaseMeshWheel::tyre_radius
float tyre_radius
Definition: RigDef_File.h:285
RigDef::Script
Definition: RigDef_File.h:1063
RigDef::Minimass::global_min_mass_Kg
float global_min_mass_Kg
minimum node mass in Kg - only effective where DefaultMinimass was not set.
Definition: RigDef_File.h:932
RigDef::VideoCamera::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:1317
RigDef::Engine::reverse_gear_ratio
float reverse_gear_ratio
Definition: RigDef_File.h:681
RoR::FlareType::REVERSE_LIGHT
@ REVERSE_LIGHT
RigDef::BeamDefaultsScale::deformation_threshold_constant
float deformation_threshold_constant
Definition: RigDef_File.h:516
RigDef::Engturbo::nturbos
int nturbos
Definition: RigDef_File.h:707
RigDef::Exhaust::direction_node
Node::Ref direction_node
Definition: RigDef_File.h:724
RigDef::Rotator::rotating_plate_nodes
Node::Ref rotating_plate_nodes[4]
Definition: RigDef_File.h:1038
RigDef::Script::filename
std::string filename
Definition: RigDef_File.h:1065
RigDef::Globals::material_name
Ogre::String material_name
Definition: RigDef_File.h:825
RigDef::SkeletonSettings::visibility_range_meters
float visibility_range_meters
Definition: RigDef_File.h:1146
RigDef::Exhaust::particle_name
Ogre::String particle_name
Definition: RigDef_File.h:725
RigDef::Exhaust::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:723
RigDef::Tie
Definition: RigDef_File.h:1206
RigDef::Animator::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:460
RoR::FlareType::USER
@ USER
RoR::VideoCamRole
VideoCamRole
Definition: Application.h:594
RigDef::WheelDetacher
Definition: RigDef_File.h:1347
RigDef::Keyword::GUISETTINGS
@ GUISETTINGS
RigDef::BeamDefaults::plastic_deform_coef
float plastic_deform_coef
Definition: RigDef_File.h:560
RigDef::Rotator2::tolerance
float tolerance
Definition: RigDef_File.h:1051
RigDef::Turbojet::side_node
Node::Ref side_node
Definition: RigDef_File.h:1291
RigDef::Minimass::option
MinimassOption option
Definition: RigDef_File.h:933
RigDef::TransferCase::has_2wd
bool has_2wd
Definition: RigDef_File.h:1257
RigDef::Fusedrag
Definition: RigDef_File.h:809
RigDef::Trigger::boundary_timer
float boundary_timer
Definition: RigDef_File.h:1280
RigDef::Globals::cargo_mass
float cargo_mass
Definition: RigDef_File.h:824
RigDef::Wheel::springiness
float springiness
Definition: RigDef_File.h:1333
RigDef::Airbrake::texcoord_y2
float texcoord_y2
Definition: RigDef_File.h:337
RigDef::Engine
Definition: RigDef_File.h:675
RigDef::Trigger::contraction_trigger_limit
float contraction_trigger_limit
Definition: RigDef_File.h:1277
RigDef::Node::node_defaults
std::shared_ptr< NodeDefaults > node_defaults
Definition: RigDef_Node.h:163
RigDef::Texcoord
Definition: RigDef_File.h:1199
RigDef::StrEqualsNocase
bool StrEqualsNocase(std::string const &s1, std::string const &s2)
Definition: RigDef_Parser.cpp:60
RigDef::Author::type
Ogre::String type
Definition: RigDef_File.h:478
RigDef::Shock3::split_vel_in
float split_vel_in
Split velocity in (m/s) - threshold for slow / fast damping during compression.
Definition: RigDef_File.h:1131
RigDef::Beam::detacher_group
int detacher_group
Definition: RigDef_File.h:501
RigDef_Parser.h
Checks the rig-def file syntax and loads data to memory.
RigDef::CustomDashboardInput::data_type
int data_type
Definition: RigDef_File.h:662
RigDef::Keyword::ANTILOCKBRAKES
@ ANTILOCKBRAKES
RigDef::TractionControl::attr_no_toggle
bool attr_no_toggle
Definition: RigDef_File.h:1250
RigDef::Wheel::band_material_name
Ogre::String band_material_name
Definition: RigDef_File.h:1336
RigDef::Keyword::COMMANDS2
@ COMMANDS2
RigDef::Turbojet::dry_thrust
float dry_thrust
Definition: RigDef_File.h:1293
RigDef::Beam::options
BitMask_t options
Definition: RigDef_File.h:498
DEFAULT_SPRING
static const float DEFAULT_SPRING
Definition: SimConstants.h:48
RigDef::Camera::center_node
Node::Ref center_node
Definition: RigDef_File.h:591
RigDef::Animation::source
BitMask64_t source
Definition: RigDef_File.h:412
RigDef::Texcoord::u
float u
Definition: RigDef_File.h:1202
RigDef::FlexBodyWheel::rim_damping
float rim_damping
Definition: RigDef_File.h:804
RigDef::Shock3::short_bound
float short_bound
Maximum contraction limit, in percentage ( 1.00 = 100% )
Definition: RigDef_File.h:1136
RigDef::Engturbo::param7
float param7
Definition: RigDef_File.h:714
RigDef::Engoption::idle_rpm
float idle_rpm
Definition: RigDef_File.h:694
RigDef::AeroAnimator::engine_idx
unsigned int engine_idx
Definition: RigDef_File.h:257
RigDef::BaseWheel2::tyre_radius
float tyre_radius
Definition: RigDef_File.h:293
RigDef::Shock2::progress_factor_damp_in
float progress_factor_damp_in
Progression factor for dampin. 0 = disabled, 1...x as multipliers, example:maximum dampingrate == spr...
Definition: RigDef_File.h:1104
RigDef::Animator::inertia_defaults
std::shared_ptr< Inertia > inertia_defaults
Definition: RigDef_File.h:459
RigDef::Node::options
BitMask_t options
Definition: RigDef_Node.h:160
RigDef::BeamDefaultsScale::springiness
float springiness
Definition: RigDef_File.h:514
RigDef::BaseWheel::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:276
RigDef::Rotator2
Definition: RigDef_File.h:1048
RigDef::Shock::options
BitMask_t options
Definition: RigDef_File.h:1086
RigDef::Command2::affect_engine
float affect_engine
Definition: RigDef_File.h:638
RigDef::Shock2::detacher_group
int detacher_group
Definition: RigDef_File.h:1114
RigDef::Author::forum_account_id
unsigned int forum_account_id
Definition: RigDef_File.h:479
RigDef::Keyword::WHEELS2
@ WHEELS2
RigDef::BaseMeshWheel::mesh_name
Ogre::String mesh_name
Definition: RigDef_File.h:282
RigDef::Forvert::line_number
int line_number
Definition: RigDef_File.h:782
RigDef::Shock3
Definition: RigDef_File.h:1117
RigDef::Exhaust
Definition: RigDef_File.h:721
RigDef::Keyword::TRACTIONCONTROL
@ TRACTIONCONTROL
RoR::FlareType::BRAKE_LIGHT
@ BRAKE_LIGHT
RigDef::Airbrake::width
float width
Definition: RigDef_File.h:331
RigDef::Command2::contract_key
RoR::CommandkeyID_t contract_key
Definition: RigDef_File.h:634
RigDef::Node::Id::setStr
void setStr(std::string const &id_str)
Definition: RigDef_Node.cpp:63
RigDef::VideoCamera::max_clip_distance
float max_clip_distance
Definition: RigDef_File.h:1323
DEFAULT_DAMP
static const float DEFAULT_DAMP
Definition: SimConstants.h:49
RigDef::Animation::motor_sources
std::list< MotorSource > motor_sources
Definition: RigDef_File.h:413
RigDef::Prop::special_prop_dashboard
DashboardSpecial special_prop_dashboard
Definition: RigDef_File.h:1009
RigDef::CollisionRange::node_collision_range
float node_collision_range
Definition: RigDef_File.h:624
RigDef::Pistonprop::blade_tip_nodes
Node::Ref blade_tip_nodes[4]
Definition: RigDef_File.h:964
RigDef::Fusedrag::airfoil_name
Ogre::String airfoil_name
Definition: RigDef_File.h:817
RigDef::BeamDefaultsScale::damping_constant
float damping_constant
Definition: RigDef_File.h:515
RigDef::Shock2::damp_in
float damp_in
Damping value applied when the shock is compressing.
Definition: RigDef_File.h:1102
RigDef::Turbojet::nozzle_length
float nozzle_length
Definition: RigDef_File.h:1297
RigDef::Lockgroup::nodes
std::vector< Node::Ref > nodes
Definition: RigDef_File.h:904
BitMask_t
uint32_t BitMask_t
Definition: BitFlags.h:7
RigDef::Axle
Definition: RigDef_File.h:485
RigDef::Shock2::options
BitMask_t options
Definition: RigDef_File.h:1112
RigDef::Keyword::ENGINE
@ ENGINE
RigDef::Fusedrag::area_coefficient
float area_coefficient
Definition: RigDef_File.h:818
RigDef::SlideNode::_attachment_rate_set
bool _attachment_rate_set
Definition: RigDef_File.h:1165
RoR::WheelPropulsion::NONE
@ NONE
RigDef::Shock::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:1080
RigDef::Cinecam::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:613
RigDef::Tie::root_node
Node::Ref root_node
Definition: RigDef_File.h:1211
RoR::Console::CONSOLE_MSGTYPE_ACTOR
@ CONSOLE_MSGTYPE_ACTOR
Parsing/spawn/simulation messages for actors.
Definition: Console.h:63
RigDef::TransferCase::has_2wd_lo
bool has_2wd_lo
Definition: RigDef_File.h:1258
RigDef::EngineType
EngineType
Definition: RigDef_File.h:90
RigDef::Lockgroup::number
int number
Definition: RigDef_File.h:903
RigDef::Node
Definition: RigDef_Node.h:39
RigDef::DocumentPtr
std::shared_ptr< Document > DocumentPtr
Definition: ForwardDeclarations.h:288
RoR::Console::CONSOLE_SYSTEM_WARNING
@ CONSOLE_SYSTEM_WARNING
Definition: Console.h:53
RigDef::Keyword::CUSTOMDASHBOARDINPUTS
@ CUSTOMDASHBOARDINPUTS
RoR::FlareType::BLINKER_RIGHT
@ BLINKER_RIGHT
RigDef::BaseWheel::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:269
RigDef::VideoCamera::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:1312
RigDef::SoundSource
Definition: RigDef_File.h:1170
RigDef::RailGroup::node_list
std::vector< Node::Range > node_list
Definition: RigDef_File.h:1015
RigDef::Turbojet::is_reversable
int is_reversable
Definition: RigDef_File.h:1292
RigDef::BaseWheel::node_defaults
std::shared_ptr< NodeDefaults > node_defaults
Definition: RigDef_File.h:275
RigDef::Airbrake::texcoord_x2
float texcoord_x2
Definition: RigDef_File.h:335
RigDef::Hook::option_lockgroup
int option_lockgroup
Definition: RigDef_File.h:853
RigDef::Hook::flag_no_rope
bool flag_no_rope
Definition: RigDef_File.h:859
RigDef::AntiLockBrakes::regulation_force
float regulation_force
Definition: RigDef_File.h:468
RigDef::Assetpack
Definition: RigDef_File.h:260
RigDef::Keyword::CINECAM
@ CINECAM
RoR::WheelBraking::FOOT_HAND_SKID_RIGHT
@ FOOT_HAND_SKID_RIGHT
= yes footbrake, yes handbrake, yes direction control (braked when vehicle steers to the right)
RigDef::Shock::damping
float damping
The 'resistance to motion' of the shock. The best value is given by this equation: 2 * sqrt(suspended...
Definition: RigDef_File.h:1082
RigDef::Animator::lenghtening_factor
float lenghtening_factor
Definition: RigDef_File.h:454
RigDef::Rotator2::description
Ogre::String description
Definition: RigDef_File.h:1052
RigDef::Prop::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:999
RigDef::SlideNode::_max_attach_dist_set
bool _max_attach_dist_set
Definition: RigDef_File.h:1167
RigDef::Hydro::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:886
RigDef::Rotator::base_plate_nodes
Node::Ref base_plate_nodes[4]
Definition: RigDef_File.h:1037
RigDef::Keyword::ENGTURBO
@ ENGTURBO
RigDef::Flexbody::x_axis_node
Node::Ref x_axis_node
Definition: RigDef_File.h:788
RigDef::Airbrake::x_axis_node
Node::Ref x_axis_node
Definition: RigDef_File.h:327
RigDef::Animation::event_name
Ogre::String event_name
Definition: RigDef_File.h:415
ignored
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 does not affect it Directive usualy set global attributes or change behavior of the parsing Directive may appear in any block section Modularity The elements can be grouped into modules Each module must belong to one or more configurations Directives sectionconfig specify truck configurations the user can choose from Exactly one must be selected If the first defined is used lettercase matches original docs(parsing is insensitive). NAME TYPE NOTES advdrag BLOCK add_animation DIRECTIVE Special syntax airbrakes BLOCK animators BLOCK Special syntax IF(values[0]=="") bad trailing chars are silently ignored no space at the end Items delimited On each side of there is max item Empty invalid string parses as node num items Acceptable item the node is the others ignored
Definition: ReadMe.txt:302
RigDef::Particle::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:956
RigDef::Pistonprop::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:962
RigDef::Shock3::damp_out
float damp_out
Damping value applied when shock extending.
Definition: RigDef_File.h:1129
RigDef::Command2::option_c_auto_center
bool option_c_auto_center
Definition: RigDef_File.h:647
RoR::FlareType::HIGH_BEAM
@ HIGH_BEAM
RigDef::Rotator::spin_left_key
unsigned int spin_left_key
Definition: RigDef_File.h:1040
RigDef::Minimass
Definition: RigDef_File.h:930
RigDef::Shock3::damp_in_slow
float damp_in_slow
Damping value applied when shock is commpressing slower than split in velocity.
Definition: RigDef_File.h:1130
RigDef::BeamDefaults::beam_material_name
Ogre::String beam_material_name
Definition: RigDef_File.h:559
RigDef::Turbojet
Definition: RigDef_File.h:1287
RigDef::Keyword::FLARES2
@ FLARES2
RigDef::Hydro::lenghtening_factor
float lenghtening_factor
Definition: RigDef_File.h:882
RigDef::VideoCamera::material_name
Ogre::String material_name
Definition: RigDef_File.h:1326
RigDef::Command2::max_contraction
float max_contraction
Definition: RigDef_File.h:632
RigDef::Command2::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:629
RoR::DC_INT
@ DC_INT
Definition: DashBoardManager.h:63
RigDef::ROOT_MODULE_NAME
const char * ROOT_MODULE_NAME
Definition: RigDef_File.cpp:35
RigDef::AntiLockBrakes::pulse_per_sec
float pulse_per_sec
Definition: RigDef_File.h:470
RigDef::Beam
Definition: RigDef_File.h:491
RigDef::Rotator2::rotating_force
float rotating_force
Definition: RigDef_File.h:1050
RigDef::Screwprop
Definition: RigDef_File.h:1055
RigDef::Hook::option_timer
float option_timer
Definition: RigDef_File.h:854
RigDef::GuiSettings::value
std::string value
Definition: RigDef_File.h:836
RigDef::Prop::x_axis_node
Node::Ref x_axis_node
Definition: RigDef_File.h:1000
RigDef::Animation::upper_limit
float upper_limit
Definition: RigDef_File.h:411
RigDef::Cab::options
BitMask_t options
Definition: RigDef_File.h:586
RigDef::ExtCamera::mode
RoR::ExtCameraMode mode
Definition: RigDef_File.h:730
RigDef::Inertia::stop_function
Ogre::String stop_function
Definition: RigDef_File.h:308
RoR::WheelPropulsion::FORWARD
@ FORWARD
RigDef::Prop::DashboardSpecial::rotation_angle
float rotation_angle
Definition: RigDef_File.h:984
RigDef::Engoption::inertia
float inertia
Definition: RigDef_File.h:688
RigDef::Keyword::FLEXBODIES
@ FLEXBODIES
RigDef::CruiseControl
Definition: RigDef_File.h:653
RigDef::BaseMeshWheel::material_name
Ogre::String material_name
Definition: RigDef_File.h:283
RigDef::Rope::detacher_group
int detacher_group
Definition: RigDef_File.h:1031
RigDef::Wing
Definition: RigDef_File.h:1353
RigDef::BaseWheel::reference_arm_node
Node::Ref reference_arm_node
Definition: RigDef_File.h:273
RigDef::Node::default_minimass
std::shared_ptr< DefaultMinimass > default_minimass
Definition: RigDef_Node.h:164
RigDef_File.h
Data structures representing 'truck' file format, see https://docs.rigsofrods.org/vehicle-creation/fi...
RigDef::Animation::dash_link_name
Ogre::String dash_link_name
Definition: RigDef_File.h:416
RoR
Definition: AppContext.h:36
RigDef::ManagedMaterialsOptions
Definition: RigDef_File.h:907
RigDef::Hook::flag_visible
bool flag_visible
Definition: RigDef_File.h:860
RigDef::Keyword::EXTCAMERA
@ EXTCAMERA
RigDef::Fusedrag::rear_node
Node::Ref rear_node
Definition: RigDef_File.h:815
RigDef::Globals
Definition: RigDef_File.h:821
RigDef::Prop::special_prop_beacon
BeaconSpecial special_prop_beacon
Definition: RigDef_File.h:1008
RigDef::RailGroup::id
unsigned int id
Definition: RigDef_File.h:1014
RigDef::Command2::needs_engine
bool needs_engine
Definition: RigDef_File.h:639
RigDef::Pistonprop::pitch
float pitch
Definition: RigDef_File.h:967
RoR::FlareType::HEADLIGHT
@ HEADLIGHT
RigDef::ExtCamera
Definition: RigDef_File.h:728
RigDef::Shock2::progress_factor_damp_out
float progress_factor_damp_out
Progression factor dampout, 0 = disabled, 1...x as multipliers, example:maximum dampingrate == spring...
Definition: RigDef_File.h:1108
RigDef::Flexbody::y_axis_node
Node::Ref y_axis_node
Definition: RigDef_File.h:789
RigDef::Rope
Definition: RigDef_File.h:1025
RigDef::Cinecam::nodes
Node::Ref nodes[8]
Definition: RigDef_File.h:609
RigDef::Airbrake::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:330
RigDef::Wheel2::rim_springiness
float rim_springiness
Definition: RigDef_File.h:1341
RigDef::Hook::option_speed_coef
float option_speed_coef
Definition: RigDef_File.h:850
RigDef::Ropable::group
int group
Definition: RigDef_File.h:1021
RigDef::Trigger::beam_defaults
std::shared_ptr< BeamDefaults > beam_defaults
Definition: RigDef_File.h:1281
RigDef::Forvert::node_y
Node::Ref node_y
Definition: RigDef_File.h:780
RigDef_Regexes.h
Defines regular expressions to verify and pull data from rig-def file. 'E' stands for Expression.
RigDef::Wheel::face_material_name
Ogre::String face_material_name
Definition: RigDef_File.h:1335
RigDef::Wing::efficacy_coef
float efficacy_coef
Definition: RigDef_File.h:1362
RoR::WheelPropulsion
WheelPropulsion
Definition: Application.h:536
RigDef::SlideNode
Definition: RigDef_File.h:1150
RigDef::Cinecam::damping
float damping
Definition: RigDef_File.h:611
RigDef::TractionControl::regulation_force
float regulation_force
Definition: RigDef_File.h:1244
RigDef::TransferCase::a2
int a2
Definition: RigDef_File.h:1256
RigDef::MeshWheel2
Definition: RigDef_File.h:939
RigDef::Hook::flag_self_lock
bool flag_self_lock
Definition: RigDef_File.h:856
RigDef::SoundSource::sound_script_name
Ogre::String sound_script_name
Definition: RigDef_File.h:1173
RigDef::Keyword
Keyword
Definition: Application.h:174
RigDef::Pistonprop::turbine_power_kW
float turbine_power_kW
Definition: RigDef_File.h:966
RigDef::Animation::MotorSource::source
BitMask_t source
Definition: RigDef_File.h:354
RigDef::WheelDetacher::detacher_group
int detacher_group
Definition: RigDef_File.h:1350
RigDef::TorqueCurve
Definition: RigDef_File.h:1223
RigDef::Shock3::damp_out_slow
float damp_out_slow
Damping value applied when shock is commpressing slower than split out velocity.
Definition: RigDef_File.h:1133
RigDef::Prop::BeaconSpecial::flare_material_name
Ogre::String flare_material_name
Definition: RigDef_File.h:995
RigDef::DifferentialTypeVec
std::vector< DifferentialType > DifferentialTypeVec
Definition: RigDef_File.h:105
RigDef::Turboprop2::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:1302
RigDef::Hook::node
Node::Ref node
Definition: RigDef_File.h:848
RigDef::Beam::nodes
Node::Ref nodes[2]
Definition: RigDef_File.h:497
RigDef::Rope::root_node
Node::Ref root_node
Definition: RigDef_File.h:1027
RigDef::Fileinfo::category_id
int category_id
Definition: RigDef_File.h:742
RigDef::VideoCamera::camera_name
Ogre::String camera_name
Definition: RigDef_File.h:1327
RigDef::Turbojet::back_node
Node::Ref back_node
Definition: RigDef_File.h:1290
RigDef::Cab::nodes
Node::Ref nodes[3]
Definition: RigDef_File.h:585
RigDef::Keyword::EXHAUSTS
@ EXHAUSTS
RigDef::Prop::BeaconSpecial::color
Ogre::ColourValue color
Definition: RigDef_File.h:996