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
ActorManager.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 "ActorManager.h"
27
28#include "Actor.h"
29#include "Application.h"
30#include "ApproxMath.h"
31#include "Buoyance.h"
32#include "CacheSystem.h"
33#include "ContentManager.h"
34#include "ChatSystem.h"
35#include "Collisions.h"
36#include "DashBoardManager.h"
37#include "DynamicCollisions.h"
38#include "Engine.h"
39#include "GameContext.h"
40#include "GfxScene.h"
41#include "GUIManager.h"
42#include "Console.h"
43#include "GUI_TopMenubar.h"
44#include "InputEngine.h"
45#include "Language.h"
46#include "MovableText.h"
47#include "Network.h"
48#include "PointColDetector.h"
49#include "Replay.h"
50#include "RigDef_Validator.h"
51#include "RigDef_Serializer.h"
52#include "ActorSpawner.h"
53#include "ScriptEngine.h"
54#include "SoundScriptManager.h"
55#include "Terrain.h"
56#include "ThreadPool.h"
57#include "TuneupFileFormat.h"
58#include "Utils.h"
59#include "VehicleAI.h"
60
61#include <fmt/format.h>
62
63using namespace Ogre;
64using namespace RoR;
65
66const ActorPtr ActorManager::ACTORPTR_NULL; // Dummy value to be returned as const reference.
67
69 : m_dt_remainder(0.0f)
70 , m_forced_awake(false)
71 , m_physics_steps(2000)
72 , m_simulation_speed(1.0f)
73{
74 // Create worker thread (used for physics calculations)
75 m_sim_thread_pool = std::unique_ptr<ThreadPool>(new ThreadPool(1));
76}
77
79{
80 this->SyncWithSimThread(); // Wait for sim task to finish
81}
82
84{
86 {
88 }
89 ActorPtr actor = new Actor(rq.asr_instance_id, static_cast<int>(m_actors.size()), def, rq);
90
92 {
93 actor->sendStreamSetup();
94 }
95
96 LOG(" == Spawning vehicle: " + def->name);
97
98 ActorSpawner spawner;
99 spawner.ConfigureSections(actor->m_section_config, def);
100 spawner.ConfigureAddonParts(actor);
101 spawner.ConfigureAssetPacks(actor);
102 spawner.ProcessNewActor(actor, rq, def);
103
104 if (App::diag_actor_dump->getBool())
105 {
106 actor->WriteDiagnosticDump(actor->ar_filename + "_dump_raw.txt"); // Saves file to 'logs'
107 }
108
109 /* POST-PROCESSING */
110
111 actor->ar_initial_node_positions.resize(actor->ar_num_nodes);
112 actor->ar_initial_beam_defaults.resize(actor->ar_num_beams);
113 actor->ar_initial_node_masses.resize(actor->ar_num_nodes);
114
115 actor->UpdateBoundingBoxes(); // (records the unrotated dimensions for 'veh_aab_size')
116
117 // Apply spawn position & spawn rotation
118 for (int i = 0; i < actor->ar_num_nodes; i++)
119 {
120 actor->ar_nodes[i].AbsPosition = rq.asr_position + rq.asr_rotation * (actor->ar_nodes[i].AbsPosition - rq.asr_position);
121 actor->ar_nodes[i].RelPosition = actor->ar_nodes[i].AbsPosition - actor->ar_origin;
122 };
123
124 /* Place correctly */
125 if (spawner.GetMemoryRequirements().num_fixes == 0)
126 {
127 Ogre::Vector3 vehicle_position = rq.asr_position;
128
129 // check if over-sized
130 actor->UpdateBoundingBoxes();
131 vehicle_position.x += vehicle_position.x - actor->ar_bounding_box.getCenter().x;
132 vehicle_position.z += vehicle_position.z - actor->ar_bounding_box.getCenter().z;
133
134 float miny = 0.0f;
135
136 if (!actor->m_preloaded_with_terrain)
137 {
138 miny = vehicle_position.y;
139 }
140
141 if (rq.asr_spawnbox != nullptr)
142 {
143 miny = rq.asr_spawnbox->relo.y + rq.asr_spawnbox->center.y;
144 }
145
146 if (rq.asr_free_position)
147 actor->resetPosition(vehicle_position, true);
148 else
149 actor->resetPosition(vehicle_position.x, vehicle_position.z, true, miny);
150
151 if (rq.asr_spawnbox != nullptr)
152 {
153 bool inside = true;
154
155 for (int i = 0; i < actor->ar_num_nodes; i++)
156 inside = (inside && App::GetGameContext()->GetTerrain()->GetCollisions()->isInside(actor->ar_nodes[i].AbsPosition, rq.asr_spawnbox, 0.2f));
157
158 if (!inside)
159 {
160 Vector3 gpos = Vector3(vehicle_position.x, 0.0f, vehicle_position.z);
161
162 gpos -= rq.asr_rotation * Vector3((rq.asr_spawnbox->hi.x - rq.asr_spawnbox->lo.x + actor->ar_bounding_box.getMaximum().x - actor->ar_bounding_box.getMinimum().x) * 0.6f, 0.0f, 0.0f);
163
164 actor->resetPosition(gpos.x, gpos.z, true, miny);
165 }
166 }
167 }
168 else
169 {
170 actor->resetPosition(rq.asr_position, true);
171 }
172 actor->UpdateBoundingBoxes();
173
174 //compute final mass
175 actor->recalculateNodeMasses();
176 actor->ar_initial_total_mass = actor->ar_total_mass;
177 actor->ar_original_dry_mass = actor->ar_dry_mass;
178 actor->ar_original_load_mass = actor->ar_load_mass;
179 actor->ar_orig_minimass = actor->ar_minimass;
180 for (int i = 0; i < actor->ar_num_nodes; i++)
181 {
182 actor->ar_initial_node_masses[i] = actor->ar_nodes[i].mass;
183 }
184
185 //setup default sounds
186 if (!actor->m_disable_default_sounds)
187 {
189 }
190
191 //compute node connectivity graph
193
194 actor->UpdateBoundingBoxes();
196
197 // calculate minimum camera radius
199 for (int i = 0; i < actor->ar_num_nodes; i++)
200 {
201 Real dist = actor->ar_nodes[i].AbsPosition.squaredDistance(actor->m_avg_node_position);
202 if (dist > actor->m_min_camera_radius)
203 {
204 actor->m_min_camera_radius = dist;
205 }
206 }
207 actor->m_min_camera_radius = std::sqrt(actor->m_min_camera_radius) * 1.2f; // twenty percent buffer
208
209 // fix up submesh collision model
210 std::string subMeshGroundModelName = spawner.GetSubmeshGroundmodelName();
211 if (!subMeshGroundModelName.empty())
212 {
214 if (!actor->ar_submesh_ground_model)
215 {
217 }
218 }
219
220 // Set beam defaults
221 for (int i = 0; i < actor->ar_num_beams; i++)
222 {
223 actor->ar_beams[i].initial_beam_strength = actor->ar_beams[i].strength;
225 actor->ar_initial_beam_defaults[i] = std::make_pair(actor->ar_beams[i].k, actor->ar_beams[i].d);
226 }
227
228 actor->m_spawn_rotation = actor->getRotation();
229
231
232 actor->NotifyActorCameraChanged(); // setup sounds properly
233
234 // calculate the number of wheel nodes
235 actor->m_wheel_node_count = 0;
236 for (int i = 0; i < actor->ar_num_nodes; i++)
237 {
238 if (actor->ar_nodes[i].nd_tyre_node)
239 actor->m_wheel_node_count++;
240 }
241
242 // search m_net_first_wheel_node
243 actor->m_net_first_wheel_node = actor->ar_num_nodes;
244 for (int i = 0; i < actor->ar_num_nodes; i++)
245 {
246 if (actor->ar_nodes[i].nd_tyre_node || actor->ar_nodes[i].nd_rim_node)
247 {
248 actor->m_net_first_wheel_node = i;
249 break;
250 }
251 }
252
253 // Initialize visuals
254 actor->updateVisual();
256
257 // perform full visual update only if the vehicle won't be immediately driven by player.
258 if (actor->isPreloadedWithTerrain() || // .tobj file - Spawned sleeping somewhere on terrain
259 rq.asr_origin == ActorSpawnRequest::Origin::CONFIG_FILE || // RoR.cfg or commandline - not entered by default
260 actor->ar_num_cinecams == 0) // Not intended for player-controlling
261 {
262 actor->GetGfxActor()->UpdateSimDataBuffer(); // Initial fill of sim data buffers
263
264 actor->GetGfxActor()->UpdateFlexbodies(); // Push tasks to threadpool
265 actor->GetGfxActor()->UpdateWheelVisuals(); // Push tasks to threadpool
266 actor->GetGfxActor()->UpdateCabMesh();
267 actor->GetGfxActor()->UpdateWingMeshes();
268 actor->GetGfxActor()->UpdateProps(0.f, false);
269 actor->GetGfxActor()->UpdateRods(); // beam visuals
270 actor->GetGfxActor()->FinishWheelUpdates(); // Sync tasks from threadpool
271 actor->GetGfxActor()->FinishFlexbodyTasks(); // Sync tasks from threadpool
272 }
273
275
276 if (actor->ar_engine)
277 {
279 actor->ar_engine->startEngine();
280 else
281 actor->ar_engine->offStart();
282 }
283 // pressurize tires
284 if (actor->getTyrePressure().IsEnabled())
285 {
286 actor->getTyrePressure().ModifyTyrePressure(0.f); // Initialize springiness of pressure-beams.
287 }
288
290
291 if (App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
292 {
293 // network buffer layout (without RoRnet::VehicleState):
294 // -----------------------------------------------------
295
296 // - 3 floats (x,y,z) for the reference node 0
297 // - ar_num_nodes - 1 times 3 short ints (compressed position info)
298 actor->m_net_node_buf_size = sizeof(float) * 3 + (actor->m_net_first_wheel_node - 1) * sizeof(short int) * 3;
300 // - ar_num_wheels times a float for the wheel rotation
301 actor->m_net_wheel_buf_size = actor->ar_num_wheels * sizeof(float);
303 // - bit array (made of ints) for the prop animation key states
305 (actor->m_prop_anim_key_states.size() / 8) + // whole chars
306 (size_t)(actor->m_prop_anim_key_states.size() % 8 != 0); // remainder: 0 or 1 chars
308
310 {
312 if (actor->ar_engine)
313 {
314 actor->ar_engine->startEngine();
315 }
316 }
317
319 actor->m_net_color_num = rq.asr_net_color;
320 }
321 else if (App::sim_replay_enabled->getBool())
322 {
323 actor->m_replay_handler = new Replay(actor, App::sim_replay_length->getInt());
324 }
325
326 //cache buoyancy nodes (must be done when position is final)
327 if (actor->m_buoyance)
328 {
329 for (int i = 0; i < actor->ar_num_buoycabs; i++)
330 {
331 int tmpv = actor->ar_buoycabs[i] * 3;
332 actor->ar_cabs_buoy_cache_ids[tmpv] = actor->m_buoyance->cacheBuoycabNode(&actor->ar_nodes[actor->ar_cabs[tmpv]]);
333 actor->ar_cabs_buoy_cache_ids[tmpv+1] = actor->m_buoyance->cacheBuoycabNode(&actor->ar_nodes[actor->ar_cabs[tmpv + 1]]);
334 actor->ar_cabs_buoy_cache_ids[tmpv+2] = actor->m_buoyance->cacheBuoycabNode(&actor->ar_nodes[actor->ar_cabs[tmpv + 2]]);
335 }
336 actor->m_buoyance->buoy_projected_nodes = actor->m_buoyance->buoy_cached_nodes;
337 }
338
339 // Launch scripts (FIXME: ignores sectionconfig)
340 for (RigDef::Script const& script_def : def->root_module->scripts)
341 {
342 App::GetScriptEngine()->loadScript(script_def.filename, ScriptCategory::ACTOR, actor);
343 }
344
345 LOG(" ===== DONE LOADING VEHICLE");
346
347 if (App::diag_actor_dump->getBool())
348 {
349 actor->WriteDiagnosticDump(actor->ar_filename + "_dump_recalc.txt"); // Saves file to 'logs'
350 }
351
352 m_actors.push_back(ActorPtr(actor));
353
354 return actor;
355}
356
358{
359 m_stream_mismatches.erase(sourceid);
361 [sourceid](const RoRnet::ActorStreamRegister& reg)
362 {
363 return reg.origin_sourceid == sourceid;
364 });
365
366 for (ActorPtr& actor : m_actors)
367 {
368 if (actor->ar_state != ActorState::NETWORKED_OK)
369 continue;
370
371 if (actor->ar_net_source_id == sourceid)
372 {
374 }
375 }
376}
377
378void ActorManager::RemoveStream(int sourceid, int streamid)
379{
380 // Delete associated actor
381 ActorPtr b = this->GetActorByNetworkLinks(sourceid, streamid);
382 if (b)
383 {
385 {
387 }
388 }
389
390 // Erase stream mismatch records
391 m_stream_mismatches[sourceid].erase(streamid);
393 [sourceid, streamid](const RoRnet::ActorStreamRegister& reg)
394 {
395 return reg.origin_sourceid == sourceid &&
396 reg.origin_streamid == streamid;
397 });
398}
399
401{
404
405 std::string filename = args->arg5ex;
407 ROR_ASSERT(entry);
408
409 for (auto it = m_stream_mismatched_regs.begin(); it != m_stream_mismatched_regs.end(); )
410 {
412 std::string reg_filename_maybe_bundlequalified = SanitizeUtf8CString(reg.name);
413 std::string reg_filename;
414 std::string reg_bundlename;
415 SplitBundleQualifiedFilename(reg_filename_maybe_bundlequalified, /*out:*/ reg_bundlename, /*out:*/ reg_filename);
416 if (reg_filename == filename)
417 {
418 RoR::LogFormat("[RoR] Retrying STREAM_REGISTER for user id %d, stream id %d, filename '%s'",
419 reg.origin_sourceid, reg.origin_streamid, reg_filename_maybe_bundlequalified.c_str());
421 it = m_stream_mismatched_regs.erase(it);
422
423 // Gather info needed to spawn
424 RoRnet::UserInfo info;
425 BitMask_t peeropts = BitMask_t(0);
426 if (!App::GetNetwork()->GetUserInfo(reg.origin_sourceid, info)
427 || !App::GetNetwork()->GetUserPeerOpts(reg.origin_sourceid, peeropts))
428 {
429 RoR::LogFormat("[RoR] Error retrying STREAM_REGISTER, user id %d does not exist", reg.origin_sourceid);
430 }
431 else
432 {
433 this->RequestSpawnRemoteActor(&reg, entry, info, peeropts);
434 }
435 }
436 else
437 {
438 ++it;
439 }
440 }
441}
442
443#ifdef USE_SOCKETW
444void ActorManager::HandleActorStreamData(std::vector<RoR::NetRecvPacket> packet_buffer)
445{
446 // Sort by stream source
447 std::stable_sort(packet_buffer.begin(), packet_buffer.end(),
448 [](const RoR::NetRecvPacket& a, const RoR::NetRecvPacket& b)
449 { return a.header.source > b.header.source; });
450 // Compress data stream by eliminating all but the last update from every consecutive group of stream data updates
451 auto it = std::unique(packet_buffer.rbegin(), packet_buffer.rend(),
452 [](const RoR::NetRecvPacket& a, const RoR::NetRecvPacket& b)
453 { return !memcmp(&a.header, &b.header, sizeof(RoRnet::Header)) &&
454 a.header.command == RoRnet::MSG2_STREAM_DATA; });
455 packet_buffer.erase(packet_buffer.begin(), it.base());
456 for (auto& packet : packet_buffer)
457 {
458 if (packet.header.command == RoRnet::MSG2_STREAM_REGISTER)
459 {
460 RoRnet::StreamRegister* reg = (RoRnet::StreamRegister *)packet.buffer;
461 if (reg->type == 0)
462 {
463 reg->name[127] = 0;
464 // NOTE: The filename is by default in "Bundle-qualified" format, i.e. "mybundle.zip:myactor.truck"
465 std::string filename_maybe_bundlequalified = SanitizeUtf8CString(reg->name);
466 std::string filename;
467 std::string bundlename;
468 SplitBundleQualifiedFilename(filename_maybe_bundlequalified, /*out:*/ bundlename, /*out:*/ filename);
469
470 RoRnet::UserInfo info;
471 BitMask_t peeropts = BitMask_t(0);
472 if (!App::GetNetwork()->GetUserInfo(reg->origin_sourceid, info)
473 || !App::GetNetwork()->GetUserPeerOpts(reg->origin_sourceid, peeropts))
474 {
475 RoR::LogFormat("[RoR] Invalid STREAM_REGISTER, user id %d does not exist", reg->origin_sourceid);
476 reg->status = -1;
477 }
478 else if (filename.empty())
479 {
480 RoR::LogFormat("[RoR] Invalid STREAM_REGISTER (user '%s', ID %d), filename is empty string", info.username, reg->origin_sourceid);
481 reg->status = -1;
482 }
483 else
484 {
485 auto actor_reg = reinterpret_cast<RoRnet::ActorStreamRegister*>(reg);
486 Str<200> text;
487 text << _L("spawned a new vehicle: ") << filename;
490
491 LOG("[RoR] Creating remote actor for " + TOSTRING(reg->origin_sourceid) + ":" + TOSTRING(reg->origin_streamid));
492
493 // Based on negative user feedback we don't check the bundle in multiplayer.
494 CacheEntryPtr actor_entry = App::GetCacheSystem()->FindEntryByFilename(LT_AllBeam, /*partial:*/false, filename);
495
496 if (!actor_entry)
497 {
500 _L("Mod not installed: ") + filename);
501 RoR::LogFormat("[RoR] Cannot create remote actor (not installed), filename: '%s'", filename_maybe_bundlequalified.c_str());
502 this->AddStreamMismatch(actor_reg);
503 reg->status = -1;
504 }
505 else
506 {
507 RoR::LogFormat("[RoR] Creating remote actor (user id %d, stream id %d) with filename '%s'",
508 reg->origin_sourceid, reg->origin_streamid, filename_maybe_bundlequalified.c_str());
509 this->RequestSpawnRemoteActor(actor_reg, actor_entry, info, peeropts);
510 reg->status = 1; // success
511 }
512 }
513
515 }
516 }
517 else if (packet.header.command == RoRnet::MSG2_STREAM_REGISTER_RESULT)
518 {
519 RoRnet::StreamRegister* reg = (RoRnet::StreamRegister *)packet.buffer;
520 for (ActorPtr& actor: m_actors)
521 {
522 if (actor->ar_net_source_id == reg->origin_sourceid && actor->ar_net_stream_id == reg->origin_streamid)
523 {
524 int sourceid = packet.header.source;
525 actor->ar_net_stream_results[sourceid] = reg->status;
526
527 String message = "";
528 switch (reg->status)
529 {
530 case 1: message = "successfully loaded stream"; break;
531 case -2: message = "detected mismatch stream"; break;
532 default: message = "could not load stream"; break;
533 }
534 LOG("Client " + TOSTRING(sourceid) + " " + message + " " + TOSTRING(reg->origin_streamid) +
535 " with name '" + reg->name + "', result code: " + TOSTRING(reg->status));
536 break;
537 }
538 }
539 }
540 else if (packet.header.command == RoRnet::MSG2_STREAM_UNREGISTER)
541 {
542 this->RemoveStream(packet.header.source, packet.header.streamid);
543 }
544 else if (packet.header.command == RoRnet::MSG2_USER_LEAVE)
545 {
546 this->RemoveStreamSource(packet.header.source);
547 }
548 else if (packet.header.command == RoRnet::MSG2_STREAM_DATA)
549 {
550 for (ActorPtr& actor: m_actors)
551 {
552 if (actor->ar_state != ActorState::NETWORKED_OK)
553 continue;
554 if (packet.header.source == actor->ar_net_source_id && packet.header.streamid == actor->ar_net_stream_id)
555 {
556 actor->pushNetwork(packet.buffer, packet.header.size);
557 break;
558 }
559 }
560 }
561 }
562}
563#endif // USE_SOCKETW
564
566{
567 if (m_stream_time_offsets.find(actor_reg->origin_sourceid) == m_stream_time_offsets.end())
568 {
569 int offset = actor_reg->time - m_net_timer.getMilliseconds();
570 m_stream_time_offsets[actor_reg->origin_sourceid] = offset - 100;
571 }
574 rq->asr_cache_entry = actor_entry;
575 if (strnlen(actor_reg->skin, 60) < 60 && actor_reg->skin[0] != '\0')
576 {
577 rq->asr_skin_entry = App::GetCacheSystem()->FetchSkinByName(actor_reg->skin); // FIXME: fetch skin by name+guid! ~ 03/2019
578 }
579 if (strnlen(actor_reg->sectionconfig, 60) < 60)
580 {
581 rq->asr_config = actor_reg->sectionconfig;
582 }
584 rq->asr_net_color = userinfo.colournum;
585 rq->asr_net_peeropts = peeropts;
586 rq->net_source_id = actor_reg->origin_sourceid;
587 rq->net_stream_id = actor_reg->origin_streamid;
588
591}
592
598
600{
601 auto search = m_stream_time_offsets.find(sourceid);
602 if (search != m_stream_time_offsets.end())
603 {
604 return search->second;
605 }
606 return 0;
607}
608
609void ActorManager::UpdateNetTimeOffset(int sourceid, int offset)
610{
611 if (m_stream_time_offsets.find(sourceid) != m_stream_time_offsets.end())
612 {
613 m_stream_time_offsets[sourceid] += offset;
614 }
615}
616
618{
619 if (!m_stream_mismatches[sourceid].empty())
621
622 for (ActorPtr& actor: m_actors)
623 {
624 if (actor->ar_state != ActorState::NETWORKED_OK)
625 continue;
626
627 if (actor->ar_net_source_id == sourceid)
628 {
630 }
631 }
632
634}
635
637{
639
640 for (ActorPtr& actor: m_actors)
641 {
642 if (actor->ar_state == ActorState::NETWORKED_OK)
643 continue;
644
645 int stream_result = actor->ar_net_stream_results[sourceid];
646 if (stream_result == -1 || stream_result == -2)
648 if (stream_result == 1)
650 }
651
652 return result;
653}
654
655const ActorPtr& ActorManager::GetActorByNetworkLinks(int source_id, int stream_id)
656{
657 for (ActorPtr& actor: m_actors)
658 {
659 if (actor->ar_net_source_id == source_id && actor->ar_net_stream_id == stream_id)
660 {
661 return actor;
662 }
663 }
664
665 return ACTORPTR_NULL;
666}
667
669{
670 if (m_actors[a]->ar_collision_bounding_boxes.empty() && m_actors[b]->ar_collision_bounding_boxes.empty())
671 {
672 return m_actors[a]->ar_bounding_box.intersects(m_actors[b]->ar_bounding_box);
673 }
674 else if (m_actors[a]->ar_collision_bounding_boxes.empty())
675 {
676 for (const auto& bbox_b : m_actors[b]->ar_collision_bounding_boxes)
677 if (bbox_b.intersects(m_actors[a]->ar_bounding_box))
678 return true;
679 }
680 else if (m_actors[b]->ar_collision_bounding_boxes.empty())
681 {
682 for (const auto& bbox_a : m_actors[a]->ar_collision_bounding_boxes)
683 if (bbox_a.intersects(m_actors[b]->ar_bounding_box))
684 return true;
685 }
686 else
687 {
688 for (const auto& bbox_a : m_actors[a]->ar_collision_bounding_boxes)
689 for (const auto& bbox_b : m_actors[b]->ar_collision_bounding_boxes)
690 if (bbox_a.intersects(bbox_b))
691 return true;
692 }
693
694 return false;
695}
696
698{
699 if (m_actors[a]->ar_predicted_coll_bounding_boxes.empty() && m_actors[b]->ar_predicted_coll_bounding_boxes.empty())
700 {
701 return m_actors[a]->ar_predicted_bounding_box.intersects(m_actors[b]->ar_predicted_bounding_box);
702 }
703 else if (m_actors[a]->ar_predicted_coll_bounding_boxes.empty())
704 {
705 for (const auto& bbox_b : m_actors[b]->ar_predicted_coll_bounding_boxes)
706 if (bbox_b.intersects(m_actors[a]->ar_predicted_bounding_box))
707 return true;
708 }
709 else if (m_actors[b]->ar_predicted_coll_bounding_boxes.empty())
710 {
711 for (const auto& bbox_a : m_actors[a]->ar_predicted_coll_bounding_boxes)
712 if (bbox_a.intersects(m_actors[b]->ar_predicted_bounding_box))
713 return true;
714 }
715 else
716 {
717 for (const auto& bbox_a : m_actors[a]->ar_predicted_coll_bounding_boxes)
718 for (const auto& bbox_b : m_actors[b]->ar_predicted_coll_bounding_boxes)
719 if (bbox_a.intersects(bbox_b))
720 return true;
721 }
722
723 return false;
724}
725
726void ActorManager::RecursiveActivation(int j, std::vector<bool>& visited)
727{
728 if (visited[j] || m_actors[j]->ar_state != ActorState::LOCAL_SIMULATED)
729 return;
730
731 visited[j] = true;
732
733 for (unsigned int t = 0; t < m_actors.size(); t++)
734 {
735 if (t == j || visited[t])
736 continue;
738 {
739 m_actors[t]->ar_sleep_counter = 0.0f;
740 this->RecursiveActivation(t, visited);
741 }
743 {
744 m_actors[t]->ar_sleep_counter = 0.0f;
746 this->RecursiveActivation(t, visited);
747 }
748 }
749}
750
752{
753 if (source_actor->ar_forward_commands)
754 {
755 auto linked_actors = source_actor->ar_linked_actors;
756
757 for (ActorPtr& actor : this->GetActors())
758 {
759 if (actor != source_actor && actor->ar_import_commands &&
760 (actor->getPosition().distance(source_actor->getPosition()) <
761 actor->m_min_camera_radius + source_actor->m_min_camera_radius))
762 {
763 // activate the truck
764 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
765 {
766 actor->ar_sleep_counter = 0.0f;
767 actor->ar_state = ActorState::LOCAL_SIMULATED;
768 }
769
770 if (App::sim_realistic_commands->getBool())
771 {
772 if (std::find(linked_actors.begin(), linked_actors.end(), actor) == linked_actors.end())
773 continue;
774 }
775
776 // forward commands
777 for (int j = 1; j <= MAX_COMMANDS; j++) // BEWARE: commandkeys are indexed 1-MAX_COMMANDS!
778 {
779 actor->ar_command_key[j].playerInputValue = std::max(source_actor->ar_command_key[j].playerInputValue,
780 source_actor->ar_command_key[j].commandValue);
781 }
782 if (source_actor->ar_toggle_ties)
783 {
784 //actor->tieToggle();
787 rq->alr_actor_instance_id = actor->ar_instance_id;
788 rq->alr_tie_group = -1;
790
791 }
792 if (source_actor->ar_toggle_ropes)
793 {
794 //actor->ropeToggle(-1);
797 rq->alr_actor_instance_id = actor->ar_instance_id;
798 rq->alr_rope_group = -1;
800 }
801 }
802 }
803 // just send brake and lights to the connected trucks, and no one else :)
804 for (auto hook : source_actor->ar_hooks)
805 {
806 if (!hook.hk_locked_actor || hook.hk_locked_actor == source_actor)
807 continue;
808
809 // forward brakes
810 hook.hk_locked_actor->ar_brake = source_actor->ar_brake;
811 if (hook.hk_locked_actor->ar_parking_brake != source_actor->ar_trailer_parking_brake)
812 {
813 hook.hk_locked_actor->parkingbrakeToggle();
814 }
815
816 // forward lights
817 hook.hk_locked_actor->importLightStateMask(source_actor->getLightStateMask());
818 }
819 }
820}
821
823{
824 for (auto& entry: inter_actor_links)
825 {
826 auto& actor_pair = entry.second;
827 if ((actor_pair.first == a1 && actor_pair.second == a2) ||
828 (actor_pair.first == a2 && actor_pair.second == a1))
829 {
830 return true;
831 }
832 }
833 return false;
834}
835
836void ActorManager::UpdateSleepingState(ActorPtr player_actor, float dt)
837{
838 if (!m_forced_awake)
839 {
840 for (ActorPtr& actor: m_actors)
841 {
842 if (actor->ar_state != ActorState::LOCAL_SIMULATED)
843 continue;
844 if (actor->ar_driveable == AI)
845 continue;
846 if (actor->getVelocity().squaredLength() > 0.01f)
847 {
848 actor->ar_sleep_counter = 0.0f;
849 continue;
850 }
851
852 actor->ar_sleep_counter += dt;
853
854 if (actor->ar_sleep_counter >= 10.0f)
855 {
856 actor->ar_state = ActorState::LOCAL_SLEEPING;
857 }
858 }
859 }
860
861 if (player_actor && player_actor->ar_state == ActorState::LOCAL_SLEEPING)
862 {
864 }
865
866 std::vector<bool> visited(m_actors.size());
867 // Recursivly activate all actors which can be reached from current actor
868 if (player_actor && player_actor->ar_state == ActorState::LOCAL_SIMULATED)
869 {
870 player_actor->ar_sleep_counter = 0.0f;
871 this->RecursiveActivation(player_actor->ar_vector_index, visited);
872 }
873 // Snowball effect (activate all actors which might soon get hit by a moving actor)
874 for (unsigned int t = 0; t < m_actors.size(); t++)
875 {
876 if (m_actors[t]->ar_state == ActorState::LOCAL_SIMULATED && m_actors[t]->ar_sleep_counter == 0.0f)
877 this->RecursiveActivation(t, visited);
878 }
879}
880
882{
883 for (ActorPtr& actor: m_actors)
884 {
885 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
886 {
887 actor->ar_state = ActorState::LOCAL_SIMULATED;
888 actor->ar_sleep_counter = 0.0f;
889 }
890 }
891}
892
894{
895 m_forced_awake = false;
896 for (ActorPtr& actor: m_actors)
897 {
898 if (actor->ar_state == ActorState::LOCAL_SIMULATED)
899 {
900 actor->ar_state = ActorState::LOCAL_SLEEPING;
901 }
902 }
903}
904
905ActorPtr ActorManager::FindActorInsideBox(Collisions* collisions, const Ogre::String& inst, const Ogre::String& box)
906{
907 // try to find the desired actor (the one in the box)
908 ActorPtr ret = nullptr;
909 for (ActorPtr& actor: m_actors)
910 {
911 if (collisions->isInside(actor->ar_nodes[0].AbsPosition, inst, box))
912 {
913 if (ret == nullptr)
914 // first actor found
915 ret = actor;
916 else
917 // second actor found -> unclear which one was meant
918 return nullptr;
919 }
920 }
921 return ret;
922}
923
924void ActorManager::RepairActor(Collisions* collisions, const Ogre::String& inst, const Ogre::String& box, bool keepPosition)
925{
926 ActorPtr actor = this->FindActorInsideBox(collisions, inst, box);
927 if (actor != nullptr)
928 {
930
932 rq->amr_actor = actor->ar_instance_id;
935 }
936}
937
938std::pair<ActorPtr, float> ActorManager::GetNearestActor(Vector3 position)
939{
940 ActorPtr nearest_actor = nullptr;
941 float min_squared_distance = std::numeric_limits<float>::max();
942 for (ActorPtr& actor : m_actors)
943 {
944 float squared_distance = position.squaredDistance(actor->ar_nodes[0].AbsPosition);
945 if (squared_distance < min_squared_distance)
946 {
947 min_squared_distance = squared_distance;
948 nearest_actor = actor;
949 }
950 }
951 return std::make_pair(nearest_actor, std::sqrt(min_squared_distance));
952}
953
954void ActorManager::CleanUpSimulation() // Called after simulation finishes
955{
956 while (m_actors.size() > 0)
957 {
958 this->DeleteActorInternal(m_actors.back()); // OK to invoke here - CleanUpSimulation() - processing `MSG_SIM_UNLOAD_TERRAIN_REQUESTED`
959 }
960
961 m_total_sim_time = 0.f;
963 m_simulation_paused = false;
964 m_simulation_speed = 1.f;
965}
966
968{
969 if (actor == nullptr || actor->ar_state == ActorState::DISPOSED)
970 return;
971
972 this->SyncWithSimThread();
973
974#ifdef USE_SOCKETW
975 if (App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
976 {
978 {
980 }
981 else if (std::count_if(m_actors.begin(), m_actors.end(), [actor](ActorPtr& b)
982 { return b->ar_net_source_id == actor->ar_net_source_id; }) == 1)
983 {
984 // We're deleting the last actor from this stream source, reset the stream time offset
986 }
987 }
988#endif // USE_SOCKETW
989
990 // Unload actor's scripts
991 std::vector<ScriptUnitID_t> unload_list;
992 for (auto& pair : App::GetScriptEngine()->getScriptUnits())
993 {
994 if (pair.second.associatedActor == actor)
995 unload_list.push_back(pair.first);
996 }
997 for (ScriptUnitID_t id : unload_list)
998 {
1000 }
1001
1002 // Remove FreeForces referencing this actor
1003 m_free_forces.erase(
1004 std::remove_if(
1005 m_free_forces.begin(),
1006 m_free_forces.end(),
1007 [actor](FreeForce& item) { return item.ffc_base_actor == actor || item.ffc_target_actor == actor; }),
1008 m_free_forces.end());
1009
1010 // Only dispose(), do not `delete`; a script may still hold pointer to the object.
1011 actor->dispose();
1012
1013 EraseIf(m_actors, [actor](ActorPtr& curActor) { return actor == curActor; });
1014
1015 // Upate actor indices
1016 for (unsigned int i = 0; i < m_actors.size(); i++)
1017 m_actors[i]->ar_vector_index = i;
1018}
1019
1020// ACTORLIST for cycling with hotkeys
1021// ----------------------------------
1022
1023int FindPivotActorId(ActorPtr player, ActorPtr prev_player)
1024{
1025 if (player != nullptr)
1026 return player->ar_vector_index;
1027 else if (prev_player != nullptr)
1028 return prev_player->ar_vector_index + 1;
1029 return -1;
1030}
1031
1033{
1034 bool retval = !actor->isPreloadedWithTerrain();
1035
1036 // Exclude remote actors, if desired
1037 if (!App::mp_cyclethru_net_actors->getBool())
1038 {
1040 {
1041 retval = false;
1042 }
1043 }
1044
1045 return retval;
1046}
1047
1049{
1050 int pivot_index = FindPivotActorId(player, prev_player);
1051
1052 for (int i = pivot_index + 1; i < m_actors.size(); i++)
1053 {
1055 return m_actors[i];
1056 }
1057
1058 for (int i = 0; i < pivot_index; i++)
1059 {
1061 return m_actors[i];
1062 }
1063
1064 if (pivot_index >= 0)
1065 {
1066 if (ShouldIncludeActorInList(m_actors[pivot_index]))
1067 return m_actors[pivot_index];
1068 }
1069
1070 return ACTORPTR_NULL;
1071}
1072
1074{
1075 int pivot_index = FindPivotActorId(player, prev_player);
1076
1077 for (int i = pivot_index - 1; i >= 0; i--)
1078 {
1080 return m_actors[i];
1081 }
1082
1083 for (int i = static_cast<int>(m_actors.size()) - 1; i > pivot_index; i--)
1084 {
1086 return m_actors[i];
1087 }
1088
1089 if (pivot_index >= 0)
1090 {
1091 if (ShouldIncludeActorInList(m_actors[pivot_index]))
1092 return m_actors[pivot_index];
1093 }
1094
1095 return ACTORPTR_NULL;
1096}
1097
1098// END actorlist
1099
1101{
1102 for (ActorPtr& actor: m_actors)
1103 {
1104 if (actor->ar_rescuer_flag)
1105 {
1106 return actor;
1107 }
1108 }
1109 return ACTORPTR_NULL;
1110}
1111
1113{
1114 float dt = m_simulation_time;
1115
1116 // do not allow dt > 1/20
1117 dt = std::min(dt, 1.0f / 20.0f);
1118
1119 dt *= m_simulation_speed;
1120
1121 dt += m_dt_remainder;
1123 if (m_physics_steps == 0)
1124 {
1125 return;
1126 }
1127
1130
1131 this->SyncWithSimThread();
1132
1133 this->UpdateSleepingState(player_actor, dt);
1134
1135 for (ActorPtr& actor: m_actors)
1136 {
1137 actor->HandleInputEvents(dt);
1138 actor->HandleAngelScriptEvents(dt);
1139
1140#ifdef USE_ANGELSCRIPT
1141 if (actor->ar_vehicle_ai && actor->ar_vehicle_ai->isActive())
1142 actor->ar_vehicle_ai->update(dt, 0);
1143#endif // USE_ANGELSCRIPT
1144
1145 if (actor->ar_engine)
1146 {
1147 if (actor->ar_driveable == TRUCK)
1148 {
1149 this->UpdateTruckFeatures(actor, dt);
1150 }
1151 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
1152 {
1153 actor->ar_engine->UpdateEngine(dt, 1);
1154 }
1155 actor->ar_engine->UpdateEngineAudio();
1156 }
1157
1158 // Always update indicator states - used by 'u' type flares.
1159 actor->updateDashBoards(dt);
1160
1161 // Blinkers (turn signals) must always be updated
1162 actor->updateFlareStates(dt);
1163
1164 if (actor->ar_state != ActorState::LOCAL_SLEEPING)
1165 {
1166 actor->updateVisual(dt);
1167 if (actor->ar_update_physics && App::gfx_skidmarks_mode->getInt() > 0)
1168 {
1169 actor->updateSkidmarks();
1170 }
1171 }
1172 if (App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
1173 {
1174 // FIXME: Hidden actors must also be updated to workaround a glitch, see https://github.com/RigsOfRods/rigs-of-rods/issues/2911
1175 if (actor->ar_state == ActorState::NETWORKED_OK || actor->ar_state == ActorState::NETWORKED_HIDDEN)
1176 actor->calcNetwork();
1177 else
1178 actor->sendStreamData();
1179 }
1180 }
1181
1182 if (player_actor != nullptr)
1183 {
1184 this->ForwardCommands(player_actor);
1185 if (player_actor->ar_toggle_ties)
1186 {
1187 //player_actor->tieToggle();
1190 rq->alr_actor_instance_id = player_actor->ar_instance_id;
1191 rq->alr_tie_group = -1;
1193
1194 player_actor->ar_toggle_ties = false;
1195 }
1196 if (player_actor->ar_toggle_ropes)
1197 {
1198 //player_actor->ropeToggle(-1);
1201 rq->alr_actor_instance_id = player_actor->ar_instance_id;
1202 rq->alr_rope_group = -1;
1204
1205 player_actor->ar_toggle_ropes = false;
1206 }
1207
1208 player_actor->ForceFeedbackStep(m_physics_steps);
1209
1210 if (player_actor->ar_state == ActorState::LOCAL_REPLAY)
1211 {
1212 player_actor->getReplay()->replayStepActor();
1213 }
1214 }
1215
1216 auto func = std::function<void()>([this]()
1217 {
1219 });
1220 m_sim_task = m_sim_thread_pool->RunTask(func);
1221
1222 m_total_sim_time += dt;
1223
1224 if (!App::app_async_physics->getBool())
1225 m_sim_task->join();
1226}
1227
1229{
1230 for (ActorPtr& actor: m_actors)
1231 {
1232 if (actor->ar_instance_id == actor_id)
1233 {
1234 return actor;
1235 }
1236 }
1237 return ACTORPTR_NULL;
1238}
1239
1241{
1242 for (ActorPtr& actor: m_actors)
1243 {
1244 actor->UpdatePhysicsOrigin();
1245 }
1246 for (int i = 0; i < m_physics_steps; i++)
1247 {
1248 {
1249 std::vector<std::function<void()>> tasks;
1250 for (ActorPtr& actor: m_actors)
1251 {
1252 if (actor->ar_update_physics = actor->CalcForcesEulerPrepare(i == 0))
1253 {
1254 auto func = std::function<void()>([this, i, &actor]()
1255 {
1256 actor->CalcForcesEulerCompute(i == 0, m_physics_steps);
1257 });
1258 tasks.push_back(func);
1259 }
1260 }
1262 for (ActorPtr& actor: m_actors)
1263 {
1264 if (actor->ar_update_physics)
1265 {
1266 actor->CalcBeamsInterActor();
1267 }
1268 }
1269 }
1270 {
1271 std::vector<std::function<void()>> tasks;
1272 for (ActorPtr& actor: m_actors)
1273 {
1274 if (actor->m_inter_point_col_detector != nullptr && (actor->ar_update_physics ||
1276 {
1277 auto func = std::function<void()>([this, &actor]()
1278 {
1279 actor->m_inter_point_col_detector->UpdateInterPoint();
1280 if (actor->ar_collision_relevant)
1281 {
1282 ResolveInterActorCollisions(PHYSICS_DT,
1283 *actor->m_inter_point_col_detector,
1284 actor->ar_num_collcabs,
1285 actor->ar_collcabs,
1286 actor->ar_cabs,
1287 actor->ar_inter_collcabrate,
1288 actor->ar_nodes,
1289 actor->ar_collision_range,
1290 *actor->ar_submesh_ground_model);
1291 }
1292 });
1293 tasks.push_back(func);
1294 }
1295 }
1297 }
1298
1299 // Apply FreeForces - intentionally as a separate pass over all actors
1300 this->CalcFreeForces();
1301 }
1302 for (ActorPtr& actor: m_actors)
1303 {
1304 actor->m_ongoing_reset = false;
1305 if (actor->ar_update_physics && m_physics_steps > 0)
1306 {
1307 Vector3 camera_gforces = actor->m_camera_gforces_accu / m_physics_steps;
1308 actor->m_camera_gforces_accu = Vector3::ZERO;
1309 actor->m_camera_gforces = actor->m_camera_gforces * 0.5f + camera_gforces * 0.5f;
1310 actor->calculateLocalGForces();
1311 actor->calculateAveragePosition();
1312 actor->m_avg_node_velocity = actor->m_avg_node_position - actor->m_avg_node_position_prev;
1313 actor->m_avg_node_velocity /= (m_physics_steps * PHYSICS_DT);
1314 actor->m_avg_node_position_prev = actor->m_avg_node_position;
1315 actor->ar_top_speed = std::max(actor->ar_top_speed, actor->ar_nodes[0].Velocity.length());
1316 }
1317 }
1318}
1319
1321{
1322 if (m_sim_task)
1323 m_sim_task->join();
1324}
1325
1326void HandleErrorLoadingFile(std::string type, std::string filename, std::string exception_msg)
1327{
1328 RoR::Str<200> msg;
1329 msg << "Failed to load '" << filename << "' (type: '" << type << "'), message: " << exception_msg;
1332}
1333
1334void HandleErrorLoadingTruckfile(std::string filename, std::string exception_msg)
1335{
1336 HandleErrorLoadingFile("actor", filename, exception_msg);
1337}
1338
1340{
1341 // Check the actor exists in mod cache
1342 if (rq.asr_cache_entry == nullptr)
1343 {
1344 HandleErrorLoadingTruckfile(rq.asr_filename, "Truckfile not found in ModCache (probably not installed)");
1345 return nullptr;
1346 }
1347
1348 // If already parsed, re-use
1349 if (rq.asr_cache_entry->actor_def != nullptr)
1350 {
1351 return rq.asr_cache_entry->actor_def;
1352 }
1353
1354 // Load the 'truckfile'
1355 try
1356 {
1358 Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(rq.asr_cache_entry->fname, rq.asr_cache_entry->resource_group);
1359
1360 if (!stream || !stream->isReadable())
1361 {
1362 HandleErrorLoadingTruckfile(rq.asr_cache_entry->fname, "Unable to open/read truckfile");
1363 return nullptr;
1364 }
1365
1366 RoR::LogFormat("[RoR] Parsing truckfile '%s'", rq.asr_cache_entry->fname.c_str());
1367 RigDef::Parser parser;
1368 parser.Prepare();
1369 parser.ProcessOgreStream(stream.get(), rq.asr_cache_entry->resource_group);
1370 parser.Finalize();
1371
1372 auto def = parser.GetFile();
1373
1374 // VALIDATING
1375 LOG(" == Validating vehicle: " + def->name);
1376
1377 RigDef::Validator validator;
1378 validator.Setup(def);
1379
1381 {
1382 // Workaround: Some terrains pre-load truckfiles with special purpose:
1383 // "soundloads" = play sound effect at certain spot
1384 // "fixes" = structures of N/B fixed to the ground
1385 // These files can have no beams. Possible extensions: .load or .fixed
1386 std::string file_extension = rq.asr_cache_entry->fname.substr(rq.asr_cache_entry->fname.find_last_of('.'));
1387 Ogre::StringUtil::toLowerCase(file_extension);
1388 if ((file_extension == ".load") || (file_extension == ".fixed"))
1389 {
1390 validator.SetCheckBeams(false);
1391 }
1392 }
1393
1394 validator.Validate(); // Sends messages to console
1395
1396 def->hash = Sha1Hash(stream->getAsString());
1397
1398 rq.asr_cache_entry->actor_def = def;
1399 return def;
1400 }
1401 catch (Ogre::Exception& oex)
1402 {
1403 HandleErrorLoadingTruckfile(rq.asr_cache_entry->fname, oex.getDescription().c_str());
1404 return nullptr;
1405 }
1406 catch (std::exception& stex)
1407 {
1409 return nullptr;
1410 }
1411 catch (...)
1412 {
1413 HandleErrorLoadingTruckfile(rq.asr_cache_entry->fname, "<Unknown exception occurred>");
1414 return nullptr;
1415 }
1416}
1417
1418void ActorManager::ExportActorDef(RigDef::DocumentPtr def, std::string filename, std::string rg_name)
1419{
1420 try
1421 {
1422 Ogre::ResourceGroupManager& rgm = Ogre::ResourceGroupManager::getSingleton();
1423
1424 // Open OGRE stream for writing
1425 Ogre::DataStreamPtr stream = rgm.createResource(filename, rg_name, /*overwrite=*/true);
1426 if (stream.isNull() || !stream->isWriteable())
1427 {
1428 OGRE_EXCEPT(Ogre::Exception::ERR_CANNOT_WRITE_TO_FILE,
1429 "Stream NULL or not writeable, filename: '" + filename
1430 + "', resource group: '" + rg_name + "'");
1431 }
1432
1433 // Serialize actor to string
1434 RigDef::Serializer serializer(def);
1435 serializer.Serialize();
1436
1437 // Flush the string to file
1438 stream->write(serializer.GetOutput().c_str(), serializer.GetOutput().size());
1439 stream->close();
1440 }
1441 catch (Ogre::Exception& oex)
1442 {
1444 fmt::format(_LC("Truck", "Failed to export truck '{}' to resource group '{}', message: {}"),
1445 filename, rg_name, oex.getFullDescription()));
1446 }
1447}
1448
1449std::vector<ActorPtr> ActorManager::GetLocalActors()
1450{
1451 std::vector<ActorPtr> actors;
1452 for (ActorPtr& actor: m_actors)
1453 {
1454 if (actor->ar_state != ActorState::NETWORKED_OK)
1455 actors.push_back(actor);
1456 }
1457 return actors;
1458}
1459
1461{
1462 // Simulation pace adjustment (slowmotion)
1463 if (!App::GetGameContext()->GetRaceSystem().IsRaceInProgress())
1464 {
1465 // EV_COMMON_ACCELERATE_SIMULATION
1466 if (App::GetInputEngine()->getEventBoolValue(EV_COMMON_ACCELERATE_SIMULATION))
1467 {
1468 float simulation_speed = this->GetSimulationSpeed() * pow(2.0f, dt / 2.0f);
1469 this->SetSimulationSpeed(simulation_speed);
1470 String ssmsg = _L("New simulation speed: ") + TOSTRING(Round(simulation_speed * 100.0f, 1)) + "%";
1472 }
1473
1474 // EV_COMMON_DECELERATE_SIMULATION
1475 if (App::GetInputEngine()->getEventBoolValue(EV_COMMON_DECELERATE_SIMULATION))
1476 {
1477 float simulation_speed = this->GetSimulationSpeed() * pow(0.5f, dt / 2.0f);
1478 this->SetSimulationSpeed(simulation_speed);
1479 String ssmsg = _L("New simulation speed: ") + TOSTRING(Round(simulation_speed * 100.0f, 1)) + "%";
1481 }
1482
1483 // EV_COMMON_RESET_SIMULATION_PACE
1484 if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_RESET_SIMULATION_PACE))
1485 {
1486 float simulation_speed = this->GetSimulationSpeed();
1487 if (simulation_speed != 1.0f)
1488 {
1489 m_last_simulation_speed = simulation_speed;
1490 this->SetSimulationSpeed(1.0f);
1491 std::string ssmsg = _L("Simulation speed reset.");
1493 }
1494 else if (m_last_simulation_speed != 1.0f)
1495 {
1497 String ssmsg = _L("New simulation speed: ") + TOSTRING(Round(m_last_simulation_speed * 100.0f, 1)) + "%";
1499 }
1500 }
1501
1502 // Special adjustment while racing
1503 if (App::GetGameContext()->GetRaceSystem().IsRaceInProgress() && this->GetSimulationSpeed() != 1.0f)
1504 {
1506 this->SetSimulationSpeed(1.f);
1507 }
1508 }
1509
1510 // EV_COMMON_TOGGLE_PHYSICS - Freeze/unfreeze physics
1511 if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_TOGGLE_PHYSICS))
1512 {
1514
1516 {
1517 String ssmsg = _L("Physics paused");
1519 }
1520 else
1521 {
1522 String ssmsg = _L("Physics unpaused");
1524 }
1525 }
1526
1527 // Calculate simulation time
1529 {
1530 m_simulation_time = 0.f;
1531
1532 // Frozen physics stepping
1533 if (this->GetSimulationSpeed() > 0.0f)
1534 {
1535 // EV_COMMON_REPLAY_FAST_FORWARD - Advance simulation while pressed
1536 // EV_COMMON_REPLAY_FORWARD - Advanced simulation one step
1537 if (App::GetInputEngine()->getEventBoolValue(EV_COMMON_REPLAY_FAST_FORWARD) ||
1538 App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_REPLAY_FORWARD))
1539 {
1541 }
1542 }
1543 }
1544 else
1545 {
1546 m_simulation_time = dt;
1547 }
1548}
1549
1551{
1552 if (vehicle->isBeingReset() || vehicle->ar_physics_paused)
1553 return;
1554#ifdef USE_ANGELSCRIPT
1555 if (vehicle->ar_vehicle_ai && vehicle->ar_vehicle_ai->isActive())
1556 return;
1557#endif // USE_ANGELSCRIPT
1558
1559 EnginePtr engine = vehicle->ar_engine;
1560
1561 if (engine && engine->hasContact() &&
1562 engine->getAutoMode() == SimGearboxMode::AUTO &&
1563 engine->getAutoShift() != Engine::NEUTRAL)
1564 {
1565 Ogre::Vector3 dirDiff = vehicle->getDirection();
1566 Ogre::Degree pitchAngle = Ogre::Radian(asin(dirDiff.dotProduct(Ogre::Vector3::UNIT_Y)));
1567
1568 if (std::abs(pitchAngle.valueDegrees()) > 2.0f)
1569 {
1570 if (engine->getAutoShift() > Engine::NEUTRAL && vehicle->ar_avg_wheel_speed < +0.02f && pitchAngle.valueDegrees() > 0.0f ||
1571 engine->getAutoShift() < Engine::NEUTRAL && vehicle->ar_avg_wheel_speed > -0.02f && pitchAngle.valueDegrees() < 0.0f)
1572 {
1573 // anti roll back in SimGearboxMode::AUTO (DRIVE, TWO, ONE) mode
1574 // anti roll forth in SimGearboxMode::AUTO (REAR) mode
1575 float g = std::abs(App::GetGameContext()->GetTerrain()->getGravity());
1576 float downhill_force = std::abs(sin(pitchAngle.valueRadians()) * vehicle->getTotalMass()) * g;
1577 float engine_force = std::abs(engine->getTorque()) / vehicle->getAvgPropedWheelRadius();
1578 float ratio = std::max(0.0f, 1.0f - (engine_force / downhill_force));
1579 if (vehicle->ar_avg_wheel_speed * pitchAngle.valueDegrees() > 0.0f)
1580 {
1581 ratio *= sqrt((0.02f - vehicle->ar_avg_wheel_speed) / 0.02f);
1582 }
1583 vehicle->ar_brake = sqrt(ratio);
1584 }
1585 }
1586 else if (vehicle->ar_brake == 0.0f && !vehicle->ar_parking_brake && engine->getTorque() == 0.0f)
1587 {
1588 float ratio = std::max(0.0f, 0.2f - std::abs(vehicle->ar_avg_wheel_speed)) / 0.2f;
1589 vehicle->ar_brake = ratio;
1590 }
1591 }
1592
1593 if (vehicle->cc_mode)
1594 {
1595 vehicle->UpdateCruiseControl(dt);
1596 }
1597 if (vehicle->sl_enabled)
1598 {
1599 // check speed limit
1600 if (engine && engine->getGear() != 0)
1601 {
1602 float accl = (vehicle->sl_speed_limit - std::abs(vehicle->ar_wheel_speed / 1.02f)) * 2.0f;
1603 engine->setAcc(Ogre::Math::Clamp(accl, 0.0f, engine->getAcc()));
1604 }
1605 }
1606
1607 BITMASK_SET(vehicle->m_lightmask, RoRnet::LIGHTMASK_BRAKES, (vehicle->ar_brake > 0.01f && !vehicle->ar_parking_brake));
1608 BITMASK_SET(vehicle->m_lightmask, RoRnet::LIGHTMASK_REVERSE, (vehicle->ar_engine && vehicle->ar_engine->getGear() < 0));
1609}
1610
1612{
1613 for (FreeForce& freeforce: m_free_forces)
1614 {
1615 // Sanity checks
1616 ROR_ASSERT(freeforce.ffc_base_actor != nullptr);
1617 ROR_ASSERT(freeforce.ffc_base_actor->ar_state != ActorState::DISPOSED);
1618 ROR_ASSERT(freeforce.ffc_base_node != NODENUM_INVALID);
1619 ROR_ASSERT(freeforce.ffc_base_node <= freeforce.ffc_base_actor->ar_num_nodes);
1620
1621
1622 switch (freeforce.ffc_type)
1623 {
1625 freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].Forces += freeforce.ffc_force_magnitude * freeforce.ffc_force_const_direction;
1626 break;
1627
1629 {
1630 const Vector3 force_direction = (freeforce.ffc_target_coords - freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].AbsPosition).normalisedCopy();
1631 freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].Forces += freeforce.ffc_force_magnitude * force_direction;
1632 }
1633 break;
1634
1636 {
1637 // Sanity checks
1638 ROR_ASSERT(freeforce.ffc_target_actor != nullptr);
1639 ROR_ASSERT(freeforce.ffc_target_actor->ar_state != ActorState::DISPOSED);
1640 ROR_ASSERT(freeforce.ffc_target_node != NODENUM_INVALID);
1641 ROR_ASSERT(freeforce.ffc_target_node <= freeforce.ffc_target_actor->ar_num_nodes);
1642
1643 const Vector3 force_direction = (freeforce.ffc_target_actor->ar_nodes[freeforce.ffc_target_node].AbsPosition - freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].AbsPosition).normalisedCopy();
1644 freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].Forces += freeforce.ffc_force_magnitude * force_direction;
1645 }
1646 break;
1647
1650 {
1651 // Sanity checks
1652 ROR_ASSERT(freeforce.ffc_target_actor != nullptr);
1653 ROR_ASSERT(freeforce.ffc_target_actor->ar_state != ActorState::DISPOSED);
1654 ROR_ASSERT(freeforce.ffc_target_node != NODENUM_INVALID);
1655 ROR_ASSERT(freeforce.ffc_target_node <= freeforce.ffc_target_actor->ar_num_nodes);
1656
1657 // ---- BEGIN COPYPASTE of `Actor::CalcBeamsInterActor()` ----
1658
1659 // Calculate beam length
1660 node_t* p1 = &freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node];
1661 node_t* p2 = &freeforce.ffc_target_actor->ar_nodes[freeforce.ffc_target_node];
1662 const Vector3 dis = p1->AbsPosition - p2->AbsPosition;
1663
1664 Real dislen = dis.squaredLength();
1665 const Real inverted_dislen = fast_invSqrt(dislen);
1666
1667 dislen *= inverted_dislen;
1668
1669 // Calculate beam's deviation from normal
1670 Real difftoBeamL = dislen - freeforce.ffc_halfb_L;
1671
1672 Real k = freeforce.ffc_halfb_spring;
1673 Real d = freeforce.ffc_halfb_damp;
1674
1675 if (freeforce.ffc_type == FreeForceType::HALFBEAM_ROPE && difftoBeamL < 0.0f)
1676 {
1677 k = 0.0f;
1678 d *= 0.1f;
1679 }
1680
1681 // Calculate beam's rate of change
1682 Vector3 v = p1->Velocity - p2->Velocity;
1683
1684 float slen = -k * (difftoBeamL)-d * v.dotProduct(dis) * inverted_dislen;
1685 freeforce.ffc_halfb_stress = slen;
1686
1687 // Fast test for deformation
1688 float len = std::abs(slen);
1689 if (len > freeforce.ffc_halfb_minmaxposnegstress)
1690 {
1691 if (k != 0.0f)
1692 {
1693 // Actual deformation tests
1694 if (slen > freeforce.ffc_halfb_maxposstress && difftoBeamL < 0.0f) // compression
1695 {
1696 Real yield_length = freeforce.ffc_halfb_maxposstress / k;
1697 Real deform = difftoBeamL + yield_length * (1.0f - freeforce.ffc_halfb_plastic_coef);
1698 Real Lold = freeforce.ffc_halfb_L;
1699 freeforce.ffc_halfb_L += deform;
1700 freeforce.ffc_halfb_L = std::max(MIN_BEAM_LENGTH, freeforce.ffc_halfb_L);
1701 slen = slen - (slen - freeforce.ffc_halfb_maxposstress) * 0.5f;
1702 len = slen;
1703 if (freeforce.ffc_halfb_L > 0.0f && Lold > freeforce.ffc_halfb_L)
1704 {
1705 freeforce.ffc_halfb_maxposstress *= Lold / freeforce.ffc_halfb_L;
1706 freeforce.ffc_halfb_minmaxposnegstress = std::min(freeforce.ffc_halfb_maxposstress, -freeforce.ffc_halfb_maxnegstress);
1707 freeforce.ffc_halfb_minmaxposnegstress = std::min(freeforce.ffc_halfb_minmaxposnegstress, freeforce.ffc_halfb_strength);
1708 }
1709 // For the compression case we do not remove any of the beam's
1710 // strength for structure stability reasons
1711 //freeforce.ffc_halfb_strength += deform * k * 0.5f;
1712
1714 fmt::format("{}", slen), fmt::format("{}", freeforce.ffc_halfb_maxposstress));
1715 }
1716 else if (slen < freeforce.ffc_halfb_maxnegstress && difftoBeamL > 0.0f) // expansion
1717 {
1718 Real yield_length = freeforce.ffc_halfb_maxnegstress / k;
1719 Real deform = difftoBeamL + yield_length * (1.0f - freeforce.ffc_halfb_plastic_coef);
1720 Real Lold = freeforce.ffc_halfb_L;
1721 freeforce.ffc_halfb_L += deform;
1722 slen = slen - (slen - freeforce.ffc_halfb_maxnegstress) * 0.5f;
1723 len = -slen;
1724 if (Lold > 0.0f && freeforce.ffc_halfb_L > Lold)
1725 {
1726 freeforce.ffc_halfb_maxnegstress *= freeforce.ffc_halfb_L / Lold;
1727 freeforce.ffc_halfb_minmaxposnegstress = std::min(freeforce.ffc_halfb_maxposstress, -freeforce.ffc_halfb_maxnegstress);
1728 freeforce.ffc_halfb_minmaxposnegstress = std::min(freeforce.ffc_halfb_minmaxposnegstress, freeforce.ffc_halfb_strength);
1729 }
1730 freeforce.ffc_halfb_strength -= deform * k;
1731
1733 fmt::format("{}", slen), fmt::format("{}", freeforce.ffc_halfb_maxnegstress));
1734 }
1735 }
1736
1737 // Test if the beam should break
1738 if (len > freeforce.ffc_halfb_strength)
1739 {
1740 // Sound effect.
1741 // Sound volume depends on springs stored energy
1742 SOUND_MODULATE(freeforce.ffc_base_actor->ar_instance_id, SS_MOD_BREAK, 0.5 * k * difftoBeamL * difftoBeamL);
1743 SOUND_PLAY_ONCE(freeforce.ffc_base_actor->ar_instance_id, SS_TRIG_BREAK);
1744
1745 freeforce.ffc_type = FreeForceType::DUMMY;
1746
1748 fmt::format("{}", len), fmt::format("{}", freeforce.ffc_halfb_strength));
1749 }
1750 }
1751
1752 // At last update the beam forces
1753 Vector3 f = dis;
1754 f *= (slen * inverted_dislen);
1755 p1->Forces += f;
1756 // ---- END COPYPASTE of `Actor::CalcBeamsInterActor()` ----
1757 }
1758 break;
1759
1760 default:
1761 break;
1762 }
1763 }
1764}
1765
1766static bool ProcessFreeForce(FreeForceRequest* rq, FreeForce& freeforce)
1767{
1768 // internal helper for processing add/modify requests, with checks
1769 // ---------------------------------------------------------------
1770
1771 // Unchecked stuff
1772 freeforce.ffc_id = (FreeForceID_t)rq->ffr_id;
1773 freeforce.ffc_type = (FreeForceType)rq->ffr_type;
1774 freeforce.ffc_force_magnitude = (float)rq->ffr_force_magnitude;
1776 freeforce.ffc_target_coords = rq->ffr_target_coords;
1777
1778 // Base actor
1780 ROR_ASSERT(freeforce.ffc_base_actor != nullptr && freeforce.ffc_base_actor->ar_state != ActorState::DISPOSED);
1781 if (!freeforce.ffc_base_actor || freeforce.ffc_base_actor->ar_state == ActorState::DISPOSED)
1782 {
1784 fmt::format("Cannot add free force with ID {} to actor {}: Base actor not found or disposed", freeforce.ffc_id, rq->ffr_base_actor));
1785 return false;
1786 }
1787
1788 // Base node
1789 ROR_ASSERT(rq->ffr_base_node >= 0);
1792 if (rq->ffr_base_node < 0 || rq->ffr_base_node >= NODENUM_MAX || rq->ffr_base_node >= freeforce.ffc_base_actor->ar_num_nodes)
1793 {
1795 fmt::format("Cannot add free force with ID {} to actor {}: Invalid base node number {}", freeforce.ffc_id, rq->ffr_base_actor, rq->ffr_base_node));
1796 return false;
1797 }
1798 freeforce.ffc_base_node = (NodeNum_t)rq->ffr_base_node;
1799
1800 if (freeforce.ffc_type == FreeForceType::TOWARDS_NODE ||
1803 {
1804 // Target actor
1806 ROR_ASSERT(freeforce.ffc_target_actor != nullptr && freeforce.ffc_target_actor->ar_state != ActorState::DISPOSED);
1807 if (!freeforce.ffc_target_actor || freeforce.ffc_target_actor->ar_state == ActorState::DISPOSED)
1808 {
1810 fmt::format("Cannot add free force of type 'TOWARDS_NODE' with ID {} to actor {}: Target actor not found or disposed", freeforce.ffc_id, rq->ffr_target_actor));
1811 return false;
1812 }
1813
1814 // Target node
1815 ROR_ASSERT(rq->ffr_target_node >= 0);
1819 {
1821 fmt::format("Cannot add free force of type 'TOWARDS_NODE' with ID {} to actor {}: Invalid target node number {}", freeforce.ffc_id, rq->ffr_target_actor, rq->ffr_target_node));
1822 return false;
1823 }
1824 freeforce.ffc_target_node = (NodeNum_t)rq->ffr_target_node;
1825
1826 if (freeforce.ffc_type == FreeForceType::HALFBEAM_GENERIC ||
1828 {
1829 freeforce.ffc_halfb_spring = (float)rq->ffr_halfb_spring;
1830 freeforce.ffc_halfb_damp = (float)rq->ffr_halfb_damp;
1831 freeforce.ffc_halfb_strength = (float)rq->ffr_halfb_strength;
1832 freeforce.ffc_halfb_deform = (float)rq->ffr_halfb_deform;
1833 freeforce.ffc_halfb_diameter = (float)rq->ffr_halfb_diameter;
1834 freeforce.ffc_halfb_plastic_coef = (float)rq->ffr_halfb_plastic_coef;
1835
1836 freeforce.ffc_halfb_minmaxposnegstress = (float)rq->ffr_halfb_deform;
1837 freeforce.ffc_halfb_maxposstress = (float)rq->ffr_halfb_deform;
1838 freeforce.ffc_halfb_maxnegstress = -(float)rq->ffr_halfb_deform;
1839
1840 // Calc length
1841 const Ogre::Vector3 base_pos = freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].AbsPosition;
1842 const Ogre::Vector3 target_pos = freeforce.ffc_target_actor->ar_nodes[freeforce.ffc_target_node].AbsPosition;
1843 freeforce.ffc_halfb_L = target_pos.distance(base_pos);
1844 }
1845 }
1846
1847 return true;
1848}
1849
1850bool ActorManager::FindFreeForce(FreeForceID_t id, ActorManager::FreeForceVec_t::iterator& out_itor)
1851{
1852 out_itor = std::find_if(m_free_forces.begin(), m_free_forces.end(), [id](FreeForce& item) { return id == item.ffc_id; });
1853 return out_itor != m_free_forces.end();
1854}
1855
1857{
1858 // Make sure ID is unique
1859 ActorManager::FreeForceVec_t::iterator it;
1860 if (this->FindFreeForce(rq->ffr_id, it))
1861 {
1863 fmt::format("Cannot add free force with ID {}: ID already in use", rq->ffr_id));
1864 return;
1865 }
1866
1867 FreeForce freeforce;
1868 if (ProcessFreeForce(rq, freeforce))
1869 {
1870 m_free_forces.push_back(freeforce);
1872 }
1873}
1874
1876{
1877 ActorManager::FreeForceVec_t::iterator it;
1878 if (!this->FindFreeForce(rq->ffr_id, it))
1879 {
1881 fmt::format("Cannot modify free force with ID {}: ID not found", rq->ffr_id));
1882 return;
1883 }
1884
1885 FreeForce& freeforce = *it;
1886 if (ProcessFreeForce(rq, freeforce))
1887 {
1888 *it = freeforce;
1890 }
1891}
1892
1894{
1895 ActorManager::FreeForceVec_t::iterator it;
1896 if (!this->FindFreeForce(id, it))
1897 {
1899 fmt::format("Cannot remove free force with ID {}: ID not found", id));
1900 return;
1901 }
1902
1903 m_free_forces.erase(it);
1905}
int FindPivotActorId(ActorPtr player, ActorPtr prev_player)
static bool ProcessFreeForce(FreeForceRequest *rq, FreeForce &freeforce)
void HandleErrorLoadingTruckfile(std::string filename, std::string exception_msg)
void HandleErrorLoadingFile(std::string type, std::string filename, std::string exception_msg)
bool ShouldIncludeActorInList(const ActorPtr &actor)
Vehicle spawning logic.
Central state/object manager and communications hub.
#define ROR_ASSERT(_EXPR)
Definition Application.h:40
#define TOSTRING(x)
Definition Application.h:57
void LOG(const char *msg)
Legacy alias - formerly a macro.
float fast_invSqrt(const float v)
Definition ApproxMath.h:124
void BITMASK_SET(BitMask_t &mask, BitMask_t flag, bool val)
Definition BitFlags.h:19
uint32_t BitMask_t
Definition BitFlags.h:7
A database of user-installed content alias 'mods' (vehicles, terrains...)
#define _L
Game state manager and message-queue provider.
#define strnlen(str, len)
Handles controller inputs from player.
#define _LC(ctx, str)
Definition Language.h:38
This creates a billboarding object that displays a text.
.truck format validator
static const int MAX_COMMANDS
maximum number of commands per actor
#define PHYSICS_DT
#define SOUND_PLAY_ONCE(_ACTOR_, _TRIG_)
#define SOUND_MODULATE(_ACTOR_, _MOD_, _VALUE_)
The vehicle tuning system; applies addonparts and user overrides to vehicles.
Simple waypoint AI.
Checks the rig-def file syntax and pulls data to File object.
RigDef::DocumentPtr GetFile()
void ProcessOgreStream(Ogre::DataStream *stream, Ogre::String resource_group)
Serializes the RigDef::File data structure to string.
std::string GetOutput() const
Performs a formal validation of the file (missing required parts, conflicts of modules,...
void Setup(RigDef::DocumentPtr file)
Prepares the validation.
void SetCheckBeams(bool check_beams)
Softbody object; can be anything from soda can to a space shuttle Constructed from a truck definition...
Definition Actor.h:55
bool ar_parking_brake
Definition Actor.h:467
bool ar_import_commands
Sim state.
Definition Actor.h:556
std::vector< float > ar_orig_minimass
minimum node mass in Kg - original unscaled values
Definition Actor.h:338
Ogre::AxisAlignedBox ar_bounding_box
standard bounding box (surrounds all nodes of an actor)
Definition Actor.h:370
int m_wheel_node_count
Static attr; filled at spawn.
Definition Actor.h:644
size_t m_net_total_buffer_size
For incoming/outgoing traffic; calculated on spawn.
Definition Actor.h:678
EnginePtr ar_engine
Definition Actor.h:432
BitMask_t getLightStateMask() const
Definition Actor.h:213
std::vector< float > ar_minimass
minimum node mass in Kg - can be scaled in-game via NBUtil
Definition Actor.h:337
float ar_dry_mass
User-defined (editable via NBUtil); from 'globals' arg#1 - default for all nodes.
Definition Actor.h:320
bool ar_forward_commands
Sim state.
Definition Actor.h:555
void calcNodeConnectivityGraph()
Definition Actor.cpp:907
float ar_wheel_speed
Physics state; wheel speed in m/s.
Definition Actor.h:453
BuoyCachedNodeID_t ar_cabs_buoy_cache_ids[MAX_CABS]
Definition Actor.h:393
CmdKeyArray ar_command_key
BEWARE: commandkeys are indexed 1-MAX_COMMANDS!
Definition Actor.h:369
node_t * ar_nodes
Definition Actor.h:330
void dispose()
Effectively destroys the object but keeps it in memory to satisfy shared pointers.
Definition Actor.cpp:89
float ar_original_load_mass
Un-edited value from 'globals' arg#2.
Definition Actor.h:323
void updateVisual(float dt=0)
Definition Actor.cpp:3285
int ar_buoycabs[MAX_CABS]
Definition Actor.h:400
GfxActor * GetGfxActor()
Definition Actor.h:309
float getRotation()
Definition Actor.cpp:355
bool m_disable_default_sounds
Spawner context; TODO: remove.
Definition Actor.h:706
void NotifyActorCameraChanged()
Logic: sound, display; Notify this vehicle that camera changed;.
Definition Actor.cpp:3893
float ar_sleep_counter
Sim state; idle time counter.
Definition Actor.h:465
float ar_original_dry_mass
Un-edited value from 'globals' arg#1.
Definition Actor.h:321
ground_model_t * ar_submesh_ground_model
Definition Actor.h:466
Replay * getReplay()
Definition Actor.cpp:4663
float ar_initial_total_mass
Calculated; total mass in Kg (snapshot at spawn)
Definition Actor.h:326
bool m_preloaded_with_terrain
Spawn context (TODO: remove!)
Definition Actor.h:702
std::vector< std::pair< float, float > > ar_initial_beam_defaults
Definition Actor.h:350
unsigned int ar_vector_index
Sim attr; actor element index in std::vector<m_actors>
Definition Actor.h:430
float m_spawn_rotation
Definition Actor.h:631
Replay * m_replay_handler
Definition Actor.h:627
bool ar_physics_paused
Actor physics individually paused by user.
Definition Actor.h:521
Ogre::Vector3 getPosition()
Definition Actor.cpp:370
void ForceFeedbackStep(int steps)
Definition Actor.cpp:1837
bool ar_toggle_ropes
Sim state.
Definition Actor.h:557
int m_net_color_num
Definition Actor.h:683
std::vector< Ogre::Vector3 > ar_initial_node_positions
Absolute world positions, for resetting to pristine state.
Definition Actor.h:340
void UpdatePhysicsOrigin()
Definition Actor.cpp:1250
int ar_net_source_id
Unique ID of remote player who spawned this actor.
Definition Actor.h:479
void recalculateNodeMasses()
Definition Actor.cpp:701
std::unique_ptr< Buoyance > m_buoyance
Definition Actor.h:490
std::string m_net_username
Definition Actor.h:682
bool sl_enabled
Speed limiter;.
Definition Actor.h:423
float getAvgPropedWheelRadius()
Definition Actor.h:299
float ar_load_mass
User-defined (editable via NBUtil); from 'globals' arg#2 - only applies to nodes with 'l' flag.
Definition Actor.h:322
Ogre::Vector3 ar_origin
Physics state; base position for softbody nodes.
Definition Actor.h:438
ActorState ar_state
Definition Actor.h:518
size_t m_net_wheel_buf_size
For incoming/outgoing traffic; calculated on spawn.
Definition Actor.h:676
void sendStreamSetup()
Definition Actor.cpp:1996
Ogre::Vector3 getDirection()
average actor velocity, calculated using the actor positions of the last two frames
Definition Actor.cpp:365
size_t m_net_propanimkey_buf_size
For incoming/outgoing traffic; calculated on spawn.
Definition Actor.h:677
bool isBeingReset() const
Definition Actor.h:313
float ar_total_mass
Calculated; total mass in Kg.
Definition Actor.h:325
void WriteDiagnosticDump(std::string const &filename)
Definition Actor.cpp:4788
int ar_num_beams
Definition Actor.h:349
ActorInstanceID_t ar_instance_id
Static attr; session-unique ID.
Definition Actor.h:429
ActorPtrVec ar_linked_actors
BEWARE: Includes indirect links, see DetermineLinkedActors(); Other actors linked using 'hooks/ties/r...
Definition Actor.h:519
float ar_avg_wheel_speed
Physics state; avg wheel speed in m/s.
Definition Actor.h:455
std::vector< PropAnimKeyState > m_prop_anim_key_states
Definition Actor.h:661
Ogre::Real ar_brake
Physics state; braking intensity.
Definition Actor.h:452
bool isPreloadedWithTerrain() const
Definition Actor.h:280
std::string ar_filename
Attribute; filled at spawn.
Definition Actor.h:476
Ogre::Real m_min_camera_radius
Definition Actor.h:623
int ar_num_cinecams
Sim attr;.
Definition Actor.h:434
TyrePressure & getTyrePressure()
Definition Actor.h:259
std::string m_section_config
Classic 'sectionconfig' in truck file.
Definition Actor.h:665
bool cc_mode
Cruise Control.
Definition Actor.h:417
int ar_cabs[MAX_CABS *3]
Definition Actor.h:392
int ar_num_nodes
Definition Actor.h:345
VehicleAIPtr ar_vehicle_ai
Definition Actor.h:450
BitMask_t m_lightmask
RoRnet::Lightmask.
Definition Actor.h:689
float getTotalMass(bool withLocked=true)
Definition Actor.cpp:843
void calculateAveragePosition()
Definition Actor.cpp:1166
std::vector< hook_t > ar_hooks
Definition Actor.h:366
void UpdateBoundingBoxes()
Definition Actor.cpp:1201
int ar_num_wheels
Definition Actor.h:385
void UpdateCruiseControl(float dt)
Defined in 'gameplay/CruiseControl.cpp'.
int m_net_first_wheel_node
Network attr; Determines data buffer layout; calculated on spawn.
Definition Actor.h:680
Ogre::Vector3 m_avg_node_position
average node position
Definition Actor.h:622
size_t m_net_node_buf_size
For incoming/outgoing traffic; calculated on spawn.
Definition Actor.h:675
beam_t * ar_beams
Definition Actor.h:348
bool ar_trailer_parking_brake
Definition Actor.h:468
int ar_num_buoycabs
Definition Actor.h:402
bool ar_toggle_ties
Sim state.
Definition Actor.h:558
std::vector< float > ar_initial_node_masses
Definition Actor.h:339
void resetPosition(Ogre::Vector3 translation, bool setInitPosition)
Moves the actor to given world coords (pivot point is node 0).
Definition Actor.cpp:1351
float sl_speed_limit
Speed limiter;.
Definition Actor.h:424
int ar_net_stream_id
Definition Actor.h:480
ActorPtrVec & GetActors()
void UpdateSleepingState(ActorPtr player_actor, float dt)
RigDef::DocumentPtr FetchActorDef(RoR::ActorSpawnRequest &rq)
float m_simulation_time
Amount of time the physics simulation is going to be advanced.
void SetSimulationSpeed(float speed)
void RequestSpawnRemoteActor(RoRnet::ActorStreamRegister *reg, const CacheEntryPtr &cache_entry, const RoRnet::UserInfo &userinfo, BitMask_t peeropts)
void DeleteActorInternal(ActorPtr actor)
Do not call directly; use GameContext::DeleteActor()
RoRnet::UiStreamsHealth CheckNetworkStreamsOk(int sourceid)
RoRnet::UiStreamsHealth CheckNetRemoteStreamsOk(int sourceid)
const ActorPtr & FetchNextVehicleOnList(ActorPtr player, ActorPtr prev_player)
std::map< beam_t *, std::pair< ActorPtr, ActorPtr > > inter_actor_links
void RemoveFreeForce(FreeForceID_t id)
std::shared_ptr< Task > m_sim_task
void ModifyFreeForce(FreeForceRequest *rq)
std::map< int, std::set< int > > m_stream_mismatches
Networking: A set of streams without a corresponding actor in the actor-array for each stream source.
const ActorPtr & GetActorByNetworkLinks(int source_id, int stream_id)
void UpdateTruckFeatures(ActorPtr vehicle, float dt)
float m_simulation_speed
slow motion < 1.0 < fast motion
void CleanUpSimulation()
Call this after simulation loop finishes.
ActorPtrVec m_actors
Use MSG_SIM_{SPAWN/DELETE}_ACTOR_REQUESTED
bool CheckActorCollAabbIntersect(int a, int b)
Returns whether or not the bounding boxes of truck a and truck b intersect. Based on the truck collis...
const ActorPtr & FetchPreviousVehicleOnList(ActorPtr player, ActorPtr prev_player)
void RemoveStreamSource(int sourceid)
bool PredictActorCollAabbIntersect(int a, int b)
Returns whether or not the bounding boxes of truck a and truck b might intersect during the next fram...
void UpdateNetTimeOffset(int sourceid, int offset)
void ForwardCommands(ActorPtr source_actor)
Fowards things to trailers.
bool m_forced_awake
disables sleep counters
void ExportActorDef(RigDef::DocumentPtr def, std::string filename, std::string rg_name)
ActorPtr FindActorInsideBox(Collisions *collisions, const Ogre::String &inst, const Ogre::String &box)
void UpdateActors(ActorPtr player_actor)
FreeForceVec_t m_free_forces
Global forces added ad-hoc by scripts.
void RetryFailedStreamRegistrations(ScriptEventArgs *args)
float GetSimulationSpeed() const
int GetNetTimeOffset(int sourceid)
const ActorPtr & GetActorById(ActorInstanceID_t actor_id)
void RemoveStream(int sourceid, int streamid)
ActorPtr CreateNewActor(ActorSpawnRequest rq, RigDef::DocumentPtr def)
void AddStreamMismatch(RoRnet::ActorStreamRegister *reg)
void HandleActorStreamData(std::vector< RoR::NetRecvPacket > packet)
std::pair< ActorPtr, float > GetNearestActor(Ogre::Vector3 position)
void UpdateInputEvents(float dt)
float m_last_simulation_speed
previously used time ratio between real time (evt.timeSinceLastFrame) and physics time ('dt' used in ...
void AddFreeForce(FreeForceRequest *rq)
std::map< int, int > m_stream_time_offsets
Networking: A network time offset for each stream source.
void RecursiveActivation(int j, std::vector< bool > &visited)
ActorInstanceID_t GetActorNextInstanceId()
Script proxy: game.getActorNextInstanceId()
void RepairActor(Collisions *collisions, const Ogre::String &inst, const Ogre::String &box, bool keepPosition=false)
void CalcFreeForces()
Apply FreeForces - intentionally as a separate pass over all actors.
const ActorPtr & FetchRescueVehicle()
std::vector< RoRnet::ActorStreamRegister > m_stream_mismatched_regs
Networking: Remember mismatched stream regs to re-process after downloading the missing mods.
std::vector< ActorPtr > GetLocalActors()
float m_dt_remainder
Keeps track of the rounding error in the time step calculation.
bool FindFreeForce(FreeForceID_t id, FreeForceVec_t::iterator &out_itor)
Ogre::Timer m_net_timer
std::unique_ptr< ThreadPool > m_sim_thread_pool
static const ActorPtr ACTORPTR_NULL
bool AreActorsDirectlyLinked(const ActorPtr &a1, const ActorPtr &a2)
Processes a RigDef::Document (parsed from 'truck' file format) into a simulated gameplay object (Acto...
void ConfigureAssetPacks(ActorPtr actor)
void ConfigureAddonParts(ActorPtr actor)
void ConfigureSections(Ogre::String const &sectionconfig, RigDef::DocumentPtr def)
void ProcessNewActor(ActorPtr actor, ActorSpawnRequest rq, RigDef::DocumentPtr def)
std::string GetSubmeshGroundmodelName()
ActorMemoryRequirements const & GetMemoryRequirements()
static void SetupDefaultSoundSources(ActorPtr const &actor)
bool getBool() const
Definition CVar.h:98
int getInt() const
Definition CVar.h:97
Ogre::String fname
filename
Definition CacheSystem.h:67
Ogre::String resource_group
Resource group of the loaded bundle. Empty if not loaded yet.
Definition CacheSystem.h:89
RigDef::DocumentPtr actor_def
Cached actor definition (aka truckfile) after first spawn.
Definition CacheSystem.h:91
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,...
CacheEntryPtr FetchSkinByName(std::string const &skin_name)
CacheEntryPtr GetEntryByNumber(int modid)
void LoadResource(CacheEntryPtr &t)
Loads the associated resource bundle if not already done.
ground_model_t * getGroundModelByString(const Ogre::String name)
ground_model_t * defaultgm
Definition Collisions.h:174
bool isInside(Ogre::Vector3 pos, const Ogre::String &inst, const Ogre::String &box, float border=0)
void putNetMessage(int user_id, MessageType type, const char *text)
Definition Console.cpp:108
@ CONSOLE_MSGTYPE_ACTOR
Parsing/spawn/simulation messages for actors.
Definition Console.h:63
@ CONSOLE_MSGTYPE_INFO
Generic message.
Definition Console.h:60
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
SimGearboxMode getAutoMode()
Definition Engine.cpp:842
void startEngine()
Quick engine start. Plays sounds.
Definition Engine.cpp:995
float getTorque()
Definition Engine.cpp:913
void offStart()
Quick start of vehicle engine.
Definition Engine.cpp:1013
int getAutoShift()
Definition Engine.cpp:1181
int getGear()
Definition Engine.cpp:1038
void setAcc(float val)
Definition Engine.cpp:852
float getAcc()
Definition Engine.cpp:880
bool hasContact()
Ignition.
Definition Engine.h:102
const TerrainPtr & GetTerrain()
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
ActorManager * GetActorManager()
void UpdateWheelVisuals()
void UpdateRods()
void FinishFlexbodyTasks()
void UpdateSimDataBuffer()
Copies sim. data from Actor to GfxActor for later update.
void UpdateCabMesh()
void UpdateProps(float dt, bool is_player_actor)
void SetDebugView(DebugViewType dv)
void FinishWheelUpdates()
void UpdateWingMeshes()
void UpdateFlexbodies()
void RegisterGfxActor(RoR::GfxActor *gfx_actor)
Definition GfxScene.cpp:290
bool GetUserPeerOpts(int uid, BitMask_t &result)
Definition Network.cpp:739
void AddPacket(int streamid, int type, int len, const char *content)
Definition Network.cpp:616
void replayStepActor()
Definition Replay.cpp:215
ScriptUnitID_t loadScript(Ogre::String filename, ScriptCategory category=ScriptCategory::TERRAIN, ActorPtr associatedActor=nullptr, std::string buffer="")
Loads a script.
ScriptUnitMap const & getScriptUnits() const
void unloadScript(ScriptUnitID_t unique_id)
Unloads a script.
Wrapper for classic c-string (local buffer) Refresher: strlen() excludes '\0' terminator; strncat() A...
Definition Str.h:36
const char * ToCStr() const
Definition Str.h:46
Collisions * GetCollisions()
Definition Terrain.h:86
Facilitates execution of (small) tasks on separate threads.
Definition ThreadPool.h:105
void Parallelize(const std::vector< std::function< void()> > &task_funcs)
Run collection of tasks in parallel and wait until all have finished.
Definition ThreadPool.h:193
bool IsEnabled() const
bool ModifyTyrePressure(float v)
bool isActive()
Returns the status of the AI.
Definition VehicleAI.cpp:58
@ TRUCK
its a truck (or other land vehicle)
Definition SimData.h:85
@ AI
machine controlled by an Artificial Intelligence
Definition SimData.h:89
DebugViewType
Definition GfxData.h:102
@ EV_COMMON_REPLAY_FORWARD
@ EV_COMMON_ACCELERATE_SIMULATION
accelerate the simulation speed
@ EV_COMMON_DECELERATE_SIMULATION
decelerate the simulation speed
@ EV_COMMON_TOGGLE_PHYSICS
toggle physics on/off
@ EV_COMMON_RESET_SIMULATION_PACE
reset the simulation speed
@ EV_COMMON_REPLAY_FAST_FORWARD
@ MSG_SIM_ACTOR_LINKING_REQUESTED
Payload = RoR::ActorLinkingRequest* (owner)
@ MSG_SIM_SPAWN_ACTOR_REQUESTED
Payload = RoR::ActorSpawnRequest* (owner)
@ MSG_SIM_DELETE_ACTOR_REQUESTED
Payload = RoR::ActorPtr* (owner)
@ MSG_SIM_MODIFY_ACTOR_REQUESTED
Payload = RoR::ActorModifyRequest* (owner)
FreeForceType
Definition SimData.h:744
static const float MIN_BEAM_LENGTH
minimum beam lenght is 10 centimeters
@ TOWARDS_COORDS
Constant force directed towards ffc_target_coords
@ HALFBEAM_ROPE
Like TOWARDS_NODE, but parametrized like a rope-beam in truck fileformat.
@ CONSTANT
Constant force given by direction and magnitude.
@ HALFBEAM_GENERIC
Like TOWARDS_NODE, but parametrized like a beam in truck fileformat.
@ TOWARDS_NODE
Constant force directed towards ffc_target_node
@ LOCAL_SIMULATED
simulated (local) actor
@ LOCAL_SLEEPING
sleeping (local) actor
@ NETWORKED_OK
not simulated (remote) actor
@ DISPOSED
removed from simulation, still in memory to satisfy pointers.
@ NETWORKED_HIDDEN
not simulated, not updated (remote)
void TRIGGER_EVENT_ASYNC(scriptEvents type, int arg1, int arg2ex=0, int arg3ex=0, int arg4ex=0, std::string arg5ex="", std::string arg6ex="", std::string arg7ex="", std::string arg8ex="")
Asynchronously (via MSG_SIM_SCRIPT_EVENT_TRIGGERED) invoke script function eventCallbackEx(),...
@ ACTOR
Defined in truck file under 'scripts', contains global variable BeamClass@ thisActor.
@ AUTO
Automatic shift.
std::shared_ptr< Document > DocumentPtr
InputEngine * GetInputEngine()
CVar * sim_spawn_running
CVar * diag_actor_dump
ThreadPool * GetThreadPool()
CVar * sim_replay_length
CVar * mp_cyclethru_net_actors
Include remote actors when cycling through with CTRL + [ and CTRL + ].
GameContext * GetGameContext()
GfxScene * GetGfxScene()
CVar * mp_state
CVar * sim_realistic_commands
Console * GetConsole()
CVar * mp_pseudo_collisions
ScriptEngine * GetScriptEngine()
CacheSystem * GetCacheSystem()
CVar * sim_replay_enabled
Network * GetNetwork()
CVar * gfx_skidmarks_mode
CVar * app_async_physics
static const NodeNum_t NODENUM_INVALID
@ LT_AllBeam
@ MODCACHEACTIVITY_ENTRY_ADDED
Args: #1 type, #2 entry number, –, –, #5 fname, #6 fext.
int ActorInstanceID_t
Unique sequentially generated ID of an actor in session. Use ActorManager::GetActorById()
int FreeForceID_t
Unique sequentially generated ID of FreeForce; use ActorManager::GetFreeForceNextId().
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
int ScriptUnitID_t
Unique sequentially generated ID of a loaded and running scriptin session. Use ScriptEngine::getScrip...
static const ActorInstanceID_t ACTORINSTANCEID_INVALID
@ FREEFORCESACTIVITY_ADDED
@ FREEFORCESACTIVITY_MODIFIED
@ FREEFORCESACTIVITY_BROKEN
Only with HALFBEAM_* types; arg #5 (string containing float) the applied force, arg #6 (string contai...
@ FREEFORCESACTIVITY_DEFORMED
Only with HALFBEAM_* types; arg #5 (string containing float) the actual stress, arg #6 (string contai...
@ FREEFORCESACTIVITY_REMOVED
RefCountingObjectPtr< Actor > ActorPtr
@ SE_GENERIC_FREEFORCES_ACTIVITY
Triggered on freeforce add/update/delete or breaking; args: #1 freeForcesActivityType,...
@ SE_GENERIC_NEW_TRUCK
triggered when the user spawns a new actor, the argument refers to the actor ID
@ SE_GENERIC_MODCACHE_ACTIVITY
Triggered when status of modcache changes, args: #1 type, #2 entry number, for other args see RoR::mo...
std::string SanitizeUtf8CString(const char *start, const char *end=nullptr)
Definition Utils.cpp:128
void EraseIf(std::vector< T, A > &c, Predicate pred)
Definition Utils.h:75
static const NodeNum_t NODENUM_MAX
std::string Sha1Hash(std::string const &data)
Definition Utils.cpp:141
void SplitBundleQualifiedFilename(const std::string &bundleQualifiedFilename, std::string &out_bundleName, std::string &out_filename)
Definition Utils.cpp:239
std::string tryConvertUTF(const char *buffer)
Definition Utils.cpp:61
uint16_t NodeNum_t
Node position within Actor::ar_nodes; use RoR::NODENUM_INVALID as empty value.
Ogre::Real Round(Ogre::Real value, unsigned short ndigits=0)
Definition Utils.cpp:101
@ LIGHTMASK_REVERSE
reverse light on
Definition RoRnet.h:121
@ LIGHTMASK_BRAKES
brake lights on
Definition RoRnet.h:120
@ MSG2_STREAM_REGISTER_RESULT
result of a stream creation
Definition RoRnet.h:64
@ MSG2_USER_LEAVE
user leaves
Definition RoRnet.h:58
@ MSG2_STREAM_UNREGISTER
remove stream
Definition RoRnet.h:65
@ MSG2_STREAM_DATA
stream data
Definition RoRnet.h:66
@ MSG2_STREAM_REGISTER
create new stream
Definition RoRnet.h:63
UiStreamsHealth
Definition RoRnet.h:138
@ ALL_OK
Stream is OK - no errors loading the mods.
@ MISMATCHES
Loading errors - some mods could not be loaded (probably not installed)
@ IDLE
Player has no active streams.
Estabilishing a physics linkage between 2 actors modifies a global linkage table and triggers immedia...
Definition SimData.h:909
ActorLinkingRequestType alr_type
Definition SimData.h:911
ActorInstanceID_t alr_actor_instance_id
Definition SimData.h:910
ActorInstanceID_t amr_actor
Definition SimData.h:875
std::string asr_net_username
Definition SimData.h:845
Ogre::String asr_config
Definition SimData.h:836
CacheEntryPtr asr_cache_entry
Optional, overrides 'asr_filename' and 'asr_cache_entry_num'.
Definition SimData.h:834
Ogre::Vector3 asr_position
Definition SimData.h:837
CacheEntryPtr asr_skin_entry
Definition SimData.h:840
ActorInstanceID_t asr_instance_id
Optional; see ActorManager::GetActorNextInstanceID();.
Definition SimData.h:833
std::string asr_filename
Can be in "Bundle-qualified" format, i.e. "mybundle.zip:myactor.truck".
Definition SimData.h:835
Ogre::Quaternion asr_rotation
Definition SimData.h:838
@ CONFIG_FILE
'Preselected vehicle' in RoR.cfg or command line
@ NETWORK
Remote controlled.
@ TERRN_DEF
Preloaded with terrain.
BitMask_t asr_net_peeropts
RoRnet::PeerOptions to be applied after spawn.
Definition SimData.h:847
collision_box_t * asr_spawnbox
Definition SimData.h:839
bool asr_free_position
Disables the automatic spawn position adjustment.
Definition SimData.h:850
Global force affecting particular (base) node of particular (base) actor; added ad-hoc by scripts.
Definition SimData.h:755
float ffc_halfb_minmaxposnegstress
Definition SimData.h:777
float ffc_halfb_deform
Definition SimData.h:770
Ogre::Vector3 ffc_force_const_direction
Expected to be normalized; only effective with FreeForceType::CONSTANT
Definition SimData.h:763
float ffc_halfb_diameter
Definition SimData.h:772
Ogre::Vector3 ffc_target_coords
Definition SimData.h:764
ActorPtr ffc_base_actor
Definition SimData.h:760
float ffc_force_magnitude
Definition SimData.h:759
float ffc_halfb_L
Length at rest, including permanent deformations.
Definition SimData.h:775
ActorPtr ffc_target_actor
Definition SimData.h:765
float ffc_halfb_maxposstress
Definition SimData.h:778
FreeForceType ffc_type
Definition SimData.h:758
FreeForceID_t ffc_id
Definition SimData.h:757
NodeNum_t ffc_base_node
Definition SimData.h:761
float ffc_halfb_damp
Definition SimData.h:769
float ffc_halfb_maxnegstress
Definition SimData.h:779
float ffc_halfb_strength
Breaking threshold.
Definition SimData.h:771
float ffc_halfb_plastic_coef
Definition SimData.h:773
NodeNum_t ffc_target_node
Definition SimData.h:766
float ffc_halfb_spring
Definition SimData.h:768
Common for ADD and MODIFY requests; tailored for use with AngelScript thru GameScript::pushMessage().
Definition SimData.h:784
double ffr_force_magnitude
Definition SimData.h:790
double ffr_halfb_strength
Definition SimData.h:802
int64_t ffr_target_actor
Definition SimData.h:796
Ogre::Vector3 ffr_target_coords
Definition SimData.h:795
double ffr_halfb_plastic_coef
Definition SimData.h:804
int64_t ffr_target_node
Definition SimData.h:797
double ffr_halfb_diameter
Definition SimData.h:803
Ogre::Vector3 ffr_force_const_direction
Definition SimData.h:794
Unified game event system - all requests and state changes are reported using a message.
Definition GameContext.h:52
Args for eventCallbackEx() queued via MSG_SIM_SCRIPT_EVENT_TRIGGERED See descriptions at enum RoR::sc...
float k
tensile spring
Definition SimData.h:311
float minmaxposnegstress
Definition SimData.h:314
float default_beam_deform
for reset
Definition SimData.h:335
float initial_beam_strength
for reset
Definition SimData.h:334
float strength
Definition SimData.h:317
float d
damping factor
Definition SimData.h:312
Ogre::Vector3 hi
absolute collision box
Definition SimData.h:687
Ogre::Vector3 relo
relative collision box
Definition SimData.h:694
Ogre::Vector3 center
center of rotation
Definition SimData.h:688
Ogre::Vector3 lo
absolute collision box
Definition SimData.h:686
Physics: A vertex in the softbody structure.
Definition SimData.h:260
Ogre::Vector3 AbsPosition
absolute position in the world (shaky)
Definition SimData.h:267
Ogre::Real mass
Definition SimData.h:271
Ogre::Vector3 Velocity
Definition SimData.h:268
bool nd_rim_node
Attr; This node is part of a rim (only wheel types with separate rim nodes)
Definition SimData.h:283
Ogre::Vector3 Forces
Definition SimData.h:269
Ogre::Vector3 RelPosition
relative to the local physics origin (one origin per actor) (shaky)
Definition SimData.h:266
bool nd_tyre_node
Attr; This node is part of a tyre (note some wheel types don't use rim nodes at all)
Definition SimData.h:284
< Must preserve mem. layout of RoRnet::StreamRegister
Definition RoRnet.h:170
char sectionconfig[60]
section configuration
Definition RoRnet.h:181
char name[128]
truck file name
Definition RoRnet.h:176
int32_t origin_sourceid
origin sourceid
Definition RoRnet.h:174
int32_t origin_streamid
origin streamid
Definition RoRnet.h:175
int32_t time
initial time stamp
Definition RoRnet.h:179
< Sent from the client to server and vice versa, to broadcast a new stream
Definition RoRnet.h:160
int32_t type
0 = Actor, 1 = Character, 3 = ChatSystem
Definition RoRnet.h:161
int32_t origin_streamid
origin streamid
Definition RoRnet.h:164
int32_t origin_sourceid
origin sourceid
Definition RoRnet.h:163
char name[128]
file name
Definition RoRnet.h:165
int32_t status
initial stream status
Definition RoRnet.h:162
char username[RORNET_MAX_USERNAME_LEN]
the nickname of the user (UTF-8)
Definition RoRnet.h:196
int32_t colournum
colour set by server
Definition RoRnet.h:194