Skip to content

Add RimThunder Core compat, fix 4 Vehicle Framework desync/hang bugs - #620

Open
Thaipho wants to merge 1 commit into
rwmt:masterfrom
Thaipho:feature/vf-rimthunder-fixes
Open

Add RimThunder Core compat, fix 4 Vehicle Framework desync/hang bugs#620
Thaipho wants to merge 1 commit into
rwmt:masterfrom
Thaipho:feature/vf-rimthunder-fixes

Conversation

@Thaipho

@Thaipho Thaipho commented Sep 5, 2026

Copy link
Copy Markdown

RimThunder Core (new)

No existing compat for rimthunder.core anywhere in the repo. Adds:

  • Isolates two unprotected ambient Rand sites in the projectile-interceptor system (CompAbilityEffect_ActiveProtectionSystem.CompTick, VehicleCompProjectileInterceptor.PostPostMake/PostExposeData)
  • Syncs RimThunder's own deploy-toggle comp (Motorization.CompDeployable), separate from Vehicle Framework's own CompVehicleTurrets deploy below

Vehicle Framework fixes

Two are unambiguous - zero existing coverage, and RefuelHalfway's own comment already flags the gap without ever closing it:

  • CompFueledTravel.RefuelHalfway (dev gizmo): calls unsynced ConsumeFuel(float.MaxValue) then synced, ADDITIVE Refuel(cap/2) - the issuing peer ends at cap/2, every other peer adds cap/2 onto its own untouched fuel value. Real fuel-value desync.
  • SyncVehicleArrivalAction: rewritten from a type-name + Activator.CreateInstance reconstruction (which only carried the vehicle's thingIDNumber, itself unused on read) to real exposable serialization, so ArrivalAction_LoadMap.arrivalModeDef, ArrivalAction_LandInMap.mapParent and AerialVehicleArrivalAction_StrafeMap.parent survive the trip. Confirmed live: with the old reconstruction, ArrivalAction_LoadMap. Arrived NREs on the null arrivalModeDef right after its long-event lambda finishes generating the map. Vanilla's LongEventHandler only sends MP's freeze-Unfreeze signal on that lambda's success path, so the exception leaves everyone stuck on "Waiting for other players" until someone quits (reported on Discord, laoune/Basilic, 2026-08-26: MP + Vehicle Framework + a RimThunder helicopter to another tile).

Two more are real per the currently Workshop-live Vehicle Framework build (3014915404) - confirmed via live 2-instance desync traces and by decompiling that exact installed DLL - but I want to flag a real uncertainty: several nearby comments in this file already say things like "CompGetGizmosExtra has no lambdas now" / "MultiplePawnFloatMenuOptions now uses OrderPawns method reference, no lambda to sync", and this file's Vehicle Framework section hasn't been touched since 2026-03-18. That's consistent with either the reference build this file was written against having since changed (lambda ordinals shift silently between Vehicle Framework builds - CompGetGizmosExtra's own comment shows this has happened here before), or with something being version-specific enough that it doesn't reproduce for you. Both registrations are defensive (try/catch or a documented no-op-on-mismatch expectation), so a wrong ordinal on a different build should fail safe rather than break anything functional:

  • CompVehicleTurrets deploy toggle: the "cached field (deployToggle), no lambda to register" comment is about CompGetGizmosExtra specifically - the toggleAction closure that flips Deployed still exists, compiled inside RecacheGizmos (where deployToggle is built) instead, and was never registered anywhere. Only the clicking peer's vehicle ever deployed; Deployed drives CanMove/TurretsAligned/ DeploymentSatisfied and (with RimThunder) LaunchRestriction_WingDeployed.
  • VehiclePawn.GetGizmos: 9 more state-mutating dev-only action lambdas (Teleport/DestroyComponent/DamageComponent/ExplodeComponent/ HealAllComponents/GiveRandomPawnMentalState/DownRandomPawn/ KillRandomPawn/ToggleLoitering) were unregistered - instant desync in dev mode if any is clicked.
  • AerialVehicleAbandonOrBanishHelper.TryAbandonOrBanishViaInterface (Thing, AerialVehicleInFlight): registered ordinal 0, which resolves to the bool(Pawn) LINQ predicate, not the void confirm action (ordinal 1) that actually removes the abandoned item from its owner's inventory and destroys it. The sibling (TransferableImmutable, ...) overload numbers these the opposite way, which is what made this easy to miss. The pawn-banish branch is already redirected by ReplaceVanillaBanishDialog/SyncedBanishPawn above, so this only affects the plain-item abandon path.

Both projects (Source/Multiplayer_Compat.csproj and Source_Referenced/Multiplayer_Compat_Referenced.csproj) build clean.

## RimThunder Core (new)

No existing compat for rimthunder.core anywhere in the repo. Adds:
- Isolates two unprotected ambient Rand sites in the projectile-interceptor
  system (CompAbilityEffect_ActiveProtectionSystem.CompTick,
  VehicleCompProjectileInterceptor.PostPostMake/PostExposeData)
- Syncs RimThunder's own deploy-toggle comp (Motorization.CompDeployable),
  separate from Vehicle Framework's own CompVehicleTurrets deploy below

## Vehicle Framework fixes

Two are unambiguous - zero existing coverage, and RefuelHalfway's own
comment already flags the gap without ever closing it:

- CompFueledTravel.RefuelHalfway (dev gizmo): calls unsynced
  ConsumeFuel(float.MaxValue) then synced, ADDITIVE Refuel(cap/2) - the
  issuing peer ends at cap/2, every other peer adds cap/2 onto its own
  untouched fuel value. Real fuel-value desync.
- SyncVehicleArrivalAction: rewritten from a type-name +
  Activator.CreateInstance reconstruction (which only carried the
  vehicle's thingIDNumber, itself unused on read) to real exposable
  serialization, so ArrivalAction_LoadMap.arrivalModeDef,
  ArrivalAction_LandInMap.mapParent and
  AerialVehicleArrivalAction_StrafeMap.parent survive the trip.
  Confirmed live: with the old reconstruction, ArrivalAction_LoadMap.
  Arrived NREs on the null arrivalModeDef right after its long-event
  lambda finishes generating the map. Vanilla's LongEventHandler only
  sends MP's freeze-Unfreeze signal on that lambda's success path, so
  the exception leaves everyone stuck on "Waiting for other players"
  until someone quits (reported on Discord, laoune/Basilic, 2026-08-26:
  MP + Vehicle Framework + a RimThunder helicopter to another tile).

Two more are real per the currently Workshop-live Vehicle Framework build
(3014915404) - confirmed via live 2-instance desync traces and by
decompiling that exact installed DLL - but I want to flag a real
uncertainty: several nearby comments in this file already say things
like "CompGetGizmosExtra has no lambdas now" / "MultiplePawnFloatMenuOptions
now uses OrderPawns method reference, no lambda to sync", and this file's
Vehicle Framework section hasn't been touched since 2026-03-18. That's
consistent with either the reference build this file was written against
having since changed (lambda ordinals shift silently between Vehicle
Framework builds - CompGetGizmosExtra's own comment shows this has
happened here before), or with something being version-specific enough
that it doesn't reproduce for you. Both registrations are defensive
(try/catch or a documented no-op-on-mismatch expectation), so a wrong
ordinal on a different build should fail safe rather than break anything
functional:

- CompVehicleTurrets deploy toggle: the "cached field (deployToggle),
  no lambda to register" comment is about CompGetGizmosExtra
  specifically - the toggleAction closure that flips Deployed still
  exists, compiled inside RecacheGizmos (where deployToggle is built)
  instead, and was never registered anywhere. Only the clicking peer's
  vehicle ever deployed; Deployed drives CanMove/TurretsAligned/
  DeploymentSatisfied and (with RimThunder) LaunchRestriction_WingDeployed.
- VehiclePawn.GetGizmos: 9 more state-mutating dev-only action lambdas
  (Teleport/DestroyComponent/DamageComponent/ExplodeComponent/
  HealAllComponents/GiveRandomPawnMentalState/DownRandomPawn/
  KillRandomPawn/ToggleLoitering) were unregistered - instant desync in
  dev mode if any is clicked.
- AerialVehicleAbandonOrBanishHelper.TryAbandonOrBanishViaInterface
  (Thing, AerialVehicleInFlight): registered ordinal 0, which resolves
  to the bool(Pawn) LINQ predicate, not the void confirm action
  (ordinal 1) that actually removes the abandoned item from its owner's
  inventory and destroys it. The sibling (TransferableImmutable, ...)
  overload numbers these the opposite way, which is what made this easy
  to miss. The pawn-banish branch is already redirected by
  ReplaceVanillaBanishDialog/SyncedBanishPawn above, so this only
  affects the plain-item abandon path.

Both projects (Source/Multiplayer_Compat.csproj and
Source_Referenced/Multiplayer_Compat_Referenced.csproj) build clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant