Rigs of Rods 2026.01
Soft-body Physics Simulation
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 "ServerScriptEngine.h"
55#include "SoundScriptManager.h"
56#include "Terrain.h"
57#include "ThreadPool.h"
58#include "TuneupFileFormat.h"
59#include "Utils.h"
60#include "VehicleAI.h"
61
62#include <fmt/format.h>
63
64using namespace Ogre;
65using namespace RoR;
66
67const ActorPtr ActorManager::ACTORPTR_NULL; // Dummy value to be returned as const reference.
68
70 : m_dt_remainder(0.0f)
71 , m_forced_awake(false)
72 , m_physics_steps(2000)
73 , m_simulation_speed(1.0f)
74{
75 // Create worker thread (used for physics calculations)
76 m_sim_thread_pool = std::unique_ptr<ThreadPool>(new ThreadPool(1));
77}
78
80{
81 this->SyncWithSimThread(); // Wait for sim task to finish
82}
83
85{
87 {
89 }
90 ActorPtr actor = new Actor(rq.asr_instance_id, static_cast<int>(m_actors.size()), def, rq);
91
93 {
94 actor->sendStreamSetup();
95 }
96
97 LOG(" == Spawning vehicle: " + def->name);
98
99 ActorSpawner spawner;
100 spawner.ConfigureSections(actor->m_section_config, def);
101 spawner.ConfigureAddonParts(actor);
102 spawner.ConfigureAssetPacks(actor);
103 spawner.ProcessNewActor(actor, rq, def);
104
105 if (App::diag_actor_dump->getBool())
106 {
107 actor->WriteDiagnosticDump(actor->ar_filename + "_dump_raw.txt"); // Saves file to 'logs'
108 }
109
110 /* POST-PROCESSING */
111
112 actor->ar_initial_node_positions.resize(actor->ar_num_nodes);
113 actor->ar_initial_beam_defaults.resize(actor->ar_num_beams);
114 actor->ar_initial_node_masses.resize(actor->ar_num_nodes);
115
116 actor->UpdateBoundingBoxes(); // (records the unrotated dimensions for 'veh_aab_size')
117
118 // Apply spawn position & spawn rotation
119 for (int i = 0; i < actor->ar_num_nodes; i++)
120 {
121 actor->ar_nodes[i].AbsPosition = rq.asr_position + rq.asr_rotation * (actor->ar_nodes[i].AbsPosition - rq.asr_position);
122 actor->ar_nodes[i].RelPosition = actor->ar_nodes[i].AbsPosition - actor->ar_origin;
123 };
124
125 /* Place correctly */
126 if (spawner.GetMemoryRequirements().num_fixes == 0)
127 {
128 Ogre::Vector3 vehicle_position = rq.asr_position;
129
130 // check if over-sized
131 actor->UpdateBoundingBoxes();
132 vehicle_position.x += vehicle_position.x - actor->ar_bounding_box.getCenter().x;
133 vehicle_position.z += vehicle_position.z - actor->ar_bounding_box.getCenter().z;
134
135 float miny = 0.0f;
136
137 if (!actor->m_preloaded_with_terrain)
138 {
139 miny = vehicle_position.y;
140 }
141
142 if (rq.asr_spawnbox != nullptr)
143 {
144 miny = rq.asr_spawnbox->relo.y + rq.asr_spawnbox->center.y;
145 }
146
147 if (rq.asr_free_position)
148 actor->resetPosition(vehicle_position, true);
149 else
150 actor->resetPosition(vehicle_position.x, vehicle_position.z, true, miny);
151
152 if (rq.asr_spawnbox != nullptr)
153 {
154 bool inside = true;
155
156 for (int i = 0; i < actor->ar_num_nodes; i++)
157 inside = (inside && App::GetGameContext()->GetTerrain()->GetCollisions()->isInside(actor->ar_nodes[i].AbsPosition, rq.asr_spawnbox, 0.2f));
158
159 if (!inside)
160 {
161 Vector3 gpos = Vector3(vehicle_position.x, 0.0f, vehicle_position.z);
162
163 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);
164
165 actor->resetPosition(gpos.x, gpos.z, true, miny);
166 }
167 }
168 }
169 else
170 {
171 actor->resetPosition(rq.asr_position, true);
172 }
173 actor->UpdateBoundingBoxes();
174
175 //compute final mass
176 actor->recalculateNodeMasses();
177 actor->ar_initial_total_mass = actor->ar_total_mass;
178 actor->ar_original_dry_mass = actor->ar_dry_mass;
179 actor->ar_original_load_mass = actor->ar_load_mass;
180 actor->ar_orig_minimass = actor->ar_minimass;
181 for (int i = 0; i < actor->ar_num_nodes; i++)
182 {
183 actor->ar_initial_node_masses[i] = actor->ar_nodes[i].mass;
184 }
185
186 //setup default sounds
187 if (!actor->m_disable_default_sounds)
188 {
190 }
191
192 //compute node connectivity graph
194
195 actor->UpdateBoundingBoxes();
197
198 // calculate minimum camera radius
200 for (int i = 0; i < actor->ar_num_nodes; i++)
201 {
202 Real dist = actor->ar_nodes[i].AbsPosition.squaredDistance(actor->m_avg_node_position);
203 if (dist > actor->m_min_camera_radius)
204 {
205 actor->m_min_camera_radius = dist;
206 }
207 }
208 actor->m_min_camera_radius = std::sqrt(actor->m_min_camera_radius) * 1.2f; // twenty percent buffer
209
210 // fix up submesh collision model
211 std::string subMeshGroundModelName = spawner.GetSubmeshGroundmodelName();
212 if (!subMeshGroundModelName.empty())
213 {
215 if (!actor->ar_submesh_ground_model)
216 {
218 }
219 }
220
221 // Set beam defaults
222 for (int i = 0; i < actor->ar_num_beams; i++)
223 {
224 actor->ar_beams[i].initial_beam_strength = actor->ar_beams[i].strength;
226 actor->ar_initial_beam_defaults[i] = std::make_pair(actor->ar_beams[i].k, actor->ar_beams[i].d);
227 }
228
229 actor->m_spawn_rotation = actor->getRotation();
230
232
233 actor->NotifyActorCameraChanged(); // setup sounds properly
234
235 // calculate the number of wheel nodes
236 actor->m_wheel_node_count = 0;
237 for (int i = 0; i < actor->ar_num_nodes; i++)
238 {
239 if (actor->ar_nodes[i].nd_tyre_node)
240 actor->m_wheel_node_count++;
241 }
242
243 // search m_net_first_wheel_node
244 actor->m_net_first_wheel_node = actor->ar_num_nodes;
245 for (int i = 0; i < actor->ar_num_nodes; i++)
246 {
247 if (actor->ar_nodes[i].nd_tyre_node || actor->ar_nodes[i].nd_rim_node)
248 {
249 actor->m_net_first_wheel_node = i;
250 break;
251 }
252 }
253
254 // Initialize visuals
255 actor->updateVisual();
257
258 // perform full visual update only if the vehicle won't be immediately driven by player.
259 if (actor->isPreloadedWithTerrain() || // .tobj file - Spawned sleeping somewhere on terrain
260 rq.asr_origin == ActorSpawnRequest::Origin::CONFIG_FILE || // RoR.cfg or commandline - not entered by default
261 actor->ar_num_cinecams == 0) // Not intended for player-controlling
262 {
263 actor->GetGfxActor()->UpdateSimDataBuffer(); // Initial fill of sim data buffers
264
265 actor->GetGfxActor()->UpdateFlexbodies(); // Push tasks to threadpool
266 actor->GetGfxActor()->UpdateWheelVisuals(); // Push tasks to threadpool
267 actor->GetGfxActor()->UpdateCabMesh();
268 actor->GetGfxActor()->UpdateWingMeshes();
269 actor->GetGfxActor()->UpdateProps(0.f, false);
270 actor->GetGfxActor()->UpdateRods(); // beam visuals
271 actor->GetGfxActor()->FinishWheelUpdates(); // Sync tasks from threadpool
272 actor->GetGfxActor()->FinishFlexbodyTasks(); // Sync tasks from threadpool
273 }
274
276
277 if (actor->ar_engine)
278 {
280 actor->ar_engine->startEngine();
281 else
282 actor->ar_engine->offStart();
283 }
284 // pressurize tires
285 if (actor->getTyrePressure().IsEnabled())
286 {
287 actor->getTyrePressure().ModifyTyrePressure(0.f); // Initialize springiness of pressure-beams.
288 }
289
291
292 if (App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
293 {
294 // network buffer layout (without RoRnet::VehicleState):
295 // -----------------------------------------------------
296
297 // - 3 floats (x,y,z) for the reference node 0
298 // - ar_num_nodes - 1 times 3 short ints (compressed position info)
299 actor->m_net_node_buf_size = sizeof(float) * 3 + (actor->m_net_first_wheel_node - 1) * sizeof(short int) * 3;
301 // - ar_num_wheels times a float for the wheel rotation
302 actor->m_net_wheel_buf_size = actor->ar_num_wheels * sizeof(float);
304 // - bit array (made of ints) for the prop animation key states
306 (actor->m_prop_anim_key_states.size() / 8) + // whole chars
307 (size_t)(actor->m_prop_anim_key_states.size() % 8 != 0); // remainder: 0 or 1 chars
309
311 {
313 if (actor->ar_engine)
314 {
315 actor->ar_engine->startEngine();
316 }
317 }
318
320 actor->m_net_color_num = rq.asr_net_color;
321 }
322 else if (App::sim_replay_enabled->getBool())
323 {
324 actor->m_replay_handler = new Replay(actor, App::sim_replay_length->getInt());
325 }
326
327 //cache buoyancy nodes (must be done when position is final)
328 if (actor->m_buoyance)
329 {
330 for (int i = 0; i < actor->ar_num_buoycabs; i++)
331 {
332 int tmpv = actor->ar_buoycabs[i] * 3;
333 actor->ar_cabs_buoy_cache_ids[tmpv] = actor->m_buoyance->cacheBuoycabNode(&actor->ar_nodes[actor->ar_cabs[tmpv]]);
334 actor->ar_cabs_buoy_cache_ids[tmpv+1] = actor->m_buoyance->cacheBuoycabNode(&actor->ar_nodes[actor->ar_cabs[tmpv + 1]]);
335 actor->ar_cabs_buoy_cache_ids[tmpv+2] = actor->m_buoyance->cacheBuoycabNode(&actor->ar_nodes[actor->ar_cabs[tmpv + 2]]);
336 }
337 actor->m_buoyance->buoy_projected_nodes = actor->m_buoyance->buoy_cached_nodes;
338 }
339
340 LOG(" ===== DONE LOADING VEHICLE");
341
342 if (App::diag_actor_dump->getBool())
343 {
344 actor->WriteDiagnosticDump(actor->ar_filename + "_dump_recalc.txt"); // Saves file to 'logs'
345 }
346
347 m_actors.push_back(ActorPtr(actor));
348
349 return actor;
350}
351
353{
354 m_stream_mismatches.erase(sourceid);
356 [sourceid](const RoRnet::ActorStreamRegister& reg)
357 {
358 return reg.origin_sourceid == sourceid;
359 });
360
361 for (ActorPtr& actor : m_actors)
362 {
363 if (actor->ar_state != ActorState::NETWORKED_OK)
364 continue;
365
366 if (actor->ar_net_source_id == sourceid)
367 {
369 }
370 }
371}
372
373void ActorManager::RemoveStream(int sourceid, int streamid)
374{
375 // Delete associated actor
376 ActorPtr b = this->GetActorByNetworkLinks(sourceid, streamid);
377 if (b)
378 {
380 {
382 }
383 }
384
385 // Erase stream mismatch records
386 m_stream_mismatches[sourceid].erase(streamid);
388 [sourceid, streamid](const RoRnet::ActorStreamRegister& reg)
389 {
390 return reg.origin_sourceid == sourceid &&
391 reg.origin_streamid == streamid;
392 });
393}
394
396{
399
400 std::string filename = args->arg5ex;
402 ROR_ASSERT(entry);
403
404 for (auto it = m_stream_mismatched_regs.begin(); it != m_stream_mismatched_regs.end(); )
405 {
407 std::string reg_filename_maybe_bundlequalified = SanitizeUtf8CString(reg.name);
408 std::string reg_filename;
409 std::string reg_bundlename;
410 SplitBundleQualifiedFilename(reg_filename_maybe_bundlequalified, /*out:*/ reg_bundlename, /*out:*/ reg_filename);
411 if (reg_filename == filename)
412 {
413 RoR::LogFormat("[RoR] Retrying STREAM_REGISTER for user id %d, stream id %d, filename '%s'",
414 reg.origin_sourceid, reg.origin_streamid, reg_filename_maybe_bundlequalified.c_str());
416 it = m_stream_mismatched_regs.erase(it);
417
418 // Gather info needed to spawn
419 RoRnet::UserInfo info;
420 BitMask_t peeropts = BitMask_t(0);
421 if (!App::GetNetwork()->GetUserInfo(reg.origin_sourceid, info)
422 || !App::GetNetwork()->GetUserPeerOpts(reg.origin_sourceid, peeropts))
423 {
424 RoR::LogFormat("[RoR] Error retrying STREAM_REGISTER, user id %d does not exist", reg.origin_sourceid);
425 }
426 else
427 {
428 this->RequestSpawnRemoteActor(&reg, entry, info, peeropts);
429 }
430 }
431 else
432 {
433 ++it;
434 }
435 }
436}
437
438#ifdef USE_SOCKETW
439void ActorManager::HandleActorStreamData(std::vector<RoR::NetRecvPacket> packet_buffer)
440{
441 // Sort by stream source
442 std::stable_sort(packet_buffer.begin(), packet_buffer.end(),
443 [](const RoR::NetRecvPacket& a, const RoR::NetRecvPacket& b)
444 { return a.header.source > b.header.source; });
445 // Compress data stream by eliminating all but the last update from every consecutive group of stream data updates
446 auto it = std::unique(packet_buffer.rbegin(), packet_buffer.rend(),
447 [](const RoR::NetRecvPacket& a, const RoR::NetRecvPacket& b)
448 { return !memcmp(&a.header, &b.header, sizeof(RoRnet::Header)) &&
449 a.header.command == RoRnet::MSG2_STREAM_DATA; });
450 packet_buffer.erase(packet_buffer.begin(), it.base());
451 for (auto& packet : packet_buffer)
452 {
453 if (packet.header.command == RoRnet::MSG2_STREAM_REGISTER)
454 {
455 RoRnet::StreamRegister* reg = (RoRnet::StreamRegister *)packet.buffer;
456 if (reg->type == 0)
457 {
458 reg->name[127] = 0;
459 // NOTE: The filename is by default in "Bundle-qualified" format, i.e. "mybundle.zip:myactor.truck"
460 std::string filename_maybe_bundlequalified = SanitizeUtf8CString(reg->name);
461 std::string filename;
462 std::string bundlename;
463 SplitBundleQualifiedFilename(filename_maybe_bundlequalified, /*out:*/ bundlename, /*out:*/ filename);
464
465 RoRnet::UserInfo info;
466 BitMask_t peeropts = BitMask_t(0);
467 if (!App::GetNetwork()->GetUserInfo(reg->origin_sourceid, info)
468 || !App::GetNetwork()->GetUserPeerOpts(reg->origin_sourceid, peeropts))
469 {
470 RoR::LogFormat("[RoR] Invalid STREAM_REGISTER, user id %d does not exist", reg->origin_sourceid);
471 reg->status = -1;
472 }
473 else if (filename.empty())
474 {
475 RoR::LogFormat("[RoR] Invalid STREAM_REGISTER (user '%s', ID %d), filename is empty string", info.username, reg->origin_sourceid);
476 reg->status = -1;
477 }
478 else
479 {
480 auto actor_reg = reinterpret_cast<RoRnet::ActorStreamRegister*>(reg);
481 Str<200> text;
482 text << _L("spawned a new vehicle: ") << filename;
485
486 LOG("[RoR] Creating remote actor for " + TOSTRING(reg->origin_sourceid) + ":" + TOSTRING(reg->origin_streamid));
487
488 // Based on negative user feedback we don't check the bundle in multiplayer.
489 CacheEntryPtr actor_entry = App::GetCacheSystem()->FindEntryByFilename(LT_AllBeam, /*partial:*/false, filename);
490
491 if (!actor_entry)
492 {
495 _L("Mod not installed: ") + filename);
496 RoR::LogFormat("[RoR] Cannot create remote actor (not installed), filename: '%s'", filename_maybe_bundlequalified.c_str());
497 this->AddStreamMismatch(actor_reg);
498 reg->status = -1;
499 }
500 else
501 {
502 RoR::LogFormat("[RoR] Creating remote actor (user id %d, stream id %d) with filename '%s'",
503 reg->origin_sourceid, reg->origin_streamid, filename_maybe_bundlequalified.c_str());
504 this->RequestSpawnRemoteActor(actor_reg, actor_entry, info, peeropts);
505 reg->status = 1; // success
506 }
507 }
508
510 }
511 }
512 else if (packet.header.command == RoRnet::MSG2_STREAM_REGISTER_RESULT)
513 {
514 RoRnet::StreamRegister* reg = (RoRnet::StreamRegister *)packet.buffer;
515 for (ActorPtr& actor: m_actors)
516 {
517 if (actor->ar_net_source_id == reg->origin_sourceid && actor->ar_net_stream_id == reg->origin_streamid)
518 {
519 int sourceid = packet.header.source;
520 actor->ar_net_stream_results[sourceid] = reg->status;
521
522 String message = "";
523 switch (reg->status)
524 {
525 case 1: message = "successfully loaded stream"; break;
526 case -2: message = "detected mismatch stream"; break;
527 default: message = "could not load stream"; break;
528 }
529 LOG("Client " + TOSTRING(sourceid) + " " + message + " " + TOSTRING(reg->origin_streamid) +
530 " with name '" + reg->name + "', result code: " + TOSTRING(reg->status));
531 break;
532 }
533 }
534 }
535 else if (packet.header.command == RoRnet::MSG2_STREAM_UNREGISTER)
536 {
537 this->RemoveStream(packet.header.source, packet.header.streamid);
538 }
539 else if (packet.header.command == RoRnet::MSG2_USER_LEAVE)
540 {
541 this->RemoveStreamSource(packet.header.source);
542 }
543 else if (packet.header.command == RoRnet::MSG2_STREAM_DATA)
544 {
545 for (ActorPtr& actor: m_actors)
546 {
547 if (actor->ar_state != ActorState::NETWORKED_OK)
548 continue;
549 if (packet.header.source == actor->ar_net_source_id && packet.header.streamid == actor->ar_net_stream_id)
550 {
551 actor->pushNetwork(packet.buffer, packet.header.size);
552 break;
553 }
554 }
555 }
556 }
557}
558#endif // USE_SOCKETW
559
561{
562 if (m_stream_time_offsets.find(actor_reg->origin_sourceid) == m_stream_time_offsets.end())
563 {
564 int offset = actor_reg->time - m_net_timer.getMilliseconds();
565 m_stream_time_offsets[actor_reg->origin_sourceid] = offset - 100;
566 }
569 rq->asr_cache_entry = actor_entry;
570 if (strnlen(actor_reg->skin, 60) < 60 && actor_reg->skin[0] != '\0')
571 {
572 rq->asr_skin_entry = App::GetCacheSystem()->FetchSkinByName(actor_reg->skin); // FIXME: fetch skin by name+guid! ~ 03/2019
573 }
574 if (strnlen(actor_reg->sectionconfig, 60) < 60)
575 {
576 rq->asr_config = actor_reg->sectionconfig;
577 }
579 rq->asr_net_color = userinfo.colournum;
580 rq->asr_net_peeropts = peeropts;
581 rq->net_source_id = actor_reg->origin_sourceid;
582 rq->net_stream_id = actor_reg->origin_streamid;
583
586}
587
593
595{
596 auto search = m_stream_time_offsets.find(sourceid);
597 if (search != m_stream_time_offsets.end())
598 {
599 return search->second;
600 }
601 return 0;
602}
603
604void ActorManager::UpdateNetTimeOffset(int sourceid, int offset)
605{
606 if (m_stream_time_offsets.find(sourceid) != m_stream_time_offsets.end())
607 {
608 m_stream_time_offsets[sourceid] += offset;
609 }
610}
611
613{
614 // Special case - local serverscript
615 if (App::mp_state->getEnum<MpState>() == MpState::LOCAL_SCRIPT)
616 {
617 // Mismatches can't happen, just check if any actor is spawned
618 for (ActorPtr& actor: m_actors)
619 {
620 if (actor->ar_driveable == ActorType::AI && actor->ar_net_source_id == sourceid)
621 {
623 }
624 }
625 }
626
627 if (!m_stream_mismatches[sourceid].empty())
629
630 for (ActorPtr& actor: m_actors)
631 {
632 if (actor->ar_state != ActorState::NETWORKED_OK)
633 continue;
634
635 if (actor->ar_net_source_id == sourceid)
636 {
638 }
639 }
640
642}
643
645{
647
648 for (ActorPtr& actor: m_actors)
649 {
650 if (actor->ar_state == ActorState::NETWORKED_OK)
651 continue;
652
653 int stream_result = actor->ar_net_stream_results[sourceid];
654 if (stream_result == -1 || stream_result == -2)
656 if (stream_result == 1)
658 }
659
660 return result;
661}
662
663const ActorPtr& ActorManager::GetActorByNetworkLinks(int source_id, int stream_id)
664{
665 for (ActorPtr& actor: m_actors)
666 {
667 if (actor->ar_net_source_id == source_id && actor->ar_net_stream_id == stream_id)
668 {
669 return actor;
670 }
671 }
672
673 return ACTORPTR_NULL;
674}
675
677{
678 if (m_actors[a]->ar_collision_bounding_boxes.empty() && m_actors[b]->ar_collision_bounding_boxes.empty())
679 {
680 return m_actors[a]->ar_bounding_box.intersects(m_actors[b]->ar_bounding_box);
681 }
682 else if (m_actors[a]->ar_collision_bounding_boxes.empty())
683 {
684 for (const auto& bbox_b : m_actors[b]->ar_collision_bounding_boxes)
685 if (bbox_b.intersects(m_actors[a]->ar_bounding_box))
686 return true;
687 }
688 else if (m_actors[b]->ar_collision_bounding_boxes.empty())
689 {
690 for (const auto& bbox_a : m_actors[a]->ar_collision_bounding_boxes)
691 if (bbox_a.intersects(m_actors[b]->ar_bounding_box))
692 return true;
693 }
694 else
695 {
696 for (const auto& bbox_a : m_actors[a]->ar_collision_bounding_boxes)
697 for (const auto& bbox_b : m_actors[b]->ar_collision_bounding_boxes)
698 if (bbox_a.intersects(bbox_b))
699 return true;
700 }
701
702 return false;
703}
704
706{
707 if (m_actors[a]->ar_predicted_coll_bounding_boxes.empty() && m_actors[b]->ar_predicted_coll_bounding_boxes.empty())
708 {
709 return m_actors[a]->ar_predicted_bounding_box.intersects(m_actors[b]->ar_predicted_bounding_box);
710 }
711 else if (m_actors[a]->ar_predicted_coll_bounding_boxes.empty())
712 {
713 for (const auto& bbox_b : m_actors[b]->ar_predicted_coll_bounding_boxes)
714 if (bbox_b.intersects(m_actors[a]->ar_predicted_bounding_box))
715 return true;
716 }
717 else if (m_actors[b]->ar_predicted_coll_bounding_boxes.empty())
718 {
719 for (const auto& bbox_a : m_actors[a]->ar_predicted_coll_bounding_boxes)
720 if (bbox_a.intersects(m_actors[b]->ar_predicted_bounding_box))
721 return true;
722 }
723 else
724 {
725 for (const auto& bbox_a : m_actors[a]->ar_predicted_coll_bounding_boxes)
726 for (const auto& bbox_b : m_actors[b]->ar_predicted_coll_bounding_boxes)
727 if (bbox_a.intersects(bbox_b))
728 return true;
729 }
730
731 return false;
732}
733
734void ActorManager::RecursiveActivation(int j, std::vector<bool>& visited)
735{
736 if (visited[j] || m_actors[j]->ar_state != ActorState::LOCAL_SIMULATED)
737 return;
738
739 visited[j] = true;
740
741 for (unsigned int t = 0; t < m_actors.size(); t++)
742 {
743 if (t == j || visited[t])
744 continue;
746 {
747 m_actors[t]->ar_sleep_counter = 0.0f;
748 this->RecursiveActivation(t, visited);
749 }
751 {
752 m_actors[t]->ar_sleep_counter = 0.0f;
754 this->RecursiveActivation(t, visited);
755 }
756 }
757}
758
760{
761 if (source_actor->ar_forward_commands)
762 {
763 auto linked_actors = source_actor->ar_linked_actors;
764
765 for (ActorPtr& actor : this->GetActors())
766 {
767 if (actor != source_actor && actor->ar_import_commands &&
768 (actor->getPosition().distance(source_actor->getPosition()) <
769 actor->m_min_camera_radius + source_actor->m_min_camera_radius))
770 {
771 // activate the truck
772 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
773 {
774 actor->ar_sleep_counter = 0.0f;
775 actor->ar_state = ActorState::LOCAL_SIMULATED;
776 }
777
778 if (App::sim_realistic_commands->getBool())
779 {
780 if (std::find(linked_actors.begin(), linked_actors.end(), actor) == linked_actors.end())
781 continue;
782 }
783
784 // forward commands
785 for (int j = 1; j <= MAX_COMMANDS; j++) // BEWARE: commandkeys are indexed 1-MAX_COMMANDS!
786 {
787 actor->ar_command_key[j].playerInputValue = std::max(source_actor->ar_command_key[j].playerInputValue,
788 source_actor->ar_command_key[j].commandValue);
789 }
790 if (source_actor->ar_toggle_ties)
791 {
792 //actor->tieToggle();
795 rq->alr_actor_instance_id = actor->ar_instance_id;
796 rq->alr_tie_group = -1;
798
799 }
800 if (source_actor->ar_toggle_ropes)
801 {
802 //actor->ropeToggle(-1);
805 rq->alr_actor_instance_id = actor->ar_instance_id;
806 rq->alr_rope_group = -1;
808 }
809 }
810 }
811 // just send brake and lights to the connected trucks, and no one else :)
812 for (auto hook : source_actor->ar_hooks)
813 {
814 if (!hook.hk_locked_actor || hook.hk_locked_actor == source_actor)
815 continue;
816
817 // forward brakes
818 hook.hk_locked_actor->ar_brake = source_actor->ar_brake;
819 if (hook.hk_locked_actor->ar_parking_brake != source_actor->ar_trailer_parking_brake)
820 {
821 hook.hk_locked_actor->parkingbrakeToggle();
822 }
823
824 // forward lights
825 hook.hk_locked_actor->importLightStateMask(source_actor->getLightStateMask());
826 }
827 }
828}
829
831{
832 for (auto& entry: inter_actor_links)
833 {
834 auto& actor_pair = entry.second;
835 if ((actor_pair.first == a1 && actor_pair.second == a2) ||
836 (actor_pair.first == a2 && actor_pair.second == a1))
837 {
838 return true;
839 }
840 }
841 return false;
842}
843
844void ActorManager::UpdateSleepingState(ActorPtr player_actor, float dt)
845{
846 if (!m_forced_awake)
847 {
848 for (ActorPtr& actor: m_actors)
849 {
850 if (actor->ar_state != ActorState::LOCAL_SIMULATED)
851 continue;
852 if (actor->ar_driveable == AI)
853 continue;
854 if (actor->getVelocity().squaredLength() > 0.01f)
855 {
856 actor->ar_sleep_counter = 0.0f;
857 continue;
858 }
859
860 actor->ar_sleep_counter += dt;
861
862 if (actor->ar_sleep_counter >= 10.0f)
863 {
864 actor->ar_state = ActorState::LOCAL_SLEEPING;
865 }
866 }
867 }
868
869 if (player_actor && player_actor->ar_state == ActorState::LOCAL_SLEEPING)
870 {
872 }
873
874 std::vector<bool> visited(m_actors.size());
875 // Recursivly activate all actors which can be reached from current actor
876 if (player_actor && player_actor->ar_state == ActorState::LOCAL_SIMULATED)
877 {
878 player_actor->ar_sleep_counter = 0.0f;
879 this->RecursiveActivation(player_actor->ar_vector_index, visited);
880 }
881 // Snowball effect (activate all actors which might soon get hit by a moving actor)
882 for (unsigned int t = 0; t < m_actors.size(); t++)
883 {
884 if (m_actors[t]->ar_state == ActorState::LOCAL_SIMULATED && m_actors[t]->ar_sleep_counter == 0.0f)
885 this->RecursiveActivation(t, visited);
886 }
887}
888
890{
891 for (ActorPtr& actor: m_actors)
892 {
893 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
894 {
895 actor->ar_state = ActorState::LOCAL_SIMULATED;
896 actor->ar_sleep_counter = 0.0f;
897 }
898 }
899}
900
902{
903 m_forced_awake = false;
904 for (ActorPtr& actor: m_actors)
905 {
906 if (actor->ar_state == ActorState::LOCAL_SIMULATED)
907 {
908 actor->ar_state = ActorState::LOCAL_SLEEPING;
909 }
910 }
911}
912
913ActorPtr ActorManager::FindActorInsideBox(Collisions* collisions, const Ogre::String& inst, const Ogre::String& box)
914{
915 // try to find the desired actor (the one in the box)
916 ActorPtr ret = nullptr;
917 for (ActorPtr& actor: m_actors)
918 {
919 if (collisions->isInside(actor->ar_nodes[0].AbsPosition, inst, box))
920 {
921 if (ret == nullptr)
922 // first actor found
923 ret = actor;
924 else
925 // second actor found -> unclear which one was meant
926 return nullptr;
927 }
928 }
929 return ret;
930}
931
932void ActorManager::RepairActor(Collisions* collisions, const Ogre::String& inst, const Ogre::String& box, bool keepPosition)
933{
934 ActorPtr actor = this->FindActorInsideBox(collisions, inst, box);
935 if (actor != nullptr)
936 {
938
940 rq->amr_actor = actor->ar_instance_id;
943 }
944}
945
946std::pair<ActorPtr, float> ActorManager::GetNearestActor(Vector3 position)
947{
948 ActorPtr nearest_actor = nullptr;
949 float min_squared_distance = std::numeric_limits<float>::max();
950 for (ActorPtr& actor : m_actors)
951 {
952 float squared_distance = position.squaredDistance(actor->ar_nodes[0].AbsPosition);
953 if (squared_distance < min_squared_distance)
954 {
955 min_squared_distance = squared_distance;
956 nearest_actor = actor;
957 }
958 }
959 return std::make_pair(nearest_actor, std::sqrt(min_squared_distance));
960}
961
962void ActorManager::CleanUpSimulation() // Called after simulation finishes
963{
964 while (m_actors.size() > 0)
965 {
966 this->DeleteActorInternal(m_actors.back()); // OK to invoke here - CleanUpSimulation() - processing `MSG_SIM_UNLOAD_TERRAIN_REQUESTED`
967 }
968
969 m_total_sim_time = 0.f;
971 m_simulation_paused = false;
972 m_simulation_speed = 1.f;
973}
974
976{
977 if (actor == nullptr || actor->ar_state == ActorState::DISPOSED)
978 return;
979
980 this->SyncWithSimThread();
981
982#ifdef USE_SOCKETW
983 if (App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
984 {
986 {
988 }
989 else if (std::count_if(m_actors.begin(), m_actors.end(), [actor](ActorPtr& b)
990 { return b->ar_net_source_id == actor->ar_net_source_id; }) == 1)
991 {
992 // We're deleting the last actor from this stream source, reset the stream time offset
994 }
995 }
996#endif // USE_SOCKETW
997
998 // Unload actor's scripts
999 std::vector<ScriptUnitID_t> unload_list;
1000 for (auto& pair : App::GetScriptEngine()->getScriptUnits())
1001 {
1002 if (pair.second.associatedActor == actor)
1003 unload_list.push_back(pair.first);
1004 }
1005 for (ScriptUnitID_t id : unload_list)
1006 {
1008 }
1009
1010 // Remove FreeForces referencing this actor
1011 m_free_forces.erase(
1012 std::remove_if(
1013 m_free_forces.begin(),
1014 m_free_forces.end(),
1015 [actor](FreeForce& item) { return item.ffc_base_actor == actor || item.ffc_target_actor == actor; }),
1016 m_free_forces.end());
1017
1018 // Only dispose(), do not `delete`; a script may still hold pointer to the object.
1019 actor->dispose();
1020
1021 EraseIf(m_actors, [actor](ActorPtr& curActor) { return actor == curActor; });
1022
1023 // Upate actor indices
1024 for (unsigned int i = 0; i < m_actors.size(); i++)
1025 m_actors[i]->ar_vector_index = i;
1026}
1027
1028// ACTORLIST for cycling with hotkeys
1029// ----------------------------------
1030
1031int FindPivotActorId(ActorPtr player, ActorPtr prev_player)
1032{
1033 if (player != nullptr)
1034 return player->ar_vector_index;
1035 else if (prev_player != nullptr)
1036 return prev_player->ar_vector_index + 1;
1037 return -1;
1038}
1039
1041{
1042 bool retval = !actor->isPreloadedWithTerrain();
1043
1044 // Exclude remote actors, if desired
1045 if (!App::mp_cyclethru_net_actors->getBool())
1046 {
1048 {
1049 retval = false;
1050 }
1051 }
1052
1053 return retval;
1054}
1055
1057{
1058 int pivot_index = FindPivotActorId(player, prev_player);
1059
1060 for (int i = pivot_index + 1; i < m_actors.size(); i++)
1061 {
1063 return m_actors[i];
1064 }
1065
1066 for (int i = 0; i < pivot_index; i++)
1067 {
1069 return m_actors[i];
1070 }
1071
1072 if (pivot_index >= 0)
1073 {
1074 if (ShouldIncludeActorInList(m_actors[pivot_index]))
1075 return m_actors[pivot_index];
1076 }
1077
1078 return ACTORPTR_NULL;
1079}
1080
1082{
1083 int pivot_index = FindPivotActorId(player, prev_player);
1084
1085 for (int i = pivot_index - 1; i >= 0; i--)
1086 {
1088 return m_actors[i];
1089 }
1090
1091 for (int i = static_cast<int>(m_actors.size()) - 1; i > pivot_index; i--)
1092 {
1094 return m_actors[i];
1095 }
1096
1097 if (pivot_index >= 0)
1098 {
1099 if (ShouldIncludeActorInList(m_actors[pivot_index]))
1100 return m_actors[pivot_index];
1101 }
1102
1103 return ACTORPTR_NULL;
1104}
1105
1106// END actorlist
1107
1109{
1110 for (ActorPtr& actor: m_actors)
1111 {
1112 if (actor->ar_rescuer_flag)
1113 {
1114 return actor;
1115 }
1116 }
1117 return ACTORPTR_NULL;
1118}
1119
1121{
1122 float dt = m_simulation_time;
1123
1124 // do not allow dt > 1/20
1125 dt = std::min(dt, 1.0f / 20.0f);
1126
1127 dt *= m_simulation_speed;
1128
1129 dt += m_dt_remainder;
1131 if (m_physics_steps == 0)
1132 {
1133 return;
1134 }
1135
1138
1139 this->SyncWithSimThread();
1140
1141 this->UpdateSleepingState(player_actor, dt);
1142
1143 for (ActorPtr& actor: m_actors)
1144 {
1145 actor->HandleInputEvents(dt);
1146 actor->HandleAngelScriptEvents(dt);
1147
1148#ifdef USE_ANGELSCRIPT
1149 if (actor->ar_vehicle_ai && actor->ar_vehicle_ai->isActive())
1150 actor->ar_vehicle_ai->update(dt, 0);
1151#endif // USE_ANGELSCRIPT
1152
1153 if (actor->ar_engine)
1154 {
1155 if (actor->ar_driveable == TRUCK)
1156 {
1157 this->UpdateTruckFeatures(actor, dt);
1158 }
1159 if (actor->ar_state == ActorState::LOCAL_SLEEPING)
1160 {
1161 actor->ar_engine->UpdateEngine(dt, 1);
1162 }
1163 actor->ar_engine->UpdateEngineAudio();
1164 }
1165
1166 // Always update indicator states - used by 'u' type flares.
1167 actor->updateDashBoards(dt);
1168
1169 // Blinkers (turn signals) must always be updated
1170 actor->updateFlareStates(dt);
1171
1172 if (actor->ar_state != ActorState::LOCAL_SLEEPING)
1173 {
1174 actor->updateVisual(dt);
1175 if (actor->ar_update_physics && App::gfx_skidmarks_mode->getInt() > 0)
1176 {
1177 actor->updateSkidmarks();
1178 }
1179 }
1180 if (App::mp_state->getEnum<MpState>() == RoR::MpState::CONNECTED)
1181 {
1182 // FIXME: Hidden actors must also be updated to workaround a glitch, see https://github.com/RigsOfRods/rigs-of-rods/issues/2911
1183 if (actor->ar_state == ActorState::NETWORKED_OK || actor->ar_state == ActorState::NETWORKED_HIDDEN)
1184 actor->calcNetwork();
1185 else
1186 actor->sendStreamData();
1187 }
1188 }
1189
1190 if (player_actor != nullptr)
1191 {
1192 this->ForwardCommands(player_actor);
1193 if (player_actor->ar_toggle_ties)
1194 {
1195 //player_actor->tieToggle();
1198 rq->alr_actor_instance_id = player_actor->ar_instance_id;
1199 rq->alr_tie_group = -1;
1201
1202 player_actor->ar_toggle_ties = false;
1203 }
1204 if (player_actor->ar_toggle_ropes)
1205 {
1206 //player_actor->ropeToggle(-1);
1209 rq->alr_actor_instance_id = player_actor->ar_instance_id;
1210 rq->alr_rope_group = -1;
1212
1213 player_actor->ar_toggle_ropes = false;
1214 }
1215
1216 player_actor->ForceFeedbackStep(m_physics_steps);
1217
1218 if (player_actor->ar_state == ActorState::LOCAL_REPLAY)
1219 {
1220 player_actor->getReplay()->replayStepActor();
1221 }
1222 }
1223
1224 auto func = std::function<void()>([this]()
1225 {
1227 });
1228 m_sim_task = m_sim_thread_pool->RunTask(func);
1229
1230 m_total_sim_time += dt;
1231
1232 if (!App::app_async_physics->getBool())
1233 m_sim_task->join();
1234}
1235
1237{
1238 for (ActorPtr& actor: m_actors)
1239 {
1240 if (actor->ar_instance_id == actor_id)
1241 {
1242 return actor;
1243 }
1244 }
1245 return ACTORPTR_NULL;
1246}
1247
1249{
1250 for (ActorPtr& actor: m_actors)
1251 {
1252 actor->UpdatePhysicsOrigin();
1253 }
1254 for (int i = 0; i < m_physics_steps; i++)
1255 {
1256 {
1257 std::vector<std::function<void()>> tasks;
1258 for (ActorPtr& actor: m_actors)
1259 {
1260 if (actor->ar_update_physics = actor->CalcForcesEulerPrepare(i == 0))
1261 {
1262 auto func = std::function<void()>([this, i, &actor]()
1263 {
1264 actor->CalcForcesEulerCompute(i == 0, m_physics_steps);
1265 });
1266 tasks.push_back(func);
1267 }
1268 }
1270 for (ActorPtr& actor: m_actors)
1271 {
1272 if (actor->ar_update_physics)
1273 {
1274 actor->CalcBeamsInterActor();
1275 }
1276 }
1277 }
1278 {
1279 std::vector<std::function<void()>> tasks;
1280 for (ActorPtr& actor: m_actors)
1281 {
1282 if (actor->m_inter_point_col_detector != nullptr && (actor->ar_update_physics ||
1284 {
1285 auto func = std::function<void()>([this, &actor]()
1286 {
1287 actor->m_inter_point_col_detector->UpdateInterPoint();
1288 if (actor->ar_collision_relevant)
1289 {
1290 ResolveInterActorCollisions(PHYSICS_DT,
1291 *actor->m_inter_point_col_detector,
1292 actor->ar_num_collcabs,
1293 actor->ar_collcabs,
1294 actor->ar_cabs,
1295 actor->ar_inter_collcabrate,
1296 actor->ar_nodes,
1297 actor->ar_collision_range,
1298 *actor->ar_submesh_ground_model);
1299 }
1300 });
1301 tasks.push_back(func);
1302 }
1303 }
1305 }
1306
1307 // Apply FreeForces - intentionally as a separate pass over all actors
1308 this->CalcFreeForces();
1309 }
1310 for (ActorPtr& actor: m_actors)
1311 {
1312 actor->m_ongoing_reset = false;
1313 if (actor->ar_update_physics && m_physics_steps > 0)
1314 {
1315 Vector3 camera_gforces = actor->m_camera_gforces_accu / m_physics_steps;
1316 actor->m_camera_gforces_accu = Vector3::ZERO;
1317 actor->m_camera_gforces = actor->m_camera_gforces * 0.5f + camera_gforces * 0.5f;
1318 actor->calculateLocalGForces();
1319 actor->calculateAveragePosition();
1320 actor->m_avg_node_velocity = actor->m_avg_node_position - actor->m_avg_node_position_prev;
1321 actor->m_avg_node_velocity /= (m_physics_steps * PHYSICS_DT);
1322 actor->m_avg_node_position_prev = actor->m_avg_node_position;
1323 actor->ar_top_speed = std::max(actor->ar_top_speed, actor->ar_nodes[0].Velocity.length());
1324 }
1325 }
1326}
1327
1329{
1330 if (m_sim_task)
1331 m_sim_task->join();
1332}
1333
1334void HandleErrorLoadingFile(std::string type, std::string filename, std::string exception_msg)
1335{
1336 RoR::Str<200> msg;
1337 msg << "Failed to load '" << filename << "' (type: '" << type << "'), message: " << exception_msg;
1340}
1341
1342void HandleErrorLoadingTruckfile(std::string filename, std::string exception_msg)
1343{
1344 HandleErrorLoadingFile("actor", filename, exception_msg);
1345}
1346
1348{
1349 // Check the actor exists in mod cache
1350 if (rq.asr_cache_entry == nullptr)
1351 {
1352 HandleErrorLoadingTruckfile(rq.asr_filename, "Truckfile not found in ModCache (probably not installed)");
1353 return nullptr;
1354 }
1355
1356 // If already parsed, re-use
1357 if (rq.asr_cache_entry->actor_def != nullptr)
1358 {
1359 return rq.asr_cache_entry->actor_def;
1360 }
1361
1362 // Load the 'truckfile'
1363 try
1364 {
1366 Ogre::DataStreamPtr stream = Ogre::ResourceGroupManager::getSingleton().openResource(rq.asr_cache_entry->fname, rq.asr_cache_entry->resource_group);
1367
1368 if (!stream || !stream->isReadable())
1369 {
1370 HandleErrorLoadingTruckfile(rq.asr_cache_entry->fname, "Unable to open/read truckfile");
1371 return nullptr;
1372 }
1373
1374 RoR::LogFormat("[RoR] Parsing truckfile '%s'", rq.asr_cache_entry->fname.c_str());
1375 RigDef::Parser parser;
1376 parser.Prepare();
1377 parser.ProcessOgreStream(stream.get(), rq.asr_cache_entry->resource_group);
1378 parser.Finalize();
1379
1380 auto def = parser.GetFile();
1381
1382 // VALIDATING
1383 LOG(" == Validating vehicle: " + def->name);
1384
1385 RigDef::Validator validator;
1386 validator.Setup(def);
1387
1389 {
1390 // Workaround: Some terrains pre-load truckfiles with special purpose:
1391 // "soundloads" = play sound effect at certain spot
1392 // "fixes" = structures of N/B fixed to the ground
1393 // These files can have no beams. Possible extensions: .load or .fixed
1394 std::string file_extension = rq.asr_cache_entry->fname.substr(rq.asr_cache_entry->fname.find_last_of('.'));
1395 Ogre::StringUtil::toLowerCase(file_extension);
1396 if ((file_extension == ".load") || (file_extension == ".fixed"))
1397 {
1398 validator.SetCheckBeams(false);
1399 }
1400 }
1401
1402 validator.Validate(); // Sends messages to console
1403
1404 def->hash = Sha1Hash(stream->getAsString());
1405
1406 rq.asr_cache_entry->actor_def = def;
1407 return def;
1408 }
1409 catch (Ogre::Exception& oex)
1410 {
1411 HandleErrorLoadingTruckfile(rq.asr_cache_entry->fname, oex.getDescription().c_str());
1412 return nullptr;
1413 }
1414 catch (std::exception& stex)
1415 {
1417 return nullptr;
1418 }
1419 catch (...)
1420 {
1421 HandleErrorLoadingTruckfile(rq.asr_cache_entry->fname, "<Unknown exception occurred>");
1422 return nullptr;
1423 }
1424}
1425
1426void ActorManager::ExportActorDef(RigDef::DocumentPtr def, std::string filename, std::string rg_name)
1427{
1428 try
1429 {
1430 Ogre::ResourceGroupManager& rgm = Ogre::ResourceGroupManager::getSingleton();
1431
1432 // Open OGRE stream for writing
1433 Ogre::DataStreamPtr stream = rgm.createResource(filename, rg_name, /*overwrite=*/true);
1434 if (stream.isNull() || !stream->isWriteable())
1435 {
1436 OGRE_EXCEPT(Ogre::Exception::ERR_CANNOT_WRITE_TO_FILE,
1437 "Stream NULL or not writeable, filename: '" + filename
1438 + "', resource group: '" + rg_name + "'");
1439 }
1440
1441 // Serialize actor to string
1442 RigDef::Serializer serializer(def);
1443 serializer.Serialize();
1444
1445 // Flush the string to file
1446 stream->write(serializer.GetOutput().c_str(), serializer.GetOutput().size());
1447 stream->close();
1448 }
1449 catch (Ogre::Exception& oex)
1450 {
1452 fmt::format(_LC("Truck", "Failed to export truck '{}' to resource group '{}', message: {}"),
1453 filename, rg_name, oex.getFullDescription()));
1454 }
1455}
1456
1457std::vector<ActorPtr> ActorManager::GetLocalActors()
1458{
1459 std::vector<ActorPtr> actors;
1460 for (ActorPtr& actor: m_actors)
1461 {
1462 if (actor->ar_state != ActorState::NETWORKED_OK)
1463 actors.push_back(actor);
1464 }
1465 return actors;
1466}
1467
1469{
1470 // Simulation pace adjustment (slowmotion)
1471 if (!App::GetGameContext()->GetRaceSystem().IsRaceInProgress())
1472 {
1473 // EV_COMMON_ACCELERATE_SIMULATION
1474 if (App::GetInputEngine()->getEventBoolValue(EV_COMMON_ACCELERATE_SIMULATION))
1475 {
1476 float simulation_speed = this->GetSimulationSpeed() * pow(2.0f, dt / 2.0f);
1477 this->SetSimulationSpeed(simulation_speed);
1478 String ssmsg = _L("New simulation speed: ") + TOSTRING(Round(simulation_speed * 100.0f, 1)) + "%";
1480 }
1481
1482 // EV_COMMON_DECELERATE_SIMULATION
1483 if (App::GetInputEngine()->getEventBoolValue(EV_COMMON_DECELERATE_SIMULATION))
1484 {
1485 float simulation_speed = this->GetSimulationSpeed() * pow(0.5f, dt / 2.0f);
1486 this->SetSimulationSpeed(simulation_speed);
1487 String ssmsg = _L("New simulation speed: ") + TOSTRING(Round(simulation_speed * 100.0f, 1)) + "%";
1489 }
1490
1491 // EV_COMMON_RESET_SIMULATION_PACE
1492 if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_RESET_SIMULATION_PACE))
1493 {
1494 float simulation_speed = this->GetSimulationSpeed();
1495 if (simulation_speed != 1.0f)
1496 {
1497 m_last_simulation_speed = simulation_speed;
1498 this->SetSimulationSpeed(1.0f);
1499 std::string ssmsg = _L("Simulation speed reset.");
1501 }
1502 else if (m_last_simulation_speed != 1.0f)
1503 {
1505 String ssmsg = _L("New simulation speed: ") + TOSTRING(Round(m_last_simulation_speed * 100.0f, 1)) + "%";
1507 }
1508 }
1509
1510 // Special adjustment while racing
1511 if (App::GetGameContext()->GetRaceSystem().IsRaceInProgress() && this->GetSimulationSpeed() != 1.0f)
1512 {
1514 this->SetSimulationSpeed(1.f);
1515 }
1516 }
1517
1518 // EV_COMMON_TOGGLE_PHYSICS - Freeze/unfreeze physics
1519 if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_TOGGLE_PHYSICS))
1520 {
1522
1524 {
1525 String ssmsg = _L("Physics paused");
1527 }
1528 else
1529 {
1530 String ssmsg = _L("Physics unpaused");
1532 }
1533 }
1534
1535 // Calculate simulation time
1537 {
1538 m_simulation_time = 0.f;
1539
1540 // Frozen physics stepping
1541 if (this->GetSimulationSpeed() > 0.0f)
1542 {
1543 // EV_COMMON_REPLAY_FAST_FORWARD - Advance simulation while pressed
1544 // EV_COMMON_REPLAY_FORWARD - Advanced simulation one step
1545 if (App::GetInputEngine()->getEventBoolValue(EV_COMMON_REPLAY_FAST_FORWARD) ||
1546 App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_REPLAY_FORWARD))
1547 {
1549 }
1550 }
1551 }
1552 else
1553 {
1554 m_simulation_time = dt;
1555 }
1556}
1557
1559{
1560 if (vehicle->isBeingReset() || vehicle->ar_physics_paused)
1561 return;
1562#ifdef USE_ANGELSCRIPT
1563 if (vehicle->ar_vehicle_ai && vehicle->ar_vehicle_ai->isActive())
1564 return;
1565#endif // USE_ANGELSCRIPT
1566
1567 EnginePtr engine = vehicle->ar_engine;
1568
1569 /* Anti roll-back is disabled when the brake input
1570 event is simulated for the vehicle.
1571 That way the brake simulated input can be freely
1572 modified without conflicts.*/
1573 if (engine && engine->hasContact() &&
1574 engine->getAutoMode() == SimGearboxMode::AUTO &&
1575 engine->getAutoShift() != Engine::NEUTRAL &&
1577 {
1578 Ogre::Vector3 dirDiff = vehicle->getDirection();
1579 Ogre::Degree pitchAngle = Ogre::Radian(asin(dirDiff.dotProduct(Ogre::Vector3::UNIT_Y)));
1580
1581 if (std::abs(pitchAngle.valueDegrees()) > 2.0f)
1582 {
1583 if (engine->getAutoShift() > Engine::NEUTRAL && vehicle->ar_avg_wheel_speed < +0.02f && pitchAngle.valueDegrees() > 0.0f ||
1584 engine->getAutoShift() < Engine::NEUTRAL && vehicle->ar_avg_wheel_speed > -0.02f && pitchAngle.valueDegrees() < 0.0f)
1585 {
1586 // anti roll back in SimGearboxMode::AUTO (DRIVE, TWO, ONE) mode
1587 // anti roll forth in SimGearboxMode::AUTO (REAR) mode
1588 float g = std::abs(App::GetGameContext()->GetTerrain()->getGravity());
1589 float downhill_force = std::abs(sin(pitchAngle.valueRadians()) * vehicle->getTotalMass()) * g;
1590 float engine_force = std::abs(engine->getTorque()) / vehicle->getAvgPropedWheelRadius();
1591 float ratio = std::max(0.0f, 1.0f - (engine_force / downhill_force));
1592 if (vehicle->ar_avg_wheel_speed * pitchAngle.valueDegrees() > 0.0f)
1593 {
1594 ratio *= sqrt((0.02f - vehicle->ar_avg_wheel_speed) / 0.02f);
1595 }
1596 vehicle->ar_brake = sqrt(ratio);
1597 }
1598 }
1599 else if (vehicle->ar_brake == 0.0f && !vehicle->ar_parking_brake && engine->getTorque() == 0.0f)
1600 {
1601 float ratio = std::max(0.0f, 0.2f - std::abs(vehicle->ar_avg_wheel_speed)) / 0.2f;
1602 vehicle->ar_brake = ratio;
1603 }
1604 }
1605
1606 if (vehicle->cc_mode)
1607 {
1608 vehicle->UpdateCruiseControl(dt);
1609 }
1610 if (vehicle->sl_enabled)
1611 {
1612 // check speed limit
1613 if (engine && engine->getGear() != 0)
1614 {
1615 float accl = (vehicle->sl_speed_limit - std::abs(vehicle->ar_wheel_speed / 1.02f)) * 2.0f;
1616 engine->setAcc(Ogre::Math::Clamp(accl, 0.0f, engine->getAcc()));
1617 }
1618 }
1619
1620 BITMASK_SET(vehicle->m_lightmask, RoRnet::LIGHTMASK_BRAKES, (vehicle->ar_brake > 0.01f && !vehicle->ar_parking_brake));
1621 BITMASK_SET(vehicle->m_lightmask, RoRnet::LIGHTMASK_REVERSE, (vehicle->ar_engine && vehicle->ar_engine->getGear() < 0));
1622}
1623
1625{
1626 for (FreeForce& freeforce: m_free_forces)
1627 {
1628 // Sanity checks
1629 ROR_ASSERT(freeforce.ffc_base_actor != nullptr);
1630 ROR_ASSERT(freeforce.ffc_base_actor->ar_state != ActorState::DISPOSED);
1631 ROR_ASSERT(freeforce.ffc_base_node != NODENUM_INVALID);
1632 ROR_ASSERT(freeforce.ffc_base_node <= freeforce.ffc_base_actor->ar_num_nodes);
1633
1634
1635 switch (freeforce.ffc_type)
1636 {
1638 freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].Forces += freeforce.ffc_force_magnitude * freeforce.ffc_force_const_direction;
1639 break;
1640
1642 {
1643 const Vector3 force_direction = (freeforce.ffc_target_coords - 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
1649 {
1650 // Sanity checks
1651 ROR_ASSERT(freeforce.ffc_target_actor != nullptr);
1652 ROR_ASSERT(freeforce.ffc_target_actor->ar_state != ActorState::DISPOSED);
1653 ROR_ASSERT(freeforce.ffc_target_node != NODENUM_INVALID);
1654 ROR_ASSERT(freeforce.ffc_target_node <= freeforce.ffc_target_actor->ar_num_nodes);
1655
1656 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();
1657 freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].Forces += freeforce.ffc_force_magnitude * force_direction;
1658 }
1659 break;
1660
1663 {
1664 // Sanity checks
1665 ROR_ASSERT(freeforce.ffc_target_actor != nullptr);
1666 ROR_ASSERT(freeforce.ffc_target_actor->ar_state != ActorState::DISPOSED);
1667 ROR_ASSERT(freeforce.ffc_target_node != NODENUM_INVALID);
1668 ROR_ASSERT(freeforce.ffc_target_node <= freeforce.ffc_target_actor->ar_num_nodes);
1669
1670 // ---- BEGIN COPYPASTE of `Actor::CalcBeamsInterActor()` ----
1671
1672 // Calculate beam length
1673 node_t* p1 = &freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node];
1674 node_t* p2 = &freeforce.ffc_target_actor->ar_nodes[freeforce.ffc_target_node];
1675 const Vector3 dis = p1->AbsPosition - p2->AbsPosition;
1676
1677 Real dislen = dis.squaredLength();
1678 const Real inverted_dislen = fast_invSqrt(dislen);
1679
1680 dislen *= inverted_dislen;
1681
1682 // Calculate beam's deviation from normal
1683 Real difftoBeamL = dislen - freeforce.ffc_halfb_L;
1684
1685 Real k = freeforce.ffc_halfb_spring;
1686 Real d = freeforce.ffc_halfb_damp;
1687
1688 if (freeforce.ffc_type == FreeForceType::HALFBEAM_ROPE && difftoBeamL < 0.0f)
1689 {
1690 k = 0.0f;
1691 d *= 0.1f;
1692 }
1693
1694 // Calculate beam's rate of change
1695 Vector3 v = p1->Velocity - p2->Velocity;
1696
1697 float slen = -k * (difftoBeamL)-d * v.dotProduct(dis) * inverted_dislen;
1698 freeforce.ffc_halfb_stress = slen;
1699
1700 // Fast test for deformation
1701 float len = std::abs(slen);
1702 if (len > freeforce.ffc_halfb_minmaxposnegstress)
1703 {
1704 if (k != 0.0f)
1705 {
1706 // Actual deformation tests
1707 if (slen > freeforce.ffc_halfb_maxposstress && difftoBeamL < 0.0f) // compression
1708 {
1709 Real yield_length = freeforce.ffc_halfb_maxposstress / k;
1710 Real deform = difftoBeamL + yield_length * (1.0f - freeforce.ffc_halfb_plastic_coef);
1711 Real Lold = freeforce.ffc_halfb_L;
1712 freeforce.ffc_halfb_L += deform;
1713 freeforce.ffc_halfb_L = std::max(MIN_BEAM_LENGTH, freeforce.ffc_halfb_L);
1714 slen = slen - (slen - freeforce.ffc_halfb_maxposstress) * 0.5f;
1715 len = slen;
1716 if (freeforce.ffc_halfb_L > 0.0f && Lold > freeforce.ffc_halfb_L)
1717 {
1718 freeforce.ffc_halfb_maxposstress *= Lold / freeforce.ffc_halfb_L;
1719 freeforce.ffc_halfb_minmaxposnegstress = std::min(freeforce.ffc_halfb_maxposstress, -freeforce.ffc_halfb_maxnegstress);
1720 freeforce.ffc_halfb_minmaxposnegstress = std::min(freeforce.ffc_halfb_minmaxposnegstress, freeforce.ffc_halfb_strength);
1721 }
1722 // For the compression case we do not remove any of the beam's
1723 // strength for structure stability reasons
1724 //freeforce.ffc_halfb_strength += deform * k * 0.5f;
1725
1727 fmt::format("{}", slen), fmt::format("{}", freeforce.ffc_halfb_maxposstress));
1728 }
1729 else if (slen < freeforce.ffc_halfb_maxnegstress && difftoBeamL > 0.0f) // expansion
1730 {
1731 Real yield_length = freeforce.ffc_halfb_maxnegstress / k;
1732 Real deform = difftoBeamL + yield_length * (1.0f - freeforce.ffc_halfb_plastic_coef);
1733 Real Lold = freeforce.ffc_halfb_L;
1734 freeforce.ffc_halfb_L += deform;
1735 slen = slen - (slen - freeforce.ffc_halfb_maxnegstress) * 0.5f;
1736 len = -slen;
1737 if (Lold > 0.0f && freeforce.ffc_halfb_L > Lold)
1738 {
1739 freeforce.ffc_halfb_maxnegstress *= freeforce.ffc_halfb_L / Lold;
1740 freeforce.ffc_halfb_minmaxposnegstress = std::min(freeforce.ffc_halfb_maxposstress, -freeforce.ffc_halfb_maxnegstress);
1741 freeforce.ffc_halfb_minmaxposnegstress = std::min(freeforce.ffc_halfb_minmaxposnegstress, freeforce.ffc_halfb_strength);
1742 }
1743 freeforce.ffc_halfb_strength -= deform * k;
1744
1746 fmt::format("{}", slen), fmt::format("{}", freeforce.ffc_halfb_maxnegstress));
1747 }
1748 }
1749
1750 // Test if the beam should break
1751 if (len > freeforce.ffc_halfb_strength)
1752 {
1753 // Sound effect.
1754 // Sound volume depends on springs stored energy
1755 SOUND_MODULATE(freeforce.ffc_base_actor->ar_instance_id, SS_MOD_BREAK, 0.5 * k * difftoBeamL * difftoBeamL);
1756 SOUND_PLAY_ONCE(freeforce.ffc_base_actor->ar_instance_id, SS_TRIG_BREAK);
1757
1758 freeforce.ffc_type = FreeForceType::DUMMY;
1759
1761 fmt::format("{}", len), fmt::format("{}", freeforce.ffc_halfb_strength));
1762 }
1763 }
1764
1765 // At last update the beam forces
1766 Vector3 f = dis;
1767 f *= (slen * inverted_dislen);
1768 p1->Forces += f;
1769 // ---- END COPYPASTE of `Actor::CalcBeamsInterActor()` ----
1770 }
1771 break;
1772
1773 default:
1774 break;
1775 }
1776 }
1777}
1778
1779static bool ProcessFreeForce(FreeForceRequest* rq, FreeForce& freeforce)
1780{
1781 // internal helper for processing add/modify requests, with checks
1782 // ---------------------------------------------------------------
1783
1784 // Unchecked stuff
1785 freeforce.ffc_id = (FreeForceID_t)rq->ffr_id;
1786 freeforce.ffc_type = (FreeForceType)rq->ffr_type;
1787 freeforce.ffc_force_magnitude = (float)rq->ffr_force_magnitude;
1789 freeforce.ffc_target_coords = rq->ffr_target_coords;
1790
1791 // Base actor
1793 ROR_ASSERT(freeforce.ffc_base_actor != nullptr && freeforce.ffc_base_actor->ar_state != ActorState::DISPOSED);
1794 if (!freeforce.ffc_base_actor || freeforce.ffc_base_actor->ar_state == ActorState::DISPOSED)
1795 {
1797 fmt::format("Cannot add free force with ID {} to actor {}: Base actor not found or disposed", freeforce.ffc_id, rq->ffr_base_actor));
1798 return false;
1799 }
1800
1801 // Base node
1802 ROR_ASSERT(rq->ffr_base_node >= 0);
1805 if (rq->ffr_base_node < 0 || rq->ffr_base_node >= NODENUM_MAX || rq->ffr_base_node >= freeforce.ffc_base_actor->ar_num_nodes)
1806 {
1808 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));
1809 return false;
1810 }
1811 freeforce.ffc_base_node = (NodeNum_t)rq->ffr_base_node;
1812
1813 if (freeforce.ffc_type == FreeForceType::TOWARDS_NODE ||
1816 {
1817 // Target actor
1819 ROR_ASSERT(freeforce.ffc_target_actor != nullptr && freeforce.ffc_target_actor->ar_state != ActorState::DISPOSED);
1820 if (!freeforce.ffc_target_actor || freeforce.ffc_target_actor->ar_state == ActorState::DISPOSED)
1821 {
1823 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));
1824 return false;
1825 }
1826
1827 // Target node
1828 ROR_ASSERT(rq->ffr_target_node >= 0);
1832 {
1834 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));
1835 return false;
1836 }
1837 freeforce.ffc_target_node = (NodeNum_t)rq->ffr_target_node;
1838
1839 if (freeforce.ffc_type == FreeForceType::HALFBEAM_GENERIC ||
1841 {
1842 freeforce.ffc_halfb_spring = (float)rq->ffr_halfb_spring;
1843 freeforce.ffc_halfb_damp = (float)rq->ffr_halfb_damp;
1844 freeforce.ffc_halfb_strength = (float)rq->ffr_halfb_strength;
1845 freeforce.ffc_halfb_deform = (float)rq->ffr_halfb_deform;
1846 freeforce.ffc_halfb_diameter = (float)rq->ffr_halfb_diameter;
1847 freeforce.ffc_halfb_plastic_coef = (float)rq->ffr_halfb_plastic_coef;
1848
1849 freeforce.ffc_halfb_minmaxposnegstress = (float)rq->ffr_halfb_deform;
1850 freeforce.ffc_halfb_maxposstress = (float)rq->ffr_halfb_deform;
1851 freeforce.ffc_halfb_maxnegstress = -(float)rq->ffr_halfb_deform;
1852
1853 // Calc length
1854 const Ogre::Vector3 base_pos = freeforce.ffc_base_actor->ar_nodes[freeforce.ffc_base_node].AbsPosition;
1855 const Ogre::Vector3 target_pos = freeforce.ffc_target_actor->ar_nodes[freeforce.ffc_target_node].AbsPosition;
1856 freeforce.ffc_halfb_L = target_pos.distance(base_pos);
1857 }
1858 }
1859
1860 return true;
1861}
1862
1863bool ActorManager::FindFreeForce(FreeForceID_t id, ActorManager::FreeForceVec_t::iterator& out_itor)
1864{
1865 out_itor = std::find_if(m_free_forces.begin(), m_free_forces.end(), [id](FreeForce& item) { return id == item.ffc_id; });
1866 return out_itor != m_free_forces.end();
1867}
1868
1870{
1871 // Make sure ID is unique
1872 ActorManager::FreeForceVec_t::iterator it;
1873 if (this->FindFreeForce(rq->ffr_id, it))
1874 {
1876 fmt::format("Cannot add free force with ID {}: ID already in use", rq->ffr_id));
1877 return;
1878 }
1879
1880 FreeForce freeforce;
1881 if (ProcessFreeForce(rq, freeforce))
1882 {
1883 m_free_forces.push_back(freeforce);
1885 }
1886}
1887
1889{
1890 ActorManager::FreeForceVec_t::iterator it;
1891 if (!this->FindFreeForce(rq->ffr_id, it))
1892 {
1894 fmt::format("Cannot modify free force with ID {}: ID not found", rq->ffr_id));
1895 return;
1896 }
1897
1898 FreeForce& freeforce = *it;
1899 if (ProcessFreeForce(rq, freeforce))
1900 {
1901 *it = freeforce;
1903 }
1904}
1905
1907{
1908 ActorManager::FreeForceVec_t::iterator it;
1909 if (!this->FindFreeForce(id, it))
1910 {
1912 fmt::format("Cannot remove free force with ID {}: ID not found", id));
1913 return;
1914 }
1915
1916 m_free_forces.erase(it);
1918}
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:58
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:509
bool ar_import_commands
Sim state.
Definition Actor.h:606
std::vector< float > ar_orig_minimass
minimum node mass in Kg - original unscaled values
Definition Actor.h:373
Ogre::AxisAlignedBox ar_bounding_box
standard bounding box (surrounds all nodes of an actor)
Definition Actor.h:405
int m_wheel_node_count
Static attr; filled at spawn.
Definition Actor.h:695
size_t m_net_total_buffer_size
For incoming/outgoing traffic; calculated on spawn.
Definition Actor.h:730
EnginePtr ar_engine
Definition Actor.h:467
BitMask_t getLightStateMask() const
Definition Actor.h:248
std::vector< float > ar_minimass
minimum node mass in Kg - can be scaled in-game via NBUtil
Definition Actor.h:372
float ar_dry_mass
User-defined (editable via NBUtil); from 'globals' arg#1 - default for all nodes.
Definition Actor.h:355
bool ar_forward_commands
Sim state.
Definition Actor.h:605
void calcNodeConnectivityGraph()
Definition Actor.cpp:907
float ar_wheel_speed
Physics state; wheel speed in m/s.
Definition Actor.h:495
bool hasEventSimulatedValue(int eventID)
Definition Actor.cpp:3053
BuoyCachedNodeID_t ar_cabs_buoy_cache_ids[MAX_CABS]
Definition Actor.h:428
CmdKeyArray ar_command_key
BEWARE: commandkeys are indexed 1-MAX_COMMANDS!
Definition Actor.h:404
node_t * ar_nodes
Definition Actor.h:365
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:358
void updateVisual(float dt=0)
Definition Actor.cpp:3421
int ar_buoycabs[MAX_CABS]
Definition Actor.h:435
GfxActor * GetGfxActor()
Definition Actor.h:344
float getRotation()
Definition Actor.cpp:355
bool m_disable_default_sounds
Spawner context; TODO: remove.
Definition Actor.h:758
void NotifyActorCameraChanged()
Logic: sound, display; Notify this vehicle that camera changed;.
Definition Actor.cpp:4029
float ar_sleep_counter
Sim state; idle time counter.
Definition Actor.h:507
float ar_original_dry_mass
Un-edited value from 'globals' arg#1.
Definition Actor.h:356
ground_model_t * ar_submesh_ground_model
Definition Actor.h:508
Replay * getReplay()
Definition Actor.cpp:4815
float ar_initial_total_mass
Calculated; total mass in Kg (snapshot at spawn)
Definition Actor.h:361
bool m_preloaded_with_terrain
Spawn context (TODO: remove!)
Definition Actor.h:754
std::vector< std::pair< float, float > > ar_initial_beam_defaults
Definition Actor.h:385
unsigned int ar_vector_index
Sim attr; actor element index in std::vector<m_actors>
Definition Actor.h:465
float m_spawn_rotation
Definition Actor.h:682
Replay * m_replay_handler
Definition Actor.h:678
bool ar_physics_paused
Actor physics individually paused by user.
Definition Actor.h:570
Ogre::Vector3 getPosition()
Definition Actor.cpp:370
void ForceFeedbackStep(int steps)
Definition Actor.cpp:1837
bool ar_toggle_ropes
Sim state.
Definition Actor.h:607
int m_net_color_num
Definition Actor.h:735
std::vector< Ogre::Vector3 > ar_initial_node_positions
Absolute world positions, for resetting to pristine state.
Definition Actor.h:375
void UpdatePhysicsOrigin()
Definition Actor.cpp:1250
int ar_net_source_id
Unique ID of remote player who spawned this actor.
Definition Actor.h:521
void recalculateNodeMasses()
Definition Actor.cpp:701
std::unique_ptr< Buoyance > m_buoyance
Definition Actor.h:531
std::string m_net_username
Definition Actor.h:734
bool sl_enabled
Speed limiter;.
Definition Actor.h:458
float getAvgPropedWheelRadius()
Definition Actor.h:334
float ar_load_mass
User-defined (editable via NBUtil); from 'globals' arg#2 - only applies to nodes with 'l' flag.
Definition Actor.h:357
Ogre::Vector3 ar_origin
Physics state; base position for softbody nodes.
Definition Actor.h:473
ActorState ar_state
Definition Actor.h:567
size_t m_net_wheel_buf_size
For incoming/outgoing traffic; calculated on spawn.
Definition Actor.h:728
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:729
bool isBeingReset() const
Definition Actor.h:348
float ar_total_mass
Calculated; total mass in Kg.
Definition Actor.h:360
void WriteDiagnosticDump(std::string const &filename)
Definition Actor.cpp:4940
int ar_num_beams
Definition Actor.h:384
ActorInstanceID_t ar_instance_id
Static attr; session-unique ID.
Definition Actor.h:464
ActorPtrVec ar_linked_actors
BEWARE: Includes indirect links, see DetermineLinkedActors(); Other actors linked using 'hooks/ties/r...
Definition Actor.h:568
float ar_avg_wheel_speed
Physics state; avg wheel speed in m/s.
Definition Actor.h:497
std::vector< PropAnimKeyState > m_prop_anim_key_states
Definition Actor.h:712
Ogre::Real ar_brake
Physics state; braking intensity.
Definition Actor.h:494
bool isPreloadedWithTerrain() const
Definition Actor.h:315
std::string ar_filename
Attribute; filled at spawn.
Definition Actor.h:518
Ogre::Real m_min_camera_radius
Definition Actor.h:674
int ar_num_cinecams
Sim attr;.
Definition Actor.h:469
TyrePressure & getTyrePressure()
Definition Actor.h:294
std::string m_section_config
Classic 'sectionconfig' in truck file.
Definition Actor.h:716
bool cc_mode
Cruise Control.
Definition Actor.h:452
int ar_cabs[MAX_CABS *3]
Definition Actor.h:427
int ar_num_nodes
Definition Actor.h:380
VehicleAIPtr ar_vehicle_ai
Definition Actor.h:485
BitMask_t m_lightmask
RoRnet::Lightmask.
Definition Actor.h:741
float getTotalMass(bool withLocked=true)
Definition Actor.cpp:843
void calculateAveragePosition()
Definition Actor.cpp:1166
std::vector< hook_t > ar_hooks
Definition Actor.h:401
void UpdateBoundingBoxes()
Definition Actor.cpp:1201
int ar_num_wheels
Definition Actor.h:420
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:732
Ogre::Vector3 m_avg_node_position
average node position
Definition Actor.h:673
size_t m_net_node_buf_size
For incoming/outgoing traffic; calculated on spawn.
Definition Actor.h:727
beam_t * ar_beams
Definition Actor.h:383
bool ar_trailer_parking_brake
Definition Actor.h:510
int ar_num_buoycabs
Definition Actor.h:437
bool ar_toggle_ties
Sim state.
Definition Actor.h:608
std::vector< float > ar_initial_node_masses
Definition Actor.h:374
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:459
int ar_net_stream_id
Definition Actor.h:522
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:852
void startEngine()
Quick engine start. Plays sounds.
Definition Engine.cpp:1005
float getTorque()
Definition Engine.cpp:923
void offStart()
Quick start of vehicle engine.
Definition Engine.cpp:1023
int getAutoShift()
Definition Engine.cpp:1191
int getGear()
Definition Engine.cpp:1048
void setAcc(float val)
Definition Engine.cpp:862
float getAcc()
Definition Engine.cpp:890
bool hasContact()
Ignition.
Definition Engine.h:103
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:740
void AddPacket(int streamid, int type, int len, const char *content)
Definition Network.cpp:617
void replayStepActor()
Definition Replay.cpp:215
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
@ LOCAL_SCRIPT
Not actually connected to network, but running server script locally.
@ 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:103
@ 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
@ EV_TRUCK_BRAKE
brake
@ 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(),...
@ 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