Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
RigDef_Validator.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-2020 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_Validator.h"
27
28#include "Actor.h"
29#include "SimConstants.h"
30#include "Application.h"
31#include "Console.h"
32
33#define CHECK_SECTION_IN_ALL_MODULES(_CLASS_, _FIELD_, _FUNCTION_) \
34{ \
35 std::list<std::shared_ptr<RigDef::Document::Module>>::iterator module_itor = m_selected_modules.begin(); \
36 for (; module_itor != m_selected_modules.end(); module_itor++) \
37 { \
38 std::vector<_CLASS_>::iterator section_itor = module_itor->get()->_FIELD_.begin(); \
39 for (; section_itor != module_itor->get()->_FIELD_.end(); section_itor++) \
40 { \
41 if (! _FUNCTION_(*section_itor))\
42 { \
43 section_itor = module_itor->get()->_FIELD_.erase(section_itor); \
44 if (section_itor == module_itor->get()->_FIELD_.end()) \
45 { \
46 break; \
47 } \
48 } \
49 } \
50 } \
51}
52
53using namespace RigDef;
54using namespace RoR;
55
57{
58 bool valid = true;
59
60 /* CHECK CONFIGURATION (SELECTED MODULES TOGETHER) */
61
62 valid &= CheckSectionSubmeshGroundmodel(); /* Unique */
63
64 valid &= CheckGearbox(); /* Min. 1 forward gear */
65
66 /* CHECK INDIVIDUAL LINES (remove invalid entries) */
67
69
71
73
75
77
79
81
82 return valid;
83}
84
86{
87 m_file = file;
88 m_selected_modules.push_back(file->root_module);
89 m_check_beams = true;
90}
91
92void Validator::AddMessage(Validator::Message::Type type, Ogre::String const & text)
93{
95 switch (type)
96 {
99 break;
100
104 break;
105
106 default:
108 break;
109 }
110
112}
113
115{
116 Ogre::String *containing_module_name = nullptr;
117
118 std::list<std::shared_ptr<RigDef::Document::Module>>::iterator module_itor = m_selected_modules.begin();
119 for (; module_itor != m_selected_modules.end(); module_itor++)
120 {
121 if (! module_itor->get()->submesh_groundmodel.empty())
122 {
123 if (containing_module_name == nullptr)
124 {
125 containing_module_name = & module_itor->get()->name;
126 }
127 else
128 {
129 std::stringstream text;
130 text << "Duplicate inline-section 'submesh_groundmodel'; found in modules: '"
131 << *containing_module_name << "' & '" << module_itor->get()->name << "'";
133 return false;
134 }
135 }
136 }
137
138 return true;
139}
140
141bool Validator::AddModule(Ogre::String const & module_name)
142{
143 std::map< Ogre::String, std::shared_ptr<RigDef::Document::Module> >::iterator result
144 = m_file->user_modules.find(module_name);
145
146 if (result != m_file->user_modules.end())
147 {
148 m_selected_modules.push_back(result->second);
149 return true;
150 }
151 return false;
152}
153
155{
156 /* Find it */
157 std::shared_ptr<RigDef::Engine> engine;
158 std::list<std::shared_ptr<RigDef::Document::Module>>::iterator module_itor = m_selected_modules.begin();
159 for (; module_itor != m_selected_modules.end(); module_itor++)
160 {
161 if (module_itor->get()->engine.size() > 0)
162 {
163 if (module_itor->get()->engine[module_itor->get()->engine.size() - 1].gear_ratios.size() > 0)
164 {
165 return true;
166 }
167 else
168 {
169 AddMessage(Message::TYPE_FATAL_ERROR, "Engine must have at least 1 forward gear.");
170 return false;
171 }
172 }
173 }
174 return true;
175}
176
178{
179 std::list<Ogre::String> bad_fields;
180
181 /* Keep these in sync with wiki doc: http://www.rigsofrods.org/wiki/pages/Truck_Description_File#Shocks2 */
182 /* We safely check for value -1.f */
183 if (shock2.spring_in < -0.8f)
184 {
185 bad_fields.push_back("spring_in_rate");
186 }
187 if (shock2.damp_in < -0.8f)
188 {
189 bad_fields.push_back("damping_in_rate");
190 }
191 if (shock2.spring_out < -0.8f)
192 {
193 bad_fields.push_back("spring_out_rate");
194 }
195 if (shock2.damp_out < -0.8f)
196 {
197 bad_fields.push_back("damping_out_rate");
198 }
199 if (shock2.progress_factor_spring_in < -0.8f)
200 {
201 bad_fields.push_back("spring_in_progression_factor");
202 }
203 if (shock2.progress_factor_damp_in < -0.8f)
204 {
205 bad_fields.push_back("damping_in_progression_factor");
206 }
207 if (shock2.progress_factor_spring_out < -0.8f)
208 {
209 bad_fields.push_back("spring_out_progression_factor");
210 }
211 if (shock2.progress_factor_damp_out < -0.8f)
212 {
213 bad_fields.push_back("damping_out_progression_factor");
214 }
215 if (shock2.short_bound < -0.8f)
216 {
217 bad_fields.push_back("max_contraction");
218 }
219 if (shock2.long_bound < -0.8f)
220 {
221 bad_fields.push_back("max_extension");
222 }
223 if (shock2.precompression < -0.8f)
224 {
225 bad_fields.push_back("precompression");
226 }
227
228 if (bad_fields.size() > 0)
229 {
230 std::stringstream msg;
231 msg << "Invalid values in section 'shocks2', fields: ";
232 std::list<Ogre::String>::iterator itor = bad_fields.begin();
233 bool first = true;
234 for( ; itor != bad_fields.end(); itor++)
235 {
236 msg << (first ? "" : ", ") << *itor;
237 first = false;
238 }
239
241 return false;
242 }
243 return true;
244}
245
247{
248 std::list<Ogre::String> bad_fields;
249
250 /* Keep these in sync with wiki doc: http://www.rigsofrods.org/wiki/pages/Truck_Description_File#Shocks3 */
251 /* We safely check for value -1.f */
252 if (shock3.spring_in < -0.8f)
253 {
254 bad_fields.push_back("spring_in_rate");
255 }
256 if (shock3.damp_in < -0.8f)
257 {
258 bad_fields.push_back("damping_in_rate");
259 }
260 if (shock3.spring_out < -0.8f)
261 {
262 bad_fields.push_back("spring_out_rate");
263 }
264 if (shock3.damp_out < -0.8f)
265 {
266 bad_fields.push_back("damping_out_rate");
267 }
268 if (shock3.damp_in_slow < -0.8f)
269 {
270 bad_fields.push_back("damp_in_slow");
271 }
272 if (shock3.split_vel_in < -0.8f)
273 {
274 bad_fields.push_back("split_in");
275 }
276 if (shock3.damp_in_fast < -0.8f)
277 {
278 bad_fields.push_back("damp_in_fast");
279 }
280 if (shock3.damp_out_slow < -0.8f)
281 {
282 bad_fields.push_back("damp_out_slow");
283 }
284 if (shock3.split_vel_out < -0.8f)
285 {
286 bad_fields.push_back("split_out");
287 }
288 if (shock3.damp_out_fast < -0.8f)
289 {
290 bad_fields.push_back("damp_out_fast");
291 }
292 if (shock3.short_bound < -0.8f)
293 {
294 bad_fields.push_back("max_contraction");
295 }
296 if (shock3.long_bound < -0.8f)
297 {
298 bad_fields.push_back("max_extension");
299 }
300 if (shock3.precompression < -0.8f)
301 {
302 bad_fields.push_back("precompression");
303 }
304
305 if (bad_fields.size() > 0)
306 {
307 std::stringstream msg;
308 msg << "Invalid values in section 'shocks3', fields: ";
309 std::list<Ogre::String>::iterator itor = bad_fields.begin();
310 bool first = true;
311 for( ; itor != bad_fields.end(); itor++)
312 {
313 msg << (first ? "" : ", ") << *itor;
314 first = false;
315 }
316
318 return false;
319 }
320 return true;
321}
322
324{
325 // Ignore non-source flags
326 unsigned int source_check = def.flags;
331 if (source_check != 0 || def.aero_animator.flags != 0)
332 {
333 return true;
334 }
335 else
336 {
337 AddMessage(Message::TYPE_ERROR, "Animator: No animator source defined");
338 return false;
339 }
340}
341
343{
344 bool ok = true;
345
346 // Caution: commandkeys are numbered from 1 to MAX_COMMANDS including.
347
349 {
350 std::stringstream msg;
351 msg << "Section 'commands' or 'commands2': Invalid 'extend_key': ";
352 msg << def.extend_key;
353 msg << "; valid range is <1 - " << MAX_COMMANDS << "> (plus any negative number is acceptable)";
355 ok = false;
356 }
357
359 {
360 std::stringstream msg;
361 msg << "Section 'commands' or 'commands2': Invalid 'contract_key': ";
362 msg << def.contract_key;
363 msg << "; valid range is <1 - " << MAX_COMMANDS << "> (plus any negative number is acceptable)";
365 ok = false;
366 }
367
368 return ok;
369}
370
372{
373 bool ok = true;
374
375 if (def.control_number < -1 || def.control_number > 500)
376 {
377 std::stringstream msg;
378 msg << "Wrong parameter 'control_number' (" << def.control_number << "), must be in range <-1, 500>";
380 ok = false;
381 }
382
383 if (def.blink_delay_milis < -2 || def.blink_delay_milis > 60000)
384 {
385 std::stringstream msg;
386 msg << "Wrong parameter 'blink_delay_milis' (" << def.blink_delay_milis << "), must be in range <-2, 60000>";
388 ok = false;
389 }
390
391 return ok;
392}
393
395{
396 bool ok = true;
397
398 bool hook_toggle =
401
404
406 {
407 if (! trigger_blocker && ! inv_trigger_blocker && ! hook_toggle )
408 {
409 /* Make the full check */
411 {
412 std::stringstream msg;
413 msg << "Wrong parameter 'shortbound_trigger_action': " << def.shortbound_trigger_action;
414 msg << "; Alloved range is <0 - " << MAX_COMMANDS << ">. ";
415 msg << "Trigger deactivated.";
417 ok = false;
418 }
419 }
420 else if (! hook_toggle)
421 {
422 /* This is a Trigger-Blocker, make special check */
423 if (def.shortbound_trigger_action < 0)
424 {
425 std::stringstream msg;
426 msg << "Wrong parameter 'shortbound_trigger_action': " << def.shortbound_trigger_action;
427 msg << "; Alloved range is <0 - " << MAX_COMMANDS << ">. ";
428 msg << "Trigger deactivated.";
430 ok = false;
431 }
432 if (def.longbound_trigger_action < 0)
433 {
434 std::stringstream msg;
435 msg << "Wrong parameter 'longbound_trigger_action': " << def.longbound_trigger_action;
436 msg << "; Alloved range is <0 - " << MAX_COMMANDS << ">. ";
437 msg << "Trigger deactivated.";
439 ok = false;
440 }
441 }
442 }
443 else
444 {
445 /* Engine trigger */
446 if (trigger_blocker || inv_trigger_blocker || hook_toggle || BITMASK_IS_1(def.options, RigDef::Trigger::OPTION_s_CMD_NUM_SWITCH))
447 {
448 AddMessage(Message::TYPE_ERROR, "Wrong command-eventnumber. Engine trigger deactivated.");
449 ok = false;
450 }
451 }
452
453 return ok;
454}
455
457{
458 bool ok = true;
459
460 /* disabled isPowerOfTwo, as it can be a renderwindow now with custom resolution */
461 if (def.texture_width <= 0 || def.texture_height <= 0)
462 {
463 AddMessage(Message::TYPE_ERROR, "Wrong texture size definition.");
464 ok = false;
465 }
466
468 {
469 AddMessage(Message::TYPE_ERROR, "Wrong clipping sizes definition.");
470 ok = false;
471 }
472
473 if (def.camera_mode < -2 )
474 {
475 AddMessage(Message::TYPE_ERROR, "Camera Mode setting incorrect.");
476 ok = false;
477 }
478
479 if (def.camera_role < -1 || def.camera_role >1)
480 {
481 AddMessage(Message::TYPE_ERROR, "Camera Role (camera, trace, mirror) setting incorrect.");
482 ok = false;
483 }
484
485 return ok;
486}
Central state/object manager and communications hub.
#define BITMASK_SET_0(VAR, FLAGS)
Definition BitFlags.h:16
#define BITMASK_IS_1(VAR, FLAGS)
Definition BitFlags.h:14
#define BITMASK_IS_0(VAR, FLAGS)
Definition BitFlags.h:13
#define CHECK_SECTION_IN_ALL_MODULES(_CLASS_, _FIELD_, _FUNCTION_)
.truck format validator
static const int MAX_COMMANDS
maximum number of commands per actor
void Setup(RigDef::DocumentPtr file)
Prepares the validation.
RigDef::DocumentPtr m_file
The parsed input file.
bool CheckVideoCamera(RigDef::VideoCamera &def)
Section 'videocamera'.
void AddMessage(Validator::Message::Type type, Ogre::String const &text)
bool CheckAnimator(RigDef::Animator &def)
bool CheckFlare2(RigDef::Flare2 &def)
bool CheckTrigger(RigDef::Trigger &def)
bool CheckShock3(RigDef::Shock3 &shock3)
bool CheckShock2(RigDef::Shock2 &shock2)
bool AddModule(Ogre::String const &module_name)
Adds a vehicle module to the validated configuration.
std::list< std::shared_ptr< RigDef::Document::Module > > m_selected_modules
bool CheckSectionSubmeshGroundmodel()
Inline-ection 'submesh_groundmodel', unique across all modules.
bool CheckCommand(RigDef::Command2 &def)
bool CheckGearbox()
Checks there's at least 1 forward gear.
@ CONSOLE_MSGTYPE_ACTOR
Parsing/spawn/simulation messages for actors.
Definition Console.h:63
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition Console.cpp:103
@ CONSOLE_SYSTEM_ERROR
Definition Console.h:52
@ CONSOLE_SYSTEM_NOTICE
Definition Console.h:51
@ CONSOLE_SYSTEM_WARNING
Definition Console.h:53
std::shared_ptr< Document > DocumentPtr
Console * GetConsole()
static const CommandkeyID_t COMMANDKEYID_INVALID
static const BitMask_t OPTION_VISIBLE
AeroAnimator aero_animator
static const BitMask_t OPTION_SHORT_LIMIT
static const BitMask_t OPTION_LONG_LIMIT
static const BitMask_t OPTION_INVISIBLE
RoR::CommandkeyID_t extend_key
RoR::CommandkeyID_t contract_key
int control_number
Only 'u' type flares.
float short_bound
Maximum contraction limit, in percentage ( 1.00 = 100% )
float progress_factor_damp_out
Progression factor dampout, 0 = disabled, 1...x as multipliers, example:maximum dampingrate == spring...
float damp_out
damping value applied when shock extending
float progress_factor_damp_in
Progression factor for dampin. 0 = disabled, 1...x as multipliers, example:maximum dampingrate == spr...
float spring_in
Spring value applied when the shock is compressing.
float precompression
Changes compression or extension of the suspension when the truck spawns. This can be used to "level"...
float progress_factor_spring_out
Progression factor springout, 0 = disabled, 1...x as multipliers, example:maximum springrate == sprin...
float spring_out
spring value applied when shock extending
float long_bound
Maximum extension limit, in percentage ( 1.00 = 100% )
float damp_in
Damping value applied when the shock is compressing.
float progress_factor_spring_in
Progression factor for springin. A value of 0 disables this option. 1...x as multipliers,...
float damp_in_slow
Damping value applied when shock is commpressing slower than split in velocity.
float spring_in
Spring value applied when the shock is compressing.
float spring_out
Spring value applied when shock extending.
float damp_in
Damping value applied when the shock is compressing.
float split_vel_in
Split velocity in (m/s) - threshold for slow / fast damping during compression.
float precompression
Changes compression or extension of the suspension when the truck spawns. This can be used to "level"...
float damp_out
Damping value applied when shock extending.
float long_bound
Maximum extension limit, in percentage ( 1.00 = 100% )
float short_bound
Maximum contraction limit, in percentage ( 1.00 = 100% )
float damp_out_slow
Damping value applied when shock is commpressing slower than split out velocity.
float damp_out_fast
Damping value applied when shock is commpressing faster than split out velocity.
float damp_in_fast
Damping value applied when shock is commpressing faster than split in velocity.
float split_vel_out
Split velocity in (m/s) - threshold for slow / fast damping during extension.
static const BitMask_t OPTION_B_TRIGGER_BLOCKER
static const BitMask_t OPTION_s_CMD_NUM_SWITCH
static const BitMask_t OPTION_h_UNLOCKS_HOOK_GROUP
static const BitMask_t OPTION_E_ENGINE_TRIGGER
BitMask_t options
static const BitMask_t OPTION_H_LOCKS_HOOK_GROUP
static const BitMask_t OPTION_A_INV_TRIGGER_BLOCKER
int shortbound_trigger_action
RoR::VideoCamRole camera_role
unsigned int texture_width
unsigned int texture_height