diff --git a/.idea/.idea.HALLUCINATE/.idea/workspace.xml b/.idea/.idea.HALLUCINATE/.idea/workspace.xml index ea7595a6..529e290e 100644 --- a/.idea/.idea.HALLUCINATE/.idea/workspace.xml +++ b/.idea/.idea.HALLUCINATE/.idea/workspace.xml @@ -6,7 +6,8 @@ - + + diff --git a/Assets/Plugins.meta b/Assets/Plugins.meta new file mode 100644 index 00000000..e7fbbc1f --- /dev/null +++ b/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f69470e84d5a2c439bd1291c2ac522f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/PrimeTween.meta b/Assets/Plugins/PrimeTween.meta new file mode 100644 index 00000000..14213309 --- /dev/null +++ b/Assets/Plugins/PrimeTween.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da2e19a1c5f8b4e2ca7c1785ea338b2e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset b/Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset new file mode 100644 index 00000000..e3d412e0 --- /dev/null +++ b/Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 118450fad714b420684eb5f984268b5c, type: 3} + m_Name: PrimeTweenInstaller + m_EditorClassIdentifier: + demoScene: {fileID: 102900000, guid: 13170347bc506405f88d3a87bd0982b3, type: 3} + demoSceneUrp: {fileID: 102900000, guid: 15054139658a5445689224c71f805b10, type: 3} + demoScenePro: {fileID: 102900000, guid: e8086c8f95dba534ca9bf16d3ce9ef31, type: 3} + demoSceneProUrp: {fileID: 102900000, guid: 2992e8ebf85ed47489b777c4d27b9952, type: 3} + uninstallButtonColor: {r: 1, g: 0.23113209, b: 0.2762581, a: 1} diff --git a/Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset.meta b/Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset.meta new file mode 100644 index 00000000..89e85985 --- /dev/null +++ b/Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset.meta @@ -0,0 +1,15 @@ +fileFormatVersion: 2 +guid: aafeeef745bb4406db1b2cd166853022 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 252960 + packageName: "PrimeTween \xB7 High-Performance Animations and Sequences" + packageVersion: 1.4.0 + assetPath: Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset + uploadId: 900888 diff --git a/Assets/Plugins/PrimeTween/internal.meta b/Assets/Plugins/PrimeTween/internal.meta new file mode 100644 index 00000000..bd0e4c4c --- /dev/null +++ b/Assets/Plugins/PrimeTween/internal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f164d11d6323e46b786f187ecd84eb1b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/PrimeTween/internal/PrimeTween.Installer.asmdef b/Assets/Plugins/PrimeTween/internal/PrimeTween.Installer.asmdef new file mode 100644 index 00000000..4bc81f0d --- /dev/null +++ b/Assets/Plugins/PrimeTween/internal/PrimeTween.Installer.asmdef @@ -0,0 +1,29 @@ +{ + "name": "PrimeTween.Installer", + "rootNamespace": "", + "references": [ + "PrimeTween.Runtime" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.kyrylokuzyk.primetween", + "expression": "1.0.0", + "define": "PRIME_TWEEN_INSTALLED" + }, + { + "name": "com.kyrylokuzyk.primetween", + "expression": "[1.3.6-pro]", + "define": "PRIME_TWEEN_PRO" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Plugins/PrimeTween/internal/PrimeTween.Installer.asmdef.meta b/Assets/Plugins/PrimeTween/internal/PrimeTween.Installer.asmdef.meta new file mode 100644 index 00000000..d4b69ac9 --- /dev/null +++ b/Assets/Plugins/PrimeTween/internal/PrimeTween.Installer.asmdef.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 090d70c1ebac0421985bd70fa7f561ef +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 252960 + packageName: "PrimeTween \xB7 High-Performance Animations and Sequences" + packageVersion: 1.4.0 + assetPath: Assets/Plugins/PrimeTween/internal/PrimeTween.Installer.asmdef + uploadId: 900888 diff --git a/Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs b/Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs new file mode 100644 index 00000000..5d7e8807 --- /dev/null +++ b/Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs @@ -0,0 +1,548 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEditor.PackageManager; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.Assertions; +using UnityEngine.Rendering; +using static UnityEngine.GUILayout; +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("PrimeTween.Internal")] + +namespace PrimeTween { + internal class PrimeTweenInstaller : ScriptableObject { + [SerializeField] internal SceneAsset demoScene; + [SerializeField] internal SceneAsset demoSceneUrp; + [SerializeField] internal SceneAsset demoScenePro; + [SerializeField] internal SceneAsset demoSceneProUrp; + [SerializeField] internal Color uninstallButtonColor; + + [ContextMenu(nameof(ResetReviewRequest))] void ResetReviewRequest() => ReviewRequest.ResetReviewRequest(); + [ContextMenu(nameof(DebugReviewRequest))] void DebugReviewRequest() => ReviewRequest.DebugReviewRequest(); + } + + [CustomEditor(typeof(PrimeTweenInstaller), false)] + internal class InstallerInspector : Editor { + internal const string pluginName = "PrimeTween"; + internal const string pluginPackageId = "com.kyrylokuzyk.primetween"; + internal const string tgzPath = "Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz"; + internal const string newTgzPath = "Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween-" + version + ".tgz"; + const string documentationUrl = "https://github.com/KyryloKuzyk/PrimeTween"; + bool isInstalled; + bool hasNewTgz; + GUIStyle boldButtonStyle; + GUIStyle uninstallButtonStyle; + GUIStyle wordWrapLabelStyle; + + void OnEnable() { + isInstalled = CheckPluginInstalled(); + hasNewTgz = File.Exists(newTgzPath); + } + + /// Use Package Manager because Unity 2018 doesn't support version defines + static bool CheckPluginInstalled() { + var listRequest = Client.List(true); + while (!listRequest.IsCompleted) { + } + return listRequest.Result.Any(_ => _.name == pluginPackageId); + } + + public override void OnInspectorGUI() { + if (boldButtonStyle == null) { + boldButtonStyle = new GUIStyle(GUI.skin.button) { fontStyle = FontStyle.Bold }; + } + var installer = (PrimeTweenInstaller)target; + if (uninstallButtonStyle == null) { + uninstallButtonStyle = new GUIStyle(GUI.skin.button) { normal = { textColor = installer.uninstallButtonColor } }; + } + if (wordWrapLabelStyle == null) { + wordWrapLabelStyle = new GUIStyle(GUI.skin.label) { wordWrap = true, richText = true, margin = new RectOffset(4, 4, 8, 8) }; + } + EditorGUI.indentLevel = 5; + Space(8); + Label(pluginName, EditorStyles.boldLabel); + Space(4); + if (!isInstalled) { + if (Button("Install " + pluginName)) { + installPlugin(); + } + return; + } + if (hasNewTgz) { + if (Button($"Update to {version}", boldButtonStyle)) { + ReviewRequest.OnPackageUpdate(); + } + Space(8); + } + if (Button("Documentation", boldButtonStyle)) { + Application.OpenURL(documentationUrl); + } + + Space(8); + var rpAsset = GraphicsSettings. + #if UNITY_2019_3_OR_NEWER + defaultRenderPipeline; + #else + renderPipelineAsset; + #endif + bool isUrp = rpAsset != null && rpAsset.GetType().Name.Contains("Universal"); + if (Button("Open Demo", boldButtonStyle)) { + var demoScene = isUrp ? installer.demoSceneUrp : installer.demoScene; + if (demoScene == null) { + Debug.LogError("Please re-import the plugin from Asset Store and import the 'Demo' folder.\n"); + return; + } + string path = AssetDatabase.GetAssetPath(demoScene); + EditorSceneManager.OpenScene(path); + } + #if PRIME_TWEEN_PRO + if (Button("Open Demo (Pro)", boldButtonStyle)) { + var demoScene = isUrp ? installer.demoSceneProUrp : installer.demoScenePro; + if (demoScene == null) { + Debug.LogError("Please re-import the plugin from Asset Store and import the 'Demo' folder.\n"); + return; + } + string path = AssetDatabase.GetAssetPath(demoScene); + EditorSceneManager.OpenScene(path); + } + #endif + #if UNITY_2019_4_OR_NEWER + if (Button("Import Basic Examples")) { + EditorUtility.DisplayDialog(pluginName, $"Please select the '{pluginName}' package in 'Package Manager', then press the 'Samples/Import' button at the bottom of the plugin's description.", "Ok"); + UnityEditor.PackageManager.UI.Window.Open(pluginPackageId); + } + #endif + if (Button("Support")) { + Application.OpenURL("https://github.com/KyryloKuzyk/PrimeTween#support"); + } + + Space(8); + if (Button("Uninstall", uninstallButtonStyle)) { + Client.Remove(pluginPackageId); + isInstalled = false; + var msg = $"Please remove the folder manually to uninstall {pluginName} completely: 'Assets/Plugins/{pluginName}'"; + EditorUtility.DisplayDialog(pluginName, msg, "Ok"); + Debug.Log(msg); + } + + if (EditorPrefs.GetBool(InsertCallbackBug.showInsertCallbackBugUi, false)) { + Space(24); + Label("Updating from PrimeTween [1.1.10 - 1.1.22]", EditorStyles.boldLabel); + Label("The behaviour of 'Sequence.ChainCallback()' and 'InsertCallback()' was fixed in PrimeTween 1.2.0 so the code written with older versions may work differently in some cases.", wordWrapLabelStyle); + if (Button("Find potential issues")) { + InsertCallbackBug.Find(); + } + BeginHorizontal(); + if (Button("More info")) { + Application.OpenURL(InsertCallbackBug.moreInfoUrl); + } + if (Button("Download version 1.1.22")) { + Application.OpenURL("https://github.com/KyryloKuzyk/PrimeTween/blob/545dcc52769d52841e282c772e98c8984bfeb243/Benchmarks/Packages/com.kyrylokuzyk.primetween.tgz"); + } + EndHorizontal(); + } + + Space(24); + Label("Enjoying PrimeTween?", EditorStyles.boldLabel); + Label("Consider leaving an honest review and starring PrimeTween on GitHub!\n\n" + + "Honest reviews make PrimeTween better and help other developers discover it.", wordWrapLabelStyle); + if (Button("Leave review!", GUI.skin.button)) { + ReviewRequest.DisableReviewRequest(); + ReviewRequest.OpenReviewsURL(); + } + } + + static void installPlugin() { + if (File.Exists(newTgzPath)) { + MoveAndRenameTgzArchive(); + } + + ReviewRequest.OnBeforeInstall(); + var path = $"file:../{tgzPath}"; + var addRequest = Client.Add(path); + while (!addRequest.IsCompleted) { + } + if (addRequest.Status == StatusCode.Success) { + Debug.Log($"{pluginName} installed successfully.\n" + + $"Offline documentation is located at Packages/{pluginName}/Documentation.md.\n" + + $"Online documentation: {documentationUrl}\n"); + } else { + Debug.LogError($"Please re-import the plugin from the Asset Store and check that the file exists: [{path}].\n\n{addRequest.Error?.message}\n"); + } + } + + internal static void MoveAndRenameTgzArchive() { + Assert.IsTrue(File.Exists(newTgzPath)); + Assert.IsTrue(File.Exists(newTgzPath + ".meta")); + File.Delete(tgzPath); + File.Delete(tgzPath + ".meta"); + File.Move(newTgzPath, tgzPath); + File.Move(newTgzPath + ".meta", tgzPath + ".meta"); + RevertTgzMeta(); + } + + static void RevertTgzMeta() { + const string path = tgzPath + ".meta"; + Assert.IsTrue(File.Exists(path), path); + File.WriteAllText(path, @"fileFormatVersion: 2 +guid: cdd0c4b9889044d73bc958a922ada300 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +"); + } + + [InitializeOnLoadMethod] + static void InitOnLoad() { + AssetDatabase.importPackageCompleted += name => { + if (name.Contains(pluginName)) { + if (CheckPluginInstalled()) { + ReviewRequest.OnPackageUpdate(); + } else { + var installer = AssetDatabase.LoadAssetAtPath("Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset"); + EditorUtility.FocusProjectWindow(); // this is important to show the installer object in the Project window + Selection.activeObject = installer; + EditorGUIUtility.PingObject(installer); + EditorApplication.update += InstallAndUnsubscribeFromUpdate; + void InstallAndUnsubscribeFromUpdate() { + EditorApplication.update -= InstallAndUnsubscribeFromUpdate; + installPlugin(); + } + } + } + }; + } + + internal const string version = "1.4.0"; + } + + internal static class FixedUpdateParameterMigration { + internal static string[] FindLocalScriptGuids() { + var listRequest = Client.List(true); + while (!listRequest.IsCompleted) { + } + Assert.AreEqual(StatusCode.Success, listRequest.Status); + string[] folders = listRequest.Result + .Where(x => x.source == PackageSource.Embedded || x.source == PackageSource.Local) + .Where(x => x.name != InstallerInspector.pluginPackageId) + .Select(x => x.assetPath) + .Append("Assets") + .ToArray(); + return AssetDatabase.FindAssets("t:Script", folders); + } + + internal static bool Process(string[] scripts, bool? fixAutomatically = null) { + var logSb = new StringBuilder(); + var fileSb = new StringBuilder(); + foreach (string guid in scripts) + { + string path = AssetDatabase.GUIDToAssetPath(guid); + var textAsset = AssetDatabase.LoadAssetAtPath(path); + string text = textAsset.text; + if (!Regex.IsMatch(text, @"using PrimeTween\s*;")) { + continue; + } + var parameterMatches = Regex.Matches(text, @"useFixedUpdate\s*:"); + if (parameterMatches.Count > 0) { + if (!fixAutomatically.HasValue) { + return true; + } + logSb.Clear(); + if (fixAutomatically.Value) { + fileSb.Clear(); + fileSb.Append(text); + for (int i = parameterMatches.Count - 1; i >= 0; i--) { + var paramMatch = parameterMatches[i]; + fileSb.Remove(paramMatch.Index, paramMatch.Length); + fileSb.Insert(paramMatch.Index, "updateType:"); + } + File.WriteAllText(path, fileSb.ToString()); + logSb.Append($"PrimeTween automatically renamed ({parameterMatches.Count}) occurrences of 'useFixedUpdate' to 'updateType' in file '{textAsset.name}.cs':\n"); + } else { + logSb.Append($"PrimeTween: please rename ({parameterMatches.Count}) occurrences of 'useFixedUpdate' to 'updateType' in file '{textAsset.name}.cs':\n"); + } + var lineMatches = Regex.Matches(text, @"(?m)^.*useFixedUpdate\s*:.*$", RegexOptions.Multiline); + foreach (Match match in lineMatches) { + logSb.Append($"{match.Value.Trim().Replace("useFixedUpdate", "useFixedUpdate")}\n"); + } + Debug.unityLogger.Log(fixAutomatically.Value ? LogType.Warning : LogType.Error, logSb.ToString()); + } + } + // no need to call AssetDatabase.Refresh() here because MoveAndRenameTgzArchive() already does that + return false; + } + } + + internal static class ReviewRequest { + const string version = InstallerInspector.version; + const string canAskKey = "PrimeTween.canAskForReview"; + const string versionKey = "PrimeTween.version"; + + internal static void OnPackageUpdate() { + log("OnPackageUpdate"); + if (!File.Exists(InstallerInspector.newTgzPath)) { + Debug.LogError($"The installation archive is missing: '{InstallerInspector.newTgzPath}'. Please re-import PrimeTween from Asset Store."); + return; + } + bool shouldAskForReview = true; + var scriptGuids = FixedUpdateParameterMigration.FindLocalScriptGuids(); + if (FixedUpdateParameterMigration.Process(scriptGuids)) { + shouldAskForReview = false; + const string msg = "'bool useFixedUpdate' parameter was changed to 'UpdateType updateType' in version 1.3.0, which will cause breaking changes in your current project.\n" + + "PrimeTween can fix the breaking changes automatically, or you can fix them manually after the update.\n"; + Debug.LogWarning($"PrimeTween: the {msg}"); + int response = EditorUtility.DisplayDialogComplex($"{InstallerInspector.pluginName} {version}", + $"The {msg}", + "Fix automatically", + "Cancel", + "Fix manually"); + string cancelMessage = $"PrimeTween: update to {version} was cancelled. You can trigger update manually from 'Assets/Plugins/PrimeTween/PrimeTweenInstaller'."; + if (response == 1) { + Debug.LogWarning(cancelMessage); + return; + } + if (!EditorUtility.DisplayDialog($"{InstallerInspector.pluginName} {version}", "Please back up your project before proceeding.", "OK", "Cancel")) { + Debug.LogWarning(cancelMessage); + return; + } + bool fixAutomatically = response == 0; + FixedUpdateParameterMigration.Process(scriptGuids, fixAutomatically); + } + InstallerInspector.MoveAndRenameTgzArchive(); + if (UNITY_2018) { + var removeRequest = Client.Remove(InstallerInspector.pluginPackageId); + while (!removeRequest.IsCompleted) { + } + string path = $"file:../{InstallerInspector.tgzPath}"; + Client.Add(path); + } else { + EditorApplication.ExecuteMenuItem("Assets/Refresh"); // AssetDatabase.Refresh() refreshes the project only partially + } + + string prevVersion = savedVersion; + if (savedVersion == version) { + log($"same version {version}"); + return; + } + savedVersion = version; + + if (InsertCallbackBug.IsUpdatingFromVersionWithBug(prevVersion)) { + InsertCallbackBug.Find(); + EditorPrefs.SetBool(InsertCallbackBug.showInsertCallbackBugUi, true); + shouldAskForReview = false; + } else { + EditorPrefs.SetBool(InsertCallbackBug.showInsertCallbackBugUi, false); + } + log($"updated from version {prevVersion} to {version}, {nameof(shouldAskForReview)}: {shouldAskForReview}"); + if (shouldAskForReview) { + TryAskForReview(); + } + } + + static bool UNITY_2018 { + get { + #if UNITY_2018 + return true; + #else + return false; + #endif + } + } + + static void TryAskForReview() { + if (!EditorPrefs.GetBool(canAskKey, true)) { + log("can't ask"); + return; + } + DisableReviewRequest(); + var response = EditorUtility.DisplayDialogComplex("Enjoying PrimeTween?", + "Would you mind to leave an honest review on Asset store? Honest reviews make PrimeTween better and help other developers discover it.", + "Sure, leave a review!", + "Never ask again", + ""); + if (response == 0) { + OpenReviewsURL(); + } + } + + internal static void OnBeforeInstall() { + log($"OnBeforeInstall {version}"); + if (string.IsNullOrEmpty(savedVersion)) { + savedVersion = version; + } + } + + static string savedVersion { + get => EditorPrefs.GetString(versionKey); + set => EditorPrefs.SetString(versionKey, value); + } + + internal static void DisableReviewRequest() => EditorPrefs.SetBool(canAskKey, false); + internal static void OpenReviewsURL() => Application.OpenURL("https://assetstore.unity.com/packages/slug/252960#reviews"); + + internal static void ResetReviewRequest() { + Debug.Log(nameof(ResetReviewRequest)); + EditorPrefs.DeleteKey(versionKey); + EditorPrefs.DeleteKey(canAskKey); + } + + internal static void DebugReviewRequest() { + Debug.Log(nameof(DebugReviewRequest)); + savedVersion = "1.1.22"; + EditorPrefs.SetBool(canAskKey, false); + // TryAskForReview(); + } + + [System.Diagnostics.Conditional("_")] + static void log(string msg) { + Debug.Log($"ReviewRequest: {msg}"); + } + } + + internal static class InsertCallbackBug { + internal const string moreInfoUrl = "https://github.com/KyryloKuzyk/PrimeTween/discussions/112"; + internal const string showInsertCallbackBugUi = "PrimeTween.showInsertCallbackBugUi"; + static Dictionary OpCodeDict; + static MethodInfo[] methodsWithBug; + static MethodInfo[] groupMethods; + + internal static bool IsUpdatingFromVersionWithBug(string prevVersionString) { + if (Version.TryParse(prevVersionString, out var prevVersion) + && new Version(1, 1, 10) <= prevVersion + && prevVersion <= new Version(1, 1, 22) + ) { + return true; + } + return false; + } + + internal static void Find() { + OpCodeDict = typeof(OpCodes) + .GetFields(BindingFlags.Public | BindingFlags.Static) + .Select(x => (OpCode)x.GetValue(null)) + .ToDictionary(x => x.Value, x => x); + #if PRIME_TWEEN_INSTALLED + methodsWithBug = typeof(Sequence).GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(methodInfo => methodInfo.Name == nameof(Sequence.ChainCallback) || methodInfo.Name == nameof(Sequence.InsertCallback)) + .Select(methodInfo => methodInfo.IsGenericMethod ? methodInfo.GetGenericMethodDefinition() : methodInfo) + .ToArray(); + Assert.AreEqual(4, methodsWithBug.Length); + groupMethods = typeof(Sequence).GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(methodInfo => methodInfo.Name == nameof(Sequence.Group)) + .ToArray(); + #endif + Assert.AreEqual(2, groupMethods.Length); + + string methodAssemblyName = methodsWithBug[0].Module.Assembly.FullName; + const BindingFlags findAll = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; + int numPotentialIssues = AppDomain.CurrentDomain.GetAssemblies() + .Where(assembly => assembly.GetReferencedAssemblies().Any(dependency => dependency.FullName == methodAssemblyName)) + .Where(assembly => !assembly.GetName().Name.StartsWith("PrimeTween.", StringComparison.Ordinal)) + .SelectMany(assembly => assembly.GetTypes()) + .SelectMany(type => type.GetMethods(findAll).Cast().Union(type.GetConstructors(findAll))) + .Count(method => FindInMethod(method)); + if (numPotentialIssues == 0) { + Debug.Log($"PrimeTween updated to version {InstallerInspector.version}: no potential issues found in ChainCallback() and InsertCallback() usages.\n" + + $"More info: {moreInfoUrl}\n"); + } + + int updateResponse = EditorUtility.DisplayDialogComplex($"{InstallerInspector.pluginName} {InstallerInspector.version}", + "PrimeTween 1.2.0 fixed a bug in ChainCallback() and InsertCallback() methods.\n" + + "This fix may introduce breaking changes in the existing projects. Please see the Console output for more details.", + "More info", + "Close", + ""); + if (updateResponse == 0) { + Application.OpenURL(moreInfoUrl); + } + } + + /// https://stackoverflow.com/a/33034906/1951038 + static bool FindInMethod(MethodBase method) { + byte[] il = method.GetMethodBody()?.GetILAsByteArray(); + if (il == null) { + return false; + } + bool bugFound = false; + using (var br = new BinaryReader(new MemoryStream(il))) { + while (br.BaseStream.Position < br.BaseStream.Length) { + byte firstByte = br.ReadByte(); + short opCodeValue = firstByte == 0xFE ? BitConverter.ToInt16(new[] { br.ReadByte(), firstByte }, 0) : firstByte; + OpCode opCode = OpCodeDict[opCodeValue]; + switch (opCode.OperandType) { + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineVar: + case OperandType.ShortInlineI: + br.ReadByte(); + break; + case OperandType.InlineVar: + br.ReadInt16(); + break; + case OperandType.InlineField: + case OperandType.InlineType: + case OperandType.ShortInlineR: + case OperandType.InlineString: + case OperandType.InlineSig: + case OperandType.InlineI: + case OperandType.InlineBrTarget: + br.ReadInt32(); + break; + case OperandType.InlineI8: + case OperandType.InlineR: + br.ReadInt64(); + break; + case OperandType.InlineSwitch: + var size = (int)br.ReadUInt32(); + br.ReadBytes(size * 4); + break; + case OperandType.InlineTok: + br.ReadUInt32(); + break; + case OperandType.InlineMethod: + int token = (int)br.ReadUInt32(); + if (method.Module.ResolveMethod(token) is MethodInfo resolvedMethod) { + if (bugFound) { + if (groupMethods.Contains(resolvedMethod)) { + Debug.LogError($"PrimeTween updated to version {InstallerInspector.version}: potential breaking change found in the '{method.DeclaringType}.{method.Name}()' method.\n" + + "Please double-check the behavior if Group() is called immediately after the ChainCallback() or InsertCallback() and apply the fix manually if necessary.\n" + + "Or use ChainCallbackObsolete/InsertCallbackObsolete() instead to preserve the old incorrect behavior.\n" + + $"More info: {moreInfoUrl}\n"); + return true; + } + } else { + bugFound = isMethodWithBug(resolvedMethod); + } + } + break; + case OperandType.InlineNone: + break; + default: + throw new Exception(); + } + } + } + return false; + } + + static bool isMethodWithBug(MethodInfo method) { + foreach (var methodWithBug in methodsWithBug) { + if (methodWithBug.IsGenericMethodDefinition && method.IsGenericMethod) { + if (methodWithBug == method.GetGenericMethodDefinition()) { + return true; + } + } else if (methodWithBug == method) { + return true; + } + } + return false; + } + } +} diff --git a/Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs.meta b/Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs.meta new file mode 100644 index 00000000..03b931f6 --- /dev/null +++ b/Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 118450fad714b420684eb5f984268b5c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 252960 + packageName: "PrimeTween \xB7 High-Performance Animations and Sequences" + packageVersion: 1.4.0 + assetPath: Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs + uploadId: 900888 diff --git a/Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz b/Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz new file mode 100644 index 00000000..328e8efe Binary files /dev/null and b/Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz differ diff --git a/Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz.meta b/Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz.meta new file mode 100644 index 00000000..254cb2d9 --- /dev/null +++ b/Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cdd0c4b9889044d73bc958a922ada300 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json index ed8a6b59..78eb6d58 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -1,5 +1,6 @@ { "dependencies": { + "com.kyrylokuzyk.primetween": "file:../Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz", "com.unity.2d.sprite": "1.0.0", "com.unity.ai.navigation": "2.0.10", "com.unity.collab-proxy": "2.11.3", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index d1bb64ec..ab78735c 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -1,5 +1,11 @@ { "dependencies": { + "com.kyrylokuzyk.primetween": { + "version": "file:../Assets/Plugins/PrimeTween/internal/com.kyrylokuzyk.primetween.tgz", + "depth": 0, + "source": "local-tarball", + "dependencies": {} + }, "com.unity.2d.sprite": { "version": "1.0.0", "depth": 0,