RigsofRods
Soft-body Physics Simulation
AddonPartFileFormat.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-2023 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "AddonPartFileFormat.h"
23 
24 #include "Actor.h"
25 #include "Application.h"
26 #include "CacheSystem.h"
27 #include "Console.h"
28 #include "GameContext.h"
29 #include "GenericFileFormat.h"
30 #include "GUI_MessageBox.h"
31 #include "RigDef_Parser.h"
32 #include "TuneupFileFormat.h"
33 
34 #include <Ogre.h>
35 
36 using namespace RoR;
37 using namespace RigDef;
38 
40 {
41  // Inits `RefCountingObjectPtr<>` (CacheEntryPtr, GenericDocumentPtr) - shouldn't be in header.
42 }
43 
45 {
46  // Destroys `RefCountingObjectPtr<>` (CacheEntryPtr, GenericDocumentPtr) - shouldn't be in header.
47 }
48 
49 std::shared_ptr<Document::Module> AddonPartUtility::TransformToRigDefModule(CacheEntryPtr& entry)
50 {
52  m_addonpart_entry = entry;
53  try
54  {
55  Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().openResource(entry->fname, entry->resource_group);
56 
57  m_document = new GenericDocument();
59  m_document->loadFromDataStream(datastream, options);
60 
61  m_module = std::shared_ptr<Document::Module>(new Document::Module(entry->dname));
62  m_module->origin_addonpart = entry;
63  m_context = new GenericDocContext(m_document);
64  Keyword keyword = Keyword::INVALID;
65  Keyword block = Keyword::INVALID;
66 
67  while (!m_context->endOfFile())
68  {
69  if (m_context->isTokKeyword())
70  {
71  // (ignore 'addonpart_*' directives)
72  if (m_context->getTokKeyword().find("addonpart_") != std::string::npos)
73  {
74  m_context->seekNextLine();
75  continue;
76  }
77 
78  keyword = Parser::IdentifyKeyword(m_context->getTokKeyword());
79  if (keyword == Keyword::INVALID && m_context->getTokKeyword() == "set_managedmaterials_options")
80  {
81  keyword = Keyword::SET_MANAGEDMATERIALS_OPTIONS; // Workaround, don't ask me why the regex doesn't match this.
82  }
83  if (keyword != Keyword::INVALID)
84  {
85  if (keyword == Keyword::SET_MANAGEDMATERIALS_OPTIONS)
86  {
87  this->ProcessDirectiveSetManagedMaterialsOptions();
88  m_context->seekNextLine();
89  continue;
90  }
91  else if (keyword == Keyword::MANAGEDMATERIALS
92  || keyword == Keyword::PROPS
93  || keyword == Keyword::FLEXBODIES
94  || keyword == Keyword::FLARES
95  || keyword == Keyword::FLARES2)
96  {
97  block = keyword;
98  m_context->seekNextLine();
99  continue;
100  }
101 
102  }
103  }
104 
105  if (block != Keyword::INVALID && !m_context->isTokComment() && !m_context->isTokLineBreak())
106  {
107  switch (block)
108  {
109  case Keyword::MANAGEDMATERIALS: this->ProcessManagedMaterial(); break;
110  case Keyword::PROPS: this->ProcessProp(); break;
111  case Keyword::FLEXBODIES: this->ProcessFlexbody(); break;
112  case Keyword::FLARES: this->ProcessFlare(); break;
113  case Keyword::FLARES2: this->ProcessFlare2(); break;
114  default: break;
115  }
116  }
117 
118  m_context->seekNextLine();
119  }
120  return m_module;
121  }
122  catch (Ogre::Exception& e)
123  {
126  fmt::format("Could not use addonpart: Error parsing file '{}', message: {}",
127  entry->fname, e.getFullDescription()));
128  return nullptr;
129  }
130 }
131 
133 {
134  // Evaluates 'addonpart_unwanted_*' directives, respecting 'protected_*' directives in the tuneup.
135  // Also handles 'addonpart_tweak_*' directives, resolving possible conflicts among used addonparts.
136  // ---------------------------------------------------------------------------------------------
137 
138  App::GetCacheSystem()->LoadResource(addonpart_entry);
139  m_addonpart_entry = addonpart_entry;
140  m_tuneup = tuneup;
141 
142  try
143  {
144  Ogre::DataStreamPtr datastream = Ogre::ResourceGroupManager::getSingleton().openResource(addonpart_entry->fname, addonpart_entry->resource_group);
145 
146  m_document = new GenericDocument();
148  m_document->loadFromDataStream(datastream, options);
149  m_context = new GenericDocContext(m_document);
150 
151  while (!m_context->endOfFile())
152  {
153  if (m_context->isTokKeyword())
154  {
155  if (m_context->getTokKeyword() == "addonpart_unwanted_prop" )
156  this->ProcessUnwantedProp();
157  else if (m_context->getTokKeyword() == "addonpart_unwanted_flexbody" )
158  this->ProcessUnwantedFlexbody();
159  else if (m_context->getTokKeyword() == "addonpart_unwanted_flare" )
160  this->ProcessUnwantedFlare();
161  else if (m_context->getTokKeyword() == "addonpart_unwanted_exhaust" )
162  this->ProcessUnwantedExhaust();
163  else if (m_context->getTokKeyword() == "addonpart_unwanted_managedmaterial")
164  this->ProcessUnwantedManagedMat();
165  else if (m_context->getTokKeyword() == "addonpart_tweak_wheel")
166  this->ProcessTweakWheel();
167  else if (m_context->getTokKeyword() == "addonpart_tweak_node")
168  this->ProcessTweakNode();
169  else if (m_context->getTokKeyword() == "addonpart_tweak_prop")
170  this->ProcessTweakProp();
171  else if (m_context->getTokKeyword() == "addonpart_tweak_flexbody")
172  this->ProcessTweakFlexbody();
173  else if (m_context->getTokKeyword() == "addonpart_tweak_managedmaterial")
174  this->ProcessTweakManagedMat();
175  }
176 
177  m_context->seekNextLine();
178  }
179 
180  }
181  catch (Ogre::Exception& e)
182  {
185  fmt::format("Addonpart unwanted elements check: Error parsing file '{}', message: {}",
186  addonpart_entry->fname, e.getFullDescription()));
187  }
188 }
189 
191 {
192  ROR_ASSERT(tuneup);
193 
194  // Unwanted
195  tuneup->unwanted_flexbodies.clear();
196  tuneup->unwanted_props.clear();
197  tuneup->unwanted_flares.clear();
198 
199  // Tweaked
200  tuneup->node_tweaks.clear();
201  tuneup->wheel_tweaks.clear();
202  tuneup->prop_tweaks.clear();
203  tuneup->flexbody_tweaks.clear();
204 }
205 
206 
207 // Helpers of `TransformToRigDefModule()`, they expect `m_context` to be in position:
208 // These expect `m_context` to be in position:
209 
211 {
212  ManagedMaterial def;
213  int n = m_context->countLineArgs();
214 
215  // Name:
216  def.name = m_context->getStringData(0); // It may be a STRING (if with quotes), or KEYWORD (if without quotes - because it's at start of line).
217 
218  // Type:
219  std::string str = m_context->getTokString(1);
220  if (str == "mesh_standard") def.type = ManagedMaterialType::MESH_STANDARD;
221  if (str == "mesh_transparent") def.type = ManagedMaterialType::MESH_TRANSPARENT;
222  if (str == "flexmesh_standard") def.type = ManagedMaterialType::FLEXMESH_STANDARD;
223  if (str == "flexmesh_transparent") def.type = ManagedMaterialType::FLEXMESH_TRANSPARENT;
224 
225  // Textures:
226  def.diffuse_map = m_context->getTokString(2);
227  if (n > 3) def.specular_map = m_context->getTokString(3);
228  if (n > 4) def.damaged_diffuse_map = m_context->getTokString(4);
229  // (placeholders)
230  if (def.specular_map == "-") def.specular_map = "";
231  if (def.damaged_diffuse_map == "-") def.damaged_diffuse_map = "";
232 
233  // Options:
234  def.options = m_managedmaterials_options;
235 
236  m_module->managedmaterials.push_back(def);
237 }
238 
240 {
241  int n = m_context->countLineArgs();
242  if (n > 1)
243  {
244  m_managedmaterials_options.double_sided = m_context->getFloatData(1) == 1.f;
245  }
246 }
247 
249 {
250  RigDef::Prop def;
251  int n = m_context->countLineArgs();
252  if (n < 10)
253  {
256  fmt::format("Error parsing addonpart file '{}': 'install_prop' has only {} arguments, expected {}",
257  m_addonpart_entry->fname, n, 10));
258  return;
259  }
260 
261  int importflags = Node::Ref::REGULAR_STATE_IS_VALID | Node::Ref::REGULAR_STATE_IS_NUMBERED;
262  def.reference_node = Node::Ref("", (unsigned int)m_context->getTokFloat(0), importflags, 0);
263  def.x_axis_node = Node::Ref("", (unsigned int)m_context->getTokFloat(1), importflags, 0);
264  def.y_axis_node = Node::Ref("", (unsigned int)m_context->getTokFloat(2), importflags, 0);
265 
266  def.offset.x = m_context->getTokFloat(3);
267  def.offset.y = m_context->getTokFloat(4);
268  def.offset.z = m_context->getTokFloat(5);
269 
270  def.rotation.x = m_context->getTokFloat(6);
271  def.rotation.y = m_context->getTokFloat(7);
272  def.rotation.z = m_context->getTokFloat(8);
273 
274  def.mesh_name = m_context->getTokString(9);
276 
277  switch (def.special)
278  {
279  case SpecialProp::BEACON:
280  if (n >= 14)
281  {
282  def.special_prop_beacon.flare_material_name = m_context->getTokString(10);
283  Ogre::StringUtil::trim(def.special_prop_beacon.flare_material_name);
284 
285  def.special_prop_beacon.color = Ogre::ColourValue(
286  m_context->getTokFloat(11), m_context->getTokFloat(12), m_context->getTokFloat(13));
287  }
288  break;
289 
290  case SpecialProp::DASHBOARD_LEFT:
291  case SpecialProp::DASHBOARD_RIGHT:
292  if (n > 10)
293  {
294  def.special_prop_dashboard.mesh_name = m_context->getTokString(10);
295  }
296  if (n > 13)
297  {
298  def.special_prop_dashboard.offset = Ogre::Vector3(m_context->getTokFloat(11), m_context->getTokFloat(12), m_context->getTokFloat(13));
300  }
301  if (n > 14)
302  {
303  def.special_prop_dashboard.rotation_angle = m_context->getTokFloat(14);
304  }
305  break;
306 
307  default:
308  break;
309  }
310 
311  m_module->props.push_back(def);
312 }
313 
315 {
316  Flexbody def;
317  int n = m_context->countLineArgs();
318  if (n < 10)
319  {
322  fmt::format("Error parsing addonpart file '{}': flexbody has only {} arguments, expected {}", m_addonpart_entry->fname, n, 10));
323  return;
324  }
325 
326  int importflags = Node::Ref::REGULAR_STATE_IS_VALID | Node::Ref::REGULAR_STATE_IS_NUMBERED;
327  def.reference_node = Node::Ref("", (unsigned int)m_context->getTokFloat(0), importflags, 0);
328  def.x_axis_node = Node::Ref("", (unsigned int)m_context->getTokFloat(1), importflags, 0);
329  def.y_axis_node = Node::Ref("", (unsigned int)m_context->getTokFloat(2), importflags, 0);
330 
331  def.offset.x = m_context->getTokFloat(3);
332  def.offset.y = m_context->getTokFloat(4);
333  def.offset.z = m_context->getTokFloat(5);
334 
335  def.rotation.x = m_context->getTokFloat(6);
336  def.rotation.y = m_context->getTokFloat(7);
337  def.rotation.z = m_context->getTokFloat(8);
338 
339  def.mesh_name = m_context->getTokString(9);
340 
341  m_context->seekNextLine();
342 
343  if (!m_context->isTokString())
344  {
347  fmt::format("Error parsing addonpart file '{}': flexbody is not followed by 'forset'!", m_addonpart_entry->fname));
348  return;
349  }
350 
351  Parser::ProcessForsetLine(def, m_context->getTokString());
352 
353  // Resolve `forset` ranges:
354  for (RigDef::Node::Range const& range: def.node_list_to_import)
355  {
356  for (unsigned int i = range.start.Num(); i <= range.end.Num(); ++i)
357  {
358  Node::Ref ref("", i, Node::Ref::REGULAR_STATE_IS_VALID | Node::Ref::REGULAR_STATE_IS_NUMBERED, 0);
359  def.node_list.push_back(ref);
360  }
361  }
362 
363  m_module->flexbodies.push_back(def);
364 }
365 
367 {
368  int n = m_context->countLineArgs();
369  if (n < 5)
370  {
373  fmt::format("Error parsing addonpart file '{}': flare has only {} arguments, expected {}", m_addonpart_entry->fname, n, 5));
374  return;
375  }
376 
377  Flare2 def; // We auto-import 'flares' as 'flares2', leaving the `offset.z` at 0.
378  int importflags = Node::Ref::REGULAR_STATE_IS_VALID | Node::Ref::REGULAR_STATE_IS_NUMBERED;
379  def.reference_node = Node::Ref("", (unsigned int)m_context->getTokFloat(0), importflags, 0);
380  def.node_axis_x = Node::Ref("", (unsigned int)m_context->getTokFloat(1), importflags, 0);
381  def.node_axis_y = Node::Ref("", (unsigned int)m_context->getTokFloat(2), importflags, 0);
382  def.offset.x = m_context->getTokFloat(3);
383  def.offset.y = m_context->getTokFloat(4);
384 
385  if (n > 5) def.type = (FlareType)m_context->getTokString(5)[0];
386 
387  if (n > 6)
388  {
389  switch (def.type)
390  {
391  case FlareType::USER: def.control_number = (int)m_context->getTokFloat(6); break;
392  case FlareType::DASHBOARD: def.dashboard_link = m_context->getTokString(6); break;
393  default: break;
394  }
395  }
396 
397  if (n > 7) { def.blink_delay_milis = (int)m_context->getTokFloat(7); }
398  if (n > 8) { def.size = m_context->getTokFloat(8); }
399  if (n > 9) { def.material_name = m_context->getTokString(9); }
400 
401  m_module->flares2.push_back(def);
402 }
403 
405 {
406  int n = m_context->countLineArgs();
407  if (n < 6)
408  {
411  fmt::format("Error parsing addonpart file '{}': flare2 has only {} arguments, expected {}", m_addonpart_entry->fname, n, 6));
412  return;
413  }
414 
415  Flare2 def;
416  int importflags = Node::Ref::REGULAR_STATE_IS_VALID | Node::Ref::REGULAR_STATE_IS_NUMBERED;
417  def.reference_node = Node::Ref("", (unsigned int)m_context->getTokFloat(0), importflags, 0);
418  def.node_axis_x = Node::Ref("", (unsigned int)m_context->getTokFloat(1), importflags, 0);
419  def.node_axis_y = Node::Ref("", (unsigned int)m_context->getTokFloat(2), importflags, 0);
420  def.offset.x = m_context->getTokFloat(3);
421  def.offset.y = m_context->getTokFloat(4);
422  def.offset.z = m_context->getTokFloat(5); // <-- Specific to 'flares2' (the only difference)
423 
424  if (n > 6) def.type = (FlareType)m_context->getTokString(6)[0];
425 
426  if (n > 7)
427  {
428  switch (def.type)
429  {
430  case FlareType::USER: def.control_number = (int)m_context->getTokFloat(7); break;
431  case FlareType::DASHBOARD: def.dashboard_link = m_context->getTokString(7); break;
432  default: break;
433  }
434  }
435 
436  if (n > 8) { def.blink_delay_milis = (int)m_context->getTokFloat(8); }
437  if (n > 9) { def.size = m_context->getTokFloat(9); }
438  if (n > 10) { def.material_name = m_context->getTokString(10); }
439 
440  m_module->flares2.push_back(def);
441 }
442 
443 // Helpers of `ResolveUnwantedAndTweakedElements()`, they expect `m_context` to be in position:
444 
446 {
447  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_unwanted_prop"); // also asserts !EOF and TokenType::KEYWORD
448 
449  if (m_context->isTokFloat(1))
450  {
451  if (!m_tuneup->isPropProtected((PropID_t)m_context->getTokFloat(1)))
452  {
453  m_tuneup->unwanted_props.insert((PropID_t)m_context->getTokFloat(1));
454  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': marking prop '{}' as UNWANTED",
455  m_addonpart_entry->fname, m_context->getTokKeyword(), (int)m_context->getTokFloat(1)));
456  }
457  else
458  {
459  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping prop '{}' because it's marked PROTECTED",
460  m_addonpart_entry->fname, m_context->getTokKeyword(), m_context->getTokString(1)));
461  }
462  }
463  else
464  {
465  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
466  }
467 }
468 
470 {
471  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_unwanted_flexbody"); // also asserts !EOF and TokenType::KEYWORD
472 
473  if (m_context->isTokFloat(1))
474  {
475  if (!m_tuneup->isFlexbodyProtected((FlexbodyID_t)m_context->getTokFloat(1)))
476  {
477  m_tuneup->unwanted_flexbodies.insert((FlexbodyID_t)m_context->getTokFloat(1));
478  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': marking flexbody '{}' as UNWANTED",
479  m_addonpart_entry->fname, m_context->getTokKeyword(), (int)m_context->getTokFloat(1)));
480  }
481  else
482  {
483  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping flexbody '{}' because it's marked PROTECTED",
484  m_addonpart_entry->fname, m_context->getTokKeyword(), m_context->getTokString(1)));
485  }
486  }
487  else
488  {
489  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
490  }
491 }
492 
494 {
495  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_unwanted_flare"); // also asserts !EOF and TokenType::KEYWORD
496 
497  if (m_context->isTokFloat(1))
498  {
499  if (!m_tuneup->isFlareProtected((FlareID_t)m_context->getTokFloat(1)))
500  {
501  m_tuneup->unwanted_flares.insert((FlareID_t)m_context->getTokFloat(1));
502  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': marking flare '{}' as UNWANTED",
503  m_addonpart_entry->fname, m_context->getTokKeyword(), (int)m_context->getTokFloat(1)));
504  }
505  else
506  {
507  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping flare '{}' because it's marked PROTECTED",
508  m_addonpart_entry->fname, m_context->getTokKeyword(), m_context->getTokString(1)));
509  }
510  }
511  else
512  {
513  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
514  }
515 }
516 
518 {
519  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_unwanted_exhaust"); // also asserts !EOF and TokenType::KEYWORD
520 
521  if (m_context->isTokFloat(1))
522  {
523  if (!m_tuneup->isExhaustProtected((ExhaustID_t)m_context->getTokFloat(1)))
524  {
525  m_tuneup->unwanted_exhausts.insert((ExhaustID_t)m_context->getTokFloat(1));
526  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': marking exhaust '{}' as UNWANTED",
527  m_addonpart_entry->fname, m_context->getTokKeyword(), (int)m_context->getTokFloat(1)));
528  }
529  else
530  {
531  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping exhaust '{}' because it's marked PROTECTED",
532  m_addonpart_entry->fname, m_context->getTokKeyword(), m_context->getTokString(1)));
533  }
534  }
535  else
536  {
537  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
538  }
539 }
540 
542 {
543  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_unwanted_managedmaterial"); // also asserts !EOF and TokenType::KEYWORD
544 
545  if (m_context->isTokString(1))
546  {
547  std::string mat_name = m_context->getTokString(1);
548  if (!m_tuneup->isManagedMatProtected(mat_name))
549  {
550  m_tuneup->unwanted_managedmats.insert(mat_name);
551  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': marking managedmaterial '{}' as UNWANTED",
552  m_addonpart_entry->fname, m_context->getTokKeyword(), mat_name));
553  }
554  else
555  {
556  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping managedmaterial '{}' because it's marked PROTECTED",
557  m_addonpart_entry->fname, m_context->getTokKeyword(), mat_name));
558  }
559  }
560  else
561  {
562  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
563  }
564 }
565 
567 {
568  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_tweak_wheel"); // also asserts !EOF and TokenType::KEYWORD
569 
570  if (m_context->isTokFloat(1) && m_context->isTokString(2))
571  {
572  const int wheel_id = (int)m_context->getTokFloat(1);
573  if (!m_tuneup->isWheelProtected(wheel_id))
574  {
575  if (m_tuneup->wheel_tweaks.find(wheel_id) == m_tuneup->wheel_tweaks.end())
576  {
577  TuneupWheelTweak data;
578  bool stop = false;
579  data.twt_origin = m_addonpart_entry->fname;
580  data.twt_wheel_id = wheel_id;
581  data.twt_media[0] = m_context->getTokString(2);
582  if (!stop && m_context->isTokString(3)) { data.twt_media[1] = m_context->getTokString(3); } else { stop=true; }
583  if (!stop && m_context->isTokString(4)) { data.twt_side = (m_context->getTokString(4)[0] == 'l') ? WheelSide::LEFT : WheelSide::RIGHT; } else { stop=true; }
584  if (!stop && m_context->isTokFloat(5)) { data.twt_tire_radius = m_context->getTokFloat(5); } else { stop=true; }
585  if (!stop && m_context->isTokFloat(6)) { data.twt_rim_radius = m_context->getTokFloat(6); } else { stop=true; }
586  m_tuneup->wheel_tweaks.insert(std::make_pair(wheel_id, data));
587 
588  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': Sheduling tweak for wheel '{}'"
589  " with params {{ media1={}, media2={}, side={}, tire_radius={}, rim_radius={} }}",
590  m_addonpart_entry->fname, m_context->getTokKeyword(), wheel_id,
591  data.twt_media[0], data.twt_media[1], (char)data.twt_side, data.twt_tire_radius, data.twt_rim_radius));
592  }
593  else if (m_tuneup->wheel_tweaks[wheel_id].twt_origin != m_addonpart_entry->fname)
594  {
595  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': Resetting tweaks for wheel '{}' due to conflict with '{}'",
596  m_addonpart_entry->fname, m_context->getTokKeyword(), wheel_id,
597  m_tuneup->wheel_tweaks[wheel_id].twt_origin));
598 
599  m_tuneup->wheel_tweaks.erase(wheel_id);
600  }
601  }
602  else
603  {
604  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping wheel '{}' because it's marked PROTECTED",
605  m_addonpart_entry->fname, m_context->getTokKeyword(), (int)m_context->getTokFloat(1)));
606  }
607  }
608  else
609  {
610  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
611  }
612 }
613 
615 {
616  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_tweak_node"); // also asserts !EOF and TokenType::KEYWORD
617 
618  if (m_context->isTokFloat(1) && m_context->isTokFloat(1) && m_context->isTokFloat(2) && m_context->isTokFloat(3))
619  {
620  NodeNum_t nodenum = (NodeNum_t)m_context->getTokFloat(1);
621  if (!m_tuneup->isNodeProtected(nodenum))
622  {
623  if (m_tuneup->node_tweaks.find(nodenum) == m_tuneup->node_tweaks.end())
624  {
625  TuneupNodeTweak data;
626  data.tnt_origin = m_addonpart_entry->fname;
627  data.tnt_nodenum = nodenum;
628  data.tnt_pos.x = m_context->getTokFloat(2);
629  data.tnt_pos.y = m_context->getTokFloat(3);
630  data.tnt_pos.z = m_context->getTokFloat(4);
631  m_tuneup->node_tweaks.insert(std::make_pair(nodenum, data));
632 
633  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': Scheduling tweak for node '{}'"
634  " with params {{ x={}, y={}, z={} }}",
635  m_addonpart_entry->fname, m_context->getTokKeyword(), nodenum,
636  data.tnt_pos.x, data.tnt_pos.y, data.tnt_pos.z));
637  }
638  else if (m_tuneup->node_tweaks[nodenum].tnt_origin != m_addonpart_entry->fname)
639  {
640  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': Resetting tweaks for node '{}' due to conflict with '{}'",
641  m_addonpart_entry->fname, m_context->getTokKeyword(), nodenum,
642  m_tuneup->node_tweaks[nodenum].tnt_origin));
643 
644  m_tuneup->node_tweaks.erase(nodenum);
645  }
646  }
647  else
648  {
649  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping node '{}' because it's marked PROTECTED",
650  m_addonpart_entry->fname, m_context->getTokKeyword(), nodenum));
651  }
652  }
653  else
654  {
655  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
656  }
657 }
658 
660 {
661  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_tweak_flexbody"); // also asserts !EOF and TokenType::KEYWORD
662 
663  // TBD: add `null` token type to GenericDocument, so these params can be made optional
664  if (m_context->isTokFloat(1) && // ID
665  m_context->isTokFloat(2) && m_context->isTokFloat(3) && m_context->isTokFloat(4) && // offset
666  m_context->isTokFloat(5) && m_context->isTokFloat(6) && m_context->isTokFloat(7) && // rotation
667  m_context->isTokString(8)) // media
668  {
669  const int flexbody_id = (int)m_context->getTokFloat(1);
670  if (!m_tuneup->isFlexbodyProtected(flexbody_id))
671  {
672  if (m_tuneup->flexbody_tweaks.find(flexbody_id) == m_tuneup->flexbody_tweaks.end())
673  {
674  TuneupFlexbodyTweak data;
675  data.tft_origin = m_addonpart_entry->fname;
676  data.tft_flexbody_id = flexbody_id;
677  data.tft_offset.x = m_context->getTokFloat(2);
678  data.tft_offset.y = m_context->getTokFloat(3);
679  data.tft_offset.z = m_context->getTokFloat(4);
680  data.tft_rotation.x = m_context->getTokFloat(5);
681  data.tft_rotation.y = m_context->getTokFloat(6);
682  data.tft_rotation.z = m_context->getTokFloat(7);
683  data.tft_media = m_context->getTokString(8);
684  m_tuneup->flexbody_tweaks.insert(std::make_pair(flexbody_id, data));
685 
686  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': Scheduling tweak for flexbody '{}'"
687  " with params {{ offsetX={}, offsetY={}, offsetZ={}, rotX={}, rotY={}, rotZ={}, media={} }}",
688  m_addonpart_entry->fname, m_context->getTokKeyword(), flexbody_id,
689  data.tft_offset.x, data.tft_offset.y, data.tft_offset.z,
690  data.tft_rotation.x, data.tft_rotation.y, data.tft_rotation.z, data.tft_media[0]));
691  }
692  else if (m_tuneup->flexbody_tweaks[flexbody_id].tft_origin != m_addonpart_entry->fname)
693  {
694  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': Resetting tweaks for flexbody '{}' due to conflict with '{}'",
695  m_addonpart_entry->fname, m_context->getTokKeyword(), flexbody_id,
696  m_tuneup->flexbody_tweaks[flexbody_id].tft_origin));
697 
698  m_tuneup->flexbody_tweaks.erase(flexbody_id);
699  }
700  }
701  else
702  {
703  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping flexbody '{}' because it's marked PROTECTED",
704  m_addonpart_entry->fname, m_context->getTokKeyword(), (int)m_context->getTokFloat(1)));
705  }
706  }
707  else
708  {
709  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
710  }
711 }
712 
714 {
715  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_tweak_prop"); // also asserts !EOF and TokenType::KEYWORD
716 
717  // TBD: add `null` token type to GenericDocument, so these params can be made optional
718  if (m_context->isTokFloat(1) && // ID
719  m_context->isTokFloat(2) && m_context->isTokFloat(3) && m_context->isTokFloat(4) && // offset
720  m_context->isTokFloat(5) && m_context->isTokFloat(6) && m_context->isTokFloat(7) && // rotation
721  m_context->isTokString(8)) // media
722  {
723  const int prop_id = (int)m_context->getTokFloat(1);
724  if (!m_tuneup->isPropProtected(prop_id))
725  {
726  if (m_tuneup->prop_tweaks.find(prop_id) == m_tuneup->prop_tweaks.end())
727  {
728  TuneupPropTweak data;
729  data.tpt_origin = m_addonpart_entry->fname;
730  data.tpt_prop_id = prop_id;
731 
732  data.tpt_offset.x = m_context->getTokFloat(2);
733  data.tpt_offset.y = m_context->getTokFloat(3);
734  data.tpt_offset.z = m_context->getTokFloat(4);
735  data.tpt_rotation.x = m_context->getTokFloat(5);
736  data.tpt_rotation.y = m_context->getTokFloat(6);
737  data.tpt_rotation.z = m_context->getTokFloat(7);
738  data.tpt_media[0] = m_context->getTokString(8);
739  if (m_context->isTokString(9)) data.tpt_media[1] = m_context->getTokString(9); // <== Optional Media2 is specific for prop
740  m_tuneup->prop_tweaks.insert(std::make_pair(prop_id, data));
741 
742  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': Scheduling tweak for prop '{}'"
743  " with params {{ media1={}, offsetX={}, offsetY={}, offsetZ={}, rotX={}, rotY={}, rotZ={}, media2={} }}",
744  m_addonpart_entry->fname, m_context->getTokKeyword(), prop_id, data.tpt_media[0],
745  data.tpt_offset.x, data.tpt_offset.y, data.tpt_offset.z,
746  data.tpt_rotation.x, data.tpt_rotation.y, data.tpt_rotation.z,
747  data.tpt_media[1]));
748  }
749  else if (m_tuneup->prop_tweaks[prop_id].tpt_origin != m_addonpart_entry->fname)
750  {
751  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': Resetting tweaks for prop '{}' due to conflict with '{}'",
752  m_addonpart_entry->fname, m_context->getTokKeyword(), prop_id,
753  m_tuneup->prop_tweaks[prop_id].tpt_origin));
754 
755  m_tuneup->prop_tweaks.erase(prop_id);
756  }
757  }
758  else
759  {
760  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping prop '{}' because it's marked PROTECTED",
761  m_addonpart_entry->fname, m_context->getTokKeyword(), (int)m_context->getTokFloat(1)));
762  }
763  }
764  else
765  {
766  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': bad arguments", m_addonpart_entry->fname, m_context->getTokKeyword()));
767  }
768 }
769 
771 {
772  ROR_ASSERT(m_context->getTokKeyword() == "addonpart_tweak_managedmaterial"); // also asserts !EOF and TokenType::KEYWORD
773 
774  if (m_context->isTokString(1) && m_context->isTokString(2))
775  {
776  const std::string& mat_name = m_context->getTokString(1);
777  if (!m_tuneup->isManagedMatProtected(mat_name))
778  {
779  if (m_tuneup->managedmat_tweaks.find(mat_name) == m_tuneup->managedmat_tweaks.end())
780  {
782  bool stop=false;
783  data.tmt_origin = m_addonpart_entry->fname;
784  data.tmt_name = mat_name;
785  data.tmt_type = m_context->getTokString(2);
786  if (!stop && m_context->isTokString(3)) { data.tmt_media[0] = m_context->getTokString(3); } else {stop=true;}
787  if (!stop && m_context->isTokString(4)) { data.tmt_media[1] = m_context->getTokString(4); } else {stop=true;}
788  if (!stop && m_context->isTokString(5)) { data.tmt_media[2] = m_context->getTokString(5); } else {stop=true;}
789  m_tuneup->managedmat_tweaks.insert(std::make_pair(mat_name, data));
790 
791  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': Scheduling tweak for managed material '{}'"
792  " with params {{ type={}, media1={}, media2={}, media3={} }}",
793  m_addonpart_entry->fname, m_context->getTokKeyword(), mat_name, data.tmt_type, data.tmt_media[0], data.tmt_media[1], data.tmt_media[2]));
794  }
795  else if (m_tuneup->managedmat_tweaks[mat_name].tmt_origin != m_addonpart_entry->fname)
796  {
797  this->Log(fmt::format("[RoR|Addonpart] WARNING: file '{}', directive '{}': Resetting tweaks for managed material '{}' due to conflict with '{}'",
798  m_addonpart_entry->fname, m_context->getTokKeyword(), mat_name,
799  m_tuneup->managedmat_tweaks[mat_name].tmt_origin));
800 
801  m_tuneup->managedmat_tweaks.erase(mat_name);
802  }
803  }
804  else
805  {
806  this->Log(fmt::format("[RoR|Addonpart] INFO: file '{}', directive '{}': skipping managed material '{}' because it's marked PROTECTED",
807  m_addonpart_entry->fname, m_context->getTokKeyword(), mat_name));
808  }
809  }
810 }
811 
813 {
814  LOG(fmt::format("[RoR|Addonpart] -- Performing `RecordAddonpartConflicts()` between '{}' and '{}' ~ this involves generating dummy tuneups (hence messages below) --", addonpart1->fname, addonpart2->fname));
815 
816  // Make sure both addonparts are loaded and cached.
817  App::GetCacheSystem()->LoadResource(addonpart1);
818  if (!addonpart1->addonpart_data_only)
819  {
820  addonpart1->addonpart_data_only = new TuneupDef();
821  AddonPartUtility util(/*silent mode:*/true);
822  util.ResolveUnwantedAndTweakedElements(addonpart1->addonpart_data_only, addonpart1);
823  }
824 
825  App::GetCacheSystem()->LoadResource(addonpart2);
826  if (!addonpart2->addonpart_data_only)
827  {
828  addonpart2->addonpart_data_only = new TuneupDef();
829  AddonPartUtility util(/*silent mode:*/true);
830  util.ResolveUnwantedAndTweakedElements(addonpart2->addonpart_data_only, addonpart2);
831  }
832 
833  // NODE TWEAKS:
834  for (auto& i_pair: addonpart1->addonpart_data_only->node_tweaks)
835  {
836  NodeNum_t suspect = i_pair.second.tnt_nodenum;
837  TuneupNodeTweak* offender = nullptr;
838  if (TuneupUtil::isNodeTweaked(addonpart2->addonpart_data_only, suspect, offender))
839  {
840  conflicts.push_back(AddonPartConflict{addonpart1, addonpart2, "addonpart_tweak_node", (int)suspect});
841  LOG(fmt::format("[RoR|Addonpart] Found conflict between '{}' and '{}' - node {} is tweaked by both", addonpart1->fname, addonpart2->fname, (int)suspect));
842  }
843  }
844 
845  // WHEEL TWEAKS:
846  for (auto& i_pair: addonpart1->addonpart_data_only->wheel_tweaks)
847  {
848  WheelID_t suspect = i_pair.second.twt_wheel_id;
849  TuneupWheelTweak* offender = nullptr;
850  if (TuneupUtil::isWheelTweaked(addonpart2->addonpart_data_only, suspect, offender))
851  {
852  conflicts.push_back(AddonPartConflict{addonpart1, addonpart2, "addonpart_tweak_wheel", (int)suspect});
853  LOG(fmt::format("[RoR|Addonpart] Found conflict between '{}' and '{}' - wheel {} is tweaked by both", addonpart1->fname, addonpart2->fname, (int)suspect));
854  }
855  }
856 
857  // PROP TWEAKS:
858  for (auto& i_pair:addonpart1->addonpart_data_only->prop_tweaks)
859  {
860  PropID_t suspect = i_pair.second.tpt_prop_id;
861  TuneupPropTweak* offender = nullptr;
862  if (TuneupUtil::isPropTweaked(addonpart2->addonpart_data_only, suspect, offender))
863  {
864  conflicts.push_back(AddonPartConflict{addonpart1, addonpart2, "addonpart_tweak_prop", (int)suspect});
865  LOG(fmt::format("[RoR|Addonpart] Found conflict between '{}' and '{}' - prop {} is tweaked by both", addonpart1->fname, addonpart2->fname, (int)suspect));
866  }
867  }
868 
869  // FLEXBODY TWEAKS:
870  for (auto& i_pair: addonpart1->addonpart_data_only->flexbody_tweaks)
871  {
872  FlexbodyID_t suspect = i_pair.second.tft_flexbody_id;
873  TuneupFlexbodyTweak* offender = nullptr;
874  if (TuneupUtil::isFlexbodyTweaked(addonpart2->addonpart_data_only, suspect, offender))
875  {
876  conflicts.push_back(AddonPartConflict{addonpart1, addonpart2, "addonpart_tweak_flexbody", (int)suspect});
877  LOG(fmt::format("[RoR|Addonpart] Found conflict between '{}' and '{}' - flexbody {} is tweaked by both", addonpart1->fname, addonpart2->fname, (int)suspect));
878  }
879  }
880 
881  LOG(fmt::format("[RoR|Addonpart] -- Done with `RecordAddonpartConflicts()` between '{}' and '{}' --", addonpart1->fname, addonpart2->fname));
882 }
883 
885 {
886  if (!addonpart1 || !addonpart2)
887  {
888  return false;
889  }
890 
891  for (AddonPartConflict& conflict: conflicts)
892  {
893  if ((conflict.atc_addonpart1 == addonpart1 && conflict.atc_addonpart2 == addonpart2) ||
894  (conflict.atc_addonpart1 == addonpart2 && conflict.atc_addonpart2 == addonpart1))
895  {
896  return true;
897  }
898  }
899  return false;
900 }
901 
902 void AddonPartUtility::Log(const std::string& text)
903 {
904  if (!m_silent_mode)
905  {
906  LOG(text);
907  }
908 }
909 
911 {
912  // Re-check conflicts (request may come from 'Browse all' button or script).
913  // -------------------------------------------------------------------------
914 
915  AddonPartConflictVec conflicts;
916  for (const std::string& use_addonpart: target_actor->getWorkingTuneupDef()->use_addonparts)
917  {
918  CacheEntryPtr use_entry = App::GetCacheSystem()->FindEntryByFilename(LT_AddonPart, /*partial=*/false, use_addonpart);
919  AddonPartUtility::RecordAddonpartConflicts(addonpart_entry, use_entry, conflicts);
920  }
921 
922  if (conflicts.size() > 0)
923  {
924  // Messagebox text
926  dialog->mbc_content_width = 700.f;
927  dialog->mbc_title = _LC("Tuning", "Cannot install addon part, conflicts were detected.");
928  dialog->mbc_text = fmt::format(_LC("Tuning", "Requested addon part: '{}' (file '{}')."), addonpart_entry->dname, addonpart_entry->fname);
929  dialog->mbc_text += "\n";
930  dialog->mbc_text += fmt::format(_LC("Tuning", "Total conflicts: {}."), conflicts.size());
931  dialog->mbc_text += "\n";
932  for (size_t i=0; i < conflicts.size(); i++)
933  {
934  dialog->mbc_text += "\n";
935  dialog->mbc_text += fmt::format(_LC("Tuning", "[{}/{}] '{}' (file '{}') conflicts with '{}' #{}."),
936  i+1, conflicts.size(),
937  conflicts[i].atc_addonpart2->dname, conflicts[i].atc_addonpart2->fname,
938  conflicts[i].atc_keyword, conflicts[i].atc_element_id);
939  }
940 
941  // Messagebox OK button
942  GUI::MessageBoxButton ok_btn;
943  ok_btn.mbb_caption = _LC("Tuning", "OK");
945  dialog->mbc_buttons.push_back(ok_btn);
946 
947  // Show the messagebox
949  }
950  return conflicts.size() > 0;
951 }
RoR::TuneupDef
Dual purpose:
Definition: TuneupFileFormat.h:93
RoR::GUI::MessageBoxConfig::mbc_buttons
std::vector< MessageBoxButton > mbc_buttons
Definition: GUI_MessageBox.h:59
ROR_ASSERT
#define ROR_ASSERT(_EXPR)
Definition: Application.h:40
GameContext.h
Game state manager and message-queue provider.
RoR::AddonPartUtility::ResolveUnwantedAndTweakedElements
void ResolveUnwantedAndTweakedElements(TuneupDefPtr &tuneup, CacheEntryPtr &addonpart_entry)
Evaluates 'addonpart_unwanted_*' elements, respecting 'protected_*' directives in the tuneup.
Definition: AddonPartFileFormat.cpp:132
RoR::MSG_GUI_SHOW_MESSAGE_BOX_REQUESTED
@ MSG_GUI_SHOW_MESSAGE_BOX_REQUESTED
Payload = MessageBoxConfig* (owner)
Definition: Application.h:138
RigDef::Prop::DashboardSpecial::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:1089
RoR::TuneupWheelTweak::twt_origin
std::string twt_origin
Addonpart filename.
Definition: TuneupFileFormat.h:60
RoR::CacheEntry::dname
Ogre::String dname
name parsed from the file
Definition: CacheSystem.h:70
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::Prop
Definition: RigDef_File.h:1078
RoR::TuneupNodeTweak::tnt_nodenum
NodeNum_t tnt_nodenum
Arg#1, required.
Definition: TuneupFileFormat.h:46
RigDef::Prop::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:1109
RoR::TuneupUtil::isWheelTweaked
static bool isWheelTweaked(TuneupDefPtr &tuneup_entry, WheelID_t wheel_id, TuneupWheelTweak *&out_tweak)
Definition: TuneupFileFormat.cpp:219
RoR::TuneupWheelTweak::twt_tire_radius
float twt_tire_radius
Arg#5, optional.
Definition: TuneupFileFormat.h:58
RigDef::ManagedMaterial::diffuse_map
Ogre::String diffuse_map
Definition: RigDef_File.h:1026
RigDef::Flare2::type
RoR::FlareType type
Definition: RigDef_File.h:882
RoR::TuneupDef::unwanted_props
std::set< PropID_t > unwanted_props
'addonpart_unwanted_prop' directives.
Definition: TuneupFileFormat.h:116
RoR::LT_AddonPart
@ LT_AddonPart
Definition: Application.h:304
RoR::TuneupPropTweak
< Data of 'addonpart_tweak_prop <prop ID> <offsetX> <offsetY> <offsetZ> <rotX> <rotY> <rotZ> <media1>...
Definition: TuneupFileFormat.h:64
RoR::TuneupWheelTweak::twt_rim_radius
float twt_rim_radius
Arg#6, optional, only applies to some wheel types.
Definition: TuneupFileFormat.h:59
RoR::TuneupFlexbodyTweak::tft_rotation
Ogre::Vector3 tft_rotation
Definition: TuneupFileFormat.h:78
GUI_MessageBox.h
Generic UI dialog (not modal). Invocable from scripting. Any number of buttons. Configurable to fire ...
RigDef::Node::Range::start
Node::Ref start
Definition: RigDef_Node.h:134
RoR::AddonPartUtility::ProcessUnwantedFlare
void ProcessUnwantedFlare()
Definition: AddonPartFileFormat.cpp:493
RoR::TuneupUtil::isPropTweaked
static bool isPropTweaked(TuneupDefPtr &tuneup_entry, PropID_t flexbody_id, TuneupPropTweak *&out_tweak)
Definition: TuneupFileFormat.cpp:341
RoR::AddonPartUtility::ProcessUnwantedExhaust
void ProcessUnwantedExhaust()
Definition: AddonPartFileFormat.cpp:517
RoR::TuneupFlexbodyTweak::tft_origin
std::string tft_origin
Addonpart filename.
Definition: TuneupFileFormat.h:79
RoR::TuneupManagedMatTweak::tmt_type
std::string tmt_type
Arg#2, required.
Definition: TuneupFileFormat.h:85
RigDef::Prop::DashboardSpecial::mesh_name
Ogre::String mesh_name
Definition: RigDef_File.h:1092
RoR::TuneupFlexbodyTweak::tft_media
std::string tft_media
Definition: TuneupFileFormat.h:76
RigDef::Prop::rotation
Ogre::Vector3 rotation
Definition: RigDef_File.h:1110
RigDef::ManagedMaterial::damaged_diffuse_map
Ogre::String damaged_diffuse_map
Definition: RigDef_File.h:1027
RoR::TuneupDef::prop_tweaks
std::map< PropID_t, TuneupPropTweak > prop_tweaks
Mesh name(s), offset and rotation overrides via 'addonpart_tweak_prop'.
Definition: TuneupFileFormat.h:113
format
Truck file format(technical spec)
RoR::TuneupDef::unwanted_flexbodies
std::set< FlexbodyID_t > unwanted_flexbodies
'addonpart_unwanted_flexbody' directives.
Definition: TuneupFileFormat.h:117
RoR::GenericDocument::OPTION_ALLOW_SLASH_COMMENTS
static const BitMask_t OPTION_ALLOW_SLASH_COMMENTS
Allow comments starting with //.
Definition: GenericFileFormat.h:68
RigDef::Flexbody::rotation
Ogre::Vector3 rotation
Definition: RigDef_File.h:901
RigDef::Flexbody::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:900
RoR::FlareType::USER
@ USER
RigDef::Flare2
Definition: RigDef_File.h:876
Console.h
RoR::AddonPartUtility::ProcessUnwantedManagedMat
void ProcessUnwantedManagedMat()
Definition: AddonPartFileFormat.cpp:541
RoR::Console::putMessage
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition: Console.cpp:97
RigDef::Flare2::node_axis_y
Node::Ref node_axis_y
Definition: RigDef_File.h:880
RoR::AddonPartUtility::TransformToRigDefModule
std::shared_ptr< RigDef::Document::Module > TransformToRigDefModule(CacheEntryPtr &addonpart_entry)
transforms the addonpart to RigDef::File::Module (fake 'section/end_section') used for spawning.
Definition: AddonPartFileFormat.cpp:49
RoR::TuneupPropTweak::tpt_prop_id
PropID_t tpt_prop_id
Definition: TuneupFileFormat.h:66
RigDef::Flare2::blink_delay_milis
int blink_delay_milis
Definition: RigDef_File.h:885
RigDef::Document::Module
Definition: RigDef_File.h:1479
RoR::CacheEntry::resource_group
Ogre::String resource_group
Resource group of the loaded bundle. Empty if not loaded yet.
Definition: CacheSystem.h:89
RoR::GUI::MessageBoxButton::mbb_caption
std::string mbb_caption
Definition: GUI_MessageBox.h:43
RoR::FlareType
FlareType
Definition: SimData.h:229
TuneupFileFormat.h
The vehicle tuning system; applies addonparts and user overrides to vehicles.
RoR::TuneupDef::use_addonparts
std::set< std::string > use_addonparts
Addonpart filenames.
Definition: TuneupFileFormat.h:109
RigDef::Node::Range
Definition: RigDef_Node.h:114
RoR::AddonPartUtility::ProcessTweakProp
void ProcessTweakProp()
Definition: AddonPartFileFormat.cpp:713
RigDef::Flexbody::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:897
RoR::TuneupPropTweak::tpt_rotation
Ogre::Vector3 tpt_rotation
Definition: TuneupFileFormat.h:69
RoR::AddonPartConflictVec
std::vector< AddonPartConflict > AddonPartConflictVec
Definition: AddonPartFileFormat.h:53
RefCountingObjectPtr< CacheEntry >
RoR::AddonPartUtility::ProcessTweakNode
void ProcessTweakNode()
Definition: AddonPartFileFormat.cpp:614
RoR::AddonPartUtility::ProcessManagedMaterial
void ProcessManagedMaterial()
Definition: AddonPartFileFormat.cpp:210
Actor.h
RoR::ExhaustID_t
int ExhaustID_t
Index into Actor::exhausts, use RoR::EXHAUSTID_INVALID as empty value.
Definition: ForwardDeclarations.h:71
RoR::TuneupWheelTweak::twt_wheel_id
WheelID_t twt_wheel_id
Arg#1, required.
Definition: TuneupFileFormat.h:53
RoR::AddonPartUtility::ProcessDirectiveSetManagedMaterialsOptions
void ProcessDirectiveSetManagedMaterialsOptions()
Definition: AddonPartFileFormat.cpp:239
RoR::TuneupUtil::isNodeTweaked
static bool isNodeTweaked(TuneupDefPtr &tuneup_entry, NodeNum_t nodenum, TuneupNodeTweak *&out_tweak)
Definition: TuneupFileFormat.cpp:250
RigDef::ManagedMaterial::type
ManagedMaterialType type
Definition: RigDef_File.h:1024
RoR::TuneupFlexbodyTweak::tft_flexbody_id
FlexbodyID_t tft_flexbody_id
Definition: TuneupFileFormat.h:75
RigDef::ManagedMaterial::options
ManagedMaterialsOptions options
Definition: RigDef_File.h:1025
RigDef::ManagedMaterial::name
Ogre::String name
Definition: RigDef_File.h:1023
RigDef::Prop::special
SpecialProp special
Definition: RigDef_File.h:1114
RoR::AddonPartUtility::ProcessUnwantedProp
void ProcessUnwantedProp()
Definition: AddonPartFileFormat.cpp:445
RoR::FlareType::DASHBOARD
@ DASHBOARD
RoR::AddonPartUtility::ResetUnwantedAndTweakedElements
static void ResetUnwantedAndTweakedElements(TuneupDefPtr &tuneup)
Definition: AddonPartFileFormat.cpp:190
RigDef::Flare2::material_name
Ogre::String material_name
Definition: RigDef_File.h:887
RoR::TuneupDef::node_tweaks
std::map< NodeNum_t, TuneupNodeTweak > node_tweaks
Node position overrides via 'addonpart_tweak_node'.
Definition: TuneupFileFormat.h:111
RoR::TuneupDef::unwanted_flares
std::set< FlareID_t > unwanted_flares
'addonpart_unwanted_flare' directives.
Definition: TuneupFileFormat.h:118
RoR::TuneupManagedMatTweak
< Data of 'addonpart_tweak_managedmaterial <name> <type> <media1> <media2> [<media3>]'
Definition: TuneupFileFormat.h:82
RigDef::Flare2::dashboard_link
std::string dashboard_link
Only 'd' type flares.
Definition: RigDef_File.h:884
RoR::TuneupManagedMatTweak::tmt_origin
std::string tmt_origin
Addonpart filename.
Definition: TuneupFileFormat.h:87
RoR::NodeNum_t
uint16_t NodeNum_t
Node position within Actor::ar_nodes; use RoR::NODENUM_INVALID as empty value.
Definition: ForwardDeclarations.h:52
RoR::CacheSystem::FindEntryByFilename
CacheEntryPtr FindEntryByFilename(RoR::LoaderType type, bool partial, const std::string &_filename_maybe_bundlequalified)
Returns NULL if none found; "Bundle-qualified" format also specifies the ZIP/directory in modcache,...
Definition: CacheSystem.cpp:184
RoR::GUI::MessageBoxButton
Definition: GUI_MessageBox.h:41
RoR::TuneupNodeTweak
< Data of 'addonpart_tweak_node <nodenum> <posX> <posY> <posZ>'
Definition: TuneupFileFormat.h:44
RoR::AddonPartUtility::RecordAddonpartConflicts
static void RecordAddonpartConflicts(CacheEntryPtr addonpart1, CacheEntryPtr addonpart2, AddonPartConflictVec &conflicts)
Definition: AddonPartFileFormat.cpp:812
CacheSystem.h
A database of user-installed content alias 'mods' (vehicles, terrains...)
keyword
static int keyword
Definition: Bench_TruckParser_IdentifyKeyword.cpp:1448
RigDef::Parser::IdentifySpecialProp
static SpecialProp IdentifySpecialProp(const std::string &str)
Definition: RigDef_Parser.cpp:3299
RigDef
Definition: RigDef_File.cpp:32
RigDef::Keyword
Keyword
Definition: RigDef_File.h:65
RigDef::Node::Range::end
Node::Ref end
Definition: RigDef_Node.h:135
RoR::TuneupWheelTweak::twt_side
WheelSide twt_side
Arg#4, optional, default LEFT (Only applicable to mesh/flexbody wheels)
Definition: TuneupFileFormat.h:57
RoR::TuneupDef::flexbody_tweaks
std::map< FlexbodyID_t, TuneupFlexbodyTweak > flexbody_tweaks
Mesh name, offset and rotation overrides via 'addonpart_tweak_flexbody'.
Definition: TuneupFileFormat.h:114
RoR::AddonPartUtility::ProcessTweakWheel
void ProcessTweakWheel()
Definition: AddonPartFileFormat.cpp:566
RoR::GameContext::PushMessage
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
Definition: GameContext.cpp:65
RigDef::Flare2::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:878
RoR::WheelID_t
int WheelID_t
Index to Actor::ar_wheels, use RoR::WHEELID_INVALID as empty value.
Definition: ForwardDeclarations.h:56
RoR::GUI::MessageBoxConfig::mbc_title
std::string mbc_title
Definition: GUI_MessageBox.h:52
RigDef::ManagedMaterial::specular_map
Ogre::String specular_map
Definition: RigDef_File.h:1028
RoR::TuneupNodeTweak::tnt_pos
Ogre::Vector3 tnt_pos
Args#234, required.
Definition: TuneupFileFormat.h:47
RigDef::Flare2::offset
Ogre::Vector3 offset
Definition: RigDef_File.h:881
RigDef::Prop::DashboardSpecial::_offset_is_set
bool _offset_is_set
Definition: RigDef_File.h:1090
RigDef::Flexbody::node_list_to_import
std::vector< Node::Range > node_list_to_import
Definition: RigDef_File.h:904
RoR::WheelSide::RIGHT
@ RIGHT
RigDef::ManagedMaterial
Definition: RigDef_File.h:1021
RoR::WheelSide::LEFT
@ LEFT
Application.h
Central state/object manager and communications hub.
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:270
RoR::TuneupPropTweak::tpt_origin
std::string tpt_origin
Addonpart filename.
Definition: TuneupFileFormat.h:70
RigDef::Flexbody::mesh_name
Ogre::String mesh_name
Definition: RigDef_File.h:902
RoR::AddonPartConflict
< Conflict between two addonparts tweaking the same element
Definition: AddonPartFileFormat.h:38
RoR::AddonPartUtility::DoubleCheckForAddonpartConflict
static bool DoubleCheckForAddonpartConflict(ActorPtr target_actor, CacheEntryPtr addonpart_entry)
Definition: AddonPartFileFormat.cpp:910
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:280
RoR::GUI::MessageBoxConfig::mbc_text
std::string mbc_text
Definition: GUI_MessageBox.h:53
RigDef::Prop::mesh_name
Ogre::String mesh_name
Definition: RigDef_File.h:1111
RoR::AddonPartUtility::Log
void Log(const std::string &text)
Definition: AddonPartFileFormat.cpp:902
RigDef::Flare2::node_axis_x
Node::Ref node_axis_x
Definition: RigDef_File.h:879
_LC
#define _LC(ctx, str)
Definition: Language.h:42
RigDef::Flexbody
Definition: RigDef_File.h:895
RoR::GUI::MessageBoxButton::mbb_mq_message
MsgType mbb_mq_message
Message to queue on click.
Definition: GUI_MessageBox.h:44
RoR::AddonPartUtility::ProcessTweakFlexbody
void ProcessTweakFlexbody()
Definition: AddonPartFileFormat.cpp:659
RigDef::Prop::y_axis_node
Node::Ref y_axis_node
Definition: RigDef_File.h:1108
RoR::AddonPartUtility::CheckForAddonpartConflict
static bool CheckForAddonpartConflict(CacheEntryPtr addonpart1, CacheEntryPtr addonpart2, AddonPartConflictVec &conflicts)
Definition: AddonPartFileFormat.cpp:884
RoR::TuneupWheelTweak::twt_media
std::array< std::string, 2 > twt_media
twt_media[0] Arg#2, required ('wheels[2]': face material, 'meshwheels[2]/flexbodywheels': rim mesh) t...
Definition: TuneupFileFormat.h:56
RoR::App::GetCacheSystem
CacheSystem * GetCacheSystem()
Definition: Application.cpp:272
RoR::TuneupPropTweak::tpt_media
std::array< std::string, 2 > tpt_media
Media1 = prop mesh; Media2: Steering wheel mesh or beacon flare material.
Definition: TuneupFileFormat.h:67
RigDef::Flexbody::node_list
std::vector< Node::Ref > node_list
Definition: RigDef_File.h:905
RoR::TuneupNodeTweak::tnt_origin
std::string tnt_origin
Addonpart filename.
Definition: TuneupFileFormat.h:48
RoR::TuneupPropTweak::tpt_offset
Ogre::Vector3 tpt_offset
Definition: TuneupFileFormat.h:68
RoR::GUI::MessageBoxConfig
Definition: GUI_MessageBox.h:50
RigDef::Flare2::size
float size
Definition: RigDef_File.h:886
RoR::CacheSystem::LoadResource
void LoadResource(CacheEntryPtr &t)
Loads the associated resource bundle if not already done.
Definition: CacheSystem.cpp:1435
RoR::GenericDocument
Definition: GenericFileFormat.h:65
RoR::Message
Unified game event system - all requests and state changes are reported using a message.
Definition: GameContext.h:51
RigDef_Parser.h
Checks the rig-def file syntax and loads data to memory.
RoR::FlareID_t
int FlareID_t
Index into Actor::ar_flares, use RoR::FLAREID_INVALID as empty value.
Definition: ForwardDeclarations.h:68
RoR::AddonPartUtility::ProcessFlare2
void ProcessFlare2()
Definition: AddonPartFileFormat.cpp:404
RigDef::Prop::special_prop_dashboard
DashboardSpecial special_prop_dashboard
Definition: RigDef_File.h:1116
RoR::TuneupManagedMatTweak::tmt_name
std::string tmt_name
Arg#1, required.
Definition: TuneupFileFormat.h:84
RoR::TuneupWheelTweak
< Data of 'addonpart_tweak_wheel <wheel ID> <media1> <media2> <side flag> <tire radius> <rim radius>'
Definition: TuneupFileFormat.h:51
RoR::GUI::MessageBoxConfig::mbc_content_width
float mbc_content_width
Parameter to ImGui::SetContentWidth() - hard limit on content size.
Definition: GUI_MessageBox.h:57
RigDef::Flare2::control_number
int control_number
Only 'u' type flares.
Definition: RigDef_File.h:883
BitMask_t
uint32_t BitMask_t
Definition: BitFlags.h:7
RoR::GenericDocContext
Definition: GenericFileFormat.h:90
RoR::AddonPartUtility::ProcessUnwantedFlexbody
void ProcessUnwantedFlexbody()
Definition: AddonPartFileFormat.cpp:469
RoR::AddonPartUtility::ProcessProp
void ProcessProp()
Definition: AddonPartFileFormat.cpp:248
RoR::Console::CONSOLE_MSGTYPE_ACTOR
@ CONSOLE_MSGTYPE_ACTOR
Parsing/spawn/simulation messages for actors.
Definition: Console.h:63
AddonPartFileFormat.h
RoR::Console::CONSOLE_SYSTEM_WARNING
@ CONSOLE_SYSTEM_WARNING
Definition: Console.h:53
RoR::AddonPartUtility::AddonPartUtility
AddonPartUtility(bool silent_mode=false)
Definition: AddonPartFileFormat.cpp:39
RoR::AddonPartUtility
NOTE: Modcache processes this format directly using RoR::GenericDocument, see RoR::CacheSystem::FillA...
Definition: AddonPartFileFormat.h:56
RoR::FlexbodyID_t
int FlexbodyID_t
Index to GfxActor::m_flexbodies, use RoR::FLEXBODYID_INVALID as empty value.
Definition: ForwardDeclarations.h:62
RigDef::Prop::reference_node
Node::Ref reference_node
Definition: RigDef_File.h:1106
RoR::TuneupUtil::isFlexbodyTweaked
static bool isFlexbodyTweaked(TuneupDefPtr &tuneup_entry, FlexbodyID_t flexbody_id, TuneupFlexbodyTweak *&out_tweak)
Definition: TuneupFileFormat.cpp:432
RigDef::Flexbody::x_axis_node
Node::Ref x_axis_node
Definition: RigDef_File.h:898
RoR::TuneupFlexbodyTweak::tft_offset
Ogre::Vector3 tft_offset
Definition: TuneupFileFormat.h:77
RoR::MSG_GUI_HIDE_MESSAGE_BOX_REQUESTED
@ MSG_GUI_HIDE_MESSAGE_BOX_REQUESTED
Definition: Application.h:139
RoR::AddonPartUtility::~AddonPartUtility
~AddonPartUtility()
Definition: AddonPartFileFormat.cpp:44
GenericFileFormat.h
Generic text file parser.
RoR::TuneupFlexbodyTweak
< Data of 'addonpart_tweak_flexbody <flexbody ID> <offsetX> <offsetY> <offsetZ> <rotX> <rotY> <rotZ> ...
Definition: TuneupFileFormat.h:73
RigDef::Node::Ref::Num
unsigned int Num() const
Definition: RigDef_Node.h:95
RoR::GenericDocument::OPTION_ALLOW_NAKED_STRINGS
static const BitMask_t OPTION_ALLOW_NAKED_STRINGS
Allow strings without quotes, for backwards compatibility.
Definition: GenericFileFormat.h:67
RigDef::Prop::x_axis_node
Node::Ref x_axis_node
Definition: RigDef_File.h:1107
RigDef::Prop::DashboardSpecial::rotation_angle
float rotation_angle
Definition: RigDef_File.h:1091
RoR::Actor::getWorkingTuneupDef
TuneupDefPtr & getWorkingTuneupDef()
Definition: Actor.cpp:4724
RoR
Definition: AppContext.h:36
RoR::TuneupManagedMatTweak::tmt_media
std::array< std::string, 3 > tmt_media
Arg#3, required, Arg#4, optional, Arg#5, optional.
Definition: TuneupFileFormat.h:86
RoR::TuneupDef::wheel_tweaks
std::map< WheelID_t, TuneupWheelTweak > wheel_tweaks
Mesh name and radius overrides via 'addonpart_tweak_wheel'.
Definition: TuneupFileFormat.h:112
RoR::CacheEntry::addonpart_data_only
RoR::TuneupDefPtr addonpart_data_only
Cached addonpart data (dummy tuneup), only used for evaluating conflicts, see AddonPartUtility::Recor...
Definition: CacheSystem.h:94
RigDef::Prop::special_prop_beacon
BeaconSpecial special_prop_beacon
Definition: RigDef_File.h:1115
RoR::Log
void Log(const char *msg)
The ultimate, application-wide logging function. Adds a line (any length) in 'RoR....
Definition: Application.cpp:419
RigDef::Flexbody::y_axis_node
Node::Ref y_axis_node
Definition: RigDef_File.h:899
RoR::PropID_t
int PropID_t
Index to GfxActor::m_props, use RoR::PROPID_INVALID as empty value.
Definition: ForwardDeclarations.h:59
RoR::AddonPartUtility::ProcessFlexbody
void ProcessFlexbody()
Definition: AddonPartFileFormat.cpp:314
RigDef::Prop::BeaconSpecial::flare_material_name
Ogre::String flare_material_name
Definition: RigDef_File.h:1102
RoR::AddonPartUtility::ProcessFlare
void ProcessFlare()
Definition: AddonPartFileFormat.cpp:366
RoR::AddonPartUtility::ProcessTweakManagedMat
void ProcessTweakManagedMat()
Definition: AddonPartFileFormat.cpp:770
RoR::CacheEntry::fname
Ogre::String fname
filename
Definition: CacheSystem.h:67
RigDef::Prop::BeaconSpecial::color
Ogre::ColourValue color
Definition: RigDef_File.h:1103