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