public VanillaFactionsVikings(ModContentPack mod) { LongEventHandler.ExecuteWhenFinished(LatePatch); // Debug stuff var type = AccessTools.TypeByName("VFEV.Apiary"); MpCompat.RegisterSyncMethodsByIndex(type, "<GetGizmos>", 0, 1).Do(m => m.SetDebugOnly()); // This method seems unused... But I guess it's better to be safe than sorry. PatchingUtilities.PatchSystemRand(AccessTools.Method(type, "ResetTend"), false); }
public static void LatePatch() { var type = AccessTools.TypeByName("VFEMech.MissileSilo"); MP.RegisterSyncMethod(type, "StartFire"); MP.RegisterSyncMethod(type, "ConfigureNewTarget"); foreach (var method in MpCompat.RegisterSyncMethodsByIndex(type, "<GetGizmos>", 2, 3)) { method.SetDebugOnly(); } type = AccessTools.TypeByName("VFE.Mechanoids.Buildings.Building_AutoPlant"); // Methods b__8_0, b__8_2, b__8_3. They are the first 3 methods in the file. The b__8_1 is the last one, and thus has index 3. MpCompat.RegisterSyncMethodsByIndex(type, "<GetGizmos>", 0, 1, 2); }
public VanillaExpandedFramework(ModContentPack mod) { var type = AccessTools.TypeByName("ItemProcessor.Building_ItemProcessor"); // _1, _5 and _7 are used to check if gizmo should be enabled, so we don't sync them MpCompat.RegisterSyncMethodsByIndex(type, "<GetGizmos>", 0, 2, 3, 4, 6, 8, 9, 10); type = AccessTools.TypeByName("ItemProcessor.Command_SetQualityList"); MP.RegisterSyncWorker <Command>(SyncCommandWithBuilding, type, shouldConstruct: true); MpCompat.RegisterSyncMethodsByIndex(type, "<ProcessInput>", Enumerable.Range(0, 8).ToArray()); type = AccessTools.TypeByName("ItemProcessor.Command_SetOutputList"); MP.RegisterSyncWorker <Command>(SyncCommandWithBuilding, type, shouldConstruct: true); MP.RegisterSyncMethod(type, "TryConfigureIngredientsByOutput"); // Keep an eye on this in the future, seems like something the devs could combine into a single class at some point foreach (var ingredientNumber in new[] { "First", "Second", "Third", "Fourth" }) { type = AccessTools.TypeByName($"ItemProcessor.Command_Set{ingredientNumber}ItemList"); MP.RegisterSyncWorker <Command>(SyncSetIngredientCommand, type, shouldConstruct: true); MP.RegisterSyncMethod(type, $"TryInsert{ingredientNumber}Thing"); MpCompat.RegisterSyncMethodsByIndex(type, "<ProcessInput>", 0); } // AddHediff desyncs with Arbiter, but seems fine without it PatchingUtilities.PatchPushPopRand("VanillaCookingExpanded.Thought_Hediff:MoodOffset"); type = AccessTools.TypeByName("VFECore.CompPawnDependsOn"); MpCompat.RegisterSyncMethodByIndex(type, "<CompGetGizmosExtra>", 0).SetDebugOnly(); type = AccessTools.TypeByName("VanillaFurnitureExpanded.CompConfigurableSpawner"); MpCompat.RegisterSyncMethodByIndex(type, "<CompGetGizmosExtra>", 0).SetDebugOnly(); type = AccessTools.TypeByName("VanillaFurnitureExpanded.Command_SetItemsToSpawn"); MP.RegisterSyncDelegate(type, "<>c__DisplayClass2_0", "<ProcessInput>b__1"); type = AccessTools.TypeByName("VanillaFurnitureExpanded.CompRockSpawner"); MpCompat.RegisterSyncMethodByIndex(type, "<CompGetGizmosExtra>", 0); type = AccessTools.TypeByName("VanillaFurnitureExpanded.Command_SetStoneType"); setStoneBuildingField = AccessTools.Field(type, "building"); MpCompat.RegisterSyncMethodByIndex(type, "<ProcessInput>", 0); MP.RegisterSyncWorker <Command>(SyncSetStoneTypeCommand, type, shouldConstruct: true); MP.RegisterSyncDelegate(type, "<>c__DisplayClass2_0", "<ProcessInput>b__1"); }
public VanillaFactionsVikings(ModContentPack mod) { LongEventHandler.ExecuteWhenFinished(LatePatch); // Debug commands, other stuff var type = AccessTools.TypeByName("VFEV.Building_MeadBarrel"); MpCompat.RegisterSyncMethodByIndex(type, "<GetGizmos>", 0).SetDebugOnly(); type = AccessTools.TypeByName("VFEV.Apiary"); foreach (var gizmo in MpCompat.RegisterSyncMethodsByIndex(type, "<GetGizmos>", 0, 1)) { gizmo.SetDebugOnly(); } // This method seems unused... But I guess it's better to be safe than sorry. PatchingUtilities.PatchSystemRand(AccessTools.Method(type, "ResetTend"), false); }
public VanillaFishingExpanded(ModContentPack mod) { // RNG fix { PatchingUtilities.PatchSystemRandCtor("VCE_Fishing.JobDriver_Fish", false); PatchingUtilities.PatchPushPopRand("VCE_Fishing.JobDriver_Fish:SelectFishToCatch"); } // Gizmo (select fish size to catch) { commandType = AccessTools.TypeByName("VCE_Fishing.Command_SetFishList"); mapField = AccessTools.Field(commandType, "map"); fishingZoneField = AccessTools.Field(commandType, "zone"); MpCompat.RegisterSyncMethodsByIndex(commandType, "<ProcessInput>", Enumerable.Range(0, 3).ToArray()); MP.RegisterSyncWorker <Command>(SyncFishingZoneChange, commandType, shouldConstruct: false); } }
public AlphaBiomes(ModContentPack mod) { var type = AccessTools.TypeByName("AlphaBiomes.Command_SetStoneType"); buildingField = AccessTools.Field(type, "building"); // SyncWorker needed as the <ProcessInput> methods require syncing of the `building` field MP.RegisterSyncWorker <Command>(SyncSetStoneType, type, shouldConstruct: true); MpCompat.RegisterSyncMethodsByIndex(type, "<ProcessInput>", Enumerable.Range(0, 6).ToArray()); var rngFixMethods = new[] { "AlphaBiomes.CompGasProducer:CompTick", "AlphaBiomes.TarSprayer:SteamSprayerTick", "AlphaBiomes.GameCondition_AcidRain:DoCellSteadyEffects", }; PatchingUtilities.PatchSystemRand(AccessTools.Constructor(AccessTools.TypeByName("AlphaBiomes.CompGasProducer")), false); PatchingUtilities.PatchPushPopRand(rngFixMethods); }
public VanillaFactionsInsectoid(ModContentPack mod) { // Gizmos { // These two methods aren't patched, but supposedly the teleporter isn't included in the mod right now due to being bugged // Working on them could be problematic, as it seems that they reimplement (or at least used to reimplement) vanilla caravan forming screen completely from scratch // VFEI.Comps.ItemComps.CompArchotechTeleporter // VFEI.Comps.ItemComps.CompCustomTransporter var type = AccessTools.TypeByName("InsectoidBioengineering.Building_BioengineeringIncubator"); MpCompat.RegisterSyncMethodsByIndex(type, "<GetGizmos>", 0, 1, 2, 3); // Keep an eye on this in the future, seems like something the devs might combine into a single class at some point foreach (var geneNumber in new[] { "First", "Second", "Third" }) { type = AccessTools.TypeByName($"InsectoidBioengineering.Command_Set{geneNumber}GenomeList"); MP.RegisterSyncWorker <Command>(SyncSetGenomeCommand, type, shouldConstruct: true); MP.RegisterSyncMethod(AccessTools.Method(type, $"TryInsert{geneNumber}Genome")); } } // RNG { var constructors = new[] { "InsectoidBioengineering.Building_BioengineeringIncubator", //"VFEI.CompFilthProducer", }; PatchingUtilities.PatchSystemRandCtor(constructors, false); var methods = new[] { "VFEI.CompTargetEffect_Tame:RandomNumber", }; PatchingUtilities.PatchSystemRand(methods); } }
public VanillaExpandedFramework(ModContentPack mod) { var type = AccessTools.TypeByName("ItemProcessor.Building_ItemProcessor"); // _1 and _5 are used to check if gizmo should be enabled, so we don't sync them MpCompat.RegisterSyncMethodsByIndex(type, "<GetGizmos>", 0, 2, 3, 4, 6, 7); type = AccessTools.TypeByName("ItemProcessor.Command_SetQualityList"); itemProcessorField = AccessTools.Field(type, "building"); MP.RegisterSyncWorker <Command>(SyncSetTargetQuality, type, shouldConstruct: true); MpCompat.RegisterSyncMethodsByIndex(type, "<ProcessInput>", Enumerable.Range(0, 8).ToArray()); // Keep an eye on this in the future, seems like something the devs could combine into a single class at some point foreach (var ingredientNumber in new[] { "First", "Second", "Third" }) { type = AccessTools.TypeByName($"ItemProcessor.Command_Set{ingredientNumber}ItemList"); MP.RegisterSyncWorker <Command>(SyncSetIngredientCommand, type, shouldConstruct: true); MP.RegisterSyncMethod(type, $"TryInsert{ingredientNumber}Thing"); MpCompat.RegisterSyncMethodsByIndex(type, "<ProcessInput>", 0); } // AddHediff desyncs with Arbiter, but seems fine without it PatchingUtilities.PatchPushPopRand("VanillaCookingExpanded.Thought_Hediff:MoodOffset"); }
public VanillaExpandedFramework(ModContentPack mod) { // ItemProcessor { var type = AccessTools.TypeByName("ItemProcessor.Building_ItemProcessor"); // _1, _5 and _7 are used to check if gizmo should be enabled, so we don't sync them MpCompat.RegisterSyncMethodsByIndex(type, "<GetGizmos>", 0, 2, 3, 4, 6, 8, 9, 10); type = AccessTools.TypeByName("ItemProcessor.Command_SetQualityList"); MP.RegisterSyncWorker <Command>(SyncCommandWithBuilding, type, shouldConstruct: true); MpCompat.RegisterSyncMethodsByIndex(type, "<ProcessInput>", Enumerable.Range(0, 8).ToArray()); type = AccessTools.TypeByName("ItemProcessor.Command_SetOutputList"); MP.RegisterSyncWorker <Command>(SyncCommandWithBuilding, type, shouldConstruct: true); MP.RegisterSyncMethod(type, "TryConfigureIngredientsByOutput"); // Keep an eye on this in the future, seems like something the devs could combine into a single class at some point foreach (var ingredientNumber in new[] { "First", "Second", "Third", "Fourth" }) { type = AccessTools.TypeByName($"ItemProcessor.Command_Set{ingredientNumber}ItemList"); MP.RegisterSyncWorker <Command>(SyncSetIngredientCommand, type, shouldConstruct: true); MP.RegisterSyncMethod(type, $"TryInsert{ingredientNumber}Thing"); MpCompat.RegisterSyncMethodsByIndex(type, "<ProcessInput>", 0); } } // Vanilla Cooking Expanded { // AddHediff desyncs with Arbiter, but seems fine without it PatchingUtilities.PatchPushPopRand("VanillaCookingExpanded.Thought_Hediff:MoodOffset"); } // VFE Core { var type = AccessTools.TypeByName("VFECore.CompPawnDependsOn"); MpCompat.RegisterSyncMethodByIndex(type, "<CompGetGizmosExtra>", 0).SetDebugOnly(); } // Vanilla Furniture Expanded { var type = AccessTools.TypeByName("VanillaFurnitureExpanded.CompConfigurableSpawner"); MpCompat.RegisterSyncMethodByIndex(type, "<CompGetGizmosExtra>", 0).SetDebugOnly(); type = AccessTools.TypeByName("VanillaFurnitureExpanded.Command_SetItemsToSpawn"); MP.RegisterSyncDelegate(type, "<>c__DisplayClass2_0", "<ProcessInput>b__1"); type = AccessTools.TypeByName("VanillaFurnitureExpanded.CompRockSpawner"); MpCompat.RegisterSyncMethodByIndex(type, "<CompGetGizmosExtra>", 0); type = AccessTools.TypeByName("VanillaFurnitureExpanded.Command_SetStoneType"); setStoneBuildingField = AccessTools.Field(type, "building"); MpCompat.RegisterSyncMethodByIndex(type, "<ProcessInput>", 0); MP.RegisterSyncWorker <Command>(SyncSetStoneTypeCommand, type, shouldConstruct: true); MP.RegisterSyncDelegate(type, "<>c__DisplayClass2_0", "<ProcessInput>b__1"); } // Vanilla Faction Mechanoids { var type = AccessTools.TypeByName("VFE.Mechanoids.CompMachineChargingStation"); MP.RegisterSyncDelegate(type, "<>c", "<CompGetGizmosExtra>b__21_1", Array.Empty <string>()).SetContext(SyncContext.MapSelected); MP.RegisterSyncDelegate(type, "<>c", "<CompGetGizmosExtra>b__21_6", Array.Empty <string>()).SetContext(SyncContext.MapSelected); MP.RegisterSyncDelegate(type, "<>c__DisplayClass21_0", "<CompGetGizmosExtra>b__4"); } // AnimalBehaviours { // RNG PatchingUtilities.PatchSystemRand("AnimalBehaviours.DamageWorker_ExtraInfecter:ApplySpecialEffectsToPart", false); PatchingUtilities.PatchSystemRandCtor(new[] { "AnimalBehaviours.CompAnimalProduct", "AnimalBehaviours.CompGasProducer" }, false); // Gizmos // Might not work, as I could not find a mod that uses this to test this var type = AccessTools.TypeByName("AnimalBehaviours.CompDestroyThisItem"); MP.RegisterSyncMethod(type, "SetObjectForDestruction"); MP.RegisterSyncMethod(type, "CancelObjectForDestruction"); } // MVCF (Multi Verb Combat Framework) { var type = AccessTools.TypeByName("MVCF.WorldComponent_MVCF"); mvcfGetWorldCompMethod = AccessTools.Method(type, "GetComp"); mvcfAllManagersListField = AccessTools.Field(type, "allManagers"); mvcfManagersTableField = AccessTools.Field(type, "managers"); MP.RegisterSyncMethod(typeof(VanillaExpandedFramework), nameof(SyncedInitVerbManager)); MpCompat.harmony.Patch(AccessTools.Method(type, "GetManagerFor"), prefix: new HarmonyMethod(typeof(VanillaExpandedFramework), nameof(GetManagerForPrefix))); type = AccessTools.TypeByName("MVCF.VerbManager"); MP.RegisterSyncWorker <object>(SyncVerbManager, type, isImplicit: true); mvcfVerbManagerCtor = AccessTools.Constructor(type); mvcfInitializeManagerMethod = AccessTools.Method(type, "Initialize"); mvcfPawnGetter = AccessTools.PropertyGetter(type, "Pawn"); mvcfVerbsField = AccessTools.Field(type, "verbs"); var weakReferenceType = typeof(System.WeakReference <>).MakeGenericType(new[] { type }); weakReferenceCtor = AccessTools.FirstConstructor(weakReferenceType, ctor => ctor.GetParameters().Count() == 1); var conditionalWeakTableType = typeof(System.Runtime.CompilerServices.ConditionalWeakTable <,>).MakeGenericType(new[] { typeof(Pawn), type }); conditionalWeakTableAddMethod = AccessTools.Method(conditionalWeakTableType, "Add"); conditionalWeakTableTryGetValueMethod = AccessTools.Method(conditionalWeakTableType, "TryGetValue"); type = AccessTools.TypeByName("MVCF.ManagedVerb"); mvcfManagerVerbManagerField = AccessTools.Field(type, "man"); MP.RegisterSyncWorker <object>(SyncManagedVerb, type, isImplicit: true); // Seems like selecting the Thing that holds the verb inits some stuff, so we need to set the context MP.RegisterSyncMethod(type, "Toggle"); type = AccessTools.TypeByName("MVCF.Harmony.Gizmos"); MP.RegisterSyncDelegate(type, "<>c__DisplayClass5_0", "<GetGizmos_Postfix>b__1"); // Fire at will MP.RegisterSyncDelegate(type, "<>c__DisplayClass6_0", "<GetAttackGizmos_Postfix>b__4"); // Interrupt Attack MP.RegisterSyncDelegate(type, "<>c__DisplayClass7_0", "<Pawn_GetGizmos_Postfix>b__0"); // Also interrupt Attack } }
public DragonsDescent(ModContentPack mod) { // Incubator { var type = AccessTools.TypeByName("DD.CompEggIncubator"); var methods = MpCompat.RegisterSyncMethodsByIndex(type, "<CompGetGizmosExtra>", 1, 2, 3, 4); foreach (var method in methods.Skip(1)) // All but the first one are debug-only gizmos { method.SetDebugOnly(); } type = AccessTools.TypeByName("DD.CompProperties_EggIncubator"); MP.RegisterSyncDelegate(type, "<>c__DisplayClass7_0", "<CreateGizmo>b__0"); } // Abilities { var type = AccessTools.TypeByName("DD.AbilityComp_AbilityControl"); var gizmoActionMethod = MpCompat.MethodByIndex(type, "<get_Gizmo>", 1); MP.RegisterSyncMethod(gizmoActionMethod); // Toggle active MpCompat.harmony.Patch(gizmoActionMethod, prefix: new HarmonyMethod(typeof(DragonsDescent), nameof(PreGizmoActionCalled))); abilityCompGizmoGetter = AccessTools.PropertyGetter(type, "Gizmo"); } // Hostility response type changing { var type = AccessTools.TypeByName("DD.CompHostileResponse"); hostilityResponseTypeField = AccessTools.Field(type, "type"); var inner = AccessTools.Inner(type, "<>c__DisplayClass15_0"); MP.RegisterSyncMethod(typeof(DragonsDescent), nameof(SyncSetHostilityResponseType)); compHostileResponseField = AccessTools.Field(inner, "<>4__this"); MpCompat.harmony.Patch(AccessTools.Method(inner, "<get_Gizmo>b__1"), prefix: new HarmonyMethod(typeof(DragonsDescent), nameof(PreSetHostilityResponseType))); } // Altar { compRitualAltarType = AccessTools.TypeByName("DD.CompRitualAltar"); MP.RegisterSyncDelegate(compRitualAltarType, "<>c__DisplayClass11_0", "<CompGetGizmosExtra>b__0").SetDebugOnly(); MP.RegisterSyncDelegate(compRitualAltarType, "<>c__DisplayClass11_0", "<CompGetGizmosExtra>b__1").SetDebugOnly(); MP.RegisterSyncDelegate(compRitualAltarType, "<>c__DisplayClass11_0", "<CompGetGizmosExtra>b__2").SetDebugOnly(); MP.RegisterSyncDelegate(compRitualAltarType, "<>c__DisplayClass11_0", "<CompGetGizmosExtra>b__3").SetDebugOnly(); var type = AccessTools.TypeByName("DD.RitualTracker"); MP.RegisterSyncWorker <object>(SyncRitualTracker, type); ritualTrackerGetRitualMethod = AccessTools.Method(type, "GetRitual"); ritualTrackerMapField = AccessTools.Field(type, "map"); trackerMapComponentType = AccessTools.TypeByName("DD.MapComponent_Tracker"); trackerMapComponentRitualsField = AccessTools.Field(trackerMapComponentType, "rituals"); ritualReferenceType = AccessTools.TypeByName("DD.RitualReference"); ritualReferenceDefField = AccessTools.Field(ritualReferenceType, "def"); var inner = AccessTools.Inner(ritualReferenceType, "<>c__DisplayClass12_0"); MpCompat.RegisterSyncMethodsByIndex(inner, "<SetupAction>", 0, 1); MP.RegisterSyncWorker <object>(SyncRitualReferenceInnerClass, inner, shouldConstruct: true); ritualReferenceInnerRitualField = AccessTools.Field(inner, "ritual"); ritualReferenceInnerSelfField = AccessTools.Field(inner, "<>4__this"); ritualReferenceInnerParentField = AccessTools.Field(inner, "parent"); ritualReferenceInnerRitualsField = AccessTools.Field(inner, "rituals"); type = AccessTools.TypeByName("DD.CompProperties_Ritual"); ritualCompPropertiesRitualsField = AccessTools.Field(type, "rituals"); } }
public VanillaPowerExpanded(ModContentPack mod) { Type type; // Gizmos // Debug fill/empty { type = AccessTools.TypeByName("GasNetwork.CompGasStorage"); // Both these methods are calling (basically) the same method, // but that method also has other callers that don't need syncing MpCompat.RegisterSyncMethodsByIndex(type, "<CompGetGizmosExtra>", 0, 1).Do(m => m.SetDebugOnly()); } // Order to or cancel plugging the hole (method names shared by both types) { var types = new[] { "VanillaPowerExpanded.Building_ChemfuelPond", "VanillaPowerExpanded.Building_GasGeyser", }; foreach (var typeName in types) { type = AccessTools.TypeByName(typeName); MP.RegisterSyncMethod(type, "SetHoleForPlugging"); MP.RegisterSyncMethod(type, "CancelHoleForPlugging"); } } // RNG Fix { var methods = new[] { "VanillaPowerExpanded.Building_SmallBattery:Tick", "VanillaPowerExpanded.Building_SmallBattery:PostApplyDamage", "VanillaPowerExpanded.WeatherEvent_CustomLightningStrike:FireEvent", "VanillaPowerExpanded.MapComponentExtender:doMapSpawns", "VanillaPowerExpanded.CompPlantHarmRadiusIfBroken:CompTick", // HarmRandomPlantInRadius is only called by CompPlantHarmRadiusIfBroken:CompTick, no need for patching // CompPowerPlantNuclear:AffectCell is only calling a seeded random "VanillaPowerExpanded.IntermittentGasSprayer:SteamSprayerTick", // IntermittentGasSprayer - NewBaseAirPuff is only called by ThrowAirPuffUp which is called by SteamSprayerTick, no need for patching // Building_GasGeyser:StartSpray is assigned to IntermittentGasSprayer:startSprayCallback, which is called from SteamSprayerTick "GasNetwork.GasNet:GasNetTick", // PipeNetGrid pushes and pops all Rand calls, no need to patch // CompPowerAdvancedWater:RebuildCache is only calling a seeded random }; // These methods are loading resources in their .ctor, must be patched later var methodsForLater = new[] { "VanillaPowerExpanded.CompPowerAdvancedWater:PostSpawnSetup", "VanillaPowerExpanded.CompPowerAdvancedWind:PostSpawnSetup", }; PatchingUtilities.PatchPushPopRand(methods); LongEventHandler.ExecuteWhenFinished(() => PatchingUtilities.PatchPushPopRand(methodsForLater)); // Wind map comp windDirectionField = AccessTools.Field(AccessTools.TypeByName("GasNetwork.MapComponent_WindDirection"), "windDirection"); PatchingUtilities.PatchUnityRand("GasNetwork.MapComponent_WindDirection:MapGenerated"); MpCompat.harmony.Patch(AccessTools.Method("GasNetwork.MapComponent_WindDirection:MapComponentTick"), prefix: new HarmonyMethod(typeof(VanillaPowerExpanded), nameof(ReplaceWindMapComponentTick))); } }
public VanillaPowerExpanded(ModContentPack mod) { Type type; /// Gizmos // Debug fill/empty { type = AccessTools.TypeByName("GasNetwork.CompGasStorage"); // Both these methods are calling (basically) the same method, // but that method also has other callers that don't need syncing MpCompat.RegisterSyncMethodsByIndex(type, "<CompGetGizmosExtra>", 0, 1); type = AccessTools.TypeByName("VanillaPowerExpanded.CompPipeTank"); // This method is only called by 2 gizmos and nothing else (as far as I can tell) MP.RegisterSyncMethod(type, "SetStoredEnergyPct"); } // Order to or cancel plugging the hole (method names shared by both types) { var types = new[] { "VanillaPowerExpanded.Building_ChemfuelPond", "VanillaPowerExpanded.Building_GasGeyser", }; foreach (var typeName in types) { type = AccessTools.TypeByName(typeName); MP.RegisterSyncMethod(type, "SetHoleForPlugging"); MP.RegisterSyncMethod(type, "CancelHoleForPlugging"); } } // RNG Fix { var methods = new[] { "VanillaPowerExpanded.Building_SmallBattery:Tick", "VanillaPowerExpanded.Building_SmallBattery:PostApplyDamage", "VanillaPowerExpanded.WeatherEvent_CustomLightningStrike:FireEvent", "VanillaPowerExpanded.MapComponentExtender:doMapSpawns", "VanillaPowerExpanded.CompPlantHarmRadiusIfBroken:CompTick", // HarmRandomPlantInRadius is only called by CompPlantHarmRadiusIfBroken:CompTick, no need for patching "VanillaPowerExpanded.CompPowerPlantNuclear:AffectCell", "VanillaPowerExpanded.Building_GasGeyser:StartSpray", "VanillaPowerExpanded.GasExplosionUtility:TryStartFireNear", "VanillaPowerExpanded.IncidentWorker_GasExplosion:TryExecuteWorker", "VanillaPowerExpanded.IntermittentGasSprayer:SteamSprayerTick", "VanillaPowerExpanded.IntermittentGasSprayer:ThrowAirPuffUp", // NewBaseAirPuff is only called by IntermittentGasSprayer:ThrowAirPuffUp, no need for patching "VanillaPowerExpanded.GasPipeNet:PowerNetTick", "GasNetwork.GasNet:GasNetTick", // PipeNetGrid pushes and pops all Rand calls, no need to patch // CompPowerAdvancedWater:RebuildCache is only calling a seeded random }; // These methods are loading resources in their .ctor, must be patched later var methodsForLater = new[] { //"VanillaPowerExpanded.Building_Tank:Tick", //"VanillaPowerExpanded.Building_Tank:PostApplyDamage", "VanillaPowerExpanded.CompPowerAdvancedWater:PostSpawnSetup", "VanillaPowerExpanded.CompPowerAdvancedWind:PostSpawnSetup", }; PatchingUtilities.PatchPushPopRand(methods); LongEventHandler.ExecuteWhenFinished(() => PatchingUtilities.PatchPushPopRand(methodsForLater)); } }