Before 优化 机场

This commit is contained in:
CortexCore
2025-03-10 18:06:44 +08:00
parent 350e6d67b2
commit 1f4e20f512
178 changed files with 17534 additions and 821 deletions

View File

@@ -0,0 +1,363 @@
#if UNITY_EDITOR
using System;
using System.Linq.Expressions;
using System.Reflection;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
namespace Kamgam.UIToolkitBlurredBackground
{
/// <summary>
/// Allows you to register a callback before compilation
/// which is then executed automatically after compilation.<br />
/// <br />
/// Methods registered are usually executed in FIFO order. Though there
/// is no guarantee that this will always be the case.
/// <example>
/// CrossCompileCallbacks.RegisterCallback(testCallbackA); // It can find the type automatically.
/// CrossCompileCallbacks.RegisterCallback(typeof(YourClass), "testCallbackA");
/// </example>
/// </summary>
public static class CrossCompileCallbacks
{
/// <summary>
/// If set to true then the callbacks will not be called immediately but
/// within the next editor update cycle.<br />
/// Use this to avoid "Calling ... from assembly reloading callbacks are not supported." errors.
/// </summary>
public static bool DelayExecutionAfterCompilation
{
get => SessionState.GetBool(typeName() + ".DelayExecution", false);
set => SessionState.SetBool(typeName() + ".DelayExecution", value);
}
static string typeName() => typeof(CrossCompileCallbacks).FullName;
const string _maxIndexKey = ".MaxIndex";
static string maxIndexKey() => typeName() + _maxIndexKey;
const string _lastReleasedIndexKey = ".LastReleasedIndex";
static string lastReleasedIndexKey() => typeName() + _lastReleasedIndexKey;
const string _indexTypeKey = ".Index[{0}].Type";
static string indexTypeKey(int index) => string.Format(typeName() + _indexTypeKey, index);
const string _indexMethodKey = ".Index[{0}].Method";
static string indexMethodKey(int index) => string.Format(typeName() + _indexMethodKey, index);
static int getMaxIndex()
{
return SessionState.GetInt(maxIndexKey(), -1);
}
static int getNextIndex()
{
int maxIndex;
// Try to reuse an old index (update max index if necessary)
int reusableIndex = SessionState.GetInt(lastReleasedIndexKey(), -1);
if (reusableIndex >= 0)
{
SessionState.SetInt(lastReleasedIndexKey(), -1);
maxIndex = getMaxIndex();
if(maxIndex < reusableIndex)
SessionState.SetInt(maxIndexKey(), reusableIndex);
return reusableIndex;
}
// New index needed (increase max index).
maxIndex = SessionState.GetInt(maxIndexKey(), -1);
maxIndex++;
SessionState.SetInt(maxIndexKey(), maxIndex);
return maxIndex;
}
public static void ReleaseIndex(int index)
{
if (index < 0)
return;
SessionState.SetInt(lastReleasedIndexKey(), index);
SessionState.EraseString(indexTypeKey(index));
SessionState.EraseString(indexMethodKey(index));
// Decrease or erase max index if needed.
int maxIndex = getMaxIndex();
if(index == maxIndex)
{
maxIndex--;
if(maxIndex < 0)
SessionState.EraseInt(maxIndexKey());
else
SessionState.SetInt(maxIndexKey(), maxIndex);
}
}
public static void ReleaseAllOnType(Type type)
{
if (type == null)
return;
int maxIndex = getMaxIndex();
for (int i = maxIndex; i >= 0; i--)
{
string typeName;
GetCallbackInfo(i, out typeName, out _);
if(typeName == type.FullName)
{
ReleaseIndex(i);
}
}
}
/// <summary>
/// Registers a callback and returns an index >= 0 on success and -1 on failure.
/// </summary>
/// <param name="callback">A static method without any parameters.</param>
/// <returns></returns>
public static int RegisterCallback(System.Action callback)
{
if (callback == null)
return -1;
var methodInfo = callback.GetMethodInfo();
if (methodInfo == null)
return -1;
if (!methodInfo.IsStatic)
{
Debug.Log("Method needs to be static.");
return -1;
}
return RegisterCallback(methodInfo.DeclaringType, methodInfo.Name);
}
/// <summary>
/// Registers a callback and returns an index >= 0 on success and -1 on failure.
/// </summary>
/// <param name="type"></param>
/// <param name="staticMethodName">A static method without any parameters.</param>
/// <returns></returns>
public static int RegisterCallback(Type type, string staticMethodName)
{
if (type == null || string.IsNullOrEmpty(staticMethodName))
{
Debug.Assert(type != null);
Debug.Assert(staticMethodName != null);
return -1;
}
// Check if methods has any parameters (that's not supported)
try
{
var flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
var methodInfo = type.GetMethod(staticMethodName, flags);
if (methodInfo == null)
{
Debug.LogError("No static method '" + staticMethodName + "' found in '" + type.FullName + "'.");
return -1;
}
if (methodInfo.GetParameters().Length > 0)
{
Debug.Assert(methodInfo.GetParameters().Length == 0);
return -1;
}
}
catch (System.Exception e)
{
Debug.LogError($"CrossCompileCallbacks: Error while checking '{staticMethodName}' method parameters. Error:\n" + e.Message);
}
int index = getNextIndex();
SessionState.SetString(indexTypeKey(index), type.FullName);
SessionState.SetString(indexMethodKey(index), staticMethodName);
return index;
}
public static void GetCallbackInfo(int index, out string typeName, out string methodName)
{
typeName = SessionState.GetString(indexTypeKey(index), null);
methodName = SessionState.GetString(indexMethodKey(index), null);
}
[DidReloadScripts(-1)]
static void onAfterCompilation()
{
if (DelayExecutionAfterCompilation)
{
EditorApplication.delayCall -= delayedExecuteRegisteredCallbacks;
EditorApplication.delayCall += delayedExecuteRegisteredCallbacks;
}
else
{
executeRegisteredCallbacks();
}
}
static void delayedExecuteRegisteredCallbacks()
{
EditorApplication.delayCall -= delayedExecuteRegisteredCallbacks;
executeRegisteredCallbacks();
}
static void executeRegisteredCallbacks()
{
int maxIndex = getMaxIndex();
for (int i = maxIndex; i >= 0; i--)
{
string typeName;
string methodName;
GetCallbackInfo(i, out typeName, out methodName);
try
{
ReleaseIndex(i);
if (string.IsNullOrEmpty(typeName) || string.IsNullOrEmpty(methodName))
continue;
var methodInfo = findStaticMethod(typeName, methodName);
methodInfo.Invoke(null, null);
}
catch (System.Exception e)
{
string errorMsg = e.Message;
if(errorMsg.Contains("invocation") && e.InnerException != null)
{
errorMsg += "\n" + e.InnerException.Message;
}
Debug.LogError($"CrossCompileCallbacks: Calling '{typeName}.{methodName}' failed. Error:\n" + errorMsg);
}
}
}
static MethodInfo findStaticMethod(string fullTypeName, string methodName)
{
var type = findType(fullTypeName);
if (type == null)
return null;
var flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
var methodInfo = type.GetMethod(methodName, flags);
return methodInfo;
}
static Type findType(string fullTypeName)
{
Debug.Assert(fullTypeName != null);
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
Type t = assembly.GetType(fullTypeName, throwOnError: false);
if (t != null)
return t;
}
throw new ArgumentException("Type " + fullTypeName + " doesn't exist in the current app domain.");
}
/// <summary>
/// Utility method to store a static parameterless Action
/// in the SessionState for retrieval at a later time.
/// </summary>
/// <param name="sessionStorageKey"></param>
/// <param name="action"></param>
/// <returns></returns>
public static bool StoreAction(string sessionStorageKey, System.Action action)
{
if (action == null)
return false;
var methodInfo = action.GetMethodInfo();
if (methodInfo == null)
return false;
if (!methodInfo.IsStatic)
{
Debug.Log("Method '"+ methodInfo.Name + "'needs to be static.");
return false;
}
SessionState.SetString(sessionStorageKey + ".Type", methodInfo.DeclaringType.FullName);
SessionState.SetString(sessionStorageKey + ".Method", methodInfo.Name);
return true;
}
/// <summary>
/// Retrieves the Action from the SessionState.
/// </summary>
/// <param name="sessionStorageKey"></param>
/// <returns></returns>
public static System.Action GetStoredAction(string sessionStorageKey)
{
var typeName = SessionState.GetString(sessionStorageKey + ".Type", null);
var methodName = SessionState.GetString(sessionStorageKey + ".Method", null);
if (string.IsNullOrEmpty(typeName) || string.IsNullOrEmpty(methodName))
{
return null;
}
var type = findType(typeName);
if (type == null)
return null;
var methodInfo = findStaticMethod(typeName, methodName);
if (methodInfo == null)
return null;
return (Action) Delegate.CreateDelegate(typeof(Action), methodInfo);
}
public static void ClearStoredAction(string sessionStorageKey)
{
SessionState.EraseString(sessionStorageKey + ".Type");
SessionState.EraseString(sessionStorageKey + ".Method");
}
// Testing
/*
[DidReloadScripts]
static void StartTest()
{
Debug.Log("CrossCompileCallbacks: Starting test.");
RegisterCallback(testCallbackA);
RegisterCallback(typeof(CrossCompileCallbacks), "testCallbackB");
var action = GetStoredAction("storedActionA");
ClearStoredAction("storedActionA");
if (action != null)
action.Invoke();
StoreAction("storedActionA", storedActionA);
}
static void testCallbackA()
{
Debug.Log("Test callback A executed.");
}
static void testCallbackB()
{
Debug.Log("Test callback B executed.");
}
static void storedActionA()
{
Debug.Log("Stored action A executed.");
}
//*/
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aa14d306c727c71409d46d6aa8335138
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,235 @@
using System;
using System.IO;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.SceneManagement;
#endif
namespace Kamgam.UIToolkitBlurredBackground
{
public class Installer
#if UNITY_EDITOR
: IActiveBuildTargetChanged
#endif
{
public const string AssetName = "UI Toolkit Blurred Background";
public const string Version = "1.2.3";
public const string Define = "KAMGAM_UI_TOOLKIT_BLURRED_BACKGROUND";
public const string ManualUrl = "https://kamgam.com/unity/UIToolkitBlurredBackgroundManual.pdf";
public const string AssetLink = "https://assetstore.unity.com/packages/slug/254328";
public static string _assetRootPathDefault = "Assets/Kamgam/UIToolkitBlurredBackground/";
public static string AssetRootPath
{
get
{
#if UNITY_EDITOR
if (System.IO.File.Exists(_assetRootPathDefault))
{
return _assetRootPathDefault;
}
// The the tool was moved then search for the installer script and derive the root
// path from there. Used Assets/ as ultimate fallback.
string finalPath = "Assets/";
string assetRootPathRelative = _assetRootPathDefault.Replace("Assets/", "");
var installerGUIDS = AssetDatabase.FindAssets("t:Script Installer");
foreach (var guid in installerGUIDS)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
if (path.Contains(assetRootPathRelative))
{
int index = path.IndexOf(assetRootPathRelative);
return path.Substring(0, index) + assetRootPathRelative;
}
}
return finalPath;
#else
return _assetRootPathDefault;
#endif
}
}
public static string ExamplePath = AssetRootPath + "Examples/UIToolkitBlurredBackgroundDemo.unity";
public static Version GetVersion() => new Version(Version);
#if UNITY_EDITOR
[UnityEditor.Callbacks.DidReloadScripts(998001)]
public static void InstallIfNeeded()
{
bool versionChanged = VersionHelper.UpgradeVersion(GetVersion, out Version oldVersion, out Version newVersion);
if (versionChanged)
{
if (versionChanged)
{
Debug.Log(AssetName + " version changed from " + oldVersion + " to " + newVersion);
if (AddDefineSymbol())
{
CrossCompileCallbacks.RegisterCallback(onPostImport);
}
else
{
onPostImport();
}
}
}
}
public int callbackOrder => 0;
public void OnActiveBuildTargetChanged(BuildTarget previousTarget, BuildTarget newTarget)
{
Logger.LogMessage($"Build target changed from {previousTarget} to {newTarget}. Refreshing define symbols.");
AddDefineSymbol();
}
[MenuItem("Tools/" + AssetName + "/Debug/Add Defines", priority = 501)]
private static void AddDefineSymbolMenu()
{
AddDefineSymbol();
}
private static bool AddDefineSymbol()
{
bool didChange = false;
foreach (BuildTargetGroup targetGroup in System.Enum.GetValues(typeof(BuildTargetGroup)))
{
#pragma warning disable CS0618 // Type or member is obsolete
if (targetGroup == BuildTargetGroup.Unknown || targetGroup == BuildTargetGroup.GameCoreScarlett)
continue;
#pragma warning restore CS0618 // Type or member is obsolete
try
{
#if UNITY_2023_1_OR_NEWER
string currentDefineSymbols = PlayerSettings.GetScriptingDefineSymbols(NamedBuildTarget.FromBuildTargetGroup(targetGroup));
#else
string currentDefineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup);
#endif
if (currentDefineSymbols.Contains(Define))
continue;
#if UNITY_2023_1_OR_NEWER
PlayerSettings.SetScriptingDefineSymbols(NamedBuildTarget.FromBuildTargetGroup(targetGroup), currentDefineSymbols + ";" + Define);
#else
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, currentDefineSymbols + ";" + Define);
#endif
// Logger.LogMessage($"{Define} symbol has been added for {targetGroup}.");
didChange = true;
}
catch (Exception)
{
// There are many obsolete defines in the enum, skip them silently.
}
}
return didChange;
}
[MenuItem("Tools/" + AssetName + "/Debug/Remove Defines", priority = 502)]
private static void RemoveDefineSymbol()
{
foreach (BuildTargetGroup targetGroup in System.Enum.GetValues(typeof(BuildTargetGroup)))
{
#pragma warning disable CS0618 // Type or member is obsolete
if (targetGroup == BuildTargetGroup.Unknown || targetGroup == BuildTargetGroup.GameCoreScarlett)
continue;
#pragma warning restore CS0618 // Type or member is obsolete
try
{
#if UNITY_2023_1_OR_NEWER
string currentDefineSymbols = PlayerSettings.GetScriptingDefineSymbols(NamedBuildTarget.FromBuildTargetGroup(targetGroup));
#else
string currentDefineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup);
#endif
if (currentDefineSymbols.Contains(Define))
{
currentDefineSymbols = currentDefineSymbols.Replace(";" + Define, "");
#if UNITY_2023_1_OR_NEWER
PlayerSettings.SetScriptingDefineSymbols(NamedBuildTarget.FromBuildTargetGroup(targetGroup), currentDefineSymbols);
#else
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, currentDefineSymbols);
#endif
Logger.LogMessage($"{Define} symbol has been removed for {targetGroup}.");
}
}
catch (Exception)
{
// There are many obsolete defines in the enum, skip them silently.
}
}
}
static void onPostImport()
{
// Import packages and then show welcome screen.
PackageImporter.ImportDelayed(showWelcomeMessage);
}
static void showWelcomeMessage()
{
bool openExample = EditorUtility.DisplayDialog(
AssetName,
"Thank you for choosing " + AssetName + ".\n\n" +
"Please start by reading the manual.\n\n" +
"You'll find the asset options under Tools > UGUI Blurred Background > ...\n\n" +
"It would be great if you could find the time to leave a review.\n\n" +
"I have prepared some examples for you.",
"Open Example", "Open manual (web)"
);
if (openExample)
OpenExample();
else
OpenManual();
UIToolkitBlurredBackgroundSettings.GetOrCreateSettings().AddShaderBeforeBuild = true;
}
[MenuItem("Tools/" + AssetName + "/Manual", priority = 101)]
public static void OpenManual()
{
Application.OpenURL(ManualUrl);
}
[MenuItem("Tools/" + AssetName + "/Open Example Scene", priority = 103)]
public static void OpenExample()
{
EditorApplication.delayCall += () =>
{
var scene = AssetDatabase.LoadAssetAtPath<SceneAsset>(ExamplePath);
EditorGUIUtility.PingObject(scene);
EditorSceneManager.OpenScene(ExamplePath);
};
}
[MenuItem("Tools/" + AssetName + "/Please leave a review :-)", priority = 510)]
public static void LeaveReview()
{
Application.OpenURL(AssetLink + "?aid=1100lqC54&pubref=asset");
}
[MenuItem("Tools/" + AssetName + "/More Asset by KAMGAM", priority = 511)]
public static void MoreAssets()
{
Application.OpenURL("https://assetstore.unity.com/publishers/37829?aid=1100lqC54&pubref=asset");
}
[MenuItem("Tools/" + AssetName + "/Version " + Version, priority = 512)]
public static void LogVersion()
{
Debug.Log(AssetName + " v" + Version);
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a0c8e1d2030d4f249a58791bb732838b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
using UnityEngine;
namespace Kamgam.UIToolkitBlurredBackground
{
public class Logger
{
public delegate void LogCallback(string msg, LogLevel logLevel);
public const string Prefix = "UITK Blurred BG: ";
public static LogLevel CurrentLogLevel = LogLevel.Warning;
/// <summary>
/// Optional: leave as is or set to NULL to not use it.<br />
/// Set this to a function which returns the log level (from settings for example).<br />
/// This will be called before every log.
/// <example>
/// [RuntimeInitializeOnLoadMethod]
/// private static void HookUpToLogger()
/// {
/// Logger.OnGetLogLevel = () => GetOrCreateSettings().LogLevel;
/// }
/// </example>
/// </summary>
public static System.Func<LogLevel> OnGetLogLevel = null;
public enum LogLevel
{
Log = 0,
Warning = 1,
Error = 2,
Message = 3,
NoLogs = 99
}
public static bool IsLogLevelVisible(LogLevel logLevel)
{
return (int)logLevel >= (int)CurrentLogLevel;
}
public static void UpdateCurrentLogLevel()
{
if (OnGetLogLevel != null)
{
CurrentLogLevel = OnGetLogLevel();
}
}
const string changeHint = "\nYou can change the verbosity of logs in the Settings under Tools > UI Toolkit Blurred Background > Settings : LogLevel";
public static void Log(string message)
{
UpdateCurrentLogLevel();
if(IsLogLevelVisible(LogLevel.Log))
Debug.Log(Prefix + message + changeHint);
}
public static void LogWarning(string message)
{
UpdateCurrentLogLevel();
if (IsLogLevelVisible(LogLevel.Warning))
Debug.LogWarning(Prefix + message + changeHint);
}
public static void LogError(string message)
{
UpdateCurrentLogLevel();
if (IsLogLevelVisible(LogLevel.Error))
Debug.LogError(Prefix + message + changeHint);
}
public static void LogMessage(string message)
{
UpdateCurrentLogLevel();
if (IsLogLevelVisible(LogLevel.Message))
Debug.Log(Prefix + message + changeHint);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7e0bd73b28c8cc543bdc4b01080f358a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,268 @@
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace Kamgam.UIToolkitBlurredBackground
{
public static class PackageImporter
{
public enum RenderPiplelineType
{
URP = 0, HDRP = 1, BuiltIn = 2
}
public enum PackageType
{
// match them 1:1 to RenderPiplelineType
URP = 0, HDRP = 1, BuiltIn = 2
}
private class Package
{
public PackageType PackageType;
public string PackagePath;
public Package(PackageType packageType, string packagePath)
{
PackageType = packageType;
PackagePath = packagePath;
}
}
static List<Package> Packages = new List<Package>()
{
new Package( PackageType.URP, "Assets/Kamgam/UIToolkitBlurredBackground/Packages/UITKBlurredBackgroundURP.unitypackage" ),
new Package( PackageType.HDRP, "Assets/Kamgam/UIToolkitBlurredBackground/Packages/UITKBlurredBackgroundHDRP.unitypackage" )
};
static Package getPackageFor(RenderPiplelineType renderPipeline)
{
foreach (var pkg in Packages)
{
if ((int)pkg.PackageType == (int)renderPipeline)
return pkg;
}
return null;
}
static Package getPackageFor(PackageType packageType)
{
foreach (var pkg in Packages)
{
if (pkg.PackageType == packageType)
return pkg;
}
return null;
}
static System.Action _onComplete;
#region Start Import Delayed
static double startPackageImportAt;
public static void ImportDelayed(System.Action onComplete)
{
// Some assets may not be loaded at this time. Thus we wait for them to be imported.
_onComplete = onComplete;
EditorApplication.update -= onEditorUpdate;
EditorApplication.update += onEditorUpdate;
startPackageImportAt = EditorApplication.timeSinceStartup + 3; // wait N seconds
}
static void onEditorUpdate()
{
// wait for the time to reach startPackageImportAt
if (startPackageImportAt - EditorApplication.timeSinceStartup < 0)
{
EditorApplication.update -= onEditorUpdate;
ImportFixes();
return;
}
}
#endregion
static int _crossCompileCallbackID = -1;
const string PackagesToImportKey = "Kamgam.SettingsGenerator.PackagesToImport";
[MenuItem("Tools/UI Toolkit Blurred Background/Debug/Import packages", priority = 500)]
public static void ImportFixes()
{
// Don't import during play mode.
if (EditorApplication.isPlaying)
return;
Debug.Log("PackageImporter: Importing..");
var packagesToImport = initializePackagesToImport();
startImportingNextPackage(packagesToImport);
}
static List<PackageType> initializePackagesToImport()
{
var packages = new List<PackageType>();
// render pipeline packages
var createdForRenderPipleline = RenderPiplelineType.BuiltIn;
var currentRenderPipline = GetCurrentRenderPiplelineType();
var package = getPackageFor(currentRenderPipline);
if (package == null)
{
Debug.Log("PackageImporter: Render Pipline seems okay, no import needed.");
}
else
{
Debug.Log("PackageImporter: Scheduling upgrade from '" + createdForRenderPipleline.ToString() + "' to '" + currentRenderPipline.ToString() + "'.");
packages.Add((PackageType)currentRenderPipline);
}
setPackagesToImportList(packages);
if (packages.Count == 0)
{
onPackageImportDone(_onComplete);
}
return packages;
}
static void startImportingNextPackage(List<PackageType> packagesToImport)
{
if (packagesToImport.Count > 0)
{
var package = getPackageFor(packagesToImport[0]);
removePackageToImportList(package.PackageType);
startImportingPackage(package);
}
}
static void startImportingPackage(Package package)
{
// AssetDatabase.importPackageCompleted callbacks are lost after a recompile.
// Therefore, if the package includes any scripts then these will not be called.
// See: https://forum.unity.com/threads/assetdatabase-importpackage-callbacks-dont-work.544031/#post-3716791
// We use CrossCompileCallbacks to register a callback for after compilation.
_crossCompileCallbackID = CrossCompileCallbacks.RegisterCallback(onPackageImportedAfterRecompile);
// We also have to store the external callback (if there is one)
CrossCompileCallbacks.StoreAction(typeof(PackageImporter).FullName + ".importedCallack", _onComplete);
// Delay to avoid "Calling ... from assembly reloading callbacks are not supported." errors.
CrossCompileCallbacks.DelayExecutionAfterCompilation = true;
// If the package does not contain any scripts the we can still use the normal callbacks.
AssetDatabase.importPackageCompleted -= onPackageImported;
AssetDatabase.importPackageCompleted += onPackageImported;
// import package
Debug.Log("PackageImporter: Importing '" + package.PackagePath + "'.");
AssetDatabase.ImportPackage(package.PackagePath, interactive: false);
AssetDatabase.SaveAssets();
}
static void setPackagesToImportList(List<PackageType> packages)
{
var packagesAsInts = packages.Select(p => (int)p).ToArray();
SessionState.SetIntArray(PackagesToImportKey, packagesAsInts);
}
static List<PackageType> getPackagesToImportList()
{
var packagesAsInts = SessionState.GetIntArray(PackagesToImportKey, new int[] { });
var packages = packagesAsInts.Select(p => (PackageType)p).ToList();
return packages;
}
static void removePackageToImportList(PackageType package)
{
var packages = getPackagesToImportList();
packages.Remove(package);
setPackagesToImportList(packages);
}
// This is only execute if the package did not contain any script files.
static void onPackageImported(string packageName)
{
Debug.Log("PackageImporter: Package '" + packageName + "' imported.");
// There was no recompile. Thus we clear the registered callback.
CrossCompileCallbacks.ReleaseIndex(_crossCompileCallbackID);
// Check if it is one of our packages.
// Abort if not.
bool isFixerPackage = false;
foreach (var pkg in Packages)
{
if (pkg.PackagePath.Contains(packageName))
isFixerPackage = true;
}
if (!isFixerPackage)
return;
AssetDatabase.importPackageCompleted -= onPackageImported;
onPackageImportDone(_onComplete);
_onComplete = null;
}
static void onPackageImportedAfterRecompile()
{
Debug.Log("PackageImporter: Recompile detected. Assuming package import is done.");
// The registered callback is already cleared by now.
// Now we let's retrieve that stored extenal callback and hand it over.
var onComplete = CrossCompileCallbacks.GetStoredAction(typeof(PackageImporter).FullName + ".importedCallack");
onPackageImportDone(onComplete);
}
static void onPackageImportDone(System.Action onComplete)
{
// Check for more packages to import
Debug.Log("PackageImporter: package imported. Looking for next package.");
var packagesToImport = getPackagesToImportList();
if (packagesToImport.Count > 0)
{
// Make sure the onComplete callback is retained across multiple package loads.
_onComplete = onComplete;
// Start importing
startImportingNextPackage(packagesToImport);
}
else
{
AssetDatabase.SaveAssets();
onComplete?.Invoke();
Debug.Log("PackageImporter: Done (no more packages to import).");
}
}
public static RenderPiplelineType GetCurrentRenderPiplelineType()
{
var currentRP = GraphicsSettings.currentRenderPipeline;
// null if built-in
if (currentRP != null)
{
if (currentRP.GetType().Name.Contains("Universal"))
{
return RenderPiplelineType.URP;
}
else
{
return RenderPiplelineType.HDRP;
}
}
return RenderPiplelineType.BuiltIn;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f365eb8588ba4cf41bfbc9d123cf0739
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,80 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
using UnityEngine.Rendering;
namespace Kamgam.UIToolkitBlurredBackground
{
/// <summary>
/// Since we do not add any objects directly referencing the materials/shaders we
/// need to make sure the shaders are added to builds so they can be found at runtime.
/// </summary>
public static class SetupShaders
{
public class SetupShadersOnBuild : IPreprocessBuildWithReport
{
public int callbackOrder => int.MinValue + 10;
public void OnPreprocessBuild(BuildReport report)
{
if (UIToolkitBlurredBackgroundSettings.GetOrCreateSettings().AddShaderBeforeBuild)
SetupShaders.AddShaders();
}
}
[MenuItem("Tools/UI Toolkit Blurred Background/Debug/Add shaders to always included shader", priority = 401)]
public static void AddShaders()
{
#if !KAMGAM_RENDER_PIPELINE_URP && !KAMGAM_RENDER_PIPELINE_HDRP
// BuiltIn
AddShaders(BlurredBackgroundBufferBuiltIn.ShaderName);
#elif KAMGAM_RENDER_PIPELINE_URP
// URP
AddShaders(BlurredBackgroundPassURP.ShaderName);
#else
// HDRP
AddShaders(BlurredBackgroundPassHDRP.ShaderName);
#endif
}
public static void AddShaders(string shaderName)
{
// Thanks to: https://forum.unity.com/threads/modify-always-included-shaders-with-pre-processor.509479/#post-3509413
var shader = Shader.Find(shaderName);
if (shader == null)
return;
var graphicsSettingsObj = AssetDatabase.LoadAssetAtPath<GraphicsSettings>("ProjectSettings/GraphicsSettings.asset");
var serializedObject = new SerializedObject(graphicsSettingsObj);
var arrayProp = serializedObject.FindProperty("m_AlwaysIncludedShaders");
bool hasShader = false;
for (int i = 0; i < arrayProp.arraySize; ++i)
{
var arrayElem = arrayProp.GetArrayElementAtIndex(i);
if (shader == arrayElem.objectReferenceValue)
{
hasShader = true;
break;
}
}
if (!hasShader)
{
int arrayIndex = arrayProp.arraySize;
arrayProp.InsertArrayElementAtIndex(arrayIndex);
var arrayElem = arrayProp.GetArrayElementAtIndex(arrayIndex);
arrayElem.objectReferenceValue = shader;
serializedObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
Debug.Log("Added the '"+ shaderName + "' shader to always included shaders (see Project Settings > Graphics). UI Toolkit Blurred Background requires it to render the blur. Hope that's okay.");
}
}
}
}
#endif

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: bd28bf476ff557e4ba94bcad28feaf45
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 254328
packageName: UI Toolkit Blurred Background - Fast translucent background image
packageVersion: 1.0.4
assetPath: Assets/Kamgam/UIToolkitBlurredBackground/Runtime/Editor/Settings/SetupShaders.cs
uploadId: 644498

View File

@@ -0,0 +1,206 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;
namespace Kamgam.UIToolkitBlurredBackground
{
// Create a new type of Settings Asset.
public class UIToolkitBlurredBackgroundSettings : ScriptableObject
{
public enum ShaderVariant { Performance, Gaussian };
public const string Version = "1.2.0";
public const string SettingsFilePath = "Assets/UIToolkitBlurredBackgroundSettings.asset";
[SerializeField, Tooltip(_logLevelTooltip)]
public Logger.LogLevel LogLevel;
public const string _logLevelTooltip = "Any log above this log level will not be shown. To turn off all logs choose 'NoLogs'";
public const string _addShaderBeforeBuildTooltip = "Should the blur shader be added to the list of always included shaders before a build is started?\n\n" +
"Disable only if you do not use any blurred images in your project but you still want to keep the asset around.";
[Tooltip(_addShaderBeforeBuildTooltip)]
public bool AddShaderBeforeBuild = true;
[RuntimeInitializeOnLoadMethod]
static void bindLoggerLevelToSetting()
{
// Notice: This does not yet create a setting instance!
Logger.OnGetLogLevel = () => GetOrCreateSettings().LogLevel;
}
static UIToolkitBlurredBackgroundSettings cachedSettings;
public static UIToolkitBlurredBackgroundSettings GetOrCreateSettings()
{
if (cachedSettings == null)
{
string typeName = typeof(UIToolkitBlurredBackgroundSettings).Name;
cachedSettings = AssetDatabase.LoadAssetAtPath<UIToolkitBlurredBackgroundSettings>(SettingsFilePath);
// Still not found? Then search for it.
if (cachedSettings == null)
{
string[] results = AssetDatabase.FindAssets("t:" + typeName);
if (results.Length > 0)
{
string path = AssetDatabase.GUIDToAssetPath(results[0]);
cachedSettings = AssetDatabase.LoadAssetAtPath<UIToolkitBlurredBackgroundSettings>(path);
}
}
if (cachedSettings != null)
{
SessionState.EraseBool(typeName + "WaitingForReload");
}
// Still not found? Then create settings.
if (cachedSettings == null)
{
// Are the settings waiting for a recompile to finish? If yes then return null;
// This is important if an external script tries to access the settings before they
// are deserialized after a re-compile.
bool isWaitingForReloadAfterCompilation = SessionState.GetBool(typeName + "WaitingForReload", false);
if (isWaitingForReloadAfterCompilation)
{
Debug.LogWarning(typeName + " is waiting for assembly reload.");
return null;
}
cachedSettings = ScriptableObject.CreateInstance<UIToolkitBlurredBackgroundSettings>();
cachedSettings.LogLevel = Logger.LogLevel.Warning;
cachedSettings.AddShaderBeforeBuild = true;
AssetDatabase.CreateAsset(cachedSettings, SettingsFilePath);
AssetDatabase.SaveAssets();
Logger.OnGetLogLevel = () => cachedSettings.LogLevel;
}
}
return cachedSettings;
}
internal static SerializedObject GetSerializedSettings()
{
return new SerializedObject(GetOrCreateSettings());
}
[MenuItem("Tools/UI Toolkit Blurred Background/Settings", priority = 101)]
public static void OpenSettings()
{
var settings = UIToolkitBlurredBackgroundSettings.GetOrCreateSettings();
if (settings != null)
{
Selection.activeObject = settings;
EditorGUIUtility.PingObject(settings);
}
else
{
EditorUtility.DisplayDialog("Error", "UI Toolkit Blurred Background Settings could not be found or created.", "Ok");
}
}
public void Save()
{
EditorUtility.SetDirty(this);
#if UNITY_2021_2_OR_NEWER
AssetDatabase.SaveAssetIfDirty(this);
#else
AssetDatabase.SaveAssets();
#endif
}
}
#if UNITY_EDITOR
[CustomEditor(typeof(UIToolkitBlurredBackgroundSettings))]
public class UIToolkitBlurredBackgroundSettingsEditor : Editor
{
public UIToolkitBlurredBackgroundSettings settings;
public void OnEnable()
{
settings = target as UIToolkitBlurredBackgroundSettings;
}
public override void OnInspectorGUI()
{
EditorGUILayout.LabelField("Version: " + UIToolkitBlurredBackgroundSettings.Version);
base.OnInspectorGUI();
}
}
#endif
static class UIToolkitBlurredBackgroundSettingsProvider
{
[SettingsProvider]
public static UnityEditor.SettingsProvider CreateUIToolkitBlurredBackgroundSettingsProvider()
{
var provider = new UnityEditor.SettingsProvider("Project/UI Toolkit Blurred Background", SettingsScope.Project)
{
label = "UI Toolkit Blurred Background",
guiHandler = (searchContext) =>
{
var settings = UIToolkitBlurredBackgroundSettings.GetSerializedSettings();
var style = new GUIStyle(GUI.skin.label);
style.wordWrap = true;
EditorGUILayout.LabelField("Version: " + UIToolkitBlurredBackgroundSettings.Version);
if (drawButton(" Open Manual ", icon: "_Help"))
{
Installer.OpenManual();
}
var settingsObj = settings.targetObject as UIToolkitBlurredBackgroundSettings;
drawField("LogLevel", "Log Level", UIToolkitBlurredBackgroundSettings._logLevelTooltip, settings, style);
drawField("AddShaderBeforeBuild", "Add Shader Before Build", UIToolkitBlurredBackgroundSettings._addShaderBeforeBuildTooltip, settings, style);
settings.ApplyModifiedProperties();
},
// Populate the search keywords to enable smart search filtering and label highlighting.
keywords = new System.Collections.Generic.HashSet<string>(new[] { "shader", "triplanar", "rendering" })
};
return provider;
}
static void drawField(string propertyName, string label, string tooltip, SerializedObject settings, GUIStyle style)
{
EditorGUILayout.PropertyField(settings.FindProperty(propertyName), new GUIContent(label));
if (!string.IsNullOrEmpty(tooltip))
{
GUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.Label(tooltip, style);
GUILayout.EndVertical();
}
GUILayout.Space(10);
}
static bool drawButton(string text, string tooltip = null, string icon = null, params GUILayoutOption[] options)
{
GUIContent content;
// icon
if (!string.IsNullOrEmpty(icon))
content = EditorGUIUtility.IconContent(icon);
else
content = new GUIContent();
// text
content.text = text;
// tooltip
if (!string.IsNullOrEmpty(tooltip))
content.tooltip = tooltip;
return GUILayout.Button(content, options);
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9535b8a7472136f4f82f99c6192cc973
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,173 @@
#if UNITY_EDITOR
using System;
using System.IO;
using UnityEngine;
namespace Kamgam.UIToolkitBlurredBackground
{
public static class VersionHelper
{
public static string VersionFileName = "." + typeof(VersionHelper).FullName + ".txt";
public static Version DefaultVersion = new Version(0, 0, 0, 1);
public delegate bool UpgradeVersionDelegate(Version oldVersion, Version newVersion);
public static Version Parse(string version)
{
if (string.IsNullOrEmpty(version))
return DefaultVersion;
if (Version.TryParse(version, out var versionObj))
return versionObj;
else
return VersionHelper.DefaultVersion;
}
/// <summary>
/// Returns false if upgrading was not necessary, True otherwise.
/// </summary>
/// <param name="getVersionFunc">Change this to return the version of the software.<br />
/// This is a separate method because your version may be stored in another class or a file.<br />
/// The return value if this is compared against the install version marker.</param>
/// <param name="upgradeVersionFunc">Use this to execute some custom code before upgrading
/// the installed version info. If this returns false then the installed version will NOT be changed.</param>
/// <returns></returns>
public static bool UpgradeVersion(Func<Version> getVersionFunc, UpgradeVersionDelegate upgradeVersionFunc = null)
{
return UpgradeVersion(getVersionFunc, out _, out _, upgradeVersionFunc);
}
/// <summary>
/// Returns false if upgrading was not necessary, True otherwise.<br />
/// Upgrades the version number only if the version info file path is valid. Otherwise it will abort.
/// </summary>
/// <param name="getVersionFunc">Change this to return the version of the software.<br />
/// This is a separate method because your version may be stored in another class or a file.<br />
/// The return value if this is compared against the install version marker.</param>
/// <param name="oldVersion"></param>
/// <param name="newVersion"></param>
/// <param name="upgradeVersionFunc">Use this to execute some custom code before upgrading
/// the installed version info. If this returns false then the installed version will NOT be changed.</param>
/// <returns>Returns false if upgrading was not necessary (or impossible). Returns true if an upgrade is needed (and possible).</returns>
public static bool UpgradeVersion(Func<Version> getVersionFunc, out Version oldVersion, out Version newVersion, UpgradeVersionDelegate upgradeVersionFunc = null)
{
oldVersion = GetInstalledVersion();
newVersion = getVersionFunc();
// Abort upgrades if version info can not be retrieved.
if (!VersionInfoPathIsValid())
{
// We abort if the dir is not found because we assume the
// user has moved the asset and thus any upgrade attempts
// will probably fail anyways.
Logger.LogWarning(
"Could not find version info directory: '" + getVersionFileDir() + "'. Aborting upgrade. Did you move the asset?\n" +
"If you want auto-upgrades to work again then please restore the asset to the original directory (" + Installer.AssetRootPath + ").");
return false;
}
// Notice: this also cover downgrades.
if (oldVersion != newVersion)
{
if (upgradeVersionFunc != null)
{
bool upgradeSucceeded = upgradeVersionFunc(oldVersion, newVersion);
if (upgradeSucceeded)
SetInstalledVersion(newVersion);
return upgradeSucceeded;
}
else
{
SetInstalledVersion(newVersion);
}
return true;
}
return false;
}
public static bool VersionInfoPathIsValid()
{
return System.IO.Directory.Exists(getVersionFileDir());
}
public static void SetInstalledVersion(Version version)
{
if (version == null)
return;
if (!VersionInfoPathIsValid())
return;
string versionString = version.ToString();
string filePath = getVersionFilePath();
string tmpPath = filePath + ".tmp";
if (File.Exists(tmpPath))
{
File.Delete(tmpPath);
}
File.WriteAllText(tmpPath, versionString);
if (File.Exists(filePath))
{
File.Delete(filePath);
}
File.Move(tmpPath, filePath);
}
public static Version GetInstalledVersion()
{
string filePath = getVersionFilePath();
if (!File.Exists(filePath))
{
return DefaultVersion;
}
string version = File.ReadAllText(filePath);
return Parse(version);
}
static string getVersionFilePath()
{
string dir = getVersionFileDir();
return dir + VersionFileName;
}
static string getVersionFileDir()
{
string dir = Installer.AssetRootPath.Trim();
// fix empty dir path
if (string.IsNullOrEmpty(dir))
{
dir = "Assets/";
}
// Fix missing ending slash
if (!dir.EndsWith("/") && !dir.EndsWith("\\"))
{
dir = dir + "/";
}
return getBasePath() + dir;
}
/// <summary>
/// Returns the path to project root (the parent dir of Assets).
/// </summary>
/// <returns></returns>
static string getBasePath()
{
// Unity Editor: <path to project folder>/Assets
// See: https://docs.unity3d.com/ScriptReference/Application-dataPath.html
string basePath = Application.dataPath.Replace("/Assets", "/");
basePath = basePath.Replace("\\Assets", "\\");
return basePath;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f7fae563c3916c40a7026d274ee36e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: