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