• We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.

Quget

Galactic Empress
86 Badges
May 17, 2014
82
188
quget.com
  • Crusader Kings II
  • Hearts of Iron IV Sign-up
  • Crusader Kings III Referal
  • Age of Wonders: Planetfall Sign Up
  • Europa Universalis IV: Third Rome
  • Stellaris - Path to Destruction bundle
  • Stellaris: Leviathans Story Pack
  • Europa Universalis IV: Rights of Man
  • Stellaris: Galaxy Edition
  • Stellaris
  • Cities: Skylines - Snowfall
  • Europa Universalis IV: Cossacks
  • Cities: Skylines - After Dark
  • Europa Universalis IV: Pre-order
  • Cities: Skylines Deluxe Edition
  • Europa Universalis IV: Res Publica
  • Europa Universalis IV: Conquest of Paradise
  • Crusader Kings II: The Old Gods
  • Crusader Kings II: The Republic
  • Crusader Kings II: Sword of Islam
  • Crusader Kings II: Legacy of Rome
  • Europa Universalis IV: Art of War
  • Magicka 2
  • Hearts of Iron IV: Cadet
  • Europa Universalis IV
  • Stellaris: Galaxy Edition
  • Europa Universalis IV: Wealth of Nations
  • Europa Universalis IV: Call to arms event
  • Magicka
  • Europa Universalis IV: Common Sense
  • Europa Universalis IV: Dharma
  • Hearts of Iron IV: Death or Dishonor
  • Surviving Mars: First Colony Edition
  • Stellaris Sign-up
  • Europa Universalis IV: Golden Century
  • Stellaris: Distant Stars
  • Age of Wonders: Planetfall Season pass
  • Imperator: Rome Deluxe Edition
  • Europa Universalis IV: El Dorado
  • Prison Architect
  • Imperator: Rome Sign Up
  • Cities: Skylines - Parklife
  • Cities: Skylines - Campus
  • Age of Wonders: Planetfall
  • Europa Universalis IV: Rule Britannia
  • Stellaris: Apocalypse
  • Age of Wonders: Planetfall Deluxe edition
  • Age of Wonders: Planetfall Premium edition
  • Hearts of Iron IV: Expansion Pass
  • Stellaris: Lithoids
Since I was unable to access classes the normal way I though I do try a more... hacky way which worked!
If there is another easier way I would like to know though xD Maybe I did this for nothing :blink:
I want to share this, so others can make even better mods and spend more time finding out stuff :)
So many possibilities...

In my More Options mod I use the code below to edit/get values.
Code:
	object GetFieldValue(MonoBehaviour monoObject, string fieldName)
	{
		try
		{
			BindingFlags bindingFlags = BindingFlags.Public |
					BindingFlags.NonPublic |
					BindingFlags.Instance |
					BindingFlags.Static;
					
			FieldInfo fieldInfo = monoObject.GetType().GetField(fieldName,bindingFlags);
			//fieldInfo.SetValue(monoObject,value);
			return fieldInfo.GetValue(monoObject);
			//return true;
		}
		catch(Exception e)
		{
			ChirpLog.Error( "Unable to get Value: " + monoObject.GetType().Name + ":" + fieldName + ":" + e.Message);
			ChirpLog.Flush();
			return 0;
		}
		
	}
	object CallMethod(MonoBehaviour monoObject, string methodName, object[] value = null)
	{
		object returnValue = null;
		try
		{
			MethodInfo[] methods = monoObject.GetType().GetMethods();
			foreach (MethodInfo info in methods)
			{
				if (info.Name == methodName)
				{
					returnValue = info.Invoke(monoObject, value); // [2]
				}
			}
			return returnValue;
		}
		catch(Exception e)
		{
			ChirpLog.Error("Unable to Call Method: " + monoObject.GetType().Name + ":" + methodName + ":" + e.Message);
			ChirpLog.Flush();
			return returnValue;
		}
		
	}
	void SetField(MonoBehaviour monoObject, string fieldName, object value)
	{
		try
		{
			BindingFlags bindingFlags = BindingFlags.Public |
					BindingFlags.NonPublic |
					BindingFlags.Instance |
					BindingFlags.Static;
					
			FieldInfo fieldInfo = monoObject.GetType().GetField(fieldName,bindingFlags);
			fieldInfo.SetValue(monoObject,value);
		}
		catch(Exception e)
		{
			ChirpLog.Error("Unable to set value:" + monoObject.GetType().Name + ":" + fieldName + ":" + e.Message);
			ChirpLog.Flush();
		}
		
	}
Example getting Fields from MonoBehaviours.
Code:
			GameObject[] currentObjects = GameObject.FindObjectsOfType<GameObject>() as GameObject[];
			MonoBehaviour[] behaviours;
			for(int s = 0; s < currentObjects.Length; s++)
			{
				//ChirpLog.Debug("#####" + currentObjects[s].name +"#####");
				if(currentObjects[s].name == "Seagull")
				{
					behaviours = currentObjects[s].GetComponents<MonoBehaviour>() as MonoBehaviour[];
					for(int i = 0; i < behaviours.Length; i++)
					{
						ChirpLog.Debug(behaviours[i].GetType().Name);
						
						BindingFlags bindingFlags = BindingFlags.Public |
                            BindingFlags.NonPublic |
                            BindingFlags.Instance |
                            BindingFlags.Static;
						foreach (FieldInfo field in behaviours[i].GetType().GetFields(bindingFlags))
						{
							ChirpLog.Debug(field.Name +":" +  GetFieldValue(behaviours[i],field.Name) );
						}
					}
				}
			}


Click below for the mod (With source code!)
http://steamcommunity.com/sharedfiles/filedetails/?id=408648436
 
I tend to avoid the specific type of code you're using (simply because it's fairly error prone).

Code:
using System;
using System.Linq;
using System.Reflection;

namespace ApocDev.CitySkylines.Mod.Utils
{
	// The copy/pasta is strong in this one. No real way to do simple static/nonstatic methods without copying code.
	internal class ReflectionUtils
	{
		#region Invoke
		/// <summary>
		/// Invokes a static method on the specified type.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="type"></param>
		/// <param name="methodName"></param>
		/// <param name="args"></param>
		/// <returns></returns>
		public static T InvokeMethod<T>(Type type, string methodName, params object[] args)
		{
			// Try and find the method via the arguments passed in.
			var methodArgumentTypes = args.Select(a => a.GetType()).ToArray();

			// Pass a null array to GetMethod as it shortcuts early instead of doing some sanity checks inside GetMethod itself.
			if (methodArgumentTypes.Length == 0)
			{
				methodArgumentTypes = null;
			}

			var methodInfo = type.GetMethod(methodName,
				BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
				null,
				methodArgumentTypes,
				null);

			if (methodInfo == null)
			{
				throw new ArgumentException(
					string.Format("Method '{0}({1})' could not be found on object of type {2}",
						methodName,
						methodArgumentTypes != null ? string.Join(", ", methodArgumentTypes.Select(t => t.Name).ToArray()) : string.Empty,
						type.FullName),
					"methodName");
			}

			// Note: The invokes here are specifically not in a try/catch. The exception will bubble up to the caller so it can be handled there properly,
			// rather than suppressing anything we'd do here.
			if (methodInfo.ReturnType == typeof(void))
			{
				methodInfo.Invoke(null, args);
				return default(T);
			}
			return (T)methodInfo.Invoke(null, args);
		}

		/// <summary>
		/// Invokes an instance method on the specified object.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="instance"></param>
		/// <param name="methodName"></param>
		/// <param name="args"></param>
		/// <returns></returns>
		public static T InvokeMethod<T>(object instance, string methodName, params object[] args)
		{
			// Try and find the method via the arguments passed in.
			var methodArgumentTypes = args.Select(a => a.GetType()).ToArray();

			// Pass a null array to GetMethod as it shortcuts early instead of doing some sanity checks inside GetMethod itself.
			if (methodArgumentTypes.Length == 0)
			{
				methodArgumentTypes = null;
			}

			var methodInfo = instance.GetType().GetMethod(methodName,
				BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
				null,
				methodArgumentTypes,
				null);

			if (methodInfo == null)
			{
				throw new ArgumentException(
					string.Format("Method '{0}({1})' could not be found on object of type {2}",
						methodName,
						methodArgumentTypes != null ? string.Join(", ", methodArgumentTypes.Select(t => t.Name).ToArray()) : string.Empty,
						instance.GetType().FullName),
					"methodName");
			}

			// Note: The invokes here are specifically not in a try/catch. The exception will bubble up to the caller so it can be handled there properly,
			// rather than suppressing anything we'd do here.
			if (methodInfo.ReturnType == typeof(void))
			{
				methodInfo.Invoke(instance, args);
				return default(T);
			}
			return (T) methodInfo.Invoke(instance, args);
		}

		#endregion

		#region Get/SetField

		public static T GetField<T>(Type type, string fieldName)
		{
			var field = type.GetField(fieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
			if (field == null)
			{
				throw new ArgumentException("Field '" + fieldName + "' could not be found on object of type " + type.FullName, "fieldName");
			}
			return (T) field.GetValue(null);
		}

		public static void SetField(Type type, string fieldName, object value)
		{
			var field = type.GetField(fieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
			if (field == null)
			{
				throw new ArgumentException("Field '" + fieldName + "' could not be found on object of type " + type.FullName, "fieldName");
			}
			field.SetValue(null, value);
		}
		public static T GetField<T>(object instance, string fieldName)
		{
			var field = instance.GetType().GetField(fieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
			if (field == null)
			{
				throw new ArgumentException("Field '" + fieldName + "' could not be found on object of type " + instance.GetType().FullName, "fieldName");
			}
			return (T) field.GetValue(instance);
		}

		public static void SetField(object instance, string fieldName, object value)
		{
			var field = instance.GetType().GetField(fieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
			if (field == null)
			{
				throw new ArgumentException("Field '" + fieldName + "' could not be found on object of type " + instance.GetType().FullName, "fieldName");
			}
			field.SetValue(instance, value);
		}
		#endregion
	}
}

Usage is a bit more straightforward:

Code:
		public static void ResizeArray32<T>(Array32<T> array, uint newSize)
		{
			array.m_size = newSize;
			Array.Resize(ref array.m_buffer, (int)newSize);
			var unusedCount = ReflectionUtils.GetField<uint>(array, "m_unusedCount");
			var unusedItems = ReflectionUtils.GetField<uint[]>(array, "m_unusedItems");

			uint[] newUnusedItems = new uint[newSize];
			Buffer.BlockCopy(unusedItems, 0, newUnusedItems, 0, 4 * unusedItems.Length);

			// Now add our own unused items
			for (uint i = (uint)unusedItems.Length; i < newSize + 1; i++)
			{
				newUnusedItems[i - 1] = i;
			}

			// Update the unusedCount to be in line with the new array size
			// This is just adding the newly sized additions.
			unusedCount += newSize - unusedCount;

			ReflectionUtils.SetField(array, "m_unusedCount", unusedCount);
			ReflectionUtils.SetField(array, "m_unusedItems", unusedItems);

			// var nextFree = ReflectionUtils.InvokeMethod<uint>(array, "NextFreeItem");
			// var nextFree = array.NextFreeItem();
		}