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 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])); } }
/// <summary> /// Constructor with endResidueLocInPeptide /// </summary> /// <param name="residue"></param> /// <param name="residueLocInPeptide"></param> /// <param name="residueTerminusState"></param> /// <param name="modDefinition"></param> /// <param name="endResidueLocInPeptide"></param> public AminoAcidModInfo(char residue, int residueLocInPeptide, ResidueTerminusState residueTerminusState, ModificationDefinition modDefinition, int endResidueLocInPeptide) { ModDefinition = modDefinition; Residue = residue; ResidueLocInPeptide = residueLocInPeptide; EndResidueLocInPeptide = endResidueLocInPeptide; TerminusState = residueTerminusState; }
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() { //Grab the Initialise method var vanilla = this.SourceDefinition.Type("Terraria.Main").Method("Initialize"); var cbkBegin = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Main").Method("InitializeBegin", parameters: vanilla.Parameters); var cbkEnd = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Main").Method("InitializeEnd", parameters: vanilla.Parameters); vanilla.Wrap ( beginCallback: cbkBegin, endCallback: cbkEnd, beginIsCancellable: false, noEndHandling: false, allowCallbackInstance: true ); }
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").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.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() { 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.NPC").Method("DropBossBags"); var callback = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method("BossBagItem"); var il = vanilla.Body.GetILProcessor(); //Grad the NewItem calls var instructions = vanilla.Body.Instructions.Where(x => x.OpCode == OpCodes.Call && x.Operand is MethodReference && (x.Operand as MethodReference).Name == "NewItem" && x.Next.OpCode == OpCodes.Stloc_1); //Quick validation check if (instructions.Count() != 1) { throw new NotSupportedException("Only one server NewItem call expected in DropBossBags."); } //The first call is in the server block. TODO: client version var ins = instructions.First(); //Swap the NewItem call to our custom item call ins.Operand = vanilla.Module.Import(callback); //Our argument appends the NPC instance (this) to the arguments il.InsertBefore(ins, il.Create(OpCodes.Ldarg_0)); //Instance methods ldarg.0 is the instance object //Now we start inserting our own if block to compare the call result. var target = ins.Next /*stloc.1*/.Next; //Grabs a reference to the instruction after the stloc.1 opcode so we can insert sequentially il.InsertBefore(target, il.Create(OpCodes.Ldloc_1)); //Load the num2 variable onto the stack il.InsertBefore(target, il.Create(OpCodes.Ldc_I4_M1)); //Load -1 onto the stack il.InsertBefore(target, il.Create(OpCodes.Ceq)); //Consume & compare the two variables and push 1 (true) or 0 (false) onto the stack il.InsertBefore(target, il.Create(OpCodes.Brfalse_S, target)); //if the output of ceq is 0 (false) then continue back on with the [target] instruction. In code terms, if the expression is not -1 then don't exit il.InsertBefore(target, il.Create(OpCodes.Ret)); //If we are here, the num2 variable is equal to -1, so we can exit the function. }
public override void Run() { foreach (var newItem in SourceDefinition.Type("Terraria.Item").Methods.Where( x => x.Name == "NewItem" )) { //In this patch we create a custom DropLoot method that will be the receiver //of all Item.NewItem calls in NPCLoot. var typeNpc = this.Type <Terraria.NPC>(); //Create the new DropLoot call in the Terraria.NPC class var dropLoot = new MethodDefinition("DropLoot", MethodAttributes.Public | MethodAttributes.Static, newItem.ReturnType); typeNpc.Methods.Add(dropLoot); dropLoot.Body.InitLocals = true; var il = dropLoot.Body.GetILProcessor(); //Clone the parameters from the Item.NewItem method (with no byreference) foreach (var prm in newItem.Parameters) { dropLoot.Parameters.Add(prm); } dropLoot.Parameters.Add(new ParameterDefinition(typeNpc) { Name = "npc", IsOptional = true, HasDefault = true, Constant = null }); //Collect the hooks var cbkBegin = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method( "DropLootBegin", parameters: dropLoot.Parameters, skipMethodParameters: 1, substituteByRefs: true ); var cbkEnd = ModificationDefinition.Type("OTAPI.Callbacks.Terraria.Npc").Method( "DropLootEnd", parameters: dropLoot.Parameters, skipMethodParameters: 0, substituteByRefs: true ); //Create the value to hold the new item id var vrbItemId = new VariableDefinition("otaItem", (cbkBegin.Parameters[0].ParameterType as ByReferenceType).ElementType); dropLoot.Body.Variables.Add(vrbItemId); il.Emit(OpCodes.Ldloca_S, vrbItemId); //Loads our variable by reference so our callback and alter it. var beginResult = dropLoot.EmitBeginCallback(cbkBegin, false, false, false, parameterOffset: 1); //Inject the begin call var insFirstForMethod = dropLoot.EmitMethodCallback(newItem, false, false); //Store the result into our new variable il.Emit(OpCodes.Stloc, vrbItemId); //Set the vanilla instruction to be resumed upon continuation of the begin hook. if (beginResult != null && beginResult.OpCode == OpCodes.Pop) { beginResult.OpCode = OpCodes.Brtrue_S; beginResult.Operand = insFirstForMethod; //Emit the cancellation return IL il.InsertAfter(beginResult, il.Create(OpCodes.Ret)); il.InsertAfter(beginResult, il.Create(OpCodes.Ldloc, vrbItemId)); } //Inject the end callback dropLoot.EmitEndCallback(cbkEnd, false, false); //Emit the return value using the result variable we injected il.Emit(OpCodes.Ldloc, vrbItemId); il.Emit(OpCodes.Ret); } }
private bool ReadModSummaryFile(string modSummaryFilePath) { ModificationDefs.Clear(); if (string.IsNullOrEmpty(modSummaryFilePath)) { return(false); } // Initialize the column mapping // Using a case-insensitive comparer var columnHeaders = new SortedDictionary <string, int>(StringComparer.OrdinalIgnoreCase) { { MOD_SUMMARY_COLUMN_Modification_Symbol, 0 }, { MOD_SUMMARY_COLUMN_Modification_Mass, 1 }, { MOD_SUMMARY_COLUMN_Target_Residues, 2 }, { MOD_SUMMARY_COLUMN_Modification_Type, 3 }, { MOD_SUMMARY_COLUMN_Mass_Correction_Tag, 4 }, { MOD_SUMMARY_COLUMN_Occurrence_Count, 5 } }; // Read the data from the ModSummary.txt file // The first line is typically a header line: // Modification_Symbol Modification_Mass Target_Residues Modification_Type Mass_Correction_Tag Occurrence_Count using var modSummaryReader = new StreamReader(new FileStream(modSummaryFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)); var headerLineParsed = false; while (!modSummaryReader.EndOfStream) { var lineIn = modSummaryReader.ReadLine(); var skipLine = false; if (string.IsNullOrEmpty(lineIn)) { continue; } var splitLine = lineIn.Split('\t'); if (!headerLineParsed) { if (string.Equals(splitLine[0], MOD_SUMMARY_COLUMN_Modification_Symbol, StringComparison.OrdinalIgnoreCase)) { // Parse the header line to confirm the column ordering // The Occurrence_Count column was misspelled prior to December 2012; need to check for this for (var index = 0; index <= splitLine.Length - 1; index++) { // ReSharper disable once StringLiteralTypo if (splitLine[index] != "Occurence_Count") { continue; } splitLine[index] = MOD_SUMMARY_COLUMN_Occurrence_Count; break; } ReaderFactory.ParseColumnHeaders(splitLine, columnHeaders); skipLine = true; } headerLineParsed = true; } if (skipLine || splitLine.Length < 4) { continue; } var modSymbolText = ReaderFactory.LookupColumnValue(splitLine, MOD_SUMMARY_COLUMN_Modification_Symbol, columnHeaders); var modMassText = ReaderFactory.LookupColumnValue(splitLine, MOD_SUMMARY_COLUMN_Modification_Mass, columnHeaders); var targetResidues = ReaderFactory.LookupColumnValue(splitLine, MOD_SUMMARY_COLUMN_Target_Residues, columnHeaders); var modType = ReaderFactory.LookupColumnValue(splitLine, MOD_SUMMARY_COLUMN_Modification_Type, columnHeaders); var massCorrectionTag = ReaderFactory.LookupColumnValue(splitLine, MOD_SUMMARY_COLUMN_Mass_Correction_Tag, columnHeaders); if (string.IsNullOrWhiteSpace(modSymbolText)) { modSymbolText = ModificationDefinition.NO_SYMBOL_MODIFICATION_SYMBOL.ToString(); } var modSymbol = modSymbolText[0]; if (!double.TryParse(modMassText, out var modificationMass)) { throw new Exception("Modification mass is not numeric for MassCorrectionTag: " + massCorrectionTag + ": " + modMassText); } ModificationDefinition.ResidueModificationType modificationType; if (string.IsNullOrWhiteSpace(modType)) { modificationType = ModificationDefinition.ResidueModificationType.UnknownType; } else { modificationType = ModificationDefinition.ModificationSymbolToModificationType(modType[0]); } var modDef = new ModificationDefinition(modSymbol, modificationMass, targetResidues, modificationType, massCorrectionTag) { ModificationMassAsText = modMassText }; ModificationDefs.Add(modDef); if (!mModDefMassesAsText.ContainsKey(massCorrectionTag)) { mModDefMassesAsText.Add(massCorrectionTag, modMassText); } } return(true); }
/// <summary> /// Returns the TypeDefintion of the type specified /// </summary> public TypeDefinition Type <T>() => ModificationDefinition.Type <T>();