Пример #1
0
        static void InjectSaveHook()
        {
            var saveWorld = typeDef_WorldFile.GetMethod("saveWorld", MethodFlags.Public | MethodFlags.Static, typeSys.Boolean.ToTypeDefOrRef(), typeSys.Boolean.ToTypeDefOrRef());

            MethodDef invokeSaveWorld;
            var       saveWorldDel = context.CreateDelegate("Terraria.PrismInjections", "WorldFile_OnSaveWorldDel", typeSys.Void, out invokeSaveWorld, typeSys.Boolean);

            var onSaveWorld = new FieldDefUser("P_OnSaveWorld", new FieldSig(saveWorldDel.ToTypeSig()), FieldAttributes.Public | FieldAttributes.Static);

            typeDef_WorldFile.Fields.Add(onSaveWorld);

            OpCode[] toFind =
            {
                OpCodes.Ldloc_S,
                OpCodes.Call,
                OpCodes.Leave_S
            };

            Instruction[] toInject =
            {
                Instruction.Create(OpCodes.Ldsfld,   onSaveWorld),
                Instruction.Create(OpCodes.Ldarg_0),
                Instruction.Create(OpCodes.Callvirt, invokeSaveWorld)
            };

            var swb = saveWorld.Body;

            using (var swbproc = swb.GetILProcessor())
            {
                var instr = swb.FindInstrSeqStart(toFind).Next(swbproc).Next(swbproc);

                for (int i = 0; i < toInject.Length; i++)
                {
                    swbproc.InsertBefore(instr, toInject[i]);
                }
            }
        }
        /// <summary>
        /// Wraps a method using a fancy delegate. Replaces all references of the method with the wrapped one and creates an "On[MethodName]" hook which passes the method's parent type followed by the type parameters of the original method.
        /// </summary>
        /// <param name="context">The current Cecil context.</param>
        /// <param name="delegateNS">The namespace of the delegate type to create.</param>
        /// <param name="delegateTypeName">The name of the delegate type to create.</param>
        /// <param name="origMethod">The method to wrap.</param>
        public static void Wrap(this MethodDef origMethod, DNContext context, string delegateNS, string delegateTypeName, string fieldName)
        {
            MethodDef invokeDelegate;

            //SingletonTRArr[0] = origMethod.DeclaringType.ToTypeSig();

            ////If anyone knows a better way to insert one element at the beginning of an array and scoot
            ////all the other elements down one index then go ahead and do it lol. I dunno how2array.
            var delegateArgs = origMethod.Parameters.Select(p => p.Type).ToArray();

            var newDelegateType = context.CreateDelegate(delegateNS, delegateTypeName, origMethod.ReturnType, out invokeDelegate, delegateArgs);

            var newMethod = origMethod.ReplaceAndHook(invokeDelegate, origMethod, fieldName);

            // you're not special anymore!
            if ((origMethod.Attributes & MethodAttributes.SpecialName) != 0)
                origMethod.Attributes ^= MethodAttributes.SpecialName;
            if ((origMethod.Attributes & MethodAttributes.RTSpecialName) != 0)
                origMethod.Attributes ^= MethodAttributes.RTSpecialName;

            origMethod.ReplaceAllMethodRefs(newMethod, context);
        }
Пример #3
0
        static void AddPlaceThingHook()
        {
            /*
             *
             * IL_2D37: ldsfld    int32 Terraria.Player::tileTargetX
             * IL_2D3C: ldsfld    int32 Terraria.Player::tileTargetY
             * IL_2D41: ldarg.0
             * IL_2D42: ldfld     class Terraria.Item[] Terraria.Player::inventory
             * IL_2D47: ldarg.0
             * IL_2D48: ldfld     int32 Terraria.Player::selectedItem
             * IL_2D4D: ldelem.ref
             * IL_2D4E: ldfld     int32 Terraria.Item::createTile
             * IL_2D53: ldc.i4.0
             * IL_2D54: ldloc.s   78
             * IL_2D56: ldarg.0
             * IL_2D57: ldfld     int32 Terraria.Entity::whoAmI
             * IL_2D5C: ldloc.s   72
             * IL_2D5E: call      bool Terraria.WorldGen::PlaceTile(int32, int32, int32, bool, bool, int32, int32)
             * IL_2D63: stloc.s   79
             */

            OpCode[] toFind =
            {
                OpCodes.Ldsfld,
                OpCodes.Ldsfld,
                OpCodes.Ldarg_0,
                OpCodes.Ldfld,
                OpCodes.Ldarg_0,
                OpCodes.Ldfld,
                OpCodes.Ldelem_Ref,
                OpCodes.Ldfld,
                OpCodes.Ldc_I4_0,
                OpCodes.Ldloc_S,
                OpCodes.Ldarg_0,
                OpCodes.Ldfld,
                OpCodes.Ldloc_S,
                OpCodes.Call,
                OpCodes.Stloc_S
            };

            var placeThing = typeDef_Player.GetMethod("PlaceThing");

            MethodDef invokePlaceThing;
            var       onPlaceThingDel = context.CreateDelegate("Terraria.PrismInjections", "Player_OnPlaceThingDel", typeSys.Void, out invokePlaceThing, typeSys.Boolean);

            var onPlaceThing = new FieldDefUser("P_OnPlaceThing", new FieldSig(onPlaceThingDel.ToTypeSig()), FieldAttributes.Public | FieldAttributes.Static);

            typeDef_Player.Fields.Add(onPlaceThing);

            var ptb = placeThing.Body;

            using (var ptbproc = ptb.GetILProcessor())
            {
                Instruction[] toInj =
                {
                    Instruction.Create(OpCodes.Ldsfld,   onPlaceThing),
                    Instruction.Create(OpCodes.Ldloc,    ptb.Variables[79]),
                    Instruction.Create(OpCodes.Callvirt, invokePlaceThing)
                };

                var first = ptb.FindInstrSeqStart(toFind);
                for (int i = 0; i < toFind.Length - 1; i++)
                {
                    first = first.Next(ptbproc);
                }

                foreach (var i in toInj.Reverse())
                {
                    ptbproc.InsertAfter(first, i);
                }
            }
        }
Пример #4
0
        static void AddPreDrawHook()
        {
            OpCode[] toFind =
            {
                /*
                 *  spriteBatch.Draw(...);
                 *
                 *  IL_29AF: ldsfld    class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.SpriteBatch Terraria.Main::spriteBatch
                 *  IL_29B4: ldc.i4.0
                 *  IL_29B5: ldsfld    class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.BlendState [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.BlendState::AlphaBlend
                 *  IL_29BA: ldsfld    class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.SamplerState [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.SamplerState::LinearClamp
                 *  IL_29BF: ldsfld    class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.DepthStencilState [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.DepthStencilState::None
                 *  IL_29C4: ldarg.0
                 *  IL_29C5: ldfld     class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.RasterizerState Terraria.Main::Rasterizer
                 *  IL_29CA: ldnull
                 *  IL_29CB: ldarg.0
                 *  IL_29CC: ldfld     valuetype [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Matrix Terraria.Main::Transform
                 *  IL_29D1: callvirt  instance void [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.SpriteBatch::Begin(valuetype [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.SpriteSortMode, class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.BlendState, class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.SamplerState, class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.DepthStencilState, class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.RasterizerState, class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.Effect, valuetype [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Matrix)
                 */

                OpCodes.Ldsfld,
                OpCodes.Ldc_I4_0,
                OpCodes.Ldsfld,
                OpCodes.Ldsfld,
                OpCodes.Ldsfld,
                OpCodes.Ldarg_0,
                OpCodes.Ldfld,
                OpCodes.Ldnull,
                OpCodes.Ldarg_0,
                OpCodes.Ldfld,
                OpCodes.Callvirt
            };

            var draw = typeDef_Main.GetMethod("Draw");

            var spriteBatch = typeDef_Main.GetField("spriteBatch");

            MethodDef invokePreDraw;
            var       onPreDrawDel = context.CreateDelegate("Terraria.PrismInjections", "Main_OnPreDrawDel", typeSys.Void, out invokePreDraw, spriteBatch.FieldType);

            var onPreDraw = new FieldDefUser("P_OnPreDraw", new FieldSig(onPreDrawDel.ToTypeSig()), FieldAttributes.Public | FieldAttributes.Static);

            typeDef_Main.Fields.Add(onPreDraw);

            var drb = draw.Body;

            using (var drbproc = drb.GetILProcessor())
            {
                Instruction[] toInj =
                {
                    Instruction.Create(OpCodes.Ldsfld,   onPreDraw),
                    Instruction.Create(OpCodes.Ldsfld,   spriteBatch),
                    Instruction.Create(OpCodes.Callvirt, invokePreDraw)
                };

                var first = drb.FindInstrSeqStart(toFind);
                for (int i = 0; i < toFind.Length; i++)
                {
                    first = first.Next(drbproc);
                }

                foreach (var i in toInj.Reverse())
                {
                    drbproc.InsertAfter(first, i);
                }

                // rewire the if before it to end at the injected instructions instead of the code we looked for
                //foreach (var i in drb.Instructions)
                //    if (i.Operand == first)
                //        i.Operand = toInj[0];

                // not rewiring the if will lead to invalid IL, because the target instruction won't exist (because we're removing it here)
            }
        }
Пример #5
0
        static void ReplaceSoundHitCalls()
        {
            #region ReflectProjectile
            { // introduce a new scope level here so variables can be reused in the StrikeNPC part
                var reflectProjectile = typeDef_NPC.GetMethod("ReflectProjectile");

                // first statement in the method is "Main.PlaySound(...);"
                // instruction after the "call Main.PlaySound" is a ldc.i4.0 (first one in the method)

                MethodDef invokeSoundHit;
                var       onReflProjSoundHit = context.CreateDelegate("Terraria.PrismInjections", "NPC_ReflectProjectile_PlaySoundHitDel", typeSys.Void, out invokeSoundHit, typeDef_NPC.ToTypeSig(), typeSys.Int32);

                var reflectProjectile_PlaySoundHit = new FieldDefUser("P_ReflectProjectile_PlaySoundHit", new FieldSig(onReflProjSoundHit.ToTypeSig()), FieldAttributes.Public | FieldAttributes.Static);
                typeDef_NPC.Fields.Add(reflectProjectile_PlaySoundHit);

                using (var rpproc = reflectProjectile.Body.GetILProcessor())
                {
                    rpproc.RemoveInstructions(reflectProjectile.Body.Instructions.TakeWhile(i => i.OpCode.Code != Code.Ldc_I4_0).ToArray() /* must enumerate this already, invalidoperation will be thrown otherwise */);

                    var first = reflectProjectile.Body.Instructions[0];

                    rpproc.InsertBefore(first, Instruction.Create(OpCodes.Ldsfld, reflectProjectile_PlaySoundHit));
                    rpproc.EmitWrapperCall(invokeSoundHit, first);
                }
            }
            #endregion

            #region StrikeNPC
            {
                var strikeNpc = typeDef_NPC.GetMethod("StrikeNPC");

                MethodDef invokeSoundHit;
                var       onStrikeNpcSoundHit = context.CreateDelegate("Terraria.PrismInjections", "NPC_StrikeNPC_PlaySoundHitDel", typeSys.Void, out invokeSoundHit,
                                                                       new[] { typeDef_NPC.ToTypeSig(), typeSys.Int32, typeSys.Single, typeSys.Int32, typeSys.Boolean, typeSys.Boolean, typeSys.Boolean });

                var strikeNpc_PlaySoundHit = new FieldDefUser("P_StrikeNPC_PlaySoundHit", new FieldSig(onStrikeNpcSoundHit.ToTypeSig()), FieldAttributes.Public | FieldAttributes.Static);
                typeDef_NPC.Fields.Add(strikeNpc_PlaySoundHit);

                var snb = strikeNpc.Body;
                using (var snproc = snb.GetILProcessor())
                {
                    OpCode[] toRem =
                    {
                        OpCodes.Ldarg_0,
                        OpCodes.Ldfld,    // NPC.soundHit
                        OpCodes.Ldc_I4_0,
                        OpCodes.Ble_S,    // <after the call>

                        OpCodes.Ldc_I4_3, // soundHit ID
                        OpCodes.Ldarg_0,
                        OpCodes.Ldflda,   // Entity.position
                        OpCodes.Ldfld,    // Vector2.X
                        OpCodes.Conv_I4,
                        OpCodes.Ldarg_0,
                        OpCodes.Ldflda, // Entity.position
                        OpCodes.Ldfld,  // Vector2.X
                        OpCodes.Conv_I4,
                        OpCodes.Ldarg_0,
                        OpCodes.Ldfld, // NPC.soundHit
                        OpCodes.Call   // Main.PlaySound(int, int, int, int)
                    };

                    var instrs  = snb.FindInstrSeqStart(toRem);
                    var instrs_ = snproc.RemoveInstructions(instrs, toRem.Length);

                    Instruction newF;
                    snproc.InsertBefore(instrs_, newF = Instruction.Create(OpCodes.Ldsfld, strikeNpc_PlaySoundHit));
                    snproc.EmitWrapperCall(invokeSoundHit, instrs_);

                    for (int i = 0; i < snb.Instructions.Count; i++)
                    {
                        if (snb.Instructions[i].Operand == instrs)
                        {
                            snb.Instructions[i].Operand = newF;
                        }
                    }
                }
            }
            #endregion
        }