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