From 448feacbaaad6fed8cac0f16f72d24a241ba0b51 Mon Sep 17 00:00:00 2001
From: lwb <q3213421wrwqr>
Date: 星期三, 13 一月 2021 19:08:06 +0800
Subject: [PATCH] 9527 InjectFix
---
Assets/IFix/Editor/ILFixEditor.cs.meta | 12
IFixToolKit/Mono.Cecil.Mdb.dll | 0
Assets/IFix/Editor.meta | 9
Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs | 37 +
Assets/IFix.meta | 8
IFixToolKit/Mono.Cecil.Pdb.dll | 0
Assets/Plugins/IFix.Core.dll.meta | 33 +
Assets/IFix/Editor/ILFixEditor.cs | 875 ++++++++++++++++++++++++++++++++++++++++++++++
Assets/IFix/Editor/Configure.cs.meta | 12
IFixToolKit/Mono.Cecil.dll | 0
IFixToolKit/IFix.exe.mdb | 0
Assets/Plugins/IFix.Core.dll | 0
Assets/IFix/Editor/Configure.cs | 152 ++++++++
13 files changed, 1,136 insertions(+), 2 deletions(-)
diff --git a/Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs b/Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs
index ab2b5ea..56f7575 100644
--- a/Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs
+++ b/Assets/Editor/AssetBundleBrowser/AssetBundleBuildTab.cs
@@ -6,6 +6,7 @@
using UnityEngine.AssetBundles.AssetBundleDataSource;
using Assets.Editor.Tool;
+using IFix.Editor;
namespace UnityEngine.AssetBundles
{
@@ -366,6 +367,11 @@
EditorApplication.delayCall += ExcuteBuildMobEffectShader;
}
+ if (GUILayout.Button("patch"))
+ {
+ EditorApplication.delayCall += ExcuteBuildPatch;
+ }
+
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
@@ -550,6 +556,7 @@
ExcuteBuildUI();
ExcuteBuildBuiltIn();
ExcuteBuildLua();
+ ExcuteBuildPatch();
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
@@ -630,6 +637,31 @@
UpdateLuaSetting.SetAllLuaAssetBundleName();
ExcuteBuildAsset("lua");
LuaBuildHelper.OnPostBuild();
+ }
+
+ private void ExcuteBuildPatch()
+ {
+ string sourcePath;
+ if (m_UserData.m_BuildTarget == ValidBuildTarget.Android)
+ {
+ IFixEditor.CompileToAndroid();
+ sourcePath = ResourcesPath.PATCH_ANDROID;
+ }
+ else if (m_UserData.m_BuildTarget == ValidBuildTarget.iOS)
+ {
+ IFixEditor.CompileToIOS();
+ sourcePath = ResourcesPath.PATCH_IOS;
+ }
+ else
+ {
+ IFixEditor.Patch();
+ sourcePath = ResourcesPath.PATCH_EDITOR;
+ }
+ var outputPath = Application.dataPath.Replace("Assets", m_UserData.m_OutputPath);
+ outputPath = StringUtility.Contact(outputPath, "/patch");
+ if (Directory.Exists(outputPath))
+ Directory.Delete(outputPath, true);
+ DirectoryCopy(sourcePath, outputPath, ".meta");
}
private void ExcuteBuildLevels()
@@ -768,7 +800,7 @@
}
}
- private static void DirectoryCopy(string sourceDirName, string destDirName)
+ private static void DirectoryCopy(string sourceDirName, string destDirName, string excludeEx = null)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
@@ -784,7 +816,8 @@
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
- file.CopyTo(temppath, false);
+ if (excludeEx == null || file.Extension != excludeEx)
+ file.CopyTo(temppath, false);
}
DirectoryInfo[] dirs = dir.GetDirectories();
diff --git a/Assets/IFix.meta b/Assets/IFix.meta
new file mode 100644
index 0000000..e5cdf9e
--- /dev/null
+++ b/Assets/IFix.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: efab94b801c78c54289af83a0e4e82fb
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/IFix/Editor.meta b/Assets/IFix/Editor.meta
new file mode 100644
index 0000000..3a5016d
--- /dev/null
+++ b/Assets/IFix/Editor.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 89d3afd1ac6383a4bb803e86127d5ed3
+folderAsset: yes
+timeCreated: 1514965388
+licenseType: Pro
+DefaultImporter:
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/IFix/Editor/Configure.cs b/Assets/IFix/Editor/Configure.cs
new file mode 100644
index 0000000..413f449
--- /dev/null
+++ b/Assets/IFix/Editor/Configure.cs
@@ -0,0 +1,152 @@
+/*
+ * Tencent is pleased to support the open source community by making InjectFix available.
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms.
+ * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package.
+ */
+
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Collections;
+using System;
+
+/************************************************************************************************
+ * 閰嶇疆
+ * 1銆両Fix銆両nterpret銆丷everseWrapper椤绘斁鍒颁竴涓墦浜咰onfigure鏍囩鐨勭被閲岋紱
+ * 2銆両Fix銆両nterpret銆丷everseWrapper鍧囩敤鎵撲簡鐩稿簲鏍囩鐨勫睘鎬ф潵琛ㄧず锛�
+ * 3銆両Fix銆両nterpret銆丷everseWrapper閰嶇疆椤绘斁鍒癊ditor鐩綍涓嬶紱
+*************************************************************************************************/
+
+namespace IFix
+{
+
+ [Configure]
+ public class InterpertConfig
+ {
+ [IFix]
+ static IEnumerable<Type> ToProcess
+ {
+ get
+ {
+ return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
+ where type.Namespace == null || (!type.Namespace.StartsWith("XLua") && !type.Namespace.StartsWith("IFix"))
+ select type);
+ }
+ }
+ }
+
+ //鏀剧疆閰嶇疆鐨�
+ [AttributeUsage(AttributeTargets.Class)]
+ public class ConfigureAttribute : Attribute
+ {
+
+ }
+
+ //榛樿鎵ц鍘熺敓浠g爜锛岃兘鍒囨崲鍒拌В鏋愭墽琛岋紝蹇呴』鏀惧湪鏍囪浜咰onfigure鐨勭被閲�
+ [AttributeUsage(AttributeTargets.Property)]
+ public class IFixAttribute : Attribute
+ {
+ }
+
+ //鐢熸垚鍙嶅悜锛堣В鏋愯皟鐢ㄥ師鐢燂級灏佽鍣紝鍔犻�熻皟鐢ㄦ�ц兘
+ [AttributeUsage(AttributeTargets.Property)]
+ public class ReverseWrapperAttribute : Attribute
+ {
+ }
+
+ [AttributeUsage(AttributeTargets.Method)]
+ public class FilterAttribute : Attribute
+ {
+ }
+
+ public static class Configure
+ {
+ //
+ public static Dictionary<string, List<KeyValuePair<object, int>>> GetConfigureByTags(List<string> tags)
+ {
+ var types = from assembly in AppDomain.CurrentDomain.GetAssemblies()
+ where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
+ from type in assembly.GetTypes()
+ where type.IsDefined(typeof(ConfigureAttribute), false)
+ select type;
+ var tagsMap = tags.ToDictionary(t => t, t => new List<KeyValuePair<object, int>>());
+
+ foreach (var type in types)
+ {
+ foreach (var prop in type.GetProperties(BindingFlags.Static | BindingFlags.Public
+ | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
+ {
+ if (typeof(IEnumerable).IsAssignableFrom(prop.PropertyType))
+ {
+ foreach (var ca in prop.GetCustomAttributes(false))
+ {
+ int flag = 0;
+ var fp = ca.GetType().GetProperty("Flag");
+ if (fp != null)
+ {
+ flag = (int)fp.GetValue(ca, null);
+ }
+ List<KeyValuePair<object, int>> infos;
+ if (tagsMap.TryGetValue(ca.GetType().ToString(), out infos))
+ {
+ foreach (var applyTo in prop.GetValue(null, null) as IEnumerable)
+ {
+ infos.Add(new KeyValuePair<object, int>(applyTo, flag));
+ }
+ }
+ }
+ }
+ }
+ }
+ return tagsMap;
+ }
+
+ public static List<MethodInfo> GetFilters()
+ {
+ var types = from assembly in AppDomain.CurrentDomain.GetAssemblies()
+ where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
+ from type in assembly.GetTypes()
+ where type.IsDefined(typeof(ConfigureAttribute), false)
+ select type;
+
+ List<MethodInfo> filters = new List<MethodInfo>();
+ foreach (var type in types)
+ {
+ foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public
+ | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
+ {
+ if (method.IsDefined(typeof(IFix.FilterAttribute), false))
+ {
+ filters.Add(method);
+ }
+ }
+ }
+ return filters;
+ }
+
+ public static IEnumerable<MethodInfo> GetTagMethods(Type tagType, string searchAssembly)
+ {
+ return (from assembly in AppDomain.CurrentDomain.GetAssemblies()
+ where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
+ && (assembly.GetName().Name == searchAssembly)
+ where assembly.CodeBase.IndexOf("ScriptAssemblies") != -1
+ from type in assembly.GetTypes()
+ from method in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public
+ | BindingFlags.NonPublic)
+ where method.IsDefined(tagType, false)
+ select method);
+ }
+ public static IEnumerable<Type> GetTagClasses(Type tagType, string searchAssembly)
+ {
+ return (from assembly in AppDomain.CurrentDomain.GetAssemblies()
+ where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
+ && (assembly.GetName().Name == searchAssembly)
+ where assembly.CodeBase.IndexOf("ScriptAssemblies") != -1
+ from type in assembly.GetTypes()
+ where type.IsDefined(tagType, false)
+ select type
+ );
+ }
+ }
+}
diff --git a/Assets/IFix/Editor/Configure.cs.meta b/Assets/IFix/Editor/Configure.cs.meta
new file mode 100644
index 0000000..7b960a2
--- /dev/null
+++ b/Assets/IFix/Editor/Configure.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: aca776d82af199a4b9018dcc5c8cceec
+timeCreated: 1514363894
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/IFix/Editor/ILFixEditor.cs b/Assets/IFix/Editor/ILFixEditor.cs
new file mode 100644
index 0000000..4368443
--- /dev/null
+++ b/Assets/IFix/Editor/ILFixEditor.cs
@@ -0,0 +1,875 @@
+/*
+ * Tencent is pleased to support the open source community by making InjectFix available.
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
+ * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms.
+ * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package.
+ */
+
+using UnityEngine;
+using UnityEditor;
+using System.Collections.Generic;
+using System.IO;
+using System;
+using System.Linq;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+using System.Text;
+using System.Reflection;
+#if UNITY_2018_3_OR_NEWER
+using UnityEditor.Build.Player;
+#endif
+
+namespace IFix.Editor
+{
+ //鐗堟湰閫夋嫨绐楀彛
+ public class VersionSelector : EditorWindow
+ {
+ public string buttonText = "Patch";
+ public string[] options = new string[] { };
+ public int index = 0;
+ public Action<int> callback = null;
+
+ public static void Show(string[] options, Action<int> callback, string buttonText = "Patch")
+ {
+ VersionSelector window = GetWindow<VersionSelector>();
+ window.options = options;
+ window.callback = callback;
+ window.buttonText = buttonText;
+ window.Show();
+ }
+
+ void OnGUI()
+ {
+ index = EditorGUILayout.Popup("Please select a version: ", index, options);
+ if (GUILayout.Button(buttonText))
+ doPatch();
+ }
+
+ void doPatch()
+ {
+ if (callback != null)
+ {
+ callback(index);
+ }
+ Close();
+ }
+ }
+
+ public class IFixEditor
+ {
+ //澶囦唤鐩綍
+ const string BACKUP_PATH = "./IFixDllBackup";
+ //澶囦唤鏂囦欢鐨勬椂闂存埑鐢熸垚鏍煎紡
+ const string TIMESTAMP_FORMAT = "yyyyMMddHHmmss";
+
+ //娉ㄥ叆鐨勭洰鏍囨枃浠跺す
+ private static string targetAssembliesFolder = "";
+
+ //system("mono ifix.exe [args]")
+ public static void CallIFix(List<string> args)
+ {
+#if UNITY_EDITOR_OSX
+ var mono_path = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName),
+ "../MonoBleedingEdge/bin/mono");
+ if(!File.Exists(mono_path))
+ {
+ mono_path = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName),
+ "../../MonoBleedingEdge/bin/mono");
+ }
+#elif UNITY_EDITOR_WIN
+ var mono_path = Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName),
+ "Data/MonoBleedingEdge/bin/mono.exe");
+#endif
+ if (!File.Exists(mono_path))
+ {
+ UnityEngine.Debug.LogError("can not find mono!");
+ }
+ var inject_tool_path = "./IFixToolKit/IFix.exe";
+ //"--runtime = v4.0.30319"
+ if (!File.Exists(inject_tool_path))
+ {
+ UnityEngine.Debug.LogError("please install the ToolKit");
+ return;
+ }
+
+ Process hotfix_injection = new Process();
+ hotfix_injection.StartInfo.FileName = mono_path;
+#if UNITY_5_6_OR_NEWER
+ hotfix_injection.StartInfo.Arguments = "--debug --runtime=v4.0.30319 \"" + inject_tool_path + "\" \""
+#else
+ hotfix_injection.StartInfo.Arguments = "--debug \"" + inject_tool_path + "\" \""
+#endif
+ + string.Join("\" \"", args.ToArray()) + "\"";
+ hotfix_injection.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ hotfix_injection.StartInfo.RedirectStandardOutput = true;
+ hotfix_injection.StartInfo.UseShellExecute = false;
+ hotfix_injection.StartInfo.CreateNoWindow = true;
+ hotfix_injection.Start();
+
+ //UnityEngine.Debug.Log(hotfix_injection.StartInfo.FileName);
+ //UnityEngine.Debug.Log(hotfix_injection.StartInfo.Arguments);
+
+ StringBuilder exceptionInfo = null;
+ while (!hotfix_injection.StandardOutput.EndOfStream)
+ {
+ string line = hotfix_injection.StandardOutput.ReadLine();
+ if (exceptionInfo != null)
+ {
+ exceptionInfo.AppendLine(line);
+ }
+ else
+ {
+ if (line.StartsWith("Warning:"))
+ {
+ UnityEngine.Debug.LogWarning(line);
+ }
+ else if (line.StartsWith("Error:"))
+ {
+ UnityEngine.Debug.LogError(line);
+ }
+ else if (line.StartsWith("Unhandled Exception:"))
+ {
+ exceptionInfo = new StringBuilder(line);
+ }
+ else
+ {
+ UnityEngine.Debug.Log(line);
+ }
+ }
+ }
+ hotfix_injection.WaitForExit();
+ if (exceptionInfo != null)
+ {
+ UnityEngine.Debug.LogError(exceptionInfo);
+ }
+ }
+
+ [MenuItem("InjectFix/Inject", false, 1)]
+ public static void InjectAssemblys()
+ {
+ if (EditorApplication.isCompiling || Application.isPlaying)
+ {
+ UnityEngine.Debug.LogError("compiling or playing");
+ return;
+ }
+ EditorUtility.DisplayProgressBar("Inject", "injecting...", 0);
+ try
+ {
+ InjectAllAssemblys();
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogError(e);
+ }
+ EditorUtility.ClearProgressBar();
+ }
+
+ public static bool AutoInject = true; //鍙互鍦ㄥ閮ㄧ鐢ㄦ帀鑷姩娉ㄥ叆
+
+ public static bool InjectOnce = false; //AutoInjectAssemblys鍙皟鐢ㄤ竴娆★紝鍙互闃叉鑷姩鍖栨墦鍖呮椂锛屽緢澶氬満鏅鑷碅utoInjectAssemblys琚娆¤皟鐢�
+
+ static bool injected = false;
+
+ [UnityEditor.Callbacks.PostProcessScene]
+ public static void AutoInjectAssemblys()
+ {
+ if (AutoInject && !injected)
+ {
+ InjectAllAssemblys();
+ if (InjectOnce)
+ {
+ injected = true;
+ }
+ }
+ }
+
+ //鑾峰彇澶囦唤鏂囦欢淇℃伅
+ public static void GetBackupInfo(out string[] backups, out string[] timestamps)
+ {
+ string pattern = @"Assembly-CSharp-(\d{14})\.dll$";
+ Regex r = new Regex(pattern);
+
+ var allBackup = Directory.GetFiles(BACKUP_PATH).Where(path => r.Match(path).Success)
+ .Select(path => path.Replace('\\', '/')).ToList();
+ allBackup.Sort();
+
+ backups = allBackup.Select(path => r.Match(path).Groups[1].Captures[0].Value).ToArray();
+ timestamps = allBackup.Select(path => DateTime.ParseExact(r.Match(path).Groups[1].Captures[0].Value,
+ TIMESTAMP_FORMAT, System.Globalization.CultureInfo.InvariantCulture)
+ .ToString("yyyy-MM-dd hh:mm:ss tt")).ToArray();
+ }
+
+ //閫夋嫨澶囦唤
+ public static void SelectBackup(string buttonText, Action<string> cb)
+ {
+ string[] backups;
+ string[] timestamps;
+ GetBackupInfo(out backups, out timestamps);
+
+ VersionSelector.Show(timestamps.ToArray(), index =>
+ {
+ cb(backups[index]);
+ }, buttonText);
+ }
+
+ /// <summary>
+ /// 瀵规寚瀹氱殑绋嬪簭闆嗘敞鍏�
+ /// </summary>
+ /// <param name="assembly">绋嬪簭闆嗚矾寰�</param>
+ public static void InjectAssembly(string assembly)
+ {
+ var configure = Configure.GetConfigureByTags(new List<string>() {
+ "IFix.IFixAttribute",
+ "IFix.InterpretAttribute",
+ "IFix.ReverseWrapperAttribute",
+ });
+
+ var filters = Configure.GetFilters();
+
+ var processCfgPath = "./process_cfg";
+
+ //璇ョ▼搴忛泦鏄惁鏈夐厤缃簡浜涚被锛屽鏋滄病鏈夊氨璺宠繃娉ㄥ叆鎿嶄綔
+ bool hasSomethingToDo = false;
+
+ var blackList = new List<MethodInfo>();
+
+ using (BinaryWriter writer = new BinaryWriter(new FileStream(processCfgPath, FileMode.Create,
+ FileAccess.Write)))
+ {
+ writer.Write(configure.Count);
+
+ foreach (var kv in configure)
+ {
+ writer.Write(kv.Key);
+
+ var typeList = kv.Value.Where(item => item.Key is Type)
+ .Select(item => new KeyValuePair<Type, int>(item.Key as Type, item.Value))
+ .Where(item => item.Key.Assembly.GetName().Name == assembly)
+ .ToList();
+ writer.Write(typeList.Count);
+
+ if (typeList.Count > 0)
+ {
+ hasSomethingToDo = true;
+ }
+
+ foreach (var cfgItem in typeList)
+ {
+ writer.Write(GetCecilTypeName(cfgItem.Key));
+ writer.Write(cfgItem.Value);
+ if (filters.Count > 0 && kv.Key == "IFix.IFixAttribute")
+ {
+ foreach (var method in cfgItem.Key.GetMethods(BindingFlags.Instance
+ | BindingFlags.Static | BindingFlags.Public
+ | BindingFlags.NonPublic | BindingFlags.DeclaredOnly))
+ {
+ foreach (var filter in filters)
+ {
+ if ((bool)filter.Invoke(null, new object[]
+ {
+ method
+ }))
+ {
+ blackList.Add(method);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ writeMethods(writer, blackList);
+ }
+
+ if (hasSomethingToDo)
+ {
+
+ var core_path = "./Assets/Plugins/IFix.Core.dll";
+ var assembly_path = string.Format("./Library/{0}/{1}.dll", targetAssembliesFolder, assembly);
+ var patch_path = string.Format("./{0}.ill.bytes", assembly);
+ List<string> args = new List<string>() { "-inject", core_path, assembly_path,
+ processCfgPath, patch_path, assembly_path };
+
+ foreach (var path in
+ (from asm in AppDomain.CurrentDomain.GetAssemblies()
+ select Path.GetDirectoryName(asm.ManifestModule.FullyQualifiedName)).Distinct())
+ {
+ try
+ {
+ //UnityEngine.Debug.Log("searchPath:" + path);
+ args.Add(path);
+ }
+ catch { }
+ }
+
+ CallIFix(args);
+ }
+
+ File.Delete(processCfgPath);
+ }
+
+ /// <summary>
+ /// 瀵筰njectAssemblys閲岀殑绋嬪簭闆嗚繘琛屾敞鍏ワ紝鐒跺悗澶囦唤
+ /// </summary>
+ public static void InjectAllAssemblys()
+ {
+ if (EditorApplication.isCompiling || Application.isPlaying)
+ {
+ return;
+ }
+
+ targetAssembliesFolder = GetScriptAssembliesFolder();
+
+ foreach (var assembly in injectAssemblys)
+ {
+ InjectAssembly(assembly);
+ }
+
+ //doBackup(DateTime.Now.ToString(TIMESTAMP_FORMAT));
+
+ AssetDatabase.Refresh();
+ }
+
+ private static string GetScriptAssembliesFolder()
+ {
+ var assembliesFolder = "PlayerScriptAssemblies";
+ if (!Directory.Exists(string.Format("./Library/{0}/", assembliesFolder)))
+ {
+ assembliesFolder = "ScriptAssemblies";
+ }
+ return assembliesFolder;
+ }
+
+ //榛樿鐨勬敞鍏ュ強澶囦唤绋嬪簭闆�
+ //鍙﹀鍙互鐩存帴璋冪敤InjectAssembly瀵瑰叾瀹冪▼搴忛泦杩涜娉ㄥ叆銆�
+ static string[] injectAssemblys = new string[]
+ {
+ "Assembly-CSharp",
+ "Assembly-CSharp-firstpass"
+ };
+
+ /// <summary>
+ /// 鎶婃敞鍏ュ悗鐨勭▼搴忛泦澶囦唤
+ /// </summary>
+ /// <param name="ts">鏃堕棿鎴�</param>
+ static void doBackup(string ts)
+ {
+ if (!Directory.Exists(BACKUP_PATH))
+ {
+ Directory.CreateDirectory(BACKUP_PATH);
+ }
+
+ var scriptAssembliesDir = string.Format("./Library/{0}/", targetAssembliesFolder);
+
+ foreach (var assembly in injectAssemblys)
+ {
+ var dllFile = string.Format("{0}{1}.dll", scriptAssembliesDir, assembly);
+ if (!File.Exists(dllFile))
+ {
+ continue;
+ }
+ File.Copy(dllFile, string.Format("{0}/{1}-{2}.dll", BACKUP_PATH, assembly, ts), true);
+
+ var mdbFile = string.Format("{0}{1}.dll.mdb", scriptAssembliesDir, assembly);
+ if (File.Exists(mdbFile))
+ {
+ File.Copy(mdbFile, string.Format("{0}/{1}-{2}.dll.mdb", BACKUP_PATH, assembly, ts), true);
+ }
+
+ var pdbFile = string.Format("{0}{1}.dll.pdb", scriptAssembliesDir, assembly);
+ if (File.Exists(pdbFile))
+ {
+ File.Copy(pdbFile, string.Format("{0}/{1}-{2}.dll.pdb", BACKUP_PATH, assembly, ts), true);
+ }
+ }
+ }
+
+ /// <summary>
+ /// 鎭㈠鏌愪釜閫夊畾鐨勫浠�
+ /// </summary>
+ /// <param name="ts">鏃堕棿鎴�</param>
+ static void doRestore(string ts)
+ {
+ var scriptAssembliesDir = string.Format("./Library/{0}/", targetAssembliesFolder);
+
+ foreach (var assembly in injectAssemblys)
+ {
+ var dllFile = string.Format("{0}/{1}-{2}.dll", BACKUP_PATH, assembly, ts);
+ if (!File.Exists(dllFile))
+ {
+ continue;
+ }
+ File.Copy(dllFile, string.Format("{0}{1}.dll", scriptAssembliesDir, assembly), true);
+ UnityEngine.Debug.Log("Revert to: " + dllFile);
+
+ var mdbFile = string.Format("{0}/{1}-{2}.dll.mdb", BACKUP_PATH, assembly, ts);
+ if (File.Exists(mdbFile))
+ {
+ File.Copy(mdbFile, string.Format("{0}{1}.dll.mdb", scriptAssembliesDir, assembly), true);
+ UnityEngine.Debug.Log("Revert to: " + mdbFile);
+ }
+
+ var pdbFile = string.Format("{0}/{1}-{2}.dll.pdb", BACKUP_PATH, assembly, ts);
+ if (File.Exists(pdbFile))
+ {
+ File.Copy(pdbFile, string.Format("{0}{1}.dll.pdb", scriptAssembliesDir, assembly), true);
+ UnityEngine.Debug.Log("Revert to: " + pdbFile);
+ }
+ }
+ }
+
+ //cecil閲岀殑绫诲悕琛ㄧず鍜�.net鏍囧噯骞朵笉涓�鏍凤紝杩欓噷鍋氫簺杞崲
+ static string GetCecilTypeName(Type type)
+ {
+ if (type.IsByRef && type.GetElementType().IsGenericType)
+ {
+ return GetCecilTypeName(type.GetElementType()) + "&";
+ }
+ else if (type.IsGenericType)
+ {
+ if (type.IsGenericTypeDefinition)
+ {
+ return type.ToString().Replace('+', '/').Replace('[', '<').Replace(']', '>');
+ }
+ else
+ {
+ return Regex.Replace(type.ToString().Replace('+', '/'), @"(`\d).+", "$1")
+ + "<" + string.Join(",", type.GetGenericArguments().Select(t => GetCecilTypeName(t))
+ .ToArray()) + ">";
+ }
+ }
+ else
+ {
+ return type.FullName.Replace('+', '/');
+ }
+ }
+
+ //鐩墠鏀寔鐨勫钩鍙扮紪璇�
+ public enum Platform
+ {
+ android,
+ ios,
+ standalone
+ }
+
+ //缂撳瓨锛氳В鏋愬ソ鐨勭紪璇戝弬鏁�
+ private static Dictionary<Platform, string> compileTemplates = new Dictionary<Platform, string>();
+
+ //瑙f瀽unity鐨勭紪璇戝弬鏁�
+ private static string parseCompileTemplate(string path)
+ {
+ return string.Join("\n", File.ReadAllLines(path).Where(line => !line.StartsWith("Assets/")
+ && !line.StartsWith("\"Assets/")
+ && !line.StartsWith("'Assets/")
+ && !line.StartsWith("-r:Assets/")
+ && !line.StartsWith("-r:\"Assets/")
+ && !line.StartsWith("-r:'Assets/")
+ && !line.StartsWith("-out")
+ ).ToArray());
+ }
+
+ //瀵硅矾寰勯澶勭悊锛岀劧鍚庢坊鍔犲埌StringBuilder
+ //瑙勫垯锛氬鏋滆矾寰勫惈绌烘牸锛屽垯鍔犱笂鍙屽紩鍙�
+ static void appendFile(StringBuilder sb, string path)
+ {
+ if (path.IndexOf(' ') > 0)
+ {
+ sb.Append('"');
+ sb.Append(path);
+ sb.Append('"');
+ sb.AppendLine();
+ }
+ else
+ {
+ sb.AppendLine(path);
+ }
+ }
+
+ //鑷姩鍔犲叆婧愮爜
+ private static void appendDirectory(StringBuilder src, string dir)
+ {
+ foreach (var file in Directory.GetFiles(dir))
+ {
+ //鎺掗櫎璋僂ditor涓嬬殑涓滆タ
+ if (file.IndexOf(Path.DirectorySeparatorChar + "Editor" + Path.DirectorySeparatorChar) > 0)
+ {
+ continue;
+ }
+ //鎺掗櫎Assembly-CSharp-firstpass
+ if (file.Substring(file.Length - 3).ToLower() == ".cs")
+ {
+ if (file.StartsWith("Assets" + Path.DirectorySeparatorChar + "Plugins") ||
+ file.StartsWith("Assets" + Path.DirectorySeparatorChar + "Standard Assets") ||
+ file.StartsWith("Assets" + Path.DirectorySeparatorChar + "Pro Standard Assets"))
+ {
+ continue;
+ }
+ appendFile(src, file);
+ }
+ }
+
+ foreach (var subDir in Directory.GetDirectories(dir))
+ {
+ appendDirectory(src, subDir);
+ }
+ }
+
+ //閫氳繃妯℃澘鏂囦欢锛岃幏鍙栫紪璇戝弬鏁�
+ private static string getCompileArguments(Platform platform, string output)
+ {
+ string compileTemplate;
+ if (!compileTemplates.TryGetValue(platform, out compileTemplate))
+ {
+#if UNITY_EDITOR_WIN
+ var hostPlatform = "win";
+#elif UNITY_EDITOR_OSX
+ var hostPlatform = "osx";
+#else
+ var hostPlatform = "linux";
+#endif
+ var path = "IFixToolKit/" + platform + "." + hostPlatform + ".tpl";
+ if (!File.Exists(path))
+ {
+ path = "IFixToolKit/" + platform + ".tpl";
+ if (!File.Exists(path))
+ {
+ throw new InvalidOperationException("please put template file for " + platform
+ + " in IFixToolKit directory!");
+ }
+ }
+ compileTemplate = parseCompileTemplate(path);
+ compileTemplates.Add(platform, compileTemplate);
+ }
+ StringBuilder cmd = new StringBuilder();
+ StringBuilder src = new StringBuilder();
+ StringBuilder dll = new StringBuilder();
+
+ appendDirectory(src, "Assets");
+ var projectDir = Application.dataPath.Replace(Path.DirectorySeparatorChar, '/');
+ foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ try
+ {
+#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
+ if (!(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder))
+ {
+#endif
+ var assemblyPath = assembly.ManifestModule.FullyQualifiedName
+ .Replace(Path.DirectorySeparatorChar, '/');
+ if (assemblyPath.StartsWith(projectDir))
+ {
+ dll.Append("-r:");
+ appendFile(dll, assemblyPath.Replace(projectDir, "Assets"));
+ }
+#if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0
+ }
+#endif
+ }
+ catch { }
+ }
+
+ cmd.AppendLine(compileTemplate);
+ cmd.Append(dll.ToString());
+ cmd.Append(src.ToString());
+ cmd.AppendLine("-sdk:2");
+ cmd.Append("-out:");
+ appendFile(cmd, output);
+
+ return cmd.ToString();
+ }
+
+ //1銆佽В鏋愮紪璇戝弬鏁帮紙澶勭悊鍏冩枃浠朵箣澶栫殑缂栬瘧鍙傛暟锛�
+ //2銆佹悳绱㈠伐绋嬬殑c#婧愮爜锛屽姞涓婄紪璇戝弬鏁扮紪璇�
+ //3銆佺紪璇慉ssembly-CSharp.dll
+ //TODO: 鍙敮鎸丄ssembly-CSharp.dll锛屼絾杈冩柊鐗堟湰Unity宸茬粡鏀寔澶歞ll鎷嗗垎
+ //TODO: 鐩墠鐨勫仛娉曟尯绻佺悙鐨勶紝闇�瑕佺敤鎴峰幓鑾峰彇Unity鐨勭紪璇戝懡浠ゆ枃浠讹紝鏇村ソ鐨勫仛娉曞簲璇ユ槸鐩存帴
+ public static void Compile(string compileArgFile)
+ {
+#if UNITY_EDITOR_OSX
+ var monoPath = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName),
+ "../MonoBleedingEdge/bin/mono");
+ var mcsPath = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName),
+ "../MonoBleedingEdge/lib/mono/4.5/mcs.exe");
+ if(!File.Exists(monoPath))
+ {
+ monoPath = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName),
+ "../../MonoBleedingEdge/bin/mono");
+ mcsPath = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName),
+ "../../MonoBleedingEdge/lib/mono/4.5/mcs.exe");
+ }
+#elif UNITY_EDITOR_WIN
+ var monoPath = Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName),
+ "Data/MonoBleedingEdge/bin/mono.exe");
+ var mcsPath = Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName),
+ "Data/MonoBleedingEdge/lib/mono/4.5/mcs.exe");
+#endif
+ if (!File.Exists(monoPath))
+ {
+ UnityEngine.Debug.LogError("can not find mono!");
+ }
+
+ Process compileProcess = new Process();
+ compileProcess.StartInfo.FileName = monoPath;
+ compileProcess.StartInfo.Arguments = "\"" + mcsPath + "\" " + "@" + compileArgFile;
+ compileProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
+ compileProcess.StartInfo.RedirectStandardOutput = true;
+ compileProcess.StartInfo.RedirectStandardError = true;
+ compileProcess.StartInfo.UseShellExecute = false;
+ compileProcess.StartInfo.CreateNoWindow = true;
+ compileProcess.Start();
+
+ //UnityEngine.Debug.Log(hotfix_injection.StartInfo.FileName);
+ //UnityEngine.Debug.Log(hotfix_injection.StartInfo.Arguments);
+
+ while (!compileProcess.StandardError.EndOfStream)
+ {
+ UnityEngine.Debug.LogError(compileProcess.StandardError.ReadLine());
+ }
+
+ while (!compileProcess.StandardOutput.EndOfStream)
+ {
+ UnityEngine.Debug.Log(compileProcess.StandardOutput.ReadLine());
+ }
+
+ compileProcess.WaitForExit();
+ }
+
+ //鐢熸垚鐗瑰畾骞冲彴鐨刾atch
+ public static void GenPlatformPatch(Platform platform, string patchOutputDir,
+ string corePath = "./Assets/Plugins/IFix.Core.dll")
+ {
+ var outputDir = "Temp/ifix";
+ Directory.CreateDirectory("Temp");
+ Directory.CreateDirectory(outputDir);
+#if UNITY_2018_3_OR_NEWER
+ ScriptCompilationSettings scriptCompilationSettings = new ScriptCompilationSettings();
+ if (platform == Platform.android)
+ {
+ scriptCompilationSettings.group = BuildTargetGroup.Android;
+ scriptCompilationSettings.target = BuildTarget.Android;
+ }
+ else if (platform == Platform.ios)
+ {
+ scriptCompilationSettings.group = BuildTargetGroup.iOS;
+ scriptCompilationSettings.target = BuildTarget.iOS;
+ }
+ else
+ {
+ scriptCompilationSettings.group = BuildTargetGroup.Standalone;
+ scriptCompilationSettings.target = BuildTarget.StandaloneWindows;
+ }
+
+ ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, outputDir);
+
+ if (Directory.Exists(patchOutputDir))
+ Directory.Delete(patchOutputDir, true);
+ Directory.CreateDirectory(patchOutputDir);
+ foreach (var assembly in injectAssemblys)
+ {
+ GenPatch(assembly, string.Format("{0}/{1}.dll", outputDir, assembly),
+ "./Assets/Plugins/IFix.Core.dll", string.Format("{0}{1}.patch.bytes", patchOutputDir, assembly));
+ }
+#else
+ throw new NotImplementedException();
+ //var compileArgFile = "Temp/ifix/unity_" + platform + "_compile_argument";
+ //var tmpDllPath = "Temp/ifix/Assembly-CSharp.dll";
+ //File.WriteAllText(compileArgFile, getCompileArguments(platform, tmpDllPath));
+ //鍏堢紪璇慸ll鍒癟emp鐩綍涓�
+ //Compile(compileArgFile);
+ //瀵圭紪璇戝悗鐨刣ll鐢熸垚琛ヤ竵
+ //GenPatch("Assembly-CSharp", tmpDllPath, corePath, patchPath);
+
+ //File.Delete(compileArgFile);
+ //File.Delete(tmpDllPath);
+ //File.Delete(tmpDllPath + ".mdb");
+#endif
+ }
+
+ //鎶婃柟娉曠鍚嶅啓鍏ユ枃浠�
+ //鐢变簬鐩墠涓嶆敮鎸佹硾鍨嬪嚱鏁扮殑patch锛屾墍浠ュ嚱鏁扮鍚嶄负鏂规硶鍚�+鍙傛暟绫诲瀷
+ static void writeMethods(BinaryWriter writer, List<MethodInfo> methods)
+ {
+ var methodGroups = methods.GroupBy(m => m.DeclaringType).ToList();
+ writer.Write(methodGroups.Count);
+ foreach (var methodGroup in methodGroups)
+ {
+ writer.Write(GetCecilTypeName(methodGroup.Key));
+ writer.Write(methodGroup.Count());
+ foreach (var method in methodGroup)
+ {
+ writer.Write(method.Name);
+ writer.Write(GetCecilTypeName(method.ReturnType));
+ writer.Write(method.GetParameters().Length);
+ foreach (var parameter in method.GetParameters())
+ {
+ writer.Write(parameter.IsOut);
+ writer.Write(GetCecilTypeName(parameter.ParameterType));
+ }
+ }
+ }
+ }
+
+ static void writeClasses(BinaryWriter writer, List<Type> classes)
+ {
+ writer.Write(classes.Count);
+ foreach (var classGroup in classes)
+ {
+ writer.Write(GetCecilTypeName(classGroup));
+ }
+ }
+
+ static bool hasGenericParameter(Type type)
+ {
+ if (type.IsByRef || type.IsArray)
+ {
+ return hasGenericParameter(type.GetElementType());
+ }
+ if (type.IsGenericType)
+ {
+ foreach (var typeArg in type.GetGenericArguments())
+ {
+ if (hasGenericParameter(typeArg))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ return type.IsGenericParameter;
+ }
+
+ static bool hasGenericParameter(MethodBase method)
+ {
+ if (method.IsGenericMethodDefinition || method.IsGenericMethod) return true;
+ if (!method.IsConstructor && hasGenericParameter((method as MethodInfo).ReturnType)) return true;
+
+ foreach (var param in method.GetParameters())
+ {
+ if (hasGenericParameter(param.ParameterType))
+ {
+ return true;
+ }
+ }
+ return false;
+
+ }
+
+ /// <summary>
+ /// 鐢熸垚patch
+ /// </summary>
+ /// <param name="assembly">绋嬪簭闆嗗悕锛岀敤鏉ヨ繃婊ら厤缃�</param>
+ /// <param name="assemblyCSharpPath">绋嬪簭闆嗚矾寰�</param>
+ /// <param name="corePath">IFix.Core.dll鎵�鍦ㄨ矾寰�</param>
+ /// <param name="patchPath">鐢熸垚鐨刾atch鐨勪繚瀛樿矾寰�</param>
+ public static void GenPatch(string assembly, string assemblyCSharpPath
+ = "./Library/ScriptAssemblies/Assembly-CSharp.dll",
+ string corePath = "./Assets/Plugins/IFix.Core.dll", string patchPath = ResourcesPath.PATCH_EDITOR)
+ {
+ var patchMethods = Configure.GetTagMethods(typeof(PatchAttribute), assembly).ToList();
+ var genericMethod = patchMethods.FirstOrDefault(m => hasGenericParameter(m));
+ if (genericMethod != null)
+ {
+ throw new InvalidDataException("not support generic method: " + genericMethod);
+ }
+
+ if (patchMethods.Count == 0)
+ {
+ return;
+ }
+
+ var newMethods = Configure.GetTagMethods(typeof(InterpretAttribute), assembly).ToList();
+ var newClasses = Configure.GetTagClasses(typeof(InterpretAttribute), assembly).ToList();
+ genericMethod = newMethods.FirstOrDefault(m => hasGenericParameter(m));
+ if (genericMethod != null)
+ {
+ throw new InvalidDataException("not support generic method: " + genericMethod);
+ }
+
+ var processCfgPath = "./process_cfg";
+
+ using (BinaryWriter writer = new BinaryWriter(new FileStream(processCfgPath, FileMode.Create,
+ FileAccess.Write)))
+ {
+ writeMethods(writer, patchMethods);
+ writeMethods(writer, newMethods);
+ writeClasses(writer, newClasses);
+ }
+
+ List<string> args = new List<string>() { "-patch", corePath, assemblyCSharpPath, "null",
+ processCfgPath, patchPath };
+
+ foreach (var path in
+ (from asm in AppDomain.CurrentDomain.GetAssemblies()
+ select Path.GetDirectoryName(asm.ManifestModule.FullyQualifiedName)).Distinct())
+ {
+ try
+ {
+ //UnityEngine.Debug.Log("searchPath:" + path);
+ args.Add(path);
+ }
+ catch { }
+ }
+
+ CallIFix(args);
+
+ File.Delete(processCfgPath);
+
+ AssetDatabase.Refresh();
+ }
+
+ [MenuItem("InjectFix/Fix", false, 2)]
+ public static void Patch()
+ {
+ EditorUtility.DisplayProgressBar("Generate Patch for Edtior", "patching...", 0);
+ try
+ {
+ if (Directory.Exists(ResourcesPath.PATCH_EDITOR))
+ Directory.Delete(ResourcesPath.PATCH_EDITOR, true);
+ Directory.CreateDirectory(ResourcesPath.PATCH_EDITOR);
+ foreach (var assembly in injectAssemblys)
+ {
+ var assembly_path = string.Format("./Library/{0}/{1}.dll", GetScriptAssembliesFolder(), assembly);
+ GenPatch(assembly, assembly_path, "./Assets/Plugins/IFix.Core.dll",
+ string.Format("{0}{1}.patch.bytes", ResourcesPath.PATCH_EDITOR, assembly));
+ }
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogError(e);
+ }
+ EditorUtility.ClearProgressBar();
+ }
+
+#if UNITY_2018_3_OR_NEWER
+ [MenuItem("InjectFix/Fix(Android)", false, 3)]
+ public static void CompileToAndroid()
+ {
+ EditorUtility.DisplayProgressBar("Generate Patch for Android", "patching...", 0);
+ try
+ {
+ GenPlatformPatch(Platform.android, ResourcesPath.PATCH_ANDROID);
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogError(e);
+ }
+ EditorUtility.ClearProgressBar();
+ }
+
+ [MenuItem("InjectFix/Fix(IOS)", false, 4)]
+ public static void CompileToIOS()
+ {
+ EditorUtility.DisplayProgressBar("Generate Patch for IOS", "patching...", 0);
+ try
+ {
+ GenPlatformPatch(Platform.ios, ResourcesPath.PATCH_IOS);
+ }
+ catch (Exception e)
+ {
+ UnityEngine.Debug.LogError(e);
+ }
+ EditorUtility.ClearProgressBar();
+ }
+#endif
+ }
+}
diff --git a/Assets/IFix/Editor/ILFixEditor.cs.meta b/Assets/IFix/Editor/ILFixEditor.cs.meta
new file mode 100644
index 0000000..37eb3ba
--- /dev/null
+++ b/Assets/IFix/Editor/ILFixEditor.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ea1d006806821c945ad3dfda116f04f7
+timeCreated: 1514863799
+licenseType: Pro
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Plugins/IFix.Core.dll b/Assets/Plugins/IFix.Core.dll
new file mode 100644
index 0000000..30fe492
--- /dev/null
+++ b/Assets/Plugins/IFix.Core.dll
Binary files differ
diff --git a/Assets/Plugins/IFix.Core.dll.meta b/Assets/Plugins/IFix.Core.dll.meta
new file mode 100644
index 0000000..ae7e328
--- /dev/null
+++ b/Assets/Plugins/IFix.Core.dll.meta
@@ -0,0 +1,33 @@
+fileFormatVersion: 2
+guid: 7c6cf326f60d243479929e308c3123fb
+PluginImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ iconMap: {}
+ executionOrder: {}
+ defineConstraints: []
+ isPreloaded: 0
+ isOverridable: 0
+ isExplicitlyReferenced: 0
+ validateReferences: 1
+ platformData:
+ - first:
+ Any:
+ second:
+ enabled: 1
+ settings: {}
+ - first:
+ Editor: Editor
+ second:
+ enabled: 0
+ settings:
+ DefaultValueInitialized: true
+ - first:
+ Windows Store Apps: WindowsStoreApps
+ second:
+ enabled: 0
+ settings:
+ CPU: AnyCPU
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/IFixToolKit/IFix.exe.mdb b/IFixToolKit/IFix.exe.mdb
new file mode 100644
index 0000000..154928f
--- /dev/null
+++ b/IFixToolKit/IFix.exe.mdb
Binary files differ
diff --git a/IFixToolKit/Mono.Cecil.Mdb.dll b/IFixToolKit/Mono.Cecil.Mdb.dll
new file mode 100644
index 0000000..4ddd104
--- /dev/null
+++ b/IFixToolKit/Mono.Cecil.Mdb.dll
Binary files differ
diff --git a/IFixToolKit/Mono.Cecil.Pdb.dll b/IFixToolKit/Mono.Cecil.Pdb.dll
new file mode 100644
index 0000000..ddfe05e
--- /dev/null
+++ b/IFixToolKit/Mono.Cecil.Pdb.dll
Binary files differ
diff --git a/IFixToolKit/Mono.Cecil.dll b/IFixToolKit/Mono.Cecil.dll
new file mode 100644
index 0000000..cb3321e
--- /dev/null
+++ b/IFixToolKit/Mono.Cecil.dll
Binary files differ
--
Gitblit v1.8.0