You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-05-14 20:20:06 +00:00
Compare commits
15 Commits
v4.6.2
...
asset_upda
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36ab069eba | ||
|
|
66c76fb92b | ||
|
|
b3a49514b5 | ||
|
|
01e08eefbd | ||
|
|
a8af984d6f | ||
|
|
1b5c359058 | ||
|
|
ea043524c0 | ||
|
|
c37c014864 | ||
|
|
dc81428921 | ||
|
|
e82c833d04 | ||
|
|
2ec3748336 | ||
|
|
2eff411bd9 | ||
|
|
46c300b347 | ||
|
|
e1863f25d3 | ||
|
|
89289c052f |
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -43,7 +43,6 @@ jobs:
|
||||
echo "🔖 New release version: '${{ steps.release.outputs.new_release_version }}'" | tee -a $GITHUB_STEP_SUMMARY
|
||||
echo "🔖 New release channel: '${{ steps.release.outputs.new_release_channel }}'" | tee -a $GITHUB_STEP_SUMMARY
|
||||
echo "🔖 New release git tag: '${{ steps.release.outputs.new_release_git_tag }}'" | tee -a $GITHUB_STEP_SUMMARY
|
||||
echo '${{ steps.release.outputs.new_release_notes }}' | tee -a $GITHUB_STEP_SUMMARY
|
||||
|
||||
merge-to-develop:
|
||||
if: needs.release.outputs.released == 'true'
|
||||
|
||||
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -7,6 +7,7 @@ name: 🧪 Test
|
||||
env:
|
||||
# MINIMUM_VERSION: The minimum version of Unity.
|
||||
MINIMUM_VERSION: 2019.4
|
||||
# EXCLUDE_FILTER: The excluded versions of Unity.
|
||||
EXCLUDE_FILTER: '(2020.2.0)'
|
||||
|
||||
on:
|
||||
@@ -14,6 +15,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- develop_v5
|
||||
tags:
|
||||
- "!*"
|
||||
paths-ignore:
|
||||
@@ -35,7 +37,8 @@ jobs:
|
||||
run: |
|
||||
echo "==== Target Unity Versions ===="
|
||||
LATEST_VERSIONS=`npx unity-changeset list --versions --latest-patch --min ${MINIMUM_VERSION} --json --all`
|
||||
ADDITIONAL_VERSIONS=`npx unity-changeset list --versions --grep '0f' --min ${MINIMUM_VERSION} --json`
|
||||
# ADDITIONAL_VERSIONS=`npx unity-changeset list --versions --grep '0f' --min ${MINIMUM_VERSION} --json`
|
||||
ADDITIONAL_VERSIONS=[]
|
||||
|
||||
VERSIONS=`echo "[${LATEST_VERSIONS}, ${ADDITIONAL_VERSIONS}]" \
|
||||
| jq -c '[ flatten | sort | unique | .[] | select( test("${{ env.EXCLUDE_FILTER }}") | not ) ]'`
|
||||
@@ -54,6 +57,7 @@ jobs:
|
||||
needs: setup
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 4
|
||||
matrix:
|
||||
unityVersion: ${{ fromJson(needs.setup.outputs.unityVersions) }}
|
||||
steps:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a81f9cd434f104e1fad7ffa20eb7a3d4
|
||||
DefaultImporter:
|
||||
userData:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,10 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.unity.ide.rider": "3.0.27",
|
||||
"com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
||||
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||
"com.coffee.simple-scene-navigator": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/SceneNavigator",
|
||||
"com.coffee.sub-asset-editor": "https://github.com/mob-sakai/SubAssetEditor.git",
|
||||
"com.unity.test-framework": "1.1.33",
|
||||
"com.unity.modules.animation": "1.0.0",
|
||||
"com.unity.modules.physics": "1.0.0"
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"com.coffee.development": {
|
||||
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {},
|
||||
"hash": "41a1b604af8769b600d9c75db02ff35ec30611dc"
|
||||
},
|
||||
"com.coffee.nano-monitor": {
|
||||
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {
|
||||
"com.unity.ugui": "1.0.0"
|
||||
},
|
||||
"hash": "41a1b604af8769b600d9c75db02ff35ec30611dc"
|
||||
},
|
||||
"com.coffee.simple-scene-navigator": {
|
||||
"version": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/SceneNavigator",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {
|
||||
"com.unity.ugui": "1.0.0"
|
||||
},
|
||||
"hash": "41a1b604af8769b600d9c75db02ff35ec30611dc"
|
||||
},
|
||||
"com.coffee.sub-asset-editor": {
|
||||
"version": "https://github.com/mob-sakai/SubAssetEditor.git",
|
||||
"depth": 0,
|
||||
"source": "git",
|
||||
"dependencies": {},
|
||||
"hash": "01464178eec1e4dbe741c11c9baeb94a151c99ee"
|
||||
},
|
||||
"com.coffee.ui-particle": {
|
||||
"version": "file:src",
|
||||
"depth": 0,
|
||||
|
||||
1
Packages/src/.coffee.internal.sed
Normal file
1
Packages/src/.coffee.internal.sed
Normal file
@@ -0,0 +1 @@
|
||||
s/Coffee.Internal/Coffee.UIParticleInternal/g
|
||||
@@ -26,9 +26,9 @@ A clear and concise description of what you expected to happen.
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment (please complete the following information):**
|
||||
- Version [e.g. 1.0.0]
|
||||
- Version [e.g. 4.0.0]
|
||||
- Platform: [e.g. Editor(Windows/Mac), Standalone(Windows/Mac), iOS, Android, WebGL]
|
||||
- Unity version: [e.g. 2018.2.8f1]
|
||||
- Unity version: [e.g. 2022.3.0f1]
|
||||
- Build options: [e.g. IL2CPP, .Net 4.x, LWRP]
|
||||
|
||||
**Additional context**
|
||||
@@ -1,3 +1,21 @@
|
||||
## [4.6.4](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.3...v4.6.4) (2024-05-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* assertion failed on expression: 'ps->array_size()' ([1b5c359](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/1b5c359058289895caf5f245fe09abb643bc38eb)), closes [#278](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/278)
|
||||
* lost Material.mainTexture when using AnimatableProperties ([ea04352](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/ea043524c0b00f67cba26a1f9ea537ee4a56d6ff)), closes [#311](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/311)
|
||||
* remove unnecessary code ([c37c014](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/c37c01486499773e3d7e8296c95bb4c3fae94abb))
|
||||
|
||||
## [4.6.3](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.2...v4.6.3) (2024-04-04)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* if only Trail Material is used, it will not be displayed ([2eff411](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2eff411bd97eb4e6947d29a02b85b414bfdaee3a)), closes [#294](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/294)
|
||||
* if the UIParticle parents do not have Canvas, an exception is thrown in OnEnable ([e82c833](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/e82c833d04b819f103984931ba29a3616ef50908)), closes [#300](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/300)
|
||||
* particle size too small due to auto scaling ([2ec3748](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/2ec374833614d64406e7c3207ca5fe234a749dcb)), closes [#295](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/295)
|
||||
|
||||
## [4.6.2](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v4.6.1...v4.6.2) (2024-02-01)
|
||||
|
||||
|
||||
|
||||
3
Packages/src/Editor/AssetModification.meta
Normal file
3
Packages/src/Editor/AssetModification.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1006234332be4f329fc1830319b31aaa
|
||||
timeCreated: 1704502465
|
||||
@@ -0,0 +1,31 @@
|
||||
using Coffee.UIExtensions;
|
||||
using Coffee.UIParticleInternal.AssetModification;
|
||||
using UnityEditor;
|
||||
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal class UIParticleComponentModifier_AbsoluteMode : ComponentModifier<UIParticle>
|
||||
{
|
||||
protected override bool ModifyComponent(UIParticle uip, bool dryRun)
|
||||
{
|
||||
if (!uip.m_AbsoluteMode) return false;
|
||||
|
||||
uip.m_AbsoluteMode = false;
|
||||
uip.positionMode = UIParticle.PositionMode.Absolute;
|
||||
|
||||
if (!dryRun)
|
||||
{
|
||||
EditorUtility.SetDirty(uip);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string Report()
|
||||
{
|
||||
return " -> UIParticle.absoluteMode is obsolete. Use UIParticle.positionMode instead.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d188d31b140094ebc84a9caafbc7ac71
|
||||
guid: d3378b5e701274218b04cb5588b8a3bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,36 @@
|
||||
using Coffee.UIExtensions;
|
||||
using Coffee.UIParticleInternal.AssetModification;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal class UIParticleComponentModifier_AutoScaling : ComponentModifier<UIParticle>
|
||||
{
|
||||
protected override bool ModifyComponent(UIParticle uip, bool dryRun)
|
||||
{
|
||||
if (!uip.m_AutoScaling) return false;
|
||||
|
||||
uip.m_AutoScaling = false;
|
||||
uip.autoScalingMode = UIParticle.AutoScalingMode.Transform;
|
||||
uip.transform.localScale = Vector3.one;
|
||||
|
||||
if (!dryRun)
|
||||
{
|
||||
EditorUtility.SetDirty(uip);
|
||||
EditorUtility.SetDirty(uip.transform);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string Report()
|
||||
{
|
||||
return
|
||||
" -> UIParticle.ignoreCanvasScaler and UIParticle.autoScaling are obsolete." +
|
||||
" Use UIParticle.autoScalingMode instead.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0beae5bb1cb142b9ab90dc0d371f026
|
||||
guid: 3d6d0ca7ae8c641aa98b66fd91c05264
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,31 @@
|
||||
using Coffee.UIExtensions;
|
||||
using Coffee.UIParticleInternal.AssetModification;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
#pragma warning disable CS0612 // Type or member is obsolete
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal class UIParticleComponentModifier_IsTrail : ComponentModifier<UIParticle>
|
||||
{
|
||||
protected override bool ModifyComponent(UIParticle uip, bool dryRun)
|
||||
{
|
||||
if (!uip.m_IsTrail) return false;
|
||||
|
||||
if (!dryRun)
|
||||
{
|
||||
var go = uip.gameObject;
|
||||
Object.DestroyImmediate(uip);
|
||||
EditorUtility.SetDirty(go);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string Report()
|
||||
{
|
||||
return " -> UIParticle for trail is no longer needed. Removed.";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfbc9e244a2a040179e7f5b58ec0b978
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Coffee.UIParticleInternal.AssetModification;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal class UIParticleModifierRunner : Runner
|
||||
{
|
||||
public UIParticleModifierRunner()
|
||||
: base("UIParticle v5", new List<(string, Func<string, Modifier>)>
|
||||
{
|
||||
(".unity", x => new SceneModifier
|
||||
{
|
||||
path = x,
|
||||
componentModifiers = new IComponentModifier[]
|
||||
{
|
||||
new UIParticleRendererComponentModifier(),
|
||||
new UIParticleComponentModifier_AutoScaling(),
|
||||
new UIParticleComponentModifier_AbsoluteMode(),
|
||||
new UIParticleComponentModifier_IsTrail()
|
||||
}
|
||||
}),
|
||||
(".prefab", x => new PrefabModifier
|
||||
{
|
||||
path = x,
|
||||
componentModifiers = new IComponentModifier[]
|
||||
{
|
||||
new UIParticleRendererComponentModifier(),
|
||||
new UIParticleComponentModifier_AutoScaling(),
|
||||
new UIParticleComponentModifier_AbsoluteMode(),
|
||||
new UIParticleComponentModifier_IsTrail()
|
||||
}
|
||||
})
|
||||
})
|
||||
{
|
||||
}
|
||||
|
||||
[MenuItem("UIParticleModifierRunner/Run")]
|
||||
private static void Run()
|
||||
{
|
||||
new UIParticleModifierRunner().RunIfUserWantsTo();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edd678db452e49869caeca7e7d269e5d
|
||||
timeCreated: 1704502476
|
||||
@@ -0,0 +1,29 @@
|
||||
using Coffee.UIExtensions;
|
||||
using Coffee.UIParticleInternal.AssetModification;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal class UIParticleRendererComponentModifier : ComponentModifier<UIParticleRenderer>
|
||||
{
|
||||
protected override bool ModifyComponent(UIParticleRenderer c, bool dryRun)
|
||||
{
|
||||
if (c.hideFlags.HasFlag(HideFlags.DontSave | HideFlags.NotEditable)) return false;
|
||||
|
||||
if (!dryRun)
|
||||
{
|
||||
var go = c.gameObject;
|
||||
Object.DestroyImmediate(c);
|
||||
EditorUtility.SetDirty(go);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string Report()
|
||||
{
|
||||
return " -> UIParticleRenderer component is now auto-generated object. Remove them.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2a025408e4a7486a941102775d2c73b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/src/Editor/Internal.meta
Normal file
8
Packages/src/Editor/Internal.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e440931f761e4e888510a4e6045287a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/src/Editor/Internal/AssetModification.meta
Normal file
8
Packages/src/Editor/Internal/AssetModification.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 269bcefd175184eebbfa31421171fadf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal abstract class ComponentModifier<T> : IComponentModifier where T : Component
|
||||
{
|
||||
private static readonly List<T> s_Components = new List<T>();
|
||||
|
||||
public bool isModified { get; private set; }
|
||||
|
||||
public bool ModifyComponent(GameObject root, bool dryRun)
|
||||
{
|
||||
root.GetComponentsInChildren(true, s_Components);
|
||||
foreach (var c in s_Components)
|
||||
{
|
||||
if (PrefabUtility.IsPartOfAnyPrefab(c.gameObject)) continue;
|
||||
|
||||
if (ModifyComponent(c, dryRun))
|
||||
{
|
||||
isModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isModified;
|
||||
}
|
||||
|
||||
public abstract string Report();
|
||||
|
||||
protected abstract bool ModifyComponent(T component, bool dryRun);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 338da2d8cec784add924489fc4a7bb01
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal abstract class GameObjectModifier : Modifier
|
||||
{
|
||||
private static readonly StringBuilder s_ReportLog = new StringBuilder();
|
||||
public IComponentModifier[] componentModifiers;
|
||||
|
||||
protected bool ModifyGameObject(GameObject root, bool dryRun)
|
||||
{
|
||||
foreach (var modifier in componentModifiers)
|
||||
{
|
||||
modifier.ModifyComponent(root, dryRun);
|
||||
}
|
||||
|
||||
return componentModifiers.Any(x => x.isModified);
|
||||
}
|
||||
|
||||
protected override string ModificationReport()
|
||||
{
|
||||
if (!hasUpgraded) return string.Empty;
|
||||
|
||||
s_ReportLog.Length = 0;
|
||||
foreach (var componentModifier in componentModifiers)
|
||||
{
|
||||
if (componentModifier.isModified)
|
||||
{
|
||||
s_ReportLog.Append(componentModifier.Report());
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < s_ReportLog.Length)
|
||||
{
|
||||
s_ReportLog.Length--;
|
||||
}
|
||||
|
||||
return s_ReportLog.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f16bc447ca4934ca3b9329d1d870440a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal interface IComponentModifier
|
||||
{
|
||||
bool isModified { get; }
|
||||
bool ModifyComponent(GameObject root, bool dryRun);
|
||||
string Report();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e50323d0799f4daf8ef476f7bf403a4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal interface ITextModifier
|
||||
{
|
||||
bool ModifyText(StringBuilder sb, string text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ad967b4f039b4deba09ed0c1401cf83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
41
Packages/src/Editor/Internal/AssetModification/Modifier.cs
Normal file
41
Packages/src/Editor/Internal/AssetModification/Modifier.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal abstract class Modifier
|
||||
{
|
||||
private string _error;
|
||||
public string path;
|
||||
|
||||
protected abstract string id { get; }
|
||||
protected bool hasUpgraded { private set; get; }
|
||||
|
||||
public void Modify(bool dryRun)
|
||||
{
|
||||
try
|
||||
{
|
||||
hasUpgraded = RunModify(dryRun);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_error = e.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetModificationReport()
|
||||
{
|
||||
return !string.IsNullOrEmpty(_error)
|
||||
? $"<b><color=red>[{id} (Error)]</color> {path}</b> {_error}\n"
|
||||
: hasUpgraded
|
||||
? $"<b><color=green>[{id}]</color> {path}</b> {ModificationReport()}\n"
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
protected abstract bool RunModify(bool dryRun);
|
||||
|
||||
protected virtual string ModificationReport()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c716fe53d75054d309923c577f5059a4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal class PrefabModifier : GameObjectModifier
|
||||
{
|
||||
protected override string id => "Prefab";
|
||||
|
||||
protected override bool RunModify(bool dryRun)
|
||||
{
|
||||
using (var scope = new EditScope(path))
|
||||
{
|
||||
var changed = ModifyGameObject(scope.root, dryRun);
|
||||
|
||||
if (!dryRun && changed)
|
||||
{
|
||||
scope.Save();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct EditScope : IDisposable
|
||||
{
|
||||
private readonly string _path;
|
||||
public readonly GameObject root;
|
||||
|
||||
public EditScope(string path)
|
||||
{
|
||||
_path = path;
|
||||
root = PrefabUtility.LoadPrefabContents(path);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PrefabUtility.UnloadPrefabContents(root);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
PrefabUtility.SaveAsPrefabAsset(root, _path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a50643d4fde75458cae1f0d4ef9549ad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
97
Packages/src/Editor/Internal/AssetModification/Runner.cs
Normal file
97
Packages/src/Editor/Internal/AssetModification/Runner.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal class Runner
|
||||
{
|
||||
private readonly List<(string ext, Func<string, Modifier> create)> _factory;
|
||||
private readonly string _name;
|
||||
|
||||
protected Runner(string name, List<(string ext, Func<string, Modifier> create)> factory)
|
||||
{
|
||||
_name = name;
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
private Modifier CreateFromPath(string assetPath)
|
||||
{
|
||||
var ext = Path.GetExtension(assetPath);
|
||||
return _factory
|
||||
.FirstOrDefault(x => x.ext == ext)
|
||||
.create?.Invoke(assetPath);
|
||||
}
|
||||
|
||||
private Modifier[] GetModifiers(string[] assetPaths)
|
||||
{
|
||||
return assetPaths
|
||||
.Where(x => x.StartsWith("Assets/", StringComparison.Ordinal))
|
||||
.Select(CreateFromPath)
|
||||
.Where(x => x != null)
|
||||
.OrderBy(x => Path.GetExtension(x.path))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public void RunIfUserWantsTo()
|
||||
{
|
||||
var select = EditorUtility.DisplayDialogComplex($"Upgrade {_name}",
|
||||
"Upgrade all assets in this project?\n\n" +
|
||||
"'Go Ahead': Upgrades all assets in this project using the old APIs. You should make a backup before proceeding.\n\n" +
|
||||
"'Dry Run': Outputs the upgrade summary to the console without changing.", "I Made a Backup. Go Ahead!",
|
||||
"No Thanks", "Dry Run");
|
||||
if (select == 1) return;
|
||||
|
||||
if (!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) return;
|
||||
|
||||
var assetPaths = AssetDatabase.GetAllAssetPaths();
|
||||
var dryRun = select == 2;
|
||||
Run(assetPaths, dryRun);
|
||||
}
|
||||
|
||||
public void Run(string[] assetPaths, bool dryRun)
|
||||
{
|
||||
var modifiers = GetModifiers(assetPaths);
|
||||
var canceled = false;
|
||||
|
||||
try
|
||||
{
|
||||
AssetDatabase.StartAssetEditing();
|
||||
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
|
||||
|
||||
for (var i = 0; i < modifiers.Length; i++)
|
||||
{
|
||||
var percentage = (float)i / modifiers.Length;
|
||||
var m = modifiers[i];
|
||||
if (EditorUtility.DisplayCancelableProgressBar("Upgrading...", m.path, percentage))
|
||||
{
|
||||
canceled = true;
|
||||
break;
|
||||
}
|
||||
|
||||
m.Modify(dryRun);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(dryRun ? "<b>[DryRun]</b> " : "");
|
||||
sb.AppendLine($"<b>Modify '{_name}' is {(canceled ? "canceled" : "completed")}.</b>");
|
||||
sb.AppendLine("==== Modifications ====");
|
||||
Debug.Log(modifiers.Aggregate(sb, (x, m) => x.Append(m.GetModificationReport())));
|
||||
EditorUtility.ClearProgressBar();
|
||||
AssetDatabase.StopAssetEditing();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f28067cf4bfca4d92bd5262ac5c7a652
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal class SceneModifier : GameObjectModifier
|
||||
{
|
||||
protected override string id => "Scene";
|
||||
|
||||
protected override bool RunModify(bool dryRun)
|
||||
{
|
||||
using (var scope = new EditScope(path))
|
||||
{
|
||||
var changed = false;
|
||||
foreach (var root in scope.scene.GetRootGameObjects())
|
||||
{
|
||||
if (ModifyGameObject(root, dryRun))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dryRun && changed)
|
||||
{
|
||||
scope.Save();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly struct EditScope : IDisposable
|
||||
{
|
||||
public readonly Scene scene;
|
||||
|
||||
public EditScope(string path)
|
||||
{
|
||||
scene = EditorSceneManager.OpenScene(path, OpenSceneMode.Additive);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
EditorSceneManager.CloseScene(scene, true);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
EditorSceneManager.SaveScene(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6764c0c6fd61a4f66a8b0e3467be420d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal class TextAssetModifier : Modifier
|
||||
{
|
||||
public ITextModifier[] textModifiers;
|
||||
protected override string id => "Text";
|
||||
protected virtual string savePath => path;
|
||||
|
||||
protected override bool RunModify(bool dryRun)
|
||||
{
|
||||
var changed = false;
|
||||
using (var scope = new EditScope(path, savePath))
|
||||
{
|
||||
foreach (var line in scope.lines)
|
||||
{
|
||||
if (ModifyLine(scope.sb, line))
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
scope.sb.AppendLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dryRun && changed)
|
||||
{
|
||||
scope.Save();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ModifyLine(StringBuilder sb, string line)
|
||||
{
|
||||
foreach (var modifier in textModifiers)
|
||||
{
|
||||
if (modifier.ModifyText(sb, line))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private readonly struct EditScope : IDisposable
|
||||
{
|
||||
private static readonly StringBuilder s_File = new StringBuilder();
|
||||
private readonly string _path;
|
||||
private readonly string _savePath;
|
||||
public IEnumerable<string> lines => File.ReadLines(_path);
|
||||
public StringBuilder sb => s_File;
|
||||
|
||||
public EditScope(string path, string savePath)
|
||||
{
|
||||
s_File.Length = 0;
|
||||
_path = path;
|
||||
_savePath = savePath;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
File.WriteAllText(_savePath, sb.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 431e5b95f2f5c4f19926a7fc5342e118
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Coffee.UIParticleInternal.AssetModification
|
||||
{
|
||||
internal class TextReplaceModifier : ITextModifier
|
||||
{
|
||||
private readonly Regex _pattern;
|
||||
private readonly string _replace;
|
||||
|
||||
public TextReplaceModifier(string pattern, string replace)
|
||||
{
|
||||
_pattern = new Regex(pattern);
|
||||
_replace = replace;
|
||||
}
|
||||
|
||||
public bool ModifyText(StringBuilder sb, string text)
|
||||
{
|
||||
if (!_pattern.IsMatch(text)) return false;
|
||||
|
||||
sb.AppendLine(_pattern.Replace(text, _replace));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afc6ba9550e5e4c25951b03db43a4fd0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -6,7 +6,6 @@ using UnityEditor.UI;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Coffee.UIParticleExtensions;
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using UnityEditor.Overlays;
|
||||
#else
|
||||
|
||||
8
Packages/src/Runtime/Internal.meta
Normal file
8
Packages/src/Runtime/Internal.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53aa3f36032944b3fb1455e774c52396
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/src/Runtime/Internal/Extensions.meta
Normal file
8
Packages/src/Runtime/Internal/Extensions.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8cf8018dee45a4c42a19eec890eaa5b1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
134
Packages/src/Runtime/Internal/Extensions/CanvasExtensions.cs
Normal file
134
Packages/src/Runtime/Internal/Extensions/CanvasExtensions.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
#if UNITY_2021_3_0 || UNITY_2021_3_1 || UNITY_2021_3_2 || UNITY_2021_3_3 || UNITY_2021_3_4 || UNITY_2021_3_5 || UNITY_2021_3_6 || UNITY_2021_3_7 || UNITY_2021_3_8 || UNITY_2021_3_9
|
||||
#elif UNITY_2021_3_10 || UNITY_2021_3_11 || UNITY_2021_3_12 || UNITY_2021_3_13 || UNITY_2021_3_14 || UNITY_2021_3_15 || UNITY_2021_3_16 || UNITY_2021_3_17 || UNITY_2021_3_18 || UNITY_2021_3_19
|
||||
#elif UNITY_2021_3_20 || UNITY_2021_3_21 || UNITY_2021_3_22 || UNITY_2021_3_23 || UNITY_2021_3_24 || UNITY_2021_3_25 || UNITY_2021_3_26 || UNITY_2021_3_27 || UNITY_2021_3_28 || UNITY_2021_3_29
|
||||
#elif UNITY_2021_3_30 || UNITY_2021_3_31 || UNITY_2021_3_32 || UNITY_2021_3_33
|
||||
#elif UNITY_2022_2_0 || UNITY_2022_2_1 || UNITY_2022_2_2 || UNITY_2022_2_3 || UNITY_2022_2_4 || UNITY_2022_2_5 || UNITY_2022_2_6 || UNITY_2022_2_7 || UNITY_2022_2_8 || UNITY_2022_2_9
|
||||
#elif UNITY_2022_2_10 || UNITY_2022_2_11 || UNITY_2022_2_12 || UNITY_2022_2_13 || UNITY_2022_2_14
|
||||
#elif UNITY_2021_3 || UNITY_2022_2 || UNITY_2022_3 || UNITY_2023_2_OR_NEWER
|
||||
#define CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||
#endif
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
#if UNITY_MODULE_VR
|
||||
using UnityEngine.XR;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class CanvasExtensions
|
||||
{
|
||||
public static bool ShouldGammaToLinearInShader(this Canvas canvas)
|
||||
{
|
||||
return QualitySettings.activeColorSpace == ColorSpace.Linear &&
|
||||
#if CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||
canvas.vertexColorAlwaysGammaSpace;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool ShouldGammaToLinearInMesh(this Canvas canvas)
|
||||
{
|
||||
return QualitySettings.activeColorSpace == ColorSpace.Linear &&
|
||||
#if CANVAS_SUPPORT_ALWAYS_GAMMA
|
||||
!canvas.vertexColorAlwaysGammaSpace;
|
||||
#else
|
||||
true;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool IsStereoCanvas(this Canvas canvas)
|
||||
{
|
||||
#if UNITY_MODULE_VR
|
||||
if (FrameCache.TryGet<bool>(canvas, nameof(IsStereoCanvas), out var stereo)) return stereo;
|
||||
|
||||
stereo =
|
||||
canvas != null && canvas.renderMode != RenderMode.ScreenSpaceOverlay && canvas.worldCamera != null
|
||||
&& XRSettings.enabled && !string.IsNullOrEmpty(XRSettings.loadedDeviceName);
|
||||
FrameCache.Set(canvas, nameof(IsStereoCanvas), stereo);
|
||||
return stereo;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view-projection matrix for a Canvas.
|
||||
/// </summary>
|
||||
public static void GetViewProjectionMatrix(this Canvas canvas, out Matrix4x4 vpMatrix)
|
||||
{
|
||||
canvas.GetViewProjectionMatrix(Camera.MonoOrStereoscopicEye.Mono, out vpMatrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view-projection matrix for a Canvas.
|
||||
/// </summary>
|
||||
public static void GetViewProjectionMatrix(this Canvas canvas, Camera.MonoOrStereoscopicEye eye,
|
||||
out Matrix4x4 vpMatrix)
|
||||
{
|
||||
if (FrameCache.TryGet(canvas, nameof(GetViewProjectionMatrix), out vpMatrix)) return;
|
||||
|
||||
canvas.GetViewProjectionMatrix(eye, out var viewMatrix, out var projectionMatrix);
|
||||
vpMatrix = viewMatrix * projectionMatrix;
|
||||
FrameCache.Set(canvas, nameof(GetViewProjectionMatrix), vpMatrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view and projection matrices for a Canvas.
|
||||
/// </summary>
|
||||
public static void GetViewProjectionMatrix(this Canvas canvas, out Matrix4x4 vMatrix, out Matrix4x4 pMatrix)
|
||||
{
|
||||
canvas.GetViewProjectionMatrix(Camera.MonoOrStereoscopicEye.Mono, out vMatrix, out pMatrix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the view and projection matrices for a Canvas.
|
||||
/// </summary>
|
||||
public static void GetViewProjectionMatrix(this Canvas canvas, Camera.MonoOrStereoscopicEye eye,
|
||||
out Matrix4x4 vMatrix, out Matrix4x4 pMatrix)
|
||||
{
|
||||
if (FrameCache.TryGet(canvas, "GetViewMatrix", (int)eye, out vMatrix) &&
|
||||
FrameCache.TryGet(canvas, "GetProjectionMatrix", (int)eye, out pMatrix))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get view and projection matrices.
|
||||
Profiler.BeginSample("(COF)[CanvasExt] GetViewProjectionMatrix");
|
||||
var rootCanvas = canvas.rootCanvas;
|
||||
var cam = rootCanvas.worldCamera;
|
||||
if (rootCanvas && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay && cam)
|
||||
{
|
||||
if (eye == Camera.MonoOrStereoscopicEye.Mono)
|
||||
{
|
||||
vMatrix = cam.worldToCameraMatrix;
|
||||
pMatrix = GL.GetGPUProjectionMatrix(cam.projectionMatrix, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
pMatrix = cam.GetStereoProjectionMatrix((Camera.StereoscopicEye)eye);
|
||||
vMatrix = cam.GetStereoViewMatrix((Camera.StereoscopicEye)eye);
|
||||
pMatrix = GL.GetGPUProjectionMatrix(pMatrix, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var pos = rootCanvas.transform.position;
|
||||
vMatrix = Matrix4x4.TRS(
|
||||
new Vector3(-pos.x, -pos.y, -1000),
|
||||
Quaternion.identity,
|
||||
new Vector3(1, 1, -1f));
|
||||
pMatrix = Matrix4x4.TRS(
|
||||
new Vector3(0, 0, -1),
|
||||
Quaternion.identity,
|
||||
new Vector3(1 / pos.x, 1 / pos.y, -2 / 10000f));
|
||||
}
|
||||
|
||||
FrameCache.Set(canvas, "GetViewMatrix", (int)eye, vMatrix);
|
||||
FrameCache.Set(canvas, "GetProjectionMatrix", (int)eye, pMatrix);
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9dd767b8c0f95478386e7d5079cd44df
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Color32Extensions
|
||||
{
|
||||
private static readonly List<Color32> s_Colors = new List<Color32>();
|
||||
private static byte[] s_LinearToGammaLut;
|
||||
private static byte[] s_GammaToLinearLut;
|
||||
|
||||
public static byte LinearToGamma(this byte self)
|
||||
{
|
||||
if (s_LinearToGammaLut == null)
|
||||
{
|
||||
s_LinearToGammaLut = new byte[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
s_LinearToGammaLut[i] = (byte)(Mathf.LinearToGammaSpace(i / 255f) * 255f);
|
||||
}
|
||||
}
|
||||
|
||||
return s_LinearToGammaLut[self];
|
||||
}
|
||||
|
||||
public static byte GammaToLinear(this byte self)
|
||||
{
|
||||
if (s_GammaToLinearLut == null)
|
||||
{
|
||||
s_GammaToLinearLut = new byte[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
s_GammaToLinearLut[i] = (byte)(Mathf.GammaToLinearSpace(i / 255f) * 255f);
|
||||
}
|
||||
}
|
||||
|
||||
return s_GammaToLinearLut[self];
|
||||
}
|
||||
|
||||
public static void LinearToGamma(this Mesh self)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[ColorExt] LinearToGamma (Mesh)");
|
||||
self.GetColors(s_Colors);
|
||||
var count = s_Colors.Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var c = s_Colors[i];
|
||||
c.r = c.r.LinearToGamma();
|
||||
c.g = c.g.LinearToGamma();
|
||||
c.b = c.b.LinearToGamma();
|
||||
s_Colors[i] = c;
|
||||
}
|
||||
|
||||
self.SetColors(s_Colors);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
public static void GammaToLinear(this Mesh self)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[ColorExt] GammaToLinear (Mesh)");
|
||||
self.GetColors(s_Colors);
|
||||
var count = s_Colors.Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var c = s_Colors[i];
|
||||
c.r = c.r.GammaToLinear();
|
||||
c.g = c.g.GammaToLinear();
|
||||
c.b = c.b.GammaToLinear();
|
||||
s_Colors[i] = c;
|
||||
}
|
||||
|
||||
self.SetColors(s_Colors);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0ef431b9df32c410ea5fa46be81def6b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
155
Packages/src/Runtime/Internal/Extensions/ComponentExtensions.cs
Normal file
155
Packages/src/Runtime/Internal/Extensions/ComponentExtensions.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for Component class.
|
||||
/// </summary>
|
||||
internal static class ComponentExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get or add a component of a specific type to a GameObject.
|
||||
/// </summary>
|
||||
public static T GetOrAddComponent<T>(this Component self) where T : Component
|
||||
{
|
||||
if (!self) return null;
|
||||
return self.TryGetComponent<T>(out var component)
|
||||
? component
|
||||
: self.gameObject.AddComponent<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the root component of a specific type in the hierarchy of a GameObject.
|
||||
/// </summary>
|
||||
public static T GetRootComponent<T>(this Component self) where T : Component
|
||||
{
|
||||
T component = null;
|
||||
var transform = self.transform;
|
||||
while (transform)
|
||||
{
|
||||
if (transform.TryGetComponent<T>(out var c))
|
||||
{
|
||||
component = c;
|
||||
}
|
||||
|
||||
transform = transform.parent;
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a component of a specific type in the parent hierarchy of a GameObject.
|
||||
/// </summary>
|
||||
public static T GetComponentInParent<T>(this Component self, bool includeSelf, Transform stopAfter,
|
||||
Predicate<T> valid)
|
||||
where T : Component
|
||||
{
|
||||
var tr = includeSelf ? self.transform : self.transform.parent;
|
||||
while (tr)
|
||||
{
|
||||
if (tr.TryGetComponent<T>(out var c) && valid(c)) return c;
|
||||
if (tr == stopAfter) return null;
|
||||
tr = tr.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a component of a specific type to the children of a GameObject.
|
||||
/// </summary>
|
||||
public static void AddComponentOnChildren<T>(this Component self, HideFlags hideFlags, bool includeSelf)
|
||||
where T : Component
|
||||
{
|
||||
if (self == null) return;
|
||||
|
||||
Profiler.BeginSample("(COF)[ComponentExt] AddComponentOnChildren > Self");
|
||||
if (includeSelf && !self.TryGetComponent<T>(out _))
|
||||
{
|
||||
var c = self.gameObject.AddComponent<T>();
|
||||
c.hideFlags = hideFlags;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
var c = child.gameObject.AddComponent<T>();
|
||||
c.hideFlags = hideFlags;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (!self) return null;
|
||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||
|
||||
var current = self.transform;
|
||||
while (current)
|
||||
{
|
||||
if (current.TryGetComponent<T>(out var c)) return c;
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Verify whether it can be converted to the specified component.
|
||||
/// </summary>
|
||||
internal static bool CanConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||
{
|
||||
return context && context.GetType() != typeof(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert to the specified component.
|
||||
/// </summary>
|
||||
internal static void ConvertTo<T>(this Object context) where T : MonoBehaviour
|
||||
{
|
||||
var target = context as MonoBehaviour;
|
||||
if (target == null) return;
|
||||
|
||||
var so = new SerializedObject(target);
|
||||
so.Update();
|
||||
|
||||
var oldEnable = target.enabled;
|
||||
target.enabled = false;
|
||||
|
||||
// Find MonoScript of the specified component.
|
||||
foreach (var script in Resources.FindObjectsOfTypeAll<MonoScript>())
|
||||
{
|
||||
if (script.GetClass() != typeof(T))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set 'm_Script' to convert.
|
||||
so.FindProperty("m_Script").objectReferenceValue = script;
|
||||
so.ApplyModifiedProperties();
|
||||
break;
|
||||
}
|
||||
|
||||
if (so.targetObject is MonoBehaviour mb)
|
||||
{
|
||||
mb.enabled = oldEnable;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8455ee485a5ee4cacbdf558f66af65fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
Packages/src/Runtime/Internal/Extensions/ListExtensions.cs
Normal file
19
Packages/src/Runtime/Internal/Extensions/ListExtensions.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for Component class.
|
||||
/// </summary>
|
||||
internal static class ListExtensions
|
||||
{
|
||||
public static void RemoveAtFast<T>(this List<T> self, int index)
|
||||
{
|
||||
if (self == null) return;
|
||||
|
||||
var lastIndex = self.Count - 1;
|
||||
self[index] = self[lastIndex];
|
||||
self.RemoveAt(lastIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 833553390099d40c9b212823f0852c46
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
48
Packages/src/Runtime/Internal/Extensions/Misc.cs
Normal file
48
Packages/src/Runtime/Internal/Extensions/Misc.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Diagnostics;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Misc
|
||||
{
|
||||
public static void Destroy(Object obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyImmediate(Object obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isEditor)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("UNITY_EDITOR")]
|
||||
public static void SetDirty(Object obj)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!obj) return;
|
||||
EditorUtility.SetDirty(obj);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Packages/src/Runtime/Internal/Extensions/Misc.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Extensions/Misc.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39ed6a6b0a72e482488bd298b2ae762e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
58
Packages/src/Runtime/Internal/Extensions/SpriteExtensions.cs
Normal file
58
Packages/src/Runtime/Internal/Extensions/SpriteExtensions.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.U2D;
|
||||
#if UNITY_EDITOR
|
||||
using System.Reflection;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for Sprite class.
|
||||
/// </summary>
|
||||
internal static class SpriteExtensions
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
private static readonly Type s_SpriteEditorExtensionType =
|
||||
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 MethodInfo s_GetActiveAtlasMethod = s_SpriteEditorExtensionType
|
||||
.GetMethod("GetActiveAtlas", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
/// <summary>
|
||||
/// Get the actual texture of a sprite in play mode or edit mode.
|
||||
/// </summary>
|
||||
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;
|
||||
return ret ? ret : self.texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the active sprite atlas of a sprite in play mode or edit mode.
|
||||
/// </summary>
|
||||
public static SpriteAtlas GetActiveAtlas(this Sprite self)
|
||||
{
|
||||
if (!self) return null;
|
||||
|
||||
return s_GetActiveAtlasMethod.Invoke(null, new object[] { self }) as SpriteAtlas;
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Get the actual texture of a sprite in play mode.
|
||||
/// </summary>
|
||||
internal static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
return self ? self.texture : null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7a2e11131111447cb7fc0394a14da65
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,46 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Vector3Extensions
|
||||
{
|
||||
public static Vector3 Inverse(this Vector3 self)
|
||||
{
|
||||
self.x = Mathf.Approximately(self.x, 0) ? 1 : 1 / self.x;
|
||||
self.y = Mathf.Approximately(self.y, 0) ? 1 : 1 / self.y;
|
||||
self.z = Mathf.Approximately(self.z, 0) ? 1 : 1 / self.z;
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1)
|
||||
{
|
||||
self.Scale(other1);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2)
|
||||
{
|
||||
self.Scale(other1);
|
||||
self.Scale(other2);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2, Vector3 other3)
|
||||
{
|
||||
self.Scale(other1);
|
||||
self.Scale(other2);
|
||||
self.Scale(other3);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static bool IsVisible(this Vector3 self)
|
||||
{
|
||||
return 0 < Mathf.Abs(self.x * self.y * self.z);
|
||||
}
|
||||
|
||||
public static bool IsVisible2D(this Vector3 self)
|
||||
{
|
||||
return 0 < Mathf.Abs(self.x * self.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a7b5fb989e4b48c8bc7ecce834060f5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/src/Runtime/Internal/ProjectSettings.meta
Normal file
8
Packages/src/Runtime/Internal/ProjectSettings.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 398e06c9985ad4291a95f0749c2927fb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
public abstract class PreloadedProjectSettings : ScriptableObject
|
||||
#if UNITY_EDITOR
|
||||
, IPreprocessBuildWithReport
|
||||
{
|
||||
int IOrderedCallback.callbackOrder => 0;
|
||||
|
||||
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
[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)
|
||||
{
|
||||
defaultSettings = t.GetProperty("instance", flags)
|
||||
?.GetValue(null, null) as PreloadedProjectSettings;
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
else if (GetPreloadedSettings(t).Length != 1)
|
||||
{
|
||||
SetDefaultSettings(defaultSettings);
|
||||
}
|
||||
}
|
||||
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
}
|
||||
|
||||
protected static string GetDefaultName(Type type, bool nicify)
|
||||
{
|
||||
var typeName = type.Name.Replace("ProjectSettings", "");
|
||||
return nicify
|
||||
? ObjectNames.NicifyVariableName(typeName)
|
||||
: typeName;
|
||||
}
|
||||
|
||||
private static Object[] GetPreloadedSettings(Type type)
|
||||
{
|
||||
return PlayerSettings.GetPreloadedAssets()
|
||||
.Where(x => x && x.GetType() == type)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
||||
{
|
||||
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
||||
?? AssetDatabase.FindAssets($"t:{nameof(PreloadedProjectSettings)}")
|
||||
.Select(AssetDatabase.GUIDToAssetPath)
|
||||
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
||||
.FirstOrDefault(x => x && x.GetType() == type);
|
||||
}
|
||||
|
||||
protected static void SetDefaultSettings(PreloadedProjectSettings asset)
|
||||
{
|
||||
var type = asset.GetType();
|
||||
if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(asset)))
|
||||
{
|
||||
if (!AssetDatabase.IsValidFolder("Assets/ProjectSettings"))
|
||||
{
|
||||
AssetDatabase.CreateFolder("Assets", "ProjectSettings");
|
||||
}
|
||||
|
||||
var assetPath = $"Assets/ProjectSettings/{GetDefaultName(type, false)}.asset";
|
||||
assetPath = AssetDatabase.GenerateUniqueAssetPath(assetPath);
|
||||
AssetDatabase.CreateAsset(asset, assetPath);
|
||||
}
|
||||
|
||||
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
|
||||
var projectSettings = GetPreloadedSettings(type);
|
||||
PlayerSettings.SetPreloadedAssets(preloadedAssets
|
||||
.Where(x => x)
|
||||
.Except(projectSettings.Except(new[] { asset }))
|
||||
.Append(asset)
|
||||
.Distinct()
|
||||
.ToArray());
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
public abstract class PreloadedProjectSettings<T> : PreloadedProjectSettings
|
||||
where T : PreloadedProjectSettings<T>
|
||||
{
|
||||
private static T s_Instance;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private string _jsonText;
|
||||
|
||||
public static T instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_Instance) return s_Instance;
|
||||
|
||||
s_Instance = GetDefaultSettings(typeof(T)) as T;
|
||||
if (s_Instance) return s_Instance;
|
||||
|
||||
s_Instance = CreateInstance<T>();
|
||||
if (!s_Instance)
|
||||
{
|
||||
s_Instance = null;
|
||||
return s_Instance;
|
||||
}
|
||||
|
||||
SetDefaultSettings(s_Instance);
|
||||
return s_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case PlayModeStateChange.ExitingEditMode:
|
||||
_jsonText = EditorJsonUtility.ToJson(this);
|
||||
break;
|
||||
case PlayModeStateChange.ExitingPlayMode:
|
||||
if (_jsonText != null)
|
||||
{
|
||||
EditorJsonUtility.FromJsonOverwrite(_jsonText, this);
|
||||
_jsonText = null;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public static T instance => s_Instance ? s_Instance : s_Instance = CreateInstance<T>();
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the object becomes enabled and active.
|
||||
/// </summary>
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var isDefaultSettings = !s_Instance || s_Instance == this || GetDefaultSettings(typeof(T)) == this;
|
||||
if (!isDefaultSettings)
|
||||
{
|
||||
DestroyImmediate(this, true);
|
||||
return;
|
||||
}
|
||||
|
||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||
#endif
|
||||
|
||||
if (s_Instance) return;
|
||||
s_Instance = this as T;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function is called when the behaviour becomes disabled.
|
||||
/// </summary>
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||
#endif
|
||||
if (s_Instance != this) return;
|
||||
|
||||
s_Instance = null;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected sealed class PreloadedProjectSettingsProvider : SettingsProvider
|
||||
{
|
||||
private Editor _editor;
|
||||
private PreloadedProjectSettings<T> _target;
|
||||
|
||||
public PreloadedProjectSettingsProvider(string path) : base(path, SettingsScope.Project)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnGUI(string searchContext)
|
||||
{
|
||||
if (!_target)
|
||||
{
|
||||
if (_editor)
|
||||
{
|
||||
DestroyImmediate(_editor);
|
||||
_editor = null;
|
||||
}
|
||||
|
||||
_target = instance;
|
||||
_editor = Editor.CreateEditor(_target);
|
||||
}
|
||||
|
||||
_editor.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 790ea008741dc411497c8794745319eb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/src/Runtime/Internal/Utilities.meta
Normal file
8
Packages/src/Runtime/Internal/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b2877595f27c4a70a426991d515434f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
81
Packages/src/Runtime/Internal/Utilities/FastAction.cs
Executable file
81
Packages/src/Runtime/Internal/Utilities/FastAction.cs
Executable file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for a fast action.
|
||||
/// </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 readonly LinkedList<T> _delegates = new LinkedList<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Adds a delegate to the action.
|
||||
/// </summary>
|
||||
public void Add(T rhs)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[FastAction] Add Action");
|
||||
var node = s_NodePool.Rent();
|
||||
node.Value = rhs;
|
||||
_delegates.AddLast(node);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a delegate from the action.
|
||||
/// </summary>
|
||||
public void Remove(T rhs)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[FastAction] Remove Action");
|
||||
var node = _delegates.Find(rhs);
|
||||
if (node != null)
|
||||
{
|
||||
_delegates.Remove(node);
|
||||
s_NodePool.Return(ref node);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the action with a callback function.
|
||||
/// </summary>
|
||||
protected void Invoke(Action<T> callback)
|
||||
{
|
||||
var node = _delegates.First;
|
||||
while (node != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback(node.Value);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A fast action without parameters.
|
||||
/// </summary>
|
||||
internal class FastAction : FastActionBase<Action>
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoke all the registered delegates.
|
||||
/// </summary>
|
||||
public void Invoke()
|
||||
{
|
||||
Invoke(action => action.Invoke());
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Packages/src/Runtime/Internal/Utilities/FastAction.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/FastAction.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7c8c268a827b4787a8e050f1fe95ad5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
102
Packages/src/Runtime/Internal/Utilities/FrameCache.cs
Normal file
102
Packages/src/Runtime/Internal/Utilities/FrameCache.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class FrameCache
|
||||
{
|
||||
private static readonly Dictionary<Type, IFrameCache> s_Caches = new Dictionary<Type, IFrameCache>();
|
||||
|
||||
static FrameCache()
|
||||
{
|
||||
s_Caches.Clear();
|
||||
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void Clear()
|
||||
{
|
||||
s_Caches.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||
/// </summary>
|
||||
public static bool TryGet<T>(object key1, string key2, out T result)
|
||||
{
|
||||
return GetFrameCache<T>().TryGet((key1.GetHashCode(), key2.GetHashCode()), out result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||
/// </summary>
|
||||
public static bool TryGet<T>(object key1, string key2, int key3, out T result)
|
||||
{
|
||||
return GetFrameCache<T>().TryGet((key1.GetHashCode(), key2.GetHashCode() + key3), out result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value in the frame cache with a specified key.
|
||||
/// </summary>
|
||||
public static void Set<T>(object key1, string key2, T result)
|
||||
{
|
||||
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode()), result);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value in the frame cache with a specified key.
|
||||
/// </summary>
|
||||
public static void Set<T>(object key1, string key2, int key3, T result)
|
||||
{
|
||||
GetFrameCache<T>().Set((key1.GetHashCode(), key2.GetHashCode() + key3), result);
|
||||
}
|
||||
|
||||
private static void ClearAllCache()
|
||||
{
|
||||
foreach (var cache in s_Caches.Values)
|
||||
{
|
||||
cache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static FrameCacheContainer<T> GetFrameCache<T>()
|
||||
{
|
||||
var t = typeof(T);
|
||||
if (s_Caches.TryGetValue(t, out var frameCache)) return frameCache as FrameCacheContainer<T>;
|
||||
|
||||
frameCache = new FrameCacheContainer<T>();
|
||||
s_Caches.Add(t, frameCache);
|
||||
|
||||
return (FrameCacheContainer<T>)frameCache;
|
||||
}
|
||||
|
||||
private interface IFrameCache
|
||||
{
|
||||
void Clear();
|
||||
}
|
||||
|
||||
private class FrameCacheContainer<T> : IFrameCache
|
||||
{
|
||||
private readonly Dictionary<(int, int), T> _caches = new Dictionary<(int, int), T>();
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_caches.Clear();
|
||||
}
|
||||
|
||||
public bool TryGet((int, int) key, out T result)
|
||||
{
|
||||
return _caches.TryGetValue(key, out result);
|
||||
}
|
||||
|
||||
public void Set((int, int) key, T result)
|
||||
{
|
||||
_caches[key] = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Packages/src/Runtime/Internal/Utilities/FrameCache.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/FrameCache.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f129e3b07ffb4d3bbb4cc5f6bd94087
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
257
Packages/src/Runtime/Internal/Utilities/Logging.cs
Normal file
257
Packages/src/Runtime/Internal/Utilities/Logging.cs
Normal file
@@ -0,0 +1,257 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Conditional = System.Diagnostics.ConditionalAttribute;
|
||||
using Object = UnityEngine.Object;
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
#endif
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal static class Logging
|
||||
{
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
private const string k_DisableSymbol = "DISABLE_COFFEE_LOGGER";
|
||||
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
private static void Log_Internal(LogType type, object tag, object message, Object context)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
AppendTag(s_Sb, tag);
|
||||
s_Sb.Append(message);
|
||||
switch (type)
|
||||
{
|
||||
case LogType.Error:
|
||||
case LogType.Assert:
|
||||
case LogType.Exception:
|
||||
Debug.LogError(s_Sb, context);
|
||||
break;
|
||||
case LogType.Warning:
|
||||
Debug.LogWarning(s_Sb, context);
|
||||
break;
|
||||
case LogType.Log:
|
||||
Debug.Log(s_Sb, context);
|
||||
break;
|
||||
}
|
||||
|
||||
s_Sb.Length = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
public static void LogIf(bool enable, object tag, object message, Object context = null)
|
||||
{
|
||||
if (!enable) return;
|
||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
public static void Log(object tag, object message, Object context = null)
|
||||
{
|
||||
Log_Internal(LogType.Log, tag, message, context ? context : tag as Object);
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
public static void LogWarning(object tag, object message, Object context = null)
|
||||
{
|
||||
Log_Internal(LogType.Warning, tag, message, context ? context : tag as Object);
|
||||
}
|
||||
|
||||
public static void LogError(object tag, object message, Object context = null)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
Log_Internal(LogType.Error, tag, message, context ? context : tag as Object);
|
||||
#else
|
||||
Debug.LogError($"{tag}: {message}", context);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
public static void LogMulticast(Type type, string fieldName, object instance = null, string message = null)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
AppendTag(s_Sb, instance ?? type);
|
||||
|
||||
var handler = type
|
||||
.GetField(fieldName,
|
||||
BindingFlags.Static | BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic)
|
||||
?.GetValue(instance);
|
||||
|
||||
var list = ((MulticastDelegate)handler)?.GetInvocationList() ?? Array.Empty<Delegate>();
|
||||
s_Sb.Append("<color=orange>");
|
||||
s_Sb.Append(type.Name);
|
||||
s_Sb.Append(".");
|
||||
s_Sb.Append(fieldName);
|
||||
s_Sb.Append(" has ");
|
||||
s_Sb.Append(list.Length);
|
||||
s_Sb.Append(" callbacks");
|
||||
if (message != null)
|
||||
{
|
||||
s_Sb.Append(" (");
|
||||
s_Sb.Append(message);
|
||||
s_Sb.Append(")");
|
||||
}
|
||||
|
||||
s_Sb.Append(":</color>");
|
||||
|
||||
for (var i = 0; i < list.Length; i++)
|
||||
{
|
||||
s_Sb.Append("\n - ");
|
||||
s_Sb.Append(list[i].Method.DeclaringType?.Name);
|
||||
s_Sb.Append(".");
|
||||
s_Sb.Append(list[i].Method.Name);
|
||||
}
|
||||
|
||||
Debug.Log(s_Sb);
|
||||
s_Sb.Length = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
private static void AppendTag(StringBuilder sb, object tag)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
try
|
||||
{
|
||||
sb.Append("f");
|
||||
sb.Append(Time.frameCount);
|
||||
sb.Append(":<color=#");
|
||||
AppendReadableCode(sb, tag);
|
||||
sb.Append("><b>[");
|
||||
|
||||
switch (tag)
|
||||
{
|
||||
case Type type:
|
||||
AppendType(sb, type);
|
||||
break;
|
||||
case Object uObject:
|
||||
AppendType(sb, tag.GetType());
|
||||
sb.Append(" #");
|
||||
sb.Append(uObject.name);
|
||||
break;
|
||||
default:
|
||||
AppendType(sb, tag.GetType());
|
||||
break;
|
||||
}
|
||||
|
||||
sb.Append("]</b></color> ");
|
||||
}
|
||||
catch
|
||||
{
|
||||
sb.Append("f");
|
||||
sb.Append(Time.frameCount);
|
||||
sb.Append(":<b>[");
|
||||
sb.Append(tag);
|
||||
sb.Append("]</b> ");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
private static void AppendType(StringBuilder sb, Type type)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
if (s_TypeNameCache.TryGetValue(type, out var name))
|
||||
{
|
||||
sb.Append(name);
|
||||
return;
|
||||
}
|
||||
|
||||
// New type found
|
||||
var start = sb.Length;
|
||||
if (0 < start && sb[start - 1] == '<' && (type.Name == "Material" || type.Name == "Color"))
|
||||
{
|
||||
sb.Append('@');
|
||||
}
|
||||
|
||||
sb.Append(type.Name);
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
sb.Length -= 2;
|
||||
sb.Append("<");
|
||||
foreach (var gType in type.GetGenericArguments())
|
||||
{
|
||||
AppendType(sb, gType);
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Length -= 2;
|
||||
sb.Append(">");
|
||||
}
|
||||
|
||||
s_TypeNameCache.Add(type, sb.ToString(start, sb.Length - start));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !ENABLE_COFFEE_LOGGER
|
||||
[Conditional(k_DisableSymbol)]
|
||||
#endif
|
||||
private static void AppendReadableCode(StringBuilder sb, object tag)
|
||||
{
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
int hash;
|
||||
try
|
||||
{
|
||||
switch (tag)
|
||||
{
|
||||
case string text:
|
||||
hash = text.GetHashCode();
|
||||
break;
|
||||
case Type type:
|
||||
type = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
|
||||
hash = type.FullName?.GetHashCode() ?? 0;
|
||||
break;
|
||||
default:
|
||||
hash = tag.GetType().FullName?.GetHashCode() ?? 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
sb.Append("FFFFFF");
|
||||
return;
|
||||
}
|
||||
|
||||
hash = hash & (s_Codes.Length - 1);
|
||||
if (s_Codes[hash] == null)
|
||||
{
|
||||
var hue = hash / (float)s_Codes.Length;
|
||||
var modifier = 1f - Mathf.Clamp01(Mathf.Abs(hue - 0.65f) / 0.2f);
|
||||
var saturation = 0.7f + modifier * -0.2f;
|
||||
var value = 0.8f + modifier * 0.3f;
|
||||
s_Codes[hash] = ColorUtility.ToHtmlStringRGB(Color.HSVToRGB(hue, saturation, value));
|
||||
}
|
||||
|
||||
sb.Append(s_Codes[hash]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_COFFEE_LOGGER
|
||||
private static readonly StringBuilder s_Sb = new StringBuilder();
|
||||
private static readonly string[] s_Codes = new string[64];
|
||||
private static readonly Dictionary<Type, string> s_TypeNameCache = new Dictionary<Type, string>();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
11
Packages/src/Runtime/Internal/Utilities/Logging.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/Logging.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8255313895da84e7cbdc876be3795334
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality to manage materials.
|
||||
/// </summary>
|
||||
internal static class MaterialRepository
|
||||
{
|
||||
private static readonly ObjectRepository<Material> s_Repository = new ObjectRepository<Material>();
|
||||
|
||||
public static int count => s_Repository.count;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||
private static void Clear()
|
||||
{
|
||||
s_Repository.Clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a cached material based on the hash.
|
||||
/// </summary>
|
||||
public static bool Valid(Hash128 hash, Material material)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRegistry] Valid");
|
||||
var ret = s_Repository.Valid(hash, material);
|
||||
Profiler.EndSample();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached material based on the hash.
|
||||
/// </summary>
|
||||
public static void Get(Hash128 hash, ref Material material, Func<Material> onCreate)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||
s_Repository.Get(hash, ref material, onCreate);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached material based on the hash.
|
||||
/// </summary>
|
||||
public static void Get<T>(Hash128 hash, ref Material material, Func<T, Material> onCreate, T source)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||
s_Repository.Get(hash, ref material, onCreate, source);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a soft mask material from the cache.
|
||||
/// </summary>
|
||||
public static void Release(ref Material material)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[MaterialRepository] Release");
|
||||
s_Repository.Release(ref material);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 702912f2ee2ec49bb8003a64151ae4f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
85
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs
Normal file
85
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Object pool.
|
||||
/// </summary>
|
||||
internal class ObjectPool<T>
|
||||
{
|
||||
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)
|
||||
{
|
||||
_onCreate = onCreate;
|
||||
_onValid = onValid;
|
||||
_onReturn = onReturn;
|
||||
}
|
||||
|
||||
/// <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.Count)
|
||||
{
|
||||
var instance = _pool.Pop();
|
||||
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.Count}, created: {++_count}).");
|
||||
return _onCreate();
|
||||
}
|
||||
|
||||
/// <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 || _pool.Contains(instance)) return; // Ignore if already pooled or null.
|
||||
|
||||
_onReturn(instance); // Return the instance to the pool.
|
||||
_pool.Push(instance);
|
||||
Logging.Log(this, $"An instance is released (pooled: {_pool.Count}, created: {_count}).");
|
||||
instance = default; // Set the reference to null.
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Object pool for <see cref="List{T}" />.
|
||||
/// </summary>
|
||||
internal static class ListPool<T>
|
||||
{
|
||||
private static readonly ObjectPool<List<T>> s_ListPool =
|
||||
new ObjectPool<List<T>>(() => new List<T>(), _ => true, x => x.Clear());
|
||||
|
||||
/// <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 s_ListPool.Rent();
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
s_ListPool.Return(ref toRelease);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/ObjectPool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 632cb1ba34e6a4e80b55a32bb63ca369
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
218
Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs
Normal file
218
Packages/src/Runtime/Internal/Utilities/ObjectRepository.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
internal class ObjectRepository<T> where T : Object
|
||||
{
|
||||
private readonly List<Entry> _cache = new List<Entry>();
|
||||
private readonly string _name;
|
||||
private readonly Action<T> _onRelease;
|
||||
private readonly Stack<Entry> _pool = new Stack<Entry>();
|
||||
|
||||
public ObjectRepository(Action<T> onRelease = null)
|
||||
{
|
||||
_name = $"{typeof(T).Name}Repository";
|
||||
if (onRelease == null)
|
||||
{
|
||||
_onRelease = x =>
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
Object.DestroyImmediate(x, false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(x);
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
_onRelease = onRelease;
|
||||
}
|
||||
}
|
||||
|
||||
public int count => _cache.Count;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
for (var i = 0; i < _cache.Count; i++)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
if (entry == null) continue;
|
||||
|
||||
entry.Release(_onRelease);
|
||||
}
|
||||
|
||||
_cache.Clear();
|
||||
}
|
||||
|
||||
public bool Valid(Hash128 hash, T obj)
|
||||
{
|
||||
// Find existing entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Valid > Find existing entry");
|
||||
for (var i = 0; i < _cache.Count; ++i)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
if (entry.hash != hash) continue;
|
||||
Profiler.EndSample();
|
||||
|
||||
// Existing entry found.
|
||||
return entry.storedObject == obj;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached object based on the hash.
|
||||
/// </summary>
|
||||
public void Get(Hash128 hash, ref T obj, Func<T> onCreate)
|
||||
{
|
||||
// Find existing entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Get > Find existing entry");
|
||||
for (var i = 0; i < _cache.Count; ++i)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
if (entry.hash != hash) continue;
|
||||
|
||||
// Existing entry found.
|
||||
if (entry.storedObject != obj)
|
||||
{
|
||||
// if the object is different, release the old one.
|
||||
Release(ref obj);
|
||||
++entry.reference;
|
||||
obj = entry.storedObject;
|
||||
Logging.Log(_name, $"Get(#{count}): {entry}");
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
return;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// Create new entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Get > Create new entry");
|
||||
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
||||
newEntry.storedObject = onCreate();
|
||||
newEntry.hash = hash;
|
||||
newEntry.reference = 1;
|
||||
_cache.Add(newEntry);
|
||||
Logging.Log(_name, $"Get(#{count}): {newEntry}");
|
||||
|
||||
Release(ref obj);
|
||||
obj = newEntry.storedObject;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or retrieves a cached object based on the hash.
|
||||
/// </summary>
|
||||
public void Get<TS>(Hash128 hash, ref T obj, Func<TS, T> onCreate, TS source)
|
||||
{
|
||||
// Find existing entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Get > Find existing entry");
|
||||
for (var i = 0; i < _cache.Count; ++i)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
if (entry.hash != hash) continue;
|
||||
|
||||
// Existing entry found.
|
||||
if (entry.storedObject != obj)
|
||||
{
|
||||
// if the object is different, release the old one.
|
||||
Release(ref obj);
|
||||
++entry.reference;
|
||||
obj = entry.storedObject;
|
||||
Logging.Log(_name, $"Get(#{count}): {entry}");
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
return;
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
// Create new entry.
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Get > Create new entry");
|
||||
var newEntry = 0 < _pool.Count ? _pool.Pop() : new Entry();
|
||||
newEntry.storedObject = onCreate(source);
|
||||
newEntry.hash = hash;
|
||||
newEntry.reference = 1;
|
||||
_cache.Add(newEntry);
|
||||
Logging.Log(_name, $"Get(#{count}): {newEntry}");
|
||||
|
||||
Release(ref obj);
|
||||
obj = newEntry.storedObject;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release a object.
|
||||
/// </summary>
|
||||
public void Release(ref T obj)
|
||||
{
|
||||
if (ReferenceEquals(obj, null)) return;
|
||||
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Release");
|
||||
for (var i = 0; i < _cache.Count; i++)
|
||||
{
|
||||
var entry = _cache[i];
|
||||
|
||||
if (entry.storedObject != obj)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--entry.reference <= 0)
|
||||
{
|
||||
Profiler.BeginSample("(COF)[ObjectRepository] Release > RemoveAt");
|
||||
_cache.RemoveAtFast(i);
|
||||
Logging.Log(_name, $"Release(#{_cache.Count}): {entry}");
|
||||
entry.Release(_onRelease);
|
||||
_pool.Push(entry);
|
||||
Profiler.EndSample();
|
||||
break;
|
||||
}
|
||||
|
||||
Logging.Log(_name, $"Release(#{count}): {entry}");
|
||||
break;
|
||||
}
|
||||
|
||||
obj = null;
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
private class Entry
|
||||
{
|
||||
public Hash128 hash;
|
||||
public int reference;
|
||||
public T storedObject;
|
||||
|
||||
public void Release(Action<T> onRelease)
|
||||
{
|
||||
reference = 0;
|
||||
if (storedObject)
|
||||
{
|
||||
onRelease?.Invoke(storedObject);
|
||||
}
|
||||
|
||||
storedObject = null;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"h{(uint)hash.GetHashCode()} (#{reference}), {storedObject}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a713d67bdb31e45e296e5f18460717e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
92
Packages/src/Runtime/Internal/Utilities/UIExtraCallbacks.cs
Executable file
92
Packages/src/Runtime/Internal/Utilities/UIExtraCallbacks.cs
Executable file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides additional callbacks related to canvas and UI system.
|
||||
/// </summary>
|
||||
internal static class UIExtraCallbacks
|
||||
{
|
||||
private static bool s_IsInitializedAfterCanvasRebuild;
|
||||
private static readonly FastAction s_AfterCanvasRebuildAction = new FastAction();
|
||||
private static readonly FastAction s_LateAfterCanvasRebuildAction = new FastAction();
|
||||
private static readonly FastAction s_BeforeCanvasRebuildAction = new FastAction();
|
||||
|
||||
static UIExtraCallbacks()
|
||||
{
|
||||
Canvas.willRenderCanvases += OnBeforeCanvasRebuild;
|
||||
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases", message: "ctor");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that occurs after canvas rebuilds.
|
||||
/// </summary>
|
||||
public static event Action onLateAfterCanvasRebuild
|
||||
{
|
||||
add => s_LateAfterCanvasRebuildAction.Add(value);
|
||||
remove => s_LateAfterCanvasRebuildAction.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that occurs before canvas rebuilds.
|
||||
/// </summary>
|
||||
public static event Action onBeforeCanvasRebuild
|
||||
{
|
||||
add => s_BeforeCanvasRebuildAction.Add(value);
|
||||
remove => s_BeforeCanvasRebuildAction.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event that occurs after canvas rebuilds.
|
||||
/// </summary>
|
||||
public static event Action onAfterCanvasRebuild
|
||||
{
|
||||
add => s_AfterCanvasRebuildAction.Add(value);
|
||||
remove => s_AfterCanvasRebuildAction.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the UIExtraCallbacks to ensure proper event handling.
|
||||
/// </summary>
|
||||
private static void InitializeAfterCanvasRebuild()
|
||||
{
|
||||
if (s_IsInitializedAfterCanvasRebuild) return;
|
||||
s_IsInitializedAfterCanvasRebuild = true;
|
||||
|
||||
CanvasUpdateRegistry.IsRebuildingLayout();
|
||||
Canvas.willRenderCanvases += OnAfterCanvasRebuild;
|
||||
Logging.LogMulticast(typeof(Canvas), "willRenderCanvases",
|
||||
message: "InitializeAfterCanvasRebuild");
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoadMethod]
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#endif
|
||||
private static void InitializeOnLoad()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback method called before canvas rebuilds.
|
||||
/// </summary>
|
||||
private static void OnBeforeCanvasRebuild()
|
||||
{
|
||||
s_BeforeCanvasRebuildAction.Invoke();
|
||||
InitializeAfterCanvasRebuild();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback method called after canvas rebuilds.
|
||||
/// </summary>
|
||||
private static void OnAfterCanvasRebuild()
|
||||
{
|
||||
s_AfterCanvasRebuildAction.Invoke();
|
||||
s_LateAfterCanvasRebuildAction.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ea318e6e3e6c46aa97c72e28230bdc9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,72 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Coffee.UIParticleExtensions
|
||||
{
|
||||
internal class ModifiedMaterial
|
||||
{
|
||||
private static readonly List<MatEntry> s_Entries = new List<MatEntry>();
|
||||
|
||||
public static Material Add(Material baseMat, Texture texture, int id, int props)
|
||||
{
|
||||
MatEntry e;
|
||||
for (var i = 0; i < s_Entries.Count; i++)
|
||||
{
|
||||
e = s_Entries[i];
|
||||
if (e.baseMat != baseMat || e.texture != texture || e.id != id || e.props != props) continue;
|
||||
++e.count;
|
||||
return e.customMat;
|
||||
}
|
||||
|
||||
e = new MatEntry
|
||||
{
|
||||
count = 1,
|
||||
baseMat = baseMat,
|
||||
texture = texture,
|
||||
id = id,
|
||||
props = props,
|
||||
customMat = new Material(baseMat)
|
||||
{
|
||||
name = $"{baseMat.name}_{id}",
|
||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
||||
mainTexture = texture ? texture : null
|
||||
}
|
||||
};
|
||||
s_Entries.Add(e);
|
||||
//Debug.LogFormat(">>>> ModifiedMaterial.Add -> count = count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count, baseMat, texture, id);
|
||||
return e.customMat;
|
||||
}
|
||||
|
||||
public static void Remove(Material customMat)
|
||||
{
|
||||
if (!customMat) return;
|
||||
|
||||
for (var i = 0; i < s_Entries.Count; ++i)
|
||||
{
|
||||
var e = s_Entries[i];
|
||||
if (e.customMat != customMat) continue;
|
||||
if (--e.count == 0)
|
||||
{
|
||||
//Debug.LogFormat(">>>> ModifiedMaterial.Remove -> count:{0}, mat:{1}, tex:{2}, id:{3}", s_Entries.Count - 1, e.customMat, e.texture, e.id);
|
||||
Misc.DestroyImmediate(e.customMat);
|
||||
e.customMat = null;
|
||||
e.baseMat = null;
|
||||
e.texture = null;
|
||||
s_Entries.RemoveAt(i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private class MatEntry
|
||||
{
|
||||
public Material baseMat;
|
||||
public int count;
|
||||
public Material customMat;
|
||||
public int id;
|
||||
public int props;
|
||||
public Texture texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Coffee.UIParticleExtensions;
|
||||
using UnityEditor;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Serialization;
|
||||
using UnityEngine.UI;
|
||||
@@ -100,9 +100,6 @@ namespace Coffee.UIExtensions
|
||||
"UIParticle: UIParticle.scale will be adjusted.")]
|
||||
private AutoScalingMode m_AutoScalingMode = AutoScalingMode.Transform;
|
||||
|
||||
[SerializeField]
|
||||
private bool m_ResetScaleOnEnable;
|
||||
|
||||
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
|
||||
private int _groupId;
|
||||
private Camera _orthoCamera;
|
||||
@@ -297,13 +294,6 @@ namespace Coffee.UIExtensions
|
||||
}
|
||||
|
||||
base.OnEnable();
|
||||
|
||||
// Reset scale for upgrade.
|
||||
if (m_ResetScaleOnEnable)
|
||||
{
|
||||
m_ResetScaleOnEnable = false;
|
||||
transform.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -345,17 +335,6 @@ namespace Coffee.UIExtensions
|
||||
m_IgnoreCanvasScaler = false;
|
||||
m_AutoScaling = false;
|
||||
m_AutoScalingMode = AutoScalingMode.Transform;
|
||||
m_ResetScaleOnEnable = true;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
if (!this || !gameObject || !transform || Application.isPlaying) return;
|
||||
transform.localScale = Vector3.one;
|
||||
m_ResetScaleOnEnable = false;
|
||||
EditorUtility.SetDirty(this);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
if (m_AbsoluteMode)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using Coffee.UIParticleExtensions;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
#elif UNITY_2022_3_OR_NEWER
|
||||
#define PS_BAKE_API_V2
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Coffee.UIParticleExtensions;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
@@ -28,7 +29,6 @@ namespace Coffee.UIExtensions
|
||||
private static readonly List<UIParticleRenderer> s_Renderers = new List<UIParticleRenderer>();
|
||||
private static readonly List<Color32> s_Colors = new List<Color32>();
|
||||
private static readonly Vector3[] s_Corners = new Vector3[4];
|
||||
private Material _currentMaterialForRendering;
|
||||
private bool _delay;
|
||||
private int _index;
|
||||
private bool _isTrail;
|
||||
@@ -117,9 +117,8 @@ namespace Coffee.UIExtensions
|
||||
}
|
||||
else
|
||||
{
|
||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||
_modifiedMaterial = null;
|
||||
_currentMaterialForRendering = null;
|
||||
MaterialRepository.Release(ref _modifiedMaterial);
|
||||
_materialForRendering = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,17 +134,14 @@ namespace Coffee.UIExtensions
|
||||
hideFlags = HideFlags.HideAndDontSave
|
||||
};
|
||||
}
|
||||
|
||||
_currentMaterialForRendering = null;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||
_modifiedMaterial = null;
|
||||
_currentMaterialForRendering = null;
|
||||
MaterialRepository.Release(ref _modifiedMaterial);
|
||||
_materialForRendering = null;
|
||||
}
|
||||
|
||||
public static UIParticleRenderer AddRenderer(UIParticle parent, int index)
|
||||
@@ -177,12 +173,9 @@ namespace Coffee.UIExtensions
|
||||
/// </summary>
|
||||
public override Material GetModifiedMaterial(Material baseMaterial)
|
||||
{
|
||||
_currentMaterialForRendering = null;
|
||||
|
||||
if (!IsActive() || !_parent)
|
||||
{
|
||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||
_modifiedMaterial = null;
|
||||
MaterialRepository.Release(ref _modifiedMaterial);
|
||||
return baseMaterial;
|
||||
}
|
||||
|
||||
@@ -192,23 +185,30 @@ namespace Coffee.UIExtensions
|
||||
var texture = mainTexture;
|
||||
if (texture == null && _parent.m_AnimatableProperties.Length == 0)
|
||||
{
|
||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||
_modifiedMaterial = null;
|
||||
MaterialRepository.Release(ref _modifiedMaterial);
|
||||
return modifiedMaterial;
|
||||
}
|
||||
|
||||
//
|
||||
var id = _parent.m_AnimatableProperties.Length == 0 ? 0 : GetInstanceID();
|
||||
var hash = new Hash128(
|
||||
modifiedMaterial ? (uint)modifiedMaterial.GetInstanceID() : 0,
|
||||
texture ? (uint)texture.GetInstanceID() : 0,
|
||||
0 < _parent.m_AnimatableProperties.Length ? (uint)GetInstanceID() : 0,
|
||||
#if UNITY_EDITOR
|
||||
var props = EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode();
|
||||
(uint)EditorJsonUtility.ToJson(modifiedMaterial).GetHashCode()
|
||||
#else
|
||||
var props = 0;
|
||||
0
|
||||
#endif
|
||||
modifiedMaterial = ModifiedMaterial.Add(modifiedMaterial, texture, id, props);
|
||||
ModifiedMaterial.Remove(_modifiedMaterial);
|
||||
_modifiedMaterial = modifiedMaterial;
|
||||
);
|
||||
if (!MaterialRepository.Valid(hash, _modifiedMaterial))
|
||||
{
|
||||
MaterialRepository.Get(hash, ref _modifiedMaterial, () => new Material(modifiedMaterial)
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave
|
||||
});
|
||||
}
|
||||
|
||||
return modifiedMaterial;
|
||||
return _modifiedMaterial;
|
||||
}
|
||||
|
||||
public void Set(UIParticle parent, ParticleSystem ps, bool isTrail)
|
||||
@@ -328,7 +328,16 @@ namespace Coffee.UIExtensions
|
||||
|
||||
// Bake mesh.
|
||||
Profiler.BeginSample("[UIParticleRenderer] Bake Mesh");
|
||||
if (_isTrail && _parent.canSimulate && 0 < s_CombineInstances[0].mesh.vertexCount)
|
||||
s_CombineInstances[0].mesh.Clear(false);
|
||||
|
||||
// Assertion failed on expression: 'ps->array_size()' #278
|
||||
var extends = s_CombineInstances[0].mesh.bounds.extents.x;
|
||||
if (!float.IsNaN(extends) && !float.IsInfinity(extends) && 0 < extends)
|
||||
{
|
||||
s_CombineInstances[0].mesh.RecalculateBounds();
|
||||
}
|
||||
|
||||
if (_isTrail && _parent.canSimulate && 0 < _particleSystem.particleCount)
|
||||
{
|
||||
#if PS_BAKE_API_V2
|
||||
_renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera,
|
||||
@@ -337,7 +346,7 @@ namespace Coffee.UIExtensions
|
||||
_renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera, true);
|
||||
#endif
|
||||
}
|
||||
else if (_renderer.CanBakeMesh())
|
||||
else if (!_isTrail && _renderer.CanBakeMesh())
|
||||
{
|
||||
_particleSystem.ValidateShape();
|
||||
#if PS_BAKE_API_V2
|
||||
@@ -347,15 +356,10 @@ namespace Coffee.UIExtensions
|
||||
_renderer.BakeMesh(s_CombineInstances[0].mesh, bakeCamera, true);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
s_CombineInstances[0].mesh.Clear(false);
|
||||
}
|
||||
|
||||
// Too many vertices to render.
|
||||
if (65535 <= s_CombineInstances[0].mesh.vertexCount)
|
||||
{
|
||||
s_CombineInstances[0].mesh.Clear(false);
|
||||
Debug.LogErrorFormat(this,
|
||||
"Too many vertices to render. index={0}, isTrail={1}, vertexCount={2}(>=65535)",
|
||||
_index,
|
||||
@@ -400,33 +404,22 @@ namespace Coffee.UIExtensions
|
||||
_lastBounds = bounds;
|
||||
|
||||
// Convert linear color to gamma color.
|
||||
if (QualitySettings.activeColorSpace == ColorSpace.Linear)
|
||||
if (canvas.ShouldGammaToLinearInMesh())
|
||||
{
|
||||
Profiler.BeginSample("[UIParticleRenderer] Convert Linear to Gamma");
|
||||
workerMesh.GetColors(s_Colors);
|
||||
var count_c = s_Colors.Count;
|
||||
for (var i = 0; i < count_c; i++)
|
||||
{
|
||||
var c = s_Colors[i];
|
||||
c.r = c.r.LinearToGamma();
|
||||
c.g = c.g.LinearToGamma();
|
||||
c.b = c.b.LinearToGamma();
|
||||
s_Colors[i] = c;
|
||||
}
|
||||
|
||||
workerMesh.SetColors(s_Colors);
|
||||
Profiler.EndSample();
|
||||
workerMesh.LinearToGamma();
|
||||
}
|
||||
|
||||
GetComponents(typeof(IMeshModifier), s_Components);
|
||||
for (var i = 0; i < s_Components.Count; i++)
|
||||
{
|
||||
var components = ListPool<Component>.Rent();
|
||||
GetComponents(typeof(IMeshModifier), components);
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
((IMeshModifier)s_Components[i]).ModifyMesh(workerMesh);
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
for (var i = 0; i < components.Count; i++)
|
||||
{
|
||||
((IMeshModifier)components[i]).ModifyMesh(workerMesh);
|
||||
}
|
||||
#pragma warning restore CS0618 // Type or member is obsolete
|
||||
|
||||
s_Components.Clear();
|
||||
ListPool<Component>.Return(ref components);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
@@ -517,7 +510,8 @@ namespace Coffee.UIExtensions
|
||||
var scale = _parent.scale3DForCalc.GetScaled(_parent.parentScale);
|
||||
|
||||
if (_parent.autoScalingMode == UIParticle.AutoScalingMode.UIParticle
|
||||
&& _particleSystem.main.scalingMode == ParticleSystemScalingMode.Local)
|
||||
&& _particleSystem.main.scalingMode == ParticleSystemScalingMode.Local
|
||||
&& _parent.canvas)
|
||||
{
|
||||
scale = scale.GetScaled(_parent.canvas.transform.localScale);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Coffee.UIParticleInternal;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -39,12 +40,12 @@ namespace Coffee.UIExtensions
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoadMethod]
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
#endif
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
private static void InitializeOnLoad()
|
||||
{
|
||||
Canvas.willRenderCanvases -= Refresh;
|
||||
Canvas.willRenderCanvases += Refresh;
|
||||
UIExtraCallbacks.onAfterCanvasRebuild += Refresh;
|
||||
}
|
||||
|
||||
private static void Refresh()
|
||||
|
||||
8
Packages/src/Runtime/Utilities.meta
Normal file
8
Packages/src/Runtime/Utilities.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66c42f0f30de84ca4bd8305a1188af85
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,96 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Coffee.UIParticleExtensions
|
||||
namespace Coffee.UIParticleInternal
|
||||
{
|
||||
public static class Color32Extensions
|
||||
{
|
||||
private static byte[] s_LinearToGammaLut;
|
||||
|
||||
public static byte LinearToGamma(this byte self)
|
||||
{
|
||||
if (s_LinearToGammaLut == null)
|
||||
{
|
||||
s_LinearToGammaLut = new byte[256];
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
s_LinearToGammaLut[i] = (byte)(Mathf.LinearToGammaSpace(i / 255f) * 255f);
|
||||
}
|
||||
}
|
||||
|
||||
return s_LinearToGammaLut[self];
|
||||
}
|
||||
}
|
||||
|
||||
public static class Vector3Extensions
|
||||
{
|
||||
public static Vector3 Inverse(this Vector3 self)
|
||||
{
|
||||
self.x = Mathf.Approximately(self.x, 0) ? 1 : 1 / self.x;
|
||||
self.y = Mathf.Approximately(self.y, 0) ? 1 : 1 / self.y;
|
||||
self.z = Mathf.Approximately(self.z, 0) ? 1 : 1 / self.z;
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1)
|
||||
{
|
||||
self.Scale(other1);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2)
|
||||
{
|
||||
self.Scale(other1);
|
||||
self.Scale(other2);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static Vector3 GetScaled(this Vector3 self, Vector3 other1, Vector3 other2, Vector3 other3)
|
||||
{
|
||||
self.Scale(other1);
|
||||
self.Scale(other2);
|
||||
self.Scale(other3);
|
||||
return self;
|
||||
}
|
||||
|
||||
public static bool IsVisible(this Vector3 self)
|
||||
{
|
||||
return 0 < Mathf.Abs(self.x * self.y * self.z);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class SpriteExtensions
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
private static readonly Type s_SpriteEditorExtensionType =
|
||||
Type.GetType("UnityEditor.Experimental.U2D.SpriteEditorExtension, UnityEditor")
|
||||
?? Type.GetType("UnityEditor.U2D.SpriteEditorExtension, UnityEditor");
|
||||
|
||||
private static readonly MethodInfo s_GetActiveAtlasTextureMethodInfo = s_SpriteEditorExtensionType
|
||||
.GetMethod("GetActiveAtlasTexture", BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
public static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
if (!self) return null;
|
||||
|
||||
if (Application.isPlaying) return self.texture;
|
||||
var ret = s_GetActiveAtlasTextureMethodInfo.Invoke(null, new object[] { self }) as Texture2D;
|
||||
return ret
|
||||
? ret
|
||||
: self.texture;
|
||||
}
|
||||
#else
|
||||
internal static Texture2D GetActualTexture(this Sprite self)
|
||||
{
|
||||
return self ? self.texture : null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public static class ParticleSystemExtensions
|
||||
internal static class ParticleSystemExtensions
|
||||
{
|
||||
private static ParticleSystem.Particle[] s_TmpParticles = new ParticleSystem.Particle[2048];
|
||||
|
||||
@@ -250,59 +165,11 @@ namespace Coffee.UIParticleExtensions
|
||||
|
||||
public static void Exec(this List<ParticleSystem> self, Action<ParticleSystem> action)
|
||||
{
|
||||
self.RemoveAll(p => !p);
|
||||
self.ForEach(action);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Misc
|
||||
{
|
||||
public static void Destroy(Object obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
foreach (var p in self)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
if (!p) continue;
|
||||
action.Invoke(p);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyImmediate(Object obj)
|
||||
{
|
||||
if (!obj) return;
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isEditor)
|
||||
{
|
||||
Object.DestroyImmediate(obj);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(obj);
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
{
|
||||
if (!self) return null;
|
||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||
|
||||
var current = self.transform;
|
||||
while (current)
|
||||
{
|
||||
var component = current.GetComponent<T>();
|
||||
if (component) return component;
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e51604bfb810e44519e2710fd1b8af90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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.6.2",
|
||||
"version": "4.6.4",
|
||||
"unity": "2018.2",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
||||
Reference in New Issue
Block a user