public static IEnumerable <MethodInfo> GetLambda(Type parentType, string parentMethod = null, MethodType parentMethodType = MethodType.Normal, Type[] parentArgs = null, params int[] lambdaOrdinals)
 {
     foreach (int ord in lambdaOrdinals)
     {
         yield return(MpMethodUtil.GetLambda(parentType, parentMethod, parentMethodType, parentArgs, ord));
     }
 }
 static IEnumerable <ISyncDelegate> RegisterLambdaDelegate_Impl(Type parentType, string parentMethod, string[] fields, params int[] lambdaOrdinals)
 {
     foreach (int ord in lambdaOrdinals)
     {
         var method = MpMethodUtil.GetLambda(parentType, parentMethod, MethodType.Normal, null, ord);
         yield return(MP.RegisterSyncDelegate(parentType, method.DeclaringType.Name, method.Name, fields));
     }
 }
 static IEnumerable <ISyncMethod> RegisterLambdaMethod_Impl(Type parentType, string parentMethod, params int[] lambdaOrdinals)
 {
     foreach (int ord in lambdaOrdinals)
     {
         var method = MpMethodUtil.GetLambda(parentType, parentMethod, MethodType.Normal, null, ord);
         yield return(MP.RegisterSyncMethod(method));
     }
 }
Example #4
0
        public MoreFactionInteraction(ModContentPack mod)
        {
            var type = AccessTools.TypeByName("Multiplayer.Client.Patches.CloseDialogsForExpiredLetters");
            // We should probably add this to the API the next time we update it
            var rejectMethods = (Dictionary <Type, MethodInfo>)AccessTools.Field(type, "rejectMethods").GetValue(null);

            type = AccessTools.TypeByName("MoreFactionInteraction.ChoiceLetter_ReverseTradeRequest");
            var methods = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, null, 0, 3).ToArray();

            MP.RegisterSyncDelegate(type, methods[0].DeclaringType.Name, methods[0].Name);
            MP.RegisterSyncMethod(methods[1]);
            rejectMethods[type] = methods[1];

            var typeNames = new[]
            {
                "MoreFactionInteraction.ChoiceLetter_DiplomaticMarriage",
                "MoreFactionInteraction.ChoiceLetter_ExtortionDemand",
                "MoreFactionInteraction.ChoiceLetter_MysticalShaman",
            };

            foreach (var typeName in typeNames)
            {
                type    = AccessTools.TypeByName(typeName);
                methods = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, null, 0, 1).ToArray();
                MP.RegisterSyncMethod(methods[0]);
                MP.RegisterSyncMethod(methods[1]);
                rejectMethods[type] = methods[1];
            }

            typeNames = new[]
            {
                "MoreFactionInteraction.FactionWarPeaceTalks",
                "MoreFactionInteraction.More_Flavour.AnnualExpo",
            };

            foreach (var typeName in typeNames)
            {
                type = AccessTools.TypeByName(typeName);
                MP.RegisterSyncDialogNodeTree(type, "Notify_CaravanArrived");
            }

            type = AccessTools.TypeByName("MoreFactionInteraction.IncidentWorker_MysticalShaman");
            MP.RegisterSyncDialogNodeTree(type, "TryExecuteWorker");

            typeNames = new[]
            {
                "MoreFactionInteraction.IncidentWorker_MysticalShaman",
                "MoreFactionInteraction.IncidentWorker_ReverseTradeRequest",
                "MoreFactionInteraction.IncidentWorker_RoadWorks",
            };

            foreach (var typeName in typeNames)
            {
                type = AccessTools.TypeByName(typeName);
                MP.RegisterSyncDialogNodeTree(type, "TryExecuteWorker");
            }
        }
Example #5
0
        public RimsentialSpaceports(ModContentPack mod)
        {
            // Gizmos
            {
                var type = AccessTools.TypeByName("Spaceports.Buildings.Building_Beacon");
                MpCompat.RegisterLambdaMethod(type, "GetGizmos", 1, 2, 3);
                MP.RegisterSyncMethod(type, "ConfirmAction");

                type = AccessTools.TypeByName("Spaceports.Buildings.Building_Shuttle");
                MpCompat.RegisterLambdaMethod(type, "GetGizmos", 0, 1);

                type = AccessTools.TypeByName("Spaceports.Buildings.Building_ShuttlePad");
                MP.RegisterSyncMethod(type, "SetAccessState");

                type = AccessTools.TypeByName("Spaceports.Buildings.Building_ShuttleSpot");
                MP.RegisterSyncMethod(type, "SetAccessState");
            }

            // Choice letters
            {
                var type = AccessTools.TypeByName("Multiplayer.Client.Patches.CloseDialogsForExpiredLetters");
                // We should probably add this to the API the next time we update it
                var rejectMethods = (Dictionary <Type, MethodInfo>)AccessTools.Field(type, "rejectMethods").GetValue(null);

                type = AccessTools.TypeByName("Spaceports.Letters.PrisonerTransferLetter");
                var methods = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, null, 0, 1, 2).ToArray();
                MP.RegisterSyncMethod(methods[0]);
                MP.RegisterSyncMethod(methods[1]);
                MP.RegisterSyncMethod(methods[2]);
                rejectMethods[type] = methods[2];

                var typeNames = new[]
                {
                    "Spaceports.Letters.InterstellarDerelictLetter",
                    "Spaceports.Letters.MedevacLetter",
                    "Spaceports.Letters.MysteryCargoLetter",
                    "Spaceports.Letters.SpicyPawnLendingLetter",
                };

                foreach (var typeName in typeNames)
                {
                    type    = AccessTools.TypeByName(typeName);
                    methods = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, null, 0, 1).ToArray();
                    MP.RegisterSyncMethod(methods[0]);
                    MP.RegisterSyncMethod(methods[1]);
                    rejectMethods[type] = methods[1];
                }
            }
        }
        public SRTSExpanded(ModContentPack mod)
        {
            LongEventHandler.ExecuteWhenFinished(DelayedPatch);

            // Refuel shuttle
            MP.RegisterSyncDelegate(AccessTools.TypeByName("SRTS.StartUp"), "<>c__DisplayClass24_1", "<LaunchAndBombGizmosPassthrough>b__3");

            // Bombing
            MP.RegisterSyncWorker <Pair <IntVec3, IntVec3> >(SyncIntVec3Pair, typeof(Pair <IntVec3, IntVec3>));
            var type = AccessTools.TypeByName("SRTS.CompBombFlyer");

            MP.RegisterSyncMethod(type, "TryLaunchBombRun");
            bombTypeSync = MP.RegisterSyncField(type, "bombType");

            foreach (MethodInfo method in MpMethodUtil.GetLambda(type, "CompGetGizmosExtra", MethodType.Normal, null, 1, 2))
            {
                MpCompat.harmony.Patch(method,
                                       prefix: new HarmonyMethod(typeof(SRTSExpanded), nameof(PreSyncBombType)),
                                       postfix: new HarmonyMethod(typeof(SRTSExpanded), nameof(PostSyncBombType)));
            }
        }
        public AndroidTiers(ModContentPack mod)
        {
            // RNG
            {
                var methods = new[]
                {
                    "MOARANDROIDS.CompHeatSensitive:PostSpawnSetup",
                    "MOARANDROIDS.CompHeatSensitive:CheckTemperature",
                    "MOARANDROIDS.StartingPawnUtility_Patch+NewGeneratedStartingPawn_Patch:Listener",
                    "MOARANDROIDS.AndroidFactionDialogOverride:Postfix",
                    "MOARANDROIDS.MultiplePawnRacesAtStart:Postfix",
                    "MOARANDROIDS.Recipe_MemoryCorruptionChance:RandomCorruption",
                    "MOARANDROIDS.Recipe_AndroidRewireSurgery:RandomCorruption",
                    "MOARANDROIDS.Recipe_RemoveSentience:RandomCorruption",
                    "MOARANDROIDS.Recipe_RerollTraits:RandomCorruption",
                    "MOARANDROIDS.StockGenerator_SlaveAndroids+<GenerateThings>d__0:MoveNext",
                };

                PatchingUtilities.PatchSystemRand(methods, false);
            }

            // Gizmos
            {
                var type = AccessTools.TypeByName("MOARANDROIDS.CompAndroidState");
                MpCompat.RegisterLambdaDelegate(type, "CompGetGizmosExtra", 0, 2, 4, 5, 7, 10, 11, 12, 14);

                type = AccessTools.TypeByName("MOARANDROIDS.CompAutoDoor");
                MpCompat.RegisterLambdaMethod(type, "CompGetGizmosExtra", 0, 1);

                type = AccessTools.TypeByName("MOARANDROIDS.CompRemotelyControlledTurret");
                MpCompat.RegisterLambdaMethod(type, "CompGetGizmosExtra", 0);

                // Really ugly... We can't sync the pawns directly here, as they're inaccessible - the ThingComp is holding them inside
                // however, it does not implement IThingHolder or whatever it's supposed to in cases like those
                // so we do a lot of workarounds to not rely on the pawn sync worker
                type = compSkyCloudCoreType = AccessTools.TypeByName("MOARANDROIDS.CompSkyCloudCore");
                skyCloudCoreStoredMindsField = AccessTools.FieldRefAccess <List <Pawn> >(type, "storedMinds");
                MpCompat.RegisterLambdaMethod(type, "CompGetGizmosExtra", 6, 10, 11, 12, 13, 26, 27);
                var methods = MpMethodUtil.GetLambda(type, "CompGetGizmosExtra", MethodType.Normal, null, 4, 16, 24);
                foreach (var method in methods)
                {
                    MP.RegisterSyncMethod(method);
                    MP.RegisterSyncWorker <object>(SyncInnerClassWithPawn, method.DeclaringType, shouldConstruct: true);
                }
                var methodsArray = MpMethodUtil.GetLambda(type, "CompGetGizmosExtra", MethodType.Normal, null, 6, 11, 27).ToArray();
                skyCloudCoreGetGizmos6  = MethodInvoker.GetHandler(methodsArray[0]);
                skyCloudCoreGetGizmos11 = MethodInvoker.GetHandler(methodsArray[1]);
                skyCloudCoreGetGizmos27 = MethodInvoker.GetHandler(methodsArray[2]);
                MP.RegisterSyncMethod(typeof(AndroidTiers), nameof(SyncedGetGizmos6));
                MP.RegisterSyncMethod(typeof(AndroidTiers), nameof(SyncedGetGizmos11));
                MP.RegisterSyncMethod(typeof(AndroidTiers), nameof(SyncedGetGizmos27));
                MpCompat.harmony.Patch(methodsArray[0], prefix: new HarmonyMethod(typeof(AndroidTiers), nameof(PreCompGetGizmos6)));
                MpCompat.harmony.Patch(methodsArray[1], prefix: new HarmonyMethod(typeof(AndroidTiers), nameof(PreCompGetGizmos11)));
                MpCompat.harmony.Patch(methodsArray[2], prefix: new HarmonyMethod(typeof(AndroidTiers), nameof(PreCompGetGizmos27)));

                type = AccessTools.TypeByName("MOARANDROIDS.CompSkyMind");
                MpCompat.RegisterLambdaMethod(type, "CompGetGizmosExtra", 1, 3);

                type = compSurrogateOwnerType = AccessTools.TypeByName("MOARANDROIDS.CompSurrogateOwner");
                surrogateOwnerSkyCloudHostField = AccessTools.FieldRefAccess <Thing>(type, "skyCloudHost");
                MpCompat.RegisterLambdaDelegate(type, "CompGetGizmosExtra", 1, 3, 5, 9, 10, 13, 16, 19, 23);

                type = AccessTools.TypeByName("MOARANDROIDS.CPaths");
                MpCompat.RegisterLambdaDelegate(type, "QEE_BuildingPawnVatGrower_GetGizmosPostfix", 2, 5, 8);

                // CompComputer - all gizmos end up using a designator to pick a target, so we sync the designator
            }

            // Designators
            {
                var type = AccessTools.TypeByName("MOARANDROIDS.Designator_SurrogateToHack");
                surrogateToHackConstructor   = AccessTools.Constructor(type, new[] { typeof(int) });
                surrogateToHackPosField      = AccessTools.FieldRefAccess <IntVec3>(type, "pos");
                surrogateToHackTargetField   = AccessTools.FieldRefAccess <Pawn>(type, "target");
                surrogateToHackMapField      = AccessTools.FieldRefAccess <Map>(type, "cmap");
                surrogateToHackHackTypeField = AccessTools.FieldRefAccess <int>(type, "hackType");
                MP.RegisterSyncWorker <Designator>(SyncSurrogateToHackDesignator, type);

                type = AccessTools.TypeByName("MOARANDROIDS.Designator_AndroidToControl");
                androidToControlConstructor       = AccessTools.Constructor(type, new[] { typeof(Pawn), typeof(bool) });
                androidToControlPawnField         = AccessTools.FieldRefAccess <Pawn>(type, "controller");
                androidToControlFromSkyCloudField = AccessTools.FieldRefAccess <bool>(type, "fromSkyCloud");
                androidToControlKindOfTargetField = AccessTools.FieldRefAccess <int>(type, "kindOfTarget");
                androidToControlPosField          = AccessTools.FieldRefAccess <IntVec3>(type, "pos");
                androidToControlTargetField       = AccessTools.FieldRefAccess <Thing>(type, "target");
                androidToControlMapField          = AccessTools.FieldRefAccess <Map>(type, "cmap");
                MP.RegisterSyncWorker <Designator>(SyncAndroidToControlDesignator, type);
                MP.RegisterSyncMethod(typeof(AndroidTiers), nameof(SyncedConnectToSkyMind));
                MpCompat.harmony.Patch(AccessTools.Method(type, "CanDesignateThing"),
                                       transpiler: new HarmonyMethod(typeof(AndroidTiers), nameof(ReplaceConnectToSkyMind)));
            }

            // Dialogs
            {
                var type = AccessTools.TypeByName("MOARANDROIDS.Dialog_SkillUp");
                skillUpDialogConstructor            = AccessTools.Constructor(type, new[] { typeof(Pawn), typeof(bool) });
                skillUpGetNbPointsWantedToBuyMethod = MethodInvoker.GetHandler(AccessTools.Method(type, "getNbPointsWantedToBuy"));
                skillUpAndroidField                       = AccessTools.FieldRefAccess <Pawn>(type, "android");
                skillUpSkillDefListField                  = AccessTools.FieldRefAccess <List <SkillDef> >(type, "sd");
                skillUpPointsField                        = AccessTools.FieldRefAccess <List <int> >(type, "points");
                skillUpPassionsStateField                 = AccessTools.FieldRefAccess <List <int> >(type, "points");
                skillUpPointsNeededPerSkillField          = AccessTools.FieldRefAccess <int>(type, "pointsNeededPerSkill");
                skillUppointsNeededToIncreasePassionField = AccessTools.FieldRefAccess <int>(type, "pointsNeededToIncreasePassion");
                MP.RegisterSyncMethod(typeof(AndroidTiers), nameof(SyncedSkillUpDialogAccept));
                MP.RegisterSyncWorker <Window>(SyncSkillUpDialog, type);
                MpCompat.harmony.Patch(AccessTools.Method(type, "DoWindowContents"),
                                       transpiler: new HarmonyMethod(typeof(AndroidTiers), nameof(ReplaceButton)));

                type            = AccessTools.TypeByName("MOARANDROIDS.Utils");
                gcAttpCompField = AccessTools.StaticFieldRefAccess <GameComponent>(AccessTools.Field(type, "GCATPP"));

                type = AccessTools.TypeByName("MOARANDROIDS.GC_ATPP");
                gameComponentDecSkillPointsMethod = MethodInvoker.GetHandler(AccessTools.Method(type, "decSkillPoints"));
                gameComponentConnectUserMethod    = MethodInvoker.GetHandler(AccessTools.Method(type, "connectUser"));
                gameComponentConnectedThingField  = AccessTools.FieldRefAccess <HashSet <Thing> >(type, "connectedThing");
                gameComponentNbSlotField          = AccessTools.FieldRefAccess <int>(type, "nbSlot");
            }

            // Choice letters
            {
                var type = AccessTools.TypeByName("Multiplayer.Client.Patches.CloseDialogsForExpiredLetters");
                // We should probably add this to the API the next time we update it
                var rejectMethods = (Dictionary <Type, MethodInfo>)AccessTools.Field(type, "rejectMethods").GetValue(null);

                var typeNames = new[]
                {
                    "MOARANDROIDS.ChoiceLetter_RansomDemand",
                    "MOARANDROIDS.ChoiceLetter_RansomwareDemand",
                };

                foreach (var typeName in typeNames)
                {
                    type = AccessTools.TypeByName(typeName);
                    rejectMethods.Add(type, AccessTools.Method(typeof(ChoiceLetter), nameof(ChoiceLetter.Option_Reject))); // Generic reject option
                    var method = MpMethodUtil.GetLambda(type, "Choices", MethodType.Getter, lambdaOrdinal: 0);
                    MP.RegisterSyncMethod(method);
                }
            }
        }
        // Things we don't sync as they're unfinished, and seem to not be implemented yet:
        // Dialog_StartRitual, which is created from BuildingSacrificialAltar

        public CorruptionWorship(ModContentPack mod)
        {
            // BuildingAltar
            {
                var type = AccessTools.TypeByName("Corruption.Worship.BuildingAltar");
                altarNameSyncField        = MP.RegisterSyncField(type, "RoomName");
                altarSermonTemplatesField = AccessTools.FieldRefAccess <IList>(type, "Templates");
                altarEndSermonMethod      = MethodInvoker.GetHandler(AccessTools.Method(type, "EndSermon"));
                altarTryStartSermonMethod = MethodInvoker.GetHandler(AccessTools.Method(type, "TryStartSermon"));

                // The class representing a sermon, with all the required data
                type = AccessTools.TypeByName("Corruption.Worship.SermonTemplate");
                sermonTemplateNameField = AccessTools.FieldRefAccess <string>(type, "Name");
                sermonTemplatePreferredStartTimeField  = AccessTools.FieldRefAccess <int>(type, "preferredStartTime");
                sermonTemplateSermonDurationHoursField = AccessTools.FieldRefAccess <float>(type, "SermonDurationHours");
                sermonTemplateActiveField = AccessTools.FieldRefAccess <bool>(type, "Active");

                // Dialog for renaming the altar, created from TempleCardUtility
                type = AccessTools.TypeByName("Corruption.Worship.Dialog_RenameTemple");
                MP.RegisterSyncMethod(typeof(CorruptionWorship), nameof(SyncSermonName));
                MpCompat.harmony.Patch(AccessTools.Method(type, nameof(Window.DoWindowContents)),
                                       prefix: new HarmonyMethod(typeof(CorruptionWorship), nameof(RenameTemplePrefix)),
                                       postfix: new HarmonyMethod(typeof(CorruptionWorship), nameof(RenameTemplePostfix)));

                // Dialog for renaming a specific sermon, created from TempleCardUtility
                type = AccessTools.TypeByName("Corruption.Worship.Dialog_RenameSermon");
                MpCompat.harmony.Patch(AccessTools.Method(type, "DoWindowContents"),
                                       prefix: new HarmonyMethod(typeof(CorruptionWorship), nameof(RenameSermonPrefix)),
                                       postfix: new HarmonyMethod(typeof(CorruptionWorship), nameof(RenameSermonPostfix)));

                // Dialog used for assigning a preacher, created from TempleCardUtility
                assignPreacherType        = AccessTools.TypeByName("Corruption.Worship.Dialog_AssignPreacher");
                assignPreacherAltarField  = AccessTools.FieldRefAccess <Building>(assignPreacherType, "altar");
                assignPreacherSermonField = AccessTools.FieldRefAccess <object>(assignPreacherType, "sermon");
                MP.RegisterSyncMethod(assignPreacherType, "AssignPawn");
                MP.RegisterSyncMethod(assignPreacherType, "UnassignPawn");
                MP.RegisterSyncWorker <Window>(SyncDialogAssignPreacher, assignPreacherType);

                // Dialog used for assigning a preacher, you guessed it, created from TempleCardUtility
                // This is a subclass of Dialog_AssignPreacher
                assignAssistantType = AccessTools.TypeByName("Corruption.Worship.Dialog_AssignAssistant");
                MP.RegisterSyncMethod(assignAssistantType, "AssignPawn");
                MP.RegisterSyncMethod(assignAssistantType, "UnassignPawn");
                MP.RegisterSyncWorker <Window>(SyncDialogAssignPreacher, assignAssistantType);
            }

            // MainTabWindow_Worship
            {
                // WonderWorker, does the work to execute the wonder defined in the MainTabWindow_Worship
                var wonderWorkerType           = AccessTools.TypeByName("Corruption.Worship.Wonders.WonderWorker");
                var wonderWorkerTargetableType = AccessTools.TypeByName("Corruption.Worship.Wonders.WonderWorker_Targetable");
                wonderWorkerDefField = AccessTools.FieldRefAccess <Def>(wonderWorkerType, "Def");
                wonderWorkerTargetableTargetField   = AccessTools.FieldRefAccess <TargetInfo>(wonderWorkerTargetableType, "target");
                wonderWorkerTargetableCanceledField = AccessTools.FieldRefAccess <bool>(wonderWorkerTargetableType, "cancelled");
                MP.RegisterSyncWorker <object>(SyncWonderWorker, wonderWorkerType, isImplicit: true);
                MP.RegisterSyncWorker <object>(SyncWonderTargetableWorker, wonderWorkerTargetableType, isImplicit: true);
                MP.RegisterSyncMethod(wonderWorkerTargetableType, "StartTargeting");
                MP.RegisterSyncMethod(wonderWorkerTargetableType, "CheckCancelled");

                // Sync the method for each class inheriting from TryExecuteWonder
                // If we ever want to sync the base class too, include .Concat(type) there
                // But since all it does is returning false, we'll skip it
                // We also check if it's not a subtype of WonderWorker_Targetable, as it uses TryDoEffectOnTarget method for the reward
                // (and then we pray that there's not another class doing it in a special way)
                foreach (var subtype in wonderWorkerType.AllSubclasses().Where(x => !x.IsAssignableFrom(wonderWorkerTargetableType)))
                {
                    // Include types for maximum safety
                    var method = AccessTools.Method(subtype, "TryExecuteWonder", new[] { typeof(Def), typeof(int) });
                    if (method != null)
                    {
                        MP.RegisterSyncMethod(method);
                    }
                }

                var methods = MpMethodUtil.GetLambda(wonderWorkerTargetableType, "TryExecuteWonderInt", lambdaOrdinals: new[] { 0, 1 }).ToArray();
                wonderWorkerTargetableInnerBaseField = AccessTools.FieldRefAccess <object>(methods[0].DeclaringType, "<>4__this");
                MpCompat.harmony.Patch(methods[0],
                                       prefix: new HarmonyMethod(typeof(CorruptionWorship), nameof(PreStartTargetting)));
                MpCompat.harmony.Patch(methods[1],
                                       prefix: new HarmonyMethod(typeof(CorruptionWorship), nameof(PreCheckCancelled)));

                // WonderDef, all we want is the field storing the WonderWorker for sync worker
                var type = AccessTools.TypeByName("Corruption.Worship.Wonders.WonderDef");
                wonderDefWorkerIntField = AccessTools.FieldRefAccess <object>(type, "workerInt");

                var database = typeof(DefDatabase <>).MakeGenericType(new Type[] { type });
                getDefByShortHash = MethodInvoker.GetHandler(AccessTools.Method(database, "GetByShortHash"));

                // GlobalWorshipTracker, we sync favor usage when the user decides to purchase a wonder
                type = AccessTools.TypeByName("Corruption.Worship.GlobalWorshipTracker");
                MP.RegisterSyncMethod(type, "ConsumeFavourFor");
            }

            LongEventHandler.ExecuteWhenFinished(LatePatch);
        }
        public DragonsDescent(ModContentPack mod)
        {
            // Incubator
            {
                var type    = AccessTools.TypeByName("DD.CompEggIncubator");
                var methods = MpCompat.RegisterLambdaMethod(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 = MpMethodUtil.GetLambda(type, "get_Gizmo", MethodType.Normal, null, 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.RegisterLambdaMethod(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");
            }
        }