public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context, FieldReference bpRef, IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes) { var module = context.Body.Method.Module; var targetTypeRef = GetBPReturnType(context, bpRef, node); TypeReference typeConverter; bpRef.HasTypeConverter(module, out typeConverter); return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes, unboxValueTypes); }
public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context, TypeReference targetTypeRef, IEnumerable<ICustomAttributeProvider> attributeProviders, IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes) { TypeReference typeConverter = null; foreach (var attributeProvider in attributeProviders) { CustomAttribute typeConverterAttribute; if ( (typeConverterAttribute = attributeProvider.CustomAttributes.FirstOrDefault( cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))) != null) { typeConverter = typeConverterAttribute.ConstructorArguments[0].Value as TypeReference; break; } } return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes, unboxValueTypes); }
static void SetDataTemplate(IElementNode parentNode, ElementNode node, ILContext parentContext, IXmlLineInfo xmlLineInfo) { var parentVar = parentContext.Variables[parentNode]; //Push the DataTemplate to the stack, for setting the template parentContext.IL.Emit(OpCodes.Ldloc, parentVar); //Create nested class // .class nested private auto ansi sealed beforefieldinit '<Main>c__AnonStorey0' // extends [mscorlib]System.Object var module = parentContext.Body.Method.Module; var anonType = new TypeDefinition( null, "<" + parentContext.Body.Method.Name + ">_anonXamlCDataTemplate_" + dtcount++, TypeAttributes.BeforeFieldInit | TypeAttributes.Sealed | TypeAttributes.NestedPrivate) { BaseType = module.TypeSystem.Object }; parentContext.Body.Method.DeclaringType.NestedTypes.Add(anonType); var ctor = anonType.AddDefaultConstructor(); var loadTemplate = new MethodDefinition("LoadDataTemplate", MethodAttributes.Assembly | MethodAttributes.HideBySig, module.TypeSystem.Object); anonType.Methods.Add(loadTemplate); var parentValues = new FieldDefinition("parentValues", FieldAttributes.Assembly, module.Import(typeof (object[]))); anonType.Fields.Add(parentValues); TypeReference rootType = null; var vdefRoot = parentContext.Root as VariableDefinition; if (vdefRoot != null) rootType = vdefRoot.VariableType; var fdefRoot = parentContext.Root as FieldDefinition; if (fdefRoot != null) rootType = fdefRoot.FieldType; var root = new FieldDefinition("root", FieldAttributes.Assembly, rootType); anonType.Fields.Add(root); //Fill the loadTemplate Body var templateIl = loadTemplate.Body.GetILProcessor(); templateIl.Emit(OpCodes.Nop); var templateContext = new ILContext(templateIl, loadTemplate.Body, parentValues) { Root = root }; node.Accept(new CreateObjectVisitor(templateContext), null); node.Accept(new SetNamescopesAndRegisterNamesVisitor(templateContext), null); node.Accept(new SetFieldVisitor(templateContext), null); node.Accept(new SetResourcesVisitor(templateContext), null); node.Accept(new SetPropertiesVisitor(templateContext), null); templateIl.Emit(OpCodes.Ldloc, templateContext.Variables[node]); templateIl.Emit(OpCodes.Ret); //Instanciate nested class var parentIl = parentContext.IL; parentIl.Emit(OpCodes.Newobj, ctor); //Copy required local vars parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance parentIl.Append(node.PushParentObjectsArray(parentContext)); parentIl.Emit(OpCodes.Stfld, parentValues); parentIl.Emit(OpCodes.Dup); //Duplicate the nestedclass instance if (parentContext.Root is VariableDefinition) parentIl.Emit(OpCodes.Ldloc, parentContext.Root as VariableDefinition); else if (parentContext.Root is FieldDefinition) { parentIl.Emit(OpCodes.Ldarg_0); parentIl.Emit(OpCodes.Ldfld, parentContext.Root as FieldDefinition); } else throw new InvalidProgramException(); parentIl.Emit(OpCodes.Stfld, root); //SetDataTemplate parentIl.Emit(OpCodes.Ldftn, loadTemplate); var funcCtor = module.Import(typeof (Func<>)) .MakeGenericInstanceType(module.TypeSystem.Object) .Resolve() .Methods.First(md => md.IsConstructor && md.Parameters.Count == 2) .MakeGeneric(module.TypeSystem.Object); parentIl.Emit(OpCodes.Newobj, module.Import(funcCtor)); var propertySetter = module.Import(typeof (IDataTemplate)).Resolve().Properties.First(p => p.Name == "LoadTemplate").SetMethod; parentContext.IL.Emit(OpCodes.Callvirt, module.Import(propertySetter)); }
public static IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ILContext context, ModuleDefinition module, ElementNode node) { GenericInstanceType markupExtension; IList<TypeReference> genericArguments; if (vardefref.VariableDefinition.VariableType.FullName == "Xamarin.Forms.Xaml.ArrayExtension" && vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1", out markupExtension, out genericArguments)) { var markExt = markupExtension.Resolve(); var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue"); var provideValue = module.Import(provideValueInfo); provideValue = module.Import(provideValue.MakeGeneric(markupExtension.GenericArguments.Select(tr => module.Import(tr)).ToArray())); var typeNode = node.Properties[new XmlName("", "Type")]; TypeReference arrayTypeRef; if (context.TypeExtensions.TryGetValue(typeNode, out arrayTypeRef)) vardefref.VariableDefinition = new VariableDefinition(module.Import(arrayTypeRef.MakeArrayType())); else vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First())); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]); foreach (var instruction in node.PushServiceProvider(context)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, provideValue); if (arrayTypeRef != null) yield return Instruction.Create(OpCodes.Castclass, module.Import(arrayTypeRef.MakeArrayType())); yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition); } else if (vardefref.VariableDefinition.VariableType.ImplementsGenericInterface("Xamarin.Forms.Xaml.IMarkupExtension`1", out markupExtension, out genericArguments)) { var markExt = markupExtension.Resolve(); var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue"); var provideValue = module.Import(provideValueInfo); provideValue = module.Import(provideValue.MakeGeneric(markupExtension.GenericArguments.Select(tr => module.Import(tr)).ToArray())); vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First())); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]); foreach (var instruction in node.PushServiceProvider(context)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, provideValue); yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition); } else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof (IMarkupExtension)))) { var markExt = module.Import(typeof (IMarkupExtension)).Resolve(); var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue"); var provideValue = module.Import(provideValueInfo); vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]); foreach (var instruction in node.PushServiceProvider(context)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, provideValue); yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition); } else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof (IValueProvider)))) { var markExt = module.Import(typeof (IValueProvider)).Resolve(); var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue"); var provideValue = module.Import(provideValueInfo); vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]); foreach (var instruction in node.PushServiceProvider(context)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, provideValue); yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition); } }
public static void SetPropertyValue(VariableDefinition parent, XmlName propertyName, INode valueNode, ILContext context, IXmlLineInfo iXmlLineInfo) { var elementType = parent.VariableType; var localName = propertyName.LocalName; var module = context.Body.Method.Module; var br = Instruction.Create(OpCodes.Nop); TypeReference declaringTypeReference; var handled = false; //If it's an attached BP, update elementType and propertyName var attached = GetNameAndTypeRef(ref elementType, propertyName.NamespaceURI, ref localName, context, iXmlLineInfo); //If the target is an event, connect // IL_0007: ldloc.0 // IL_0008: ldarg.0 // IL_0009: ldftn instance void class Xamarin.Forms.Xaml.XamlcTests.MyPage::OnButtonClicked(object, class [mscorlib]System.EventArgs) // IL_000f: newobj instance void class [mscorlib]System.EventHandler::'.ctor'(object, native int) // IL_0014: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Button::add_Clicked(class [mscorlib]System.EventHandler) var eventinfo = elementType.GetEvent(ed => ed.Name == localName); if (eventinfo != null) { var value = ((ValueNode)valueNode).Value; context.IL.Emit(OpCodes.Ldloc, parent); if (context.Root is VariableDefinition) context.IL.Emit(OpCodes.Ldloc, context.Root as VariableDefinition); else if (context.Root is FieldDefinition) { context.IL.Emit(OpCodes.Ldarg_0); context.IL.Emit(OpCodes.Ldfld, context.Root as FieldDefinition); } else throw new InvalidProgramException(); var declaringType = context.Body.Method.DeclaringType; if (declaringType.IsNested) declaringType = declaringType.DeclaringType; var handler = declaringType.AllMethods().FirstOrDefault(md => md.Name == value as string); if (handler == null) { throw new XamlParseException( string.Format("EventHandler \"{0}\" not found in type \"{1}\"", value, context.Body.Method.DeclaringType.FullName), iXmlLineInfo); } context.IL.Emit(OpCodes.Ldftn, handler); //FIXME: eventually get the right ctor instead fo the First() one, just in case another one could exists (not even sure it's possible). var ctor = module.Import(eventinfo.EventType.Resolve().GetConstructors().First()); ctor = ctor.ResolveGenericParameters(eventinfo.EventType, module); context.IL.Emit(OpCodes.Newobj, module.Import(ctor)); context.IL.Emit(OpCodes.Callvirt, module.Import(eventinfo.AddMethod)); return; } FieldReference bpRef = elementType.GetField(fd => fd.Name == localName + "Property" && fd.IsStatic && fd.IsPublic, out declaringTypeReference); if (bpRef != null) { bpRef = module.Import(bpRef.ResolveGenericParameters(declaringTypeReference)); bpRef.FieldType = module.Import(bpRef.FieldType); } //If Value is DynamicResource, SetDynamicResource VariableDefinition varValue; if (bpRef != null && valueNode is IElementNode && context.Variables.TryGetValue(valueNode as IElementNode, out varValue) && varValue.VariableType.FullName == typeof (DynamicResource).FullName) { var setDynamicResource = module.Import(typeof (IDynamicResourceHandler)).Resolve().Methods.First(m => m.Name == "SetDynamicResource"); var getKey = typeof (DynamicResource).GetProperty("Key").GetMethod; context.IL.Emit(OpCodes.Ldloc, parent); context.IL.Emit(OpCodes.Ldsfld, bpRef); context.IL.Emit(OpCodes.Ldloc, varValue); context.IL.Emit(OpCodes.Callvirt, module.Import(getKey)); context.IL.Emit(OpCodes.Callvirt, module.Import(setDynamicResource)); return; } //If Value is a BindingBase and target is a BP, SetBinding if (bpRef != null && valueNode is IElementNode && context.Variables.TryGetValue(valueNode as IElementNode, out varValue) && varValue.VariableType.InheritsFromOrImplements(module.Import(typeof (BindingBase)))) { //TODO: check if parent is a BP var setBinding = typeof (BindableObject).GetMethod("SetBinding", new[] { typeof (BindableProperty), typeof (BindingBase) }); context.IL.Emit(OpCodes.Ldloc, parent); context.IL.Emit(OpCodes.Ldsfld, bpRef); context.IL.Emit(OpCodes.Ldloc, varValue); context.IL.Emit(OpCodes.Callvirt, module.Import(setBinding)); return; } //If it's a BP, SetValue () // IL_0007: ldloc.0 // IL_0008: ldsfld class [Xamarin.Forms.Core]Xamarin.Forms.BindableProperty [Xamarin.Forms.Core]Xamarin.Forms.Label::TextProperty // IL_000d: ldstr "foo" // IL_0012: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.BindableObject::SetValue(class [Xamarin.Forms.Core]Xamarin.Forms.BindableProperty, object) if (bpRef != null) { //TODO: check if parent is a BP var setValue = typeof (BindableObject).GetMethod("SetValue", new[] { typeof (BindableProperty), typeof (object) }); if (valueNode is ValueNode) { context.IL.Emit(OpCodes.Ldloc, parent); context.IL.Emit(OpCodes.Ldsfld, bpRef); context.IL.Append(((ValueNode)valueNode).PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context), true, false)); context.IL.Emit(OpCodes.Callvirt, module.Import(setValue)); return; } if (valueNode is IElementNode) { var getPropertyReturnType = module.Import(typeof (BindableProperty).GetProperty("ReturnType").GetGetMethod()); //FIXME: this should check for inheritance too var isInstanceOfType = module.Import(typeof (Type).GetMethod("IsInstanceOfType", new[] { typeof (object) })); var brfalse = Instruction.Create(OpCodes.Nop); context.IL.Emit(OpCodes.Ldsfld, bpRef); context.IL.Emit(OpCodes.Call, getPropertyReturnType); context.IL.Emit(OpCodes.Ldloc, context.Variables[valueNode as IElementNode]); if (context.Variables[valueNode as IElementNode].VariableType.IsValueType) context.IL.Emit(OpCodes.Box, context.Variables[valueNode as IElementNode].VariableType); context.IL.Emit(OpCodes.Callvirt, isInstanceOfType); context.IL.Emit(OpCodes.Brfalse, brfalse); context.IL.Emit(OpCodes.Ldloc, parent); context.IL.Emit(OpCodes.Ldsfld, bpRef); context.IL.Emit(OpCodes.Ldloc, context.Variables[(IElementNode)valueNode]); if (context.Variables[valueNode as IElementNode].VariableType.IsValueType) context.IL.Emit(OpCodes.Box, context.Variables[valueNode as IElementNode].VariableType); context.IL.Emit(OpCodes.Callvirt, module.Import(setValue)); context.IL.Emit(OpCodes.Br, br); context.IL.Append(brfalse); handled = true; } } //If it's a property, set it // IL_0007: ldloc.0 // IL_0008: ldstr "foo" // IL_000d: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.Label::set_Text(string) PropertyDefinition property = elementType.GetProperty(pd => pd.Name == localName, out declaringTypeReference); MethodDefinition propertySetter; if (property != null && (propertySetter = property.SetMethod) != null && propertySetter.IsPublic) { module.Import(elementType.Resolve()); var propertySetterRef = module.Import(module.Import(propertySetter).ResolveGenericParameters(declaringTypeReference, module)); propertySetterRef.ImportTypes(module); var propertyType = property.ResolveGenericPropertyType(declaringTypeReference); ValueNode vnode = null; if ((vnode = valueNode as ValueNode) != null) { context.IL.Emit(OpCodes.Ldloc, parent); context.IL.Append(vnode.PushConvertedValue(context, propertyType, new ICustomAttributeProvider[] { property, propertyType.Resolve() }, valueNode.PushServiceProvider(context), false, true)); context.IL.Emit(OpCodes.Callvirt, propertySetterRef); context.IL.Append(br); return; } if (valueNode is IElementNode) { var vardef = context.Variables[(ElementNode)valueNode]; var implicitOperators = vardef.VariableType.GetMethods(md => md.IsPublic && md.IsStatic && md.IsSpecialName && md.Name == "op_Implicit", module).ToList(); MethodReference implicitOperator = null; if (implicitOperators.Any()) { foreach (var op in implicitOperators) { var cast = op.Item1; var opDeclTypeRef = op.Item2; var castDef = module.Import(cast).ResolveGenericParameters(opDeclTypeRef, module); var returnType = castDef.ReturnType; if (returnType.IsGenericParameter) returnType = ((GenericInstanceType)opDeclTypeRef).GenericArguments[((GenericParameter)returnType).Position]; if (returnType.FullName == propertyType.FullName && cast.Parameters[0].ParameterType.Name == vardef.VariableType.Name) { implicitOperator = castDef; break; } } } //TODO replace latest check by a runtime type check if (implicitOperator != null || vardef.VariableType.InheritsFromOrImplements(propertyType) || propertyType.FullName == "System.Object" || vardef.VariableType.FullName == "System.Object") { context.IL.Emit(OpCodes.Ldloc, parent); context.IL.Emit(OpCodes.Ldloc, vardef); if (implicitOperator != null) { // IL_000f: call !0 class [Xamarin.Forms.Core]Xamarin.Forms.OnPlatform`1<bool>::op_Implicit(class [Xamarin.Forms.Core]Xamarin.Forms.OnPlatform`1<!0>) context.IL.Emit(OpCodes.Call, module.Import(implicitOperator)); } else if (!vardef.VariableType.IsValueType && propertyType.IsValueType) context.IL.Emit(OpCodes.Unbox_Any, module.Import(propertyType)); else if (vardef.VariableType.IsValueType && propertyType.FullName == "System.Object") context.IL.Emit(OpCodes.Box, vardef.VariableType); context.IL.Emit(OpCodes.Callvirt, propertySetterRef); context.IL.Append(br); return; } handled = true; } } //If it's an already initialized property, add to it MethodDefinition propertyGetter; //TODO: check if property is assigned if (property != null && (propertyGetter = property.GetMethod) != null && propertyGetter.IsPublic) { var propertyGetterRef = module.Import(propertyGetter); propertyGetterRef = module.Import(propertyGetterRef.ResolveGenericParameters(declaringTypeReference, module)); var propertyType = propertyGetterRef.ReturnType.ResolveGenericParameters(declaringTypeReference); //TODO check md.Parameters[0] type var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault(); if (adderTuple != null) { var adderRef = module.Import(adderTuple.Item1); adderRef = module.Import(adderRef.ResolveGenericParameters(adderTuple.Item2, module)); if (valueNode is IElementNode) { context.IL.Emit(OpCodes.Ldloc, parent); context.IL.Emit(OpCodes.Callvirt, propertyGetterRef); context.IL.Emit(OpCodes.Ldloc, context.Variables[(ElementNode)valueNode]); context.IL.Emit(OpCodes.Callvirt, adderRef); if (adderRef.ReturnType.FullName != "System.Void") context.IL.Emit(OpCodes.Pop); context.IL.Append(br); return; } } } if (!handled) { throw new XamlParseException(string.Format("No property, bindable property, or event found for '{0}'", localName), iXmlLineInfo); } context.IL.Append(br); }
private static void ApplyModHackfixes(MonoModder modder) { // See Coroutine.ForceDelayedSwap for more info. // Older mods are built with this delay in mind, except for hooks. MethodInfo coroutineWrapper = (_Relinking?.Dependencies?.Find(dep => dep.Name == CoreModule.Instance.Metadata.Name) ?.Version ?? new Version(0, 0, 0, 0)) < new Version(1, 2563, 0) ? typeof(CoroutineDelayHackfixHelper).GetMethod("Wrap") : null; if (coroutineWrapper == null && _Relinking == null && !( // Some mods require additional special care. _Relinking.Name == "AdventureHelper" // Don't check the version for this mod as the hackfix is harmless. )) { return; // No hackfixes necessary. } void CrawlMethod(MethodDefinition method) { string methodID = method.GetID(); if (coroutineWrapper != null && method.HasBody && method.ReturnType.FullName == "System.Collections.IEnumerator") { using (ILContext ctx = new ILContext(method)) { ctx.Invoke(ctx => { ILCursor c = new ILCursor(ctx); while (c.TryGotoNext(i => i.MatchRet())) { c.Next.OpCode = OpCodes.Ldstr; c.Next.Operand = methodID; c.Index++; // Scan the nested IEnumerator type if it's already getting rid of the delay itself. c.Emit( method.GetCustomAttribute("System.Runtime.CompilerServices.IteratorStateMachineAttribute") is CustomAttribute ca_IteratorStateMachine && ca_IteratorStateMachine.ConstructorArguments[0].Value is TypeReference iteratorType && iteratorType.SafeResolve()?.FindMethod("MoveNext") is MethodDefinition iteratorMethod && (iteratorMethod.Body?.Instructions.Any(i => i.Operand is MethodReference callee && callee.Name == "MoveNext") ?? false) ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); c.Emit(OpCodes.Call, coroutineWrapper); c.Emit(OpCodes.Ret); } }); } } if (_ModHackfixNoAtlasFallback.Contains(methodID)) { using (ILContext ctx = new ILContext(method)) { ctx.Invoke(ctx => { ILCursor c = new ILCursor(ctx); c.Emit(OpCodes.Ldsfld, typeof(GFX).GetField("Game")); c.Emit(OpCodes.Ldnull); c.Emit(OpCodes.Callvirt, typeof(patch_Atlas).GetMethod("PushFallback")); while (c.TryGotoNext(MoveType.AfterLabel, i => i.MatchRet())) { c.Emit(OpCodes.Ldsfld, typeof(GFX).GetField("Game")); c.Emit(OpCodes.Callvirt, typeof(patch_Atlas).GetMethod("PopFallback")); c.Emit(OpCodes.Pop); c.Index++; } }); } } } void CrawlType(TypeDefinition type) { foreach (MethodDefinition method in type.Methods) { CrawlMethod(method); } foreach (TypeDefinition nested in type.NestedTypes) { CrawlType(nested); } } foreach (TypeDefinition type in modder.Module.Types) { CrawlType(type); } }
// We're looking for these instructions and we want to delete all but the first one // IL_0114: stfld int32 Terraria.Player::manaRegen // // IL_0119: ldarg.0 // IL_011A: ldflda valuetype [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2 Terraria.Entity::velocity // IL_011F: ldfld float32 [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2::X // IL_0124: ldc.r4 0.0 // IL_0129: bne.un.s IL_013D // // IL_012B: ldarg.0 // IL_012C: ldflda valuetype [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2 Terraria.Entity::velocity // IL_0131: ldfld float32 [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2::Y // IL_0136: ldc.r4 0.0 // IL_013B: beq.s IL_0150 // // IL_013D: ldarg.0 // IL_013E: ldfld int32[] Terraria.Player::grappling // IL_0143: ldc.i4.0 // IL_0144: ldelem.i4 // IL_0145: ldc.i4.0 // IL_0146: bge.s IL_0150 // // IL_0148: ldarg.0 // IL_0149: ldfld bool Terraria.Player::manaRegenBuff // IL_014E: brfalse.s IL_0165 private void Player_UpdateManaRegen(ILContext ilContext) { ILCursor cursor = new ILCursor(ilContext); Func <Instruction, bool>[] ilToRemove = { instruction => instruction.MatchLdarg(0), instruction => instruction.MatchLdflda <Entity>("velocity"), instruction => instruction.MatchLdfld <Vector2>("X"), instruction => instruction.MatchLdcR4(0.0f), instruction => instruction.Match(OpCodes.Bne_Un_S), instruction => instruction.MatchLdarg(0), instruction => instruction.MatchLdflda <Entity>("velocity"), instruction => instruction.MatchLdfld <Vector2>("Y"), instruction => instruction.MatchLdcR4(0.0f), instruction => instruction.Match(OpCodes.Beq_S), instruction => instruction.MatchLdarg(0), instruction => instruction.MatchLdfld <Terraria.Player>("grappling"), instruction => instruction.MatchLdcI4(0), instruction => instruction.MatchLdelemI4(), instruction => instruction.MatchLdcI4(0), instruction => instruction.Match(OpCodes.Bge_S), instruction => instruction.MatchLdarg(0), instruction => instruction.MatchLdfld <Terraria.Player>("manaRegenBuff"), instruction => instruction.Match(OpCodes.Brfalse_S) }; bool found = false; //whether or not we have matched our 1 + 19 instructions int attemptCount = 0; //used for logging string loggedInstructions = ""; while (cursor.TryGotoNext( // Look for when we store "manaRegen". This occurs just before our ilToRemove instructions instruction => instruction.MatchStfld <Terraria.Player>("manaRegen"))) { ILCursor backup = cursor.Clone(); found = true; foreach (Func <Instruction, bool> il in ilToRemove) { // Move cursor to next instruction and see if it doesn't match cursor.GotoNext(); loggedInstructions += attemptCount + ": " + cursor.Next?.OpCode + "\n"; if (!il(cursor.Next)) { found = false; break; } } if (!found) { continue; } // We use the backup cursor which was at the original position just before the 19 instructions backup.GotoNext(); // remove the 19 instructions for (int i = 0; i < ilToRemove.Length; i++) { backup.Remove(); } break; } if (!found) { throw new Exception("Instructions not found; unable to patch. Sorry!\n" + loggedInstructions); } }
public IEnumerable <Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context) { INode sourceNode = null; ((IElementNode)node).Properties.TryGetValue(new XmlName("", "Source"), out sourceNode); if (sourceNode == null) { ((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Source"), out sourceNode); } INode styleNode = null; if (!((IElementNode)node).Properties.TryGetValue(new XmlName("", "Style"), out styleNode) && !((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Style"), out styleNode) && ((IElementNode)node).CollectionItems.Count == 1) { styleNode = ((IElementNode)node).CollectionItems[0]; } if (sourceNode != null && styleNode != null) { throw new XamlParseException("StyleSheet can not have both a Source and a content", node); } if (sourceNode == null && styleNode == null) { throw new XamlParseException("StyleSheet require either a Source or a content", node); } if (styleNode != null && !(styleNode is ValueNode)) { throw new XamlParseException("Style property or Content is not a string literal", node); } if (sourceNode != null && !(sourceNode is ValueNode)) { throw new XamlParseException("Source property is not a string literal", node); } if (styleNode != null) { var style = (styleNode as ValueNode).Value as string; yield return(Create(Ldstr, style)); yield return(Create(Call, module.ImportMethodReference(("System.Maui.Core", "System.Maui.StyleSheets", "StyleSheet"), methodName: "FromString", parameterTypes: new[] { ("mscorlib", "System", "String") },
private static void GetVRLookInput(ILContext il) { ILCursor c = new ILCursor(il); //Remove target info from stack. Why is it pushed so early anyway? c.GotoNext(x => x.MatchLdflda(typeof(RoR2.CameraModes.CameraModeBase.CameraModeContext), "targetInfo") ); c.Index--; c.RemoveRange(2); //Fixing brtrue label c.GotoNext(x => x.MatchLdloca(6) ); ILLabel sussyLabel = c.IncomingLabels.First(); c.Index++; sussyLabel.Target = c.Next; c.Index--; //Replacing input vectors c.Remove(); c.Index++; c.RemoveRange(6); c.EmitDelegate <Func <Rewired.Player, Vector2> >((player) => { return(ModConfig.InitialMotionControlsValue ? Vector2.zero : new Vector2(player.GetAxisRaw(ModConfig.SnapTurn.Value ? 26 : 2), ModConfig.TempLockedCameraPitchValue ? 0 : player.GetAxisRaw(3))); }); c.Emit(OpCodes.Stloc_S, (byte)6); c.Remove(); c.Index++; c.RemoveRange(6); c.EmitDelegate <Func <Rewired.Player, Vector2> >((player) => { return(new Vector2(player.GetAxisRaw(16), ModConfig.TempLockedCameraPitchValue ? 0 : player.GetAxisRaw(17))); }); c.Emit(OpCodes.Stloc_S, (byte)7); int startIndex = c.Index; //Removing aim assist c.GotoNext(x => x.MatchCall(typeof(RoR2.CameraModes.CameraModePlayerBasic), "PerformAimAssist")); c.Index -= 3; c.RemoveRange(4); //Adding snap turn code c.GotoNext(x => x.MatchLdflda(typeof(RoR2.CameraModes.CameraModeBase.CollectLookInputResult), "lookInput")); c.Index--; int snapTurnIndex = c.Index; c.Emit(OpCodes.Ldarg_3); c.Emit(OpCodes.Ldloc_S, (byte)6); c.Emit(OpCodes.Ldloc_S, (byte)7); c.EmitDelegate <Func <Vector2, Vector2, Vector2> >((mouseVector, joystickVector) => { wasTurningLeft = isTurningLeft; wasTurningRight = isTurningRight; isTurningLeft = joystickVector.x < -0.8f; isTurningRight = joystickVector.x > 0.8f; if (!ModConfig.MotionControlsEnabled) { isTurningLeft = isTurningLeft || mouseVector.x < -0.8f; isTurningRight = isTurningRight || mouseVector.x > 0.8f; } Vector2 result = Vector2.zero; if (justTurnedLeft) { result.x = -ModConfig.SnapTurnAngle.Value; } else if (justTurnedRight) { result.x = ModConfig.SnapTurnAngle.Value; } if ((isTurningLeft || isTurningRight) && timeSinceLastSnapTurn <= ModConfig.SnapTurnHoldDelay.Value) { timeSinceLastSnapTurn += Time.deltaTime; } else { timeSinceLastSnapTurn = 0; } return(result); }); c.Emit(OpCodes.Stfld, typeof(RoR2.CameraModes.CameraModeBase.CollectLookInputResult).GetField("lookInput")); //Removing sensitivity modifications; var labels = il.GetIncomingLabels(c.Next); c.RemoveRange(24); foreach (var label in labels) { label.Target = c.Next; } //Adding jump after smooth turn code ILLabel endLabel = c.MarkLabel(); c.Index = snapTurnIndex; c.Emit(OpCodes.Br_S, endLabel); //Adding snap turn condition and jump to snap turn ILLabel snapTurnLabel = c.MarkLabel(); c.Index = startIndex; c.EmitDelegate <Func <bool> >(() => { return(ModConfig.SnapTurn.Value); }); c.Emit(OpCodes.Brtrue_S, snapTurnLabel); }
private void FixedUpdate_Il3(ILContext il) { BindingFlags allFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; FieldInfo characterBody = typeof(HuntressTracker).GetField("characterBody", allFlags); FieldInfo trackingTarget = typeof(HuntressTracker).GetField("trackingTarget", allFlags); FieldInfo maxDistance = typeof(HuntressTracker).GetField("maxTrackingDistance", allFlags); FieldInfo trackerUpdateStopwatch = typeof(HuntressTracker).GetField("trackerUpdateStopwatch", allFlags); FieldInfo trackerUpdateFrequency = typeof(HuntressTracker).GetField("trackerUpdateFrequency", allFlags); FieldInfo indicator = typeof(HuntressTracker).GetField("indicator", allFlags); FieldInfo indicator_targetTransform = typeof(RoR2.Indicator).GetField("targetTransform", allFlags); FieldInfo hurtBox_group = typeof(HurtBox).GetField(nameof(HurtBox.hurtBoxGroup), allFlags); FieldInfo mainHurtBox = typeof(HurtBoxGroup).GetField(nameof(HurtBoxGroup.mainHurtBox), allFlags); //MethodInfo fixedDeltaTime = typeof(Time).GetProperty( "fixedDeltaTime", allFlags ).GetGetMethod(); MethodInfo object_implicit = typeof(UnityEngine.Object).GetMethod("op_Implicit", allFlags); HurtBox CastTarget(CharacterBody body, Single range) { var ray = body.inputBank.GetAimRay(); var myTeam = body.teamComponent.teamIndex; var hits = Physics.SphereCastNonAlloc(ray, 0.75f, hitResultsBuffer, range, LayerIndex.entityPrecise.mask, QueryTriggerInteraction.UseGlobal); Single worldDist = Single.PositiveInfinity; if (hits > 0 && Physics.Raycast(ray, out RaycastHit hit, range, LayerIndex.world.mask, QueryTriggerInteraction.UseGlobal)) { worldDist = hit.distance + 1f; } HurtBox result = null; Single bestDistance = Single.PositiveInfinity; for (Int32 i = 0; i < hits; ++i) { var res = hitResultsBuffer[i]; if (res.distance > bestDistance) { continue; } if (res.distance > worldDist) { continue; } var col = res.collider; if (col is null) { continue; } var hb = col.GetComponent <HurtBox>(); if (hb is null) { continue; } var hc = hb.healthComponent; if (hc is null) { continue; } if (hc == body.healthComponent) { continue; } if (!FriendlyFireManager.ShouldDirectHitProceed(hc, myTeam)) { continue; } result = hb; bestDistance = res.distance; } return(result); } var cursor = new ILCursor(il); _ = cursor.Emit(OpCodes.Stfld, trackingTarget); _ = cursor.Emit(OpCodes.Ldarg_0); _ = cursor.Emit(OpCodes.Ldfld, indicator); _ = cursor.Emit(OpCodes.Ldarg_0); _ = cursor.Emit(OpCodes.Ldfld, trackingTarget); _ = cursor.Emit(OpCodes.Ldfld, hurtBox_group); _ = cursor.Emit(OpCodes.Ldfld, mainHurtBox); _ = cursor.Emit <Component>(OpCodes.Callvirt, "get_transform"); _ = cursor.Emit(OpCodes.Stfld, indicator_targetTransform); _ = cursor.Emit(OpCodes.Ldarg_0); _ = cursor.Emit(OpCodes.Ldarg_0); _ = cursor.Emit(OpCodes.Ldfld, trackerUpdateStopwatch); _ = cursor.EmitDelegate <Func <Single> >(() => Time.fixedDeltaTime); _ = cursor.Emit(OpCodes.Add); _ = cursor.Emit(OpCodes.Stfld, trackerUpdateStopwatch); ILLabel normalPath = cursor.MarkLabel(); _ = cursor.Emit(OpCodes.Pop); _ = cursor.Emit(OpCodes.Pop); ILLabel breakLabel = null; _ = cursor.GotoNext(MoveType.AfterLabel, x => x.MatchBltUn(out breakLabel)); cursor.Index = 0; _ = cursor.Emit(OpCodes.Ldarg_0); _ = cursor.Emit(OpCodes.Ldarg_0); _ = cursor.Emit(OpCodes.Ldfld, characterBody); _ = cursor.Emit(OpCodes.Ldarg_0); _ = cursor.Emit(OpCodes.Ldfld, maxDistance); _ = cursor.EmitDelegate <Func <CharacterBody, Single, HurtBox> >(CastTarget); _ = cursor.Emit(OpCodes.Dup); _ = cursor.EmitDelegate <Func <HurtBox, Boolean> >((hb) => hb); _ = cursor.Emit(OpCodes.Brfalse, normalPath); _ = cursor.GotoLabel(normalPath, MoveType.Before); _ = cursor.Emit(OpCodes.Br, breakLabel); }
private void RemoveSummonDamageBonus(ILContext il) { // FNA IL for this method seems to be different. if (Platform.IsWindows) { ILCursor c = new ILCursor(il); /* Match the base float damage of Fungal Clumps * // Projectile.NewProjectile(player.Center.X, player.Center.Y, 0f, -1f, ModContent.ProjectileType<FungalClumpMinion>(), (int)(10f * player.MinionDamage()), 1f, player.whoAmI); * IL_0047: ldarg.1 * IL_0048: callvirt instance valuetype [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2 [Terraria]Terraria.Entity::get_Center() * IL_004d: ldfld float32 [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2::X * IL_0052: ldarg.1 * IL_0053: callvirt instance valuetype [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2 [Terraria]Terraria.Entity::get_Center() * IL_0058: ldfld float32 [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2::Y * IL_005d: ldc.r4 0.0 * IL_0062: ldc.r4 -1 * IL_0067: call int32 [Terraria]Terraria.ModLoader.ModContent::ProjectileType<class CalamityMod.Projectiles.Summon.FungalClumpMinion>() * IL_006c: ldc.r4 10 * IL_0071: ldarg.1 * IL_0072: call float32 CalamityMod.CalamityUtils::MinionDamage(class [Terraria]Terraria.Player) * IL_0077: mul * IL_0078: conv.i4 * IL_0079: ldc.r4 1 * IL_007e: ldarg.1 * IL_007f: ldfld int32 [Terraria]Terraria.Entity::whoAmI * IL_0084: ldc.r4 0.0 * IL_0089: ldc.r4 0.0 * // { * IL_008e: call int32 [Terraria]Terraria.Projectile::NewProjectile(float32, float32, float32, float32, int32, int32, float32, int32, float32, float32) * // } * IL_0093: pop */ if (!c.TryGotoNext(i => i.MatchLdcR4(10))) { ModContent.GetInstance <CataclysmMod>().Logger.Warn("[IL] Unable to match ldc.r4 \"10\"!"); return; } c.Index++; // Replace with a regular int c.Emit(OpCodes.Pop); c.Emit(OpCodes.Ldc_I4, 10); c.Index++; /* Remove the IL code responsible for multiplying it based on summon damage * IL_0071: ldarg.1 * IL_0072: call float32 CalamityMod.CalamityUtils::MinionDamage(class [Terraria]Terraria.Player) * IL_0077: mul * IL_0078: conv.i4 */ c.RemoveRange(4); ModContent.GetInstance <CataclysmMod>().Logger.Info("[IL] Finished patching!"); } else { ModContent.GetInstance <CataclysmMod>().Logger.Warn("[IL] Linux or Mac OS detected, skipping Funal Clump IL editing..."); } }
public void HookAdjustAngler(ILContext il) { var c = new ILCursor(il).Goto(0); // we force reset the angler quest if not on a server if (!c.TryGotoNext(i => i.MatchLdsfld(typeof(Main).GetField(nameof(Main.anglerWhoFinishedToday))))) { throw new Exception("Can't patch force reset"); } if (!c.TryGotoNext(i => i.MatchCall(typeof(Lang).GetMethod(nameof(Lang.AnglerQuestChat))))) { throw new Exception("Can't patch force reset"); } ILLabel label = il.DefineLabel(); c.Emit(Brtrue_S, label); c.Emit(Ldloc_S, (byte)50); c.Index += 2; c.MarkLabel(label); if (!c.TryGotoNext(i => i.MatchCall(typeof(AchievementsHelper).GetMethod(nameof(AchievementsHelper.HandleAnglerService))))) { throw new Exception("Can't patch force reset"); } c.Emit(Call, typeof(NoFishTimer).GetMethod(nameof(NoFishTimer.AnglerQuestSwap))); c.EmitDelegate <Action>(() => { if (!NoFishWorld.serverConfig.DisableAnglerTimer) { Main.npcChatText = Lang.AnglerQuestChat(true); } else if (Main.netMode != 1) { Main.npcChatText = Lang.AnglerQuestChat(); } }); // add reroll button c.Goto(0); if (!c.TryGotoNext(i => i.MatchLdcI4(NPCID.Angler))) { throw new Exception("Can't patch reroll button"); } if (!c.TryGotoNext(i => i.MatchLdcI4(NPCID.Angler))) { throw new Exception("Can't patch reroll button"); } c.Index += 2; label = il.DefineLabel(); c.EmitDelegate <Func <bool> >(() => NoFishWorld.serverConfig.RerollPrice > 0); c.Emit(Brfalse_S, label); c.EmitDelegate <Func <string> >(() => { int num13 = 0, num14 = 0, num15 = 0, num16 = 0; int num17 = NoFishWorld.serverConfig.RerollPrice; string text2 = ""; if (num17 >= 1000000) { num13 = num17 / 1000000; num17 -= num13 * 1000000; } if (num17 >= 10000) { num14 = num17 / 10000; num17 -= num14 * 10000; } if (num17 >= 100) { num15 = num17 / 100; num17 -= num15 * 100; } if (num17 >= 1) { num16 = num17; } if (num13 > 0) { object obj5 = text2; text2 = string.Concat(new object[] { obj5, num13, " ", Language.GetText("LegacyInterface.15").Value, " " }); } if (num14 > 0) { object obj6 = text2; text2 = string.Concat(new object[] { obj6, num14, " ", Language.GetText("LegacyInterface.16").Value, " " }); } if (num15 > 0) { object obj7 = text2; text2 = string.Concat(new object[] { obj7, num15, " ", Language.GetText("LegacyInterface.17").Value, " " }); } if (num16 > 0) { object obj8 = text2; text2 = string.Concat(new object[] { obj8, num16, " ", Language.GetText("LegacyInterface.18").Value, " " }); } text2 = text2.Substring(0, text2.Length - 1); return(Language.GetTextValue("Mods.NoFishTimer.Dialog.Reroll") + " (" + text2 + ")"); }); c.Emit(Stloc_S, (byte)10); c.EmitDelegate <Func <Color> >(() => { int num13 = 0, num14 = 0, num15 = 0, num16 = 0; int num17 = NoFishWorld.serverConfig.RerollPrice; if (num17 >= 1000000) { num13 = num17 / 1000000; num17 -= num13 * 1000000; } if (num17 >= 10000) { num14 = num17 / 10000; num17 -= num14 * 10000; } if (num17 >= 100) { num15 = num17 / 100; num17 -= num15 * 100; } if (num17 >= 1) { num16 = num17; } float num18 = Main.mouseTextColor / 255f; if (num13 > 0) { return(new Color((byte)(220f * num18), (byte)(220f * num18), (byte)(198f * num18), Main.mouseTextColor)); } else if (num14 > 0) { return(new Color((byte)(224f * num18), (byte)(201f * num18), (byte)(92f * num18), Main.mouseTextColor)); } else if (num15 > 0) { return(new Color((byte)(181f * num18), (byte)(192f * num18), (byte)(193f * num18), Main.mouseTextColor)); } return(new Color((byte)(246f * num18), (byte)(138f * num18), (byte)(96f * num18), Main.mouseTextColor)); }); c.Emit(Stloc_S, (byte)2); c.MarkLabel(label); }
private void HookBeeType(ILContext il) { var c = new ILCursor(il); // Try to find where 566 is placed onto the stack if (!c.TryGotoNext(i => i.MatchLdcI4(566))) { return; // Patch unable to be applied } // Showcase different patch approaches if (implementation == 0) { // Move the cursor after 566 and onto the ret op. c.Index++; // Push the Player instance onto the stack c.Emit(Ldarg_0); // Call a delegate using the int and Player from the stack. c.EmitDelegate <Func <int, Player, int> >((returnValue, player) => { // Regular c# code if (player.GetModPlayer <ExamplePlayer>().strongBeesUpgrade&& Main.rand.NextBool(10) && Main.ProjectileUpdateLoopIndex == -1) { return(ProjectileID.Beenade); } return(returnValue); }); } else if (implementation == 1) { // Make a label to use later var label = c.DefineLabel(); // Push the Player instance onto the stack c.Emit(Ldarg_0); // Call a delegate popping the Player from the stack and pushing a bool c.EmitDelegate <Func <Player, bool> >(player => player.GetModPlayer <ExamplePlayer>().strongBeesUpgrade&& Main.rand.NextBool(10) && Main.ProjectileUpdateLoopIndex == -1); // if the bool on the stack is false, jump to label c.Emit(Brfalse, label); // Otherwise, push ProjectileID.Beenade and return c.Emit(Ldc_I4, ProjectileID.Beenade); c.Emit(Ret); // Set the label to the current cursor, which is still the instruction pushing 566 (which is followed by Ret) c.MarkLabel(label); } else { var label = c.DefineLabel(); // Here we simply adapt the dnSpy output. This approach is tedious but easier if you don't understand IL instructions. c.Emit(Ldarg_0); // We need to make sure to pass in FieldInfo or MethodInfo into Call instructions. // Here we show how to retrieve a generic version of a MethodInfo c.Emit(Call, typeof(Player).GetMethod("GetModPlayer", new Type[] { }).MakeGenericMethod(typeof(ExamplePlayer))); // nameof helps avoid spelling mistakes c.Emit(Ldfld, typeof(ExamplePlayer).GetField(nameof(ExamplePlayer.strongBeesUpgrade))); c.Emit(Brfalse_S, label); c.Emit(Ldsfld, typeof(Main).GetField(nameof(Main.rand))); // Ldc_I4_S expects an int8, aka an sbyte. Failure to cast correctly will crash the game c.Emit(Ldc_I4_S, (sbyte)10); c.Emit(Call, typeof(Utils).GetMethod("NextBool", new Type[] { typeof(Terraria.Utilities.UnifiedRandom), typeof(int) })); c.Emit(Brfalse_S, label); // You may be tempted to write c.Emit(Ldsfld, Main.ProjectileUpdateLoopIndex);, this won't work and will simply use the value of the field at patch time. That will crash. c.Emit(Ldsfld, typeof(Main).GetField(nameof(Main.ProjectileUpdateLoopIndex))); c.Emit(Ldc_I4_M1); c.Emit(Bne_Un_S, label); c.Emit(Ldc_I4, ProjectileID.Beenade); c.Emit(Ret); // As Emit has been inserting and advancing the cursor index, we are still pointing at the 566 instruction. // All the branches in the dnspy output jumped to this instruction, so we set the label to this instruction. c.MarkLabel(label); } // change implementation every time the mod is reloaded implementation = (implementation + 1) % 3; }
#pragma warning disable IDE0051 private static void Main_DrawPlayer(ILContext il) { ILCursor c = new ILCursor(il); ILHelper.CompleteLog(c, beforeEdit: true); /* Edit: Adding a specific conditional for item frames on the held item drawing * * Main.itemTexture[type18], * new Vector2((float)((int)(vector.X - Main.screenPosition.X)), (float)((int)(vector.Y - Main.screenPosition.Y))), * new Rectangle?(new Rectangle(0, 0, Main.itemTexture[type18].Width, Main.itemTexture[type18].Height)), * ^ Edit goes where this parameter is * * IL_C098: sub * IL_C099: conv.i4 * IL_C09A: conv.r4 * IL_C09B: newobj instance void [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2::.ctor(float32, float32) * === EDIT GOES HERE === * IL_C0A0: ldc.i4.0 * IL_C0A1: ldc.i4.0 * IL_C0A2: ldsfld class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.Texture2D[] Terraria.Main::itemTexture * IL_C0A7: ldloc V_299 * IL_C0AB: nop * IL_C0AC: nop * IL_C0AD: ldelem.ref * IL_C0AE: callvirt instance int32 [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.Texture2D::get_Width() * IL_C0B3: ldsfld class [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.Texture2D[] Terraria.Main::itemTexture * IL_C0B8: ldloc V_299 * IL_C0BC: nop * IL_C0BD: nop * IL_C0BE: ldelem.ref * IL_C0BF: callvirt instance int32 [Microsoft.Xna.Framework.Graphics]Microsoft.Xna.Framework.Graphics.Texture2D::get_Height() * IL_C0C4: newobj instance void [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Rectangle::.ctor(int32, int32, int32, int32) * IL_C0C9: newobj instance void valuetype [mscorlib]System.Nullable`1<valuetype [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Rectangle>::.ctor(!0) * IL_C0CE: ldarg.1 * === BRANCH TO ABOVE STATEMENT IS ADDED === */ if (!c.TryGotoNext(MoveType.Before, i => i.MatchNewobj(ILHelper.Vector2_ctor_float_float), i => i.MatchLdcI4(0), i => i.MatchLdcI4(0), i => i.MatchLdsfld(ILHelper.Main_itemTexture), i => i.MatchLdloc(299), i => i.MatchNop(), i => i.MatchNop(), i => i.MatchLdelemRef(), i => i.MatchCallvirt(ILHelper.Texture2D_get_Width), i => i.MatchLdsfld(ILHelper.Main_itemTexture), i => i.MatchLdloc(299), i => i.MatchNop(), i => i.MatchNop(), i => i.MatchLdelemRef(), i => i.MatchCallvirt(ILHelper.Texture2D_get_Height), i => i.MatchNewobj(ILHelper.Rectangle_ctor_int_int_int_int), i => i.MatchNewobj(ILHelper.Nullable_Rectangle_ctor_Rectangle))) { goto bad_il; } c.Index++; //Put a branch target here for the "false" case ILLabel origCode = c.MarkLabel(); //Go to after the nullable ctor, add a branch target there, then go back ILLabel atNullableRectangle_ctor = c.DefineLabel(); c.Index += 15; c.MarkLabel(atNullableRectangle_ctor); c.Index -= 15; //Emit the things c.Emit(OpCodes.Ldloc, 299); c.EmitDelegate <Func <int, bool> >(itemType => itemType == ModContent.ItemType <TransportJunctionItem>()); c.Emit(OpCodes.Brfalse, origCode); c.Emit(OpCodes.Ldarg_1); c.EmitDelegate <Func <Player, Rectangle> >(player => new Rectangle(player.HeldItem.placeStyle * 18, 0, 18, 18)); c.Emit(OpCodes.Br, atNullableRectangle_ctor); ILHelper.UpdateInstructionOffsets(c); ILHelper.CompleteLog(c, beforeEdit: false); return; bad_il: TechMod.Instance.Logger.Error("Could not fully edit method \"Terraria.Main.DrawPlayer(Player, Vector2, float, Vector2, [float])\""); }
private void ProjectileAssignTarget(ILContext il) { var c = new ILCursor(il); bool ILFound; ILFound = c.TryGotoNext( x => x.MatchLdloc(2), x => x.MatchCallOrCallvirt <UnityEngine.Object>("op_Implicit")); if (!ILFound) { ilFailed = true; KevinsAdditionsPlugin._logger.LogError("Failed to apply Seeking Stone IL patch (ProjectileAssignTarget), item will not work; target instructions not found"); return; } c.Emit(OpCodes.Ldloc_0); c.Emit(OpCodes.Ldarg_1); c.Emit(OpCodes.Ldloc, 4); c.Emit(OpCodes.Ldloc, 5); c.EmitDelegate <Action <GameObject, FireProjectileInfo, ProjectileTargetComponent, ProjectileSimple> >((gameObject, fireProjectileInfo, targetComponent, projectileSimple) => { var cpt = fireProjectileInfo.owner.GetComponent <SeekingStoneComponent>(); if (!cpt || !projectileSimple) { return; } if (fireProjectileInfo.target == null && cpt.cachedIcnt > 0 && cpt.target) { if (!targetComponent) { targetComponent = gameObject.AddComponent <ProjectileTargetComponent>(); } if (gameObject.GetComponent <ProjectileDirectionalTargetFinder>()) { UnityEngine.Object.Destroy(gameObject.GetComponent <ProjectileDirectionalTargetFinder>()); } if (gameObject.GetComponent <ProjectileSphereTargetFinder>()) { UnityEngine.Object.Destroy(gameObject.GetComponent <ProjectileSphereTargetFinder>()); } //This sets the gameObject's forward to be the aim direction so it's easier to work with /*gameObject.transform.rotation = Util.QuaternionSafeLookRotation(cpt.body.GetComponent<InputBankTest>().aimDirection); * * gameObject.GetComponent<Rigidbody>().rotation = gameObject.transform.rotation; * if(gameObject.GetComponent<Rigidbody>().angularVelocity != Vector3.zero) * { * KevinsAdditionsPlugin._logger.LogError("Angular Velocity is not zero. Setting to zero"); * gameObject.GetComponent<Rigidbody>().angularVelocity = Vector3.zero; * }*/ projectileSimple.updateAfterFiring = true; MaintainTarget projectileFinderComponent = gameObject.AddComponent <MaintainTarget>(); var steerComponent = gameObject.GetComponent <ProjectileSteerTowardTarget>(); if (!steerComponent) { steerComponent = gameObject.AddComponent <ProjectileSteerTowardTarget>(); } if (gameObject.GetComponent <Rigidbody>().useGravity) { steerComponent.yAxisOnly = true; projectileFinderComponent.isAffectedByGravity = true; } steerComponent.rotationSpeed = 80f - 80f / (1f + 0.2f * cpt.cachedIcnt); steerComponent.transform = gameObject.transform; } }); }
public IEnumerable <Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context) { yield break; }
private void CutsceneWarpTargetMirror(ILContext il) { this.CutsceneWarpTarget(il); this.CutsceneWarpMirrorFakeBSide(il); }
public IEnumerable <Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context) { INode sourceNode = null; ((IElementNode)node).Properties.TryGetValue(new XmlName("", "Source"), out sourceNode); if (sourceNode == null) { ((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Source"), out sourceNode); } INode styleNode = null; if (!((IElementNode)node).Properties.TryGetValue(new XmlName("", "Style"), out styleNode) && !((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Style"), out styleNode) && ((IElementNode)node).CollectionItems.Count == 1) { styleNode = ((IElementNode)node).CollectionItems[0]; } if (sourceNode != null && styleNode != null) { throw new XamlParseException($"StyleSheet can not have both a Source and a content", node); } if (sourceNode == null && styleNode == null) { throw new XamlParseException($"StyleSheet require either a Source or a content", node); } if (styleNode != null && !(styleNode is ValueNode)) { throw new XamlParseException($"Style property or Content is not a string literal", node); } if (sourceNode != null && !(sourceNode is ValueNode)) { throw new XamlParseException($"Source property is not a string literal", node); } if (styleNode != null) { var style = (styleNode as ValueNode).Value as string; yield return(Create(Ldstr, style)); var fromString = module.ImportReference(typeof(StyleSheets.StyleSheet).GetMethods().FirstOrDefault(mi => mi.Name == nameof(StyleSheets.StyleSheet.FromString) && mi.GetParameters().Length == 1)); yield return(Create(Call, module.ImportReference(fromString))); } else { string source = (sourceNode as ValueNode)?.Value as string; INode rootNode = node; while (!(rootNode is ILRootNode)) { rootNode = rootNode.Parent; } var rootTargetPath = RDSourceTypeConverter.GetPathForType(module, ((ILRootNode)rootNode).TypeReference); var uri = new Uri(source, UriKind.Relative); var resourcePath = ResourceDictionary.RDSourceTypeConverter.GetResourcePath(uri, rootTargetPath); //fail early var resourceId = XamlCTask.GetResourceIdForPath(module, resourcePath); if (resourceId == null) { throw new XamlParseException($"Resource '{source}' not found.", node); } var getTypeFromHandle = module.ImportReference(typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle), new[] { typeof(RuntimeTypeHandle) })); var getAssembly = module.ImportReference(typeof(Type).GetProperty(nameof(Type.Assembly)).GetGetMethod()); yield return(Create(Ldtoken, module.ImportReference(((ILRootNode)rootNode).TypeReference))); yield return(Create(Call, module.ImportReference(getTypeFromHandle))); yield return(Create(Callvirt, module.ImportReference(getAssembly))); //assembly yield return(Create(Ldstr, resourceId)); //resourceId foreach (var instruction in node.PushXmlLineInfo(context)) { yield return(instruction); //lineinfo } var fromAssemblyResource = module.ImportReference(typeof(StyleSheets.StyleSheet).GetMethods().FirstOrDefault(mi => mi.Name == nameof(StyleSheets.StyleSheet.FromAssemblyResource) && mi.GetParameters().Length == 3)); yield return(Create(Call, module.ImportReference(fromAssemblyResource))); } //the variable is of type `object`. fix that var vardef = new VariableDefinition(module.ImportReference(typeof(StyleSheets.StyleSheet))); yield return(Create(Stloc, vardef)); vardefref.VariableDefinition = vardef; }
public static IEnumerable<Instruction> PushServiceProvider(this INode node, ILContext context) { var module = context.Body.Method.Module; #if NOSERVICEPROVIDER yield return Instruction.Create (OpCodes.Ldnull); yield break; #endif var ctorinfo = typeof (XamlServiceProvider).GetConstructor(new Type[] { }); var ctor = module.Import(ctorinfo); var addServiceInfo = typeof (XamlServiceProvider).GetMethod("Add", new[] { typeof (Type), typeof (object) }); var addService = module.Import(addServiceInfo); var getTypeFromHandle = module.Import(typeof (Type).GetMethod("GetTypeFromHandle", new[] { typeof (RuntimeTypeHandle) })); var getAssembly = module.Import(typeof (Type).GetProperty("Assembly").GetMethod); yield return Instruction.Create(OpCodes.Newobj, ctor); //Add a SimpleValueTargetProvider var pushParentIl = node.PushParentObjectsArray(context).ToList(); if (pushParentIl[pushParentIl.Count - 1].OpCode != OpCodes.Ldnull) { yield return Instruction.Create(OpCodes.Dup); //Keep the serviceProvider on the stack yield return Instruction.Create(OpCodes.Ldtoken, module.Import(typeof (IProvideValueTarget))); yield return Instruction.Create(OpCodes.Call, module.Import(getTypeFromHandle)); foreach (var instruction in pushParentIl) yield return instruction; var targetProviderCtor = module.Import(typeof (SimpleValueTargetProvider).GetConstructor(new[] { typeof (object[]) })); yield return Instruction.Create(OpCodes.Newobj, targetProviderCtor); yield return Instruction.Create(OpCodes.Callvirt, addService); } //Add a NamescopeProvider if (context.Scopes.ContainsKey(node)) { yield return Instruction.Create(OpCodes.Dup); //Dupicate the serviceProvider yield return Instruction.Create(OpCodes.Ldtoken, module.Import(typeof (INameScopeProvider))); yield return Instruction.Create(OpCodes.Call, module.Import(getTypeFromHandle)); var namescopeProviderCtor = module.Import(typeof (NameScopeProvider).GetConstructor(new Type[] { })); yield return Instruction.Create(OpCodes.Newobj, namescopeProviderCtor); yield return Instruction.Create(OpCodes.Dup); //Duplicate the namescopeProvider var setNamescope = module.Import(typeof (NameScopeProvider).GetProperty("NameScope").GetSetMethod()); yield return Instruction.Create(OpCodes.Ldloc, context.Scopes[node]); yield return Instruction.Create(OpCodes.Callvirt, setNamescope); yield return Instruction.Create(OpCodes.Callvirt, addService); } //Add a XamlTypeResolver if (node.NamespaceResolver != null) { yield return Instruction.Create(OpCodes.Dup); //Dupicate the serviceProvider yield return Instruction.Create(OpCodes.Ldtoken, module.Import(typeof (IXamlTypeResolver))); yield return Instruction.Create(OpCodes.Call, module.Import(getTypeFromHandle)); var xmlNamespaceResolverCtor = module.Import(typeof (XmlNamespaceResolver).GetConstructor(new Type[] { })); var addNamespace = module.Import(typeof (XmlNamespaceResolver).GetMethod("Add")); yield return Instruction.Create(OpCodes.Newobj, xmlNamespaceResolverCtor); foreach (var kvp in node.NamespaceResolver.GetNamespacesInScope(XmlNamespaceScope.ExcludeXml)) { yield return Instruction.Create(OpCodes.Dup); //dup the resolver yield return Instruction.Create(OpCodes.Ldstr, kvp.Key); yield return Instruction.Create(OpCodes.Ldstr, kvp.Value); yield return Instruction.Create(OpCodes.Callvirt, addNamespace); } yield return Instruction.Create(OpCodes.Ldtoken, context.Body.Method.DeclaringType); yield return Instruction.Create(OpCodes.Call, module.Import(getTypeFromHandle)); yield return Instruction.Create(OpCodes.Callvirt, getAssembly); var xtr = module.Import(typeof (XamlTypeResolver)).Resolve(); var xamlTypeResolverCtor = module.Import(xtr.Methods.First(md => md.IsConstructor && md.Parameters.Count == 2)); yield return Instruction.Create(OpCodes.Newobj, xamlTypeResolverCtor); yield return Instruction.Create(OpCodes.Callvirt, addService); } if (node is IXmlLineInfo) { yield return Instruction.Create(OpCodes.Dup); //Dupicate the serviceProvider yield return Instruction.Create(OpCodes.Ldtoken, module.Import(typeof (IXmlLineInfoProvider))); yield return Instruction.Create(OpCodes.Call, module.Import(getTypeFromHandle)); foreach (var instruction in node.PushXmlLineInfo(context)) yield return instruction; var lip = module.Import(typeof (XmlLineInfoProvider)).Resolve(); var lineInfoProviderCtor = module.Import(lip.Methods.First(md => md.IsConstructor && md.Parameters.Count == 1)); yield return Instruction.Create(OpCodes.Newobj, lineInfoProviderCtor); yield return Instruction.Create(OpCodes.Callvirt, addService); } }
public IEnumerable <Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context) { INode sourceNode = null; ((IElementNode)node).Properties.TryGetValue(new XmlName("", "Source"), out sourceNode); if (sourceNode == null) { ((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Source"), out sourceNode); } INode styleNode = null; if (!((IElementNode)node).Properties.TryGetValue(new XmlName("", "Style"), out styleNode) && !((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Style"), out styleNode) && ((IElementNode)node).CollectionItems.Count == 1) { styleNode = ((IElementNode)node).CollectionItems[0]; } if (sourceNode != null && styleNode != null) { throw new BuildException(BuildExceptionCode.StyleSheetSourceOrContent, node, null); } if (sourceNode == null && styleNode == null) { throw new BuildException(BuildExceptionCode.StyleSheetNoSourceOrContent, node, null); } if (styleNode != null && !(styleNode is ValueNode)) { throw new BuildException(BuildExceptionCode.StyleSheetStyleNotALiteral, node, null); } if (sourceNode != null && !(sourceNode is ValueNode)) { throw new BuildException(BuildExceptionCode.StyleSheetSourceNotALiteral, node, null); } if (styleNode != null) { var style = (styleNode as ValueNode).Value as string; yield return(Create(Ldstr, style)); yield return(Create(Call, module.ImportMethodReference(("Xamarin.Forms.Core", "Xamarin.Forms.StyleSheets", "StyleSheet"), methodName: "FromString", parameterTypes: new[] { ("mscorlib", "System", "String") },
/// <summary> /// Change the following code sequence in Wiring.HitWireSingle /// num12 = Utils.SelectRandom(Main.rand, new short[5] /// { /// 359, /// 359, /// 359, /// 359, /// 360, /// }); /// /// to /// /// var arr = new short[5] /// { /// 359, /// 359, /// 359, /// 359, /// 360, /// } /// arr = arr.ToList().Add(id).ToArray(); /// num12 = Utils.SelectRandom(Main.rand, arr); /// /// </summary> /// <param name="il"></param> private void HookStatue(ILContext il) { // obtain a cursor positioned before the first instruction of the method // the cursor is used for navigating and modifying the il var c = new ILCursor(il); // the exact location for this hook is very complex to search for due to the hook instructions not being unique, and buried deep in control flow // switch statements are sometimes compiled to if-else chains, and debug builds litter the code with no-ops and redundant locals // in general you want to search using structure and function rather than numerical constants which may change across different versions or compile settings // using local variable indices is almost always a bad idea // we can search for // switch (*) // case 56: // Utils.SelectRandom * // in general you'd want to look for a specific switch variable, or perhaps the containing switch (type) { case 105: // but the generated IL is really variable and hard to match in this case // we'll just use the fact that there are no other switch statements with case 56, followed by a SelectRandom ILLabel[] targets = null; while (c.TryGotoNext(i => i.MatchSwitch(out targets))) { // some optimising compilers generate a sub so that all the switch cases start at 0 // ldc.i4.s 51 // sub // switch int offset = 0; if (c.Prev.MatchSub() && c.Prev.Previous.MatchLdcI4(out offset)) { ; } // get the label for case 56: if it exists int case56Index = 56 - offset; if (case56Index < 0 || case56Index >= targets.Length || !(targets[case56Index] is ILLabel target)) { continue; } // move the cursor to case 56: c.GotoLabel(target); // there's lots of extra checks we could add here to make sure we're at the right spot, such as not encountering any branching instructions c.GotoNext(i => i.MatchCall(typeof(Utils), nameof(Utils.SelectRandom))); // goto next positions us before the instruction we searched for, so we can insert our array modifying code right here c.EmitDelegate <Func <short[], short[]> >(arr => { // resize the array and add our custom snail Array.Resize(ref arr, arr.Length + 1); arr[arr.Length - 1] = (short)npc.type; return(arr); }); // hook applied successfully return; } // couldn't find the right place to insert throw new Exception("Hook location not found, switch(*) { case 56: ..."); }
public IEnumerable <Instruction> ConvertFromString(string value, ILContext context, BaseNode node) { var module = context.Body.Method.Module; var body = context.Body; INode rootNode = node; while (!(rootNode is ILRootNode)) { rootNode = rootNode.Parent; } var rdNode = node.Parent as IElementNode; var rootTargetPath = GetPathForType(module, ((ILRootNode)rootNode).TypeReference); var uri = new Uri(value, UriKind.Relative); var resourceId = ResourceDictionary.RDSourceTypeConverter.GetResourceId(uri, rootTargetPath, s => GetResourceIdForPath(module, s)); if (resourceId == null) { throw new XamlParseException($"Resource '{value}' not found.", node); } //abuse the converter, produce some side effect, but leave the stack untouched //public void SetAndLoadSource(Uri value, string resourceID, Assembly assembly, System.Xml.IXmlLineInfo lineInfo) yield return(Create(Ldloc, context.Variables[rdNode])); //the resourcedictionary foreach (var instruction in (new UriTypeConverter()).ConvertFromString(value, context, node)) { yield return(instruction); //the Uri } //keep the Uri for later yield return(Create(Dup)); var uriVarDef = new VariableDefinition(module.ImportReference(typeof(Uri))); body.Variables.Add(uriVarDef); yield return(Create(Stloc, uriVarDef)); yield return(Create(Ldstr, resourceId)); //resourceId var getTypeFromHandle = module.ImportReference(typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) })); var getAssembly = module.ImportReference(typeof(Type).GetProperty("Assembly").GetGetMethod()); yield return(Create(Ldtoken, module.ImportReference(((ILRootNode)rootNode).TypeReference))); yield return(Create(Call, module.ImportReference(getTypeFromHandle))); yield return(Create(Callvirt, module.ImportReference(getAssembly))); //assembly foreach (var instruction in node.PushXmlLineInfo(context)) { yield return(instruction); //lineinfo } var setAndLoadSource = module.ImportReference(typeof(ResourceDictionary).GetMethod("SetAndLoadSource")); yield return(Create(Callvirt, module.ImportReference(setAndLoadSource))); //ldloc the stored uri as return value yield return(Create(Ldloc, uriVarDef)); }
private static void filterOutJumpThrusFromCollideChecks(ILContext il) { ILCursor cursor = new ILCursor(il); while (cursor.Next != null) { Instruction nextInstruction = cursor.Next; if (nextInstruction.OpCode == OpCodes.Call || nextInstruction.OpCode == OpCodes.Callvirt) { switch ((nextInstruction.Operand as MethodReference)?.FullName ?? "") { case "T Monocle.Entity::CollideFirstOutside<Celeste.JumpThru>(Microsoft.Xna.Framework.Vector2)": Logger.Log("SpringCollab2020/UpsideDownJumpThru", $"Patching CollideFirstOutside at {cursor.Index} in IL for {il.Method.Name}"); cursor.Index++; // nullify if mod jumpthru. cursor.EmitDelegate <Func <JumpThru, JumpThru> >(jumpThru => { if (jumpThru?.GetType() == typeof(UpsideDownJumpThru)) { return(null); } return(jumpThru); }); break; case "System.Boolean Monocle.Entity::CollideCheckOutside<Celeste.JumpThru>(Microsoft.Xna.Framework.Vector2)": Logger.Log("SpringCollab2020/UpsideDownJumpThru", $"Patching CollideCheckOutside at {cursor.Index} in IL for {il.Method.Name}"); cursor.Remove(); // check if colliding with a jumpthru but not an upside-down jumpthru. cursor.EmitDelegate <Func <Entity, Vector2, bool> >((self, at) => self.CollideCheckOutside <JumpThru>(at) && !self.CollideCheckOutside <UpsideDownJumpThru>(at)); break; case "System.Boolean Monocle.Entity::CollideCheck<Celeste.JumpThru>()": Logger.Log("SpringCollab2020/UpsideDownJumpThru", $"Patching CollideCheck at {cursor.Index} in IL for {il.Method.Name}"); // we want stack to be: CollideCheck result, this cursor.Index++; cursor.Emit(OpCodes.Ldarg_0); // turn check to false if colliding with an upside-down jumpthru. cursor.EmitDelegate <Func <bool, Player, bool> >((vanillaCheck, self) => vanillaCheck && !self.CollideCheck <UpsideDownJumpThru>()); break; case "System.Collections.Generic.List`1<Monocle.Entity> Monocle.Tracker::GetEntities<Celeste.JumpThru>()": Logger.Log("SpringCollab2020/UpsideDownJumpThru", $"Patching GetEntities at {cursor.Index} in IL for {il.Method.Name}"); cursor.Index++; // remove all mod jumpthrus from the returned list. cursor.EmitDelegate <Func <List <Entity>, List <Entity> > >(matches => { for (int i = 0; i < matches.Count; i++) { if (matches[i].GetType() == typeof(UpsideDownJumpThru)) { matches.RemoveAt(i); i--; } } return(matches); }); break; } } cursor.Index++; } }
public IEnumerable <Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context) { INode valueNode = null; if (!((IElementNode)node).Properties.TryGetValue(new XmlName("", "Value"), out valueNode) && !((IElementNode)node).Properties.TryGetValue(new XmlName(XamlParser.XFUri, "Value"), out valueNode) && ((IElementNode)node).CollectionItems.Count == 1) { valueNode = ((IElementNode)node).CollectionItems[0]; } var bpNode = ((ValueNode)((IElementNode)node).Properties[new XmlName("", "Property")]); var bpRef = (new BindablePropertyConverter()).GetBindablePropertyFieldReference((string)bpNode.Value, module, bpNode); if (SetterValueIsCollection(bpRef, module, node, context)) { yield break; } if (valueNode == null) { throw new XamlParseException("Missing Value for Setter", (IXmlLineInfo)node); } //if it's an elementNode, there's probably no need to convert it if (valueNode is IElementNode) { yield break; } var value = ((string)((ValueNode)valueNode).Value); var setterType = ("Microsoft.Maui.Controls", "Microsoft.Maui.Controls", "Setter"); //push the setter foreach (var instruction in vardefref.VariableDefinition.LoadAs(module.GetTypeDefinition(setterType), module)) { yield return(instruction); } //push the value foreach (var instruction in ((ValueNode)valueNode).PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context, bpRef: bpRef), boxValueTypes: true, unboxValueTypes: false)) { yield return(instruction); } //set the value yield return(Instruction.Create(OpCodes.Callvirt, module.ImportPropertySetterReference(setterType, propertyName: "Value"))); }
private static void OverrideAffixBlueDamage(ILContext il) { ILCursor c = new ILCursor(il); int bodyIndex = -1; bool found = c.TryGotoNext( x => x.MatchLdarg(2), x => x.MatchLdfld <DamageInfo>("attacker"), x => x.MatchCallOrCallvirt <GameObject>("GetComponent"), x => x.MatchStloc(out bodyIndex) ); if (bodyIndex != -1) { found = c.TryGotoNext( x => x.MatchLdsfld(AffixBlueDamageCoeffField) ); if (found) { affixBlueDamageHook++; Logger.Info("[EliteReworksCompat] - AffixBlueDamageCoeffField Index : " + c.Index); c.Index += 1; c.Emit(OpCodes.Ldloc, bodyIndex); c.EmitDelegate <Func <float, CharacterBody, float> >((mult, body) => { if (Configuration.AspectBlueEliteReworksDamage.Value && Configuration.AspectBlueBaseDamage.Value > 0f) { float count = Catalog.GetStackMagnitude(body, RoR2Content.Buffs.AffixBlue); mult = Configuration.AspectBlueBaseDamage.Value + Configuration.AspectBlueStackDamage.Value * (count - 1f); if (body.teamComponent.teamIndex != TeamIndex.Player) { mult *= Configuration.AspectBlueMonsterDamageMult.Value; } } return(mult); }); } else { Logger.Warn("[EliteReworksCompat] - OverrideAffixBlueDamage - Failed to find AffixBlueDamageCoefficientField"); } found = c.TryGotoNext( x => x.MatchLdsfld(AffixBlueDamageCoeffField) ); if (found) { affixBlueDamageHook++; Logger.Info("[EliteReworksCompat] - AffixBlueDamageCoeffField Index : " + c.Index); c.Index += 1; c.Emit(OpCodes.Ldloc, bodyIndex); c.EmitDelegate <Func <float, CharacterBody, float> >((mult, body) => { if (Configuration.AspectBlueEliteReworksDamage.Value && Configuration.AspectBlueBaseDamage.Value > 0f) { float count = Catalog.GetStackMagnitude(body, RoR2Content.Buffs.AffixBlue); mult = Configuration.AspectBlueBaseDamage.Value + Configuration.AspectBlueStackDamage.Value * (count - 1f); if (body.teamComponent.teamIndex != TeamIndex.Player) { mult *= Configuration.AspectBlueMonsterDamageMult.Value; } } return(mult); }); } else { Logger.Warn("[EliteReworksCompat] - OverrideAffixBlueDamage - Failed to find AffixBlueDamageCoefficientField"); } } else { Logger.Warn("[EliteReworksCompat] - OverrideAffixBlueDamage - Failed to find CharacterBody Local Variable Index"); } }
static bool SetterValueIsCollection(FieldReference bindablePropertyReference, ModuleDefinition module, BaseNode node, ILContext context) { var items = (node as IElementNode)?.CollectionItems; if (items == null || items.Count <= 0) { return(false); } // Is this a generic type ? var generic = bindablePropertyReference.GetBindablePropertyType(node, module) as GenericInstanceType; // With a single generic argument? if (generic?.GenericArguments.Count != 1) { return(false); } // Is the generic argument assignable from this value? var genericType = generic.GenericArguments[0]; if (!(items[0] is IElementNode firstItem)) { return(false); } return(context.Variables[firstItem].VariableType.InheritsFromOrImplements(genericType)); }
public bool Compile() { LogLine(1, "Compiling Xaml"); LogLine(1, "\nAssembly: {0}", Assembly); if (!string.IsNullOrEmpty(DependencyPaths)) LogLine(1, "DependencyPaths: \t{0}", DependencyPaths); if (!string.IsNullOrEmpty(ReferencePath)) LogLine(1, "ReferencePath: \t{0}", ReferencePath.Replace("//", "/")); LogLine(3, "DebugSymbols:\"{0}\"", DebugSymbols); var skipassembly = true; //change this to false to enable XamlC by default bool success = true; if (!File.Exists(Assembly)) { LogLine(1, "Assembly file not found. Skipping XamlC."); return true; } var resolver = new XamlCAssemblyResolver(); if (!string.IsNullOrEmpty(DependencyPaths)) { foreach (var dep in DependencyPaths.Split(';')) { LogLine(3, "Adding searchpath {0}", dep); resolver.AddSearchDirectory(dep); } } if (!string.IsNullOrEmpty(ReferencePath)) { var paths = ReferencePath.Replace("//", "/").Split(';'); foreach (var p in paths) { var searchpath = Path.GetDirectoryName(p); LogLine(3, "Adding searchpath {0}", searchpath); resolver.AddSearchDirectory(searchpath); // LogLine (3, "Referencing {0}", p); // resolver.AddAssembly (p); } } var assemblyDefinition = AssemblyDefinition.ReadAssembly(Path.GetFullPath(Assembly), new ReaderParameters { AssemblyResolver = resolver, ReadSymbols = DebugSymbols }); CustomAttribute xamlcAttr; if (assemblyDefinition.HasCustomAttributes && (xamlcAttr = assemblyDefinition.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) skipassembly = true; if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) skipassembly = false; } foreach (var module in assemblyDefinition.Modules) { var skipmodule = skipassembly; if (module.HasCustomAttributes && (xamlcAttr = module.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) skipmodule = true; if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) skipmodule = false; } LogLine(2, " Module: {0}", module.Name); var resourcesToPrune = new List<EmbeddedResource>(); foreach (var resource in module.Resources.OfType<EmbeddedResource>()) { Log(2, " Resource: {0}... ", resource.Name); string classname; if (!resource.IsXaml(out classname)) { LogLine(2, "skipped."); continue; } TypeDefinition typeDef = module.GetType(classname); if (typeDef == null) { LogLine(2, "no type found... skipped."); continue; } var skiptype = skipmodule; if (typeDef.HasCustomAttributes && (xamlcAttr = typeDef.CustomAttributes.FirstOrDefault( ca => ca.AttributeType.FullName == "Xamarin.Forms.Xaml.XamlCompilationAttribute")) != null) { var options = (XamlCompilationOptions)xamlcAttr.ConstructorArguments[0].Value; if ((options & XamlCompilationOptions.Skip) == XamlCompilationOptions.Skip) skiptype = true; if ((options & XamlCompilationOptions.Compile) == XamlCompilationOptions.Compile) skiptype = false; } if (skiptype) { LogLine(2, "Has XamlCompilationAttribute set to Skip and not Compile... skipped"); continue; } var initComp = typeDef.Methods.FirstOrDefault(md => md.Name == "InitializeComponent"); if (initComp == null) { LogLine(2, "no InitializeComponent found... skipped."); continue; } LogLine(2, ""); Log(2, " Parsing Xaml... "); var rootnode = ParseXaml(resource.GetResourceStream(), typeDef); if (rootnode == null) { LogLine(2, "failed."); continue; } LogLine(2, "done."); hasCompiledXamlResources = true; try { Log(2, " Replacing {0}.InitializeComponent ()... ", typeDef.Name); var body = new MethodBody(initComp); var il = body.GetILProcessor(); il.Emit(OpCodes.Nop); var visitorContext = new ILContext(il, body); rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null); rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null); rootnode.Accept(new CreateObjectVisitor(visitorContext), null); rootnode.Accept(new SetNamescopesAndRegisterNamesVisitor(visitorContext), null); rootnode.Accept(new SetFieldVisitor(visitorContext), null); rootnode.Accept(new SetResourcesVisitor(visitorContext), null); rootnode.Accept(new SetPropertiesVisitor(visitorContext, true), null); il.Emit(OpCodes.Ret); initComp.Body = body; } catch (XamlParseException xpe) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, xpe.XmlInfo.LineNumber, xpe.XmlInfo.LinePosition, 0, 0, xpe.Message, xpe.HelpLink, xpe.Source); LogLine(4, xpe.StackTrace); success = false; continue; } catch (XmlException xe) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, xe.LineNumber, xe.LinePosition, 0, 0, xe.Message, xe.HelpLink, xe.Source); LogLine(4, xe.StackTrace); success = false; continue; } catch (Exception e) { LogLine(2, "failed."); LogError(null, null, null, resource.Name, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source); LogLine(4, e.StackTrace); success = false; continue; } LogLine(2, "done."); if (OptimizeIL) { Log(2, " Optimizing IL... "); initComp.Body.OptimizeMacros(); LogLine(2, "done"); } if (OutputGeneratedILAsCode) { var filepath = Path.Combine(Path.GetDirectoryName(Assembly), typeDef.FullName + ".decompiled.cs"); Log(2, " Decompiling {0} into {1}...", typeDef.FullName, filepath); var decompilerContext = new DecompilerContext(module); using (var writer = new StreamWriter(filepath)) { var output = new PlainTextOutput(writer); var codeDomBuilder = new AstBuilder(decompilerContext); codeDomBuilder.AddType(typeDef); codeDomBuilder.GenerateCode(output); } LogLine(2, "done"); } resourcesToPrune.Add(resource); } if (!KeepXamlResources) { if (resourcesToPrune.Any()) LogLine(2, " Removing compiled xaml resources"); foreach (var resource in resourcesToPrune) { Log(2, " Removing {0}... ", resource.Name); module.Resources.Remove(resource); LogLine(2, "done"); } } LogLine(2, ""); } if (!hasCompiledXamlResources) { LogLine(1, "No compiled resources. Skipping writing assembly."); return success; } Log(1, "Writing the assembly... "); try { assemblyDefinition.Write(Assembly, new WriterParameters { WriteSymbols = DebugSymbols }); LogLine(1, "done."); } catch (Exception e) { LogLine(1, "failed."); LogError(null, null, null, null, 0, 0, 0, 0, e.Message, e.HelpLink, e.Source); LogLine(4, e.StackTrace); success = false; } return success; }
/// <summary> /// Creates an <see cref="ILCursor"/> with an <see cref="ILContext"/>. /// </summary> public static void CreateCursor(this ILContext context, out ILCursor c) => c = new ILCursor(context);
public SetPropertiesVisitor(ILContext context, bool stopOnResourceDictionary = false) { Context = context; Module = context.Body.Method.Module; StopOnResourceDictionary = stopOnResourceDictionary; }
static TypeReference GetBPReturnType(ILContext context, FieldReference bpRef, IXmlLineInfo lineInfo) { //Find a property with a matching name var name = bpRef.Name; if (!name.EndsWith("Property", StringComparison.Ordinal)) return context.Body.Method.Module.TypeSystem.Object; name = name.Substring(0, name.Length - 8); //First, check for a property TypeReference declaringTypeRef; var property = bpRef.DeclaringType.GetProperty(pd => pd.Name == name, out declaringTypeRef); if (property != null) return property.PropertyType; //Then check for getter or setter (attached BPs) var getters = bpRef.DeclaringType.GetMethods(md => md.Name == "Get" + name && md.IsStatic, context.Body.Method.Module) .SingleOrDefault(); if (getters != null) return getters.Item1.ReturnType; //throws throw new XamlParseException( string.Format( "Can not find a Property named \"{0}\" or a static method named \"Get{0}\" for BindableProperty \"{1}\"", name, bpRef.Name), lineInfo); }
static bool GetNameAndTypeRef(ref TypeReference elementType, string namespaceURI, ref string localname, ILContext context, IXmlLineInfo lineInfo) { var dotIdx = localname.IndexOf('.'); if (dotIdx > 0) { var typename = localname.Substring(0, dotIdx); localname = localname.Substring(dotIdx + 1); elementType = new XmlType(namespaceURI, typename, null).GetTypeReference(context.Body.Method.Module, lineInfo); return true; } return false; }
public static IEnumerable<Instruction> PushParentObjectsArray(this INode node, ILContext context) { var module = context.Body.Method.Module; var nodes = new List<IElementNode>(); INode n = node.Parent; while (n != null) { var en = n as IElementNode; if (en != null && context.Variables.ContainsKey(en)) nodes.Add(en); n = n.Parent; } if (nodes.Count == 0 && context.ParentContextValues == null) { yield return Instruction.Create(OpCodes.Ldnull); yield break; } if (nodes.Count == 0) { yield return Instruction.Create(OpCodes.Ldarg_0); yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues); yield break; } //Compute parent object length if (context.ParentContextValues != null) { yield return Instruction.Create(OpCodes.Ldarg_0); yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues); yield return Instruction.Create(OpCodes.Ldlen); yield return Instruction.Create(OpCodes.Conv_I4); } else yield return Instruction.Create(OpCodes.Ldc_I4_0); var parentObjectLength = new VariableDefinition(module.TypeSystem.Int32); context.Body.Variables.Add(parentObjectLength); yield return Instruction.Create(OpCodes.Stloc, parentObjectLength); //Create the final array yield return Instruction.Create(OpCodes.Ldloc, parentObjectLength); yield return Instruction.Create(OpCodes.Ldc_I4, nodes.Count); yield return Instruction.Create(OpCodes.Add); yield return Instruction.Create(OpCodes.Newarr, module.TypeSystem.Object); var finalArray = new VariableDefinition(module.Import(typeof (object[]))); context.Body.Variables.Add(finalArray); yield return Instruction.Create(OpCodes.Stloc, finalArray); //Copy original array to final if (context.ParentContextValues != null) { yield return Instruction.Create(OpCodes.Ldarg_0); yield return Instruction.Create(OpCodes.Ldfld, context.ParentContextValues); //sourceArray yield return Instruction.Create(OpCodes.Ldc_I4_0); //sourceIndex yield return Instruction.Create(OpCodes.Ldloc, finalArray); //destinationArray yield return Instruction.Create(OpCodes.Ldc_I4, nodes.Count); //destinationIndex yield return Instruction.Create(OpCodes.Ldloc, parentObjectLength); //length var arrayCopy = module.Import(typeof (Array)) .Resolve() .Methods.First( md => md.Name == "Copy" && md.Parameters.Count == 5 && md.Parameters[1].ParameterType.FullName == module.TypeSystem.Int32.FullName); yield return Instruction.Create(OpCodes.Call, module.Import(arrayCopy)); } //Add nodes to array yield return Instruction.Create(OpCodes.Ldloc, finalArray); if (nodes.Count > 0) { for (var i = 0; i < nodes.Count; i++) { var en = nodes[i]; yield return Instruction.Create(OpCodes.Dup); yield return Instruction.Create(OpCodes.Ldc_I4, i); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[en]); if (context.Variables[en].VariableType.IsValueType) yield return Instruction.Create(OpCodes.Box, module.Import(context.Variables[en].VariableType)); yield return Instruction.Create(OpCodes.Stelem_Ref); } } }
public static void HookMap(ILContext il) { var c = new ILCursor(il); #region size // Find Main.minimapWidth = 240; /* * IL_0C0C: ldsfld int32 Terraria.Main::mapStyle * IL_0C11: ldc.i4.1 * IL_0C12: bne.un IL_0E16 * IL_0C17: ldc.i4 240 */ if (!c.TryGotoNext(MoveType.After, i => i.MatchLdsfld(typeof(Main).GetField("mapStyle")), i => i.MatchLdcI4(1), i => i.MatchBneUn(out _), i => i.MatchLdcI4(240))) { return; } // Change "Main.minimapWidth = 240;" to "Main.minimapWidth = 240 * minimapScale;" c.EmitDelegate <Func <int, int> >((returnvalue) => { return((int)(240 * BetterZoom.minimapScale)); }); // Find Main.minimapHeight = 240; /* * IL_0C1C: stsfld int32 Terraria.Main::miniMapWidth * IL_0C21: ldc.i4 240 */ if (!c.TryGotoNext(MoveType.After, i => i.MatchStsfld(typeof(Main).GetField("miniMapWidth")), i => i.MatchLdcI4(240))) { return; } // Change "Main.minimapHeight = 240;" to "Main.minimapHeight = 240 * minimapScale;" c.EmitDelegate <Func <int, int> >((returnvalue) => { return((int)(240 * BetterZoom.minimapScale)); }); #endregion #region border // Go to IL_0E01 (L326: Main.spriteBatch.Draw(Main.minimapFrame2Texture, ..., ..., ..., ..., ..., 1f)) // Draw call for the black background /* * * IL_0DF2: ldc.r4 0.0 * IL_0DF7: ldloca.s V_49 * IL_0DF9: initobj [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2 * IL_0DFF: ldloc.s V_49 * IL_0E01: ldc.r4 1 * */ if (!c.TryGotoNext(MoveType.After, i => i.MatchLdcR4(0), i => i.MatchLdloca(49), i => i.MatchInitobj(typeof(Vector2)), i => i.MatchLdloc(49), i => i.MatchLdcR4(1))) { return; } // change scale parameter to minimapScale c.EmitDelegate <Func <float, float> >((returnvalue) => { return(BetterZoom.minimapScale); }); c.Index++; // Go to IL_21E9 (L683: Main.spriteBatch.Draw(Main.minimapFrameTexture, ..., ..., ..., ..., ..., ..., 1f)) // Draw call for the minimap frame /* * IL_21DA: ldc.r4 0.0 * IL_21DF: ldloca.s V_49 * IL_21E1: initobj [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2 * IL_21E7: ldloc.s V_49 * IL_21E9: ldc.r4 1 */ if (!c.TryGotoNext(MoveType.After, i => i.MatchLdcR4(0), i => i.MatchLdloca(49), i => i.MatchInitobj(typeof(Vector2)), i => i.MatchLdloc(49), i => i.MatchLdcR4(1))) { return; } c.EmitDelegate <Func <float, float> >((returnvalue) => { return(BetterZoom.minimapScale); }); #endregion #region buttons // Go to IL_2201 (L686: float num88 = num57 + 148f + (float)(num87 * 26);) /* * IL_2201: ldloc.s num58 [84] * IL_2203: ldc.r4 148 * IL_2208: add * IL_2209: ldloc.s num88 [121] * IL_220B: ldc.i4.s 26 * IL_220D: mul * IL_220E: conv.r4 * IL_220F: add * IL_2210: stloc.s num89 [122] */ if (!c.TryGotoNext(MoveType.After, i => i.MatchLdloc(84), i => i.MatchLdcR4(148), i => i.MatchAdd(), i => i.MatchLdloc(121), i => i.MatchLdcI4(26), i => i.MatchMul(), i => i.MatchConvR4(), i => i.MatchAdd())) { return; } // Change button X position c.EmitDelegate <Func <float, float> >((returnvalue) => { float newX = Main.miniMapX - 6; float offset = returnvalue - (newX + 148f); return(newX + (148f * BetterZoom.minimapScale) + offset * BetterZoom.minimapScale); }); // Go to IL_2212 (L687: float num89 = num58 + 234f;) /* * IL_2212: ldloc.s num59 * IL_2214: ldc.r4 234 * IL_2219: add * IL_221A: stloc.s num90 */ if (!c.TryGotoNext(MoveType.After, i => i.MatchLdloc(85), i => i.MatchLdcR4(234), i => i.MatchAdd())) { return; } // Change button Y position c.EmitDelegate <Func <float, float> >((returnvalue) => { float newY = Main.miniMapY - 6; return(newY + 234f * BetterZoom.minimapScale); }); // Go to IL_2229 (L688: if((float)Main.mouseX < num88 + 22f))) /* * IL_2229: ldsfld int32 Terraria.Main::mouseX * IL_222E: conv.r4 * IL_222F: ldloc.s num89 [122] * IL_2231: ldc.r4 22 * IL_2236: add */ if (!c.TryGotoNext(MoveType.After, i => i.MatchLdsfld(typeof(Main).GetField("mouseX")), i => i.MatchConvR4(), i => i.MatchLdloc(122), i => i.MatchLdcR4(22))) { return; } // Change click hitbox X c.EmitDelegate <Func <float, float> >((returnvalue) => { return(returnvalue * BetterZoom.minimapScale); }); // Go to (L688: if((float)Main.mouseY < num89 + 22f))) /* * IL_2249: ldsfld int32 Terraria.Main::mouseY * IL_224E: conv.r4 * IL_224F: ldloc.s num90 [123] * IL_2251: ldc.r4 22 * IL_2256: add */ if (!c.TryGotoNext(MoveType.After, i => i.MatchLdsfld(typeof(Main).GetField("mouseY")), i => i.MatchConvR4(), i => i.MatchLdloc(123), i => i.MatchLdcR4(22))) { return; } // Change click hitbox Y c.EmitDelegate <Func <float, float> >((returnvalue) => { return(returnvalue * BetterZoom.minimapScale); }); // Go to IL_229D (L690: Main.spriteBatch.Draw(Main.miniMapButtonTexture[i], ..., ..., ..., ..., ..., 1f)) /* * IL_229D: ldc.r4 0.0 * IL_22A2: ldloca.s V_49 * IL_22A4: initobj [Microsoft.Xna.Framework]Microsoft.Xna.Framework.Vector2 * IL_22AA: ldloc.s V_49 * IL_22AC: ldc.r4 1 */ if (!c.TryGotoNext(MoveType.After, i => i.MatchLdcR4(0), i => i.MatchLdloca(49), i => i.MatchInitobj(typeof(Vector2)), i => i.MatchLdloc(49), i => i.MatchLdcR4(1))) { return; } // Change scale of Buttons c.EmitDelegate <Func <float, float> >((returnvalue) => { return(BetterZoom.minimapScale); }); #endregion }
private static void modOuiChapterPanelSetStatsPosition(ILContext il) { ILCursor cursor = new ILCursor(il); // this is a tricky one... in lines like this: // this.strawberriesOffset = this.Approach(this.strawberriesOffset, new Vector2(120f, (float)(this.deaths.Visible ? -40 : 0)), !approach); // we want to catch the result of (float)(this.deaths.Visible ? -40 : 0) and transform it to shift the things up if the speed berry PB is there. while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchConvR4())) { Logger.Log("CollabUtils2/SpeedBerryPBInChapterPanel", $"Modifying strawberry/death counter positioning at {cursor.Index} in CIL code for OuiChapterPanel.SetStatsPosition"); cursor.EmitDelegate <Func <float, float> >(position => (speedBerryPBDisplay?.Visible ?? false) ? position - 40 : position); } cursor.Index = 0; // we will cross 2 occurrences when deathsOffset will be set: first time with the heart, second time without. // the only difference is the X offset, so put the code in common. bool hasHeart = true; while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchStfld(typeof(OuiChapterPanel), "deathsOffset"))) { Logger.Log("CollabUtils2/SpeedBerryPBInChapterPanel", $"Injecting speed berry PB position updating at {cursor.Index} in CIL code for OuiChapterPanel.SetStatsPosition (has heart = {hasHeart})"); // bool approach cursor.Emit(OpCodes.Ldarg_1); // StrawberriesCounter strawberries cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Ldfld, typeof(OuiChapterPanel).GetField("strawberries", BindingFlags.NonPublic | BindingFlags.Instance)); // DeathsCounter deaths cursor.Emit(OpCodes.Ldarg_0); cursor.Emit(OpCodes.Ldfld, typeof(OuiChapterPanel).GetField("deaths", BindingFlags.NonPublic | BindingFlags.Instance)); // bool hasHeart cursor.Emit(hasHeart ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); // function call cursor.EmitDelegate <Action <bool, StrawberriesCounter, DeathsCounter, bool> >((approach, strawberries, deaths, thisHasHeart) => { int shift = 0; if (strawberries.Visible) { shift += 40; } if (deaths.Visible) { shift += 40; } speedBerryPBOffset = SpeedBerryPBInChapterPanel.approach(speedBerryPBOffset, new Vector2(thisHasHeart ? 150f : 0f, shift), !approach); }); hasHeart = false; } cursor.Index = 0; // have a bigger spacing between heart and text when the speed berry PB is displayed, because it is bigger than berry / death count. while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchLdcR4(120f) || instr.MatchLdcR4(-120f))) { Logger.Log("CollabUtils2/SpeedBerryPBInChapterPanel", $"Modifying column spacing at {cursor.Index} in CIL code for OuiChapterPanel.SetStatsPosition"); cursor.EmitDelegate <Func <float, float> >(orig => { if (speedBerryPBDisplay?.Visible ?? false) { return(orig + 30f * Math.Sign(orig)); } return(orig); }); } }
public static IEnumerable<Instruction> PushXmlLineInfo(this INode node, ILContext context) { var module = context.Body.Method.Module; var xmlLineInfo = node as IXmlLineInfo; if (xmlLineInfo == null) { yield return Instruction.Create(OpCodes.Ldnull); yield break; } MethodReference ctor; if (xmlLineInfo.HasLineInfo()) { yield return Instruction.Create(OpCodes.Ldc_I4, xmlLineInfo.LineNumber); yield return Instruction.Create(OpCodes.Ldc_I4, xmlLineInfo.LinePosition); ctor = module.Import(typeof (XmlLineInfo).GetConstructor(new[] { typeof (int), typeof (int) })); } else ctor = module.Import(typeof (XmlLineInfo).GetConstructor(new Type[] { })); yield return Instruction.Create(OpCodes.Newobj, ctor); }
private void DrawZoomOut(ILContext il) { var c = new ILCursor(il); if (!c.TryGotoNext(MoveType.After, i => i.MatchSub(), i => i.MatchLdcR4(16), i => i.MatchDiv(), i => i.MatchLdcR4(1), i => i.MatchSub())) { return; } c.EmitDelegate <Func <float, float> >((returnvalue) => { return((int)((Main.screenPosition.X - 1600) / 16f - 1f)); }); /* * IL_00B5: add * IL_00B6: ldc.r4 16 * IL_00BB: div * IL_00BC: conv.i4 * IL_00BD: ldc.i4.2 * IL_00BE: add * ---> here */ if (!c.TryGotoNext(MoveType.After, i => i.MatchAdd(), i => i.MatchLdcR4(16), i => i.MatchDiv(), i => i.MatchConvI4(), i => i.MatchLdcI4(2), i => i.MatchAdd())) { return; } c.EmitDelegate <Func <int, int> >((returnvalue) => { return((int)((Main.screenPosition.X + Main.screenWidth + 1600) / 16f + 2)); }); return; Vector2 zero = new Vector2((float)Main.offScreenRange, (float)Main.offScreenRange); //var c = new ILCursor(il); if (!c.TryGotoNext(MoveType.After, i => i.MatchStloc(8))) { return; } c.Index++; c.Emit(OpCodes.Ldc_I4, (int)((Main.screenPosition.X - zero.X) / 16f - 1f)); c.Emit(OpCodes.Stloc, 5); c.Emit(OpCodes.Ldc_I4, (int)((Main.screenPosition.X + (float)Main.screenWidth + zero.X) / 16f) + 2); c.Emit(OpCodes.Stloc, 6); c.Emit(OpCodes.Ldc_I4, (int)((Main.screenPosition.Y - zero.Y) / 16f - 1f)); c.Emit(OpCodes.Stloc, 7); c.Emit(OpCodes.Ldc_I4, (int)((Main.screenPosition.Y + (float)Main.screenHeight + zero.Y) / 16f) + 5); c.Emit(OpCodes.Stloc, 8); }
private void IL_ESPerformEquipmentAction(ILContext il) { ILCursor c = new ILCursor(il); //Insert a check for Embryo procs at the top of the function bool boost = false; EmbryoComponent cpt = null; c.Emit(OpCodes.Ldarg_0); c.EmitDelegate <Action <EquipmentSlot> >((slot) => { boost = Util.CheckRoll(GetCount(slot.characterBody) * procChance); cpt = slot.characterBody?.GetComponentInChildren <EmbryoComponent>(); }); bool ILFound; ILLabel[] swarr = new ILLabel[] {}; //Load switch case locations ILFound = c.TryGotoNext( x => x.MatchSwitch(out swarr)); if (!ILFound) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch (ALL EQUIPMENTS): couldn't find switch!"); return; } //CommandMissile: double number of missiles fired in the same timespan if ((int)EquipmentIndex.CommandMissile >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: CommandMissile (PerformEquipmentAction); not in switch"); } else if (subEnable[EquipmentIndex.CommandMissile]) { //Find: default missile increment (+= (int)12) c.GotoLabel(swarr[(int)EquipmentIndex.CommandMissile]); ILFound = c.TryGotoNext( x => x.MatchLdfld <EquipmentSlot>("remainingMissiles"), x => x.OpCode == OpCodes.Ldc_I4_S, x => x.MatchAdd()); if (ILFound) { c.Index += 2; //Replace original increment number with a custom function to check for Embryo proc //If proc happens, doubles number of missiles added and marks the total number of missiles added as boosted; otherwise returns original c.EmitDelegate <Func <int, int> >((int origMissiles) => { if (boost && cpt) { cpt.boostedMissiles += origMissiles * 2; } return((sbyte)(boost ? origMissiles * 2 : origMissiles)); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: CommandMissile (PerformEquipmentAction); target instructions not found"); } } //Blackhole: double yoink radius if ((int)EquipmentIndex.CommandMissile >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Blackhole; not in switch"); } else if (subEnable[EquipmentIndex.Blackhole]) { //Find: string "Prefabs/Projectiles/GravSphere", ldloc 15 (Vector3 position) c.GotoLabel(swarr[(int)EquipmentIndex.Blackhole]); ILFound = c.TryGotoNext(MoveType.After, x => x.MatchLdstr("Prefabs/Projectiles/GravSphere"), x => x.MatchCallOrCallvirt <Resources>("Load")); if (ILFound) { //Insert a custom function to check for Embryo proc (captures GravSphere projectile prefab) //If proc happens, radius of prefab's RadialForce component (GravSphere pull range) is doubled c.EmitDelegate <Func <GameObject, GameObject> >((obj) => { var newobj = UnityEngine.Object.Instantiate(obj); if (boost) { newobj.GetComponent <RadialForce>().radius *= 2; } return(newobj); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Blackhole; target instructions not found"); } } //CritOnUse: double duration if ((int)EquipmentIndex.CritOnUse >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: CritOnUse; not in switch"); } else if (subEnable[EquipmentIndex.CritOnUse]) { //Find: AddTimedBuff(BuffIndex.FullCrit, 8f) c.GotoLabel(swarr[(int)EquipmentIndex.CritOnUse]); ILFound = c.TryGotoNext( x => x.MatchLdcI4((int)BuffIndex.FullCrit), x => x.OpCode == OpCodes.Ldc_R4, x => x.MatchCallOrCallvirt <CharacterBody>("AddTimedBuff")); if (ILFound) { //Advance cursor to the found ldcR4 (time argument of AddTimedBuff) c.Index += 2; //Replace original buff time with a custom function to check for Embryo proc //If proc happens, doubles the buff time; otherwise returns original c.EmitDelegate <Func <float, float> >((origBuffTime) => { if (cpt) { cpt.lastCOUBoosted = boost; } return(boost ? origBuffTime * 2 : origBuffTime); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: CritOnUse; target instructions not found"); } } //Gateway: double speed if ((int)EquipmentIndex.Gateway >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Gateway; not in switch"); } else if (subEnable[EquipmentIndex.Gateway]) { //Find: start of Gateway label c.GotoLabel(swarr[(int)EquipmentIndex.Gateway]); //Insert a custom function to check boost //If proc happens, increments the player's boosted gateway counter; this will be spent once the gateway spawns c.EmitDelegate <Action>(() => { if (boost && cpt) { cpt.boostedGates++; } }); } //Scanner: double duration if ((int)EquipmentIndex.Scanner >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Scanner; not in switch"); } else if (subEnable[EquipmentIndex.Scanner]) { //Find: loading of prefab c.GotoLabel(swarr[(int)EquipmentIndex.Scanner]); ILFound = c.TryGotoNext(MoveType.After, x => x.MatchLdstr("Prefabs/NetworkedObjects/ChestScanner"), x => x.MatchCall <UnityEngine.Resources>("Load")); if (ILFound) { //Insert a custom function to check boost //If proc happens, replace the loaded prefab with a boosted copy (allows proper networking) c.EmitDelegate <Func <GameObject, GameObject> >((origObj) => { if (boost) { return(boostedScannerPrefab); } else { return(origObj); } }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Scanner; target instructions not found"); } } //BFG: double impact damage if ((int)EquipmentIndex.BFG >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: BFG; not in switch"); } else if (subEnable[EquipmentIndex.BFG]) { //Find: loading of (int)2 into EquipmentSlot.bfgChargeTimer c.GotoLabel(swarr[(int)EquipmentIndex.BFG]); ILFound = c.TryGotoNext(MoveType.After, x => x.OpCode == OpCodes.Ldc_R4, x => x.MatchStfld <EquipmentSlot>("bfgChargeTimer")); if (ILFound) { //Insert a custom function to check boost //If proc happens, increments the player's boosted BFG shot counter; this will be spent once the BFG actually fires c.EmitDelegate <Action>(() => { if (boost && cpt) { cpt.boostedBFGs++; } }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: BFG (PerformEquipmentAction); target instructions not found"); } } //Jetpack: double duration if ((int)EquipmentIndex.Jetpack >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Jetpack; not in switch"); } else if (subEnable[EquipmentIndex.Jetpack]) { //Find: start of Jetpack label c.GotoLabel(swarr[(int)EquipmentIndex.Jetpack]); //Insert a custom function to check boost //If proc happens, increments the player's boosted jetpack counter; this will be spent during the RPC duration reset c.EmitDelegate <Action>(() => { if (boost && cpt) { cpt.boostedJetTime = 15f; } }); } //FireBallDash: double speed and damage if ((int)EquipmentIndex.FireBallDash >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: FireBallDash; not in switch"); } else if (subEnable[EquipmentIndex.FireBallDash]) { //Find: string "Prefabs/NetworkedObjects/FireballVehicle" //Then find: instantiation of the prefab c.GotoLabel(swarr[(int)EquipmentIndex.FireBallDash]); ILFound = c.TryGotoNext( x => x.MatchLdstr("Prefabs/NetworkedObjects/FireballVehicle")) && c.TryGotoNext( x => x.MatchCallOrCallvirt <UnityEngine.Object>("Instantiate")); if (ILFound) { c.Index++; //Insert a custom function to check boost (captures a dup of the instantiated FireballVehicle) //If proc happens, doubles the instanced vehicle's target speed, acceleration, and blast and collision damage c.Emit(OpCodes.Dup); c.EmitDelegate <Action <GameObject> >((go) => { if (boost) { go.GetComponent <FireballVehicle>().targetSpeed *= 2f; go.GetComponent <FireballVehicle>().acceleration *= 2f; go.GetComponent <FireballVehicle>().blastDamageCoefficient *= 2f; go.GetComponent <FireballVehicle>().overlapDamageCoefficient *= 2f; } }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: FireBallDash; target instructions not found"); } } //GainArmor: double duration if ((int)EquipmentIndex.GainArmor >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: GainArmor; not in switch"); } else if (subEnable[EquipmentIndex.GainArmor]) { //Find: AddTimedBuff(BuffIndex.ElephantArmorBoost, 5f) c.GotoLabel(swarr[(int)EquipmentIndex.GainArmor]); ILFound = c.TryGotoNext( x => x.MatchLdcI4((int)BuffIndex.ElephantArmorBoost), x => x.OpCode == OpCodes.Ldc_R4, x => x.MatchCallvirt <CharacterBody>("AddTimedBuff")); if (ILFound) { //Advance cursor to the found ldcR4 (time argument of AddTimedBuff) c.Index += 2; //Replace original buff time (5f) with a custom function to check for Embryo proc //If proc happens, doubles the buff time to 10f; otherwise returns original c.EmitDelegate <Func <float, float> >((origBuffTime) => { return(boost?2 * origBuffTime:origBuffTime); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: GainArmor; target instructions not found"); } } //Cleanse: double projectile delete radius if ((int)EquipmentIndex.Cleanse >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Cleanse; not in switch"); } else if (subEnable[EquipmentIndex.Cleanse]) { c.EmitDelegate <Action>(() => { if (cpt) { cpt.lastCleanseBoosted = boost; } }); } //Recycle: double recycle count if ((int)EquipmentIndex.Recycle >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Recycle; not in switch"); } else if (subEnable[EquipmentIndex.Recycle]) { c.GotoLabel(swarr[(int)EquipmentIndex.Recycle]); ILFound = c.TryGotoNext( x => x.MatchLdloc(out _), x => x.MatchLdcI4(1), x => x.MatchCallOrCallvirt <GenericPickupController>("set_NetworkRecycled")); if (ILFound) { c.Index++; c.Emit(OpCodes.Dup); c.Index++; c.EmitDelegate <Func <GenericPickupController, bool, bool> >((pctrl, origRecyc) => { if (boost && pctrl && pctrl.GetComponent <EmbryoRecycleFlag>() == null) { pctrl.gameObject.AddComponent <EmbryoRecycleFlag>(); return(false); } return(true); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: Recycle; target instructions not found"); } } //LifestealOnHit: double buff duration if ((int)EquipmentIndex.LifestealOnHit >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: LifestealOnHit; not in switch"); } else if (subEnable[EquipmentIndex.LifestealOnHit]) { c.GotoLabel(swarr[(int)EquipmentIndex.LifestealOnHit]); ILFound = c.TryGotoNext(MoveType.After, x => x.MatchLdcI4((int)BuffIndex.LifeSteal), x => x.MatchLdcR4(out _), x => x.MatchCallOrCallvirt <CharacterBody>("AddTimedBuff")); if (ILFound) { c.Index--; c.EmitDelegate <Func <float, float> >((origBuffTime) => { return(boost?2 * origBuffTime:origBuffTime); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: LifestealOnHit; target instructions not found"); } } //TeamWarCry: double buff duration if ((int)EquipmentIndex.TeamWarCry >= swarr.Length) { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: TeamWarCry; not in switch"); } else if (subEnable[EquipmentIndex.TeamWarCry]) { c.GotoLabel(swarr[(int)EquipmentIndex.TeamWarCry]); ILFound = c.TryGotoNext(MoveType.After, x => x.MatchLdcI4((int)BuffIndex.TeamWarCry), x => x.MatchLdcR4(out _), x => x.MatchCallOrCallvirt <CharacterBody>("AddTimedBuff")); if (ILFound) { c.Index--; c.EmitDelegate <Func <float, float> >((origBuffTime) => { return(boost?2 * origBuffTime:origBuffTime); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: TeamWarCry; target instructions not found (first buff time replacement)"); } ILFound = c.TryGotoNext(MoveType.After, x => x.MatchLdcI4((int)BuffIndex.TeamWarCry), x => x.MatchLdcR4(out _), x => x.MatchCallOrCallvirt <CharacterBody>("AddTimedBuff")); if (ILFound) { c.Index--; c.EmitDelegate <Func <float, float> >((origBuffTime) => { return(boost?2 * origBuffTime:origBuffTime); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: TeamWarCry; target instructions not found (second buff time replacement)"); } } }
private void IL_ESFixedUpdate(ILContext il) { ILCursor c = new ILCursor(il); EmbryoComponent cpt = null; c.Emit(OpCodes.Ldarg_0); c.EmitDelegate <Action <EquipmentSlot> >((slot) => { cpt = slot.characterBody?.GetComponentInChildren <EmbryoComponent>(); }); bool ILFound; if (subEnable[EquipmentIndex.CommandMissile]) { //Find: loading of 0.125f into EquipmentSlot.missileTimer ILFound = c.TryGotoNext( x => x.OpCode == OpCodes.Ldc_R4, x => x.MatchStfld <EquipmentSlot>("missileTimer")); if (ILFound) { //Replace original missile cooldown (0.125f) with a custom function to check for Embryo-boosted missiles //If boosts exist, halves the missile cooldown to 0.0625f and deducts a boost from CPD; otherwise returns original c.Index++; c.EmitDelegate <Func <float, float> >((origCooldown) => { if (cpt && cpt.boostedMissiles > 0) { cpt.boostedMissiles--; return(origCooldown / 2); } return(origCooldown); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: CommandMissile (FixedUpdate)"); } } if (subEnable[EquipmentIndex.BFG]) { //Find: string "Prefabs/Projectiles/BeamSphere" //Then find: CharacterBody.get_damage * 2f (damage argument of FireProjectile) ILFound = c.TryGotoNext( x => x.MatchLdstr("Prefabs/Projectiles/BeamSphere")) && c.TryGotoNext( x => x.MatchCallvirt <CharacterBody>("get_damage"), x => x.OpCode == OpCodes.Ldc_R4, x => x.MatchMul()); if (ILFound) { //Advance cursor to found ldcR4 c.Index += 2; //Replace original FireProjectile damage coefficient (2f) with a custom function to check for Embryo-boosted BFG shots //If boosts exist, doubles the damage coefficient to 4f and deducts a boost from CPD; otherwise returns original c.EmitDelegate <Func <float, float> >((origDamage) => { if (cpt && cpt.boostedBFGs > 0) { cpt.boostedBFGs--; return(origDamage * 2f); } return(origDamage); }); } else { ClassicItemsPlugin._logger.LogError("Failed to apply Beating Embryo IL patch: BFG (FixedUpdate)"); } } }
public static IEnumerable<Instruction> PushConvertedValue(this ValueNode node, ILContext context, TypeReference targetTypeRef, TypeReference typeConverter, IEnumerable<Instruction> pushServiceProvider, bool boxValueTypes, bool unboxValueTypes) { var module = context.Body.Method.Module; var str = (string)node.Value; //If there's a [TypeConverter], use it if (typeConverter != null) { var isExtendedConverter = typeConverter.ImplementsInterface(module.Import(typeof (IExtendedTypeConverter))); var typeConverterCtor = typeConverter.Resolve().Methods.Single(md => md.IsConstructor && md.Parameters.Count == 0); var typeConverterCtorRef = module.Import(typeConverterCtor); var convertFromInvariantStringDefinition = isExtendedConverter ? module.Import(typeof (IExtendedTypeConverter)) .Resolve() .Methods.FirstOrDefault(md => md.Name == "ConvertFromInvariantString" && md.Parameters.Count == 2) : typeConverter.Resolve() .AllMethods() .FirstOrDefault(md => md.Name == "ConvertFromInvariantString" && md.Parameters.Count == 1); var convertFromInvariantStringReference = module.Import(convertFromInvariantStringDefinition); yield return Instruction.Create(OpCodes.Newobj, typeConverterCtorRef); yield return Instruction.Create(OpCodes.Ldstr, node.Value as string); if (isExtendedConverter) { foreach (var instruction in pushServiceProvider) yield return instruction; } yield return Instruction.Create(OpCodes.Callvirt, convertFromInvariantStringReference); if (targetTypeRef.IsValueType && unboxValueTypes) yield return Instruction.Create(OpCodes.Unbox_Any, module.Import(targetTypeRef)); //ConvertFrom returns an object, no need to Box yield break; } var originalTypeRef = targetTypeRef; var isNullable = false; MethodReference nullableCtor = null; if (targetTypeRef.Resolve().FullName == "System.Nullable`1") { targetTypeRef = ((GenericInstanceType)targetTypeRef).GenericArguments[0]; isNullable = true; nullableCtor = originalTypeRef.GetMethods(md => md.IsConstructor && md.Parameters.Count == 1, module).Single().Item1; nullableCtor = nullableCtor.MakeGeneric(targetTypeRef); } //Obvious Built-in conversions if (targetTypeRef.Resolve().BaseType != null && targetTypeRef.Resolve().BaseType.FullName == "System.Enum") yield return Instruction.Create(OpCodes.Ldc_I4, ParseEnum(targetTypeRef, str, node)); else if (targetTypeRef.FullName == "System.Char") yield return Instruction.Create(OpCodes.Ldc_I4, Char.Parse(str)); else if (targetTypeRef.FullName == "System.Byte") yield return Instruction.Create(OpCodes.Ldc_I4, Byte.Parse(str, CultureInfo.InvariantCulture)); else if (targetTypeRef.FullName == "System.Int16") yield return Instruction.Create(OpCodes.Ldc_I4, Int16.Parse(str, CultureInfo.InvariantCulture)); else if (targetTypeRef.FullName == "System.Int32") yield return Instruction.Create(OpCodes.Ldc_I4, Int32.Parse(str, CultureInfo.InvariantCulture)); else if (targetTypeRef.FullName == "System.Int64") yield return Instruction.Create(OpCodes.Ldc_I8, Int64.Parse(str, CultureInfo.InvariantCulture)); else if (targetTypeRef.FullName == "System.Single") yield return Instruction.Create(OpCodes.Ldc_R4, Single.Parse(str, CultureInfo.InvariantCulture)); else if (targetTypeRef.FullName == "System.Double") yield return Instruction.Create(OpCodes.Ldc_R8, Double.Parse(str, CultureInfo.InvariantCulture)); else if (targetTypeRef.FullName == "System.Boolean") { if (Boolean.Parse(str)) yield return Instruction.Create(OpCodes.Ldc_I4_1); else yield return Instruction.Create(OpCodes.Ldc_I4_0); } else if (targetTypeRef.FullName == "System.TimeSpan") { var ts = TimeSpan.Parse(str, CultureInfo.InvariantCulture); var ticks = ts.Ticks; var timeSpanCtor = module.Import(typeof (TimeSpan)) .Resolve() .Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 1); var timeSpanCtorRef = module.Import(timeSpanCtor); yield return Instruction.Create(OpCodes.Ldc_I8, ticks); yield return Instruction.Create(OpCodes.Newobj, timeSpanCtorRef); } else if (targetTypeRef.FullName == "System.DateTime") { var dt = DateTime.Parse(str, CultureInfo.InvariantCulture); var ticks = dt.Ticks; var dateTimeCtor = module.Import(typeof (DateTime)) .Resolve() .Methods.FirstOrDefault(md => md.IsConstructor && md.Parameters.Count == 1); var dateTimeCtorRef = module.Import(dateTimeCtor); yield return Instruction.Create(OpCodes.Ldc_I8, ticks); yield return Instruction.Create(OpCodes.Newobj, dateTimeCtorRef); } else if (targetTypeRef.FullName == "System.String" && str.StartsWith("{}", StringComparison.Ordinal)) yield return Instruction.Create(OpCodes.Ldstr, str.Substring(2)); else if (targetTypeRef.FullName == "System.String") yield return Instruction.Create(OpCodes.Ldstr, str); else if (targetTypeRef.FullName == "System.Object") yield return Instruction.Create(OpCodes.Ldstr, str); else yield return Instruction.Create(OpCodes.Ldnull); if (isNullable) yield return Instruction.Create(OpCodes.Newobj, module.Import(nullableCtor)); if (originalTypeRef.IsValueType && boxValueTypes) yield return Instruction.Create(OpCodes.Box, module.Import(originalTypeRef)); }
public SetResourcesVisitor(ILContext context) { Context = context; Module = context.Body.Method.Module; }