Beispiel #1
0
        public ExpansionContext SpinOff(MethodBase callee)
        {
            Stack.Contains(callee).AssertFalse();
            var new_stack = new Stack <MethodBase>();

            callee.Concat(Stack).Reverse().ForEach(new_stack.Push);
            return(new ExpansionContext(new_stack, Scope, Names, Env)
            {
                Parent = this
            });
        }
Beispiel #2
0
        private static void DoPatches()
        {
            bool   categoryNeedsAnnouncement = true;
            string category = null;

            void SetCategory(string str)
            {
                categoryNeedsAnnouncement = true;
                category = str;
            }

            void LogError(string str)
            {
                if (categoryNeedsAnnouncement)
                {
                    Log.Message($"Multiplayer :: {category}");
                }
                Log.Error(str);
                Multiplayer.loadingErrors = true;
            }

            var harmony = Multiplayer.harmony;

            SetCategory("Annotated patches");

            Assembly.GetCallingAssembly().GetTypes().Do(type => {
                // EarlyPatches are handled in MultiplayerMod.EarlyPatches
                if (type.IsDefined(typeof(EarlyPatchAttribute)))
                {
                    return;
                }

                try {
                    harmony.CreateClassProcessor(type).Patch();
                } catch (Exception e) {
                    LogError($"FAIL: {type} with {e}");
                }
            });

            SetCategory("General designation patches");

            // General designation handling
            {
                var designatorFinalizer = AccessTools.Method(typeof(DesignatorPatches), "DesignateFinalizer");
                var designatorMethods   = new[] {
                    "DesignateSingleCell",
                    "DesignateMultiCell",
                    "DesignateThing",
                };

                foreach (Type t in typeof(Designator).AllSubtypesAndSelf())
                {
                    foreach (string m in designatorMethods)
                    {
                        MethodInfo method = t.GetMethod(m, BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
                        if (method == null)
                        {
                            continue;
                        }

                        MethodInfo prefix = AccessTools.Method(typeof(DesignatorPatches), m);
                        try
                        {
                            harmony.PatchMeasure(method, new HarmonyMethod(prefix), null, null, new HarmonyMethod(designatorFinalizer));
                        } catch (Exception e) {
                            LogError($"FAIL: {t.FullName}:{method.Name} with {e}");
                        }
                    }
                }
            }

            SetCategory("Non-deterministic patches 1");

            // Remove side effects from methods which are non-deterministic during ticking (e.g. camera dependent motes and sound effects)
            {
                var randPatchPrefix  = new HarmonyMethod(typeof(RandPatches), "Prefix");
                var randPatchPostfix = new HarmonyMethod(typeof(RandPatches), "Postfix");

                var subSustainerStart = MpMethodUtil.GetLambda(typeof(SubSustainer), parentMethodType: MethodType.Constructor, parentArgs: new[] { typeof(Sustainer), typeof(SubSoundDef) });
                var sampleCtor        = typeof(Sample).GetConstructor(new[] { typeof(SubSoundDef) });
                var subSoundPlay      = typeof(SubSoundDef).GetMethod(nameof(SubSoundDef.TryPlay));
                var effecterTick      = typeof(Effecter).GetMethod(nameof(Effecter.EffectTick));
                var effecterTrigger   = typeof(Effecter).GetMethod(nameof(Effecter.Trigger));
                var effecterCleanup   = typeof(Effecter).GetMethod(nameof(Effecter.Cleanup));
                var randomBoltMesh    = typeof(LightningBoltMeshPool).GetProperty(nameof(LightningBoltMeshPool.RandomBoltMesh)).GetGetMethod();
                var drawTrackerCtor   = typeof(Pawn_DrawTracker).GetConstructor(new[] { typeof(Pawn) });
                var randomHair        = typeof(PawnStyleItemChooser).GetMethod(nameof(PawnStyleItemChooser.RandomHairFor));

                var effectMethods = new MethodBase[] { subSustainerStart, sampleCtor, subSoundPlay, effecterTick, effecterTrigger, effecterCleanup, randomBoltMesh, drawTrackerCtor, randomHair };
                var moteMethods   = typeof(MoteMaker).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                    .Where(m => m.Name != "MakeBombardmentMote"); // Special case, just calls MakeBombardmentMote_NewTmp, prevents Hugslib complains
                var fleckMethods = typeof(FleckMaker).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                   .Where(m => m.ReturnType == typeof(void));

                foreach (MethodBase m in effectMethods.Concat(moteMethods).Concat(fleckMethods))
                {
                    try
                    {
                        harmony.PatchMeasure(m, randPatchPrefix, randPatchPostfix);
                    } catch (Exception e) {
                        LogError($"FAIL: {m.DeclaringType.FullName}:{m.Name} with {e}");
                    }
                }
            }

            SetCategory("Non-deterministic patches 2");

            // Set ThingContext and FactionContext (for pawns and buildings) in common Thing methods
            {
                var thingMethodPrefix  = new HarmonyMethod(typeof(ThingMethodPatches).GetMethod("Prefix"));
                var thingMethodPostfix = new HarmonyMethod(typeof(ThingMethodPatches).GetMethod("Postfix"));
                var thingMethods       = new[] { "Tick", "TickRare", "TickLong", "SpawnSetup", "TakeDamage", "Kill" };

                foreach (Type t in typeof(Thing).AllSubtypesAndSelf())
                {
                    foreach (string m in thingMethods)
                    {
                        MethodInfo method = t.GetMethod(m, BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
                        if (method != null)
                        {
                            try
                            {
                                harmony.PatchMeasure(method, thingMethodPrefix, thingMethodPostfix);
                            } catch (Exception e) {
                                LogError($"FAIL: {method.DeclaringType.FullName}:{method.Name} with {e}");
                            }
                        }
                    }
                }
            }

            // Full precision floating point saving
            {
                var doubleSavePrefix = new HarmonyMethod(typeof(ValueSavePatch).GetMethod(nameof(ValueSavePatch.DoubleSave_Prefix)));
                var floatSavePrefix  = new HarmonyMethod(typeof(ValueSavePatch).GetMethod(nameof(ValueSavePatch.FloatSave_Prefix)));
                var valueSaveMethod  = typeof(Scribe_Values).GetMethod(nameof(Scribe_Values.Look));

                harmony.PatchMeasure(valueSaveMethod.MakeGenericMethod(typeof(double)), doubleSavePrefix, null);
                harmony.PatchMeasure(valueSaveMethod.MakeGenericMethod(typeof(float)), floatSavePrefix, null);
            }

            SetCategory("Map time gui patches");

            // Set the map time for GUI methods depending on it
            {
                var setMapTimePrefix  = new HarmonyMethod(AccessTools.Method(typeof(SetMapTimeForUI), "Prefix"));
                var setMapTimePostfix = new HarmonyMethod(AccessTools.Method(typeof(SetMapTimeForUI), "Postfix"));

                var windowMethods = new[] { "DoWindowContents", "WindowUpdate" };
                foreach (string m in windowMethods)
                {
                    harmony.PatchMeasure(typeof(MainTabWindow_Inspect).GetMethod(m), setMapTimePrefix, setMapTimePostfix);
                }

                foreach (var t in typeof(InspectTabBase).AllSubtypesAndSelf())
                {
                    var method = t.GetMethod("FillTab", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
                    if (method != null && !method.IsAbstract)
                    {
                        try
                        {
                            harmony.PatchMeasure(method, setMapTimePrefix, setMapTimePostfix);
                        } catch (Exception e) {
                            LogError($"FAIL: {method.DeclaringType.FullName}:{method.Name} with {e}");
                        }
                    }
                }
            }

            SetCategory("");
        }