public override void Run() { var vanilla = SourceDefinition.Type("Terraria.NPC").Method("NewNPC"); int tmp = 0; var callback = this.Method(() => OTAPI.Callbacks.Terraria.Npc.Spawn(ref tmp)); var importedCallback = SourceDefinition.MainModule.Import(callback); //This hook is to notify when a npc has been created, and is about to be spawned into //the world. //What we do is look in Terraria.NPC.NewNPC for the following code: // Main.npc[num].target = Target; // if (Type == 50) // //Between these two lines we inject a cancelable callback: // Main.npc[num].target = Target; // if(!OTAPI.Callbacks.Terraria.Npc.Spawn(ref num)) // { // return index; // } // if (Type == 50) //Find the `if (Type == 50) offset instruction so we can use it //as our insertion point var insInsertionPoint = vanilla.Body.Instructions.Single(i => i.OpCode == OpCodes.Ldarg_2 && i.Next.OpCode == OpCodes.Ldc_I4_S && i.Next.Operand.Equals((sbyte)50) && i.Next.Next.OpCode == OpCodes.Bne_Un_S ); //Get the il processor so we can alter il var processor = vanilla.Body.GetILProcessor(); //Find the npc index, using the only ret instruction that doesn't //have an operand var insNpcIndex = vanilla.Body.Instructions.Single(i => i.OpCode == OpCodes.Ret && i.Previous != null && i.Previous.Operand == null ); //Expect ldloc.0 (as we will use it by reference later) if (insNpcIndex.Previous.OpCode != OpCodes.Ldloc_0) { throw new NotImplementedException($"Expected ldloc.0 rather than {insNpcIndex.Previous.OpCode}"); } //Inject out callback il processor.InsertBefore(insInsertionPoint, //Load the npc index by reference new { OpCodes.Ldloca, Operand = vanilla.Body.Variables.First() }, //Invoke our callback using the npc index that is on the stack as a reference new { OpCodes.Call, importedCallback }, //If the callback returns true, then continue back to vanilla new { OpCodes.Brtrue_S, insInsertionPoint }, //Otherwise, if false then return the modified npc index new { OpCodes.Ldloc_0 }, new { OpCodes.Ret } ); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Player") .Method("KillMe"); double tmp = 0; int tmp1 = 0; bool tmp2 = false; string tmp3 = null; var cbkBegin = this.SourceDefinition.MainModule.Import( this.Method(() => OTAPI.Callbacks.Terraria.Player.KillMeBegin(null, ref tmp, ref tmp1, ref tmp2, ref tmp3)) ); var cbkEnd = this.SourceDefinition.MainModule.Import( this.Method(() => OTAPI.Callbacks.Terraria.Player.KillMeEnd(null, 0, 0, false, null)) ); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: true ); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.NPC").Method("NewNPC"); var callback = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method("Create"); var ctor = vanilla.Body.Instructions.Single(x => x.OpCode == OpCodes.Newobj && x.Operand is MethodReference && (x.Operand as MethodReference).DeclaringType.Name == "NPC"); ctor.OpCode = OpCodes.Call; ctor.Operand = vanilla.Module.Import(callback); //Remove <npc>.SetDefault() as we do something custom var remFrom = ctor.Next; var il = vanilla.Body.GetILProcessor(); while (remFrom.Next.Next.OpCode != OpCodes.Call) //Remove until TypeToNum { il.Remove(remFrom.Next); } // //Add Type to our callback // il.InsertBefore(ctor, il.Create(OpCodes.Ldarg_2)); il.InsertBefore(ctor, il.Create(OpCodes.Ldloca, vanilla.Body.Variables.First())); //The first variable is the index for (var x = 0; x < vanilla.Parameters.Count; x++) { var opcode = callback.Parameters[x].ParameterType.IsByReference ? OpCodes.Ldarga : OpCodes.Ldarg; il.InsertBefore(ctor, il.Create(opcode, vanilla.Parameters[x])); } }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Player") .Method("LoadPlayer"); string tmp = null; bool tmp2 = false; global::Terraria.IO.PlayerFileData data = null; var cbkBegin = //this.SourceDefinition.MainModule.Import( this.Method(() => OTAPI.Callbacks.Terraria.Player.LoadBegin(ref data, ref tmp, ref tmp2)); //); //var cbkEnd = this.SourceDefinition.MainModule.Import( // this.Method(() => OTAPI.Callbacks.Terraria.Player.LoadEnd(null, false)) //); vanilla.InjectNonVoidBeginCallback(cbkBegin); //vanilla.Wrap //( // beginCallback: cbkBegin, // endCallback: cbkEnd, // beginIsCancellable: true, // noEndHandling: false, // allowCallbackInstance: false, // overrideReturnType: vanilla.ReturnType //); }
public override void Run() { var npcLoot = SourceDefinition.Type("Terraria.NPC").Method("NPCLoot"); var dropLoot = SourceDefinition.Type("Terraria.NPC").Method("DropLoot"); //In the NPCLoot method there is a call to send packet 88 (after item drop). //We will also want to hook this in the case the returned value from DropLoot //cancels the event. //Note, each update will need checking for any other calls to DropLoot that populate variables //as currently this is the only one. //TODO: write a test for this var il = npcLoot.Body.GetILProcessor(); //This section will add '&& num40 >= 0' to the statement above "Main.item [num40].color = this.color;" var insColour = npcLoot.Body.Instructions.Single(x => x.OpCode == OpCodes.Ldfld && x.Operand == SourceDefinition.Type("Terraria.NPC").Field("color")); //Grab where the call is located var insColorStart = insColour.Previous(i => i.OpCode == OpCodes.Ldsfld); //Find the first instruction for the color call var resumeInstruction = insColorStart.Previous.Operand as Instruction; //Find the instruction where it should be transferred to if false is evaludated il = npcLoot.Body.GetILProcessor(); //Insert the num40 variable (the result back from the DropLoot method) il.InsertBefore(insColorStart, il.Create(OpCodes.Ldloc, (VariableDefinition)insColorStart.Next.Operand)); //Place 0 on the stack il.InsertBefore(insColorStart, il.Create(OpCodes.Ldc_I4_0)); //Compare the current values on stack, using >= il.InsertBefore(insColorStart, il.Create(OpCodes.Blt, resumeInstruction)); npcLoot.Body.OptimizeMacros(); }
void AddSource(string link) { try { var uri = new Uri(link).ToString(); if (uri[uri.Length - 1] != '/') { uri = uri + '/'; } foreach (var src in Sources) { if (uri == src.ToString()) { MessageBox.Show("The given URI is already exist.", "Can't add source", MessageBoxButton.OK, MessageBoxImage.Warning); return; } } var sd = new SourceDefinition(uri); Sources.Add(sd); sd.ApplySources(Sources); wapkg.PushSources(Sources); } catch (UriFormatException) { MessageBox.Show("Invalid URI.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }
/// <summary> /// Abstract base class for joins of two source definitions. /// </summary> /// <param name="Left">Left source definition.</param> /// <param name="Right">Right source definition.</param> /// <param name="Conditions">Join conditions.</param> /// <param name="Start">Start position in script expression.</param> /// <param name="Length">Length of expression covered by node.</param> /// <param name="Expression">Expression containing script.</param> public Join(SourceDefinition Left, SourceDefinition Right, ScriptNode Conditions, int Start, int Length, Expression Expression) : base(Start, Length, Expression) { this.left = Left; this.right = Right; this.conditions = Conditions; }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.NPC").Method("StrikeNPC"); var callback = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method("Strike"); vanilla.InjectNonVoidBeginCallback(callback); }
public override void Run() { var npcLoot = SourceDefinition.Type("Terraria.NPC").Method("NPCLoot"); var dropLoot = SourceDefinition.Type("Terraria.NPC").Method("DropLoot"); //In this patch we swap all Item.NewItem calls in NPCLoot to use our previously //created DropLoot method //Gather all Item.NewItem calls var itemCalls = npcLoot.Body.Instructions.Where(x => x.OpCode == OpCodes.Call && x.Operand is MethodReference && (x.Operand as MethodReference).Name == "NewItem" && (x.Operand as MethodReference).DeclaringType.Name == "Item").ToArray(); var processor = npcLoot.Body.GetILProcessor(); //Swap each Item.NewItem calls to our Npc.DropLoot method. foreach (var call in itemCalls) { //Swap to our custom method call.Operand = dropLoot; //Append the additional arguments to the end of the existing call processor.InsertBefore(call, new[] { new { OpCodes.Ldarg_0 } //Adds 'this' (so the npc instance) }); } //Ensure the short branches are updated npcLoot.Body.SimplifyMacros(); npcLoot.Body.OptimizeMacros(); }
public override void Run() { //Get the vanilla meteor method reference var vanilla = SourceDefinition.Type("Terraria.WorldGen").Method("meteor"); //Get the OTAPI callback method reference int tmp = 0; var callback = this.SourceDefinition.MainModule.Import( this.Method(() => OTAPI.Callbacks.Terraria.WorldGen.DropMeteor(ref tmp, ref tmp)) ); //Look for stopDrops = true in the vanilla methods instructions var stopDrops = vanilla.Body.Instructions.Single(instruction => instruction.OpCode == OpCodes.Stsfld && instruction.Operand is FieldReference && (instruction.Operand as FieldReference).Name == "stopDrops" && instruction.Previous.OpCode == OpCodes.Ldc_I4_1 ); //Get the IL processor instance so we can inject some il var processor = vanilla.Body.GetILProcessor(); //Get the instruction reference in which we use to continue //on with vanilla code if our callback doesn't cancel the method. //Since we are inserting before the stopDrops = true, we use the //first instruction for the setter, which is ldc.i4.1 (which means (bool)true) var insContinue = stopDrops.Previous; //Inject the callback IL processor.InsertBefore(insContinue, //Create the callback execution new { OpCodes.Ldarga, Operand = vanilla.Parameters[0] }, //reference to int x new { OpCodes.Ldarga, Operand = vanilla.Parameters[1] }, //reference to int y new { OpCodes.Call, callback }, //OTAPI.Callbacks.Terraria.WordGen.DropMeteor(ref x, ref y) //If the callback is not canceled, continue on with vanilla code new { OpCodes.Brtrue_S, insContinue }, //If the callback is canceled, return false new { OpCodes.Ldc_I4_0 }, //false new { OpCodes.Ret } //return ); /* We now should have code in meteor looking like: * } * } * if (!WorldGen.DropMeteor(ref i, ref j)) * { * return false; * } * WorldGen.stopDrops = true; * num = WorldGen.genRand.Next(17, 23); */ }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Netplay").Method("ServerLoop"); var callback = this.Method(() => OTAPI.Callbacks.Terraria.Netplay.ServerSocketCreate()); var iTcpSocket = vanilla.Body.Instructions.Single(x => x.OpCode == OpCodes.Newobj && x.Operand is MethodReference && (x.Operand as MethodReference).Name == ".ctor" && (x.Operand as MethodReference).DeclaringType.Name == "TcpSocket" ); iTcpSocket.OpCode = OpCodes.Call; //Replace newobj to be call as we need to execute out callback instead iTcpSocket.Operand = vanilla.Module.Import(callback); //Replace the method reference from the TcpSocket constructor, to our callback }
protected virtual void ConvertLine(LuaTextWriter luaWriter, TsvLine line) { var firstValue = line.Fields.First(); if (State == null && firstValue.StartsWith("SOURCE")) { luaWriter.Write("SetSource("); SourceDefinition.Parse(line.Fields).Dump(luaWriter); luaWriter.Write(")\n"); return; } throw new ParseFailedException(firstValue, $"Unknown field {firstValue.Value} seen in state {State}"); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.NetMessage").Method("SendData"); var callback = vanilla.Module.Import(ModificationDefinition.Type("OTAPI.Callbacks.Terraria.NetMessage").Method("SendBytes")); //Hooking send bytes should be as simple as replacing each AsyncSend call with //the OTAPI callback as well as removing the socket instance and leaving the //remoteClient/num variable. //TODO: Netplay.Connection.Socket AsyncSend for client //Find all calls to AsyncSend var asyncSendCalls = vanilla.Body.Instructions.Where(x => x.OpCode == OpCodes.Callvirt && x.Operand is MethodReference && (x.Operand as MethodReference).Name == "AsyncSend" && x.Previous(6).Operand is FieldReference && (x.Previous(6).Operand as FieldReference).Name == "Clients") .ToArray(); var il = vanilla.Body.GetILProcessor(); foreach (var call in asyncSendCalls) { //Replace the call with our OTAPI callback call.OpCode = OpCodes.Call; call.Operand = callback; //Wind back to the first Netplay.Clients (there are two, we want the one before the Socket reference) var clients = call.Previous(x => x.OpCode == OpCodes.Ldfld && x.Operand is FieldReference && (x.Operand as FieldReference).Name == "Socket") .Previous(x => x.OpCode == OpCodes.Ldsfld && x.Operand is FieldReference && (x.Operand as FieldReference).Name == "Clients"); //Remove the Socket call if (clients.Next.Next.OpCode != OpCodes.Ldelem_Ref) { throw new InvalidOperationException($"{clients.Next.Next.OpCode} was not expected."); } il.Remove(clients.Next.Next); //ldelem.ref if (clients.Next.Next.OpCode != OpCodes.Ldfld) { throw new InvalidOperationException($"{clients.Next.Next.OpCode} was not expected."); } il.Remove(clients.Next.Next); //ldfld //Remove the client call il.Remove(clients); } }
public override void Run() { var netMessage = SourceDefinition.Type <NetMessage>(); var sendData = netMessage.Method("SendData"); // Create new method var overloading = new MethodDefinition(sendData.Name, sendData.Attributes, sendData.ReturnType); foreach (var p in sendData.Parameters) { var prm = new ParameterDefinition(p.Name, p.Attributes, p.ParameterType); prm.Constant = p.Constant; if (prm.ParameterType == SourceDefinition.MainModule.TypeSystem.String) { prm.ParameterType = Type <NetworkText>(); prm.Constant = NetworkText.Empty; } overloading.Parameters.Add(prm); } // Create method body var ilprocessor = overloading.Body.GetILProcessor(); ParameterDefinition text = null; for (int i = 0; i < overloading.Parameters.Count; i++) { ilprocessor.Append(Instruction.Create(OpCodes.Ldarg, overloading.Parameters[i])); if (overloading.Parameters[i].ParameterType == Type <NetworkText>()) { text = overloading.Parameters[i]; ilprocessor.Append(Instruction.Create(OpCodes.Callvirt, Type <NetworkText>().Method("ToString"))); } } ilprocessor.Append(Instruction.Create(OpCodes.Call, sendData)); ilprocessor.Append(Instruction.Create(OpCodes.Ret)); foreach (var i in new [] { Instruction.Create(OpCodes.Ldarg, text), Instruction.Create(OpCodes.Brtrue_S, overloading.Body.Instructions[0]), Instruction.Create(OpCodes.Ldsfld, Type <NetworkText>().Field("Empty")), Instruction.Create(OpCodes.Starg, text), }.Reverse()) { ilprocessor.InsertBefore(overloading.Body.Instructions[0], i); } netMessage.Methods.Add(overloading); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Netplay").Method("OnConnectionAccepted"); var callback = SourceDefinition.MainModule.Import( this.Method(() => OTAPI.Callbacks.Terraria.Netplay.OnConnectionAccepted(null)) ); vanilla.Wrap ( beginCallback: callback, endCallback: null, beginIsCancellable: true, noEndHandling: true, allowCallbackInstance: false ); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Projectile").Method("Kill"); var cbkBegin = this.Method(() => Callbacks.Terraria.Projectile.KillBegin(null)); var cbkEnd = this.Method(() => Callbacks.Terraria.Projectile.KillEnd(null)); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: true ); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Player") .Method("Hurt"); int tmp = 0; bool tmp1 = false; string tmp2 = null; double tmp3 = 0; var cbkBegin = //this.SourceDefinition.MainModule.Import( this.Method(() => OTAPI.Callbacks.Terraria.Player.HurtBegin(ref tmp3, null, ref tmp, ref tmp, ref tmp1, ref tmp1, ref tmp2, ref tmp1, ref tmp)); //); vanilla.InjectNonVoidBeginCallback(cbkBegin); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.RemoteClient").Method("Reset"); var cbkBegin = this.Method(() => OTAPI.Callbacks.Terraria.RemoteClient.PreReset(null)); var cbkEnd = this.Method(() => OTAPI.Callbacks.Terraria.RemoteClient.PostReset(null)); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: true ); }
internal static bool TryParseSource(ScriptParser Parser, out SourceDefinition Source) { Parser.SkipWhiteSpace(); int Start = Parser.Position; ScriptNode Node = Parser.ParseNoWhiteSpace(); ScriptNode Name = null; string s; Parser.SkipWhiteSpace(); s = Parser.PeekNextToken().ToUpper(); if (!string.IsNullOrEmpty(s) && IsAlias(s) && s != "INNER" && s != "OUTER" && s != "LEFT" && s != "RIGHT" && s != "FULL" && s != "JOIN" && s != "WHERE" && s != "GROUP" && s != "ORDER" && s != "OFFSET" && s != "ON" && s != "SET" && s != "SELECT" && s != "OBJECT" && s != "OBJECTS") { if (s == "AS") { Parser.NextToken(); } Name = Parser.ParseNoWhiteSpace(); } else if (Node is VariableReference Ref) { Name = new ConstantElement(new StringValue(Ref.VariableName), Node.Start, Node.Length, Node.Expression); } Source = new SourceReference(Node, Name, Start, Parser.Position - Start, Parser.Expression); return(true); }
public async Task Run(SourceDefinition source, CancellationToken token) { if (source.Source == SourceType.Amazon) { var amazon = new Amazon(_client, _logger, _runner, source); await amazon.Run(token); } else if (source.Source == SourceType.NewEgg) { var newEgg = new NewEgg(_client, source); await newEgg.Run(token); } else { throw new Exception($"Unrecognized source type {source.Source}"); } }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.NetMessage").Method("SendData"); var callback = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.NetMessage").Method("SendData"); //Few stack issues arose trying to inject a callback before for lock, so i'll resort to //wrapping the method; vanilla.Wrap ( beginCallback: callback, endCallback: null, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: false ); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Projectile").Methods.Single( x => x.Name == "AI" && x.Parameters.Count() == 0 ); var cbkBegin = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Projectile").Method("AIBegin", parameters: vanilla.Parameters); var cbkEnd = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Projectile").Method("AIEnd", parameters: vanilla.Parameters); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: true ); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.NPC").Method("Transform"); int tmp = 0; var preCallback = vanilla.Module.Import(this.Method(() => OTAPI.Callbacks.Terraria.Npc.PreTransform(null, ref tmp))); var postCallback = vanilla.Module.Import(this.Method(() => OTAPI.Callbacks.Terraria.Npc.PostTransform(null))); //We could wrap this method, but this hooks is to inform when an npc transforms, not //an occurrence of the call. //Anyway, this instance we need to insert before the netMode == 2 check. //Get the IL processor instance so we can modify IL var processor = vanilla.Body.GetILProcessor(); //Pre callback section { var first = vanilla.Body.Instructions.First(); processor.InsertBefore(first, new { OpCodes.Ldarg_0 }, new { OpCodes.Ldarga, Operand = vanilla.Parameters.Single() }, new { OpCodes.Call, Operand = preCallback }, new { OpCodes.Brtrue_S, Operand = first }, new { OpCodes.Ret } ); } //Post callback section { var insertionPoint = vanilla.Body.Instructions.Single(x => x.OpCode == OpCodes.Ldsfld && x.Operand is FieldReference && (x.Operand as FieldReference).Name == "netMode" && x.Next.OpCode == OpCodes.Ldc_I4_2 ); //Insert our callback before the if block, ensuring we consider that the if block may be referenced elsewhere Instruction ourEntry; processor.InsertBefore(insertionPoint, ourEntry = processor.Create(OpCodes.Ldarg_0)); //Add the current instance (this in C#) to the callback processor.InsertBefore(insertionPoint, processor.Create(OpCodes.Call, postCallback)); //Replace transfers insertionPoint.ReplaceTransfer(ourEntry, vanilla); } }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.NPC").Methods.Single( x => x.Name == "SetDefaults" && x.Parameters.First().ParameterType == SourceDefinition.MainModule.TypeSystem.String ); var cbkBegin = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method("SetDefaultsByNameBegin", parameters: vanilla.Parameters); var cbkEnd = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method("SetDefaultsByNameEnd", parameters: vanilla.Parameters); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: true ); }
public override void Run() { foreach (var type in new[] { new { TypeDef = SourceDefinition.Type("Terraria.NPC"), MechType = OpCodes.Ldc_I4_1 }, new { TypeDef = SourceDefinition.Type("Terraria.Item"), MechType = OpCodes.Ldc_I4_2 } }) { var vanilla = type.TypeDef.Methods.Single(x => x.Name == "MechSpawn"); var hook = SourceDefinition.MainModule.Import(ModificationDefinition.Type("OTAPI.Callbacks.Terraria.World").Method("MechSpawn")); //Here we find the insertion point where we want to inject our callback at. var iInsertionPoint = vanilla.Body.Instructions.Last(x => x.OpCode == OpCodes.Ldloc_1); //If the result of the callback instructs us to cancel, this instruction will transfer us to the existing "return false" var iContinuePoint = vanilla.Body.Instructions.Last(x => x.OpCode == OpCodes.Ldc_I4_0); var il = vanilla.Body.GetILProcessor(); //Add all the parameters foreach (var prm in vanilla.Parameters) { il.InsertBefore(iInsertionPoint, il.Create(OpCodes.Ldarg, prm)); } //Add the first three variables by reference for (var x = 0; x < 3; x++) { il.InsertBefore(iInsertionPoint, il.Create(OpCodes.Ldloca, vanilla.Body.Variables[x])); } //Append our mech type enum value to the method call il.InsertBefore(iInsertionPoint, il.Create(type.MechType)); //Trigger the method to run with the parameters on the stck il.InsertBefore(iInsertionPoint, il.Create(OpCodes.Call, hook)); //If the result left on the stack is false, then jump to the "return false" il.InsertBefore(iInsertionPoint, il.Create(OpCodes.Brfalse_S, iContinuePoint)); vanilla.Body.OptimizeMacros(); } }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Projectile").Methods.Single( x => x.Name == "Update" && x.Parameters.Single().ParameterType == SourceDefinition.MainModule.TypeSystem.Int32 ); var cbkBegin = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Projectile").Method("UpdateBegin", parameters: vanilla.Parameters); var cbkEnd = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Projectile").Method("UpdateEnd", parameters: vanilla.Parameters); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: true ); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.NetMessage") .Method("greetPlayer"); var cbkBegin = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.NetMessage") .Method("GreetPlayerBegin", parameters: vanilla.Parameters); var cbkEnd = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.NetMessage") .Method("GreetPlayerEnd", parameters: vanilla.Parameters); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: false ); }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.IO.WorldFile").Methods.Single( x => x.Name == "loadWorld" && x.Parameters.Count() == 1 && x.Parameters[0].ParameterType == SourceDefinition.MainModule.TypeSystem.Boolean ); var cbkBegin = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.WorldFile").Method("LoadWorldBegin", parameters: vanilla.Parameters); var cbkEnd = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.WorldFile").Method("LoadWorldEnd", parameters: vanilla.Parameters); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: false ); }
public override void Run() { //Get the vanilla method reference var vanilla = SourceDefinition.Type("Terraria.WorldGen").Method("hardUpdateWorld"); //Get the OTAPI callback method reference //int tmp = 0; var callback = this.SourceDefinition.MainModule.Import( this.Method(() => OTAPI.Callbacks.Terraria.WorldGen.HardmodeTilePlace(0, 0, 0, false, false, 0, 0)) ); /* In this particular hardmode tile mod we replace all WorldGen.PlaceTile * calls to a custom callback version, then replace the Pop instruction * with cancelable IL. */ var targets = vanilla.Body.Instructions.Where(instruction => instruction.OpCode == OpCodes.Call && (instruction.Operand as MethodReference).Name == "PlaceTile" && instruction.Next.OpCode == OpCodes.Pop ).ToArray(); var processor = vanilla.Body.GetILProcessor(); foreach (var replacementPoint in targets) //.Take(1)) { replacementPoint.Operand = callback; var insContinue = replacementPoint.Next.Next.Next(i => i.OpCode == OpCodes.Call && (i.Operand as MethodReference).Name == "SendTileSquare" ).Next; replacementPoint.Next.OpCode = OpCodes.Brtrue_S; replacementPoint.Next.Operand = insContinue; processor.InsertAfter(replacementPoint.Next, processor.Create(OpCodes.Ret)); } }
public override void Run() { var vanilla = SourceDefinition.Type("Terraria.Item").Methods.Single( x => x.Name == "SetDefaults" && x.Parameters.First().ParameterType == this.SourceDefinition.MainModule.TypeSystem.Int32 && x.Parameters.Skip(1).First().ParameterType == this.SourceDefinition.MainModule.TypeSystem.Boolean ); var cbkBegin = this.ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Item").Method("SetDefaultsByIdBegin", parameters: vanilla.Parameters); var cbkEnd = this.ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Item").Method("SetDefaultsByIdEnd", parameters: vanilla.Parameters); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: true, noEndHandling: false, allowCallbackInstance: true ); }
/// <summary> /// The add expression to collection. /// </summary> /// <param name="source"> /// The source. /// </param> /// <param name="hookType"> /// The hook type. /// </param> /// <param name="description"> /// The description. /// </param> /// <param name="processDescription"> /// The process description. /// </param> /// <param name="expression"> /// The expression. /// </param> /// <param name="sysid"> /// The sysid. /// </param> private void AddExpressionToCollection( SourceDefinition source, SourceDefinition hookType, string description, DefinitionDescription processDescription, string expression, string sysid = "") { JobManager.RunInDispatcherThread( DebugWindowManager.DebugConsoleWindow.Dispatcher, DispatcherPriority.Normal, delegate { try { switch (source) { case SourceDefinition.Field: this.AddItemToCollection( processDescription.DictionaryExpressions, new SBExpression(processDescription.FileName, expression, hookType, sysid) { Description = description }); break; case SourceDefinition.Screen: /* if (hookType == SourceDefinition.Process) { //AddItemToCollection(processDescription.ProcessCollection, ); this.AddProcessToCollection( description, processDescription, new SBExpression(processDescription.FileName, expression, hookType, sysid, expression) { Description = description }); } else { */ this.AddItemToCollection( processDescription.ScreenExpressions, new SBExpression(processDescription.FileName, expression, hookType, sysid) { Description = description }); /* } */ break; case SourceDefinition.Menu: this.AddProcessToCollection( description, processDescription, new SBExpression(processDescription.FileName, expression, hookType, sysid, expression) { Description = description }); break; case SourceDefinition.Paragraph: this.AddItemToCollection( processDescription.Expressions, new SBExpression(processDescription.FileName, expression, hookType, sysid) { Description = description }); break; case SourceDefinition.Unknown: this.AddItemToCollection( processDescription.Expressions, new SBExpression(processDescription.FileName, expression, hookType, sysid) { Description = description }); break; } } catch (Exception exception) { CustomLogger.LogException(exception, "Problem adding expression to the collection."); } }); }
/// <summary> /// Loads the definition from expression. /// </summary> /// <param name="source"> /// Where the expression is being called from. /// </param> /// <param name="hookType"> /// If this is a process hook point or expression hook point. /// </param> /// <param name="expression"> /// The original expression that the definition name was derrived from. /// </param> /// <param name="parent"> /// Parent <see cref="DefinitionDescription"/>, if this is null then it will be the root of the tree. /// </param> /// <param name="hookPoint"> /// The name of the definition slot where the definition was found. /// </param> /// <param name="sysid"> /// The system id to use otherwise the current system id will be used. /// </param> internal void LoadProcessFromExpression( SourceDefinition source, SourceDefinition hookType, string expression, DefinitionDescription parent = null, string hookPoint = "", string sysid = "") { if (string.IsNullOrEmpty(expression)) { // there is no expression so no need to try load it. return; } if (expression.StartsWith("P.CALL.PROCESS")) { // this is specific to American Auto Shield. The have a process used to call other processes so we can just remove it. expression = expression.Substring(15); } // Check to see if it is a constant, if so just add it to the collection. if (SBExpression.IsConstantValueExpression(expression)) { this.AddExpressionToCollection(source, hookType, hookPoint, parent, expression); return; } var colonPos = expression.IndexOf(":", StringComparison.Ordinal); if (colonPos != 1) { // SB expression that have an identified, i.e. B: D: all have a single character then a ':' colonPos = 0; } // a field definition has no process hooks they are all expressions, etc. int help. if (source != SourceDefinition.Paragraph && (colonPos > 0 || source == SourceDefinition.Field || source == SourceDefinition.Expression)) { this.AddExpressionToCollection(source, hookType, hookPoint, parent, expression); return; } string callType; var pName = GetProcessName(expression, out callType); if (!string.IsNullOrEmpty(pName)) { switch (callType) { case "C": this.LoadProcess(pName, source, hookType, parent, expression, hookPoint, sysid); break; case "B": this.LoadBasicProgramFromExpression(pName, parent, hookPoint); break; case "M": break; case "D": this.AddExpressionToCollection(source, hookType, hookPoint, parent, expression); break; case "V": this.AddExpressionToCollection(source, hookType, hookPoint, parent, expression); break; default: this.LoadProcess(pName, source, hookType, parent, expression, hookPoint, sysid); break; } } }
/// <summary> /// Loads the definition from xxPROCESS. /// </summary> /// <param name="pName"> /// Name of the definition. /// </param> /// <param name="slotType"></param> /// <param name="parent"> /// Parent <see cref="DefinitionDescription"/>, if this is null then it will be the root of the tree. /// </param> /// <param name="expression"> /// The original expression that the definition name was derrived from. /// </param> /// <param name="hookPoint"> /// The name of the definition slot where the definition was found. /// </param> /// <param name="sysid"> /// The system id to use otherwise the current system id will be used. /// </param> /// <param name="source"></param> internal void LoadProcess( string pName, SourceDefinition source, SourceDefinition slotType, DefinitionDescription parent = null, string expression = "", string hookPoint = "", string sysid = "") { if (SBExpression.IsStandardSBExpression(expression)) { // standard SB expression elements and therefore no need to try read the process, just add the element this.AddExpressionToCollection(parent, hookPoint, expression); return; } if (string.IsNullOrEmpty(expression)) { expression = pName; } JobManager.RunInUIThread( DispatcherPriority.Input, delegate { var processFile = sysid; if (string.IsNullOrEmpty(processFile)) { processFile = SBPlusClient.Current.SystemId; } // read definition record from current xxProcess processFile += "PROCESS"; // check if I already have the definition in the collection lock (this.processCollection) { if (this.processCollection.ContainsKey(processFile, pName)) { this.SetIsLoading(1); this.AddProcessToCollection(pName, parent, this.processCollection[pName]); this.SetIsLoading(-1); return; } } this.SetIsLoading(1); SBFile.Read( processFile, pName, this.ReadProcessCompleted, new ProcessLoadState { HookPoint = hookPoint, ParentDefinitionDescription = parent, Expression = expression, Source = source, SlotType = slotType, SysId = sysid }); }); }
/// <summary> /// The add process to collection. /// </summary> /// <param name="description"> /// The description. /// </param> /// <param name="parentDefinitionDescription"> /// The parent definition description. /// </param> /// <param name="processDescription"> /// The process description. /// </param> /// <param name="source">Where is the process being called from.</param> private void AddProcessToCollection( string description, DefinitionDescription parentDefinitionDescription, DefinitionDescription processDescription, SourceDefinition source = SourceDefinition.Unknown) { JobManager.RunInDispatcherThread( DebugWindowManager.DebugConsoleWindow.Dispatcher, DispatcherPriority.Normal, delegate { if (parentDefinitionDescription == null) { this.Definition = processDescription; this.ResetAnalysis(); this.ProcessStack.Push(this.Definition); } else { switch (source) { case SourceDefinition.Screen: if (processDescription is SBExpression) { this.AddItemToCollection(parentDefinitionDescription.ScreenExpressions, processDescription as SBExpression); } else { this.AddItemToCollection( parentDefinitionDescription.ProcessCollection, new ProcessCall { Description = description, ProcessDescription = processDescription }); } break; case SourceDefinition.Button: //this.AddItemToCollection(description, processDescription, parentDefinitionDescription.ProcessCollection); this.AddItemToCollection( parentDefinitionDescription.ProcessCollection, new ProcessCall { Description = description, ProcessDescription = processDescription }); break; default: this.AddItemToCollection( parentDefinitionDescription.ProcessCollection, new ProcessCall { Description = description, ProcessDescription = processDescription }); break; } } }); }
public ButtonDefinitionDescription(string fileName, string name, SourceDefinition hookType, string expression) : base(fileName, name, hookType, expression) { }
/// <summary> /// Initializes a new instance of the <see cref="SBExpression"/> class. /// </summary> /// <param name="fileName"> /// The file name. /// </param> /// <param name="expression"> /// The expression. /// </param> /// <param name="hookType"> /// The hook type. /// </param> /// <param name="sysid"> /// The sysid. /// </param> public SBExpression(string fileName, string expression, SourceDefinition hookType, string sysid) : this(fileName, expression, hookType, sysid, string.Empty) { }
/// <summary> /// Initializes a new instance of the <see cref="SBExpression"/> class. /// </summary> /// <param name="fileName"> /// The file name. /// </param> /// <param name="expression"> /// The expression. /// </param> /// <param name="hookType"> /// The hook type. /// </param> /// <param name="sysid"> /// The sysid. /// </param> /// <param name="name"> /// The name. /// </param> public SBExpression(string fileName, string expression, SourceDefinition hookType, string sysid, string name) : base(fileName, name, hookType, expression) { this.SystemId = sysid; }
/// <summary> /// Initializes a new instance of the <see cref="SelectionProcessDescription"/> class. /// </summary> /// <param name="fileName"> /// The file name. /// </param> /// <param name="name"> /// The name. /// </param> /// <param name="definition"> /// The definition. /// </param> public SelectionProcessDescription(string fileName, string name, SourceDefinition hookType, string sysId, SBString definition) : base(fileName, name, hookType, sysId) { this.Name = name; }