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.