Skip to content

Commit

Permalink
🐛 Fixed paused physics resuming after switching vehicle.
Browse files Browse the repository at this point in the history
The problem was introduced by myself in 9431e1b - I cleaned up duplicate syncing code but oversimplified the logic to reset unlinked actors. As result, the physics paused state and skeletonview state could only be active on player's actor and connected actor, not on any free standing one.

This is quite a significant remake of actor-linking code; a direct follow-up to d36c4ec which introduced ✉️ MSG_SIM_ACTOR_LINKING_REQUESTED. A remake was needed because there was no single spot to correctly reset the skeleton/physicspause on actor unlink - there was simply no concept of "actors were just linked/unlinked". While researching how to add it, I realized scripts may want to know when that happens, so I added a script event `SE_GENERIC_TRUCK_LINKING_CHANGED` for it. Keep in mind there can be multiple interlinking beams at the same time, so not every added/removed beam means linking changes. The new event also helps navigate the codebase and documents how stuff works.

Note that only code changed; all data remained the same - code handling hooks/ties/ropes/slidenodes got only cosmetic edits.

Code changes:
* ScriptEvents.h - added SE_GENERIC_TRUCK_LINKING_CHANGED ~ args: #1 action (1=linked, 0=unlinked), #2 link type `ActorLinkingRequestType` (will be INVALID on savegame load or forced unlink when deleting actor) #3 master ActorInstanceID_t, #4 slave ActorInstanceID_t
* Actor.h/cpp - Removed functions `Add/RemoveInterActorbeam()` - using new ones in ActorManager.
* ActorManager.h/cpp -  Added newly implemented functions `Add/RemoveInterActorBeam()`.
  • Loading branch information
ohlidalp committed Mar 31, 2024
1 parent f2a9a0d commit 258ec18
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 102 deletions.
4 changes: 3 additions & 1 deletion doc/angelscript/Script2Game/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ void print(const string message);

SE_GENERIC_MESSAGEBOX_CLICK //!< triggered when the user clicks on a message box button, the argument refers to the button pressed
SE_GENERIC_EXCEPTION_CAUGHT //!< Triggered when C++ exception (usually Ogre::Exception) is thrown; #1 ScriptUnitID, #5 originFuncName, #6 type, #7 message.
SE_GENERIC_MODCACHE_ACTIVITY //!< Triggered when status of modcache changes, args: #1 type, #2 entry number, for other args see `RoR::modCacheActivityType`
SE_GENERIC_MODCACHE_ACTIVITY //!< Triggered when status of modcache changes, args: #1 type, #2 entry number, for other args see `RoR::modCacheActivityType`

SE_GENERIC_TRUCK_LINKING_CHANGED //!< Triggered when 2 actors become linked or unlinked via ties/hooks/ropes/slidenodes; args: #1 action (1=linked, 0=unlinked), #2 link type `ActorLinkingRequestType` (will be INVALID on savegame load or forced unlink when deleting actor) #3 master ActorInstanceID_t, #4 slave ActorInstanceID_t

SE_ALL_EVENTS = 0xffffffff,
SE_NO_EVENTS = 0
Expand Down
2 changes: 2 additions & 0 deletions source/main/gameplay/ScriptEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ enum scriptEvents
SE_GENERIC_EXCEPTION_CAUGHT = BITMASK(24), //!< Triggered when C++ exception (usually Ogre::Exception) is thrown; #1 ScriptUnitID, #5 originFuncName, #6 type, #7 message.
SE_GENERIC_MODCACHE_ACTIVITY = BITMASK(25), //!< Triggered when status of modcache changes, args: #1 type, #2 entry number, for other args see `RoR::modCacheActivityType`

SE_GENERIC_TRUCK_LINKING_CHANGED = BITMASK(26), //!< Triggered when 2 actors become linked or unlinked via ties/hooks/ropes/slidenodes; args: #1 action (1=linked, 0=unlinked), #2 link type `ActorLinkingRequestType` (will be INVALID on savegame load or forced unlink when deleting actor) #3 master ActorInstanceID_t, #4 slave ActorInstanceID_t

SE_ALL_EVENTS = 0xffffffff,
SE_NO_EVENTS = 0

Expand Down
96 changes: 37 additions & 59 deletions source/main/physics/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,12 @@ Actor::~Actor()

void Actor::dispose()
{
// Handler for `MSG_SIM_DELETE_ACTOR_REQUESTED` message - should not be invoked otherwise.
// --------------------------------------------------------------------------------------

ROR_ASSERT(ar_state != ActorState::DISPOSED);

this->DisjoinInterActorBeams();
this->DisjoinInterActorBeams(); // OK to be invoked here - processing `MSG_SIM_DELETE_ACTOR_REQUESTED`.
ar_hooks.clear();
ar_ties.clear();
ar_node_to_beam_connections.clear();
Expand Down Expand Up @@ -1594,7 +1597,7 @@ void Actor::SyncReset(bool reset_position)

this->applyNodeBeamScales();

this->DisjoinInterActorBeams();
// Remove inter-actor beams (links from this actor to other):

for (auto& h : ar_hooks)
{
Expand All @@ -1605,15 +1608,15 @@ void Actor::SyncReset(bool reset_position)
h.hk_beam->bm_disabled = true;
h.hk_beam->bm_inter_actor = false;
h.hk_beam->L = (ar_nodes[0].AbsPosition - h.hk_hook_node->AbsPosition).length();
this->RemoveInterActorBeam(h.hk_beam);
App::GetGameContext()->GetActorManager()->RemoveInterActorBeam(h.hk_beam, ActorLinkingRequestType::HOOK_ACTION); // OK to be invoked here - SyncReset() - `processing MSG_SIM_MODIFY_ACTOR_REQUESTED`
}

for (auto& r : ar_ropes)
{
r.rp_locked = UNLOCKED;
r.rp_locked_ropable = nullptr;
r.rp_locked_actor = nullptr;
this->RemoveInterActorBeam(r.rp_beam);
App::GetGameContext()->GetActorManager()->RemoveInterActorBeam(r.rp_beam, ActorLinkingRequestType::ROPE_ACTION); // OK to be invoked here - SyncReset() - `processing MSG_SIM_MODIFY_ACTOR_REQUESTED`
}

for (auto& t : ar_ties)
Expand All @@ -1625,9 +1628,13 @@ void Actor::SyncReset(bool reset_position)
t.ti_beam->p2 = &ar_nodes[0];
t.ti_beam->bm_disabled = true;
t.ti_beam->bm_inter_actor = false;
this->RemoveInterActorBeam(t.ti_beam);
App::GetGameContext()->GetActorManager()->RemoveInterActorBeam(t.ti_beam, ActorLinkingRequestType::TIE_ACTION); // OK to be invoked here - SyncReset() - `processing MSG_SIM_MODIFY_ACTOR_REQUESTED`
}

// Remove any possible links from other actors to this actor.

this->DisjoinInterActorBeams(); // OK to be invoked here - SyncReset() - `processing MSG_SIM_MODIFY_ACTOR_REQUESTED`

for (auto& r : ar_ropables)
{
r.attached_ties = 0;
Expand Down Expand Up @@ -3282,54 +3289,18 @@ void Actor::updateVisual(float dt)
ar_hydro_elevator_command = autoelevator;
}

void Actor::AddInterActorBeam(beam_t* beam, ActorPtr a, ActorPtr b)
{
beam->bm_locked_actor = b;

auto pos = std::find(ar_inter_beams.begin(), ar_inter_beams.end(), beam);
if (pos == ar_inter_beams.end())
{
ar_inter_beams.push_back(beam);
}

std::pair<ActorPtr, ActorPtr> actor_pair(a, b);
App::GetGameContext()->GetActorManager()->inter_actor_links[beam] = actor_pair;

a->DetermineLinkedActors();
for (ActorPtr& actor : a->ar_linked_actors)
actor->DetermineLinkedActors();

b->DetermineLinkedActors();
for (ActorPtr& actor : b->ar_linked_actors)
actor->DetermineLinkedActors();
}

void Actor::RemoveInterActorBeam(beam_t* beam)
void Actor::DisjoinInterActorBeams()
{
auto pos = std::find(ar_inter_beams.begin(), ar_inter_beams.end(), beam);
if (pos != ar_inter_beams.end())
for (auto inter_actor_link: App::GetGameContext()->GetActorManager()->inter_actor_links)
{
ar_inter_beams.erase(pos);
}

auto it = App::GetGameContext()->GetActorManager()->inter_actor_links.find(beam);
if (it != App::GetGameContext()->GetActorManager()->inter_actor_links.end())
{
auto actor_pair = it->second;
App::GetGameContext()->GetActorManager()->inter_actor_links.erase(it);

actor_pair.first->DetermineLinkedActors();
for (ActorPtr& actor : actor_pair.first->ar_linked_actors)
actor->DetermineLinkedActors();

actor_pair.second->DetermineLinkedActors();
for (ActorPtr& actor : actor_pair.second->ar_linked_actors)
actor->DetermineLinkedActors();
beam_t* beam = inter_actor_link.first;
auto actor_pair = inter_actor_link.second;
if (actor_pair.first == this || actor_pair.second == this)
{
App::GetGameContext()->GetActorManager()->RemoveInterActorBeam(beam, ActorLinkingRequestType::INVALID); // OK to invoke synchronously; already handling `MSG_SIM_{MODIFY/DELETE}_ACTOR_REQUESTED`
}
}
}

void Actor::DisjoinInterActorBeams()
{
ar_inter_beams.clear();
auto inter_actor_links = &App::GetGameContext()->GetActorManager()->inter_actor_links;
for (auto it = inter_actor_links->begin(); it != inter_actor_links->end();)
Expand Down Expand Up @@ -3386,8 +3357,7 @@ void Actor::tieToggle(int group)
it->ti_beam->bm_disabled = true;
if (it->ti_locked_actor != this)
{
this->RemoveInterActorBeam(it->ti_beam);
// NOTE: updating skeletonview on the tied actors is now done in `SyncLinkedActors()`
App::GetGameContext()->GetActorManager()->RemoveInterActorBeam(it->ti_beam, ActorLinkingRequestType::TIE_ACTION); // OK to invoke here - tieToggle() - processing `MSG_SIM_ACTOR_LINKING_REQUESTED`
}
it->ti_locked_actor = nullptr;
}
Expand Down Expand Up @@ -3457,7 +3427,7 @@ void Actor::tieToggle(int group)
it->ti_locked_ropable->attached_ties++;
if (it->ti_beam->bm_inter_actor)
{
AddInterActorBeam(it->ti_beam, this, nearest_actor);
App::GetGameContext()->GetActorManager()->AddInterActorBeam(it->ti_beam, this, nearest_actor, ActorLinkingRequestType::TIE_ACTION); // OK to invoke here - tieToggle() - processing `MSG_SIM_ACTOR_LINKING_REQUESTED`
// NOTE: updating skeletonview on the tied actors is now done in `SyncLinkedActors()`
}
}
Expand Down Expand Up @@ -3489,8 +3459,7 @@ void Actor::ropeToggle(int group)
it->rp_locked_ropable->attached_ropes--;
if (it->rp_locked_actor != this)
{
this->RemoveInterActorBeam(it->rp_beam);
// NOTE: updating skeletonview on the unroped actors is now done in `SyncLinkedActors()`
App::GetGameContext()->GetActorManager()->RemoveInterActorBeam(it->rp_beam, ActorLinkingRequestType::ROPE_ACTION); // OK to invoke here - ropeToggle() - processing `MSG_SIM_ACTOR_LINKING_REQUESTED`
}
it->rp_locked_actor = nullptr;
it->rp_locked_ropable = nullptr;
Expand Down Expand Up @@ -3534,7 +3503,7 @@ void Actor::ropeToggle(int group)
it->rp_locked_ropable->attached_ropes++;
if (nearest_actor != this)
{
AddInterActorBeam(it->rp_beam, this, nearest_actor);
App::GetGameContext()->GetActorManager()->AddInterActorBeam(it->rp_beam, this, nearest_actor, ActorLinkingRequestType::ROPE_ACTION); // OK to invoke here - ropeToggle() - processing `MSG_SIM_ACTOR_LINKING_REQUESTED`
// NOTE: updating skeletonview on the roped up actor is now done in `SyncLinkedActors()`
}
}
Expand Down Expand Up @@ -3643,7 +3612,8 @@ void Actor::hookToggle(int group, HookAction mode, NodeNum_t mousenode /*=NODENU
it->hk_beam->bm_inter_actor = (it->hk_locked_actor != nullptr);
it->hk_beam->L = (it->hk_hook_node->AbsPosition - it->hk_lock_node->AbsPosition).length();
it->hk_beam->bm_disabled = false;
this->AddInterActorBeam(it->hk_beam, this, it->hk_locked_actor);
App::GetGameContext()->GetActorManager()->AddInterActorBeam(it->hk_beam, this, it->hk_locked_actor, ActorLinkingRequestType::HOOK_ACTION); // OK to invoke here - hookToggle() - processing `MSG_SIM_ACTOR_LINKING_REQUESTED`
// NOTE: updating skeletonview on the hooked actor is done in `SyncLinkedActors()`
}
}
}
Expand All @@ -3653,7 +3623,7 @@ void Actor::hookToggle(int group, HookAction mode, NodeNum_t mousenode /*=NODENU
{
// we unlock ropes immediatelly
it->hk_locked = UNLOCKED;
this->RemoveInterActorBeam(it->hk_beam);
App::GetGameContext()->GetActorManager()->RemoveInterActorBeam(it->hk_beam, ActorLinkingRequestType::HOOK_ACTION); // OK to invoke here - hookToggle() - processing `MSG_SIM_ACTOR_LINKING_REQUESTED`
if (it->hk_group <= -2)
{
it->hk_timer = it->hk_timer_preset; //timer reset for autolock nodes
Expand All @@ -3666,8 +3636,6 @@ void Actor::hookToggle(int group, HookAction mode, NodeNum_t mousenode /*=NODENU
it->hk_beam->L = (ar_nodes[0].AbsPosition - it->hk_hook_node->AbsPosition).length();
it->hk_beam->bm_disabled = true;
}

// NOTE: updating skeletonview on the (un)hooked actor is now done in `SyncLinkedActors()`
}
}

Expand Down Expand Up @@ -4621,3 +4589,13 @@ void Actor::removeWorkingTuneupDef()
{
m_working_tuneup_def = nullptr;
}

bool Actor::ownsBeam(beam_t* beam)
{
for (int i = 0; i < ar_num_beams; i++)
{
if (&ar_beams[i] == beam)
return true;
}
return false;
}
7 changes: 3 additions & 4 deletions source/main/physics/Actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class Actor : public RefCountingObject<Actor>
Ogre::Real getMinimalCameraRadius();
float GetFFbHydroForces() const { return m_force_sensors.out_hydros_forces; }
void UpdatePropAnimInputEvents();
bool ownsBeam(beam_t* beam);

// -------------------- Public data -------------------- //

Expand Down Expand Up @@ -302,7 +303,6 @@ class Actor : public RefCountingObject<Actor>
std::vector<Ogre::Vector3> ar_initial_node_positions;
std::vector<std::pair<float, float>> ar_initial_beam_defaults;
std::vector<wheeldetacher_t> ar_wheeldetachers;
ActorPtrVec ar_linked_actors; //!< Sim state; other actors linked using 'hooks'
std::vector<std::vector<int>> ar_node_to_node_connections;
std::vector<std::vector<int>> ar_node_to_beam_connections;
std::vector<Ogre::AxisAlignedBox> ar_collision_bounding_boxes; //!< smart bounding boxes, used for determining the state of an actor (every box surrounds only a subset of nodes)
Expand Down Expand Up @@ -436,6 +436,7 @@ class Actor : public RefCountingObject<Actor>
ActorState ar_state = ActorState::LOCAL_SIMULATED;
bool ar_physics_paused = false; //!< Valid with `ActorState::LOCAL_SIMULATED`; triggered by `EV_TRUCK_TOGGLE_PHYSICS`
bool ar_ongoing_reset = false; //!< Hack to prevent position/rotation creep during LiveRepair (a.k.a. interactive truck reset)
ActorPtrVec ar_linked_actors; //!< Other actors linked using 'hooks/ties/ropes/slidenodes'; see `MSG_SIM_ACTOR_LINKING_REQUESTED`

// Repair state
Ogre::Vector3 m_rotation_request_center = Ogre::Vector3::ZERO;
Expand Down Expand Up @@ -506,9 +507,7 @@ class Actor : public RefCountingObject<Actor>
void DetermineLinkedActors();
void RecalculateNodeMasses(Ogre::Real total); //!< Previously 'calc_masses2()'
void calcNodeConnectivityGraph();
void AddInterActorBeam(beam_t* beam, ActorPtr a, ActorPtr b);
void RemoveInterActorBeam(beam_t* beam);
void DisjoinInterActorBeams(); //!< Destroys all inter-actor beams which are connected with this actor
void DisjoinInterActorBeams(); //!< Helper for `MSG_` handlers, do not invoke by hand.
void autoBlinkReset(); //!< Resets the turn signal when the steering wheel is turned back.
void ResetAngle(float rot);
void calculateLocalGForces(); //!< Derive the truck local g-forces from the global ones
Expand Down
Loading

0 comments on commit 258ec18

Please sign in to comment.