diff --git a/References/VanillaGravshipExpanded.dll b/References/VanillaGravshipExpanded.dll index a688431e..c3d840ab 100755 Binary files a/References/VanillaGravshipExpanded.dll and b/References/VanillaGravshipExpanded.dll differ diff --git a/Source/Mods/VanillaExpandedFramework.cs b/Source/Mods/VanillaExpandedFramework.cs index 0762ac25..1dab9a4f 100644 --- a/Source/Mods/VanillaExpandedFramework.cs +++ b/Source/Mods/VanillaExpandedFramework.cs @@ -46,7 +46,6 @@ public VanillaExpandedFramework(ModContentPack mod) (PatchWeatherOverlayEffects, "Weather Overlay Effects", false), (PatchExtraPregnancyApproaches, "Extra Pregnancy Approaches", false), (PatchWorkGiverDeliverResources, "Building stuff requiring non-construction skill", false), - (PatchStaticCaches, "Static caches", false), (PatchGraphicCustomizationDialog, "Graphic Customization Dialog", true), (PatchDraftedAi, "Drafted AI", true), (PatchMapObjectGeneration, "Thing spawning on map generation (ObjectSpawnsDef)", false), @@ -1802,18 +1801,6 @@ private static void PostIsConstruction(WorkGiver w, ref bool __result) #endregion - #region Caches - - private static void PatchStaticCaches() - { - // TODO: Go through Vanilla Expanded Framework's VanillaGenesExpanded.StaticCollectionsClass and clean some of those on join. - // While not critical for fixing MP desyncs, it should help with RAM usage as many of those have data unique to a specific - // game, and leaving it will just leave garbage data. In the context of MP it could be especially useful in case of - // frequent (unrelated) desyncs, as the players joining in would gain more and more garbage data each time they join. - } - - #endregion - #region Graphic Customization Dialog // Dialog_GraphicCustomization diff --git a/Source/Mods/VanillaGravshipExpanded2.cs b/Source/Mods/VanillaGravshipExpanded2.cs new file mode 100644 index 00000000..738aa2b5 --- /dev/null +++ b/Source/Mods/VanillaGravshipExpanded2.cs @@ -0,0 +1,68 @@ +using HarmonyLib; +using Multiplayer.API; +using RimWorld; +using Verse; + +namespace Multiplayer.Compat; + +/// Vanilla Gravship Expanded 2 by Oskar Potocki and the Vanilla Expanded team +/// +/// +[MpCompatFor("vanillaexpanded.gravship2")] +public class VanillaGravshipExpanded2 +{ + public VanillaGravshipExpanded2(ModContentPack mod) + { + // Patching these methods can initialize DefOf caches and load gizmo textures. + LongEventHandler.ExecuteWhenFinished(LatePatch); + } + + private static void LatePatch() + { + var worldComponentType = AccessTools.TypeByName("VanillaGravshipExpanded2.WorldComponent_GravshipCombat"); + var warpodType = AccessTools.TypeByName("VanillaGravshipExpanded2.CompLaunchable_Warpod"); + var vacuumLightType = AccessTools.TypeByName("VanillaGravshipExpanded2.CompVacuumWarningLight"); + var escapePodType = AccessTools.TypeByName("VanillaGravshipExpanded2.CompEscapePod"); + + // Escape pods + MP.RegisterSyncMethod(AccessTools.TypeByName("VanillaGravshipExpanded2.VGE2_MapComponent"), "EvacuationActive"); + MP.RegisterSyncMethod(escapePodType, "ClaimIfNeeded"); + MpCompat.RegisterLambdaMethod(escapePodType, nameof(ThingComp.CompGetGizmosExtra), 1); + MpCompat.RegisterLambdaDelegate(escapePodType, nameof(ThingComp.CompFloatMenuOptions), 0, 2, 3); + + // Vacuum warning lights + MP.RegisterSyncMethod(vacuumLightType, "ConcerningVacuumLevel"); + MP.RegisterSyncMethod(vacuumLightType, "EvacuatePawns"); + + // Salvager tribute dialog + MP.RegisterSyncMethod(worldComponentType, "PayTribute"); + MP.RegisterSyncMethod(worldComponentType, "SpawnActiveWarplatform"); + MpCompat.RegisterLambdaDelegate(worldComponentType, "ShowTributeDemandDialog", 0); + + // Salvager station comms job + MpCompat.RegisterLambdaDelegate( + "VanillaGravshipExpanded2.Building_CommsConsole_GetFloatMenuOptions_Patch", "Postfix", 0); + + MP.RegisterSyncMethod(warpodType, "LaunchWarpodTo"); + MP.RegisterSyncMethod(warpodType, "LaunchHellpodTo"); + + // ProcessInput creates the map directly; MP reconstructs the designator and ignores its unused Event. + MP.RegisterSyncMethod(AccessTools.TypeByName("VanillaGravshipExpanded2.Designator_GenerateEmptyOrbit"), nameof(Designator.ProcessInput)) + .SetContext(SyncContext.CurrentMap); + + // Developer gizmos + // These callbacks capture no comp; their target is the compiler-generated singleton. + MpCompat.RegisterLambdaDelegate( + "VanillaGravshipExpanded2.CompPowerEmergencyGravshipGenerator", nameof(ThingComp.CompGetGizmosExtra), 0, 1, 2) + .SetDebugOnly(); + MpCompat.RegisterLambdaMethod( + "VanillaGravshipExpanded2.CompGravshipShieldGeneratorWithHeat", nameof(ThingComp.CompGetGizmosExtra), 0, 1, 2) + .SetDebugOnly(); + MpCompat.RegisterLambdaMethod( + "VanillaGravshipExpanded2.CompPower_InputOnlyBattery", nameof(ThingComp.CompGetGizmosExtra), 0, 1, 2) + .SetDebugOnly(); + MpCompat.RegisterLambdaMethod( + "VanillaGravshipExpanded2.CompApparelVerbOwner_Oxygen", "CompGetWornGizmosExtra", 0) + .SetDebugOnly(); + } +} diff --git a/Source_Referenced/VanillaGravshipExpanded.cs b/Source_Referenced/VanillaGravshipExpanded.cs index c25f73ef..54d3c4b8 100644 --- a/Source_Referenced/VanillaGravshipExpanded.cs +++ b/Source_Referenced/VanillaGravshipExpanded.cs @@ -26,8 +26,8 @@ class VanillaGravshipExpanded // Flag to preserve VGE state during our SyncedGravshipTileSelected flow private static bool inSyncedTileSelectedFlow; - // Gizmo_OxygenProvider sync field (#880 workaround) - private static ISyncField oxygenTargetValuePctField; + // Gizmo_OxygenProvider refill threshold + private static ISyncField oxygenRechargeThresholdField; // VGE launch flow — MP internals (not publicized, reached via reflection) private static Action closeGravshipSession; @@ -286,17 +286,10 @@ private static void LatePatch() #region Gizmo_OxygenProvider { - MP.RegisterSyncMethod(AccessTools.PropertySetter(typeof(CompApparelOxygenProvider), nameof(CompApparelOxygenProvider.AutomaticRechargeEnabled))); + MP.RegisterSyncMethod(typeof(CompApparelOxygenProvider), nameof(CompApparelOxygenProvider.AutomaticRechargeEnabled)); - oxygenTargetValuePctField = MP.RegisterSyncField(typeof(Gizmo_OxygenProvider), "targetValuePct").SetBufferChanges(); - - // MP issue #880 workaround: RegisterSyncField resolves targetType via ReflectedType, - // which returns Gizmo_Slider (the base declaring "targetValuePct"), not Gizmo_OxygenProvider. - // Rewrite the private targetType field so Watch() matches our subclass instance. - AccessTools.Field(oxygenTargetValuePctField.GetType(), "targetType") - .SetValue(oxygenTargetValuePctField, typeof(Gizmo_OxygenProvider)); - - MP.RegisterSyncWorker(SyncOxygenGizmo, typeof(Gizmo_OxygenProvider)); + // The released mod recreates this gizmo; sync its persistent comp instead. + oxygenRechargeThresholdField = MP.RegisterSyncField(typeof(CompApparelOxygenProvider), nameof(CompApparelOxygenProvider.rechargeAtCharges)).SetBufferChanges(); MpCompat.harmony.Patch( AccessTools.DeclaredMethod(typeof(Gizmo_Slider), nameof(Gizmo_Slider.GizmoOnGUI)), @@ -611,7 +604,9 @@ private static void PreOxygenGizmoOnGUI(Gizmo_Slider __instance) return; MP.WatchBegin(); - oxygenTargetValuePctField.Watch(__instance); + oxygenRechargeThresholdField.Watch(((Gizmo_OxygenProvider)__instance).oxygenProvider); + // Refresh the vanilla slider cache after Watch restores any pending local value. + __instance.targetValuePct = ((Gizmo_OxygenProvider)__instance).Target; } private static void PostOxygenGizmoOnGUI(Gizmo_Slider __instance) @@ -622,19 +617,6 @@ private static void PostOxygenGizmoOnGUI(Gizmo_Slider __instance) MP.WatchEnd(); } - private static void SyncOxygenGizmo(SyncWorker sync, ref Gizmo_Slider gizmo) - { - if (sync.isWriting) - { - sync.Write(((Gizmo_OxygenProvider)gizmo).oxygenProvider); - } - else - { - var comp = (CompApparelOxygenProvider)sync.Read(); - gizmo = comp.oxygenConfigurationGizmo; - } - } - /// /// Intercept the paste color gizmo action. ColorClipboard is per-client /// state, so we capture the color value and sync per-barrier.