From edd7e41a1773c2052b6e83c755fe765cb511da51 Mon Sep 17 00:00:00 2001 From: SokyranTheDragon Date: Mon, 2 Dec 2024 20:05:50 +0100 Subject: [PATCH] Fix Vehicle Framework issues with upgrade overlays 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. --- Source_Referenced/VehicleFramework.cs | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Source_Referenced/VehicleFramework.cs b/Source_Referenced/VehicleFramework.cs index 1c27660..e8926fe 100644 --- a/Source_Referenced/VehicleFramework.cs +++ b/Source_Referenced/VehicleFramework.cs @@ -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(); + // Needed for overlay fix. + PatchingUtilities.PatchLongEventMarkers(); + #endregion #region VehicleFramework @@ -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 FixHostOverlayInit(IEnumerable 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 } } \ No newline at end of file