123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- using System;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Runtime.Serialization;
- using System.Runtime.Serialization.Formatters.Binary;
- namespace Harmony
- {
- public static class PatchInfoSerialization
- {
- class Binder : SerializationBinder
- {
- public override Type BindToType(string assemblyName, string typeName)
- {
- var types = new Type[] {
- typeof(PatchInfo),
- typeof(Patch[]),
- typeof(Patch)
- };
- foreach (var type in types)
- if (typeName == type.FullName)
- return type;
- var typeToDeserialize = Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
- return typeToDeserialize;
- }
- }
- public static byte[] Serialize(this PatchInfo patchInfo)
- {
- #pragma warning disable XS0001
- using (var streamMemory = new MemoryStream())
- {
- var formatter = new BinaryFormatter();
- formatter.Serialize(streamMemory, patchInfo);
- return streamMemory.GetBuffer();
- }
- #pragma warning restore XS0001
- }
- public static PatchInfo Deserialize(byte[] bytes)
- {
- var formatter = new BinaryFormatter { Binder = new Binder() };
- #pragma warning disable XS0001
- var streamMemory = new MemoryStream(bytes);
- #pragma warning restore XS0001
- return (PatchInfo)formatter.Deserialize(streamMemory);
- }
- // general sorting by (in that order): before, after, priority and index
- public static int PriorityComparer(object obj, int index, int priority, string[] before, string[] after)
- {
- var trv = Traverse.Create(obj);
- var theirOwner = trv.Field("owner").GetValue<string>();
- var theirPriority = trv.Field("priority").GetValue<int>();
- var theirIndex = trv.Field("index").GetValue<int>();
- if (before != null && Array.IndexOf(before, theirOwner) > -1)
- return -1;
- if (after != null && Array.IndexOf(after, theirOwner) > -1)
- return 1;
- if (priority != theirPriority)
- return -(priority.CompareTo(theirPriority));
- return index.CompareTo(theirIndex);
- }
- }
- [Serializable]
- public class PatchInfo
- {
- public Patch[] prefixes;
- public Patch[] postfixes;
- public Patch[] transpilers;
- public PatchInfo()
- {
- prefixes = new Patch[0];
- postfixes = new Patch[0];
- transpilers = new Patch[0];
- }
- public void AddPrefix(MethodInfo patch, string owner, int priority, string[] before, string[] after)
- {
- var l = prefixes.ToList();
- l.Add(new Patch(patch, prefixes.Count() + 1, owner, priority, before, after));
- prefixes = l.ToArray();
- }
- public void RemovePrefix(string owner)
- {
- if (owner == "*")
- {
- prefixes = new Patch[0];
- return;
- }
- prefixes = prefixes.Where(patch => patch.owner != owner).ToArray();
- }
- public void AddPostfix(MethodInfo patch, string owner, int priority, string[] before, string[] after)
- {
- var l = postfixes.ToList();
- l.Add(new Patch(patch, postfixes.Count() + 1, owner, priority, before, after));
- postfixes = l.ToArray();
- }
- public void RemovePostfix(string owner)
- {
- if (owner == "*")
- {
- postfixes = new Patch[0];
- return;
- }
- postfixes = postfixes.Where(patch => patch.owner != owner).ToArray();
- }
- public void AddTranspiler(MethodInfo patch, string owner, int priority, string[] before, string[] after)
- {
- var l = transpilers.ToList();
- l.Add(new Patch(patch, transpilers.Count() + 1, owner, priority, before, after));
- transpilers = l.ToArray();
- }
- public void RemoveTranspiler(string owner)
- {
- if (owner == "*")
- {
- transpilers = new Patch[0];
- return;
- }
- transpilers = transpilers.Where(patch => patch.owner != owner).ToArray();
- }
- public void RemovePatch(MethodInfo patch)
- {
- prefixes = prefixes.Where(p => p.patch != patch).ToArray();
- postfixes = postfixes.Where(p => p.patch != patch).ToArray();
- transpilers = transpilers.Where(p => p.patch != patch).ToArray();
- }
- }
- [Serializable]
- public class Patch : IComparable
- {
- readonly public int index;
- readonly public string owner;
- readonly public int priority;
- readonly public string[] before;
- readonly public string[] after;
- readonly public MethodInfo patch;
- public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after)
- {
- if (patch is DynamicMethod) throw new Exception("Cannot directly reference dynamic method \"" + patch.FullDescription() + "\" in Harmony. Use a factory method instead that will return the dynamic method.");
- this.index = index;
- this.owner = owner;
- this.priority = priority;
- this.before = before;
- this.after = after;
- this.patch = patch;
- }
- public MethodInfo GetMethod(MethodBase original)
- {
- if (patch.ReturnType != typeof(DynamicMethod)) return patch;
- if (patch.IsStatic == false) return patch;
- var parameters = patch.GetParameters();
- if (parameters.Count() != 1) return patch;
- if (parameters[0].ParameterType != typeof(MethodBase)) return patch;
- // we have a DynamicMethod factory, let's use it
- return patch.Invoke(null, new object[] { original }) as DynamicMethod;
- }
- public override bool Equals(object obj)
- {
- return ((obj != null) && (obj is Patch) && (patch == ((Patch)obj).patch));
- }
- public int CompareTo(object obj)
- {
- return PatchInfoSerialization.PriorityComparer(obj, index, priority, before, after);
- }
- public override int GetHashCode()
- {
- return patch.GetHashCode();
- }
- }
- }
|