Issue with Generics (for sure) and Generating IL Code (maybe)

Discuss modding questions and implementation details.
Post Reply
DFIronman
Posts: 63
Joined: Sat Aug 24, 2019 12:48 am

Issue with Generics (for sure) and Generating IL Code (maybe)

Post by DFIronman » Mon Sep 02, 2019 1:55 am

Edit: There definitely seems to be a problem with using generics in a mod. See my second post. When I made this first post, I thought it was purely to do with generating IL code. Using Reflection.Emit() may be fine?

-

I'm trying to make my Reflection usage faster - and it works great in the Unity Editor - but, in the live game, I get the following error:

InvalidProgramException: Invalid IL code in DaggerfallWorkshop.Game.Mods.Ironman.ReflectionHelper:GetFieldGetter<TClass, TResult> (object,string,System.Type,System.Reflection.BindingFlags): method body is empty.

I'm pretty certain there's nothing wrong with the code, unless there's something special you need to do in DFUnity to make IL generation work from a mod. Code below:

Code: Select all

        public static Func<TClass, TResult> GetFieldGetter<TClass, TResult>(this object obj, string field, Type startingType = null, BindingFlags bindingFlags = _BindingFlags)
        {
            Type type = typeof(TClass);

            // GetFieldInfo is a custom function that returns a FieldInfo object.
            FieldInfo info = GetFieldInfo(obj, field, startingType, bindingFlags);
            DynamicMethod DM = new DynamicMethod("dynamic_get_" + info.Name, typeof(TResult), new Type[] { type }, type);
            ILGenerator ILG = DM.GetILGenerator();

            ILG.Emit(OpCodes.Ldarg_0);
            ILG.Emit(OpCodes.Ldfld, info);
            ILG.Emit(OpCodes.Ret);

            return (Func<TClass, TResult>)DM.CreateDelegate(typeof(Func<TClass, TResult>));
        }
Again, it works perfectly in the Unity Editor. Anyone have any ideas?
Last edited by DFIronman on Mon Sep 02, 2019 4:11 am, edited 7 times in total.

DFIronman
Posts: 63
Joined: Sat Aug 24, 2019 12:48 am

Issue with Generics (for sure) and Generating IL Code (maybe)

Post by DFIronman » Mon Sep 02, 2019 3:27 am

Weird. I just got the same error message with the following code as well (this code didn't exist when I made this topic):

Code: Select all

        public static Component ReplaceAndReturnComponent<TOldComp, TNewComp>(GameObject owning_object)
        {
            owning_object.AddComponent(typeof(TNewComp));

            Component old_component = owning_object.GetComponent(typeof(TOldComp));

            if (old_component == null)
                throw new NullReferenceException("No component of type '" + old_type + "' on GameObject '" + owning_object.name + "'");

            Component new_component = owning_object.GetComponent(new_type);

            if (new_component == null)
                throw new NullReferenceException("No component of type '" + new_type + "' on GameObject '" + owning_object.name + "'");


            // Copy the state of the old component to the new component
            FieldInfo[] fields = old_component.GetType().GetFields();
            foreach (FieldInfo field in fields)
                field.SetValue(new_component, field.GetValue(old_component));

            UnityEngine.Object.Destroy(old_component);

            return new_component;
        }
The following code works in the live game. It looks like there's some kind of an issue with generics?

Code: Select all

        public static Component ReplaceAndReturnComponent(GameObject owning_object, Type new_type, Type old_type)
        {
            owning_object.AddComponent(new_type);

            Component old_component = owning_object.GetComponent(old_type);

            if (old_component == null)
                throw new NullReferenceException("No component of type '" + old_type + "' on GameObject '" + owning_object.name + "'");

            Component new_component = owning_object.GetComponent(new_type);

            if (new_component == null)
                throw new NullReferenceException("No component of type '" + new_type + "' on GameObject '" + owning_object.name + "'");

            // Copy the state of the old component to the new component
            FieldInfo[] fields = old_component.GetType().GetFields();
            foreach (FieldInfo field in fields)
                field.SetValue(new_component, field.GetValue(old_component));

            UnityEngine.Object.Destroy(old_component);

            return new_component;
        }

Post Reply