install useful assets
This commit is contained in:
17
Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset
Normal file
17
Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset
Normal file
@@ -0,0 +1,17 @@
|
||||
%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}
|
||||
uninstallButtonColor: {r: 1, g: 0.23113209, b: 0.2762581, a: 1}
|
||||
15
Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset.meta
Normal file
15
Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset.meta
Normal file
@@ -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.3.4
|
||||
assetPath: Assets/Plugins/PrimeTween/PrimeTweenInstaller.asset
|
||||
uploadId: 805664
|
||||
8
Assets/Plugins/PrimeTween/internal.meta
Normal file
8
Assets/Plugins/PrimeTween/internal.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f164d11d6323e46b786f187ecd84eb1b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -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.3.4
|
||||
assetPath: Assets/Plugins/PrimeTween/internal/PrimeTween.Installer.asmdef
|
||||
uploadId: 805664
|
||||
535
Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs
Normal file
535
Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs
Normal file
@@ -0,0 +1,535 @@
|
||||
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 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);
|
||||
if (Button("Open Demo", boldButtonStyle)) {
|
||||
var rpAsset = GraphicsSettings.
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
defaultRenderPipeline;
|
||||
#else
|
||||
renderPipelineAsset;
|
||||
#endif
|
||||
bool isUrp = rpAsset != null && rpAsset.GetType().Name.Contains("Universal");
|
||||
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;
|
||||
}
|
||||
var path = AssetDatabase.GetAssetPath(demoScene);
|
||||
EditorSceneManager.OpenScene(path);
|
||||
}
|
||||
#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 <b>honest review</b> 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<PrimeTweenInstaller>("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.3.5";
|
||||
}
|
||||
|
||||
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<TextAsset>(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", "<b>useFixedUpdate</b>")}\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<short, OpCode> 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<MethodBase>().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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.3.4
|
||||
assetPath: Assets/Plugins/PrimeTween/internal/PrimeTweenInstaller.cs
|
||||
uploadId: 805664
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cdd0c4b9889044d73bc958a922ada300
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user