From 2a66393cb07c471d2eaba0902cfd9fa481b98446 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Thu, 21 Nov 2024 01:36:51 +0900
Subject: [PATCH 01/23] refactor: update coffee.internal

---
 .../Extensions/ComponentExtensions.cs         | 29 +++++++++++++++++++
 .../{Extensions => Utilities}/Misc.cs         |  9 ++++++
 .../{Extensions => Utilities}/Misc.cs.meta    |  2 +-
 .../Internal/Utilities/UIExtraCallbacks.cs    | 22 ++++++++++++++
 Runtime/UIParticle.cs                         |  2 ++
 Samples~/Demo/Scripts/UIParticle_Demo.cs      | 25 ++++------------
 6 files changed, 68 insertions(+), 21 deletions(-)
 rename Runtime/Internal/{Extensions => Utilities}/Misc.cs (78%)
 rename Runtime/Internal/{Extensions => Utilities}/Misc.cs.meta (83%)

diff --git a/Runtime/Internal/Extensions/ComponentExtensions.cs b/Runtime/Internal/Extensions/ComponentExtensions.cs
index b45f0162..d65be225 100644
--- a/Runtime/Internal/Extensions/ComponentExtensions.cs
+++ b/Runtime/Internal/Extensions/ComponentExtensions.cs
@@ -134,6 +134,35 @@ public static void AddComponentOnChildren<T>(this Component self, HideFlags hide
             Profiler.EndSample();
         }
 
+        /// <summary>
+        /// Add a component of a specific type to the children of a GameObject.
+        /// </summary>
+        public static void AddComponentOnChildren<T>(this Component self, bool includeSelf)
+            where T : Component
+        {
+            if (self == null) return;
+
+            Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
+            if (includeSelf && !self.TryGetComponent<T>(out _))
+            {
+                self.gameObject.AddComponent<T>();
+            }
+
+            Profiler.EndSample();
+
+            Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Child");
+            var childCount = self.transform.childCount;
+            for (var i = 0; i < childCount; i++)
+            {
+                var child = self.transform.GetChild(i);
+                if (child.TryGetComponent<T>(out _)) continue;
+
+                child.gameObject.AddComponent<T>();
+            }
+
+            Profiler.EndSample();
+        }
+
 #if !UNITY_2021_2_OR_NEWER && !UNITY_2020_3_45 && !UNITY_2020_3_46 && !UNITY_2020_3_47 && !UNITY_2020_3_48
         public static T GetComponentInParent<T>(this Component self, bool includeInactive) where T : Component
         {
diff --git a/Runtime/Internal/Extensions/Misc.cs b/Runtime/Internal/Utilities/Misc.cs
similarity index 78%
rename from Runtime/Internal/Extensions/Misc.cs
rename to Runtime/Internal/Utilities/Misc.cs
index 66d0b4e8..fb1a2108 100644
--- a/Runtime/Internal/Extensions/Misc.cs
+++ b/Runtime/Internal/Utilities/Misc.cs
@@ -6,6 +6,15 @@ namespace Coffee.UIParticleInternal
 {
     internal static class Misc
     {
+        public static T[] FindObjectsOfType<T>() where T : Object
+        {
+#if UNITY_2023_1_OR_NEWER
+            return Object.FindObjectsByType<T>(FindObjectsInactive.Include, FindObjectsSortMode.None);
+#else
+            return Object.FindObjectsOfType<T>();
+#endif
+        }
+
         public static void Destroy(Object obj)
         {
             if (!obj) return;
diff --git a/Runtime/Internal/Extensions/Misc.cs.meta b/Runtime/Internal/Utilities/Misc.cs.meta
similarity index 83%
rename from Runtime/Internal/Extensions/Misc.cs.meta
rename to Runtime/Internal/Utilities/Misc.cs.meta
index 56683926..e9f550c8 100644
--- a/Runtime/Internal/Extensions/Misc.cs.meta
+++ b/Runtime/Internal/Utilities/Misc.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 39ed6a6b0a72e482488bd298b2ae762e
+guid: 182319ecc315e4858b119764af0fbcb0
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Runtime/Internal/Utilities/UIExtraCallbacks.cs b/Runtime/Internal/Utilities/UIExtraCallbacks.cs
index be9e7ee4..6ad33ed9 100755
--- a/Runtime/Internal/Utilities/UIExtraCallbacks.cs
+++ b/Runtime/Internal/Utilities/UIExtraCallbacks.cs
@@ -14,6 +14,8 @@ internal static class UIExtraCallbacks
         private static readonly FastAction s_AfterCanvasRebuildAction = new FastAction();
         private static readonly FastAction s_LateAfterCanvasRebuildAction = new FastAction();
         private static readonly FastAction s_BeforeCanvasRebuildAction = new FastAction();
+        private static readonly FastAction s_OnScreenSizeChangedAction = new FastAction();
+        private static Vector2Int s_LastScreenSize;
 
         static UIExtraCallbacks()
         {
@@ -48,6 +50,15 @@ public static event Action onAfterCanvasRebuild
             remove => s_AfterCanvasRebuildAction.Remove(value);
         }
 
+        /// <summary>
+        /// Event that occurs when the screen size changes.
+        /// </summary>
+        public static event Action onScreenSizeChanged
+        {
+            add => s_OnScreenSizeChangedAction.Add(value);
+            remove => s_OnScreenSizeChangedAction.Remove(value);
+        }
+
         /// <summary>
         /// Initializes the UIExtraCallbacks to ensure proper event handling.
         /// </summary>
@@ -77,6 +88,17 @@ private static void InitializeOnLoad()
         /// </summary>
         private static void OnBeforeCanvasRebuild()
         {
+            var screenSize = new Vector2Int(Screen.width, Screen.height);
+            if (s_LastScreenSize != screenSize)
+            {
+                if (s_LastScreenSize != default)
+                {
+                    s_OnScreenSizeChangedAction.Invoke();
+                }
+
+                s_LastScreenSize = screenSize;
+            }
+
             s_BeforeCanvasRebuildAction.Invoke();
             InitializeAfterCanvasRebuild();
         }
diff --git a/Runtime/UIParticle.cs b/Runtime/UIParticle.cs
index 40133d6b..5ad390d4 100644
--- a/Runtime/UIParticle.cs
+++ b/Runtime/UIParticle.cs
@@ -9,6 +9,8 @@
 using Random = UnityEngine.Random;
 
 [assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
+[assembly: InternalsVisibleTo("Coffee.UIParticle.PerformanceDemo")]
+[assembly: InternalsVisibleTo("Coffee.UIParticle.Demo")]
 
 namespace Coffee.UIExtensions
 {
diff --git a/Samples~/Demo/Scripts/UIParticle_Demo.cs b/Samples~/Demo/Scripts/UIParticle_Demo.cs
index 266eda3a..68e89930 100644
--- a/Samples~/Demo/Scripts/UIParticle_Demo.cs
+++ b/Samples~/Demo/Scripts/UIParticle_Demo.cs
@@ -1,3 +1,4 @@
+using Coffee.UIParticleInternal;
 using UnityEngine;
 using UnityEngine.Serialization;
 using UnityEngine.UI;
@@ -51,11 +52,7 @@ public void FullScreen()
 
         public void EnableAnimations(bool flag)
         {
-#if UNITY_2023_1_OR_NEWER
-            foreach (var animator in FindObjectsByType<Animator>(FindObjectsInactive.Include, FindObjectsSortMode.None))
-#else
-            foreach (var animator in FindObjectsOfType<Animator>())
-#endif
+            foreach (var animator in Misc.FindObjectsOfType<Animator>())
             {
                 animator.enabled = flag;
             }
@@ -83,11 +80,7 @@ public void UIParticle_RandomGroup(bool flag)
 
         public void UIParticle_Scale(float scale)
         {
-#if UNITY_2023_1_OR_NEWER
-            foreach (var uip in FindObjectsByType<UIParticle>(FindObjectsInactive.Include, FindObjectsSortMode.None))
-#else
-            foreach (var uip in FindObjectsOfType<UIParticle>())
-#endif
+            foreach (var uip in Misc.FindObjectsOfType<UIParticle>())
             {
                 uip.scale = scale;
             }
@@ -95,11 +88,7 @@ public void UIParticle_Scale(float scale)
 
         public void ParticleSystem_WorldSpaseSimulation(bool flag)
         {
-#if UNITY_2023_1_OR_NEWER
-            foreach (var p in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
-#else
-            foreach (var p in FindObjectsOfType<ParticleSystem>())
-#endif
+            foreach (var p in Misc.FindObjectsOfType<ParticleSystem>())
             {
                 var main = p.main;
                 main.simulationSpace = flag
@@ -135,11 +124,7 @@ public void ParticleSystem_Emit(ParticleSystem ps)
 
         public void ParticleSystem_SetScale(float scale)
         {
-#if UNITY_2023_1_OR_NEWER
-            foreach (var ps in FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None))
-#else
-            foreach (var ps in FindObjectsOfType<ParticleSystem>())
-#endif
+            foreach (var ps in Misc.FindObjectsOfType<ParticleSystem>())
             {
                 ps.transform.localScale = new Vector3(scale, scale, scale);
             }

From 5f479902aab3be537277f126c8d3ee3d3fd25ff9 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Thu, 21 Nov 2024 01:39:16 +0900
Subject: [PATCH 02/23] fix: if not configured as a preloaded asset, the
 project settings asset will be regenerated close #342

---
 .../PreloadedProjectSettings.cs               | 41 ++++++++++++++-----
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs b/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs
index b5689deb..21ff15a5 100644
--- a/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs
+++ b/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs
@@ -1,9 +1,9 @@
 using System;
 using System.Linq;
-using System.Reflection;
 using UnityEngine;
 using Object = UnityEngine.Object;
 #if UNITY_EDITOR
+using System.IO;
 using UnityEditor;
 using UnityEditor.Build;
 using UnityEditor.Build.Reporting;
@@ -14,6 +14,14 @@ namespace Coffee.UIParticleInternal
     public abstract class PreloadedProjectSettings : ScriptableObject
 #if UNITY_EDITOR
     {
+        private class Postprocessor : AssetPostprocessor
+        {
+            private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
+            {
+                Initialize();
+            }
+        }
+
         private class PreprocessBuildWithReport : IPreprocessBuildWithReport
         {
             int IOrderedCallback.callbackOrder => 0;
@@ -24,32 +32,32 @@ void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
             }
         }
 
-        [InitializeOnLoadMethod]
-        [InitializeOnEnterPlayMode]
         private static void Initialize()
         {
-            const BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
             foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
             {
                 var defaultSettings = GetDefaultSettings(t);
                 if (!defaultSettings)
                 {
                     // When create a new instance, automatically set it as default settings.
-                    defaultSettings = t.GetProperty("instance", flags)
-                        ?.GetValue(null, null) as PreloadedProjectSettings;
+                    defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
+                    SetDefaultSettings(defaultSettings);
                 }
                 else if (GetPreloadedSettings(t).Length != 1)
                 {
                     SetDefaultSettings(defaultSettings);
                 }
-            }
 
-            EditorApplication.QueuePlayerLoopUpdate();
+                if (defaultSettings)
+                {
+                    defaultSettings.OnInitialize();
+                }
+            }
         }
 
         protected static string GetDefaultName(Type type, bool nicify)
         {
-            var typeName = type.Name.Replace("ProjectSettings", "");
+            var typeName = type.Name;
             return nicify
                 ? ObjectNames.NicifyVariableName(typeName)
                 : typeName;
@@ -74,6 +82,7 @@ protected static PreloadedProjectSettings GetDefaultSettings(Type type)
         protected static void SetDefaultSettings(PreloadedProjectSettings asset)
         {
             if (!asset) return;
+
             var type = asset.GetType();
             if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
             {
@@ -84,7 +93,11 @@ protected static void SetDefaultSettings(PreloadedProjectSettings asset)
 
                 var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
                 assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
-                AssetDatabase.CreateAsset(asset, assetPath);
+                if (!File.Exists(assetPath))
+                {
+                    AssetDatabase.CreateAsset(asset, assetPath);
+                    asset.OnCreateAsset();
+                }
             }
 
             var preloadedAssets = PlayerSettings.GetPreloadedAssets();
@@ -98,6 +111,14 @@ protected static void SetDefaultSettings(PreloadedProjectSettings asset)
 
             AssetDatabase.Refresh();
         }
+
+        protected virtual void OnCreateAsset()
+        {
+        }
+
+        protected virtual void OnInitialize()
+        {
+        }
     }
 #else
     {

From 598c85e0f455d38d7592758cffeeef7771609b16 Mon Sep 17 00:00:00 2001
From: semantic-release-bot <semantic-release-bot@martynus.net>
Date: Wed, 20 Nov 2024 16:56:36 +0000
Subject: [PATCH 03/23] chore(release): 4.10.3 [skip ci]

## [4.10.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.2...v4.10.3) (2024-11-20)

### Bug Fixes

* if not configured as a preloaded asset, the project settings asset will be regenerated ([abe0948](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/abe09485f65dd4efd18e74675e752e0213bdf3be)), closes [#342](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/342)
---
 CHANGELOG.md | 7 +++++++
 package.json | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 06bbb983..a53d6b31 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## [4.10.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.2...v4.10.3) (2024-11-20)
+
+
+### Bug Fixes
+
+* if not configured as a preloaded asset, the project settings asset will be regenerated ([abe0948](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/abe09485f65dd4efd18e74675e752e0213bdf3be)), closes [#342](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/342)
+
 ## [4.10.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.1...v4.10.2) (2024-11-01)
 
 
diff --git a/package.json b/package.json
index 561ea4d1..7083f28d 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "com.coffee.ui-particle",
   "displayName": "UI Particle",
   "description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
-  "version": "4.10.2",
+  "version": "4.10.3",
   "unity": "2018.2",
   "license": "MIT",
   "repository": {

From ac3e147bd9d7f5590f497f5e959dea6bdc6815fc Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Wed, 18 Dec 2024 19:46:32 +0900
Subject: [PATCH 04/23] fix: rendering issues when playing with opening a
 prefab stage

close #345
---
 .../Internal/Extensions/SpriteExtensions.cs    | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/Runtime/Internal/Extensions/SpriteExtensions.cs b/Runtime/Internal/Extensions/SpriteExtensions.cs
index e0d4e65f..9e3d1c2d 100644
--- a/Runtime/Internal/Extensions/SpriteExtensions.cs
+++ b/Runtime/Internal/Extensions/SpriteExtensions.cs
@@ -17,11 +17,15 @@ internal static class SpriteExtensions
             Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
             ?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
 
-        private static readonly MethodInfo s_GetActiveAtlasTextureMethod = s_SpriteEditorExtensionType
-            .GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
+        private static readonly Func<Sprite, Texture2D> s_GetActiveAtlasTextureMethod =
+            (Func<Sprite, Texture2D>)Delegate.CreateDelegate(typeof(Func<Sprite, Texture2D>),
+                s_SpriteEditorExtensionType
+                    .GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic));
 
-        private static readonly MethodInfo s_GetActiveAtlasMethod = s_SpriteEditorExtensionType
-            .GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic);
+        private static readonly Func<Sprite, SpriteAtlas> s_GetActiveAtlasMethod =
+            (Func<Sprite, SpriteAtlas>)Delegate.CreateDelegate(typeof(Func<Sprite, SpriteAtlas>),
+                s_SpriteEditorExtensionType
+                    .GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic));
 
         /// <summary>
         /// Get the actual texture of a sprite in play mode or edit mode.
@@ -30,9 +34,7 @@ public static Texture2D GetActualTexture(this Sprite self)
         {
             if (!self) return null;
 
-            if (Application.isPlaying) return self.texture;
-
-            var ret = s_GetActiveAtlasTextureMethod.Invoke(null, new object[] { self }) as Texture2D;
+            var ret = s_GetActiveAtlasTextureMethod(self);
             return ret ? ret : self.texture;
         }
 
@@ -43,7 +45,7 @@ public static SpriteAtlas GetActiveAtlas(this Sprite self)
         {
             if (!self) return null;
 
-            return s_GetActiveAtlasMethod.Invoke(null, new object[] { self }) as SpriteAtlas;
+            return s_GetActiveAtlasMethod(self);
         }
 #else
         /// <summary>

From 847af6397eea6388150eded48ddb5c796adb44b8 Mon Sep 17 00:00:00 2001
From: semantic-release-bot <semantic-release-bot@martynus.net>
Date: Thu, 19 Dec 2024 08:50:19 +0000
Subject: [PATCH 05/23] chore(release): 4.10.4 [skip ci]

## [4.10.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.3...v4.10.4) (2024-12-19)

### Bug Fixes

* rendering issues when playing with opening a prefab stage ([95235a9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/95235a929b82cf681365ed6eba837d857f83e3d2)), closes [#345](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/345)
---
 CHANGELOG.md | 7 +++++++
 package.json | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index a53d6b31..67c13ed0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## [4.10.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.3...v4.10.4) (2024-12-19)
+
+
+### Bug Fixes
+
+* rendering issues when playing with opening a prefab stage ([95235a9](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/95235a929b82cf681365ed6eba837d857f83e3d2)), closes [#345](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/345)
+
 ## [4.10.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.2...v4.10.3) (2024-11-20)
 
 
diff --git a/package.json b/package.json
index 7083f28d..ccf0aa29 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "com.coffee.ui-particle",
   "displayName": "UI Particle",
   "description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
-  "version": "4.10.3",
+  "version": "4.10.4",
   "unity": "2018.2",
   "license": "MIT",
   "repository": {

From abdf260352db517a2740aedf1c76d0ac162283d9 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Sun, 22 Dec 2024 11:38:32 +0900
Subject: [PATCH 06/23] fix: '3D' scale toggle in the inspector does not keep
 on reload

close #346
---
 Editor/UIParticleEditor.cs | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/Editor/UIParticleEditor.cs b/Editor/UIParticleEditor.cs
index 16085db8..c58924f0 100644
--- a/Editor/UIParticleEditor.cs
+++ b/Editor/UIParticleEditor.cs
@@ -28,6 +28,11 @@ namespace Coffee.UIExtensions
     [CanEditMultipleObjects]
     internal class UIParticleEditor : GraphicEditor
     {
+        internal class State : ScriptableSingleton<State>
+        {
+            public bool is3DScaleMode;
+        }
+
         //################################
         // Constant or Static Members.
         //################################
@@ -46,7 +51,6 @@ internal class UIParticleEditor : GraphicEditor
         private static readonly GUIContent s_ContentPrimary = new GUIContent("Primary");
         private static readonly Regex s_RegexBuiltInGuid = new Regex(@"^0{16}.0{15}$", RegexOptions.Compiled);
         private static readonly List<Material> s_TempMaterials = new List<Material>();
-        private static bool s_XYZMode;
 
         private SerializedProperty _maskable;
         private SerializedProperty _scale3D;
@@ -60,6 +64,7 @@ internal class UIParticleEditor : GraphicEditor
         private SerializedProperty _customViewSize;
         private ReorderableList _ro;
         private bool _showMax;
+        private bool _is3DScaleMode;
 
         private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
 #if UNITY_2018 || UNITY_2019
@@ -163,6 +168,19 @@ protected override void OnEnable()
                     uip.RefreshParticles(uip.particles);
                 }
             }
+
+            // Initialize 3D scale mode.
+            _is3DScaleMode = State.instance.is3DScaleMode;
+            if (!_is3DScaleMode)
+            {
+                var x = _scale3D.FindPropertyRelative("x");
+                var y = _scale3D.FindPropertyRelative("y");
+                var z = _scale3D.FindPropertyRelative("z");
+                _is3DScaleMode = !Mathf.Approximately(x.floatValue, y.floatValue) ||
+                                 !Mathf.Approximately(y.floatValue, z.floatValue) ||
+                                 y.hasMultipleDifferentValues ||
+                                 z.hasMultipleDifferentValues;
+            }
         }
 
         /// <summary>
@@ -181,7 +199,11 @@ public override void OnInspectorGUI()
 
             // Scale
             EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
-            s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
+            if (DrawFloatOrVector3Field(_scale3D, _is3DScaleMode) != _is3DScaleMode)
+            {
+                State.instance.is3DScaleMode = _is3DScaleMode = !_is3DScaleMode;
+            }
+
             EditorGUI.EndDisabledGroup();
 
             // AnimatableProperties

From ff179f027183bf0e27494c63114250cb4a6f4c04 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Sun, 22 Dec 2024 13:09:07 +0900
Subject: [PATCH 07/23] refactor: update coffee.internal

---
 .../Extensions/ComponentExtensions.cs         |  4 +-
 Runtime/Internal/Utilities/FastAction.cs      |  5 +-
 Runtime/Internal/Utilities/Misc.cs            | 17 ++++
 Runtime/Internal/Utilities/ObjectPool.cs      | 79 +++++++++++++++++--
 Runtime/UIParticleRenderer.cs                 |  8 +-
 5 files changed, 100 insertions(+), 13 deletions(-)

diff --git a/Runtime/Internal/Extensions/ComponentExtensions.cs b/Runtime/Internal/Extensions/ComponentExtensions.cs
index d65be225..f14fc1d8 100644
--- a/Runtime/Internal/Extensions/ComponentExtensions.cs
+++ b/Runtime/Internal/Extensions/ComponentExtensions.cs
@@ -18,10 +18,10 @@ internal static class ComponentExtensions
         public static T[] GetComponentsInChildren<T>(this Component self, int depth)
             where T : Component
         {
-            var results = ListPool<T>.Rent();
+            var results = InternalListPool<T>.Rent();
             self.GetComponentsInChildren_Internal(results, depth);
             var array = results.ToArray();
-            ListPool<T>.Return(ref results);
+            InternalListPool<T>.Return(ref results);
             return array;
         }
 
diff --git a/Runtime/Internal/Utilities/FastAction.cs b/Runtime/Internal/Utilities/FastAction.cs
index 0428d6db..c5fbf508 100755
--- a/Runtime/Internal/Utilities/FastAction.cs
+++ b/Runtime/Internal/Utilities/FastAction.cs
@@ -10,8 +10,9 @@ namespace Coffee.UIParticleInternal
     /// </summary>
     internal class FastActionBase<T>
     {
-        private static readonly ObjectPool<LinkedListNode<T>> s_NodePool =
-            new ObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true, x => x.Value = default);
+        private static readonly InternalObjectPool<LinkedListNode<T>> s_NodePool =
+            new InternalObjectPool<LinkedListNode<T>>(() => new LinkedListNode<T>(default), _ => true,
+                x => x.Value = default);
 
         private readonly LinkedList<T> _delegates = new LinkedList<T>();
 
diff --git a/Runtime/Internal/Utilities/Misc.cs b/Runtime/Internal/Utilities/Misc.cs
index fb1a2108..26c03cff 100644
--- a/Runtime/Internal/Utilities/Misc.cs
+++ b/Runtime/Internal/Utilities/Misc.cs
@@ -1,6 +1,13 @@
+using System;
 using System.Diagnostics;
 using UnityEditor;
 using UnityEngine;
+using Object = UnityEngine.Object;
+#if UNITY_EDITOR && UNITY_2021_2_OR_NEWER
+using UnityEditor.SceneManagement;
+#elif UNITY_EDITOR
+using UnityEditor.Experimental.SceneManagement;
+#endif
 
 namespace Coffee.UIParticleInternal
 {
@@ -53,5 +60,15 @@ public static void SetDirty(Object obj)
             EditorUtility.SetDirty(obj);
 #endif
         }
+
+#if UNITY_EDITOR
+        public static T[] GetAllComponentsInPrefabStage<T>() where T : Component
+        {
+            var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
+            if (prefabStage == null) return Array.Empty<T>();
+
+            return prefabStage.prefabContentsRoot.GetComponentsInChildren<T>(true);
+        }
+#endif
     }
 }
diff --git a/Runtime/Internal/Utilities/ObjectPool.cs b/Runtime/Internal/Utilities/ObjectPool.cs
index fa1c8488..141cccfe 100644
--- a/Runtime/Internal/Utilities/ObjectPool.cs
+++ b/Runtime/Internal/Utilities/ObjectPool.cs
@@ -6,15 +6,58 @@ namespace Coffee.UIParticleInternal
     /// <summary>
     /// Object pool.
     /// </summary>
-    internal class ObjectPool<T>
+    internal class InternalObjectPool<T> where T : class
     {
+#if UNITY_2021_1_OR_NEWER
+        private readonly Predicate<T> _onValid; // Delegate for checking if instances are valid
+        private readonly UnityEngine.Pool.ObjectPool<T> _pool;
+
+        public InternalObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
+        {
+            _pool = new UnityEngine.Pool.ObjectPool<T>(onCreate, null, onReturn);
+            _onValid = onValid;
+        }
+
+        /// <summary>
+        /// Rent an instance from the pool.
+        /// When you no longer need it, return it with <see cref="Return" />.
+        /// </summary>
+        public T Rent()
+        {
+            while (0 < _pool.CountInactive)
+            {
+                var instance = _pool.Get();
+                if (_onValid(instance))
+                {
+                    return instance;
+                }
+            }
+
+            // If there are no instances in the pool, create a new one.
+            Logging.Log(this, $"A new instance is created (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
+            return _pool.Get();
+        }
+
+        /// <summary>
+        /// Return an instance to the pool and assign null.
+        /// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
+        /// </summary>
+        public void Return(ref T instance)
+        {
+            if (instance == null) return; // Ignore if already pooled or null.
+
+            _pool.Release(instance);
+            Logging.Log(this, $"An instance is released (pooled: {_pool.CountInactive}, created: {_pool.CountAll}).");
+            instance = default; // Set the reference to null.
+        }
+#else
         private readonly Func<T> _onCreate; // Delegate for creating instances
         private readonly Action<T> _onReturn; // Delegate for returning instances to the pool
         private readonly Predicate<T> _onValid; // Delegate for checking if instances are valid
         private readonly Stack<T> _pool = new Stack<T>(32); // Object pool
         private int _count; // Total count of created instances
 
-        public ObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
+        public InternalObjectPool(Func<T> onCreate, Predicate<T> onValid, Action<T> onReturn)
         {
             _onCreate = onCreate;
             _onValid = onValid;
@@ -54,15 +97,40 @@ public void Return(ref T instance)
             Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
             instance = default; // Set the reference to null.
         }
+#endif
     }
 
     /// <summary>
     /// Object pool for <see cref="List{T}" />.
     /// </summary>
-    internal static class ListPool<T>
+    internal static class InternalListPool<T>
     {
-        private static readonly ObjectPool<List<T>> s_ListPool =
-            new ObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
+#if UNITY_2021_1_OR_NEWER
+        /// <summary>
+        /// Rent an instance from the pool.
+        /// When you no longer need it, return it with <see cref="Return" />.
+        /// </summary>
+        public static List<T> Rent()
+        {
+            return UnityEngine.Pool.ListPool<T>.Get();
+        }
+
+        /// <summary>
+        /// Return an instance to the pool and assign null.
+        /// Be sure to return the instance obtained with <see cref="Rent" /> with this method.
+        /// </summary>
+        public static void Return(ref List<T> toRelease)
+        {
+            if (toRelease != null)
+            {
+                UnityEngine.Pool.ListPool<T>.Release(toRelease);
+            }
+
+            toRelease = null;
+        }
+#else
+        private static readonly InternalObjectPool<List<T>> s_ListPool =
+            new InternalObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
 
         /// <summary>
         /// Rent an instance from the pool.
@@ -81,5 +149,6 @@ public static void Return(ref List<T> toRelease)
         {
             s_ListPool.Return(ref toRelease);
         }
+#endif
     }
 }
diff --git a/Runtime/UIParticleRenderer.cs b/Runtime/UIParticleRenderer.cs
index 3417e10c..80936b83 100644
--- a/Runtime/UIParticleRenderer.cs
+++ b/Runtime/UIParticleRenderer.cs
@@ -421,7 +421,7 @@ public void UpdateMesh(Camera bakeCamera)
                     workerMesh.LinearToGamma();
                 }
 
-                var components = ListPool<Component>.Rent();
+                var components = InternalListPool<Component>.Rent();
                 GetComponents(typeof(IMeshModifier), components);
                 for (var i = 0; i < components.Count; i++)
                 {
@@ -430,7 +430,7 @@ public void UpdateMesh(Camera bakeCamera)
 #pragma warning restore CS0618 // Type or member is obsolete
                 }
 
-                ListPool<Component>.Return(ref components);
+                InternalListPool<Component>.Return(ref components);
             }
 
             Profiler.EndSample();
@@ -442,7 +442,7 @@ public void UpdateMesh(Camera bakeCamera)
 
             // Get grouped renderers.
             Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
-            var renderers = ListPool<UIParticleRenderer>.Rent();
+            var renderers = InternalListPool<UIParticleRenderer>.Rent();
             if (_parent.useMeshSharing)
             {
                 UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, renderers);
@@ -459,7 +459,7 @@ public void UpdateMesh(Camera bakeCamera)
                 r.canvasRenderer.SetMaterial(materialForRendering, 0);
             }
 
-            ListPool<UIParticleRenderer>.Return(ref renderers);
+            InternalListPool<UIParticleRenderer>.Return(ref renderers);
 
             if (_parent.canRender)
             {

From f4b28b68b1e1367ac7fdc89f1e750ee7a148e325 Mon Sep 17 00:00:00 2001
From: semantic-release-bot <semantic-release-bot@martynus.net>
Date: Mon, 23 Dec 2024 03:54:11 +0000
Subject: [PATCH 08/23] chore(release): 4.10.5 [skip ci]

## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)

### Bug Fixes

* '3D' scale toggle in the inspector does not keep on reload ([934f4b8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/934f4b8f1c61f8ff20228d0ebcea9f636a3758ed)), closes [#346](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/346)
---
 CHANGELOG.md | 7 +++++++
 package.json | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67c13ed0..72a1c621 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)
+
+
+### Bug Fixes
+
+* '3D' scale toggle in the inspector does not keep on reload ([934f4b8](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/934f4b8f1c61f8ff20228d0ebcea9f636a3758ed)), closes [#346](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/346)
+
 ## [4.10.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.3...v4.10.4) (2024-12-19)
 
 
diff --git a/package.json b/package.json
index ccf0aa29..d0621421 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "com.coffee.ui-particle",
   "displayName": "UI Particle",
   "description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
-  "version": "4.10.4",
+  "version": "4.10.5",
   "unity": "2018.2",
   "license": "MIT",
   "repository": {

From 1c33dac1255dca4ee00214fcfd6e10cf79256c73 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Wed, 1 Jan 2025 10:05:46 +0900
Subject: [PATCH 09/23] fix: sub-emitter's `inherit velocity` module doubles at
 runtime

close #349
---
 Runtime/UIParticle.cs                         |  6 +++--
 Runtime/UIParticleRenderer.cs                 | 10 ++++----
 Runtime/Utilities/ParticleSystemExtensions.cs | 25 +++++++++++++++++++
 3 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/Runtime/UIParticle.cs b/Runtime/UIParticle.cs
index 5ad390d4..f0a2bedc 100644
--- a/Runtime/UIParticle.cs
+++ b/Runtime/UIParticle.cs
@@ -577,12 +577,14 @@ public void RefreshParticles(List<ParticleSystem> particleSystems)
             {
                 var ps = particleSystems[i];
                 if (!ps) continue;
-                GetRenderer(j++).Set(this, ps, false);
+
+                var mainEmitter = ps.GetMainEmitter(particleSystems);
+                GetRenderer(j++).Set(this, ps, false, mainEmitter);
 
                 // If the trail is enabled, set it additionally.
                 if (ps.trails.enabled)
                 {
-                    GetRenderer(j++).Set(this, ps, true);
+                    GetRenderer(j++).Set(this, ps, true, mainEmitter);
                 }
             }
         }
diff --git a/Runtime/UIParticleRenderer.cs b/Runtime/UIParticleRenderer.cs
index 80936b83..e85d2587 100644
--- a/Runtime/UIParticleRenderer.cs
+++ b/Runtime/UIParticleRenderer.cs
@@ -40,6 +40,7 @@ internal class UIParticleRenderer : MaskableGraphic
         private Vector2Int _prevScreenSize;
         private bool _preWarm;
         private ParticleSystemRenderer _renderer;
+        private ParticleSystem _mainEmitter;
 
         public override Texture mainTexture => _isTrail ? null : _particleSystem.GetTextureForSprite();
 
@@ -112,6 +113,7 @@ public void Reset(int index = -1)
             _parent = null;
             _particleSystem = null;
             _renderer = null;
+            _mainEmitter = null;
             if (0 <= index)
             {
                 _index = index;
@@ -223,7 +225,7 @@ public override Material GetModifiedMaterial(Material baseMaterial)
             return _modifiedMaterial;
         }
 
-        public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
+        public void Set(UIParticle parent, ParticleSystem ps, bool isTrail, ParticleSystem mainEmitter)
         {
             _parent = parent;
             maskable = parent.maskable;
@@ -246,10 +248,7 @@ public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
 
             ps.TryGetComponent(out _renderer);
             _renderer.enabled = false;
-
-            //_emitter = emitter;
             _isTrail = isTrail;
-
             _renderer.GetSharedMaterials(s_Materials);
             material = s_Materials[isTrail ? 1 : 0];
             s_Materials.Clear();
@@ -266,6 +265,7 @@ public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
             _prevScreenSize = new Vector2Int(Screen.width, Screen.height);
             _prevCanvasScale = canvas ? canvas.scaleFactor : 1f;
             _delay = true;
+            _mainEmitter = mainEmitter;
 
             canvasRenderer.SetTexture(null);
 
@@ -303,7 +303,7 @@ public void UpdateMesh(Camera bakeCamera)
 
             // Simulate particles.
             Profiler.BeginSample("[UIParticle] Bake Mesh > Simulate Particles");
-            if (!_isTrail && _parent.canSimulate)
+            if (!_isTrail && _parent.canSimulate && !_mainEmitter)
             {
 #if UNITY_EDITOR
                 if (!Application.isPlaying)
diff --git a/Runtime/Utilities/ParticleSystemExtensions.cs b/Runtime/Utilities/ParticleSystemExtensions.cs
index 48329f0e..b9c08a01 100644
--- a/Runtime/Utilities/ParticleSystemExtensions.cs
+++ b/Runtime/Utilities/ParticleSystemExtensions.cs
@@ -171,5 +171,30 @@ public static void Exec(this List<ParticleSystem> self, Action<ParticleSystem> a
                 action.Invoke(p);
             }
         }
+
+        public static ParticleSystem GetMainEmitter(this ParticleSystem self, List<ParticleSystem> list)
+        {
+            if (!self || list == null || list.Count == 0) return null;
+
+            for (var i = 0; i < list.Count; i++)
+            {
+                var parent = list[i];
+                if (parent != self && IsSubEmitterOf(self, parent)) return parent;
+            }
+
+            return null;
+        }
+
+        public static bool IsSubEmitterOf(this ParticleSystem self, ParticleSystem parent)
+        {
+            var subEmitters = parent.subEmitters;
+            var count = subEmitters.subEmittersCount;
+            for (var i = 0; i < count; i++)
+            {
+                if (subEmitters.GetSubEmitterSystem(i) == self) return true;
+            }
+
+            return false;
+        }
     }
 }

From 23cd44876659ffefb5aa4ea66d7264e55677eb8a Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Fri, 3 Jan 2025 22:50:36 +0900
Subject: [PATCH 10/23] fix: sub-emitter particles may not render correctly in
 certain scenarios

close #348
---
 Runtime/UIParticleRenderer.cs | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/Runtime/UIParticleRenderer.cs b/Runtime/UIParticleRenderer.cs
index e85d2587..a73b4b47 100644
--- a/Runtime/UIParticleRenderer.cs
+++ b/Runtime/UIParticleRenderer.cs
@@ -548,6 +548,24 @@ private Matrix4x4 GetWorldMatrix(Vector3 psPos, Vector3 scale)
                                * Matrix4x4.Scale(scale)
                                * Matrix4x4.Translate(-psPos);
                     }
+
+                    if (_mainEmitter)
+                    {
+                        if (_mainEmitter.IsLocalSpace())
+                        {
+                            return Matrix4x4.Translate(psPos)
+                                   * Matrix4x4.Scale(scale)
+                                   * Matrix4x4.Translate(-psPos);
+                        }
+                        else
+                        {
+                            psPos = _particleSystem.transform.position - _mainEmitter.transform.position;
+                            return Matrix4x4.Translate(psPos)
+                                   * Matrix4x4.Scale(scale)
+                                   * Matrix4x4.Translate(-psPos);
+                        }
+                    }
+
                     return Matrix4x4.Scale(scale);
                 case ParticleSystemSimulationSpace.Custom:
                     return Matrix4x4.Translate(_particleSystem.main.customSimulationSpace.position.GetScaled(scale))

From a0a2f4aece3c31e9673bd4b5b65553e047bf680f Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Fri, 3 Jan 2025 22:58:18 +0900
Subject: [PATCH 11/23] chore: update coffee.internal

---
 Runtime/Coffee.UIParticle.R.dll               | Bin 0 -> 3072 bytes
 Runtime/Coffee.UIParticle.R.dll.meta          |  33 ++++++++++++++++++
 .../PreloadedProjectSettings.cs               |   2 ++
 .../Internal/Utilities/MaterialRepository.cs  |   2 +-
 Runtime/Internal/Utilities/Misc.cs            |   2 ++
 5 files changed, 38 insertions(+), 1 deletion(-)
 create mode 100644 Runtime/Coffee.UIParticle.R.dll
 create mode 100644 Runtime/Coffee.UIParticle.R.dll.meta

diff --git a/Runtime/Coffee.UIParticle.R.dll b/Runtime/Coffee.UIParticle.R.dll
new file mode 100644
index 0000000000000000000000000000000000000000..de59dad0bf2d83bfe317c10c555ff1eea6470ba3
GIT binary patch
literal 3072
zcmeHJ&2Jk;6#s4Fge0YfsHhatmTg@mK3A@i14tD(u>+(^8aIy9h)c7!$Iilf*V-Mo
zi9je94&0Cs|3N`qka9pMLV`=h1rgLkFC36KaYdXeAw>AS*>&u+DNv56&zU#x`)g)L
znSb*`3<Ah-?d}5G+y(Lm|2^8I`p8pX9l;l)JEym;xt-HXYhG-(qp%sdExYChL8$Gj
zvZGF5dx2eCDBG>DuAIY%$IhmqOEbWnHHdHZ<DYi3{fsmAAuE>@HJnI)$a1&2@?5~9
zh8{>vL?HDW*d(T0U=aED#Z>-!d&-K4@Gj#n2$2VFrhdZi!7A`DnN`}I*c1K>!UjhA
z%tpw+(Z@Slt!whPWcbvX2JXmD@v0NWQH^R-TRyc*XF|?Ep4B^%@<SR*tytxfSYup$
zkO!vwSVL}Q6N%I|fFYD@);$PVi5M%?_xF*C@3~EvFHBphx72cV(#bg!xruWxi^~vv
z;y<{u?*VH}a-J(&){z%9W3jl-y5%ghl`=jfEk~Dqy)s+mzD>R){InldxeHKaJ@gnb
zDh2;;P2gBkyNpOgL+KKlwrOQQru#5Fj9J6@#NYyM;}JYZ(=lAe4dM@o1;kshg;D%Q
zJWf1}Cy2-Jtf9{t?BEck4vyjs@spS$&f)^`^Te4=2H6L4Km%!XQ6$%Tp9z^4_5@PL
zsf0T}AJ#j*dIg2B(NM~%%$D3pdo^D<i@1V7=~%l#-Hqy~1fJfQ37TG@oI)6>#1lnT
z?KGQi)mKxR2T<*3g;Jzq6<zI<6v9^9^Ih$Q!J_irbwkBHk179}yAjWM!P`@DtXfrn
zqo-T!1lnsU2|>52=d+HUw!f@$E%Mr$m*AjwoVxGBsp&96c_Y@U<rF=)8H6$0jk}^W
z7aNp%Ra9mhUQNYmn+(mi$)@n}m*Xct`ut>J%R6!7t;To1AY)tB$e;~th{X8#$oKCY
z-Q9Wdr%NMNdjC(!@h=S=yBxXgi(xRcUQ?_%43^fS@LFuqPVN_PZ*p1EJpG$_hWZ58
z({E2i-w16BbvJas(L{5FM_BazdDjcjifcSiWd<bL-KQDj&NO!iyr;x6&c}hx{U*s5
zojX7-cJg+t<N=)wKt!Y`iI-94U0lWt7D>(WrM*agmiV>g)y3DDU;pfWU&b*-uco`a
z1$|+SRNexMQC&og<MB;Vj2WPT(CE*a7i5WAm(rMe7n*h<xdgT{w|GhxYtppxC~qDR
zY0KE;(EUxKN?N{0`DVMBi_9LQX5zH><*{j-<L&9$F4H!mb+48j--h0j_w6|Cr5kN*
z1J>?yUM^bXfdac|@Td55P@!dsy2#|MnMpXDwSziod263Bwa(GHX(EY#8ylwDCf4W&
zbM014-i1^y6Op{#9)<gF`6o^PCB_X|Q-^cXJh}Z-==CqN0A4aaQ=C&w%ND2Zvts)n
Z{pk7t?so!q@;}4PiTibYVE=!Zz+Z=VLS6s>

literal 0
HcmV?d00001

diff --git a/Runtime/Coffee.UIParticle.R.dll.meta b/Runtime/Coffee.UIParticle.R.dll.meta
new file mode 100644
index 00000000..fb448a10
--- /dev/null
+++ b/Runtime/Coffee.UIParticle.R.dll.meta
@@ -0,0 +1,33 @@
+fileFormatVersion: 2
+guid: 4d73b3825bf044d418ae21bb331d3902
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 1
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      Any: 
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
+  - first:
+      Windows Store Apps: WindowsStoreApps
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs b/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs
index 21ff15a5..7f5326ad 100644
--- a/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs
+++ b/Runtime/Internal/ProjectSettings/PreloadedProjectSettings.cs
@@ -133,6 +133,8 @@ public abstract class PreloadedProjectSettings<T> : PreloadedProjectSettings
 #if UNITY_EDITOR
         private string _jsonText;
 
+        public static bool hasInstance => s_Instance;
+
         public static T instance
         {
             get
diff --git a/Runtime/Internal/Utilities/MaterialRepository.cs b/Runtime/Internal/Utilities/MaterialRepository.cs
index 7f159454..cd3c05ea 100644
--- a/Runtime/Internal/Utilities/MaterialRepository.cs
+++ b/Runtime/Internal/Utilities/MaterialRepository.cs
@@ -15,7 +15,7 @@ internal static class MaterialRepository
 
 #if UNITY_EDITOR
         [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
-        private static void Clear()
+        public static void Clear()
         {
             s_Repository.Clear();
         }
diff --git a/Runtime/Internal/Utilities/Misc.cs b/Runtime/Internal/Utilities/Misc.cs
index 26c03cff..3f6fb474 100644
--- a/Runtime/Internal/Utilities/Misc.cs
+++ b/Runtime/Internal/Utilities/Misc.cs
@@ -69,6 +69,8 @@ public static T[] GetAllComponentsInPrefabStage<T>() where T : Component
 
             return prefabStage.prefabContentsRoot.GetComponentsInChildren<T>(true);
         }
+
+        public static bool isBatchOrBuilding => Application.isBatchMode || BuildPipeline.isBuildingPlayer;
 #endif
     }
 }

From 4f429965144092fc84e57910293e744b6b0e844b Mon Sep 17 00:00:00 2001
From: semantic-release-bot <semantic-release-bot@martynus.net>
Date: Fri, 3 Jan 2025 14:24:40 +0000
Subject: [PATCH 12/23] chore(release): 4.10.6 [skip ci]

## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)

### Bug Fixes

* sub-emitter particles may not render correctly in certain scenarios ([8276684](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8276684c3b1646f0490ed64557547ba15281664a)), closes [#348](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/348)
* sub-emitter's `inherit velocity` module doubles at runtime ([67de3d1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/67de3d1bd3e16dc9b564625cb990c53d75769506)), closes [#349](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/349)
---
 CHANGELOG.md | 8 ++++++++
 package.json | 2 +-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 72a1c621..8e6c1303 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)
+
+
+### Bug Fixes
+
+* sub-emitter particles may not render correctly in certain scenarios ([8276684](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/8276684c3b1646f0490ed64557547ba15281664a)), closes [#348](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/348)
+* sub-emitter's `inherit velocity` module doubles at runtime ([67de3d1](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/67de3d1bd3e16dc9b564625cb990c53d75769506)), closes [#349](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/349)
+
 ## [4.10.5](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.4...v4.10.5) (2024-12-23)
 
 
diff --git a/package.json b/package.json
index d0621421..1ae90f0c 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "com.coffee.ui-particle",
   "displayName": "UI Particle",
   "description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
-  "version": "4.10.5",
+  "version": "4.10.6",
   "unity": "2018.2",
   "license": "MIT",
   "repository": {

From 12d604feddd6e60e5c57a263c436b33bef86c4fc Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Tue, 7 Jan 2025 10:25:23 +0900
Subject: [PATCH 13/23] fix: editor crashed on exit play mode (editor, windows)

close #351
---
 Runtime/UIParticleUpdater.cs | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/Runtime/UIParticleUpdater.cs b/Runtime/UIParticleUpdater.cs
index 4df51537..2e353e93 100644
--- a/Runtime/UIParticleUpdater.cs
+++ b/Runtime/UIParticleUpdater.cs
@@ -40,13 +40,26 @@ public static void Unregister(UIParticleAttractor attractor)
 
 #if UNITY_EDITOR
         [InitializeOnLoadMethod]
+        private static void InitializeOnLoad()
+        {
+            UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
+
+            EditorApplication.playModeStateChanged += state =>
+            {
+                UIExtraCallbacks.onAfterCanvasRebuild -= Refresh;
+                if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.EnteredPlayMode)
+                {
+                    UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
+                }
+            };
+        }
 #else
         [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
-#endif
         private static void InitializeOnLoad()
         {
             UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
         }
+#endif
 
         private static void Refresh()
         {

From 201bd9180eaa9d581eeaa048a164a5abd09001c9 Mon Sep 17 00:00:00 2001
From: semantic-release-bot <semantic-release-bot@martynus.net>
Date: Tue, 14 Jan 2025 11:49:21 +0000
Subject: [PATCH 14/23] chore(release): 4.10.7 [skip ci]

## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)

### Bug Fixes

* editor crashed on exit play mode (editor, windows) ([47ee45c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/47ee45cbbe651a8f87ca2b8a3948f8b88db8211e)), closes [#351](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/351)
---
 CHANGELOG.md | 7 +++++++
 package.json | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8e6c1303..8d6f29f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)
+
+
+### Bug Fixes
+
+* editor crashed on exit play mode (editor, windows) ([47ee45c](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/47ee45cbbe651a8f87ca2b8a3948f8b88db8211e)), closes [#351](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/351)
+
 ## [4.10.6](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.5...v4.10.6) (2025-01-03)
 
 
diff --git a/package.json b/package.json
index 1ae90f0c..80fb40b7 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "com.coffee.ui-particle",
   "displayName": "UI Particle",
   "description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
-  "version": "4.10.6",
+  "version": "4.10.7",
   "unity": "2018.2",
   "license": "MIT",
   "repository": {

From 9832485c04b03ebdffcaf4db0a1025f40a3f9cdc Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Fri, 21 Feb 2025 14:32:01 +0900
Subject: [PATCH 15/23] feat: add 'TimeScaleMultiplier' option

---
 Editor/UIParticleEditor.cs    |  5 +++++
 Runtime/UIParticle.cs         | 13 +++++++++++++
 Runtime/UIParticleRenderer.cs |  1 +
 3 files changed, 19 insertions(+)

diff --git a/Editor/UIParticleEditor.cs b/Editor/UIParticleEditor.cs
index c58924f0..0cffc983 100644
--- a/Editor/UIParticleEditor.cs
+++ b/Editor/UIParticleEditor.cs
@@ -62,6 +62,7 @@ internal class State : ScriptableSingleton<State>
         private SerializedProperty _autoScalingMode;
         private SerializedProperty _useCustomView;
         private SerializedProperty _customViewSize;
+        private SerializedProperty _timeScaleMultiplier;
         private ReorderableList _ro;
         private bool _showMax;
         private bool _is3DScaleMode;
@@ -100,6 +101,7 @@ protected override void OnEnable()
             _autoScalingMode = serializedObject.FindProperty("m_AutoScalingMode");
             _useCustomView = serializedObject.FindProperty("m_UseCustomView");
             _customViewSize = serializedObject.FindProperty("m_CustomViewSize");
+            _timeScaleMultiplier = serializedObject.FindProperty("m_TimeScaleMultiplier");
 
             var sp = serializedObject.FindProperty("m_Particles");
             _ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
@@ -244,6 +246,9 @@ public override void OnInspectorGUI()
                 _customViewSize.floatValue = Mathf.Max(0.1f, _customViewSize.floatValue);
             }
 
+            // Time Scale Multiplier
+            EditorGUILayout.PropertyField(_timeScaleMultiplier);
+
             // Target ParticleSystems.
             EditorGUI.BeginChangeCheck();
             _ro.DoLayoutList();
diff --git a/Runtime/UIParticle.cs b/Runtime/UIParticle.cs
index f0a2bedc..354f4dfc 100644
--- a/Runtime/UIParticle.cs
+++ b/Runtime/UIParticle.cs
@@ -119,6 +119,10 @@ public enum PositionMode
                  "Change the bake view size.")]
         private float m_CustomViewSize = 10;
 
+        [SerializeField]
+        [Tooltip("Time scale multiplier.")]
+        private float m_TimeScaleMultiplier = 1;
+
         private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
         private Camera _bakeCamera;
         private int _groupId;
@@ -257,6 +261,15 @@ public float customViewSize
             set => m_CustomViewSize = Mathf.Max(0.1f, value);
         }
 
+        /// <summary>
+        /// Time scale multiplier.
+        /// </summary>
+        public float timeScaleMultiplier
+        {
+            get => m_TimeScaleMultiplier;
+            set => m_TimeScaleMultiplier = value;
+        }
+
         internal bool useMeshSharing => m_MeshSharing != MeshSharing.None;
 
         internal bool isPrimary =>
diff --git a/Runtime/UIParticleRenderer.cs b/Runtime/UIParticleRenderer.cs
index a73b4b47..fef02be2 100644
--- a/Runtime/UIParticleRenderer.cs
+++ b/Runtime/UIParticleRenderer.cs
@@ -628,6 +628,7 @@ private void Simulate(Vector3 scale, bool paused)
                 : main.useUnscaledTime
                     ? Time.unscaledDeltaTime
                     : Time.deltaTime;
+            deltaTime *= _parent.timeScaleMultiplier;
 
             // Pre-warm:
             if (0 < deltaTime && _preWarm)

From 3d0284c63048c7205f7244e99936622e1f8cbb4e Mon Sep 17 00:00:00 2001
From: semantic-release-bot <semantic-release-bot@martynus.net>
Date: Fri, 21 Feb 2025 07:17:09 +0000
Subject: [PATCH 16/23] chore(release): 4.11.0 [skip ci]

# [4.11.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.7...v4.11.0) (2025-02-21)

### Features

* add 'TimeScaleMultiplier' option ([925af0b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/925af0b6046f65f23a778f67cefa8ff9cbedb513))
---
 CHANGELOG.md | 7 +++++++
 package.json | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d6f29f1..5e02fa94 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# [4.11.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.7...v4.11.0) (2025-02-21)
+
+
+### Features
+
+* add 'TimeScaleMultiplier' option ([925af0b](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/925af0b6046f65f23a778f67cefa8ff9cbedb513))
+
 ## [4.10.7](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.6...v4.10.7) (2025-01-14)
 
 
diff --git a/package.json b/package.json
index 80fb40b7..fcf6d0e0 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "com.coffee.ui-particle",
   "displayName": "UI Particle",
   "description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
-  "version": "4.10.7",
+  "version": "4.11.0",
   "unity": "2018.2",
   "license": "MIT",
   "repository": {

From 8b5f7ff57e724b92d9215af9a4bb6fea1f7be129 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Fri, 21 Feb 2025 17:37:38 +0900
Subject: [PATCH 17/23] doc: update readme

---
 README.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index beb1a637..8e049eca 100644
--- a/README.md
+++ b/README.md
@@ -158,7 +158,7 @@ _This package requires **Unity 2018.3 or later**._
 
 `UIParticle` controls the ParticleSystems that are attached to its own game objects and child game objects.
 
-![](https://github.com/mob-sakai/ParticleEffectForUGUI/assets/12690315/1cf5753b-33fc-4cef-91c3-413c515a954f)
+![](https://github.com/user-attachments/assets/bc9eb783-afce-4102-ac61-aee9ea8d6f2f)
 
 - **Maskable**: Does this graphic allow maskable.
 - **Scale**: Scale the rendering particles. When the `3D` toggle is enabled, 3D scale (x, y, z) is supported.
@@ -180,6 +180,7 @@ _This package requires **Unity 2018.3 or later**._
   - **UIParticle:** UIParticle.scale will be adjusted.
 - **Use Custom View:** Use this if the particles are not displayed correctly due to min/max particle size.
   - **Custom view size:** Change the bake view size.
+- **Time Scale Multiplier:** Time scale multiplier.
 - **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
 
 **NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
@@ -210,7 +211,7 @@ and z-position.
 If you want to mask particles, set a stencil-supported shader (such as `UI/UIAdditive`) to the material for
 ParticleSystem.
 If you use some custom shaders, see
-the [How to Make a Custom Shader to Support Mask/RectMask2D Component](#how-to-make-a-custom-shader-to-support-maskrectmask2d-component)
+the [How to Make a Custom Shader to Support Mask/RectMask2D Component](#how-to-make-a-custom-shader-to-support-mask-and-rectmask2d-component)
 section.
 
 ![](https://user-images.githubusercontent.com/12690315/95017591-3b512700-0695-11eb-864e-04166ea1809a.png)

From 803af8113dd382be0e30542a2fd88730b3a236e8 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Fri, 21 Feb 2025 18:00:29 +0900
Subject: [PATCH 18/23] fix: component icons will no longer be displayed in the
 scene view

---
 .../Extensions/ComponentExtensions.cs         |  2 +-
 Runtime/Internal/Utilities/Misc.cs            | 60 ++++++++++++++++++-
 Runtime/UIParticle.cs                         |  1 +
 Runtime/UIParticle.cs.meta                    |  2 +-
 Runtime/UIParticleProjectSettings.cs          |  1 +
 Runtime/UIParticleProjectSettings.cs.meta     |  2 +-
 Runtime/UIParticleRenderer.cs                 |  1 +
 Runtime/UIParticleRenderer.cs.meta            |  2 +-
 8 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/Runtime/Internal/Extensions/ComponentExtensions.cs b/Runtime/Internal/Extensions/ComponentExtensions.cs
index f14fc1d8..e9ec78be 100644
--- a/Runtime/Internal/Extensions/ComponentExtensions.cs
+++ b/Runtime/Internal/Extensions/ComponentExtensions.cs
@@ -204,7 +204,7 @@ internal static void ConvertTo<T>(this Object context) where T : MonoBehaviour
             target.enabled = false;
 
             // Find MonoScript of the specified component.
-            foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
+            foreach (var script in MonoImporter.GetAllRuntimeMonoScripts())
             {
                 if (script.GetClass() != typeof(T))
                 {
diff --git a/Runtime/Internal/Utilities/Misc.cs b/Runtime/Internal/Utilities/Misc.cs
index 3f6fb474..4eac3d89 100644
--- a/Runtime/Internal/Utilities/Misc.cs
+++ b/Runtime/Internal/Utilities/Misc.cs
@@ -3,11 +3,16 @@
 using UnityEditor;
 using UnityEngine;
 using Object = UnityEngine.Object;
-#if UNITY_EDITOR && UNITY_2021_2_OR_NEWER
+#if UNITY_EDITOR
+using System.IO;
+using System.Linq;
+using System.Reflection;
+#if UNITY_2021_2_OR_NEWER
 using UnityEditor.SceneManagement;
-#elif UNITY_EDITOR
+#else
 using UnityEditor.Experimental.SceneManagement;
 #endif
+#endif
 
 namespace Coffee.UIParticleInternal
 {
@@ -72,5 +77,56 @@ public static T[] GetAllComponentsInPrefabStage<T>() where T : Component
 
         public static bool isBatchOrBuilding => Application.isBatchMode || BuildPipeline.isBuildingPlayer;
 #endif
+
+        [Conditional("UNITY_EDITOR")]
+        public static void QueuePlayerLoopUpdate()
+        {
+#if UNITY_EDITOR
+            if (!EditorApplication.isPlaying)
+            {
+                EditorApplication.QueuePlayerLoopUpdate();
+            }
+#endif
+        }
     }
+
+#if !UNITY_2021_2_OR_NEWER
+    [AttributeUsage(AttributeTargets.Class)]
+    [Conditional("UNITY_EDITOR")]
+    internal class IconAttribute : Attribute
+    {
+        private readonly string _path;
+
+        public IconAttribute(string path)
+        {
+            _path = path;
+        }
+
+#if UNITY_EDITOR
+        private static Action<Object, Texture2D> s_SetIconForObject = typeof(EditorGUIUtility)
+            .GetMethod("SetIconForObject", BindingFlags.Static | BindingFlags.NonPublic)
+            .CreateDelegate(typeof(Action<Object, Texture2D>), null) as Action<Object, Texture2D>;
+
+        [InitializeOnLoadMethod]
+        private static void InitializeOnLoadMethod()
+        {
+            if (Misc.isBatchOrBuilding) return;
+
+            var types = TypeCache.GetTypesWithAttribute<IconAttribute>();
+            var scripts = MonoImporter.GetAllRuntimeMonoScripts();
+            foreach (var type in types)
+            {
+                var script = scripts.FirstOrDefault(x => x.GetClass() == type);
+                if (!script) continue;
+
+                var path = type.GetCustomAttribute<IconAttribute>()?._path;
+                var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
+                if (!icon) continue;
+
+                s_SetIconForObject(script, icon);
+            }
+        }
+#endif
+    }
+#endif
 }
diff --git a/Runtime/UIParticle.cs b/Runtime/UIParticle.cs
index 354f4dfc..9caaf193 100644
--- a/Runtime/UIParticle.cs
+++ b/Runtime/UIParticle.cs
@@ -17,6 +17,7 @@ namespace Coffee.UIExtensions
     /// <summary>
     /// Render maskable and sortable particle effect ,without Camera, RenderTexture or Canvas.
     /// </summary>
+    [Icon("Packages/com.coffee.ui-particle/Icons/UIParticleIcon.png")]
     [ExecuteAlways]
     [RequireComponent(typeof(RectTransform))]
     [RequireComponent(typeof(CanvasRenderer))]
diff --git a/Runtime/UIParticle.cs.meta b/Runtime/UIParticle.cs.meta
index f076457d..1dc794d9 100644
--- a/Runtime/UIParticle.cs.meta
+++ b/Runtime/UIParticle.cs.meta
@@ -5,7 +5,7 @@ MonoImporter:
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0
-  icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
+  icon: {instanceID: 0}
   userData: 
   assetBundleName: 
   assetBundleVariant: 
diff --git a/Runtime/UIParticleProjectSettings.cs b/Runtime/UIParticleProjectSettings.cs
index ab295d65..6da01704 100644
--- a/Runtime/UIParticleProjectSettings.cs
+++ b/Runtime/UIParticleProjectSettings.cs
@@ -5,6 +5,7 @@
 
 namespace Coffee.UIExtensions
 {
+    [Icon("Packages/com.coffee.ui-particle/Icons/UIParticleIcon.png")]
     public class UIParticleProjectSettings : PreloadedProjectSettings<UIParticleProjectSettings>
     {
         [Header("Setting")]
diff --git a/Runtime/UIParticleProjectSettings.cs.meta b/Runtime/UIParticleProjectSettings.cs.meta
index ca6db89f..22e35afa 100644
--- a/Runtime/UIParticleProjectSettings.cs.meta
+++ b/Runtime/UIParticleProjectSettings.cs.meta
@@ -5,7 +5,7 @@ MonoImporter:
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0
-  icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
+  icon: {instanceID: 0}
   userData: 
   assetBundleName: 
   assetBundleVariant: 
diff --git a/Runtime/UIParticleRenderer.cs b/Runtime/UIParticleRenderer.cs
index fef02be2..fc1ea73e 100644
--- a/Runtime/UIParticleRenderer.cs
+++ b/Runtime/UIParticleRenderer.cs
@@ -15,6 +15,7 @@
 
 namespace Coffee.UIExtensions
 {
+    [Icon("Packages/com.coffee.ui-particle/Icons/UIParticleIcon.png")]
     [ExecuteAlways]
     [RequireComponent(typeof(RectTransform))]
     [RequireComponent(typeof(CanvasRenderer))]
diff --git a/Runtime/UIParticleRenderer.cs.meta b/Runtime/UIParticleRenderer.cs.meta
index 9896f40a..2f3f29cf 100644
--- a/Runtime/UIParticleRenderer.cs.meta
+++ b/Runtime/UIParticleRenderer.cs.meta
@@ -5,7 +5,7 @@ MonoImporter:
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0
-  icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
+  icon: {instanceID: 0}
   userData: 
   assetBundleName: 
   assetBundleVariant: 

From 7ea0a436d159e245605bcd2d8a287432e4a13c79 Mon Sep 17 00:00:00 2001
From: semantic-release-bot <semantic-release-bot@martynus.net>
Date: Fri, 21 Feb 2025 09:35:05 +0000
Subject: [PATCH 19/23] chore(release): 4.11.1 [skip ci]

## [4.11.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.0...v4.11.1) (2025-02-21)

### Bug Fixes

* component icons will no longer be displayed in the scene view ([6dfbdae](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/6dfbdae38d3822ab9c2c6f0e4ca1ca32ee98a239))
---
 CHANGELOG.md | 7 +++++++
 package.json | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e02fa94..ec8a4902 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+## [4.11.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.0...v4.11.1) (2025-02-21)
+
+
+### Bug Fixes
+
+* component icons will no longer be displayed in the scene view ([6dfbdae](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/6dfbdae38d3822ab9c2c6f0e4ca1ca32ee98a239))
+
 # [4.11.0](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.10.7...v4.11.0) (2025-02-21)
 
 
diff --git a/package.json b/package.json
index fcf6d0e0..0acfd33a 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "com.coffee.ui-particle",
   "displayName": "UI Particle",
   "description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
-  "version": "4.11.0",
+  "version": "4.11.1",
   "unity": "2018.2",
   "license": "MIT",
   "repository": {

From 4b6da7c218d440908642219372bae59ea0a8c398 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Fri, 14 Mar 2025 19:24:22 +0900
Subject: [PATCH 20/23] chore: fix settings icon

---
 {Icons => Editor}/UIParticleIcon.png      | Bin
 {Icons => Editor}/UIParticleIcon.png.meta |   0
 Icons.meta                                |   8 --------
 Runtime/UIParticleProjectSettings.cs      |   1 -
 Runtime/UIParticleProjectSettings.cs.meta |   2 +-
 5 files changed, 1 insertion(+), 10 deletions(-)
 rename {Icons => Editor}/UIParticleIcon.png (100%)
 rename {Icons => Editor}/UIParticleIcon.png.meta (100%)
 delete mode 100644 Icons.meta

diff --git a/Icons/UIParticleIcon.png b/Editor/UIParticleIcon.png
similarity index 100%
rename from Icons/UIParticleIcon.png
rename to Editor/UIParticleIcon.png
diff --git a/Icons/UIParticleIcon.png.meta b/Editor/UIParticleIcon.png.meta
similarity index 100%
rename from Icons/UIParticleIcon.png.meta
rename to Editor/UIParticleIcon.png.meta
diff --git a/Icons.meta b/Icons.meta
deleted file mode 100644
index e257c714..00000000
--- a/Icons.meta
+++ /dev/null
@@ -1,8 +0,0 @@
-fileFormatVersion: 2
-guid: 7a55e246f37df405bac88eac692e3a86
-folderAsset: yes
-DefaultImporter:
-  externalObjects: {}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/Runtime/UIParticleProjectSettings.cs b/Runtime/UIParticleProjectSettings.cs
index 6da01704..ab295d65 100644
--- a/Runtime/UIParticleProjectSettings.cs
+++ b/Runtime/UIParticleProjectSettings.cs
@@ -5,7 +5,6 @@
 
 namespace Coffee.UIExtensions
 {
-    [Icon("Packages/com.coffee.ui-particle/Icons/UIParticleIcon.png")]
     public class UIParticleProjectSettings : PreloadedProjectSettings<UIParticleProjectSettings>
     {
         [Header("Setting")]
diff --git a/Runtime/UIParticleProjectSettings.cs.meta b/Runtime/UIParticleProjectSettings.cs.meta
index 22e35afa..ca6db89f 100644
--- a/Runtime/UIParticleProjectSettings.cs.meta
+++ b/Runtime/UIParticleProjectSettings.cs.meta
@@ -5,7 +5,7 @@ MonoImporter:
   serializedVersion: 2
   defaultReferences: []
   executionOrder: 0
-  icon: {instanceID: 0}
+  icon: {fileID: 2800000, guid: 5f0675613942149309588d556e33d990, type: 3}
   userData: 
   assetBundleName: 
   assetBundleVariant: 

From 29eebf79fa863d1992856d2a371d671bbb86962d Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Fri, 14 Mar 2025 19:29:41 +0900
Subject: [PATCH 21/23] fix: IL2CPP build fails on older versions of Unity

---
 Runtime/Coffee.UIParticle.R.dll | Bin 3072 -> 3584 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/Runtime/Coffee.UIParticle.R.dll b/Runtime/Coffee.UIParticle.R.dll
index de59dad0bf2d83bfe317c10c555ff1eea6470ba3..bece387564a033a4e956799e352b1069579a10c2 100644
GIT binary patch
delta 442
zcmX|7&r1S96n<~k-E6bc7AnERt{yBDT20s8OGpGEL>G|?Iz>MaqC<J8OLz*ai!%Q}
zm!POlLU{AowS$K)g&hP>c~6MmtkyTY?|n1x@y(kl&z3{gilNWMx-di=!ulAR016$5
zApF$sH}H`oM&)V*AjCiAIN!pk>hVxjr%?D6#?Z^3F^WF^fnjWOWZJkb0U*@{D%@as
z$4A@9Ilw99ZK3m}<Kof5iRfrC0O1%Z<l&99U+C3BZiRA}Kd}X5{GA1N`$JC!t|5*J
zytupvL7ap&@>JmrI>Zme0yHxLY2CQ_Z#N1WA_RyP2okF>@9G3GUz3troI2V61H?ef
zHAA!4g@FsY46*|WkV~fRbiz(8nx?g%NF{8`F*7@smA0LX?W7&2-jJ5i-@NP39acB9
wm%VVa*=byGuUwjH4Q6z$zJ%6m#x#B6tz4|@>MPbKly8Yasvb~#STjd{0hZ%TV*mgE

delta 386
zcmZpWX^@!Ep?I`Jd>I22JYY~#;AS*nU|<0Xut5aRO<WnySTmWCQJpnGnSnuOvLKtz
z<VZ$!t}Dzy1qwjSGP#RUn~`nuHb!+uuF3Zpl^8cnW@HlP<p3&Rgc!mQF<Fr**zymM
zr(DOtkO3670b=FglA_GK^kR^rB}@=&l|zFWRsh)oAhqtHo-ROo$K<t4`izW|?=ne-
z-GrLS#*oRt#mL666ihlZd}rWi&;pvt#SqSL7)W*kNf3azfDuS@GJFJ*f<TguK@v!E
zF=&F>hCp(16tj^q7f?A9R0Bw>0E5CrMPU&g5E~3YX32qBn_n^8F$ys-Ox-3ZJ9(|F
x^M*{B!&zyko=vu3EfHD*3?~@a2Vw(_5d#LwRo2YSd>p@+nJyS_7G(Rz2mmi;L#6-#


From 63ec8f61e38190331c072a145df82c53c7e75d53 Mon Sep 17 00:00:00 2001
From: mob-sakai <12690315+mob-sakai@users.noreply.github.com>
Date: Fri, 14 Mar 2025 19:43:48 +0900
Subject: [PATCH 22/23] fix: NRE on enable

close #359
---
 Runtime/Utilities/ParticleSystemExtensions.cs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Runtime/Utilities/ParticleSystemExtensions.cs b/Runtime/Utilities/ParticleSystemExtensions.cs
index b9c08a01..709fce89 100644
--- a/Runtime/Utilities/ParticleSystemExtensions.cs
+++ b/Runtime/Utilities/ParticleSystemExtensions.cs
@@ -187,6 +187,8 @@ public static ParticleSystem GetMainEmitter(this ParticleSystem self, List<Parti
 
         public static bool IsSubEmitterOf(this ParticleSystem self, ParticleSystem parent)
         {
+            if (!self || !parent) return false;
+
             var subEmitters = parent.subEmitters;
             var count = subEmitters.subEmittersCount;
             for (var i = 0; i < count; i++)

From 4b98abd7469b10d55c9c623830cb6e1518f72731 Mon Sep 17 00:00:00 2001
From: semantic-release-bot <semantic-release-bot@martynus.net>
Date: Sat, 15 Mar 2025 07:59:37 +0000
Subject: [PATCH 23/23] chore(release): 4.11.2 [skip ci]

## [4.11.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.1...v4.11.2) (2025-03-15)

### Bug Fixes

* IL2CPP build fails on older versions of Unity ([0da6525](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0da652520cd165b43de7404c0b0ab1fbcf9349d1))
* NRE on enable ([0cff50e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0cff50ef696aa53fb7c46a9a737b7cf3a05b7b9b)), closes [#359](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/359)
---
 CHANGELOG.md | 8 ++++++++
 package.json | 2 +-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ec8a4902..59e1327d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+## [4.11.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.1...v4.11.2) (2025-03-15)
+
+
+### Bug Fixes
+
+* IL2CPP build fails on older versions of Unity ([0da6525](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0da652520cd165b43de7404c0b0ab1fbcf9349d1))
+* NRE on enable ([0cff50e](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/0cff50ef696aa53fb7c46a9a737b7cf3a05b7b9b)), closes [#359](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/359)
+
 ## [4.11.1](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.11.0...v4.11.1) (2025-02-21)
 
 
diff --git a/package.json b/package.json
index 0acfd33a..0f9b1467 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
   "name": "com.coffee.ui-particle",
   "displayName": "UI Particle",
   "description": "This package provides a component to render particle effects for uGUI.\nThe particle rendering is maskable and sortable, without the need for an extra Camera, RenderTexture, or Canvas.",
-  "version": "4.11.1",
+  "version": "4.11.2",
   "unity": "2018.2",
   "license": "MIT",
   "repository": {