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