Skip to content

Commit

Permalink
Fix Vehicle Framework issues with upgrade overlays (#500)
Browse files Browse the repository at this point in the history
When loading a game where a vehicle has an upgrade that applies an overlay to a vehicle, the overlay initialization would fail for the host causing issues and desyncs.

This should fix all of those issues by patching the method and forcing it to run inside a `LongEventHandler.ExecuteWhenFinished` call, delaying it until it's safe to run it.
  • Loading branch information
SokyranTheDragon authored Dec 3, 2024
1 parent 60f95c6 commit 8b291fb
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions Source_Referenced/VehicleFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ static ISyncMethod TrySyncDeclaredMethod(Type targetType, string targetMethodNam
// so this exists here as an extra safety in case those ever get removed later on.
MpCompatPatchLoader.LoadPatch<VehicleFramework>();

// Needed for overlay fix.
PatchingUtilities.PatchLongEventMarkers();

#endregion

#region VehicleFramework
Expand Down Expand Up @@ -2602,5 +2605,44 @@ private static void RestoreLocalRoadType()
}

#endregion

#region Upgrade Fixes

private static bool ShouldExecuteWhenFinished()
{
// If not on main thread we always need to
// execute when finished, both in MP and in SP.
if (!UnityData.IsInMainThread)
return false;
// If main thread and not in MP, leave current behavior.
if (!MP.IsInMultiplayer)
return true;

// If in MP and on main thread, ensure that we call it in
// ExecuteWhenFinished during game loading as it's
// unsafe there and will cause errors for the host.
// AllowedToRunLongEvents is false only for host during
// loading
return PatchingUtilities.AllowedToRunLongEvents;
}

[MpCompatTranspiler(typeof(UpgradeNode), nameof(UpgradeNode.AddOverlays))]
private static IEnumerable<CodeInstruction> FixHostOverlayInit(IEnumerable<CodeInstruction> instr, MethodBase baseMethod)
{
// The mod fails to initialize the overlays for the host when (re)loading the game.
// It fails to initialize the second time as the initialization method is not called
// inside "LongEventHandler.ExecuteWhenFinished" call (this only happens when not on
// the main thread, the code checks UnityData.IsInMainThread). The issue is that likely
// due to the way MP handles loading some of the data required for overlay initialization
// is not yet initialized. We need to ensure that the execution is delayed until it's
// safe to initialize them.

var target = AccessTools.DeclaredPropertyGetter(typeof(UnityData), nameof(UnityData.IsInMainThread));
var replacement = MpMethodUtil.MethodOf(ShouldExecuteWhenFinished);

return instr.ReplaceMethod(target, replacement, baseMethod, expectedReplacements: 1);
}

#endregion
}
}

0 comments on commit 8b291fb

Please sign in to comment.