Example #1
0
        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);
        }
Example #5
0
        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);
            }
        }
Example #6
0
        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);
        }
Example #7
0
        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");
            }
        }
Example #11
0
        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));
            }
        }